client.h (10307B)
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 int 135 client_get_pid(Client *c) 136 { 137 pid_t pid; 138 #ifdef XWAYLAND 139 if (client_is_x11(c)) 140 return c->surface.xwayland->pid; 141 #endif 142 wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); 143 return pid; 144 } 145 146 static inline void 147 client_get_clip(Client *c, struct wlr_box *clip) 148 { 149 struct wlr_box xdg_geom = {0}; 150 *clip = (struct wlr_box){ 151 .x = 0, 152 .y = 0, 153 .width = c->geom.width - c->bw, 154 .height = c->geom.height - c->bw, 155 }; 156 157 #ifdef XWAYLAND 158 if (client_is_x11(c)) 159 return; 160 #endif 161 162 wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom); 163 clip->x = xdg_geom.x; 164 clip->y = xdg_geom.y; 165 } 166 167 static inline void 168 client_get_geometry(Client *c, struct wlr_box *geom) 169 { 170 #ifdef XWAYLAND 171 if (client_is_x11(c)) { 172 geom->x = c->surface.xwayland->x; 173 geom->y = c->surface.xwayland->y; 174 geom->width = c->surface.xwayland->width; 175 geom->height = c->surface.xwayland->height; 176 return; 177 } 178 #endif 179 wlr_xdg_surface_get_geometry(c->surface.xdg, geom); 180 } 181 182 static inline Client * 183 client_get_parent(Client *c) 184 { 185 Client *p = NULL; 186 #ifdef XWAYLAND 187 if (client_is_x11(c)) { 188 if (c->surface.xwayland->parent) 189 toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); 190 return p; 191 } 192 #endif 193 if (c->surface.xdg->toplevel->parent) 194 toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); 195 return p; 196 } 197 198 static inline int 199 client_has_children(Client *c) 200 { 201 #ifdef XWAYLAND 202 if (client_is_x11(c)) 203 return !wl_list_empty(&c->surface.xwayland->children); 204 #endif 205 /* surface.xdg->link is never empty because it always contains at least the 206 * surface itself. */ 207 return wl_list_length(&c->surface.xdg->link) > 1; 208 } 209 210 static inline const char * 211 client_get_title(Client *c) 212 { 213 #ifdef XWAYLAND 214 if (client_is_x11(c)) 215 return c->surface.xwayland->title; 216 #endif 217 return c->surface.xdg->toplevel->title; 218 } 219 220 static inline int 221 client_is_float_type(Client *c) 222 { 223 struct wlr_xdg_toplevel *toplevel; 224 struct wlr_xdg_toplevel_state state; 225 226 #ifdef XWAYLAND 227 if (client_is_x11(c)) { 228 struct wlr_xwayland_surface *surface = c->surface.xwayland; 229 xcb_size_hints_t *size_hints = surface->size_hints; 230 size_t i; 231 if (surface->modal) 232 return 1; 233 234 for (i = 0; i < surface->window_type_len; i++) 235 if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] 236 || surface->window_type[i] == netatom[NetWMWindowTypeSplash] 237 || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] 238 || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) 239 return 1; 240 241 return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 242 && (size_hints->max_width == size_hints->min_width 243 || size_hints->max_height == size_hints->min_height); 244 } 245 #endif 246 247 toplevel = c->surface.xdg->toplevel; 248 state = toplevel->current; 249 return toplevel->parent || (state.min_width != 0 && state.min_height != 0 250 && (state.min_width == state.max_width 251 || state.min_height == state.max_height)); 252 } 253 254 static inline int 255 client_is_rendered_on_mon(Client *c, Monitor *m) 256 { 257 /* This is needed for when you don't want to check formal assignment, 258 * but rather actual displaying of the pixels. 259 * Usually VISIBLEON suffices and is also faster. */ 260 struct wlr_surface_output *s; 261 int unused_lx, unused_ly; 262 if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly)) 263 return 0; 264 wl_list_for_each(s, &client_surface(c)->current_outputs, link) 265 if (s->output == m->wlr_output) 266 return 1; 267 return 0; 268 } 269 270 static inline int 271 client_is_stopped(Client *c) 272 { 273 int pid; 274 siginfo_t in = {0}; 275 #ifdef XWAYLAND 276 if (client_is_x11(c)) 277 return 0; 278 #endif 279 280 wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); 281 if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) { 282 /* This process is not our child process, while is very unluckely that 283 * it is stopped, in order to do not skip frames assume that it is. */ 284 if (errno == ECHILD) 285 return 1; 286 } else if (in.si_pid) { 287 if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) 288 return 1; 289 if (in.si_code == CLD_CONTINUED) 290 return 0; 291 } 292 293 return 0; 294 } 295 296 static inline int 297 client_is_unmanaged(Client *c) 298 { 299 #ifdef XWAYLAND 300 if (client_is_x11(c)) 301 return c->surface.xwayland->override_redirect; 302 #endif 303 return 0; 304 } 305 306 static inline void 307 client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb) 308 { 309 if (kb) 310 wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes, 311 kb->num_keycodes, &kb->modifiers); 312 else 313 wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL); 314 } 315 316 static inline void 317 client_restack_surface(Client *c) 318 { 319 #ifdef XWAYLAND 320 if (client_is_x11(c)) 321 wlr_xwayland_surface_restack(c->surface.xwayland, NULL, 322 XCB_STACK_MODE_ABOVE); 323 #endif 324 return; 325 } 326 327 static inline void 328 client_send_close(Client *c) 329 { 330 #ifdef XWAYLAND 331 if (client_is_x11(c)) { 332 wlr_xwayland_surface_close(c->surface.xwayland); 333 return; 334 } 335 #endif 336 wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel); 337 } 338 339 static inline void 340 client_set_border_color(Client *c, const float color[static 4]) 341 { 342 int i; 343 for (i = 0; i < 4; i++) 344 wlr_scene_rect_set_color(c->border[i], color); 345 } 346 347 static inline void 348 client_set_fullscreen(Client *c, int fullscreen) 349 { 350 #ifdef XWAYLAND 351 if (client_is_x11(c)) { 352 wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen); 353 return; 354 } 355 #endif 356 wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen); 357 } 358 359 static inline uint32_t 360 client_set_size(Client *c, uint32_t width, uint32_t height) 361 { 362 #ifdef XWAYLAND 363 if (client_is_x11(c)) { 364 wlr_xwayland_surface_configure(c->surface.xwayland, 365 c->geom.x, c->geom.y, width, height); 366 return 0; 367 } 368 #endif 369 if ((int32_t)width == c->surface.xdg->toplevel->current.width 370 && (int32_t)height == c->surface.xdg->toplevel->current.height) 371 return 0; 372 return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height); 373 } 374 375 static inline void 376 client_set_tiled(Client *c, uint32_t edges) 377 { 378 #ifdef XWAYLAND 379 if (client_is_x11(c)) 380 return; 381 #endif 382 if (wl_resource_get_version(c->surface.xdg->toplevel->resource) 383 >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { 384 wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); 385 } else { 386 wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE); 387 } 388 } 389 390 static inline void 391 client_set_suspended(Client *c, int suspended) 392 { 393 #ifdef XWAYLAND 394 if (client_is_x11(c)) { 395 wlr_xwayland_surface_set_withdrawn(c->surface.xwayland, suspended); 396 return; 397 } 398 #endif 399 400 wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); 401 } 402 403 static inline int 404 client_wants_focus(Client *c) 405 { 406 #ifdef XWAYLAND 407 return client_is_unmanaged(c) 408 && wlr_xwayland_or_surface_wants_focus(c->surface.xwayland) 409 && wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE; 410 #endif 411 return 0; 412 } 413 414 static inline int 415 client_wants_fullscreen(Client *c) 416 { 417 #ifdef XWAYLAND 418 if (client_is_x11(c)) 419 return c->surface.xwayland->fullscreen; 420 #endif 421 return c->surface.xdg->toplevel->requested.fullscreen; 422 }