diff options
Diffstat (limited to 'wm/dwl/client.h')
| -rw-r--r-- | wm/dwl/client.h | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/wm/dwl/client.h b/wm/dwl/client.h new file mode 100644 index 0000000..5a45edc --- /dev/null +++ b/wm/dwl/client.h @@ -0,0 +1,394 @@ +/* + * Attempt to consolidate unavoidable suck into one file, away from dwl.c. This + * file is not meant to be pretty. We use a .h file with static inline + * functions instead of a separate .c module, or function pointers like sway, so + * that they will simply compile out if the chosen #defines leave them unused. + */ + +/* Leave these functions first; they're used in the others */ +static inline int +client_is_x11(Client *c) +{ +#ifdef XWAYLAND + return c->type == X11Managed || c->type == X11Unmanaged; +#else + return 0; +#endif +} + +static inline void +client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min) +{ + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state *state; +#ifdef XWAYLAND + if (client_is_x11(c)) { + xcb_size_hints_t *size_hints = c->surface.xwayland->size_hints; + if (size_hints) { + max->width = size_hints->max_width; + max->height = size_hints->max_height; + min->width = size_hints->min_width; + min->height = size_hints->min_height; + } + return; + } +#endif + toplevel = c->surface.xdg->toplevel; + state = &toplevel->current; + max->width = state->max_width; + max->height = state->max_height; + min->width = state->min_width; + min->height = state->min_height; +} + +static inline struct wlr_surface * +client_surface(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->surface; +#endif + return c->surface.xdg->surface; +} + +static inline int +toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) +{ + struct wlr_xdg_surface *xdg_surface; + struct wlr_surface *root_surface; + struct wlr_layer_surface_v1 *layer_surface; + Client *c = NULL; + LayerSurface *l = NULL; + int type = -1; +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface; +#endif + + if (!s) + return type; + root_surface = wlr_surface_get_root_surface(s); + +#ifdef XWAYLAND + if (wlr_surface_is_xwayland_surface(root_surface) + && (xsurface = wlr_xwayland_surface_from_wlr_surface(root_surface))) { + c = xsurface->data; + type = c->type; + goto end; + } +#endif + + if (wlr_surface_is_layer_surface(root_surface) + && (layer_surface = wlr_layer_surface_v1_from_wlr_surface(root_surface))) { + l = layer_surface->data; + type = LayerShell; + goto end; + } + + if (wlr_surface_is_xdg_surface(root_surface) + && (xdg_surface = wlr_xdg_surface_from_wlr_surface(root_surface))) { + while (1) { + switch (xdg_surface->role) { + case WLR_XDG_SURFACE_ROLE_POPUP: + if (!xdg_surface->popup->parent) + return -1; + else if (!wlr_surface_is_xdg_surface(xdg_surface->popup->parent)) + return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); + + xdg_surface = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + c = xdg_surface->data; + type = c->type; + goto end; + case WLR_XDG_SURFACE_ROLE_NONE: + return -1; + } + } + } + +end: + if (pl) + *pl = l; + if (pc) + *pc = c; + return type; +} + +/* The others */ +static inline void +client_activate_surface(struct wlr_surface *s, int activated) +{ + struct wlr_xdg_surface *surface; +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface; + if (wlr_surface_is_xwayland_surface(s) + && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) { + wlr_xwayland_surface_activate(xsurface, activated); + return; + } +#endif + if (wlr_surface_is_xdg_surface(s) + && (surface = wlr_xdg_surface_from_wlr_surface(s)) + && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) + wlr_xdg_toplevel_set_activated(surface->toplevel, activated); +} + +static inline uint32_t +client_set_bounds(Client *c, int32_t width, int32_t height) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return 0; +#endif + if (c->surface.xdg->client->shell->version >= + XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0) + return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); + return 0; +} + +static inline void +client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data) +{ + wlr_surface_for_each_surface(client_surface(c), fn, data); +#ifdef XWAYLAND + if (client_is_x11(c)) + return; +#endif + wlr_xdg_surface_for_each_popup_surface(c->surface.xdg, fn, data); +} + +static inline const char * +client_get_appid(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->class; +#endif + return c->surface.xdg->toplevel->app_id; +} + +static inline void +client_get_geometry(Client *c, struct wlr_box *geom) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + geom->x = c->surface.xwayland->x; + geom->y = c->surface.xwayland->y; + geom->width = c->surface.xwayland->width; + geom->height = c->surface.xwayland->height; + return; + } +#endif + wlr_xdg_surface_get_geometry(c->surface.xdg, geom); +} + +static inline Client * +client_get_parent(Client *c) +{ + Client *p = NULL; +#ifdef XWAYLAND + if (client_is_x11(c) && c->surface.xwayland->parent) + toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); +#endif + if (c->surface.xdg->toplevel->parent) + toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); + + return p; +} + +static inline const char * +client_get_title(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->title; +#endif + return c->surface.xdg->toplevel->title; +} + +static inline int +client_is_float_type(Client *c) +{ + struct wlr_box min = {0}, max = {0}; + client_get_size_hints(c, &max, &min); + +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface *surface = c->surface.xwayland; + if (surface->modal) + return 1; + + for (size_t i = 0; i < surface->window_type_len; i++) + if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] + || surface->window_type[i] == netatom[NetWMWindowTypeSplash] + || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] + || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) + return 1; + } +#endif + return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) + && (min.width == max.width || min.height == max.height)); +} + +static inline int +client_is_mapped(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->mapped; +#endif + return c->surface.xdg->mapped; +} + +static inline int +client_is_rendered_on_mon(Client *c, Monitor *m) +{ + /* This is needed for when you don't want to check formal assignment, + * but rather actual displaying of the pixels. + * Usually VISIBLEON suffices and is also faster. */ + struct wlr_surface_output *s; + if (!c->scene->node.enabled) + return 0; + wl_list_for_each(s, &client_surface(c)->current_outputs, link) + if (s->output == m->wlr_output) + return 1; + return 0; +} + +static inline int +client_is_stopped(Client *c) +{ + int pid; + siginfo_t in = {0}; +#ifdef XWAYLAND + if (client_is_x11(c)) + return 0; +#endif + + wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); + if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) { + /* This process is not our child process, while is very unluckely that + * it is stopped, in order to do not skip frames assume that it is. */ + if (errno == ECHILD) + return 1; + } else if (in.si_pid) { + if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) + return 1; + if (in.si_code == CLD_CONTINUED) + return 0; + } + + return 0; +} + +static inline int +client_is_unmanaged(Client *c) +{ +#ifdef XWAYLAND + return c->type == X11Unmanaged; +#endif + return 0; +} + +static inline void +client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb) +{ + if (kb) + wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes, + kb->num_keycodes, &kb->modifiers); + else + wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL); +} + +static inline void +client_restack_surface(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + wlr_xwayland_surface_restack(c->surface.xwayland, NULL, + XCB_STACK_MODE_ABOVE); +#endif + return; +} + +static inline void +client_send_close(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + wlr_xwayland_surface_close(c->surface.xwayland); + return; + } +#endif + wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel); +} + +static inline void +client_set_fullscreen(Client *c, int fullscreen) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen); + return; + } +#endif + wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen); +} + +static inline uint32_t +client_set_size(Client *c, uint32_t width, uint32_t height) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + wlr_xwayland_surface_configure(c->surface.xwayland, + c->geom.x, c->geom.y, width, height); + return 0; + } +#endif + if (width == c->surface.xdg->toplevel->current.width + && height ==c->surface.xdg->toplevel->current.height) + return 0; + return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, width, height); +} + +static inline void +client_set_tiled(Client *c, uint32_t edges) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return; +#endif + wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); +} + +static inline struct wlr_surface * +client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return wlr_surface_surface_at(c->surface.xwayland->surface, + cx, cy, sx, sy); +#endif + return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); +} + +static inline int +client_wants_focus(Client *c) +{ +#ifdef XWAYLAND + return client_is_unmanaged(c) + && wlr_xwayland_or_surface_wants_focus(c->surface.xwayland) + && wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE; +#endif + return 0; +} + +static inline int +client_wants_fullscreen(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->fullscreen; +#endif + return c->surface.xdg->toplevel->requested.fullscreen; +} |