client.h (9970B)
1 /* 2 * Attempt to consolidate unavoidable suck into one file, away from dwl.c. This 3 * file is not meant to be pretty. We use a .h file with static inline 4 * functions instead of a separate .c module, or function pointers like sway, so 5 * that they will simply compile out if the chosen #defines leave them unused. 6 */ 7 8 /* Leave these functions first; they're used in the others */ 9 static inline int 10 client_is_x11(Client *c) 11 { 12 #ifdef XWAYLAND 13 return c->type == X11; 14 #endif 15 return 0; 16 } 17 18 static inline struct wlr_surface * 19 client_surface(Client *c) 20 { 21 #ifdef XWAYLAND 22 if (client_is_x11(c)) 23 return c->surface.xwayland->surface; 24 #endif 25 return c->surface.xdg->surface; 26 } 27 28 static inline int 29 toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) 30 { 31 struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface; 32 struct wlr_surface *root_surface; 33 struct wlr_layer_surface_v1 *layer_surface; 34 Client *c = NULL; 35 LayerSurface *l = NULL; 36 int type = -1; 37 #ifdef XWAYLAND 38 struct wlr_xwayland_surface *xsurface; 39 #endif 40 41 if (!s) 42 return -1; 43 root_surface = wlr_surface_get_root_surface(s); 44 45 #ifdef XWAYLAND 46 if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) { 47 c = xsurface->data; 48 type = c->type; 49 goto end; 50 } 51 #endif 52 53 if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) { 54 l = layer_surface->data; 55 type = LayerShell; 56 goto end; 57 } 58 59 xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface); 60 while (xdg_surface) { 61 tmp_xdg_surface = NULL; 62 switch (xdg_surface->role) { 63 case WLR_XDG_SURFACE_ROLE_POPUP: 64 if (!xdg_surface->popup || !xdg_surface->popup->parent) 65 return -1; 66 67 tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent); 68 69 if (!tmp_xdg_surface) 70 return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); 71 72 xdg_surface = tmp_xdg_surface; 73 break; 74 case WLR_XDG_SURFACE_ROLE_TOPLEVEL: 75 c = xdg_surface->data; 76 type = c->type; 77 goto end; 78 case WLR_XDG_SURFACE_ROLE_NONE: 79 return -1; 80 } 81 } 82 83 end: 84 if (pl) 85 *pl = l; 86 if (pc) 87 *pc = c; 88 return type; 89 } 90 91 /* The others */ 92 static inline void 93 client_activate_surface(struct wlr_surface *s, int activated) 94 { 95 struct wlr_xdg_toplevel *toplevel; 96 #ifdef XWAYLAND 97 struct wlr_xwayland_surface *xsurface; 98 if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) { 99 wlr_xwayland_surface_activate(xsurface, activated); 100 return; 101 } 102 #endif 103 if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s))) 104 wlr_xdg_toplevel_set_activated(toplevel, activated); 105 } 106 107 static inline uint32_t 108 client_set_bounds(Client *c, int32_t width, int32_t height) 109 { 110 #ifdef XWAYLAND 111 if (client_is_x11(c)) 112 return 0; 113 #endif 114 if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= 115 XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0 116 && (c->bounds.width != width || c->bounds.height != height)) { 117 c->bounds.width = width; 118 c->bounds.height = height; 119 return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); 120 } 121 return 0; 122 } 123 124 static inline const char * 125 client_get_appid(Client *c) 126 { 127 #ifdef XWAYLAND 128 if (client_is_x11(c)) 129 return c->surface.xwayland->class; 130 #endif 131 return c->surface.xdg->toplevel->app_id; 132 } 133 134 static inline void 135 client_get_clip(Client *c, struct wlr_box *clip) 136 { 137 struct wlr_box xdg_geom = {0}; 138 *clip = (struct wlr_box){ 139 .x = 0, 140 .y = 0, 141 .width = c->geom.width - c->bw, 142 .height = c->geom.height - c->bw, 143 }; 144 145 #ifdef XWAYLAND 146 if (client_is_x11(c)) 147 return; 148 #endif 149 150 wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom); 151 clip->x = xdg_geom.x; 152 clip->y = xdg_geom.y; 153 } 154 155 static inline void 156 client_get_geometry(Client *c, struct wlr_box *geom) 157 { 158 #ifdef XWAYLAND 159 if (client_is_x11(c)) { 160 geom->x = c->surface.xwayland->x; 161 geom->y = c->surface.xwayland->y; 162 geom->width = c->surface.xwayland->width; 163 geom->height = c->surface.xwayland->height; 164 return; 165 } 166 #endif 167 wlr_xdg_surface_get_geometry(c->surface.xdg, geom); 168 } 169 170 static inline Client * 171 client_get_parent(Client *c) 172 { 173 Client *p = NULL; 174 #ifdef XWAYLAND 175 if (client_is_x11(c)) { 176 if (c->surface.xwayland->parent) 177 toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); 178 return p; 179 } 180 #endif 181 if (c->surface.xdg->toplevel->parent) 182 toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); 183 return p; 184 } 185 186 static inline int 187 client_has_children(Client *c) 188 { 189 #ifdef XWAYLAND 190 if (client_is_x11(c)) 191 return !wl_list_empty(&c->surface.xwayland->children); 192 #endif 193 /* surface.xdg->link is never empty because it always contains at least the 194 * surface itself. */ 195 return wl_list_length(&c->surface.xdg->link) > 1; 196 } 197 198 static inline const char * 199 client_get_title(Client *c) 200 { 201 #ifdef XWAYLAND 202 if (client_is_x11(c)) 203 return c->surface.xwayland->title; 204 #endif 205 return c->surface.xdg->toplevel->title; 206 } 207 208 static inline int 209 client_is_float_type(Client *c) 210 { 211 struct wlr_xdg_toplevel *toplevel; 212 struct wlr_xdg_toplevel_state state; 213 214 #ifdef XWAYLAND 215 if (client_is_x11(c)) { 216 struct wlr_xwayland_surface *surface = c->surface.xwayland; 217 xcb_size_hints_t *size_hints = surface->size_hints; 218 size_t i; 219 if (surface->modal) 220 return 1; 221 222 for (i = 0; i < surface->window_type_len; i++) 223 if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] 224 || surface->window_type[i] == netatom[NetWMWindowTypeSplash] 225 || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] 226 || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) 227 return 1; 228 229 return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 230 && (size_hints->max_width == size_hints->min_width 231 || size_hints->max_height == size_hints->min_height); 232 } 233 #endif 234 235 toplevel = c->surface.xdg->toplevel; 236 state = toplevel->current; 237 return toplevel->parent || (state.min_width != 0 && state.min_height != 0 238 && (state.min_width == state.max_width 239 || state.min_height == state.max_height)); 240 } 241 242 static inline int 243 client_is_rendered_on_mon(Client *c, Monitor *m) 244 { 245 /* This is needed for when you don't want to check formal assignment, 246 * but rather actual displaying of the pixels. 247 * Usually VISIBLEON suffices and is also faster. */ 248 struct wlr_surface_output *s; 249 int unused_lx, unused_ly; 250 if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly)) 251 return 0; 252 wl_list_for_each(s, &client_surface(c)->current_outputs, link) 253 if (s->output == m->wlr_output) 254 return 1; 255 return 0; 256 } 257 258 static inline int 259 client_is_stopped(Client *c) 260 { 261 int pid; 262 siginfo_t in = {0}; 263 #ifdef XWAYLAND 264 if (client_is_x11(c)) 265 return 0; 266 #endif 267 268 wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); 269 if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) { 270 /* This process is not our child process, while is very unluckely that 271 * it is stopped, in order to do not skip frames assume that it is. */ 272 if (errno == ECHILD) 273 return 1; 274 } else if (in.si_pid) { 275 if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) 276 return 1; 277 if (in.si_code == CLD_CONTINUED) 278 return 0; 279 } 280 281 return 0; 282 } 283 284 static inline int 285 client_is_unmanaged(Client *c) 286 { 287 #ifdef XWAYLAND 288 if (client_is_x11(c)) 289 return c->surface.xwayland->override_redirect; 290 #endif 291 return 0; 292 } 293 294 static inline void 295 client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb) 296 { 297 if (kb) 298 wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes, 299 kb->num_keycodes, &kb->modifiers); 300 else 301 wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL); 302 } 303 304 static inline void 305 client_restack_surface(Client *c) 306 { 307 #ifdef XWAYLAND 308 if (client_is_x11(c)) 309 wlr_xwayland_surface_restack(c->surface.xwayland, NULL, 310 XCB_STACK_MODE_ABOVE); 311 #endif 312 return; 313 } 314 315 static inline void 316 client_send_close(Client *c) 317 { 318 #ifdef XWAYLAND 319 if (client_is_x11(c)) { 320 wlr_xwayland_surface_close(c->surface.xwayland); 321 return; 322 } 323 #endif 324 wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel); 325 } 326 327 static inline void 328 client_set_border_color(Client *c, const float color[static 4]) 329 { 330 int i; 331 for (i = 0; i < 4; i++) 332 wlr_scene_rect_set_color(c->border[i], color); 333 } 334 335 static inline void 336 client_set_fullscreen(Client *c, int fullscreen) 337 { 338 #ifdef XWAYLAND 339 if (client_is_x11(c)) { 340 wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen); 341 return; 342 } 343 #endif 344 wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen); 345 } 346 347 static inline uint32_t 348 client_set_size(Client *c, uint32_t width, uint32_t height) 349 { 350 #ifdef XWAYLAND 351 if (client_is_x11(c)) { 352 wlr_xwayland_surface_configure(c->surface.xwayland, 353 c->geom.x + c->bw, c->geom.y + c->bw, width, height); 354 return 0; 355 } 356 #endif 357 if ((int32_t)width == c->surface.xdg->toplevel->current.width 358 && (int32_t)height == c->surface.xdg->toplevel->current.height) 359 return 0; 360 return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height); 361 } 362 363 static inline void 364 client_set_tiled(Client *c, uint32_t edges) 365 { 366 #ifdef XWAYLAND 367 if (client_is_x11(c)) 368 return; 369 #endif 370 if (wl_resource_get_version(c->surface.xdg->toplevel->resource) 371 >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { 372 wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); 373 } else { 374 wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE); 375 } 376 } 377 378 static inline void 379 client_set_suspended(Client *c, int suspended) 380 { 381 #ifdef XWAYLAND 382 if (client_is_x11(c)) 383 return; 384 #endif 385 386 wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); 387 } 388 389 static inline int 390 client_wants_focus(Client *c) 391 { 392 #ifdef XWAYLAND 393 return client_is_unmanaged(c) 394 && wlr_xwayland_or_surface_wants_focus(c->surface.xwayland) 395 && wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE; 396 #endif 397 return 0; 398 } 399 400 static inline int 401 client_wants_fullscreen(Client *c) 402 { 403 #ifdef XWAYLAND 404 if (client_is_x11(c)) 405 return c->surface.xwayland->fullscreen; 406 #endif 407 return c->surface.xdg->toplevel->requested.fullscreen; 408 }