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