dwl.c (102542B)
1 /* 2 * See LICENSE file for copyright and license details. 3 */ 4 #include <getopt.h> 5 #include <libinput.h> 6 #include <linux/input-event-codes.h> 7 #include <math.h> 8 #include <signal.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <sys/wait.h> 12 #include <time.h> 13 #include <unistd.h> 14 #include <wayland-server-core.h> 15 #include <wlr/backend.h> 16 #include <wlr/backend/libinput.h> 17 #include <wlr/render/allocator.h> 18 #include <wlr/render/wlr_renderer.h> 19 #include <wlr/types/wlr_alpha_modifier_v1.h> 20 #include <wlr/types/wlr_compositor.h> 21 #include <wlr/types/wlr_cursor.h> 22 #include <wlr/types/wlr_cursor_shape_v1.h> 23 #include <wlr/types/wlr_data_control_v1.h> 24 #include <wlr/types/wlr_data_device.h> 25 #include <wlr/types/wlr_drm.h> 26 #include <wlr/types/wlr_export_dmabuf_v1.h> 27 #include <wlr/types/wlr_fractional_scale_v1.h> 28 #include <wlr/types/wlr_gamma_control_v1.h> 29 #include <wlr/types/wlr_idle_inhibit_v1.h> 30 #include <wlr/types/wlr_idle_notify_v1.h> 31 #include <wlr/types/wlr_input_device.h> 32 #include <wlr/types/wlr_keyboard.h> 33 #include <wlr/types/wlr_keyboard_group.h> 34 #include <wlr/types/wlr_layer_shell_v1.h> 35 #include <wlr/types/wlr_linux_dmabuf_v1.h> 36 #include <wlr/types/wlr_linux_drm_syncobj_v1.h> 37 #include <wlr/types/wlr_output.h> 38 #include <wlr/types/wlr_output_layout.h> 39 #include <wlr/types/wlr_output_management_v1.h> 40 #include <wlr/types/wlr_output_power_management_v1.h> 41 #include <wlr/types/wlr_pointer.h> 42 #include <wlr/types/wlr_pointer_constraints_v1.h> 43 #include <wlr/types/wlr_presentation_time.h> 44 #include <wlr/types/wlr_primary_selection.h> 45 #include <wlr/types/wlr_primary_selection_v1.h> 46 #include <wlr/types/wlr_relative_pointer_v1.h> 47 #include <wlr/types/wlr_scene.h> 48 #include <wlr/types/wlr_screencopy_v1.h> 49 #include <wlr/types/wlr_seat.h> 50 #include <wlr/types/wlr_server_decoration.h> 51 #include <wlr/types/wlr_session_lock_v1.h> 52 #include <wlr/types/wlr_single_pixel_buffer_v1.h> 53 #include <wlr/types/wlr_subcompositor.h> 54 #include <wlr/types/wlr_viewporter.h> 55 #include <wlr/types/wlr_virtual_keyboard_v1.h> 56 #include <wlr/types/wlr_virtual_pointer_v1.h> 57 #include <wlr/types/wlr_xcursor_manager.h> 58 #include <wlr/types/wlr_xdg_activation_v1.h> 59 #include <wlr/types/wlr_xdg_decoration_v1.h> 60 #include <wlr/types/wlr_xdg_output_v1.h> 61 #include <wlr/types/wlr_xdg_shell.h> 62 #include <wlr/util/log.h> 63 #include <wlr/util/region.h> 64 #include <xkbcommon/xkbcommon.h> 65 #ifdef XWAYLAND 66 #include <wlr/xwayland.h> 67 #include <xcb/xcb.h> 68 #include <xcb/xcb_icccm.h> 69 #endif 70 71 #include "util.h" 72 73 /* macros */ 74 #define MAX(A, B) ((A) > (B) ? (A) : (B)) 75 #define MIN(A, B) ((A) < (B) ? (A) : (B)) 76 #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) 77 #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) 78 #define LENGTH(X) (sizeof X / sizeof X[0]) 79 #define END(A) ((A) + LENGTH(A)) 80 #define TAGMASK ((1u << TAGCOUNT) - 1) 81 #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) 82 #define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) 83 84 /* enums */ 85 enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ 86 enum { XDGShell, LayerShell, X11 }; /* client types */ 87 enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ 88 #ifdef XWAYLAND 89 enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, 90 NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ 91 #endif 92 93 typedef union { 94 int i; 95 uint32_t ui; 96 float f; 97 const void *v; 98 } Arg; 99 100 typedef struct { 101 unsigned int mod; 102 unsigned int button; 103 void (*func)(const Arg *); 104 const Arg arg; 105 } Button; 106 107 typedef struct Monitor Monitor; 108 typedef struct { 109 /* Must keep this field first */ 110 unsigned int type; /* XDGShell or X11* */ 111 112 Monitor *mon; 113 struct wlr_scene_tree *scene; 114 struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ 115 struct wlr_scene_tree *scene_surface; 116 struct wl_list link; 117 struct wl_list flink; 118 struct wlr_box geom; /* layout-relative, includes border */ 119 struct wlr_box prev; /* layout-relative, includes border */ 120 struct wlr_box bounds; /* only width and height are used */ 121 union { 122 struct wlr_xdg_surface *xdg; 123 struct wlr_xwayland_surface *xwayland; 124 } surface; 125 struct wlr_xdg_toplevel_decoration_v1 *decoration; 126 struct wl_listener commit; 127 struct wl_listener map; 128 struct wl_listener maximize; 129 struct wl_listener unmap; 130 struct wl_listener destroy; 131 struct wl_listener set_title; 132 struct wl_listener fullscreen; 133 struct wl_listener set_decoration_mode; 134 struct wl_listener destroy_decoration; 135 #ifdef XWAYLAND 136 struct wl_listener activate; 137 struct wl_listener associate; 138 struct wl_listener dissociate; 139 struct wl_listener configure; 140 struct wl_listener set_hints; 141 #endif 142 unsigned int bw; 143 uint32_t tags; 144 int isfloating, isurgent, isfullscreen; 145 uint32_t resize; /* configure serial of a pending resize */ 146 } Client; 147 148 typedef struct { 149 uint32_t mod; 150 xkb_keysym_t keysym; 151 void (*func)(const Arg *); 152 const Arg arg; 153 } Key; 154 155 typedef struct { 156 struct wlr_keyboard_group *wlr_group; 157 158 int nsyms; 159 const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ 160 uint32_t mods; /* invalid if nsyms == 0 */ 161 struct wl_event_source *key_repeat_source; 162 163 struct wl_listener modifiers; 164 struct wl_listener key; 165 struct wl_listener destroy; 166 } KeyboardGroup; 167 168 typedef struct { 169 /* Must keep this field first */ 170 unsigned int type; /* LayerShell */ 171 172 Monitor *mon; 173 struct wlr_scene_tree *scene; 174 struct wlr_scene_tree *popups; 175 struct wlr_scene_layer_surface_v1 *scene_layer; 176 struct wl_list link; 177 int mapped; 178 struct wlr_layer_surface_v1 *layer_surface; 179 180 struct wl_listener destroy; 181 struct wl_listener unmap; 182 struct wl_listener surface_commit; 183 } LayerSurface; 184 185 typedef struct { 186 const char *symbol; 187 void (*arrange)(Monitor *); 188 } Layout; 189 190 struct Monitor { 191 struct wl_list link; 192 struct wlr_output *wlr_output; 193 struct wlr_scene_output *scene_output; 194 struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ 195 struct wl_listener frame; 196 struct wl_listener destroy; 197 struct wl_listener request_state; 198 struct wl_listener destroy_lock_surface; 199 struct wlr_session_lock_surface_v1 *lock_surface; 200 struct wlr_box m; /* monitor area, layout-relative */ 201 struct wlr_box w; /* window area, layout-relative */ 202 struct wl_list layers[4]; /* LayerSurface.link */ 203 const Layout *lt[2]; 204 unsigned int seltags; 205 unsigned int sellt; 206 uint32_t tagset[2]; 207 float mfact; 208 int gamma_lut_changed; 209 int nmaster; 210 char ltsymbol[16]; 211 int asleep; 212 }; 213 214 typedef struct { 215 const char *name; 216 float mfact; 217 int nmaster; 218 float scale; 219 const Layout *lt; 220 enum wl_output_transform rr; 221 int x, y; 222 } MonitorRule; 223 224 typedef struct { 225 struct wlr_pointer_constraint_v1 *constraint; 226 struct wl_listener destroy; 227 } PointerConstraint; 228 229 typedef struct { 230 const char *id; 231 const char *title; 232 uint32_t tags; 233 int isfloating; 234 int monitor; 235 } Rule; 236 237 typedef struct { 238 struct wlr_scene_tree *scene; 239 240 struct wlr_session_lock_v1 *lock; 241 struct wl_listener new_surface; 242 struct wl_listener unlock; 243 struct wl_listener destroy; 244 } SessionLock; 245 246 /* function declarations */ 247 static void applybounds(Client *c, struct wlr_box *bbox); 248 static void applyrules(Client *c); 249 static void arrange(Monitor *m); 250 static void arrangelayer(Monitor *m, struct wl_list *list, 251 struct wlr_box *usable_area, int exclusive); 252 static void arrangelayers(Monitor *m); 253 static void axisnotify(struct wl_listener *listener, void *data); 254 static void buttonpress(struct wl_listener *listener, void *data); 255 static void chvt(const Arg *arg); 256 static void checkidleinhibitor(struct wlr_surface *exclude); 257 static void cleanup(void); 258 static void cleanupmon(struct wl_listener *listener, void *data); 259 static void closemon(Monitor *m); 260 static void commitlayersurfacenotify(struct wl_listener *listener, void *data); 261 static void commitnotify(struct wl_listener *listener, void *data); 262 static void commitpopup(struct wl_listener *listener, void *data); 263 static void createdecoration(struct wl_listener *listener, void *data); 264 static void createidleinhibitor(struct wl_listener *listener, void *data); 265 static void createkeyboard(struct wlr_keyboard *keyboard); 266 static KeyboardGroup *createkeyboardgroup(void); 267 static void createlayersurface(struct wl_listener *listener, void *data); 268 static void createlocksurface(struct wl_listener *listener, void *data); 269 static void createmon(struct wl_listener *listener, void *data); 270 static void createnotify(struct wl_listener *listener, void *data); 271 static void createpointer(struct wlr_pointer *pointer); 272 static void createpointerconstraint(struct wl_listener *listener, void *data); 273 static void createpopup(struct wl_listener *listener, void *data); 274 static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); 275 static void cursorframe(struct wl_listener *listener, void *data); 276 static void cursorwarptohint(void); 277 static void destroydecoration(struct wl_listener *listener, void *data); 278 static void destroydragicon(struct wl_listener *listener, void *data); 279 static void destroyidleinhibitor(struct wl_listener *listener, void *data); 280 static void destroylayersurfacenotify(struct wl_listener *listener, void *data); 281 static void destroylock(SessionLock *lock, int unlocked); 282 static void destroylocksurface(struct wl_listener *listener, void *data); 283 static void destroynotify(struct wl_listener *listener, void *data); 284 static void destroypointerconstraint(struct wl_listener *listener, void *data); 285 static void destroysessionlock(struct wl_listener *listener, void *data); 286 static void destroysessionmgr(struct wl_listener *listener, void *data); 287 static void destroykeyboardgroup(struct wl_listener *listener, void *data); 288 static Monitor *dirtomon(enum wlr_direction dir); 289 static void focusclient(Client *c, int lift); 290 static void focusmon(const Arg *arg); 291 static void focusstack(const Arg *arg); 292 static Client *focustop(Monitor *m); 293 static void fullscreennotify(struct wl_listener *listener, void *data); 294 static void gpureset(struct wl_listener *listener, void *data); 295 static void handlesig(int signo); 296 static void incnmaster(const Arg *arg); 297 static void inputdevice(struct wl_listener *listener, void *data); 298 static int keybinding(uint32_t mods, xkb_keysym_t sym); 299 static void keypress(struct wl_listener *listener, void *data); 300 static void keypressmod(struct wl_listener *listener, void *data); 301 static int keyrepeat(void *data); 302 static void killclient(const Arg *arg); 303 static void locksession(struct wl_listener *listener, void *data); 304 static void mapnotify(struct wl_listener *listener, void *data); 305 static void maximizenotify(struct wl_listener *listener, void *data); 306 static void monocle(Monitor *m); 307 static void motionabsolute(struct wl_listener *listener, void *data); 308 static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx, 309 double sy, double sx_unaccel, double sy_unaccel); 310 static void motionrelative(struct wl_listener *listener, void *data); 311 static void moveresize(const Arg *arg); 312 static void outputmgrapply(struct wl_listener *listener, void *data); 313 static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); 314 static void outputmgrtest(struct wl_listener *listener, void *data); 315 static void pointerfocus(Client *c, struct wlr_surface *surface, 316 double sx, double sy, uint32_t time); 317 static void printstatus(void); 318 static void powermgrsetmode(struct wl_listener *listener, void *data); 319 static void quit(const Arg *arg); 320 static void rendermon(struct wl_listener *listener, void *data); 321 static void requestdecorationmode(struct wl_listener *listener, void *data); 322 static void requeststartdrag(struct wl_listener *listener, void *data); 323 static void requestmonstate(struct wl_listener *listener, void *data); 324 static void resize(Client *c, struct wlr_box geo, int interact); 325 static void run(char *startup_cmd); 326 static void setcursor(struct wl_listener *listener, void *data); 327 static void setcursorshape(struct wl_listener *listener, void *data); 328 static void setfloating(Client *c, int floating); 329 static void setfullscreen(Client *c, int fullscreen); 330 static void setlayout(const Arg *arg); 331 static void setmfact(const Arg *arg); 332 static void setmon(Client *c, Monitor *m, uint32_t newtags); 333 static void setpsel(struct wl_listener *listener, void *data); 334 static void setsel(struct wl_listener *listener, void *data); 335 static void setup(void); 336 static void spawn(const Arg *arg); 337 static void startdrag(struct wl_listener *listener, void *data); 338 static void tag(const Arg *arg); 339 static void tagmon(const Arg *arg); 340 static void tile(Monitor *m); 341 static void togglefloating(const Arg *arg); 342 static void togglefullscreen(const Arg *arg); 343 static void toggletag(const Arg *arg); 344 static void toggleview(const Arg *arg); 345 static void unlocksession(struct wl_listener *listener, void *data); 346 static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); 347 static void unmapnotify(struct wl_listener *listener, void *data); 348 static void updatemons(struct wl_listener *listener, void *data); 349 static void updatetitle(struct wl_listener *listener, void *data); 350 static void urgent(struct wl_listener *listener, void *data); 351 static void view(const Arg *arg); 352 static void virtualkeyboard(struct wl_listener *listener, void *data); 353 static void virtualpointer(struct wl_listener *listener, void *data); 354 static Monitor *xytomon(double x, double y); 355 static void xytonode(double x, double y, struct wlr_surface **psurface, 356 Client **pc, LayerSurface **pl, double *nx, double *ny); 357 static void zoom(const Arg *arg); 358 359 /* variables */ 360 static pid_t child_pid = -1; 361 static int locked; 362 static void *exclusive_focus; 363 static struct wl_display *dpy; 364 static struct wl_event_loop *event_loop; 365 static struct wlr_backend *backend; 366 static struct wlr_scene *scene; 367 static struct wlr_scene_tree *layers[NUM_LAYERS]; 368 static struct wlr_scene_tree *drag_icon; 369 /* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */ 370 static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay }; 371 static struct wlr_renderer *drw; 372 static struct wlr_allocator *alloc; 373 static struct wlr_compositor *compositor; 374 static struct wlr_session *session; 375 376 static struct wlr_xdg_shell *xdg_shell; 377 static struct wlr_xdg_activation_v1 *activation; 378 static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; 379 static struct wl_list clients; /* tiling order */ 380 static struct wl_list fstack; /* focus order */ 381 static struct wlr_idle_notifier_v1 *idle_notifier; 382 static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; 383 static struct wlr_layer_shell_v1 *layer_shell; 384 static struct wlr_output_manager_v1 *output_mgr; 385 static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; 386 static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; 387 static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; 388 static struct wlr_output_power_manager_v1 *power_mgr; 389 390 static struct wlr_pointer_constraints_v1 *pointer_constraints; 391 static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; 392 static struct wlr_pointer_constraint_v1 *active_constraint; 393 394 static struct wlr_cursor *cursor; 395 static struct wlr_xcursor_manager *cursor_mgr; 396 397 static struct wlr_scene_rect *root_bg; 398 static struct wlr_session_lock_manager_v1 *session_lock_mgr; 399 static struct wlr_scene_rect *locked_bg; 400 static struct wlr_session_lock_v1 *cur_lock; 401 static struct wl_listener lock_listener = {.notify = locksession}; 402 403 static struct wlr_seat *seat; 404 static KeyboardGroup *kb_group; 405 static unsigned int cursor_mode; 406 static Client *grabc; 407 static int grabcx, grabcy; /* client-relative */ 408 409 static struct wlr_output_layout *output_layout; 410 static struct wlr_box sgeom; 411 static struct wl_list mons; 412 static Monitor *selmon; 413 414 #ifdef XWAYLAND 415 static void activatex11(struct wl_listener *listener, void *data); 416 static void associatex11(struct wl_listener *listener, void *data); 417 static void configurex11(struct wl_listener *listener, void *data); 418 static void createnotifyx11(struct wl_listener *listener, void *data); 419 static void dissociatex11(struct wl_listener *listener, void *data); 420 static xcb_atom_t getatom(xcb_connection_t *xc, const char *name); 421 static void sethints(struct wl_listener *listener, void *data); 422 static void xwaylandready(struct wl_listener *listener, void *data); 423 static struct wlr_xwayland *xwayland; 424 static xcb_atom_t netatom[NetLast]; 425 #endif 426 427 /* configuration, allows nested code to access above variables */ 428 #include "config.h" 429 430 /* attempt to encapsulate suck into one file */ 431 #include "client.h" 432 433 /* function implementations */ 434 void 435 applybounds(Client *c, struct wlr_box *bbox) 436 { 437 /* set minimum possible */ 438 c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); 439 c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height); 440 441 if (c->geom.x >= bbox->x + bbox->width) 442 c->geom.x = bbox->x + bbox->width - c->geom.width; 443 if (c->geom.y >= bbox->y + bbox->height) 444 c->geom.y = bbox->y + bbox->height - c->geom.height; 445 if (c->geom.x + c->geom.width <= bbox->x) 446 c->geom.x = bbox->x; 447 if (c->geom.y + c->geom.height <= bbox->y) 448 c->geom.y = bbox->y; 449 } 450 451 void 452 applyrules(Client *c) 453 { 454 /* rule matching */ 455 const char *appid, *title; 456 uint32_t newtags = 0; 457 int i; 458 const Rule *r; 459 Monitor *mon = selmon, *m; 460 461 c->isfloating = client_is_float_type(c); 462 appid = client_get_appid(c); 463 title = client_get_title(c); 464 465 for (r = rules; r < END(rules); r++) { 466 if ((!r->title || strstr(title, r->title)) 467 && (!r->id || strstr(appid, r->id))) { 468 c->isfloating = r->isfloating; 469 newtags |= r->tags; 470 i = 0; 471 wl_list_for_each(m, &mons, link) { 472 if (r->monitor == i++) 473 mon = m; 474 } 475 } 476 } 477 setmon(c, mon, newtags); 478 } 479 480 void 481 arrange(Monitor *m) 482 { 483 Client *c; 484 485 if (!m->wlr_output->enabled) 486 return; 487 488 wl_list_for_each(c, &clients, link) { 489 if (c->mon == m) { 490 wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); 491 client_set_suspended(c, !VISIBLEON(c, m)); 492 } 493 } 494 495 wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 496 (c = focustop(m)) && c->isfullscreen); 497 498 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); 499 500 /* We move all clients (except fullscreen and unmanaged) to LyrTile while 501 * in floating layout to avoid "real" floating clients be always on top */ 502 wl_list_for_each(c, &clients, link) { 503 if (c->mon != m || c->scene->node.parent == layers[LyrFS]) 504 continue; 505 506 wlr_scene_node_reparent(&c->scene->node, 507 (!m->lt[m->sellt]->arrange && c->isfloating) 508 ? layers[LyrTile] 509 : (m->lt[m->sellt]->arrange && c->isfloating) 510 ? layers[LyrFloat] 511 : c->scene->node.parent); 512 } 513 514 if (m->lt[m->sellt]->arrange) 515 m->lt[m->sellt]->arrange(m); 516 motionnotify(0, NULL, 0, 0, 0, 0); 517 checkidleinhibitor(NULL); 518 } 519 520 void 521 arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) 522 { 523 LayerSurface *l; 524 struct wlr_box full_area = m->m; 525 526 wl_list_for_each(l, list, link) { 527 struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; 528 529 if (exclusive != (layer_surface->current.exclusive_zone > 0)) 530 continue; 531 532 wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); 533 wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, l->scene->node.y); 534 } 535 } 536 537 void 538 arrangelayers(Monitor *m) 539 { 540 int i; 541 struct wlr_box usable_area = m->m; 542 LayerSurface *l; 543 uint32_t layers_above_shell[] = { 544 ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, 545 ZWLR_LAYER_SHELL_V1_LAYER_TOP, 546 }; 547 if (!m->wlr_output->enabled) 548 return; 549 550 /* Arrange exclusive surfaces from top->bottom */ 551 for (i = 3; i >= 0; i--) 552 arrangelayer(m, &m->layers[i], &usable_area, 1); 553 554 if (!wlr_box_equal(&usable_area, &m->w)) { 555 m->w = usable_area; 556 arrange(m); 557 } 558 559 /* Arrange non-exlusive surfaces from top->bottom */ 560 for (i = 3; i >= 0; i--) 561 arrangelayer(m, &m->layers[i], &usable_area, 0); 562 563 /* Find topmost keyboard interactive layer, if such a layer exists */ 564 for (i = 0; i < (int)LENGTH(layers_above_shell); i++) { 565 wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { 566 if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped) 567 continue; 568 /* Deactivate the focused client. */ 569 focusclient(NULL, 0); 570 exclusive_focus = l; 571 client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); 572 return; 573 } 574 } 575 } 576 577 void 578 axisnotify(struct wl_listener *listener, void *data) 579 { 580 /* This event is forwarded by the cursor when a pointer emits an axis event, 581 * for example when you move the scroll wheel. */ 582 struct wlr_pointer_axis_event *event = data; 583 wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); 584 /* TODO: allow usage of scroll whell for mousebindings, it can be implemented 585 * checking the event's orientation and the delta of the event */ 586 /* Notify the client with pointer focus of the axis event. */ 587 wlr_seat_pointer_notify_axis(seat, 588 event->time_msec, event->orientation, event->delta, 589 event->delta_discrete, event->source, event->relative_direction); 590 } 591 592 void 593 buttonpress(struct wl_listener *listener, void *data) 594 { 595 struct wlr_pointer_button_event *event = data; 596 struct wlr_keyboard *keyboard; 597 uint32_t mods; 598 Client *c; 599 const Button *b; 600 601 wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); 602 603 switch (event->state) { 604 case WL_POINTER_BUTTON_STATE_PRESSED: 605 cursor_mode = CurPressed; 606 selmon = xytomon(cursor->x, cursor->y); 607 if (locked) 608 break; 609 610 /* Change focus if the button was _pressed_ over a client */ 611 xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); 612 if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) 613 focusclient(c, 1); 614 615 keyboard = wlr_seat_get_keyboard(seat); 616 mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; 617 for (b = buttons; b < END(buttons); b++) { 618 if (CLEANMASK(mods) == CLEANMASK(b->mod) && 619 event->button == b->button && b->func) { 620 b->func(&b->arg); 621 return; 622 } 623 } 624 break; 625 case WL_POINTER_BUTTON_STATE_RELEASED: 626 /* If you released any buttons, we exit interactive move/resize mode. */ 627 /* TODO: should reset to the pointer focus's current setcursor */ 628 if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { 629 wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); 630 cursor_mode = CurNormal; 631 /* Drop the window off on its new monitor */ 632 selmon = xytomon(cursor->x, cursor->y); 633 setmon(grabc, selmon, 0); 634 grabc = NULL; 635 return; 636 } 637 cursor_mode = CurNormal; 638 break; 639 } 640 /* If the event wasn't handled by the compositor, notify the client with 641 * pointer focus that a button press has occurred */ 642 wlr_seat_pointer_notify_button(seat, 643 event->time_msec, event->button, event->state); 644 } 645 646 void 647 chvt(const Arg *arg) 648 { 649 wlr_session_change_vt(session, arg->ui); 650 } 651 652 void 653 checkidleinhibitor(struct wlr_surface *exclude) 654 { 655 int inhibited = 0, unused_lx, unused_ly; 656 struct wlr_idle_inhibitor_v1 *inhibitor; 657 wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { 658 struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface); 659 struct wlr_scene_tree *tree = surface->data; 660 if (exclude != surface && (bypass_surface_visibility || (!tree 661 || wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) { 662 inhibited = 1; 663 break; 664 } 665 } 666 667 wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); 668 } 669 670 void 671 cleanup(void) 672 { 673 #ifdef XWAYLAND 674 wlr_xwayland_destroy(xwayland); 675 xwayland = NULL; 676 #endif 677 wl_display_destroy_clients(dpy); 678 if (child_pid > 0) { 679 kill(-child_pid, SIGTERM); 680 waitpid(child_pid, NULL, 0); 681 } 682 wlr_xcursor_manager_destroy(cursor_mgr); 683 684 destroykeyboardgroup(&kb_group->destroy, NULL); 685 686 /* If it's not destroyed manually it will cause a use-after-free of wlr_seat. 687 * Destroy it until it's fixed in the wlroots side */ 688 wlr_backend_destroy(backend); 689 690 wl_display_destroy(dpy); 691 /* Destroy after the wayland display (when the monitors are already destroyed) 692 to avoid destroying them with an invalid scene output. */ 693 wlr_scene_node_destroy(&scene->tree.node); 694 } 695 696 void 697 cleanupmon(struct wl_listener *listener, void *data) 698 { 699 Monitor *m = wl_container_of(listener, m, destroy); 700 LayerSurface *l, *tmp; 701 size_t i; 702 703 /* m->layers[i] are intentionally not unlinked */ 704 for (i = 0; i < LENGTH(m->layers); i++) { 705 wl_list_for_each_safe(l, tmp, &m->layers[i], link) 706 wlr_layer_surface_v1_destroy(l->layer_surface); 707 } 708 709 wl_list_remove(&m->destroy.link); 710 wl_list_remove(&m->frame.link); 711 wl_list_remove(&m->link); 712 wl_list_remove(&m->request_state.link); 713 m->wlr_output->data = NULL; 714 wlr_output_layout_remove(output_layout, m->wlr_output); 715 wlr_scene_output_destroy(m->scene_output); 716 717 closemon(m); 718 wlr_scene_node_destroy(&m->fullscreen_bg->node); 719 free(m); 720 } 721 722 void 723 closemon(Monitor *m) 724 { 725 /* update selmon if needed and 726 * move closed monitor's clients to the focused one */ 727 Client *c; 728 int i = 0, nmons = wl_list_length(&mons); 729 if (!nmons) { 730 selmon = NULL; 731 } else if (m == selmon) { 732 do /* don't switch to disabled mons */ 733 selmon = wl_container_of(mons.next, selmon, link); 734 while (!selmon->wlr_output->enabled && i++ < nmons); 735 736 if (!selmon->wlr_output->enabled) 737 selmon = NULL; 738 } 739 740 wl_list_for_each(c, &clients, link) { 741 if (c->isfloating && c->geom.x > m->m.width) 742 resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y, 743 .width = c->geom.width, .height = c->geom.height}, 0); 744 if (c->mon == m) 745 setmon(c, selmon, c->tags); 746 } 747 focusclient(focustop(selmon), 1); 748 printstatus(); 749 } 750 751 void 752 commitlayersurfacenotify(struct wl_listener *listener, void *data) 753 { 754 LayerSurface *l = wl_container_of(listener, l, surface_commit); 755 struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; 756 struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]]; 757 struct wlr_layer_surface_v1_state old_state; 758 759 if (l->layer_surface->initial_commit) { 760 client_set_scale(layer_surface->surface, l->mon->wlr_output->scale); 761 762 /* Temporarily set the layer's current state to pending 763 * so that we can easily arrange it */ 764 old_state = l->layer_surface->current; 765 l->layer_surface->current = l->layer_surface->pending; 766 arrangelayers(l->mon); 767 l->layer_surface->current = old_state; 768 return; 769 } 770 771 if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) 772 return; 773 l->mapped = layer_surface->surface->mapped; 774 775 if (scene_layer != l->scene->node.parent) { 776 wlr_scene_node_reparent(&l->scene->node, scene_layer); 777 wl_list_remove(&l->link); 778 wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link); 779 wlr_scene_node_reparent(&l->popups->node, (layer_surface->current.layer 780 < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer)); 781 } 782 783 arrangelayers(l->mon); 784 } 785 786 void 787 commitnotify(struct wl_listener *listener, void *data) 788 { 789 Client *c = wl_container_of(listener, c, commit); 790 791 if (c->surface.xdg->initial_commit) { 792 /* 793 * Get the monitor this client will be rendered on 794 * Note that if the user set a rule in which the client is placed on 795 * a different monitor based on its title this will likely select 796 * a wrong monitor. 797 */ 798 applyrules(c); 799 if (c->mon) { 800 client_set_scale(client_surface(c), c->mon->wlr_output->scale); 801 } 802 setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ 803 804 wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, 805 WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); 806 if (c->decoration) 807 requestdecorationmode(&c->set_decoration_mode, c->decoration); 808 wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); 809 return; 810 } 811 812 resize(c, c->geom, (c->isfloating && !c->isfullscreen)); 813 814 /* mark a pending resize as completed */ 815 if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) 816 c->resize = 0; 817 } 818 819 void 820 commitpopup(struct wl_listener *listener, void *data) 821 { 822 struct wlr_surface *surface = data; 823 struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); 824 LayerSurface *l = NULL; 825 Client *c = NULL; 826 struct wlr_box box; 827 int type = -1; 828 829 if (!popup->base->initial_commit) 830 return; 831 832 type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); 833 if (!popup->parent || type < 0) 834 return; 835 popup->base->surface->data = wlr_scene_xdg_surface_create( 836 popup->parent->data, popup->base); 837 if ((l && !l->mon) || (c && !c->mon)) { 838 wlr_xdg_popup_destroy(popup); 839 return; 840 } 841 box = type == LayerShell ? l->mon->m : c->mon->w; 842 box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x); 843 box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y); 844 wlr_xdg_popup_unconstrain_from_box(popup, &box); 845 wl_list_remove(&listener->link); 846 } 847 848 void 849 createdecoration(struct wl_listener *listener, void *data) 850 { 851 struct wlr_xdg_toplevel_decoration_v1 *deco = data; 852 Client *c = deco->toplevel->base->data; 853 c->decoration = deco; 854 855 LISTEN(&deco->events.request_mode, &c->set_decoration_mode, requestdecorationmode); 856 LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration); 857 858 requestdecorationmode(&c->set_decoration_mode, deco); 859 } 860 861 void 862 createidleinhibitor(struct wl_listener *listener, void *data) 863 { 864 struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; 865 LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor); 866 867 checkidleinhibitor(NULL); 868 } 869 870 void 871 createkeyboard(struct wlr_keyboard *keyboard) 872 { 873 /* Set the keymap to match the group keymap */ 874 wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); 875 876 /* Add the new keyboard to the group */ 877 wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); 878 } 879 880 KeyboardGroup * 881 createkeyboardgroup(void) 882 { 883 KeyboardGroup *group = ecalloc(1, sizeof(*group)); 884 struct xkb_context *context; 885 struct xkb_keymap *keymap; 886 887 group->wlr_group = wlr_keyboard_group_create(); 888 group->wlr_group->data = group; 889 890 /* Prepare an XKB keymap and assign it to the keyboard group. */ 891 context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); 892 if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, 893 XKB_KEYMAP_COMPILE_NO_FLAGS))) 894 die("failed to compile keymap"); 895 896 wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); 897 xkb_keymap_unref(keymap); 898 xkb_context_unref(context); 899 900 wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, repeat_delay); 901 902 /* Set up listeners for keyboard events */ 903 LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); 904 LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod); 905 906 group->key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, group); 907 908 /* A seat can only have one keyboard, but this is a limitation of the 909 * Wayland protocol - not wlroots. We assign all connected keyboards to the 910 * same wlr_keyboard_group, which provides a single wlr_keyboard interface for 911 * all of them. Set this combined wlr_keyboard as the seat keyboard. 912 */ 913 wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); 914 return group; 915 } 916 917 void 918 createlayersurface(struct wl_listener *listener, void *data) 919 { 920 struct wlr_layer_surface_v1 *layer_surface = data; 921 LayerSurface *l; 922 struct wlr_surface *surface = layer_surface->surface; 923 struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]]; 924 925 if (!layer_surface->output 926 && !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) { 927 wlr_layer_surface_v1_destroy(layer_surface); 928 return; 929 } 930 931 l = layer_surface->data = ecalloc(1, sizeof(*l)); 932 l->type = LayerShell; 933 LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); 934 LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); 935 LISTEN(&layer_surface->events.destroy, &l->destroy, destroylayersurfacenotify); 936 937 l->layer_surface = layer_surface; 938 l->mon = layer_surface->output->data; 939 l->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, layer_surface); 940 l->scene = l->scene_layer->tree; 941 l->popups = surface->data = wlr_scene_tree_create(layer_surface->current.layer 942 < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer); 943 l->scene->node.data = l->popups->node.data = l; 944 945 wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); 946 wlr_surface_send_enter(surface, layer_surface->output); 947 } 948 949 void 950 createlocksurface(struct wl_listener *listener, void *data) 951 { 952 SessionLock *lock = wl_container_of(listener, lock, new_surface); 953 struct wlr_session_lock_surface_v1 *lock_surface = data; 954 Monitor *m = lock_surface->output->data; 955 struct wlr_scene_tree *scene_tree = lock_surface->surface->data 956 = wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface); 957 m->lock_surface = lock_surface; 958 959 wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); 960 wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height); 961 962 LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface); 963 964 if (m == selmon) 965 client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat)); 966 } 967 968 void 969 createmon(struct wl_listener *listener, void *data) 970 { 971 /* This event is raised by the backend when a new output (aka a display or 972 * monitor) becomes available. */ 973 struct wlr_output *wlr_output = data; 974 const MonitorRule *r; 975 size_t i; 976 struct wlr_output_state state; 977 Monitor *m; 978 979 if (!wlr_output_init_render(wlr_output, alloc, drw)) 980 return; 981 982 m = wlr_output->data = ecalloc(1, sizeof(*m)); 983 m->wlr_output = wlr_output; 984 985 for (i = 0; i < LENGTH(m->layers); i++) 986 wl_list_init(&m->layers[i]); 987 988 wlr_output_state_init(&state); 989 /* Initialize monitor state using configured rules */ 990 m->tagset[0] = m->tagset[1] = 1; 991 for (r = monrules; r < END(monrules); r++) { 992 if (!r->name || strstr(wlr_output->name, r->name)) { 993 m->m.x = r->x; 994 m->m.y = r->y; 995 m->mfact = r->mfact; 996 m->nmaster = r->nmaster; 997 m->lt[0] = r->lt; 998 m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]]; 999 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); 1000 wlr_output_state_set_scale(&state, r->scale); 1001 wlr_output_state_set_transform(&state, r->rr); 1002 break; 1003 } 1004 } 1005 1006 /* The mode is a tuple of (width, height, refresh rate), and each 1007 * monitor supports only a specific set of modes. We just pick the 1008 * monitor's preferred mode; a more sophisticated compositor would let 1009 * the user configure it. */ 1010 wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); 1011 1012 /* Set up event listeners */ 1013 LISTEN(&wlr_output->events.frame, &m->frame, rendermon); 1014 LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); 1015 LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); 1016 1017 wlr_output_state_set_enabled(&state, 1); 1018 wlr_output_commit_state(wlr_output, &state); 1019 wlr_output_state_finish(&state); 1020 1021 wl_list_insert(&mons, &m->link); 1022 printstatus(); 1023 1024 /* The xdg-protocol specifies: 1025 * 1026 * If the fullscreened surface is not opaque, the compositor must make 1027 * sure that other screen content not part of the same surface tree (made 1028 * up of subsurfaces, popups or similarly coupled surfaces) are not 1029 * visible below the fullscreened surface. 1030 * 1031 */ 1032 /* updatemons() will resize and set correct position */ 1033 m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); 1034 wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); 1035 1036 /* Adds this to the output layout in the order it was configured. 1037 * 1038 * The output layout utility automatically adds a wl_output global to the 1039 * display, which Wayland clients can see to find out information about the 1040 * output (such as DPI, scale factor, manufacturer, etc). 1041 */ 1042 m->scene_output = wlr_scene_output_create(scene, wlr_output); 1043 if (m->m.x == -1 && m->m.y == -1) 1044 wlr_output_layout_add_auto(output_layout, wlr_output); 1045 else 1046 wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); 1047 } 1048 1049 void 1050 createnotify(struct wl_listener *listener, void *data) 1051 { 1052 /* This event is raised when a client creates a new toplevel (application window). */ 1053 struct wlr_xdg_toplevel *toplevel = data; 1054 Client *c = NULL; 1055 1056 /* Allocate a Client for this surface */ 1057 c = toplevel->base->data = ecalloc(1, sizeof(*c)); 1058 c->surface.xdg = toplevel->base; 1059 c->bw = borderpx; 1060 1061 LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); 1062 LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); 1063 LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify); 1064 LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify); 1065 LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); 1066 LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify); 1067 LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle); 1068 } 1069 1070 void 1071 createpointer(struct wlr_pointer *pointer) 1072 { 1073 struct libinput_device *device; 1074 if (wlr_input_device_is_libinput(&pointer->base) 1075 && (device = wlr_libinput_get_device_handle(&pointer->base))) { 1076 1077 if (libinput_device_config_tap_get_finger_count(device)) { 1078 libinput_device_config_tap_set_enabled(device, tap_to_click); 1079 libinput_device_config_tap_set_drag_enabled(device, tap_and_drag); 1080 libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock); 1081 libinput_device_config_tap_set_button_map(device, button_map); 1082 } 1083 1084 if (libinput_device_config_scroll_has_natural_scroll(device)) 1085 libinput_device_config_scroll_set_natural_scroll_enabled(device, natural_scrolling); 1086 1087 if (libinput_device_config_dwt_is_available(device)) 1088 libinput_device_config_dwt_set_enabled(device, disable_while_typing); 1089 1090 if (libinput_device_config_left_handed_is_available(device)) 1091 libinput_device_config_left_handed_set(device, left_handed); 1092 1093 if (libinput_device_config_middle_emulation_is_available(device)) 1094 libinput_device_config_middle_emulation_set_enabled(device, middle_button_emulation); 1095 1096 if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) 1097 libinput_device_config_scroll_set_method(device, scroll_method); 1098 1099 if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) 1100 libinput_device_config_click_set_method(device, click_method); 1101 1102 if (libinput_device_config_send_events_get_modes(device)) 1103 libinput_device_config_send_events_set_mode(device, send_events_mode); 1104 1105 if (libinput_device_config_accel_is_available(device)) { 1106 libinput_device_config_accel_set_profile(device, accel_profile); 1107 libinput_device_config_accel_set_speed(device, accel_speed); 1108 } 1109 } 1110 1111 wlr_cursor_attach_input_device(cursor, &pointer->base); 1112 } 1113 1114 void 1115 createpointerconstraint(struct wl_listener *listener, void *data) 1116 { 1117 PointerConstraint *pointer_constraint = ecalloc(1, sizeof(*pointer_constraint)); 1118 pointer_constraint->constraint = data; 1119 LISTEN(&pointer_constraint->constraint->events.destroy, 1120 &pointer_constraint->destroy, destroypointerconstraint); 1121 } 1122 1123 void 1124 createpopup(struct wl_listener *listener, void *data) 1125 { 1126 /* This event is raised when a client (either xdg-shell or layer-shell) 1127 * creates a new popup. */ 1128 struct wlr_xdg_popup *popup = data; 1129 LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); 1130 } 1131 1132 void 1133 cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) 1134 { 1135 if (active_constraint == constraint) 1136 return; 1137 1138 if (active_constraint) 1139 wlr_pointer_constraint_v1_send_deactivated(active_constraint); 1140 1141 active_constraint = constraint; 1142 wlr_pointer_constraint_v1_send_activated(constraint); 1143 } 1144 1145 void 1146 cursorframe(struct wl_listener *listener, void *data) 1147 { 1148 /* This event is forwarded by the cursor when a pointer emits an frame 1149 * event. Frame events are sent after regular pointer events to group 1150 * multiple events together. For instance, two axis events may happen at the 1151 * same time, in which case a frame event won't be sent in between. */ 1152 /* Notify the client with pointer focus of the frame event. */ 1153 wlr_seat_pointer_notify_frame(seat); 1154 } 1155 1156 void 1157 cursorwarptohint(void) 1158 { 1159 Client *c = NULL; 1160 double sx = active_constraint->current.cursor_hint.x; 1161 double sy = active_constraint->current.cursor_hint.y; 1162 1163 toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); 1164 if (c && active_constraint->current.cursor_hint.enabled) { 1165 wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw); 1166 wlr_seat_pointer_warp(active_constraint->seat, sx, sy); 1167 } 1168 } 1169 1170 void 1171 destroydecoration(struct wl_listener *listener, void *data) 1172 { 1173 Client *c = wl_container_of(listener, c, destroy_decoration); 1174 1175 wl_list_remove(&c->destroy_decoration.link); 1176 wl_list_remove(&c->set_decoration_mode.link); 1177 } 1178 1179 void 1180 destroydragicon(struct wl_listener *listener, void *data) 1181 { 1182 /* Focus enter isn't sent during drag, so refocus the focused node. */ 1183 focusclient(focustop(selmon), 1); 1184 motionnotify(0, NULL, 0, 0, 0, 0); 1185 } 1186 1187 void 1188 destroyidleinhibitor(struct wl_listener *listener, void *data) 1189 { 1190 /* `data` is the wlr_surface of the idle inhibitor being destroyed, 1191 * at this point the idle inhibitor is still in the list of the manager */ 1192 checkidleinhibitor(wlr_surface_get_root_surface(data)); 1193 } 1194 1195 void 1196 destroylayersurfacenotify(struct wl_listener *listener, void *data) 1197 { 1198 LayerSurface *l = wl_container_of(listener, l, destroy); 1199 1200 wl_list_remove(&l->link); 1201 wl_list_remove(&l->destroy.link); 1202 wl_list_remove(&l->unmap.link); 1203 wl_list_remove(&l->surface_commit.link); 1204 wlr_scene_node_destroy(&l->scene->node); 1205 wlr_scene_node_destroy(&l->popups->node); 1206 free(l); 1207 } 1208 1209 void 1210 destroylock(SessionLock *lock, int unlock) 1211 { 1212 wlr_seat_keyboard_notify_clear_focus(seat); 1213 if ((locked = !unlock)) 1214 goto destroy; 1215 1216 wlr_scene_node_set_enabled(&locked_bg->node, 0); 1217 1218 focusclient(focustop(selmon), 0); 1219 motionnotify(0, NULL, 0, 0, 0, 0); 1220 1221 destroy: 1222 wl_list_remove(&lock->new_surface.link); 1223 wl_list_remove(&lock->unlock.link); 1224 wl_list_remove(&lock->destroy.link); 1225 1226 wlr_scene_node_destroy(&lock->scene->node); 1227 cur_lock = NULL; 1228 free(lock); 1229 } 1230 1231 void 1232 destroylocksurface(struct wl_listener *listener, void *data) 1233 { 1234 Monitor *m = wl_container_of(listener, m, destroy_lock_surface); 1235 struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface; 1236 1237 m->lock_surface = NULL; 1238 wl_list_remove(&m->destroy_lock_surface.link); 1239 1240 if (lock_surface->surface != seat->keyboard_state.focused_surface) 1241 return; 1242 1243 if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { 1244 surface = wl_container_of(cur_lock->surfaces.next, surface, link); 1245 client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); 1246 } else if (!locked) { 1247 focusclient(focustop(selmon), 1); 1248 } else { 1249 wlr_seat_keyboard_clear_focus(seat); 1250 } 1251 } 1252 1253 void 1254 destroynotify(struct wl_listener *listener, void *data) 1255 { 1256 /* Called when the xdg_toplevel is destroyed. */ 1257 Client *c = wl_container_of(listener, c, destroy); 1258 wl_list_remove(&c->destroy.link); 1259 wl_list_remove(&c->set_title.link); 1260 wl_list_remove(&c->fullscreen.link); 1261 #ifdef XWAYLAND 1262 if (c->type != XDGShell) { 1263 wl_list_remove(&c->activate.link); 1264 wl_list_remove(&c->associate.link); 1265 wl_list_remove(&c->configure.link); 1266 wl_list_remove(&c->dissociate.link); 1267 wl_list_remove(&c->set_hints.link); 1268 } else 1269 #endif 1270 { 1271 wl_list_remove(&c->commit.link); 1272 wl_list_remove(&c->map.link); 1273 wl_list_remove(&c->unmap.link); 1274 wl_list_remove(&c->maximize.link); 1275 } 1276 free(c); 1277 } 1278 1279 void 1280 destroypointerconstraint(struct wl_listener *listener, void *data) 1281 { 1282 PointerConstraint *pointer_constraint = wl_container_of(listener, pointer_constraint, destroy); 1283 1284 if (active_constraint == pointer_constraint->constraint) { 1285 cursorwarptohint(); 1286 active_constraint = NULL; 1287 } 1288 1289 wl_list_remove(&pointer_constraint->destroy.link); 1290 free(pointer_constraint); 1291 } 1292 1293 void 1294 destroysessionlock(struct wl_listener *listener, void *data) 1295 { 1296 SessionLock *lock = wl_container_of(listener, lock, destroy); 1297 destroylock(lock, 0); 1298 } 1299 1300 void 1301 destroysessionmgr(struct wl_listener *listener, void *data) 1302 { 1303 wl_list_remove(&lock_listener.link); 1304 wl_list_remove(&listener->link); 1305 } 1306 1307 void 1308 destroykeyboardgroup(struct wl_listener *listener, void *data) 1309 { 1310 KeyboardGroup *group = wl_container_of(listener, group, destroy); 1311 wl_event_source_remove(group->key_repeat_source); 1312 wlr_keyboard_group_destroy(group->wlr_group); 1313 wl_list_remove(&group->key.link); 1314 wl_list_remove(&group->modifiers.link); 1315 wl_list_remove(&group->destroy.link); 1316 free(group); 1317 } 1318 1319 Monitor * 1320 dirtomon(enum wlr_direction dir) 1321 { 1322 struct wlr_output *next; 1323 if (!wlr_output_layout_get(output_layout, selmon->wlr_output)) 1324 return selmon; 1325 if ((next = wlr_output_layout_adjacent_output(output_layout, 1326 dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) 1327 return next->data; 1328 if ((next = wlr_output_layout_farthest_output(output_layout, 1329 dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT), 1330 selmon->wlr_output, selmon->m.x, selmon->m.y))) 1331 return next->data; 1332 return selmon; 1333 } 1334 1335 void 1336 focusclient(Client *c, int lift) 1337 { 1338 struct wlr_surface *old = seat->keyboard_state.focused_surface; 1339 int unused_lx, unused_ly, old_client_type; 1340 Client *old_c = NULL; 1341 LayerSurface *old_l = NULL; 1342 1343 if (locked) 1344 return; 1345 1346 /* Raise client in stacking order if requested */ 1347 if (c && lift) 1348 wlr_scene_node_raise_to_top(&c->scene->node); 1349 1350 if (c && client_surface(c) == old) 1351 return; 1352 1353 if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == XDGShell) { 1354 struct wlr_xdg_popup *popup, *tmp; 1355 wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link) 1356 wlr_xdg_popup_destroy(popup); 1357 } 1358 1359 /* Put the new client atop the focus stack and select its monitor */ 1360 if (c && !client_is_unmanaged(c)) { 1361 wl_list_remove(&c->flink); 1362 wl_list_insert(&fstack, &c->flink); 1363 selmon = c->mon; 1364 c->isurgent = 0; 1365 1366 /* Don't change border color if there is an exclusive focus or we are 1367 * handling a drag operation */ 1368 if (!exclusive_focus && !seat->drag) 1369 client_set_border_color(c, focuscolor); 1370 } 1371 1372 /* Deactivate old client if focus is changing */ 1373 if (old && (!c || client_surface(c) != old)) { 1374 /* If an overlay is focused, don't focus or activate the client, 1375 * but only update its position in fstack to render its border with focuscolor 1376 * and focus it after the overlay is closed. */ 1377 if (old_client_type == LayerShell && wlr_scene_node_coords( 1378 &old_l->scene->node, &unused_lx, &unused_ly) 1379 && old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { 1380 return; 1381 } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) { 1382 return; 1383 /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg 1384 * and probably other clients */ 1385 } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) { 1386 client_set_border_color(old_c, bordercolor); 1387 1388 client_activate_surface(old, 0); 1389 } 1390 } 1391 printstatus(); 1392 1393 if (!c) { 1394 /* With no client, all we have left is to clear focus */ 1395 wlr_seat_keyboard_notify_clear_focus(seat); 1396 return; 1397 } 1398 1399 /* Change cursor surface */ 1400 motionnotify(0, NULL, 0, 0, 0, 0); 1401 1402 /* Have a client, so focus its top-level wlr_surface */ 1403 client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); 1404 1405 /* Activate the new client */ 1406 client_activate_surface(client_surface(c), 1); 1407 } 1408 1409 void 1410 focusmon(const Arg *arg) 1411 { 1412 int i = 0, nmons = wl_list_length(&mons); 1413 if (nmons) { 1414 do /* don't switch to disabled mons */ 1415 selmon = dirtomon(arg->i); 1416 while (!selmon->wlr_output->enabled && i++ < nmons); 1417 } 1418 focusclient(focustop(selmon), 1); 1419 } 1420 1421 void 1422 focusstack(const Arg *arg) 1423 { 1424 /* Focus the next or previous client (in tiling order) on selmon */ 1425 Client *c, *sel = focustop(selmon); 1426 if (!sel || (sel->isfullscreen && !client_has_children(sel))) 1427 return; 1428 if (arg->i > 0) { 1429 wl_list_for_each(c, &sel->link, link) { 1430 if (&c->link == &clients) 1431 continue; /* wrap past the sentinel node */ 1432 if (VISIBLEON(c, selmon)) 1433 break; /* found it */ 1434 } 1435 } else { 1436 wl_list_for_each_reverse(c, &sel->link, link) { 1437 if (&c->link == &clients) 1438 continue; /* wrap past the sentinel node */ 1439 if (VISIBLEON(c, selmon)) 1440 break; /* found it */ 1441 } 1442 } 1443 /* If only one client is visible on selmon, then c == sel */ 1444 focusclient(c, 1); 1445 } 1446 1447 /* We probably should change the name of this, it sounds like 1448 * will focus the topmost client of this mon, when actually will 1449 * only return that client */ 1450 Client * 1451 focustop(Monitor *m) 1452 { 1453 Client *c; 1454 wl_list_for_each(c, &fstack, flink) { 1455 if (VISIBLEON(c, m)) 1456 return c; 1457 } 1458 return NULL; 1459 } 1460 1461 void 1462 fullscreennotify(struct wl_listener *listener, void *data) 1463 { 1464 Client *c = wl_container_of(listener, c, fullscreen); 1465 setfullscreen(c, client_wants_fullscreen(c)); 1466 } 1467 1468 void 1469 gpureset(struct wl_listener *listener, void *data) 1470 { 1471 struct wlr_renderer *old_drw = drw; 1472 struct wlr_allocator *old_alloc = alloc; 1473 struct Monitor *m; 1474 if (!(drw = wlr_renderer_autocreate(backend))) 1475 die("couldn't recreate renderer"); 1476 1477 if (!(alloc = wlr_allocator_autocreate(backend, drw))) 1478 die("couldn't recreate allocator"); 1479 1480 LISTEN_STATIC(&drw->events.lost, gpureset); 1481 1482 wlr_compositor_set_renderer(compositor, drw); 1483 1484 wl_list_for_each(m, &mons, link) { 1485 wlr_output_init_render(m->wlr_output, alloc, drw); 1486 } 1487 1488 wlr_allocator_destroy(old_alloc); 1489 wlr_renderer_destroy(old_drw); 1490 } 1491 1492 void 1493 handlesig(int signo) 1494 { 1495 if (signo == SIGCHLD) { 1496 #ifdef XWAYLAND 1497 siginfo_t in; 1498 /* wlroots expects to reap the XWayland process itself, so we 1499 * use WNOWAIT to keep the child waitable until we know it's not 1500 * XWayland. 1501 */ 1502 while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid 1503 && (!xwayland || in.si_pid != xwayland->server->pid)) 1504 waitpid(in.si_pid, NULL, 0); 1505 #else 1506 while (waitpid(-1, NULL, WNOHANG) > 0); 1507 #endif 1508 } else if (signo == SIGINT || signo == SIGTERM) { 1509 quit(NULL); 1510 } 1511 } 1512 1513 void 1514 incnmaster(const Arg *arg) 1515 { 1516 if (!arg || !selmon) 1517 return; 1518 selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); 1519 arrange(selmon); 1520 } 1521 1522 void 1523 inputdevice(struct wl_listener *listener, void *data) 1524 { 1525 /* This event is raised by the backend when a new input device becomes 1526 * available. */ 1527 struct wlr_input_device *device = data; 1528 uint32_t caps; 1529 1530 switch (device->type) { 1531 case WLR_INPUT_DEVICE_KEYBOARD: 1532 createkeyboard(wlr_keyboard_from_input_device(device)); 1533 break; 1534 case WLR_INPUT_DEVICE_POINTER: 1535 createpointer(wlr_pointer_from_input_device(device)); 1536 break; 1537 default: 1538 /* TODO handle other input device types */ 1539 break; 1540 } 1541 1542 /* We need to let the wlr_seat know what our capabilities are, which is 1543 * communiciated to the client. In dwl we always have a cursor, even if 1544 * there are no pointer devices, so we always include that capability. */ 1545 /* TODO do we actually require a cursor? */ 1546 caps = WL_SEAT_CAPABILITY_POINTER; 1547 if (!wl_list_empty(&kb_group->wlr_group->devices)) 1548 caps |= WL_SEAT_CAPABILITY_KEYBOARD; 1549 wlr_seat_set_capabilities(seat, caps); 1550 } 1551 1552 int 1553 keybinding(uint32_t mods, xkb_keysym_t sym) 1554 { 1555 /* 1556 * Here we handle compositor keybindings. This is when the compositor is 1557 * processing keys, rather than passing them on to the client for its own 1558 * processing. 1559 */ 1560 const Key *k; 1561 for (k = keys; k < END(keys); k++) { 1562 if (CLEANMASK(mods) == CLEANMASK(k->mod) 1563 && sym == k->keysym && k->func) { 1564 k->func(&k->arg); 1565 return 1; 1566 } 1567 } 1568 return 0; 1569 } 1570 1571 void 1572 keypress(struct wl_listener *listener, void *data) 1573 { 1574 int i; 1575 /* This event is raised when a key is pressed or released. */ 1576 KeyboardGroup *group = wl_container_of(listener, group, key); 1577 struct wlr_keyboard_key_event *event = data; 1578 1579 /* Translate libinput keycode -> xkbcommon */ 1580 uint32_t keycode = event->keycode + 8; 1581 /* Get a list of keysyms based on the keymap for this keyboard */ 1582 const xkb_keysym_t *syms; 1583 int nsyms = xkb_state_key_get_syms( 1584 group->wlr_group->keyboard.xkb_state, keycode, &syms); 1585 1586 int handled = 0; 1587 uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); 1588 1589 wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); 1590 1591 /* On _press_ if there is no active screen locker, 1592 * attempt to process a compositor keybinding. */ 1593 if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { 1594 for (i = 0; i < nsyms; i++) 1595 handled = keybinding(mods, syms[i]) || handled; 1596 } 1597 1598 if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { 1599 group->mods = mods; 1600 group->keysyms = syms; 1601 group->nsyms = nsyms; 1602 wl_event_source_timer_update(group->key_repeat_source, 1603 group->wlr_group->keyboard.repeat_info.delay); 1604 } else { 1605 group->nsyms = 0; 1606 wl_event_source_timer_update(group->key_repeat_source, 0); 1607 } 1608 1609 if (handled) 1610 return; 1611 1612 wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); 1613 /* Pass unhandled keycodes along to the client. */ 1614 wlr_seat_keyboard_notify_key(seat, event->time_msec, 1615 event->keycode, event->state); 1616 } 1617 1618 void 1619 keypressmod(struct wl_listener *listener, void *data) 1620 { 1621 /* This event is raised when a modifier key, such as shift or alt, is 1622 * pressed. We simply communicate this to the client. */ 1623 KeyboardGroup *group = wl_container_of(listener, group, modifiers); 1624 1625 wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); 1626 /* Send modifiers to the client. */ 1627 wlr_seat_keyboard_notify_modifiers(seat, 1628 &group->wlr_group->keyboard.modifiers); 1629 } 1630 1631 int 1632 keyrepeat(void *data) 1633 { 1634 KeyboardGroup *group = data; 1635 int i; 1636 if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) 1637 return 0; 1638 1639 wl_event_source_timer_update(group->key_repeat_source, 1640 1000 / group->wlr_group->keyboard.repeat_info.rate); 1641 1642 for (i = 0; i < group->nsyms; i++) 1643 keybinding(group->mods, group->keysyms[i]); 1644 1645 return 0; 1646 } 1647 1648 void 1649 killclient(const Arg *arg) 1650 { 1651 Client *sel = focustop(selmon); 1652 if (sel) 1653 client_send_close(sel); 1654 } 1655 1656 void 1657 locksession(struct wl_listener *listener, void *data) 1658 { 1659 struct wlr_session_lock_v1 *session_lock = data; 1660 SessionLock *lock; 1661 wlr_scene_node_set_enabled(&locked_bg->node, 1); 1662 if (cur_lock) { 1663 wlr_session_lock_v1_destroy(session_lock); 1664 return; 1665 } 1666 lock = session_lock->data = ecalloc(1, sizeof(*lock)); 1667 focusclient(NULL, 0); 1668 1669 lock->scene = wlr_scene_tree_create(layers[LyrBlock]); 1670 cur_lock = lock->lock = session_lock; 1671 locked = 1; 1672 1673 LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface); 1674 LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); 1675 LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession); 1676 1677 wlr_session_lock_v1_send_locked(session_lock); 1678 } 1679 1680 void 1681 mapnotify(struct wl_listener *listener, void *data) 1682 { 1683 /* Called when the surface is mapped, or ready to display on-screen. */ 1684 Client *p = NULL; 1685 Client *w, *c = wl_container_of(listener, c, map); 1686 Monitor *m; 1687 int i; 1688 1689 /* Create scene tree for this client and its border */ 1690 c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); 1691 /* Enabled later by a call to arrange() */ 1692 wlr_scene_node_set_enabled(&c->scene->node, client_is_unmanaged(c)); 1693 c->scene_surface = c->type == XDGShell 1694 ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) 1695 : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); 1696 c->scene->node.data = c->scene_surface->node.data = c; 1697 1698 client_get_geometry(c, &c->geom); 1699 1700 /* Handle unmanaged clients first so we can return prior create borders */ 1701 if (client_is_unmanaged(c)) { 1702 /* Unmanaged clients always are floating */ 1703 wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); 1704 wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); 1705 client_set_size(c, c->geom.width, c->geom.height); 1706 if (client_wants_focus(c)) { 1707 focusclient(c, 1); 1708 exclusive_focus = c; 1709 } 1710 goto unset_fullscreen; 1711 } 1712 1713 for (i = 0; i < 4; i++) { 1714 c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, 1715 c->isurgent ? urgentcolor : bordercolor); 1716 c->border[i]->node.data = c; 1717 } 1718 1719 /* Initialize client geometry with room for border */ 1720 client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); 1721 c->geom.width += 2 * c->bw; 1722 c->geom.height += 2 * c->bw; 1723 1724 /* Insert this client into client lists. */ 1725 wl_list_insert(&clients, &c->link); 1726 wl_list_insert(&fstack, &c->flink); 1727 1728 /* Set initial monitor, tags, floating status, and focus: 1729 * we always consider floating, clients that have parent and thus 1730 * we set the same tags and monitor than its parent, if not 1731 * try to apply rules for them */ 1732 if ((p = client_get_parent(c))) { 1733 c->isfloating = 1; 1734 setmon(c, p->mon, p->tags); 1735 } else { 1736 applyrules(c); 1737 } 1738 printstatus(); 1739 1740 unset_fullscreen: 1741 m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); 1742 wl_list_for_each(w, &clients, link) { 1743 if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags)) 1744 setfullscreen(w, 0); 1745 } 1746 } 1747 1748 void 1749 maximizenotify(struct wl_listener *listener, void *data) 1750 { 1751 /* This event is raised when a client would like to maximize itself, 1752 * typically because the user clicked on the maximize button on 1753 * client-side decorations. dwl doesn't support maximization, but 1754 * to conform to xdg-shell protocol we still must send a configure. 1755 * Since xdg-shell protocol v5 we should ignore request of unsupported 1756 * capabilities, just schedule a empty configure when the client uses <5 1757 * protocol version 1758 * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ 1759 Client *c = wl_container_of(listener, c, maximize); 1760 if (c->surface.xdg->initialized 1761 && wl_resource_get_version(c->surface.xdg->toplevel->resource) 1762 < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) 1763 wlr_xdg_surface_schedule_configure(c->surface.xdg); 1764 } 1765 1766 void 1767 monocle(Monitor *m) 1768 { 1769 Client *c; 1770 int n = 0; 1771 1772 wl_list_for_each(c, &clients, link) { 1773 if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) 1774 continue; 1775 resize(c, m->w, 0); 1776 n++; 1777 } 1778 if (n) 1779 snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n); 1780 if ((c = focustop(m))) 1781 wlr_scene_node_raise_to_top(&c->scene->node); 1782 } 1783 1784 void 1785 motionabsolute(struct wl_listener *listener, void *data) 1786 { 1787 /* This event is forwarded by the cursor when a pointer emits an _absolute_ 1788 * motion event, from 0..1 on each axis. This happens, for example, when 1789 * wlroots is running under a Wayland window rather than KMS+DRM, and you 1790 * move the mouse over the window. You could enter the window from any edge, 1791 * so we have to warp the mouse there. There is also some hardware which 1792 * emits these events. */ 1793 struct wlr_pointer_motion_absolute_event *event = data; 1794 double lx, ly, dx, dy; 1795 1796 if (!event->time_msec) /* this is 0 with virtual pointers */ 1797 wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); 1798 1799 wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, event->y, &lx, &ly); 1800 dx = lx - cursor->x; 1801 dy = ly - cursor->y; 1802 motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); 1803 } 1804 1805 void 1806 motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, 1807 double dx_unaccel, double dy_unaccel) 1808 { 1809 double sx = 0, sy = 0, sx_confined, sy_confined; 1810 Client *c = NULL, *w = NULL; 1811 LayerSurface *l = NULL; 1812 struct wlr_surface *surface = NULL; 1813 struct wlr_pointer_constraint_v1 *constraint; 1814 1815 /* Find the client under the pointer and send the event along. */ 1816 xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); 1817 1818 if (cursor_mode == CurPressed && !seat->drag 1819 && surface != seat->pointer_state.focused_surface 1820 && toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= 0) { 1821 c = w; 1822 surface = seat->pointer_state.focused_surface; 1823 sx = cursor->x - (l ? l->scene->node.x : w->geom.x); 1824 sy = cursor->y - (l ? l->scene->node.y : w->geom.y); 1825 } 1826 1827 /* time is 0 in internal calls meant to restore pointer focus. */ 1828 if (time) { 1829 wlr_relative_pointer_manager_v1_send_relative_motion( 1830 relative_pointer_mgr, seat, (uint64_t)time * 1000, 1831 dx, dy, dx_unaccel, dy_unaccel); 1832 1833 wl_list_for_each(constraint, &pointer_constraints->constraints, link) 1834 cursorconstrain(constraint); 1835 1836 if (active_constraint && cursor_mode != CurResize && cursor_mode != CurMove) { 1837 toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); 1838 if (c && active_constraint->surface == seat->pointer_state.focused_surface) { 1839 sx = cursor->x - c->geom.x - c->bw; 1840 sy = cursor->y - c->geom.y - c->bw; 1841 if (wlr_region_confine(&active_constraint->region, sx, sy, 1842 sx + dx, sy + dy, &sx_confined, &sy_confined)) { 1843 dx = sx_confined - sx; 1844 dy = sy_confined - sy; 1845 } 1846 1847 if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) 1848 return; 1849 } 1850 } 1851 1852 wlr_cursor_move(cursor, device, dx, dy); 1853 wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); 1854 1855 /* Update selmon (even while dragging a window) */ 1856 if (sloppyfocus) 1857 selmon = xytomon(cursor->x, cursor->y); 1858 } 1859 1860 /* Update drag icon's position */ 1861 wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); 1862 1863 /* If we are currently grabbing the mouse, handle and return */ 1864 if (cursor_mode == CurMove) { 1865 /* Move the grabbed client to the new position. */ 1866 resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy, 1867 .width = grabc->geom.width, .height = grabc->geom.height}, 1); 1868 return; 1869 } else if (cursor_mode == CurResize) { 1870 resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y, 1871 .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1); 1872 return; 1873 } 1874 1875 /* If there's no client surface under the cursor, set the cursor image to a 1876 * default. This is what makes the cursor image appear when you move it 1877 * off of a client or over its border. */ 1878 if (!surface && !seat->drag) 1879 wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); 1880 1881 pointerfocus(c, surface, sx, sy, time); 1882 } 1883 1884 void 1885 motionrelative(struct wl_listener *listener, void *data) 1886 { 1887 /* This event is forwarded by the cursor when a pointer emits a _relative_ 1888 * pointer motion event (i.e. a delta) */ 1889 struct wlr_pointer_motion_event *event = data; 1890 /* The cursor doesn't move unless we tell it to. The cursor automatically 1891 * handles constraining the motion to the output layout, as well as any 1892 * special configuration applied for the specific input device which 1893 * generated the event. You can pass NULL for the device if you want to move 1894 * the cursor around without any input. */ 1895 motionnotify(event->time_msec, &event->pointer->base, event->delta_x, event->delta_y, 1896 event->unaccel_dx, event->unaccel_dy); 1897 } 1898 1899 void 1900 moveresize(const Arg *arg) 1901 { 1902 if (cursor_mode != CurNormal && cursor_mode != CurPressed) 1903 return; 1904 xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); 1905 if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) 1906 return; 1907 1908 /* Float the window and tell motionnotify to grab it */ 1909 setfloating(grabc, 1); 1910 switch (cursor_mode = arg->ui) { 1911 case CurMove: 1912 grabcx = (int)round(cursor->x) - grabc->geom.x; 1913 grabcy = (int)round(cursor->y) - grabc->geom.y; 1914 wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); 1915 break; 1916 case CurResize: 1917 /* Doesn't work for X11 output - the next absolute motion event 1918 * returns the cursor to where it started */ 1919 wlr_cursor_warp_closest(cursor, NULL, 1920 grabc->geom.x + grabc->geom.width, 1921 grabc->geom.y + grabc->geom.height); 1922 wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize"); 1923 break; 1924 } 1925 } 1926 1927 void 1928 outputmgrapply(struct wl_listener *listener, void *data) 1929 { 1930 struct wlr_output_configuration_v1 *config = data; 1931 outputmgrapplyortest(config, 0); 1932 } 1933 1934 void 1935 outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) 1936 { 1937 /* 1938 * Called when a client such as wlr-randr requests a change in output 1939 * configuration. This is only one way that the layout can be changed, 1940 * so any Monitor information should be updated by updatemons() after an 1941 * output_layout.change event, not here. 1942 */ 1943 struct wlr_output_configuration_head_v1 *config_head; 1944 int ok = 1; 1945 1946 wl_list_for_each(config_head, &config->heads, link) { 1947 struct wlr_output *wlr_output = config_head->state.output; 1948 Monitor *m = wlr_output->data; 1949 struct wlr_output_state state; 1950 1951 /* Ensure displays previously disabled by wlr-output-power-management-v1 1952 * are properly handled*/ 1953 m->asleep = 0; 1954 1955 wlr_output_state_init(&state); 1956 wlr_output_state_set_enabled(&state, config_head->state.enabled); 1957 if (!config_head->state.enabled) 1958 goto apply_or_test; 1959 1960 if (config_head->state.mode) 1961 wlr_output_state_set_mode(&state, config_head->state.mode); 1962 else 1963 wlr_output_state_set_custom_mode(&state, 1964 config_head->state.custom_mode.width, 1965 config_head->state.custom_mode.height, 1966 config_head->state.custom_mode.refresh); 1967 1968 wlr_output_state_set_transform(&state, config_head->state.transform); 1969 wlr_output_state_set_scale(&state, config_head->state.scale); 1970 wlr_output_state_set_adaptive_sync_enabled(&state, 1971 config_head->state.adaptive_sync_enabled); 1972 1973 apply_or_test: 1974 ok &= test ? wlr_output_test_state(wlr_output, &state) 1975 : wlr_output_commit_state(wlr_output, &state); 1976 1977 /* Don't move monitors if position wouldn't change, this to avoid 1978 * wlroots marking the output as manually configured. 1979 * wlr_output_layout_add does not like disabled outputs */ 1980 if (!test && wlr_output->enabled && (m->m.x != config_head->state.x || m->m.y != config_head->state.y)) 1981 wlr_output_layout_add(output_layout, wlr_output, 1982 config_head->state.x, config_head->state.y); 1983 1984 wlr_output_state_finish(&state); 1985 } 1986 1987 if (ok) 1988 wlr_output_configuration_v1_send_succeeded(config); 1989 else 1990 wlr_output_configuration_v1_send_failed(config); 1991 wlr_output_configuration_v1_destroy(config); 1992 1993 /* https://codeberg.org/dwl/dwl/issues/577 */ 1994 updatemons(NULL, NULL); 1995 } 1996 1997 void 1998 outputmgrtest(struct wl_listener *listener, void *data) 1999 { 2000 struct wlr_output_configuration_v1 *config = data; 2001 outputmgrapplyortest(config, 1); 2002 } 2003 2004 void 2005 pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, 2006 uint32_t time) 2007 { 2008 struct timespec now; 2009 2010 if (surface != seat->pointer_state.focused_surface && 2011 sloppyfocus && time && c && !client_is_unmanaged(c)) 2012 focusclient(c, 0); 2013 2014 /* If surface is NULL, clear pointer focus */ 2015 if (!surface) { 2016 wlr_seat_pointer_notify_clear_focus(seat); 2017 return; 2018 } 2019 2020 if (!time) { 2021 clock_gettime(CLOCK_MONOTONIC, &now); 2022 time = now.tv_sec * 1000 + now.tv_nsec / 1000000; 2023 } 2024 2025 /* Let the client know that the mouse cursor has entered one 2026 * of its surfaces, and make keyboard focus follow if desired. 2027 * wlroots makes this a no-op if surface is already focused */ 2028 wlr_seat_pointer_notify_enter(seat, surface, sx, sy); 2029 wlr_seat_pointer_notify_motion(seat, time, sx, sy); 2030 } 2031 2032 void 2033 printstatus(void) 2034 { 2035 Monitor *m = NULL; 2036 Client *c; 2037 uint32_t occ, urg, sel; 2038 2039 wl_list_for_each(m, &mons, link) { 2040 occ = urg = 0; 2041 wl_list_for_each(c, &clients, link) { 2042 if (c->mon != m) 2043 continue; 2044 occ |= c->tags; 2045 if (c->isurgent) 2046 urg |= c->tags; 2047 } 2048 if ((c = focustop(m))) { 2049 printf("%s title %s\n", m->wlr_output->name, client_get_title(c)); 2050 printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c)); 2051 printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen); 2052 printf("%s floating %d\n", m->wlr_output->name, c->isfloating); 2053 sel = c->tags; 2054 } else { 2055 printf("%s title \n", m->wlr_output->name); 2056 printf("%s appid \n", m->wlr_output->name); 2057 printf("%s fullscreen \n", m->wlr_output->name); 2058 printf("%s floating \n", m->wlr_output->name); 2059 sel = 0; 2060 } 2061 2062 printf("%s selmon %u\n", m->wlr_output->name, m == selmon); 2063 printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n", 2064 m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); 2065 printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); 2066 } 2067 fflush(stdout); 2068 } 2069 2070 void 2071 powermgrsetmode(struct wl_listener *listener, void *data) 2072 { 2073 struct wlr_output_power_v1_set_mode_event *event = data; 2074 struct wlr_output_state state = {0}; 2075 Monitor *m = event->output->data; 2076 2077 if (!m) 2078 return; 2079 2080 m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */ 2081 wlr_output_state_set_enabled(&state, event->mode); 2082 wlr_output_commit_state(m->wlr_output, &state); 2083 2084 m->asleep = !event->mode; 2085 } 2086 2087 void 2088 quit(const Arg *arg) 2089 { 2090 wl_display_terminate(dpy); 2091 } 2092 2093 void 2094 rendermon(struct wl_listener *listener, void *data) 2095 { 2096 /* This function is called every time an output is ready to display a frame, 2097 * generally at the output's refresh rate (e.g. 60Hz). */ 2098 Monitor *m = wl_container_of(listener, m, frame); 2099 Client *c; 2100 struct wlr_output_state pending = {0}; 2101 struct timespec now; 2102 2103 /* Render if no XDG clients have an outstanding resize and are visible on 2104 * this monitor. */ 2105 wl_list_for_each(c, &clients, link) { 2106 if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) 2107 goto skip; 2108 } 2109 2110 wlr_scene_output_commit(m->scene_output, NULL); 2111 2112 skip: 2113 /* Let clients know a frame has been rendered */ 2114 clock_gettime(CLOCK_MONOTONIC, &now); 2115 wlr_scene_output_send_frame_done(m->scene_output, &now); 2116 wlr_output_state_finish(&pending); 2117 } 2118 2119 void 2120 requestdecorationmode(struct wl_listener *listener, void *data) 2121 { 2122 Client *c = wl_container_of(listener, c, set_decoration_mode); 2123 if (c->surface.xdg->initialized) 2124 wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, 2125 WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); 2126 } 2127 2128 void 2129 requeststartdrag(struct wl_listener *listener, void *data) 2130 { 2131 struct wlr_seat_request_start_drag_event *event = data; 2132 2133 if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, 2134 event->serial)) 2135 wlr_seat_start_pointer_drag(seat, event->drag, event->serial); 2136 else 2137 wlr_data_source_destroy(event->drag->source); 2138 } 2139 2140 void 2141 requestmonstate(struct wl_listener *listener, void *data) 2142 { 2143 struct wlr_output_event_request_state *event = data; 2144 wlr_output_commit_state(event->output, event->state); 2145 updatemons(NULL, NULL); 2146 } 2147 2148 void 2149 resize(Client *c, struct wlr_box geo, int interact) 2150 { 2151 struct wlr_box *bbox; 2152 struct wlr_box clip; 2153 2154 if (!c->mon || !client_surface(c)->mapped) 2155 return; 2156 2157 bbox = interact ? &sgeom : &c->mon->w; 2158 2159 client_set_bounds(c, geo.width, geo.height); 2160 c->geom = geo; 2161 applybounds(c, bbox); 2162 2163 /* Update scene-graph, including borders */ 2164 wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); 2165 wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); 2166 wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); 2167 wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); 2168 wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); 2169 wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); 2170 wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); 2171 wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); 2172 wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); 2173 2174 /* this is a no-op if size hasn't changed */ 2175 c->resize = client_set_size(c, c->geom.width - 2 * c->bw, 2176 c->geom.height - 2 * c->bw); 2177 client_get_clip(c, &clip); 2178 wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); 2179 } 2180 2181 void 2182 run(char *startup_cmd) 2183 { 2184 /* Add a Unix socket to the Wayland display. */ 2185 const char *socket = wl_display_add_socket_auto(dpy); 2186 if (!socket) 2187 die("startup: display_add_socket_auto"); 2188 setenv("WAYLAND_DISPLAY", socket, 1); 2189 2190 /* Start the backend. This will enumerate outputs and inputs, become the DRM 2191 * master, etc */ 2192 if (!wlr_backend_start(backend)) 2193 die("startup: backend_start"); 2194 2195 /* Now that the socket exists and the backend is started, run the startup command */ 2196 if (startup_cmd) { 2197 int piperw[2]; 2198 if (pipe(piperw) < 0) 2199 die("startup: pipe:"); 2200 if ((child_pid = fork()) < 0) 2201 die("startup: fork:"); 2202 if (child_pid == 0) { 2203 setsid(); 2204 dup2(piperw[0], STDIN_FILENO); 2205 close(piperw[0]); 2206 close(piperw[1]); 2207 execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); 2208 die("startup: execl:"); 2209 } 2210 dup2(piperw[1], STDOUT_FILENO); 2211 close(piperw[1]); 2212 close(piperw[0]); 2213 } 2214 2215 /* Mark stdout as non-blocking to avoid people who does not close stdin 2216 * nor consumes it in their startup script getting dwl frozen */ 2217 if (fd_set_nonblock(STDOUT_FILENO) < 0) 2218 close(STDOUT_FILENO); 2219 2220 printstatus(); 2221 2222 /* At this point the outputs are initialized, choose initial selmon based on 2223 * cursor position, and set default cursor image */ 2224 selmon = xytomon(cursor->x, cursor->y); 2225 2226 /* TODO hack to get cursor to display in its initial location (100, 100) 2227 * instead of (0, 0) and then jumping. still may not be fully 2228 * initialized, as the image/coordinates are not transformed for the 2229 * monitor when displayed here */ 2230 wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); 2231 wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); 2232 2233 /* Run the Wayland event loop. This does not return until you exit the 2234 * compositor. Starting the backend rigged up all of the necessary event 2235 * loop configuration to listen to libinput events, DRM events, generate 2236 * frame events at the refresh rate, and so on. */ 2237 wl_display_run(dpy); 2238 } 2239 2240 void 2241 setcursor(struct wl_listener *listener, void *data) 2242 { 2243 /* This event is raised by the seat when a client provides a cursor image */ 2244 struct wlr_seat_pointer_request_set_cursor_event *event = data; 2245 /* If we're "grabbing" the cursor, don't use the client's image, we will 2246 * restore it after "grabbing" sending a leave event, followed by a enter 2247 * event, which will result in the client requesting set the cursor surface */ 2248 if (cursor_mode != CurNormal && cursor_mode != CurPressed) 2249 return; 2250 /* This can be sent by any client, so we check to make sure this one is 2251 * actually has pointer focus first. If so, we can tell the cursor to 2252 * use the provided surface as the cursor image. It will set the 2253 * hardware cursor on the output that it's currently on and continue to 2254 * do so as the cursor moves between outputs. */ 2255 if (event->seat_client == seat->pointer_state.focused_client) 2256 wlr_cursor_set_surface(cursor, event->surface, 2257 event->hotspot_x, event->hotspot_y); 2258 } 2259 2260 void 2261 setcursorshape(struct wl_listener *listener, void *data) 2262 { 2263 struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; 2264 if (cursor_mode != CurNormal && cursor_mode != CurPressed) 2265 return; 2266 /* This can be sent by any client, so we check to make sure this one is 2267 * actually has pointer focus first. If so, we can tell the cursor to 2268 * use the provided cursor shape. */ 2269 if (event->seat_client == seat->pointer_state.focused_client) 2270 wlr_cursor_set_xcursor(cursor, cursor_mgr, 2271 wlr_cursor_shape_v1_name(event->shape)); 2272 } 2273 2274 void 2275 setfloating(Client *c, int floating) 2276 { 2277 Client *p = client_get_parent(c); 2278 c->isfloating = floating; 2279 /* If in floating layout do not change the client's layer */ 2280 if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange) 2281 return; 2282 wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || 2283 (p && p->isfullscreen) ? LyrFS 2284 : c->isfloating ? LyrFloat : LyrTile]); 2285 arrange(c->mon); 2286 printstatus(); 2287 } 2288 2289 void 2290 setfullscreen(Client *c, int fullscreen) 2291 { 2292 c->isfullscreen = fullscreen; 2293 if (!c->mon || !client_surface(c)->mapped) 2294 return; 2295 c->bw = fullscreen ? 0 : borderpx; 2296 client_set_fullscreen(c, fullscreen); 2297 wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen 2298 ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); 2299 2300 if (fullscreen) { 2301 c->prev = c->geom; 2302 resize(c, c->mon->m, 0); 2303 } else { 2304 /* restore previous size instead of arrange for floating windows since 2305 * client positions are set by the user and cannot be recalculated */ 2306 resize(c, c->prev, 0); 2307 } 2308 arrange(c->mon); 2309 printstatus(); 2310 } 2311 2312 void 2313 setlayout(const Arg *arg) 2314 { 2315 if (!selmon) 2316 return; 2317 if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) 2318 selmon->sellt ^= 1; 2319 if (arg && arg->v) 2320 selmon->lt[selmon->sellt] = (Layout *)arg->v; 2321 strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol)); 2322 arrange(selmon); 2323 printstatus(); 2324 } 2325 2326 /* arg > 1.0 will set mfact absolutely */ 2327 void 2328 setmfact(const Arg *arg) 2329 { 2330 float f; 2331 2332 if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) 2333 return; 2334 f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f; 2335 if (f < 0.1 || f > 0.9) 2336 return; 2337 selmon->mfact = f; 2338 arrange(selmon); 2339 } 2340 2341 void 2342 setmon(Client *c, Monitor *m, uint32_t newtags) 2343 { 2344 Monitor *oldmon = c->mon; 2345 2346 if (oldmon == m) 2347 return; 2348 c->mon = m; 2349 c->prev = c->geom; 2350 2351 /* Scene graph sends surface leave/enter events on move and resize */ 2352 if (oldmon) 2353 arrange(oldmon); 2354 if (m) { 2355 /* Make sure window actually overlaps with the monitor */ 2356 resize(c, c->geom, 0); 2357 c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ 2358 setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ 2359 setfloating(c, c->isfloating); 2360 } 2361 focusclient(focustop(selmon), 1); 2362 } 2363 2364 void 2365 setpsel(struct wl_listener *listener, void *data) 2366 { 2367 /* This event is raised by the seat when a client wants to set the selection, 2368 * usually when the user copies something. wlroots allows compositors to 2369 * ignore such requests if they so choose, but in dwl we always honor 2370 */ 2371 struct wlr_seat_request_set_primary_selection_event *event = data; 2372 wlr_seat_set_primary_selection(seat, event->source, event->serial); 2373 } 2374 2375 void 2376 setsel(struct wl_listener *listener, void *data) 2377 { 2378 /* This event is raised by the seat when a client wants to set the selection, 2379 * usually when the user copies something. wlroots allows compositors to 2380 * ignore such requests if they so choose, but in dwl we always honor 2381 */ 2382 struct wlr_seat_request_set_selection_event *event = data; 2383 wlr_seat_set_selection(seat, event->source, event->serial); 2384 } 2385 2386 void 2387 setup(void) 2388 { 2389 int drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; 2390 struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; 2391 sigemptyset(&sa.sa_mask); 2392 2393 for (i = 0; i < (int)LENGTH(sig); i++) 2394 sigaction(sig[i], &sa, NULL); 2395 2396 wlr_log_init(log_level, NULL); 2397 2398 /* The Wayland display is managed by libwayland. It handles accepting 2399 * clients from the Unix socket, manging Wayland globals, and so on. */ 2400 dpy = wl_display_create(); 2401 event_loop = wl_display_get_event_loop(dpy); 2402 2403 /* The backend is a wlroots feature which abstracts the underlying input and 2404 * output hardware. The autocreate option will choose the most suitable 2405 * backend based on the current environment, such as opening an X11 window 2406 * if an X11 server is running. */ 2407 if (!(backend = wlr_backend_autocreate(event_loop, &session))) 2408 die("couldn't create backend"); 2409 2410 /* Initialize the scene graph used to lay out windows */ 2411 scene = wlr_scene_create(); 2412 root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor); 2413 for (i = 0; i < NUM_LAYERS; i++) 2414 layers[i] = wlr_scene_tree_create(&scene->tree); 2415 drag_icon = wlr_scene_tree_create(&scene->tree); 2416 wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node); 2417 2418 /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user 2419 * can also specify a renderer using the WLR_RENDERER env var. 2420 * The renderer is responsible for defining the various pixel formats it 2421 * supports for shared memory, this configures that for clients. */ 2422 if (!(drw = wlr_renderer_autocreate(backend))) 2423 die("couldn't create renderer"); 2424 LISTEN_STATIC(&drw->events.lost, gpureset); 2425 2426 /* Create shm, drm and linux_dmabuf interfaces by ourselves. 2427 * The simplest way is call: 2428 * wlr_renderer_init_wl_display(drw); 2429 * but we need to create manually the linux_dmabuf interface to integrate it 2430 * with wlr_scene. */ 2431 wlr_renderer_init_wl_shm(drw, dpy); 2432 2433 if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { 2434 wlr_drm_create(dpy, drw); 2435 wlr_scene_set_linux_dmabuf_v1(scene, 2436 wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); 2437 } 2438 2439 if ((drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && drw->features.timeline 2440 && backend->features.timeline) 2441 wlr_linux_drm_syncobj_manager_v1_create(dpy, 1, drm_fd); 2442 2443 /* Autocreates an allocator for us. 2444 * The allocator is the bridge between the renderer and the backend. It 2445 * handles the buffer creation, allowing wlroots to render onto the 2446 * screen */ 2447 if (!(alloc = wlr_allocator_autocreate(backend, drw))) 2448 die("couldn't create allocator"); 2449 2450 /* This creates some hands-off wlroots interfaces. The compositor is 2451 * necessary for clients to allocate surfaces and the data device manager 2452 * handles the clipboard. Each of these wlroots interfaces has room for you 2453 * to dig your fingers in and play with their behavior if you want. Note that 2454 * the clients cannot set the selection directly without compositor approval, 2455 * see the setsel() function. */ 2456 compositor = wlr_compositor_create(dpy, 6, drw); 2457 wlr_subcompositor_create(dpy); 2458 wlr_data_device_manager_create(dpy); 2459 wlr_export_dmabuf_manager_v1_create(dpy); 2460 wlr_screencopy_manager_v1_create(dpy); 2461 wlr_data_control_manager_v1_create(dpy); 2462 wlr_primary_selection_v1_device_manager_create(dpy); 2463 wlr_viewporter_create(dpy); 2464 wlr_single_pixel_buffer_manager_v1_create(dpy); 2465 wlr_fractional_scale_manager_v1_create(dpy, 1); 2466 wlr_presentation_create(dpy, backend, 2); 2467 wlr_alpha_modifier_v1_create(dpy); 2468 2469 /* Initializes the interface used to implement urgency hints */ 2470 activation = wlr_xdg_activation_v1_create(dpy); 2471 LISTEN_STATIC(&activation->events.request_activate, urgent); 2472 2473 wlr_scene_set_gamma_control_manager_v1(scene, wlr_gamma_control_manager_v1_create(dpy)); 2474 2475 power_mgr = wlr_output_power_manager_v1_create(dpy); 2476 LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode); 2477 2478 /* Creates an output layout, which a wlroots utility for working with an 2479 * arrangement of screens in a physical layout. */ 2480 output_layout = wlr_output_layout_create(dpy); 2481 LISTEN_STATIC(&output_layout->events.change, updatemons); 2482 wlr_xdg_output_manager_v1_create(dpy, output_layout); 2483 2484 /* Configure a listener to be notified when new outputs are available on the 2485 * backend. */ 2486 wl_list_init(&mons); 2487 LISTEN_STATIC(&backend->events.new_output, createmon); 2488 2489 /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a 2490 * Wayland protocol which is used for application windows. For more 2491 * detail on shells, refer to the article: 2492 * 2493 * https://drewdevault.com/2018/07/29/Wayland-shells.html 2494 */ 2495 wl_list_init(&clients); 2496 wl_list_init(&fstack); 2497 2498 xdg_shell = wlr_xdg_shell_create(dpy, 6); 2499 LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); 2500 LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup); 2501 2502 layer_shell = wlr_layer_shell_v1_create(dpy, 3); 2503 LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); 2504 2505 idle_notifier = wlr_idle_notifier_v1_create(dpy); 2506 2507 idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); 2508 LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); 2509 2510 session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); 2511 wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); 2512 LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr); 2513 locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, 2514 (float [4]){0.1f, 0.1f, 0.1f, 1.0f}); 2515 wlr_scene_node_set_enabled(&locked_bg->node, 0); 2516 2517 /* Use decoration protocols to negotiate server-side decorations */ 2518 wlr_server_decoration_manager_set_default_mode( 2519 wlr_server_decoration_manager_create(dpy), 2520 WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); 2521 xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); 2522 LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); 2523 2524 pointer_constraints = wlr_pointer_constraints_v1_create(dpy); 2525 LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint); 2526 2527 relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); 2528 2529 /* 2530 * Creates a cursor, which is a wlroots utility for tracking the cursor 2531 * image shown on screen. 2532 */ 2533 cursor = wlr_cursor_create(); 2534 wlr_cursor_attach_output_layout(cursor, output_layout); 2535 2536 /* Creates an xcursor manager, another wlroots utility which loads up 2537 * Xcursor themes to source cursor images from and makes sure that cursor 2538 * images are available at all scale factors on the screen (necessary for 2539 * HiDPI support). Scaled cursors will be loaded with each output. */ 2540 cursor_mgr = wlr_xcursor_manager_create(NULL, 24); 2541 setenv("XCURSOR_SIZE", "24", 1); 2542 2543 /* 2544 * wlr_cursor *only* displays an image on screen. It does not move around 2545 * when the pointer moves. However, we can attach input devices to it, and 2546 * it will generate aggregate events for all of them. In these events, we 2547 * can choose how we want to process them, forwarding them to clients and 2548 * moving the cursor around. More detail on this process is described in 2549 * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html 2550 * 2551 * And more comments are sprinkled throughout the notify functions above. 2552 */ 2553 LISTEN_STATIC(&cursor->events.motion, motionrelative); 2554 LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute); 2555 LISTEN_STATIC(&cursor->events.button, buttonpress); 2556 LISTEN_STATIC(&cursor->events.axis, axisnotify); 2557 LISTEN_STATIC(&cursor->events.frame, cursorframe); 2558 2559 cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); 2560 LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape); 2561 2562 /* 2563 * Configures a seat, which is a single "seat" at which a user sits and 2564 * operates the computer. This conceptually includes up to one keyboard, 2565 * pointer, touch, and drawing tablet device. We also rig up a listener to 2566 * let us know when new input devices are available on the backend. 2567 */ 2568 LISTEN_STATIC(&backend->events.new_input, inputdevice); 2569 virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); 2570 LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard); 2571 virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy); 2572 LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, virtualpointer); 2573 2574 seat = wlr_seat_create(dpy, "seat0"); 2575 LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); 2576 LISTEN_STATIC(&seat->events.request_set_selection, setsel); 2577 LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); 2578 LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); 2579 LISTEN_STATIC(&seat->events.start_drag, startdrag); 2580 2581 kb_group = createkeyboardgroup(); 2582 wl_list_init(&kb_group->destroy.link); 2583 2584 output_mgr = wlr_output_manager_v1_create(dpy); 2585 LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); 2586 LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); 2587 2588 /* Make sure XWayland clients don't connect to the parent X server, 2589 * e.g when running in the x11 backend or the wayland backend and the 2590 * compositor has Xwayland support */ 2591 unsetenv("DISPLAY"); 2592 #ifdef XWAYLAND 2593 /* 2594 * Initialise the XWayland X server. 2595 * It will be started when the first X client is started. 2596 */ 2597 if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) { 2598 LISTEN_STATIC(&xwayland->events.ready, xwaylandready); 2599 LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); 2600 2601 setenv("DISPLAY", xwayland->display_name, 1); 2602 } else { 2603 fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); 2604 } 2605 #endif 2606 } 2607 2608 void 2609 spawn(const Arg *arg) 2610 { 2611 if (fork() == 0) { 2612 dup2(STDERR_FILENO, STDOUT_FILENO); 2613 setsid(); 2614 execvp(((char **)arg->v)[0], (char **)arg->v); 2615 die("dwl: execvp %s failed:", ((char **)arg->v)[0]); 2616 } 2617 } 2618 2619 void 2620 startdrag(struct wl_listener *listener, void *data) 2621 { 2622 struct wlr_drag *drag = data; 2623 if (!drag->icon) 2624 return; 2625 2626 drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node; 2627 LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); 2628 } 2629 2630 void 2631 tag(const Arg *arg) 2632 { 2633 Client *sel = focustop(selmon); 2634 if (!sel || (arg->ui & TAGMASK) == 0) 2635 return; 2636 2637 sel->tags = arg->ui & TAGMASK; 2638 focusclient(focustop(selmon), 1); 2639 arrange(selmon); 2640 printstatus(); 2641 } 2642 2643 void 2644 tagmon(const Arg *arg) 2645 { 2646 Client *sel = focustop(selmon); 2647 if (sel) 2648 setmon(sel, dirtomon(arg->i), 0); 2649 } 2650 2651 void 2652 tile(Monitor *m) 2653 { 2654 unsigned int mw, my, ty; 2655 int i, n = 0; 2656 Client *c; 2657 2658 wl_list_for_each(c, &clients, link) 2659 if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) 2660 n++; 2661 if (n == 0) 2662 return; 2663 2664 if (n > m->nmaster) 2665 mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0; 2666 else 2667 mw = m->w.width; 2668 i = my = ty = 0; 2669 wl_list_for_each(c, &clients, link) { 2670 if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) 2671 continue; 2672 if (i < m->nmaster) { 2673 resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw, 2674 .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0); 2675 my += c->geom.height; 2676 } else { 2677 resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty, 2678 .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0); 2679 ty += c->geom.height; 2680 } 2681 i++; 2682 } 2683 } 2684 2685 void 2686 togglefloating(const Arg *arg) 2687 { 2688 Client *sel = focustop(selmon); 2689 /* return if fullscreen */ 2690 if (sel && !sel->isfullscreen) 2691 setfloating(sel, !sel->isfloating); 2692 } 2693 2694 void 2695 togglefullscreen(const Arg *arg) 2696 { 2697 Client *sel = focustop(selmon); 2698 if (sel) 2699 setfullscreen(sel, !sel->isfullscreen); 2700 } 2701 2702 void 2703 toggletag(const Arg *arg) 2704 { 2705 uint32_t newtags; 2706 Client *sel = focustop(selmon); 2707 if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK))) 2708 return; 2709 2710 sel->tags = newtags; 2711 focusclient(focustop(selmon), 1); 2712 arrange(selmon); 2713 printstatus(); 2714 } 2715 2716 void 2717 toggleview(const Arg *arg) 2718 { 2719 uint32_t newtagset; 2720 if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0)) 2721 return; 2722 2723 selmon->tagset[selmon->seltags] = newtagset; 2724 focusclient(focustop(selmon), 1); 2725 arrange(selmon); 2726 printstatus(); 2727 } 2728 2729 void 2730 unlocksession(struct wl_listener *listener, void *data) 2731 { 2732 SessionLock *lock = wl_container_of(listener, lock, unlock); 2733 destroylock(lock, 1); 2734 } 2735 2736 void 2737 unmaplayersurfacenotify(struct wl_listener *listener, void *data) 2738 { 2739 LayerSurface *l = wl_container_of(listener, l, unmap); 2740 2741 l->mapped = 0; 2742 wlr_scene_node_set_enabled(&l->scene->node, 0); 2743 if (l == exclusive_focus) 2744 exclusive_focus = NULL; 2745 if (l->layer_surface->output && (l->mon = l->layer_surface->output->data)) 2746 arrangelayers(l->mon); 2747 if (l->layer_surface->surface == seat->keyboard_state.focused_surface) 2748 focusclient(focustop(selmon), 1); 2749 motionnotify(0, NULL, 0, 0, 0, 0); 2750 } 2751 2752 void 2753 unmapnotify(struct wl_listener *listener, void *data) 2754 { 2755 /* Called when the surface is unmapped, and should no longer be shown. */ 2756 Client *c = wl_container_of(listener, c, unmap); 2757 if (c == grabc) { 2758 cursor_mode = CurNormal; 2759 grabc = NULL; 2760 } 2761 2762 if (client_is_unmanaged(c)) { 2763 if (c == exclusive_focus) { 2764 exclusive_focus = NULL; 2765 focusclient(focustop(selmon), 1); 2766 } 2767 } else { 2768 wl_list_remove(&c->link); 2769 setmon(c, NULL, 0); 2770 wl_list_remove(&c->flink); 2771 } 2772 2773 wlr_scene_node_destroy(&c->scene->node); 2774 printstatus(); 2775 motionnotify(0, NULL, 0, 0, 0, 0); 2776 } 2777 2778 void 2779 updatemons(struct wl_listener *listener, void *data) 2780 { 2781 /* 2782 * Called whenever the output layout changes: adding or removing a 2783 * monitor, changing an output's mode or position, etc. This is where 2784 * the change officially happens and we update geometry, window 2785 * positions, focus, and the stored configuration in wlroots' 2786 * output-manager implementation. 2787 */ 2788 struct wlr_output_configuration_v1 *config 2789 = wlr_output_configuration_v1_create(); 2790 Client *c; 2791 struct wlr_output_configuration_head_v1 *config_head; 2792 Monitor *m; 2793 2794 /* First remove from the layout the disabled monitors */ 2795 wl_list_for_each(m, &mons, link) { 2796 if (m->wlr_output->enabled || m->asleep) 2797 continue; 2798 config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); 2799 config_head->state.enabled = 0; 2800 /* Remove this output from the layout to avoid cursor enter inside it */ 2801 wlr_output_layout_remove(output_layout, m->wlr_output); 2802 closemon(m); 2803 m->m = m->w = (struct wlr_box){0}; 2804 } 2805 /* Insert outputs that need to */ 2806 wl_list_for_each(m, &mons, link) { 2807 if (m->wlr_output->enabled 2808 && !wlr_output_layout_get(output_layout, m->wlr_output)) 2809 wlr_output_layout_add_auto(output_layout, m->wlr_output); 2810 } 2811 2812 /* Now that we update the output layout we can get its box */ 2813 wlr_output_layout_get_box(output_layout, NULL, &sgeom); 2814 2815 wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y); 2816 wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height); 2817 2818 /* Make sure the clients are hidden when dwl is locked */ 2819 wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y); 2820 wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); 2821 2822 wl_list_for_each(m, &mons, link) { 2823 if (!m->wlr_output->enabled) 2824 continue; 2825 config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); 2826 2827 /* Get the effective monitor geometry to use for surfaces */ 2828 wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m); 2829 m->w = m->m; 2830 wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); 2831 2832 wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); 2833 wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); 2834 2835 if (m->lock_surface) { 2836 struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data; 2837 wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); 2838 wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height); 2839 } 2840 2841 /* Calculate the effective monitor geometry to use for clients */ 2842 arrangelayers(m); 2843 /* Don't move clients to the left output when plugging monitors */ 2844 arrange(m); 2845 /* make sure fullscreen clients have the right size */ 2846 if ((c = focustop(m)) && c->isfullscreen) 2847 resize(c, m->m, 0); 2848 2849 /* Try to re-set the gamma LUT when updating monitors, 2850 * it's only really needed when enabling a disabled output, but meh. */ 2851 m->gamma_lut_changed = 1; 2852 2853 config_head->state.x = m->m.x; 2854 config_head->state.y = m->m.y; 2855 2856 if (!selmon) { 2857 selmon = m; 2858 } 2859 } 2860 2861 if (selmon && selmon->wlr_output->enabled) { 2862 wl_list_for_each(c, &clients, link) { 2863 if (!c->mon && client_surface(c)->mapped) 2864 setmon(c, selmon, c->tags); 2865 } 2866 focusclient(focustop(selmon), 1); 2867 if (selmon->lock_surface) { 2868 client_notify_enter(selmon->lock_surface->surface, 2869 wlr_seat_get_keyboard(seat)); 2870 client_activate_surface(selmon->lock_surface->surface, 1); 2871 } 2872 } 2873 2874 /* FIXME: figure out why the cursor image is at 0,0 after turning all 2875 * the monitors on. 2876 * Move the cursor image where it used to be. It does not generate a 2877 * wl_pointer.motion event for the clients, it's only the image what it's 2878 * at the wrong position after all. */ 2879 wlr_cursor_move(cursor, NULL, 0, 0); 2880 2881 wlr_output_manager_v1_set_configuration(output_mgr, config); 2882 } 2883 2884 void 2885 updatetitle(struct wl_listener *listener, void *data) 2886 { 2887 Client *c = wl_container_of(listener, c, set_title); 2888 if (c == focustop(c->mon)) 2889 printstatus(); 2890 } 2891 2892 void 2893 urgent(struct wl_listener *listener, void *data) 2894 { 2895 struct wlr_xdg_activation_v1_request_activate_event *event = data; 2896 Client *c = NULL; 2897 toplevel_from_wlr_surface(event->surface, &c, NULL); 2898 if (!c || c == focustop(selmon)) 2899 return; 2900 2901 c->isurgent = 1; 2902 printstatus(); 2903 2904 if (client_surface(c)->mapped) 2905 client_set_border_color(c, urgentcolor); 2906 } 2907 2908 void 2909 view(const Arg *arg) 2910 { 2911 if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) 2912 return; 2913 selmon->seltags ^= 1; /* toggle sel tagset */ 2914 if (arg->ui & TAGMASK) 2915 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; 2916 focusclient(focustop(selmon), 1); 2917 arrange(selmon); 2918 printstatus(); 2919 } 2920 2921 void 2922 virtualkeyboard(struct wl_listener *listener, void *data) 2923 { 2924 struct wlr_virtual_keyboard_v1 *kb = data; 2925 /* virtual keyboards shouldn't share keyboard group */ 2926 KeyboardGroup *group = createkeyboardgroup(); 2927 /* Set the keymap to match the group keymap */ 2928 wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); 2929 LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup); 2930 2931 /* Add the new keyboard to the group */ 2932 wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); 2933 } 2934 2935 void 2936 virtualpointer(struct wl_listener *listener, void *data) 2937 { 2938 struct wlr_virtual_pointer_v1_new_pointer_event *event = data; 2939 struct wlr_input_device *device = &event->new_pointer->pointer.base; 2940 2941 wlr_cursor_attach_input_device(cursor, device); 2942 if (event->suggested_output) 2943 wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); 2944 } 2945 2946 Monitor * 2947 xytomon(double x, double y) 2948 { 2949 struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); 2950 return o ? o->data : NULL; 2951 } 2952 2953 void 2954 xytonode(double x, double y, struct wlr_surface **psurface, 2955 Client **pc, LayerSurface **pl, double *nx, double *ny) 2956 { 2957 struct wlr_scene_node *node, *pnode; 2958 struct wlr_surface *surface = NULL; 2959 Client *c = NULL; 2960 LayerSurface *l = NULL; 2961 int layer; 2962 2963 for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { 2964 if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) 2965 continue; 2966 2967 if (node->type == WLR_SCENE_NODE_BUFFER) 2968 surface = wlr_scene_surface_try_from_buffer( 2969 wlr_scene_buffer_from_node(node))->surface; 2970 /* Walk the tree to find a node that knows the client */ 2971 for (pnode = node; pnode && !c; pnode = &pnode->parent->node) 2972 c = pnode->data; 2973 if (c && c->type == LayerShell) { 2974 c = NULL; 2975 l = pnode->data; 2976 } 2977 } 2978 2979 if (psurface) *psurface = surface; 2980 if (pc) *pc = c; 2981 if (pl) *pl = l; 2982 } 2983 2984 void 2985 zoom(const Arg *arg) 2986 { 2987 Client *c, *sel = focustop(selmon); 2988 2989 if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) 2990 return; 2991 2992 /* Search for the first tiled window that is not sel, marking sel as 2993 * NULL if we pass it along the way */ 2994 wl_list_for_each(c, &clients, link) { 2995 if (VISIBLEON(c, selmon) && !c->isfloating) { 2996 if (c != sel) 2997 break; 2998 sel = NULL; 2999 } 3000 } 3001 3002 /* Return if no other tiled window was found */ 3003 if (&c->link == &clients) 3004 return; 3005 3006 /* If we passed sel, move c to the front; otherwise, move sel to the 3007 * front */ 3008 if (!sel) 3009 sel = c; 3010 wl_list_remove(&sel->link); 3011 wl_list_insert(&clients, &sel->link); 3012 3013 focusclient(sel, 1); 3014 arrange(selmon); 3015 } 3016 3017 #ifdef XWAYLAND 3018 void 3019 activatex11(struct wl_listener *listener, void *data) 3020 { 3021 Client *c = wl_container_of(listener, c, activate); 3022 3023 /* Only "managed" windows can be activated */ 3024 if (!client_is_unmanaged(c)) 3025 wlr_xwayland_surface_activate(c->surface.xwayland, 1); 3026 } 3027 3028 void 3029 associatex11(struct wl_listener *listener, void *data) 3030 { 3031 Client *c = wl_container_of(listener, c, associate); 3032 3033 LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); 3034 LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); 3035 } 3036 3037 void 3038 configurex11(struct wl_listener *listener, void *data) 3039 { 3040 Client *c = wl_container_of(listener, c, configure); 3041 struct wlr_xwayland_surface_configure_event *event = data; 3042 if (!client_surface(c) || !client_surface(c)->mapped) { 3043 wlr_xwayland_surface_configure(c->surface.xwayland, 3044 event->x, event->y, event->width, event->height); 3045 return; 3046 } 3047 if (client_is_unmanaged(c)) { 3048 wlr_scene_node_set_position(&c->scene->node, event->x, event->y); 3049 wlr_xwayland_surface_configure(c->surface.xwayland, 3050 event->x, event->y, event->width, event->height); 3051 return; 3052 } 3053 if ((c->isfloating && c != grabc) || !c->mon->lt[c->mon->sellt]->arrange) { 3054 resize(c, (struct wlr_box){.x = event->x - c->bw, 3055 .y = event->y - c->bw, .width = event->width + c->bw * 2, 3056 .height = event->height + c->bw * 2}, 0); 3057 } else { 3058 arrange(c->mon); 3059 } 3060 } 3061 3062 void 3063 createnotifyx11(struct wl_listener *listener, void *data) 3064 { 3065 struct wlr_xwayland_surface *xsurface = data; 3066 Client *c; 3067 3068 /* Allocate a Client for this surface */ 3069 c = xsurface->data = ecalloc(1, sizeof(*c)); 3070 c->surface.xwayland = xsurface; 3071 c->type = X11; 3072 c->bw = client_is_unmanaged(c) ? 0 : borderpx; 3073 3074 /* Listen to the various events it can emit */ 3075 LISTEN(&xsurface->events.associate, &c->associate, associatex11); 3076 LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); 3077 LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11); 3078 LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); 3079 LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); 3080 LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); 3081 LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); 3082 LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); 3083 } 3084 3085 void 3086 dissociatex11(struct wl_listener *listener, void *data) 3087 { 3088 Client *c = wl_container_of(listener, c, dissociate); 3089 wl_list_remove(&c->map.link); 3090 wl_list_remove(&c->unmap.link); 3091 } 3092 3093 xcb_atom_t 3094 getatom(xcb_connection_t *xc, const char *name) 3095 { 3096 xcb_atom_t atom = 0; 3097 xcb_intern_atom_reply_t *reply; 3098 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name); 3099 if ((reply = xcb_intern_atom_reply(xc, cookie, NULL))) 3100 atom = reply->atom; 3101 free(reply); 3102 3103 return atom; 3104 } 3105 3106 void 3107 sethints(struct wl_listener *listener, void *data) 3108 { 3109 Client *c = wl_container_of(listener, c, set_hints); 3110 struct wlr_surface *surface = client_surface(c); 3111 if (c == focustop(selmon)) 3112 return; 3113 3114 c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); 3115 printstatus(); 3116 3117 if (c->isurgent && surface && surface->mapped) 3118 client_set_border_color(c, urgentcolor); 3119 } 3120 3121 void 3122 xwaylandready(struct wl_listener *listener, void *data) 3123 { 3124 struct wlr_xcursor *xcursor; 3125 xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL); 3126 int err = xcb_connection_has_error(xc); 3127 if (err) { 3128 fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err); 3129 return; 3130 } 3131 3132 /* Collect atoms we are interested in. If getatom returns 0, we will 3133 * not detect that window type. */ 3134 netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG"); 3135 netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH"); 3136 netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR"); 3137 netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY"); 3138 3139 /* assign the one and only seat */ 3140 wlr_xwayland_set_seat(xwayland, seat); 3141 3142 /* Set the default XWayland cursor to match the rest of dwl. */ 3143 if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) 3144 wlr_xwayland_set_cursor(xwayland, 3145 xcursor->images[0]->buffer, xcursor->images[0]->width * 4, 3146 xcursor->images[0]->width, xcursor->images[0]->height, 3147 xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); 3148 3149 xcb_disconnect(xc); 3150 } 3151 #endif 3152 3153 int 3154 main(int argc, char *argv[]) 3155 { 3156 char *startup_cmd = NULL; 3157 int c; 3158 3159 while ((c = getopt(argc, argv, "s:hdv")) != -1) { 3160 if (c == 's') 3161 startup_cmd = optarg; 3162 else if (c == 'd') 3163 log_level = WLR_DEBUG; 3164 else if (c == 'v') 3165 die("dwl " VERSION); 3166 else 3167 goto usage; 3168 } 3169 if (optind < argc) 3170 goto usage; 3171 3172 /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ 3173 if (!getenv("XDG_RUNTIME_DIR")) 3174 die("XDG_RUNTIME_DIR must be set"); 3175 setup(); 3176 run(startup_cmd); 3177 cleanup(); 3178 return EXIT_SUCCESS; 3179 3180 usage: 3181 die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); 3182 }