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