From 61826c9ba76ad789d39789b6e2c1f3bb61104989 Mon Sep 17 00:00:00 2001 From: tomit4 Date: Sun, 7 Jun 2026 10:03:53 -0700 Subject: [PATCH] :wrench: Settuping up dwl --- dwl/alwayscenter.patch | 25 + dwl/customfloat-0.8.patch | 95 + dwl/dragresize.patch | 210 + dwl/dwl-v0.7/client.h | 12 - dwl/dwl-v0.7/config.def.h | 279 +- dwl/dwl-v0.7/config.mk | 4 +- dwl/dwl-v0.7/dwl.c | 4906 ++++++++--------- dwl/dwl-v0.7_bak/CHANGELOG.md | 200 + dwl/dwl-v0.7_bak/LICENSE | 692 +++ dwl/dwl-v0.7_bak/LICENSE.dwm | 39 + dwl/dwl-v0.7_bak/LICENSE.sway | 19 + dwl/dwl-v0.7_bak/LICENSE.tinywl | 127 + dwl/dwl-v0.7_bak/Makefile | 78 + dwl/dwl-v0.7_bak/README.md | 201 + dwl/dwl-v0.7_bak/client.h | 420 ++ dwl/dwl-v0.7_bak/config.def.h | 269 + dwl/dwl-v0.7_bak/config.def.h.orig | 269 + dwl/dwl-v0.7_bak/config.def.h.rej | 34 + dwl/dwl-v0.7_bak/config.h | 269 + dwl/dwl-v0.7_bak/config.mk | 17 + dwl/dwl-v0.7_bak/cursor-shape-v1-protocol.h | 201 + dwl/dwl-v0.7_bak/dwl | Bin 0 -> 299856 bytes dwl/dwl-v0.7_bak/dwl.1 | 158 + dwl/dwl-v0.7_bak/dwl.c | 3359 +++++++++++ dwl/dwl-v0.7_bak/dwl.c.orig | 3215 +++++++++++ dwl/dwl-v0.7_bak/dwl.desktop | 5 + dwl/dwl-v0.7_bak/dwl.o | Bin 0 -> 336584 bytes ...pointer-constraints-unstable-v1-protocol.h | 63 + .../protocols/wlr-layer-shell-unstable-v1.xml | 390 ++ ...lr-output-power-management-unstable-v1.xml | 128 + dwl/dwl-v0.7_bak/swallow.patch | 350 ++ dwl/dwl-v0.7_bak/util.c | 51 + dwl/dwl-v0.7_bak/util.h | 5 + dwl/dwl-v0.7_bak/util.o | Bin 0 -> 9400 bytes .../wlr-layer-shell-unstable-v1-protocol.h | 177 + ...ut-power-management-unstable-v1-protocol.h | 285 + dwl/dwl-v0.7_bak/xdg-shell-protocol.h | 2374 ++++++++ dwl/hide-cursor-when-typing.patch | 204 + 38 files changed, 16445 insertions(+), 2685 deletions(-) create mode 100644 dwl/alwayscenter.patch create mode 100644 dwl/customfloat-0.8.patch create mode 100644 dwl/dragresize.patch create mode 100644 dwl/dwl-v0.7_bak/CHANGELOG.md create mode 100644 dwl/dwl-v0.7_bak/LICENSE create mode 100644 dwl/dwl-v0.7_bak/LICENSE.dwm create mode 100644 dwl/dwl-v0.7_bak/LICENSE.sway create mode 100644 dwl/dwl-v0.7_bak/LICENSE.tinywl create mode 100644 dwl/dwl-v0.7_bak/Makefile create mode 100644 dwl/dwl-v0.7_bak/README.md create mode 100644 dwl/dwl-v0.7_bak/client.h create mode 100644 dwl/dwl-v0.7_bak/config.def.h create mode 100644 dwl/dwl-v0.7_bak/config.def.h.orig create mode 100644 dwl/dwl-v0.7_bak/config.def.h.rej create mode 100644 dwl/dwl-v0.7_bak/config.h create mode 100644 dwl/dwl-v0.7_bak/config.mk create mode 100644 dwl/dwl-v0.7_bak/cursor-shape-v1-protocol.h create mode 100755 dwl/dwl-v0.7_bak/dwl create mode 100644 dwl/dwl-v0.7_bak/dwl.1 create mode 100644 dwl/dwl-v0.7_bak/dwl.c create mode 100644 dwl/dwl-v0.7_bak/dwl.c.orig create mode 100644 dwl/dwl-v0.7_bak/dwl.desktop create mode 100644 dwl/dwl-v0.7_bak/dwl.o create mode 100644 dwl/dwl-v0.7_bak/pointer-constraints-unstable-v1-protocol.h create mode 100644 dwl/dwl-v0.7_bak/protocols/wlr-layer-shell-unstable-v1.xml create mode 100644 dwl/dwl-v0.7_bak/protocols/wlr-output-power-management-unstable-v1.xml create mode 100644 dwl/dwl-v0.7_bak/swallow.patch create mode 100644 dwl/dwl-v0.7_bak/util.c create mode 100644 dwl/dwl-v0.7_bak/util.h create mode 100644 dwl/dwl-v0.7_bak/util.o create mode 100644 dwl/dwl-v0.7_bak/wlr-layer-shell-unstable-v1-protocol.h create mode 100644 dwl/dwl-v0.7_bak/wlr-output-power-management-unstable-v1-protocol.h create mode 100644 dwl/dwl-v0.7_bak/xdg-shell-protocol.h create mode 100644 dwl/hide-cursor-when-typing.patch diff --git a/dwl/alwayscenter.patch b/dwl/alwayscenter.patch new file mode 100644 index 00000000..962745de --- /dev/null +++ b/dwl/alwayscenter.patch @@ -0,0 +1,25 @@ +From 48110f0443c8e1ddcd56b6fed5da46535024919c Mon Sep 17 00:00:00 2001 +From: Guido Cella +Date: Tue, 13 Jan 2026 21:17:22 +0100 +Subject: [PATCH] center floating windows + +--- + dwl.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/dwl.c b/dwl.c +index 44f3ad9..72714f8 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -2414,6 +2414,8 @@ setmon(Client *c, Monitor *m, uint32_t newtags) + /* Make sure window actually overlaps with the monitor */ + resize(c, c->geom, 0); + c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ ++ c->prev.x = (m->w.width - c->prev.width) / 2 + m->m.x; ++ c->prev.y = (m->w.height - c->prev.height) / 2 + m->m.y; + setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ + setfloating(c, c->isfloating); + } +-- +2.52.0 + diff --git a/dwl/customfloat-0.8.patch b/dwl/customfloat-0.8.patch new file mode 100644 index 00000000..6f760d14 --- /dev/null +++ b/dwl/customfloat-0.8.patch @@ -0,0 +1,95 @@ +From 96125a70b7525740a42803f1faa666ca37b9433f Mon Sep 17 00:00:00 2001 +From: A Frederick Christensen +Date: Mon, 23 Feb 2026 09:06:33 -0600 +Subject: [PATCH] Apply customfloat patch + +--- + config.def.h | 7 ++++--- + dwl.c | 26 ++++++++++++++++++++++++++ + 2 files changed, 30 insertions(+), 3 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..16afbb3 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,7 @@ static const float focuscolor[] = COLOR(0x005577ff); + static const float urgentcolor[] = COLOR(0xff0000ff); + /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ + static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */ ++static const int respect_monitor_reserved_area = 0; /* 1 to monitor center while respecting the monitor's reserved area, 0 to monitor center */ + + /* tagging - TAGCOUNT must be no greater than 31 */ + #define TAGCOUNT (9) +@@ -21,9 +22,9 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca + static int log_level = WLR_ERROR; + + static const Rule rules[] = { +- /* app_id title tags mask isfloating monitor */ +- { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ +- { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ ++ /* app_id title tags mask isfloating monitor x y width height */ ++ { "Gimp_EXAMPLE", NULL, 0, 1, -1, -1, -1, 1000, 0.75 }, /* Start on currently visible tags floating, not tiled */ ++ { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1, -1, -1, -1, -1 }, /* Start on ONLY tag "9" */ + /* default/example rule: can be changed but cannot be eliminated; at least one rule must exist */ + }; + +diff --git a/dwl.c b/dwl.c +index 44f3ad9..801696a 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -228,6 +228,10 @@ typedef struct { + uint32_t tags; + int isfloating; + int monitor; ++ int x; ++ int y; ++ float w; ++ float h; + } Rule; + + typedef struct { +@@ -482,6 +486,11 @@ applyrules(Client *c) + int i; + const Rule *r; + Monitor *mon = selmon, *m; ++ int newwidth; ++ int newheight; ++ int newx; ++ int newy; ++ int apply_resize = 0; + + appid = client_get_appid(c); + title = client_get_title(c); +@@ -495,12 +504,29 @@ applyrules(Client *c) + wl_list_for_each(m, &mons, link) { + if (r->monitor == i++) + mon = m; ++ if (c->isfloating || !mon->lt[mon->sellt]->arrange) { ++ /* client is floating or in floating layout */ ++ struct wlr_box b = respect_monitor_reserved_area ? mon->w : mon->m; ++ newwidth = (int)round((r->w >= 0) ? (r->w <= 1 ? b.width * r->w : r->w) : c->geom.width); ++ newheight = (int)round((r->h >= 0) ? (r->h <= 1 ? b.height * r->h : r->h) : c->geom.height); ++ newx = (int)round((r->x >= 0) ? (r->x <= 1 ? b.width * r->x + b.x : r->x + b.x) : c->geom.x); ++ newy = (int)round((r->y >= 0) ? (r->y <= 1 ? b.height * r->y + b.y : r->y + b.y) : c->geom.y); ++ apply_resize = 1; ++ } + } + } + } + + c->isfloating |= client_is_float_type(c); + setmon(c, mon, newtags); ++ if (apply_resize) { ++ resize(c, (struct wlr_box){ ++ .x = newx, ++ .y = newy, ++ .width = newwidth, ++ .height = newheight, ++ }, 1); ++ } + } + + void +-- +2.52.0 + diff --git a/dwl/dragresize.patch b/dwl/dragresize.patch new file mode 100644 index 00000000..1e4cfe01 --- /dev/null +++ b/dwl/dragresize.patch @@ -0,0 +1,210 @@ +From 83ae7d4816a49f46063ab16ffecd32b2e7e61784 Mon Sep 17 00:00:00 2001 +From: choc +Date: Fri, 15 Sep 2023 11:45:16 +0800 +Subject: [PATCH] dragresize: implement rio-like window resizing + +select window to resize then drag out an area for it to occupy +--- + dwl.c | 132 +++++++++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 98 insertions(+), 34 deletions(-) + +diff --git a/dwl.c b/dwl.c +index dc0437e..843aa7a 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -80,7 +80,7 @@ + #define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) + + /* enums */ +-enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ ++enum { CurNormal, CurPressed, CurSelect, CurMove, CurResize, CurBind }; /* cursor */ + enum { XDGShell, LayerShell, X11 }; /* client types */ + enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ + #ifdef XWAYLAND +@@ -603,15 +603,21 @@ buttonpress(struct wl_listener *listener, void *data) + + switch (event->state) { + case WLR_BUTTON_PRESSED: +- cursor_mode = CurPressed; + selmon = xytomon(cursor->x, cursor->y); +- if (locked) ++ if (locked) { ++ cursor_mode = CurPressed; + break; ++ } + +- /* Change focus if the button was _pressed_ over a client */ +- xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); +- if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) +- focusclient(c, 1); ++ if (cursor_mode == CurNormal) ++ cursor_mode = CurPressed; ++ ++ if (cursor_mode != CurResize) { ++ /* Change focus if the button was _pressed_ over a client */ ++ xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); ++ if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) ++ focusclient(c, 1); ++ } + + keyboard = wlr_seat_get_keyboard(seat); + mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; +@@ -624,17 +630,42 @@ buttonpress(struct wl_listener *listener, void *data) + } + break; + case WLR_BUTTON_RELEASED: ++ if (locked) { ++ cursor_mode = CurNormal; ++ break; ++ } + /* If you released any buttons, we exit interactive move/resize mode. */ +- /* TODO should reset to the pointer focus's current setcursor */ +- if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { +- wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); ++ switch (cursor_mode) { ++ case CurPressed: + cursor_mode = CurNormal; +- /* Drop the window off on its new monitor */ +- selmon = xytomon(cursor->x, cursor->y); +- setmon(grabc, selmon, 0); ++ case CurNormal: ++ break; ++ case CurSelect: + return; +- } else { ++ case CurResize: ++ /* a label can only be part of a statement - Wpedantic */ ++ { ++ int nw = abs((int) cursor->x - grabcx); ++ int nh = abs((int) cursor->y - grabcy); ++ if (nw > 1 && nh > 1) { ++ setfloating(grabc, 1); ++ resize(grabc, (struct wlr_box){.x = MIN(ROUND(cursor->x), grabcx), ++ .y = MIN(ROUND(cursor->y), grabcy), ++ .width = nw, .height = nh}, 1); ++ } ++ } ++ /* fallthrough */ ++ default: ++ /* TODO should reset to the pointer focus's current setcursor */ ++ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); ++ /* Drop the window off on its new monitor */ ++ if (grabc && cursor_mode != CurBind) { ++ selmon = xytomon(cursor->x, cursor->y); ++ setmon(grabc, selmon, 0); ++ grabc = NULL; ++ } + cursor_mode = CurNormal; ++ return; + } + break; + } +@@ -1815,15 +1846,33 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d + wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); + + /* If we are currently grabbing the mouse, handle and return */ +- if (cursor_mode == CurMove) { ++ switch (cursor_mode) { ++ case CurSelect: ++ return; ++ case CurMove: + /* Move the grabbed client to the new position. */ + resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy, + .width = grabc->geom.width, .height = grabc->geom.height}, 1); + return; +- } else if (cursor_mode == CurResize) { +- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y, +- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1); +- return; ++ case CurResize: ++ { ++ int w, h, x, y; ++ if (!grabc) ++ return; ++ w = abs(grabcx - (int)round(cursor->x)); ++ h = abs(grabcy - (int)round(cursor->y)); ++ x = MIN(grabcx, (int)round(cursor->x)) - grabc->geom.x; ++ y = MIN(grabcy, (int)round(cursor->y)) - grabc->geom.y; ++ wlr_scene_rect_set_size(grabc->border[0], w, grabc->bw); ++ wlr_scene_rect_set_size(grabc->border[1], w, grabc->bw); ++ wlr_scene_rect_set_size(grabc->border[2], grabc->bw, h - 2 * grabc->bw); ++ wlr_scene_rect_set_size(grabc->border[3], grabc->bw, h - 2 * grabc->bw); ++ wlr_scene_node_set_position(&grabc->border[0]->node, x, y); ++ wlr_scene_node_set_position(&grabc->border[1]->node, x, y + h - grabc->bw); ++ wlr_scene_node_set_position(&grabc->border[2]->node, x, y + grabc->bw); ++ wlr_scene_node_set_position(&grabc->border[3]->node, x + w - grabc->bw, y + grabc->bw); ++ return; ++ } + } + + /* If there's no client surface under the cursor, set the cursor image to a +@@ -1853,29 +1902,43 @@ motionrelative(struct wl_listener *listener, void *data) + void + moveresize(const Arg *arg) + { +- if (cursor_mode != CurNormal && cursor_mode != CurPressed) +- return; +- xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); +- if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) ++ /* Consider global select bool instead of this + CurSelect enum */ ++ bool selected = (cursor_mode == CurSelect); ++ if (!selected) { ++ if (cursor_mode != CurNormal && cursor_mode != CurPressed) ++ return; ++ xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); ++ } ++ ++ if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) { ++ grabc = NULL; ++ cursor_mode = CurNormal; + return; ++ } + +- /* Float the window and tell motionnotify to grab it */ +- setfloating(grabc, 1); ++ /* TODO: factor out selected bool */ + switch (cursor_mode = arg->ui) { ++ case CurResize: ++ if (!selected) break; ++ grabcx = ROUND(cursor->x); ++ grabcy = ROUND(cursor->y); ++ wlr_cursor_set_xcursor(cursor, cursor_mgr, "tcross"); ++ return; + case CurMove: + grabcx = (int)round(cursor->x) - grabc->geom.x; + grabcy = (int)round(cursor->y) - grabc->geom.y; ++ setfloating(grabc, 1); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); +- break; +- case CurResize: +- /* Doesn't work for X11 output - the next absolute motion event +- * returns the cursor to where it started */ +- wlr_cursor_warp_closest(cursor, NULL, +- grabc->geom.x + grabc->geom.width, +- grabc->geom.y + grabc->geom.height); +- wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize"); +- break; ++ return; ++ default: ++ grabc = NULL; ++ cursor_mode = CurNormal; ++ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); ++ return; + } ++ ++ cursor_mode = CurSelect; ++ wlr_cursor_set_xcursor(cursor, cursor_mgr, "crosshair"); + } + + void +@@ -2149,6 +2212,7 @@ resize(Client *c, struct wlr_box geo, int interact) + wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); + wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); ++ wlr_scene_node_set_position(&c->border[0]->node, 0, 0); + wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); + wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); + wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); +-- +2.43.0 + diff --git a/dwl/dwl-v0.7/client.h b/dwl/dwl-v0.7/client.h index bc9cad2e..42f225f9 100644 --- a/dwl/dwl-v0.7/client.h +++ b/dwl/dwl-v0.7/client.h @@ -131,18 +131,6 @@ client_get_appid(Client *c) return c->surface.xdg->toplevel->app_id; } -static inline int -client_get_pid(Client *c) -{ - pid_t pid; -#ifdef XWAYLAND - if (client_is_x11(c)) - return c->surface.xwayland->pid; -#endif - wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); - return pid; -} - static inline void client_get_clip(Client *c, struct wlr_box *clip) { diff --git a/dwl/dwl-v0.7/config.def.h b/dwl/dwl-v0.7/config.def.h index 4cc09478..22d2171d 100644 --- a/dwl/dwl-v0.7/config.def.h +++ b/dwl/dwl-v0.7/config.def.h @@ -1,23 +1,18 @@ /* Taken from https://github.com/djpohly/dwl/issues/466 */ -#define COLOR(hex) \ - {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f, \ - ((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f} +#define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \ + ((hex >> 16) & 0xFF) / 255.0f, \ + ((hex >> 8) & 0xFF) / 255.0f, \ + (hex & 0xFF) / 255.0f } /* appearance */ -static const int sloppyfocus = 1; /* focus follows mouse */ -static const int bypass_surface_visibility = - 0; /* 1 means idle inhibitors will disable idle tracking even if it's - surface isn't visible */ -static const unsigned int borderpx = 1; /* border pixel of windows */ -static const float rootcolor[] = COLOR(0x222222ff); -static const float bordercolor[] = COLOR(0x444444ff); -static const float focuscolor[] = COLOR(0x005577ff); -static const float urgentcolor[] = COLOR(0xff0000ff); -/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old - * behavior */ -static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, - 1.0f}; /* You can also use glsl colors */ -static int enableautoswallow = - 1; /* enables autoswallowing newly spawned clients */ +static const int sloppyfocus = 1; /* focus follows mouse */ +static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const float rootcolor[] = COLOR(0x222222ff); +static const float bordercolor[] = COLOR(0x444444ff); +static const float focuscolor[] = COLOR(0x005577ff); +static const float urgentcolor[] = COLOR(0xff0000ff); +/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ +static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */ /* tagging - TAGCOUNT must be no greater than 31 */ #define TAGCOUNT (9) @@ -25,73 +20,44 @@ static int enableautoswallow = /* logging */ static int log_level = WLR_ERROR; -/* Autostart */ -static const char *const autostart[] = { - "swaybg", - "-i", - "/home/brian/Pictures/leaves.jpg", - "-m", - "fill", - NULL, - "gammastep", - "-b", - "0.95", - "-O", - "5500K", - NULL, - "foot", - "-c", - "/home/brian/.config/foot/bfoot.ini", - "/usr/bin/btop", - NULL, - - NULL /* terminate */ -}; - -/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at - * least one example) */ +/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */ static const Rule rules[] = { - /* app_id title tags mask isfloating isterm - noswallow monitor */ - /* examples: */ - {"foot", NULL, 0, 0, 1, 1, -1}, - {"Gimp_EXAMPLE", NULL, 0, 1, 0, 0, - -1}, /* Start on currently visible tags floating, not tiled */ - {"firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1}, /* Start on ONLY tag "9" */ + /* app_id title tags mask isfloating monitor */ + /* examples: */ + { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ + { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ }; /* layout(s) */ static const Layout layouts[] = { - /* symbol arrange function */ - {"[]=", tile}, - {"><>", NULL}, /* no layout function means floating behavior */ - {"[M]", monocle}, + /* symbol arrange function */ + { "[]=", tile }, + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, }; /* monitors */ /* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator - * WARNING: negative values other than (-1, -1) cause problems with Xwayland - * clients https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 - */ -/* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be - * used */ + * WARNING: negative values other than (-1, -1) cause problems with Xwayland clients + * https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 +*/ +/* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */ static const MonitorRule monrules[] = { - /* name mfact nmaster scale layout rotate/reflect x y */ - /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, - -1, -1 }, - */ - /* defaults */ - {NULL, 0.50f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1}, + /* name mfact nmaster scale layout rotate/reflect x y */ + /* example of a HiDPI laptop monitor: + { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, + */ + /* defaults */ + { NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, }; /* keyboard */ static const struct xkb_rule_names xkb_rules = { - /* can specify fields: rules, model, layout, variant, options */ - /* example: - .options = "ctrl:nocaps", - */ - .options = NULL, + /* can specify fields: rules, model, layout, variant, options */ + /* example: + .options = "ctrl:nocaps", + */ + .options = NULL, }; static const int repeat_rate = 25; @@ -111,16 +77,14 @@ LIBINPUT_CONFIG_SCROLL_2FG LIBINPUT_CONFIG_SCROLL_EDGE LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN */ -static const enum libinput_config_scroll_method scroll_method = - LIBINPUT_CONFIG_SCROLL_2FG; +static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; /* You can choose between: LIBINPUT_CONFIG_CLICK_METHOD_NONE LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER */ -static const enum libinput_config_click_method click_method = - LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; +static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; /* You can choose between: LIBINPUT_CONFIG_SEND_EVENTS_ENABLED @@ -133,131 +97,80 @@ static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE */ -static const enum libinput_config_accel_profile accel_profile = - LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; +static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; static const double accel_speed = 0.0; /* You can choose between: LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right */ -static const enum libinput_config_tap_button_map button_map = - LIBINPUT_CONFIG_TAP_MAP_LRM; +static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; /* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ -#define MODKEY WLR_MODIFIER_LOGO +#define MODKEY WLR_MODIFIER_ALT -#define TAGKEYS(KEY, SKEY, TAG) \ - {MODKEY, KEY, view, {.ui = 1 << TAG}}, \ - {MODKEY | WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG}}, \ - {MODKEY | WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG}}, { \ - MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT, SKEY, toggletag, { \ - .ui = 1 << TAG \ - } \ - } +#define TAGKEYS(KEY,SKEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} } /* helper for spawning shell commands in the pre dwm-5.0 fashion */ -#define SHCMD(cmd) \ - { \ - .v = (const char *[]) { "/bin/sh", "-c", cmd, NULL } \ - } +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } /* commands */ -static const char *termcmd[] = {"foot", NULL}; -static const char *menucmd[] = {"wmenu-run", NULL}; -static const char *librewolfcmd[] = {"librewolf-bin", NULL}; -static const char *chromiumcmd[] = {"chromium-bin", NULL}; -static const char *inkscapecmd[] = {"inkscape", NULL}; -static const char *gimpcmd[] = {"gimp", NULL}; -static const char *pcmanfmcmd[] = {"pcmanfm", NULL}; -static const char *keepassxccmd[] = {"keepassxc", NULL}; -static const char *libreofficecmd[] = {"libreoffice-bin", NULL}; -static const char *mousepadcmd[] = {"mousepad", NULL}; -static const char *virtmanagercmd[] = {"virt-manager", NULL}; -static const char *qalculatecmd[] = {"qalculate-qt", NULL}; +static const char *termcmd[] = { "foot", NULL }; +static const char *menucmd[] = { "wmenu-run", NULL }; static const Key keys[] = { - /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ - /* modifier key function argument */ - {MODKEY, XKB_KEY_Return, spawn, {.v = termcmd}}, - {MODKEY, XKB_KEY_d, spawn, {.v = menucmd}}, - {MODKEY, XKB_KEY_f, spawn, {.v = librewolfcmd}}, - {MODKEY, XKB_KEY_c, spawn, {.v = chromiumcmd}}, - {MODKEY, XKB_KEY_i, spawn, {.v = inkscapecmd}}, - {MODKEY, XKB_KEY_g, spawn, {.v = gimpcmd}}, - {MODKEY, XKB_KEY_p, spawn, {.v = pcmanfmcmd}}, - {MODKEY, XKB_KEY_k, spawn, {.v = keepassxccmd}}, - {MODKEY, XKB_KEY_n, spawn, {.v = libreofficecmd}}, - {MODKEY, XKB_KEY_m, spawn, {.v = mousepadcmd}}, - {MODKEY, XKB_KEY_v, spawn, {.v = virtmanagercmd}}, - {MODKEY, XKB_KEY_u, spawn, {.v = qalculatecmd}}, - {MODKEY, XKB_KEY_Left, setmfact, {.f = -0.025f}}, - {MODKEY, XKB_KEY_Right, setmfact, {.f = +0.025f}}, - {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Q, killclient, {0}}, - {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Escape, quit, {0}}, - {MODKEY, XKB_KEY_o, togglefloating, {0}}, - {MODKEY, XKB_KEY_j, focusstack, {.i = +1}}, - {MODKEY, XKB_KEY_k, focusstack, {.i = -1}}, - {MODKEY, XKB_KEY_i, incnmaster, {.i = +1}}, - {MODKEY, XKB_KEY_d, incnmaster, {.i = -1}}, - {MODKEY, XKB_KEY_Return, zoom, {0}}, - {MODKEY, XKB_KEY_Tab, view, {0}}, - // {MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]}}, - // {MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]}}, - // {MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]}}, - {MODKEY, XKB_KEY_space, setlayout, {0}}, - {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_f, togglefullscreen, {0}}, - {MODKEY, XKB_KEY_a, toggleswallow, {0}}, - {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow, {0}}, - {MODKEY, XKB_KEY_0, view, {.ui = ~0}}, - {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0}}, - {MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT}}, - {MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT}}, - {MODKEY | WLR_MODIFIER_SHIFT, - XKB_KEY_less, - tagmon, - {.i = WLR_DIRECTION_LEFT}}, - {MODKEY | WLR_MODIFIER_SHIFT, - XKB_KEY_greater, - tagmon, - {.i = WLR_DIRECTION_RIGHT}}, - TAGKEYS(XKB_KEY_1, XKB_KEY_exclam, 0), - TAGKEYS(XKB_KEY_2, XKB_KEY_at, 1), - TAGKEYS(XKB_KEY_3, XKB_KEY_numbersign, 2), - TAGKEYS(XKB_KEY_4, XKB_KEY_dollar, 3), - TAGKEYS(XKB_KEY_5, XKB_KEY_percent, 4), - TAGKEYS(XKB_KEY_6, XKB_KEY_asciicircum, 5), - TAGKEYS(XKB_KEY_7, XKB_KEY_ampersand, 6), - TAGKEYS(XKB_KEY_8, XKB_KEY_asterisk, 7), - TAGKEYS(XKB_KEY_9, XKB_KEY_parenleft, 8), + /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ + /* modifier key function argument */ + { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, + { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, + { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, + { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, + { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, + { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} }, + { MODKEY, XKB_KEY_Return, zoom, {0} }, + { MODKEY, XKB_KEY_Tab, view, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} }, + { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, + { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, + { MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} }, + TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0), + TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), + TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), + TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3), + TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4), + TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5), + TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6), + TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7), + TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8), + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} }, - /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ - {WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_Terminate_Server, quit, {0}}, -/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is - * do not remove them. - */ -#define CHVT(n) \ - { \ - WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_XF86Switch_VT_##n, chvt, { \ - .ui = (n) \ - } \ - } - CHVT(1), - CHVT(2), - CHVT(3), - CHVT(4), - CHVT(5), - CHVT(6), - CHVT(7), - CHVT(8), - CHVT(9), - CHVT(10), - CHVT(11), - CHVT(12), + /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ + { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} }, + /* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is + * do not remove them. + */ +#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} } + CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6), + CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12), }; static const Button buttons[] = { - {MODKEY, BTN_LEFT, moveresize, {.ui = CurMove}}, - {MODKEY, BTN_MIDDLE, togglefloating, {0}}, - {MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize}}, + { MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} }, + { MODKEY, BTN_MIDDLE, togglefloating, {0} }, + { MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} }, }; diff --git a/dwl/dwl-v0.7/config.mk b/dwl/dwl-v0.7/config.mk index b2d0221b..1e0b810f 100644 --- a/dwl/dwl-v0.7/config.mk +++ b/dwl/dwl-v0.7/config.mk @@ -11,7 +11,7 @@ DATADIR = $(PREFIX)/share XWAYLAND = XLIBS = # Uncomment to build XWayland support -# XWAYLAND = -DXWAYLAND -# XLIBS = xcb xcb-icccm +#XWAYLAND = -DXWAYLAND +#XLIBS = xcb xcb-icccm CC = gcc diff --git a/dwl/dwl-v0.7/dwl.c b/dwl/dwl-v0.7/dwl.c index fd2e3b2c..a2711f67 100644 --- a/dwl/dwl-v0.7/dwl.c +++ b/dwl/dwl-v0.7/dwl.c @@ -70,205 +70,176 @@ #include "util.h" /* macros */ -#define MAX(A, B) ((A) > (B) ? (A) : (B)) -#define MIN(A, B) ((A) < (B) ? (A) : (B)) -#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) -#define VISIBLEON(C, M) \ - ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]) && \ - !(C)->swallowedby) -#define LENGTH(X) (sizeof X / sizeof X[0]) -#define END(A) ((A) + LENGTH(A)) -#define TAGMASK ((1u << TAGCOUNT) - 1) -#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) -#define LISTEN_STATIC(E, H) \ - do { \ - static struct wl_listener _l = {.notify = (H)}; \ - wl_signal_add((E), &_l); \ - } while (0) -#define BORDERPX(C) (borderpx + ((C)->swallowing ? (C)->swallowing->bw : 0)) +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) +#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define END(A) ((A) + LENGTH(A)) +#define TAGMASK ((1u << TAGCOUNT) - 1) +#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) +#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ -enum { XDGShell, LayerShell, X11 }; /* client types */ -enum { - LyrBg, - LyrBottom, - LyrTile, - LyrFloat, - LyrTop, - LyrFS, - LyrOverlay, - LyrBlock, - NUM_LAYERS -}; /* scene layers */ +enum { XDGShell, LayerShell, X11 }; /* client types */ +enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND -enum { - NetWMWindowTypeDialog, - NetWMWindowTypeSplash, - NetWMWindowTypeToolbar, - NetWMWindowTypeUtility, - NetLast -}; /* EWMH atoms */ +enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, + NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ #endif typedef union { - int i; - uint32_t ui; - float f; - const void *v; + int i; + uint32_t ui; + float f; + const void *v; } Arg; typedef struct { - unsigned int mod; - unsigned int button; - void (*func)(const Arg *); - const Arg arg; + unsigned int mod; + unsigned int button; + void (*func)(const Arg *); + const Arg arg; } Button; typedef struct Monitor Monitor; -typedef struct Client Client; -struct Client { - /* Must keep these three elements in this order */ - unsigned int type; /* XDGShell or X11* */ - struct wlr_box geom; /* layout-relative, includes border */ - Monitor *mon; - struct wlr_scene_tree *scene; - struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ - struct wlr_scene_tree *scene_surface; - struct wl_list link; - struct wl_list flink; - union { - struct wlr_xdg_surface *xdg; - struct wlr_xwayland_surface *xwayland; - } surface; - struct wlr_xdg_toplevel_decoration_v1 *decoration; - struct wl_listener commit; - struct wl_listener map; - struct wl_listener maximize; - struct wl_listener unmap; - struct wl_listener destroy; - struct wl_listener set_title; - struct wl_listener fullscreen; - struct wl_listener set_decoration_mode; - struct wl_listener destroy_decoration; - struct wlr_box prev; /* layout-relative, includes border */ - struct wlr_box bounds; +typedef struct { + /* Must keep these three elements in this order */ + unsigned int type; /* XDGShell or X11* */ + struct wlr_box geom; /* layout-relative, includes border */ + Monitor *mon; + struct wlr_scene_tree *scene; + struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ + struct wlr_scene_tree *scene_surface; + struct wl_list link; + struct wl_list flink; + union { + struct wlr_xdg_surface *xdg; + struct wlr_xwayland_surface *xwayland; + } surface; + struct wlr_xdg_toplevel_decoration_v1 *decoration; + struct wl_listener commit; + struct wl_listener map; + struct wl_listener maximize; + struct wl_listener unmap; + struct wl_listener destroy; + struct wl_listener set_title; + struct wl_listener fullscreen; + struct wl_listener set_decoration_mode; + struct wl_listener destroy_decoration; + struct wlr_box prev; /* layout-relative, includes border */ + struct wlr_box bounds; #ifdef XWAYLAND - struct wl_listener activate; - struct wl_listener associate; - struct wl_listener dissociate; - struct wl_listener configure; - struct wl_listener set_hints; + struct wl_listener activate; + struct wl_listener associate; + struct wl_listener dissociate; + struct wl_listener configure; + struct wl_listener set_hints; #endif - unsigned int bw; - uint32_t tags; - int isfloating, isurgent, isfullscreen; - int isterm, noswallow; - uint32_t resize; /* configure serial of a pending resize */ - pid_t pid; - Client *swallowing; /* client being hidden */ - Client *swallowedby; -}; + unsigned int bw; + uint32_t tags; + int isfloating, isurgent, isfullscreen; + uint32_t resize; /* configure serial of a pending resize */ +} Client; typedef struct { - uint32_t mod; - xkb_keysym_t keysym; - void (*func)(const Arg *); - const Arg arg; + uint32_t mod; + xkb_keysym_t keysym; + void (*func)(const Arg *); + const Arg arg; } Key; typedef struct { - struct wl_list link; - struct wlr_keyboard_group *wlr_group; + struct wl_list link; + struct wlr_keyboard_group *wlr_group; - int nsyms; - const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ - uint32_t mods; /* invalid if nsyms == 0 */ - struct wl_event_source *key_repeat_source; + int nsyms; + const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ + uint32_t mods; /* invalid if nsyms == 0 */ + struct wl_event_source *key_repeat_source; - struct wl_listener modifiers; - struct wl_listener key; - struct wl_listener destroy; + struct wl_listener modifiers; + struct wl_listener key; + struct wl_listener destroy; } KeyboardGroup; typedef struct { - /* Must keep these three elements in this order */ - unsigned int type; /* LayerShell */ - struct wlr_box geom; - Monitor *mon; - struct wlr_scene_tree *scene; - struct wlr_scene_tree *popups; - struct wlr_scene_layer_surface_v1 *scene_layer; - struct wl_list link; - int mapped; - struct wlr_layer_surface_v1 *layer_surface; + /* Must keep these three elements in this order */ + unsigned int type; /* LayerShell */ + struct wlr_box geom; + Monitor *mon; + struct wlr_scene_tree *scene; + struct wlr_scene_tree *popups; + struct wlr_scene_layer_surface_v1 *scene_layer; + struct wl_list link; + int mapped; + struct wlr_layer_surface_v1 *layer_surface; - struct wl_listener destroy; - struct wl_listener unmap; - struct wl_listener surface_commit; + struct wl_listener destroy; + struct wl_listener unmap; + struct wl_listener surface_commit; } LayerSurface; typedef struct { - const char *symbol; - void (*arrange)(Monitor *); + const char *symbol; + void (*arrange)(Monitor *); } Layout; struct Monitor { - struct wl_list link; - struct wlr_output *wlr_output; - struct wlr_scene_output *scene_output; - struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ - struct wl_listener frame; - struct wl_listener destroy; - struct wl_listener request_state; - struct wl_listener destroy_lock_surface; - struct wlr_session_lock_surface_v1 *lock_surface; - struct wlr_box m; /* monitor area, layout-relative */ - struct wlr_box w; /* window area, layout-relative */ - struct wl_list layers[4]; /* LayerSurface.link */ - const Layout *lt[2]; - unsigned int seltags; - unsigned int sellt; - uint32_t tagset[2]; - float mfact; - int gamma_lut_changed; - int nmaster; - char ltsymbol[16]; - int asleep; + struct wl_list link; + struct wlr_output *wlr_output; + struct wlr_scene_output *scene_output; + struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ + struct wl_listener frame; + struct wl_listener destroy; + struct wl_listener request_state; + struct wl_listener destroy_lock_surface; + struct wlr_session_lock_surface_v1 *lock_surface; + struct wlr_box m; /* monitor area, layout-relative */ + struct wlr_box w; /* window area, layout-relative */ + struct wl_list layers[4]; /* LayerSurface.link */ + const Layout *lt[2]; + unsigned int seltags; + unsigned int sellt; + uint32_t tagset[2]; + float mfact; + int gamma_lut_changed; + int nmaster; + char ltsymbol[16]; + int asleep; }; typedef struct { - const char *name; - float mfact; - int nmaster; - float scale; - const Layout *lt; - enum wl_output_transform rr; - int x, y; + const char *name; + float mfact; + int nmaster; + float scale; + const Layout *lt; + enum wl_output_transform rr; + int x, y; } MonitorRule; typedef struct { - struct wlr_pointer_constraint_v1 *constraint; - struct wl_listener destroy; + struct wlr_pointer_constraint_v1 *constraint; + struct wl_listener destroy; } PointerConstraint; typedef struct { - const char *id; - const char *title; - uint32_t tags; - int isfloating; - int isterm; - int noswallow; - int monitor; + const char *id; + const char *title; + uint32_t tags; + int isfloating; + int monitor; } Rule; typedef struct { - struct wlr_scene_tree *scene; + struct wlr_scene_tree *scene; - struct wlr_session_lock_v1 *lock; - struct wl_listener new_surface; - struct wl_listener unlock; - struct wl_listener destroy; + struct wlr_session_lock_v1 *lock; + struct wl_listener new_surface; + struct wl_listener unlock; + struct wl_listener destroy; } SessionLock; /* function declarations */ @@ -276,9 +247,8 @@ static void applybounds(Client *c, struct wlr_box *bbox); static void applyrules(Client *c); static void arrange(Monitor *m); static void arrangelayer(Monitor *m, struct wl_list *list, - struct wlr_box *usable_area, int exclusive); + struct wlr_box *usable_area, int exclusive); static void arrangelayers(Monitor *m); -static void autostartexec(void); static void axisnotify(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data); static void chvt(const Arg *arg); @@ -334,18 +304,15 @@ static void mapnotify(struct wl_listener *listener, void *data); static void maximizenotify(struct wl_listener *listener, void *data); static void monocle(Monitor *m); static void motionabsolute(struct wl_listener *listener, void *data); -static void motionnotify(uint32_t time, struct wlr_input_device *device, - double sx, double sy, double sx_unaccel, - double sy_unaccel); +static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx, + double sy, double sx_unaccel, double sy_unaccel); static void motionrelative(struct wl_listener *listener, void *data); static void moveresize(const Arg *arg); static void outputmgrapply(struct wl_listener *listener, void *data); -static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, - int test); +static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); static void outputmgrtest(struct wl_listener *listener, void *data); -static pid_t parentpid(pid_t pid); -static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, - double sy, uint32_t time); +static void pointerfocus(Client *c, struct wlr_surface *surface, + double sx, double sy, uint32_t time); static void printstatus(void); static void powermgrsetmode(struct wl_listener *listener, void *data); static void quit(const Arg *arg); @@ -368,15 +335,11 @@ static void setsel(struct wl_listener *listener, void *data); static void setup(void); static void spawn(const Arg *arg); static void startdrag(struct wl_listener *listener, void *data); -static void swallow(Client *c, Client *toswallow); static void tag(const Arg *arg); static void tagmon(const Arg *arg); -static Client *termforwin(Client *c); static void tile(Monitor *m); static void togglefloating(const Arg *arg); static void togglefullscreen(const Arg *arg); -static void toggleswallow(const Arg *arg); -static void toggleautoswallow(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unlocksession(struct wl_listener *listener, void *data); @@ -390,7 +353,7 @@ static void virtualkeyboard(struct wl_listener *listener, void *data); static void virtualpointer(struct wl_listener *listener, void *data); static Monitor *xytomon(double x, double y); static void xytonode(double x, double y, struct wlr_surface **psurface, - Client **pc, LayerSurface **pl, double *nx, double *ny); + Client **pc, LayerSurface **pl, double *nx, double *ny); static void zoom(const Arg *arg); /* variables */ @@ -405,7 +368,7 @@ static struct wlr_scene *scene; static struct wlr_scene_tree *layers[NUM_LAYERS]; static struct wlr_scene_tree *drag_icon; /* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */ -static const int layermap[] = {LyrBg, LyrBottom, LyrTop, LyrOverlay}; +static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay }; static struct wlr_renderer *drw; static struct wlr_allocator *alloc; static struct wlr_compositor *compositor; @@ -463,9 +426,6 @@ static struct wlr_xwayland *xwayland; static xcb_atom_t netatom[NetLast]; #endif -static pid_t *autostart_pids; -static size_t autostart_len; - /* configuration, allows nested code to access above variables */ #include "config.h" @@ -473,2813 +433,2783 @@ static size_t autostart_len; #include "client.h" /* function implementations */ -void applybounds(Client *c, struct wlr_box *bbox) { - /* set minimum possible */ - c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); - c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height); +void +applybounds(Client *c, struct wlr_box *bbox) +{ + /* set minimum possible */ + c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); + c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height); - if (c->geom.x >= bbox->x + bbox->width) - c->geom.x = bbox->x + bbox->width - c->geom.width; - if (c->geom.y >= bbox->y + bbox->height) - c->geom.y = bbox->y + bbox->height - c->geom.height; - if (c->geom.x + c->geom.width <= bbox->x) - c->geom.x = bbox->x; - if (c->geom.y + c->geom.height <= bbox->y) - c->geom.y = bbox->y; + if (c->geom.x >= bbox->x + bbox->width) + c->geom.x = bbox->x + bbox->width - c->geom.width; + if (c->geom.y >= bbox->y + bbox->height) + c->geom.y = bbox->y + bbox->height - c->geom.height; + if (c->geom.x + c->geom.width <= bbox->x) + c->geom.x = bbox->x; + if (c->geom.y + c->geom.height <= bbox->y) + c->geom.y = bbox->y; } -void applyrules(Client *c) { - /* rule matching */ - const char *appid, *title; - uint32_t newtags = 0; - int i; - const Rule *r; - Monitor *mon = selmon, *m; +void +applyrules(Client *c) +{ + /* rule matching */ + const char *appid, *title; + uint32_t newtags = 0; + int i; + const Rule *r; + Monitor *mon = selmon, *m; - c->isfloating = client_is_float_type(c); - if (!(appid = client_get_appid(c))) - appid = broken; - if (!(title = client_get_title(c))) - title = broken; + c->isfloating = client_is_float_type(c); + if (!(appid = client_get_appid(c))) + appid = broken; + if (!(title = client_get_title(c))) + title = broken; - c->pid = client_get_pid(c); - - for (r = rules; r < END(rules); r++) { - if ((!r->title || strstr(title, r->title)) && - (!r->id || strstr(appid, r->id))) { - c->isfloating = r->isfloating; - newtags |= r->tags; - c->isterm = r->isterm; - c->noswallow = r->noswallow; - i = 0; - wl_list_for_each(m, &mons, link) { - if (r->monitor == i++) - mon = m; - } - } - } - if (enableautoswallow && !c->noswallow && !c->isfloating && - !c->surface.xdg->initial_commit) { - Client *p = termforwin(c); - if (p) - swallow(c, p); - } - setmon(c, mon, newtags); + for (r = rules; r < END(rules); r++) { + if ((!r->title || strstr(title, r->title)) + && (!r->id || strstr(appid, r->id))) { + c->isfloating = r->isfloating; + newtags |= r->tags; + i = 0; + wl_list_for_each(m, &mons, link) { + if (r->monitor == i++) + mon = m; + } + } + } + setmon(c, mon, newtags); } -void arrange(Monitor *m) { - Client *c; +void +arrange(Monitor *m) +{ + Client *c; - if (!m->wlr_output->enabled) - return; + if (!m->wlr_output->enabled) + return; - wl_list_for_each(c, &clients, link) { - if (c->mon == m) { - wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); - client_set_suspended(c, !VISIBLEON(c, m)); - } - } + wl_list_for_each(c, &clients, link) { + if (c->mon == m) { + wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); + client_set_suspended(c, !VISIBLEON(c, m)); + } + } - wlr_scene_node_set_enabled(&m->fullscreen_bg->node, - (c = focustop(m)) && c->isfullscreen); + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, + (c = focustop(m)) && c->isfullscreen); - strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); - /* We move all clients (except fullscreen and unmanaged) to LyrTile while - * in floating layout to avoid "real" floating clients be always on top */ - wl_list_for_each(c, &clients, link) { - if (c->mon != m || c->scene->node.parent == layers[LyrFS]) - continue; + /* We move all clients (except fullscreen and unmanaged) to LyrTile while + * in floating layout to avoid "real" floating clients be always on top */ + wl_list_for_each(c, &clients, link) { + if (c->mon != m || c->scene->node.parent == layers[LyrFS]) + continue; - wlr_scene_node_reparent( - &c->scene->node, - (!m->lt[m->sellt]->arrange && c->isfloating) ? layers[LyrTile] - : (m->lt[m->sellt]->arrange && c->isfloating) ? layers[LyrFloat] - : c->scene->node.parent); - } + wlr_scene_node_reparent(&c->scene->node, + (!m->lt[m->sellt]->arrange && c->isfloating) + ? layers[LyrTile] + : (m->lt[m->sellt]->arrange && c->isfloating) + ? layers[LyrFloat] + : c->scene->node.parent); + } - if (m->lt[m->sellt]->arrange) - m->lt[m->sellt]->arrange(m); - motionnotify(0, NULL, 0, 0, 0, 0); - checkidleinhibitor(NULL); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); + motionnotify(0, NULL, 0, 0, 0, 0); + checkidleinhibitor(NULL); } -void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, - int exclusive) { - LayerSurface *l; - struct wlr_box full_area = m->m; +void +arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) +{ + LayerSurface *l; + struct wlr_box full_area = m->m; - wl_list_for_each(l, list, link) { - struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + wl_list_for_each(l, list, link) { + struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; - if (exclusive != (layer_surface->current.exclusive_zone > 0)) - continue; + if (exclusive != (layer_surface->current.exclusive_zone > 0)) + continue; - wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, - usable_area); - wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, - l->scene->node.y); - l->geom.x = l->scene->node.x; - l->geom.y = l->scene->node.y; - } + wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); + wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, l->scene->node.y); + l->geom.x = l->scene->node.x; + l->geom.y = l->scene->node.y; + } } -void arrangelayers(Monitor *m) { - int i; - struct wlr_box usable_area = m->m; - LayerSurface *l; - uint32_t layers_above_shell[] = { - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - ZWLR_LAYER_SHELL_V1_LAYER_TOP, - }; - if (!m->wlr_output->enabled) - return; +void +arrangelayers(Monitor *m) +{ + int i; + struct wlr_box usable_area = m->m; + LayerSurface *l; + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + if (!m->wlr_output->enabled) + return; - /* Arrange exclusive surfaces from top->bottom */ - for (i = 3; i >= 0; i--) - arrangelayer(m, &m->layers[i], &usable_area, 1); + /* Arrange exclusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer(m, &m->layers[i], &usable_area, 1); - if (!wlr_box_equal(&usable_area, &m->w)) { - m->w = usable_area; - arrange(m); - } + if (!wlr_box_equal(&usable_area, &m->w)) { + m->w = usable_area; + arrange(m); + } - /* Arrange non-exlusive surfaces from top->bottom */ - for (i = 3; i >= 0; i--) - arrangelayer(m, &m->layers[i], &usable_area, 0); + /* Arrange non-exlusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer(m, &m->layers[i], &usable_area, 0); - /* Find topmost keyboard interactive layer, if such a layer exists */ - for (i = 0; i < (int)LENGTH(layers_above_shell); i++) { - wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { - if (locked || !l->layer_surface->current.keyboard_interactive || - !l->mapped) - continue; - /* Deactivate the focused client. */ - focusclient(NULL, 0); - exclusive_focus = l; - client_notify_enter(l->layer_surface->surface, - wlr_seat_get_keyboard(seat)); - return; - } - } + /* Find topmost keyboard interactive layer, if such a layer exists */ + for (i = 0; i < (int)LENGTH(layers_above_shell); i++) { + wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { + if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped) + continue; + /* Deactivate the focused client. */ + focusclient(NULL, 0); + exclusive_focus = l; + client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); + return; + } + } } -void autostartexec(void) { - const char *const *p; - size_t i = 0; - - /* count entries */ - for (p = autostart; *p; autostart_len++, p++) - while (*++p) - ; - - autostart_pids = calloc(autostart_len, sizeof(pid_t)); - for (p = autostart; *p; i++, p++) { - if ((autostart_pids[i] = fork()) == 0) { - setsid(); - execvp(*p, (char *const *)p); - die("dwl: execvp %s:", *p); - } - /* skip arguments */ - while (*++p) - ; - } +void +axisnotify(struct wl_listener *listener, void *data) +{ + /* This event is forwarded by the cursor when a pointer emits an axis event, + * for example when you move the scroll wheel. */ + struct wlr_pointer_axis_event *event = data; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + /* TODO: allow usage of scroll whell for mousebindings, it can be implemented + * checking the event's orientation and the delta of the event */ + /* Notify the client with pointer focus of the axis event. */ + wlr_seat_pointer_notify_axis(seat, + event->time_msec, event->orientation, event->delta, + event->delta_discrete, event->source, event->relative_direction); } -void axisnotify(struct wl_listener *listener, void *data) { - /* This event is forwarded by the cursor when a pointer emits an axis event, - * for example when you move the scroll wheel. */ - struct wlr_pointer_axis_event *event = data; - wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); - /* TODO: allow usage of scroll whell for mousebindings, it can be implemented - * checking the event's orientation and the delta of the event */ - /* Notify the client with pointer focus of the axis event. */ - wlr_seat_pointer_notify_axis(seat, event->time_msec, event->orientation, - event->delta, event->delta_discrete, - event->source, event->relative_direction); +void +buttonpress(struct wl_listener *listener, void *data) +{ + struct wlr_pointer_button_event *event = data; + struct wlr_keyboard *keyboard; + uint32_t mods; + Client *c; + const Button *b; + + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + + switch (event->state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + cursor_mode = CurPressed; + selmon = xytomon(cursor->x, cursor->y); + if (locked) + break; + + /* Change focus if the button was _pressed_ over a client */ + xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); + if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) + focusclient(c, 1); + + keyboard = wlr_seat_get_keyboard(seat); + mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; + for (b = buttons; b < END(buttons); b++) { + if (CLEANMASK(mods) == CLEANMASK(b->mod) && + event->button == b->button && b->func) { + b->func(&b->arg); + return; + } + } + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + /* If you released any buttons, we exit interactive move/resize mode. */ + /* TODO should reset to the pointer focus's current setcursor */ + if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + cursor_mode = CurNormal; + /* Drop the window off on its new monitor */ + selmon = xytomon(cursor->x, cursor->y); + setmon(grabc, selmon, 0); + return; + } else { + cursor_mode = CurNormal; + } + break; + } + /* If the event wasn't handled by the compositor, notify the client with + * pointer focus that a button press has occurred */ + wlr_seat_pointer_notify_button(seat, + event->time_msec, event->button, event->state); } -void buttonpress(struct wl_listener *listener, void *data) { - struct wlr_pointer_button_event *event = data; - struct wlr_keyboard *keyboard; - uint32_t mods; - Client *c; - const Button *b; - - wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); - - switch (event->state) { - case WL_POINTER_BUTTON_STATE_PRESSED: - cursor_mode = CurPressed; - selmon = xytomon(cursor->x, cursor->y); - if (locked) - break; - - /* Change focus if the button was _pressed_ over a client */ - xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); - if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) - focusclient(c, 1); - - keyboard = wlr_seat_get_keyboard(seat); - mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; - for (b = buttons; b < END(buttons); b++) { - if (CLEANMASK(mods) == CLEANMASK(b->mod) && event->button == b->button && - b->func) { - b->func(&b->arg); - return; - } - } - break; - case WL_POINTER_BUTTON_STATE_RELEASED: - /* If you released any buttons, we exit interactive move/resize mode. */ - /* TODO should reset to the pointer focus's current setcursor */ - if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { - wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); - cursor_mode = CurNormal; - /* Drop the window off on its new monitor */ - selmon = xytomon(cursor->x, cursor->y); - setmon(grabc, selmon, 0); - return; - } else { - cursor_mode = CurNormal; - } - break; - } - /* If the event wasn't handled by the compositor, notify the client with - * pointer focus that a button press has occurred */ - wlr_seat_pointer_notify_button(seat, event->time_msec, event->button, - event->state); +void +chvt(const Arg *arg) +{ + wlr_session_change_vt(session, arg->ui); } -void chvt(const Arg *arg) { wlr_session_change_vt(session, arg->ui); } +void +checkidleinhibitor(struct wlr_surface *exclude) +{ + int inhibited = 0, unused_lx, unused_ly; + struct wlr_idle_inhibitor_v1 *inhibitor; + wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { + struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface); + struct wlr_scene_tree *tree = surface->data; + if (exclude != surface && (bypass_surface_visibility || (!tree + || wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) { + inhibited = 1; + break; + } + } -void checkidleinhibitor(struct wlr_surface *exclude) { - int inhibited = 0, unused_lx, unused_ly; - struct wlr_idle_inhibitor_v1 *inhibitor; - wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - struct wlr_surface *surface = - wlr_surface_get_root_surface(inhibitor->surface); - struct wlr_scene_tree *tree = surface->data; - if (exclude != surface && - (bypass_surface_visibility || - (!tree || - wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) { - inhibited = 1; - break; - } - } - - wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); + wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } -void cleanup(void) { - size_t i; +void +cleanup(void) +{ #ifdef XWAYLAND - wlr_xwayland_destroy(xwayland); - xwayland = NULL; + wlr_xwayland_destroy(xwayland); + xwayland = NULL; #endif - wl_display_destroy_clients(dpy); + wl_display_destroy_clients(dpy); + if (child_pid > 0) { + kill(-child_pid, SIGTERM); + waitpid(child_pid, NULL, 0); + } + wlr_xcursor_manager_destroy(cursor_mgr); - /* kill child processes */ - for (i = 0; i < autostart_len; i++) { - if (0 < autostart_pids[i]) { - kill(autostart_pids[i], SIGTERM); - waitpid(autostart_pids[i], NULL, 0); - } - } + destroykeyboardgroup(&kb_group->destroy, NULL); - if (child_pid > 0) { - kill(-child_pid, SIGTERM); - waitpid(child_pid, NULL, 0); - } - wlr_xcursor_manager_destroy(cursor_mgr); + /* If it's not destroyed manually it will cause a use-after-free of wlr_seat. + * Destroy it until it's fixed in the wlroots side */ + wlr_backend_destroy(backend); - destroykeyboardgroup(&kb_group->destroy, NULL); - - /* If it's not destroyed manually it will cause a use-after-free of wlr_seat. - * Destroy it until it's fixed in the wlroots side */ - wlr_backend_destroy(backend); - - wl_display_destroy(dpy); - /* Destroy after the wayland display (when the monitors are already destroyed) - to avoid destroying them with an invalid scene output. */ - wlr_scene_node_destroy(&scene->tree.node); + wl_display_destroy(dpy); + /* Destroy after the wayland display (when the monitors are already destroyed) + to avoid destroying them with an invalid scene output. */ + wlr_scene_node_destroy(&scene->tree.node); } -void cleanupmon(struct wl_listener *listener, void *data) { - Monitor *m = wl_container_of(listener, m, destroy); - LayerSurface *l, *tmp; - size_t i; +void +cleanupmon(struct wl_listener *listener, void *data) +{ + Monitor *m = wl_container_of(listener, m, destroy); + LayerSurface *l, *tmp; + size_t i; - /* m->layers[i] are intentionally not unlinked */ - for (i = 0; i < LENGTH(m->layers); i++) { - wl_list_for_each_safe(l, tmp, &m->layers[i], link) - wlr_layer_surface_v1_destroy(l->layer_surface); - } + /* m->layers[i] are intentionally not unlinked */ + for (i = 0; i < LENGTH(m->layers); i++) { + wl_list_for_each_safe(l, tmp, &m->layers[i], link) + wlr_layer_surface_v1_destroy(l->layer_surface); + } - wl_list_remove(&m->destroy.link); - wl_list_remove(&m->frame.link); - wl_list_remove(&m->link); - wl_list_remove(&m->request_state.link); - m->wlr_output->data = NULL; - wlr_output_layout_remove(output_layout, m->wlr_output); - wlr_scene_output_destroy(m->scene_output); + wl_list_remove(&m->destroy.link); + wl_list_remove(&m->frame.link); + wl_list_remove(&m->link); + wl_list_remove(&m->request_state.link); + m->wlr_output->data = NULL; + wlr_output_layout_remove(output_layout, m->wlr_output); + wlr_scene_output_destroy(m->scene_output); - closemon(m); - wlr_scene_node_destroy(&m->fullscreen_bg->node); - free(m); + closemon(m); + wlr_scene_node_destroy(&m->fullscreen_bg->node); + free(m); } -void closemon(Monitor *m) { - /* update selmon if needed and - * move closed monitor's clients to the focused one */ - Client *c; - int i = 0, nmons = wl_list_length(&mons); - if (!nmons) { - selmon = NULL; - } else if (m == selmon) { - do /* don't switch to disabled mons */ - selmon = wl_container_of(mons.next, selmon, link); - while (!selmon->wlr_output->enabled && i++ < nmons); +void +closemon(Monitor *m) +{ + /* update selmon if needed and + * move closed monitor's clients to the focused one */ + Client *c; + int i = 0, nmons = wl_list_length(&mons); + if (!nmons) { + selmon = NULL; + } else if (m == selmon) { + do /* don't switch to disabled mons */ + selmon = wl_container_of(mons.next, selmon, link); + while (!selmon->wlr_output->enabled && i++ < nmons); - if (!selmon->wlr_output->enabled) - selmon = NULL; - } + if (!selmon->wlr_output->enabled) + selmon = NULL; + } - wl_list_for_each(c, &clients, link) { - if (c->isfloating && c->geom.x > m->m.width) - resize(c, - (struct wlr_box){.x = c->geom.x - m->w.width, - .y = c->geom.y, - .width = c->geom.width, - .height = c->geom.height}, - 0); - if (c->mon == m) - setmon(c, selmon, c->tags); - } - focusclient(focustop(selmon), 1); - printstatus(); + wl_list_for_each(c, &clients, link) { + if (c->isfloating && c->geom.x > m->m.width) + resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y, + .width = c->geom.width, .height = c->geom.height}, 0); + if (c->mon == m) + setmon(c, selmon, c->tags); + } + focusclient(focustop(selmon), 1); + printstatus(); } -void commitlayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *l = wl_container_of(listener, l, surface_commit); - struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; - struct wlr_scene_tree *scene_layer = - layers[layermap[layer_surface->current.layer]]; - struct wlr_layer_surface_v1_state old_state; +void +commitlayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *l = wl_container_of(listener, l, surface_commit); + struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]]; + struct wlr_layer_surface_v1_state old_state; - if (l->layer_surface->initial_commit) { - wlr_fractional_scale_v1_notify_scale(layer_surface->surface, - l->mon->wlr_output->scale); - wlr_surface_set_preferred_buffer_scale( - layer_surface->surface, (int32_t)ceilf(l->mon->wlr_output->scale)); + if (l->layer_surface->initial_commit) { + wlr_fractional_scale_v1_notify_scale(layer_surface->surface, l->mon->wlr_output->scale); + wlr_surface_set_preferred_buffer_scale(layer_surface->surface, (int32_t)ceilf(l->mon->wlr_output->scale)); - /* Temporarily set the layer's current state to pending - * so that we can easily arrange it */ - old_state = l->layer_surface->current; - l->layer_surface->current = l->layer_surface->pending; - arrangelayers(l->mon); - l->layer_surface->current = old_state; - return; - } + /* Temporarily set the layer's current state to pending + * so that we can easily arrange it */ + old_state = l->layer_surface->current; + l->layer_surface->current = l->layer_surface->pending; + arrangelayers(l->mon); + l->layer_surface->current = old_state; + return; + } - if (layer_surface->current.committed == 0 && - l->mapped == layer_surface->surface->mapped) - return; - l->mapped = layer_surface->surface->mapped; + if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) + return; + l->mapped = layer_surface->surface->mapped; - if (scene_layer != l->scene->node.parent) { - wlr_scene_node_reparent(&l->scene->node, scene_layer); - wl_list_remove(&l->link); - wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link); - wlr_scene_node_reparent( - &l->popups->node, - (layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP - ? layers[LyrTop] - : scene_layer)); - } + if (scene_layer != l->scene->node.parent) { + wlr_scene_node_reparent(&l->scene->node, scene_layer); + wl_list_remove(&l->link); + wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link); + wlr_scene_node_reparent(&l->popups->node, (layer_surface->current.layer + < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer)); + } - arrangelayers(l->mon); + arrangelayers(l->mon); } -void commitnotify(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, commit); +void +commitnotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, commit); - if (c->surface.xdg->initial_commit) { - /* - * Get the monitor this client will be rendered on - * Note that if the user set a rule in which the client is placed on - * a different monitor based on its title this will likely select - * a wrong monitor. - */ - applyrules(c); - wlr_surface_set_preferred_buffer_scale( - client_surface(c), (int)ceilf(c->mon->wlr_output->scale)); - wlr_fractional_scale_v1_notify_scale(client_surface(c), - c->mon->wlr_output->scale); - setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ + if (c->surface.xdg->initial_commit) { + /* + * Get the monitor this client will be rendered on + * Note that if the user set a rule in which the client is placed on + * a different monitor based on its title this will likely select + * a wrong monitor. + */ + applyrules(c); + wlr_surface_set_preferred_buffer_scale(client_surface(c), (int)ceilf(c->mon->wlr_output->scale)); + wlr_fractional_scale_v1_notify_scale(client_surface(c), c->mon->wlr_output->scale); + setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ - wlr_xdg_toplevel_set_wm_capabilities( - c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); - wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); - if (c->decoration) - requestdecorationmode(&c->set_decoration_mode, c->decoration); - return; - } + wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); + if (c->decoration) + requestdecorationmode(&c->set_decoration_mode, c->decoration); + return; + } - if (client_surface(c)->mapped && c->mon) - resize(c, c->geom, (c->isfloating && !c->isfullscreen)); + if (client_surface(c)->mapped && c->mon) + resize(c, c->geom, (c->isfloating && !c->isfullscreen)); - /* mark a pending resize as completed */ - if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) - c->resize = 0; + /* mark a pending resize as completed */ + if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) + c->resize = 0; } -void commitpopup(struct wl_listener *listener, void *data) { - struct wlr_surface *surface = data; - struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); - LayerSurface *l = NULL; - Client *c = NULL; - struct wlr_box box; - int type = -1; +void +commitpopup(struct wl_listener *listener, void *data) +{ + struct wlr_surface *surface = data; + struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); + LayerSurface *l = NULL; + Client *c = NULL; + struct wlr_box box; + int type = -1; - if (!popup->base->initial_commit) - return; + if (!popup->base->initial_commit) + return; - type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); - if (!popup->parent || type < 0) - return; - popup->base->surface->data = - wlr_scene_xdg_surface_create(popup->parent->data, popup->base); - if ((l && !l->mon) || (c && !c->mon)) - return; - box = type == LayerShell ? l->mon->m : c->mon->w; - box.x -= (type == LayerShell ? l->geom.x : c->geom.x); - box.y -= (type == LayerShell ? l->geom.y : c->geom.y); - wlr_xdg_popup_unconstrain_from_box(popup, &box); - wl_list_remove(&listener->link); + type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); + if (!popup->parent || type < 0) + return; + popup->base->surface->data = wlr_scene_xdg_surface_create( + popup->parent->data, popup->base); + if ((l && !l->mon) || (c && !c->mon)) + return; + box = type == LayerShell ? l->mon->m : c->mon->w; + box.x -= (type == LayerShell ? l->geom.x : c->geom.x); + box.y -= (type == LayerShell ? l->geom.y : c->geom.y); + wlr_xdg_popup_unconstrain_from_box(popup, &box); + wl_list_remove(&listener->link); } -void createdecoration(struct wl_listener *listener, void *data) { - struct wlr_xdg_toplevel_decoration_v1 *deco = data; - Client *c = deco->toplevel->base->data; - c->decoration = deco; +void +createdecoration(struct wl_listener *listener, void *data) +{ + struct wlr_xdg_toplevel_decoration_v1 *deco = data; + Client *c = deco->toplevel->base->data; + c->decoration = deco; - LISTEN(&deco->events.request_mode, &c->set_decoration_mode, - requestdecorationmode); - LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration); + LISTEN(&deco->events.request_mode, &c->set_decoration_mode, requestdecorationmode); + LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration); - requestdecorationmode(&c->set_decoration_mode, deco); + requestdecorationmode(&c->set_decoration_mode, deco); } -void createidleinhibitor(struct wl_listener *listener, void *data) { - struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; - LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor); +void +createidleinhibitor(struct wl_listener *listener, void *data) +{ + struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; + LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor); - checkidleinhibitor(NULL); + checkidleinhibitor(NULL); } -void createkeyboard(struct wlr_keyboard *keyboard) { - /* Set the keymap to match the group keymap */ - wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); +void +createkeyboard(struct wlr_keyboard *keyboard) +{ + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); - /* Add the new keyboard to the group */ - wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); } -KeyboardGroup *createkeyboardgroup(void) { - KeyboardGroup *group = ecalloc(1, sizeof(*group)); - struct xkb_context *context; - struct xkb_keymap *keymap; +KeyboardGroup * +createkeyboardgroup(void) +{ + KeyboardGroup *group = ecalloc(1, sizeof(*group)); + struct xkb_context *context; + struct xkb_keymap *keymap; - group->wlr_group = wlr_keyboard_group_create(); - group->wlr_group->data = group; + group->wlr_group = wlr_keyboard_group_create(); + group->wlr_group->data = group; - /* Prepare an XKB keymap and assign it to the keyboard group. */ - context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, - XKB_KEYMAP_COMPILE_NO_FLAGS))) - die("failed to compile keymap"); + /* Prepare an XKB keymap and assign it to the keyboard group. */ + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS))) + die("failed to compile keymap"); - wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); + wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); - wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, - repeat_delay); + wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, repeat_delay); - /* Set up listeners for keyboard events */ - LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); - LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, - keypressmod); + /* Set up listeners for keyboard events */ + LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); + LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod); - group->key_repeat_source = - wl_event_loop_add_timer(event_loop, keyrepeat, group); + group->key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, group); - /* A seat can only have one keyboard, but this is a limitation of the - * Wayland protocol - not wlroots. We assign all connected keyboards to the - * same wlr_keyboard_group, which provides a single wlr_keyboard interface for - * all of them. Set this combined wlr_keyboard as the seat keyboard. - */ - wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); - return group; + /* A seat can only have one keyboard, but this is a limitation of the + * Wayland protocol - not wlroots. We assign all connected keyboards to the + * same wlr_keyboard_group, which provides a single wlr_keyboard interface for + * all of them. Set this combined wlr_keyboard as the seat keyboard. + */ + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + return group; } -void createlayersurface(struct wl_listener *listener, void *data) { - struct wlr_layer_surface_v1 *layer_surface = data; - LayerSurface *l; - struct wlr_surface *surface = layer_surface->surface; - struct wlr_scene_tree *scene_layer = - layers[layermap[layer_surface->pending.layer]]; +void +createlayersurface(struct wl_listener *listener, void *data) +{ + struct wlr_layer_surface_v1 *layer_surface = data; + LayerSurface *l; + struct wlr_surface *surface = layer_surface->surface; + struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]]; - if (!layer_surface->output && - !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) { - wlr_layer_surface_v1_destroy(layer_surface); - return; - } + if (!layer_surface->output + && !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) { + wlr_layer_surface_v1_destroy(layer_surface); + return; + } - l = layer_surface->data = ecalloc(1, sizeof(*l)); - l->type = LayerShell; - LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); - LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); - LISTEN(&layer_surface->events.destroy, &l->destroy, - destroylayersurfacenotify); + l = layer_surface->data = ecalloc(1, sizeof(*l)); + l->type = LayerShell; + LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); + LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); + LISTEN(&layer_surface->events.destroy, &l->destroy, destroylayersurfacenotify); - l->layer_surface = layer_surface; - l->mon = layer_surface->output->data; - l->scene_layer = - wlr_scene_layer_surface_v1_create(scene_layer, layer_surface); - l->scene = l->scene_layer->tree; - l->popups = surface->data = wlr_scene_tree_create( - layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP - ? layers[LyrTop] - : scene_layer); - l->scene->node.data = l->popups->node.data = l; + l->layer_surface = layer_surface; + l->mon = layer_surface->output->data; + l->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, layer_surface); + l->scene = l->scene_layer->tree; + l->popups = surface->data = wlr_scene_tree_create(layer_surface->current.layer + < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer); + l->scene->node.data = l->popups->node.data = l; - wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link); - wlr_surface_send_enter(surface, layer_surface->output); + wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); + wlr_surface_send_enter(surface, layer_surface->output); } -void createlocksurface(struct wl_listener *listener, void *data) { - SessionLock *lock = wl_container_of(listener, lock, new_surface); - struct wlr_session_lock_surface_v1 *lock_surface = data; - Monitor *m = lock_surface->output->data; - struct wlr_scene_tree *scene_tree = lock_surface->surface->data = - wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface); - m->lock_surface = lock_surface; +void +createlocksurface(struct wl_listener *listener, void *data) +{ + SessionLock *lock = wl_container_of(listener, lock, new_surface); + struct wlr_session_lock_surface_v1 *lock_surface = data; + Monitor *m = lock_surface->output->data; + struct wlr_scene_tree *scene_tree = lock_surface->surface->data + = wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface); + m->lock_surface = lock_surface; - wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); - wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height); + wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); + wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height); - LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, - destroylocksurface); + LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface); - if (m == selmon) - client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat)); + if (m == selmon) + client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat)); } -void createmon(struct wl_listener *listener, void *data) { - /* This event is raised by the backend when a new output (aka a display or - * monitor) becomes available. */ - struct wlr_output *wlr_output = data; - const MonitorRule *r; - size_t i; - struct wlr_output_state state; - Monitor *m; +void +createmon(struct wl_listener *listener, void *data) +{ + /* This event is raised by the backend when a new output (aka a display or + * monitor) becomes available. */ + struct wlr_output *wlr_output = data; + const MonitorRule *r; + size_t i; + struct wlr_output_state state; + Monitor *m; - if (!wlr_output_init_render(wlr_output, alloc, drw)) - return; + if (!wlr_output_init_render(wlr_output, alloc, drw)) + return; - m = wlr_output->data = ecalloc(1, sizeof(*m)); - m->wlr_output = wlr_output; + m = wlr_output->data = ecalloc(1, sizeof(*m)); + m->wlr_output = wlr_output; - for (i = 0; i < LENGTH(m->layers); i++) - wl_list_init(&m->layers[i]); + for (i = 0; i < LENGTH(m->layers); i++) + wl_list_init(&m->layers[i]); - wlr_output_state_init(&state); - /* Initialize monitor state using configured rules */ - m->tagset[0] = m->tagset[1] = 1; - for (r = monrules; r < END(monrules); r++) { - if (!r->name || strstr(wlr_output->name, r->name)) { - m->m.x = r->x; - m->m.y = r->y; - m->mfact = r->mfact; - m->nmaster = r->nmaster; - m->lt[0] = r->lt; - m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]]; - strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); - wlr_output_state_set_scale(&state, r->scale); - wlr_output_state_set_transform(&state, r->rr); - break; - } - } + wlr_output_state_init(&state); + /* Initialize monitor state using configured rules */ + m->tagset[0] = m->tagset[1] = 1; + for (r = monrules; r < END(monrules); r++) { + if (!r->name || strstr(wlr_output->name, r->name)) { + m->m.x = r->x; + m->m.y = r->y; + m->mfact = r->mfact; + m->nmaster = r->nmaster; + m->lt[0] = r->lt; + m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]]; + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + wlr_output_state_set_scale(&state, r->scale); + wlr_output_state_set_transform(&state, r->rr); + break; + } + } - /* The mode is a tuple of (width, height, refresh rate), and each - * monitor supports only a specific set of modes. We just pick the - * monitor's preferred mode; a more sophisticated compositor would let - * the user configure it. */ - wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); + /* The mode is a tuple of (width, height, refresh rate), and each + * monitor supports only a specific set of modes. We just pick the + * monitor's preferred mode; a more sophisticated compositor would let + * the user configure it. */ + wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); - /* Set up event listeners */ - LISTEN(&wlr_output->events.frame, &m->frame, rendermon); - LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); - LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); + /* Set up event listeners */ + LISTEN(&wlr_output->events.frame, &m->frame, rendermon); + LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); + LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); - wlr_output_state_set_enabled(&state, 1); - wlr_output_commit_state(wlr_output, &state); - wlr_output_state_finish(&state); + wlr_output_state_set_enabled(&state, 1); + wlr_output_commit_state(wlr_output, &state); + wlr_output_state_finish(&state); - wl_list_insert(&mons, &m->link); - printstatus(); + wl_list_insert(&mons, &m->link); + printstatus(); - /* The xdg-protocol specifies: - * - * If the fullscreened surface is not opaque, the compositor must make - * sure that other screen content not part of the same surface tree (made - * up of subsurfaces, popups or similarly coupled surfaces) are not - * visible below the fullscreened surface. - * - */ - /* updatemons() will resize and set correct position */ - m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); - wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); + /* The xdg-protocol specifies: + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + * + */ + /* updatemons() will resize and set correct position */ + m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); - /* Adds this to the output layout in the order it was configured. - * - * The output layout utility automatically adds a wl_output global to the - * display, which Wayland clients can see to find out information about the - * output (such as DPI, scale factor, manufacturer, etc). - */ - m->scene_output = wlr_scene_output_create(scene, wlr_output); - if (m->m.x == -1 && m->m.y == -1) - wlr_output_layout_add_auto(output_layout, wlr_output); - else - wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); + /* Adds this to the output layout in the order it was configured. + * + * The output layout utility automatically adds a wl_output global to the + * display, which Wayland clients can see to find out information about the + * output (such as DPI, scale factor, manufacturer, etc). + */ + m->scene_output = wlr_scene_output_create(scene, wlr_output); + if (m->m.x == -1 && m->m.y == -1) + wlr_output_layout_add_auto(output_layout, wlr_output); + else + wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); } -void createnotify(struct wl_listener *listener, void *data) { - /* This event is raised when a client creates a new toplevel (application - * window). */ - struct wlr_xdg_toplevel *toplevel = data; - Client *c = NULL; +void +createnotify(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client creates a new toplevel (application window). */ + struct wlr_xdg_toplevel *toplevel = data; + Client *c = NULL; - /* Allocate a Client for this surface */ - c = toplevel->base->data = ecalloc(1, sizeof(*c)); - c->surface.xdg = toplevel->base; - c->bw = borderpx; + /* Allocate a Client for this surface */ + c = toplevel->base->data = ecalloc(1, sizeof(*c)); + c->surface.xdg = toplevel->base; + c->bw = borderpx; - LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); - LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); - LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify); - LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, - fullscreennotify); - LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify); - LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle); + LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); + LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); + LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify); + LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); + LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify); + LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle); } -void createpointer(struct wlr_pointer *pointer) { - struct libinput_device *device; - if (wlr_input_device_is_libinput(&pointer->base) && - (device = wlr_libinput_get_device_handle(&pointer->base))) { +void +createpointer(struct wlr_pointer *pointer) +{ + struct libinput_device *device; + if (wlr_input_device_is_libinput(&pointer->base) + && (device = wlr_libinput_get_device_handle(&pointer->base))) { - if (libinput_device_config_tap_get_finger_count(device)) { - libinput_device_config_tap_set_enabled(device, tap_to_click); - libinput_device_config_tap_set_drag_enabled(device, tap_and_drag); - libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock); - libinput_device_config_tap_set_button_map(device, button_map); - } + if (libinput_device_config_tap_get_finger_count(device)) { + libinput_device_config_tap_set_enabled(device, tap_to_click); + libinput_device_config_tap_set_drag_enabled(device, tap_and_drag); + libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock); + libinput_device_config_tap_set_button_map(device, button_map); + } - if (libinput_device_config_scroll_has_natural_scroll(device)) - libinput_device_config_scroll_set_natural_scroll_enabled( - device, natural_scrolling); + if (libinput_device_config_scroll_has_natural_scroll(device)) + libinput_device_config_scroll_set_natural_scroll_enabled(device, natural_scrolling); - if (libinput_device_config_dwt_is_available(device)) - libinput_device_config_dwt_set_enabled(device, disable_while_typing); + if (libinput_device_config_dwt_is_available(device)) + libinput_device_config_dwt_set_enabled(device, disable_while_typing); - if (libinput_device_config_left_handed_is_available(device)) - libinput_device_config_left_handed_set(device, left_handed); + if (libinput_device_config_left_handed_is_available(device)) + libinput_device_config_left_handed_set(device, left_handed); - if (libinput_device_config_middle_emulation_is_available(device)) - libinput_device_config_middle_emulation_set_enabled( - device, middle_button_emulation); + if (libinput_device_config_middle_emulation_is_available(device)) + libinput_device_config_middle_emulation_set_enabled(device, middle_button_emulation); - if (libinput_device_config_scroll_get_methods(device) != - LIBINPUT_CONFIG_SCROLL_NO_SCROLL) - libinput_device_config_scroll_set_method(device, scroll_method); + if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) + libinput_device_config_scroll_set_method (device, scroll_method); - if (libinput_device_config_click_get_methods(device) != - LIBINPUT_CONFIG_CLICK_METHOD_NONE) - libinput_device_config_click_set_method(device, click_method); + if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) + libinput_device_config_click_set_method (device, click_method); - if (libinput_device_config_send_events_get_modes(device)) - libinput_device_config_send_events_set_mode(device, send_events_mode); + if (libinput_device_config_send_events_get_modes(device)) + libinput_device_config_send_events_set_mode(device, send_events_mode); - if (libinput_device_config_accel_is_available(device)) { - libinput_device_config_accel_set_profile(device, accel_profile); - libinput_device_config_accel_set_speed(device, accel_speed); - } - } + if (libinput_device_config_accel_is_available(device)) { + libinput_device_config_accel_set_profile(device, accel_profile); + libinput_device_config_accel_set_speed(device, accel_speed); + } + } - wlr_cursor_attach_input_device(cursor, &pointer->base); + wlr_cursor_attach_input_device(cursor, &pointer->base); } -void createpointerconstraint(struct wl_listener *listener, void *data) { - PointerConstraint *pointer_constraint = - ecalloc(1, sizeof(*pointer_constraint)); - pointer_constraint->constraint = data; - LISTEN(&pointer_constraint->constraint->events.destroy, - &pointer_constraint->destroy, destroypointerconstraint); +void +createpointerconstraint(struct wl_listener *listener, void *data) +{ + PointerConstraint *pointer_constraint = ecalloc(1, sizeof(*pointer_constraint)); + pointer_constraint->constraint = data; + LISTEN(&pointer_constraint->constraint->events.destroy, + &pointer_constraint->destroy, destroypointerconstraint); } -void createpopup(struct wl_listener *listener, void *data) { - /* This event is raised when a client (either xdg-shell or layer-shell) - * creates a new popup. */ - struct wlr_xdg_popup *popup = data; - LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); +void +createpopup(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client (either xdg-shell or layer-shell) + * creates a new popup. */ + struct wlr_xdg_popup *popup = data; + LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); } -void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) { - if (active_constraint == constraint) - return; +void +cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) +{ + if (active_constraint == constraint) + return; - if (active_constraint) - wlr_pointer_constraint_v1_send_deactivated(active_constraint); + if (active_constraint) + wlr_pointer_constraint_v1_send_deactivated(active_constraint); - active_constraint = constraint; - wlr_pointer_constraint_v1_send_activated(constraint); + active_constraint = constraint; + wlr_pointer_constraint_v1_send_activated(constraint); } -void cursorframe(struct wl_listener *listener, void *data) { - /* This event is forwarded by the cursor when a pointer emits an frame - * event. Frame events are sent after regular pointer events to group - * multiple events together. For instance, two axis events may happen at the - * same time, in which case a frame event won't be sent in between. */ - /* Notify the client with pointer focus of the frame event. */ - wlr_seat_pointer_notify_frame(seat); +void +cursorframe(struct wl_listener *listener, void *data) +{ + /* This event is forwarded by the cursor when a pointer emits an frame + * event. Frame events are sent after regular pointer events to group + * multiple events together. For instance, two axis events may happen at the + * same time, in which case a frame event won't be sent in between. */ + /* Notify the client with pointer focus of the frame event. */ + wlr_seat_pointer_notify_frame(seat); } -void cursorwarptohint(void) { - Client *c = NULL; - double sx = active_constraint->current.cursor_hint.x; - double sy = active_constraint->current.cursor_hint.y; +void +cursorwarptohint(void) +{ + Client *c = NULL; + double sx = active_constraint->current.cursor_hint.x; + double sy = active_constraint->current.cursor_hint.y; - toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); - if (c && active_constraint->current.cursor_hint.enabled) { - wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, - sy + c->geom.y + c->bw); - wlr_seat_pointer_warp(active_constraint->seat, sx, sy); - } + toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); + if (c && active_constraint->current.cursor_hint.enabled) { + wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw); + wlr_seat_pointer_warp(active_constraint->seat, sx, sy); + } } -void destroydecoration(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, destroy_decoration); - c->decoration = NULL; +void +destroydecoration(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, destroy_decoration); + c->decoration = NULL; - wl_list_remove(&c->destroy_decoration.link); - wl_list_remove(&c->set_decoration_mode.link); + wl_list_remove(&c->destroy_decoration.link); + wl_list_remove(&c->set_decoration_mode.link); } -void destroydragicon(struct wl_listener *listener, void *data) { - /* Focus enter isn't sent during drag, so refocus the focused node. */ - focusclient(focustop(selmon), 1); - motionnotify(0, NULL, 0, 0, 0, 0); +void +destroydragicon(struct wl_listener *listener, void *data) +{ + /* Focus enter isn't sent during drag, so refocus the focused node. */ + focusclient(focustop(selmon), 1); + motionnotify(0, NULL, 0, 0, 0, 0); } -void destroyidleinhibitor(struct wl_listener *listener, void *data) { - /* `data` is the wlr_surface of the idle inhibitor being destroyed, - * at this point the idle inhibitor is still in the list of the manager */ - checkidleinhibitor(wlr_surface_get_root_surface(data)); +void +destroyidleinhibitor(struct wl_listener *listener, void *data) +{ + /* `data` is the wlr_surface of the idle inhibitor being destroyed, + * at this point the idle inhibitor is still in the list of the manager */ + checkidleinhibitor(wlr_surface_get_root_surface(data)); } -void destroylayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *l = wl_container_of(listener, l, destroy); +void +destroylayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *l = wl_container_of(listener, l, destroy); - wl_list_remove(&l->link); - wl_list_remove(&l->destroy.link); - wl_list_remove(&l->unmap.link); - wl_list_remove(&l->surface_commit.link); - wlr_scene_node_destroy(&l->scene->node); - wlr_scene_node_destroy(&l->popups->node); - free(l); + wl_list_remove(&l->link); + wl_list_remove(&l->destroy.link); + wl_list_remove(&l->unmap.link); + wl_list_remove(&l->surface_commit.link); + wlr_scene_node_destroy(&l->scene->node); + wlr_scene_node_destroy(&l->popups->node); + free(l); } -void destroylock(SessionLock *lock, int unlock) { - wlr_seat_keyboard_notify_clear_focus(seat); - if ((locked = !unlock)) - goto destroy; +void +destroylock(SessionLock *lock, int unlock) +{ + wlr_seat_keyboard_notify_clear_focus(seat); + if ((locked = !unlock)) + goto destroy; - wlr_scene_node_set_enabled(&locked_bg->node, 0); + wlr_scene_node_set_enabled(&locked_bg->node, 0); - focusclient(focustop(selmon), 0); - motionnotify(0, NULL, 0, 0, 0, 0); + focusclient(focustop(selmon), 0); + motionnotify(0, NULL, 0, 0, 0, 0); destroy: - wl_list_remove(&lock->new_surface.link); - wl_list_remove(&lock->unlock.link); - wl_list_remove(&lock->destroy.link); + wl_list_remove(&lock->new_surface.link); + wl_list_remove(&lock->unlock.link); + wl_list_remove(&lock->destroy.link); - wlr_scene_node_destroy(&lock->scene->node); - cur_lock = NULL; - free(lock); + wlr_scene_node_destroy(&lock->scene->node); + cur_lock = NULL; + free(lock); } -void destroylocksurface(struct wl_listener *listener, void *data) { - Monitor *m = wl_container_of(listener, m, destroy_lock_surface); - struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface; +void +destroylocksurface(struct wl_listener *listener, void *data) +{ + Monitor *m = wl_container_of(listener, m, destroy_lock_surface); + struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface; - m->lock_surface = NULL; - wl_list_remove(&m->destroy_lock_surface.link); + m->lock_surface = NULL; + wl_list_remove(&m->destroy_lock_surface.link); - if (lock_surface->surface != seat->keyboard_state.focused_surface) - return; + if (lock_surface->surface != seat->keyboard_state.focused_surface) + return; - if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { - surface = wl_container_of(cur_lock->surfaces.next, surface, link); - client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); - } else if (!locked) { - focusclient(focustop(selmon), 1); - } else { - wlr_seat_keyboard_clear_focus(seat); - } + if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { + surface = wl_container_of(cur_lock->surfaces.next, surface, link); + client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); + } else if (!locked) { + focusclient(focustop(selmon), 1); + } else { + wlr_seat_keyboard_clear_focus(seat); + } } -void destroynotify(struct wl_listener *listener, void *data) { - /* Called when the xdg_toplevel is destroyed. */ - Client *c = wl_container_of(listener, c, destroy); - wl_list_remove(&c->destroy.link); - wl_list_remove(&c->set_title.link); - wl_list_remove(&c->fullscreen.link); +void +destroynotify(struct wl_listener *listener, void *data) +{ + /* Called when the xdg_toplevel is destroyed. */ + Client *c = wl_container_of(listener, c, destroy); + wl_list_remove(&c->destroy.link); + wl_list_remove(&c->set_title.link); + wl_list_remove(&c->fullscreen.link); #ifdef XWAYLAND - if (c->type != XDGShell) { - wl_list_remove(&c->activate.link); - wl_list_remove(&c->associate.link); - wl_list_remove(&c->configure.link); - wl_list_remove(&c->dissociate.link); - wl_list_remove(&c->set_hints.link); - } else + if (c->type != XDGShell) { + wl_list_remove(&c->activate.link); + wl_list_remove(&c->associate.link); + wl_list_remove(&c->configure.link); + wl_list_remove(&c->dissociate.link); + wl_list_remove(&c->set_hints.link); + } else #endif - { - wl_list_remove(&c->commit.link); - wl_list_remove(&c->map.link); - wl_list_remove(&c->unmap.link); - } - free(c); + { + wl_list_remove(&c->commit.link); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); + } + free(c); } -void destroypointerconstraint(struct wl_listener *listener, void *data) { - PointerConstraint *pointer_constraint = - wl_container_of(listener, pointer_constraint, destroy); +void +destroypointerconstraint(struct wl_listener *listener, void *data) +{ + PointerConstraint *pointer_constraint = wl_container_of(listener, pointer_constraint, destroy); - if (active_constraint == pointer_constraint->constraint) { - cursorwarptohint(); - active_constraint = NULL; - } + if (active_constraint == pointer_constraint->constraint) { + cursorwarptohint(); + active_constraint = NULL; + } - wl_list_remove(&pointer_constraint->destroy.link); - free(pointer_constraint); + wl_list_remove(&pointer_constraint->destroy.link); + free(pointer_constraint); } -void destroysessionlock(struct wl_listener *listener, void *data) { - SessionLock *lock = wl_container_of(listener, lock, destroy); - destroylock(lock, 0); +void +destroysessionlock(struct wl_listener *listener, void *data) +{ + SessionLock *lock = wl_container_of(listener, lock, destroy); + destroylock(lock, 0); } -void destroysessionmgr(struct wl_listener *listener, void *data) { - wl_list_remove(&lock_listener.link); - wl_list_remove(&listener->link); +void +destroysessionmgr(struct wl_listener *listener, void *data) +{ + wl_list_remove(&lock_listener.link); + wl_list_remove(&listener->link); } -void destroykeyboardgroup(struct wl_listener *listener, void *data) { - KeyboardGroup *group = wl_container_of(listener, group, destroy); - wl_event_source_remove(group->key_repeat_source); - wlr_keyboard_group_destroy(group->wlr_group); - wl_list_remove(&group->key.link); - wl_list_remove(&group->modifiers.link); - wl_list_remove(&group->destroy.link); - free(group); +void +destroykeyboardgroup(struct wl_listener *listener, void *data) +{ + KeyboardGroup *group = wl_container_of(listener, group, destroy); + wl_event_source_remove(group->key_repeat_source); + wlr_keyboard_group_destroy(group->wlr_group); + wl_list_remove(&group->key.link); + wl_list_remove(&group->modifiers.link); + wl_list_remove(&group->destroy.link); + free(group); } -Monitor *dirtomon(enum wlr_direction dir) { - struct wlr_output *next; - if (!wlr_output_layout_get(output_layout, selmon->wlr_output)) - return selmon; - if ((next = wlr_output_layout_adjacent_output( - output_layout, dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) - return next->data; - if ((next = wlr_output_layout_farthest_output( - output_layout, dir ^ (WLR_DIRECTION_LEFT | WLR_DIRECTION_RIGHT), - selmon->wlr_output, selmon->m.x, selmon->m.y))) - return next->data; - return selmon; +Monitor * +dirtomon(enum wlr_direction dir) +{ + struct wlr_output *next; + if (!wlr_output_layout_get(output_layout, selmon->wlr_output)) + return selmon; + if ((next = wlr_output_layout_adjacent_output(output_layout, + dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) + return next->data; + if ((next = wlr_output_layout_farthest_output(output_layout, + dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT), + selmon->wlr_output, selmon->m.x, selmon->m.y))) + return next->data; + return selmon; } -void focusclient(Client *c, int lift) { - struct wlr_surface *old = seat->keyboard_state.focused_surface; - int unused_lx, unused_ly, old_client_type; - Client *old_c = NULL; - LayerSurface *old_l = NULL; +void +focusclient(Client *c, int lift) +{ + struct wlr_surface *old = seat->keyboard_state.focused_surface; + int unused_lx, unused_ly, old_client_type; + Client *old_c = NULL; + LayerSurface *old_l = NULL; - if (locked) - return; + if (locked) + return; - /* Raise client in stacking order if requested */ - if (c && lift) - wlr_scene_node_raise_to_top(&c->scene->node); + /* Raise client in stacking order if requested */ + if (c && lift) + wlr_scene_node_raise_to_top(&c->scene->node); - if (c && client_surface(c) == old) - return; + if (c && client_surface(c) == old) + return; - if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == - XDGShell) { - struct wlr_xdg_popup *popup, *tmp; - wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link) - wlr_xdg_popup_destroy(popup); - } + if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == XDGShell) { + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link) + wlr_xdg_popup_destroy(popup); + } - /* Put the new client atop the focus stack and select its monitor */ - if (c && !client_is_unmanaged(c)) { - wl_list_remove(&c->flink); - wl_list_insert(&fstack, &c->flink); - selmon = c->mon; - c->isurgent = 0; - client_restack_surface(c); + /* Put the new client atop the focus stack and select its monitor */ + if (c && !client_is_unmanaged(c)) { + wl_list_remove(&c->flink); + wl_list_insert(&fstack, &c->flink); + selmon = c->mon; + c->isurgent = 0; + client_restack_surface(c); - /* Don't change border color if there is an exclusive focus or we are - * handling a drag operation */ - if (!exclusive_focus && !seat->drag) - client_set_border_color(c, focuscolor); - } + /* Don't change border color if there is an exclusive focus or we are + * handling a drag operation */ + if (!exclusive_focus && !seat->drag) + client_set_border_color(c, focuscolor); + } - /* Deactivate old client if focus is changing */ - if (old && (!c || client_surface(c) != old)) { - /* If an overlay is focused, don't focus or activate the client, - * but only update its position in fstack to render its border with - * focuscolor and focus it after the overlay is closed. */ - if (old_client_type == LayerShell && - wlr_scene_node_coords(&old_l->scene->node, &unused_lx, &unused_ly) && - old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { - return; - } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) { - return; - /* Don't deactivate old client if the new one wants focus, as this causes - * issues with winecfg and probably other clients */ - } else if (old_c && !client_is_unmanaged(old_c) && - (!c || !client_wants_focus(c))) { - client_set_border_color(old_c, bordercolor); + /* Deactivate old client if focus is changing */ + if (old && (!c || client_surface(c) != old)) { + /* If an overlay is focused, don't focus or activate the client, + * but only update its position in fstack to render its border with focuscolor + * and focus it after the overlay is closed. */ + if (old_client_type == LayerShell && wlr_scene_node_coords( + &old_l->scene->node, &unused_lx, &unused_ly) + && old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { + return; + } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) { + return; + /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg + * and probably other clients */ + } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) { + client_set_border_color(old_c, bordercolor); - client_activate_surface(old, 0); - } - } - printstatus(); + client_activate_surface(old, 0); + } + } + printstatus(); - if (!c) { - /* With no client, all we have left is to clear focus */ - wlr_seat_keyboard_notify_clear_focus(seat); - return; - } + if (!c) { + /* With no client, all we have left is to clear focus */ + wlr_seat_keyboard_notify_clear_focus(seat); + return; + } - /* Change cursor surface */ - motionnotify(0, NULL, 0, 0, 0, 0); + /* Change cursor surface */ + motionnotify(0, NULL, 0, 0, 0, 0); - /* Have a client, so focus its top-level wlr_surface */ - client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); + /* Have a client, so focus its top-level wlr_surface */ + client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); - /* Activate the new client */ - client_activate_surface(client_surface(c), 1); + /* Activate the new client */ + client_activate_surface(client_surface(c), 1); } -void focusmon(const Arg *arg) { - int i = 0, nmons = wl_list_length(&mons); - if (nmons) { - do /* don't switch to disabled mons */ - selmon = dirtomon(arg->i); - while (!selmon->wlr_output->enabled && i++ < nmons); - } - focusclient(focustop(selmon), 1); +void +focusmon(const Arg *arg) +{ + int i = 0, nmons = wl_list_length(&mons); + if (nmons) { + do /* don't switch to disabled mons */ + selmon = dirtomon(arg->i); + while (!selmon->wlr_output->enabled && i++ < nmons); + } + focusclient(focustop(selmon), 1); } -void focusstack(const Arg *arg) { - /* Focus the next or previous client (in tiling order) on selmon */ - Client *c, *sel = focustop(selmon); - if (!sel || (sel->isfullscreen && !client_has_children(sel))) - return; - if (arg->i > 0) { - wl_list_for_each(c, &sel->link, link) { - if (&c->link == &clients) - continue; /* wrap past the sentinel node */ - if (VISIBLEON(c, selmon)) - break; /* found it */ - } - } else { - wl_list_for_each_reverse(c, &sel->link, link) { - if (&c->link == &clients) - continue; /* wrap past the sentinel node */ - if (VISIBLEON(c, selmon)) - break; /* found it */ - } - } - /* If only one client is visible on selmon, then c == sel */ - focusclient(c, 1); +void +focusstack(const Arg *arg) +{ + /* Focus the next or previous client (in tiling order) on selmon */ + Client *c, *sel = focustop(selmon); + if (!sel || (sel->isfullscreen && !client_has_children(sel))) + return; + if (arg->i > 0) { + wl_list_for_each(c, &sel->link, link) { + if (&c->link == &clients) + continue; /* wrap past the sentinel node */ + if (VISIBLEON(c, selmon)) + break; /* found it */ + } + } else { + wl_list_for_each_reverse(c, &sel->link, link) { + if (&c->link == &clients) + continue; /* wrap past the sentinel node */ + if (VISIBLEON(c, selmon)) + break; /* found it */ + } + } + /* If only one client is visible on selmon, then c == sel */ + focusclient(c, 1); } /* We probably should change the name of this, it sounds like * will focus the topmost client of this mon, when actually will * only return that client */ -Client *focustop(Monitor *m) { - Client *c; - wl_list_for_each(c, &fstack, flink) { - if (VISIBLEON(c, m)) - return c; - } - return NULL; +Client * +focustop(Monitor *m) +{ + Client *c; + wl_list_for_each(c, &fstack, flink) { + if (VISIBLEON(c, m)) + return c; + } + return NULL; } -void fullscreennotify(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, fullscreen); - setfullscreen(c, client_wants_fullscreen(c)); +void +fullscreennotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, fullscreen); + setfullscreen(c, client_wants_fullscreen(c)); } -void gpureset(struct wl_listener *listener, void *data) { - struct wlr_renderer *old_drw = drw; - struct wlr_allocator *old_alloc = alloc; - struct Monitor *m; - if (!(drw = wlr_renderer_autocreate(backend))) - die("couldn't recreate renderer"); +void +gpureset(struct wl_listener *listener, void *data) +{ + struct wlr_renderer *old_drw = drw; + struct wlr_allocator *old_alloc = alloc; + struct Monitor *m; + if (!(drw = wlr_renderer_autocreate(backend))) + die("couldn't recreate renderer"); - if (!(alloc = wlr_allocator_autocreate(backend, drw))) - die("couldn't recreate allocator"); + if (!(alloc = wlr_allocator_autocreate(backend, drw))) + die("couldn't recreate allocator"); - LISTEN_STATIC(&drw->events.lost, gpureset); + LISTEN_STATIC(&drw->events.lost, gpureset); - wlr_compositor_set_renderer(compositor, drw); + wlr_compositor_set_renderer(compositor, drw); - wl_list_for_each(m, &mons, link) { - wlr_output_init_render(m->wlr_output, alloc, drw); - } + wl_list_for_each(m, &mons, link) { + wlr_output_init_render(m->wlr_output, alloc, drw); + } - wlr_allocator_destroy(old_alloc); - wlr_renderer_destroy(old_drw); + wlr_allocator_destroy(old_alloc); + wlr_renderer_destroy(old_drw); } -void handlesig(int signo) { +void +handlesig(int signo) +{ + if (signo == SIGCHLD) { #ifdef XWAYLAND - siginfo_t in; - /* wlroots expects to reap the XWayland process itself, so we - * use WNOWAIT to keep the child waitable until we know it's not - * XWayland. - */ - while (!waitid(P_ALL, 0, &in, WEXITED | WNOHANG | WNOWAIT) && in.si_pid && - (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); + siginfo_t in; + /* wlroots expects to reap the XWayland process itself, so we + * use WNOWAIT to keep the child waitable until we know it's not + * XWayland. + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid + && (!xwayland || in.si_pid != xwayland->server->pid)) + waitpid(in.si_pid, NULL, 0); #else - while (waitpid(-1, NULL, WNOHANG) > 0) - ; + while (waitpid(-1, NULL, WNOHANG) > 0); #endif - if (signo == SIGCHLD) { - pid_t pid, *p, *lim; - while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { - if (pid == child_pid) - child_pid = -1; - if (!(p = autostart_pids)) - continue; - lim = &p[autostart_len]; - - for (; p < lim; p++) { - if (*p == pid) { - *p = -1; - break; - } - } - } - } else if (signo == SIGINT || signo == SIGTERM) { - quit(NULL); - } + } else if (signo == SIGINT || signo == SIGTERM) { + quit(NULL); + } } -void incnmaster(const Arg *arg) { - if (!arg || !selmon) - return; - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); - arrange(selmon); +void +incnmaster(const Arg *arg) +{ + if (!arg || !selmon) + return; + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); } -void inputdevice(struct wl_listener *listener, void *data) { - /* This event is raised by the backend when a new input device becomes - * available. */ - struct wlr_input_device *device = data; - uint32_t caps; +void +inputdevice(struct wl_listener *listener, void *data) +{ + /* This event is raised by the backend when a new input device becomes + * available. */ + struct wlr_input_device *device = data; + uint32_t caps; - switch (device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - createkeyboard(wlr_keyboard_from_input_device(device)); - break; - case WLR_INPUT_DEVICE_POINTER: - createpointer(wlr_pointer_from_input_device(device)); - break; - default: - /* TODO handle other input device types */ - break; - } + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + createkeyboard(wlr_keyboard_from_input_device(device)); + break; + case WLR_INPUT_DEVICE_POINTER: + createpointer(wlr_pointer_from_input_device(device)); + break; + default: + /* TODO handle other input device types */ + break; + } - /* We need to let the wlr_seat know what our capabilities are, which is - * communiciated to the client. In dwl we always have a cursor, even if - * there are no pointer devices, so we always include that capability. */ - /* TODO do we actually require a cursor? */ - caps = WL_SEAT_CAPABILITY_POINTER; - if (!wl_list_empty(&kb_group->wlr_group->devices)) - caps |= WL_SEAT_CAPABILITY_KEYBOARD; - wlr_seat_set_capabilities(seat, caps); + /* We need to let the wlr_seat know what our capabilities are, which is + * communiciated to the client. In dwl we always have a cursor, even if + * there are no pointer devices, so we always include that capability. */ + /* TODO do we actually require a cursor? */ + caps = WL_SEAT_CAPABILITY_POINTER; + if (!wl_list_empty(&kb_group->wlr_group->devices)) + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + wlr_seat_set_capabilities(seat, caps); } -int keybinding(uint32_t mods, xkb_keysym_t sym) { - /* - * Here we handle compositor keybindings. This is when the compositor is - * processing keys, rather than passing them on to the client for its own - * processing. - */ - const Key *k; - for (k = keys; k < END(keys); k++) { - if (CLEANMASK(mods) == CLEANMASK(k->mod) && sym == k->keysym && k->func) { - k->func(&k->arg); - return 1; - } - } - return 0; +int +keybinding(uint32_t mods, xkb_keysym_t sym) +{ + /* + * Here we handle compositor keybindings. This is when the compositor is + * processing keys, rather than passing them on to the client for its own + * processing. + */ + const Key *k; + for (k = keys; k < END(keys); k++) { + if (CLEANMASK(mods) == CLEANMASK(k->mod) + && sym == k->keysym && k->func) { + k->func(&k->arg); + return 1; + } + } + return 0; } -void keypress(struct wl_listener *listener, void *data) { - int i; - /* This event is raised when a key is pressed or released. */ - KeyboardGroup *group = wl_container_of(listener, group, key); - struct wlr_keyboard_key_event *event = data; +void +keypress(struct wl_listener *listener, void *data) +{ + int i; + /* This event is raised when a key is pressed or released. */ + KeyboardGroup *group = wl_container_of(listener, group, key); + struct wlr_keyboard_key_event *event = data; - /* Translate libinput keycode -> xkbcommon */ - uint32_t keycode = event->keycode + 8; - /* Get a list of keysyms based on the keymap for this keyboard */ - const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(group->wlr_group->keyboard.xkb_state, - keycode, &syms); + /* Translate libinput keycode -> xkbcommon */ + uint32_t keycode = event->keycode + 8; + /* Get a list of keysyms based on the keymap for this keyboard */ + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms( + group->wlr_group->keyboard.xkb_state, keycode, &syms); - int handled = 0; - uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); + int handled = 0; + uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); - wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); - /* On _press_ if there is no active screen locker, - * attempt to process a compositor keybinding. */ - if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { - for (i = 0; i < nsyms; i++) - handled = keybinding(mods, syms[i]) || handled; - } + /* On _press_ if there is no active screen locker, + * attempt to process a compositor keybinding. */ + if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + for (i = 0; i < nsyms; i++) + handled = keybinding(mods, syms[i]) || handled; + } - if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { - group->mods = mods; - group->keysyms = syms; - group->nsyms = nsyms; - wl_event_source_timer_update(group->key_repeat_source, - group->wlr_group->keyboard.repeat_info.delay); - } else { - group->nsyms = 0; - wl_event_source_timer_update(group->key_repeat_source, 0); - } + if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { + group->mods = mods; + group->keysyms = syms; + group->nsyms = nsyms; + wl_event_source_timer_update(group->key_repeat_source, + group->wlr_group->keyboard.repeat_info.delay); + } else { + group->nsyms = 0; + wl_event_source_timer_update(group->key_repeat_source, 0); + } - if (handled) - return; + if (handled) + return; - wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); - /* Pass unhandled keycodes along to the client. */ - wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, - event->state); + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + /* Pass unhandled keycodes along to the client. */ + wlr_seat_keyboard_notify_key(seat, event->time_msec, + event->keycode, event->state); } -void keypressmod(struct wl_listener *listener, void *data) { - /* This event is raised when a modifier key, such as shift or alt, is - * pressed. We simply communicate this to the client. */ - KeyboardGroup *group = wl_container_of(listener, group, modifiers); +void +keypressmod(struct wl_listener *listener, void *data) +{ + /* This event is raised when a modifier key, such as shift or alt, is + * pressed. We simply communicate this to the client. */ + KeyboardGroup *group = wl_container_of(listener, group, modifiers); - wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); - /* Send modifiers to the client. */ - wlr_seat_keyboard_notify_modifiers(seat, - &group->wlr_group->keyboard.modifiers); + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + /* Send modifiers to the client. */ + wlr_seat_keyboard_notify_modifiers(seat, + &group->wlr_group->keyboard.modifiers); } -int keyrepeat(void *data) { - KeyboardGroup *group = data; - int i; - if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) - return 0; +int +keyrepeat(void *data) +{ + KeyboardGroup *group = data; + int i; + if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) + return 0; - wl_event_source_timer_update(group->key_repeat_source, - 1000 / - group->wlr_group->keyboard.repeat_info.rate); + wl_event_source_timer_update(group->key_repeat_source, + 1000 / group->wlr_group->keyboard.repeat_info.rate); - for (i = 0; i < group->nsyms; i++) - keybinding(group->mods, group->keysyms[i]); + for (i = 0; i < group->nsyms; i++) + keybinding(group->mods, group->keysyms[i]); - return 0; + return 0; } -void killclient(const Arg *arg) { - Client *sel = focustop(selmon); - if (sel) - client_send_close(sel); +void +killclient(const Arg *arg) +{ + Client *sel = focustop(selmon); + if (sel) + client_send_close(sel); } -void locksession(struct wl_listener *listener, void *data) { - struct wlr_session_lock_v1 *session_lock = data; - SessionLock *lock; - wlr_scene_node_set_enabled(&locked_bg->node, 1); - if (cur_lock) { - wlr_session_lock_v1_destroy(session_lock); - return; - } - lock = session_lock->data = ecalloc(1, sizeof(*lock)); - focusclient(NULL, 0); +void +locksession(struct wl_listener *listener, void *data) +{ + struct wlr_session_lock_v1 *session_lock = data; + SessionLock *lock; + wlr_scene_node_set_enabled(&locked_bg->node, 1); + if (cur_lock) { + wlr_session_lock_v1_destroy(session_lock); + return; + } + lock = session_lock->data = ecalloc(1, sizeof(*lock)); + focusclient(NULL, 0); - lock->scene = wlr_scene_tree_create(layers[LyrBlock]); - cur_lock = lock->lock = session_lock; - locked = 1; + lock->scene = wlr_scene_tree_create(layers[LyrBlock]); + cur_lock = lock->lock = session_lock; + locked = 1; - LISTEN(&session_lock->events.new_surface, &lock->new_surface, - createlocksurface); - LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); - LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession); + LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface); + LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); + LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession); - wlr_session_lock_v1_send_locked(session_lock); + wlr_session_lock_v1_send_locked(session_lock); } -void mapnotify(struct wl_listener *listener, void *data) { - /* Called when the surface is mapped, or ready to display on-screen. */ - Client *p = NULL; - Client *w, *c = wl_container_of(listener, c, map); - Monitor *m; - int i; +void +mapnotify(struct wl_listener *listener, void *data) +{ + /* Called when the surface is mapped, or ready to display on-screen. */ + Client *p = NULL; + Client *w, *c = wl_container_of(listener, c, map); + Monitor *m; + int i; - /* Create scene tree for this client and its border */ - c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); - wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell); - c->scene_surface = - c->type == XDGShell - ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) - : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - c->scene->node.data = c->scene_surface->node.data = c; + /* Create scene tree for this client and its border */ + c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); + wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell); + c->scene_surface = c->type == XDGShell + ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) + : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); + c->scene->node.data = c->scene_surface->node.data = c; - client_get_geometry(c, &c->geom); + client_get_geometry(c, &c->geom); - /* Handle unmanaged clients first so we can return prior create borders */ - if (client_is_unmanaged(c)) { - /* Unmanaged clients always are floating */ - wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); - wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); - if (client_wants_focus(c)) { - focusclient(c, 1); - exclusive_focus = c; - } - goto unset_fullscreen; - } + /* Handle unmanaged clients first so we can return prior create borders */ + if (client_is_unmanaged(c)) { + /* Unmanaged clients always are floating */ + wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + if (client_wants_focus(c)) { + focusclient(c, 1); + exclusive_focus = c; + } + goto unset_fullscreen; + } - for (i = 0; i < 4; i++) { - c->border[i] = wlr_scene_rect_create( - c->scene, 0, 0, c->isurgent ? urgentcolor : bordercolor); - c->border[i]->node.data = c; - } + for (i = 0; i < 4; i++) { + c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, + c->isurgent ? urgentcolor : bordercolor); + c->border[i]->node.data = c; + } - /* Initialize client geometry with room for border */ - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | - WLR_EDGE_RIGHT); - c->geom.width += 2 * c->bw; - c->geom.height += 2 * c->bw; + /* Initialize client geometry with room for border */ + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); + c->geom.width += 2 * c->bw; + c->geom.height += 2 * c->bw; - /* Insert this client into client lists. */ - wl_list_insert(&clients, &c->link); - wl_list_insert(&fstack, &c->flink); + /* Insert this client into client lists. */ + wl_list_insert(&clients, &c->link); + wl_list_insert(&fstack, &c->flink); - /* Set initial monitor, tags, floating status, and focus: - * we always consider floating, clients that have parent and thus - * we set the same tags and monitor than its parent, if not - * try to apply rules for them */ - if ((p = client_get_parent(c))) { - c->isfloating = 1; - setmon(c, p->mon, p->tags); - } else { - applyrules(c); - } - printstatus(); + /* Set initial monitor, tags, floating status, and focus: + * we always consider floating, clients that have parent and thus + * we set the same tags and monitor than its parent, if not + * try to apply rules for them */ + if ((p = client_get_parent(c))) { + c->isfloating = 1; + setmon(c, p->mon, p->tags); + } else { + applyrules(c); + } + printstatus(); unset_fullscreen: - m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); - wl_list_for_each(w, &clients, link) { - if (w != c && w != p && w->isfullscreen && m == w->mon && - (w->tags & c->tags)) - setfullscreen(w, 0); - } + m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); + wl_list_for_each(w, &clients, link) { + if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags)) + setfullscreen(w, 0); + } } -void maximizenotify(struct wl_listener *listener, void *data) { - /* This event is raised when a client would like to maximize itself, - * typically because the user clicked on the maximize button on - * client-side decorations. dwl doesn't support maximization, but - * to conform to xdg-shell protocol we still must send a configure. - * Since xdg-shell protocol v5 we should ignore request of unsupported - * capabilities, just schedule a empty configure when the client uses <5 - * protocol version - * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ - Client *c = wl_container_of(listener, c, maximize); - if (c->surface.xdg->initialized && - wl_resource_get_version(c->surface.xdg->toplevel->resource) < - XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) - wlr_xdg_surface_schedule_configure(c->surface.xdg); +void +maximizenotify(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client would like to maximize itself, + * typically because the user clicked on the maximize button on + * client-side decorations. dwl doesn't support maximization, but + * to conform to xdg-shell protocol we still must send a configure. + * Since xdg-shell protocol v5 we should ignore request of unsupported + * capabilities, just schedule a empty configure when the client uses <5 + * protocol version + * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ + Client *c = wl_container_of(listener, c, maximize); + if (c->surface.xdg->initialized + && wl_resource_get_version(c->surface.xdg->toplevel->resource) + < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) + wlr_xdg_surface_schedule_configure(c->surface.xdg); } -void monocle(Monitor *m) { - Client *c; - int n = 0; +void +monocle(Monitor *m) +{ + Client *c; + int n = 0; - wl_list_for_each(c, &clients, link) { - if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) - continue; - resize(c, m->w, 0); - n++; - } - if (n) - snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n); - if ((c = focustop(m))) - wlr_scene_node_raise_to_top(&c->scene->node); + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; + resize(c, m->w, 0); + n++; + } + if (n) + snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n); + if ((c = focustop(m))) + wlr_scene_node_raise_to_top(&c->scene->node); } -void motionabsolute(struct wl_listener *listener, void *data) { - /* This event is forwarded by the cursor when a pointer emits an _absolute_ - * motion event, from 0..1 on each axis. This happens, for example, when - * wlroots is running under a Wayland window rather than KMS+DRM, and you - * move the mouse over the window. You could enter the window from any edge, - * so we have to warp the mouse there. There is also some hardware which - * emits these events. */ - struct wlr_pointer_motion_absolute_event *event = data; - double lx, ly, dx, dy; +void +motionabsolute(struct wl_listener *listener, void *data) +{ + /* This event is forwarded by the cursor when a pointer emits an _absolute_ + * motion event, from 0..1 on each axis. This happens, for example, when + * wlroots is running under a Wayland window rather than KMS+DRM, and you + * move the mouse over the window. You could enter the window from any edge, + * so we have to warp the mouse there. There is also some hardware which + * emits these events. */ + struct wlr_pointer_motion_absolute_event *event = data; + double lx, ly, dx, dy; - if (!event->time_msec) /* this is 0 with virtual pointers */ - wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); + if (!event->time_msec) /* this is 0 with virtual pointers */ + wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); - wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, - event->y, &lx, &ly); - dx = lx - cursor->x; - dy = ly - cursor->y; - motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); + wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, event->y, &lx, &ly); + dx = lx - cursor->x; + dy = ly - cursor->y; + motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); } -void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, - double dy, double dx_unaccel, double dy_unaccel) { - double sx = 0, sy = 0, sx_confined, sy_confined; - Client *c = NULL, *w = NULL; - LayerSurface *l = NULL; - struct wlr_surface *surface = NULL; - struct wlr_pointer_constraint_v1 *constraint; +void +motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, + double dx_unaccel, double dy_unaccel) +{ + double sx = 0, sy = 0, sx_confined, sy_confined; + Client *c = NULL, *w = NULL; + LayerSurface *l = NULL; + struct wlr_surface *surface = NULL; + struct wlr_pointer_constraint_v1 *constraint; - /* Find the client under the pointer and send the event along. */ - xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + /* Find the client under the pointer and send the event along. */ + xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); - if (cursor_mode == CurPressed && !seat->drag && - surface != seat->pointer_state.focused_surface && - toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= - 0) { - c = w; - surface = seat->pointer_state.focused_surface; - sx = cursor->x - (l ? l->geom.x : w->geom.x); - sy = cursor->y - (l ? l->geom.y : w->geom.y); - } + if (cursor_mode == CurPressed && !seat->drag + && surface != seat->pointer_state.focused_surface + && toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= 0) { + c = w; + surface = seat->pointer_state.focused_surface; + sx = cursor->x - (l ? l->geom.x : w->geom.x); + sy = cursor->y - (l ? l->geom.y : w->geom.y); + } - /* time is 0 in internal calls meant to restore pointer focus. */ - if (time) { - wlr_relative_pointer_manager_v1_send_relative_motion( - relative_pointer_mgr, seat, (uint64_t)time * 1000, dx, dy, dx_unaccel, - dy_unaccel); + /* time is 0 in internal calls meant to restore pointer focus. */ + if (time) { + wlr_relative_pointer_manager_v1_send_relative_motion( + relative_pointer_mgr, seat, (uint64_t)time * 1000, + dx, dy, dx_unaccel, dy_unaccel); - wl_list_for_each(constraint, &pointer_constraints->constraints, link) - cursorconstrain(constraint); + wl_list_for_each(constraint, &pointer_constraints->constraints, link) + cursorconstrain(constraint); - if (active_constraint && cursor_mode != CurResize && - cursor_mode != CurMove) { - toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); - if (c && - active_constraint->surface == seat->pointer_state.focused_surface) { - sx = cursor->x - c->geom.x - c->bw; - sy = cursor->y - c->geom.y - c->bw; - if (wlr_region_confine(&active_constraint->region, sx, sy, sx + dx, - sy + dy, &sx_confined, &sy_confined)) { - dx = sx_confined - sx; - dy = sy_confined - sy; - } + if (active_constraint && cursor_mode != CurResize && cursor_mode != CurMove) { + toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); + if (c && active_constraint->surface == seat->pointer_state.focused_surface) { + sx = cursor->x - c->geom.x - c->bw; + sy = cursor->y - c->geom.y - c->bw; + if (wlr_region_confine(&active_constraint->region, sx, sy, + sx + dx, sy + dy, &sx_confined, &sy_confined)) { + dx = sx_confined - sx; + dy = sy_confined - sy; + } - if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) - return; - } - } + if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) + return; + } + } - wlr_cursor_move(cursor, device, dx, dy); - wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + wlr_cursor_move(cursor, device, dx, dy); + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); - /* Update selmon (even while dragging a window) */ - if (sloppyfocus) - selmon = xytomon(cursor->x, cursor->y); - } + /* Update selmon (even while dragging a window) */ + if (sloppyfocus) + selmon = xytomon(cursor->x, cursor->y); + } - /* Update drag icon's position */ - wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), - (int)round(cursor->y)); + /* Update drag icon's position */ + wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); - /* If we are currently grabbing the mouse, handle and return */ - if (cursor_mode == CurMove) { - /* Move the grabbed client to the new position. */ - resize(grabc, - (struct wlr_box){.x = (int)round(cursor->x) - grabcx, - .y = (int)round(cursor->y) - grabcy, - .width = grabc->geom.width, - .height = grabc->geom.height}, - 1); - return; - } else if (cursor_mode == CurResize) { - resize(grabc, - (struct wlr_box){.x = grabc->geom.x, - .y = grabc->geom.y, - .width = (int)round(cursor->x) - grabc->geom.x, - .height = (int)round(cursor->y) - grabc->geom.y}, - 1); - return; - } + /* If we are currently grabbing the mouse, handle and return */ + if (cursor_mode == CurMove) { + /* Move the grabbed client to the new position. */ + resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy, + .width = grabc->geom.width, .height = grabc->geom.height}, 1); + return; + } else if (cursor_mode == CurResize) { + resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y, + .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1); + return; + } - /* If there's no client surface under the cursor, set the cursor image to a - * default. This is what makes the cursor image appear when you move it - * off of a client or over its border. */ - if (!surface && !seat->drag) - wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + /* If there's no client surface under the cursor, set the cursor image to a + * default. This is what makes the cursor image appear when you move it + * off of a client or over its border. */ + if (!surface && !seat->drag) + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); - pointerfocus(c, surface, sx, sy, time); + pointerfocus(c, surface, sx, sy, time); } -void motionrelative(struct wl_listener *listener, void *data) { - /* This event is forwarded by the cursor when a pointer emits a _relative_ - * pointer motion event (i.e. a delta) */ - struct wlr_pointer_motion_event *event = data; - /* The cursor doesn't move unless we tell it to. The cursor automatically - * handles constraining the motion to the output layout, as well as any - * special configuration applied for the specific input device which - * generated the event. You can pass NULL for the device if you want to move - * the cursor around without any input. */ - motionnotify(event->time_msec, &event->pointer->base, event->delta_x, - event->delta_y, event->unaccel_dx, event->unaccel_dy); +void +motionrelative(struct wl_listener *listener, void *data) +{ + /* This event is forwarded by the cursor when a pointer emits a _relative_ + * pointer motion event (i.e. a delta) */ + struct wlr_pointer_motion_event *event = data; + /* The cursor doesn't move unless we tell it to. The cursor automatically + * handles constraining the motion to the output layout, as well as any + * special configuration applied for the specific input device which + * generated the event. You can pass NULL for the device if you want to move + * the cursor around without any input. */ + motionnotify(event->time_msec, &event->pointer->base, event->delta_x, event->delta_y, + event->unaccel_dx, event->unaccel_dy); } -void moveresize(const Arg *arg) { - if (cursor_mode != CurNormal && cursor_mode != CurPressed) - return; - xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); - if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) - return; +void +moveresize(const Arg *arg) +{ + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); + if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) + return; - /* Float the window and tell motionnotify to grab it */ - setfloating(grabc, 1); - switch (cursor_mode = arg->ui) { - case CurMove: - grabcx = (int)round(cursor->x) - grabc->geom.x; - grabcy = (int)round(cursor->y) - grabc->geom.y; - wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); - break; - case CurResize: - /* Doesn't work for X11 output - the next absolute motion event - * returns the cursor to where it started */ - wlr_cursor_warp_closest(cursor, NULL, grabc->geom.x + grabc->geom.width, - grabc->geom.y + grabc->geom.height); - wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize"); - break; - } + /* Float the window and tell motionnotify to grab it */ + setfloating(grabc, 1); + switch (cursor_mode = arg->ui) { + case CurMove: + grabcx = (int)round(cursor->x) - grabc->geom.x; + grabcy = (int)round(cursor->y) - grabc->geom.y; + wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); + break; + case CurResize: + /* Doesn't work for X11 output - the next absolute motion event + * returns the cursor to where it started */ + wlr_cursor_warp_closest(cursor, NULL, + grabc->geom.x + grabc->geom.width, + grabc->geom.y + grabc->geom.height); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize"); + break; + } } -void outputmgrapply(struct wl_listener *listener, void *data) { - struct wlr_output_configuration_v1 *config = data; - outputmgrapplyortest(config, 0); +void +outputmgrapply(struct wl_listener *listener, void *data) +{ + struct wlr_output_configuration_v1 *config = data; + outputmgrapplyortest(config, 0); } -void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, - int test) { - /* - * Called when a client such as wlr-randr requests a change in output - * configuration. This is only one way that the layout can be changed, - * so any Monitor information should be updated by updatemons() after an - * output_layout.change event, not here. - */ - struct wlr_output_configuration_head_v1 *config_head; - int ok = 1; +void +outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) +{ + /* + * Called when a client such as wlr-randr requests a change in output + * configuration. This is only one way that the layout can be changed, + * so any Monitor information should be updated by updatemons() after an + * output_layout.change event, not here. + */ + struct wlr_output_configuration_head_v1 *config_head; + int ok = 1; - wl_list_for_each(config_head, &config->heads, link) { - struct wlr_output *wlr_output = config_head->state.output; - Monitor *m = wlr_output->data; - struct wlr_output_state state; + wl_list_for_each(config_head, &config->heads, link) { + struct wlr_output *wlr_output = config_head->state.output; + Monitor *m = wlr_output->data; + struct wlr_output_state state; - /* Ensure displays previously disabled by wlr-output-power-management-v1 - * are properly handled*/ - m->asleep = 0; + /* Ensure displays previously disabled by wlr-output-power-management-v1 + * are properly handled*/ + m->asleep = 0; - wlr_output_state_init(&state); - wlr_output_state_set_enabled(&state, config_head->state.enabled); - if (!config_head->state.enabled) - goto apply_or_test; + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, config_head->state.enabled); + if (!config_head->state.enabled) + goto apply_or_test; - if (config_head->state.mode) - wlr_output_state_set_mode(&state, config_head->state.mode); - else - wlr_output_state_set_custom_mode(&state, - config_head->state.custom_mode.width, - config_head->state.custom_mode.height, - config_head->state.custom_mode.refresh); + if (config_head->state.mode) + wlr_output_state_set_mode(&state, config_head->state.mode); + else + wlr_output_state_set_custom_mode(&state, + config_head->state.custom_mode.width, + config_head->state.custom_mode.height, + config_head->state.custom_mode.refresh); - wlr_output_state_set_transform(&state, config_head->state.transform); - wlr_output_state_set_scale(&state, config_head->state.scale); - wlr_output_state_set_adaptive_sync_enabled( - &state, config_head->state.adaptive_sync_enabled); + wlr_output_state_set_transform(&state, config_head->state.transform); + wlr_output_state_set_scale(&state, config_head->state.scale); + wlr_output_state_set_adaptive_sync_enabled(&state, + config_head->state.adaptive_sync_enabled); - apply_or_test: - ok &= test ? wlr_output_test_state(wlr_output, &state) - : wlr_output_commit_state(wlr_output, &state); +apply_or_test: + ok &= test ? wlr_output_test_state(wlr_output, &state) + : wlr_output_commit_state(wlr_output, &state); - /* Don't move monitors if position wouldn't change, this to avoid - * wlroots marking the output as manually configured. - * wlr_output_layout_add does not like disabled outputs */ - if (!test && wlr_output->enabled && - (m->m.x != config_head->state.x || m->m.y != config_head->state.y)) - wlr_output_layout_add(output_layout, wlr_output, config_head->state.x, - config_head->state.y); + /* Don't move monitors if position wouldn't change, this to avoid + * wlroots marking the output as manually configured. + * wlr_output_layout_add does not like disabled outputs */ + if (!test && wlr_output->enabled && (m->m.x != config_head->state.x || m->m.y != config_head->state.y)) + wlr_output_layout_add(output_layout, wlr_output, + config_head->state.x, config_head->state.y); - wlr_output_state_finish(&state); - } + wlr_output_state_finish(&state); + } - if (ok) - wlr_output_configuration_v1_send_succeeded(config); - else - wlr_output_configuration_v1_send_failed(config); - wlr_output_configuration_v1_destroy(config); + if (ok) + wlr_output_configuration_v1_send_succeeded(config); + else + wlr_output_configuration_v1_send_failed(config); + wlr_output_configuration_v1_destroy(config); - /* https://codeberg.org/dwl/dwl/issues/577 */ - updatemons(NULL, NULL); + /* https://codeberg.org/dwl/dwl/issues/577 */ + updatemons(NULL, NULL); } -void outputmgrtest(struct wl_listener *listener, void *data) { - struct wlr_output_configuration_v1 *config = data; - outputmgrapplyortest(config, 1); +void +outputmgrtest(struct wl_listener *listener, void *data) +{ + struct wlr_output_configuration_v1 *config = data; + outputmgrapplyortest(config, 1); } -pid_t parentpid(pid_t pid) { - unsigned int v = 0; - FILE *f; - char buf[256]; - snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)pid); - if (!(f = fopen(buf, "r"))) - return 0; - fscanf(f, "%*u %*s %*c %u", &v); - fclose(f); - return (pid_t)v; +void +pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, + uint32_t time) +{ + struct timespec now; + + if (surface != seat->pointer_state.focused_surface && + sloppyfocus && time && c && !client_is_unmanaged(c)) + focusclient(c, 0); + + /* If surface is NULL, clear pointer focus */ + if (!surface) { + wlr_seat_pointer_notify_clear_focus(seat); + return; + } + + if (!time) { + clock_gettime(CLOCK_MONOTONIC, &now); + time = now.tv_sec * 1000 + now.tv_nsec / 1000000; + } + + /* Let the client know that the mouse cursor has entered one + * of its surfaces, and make keyboard focus follow if desired. + * wlroots makes this a no-op if surface is already focused */ + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(seat, time, sx, sy); } -void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, - uint32_t time) { - struct timespec now; +void +printstatus(void) +{ + Monitor *m = NULL; + Client *c; + uint32_t occ, urg, sel; + const char *appid, *title; - if (surface != seat->pointer_state.focused_surface && sloppyfocus && time && - c && !client_is_unmanaged(c)) - focusclient(c, 0); + wl_list_for_each(m, &mons, link) { + occ = urg = 0; + wl_list_for_each(c, &clients, link) { + if (c->mon != m) + continue; + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + if ((c = focustop(m))) { + title = client_get_title(c); + appid = client_get_appid(c); + printf("%s title %s\n", m->wlr_output->name, title ? title : broken); + printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken); + printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen); + printf("%s floating %d\n", m->wlr_output->name, c->isfloating); + sel = c->tags; + } else { + printf("%s title \n", m->wlr_output->name); + printf("%s appid \n", m->wlr_output->name); + printf("%s fullscreen \n", m->wlr_output->name); + printf("%s floating \n", m->wlr_output->name); + sel = 0; + } - /* If surface is NULL, clear pointer focus */ - if (!surface) { - wlr_seat_pointer_notify_clear_focus(seat); - return; - } - - if (!time) { - clock_gettime(CLOCK_MONOTONIC, &now); - time = now.tv_sec * 1000 + now.tv_nsec / 1000000; - } - - /* Let the client know that the mouse cursor has entered one - * of its surfaces, and make keyboard focus follow if desired. - * wlroots makes this a no-op if surface is already focused */ - wlr_seat_pointer_notify_enter(seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(seat, time, sx, sy); + printf("%s selmon %u\n", m->wlr_output->name, m == selmon); + printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n", + m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); + printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); + } + fflush(stdout); } -void printstatus(void) { - Monitor *m = NULL; - Client *c; - uint32_t occ, urg, sel; - const char *appid, *title; +void +powermgrsetmode(struct wl_listener *listener, void *data) +{ + struct wlr_output_power_v1_set_mode_event *event = data; + struct wlr_output_state state = {0}; + Monitor *m = event->output->data; - wl_list_for_each(m, &mons, link) { - occ = urg = 0; - wl_list_for_each(c, &clients, link) { - if (c->mon != m) - continue; - occ |= c->tags; - if (c->isurgent) - urg |= c->tags; - } - if ((c = focustop(m))) { - title = client_get_title(c); - appid = client_get_appid(c); - printf("%s title %s\n", m->wlr_output->name, title ? title : broken); - printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken); - printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen); - printf("%s floating %d\n", m->wlr_output->name, c->isfloating); - sel = c->tags; - } else { - printf("%s title \n", m->wlr_output->name); - printf("%s appid \n", m->wlr_output->name); - printf("%s fullscreen \n", m->wlr_output->name); - printf("%s floating \n", m->wlr_output->name); - sel = 0; - } + if (!m) + return; - printf("%s selmon %u\n", m->wlr_output->name, m == selmon); - printf("%s tags %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 "\n", - m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); - printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); - } - fflush(stdout); + m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */ + wlr_output_state_set_enabled(&state, event->mode); + wlr_output_commit_state(m->wlr_output, &state); + + m->asleep = !event->mode; } -void powermgrsetmode(struct wl_listener *listener, void *data) { - struct wlr_output_power_v1_set_mode_event *event = data; - struct wlr_output_state state = {0}; - Monitor *m = event->output->data; - - if (!m) - return; - - m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */ - wlr_output_state_set_enabled(&state, event->mode); - wlr_output_commit_state(m->wlr_output, &state); - - m->asleep = !event->mode; +void +quit(const Arg *arg) +{ + wl_display_terminate(dpy); } -void quit(const Arg *arg) { wl_display_terminate(dpy); } +void +rendermon(struct wl_listener *listener, void *data) +{ + /* This function is called every time an output is ready to display a frame, + * generally at the output's refresh rate (e.g. 60Hz). */ + Monitor *m = wl_container_of(listener, m, frame); + Client *c; + struct wlr_output_state pending = {0}; + struct wlr_gamma_control_v1 *gamma_control; + struct timespec now; -void rendermon(struct wl_listener *listener, void *data) { - /* This function is called every time an output is ready to display a frame, - * generally at the output's refresh rate (e.g. 60Hz). */ - Monitor *m = wl_container_of(listener, m, frame); - Client *c; - struct wlr_output_state pending = {0}; - struct wlr_gamma_control_v1 *gamma_control; - struct timespec now; + /* Render if no XDG clients have an outstanding resize and are visible on + * this monitor. */ + wl_list_for_each(c, &clients, link) { + if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) + goto skip; + } - /* Render if no XDG clients have an outstanding resize and are visible on - * this monitor. */ - wl_list_for_each(c, &clients, link) { - if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && - !client_is_stopped(c)) - goto skip; - } + /* + * HACK: The "correct" way to set the gamma is to commit it together with + * the rest of the state in one go, but to do that we would need to rewrite + * wlr_scene_output_commit() in order to add the gamma to the pending + * state before committing, instead try to commit the gamma in one frame, + * and commit the rest of the state in the next one (or in the same frame if + * the gamma can not be committed). + */ + if (m->gamma_lut_changed) { + gamma_control + = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output); + m->gamma_lut_changed = 0; - /* - * HACK: The "correct" way to set the gamma is to commit it together with - * the rest of the state in one go, but to do that we would need to rewrite - * wlr_scene_output_commit() in order to add the gamma to the pending - * state before committing, instead try to commit the gamma in one frame, - * and commit the rest of the state in the next one (or in the same frame if - * the gamma can not be committed). - */ - if (m->gamma_lut_changed) { - gamma_control = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, - m->wlr_output); - m->gamma_lut_changed = 0; + if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) + goto commit; - if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) - goto commit; - - if (!wlr_output_test_state(m->wlr_output, &pending)) { - wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); - goto commit; - } - wlr_output_commit_state(m->wlr_output, &pending); - wlr_output_schedule_frame(m->wlr_output); - } else { - commit: - wlr_scene_output_commit(m->scene_output, NULL); - } + if (!wlr_output_test_state(m->wlr_output, &pending)) { + wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); + goto commit; + } + wlr_output_commit_state(m->wlr_output, &pending); + wlr_output_schedule_frame(m->wlr_output); + } else { +commit: + wlr_scene_output_commit(m->scene_output, NULL); + } skip: - /* Let clients know a frame has been rendered */ - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_scene_output_send_frame_done(m->scene_output, &now); - wlr_output_state_finish(&pending); + /* Let clients know a frame has been rendered */ + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_scene_output_send_frame_done(m->scene_output, &now); + wlr_output_state_finish(&pending); } -void requestdecorationmode(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, set_decoration_mode); - if (c->surface.xdg->initialized) - wlr_xdg_toplevel_decoration_v1_set_mode( - c->decoration, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +void +requestdecorationmode(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, set_decoration_mode); + if (c->surface.xdg->initialized) + wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } -void requeststartdrag(struct wl_listener *listener, void *data) { - struct wlr_seat_request_start_drag_event *event = data; +void +requeststartdrag(struct wl_listener *listener, void *data) +{ + struct wlr_seat_request_start_drag_event *event = data; - if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, event->serial)) - wlr_seat_start_pointer_drag(seat, event->drag, event->serial); - else - wlr_data_source_destroy(event->drag->source); + if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, + event->serial)) + wlr_seat_start_pointer_drag(seat, event->drag, event->serial); + else + wlr_data_source_destroy(event->drag->source); } -void requestmonstate(struct wl_listener *listener, void *data) { - struct wlr_output_event_request_state *event = data; - wlr_output_commit_state(event->output, event->state); - updatemons(NULL, NULL); +void +requestmonstate(struct wl_listener *listener, void *data) +{ + struct wlr_output_event_request_state *event = data; + wlr_output_commit_state(event->output, event->state); + updatemons(NULL, NULL); } -void resize(Client *c, struct wlr_box geo, int interact) { - struct wlr_box *bbox; - struct wlr_box clip; +void +resize(Client *c, struct wlr_box geo, int interact) +{ + struct wlr_box *bbox; + struct wlr_box clip; - if (!c->mon || !client_surface(c)->mapped) - return; + if (!c->mon || !client_surface(c)->mapped) + return; - bbox = interact ? &sgeom : &c->mon->w; + bbox = interact ? &sgeom : &c->mon->w; - client_set_bounds(c, geo.width, geo.height); - c->geom = geo; - applybounds(c, bbox); + client_set_bounds(c, geo.width, geo.height); + c->geom = geo; + applybounds(c, bbox); - /* Update scene-graph, including borders */ - wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); - wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); - wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); - wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); - wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); - wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); - wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); - wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); - wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, - c->bw); + /* Update scene-graph, including borders */ + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); + wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); + wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); + wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); + wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); + wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); - /* this is a no-op if size hasn't changed */ - c->resize = - client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); - client_get_clip(c, &clip); - wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); + /* this is a no-op if size hasn't changed */ + c->resize = client_set_size(c, c->geom.width - 2 * c->bw, + c->geom.height - 2 * c->bw); + client_get_clip(c, &clip); + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); } -void run(char *startup_cmd) { - /* Add a Unix socket to the Wayland display. */ - const char *socket = wl_display_add_socket_auto(dpy); - if (!socket) - die("startup: display_add_socket_auto"); - setenv("WAYLAND_DISPLAY", socket, 1); +void +run(char *startup_cmd) +{ + /* Add a Unix socket to the Wayland display. */ + const char *socket = wl_display_add_socket_auto(dpy); + if (!socket) + die("startup: display_add_socket_auto"); + setenv("WAYLAND_DISPLAY", socket, 1); - /* Start the backend. This will enumerate outputs and inputs, become the DRM - * master, etc */ - if (!wlr_backend_start(backend)) - die("startup: backend_start"); + /* Start the backend. This will enumerate outputs and inputs, become the DRM + * master, etc */ + if (!wlr_backend_start(backend)) + die("startup: backend_start"); - /* Now that the socket exists and the backend is started, run the startup - * command */ - autostartexec(); - if (startup_cmd) { - int piperw[2]; - if (pipe(piperw) < 0) - die("startup: pipe:"); - if ((child_pid = fork()) < 0) - die("startup: fork:"); - if (child_pid == 0) { - setsid(); - dup2(piperw[0], STDIN_FILENO); - close(piperw[0]); - close(piperw[1]); - execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); - die("startup: execl:"); - } - dup2(piperw[1], STDOUT_FILENO); - close(piperw[1]); - close(piperw[0]); - } + /* Now that the socket exists and the backend is started, run the startup command */ + if (startup_cmd) { + int piperw[2]; + if (pipe(piperw) < 0) + die("startup: pipe:"); + if ((child_pid = fork()) < 0) + die("startup: fork:"); + if (child_pid == 0) { + setsid(); + dup2(piperw[0], STDIN_FILENO); + close(piperw[0]); + close(piperw[1]); + execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); + die("startup: execl:"); + } + dup2(piperw[1], STDOUT_FILENO); + close(piperw[1]); + close(piperw[0]); + } - /* Mark stdout as non-blocking to avoid people who does not close stdin - * nor consumes it in their startup script getting dwl frozen */ - if (fd_set_nonblock(STDOUT_FILENO) < 0) - close(STDOUT_FILENO); + /* Mark stdout as non-blocking to avoid people who does not close stdin + * nor consumes it in their startup script getting dwl frozen */ + if (fd_set_nonblock(STDOUT_FILENO) < 0) + close(STDOUT_FILENO); - printstatus(); + printstatus(); - /* At this point the outputs are initialized, choose initial selmon based on - * cursor position, and set default cursor image */ - selmon = xytomon(cursor->x, cursor->y); + /* At this point the outputs are initialized, choose initial selmon based on + * cursor position, and set default cursor image */ + selmon = xytomon(cursor->x, cursor->y); - /* TODO hack to get cursor to display in its initial location (100, 100) - * instead of (0, 0) and then jumping. still may not be fully - * initialized, as the image/coordinates are not transformed for the - * monitor when displayed here */ - wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); - wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + /* TODO hack to get cursor to display in its initial location (100, 100) + * instead of (0, 0) and then jumping. still may not be fully + * initialized, as the image/coordinates are not transformed for the + * monitor when displayed here */ + wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); - /* Run the Wayland event loop. This does not return until you exit the - * compositor. Starting the backend rigged up all of the necessary event - * loop configuration to listen to libinput events, DRM events, generate - * frame events at the refresh rate, and so on. */ - wl_display_run(dpy); + /* Run the Wayland event loop. This does not return until you exit the + * compositor. Starting the backend rigged up all of the necessary event + * loop configuration to listen to libinput events, DRM events, generate + * frame events at the refresh rate, and so on. */ + wl_display_run(dpy); } -void setcursor(struct wl_listener *listener, void *data) { - /* This event is raised by the seat when a client provides a cursor image */ - struct wlr_seat_pointer_request_set_cursor_event *event = data; - /* If we're "grabbing" the cursor, don't use the client's image, we will - * restore it after "grabbing" sending a leave event, followed by a enter - * event, which will result in the client requesting set the cursor surface */ - if (cursor_mode != CurNormal && cursor_mode != CurPressed) - return; - /* This can be sent by any client, so we check to make sure this one is - * actually has pointer focus first. If so, we can tell the cursor to - * use the provided surface as the cursor image. It will set the - * hardware cursor on the output that it's currently on and continue to - * do so as the cursor moves between outputs. */ - if (event->seat_client == seat->pointer_state.focused_client) - wlr_cursor_set_surface(cursor, event->surface, event->hotspot_x, - event->hotspot_y); +void +setcursor(struct wl_listener *listener, void *data) +{ + /* This event is raised by the seat when a client provides a cursor image */ + struct wlr_seat_pointer_request_set_cursor_event *event = data; + /* If we're "grabbing" the cursor, don't use the client's image, we will + * restore it after "grabbing" sending a leave event, followed by a enter + * event, which will result in the client requesting set the cursor surface */ + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + /* This can be sent by any client, so we check to make sure this one is + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided surface as the cursor image. It will set the + * hardware cursor on the output that it's currently on and continue to + * do so as the cursor moves between outputs. */ + if (event->seat_client == seat->pointer_state.focused_client) + wlr_cursor_set_surface(cursor, event->surface, + event->hotspot_x, event->hotspot_y); } -void setcursorshape(struct wl_listener *listener, void *data) { - struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; - if (cursor_mode != CurNormal && cursor_mode != CurPressed) - return; - /* This can be sent by any client, so we check to make sure this one is - * actually has pointer focus first. If so, we can tell the cursor to - * use the provided cursor shape. */ - if (event->seat_client == seat->pointer_state.focused_client) - wlr_cursor_set_xcursor(cursor, cursor_mgr, - wlr_cursor_shape_v1_name(event->shape)); +void +setcursorshape(struct wl_listener *listener, void *data) +{ + struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + /* This can be sent by any client, so we check to make sure this one is + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided cursor shape. */ + if (event->seat_client == seat->pointer_state.focused_client) + wlr_cursor_set_xcursor(cursor, cursor_mgr, + wlr_cursor_shape_v1_name(event->shape)); } -void setfloating(Client *c, int floating) { - Client *p = client_get_parent(c); - c->isfloating = floating; - /* If in floating layout do not change the client's layer */ - if (!c->mon || !client_surface(c)->mapped || - !c->mon->lt[c->mon->sellt]->arrange) - return; - wlr_scene_node_reparent( - &c->scene->node, layers[c->isfullscreen || (p && p->isfullscreen) ? LyrFS - : c->isfloating ? LyrFloat - : LyrTile]); - arrange(c->mon); - printstatus(); +void +setfloating(Client *c, int floating) +{ + Client *p = client_get_parent(c); + c->isfloating = floating; + /* If in floating layout do not change the client's layer */ + if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange) + return; + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || + (p && p->isfullscreen) ? LyrFS + : c->isfloating ? LyrFloat : LyrTile]); + arrange(c->mon); + printstatus(); } -void setfullscreen(Client *c, int fullscreen) { - c->isfullscreen = fullscreen; - if (!c->mon || !client_surface(c)->mapped) - return; - c->bw = fullscreen ? 0 : BORDERPX(c); - client_set_fullscreen(c, fullscreen); - wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ? LyrFS - : c->isfloating ? LyrFloat - : LyrTile]); +void +setfullscreen(Client *c, int fullscreen) +{ + c->isfullscreen = fullscreen; + if (!c->mon || !client_surface(c)->mapped) + return; + c->bw = fullscreen ? 0 : borderpx; + client_set_fullscreen(c, fullscreen); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); - if (fullscreen) { - c->prev = c->geom; - resize(c, c->mon->m, 0); - } else { - /* restore previous size instead of arrange for floating windows since - * client positions are set by the user and cannot be recalculated */ - resize(c, c->prev, 0); - } - arrange(c->mon); - printstatus(); + if (fullscreen) { + c->prev = c->geom; + resize(c, c->mon->m, 0); + } else { + /* restore previous size instead of arrange for floating windows since + * client positions are set by the user and cannot be recalculated */ + resize(c, c->prev, 0); + } + arrange(c->mon); + printstatus(); } -void setgamma(struct wl_listener *listener, void *data) { - struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; - Monitor *m = event->output->data; - if (!m) - return; - m->gamma_lut_changed = 1; - wlr_output_schedule_frame(m->wlr_output); +void +setgamma(struct wl_listener *listener, void *data) +{ + struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; + Monitor *m = event->output->data; + if (!m) + return; + m->gamma_lut_changed = 1; + wlr_output_schedule_frame(m->wlr_output); } -void setlayout(const Arg *arg) { - if (!selmon) - return; - if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; - if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; - strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, - LENGTH(selmon->ltsymbol)); - arrange(selmon); - printstatus(); +void +setlayout(const Arg *arg) +{ + if (!selmon) + return; + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol)); + arrange(selmon); + printstatus(); } /* arg > 1.0 will set mfact absolutely */ -void setmfact(const Arg *arg) { - float f; +void +setmfact(const Arg *arg) +{ + float f; - if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) - return; - f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f; - if (f < 0.1 || f > 0.9) - return; - selmon->mfact = f; - arrange(selmon); + if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f; + if (f < 0.1 || f > 0.9) + return; + selmon->mfact = f; + arrange(selmon); } -void setmon(Client *c, Monitor *m, uint32_t newtags) { - Monitor *oldmon = c->mon; +void +setmon(Client *c, Monitor *m, uint32_t newtags) +{ + Monitor *oldmon = c->mon; - if (oldmon == m) - return; - c->mon = m; - c->prev = c->geom; + if (oldmon == m) + return; + c->mon = m; + c->prev = c->geom; - /* Scene graph sends surface leave/enter events on move and resize */ - if (oldmon) - arrange(oldmon); - if (m) { - /* Make sure window actually overlaps with the monitor */ - resize(c, c->geom, 0); - c->tags = newtags - ? newtags - : m->tagset[m->seltags]; /* assign tags of target monitor */ - setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ - setfloating(c, c->isfloating); - } - focusclient(focustop(selmon), 1); - - if (c->swallowing) - setmon(c->swallowing, m, newtags); + /* Scene graph sends surface leave/enter events on move and resize */ + if (oldmon) + arrange(oldmon); + if (m) { + /* Make sure window actually overlaps with the monitor */ + resize(c, c->geom, 0); + c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ + setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ + setfloating(c, c->isfloating); + } + focusclient(focustop(selmon), 1); } -void setpsel(struct wl_listener *listener, void *data) { - /* This event is raised by the seat when a client wants to set the selection, - * usually when the user copies something. wlroots allows compositors to - * ignore such requests if they so choose, but in dwl we always honor - */ - struct wlr_seat_request_set_primary_selection_event *event = data; - wlr_seat_set_primary_selection(seat, event->source, event->serial); +void +setpsel(struct wl_listener *listener, void *data) +{ + /* This event is raised by the seat when a client wants to set the selection, + * usually when the user copies something. wlroots allows compositors to + * ignore such requests if they so choose, but in dwl we always honor + */ + struct wlr_seat_request_set_primary_selection_event *event = data; + wlr_seat_set_primary_selection(seat, event->source, event->serial); } -void setsel(struct wl_listener *listener, void *data) { - /* This event is raised by the seat when a client wants to set the selection, - * usually when the user copies something. wlroots allows compositors to - * ignore such requests if they so choose, but in dwl we always honor - */ - struct wlr_seat_request_set_selection_event *event = data; - wlr_seat_set_selection(seat, event->source, event->serial); +void +setsel(struct wl_listener *listener, void *data) +{ + /* This event is raised by the seat when a client wants to set the selection, + * usually when the user copies something. wlroots allows compositors to + * ignore such requests if they so choose, but in dwl we always honor + */ + struct wlr_seat_request_set_selection_event *event = data; + wlr_seat_set_selection(seat, event->source, event->serial); } -void setup(void) { - int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; - struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; - sigemptyset(&sa.sa_mask); +void +setup(void) +{ + int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; + sigemptyset(&sa.sa_mask); - for (i = 0; i < (int)LENGTH(sig); i++) - sigaction(sig[i], &sa, NULL); + for (i = 0; i < (int)LENGTH(sig); i++) + sigaction(sig[i], &sa, NULL); - wlr_log_init(log_level, NULL); + wlr_log_init(log_level, NULL); - /* The Wayland display is managed by libwayland. It handles accepting - * clients from the Unix socket, manging Wayland globals, and so on. */ - dpy = wl_display_create(); - event_loop = wl_display_get_event_loop(dpy); + /* The Wayland display is managed by libwayland. It handles accepting + * clients from the Unix socket, manging Wayland globals, and so on. */ + dpy = wl_display_create(); + event_loop = wl_display_get_event_loop(dpy); - /* The backend is a wlroots feature which abstracts the underlying input and - * output hardware. The autocreate option will choose the most suitable - * backend based on the current environment, such as opening an X11 window - * if an X11 server is running. */ - if (!(backend = wlr_backend_autocreate(event_loop, &session))) - die("couldn't create backend"); + /* The backend is a wlroots feature which abstracts the underlying input and + * output hardware. The autocreate option will choose the most suitable + * backend based on the current environment, such as opening an X11 window + * if an X11 server is running. */ + if (!(backend = wlr_backend_autocreate(event_loop, &session))) + die("couldn't create backend"); - /* Initialize the scene graph used to lay out windows */ - scene = wlr_scene_create(); - root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor); - for (i = 0; i < NUM_LAYERS; i++) - layers[i] = wlr_scene_tree_create(&scene->tree); - drag_icon = wlr_scene_tree_create(&scene->tree); - wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node); + /* Initialize the scene graph used to lay out windows */ + scene = wlr_scene_create(); + root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor); + for (i = 0; i < NUM_LAYERS; i++) + layers[i] = wlr_scene_tree_create(&scene->tree); + drag_icon = wlr_scene_tree_create(&scene->tree); + wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node); - /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user - * can also specify a renderer using the WLR_RENDERER env var. - * The renderer is responsible for defining the various pixel formats it - * supports for shared memory, this configures that for clients. */ - if (!(drw = wlr_renderer_autocreate(backend))) - die("couldn't create renderer"); - LISTEN_STATIC(&drw->events.lost, gpureset); + /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user + * can also specify a renderer using the WLR_RENDERER env var. + * The renderer is responsible for defining the various pixel formats it + * supports for shared memory, this configures that for clients. */ + if (!(drw = wlr_renderer_autocreate(backend))) + die("couldn't create renderer"); + LISTEN_STATIC(&drw->events.lost, gpureset); - /* Create shm, drm and linux_dmabuf interfaces by ourselves. - * The simplest way is call: - * wlr_renderer_init_wl_display(drw); - * but we need to create manually the linux_dmabuf interface to integrate it - * with wlr_scene. */ - wlr_renderer_init_wl_shm(drw, dpy); + /* Create shm, drm and linux_dmabuf interfaces by ourselves. + * The simplest way is call: + * wlr_renderer_init_wl_display(drw); + * but we need to create manually the linux_dmabuf interface to integrate it + * with wlr_scene. */ + wlr_renderer_init_wl_shm(drw, dpy); - if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { - wlr_drm_create(dpy, drw); - wlr_scene_set_linux_dmabuf_v1( - scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); - } + if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { + wlr_drm_create(dpy, drw); + wlr_scene_set_linux_dmabuf_v1(scene, + wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); + } - /* Autocreates an allocator for us. - * The allocator is the bridge between the renderer and the backend. It - * handles the buffer creation, allowing wlroots to render onto the - * screen */ - if (!(alloc = wlr_allocator_autocreate(backend, drw))) - die("couldn't create allocator"); + /* Autocreates an allocator for us. + * The allocator is the bridge between the renderer and the backend. It + * handles the buffer creation, allowing wlroots to render onto the + * screen */ + if (!(alloc = wlr_allocator_autocreate(backend, drw))) + die("couldn't create allocator"); - /* This creates some hands-off wlroots interfaces. The compositor is - * necessary for clients to allocate surfaces and the data device manager - * handles the clipboard. Each of these wlroots interfaces has room for you - * to dig your fingers in and play with their behavior if you want. Note that - * the clients cannot set the selection directly without compositor approval, - * see the setsel() function. */ - compositor = wlr_compositor_create(dpy, 6, drw); - wlr_subcompositor_create(dpy); - wlr_data_device_manager_create(dpy); - wlr_export_dmabuf_manager_v1_create(dpy); - wlr_screencopy_manager_v1_create(dpy); - wlr_data_control_manager_v1_create(dpy); - wlr_primary_selection_v1_device_manager_create(dpy); - wlr_viewporter_create(dpy); - wlr_single_pixel_buffer_manager_v1_create(dpy); - wlr_fractional_scale_manager_v1_create(dpy, 1); - wlr_presentation_create(dpy, backend); - wlr_alpha_modifier_v1_create(dpy); + /* This creates some hands-off wlroots interfaces. The compositor is + * necessary for clients to allocate surfaces and the data device manager + * handles the clipboard. Each of these wlroots interfaces has room for you + * to dig your fingers in and play with their behavior if you want. Note that + * the clients cannot set the selection directly without compositor approval, + * see the setsel() function. */ + compositor = wlr_compositor_create(dpy, 6, drw); + wlr_subcompositor_create(dpy); + wlr_data_device_manager_create(dpy); + wlr_export_dmabuf_manager_v1_create(dpy); + wlr_screencopy_manager_v1_create(dpy); + wlr_data_control_manager_v1_create(dpy); + wlr_primary_selection_v1_device_manager_create(dpy); + wlr_viewporter_create(dpy); + wlr_single_pixel_buffer_manager_v1_create(dpy); + wlr_fractional_scale_manager_v1_create(dpy, 1); + wlr_presentation_create(dpy, backend); + wlr_alpha_modifier_v1_create(dpy); - /* Initializes the interface used to implement urgency hints */ - activation = wlr_xdg_activation_v1_create(dpy); - LISTEN_STATIC(&activation->events.request_activate, urgent); + /* Initializes the interface used to implement urgency hints */ + activation = wlr_xdg_activation_v1_create(dpy); + LISTEN_STATIC(&activation->events.request_activate, urgent); - gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy); - LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma); + gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy); + LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma); - power_mgr = wlr_output_power_manager_v1_create(dpy); - LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode); + power_mgr = wlr_output_power_manager_v1_create(dpy); + LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode); - /* Creates an output layout, which a wlroots utility for working with an - * arrangement of screens in a physical layout. */ - output_layout = wlr_output_layout_create(dpy); - LISTEN_STATIC(&output_layout->events.change, updatemons); - wlr_xdg_output_manager_v1_create(dpy, output_layout); + /* Creates an output layout, which a wlroots utility for working with an + * arrangement of screens in a physical layout. */ + output_layout = wlr_output_layout_create(dpy); + LISTEN_STATIC(&output_layout->events.change, updatemons); + wlr_xdg_output_manager_v1_create(dpy, output_layout); - /* Configure a listener to be notified when new outputs are available on the - * backend. */ - wl_list_init(&mons); - LISTEN_STATIC(&backend->events.new_output, createmon); + /* Configure a listener to be notified when new outputs are available on the + * backend. */ + wl_list_init(&mons); + LISTEN_STATIC(&backend->events.new_output, createmon); - /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell - * is a Wayland protocol which is used for application windows. For more - * detail on shells, refer to the article: - * - * https://drewdevault.com/2018/07/29/Wayland-shells.html - */ - wl_list_init(&clients); - wl_list_init(&fstack); + /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a + * Wayland protocol which is used for application windows. For more + * detail on shells, refer to the article: + * + * https://drewdevault.com/2018/07/29/Wayland-shells.html + */ + wl_list_init(&clients); + wl_list_init(&fstack); - xdg_shell = wlr_xdg_shell_create(dpy, 6); - LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); - LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup); + xdg_shell = wlr_xdg_shell_create(dpy, 6); + LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); + LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup); - layer_shell = wlr_layer_shell_v1_create(dpy, 3); - LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); + layer_shell = wlr_layer_shell_v1_create(dpy, 3); + LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); - idle_notifier = wlr_idle_notifier_v1_create(dpy); + idle_notifier = wlr_idle_notifier_v1_create(dpy); - idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); - LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); + idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); + LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); - session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); - wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); - LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr); - locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, - (float[4]){0.1f, 0.1f, 0.1f, 1.0f}); - wlr_scene_node_set_enabled(&locked_bg->node, 0); + session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); + wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); + LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr); + locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, + (float [4]){0.1f, 0.1f, 0.1f, 1.0f}); + wlr_scene_node_set_enabled(&locked_bg->node, 0); - /* Use decoration protocols to negotiate server-side decorations */ - wlr_server_decoration_manager_set_default_mode( - wlr_server_decoration_manager_create(dpy), - WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); - xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); - LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, - createdecoration); + /* Use decoration protocols to negotiate server-side decorations */ + wlr_server_decoration_manager_set_default_mode( + wlr_server_decoration_manager_create(dpy), + WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); + LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); - pointer_constraints = wlr_pointer_constraints_v1_create(dpy); - LISTEN_STATIC(&pointer_constraints->events.new_constraint, - createpointerconstraint); + pointer_constraints = wlr_pointer_constraints_v1_create(dpy); + LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint); - relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); + relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); - /* - * Creates a cursor, which is a wlroots utility for tracking the cursor - * image shown on screen. - */ - cursor = wlr_cursor_create(); - wlr_cursor_attach_output_layout(cursor, output_layout); + /* + * Creates a cursor, which is a wlroots utility for tracking the cursor + * image shown on screen. + */ + cursor = wlr_cursor_create(); + wlr_cursor_attach_output_layout(cursor, output_layout); - /* Creates an xcursor manager, another wlroots utility which loads up - * Xcursor themes to source cursor images from and makes sure that cursor - * images are available at all scale factors on the screen (necessary for - * HiDPI support). Scaled cursors will be loaded with each output. */ - cursor_mgr = wlr_xcursor_manager_create(NULL, 24); - setenv("XCURSOR_SIZE", "24", 1); + /* Creates an xcursor manager, another wlroots utility which loads up + * Xcursor themes to source cursor images from and makes sure that cursor + * images are available at all scale factors on the screen (necessary for + * HiDPI support). Scaled cursors will be loaded with each output. */ + cursor_mgr = wlr_xcursor_manager_create(NULL, 24); + setenv("XCURSOR_SIZE", "24", 1); - /* - * wlr_cursor *only* displays an image on screen. It does not move around - * when the pointer moves. However, we can attach input devices to it, and - * it will generate aggregate events for all of them. In these events, we - * can choose how we want to process them, forwarding them to clients and - * moving the cursor around. More detail on this process is described in - * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html - * - * And more comments are sprinkled throughout the notify functions above. - */ - LISTEN_STATIC(&cursor->events.motion, motionrelative); - LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute); - LISTEN_STATIC(&cursor->events.button, buttonpress); - LISTEN_STATIC(&cursor->events.axis, axisnotify); - LISTEN_STATIC(&cursor->events.frame, cursorframe); + /* + * wlr_cursor *only* displays an image on screen. It does not move around + * when the pointer moves. However, we can attach input devices to it, and + * it will generate aggregate events for all of them. In these events, we + * can choose how we want to process them, forwarding them to clients and + * moving the cursor around. More detail on this process is described in + * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html + * + * And more comments are sprinkled throughout the notify functions above. + */ + LISTEN_STATIC(&cursor->events.motion, motionrelative); + LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute); + LISTEN_STATIC(&cursor->events.button, buttonpress); + LISTEN_STATIC(&cursor->events.axis, axisnotify); + LISTEN_STATIC(&cursor->events.frame, cursorframe); - cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); - LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape); + cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); + LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape); - /* - * Configures a seat, which is a single "seat" at which a user sits and - * operates the computer. This conceptually includes up to one keyboard, - * pointer, touch, and drawing tablet device. We also rig up a listener to - * let us know when new input devices are available on the backend. - */ - LISTEN_STATIC(&backend->events.new_input, inputdevice); - virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); - LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, - virtualkeyboard); - virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy); - LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, - virtualpointer); + /* + * Configures a seat, which is a single "seat" at which a user sits and + * operates the computer. This conceptually includes up to one keyboard, + * pointer, touch, and drawing tablet device. We also rig up a listener to + * let us know when new input devices are available on the backend. + */ + LISTEN_STATIC(&backend->events.new_input, inputdevice); + virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); + LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard); + virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy); + LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, virtualpointer); - seat = wlr_seat_create(dpy, "seat0"); - LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); - LISTEN_STATIC(&seat->events.request_set_selection, setsel); - LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); - LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); - LISTEN_STATIC(&seat->events.start_drag, startdrag); + seat = wlr_seat_create(dpy, "seat0"); + LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); + LISTEN_STATIC(&seat->events.request_set_selection, setsel); + LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); + LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); + LISTEN_STATIC(&seat->events.start_drag, startdrag); - kb_group = createkeyboardgroup(); - wl_list_init(&kb_group->destroy.link); + kb_group = createkeyboardgroup(); + wl_list_init(&kb_group->destroy.link); - output_mgr = wlr_output_manager_v1_create(dpy); - LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); - LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); + output_mgr = wlr_output_manager_v1_create(dpy); + LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); + LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); - /* Make sure XWayland clients don't connect to the parent X server, - * e.g when running in the x11 backend or the wayland backend and the - * compositor has Xwayland support */ - unsetenv("DISPLAY"); + /* Make sure XWayland clients don't connect to the parent X server, + * e.g when running in the x11 backend or the wayland backend and the + * compositor has Xwayland support */ + unsetenv("DISPLAY"); #ifdef XWAYLAND - /* - * Initialise the XWayland X server. - * It will be started when the first X client is started. - */ - if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) { - LISTEN_STATIC(&xwayland->events.ready, xwaylandready); - LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); + /* + * Initialise the XWayland X server. + * It will be started when the first X client is started. + */ + if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) { + LISTEN_STATIC(&xwayland->events.ready, xwaylandready); + LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); - setenv("DISPLAY", xwayland->display_name, 1); - } else { - fprintf(stderr, - "failed to setup XWayland X server, continuing without it\n"); - } + setenv("DISPLAY", xwayland->display_name, 1); + } else { + fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); + } #endif } -void spawn(const Arg *arg) { - if (fork() == 0) { - dup2(STDERR_FILENO, STDOUT_FILENO); - setsid(); - execvp(((char **)arg->v)[0], (char **)arg->v); - die("dwl: execvp %s failed:", ((char **)arg->v)[0]); - } +void +spawn(const Arg *arg) +{ + if (fork() == 0) { + dup2(STDERR_FILENO, STDOUT_FILENO); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + die("dwl: execvp %s failed:", ((char **)arg->v)[0]); + } } -void startdrag(struct wl_listener *listener, void *data) { - struct wlr_drag *drag = data; - if (!drag->icon) - return; +void +startdrag(struct wl_listener *listener, void *data) +{ + struct wlr_drag *drag = data; + if (!drag->icon) + return; - drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node; - LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); + drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node; + LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); } -void swallow(Client *c, Client *toswallow) { - /* Do not allow a client to swallow itself */ - if (c == toswallow) - return; +void +tag(const Arg *arg) +{ + Client *sel = focustop(selmon); + if (!sel || (arg->ui & TAGMASK) == 0) + return; - /* Swallow */ - if (toswallow && !c->swallowing) { - c->swallowing = toswallow; - toswallow->swallowedby = c; - toswallow->mon = c->mon; - toswallow->mon = c->mon; - wl_list_remove(&c->link); - wl_list_insert(&c->swallowing->link, &c->link); - wl_list_remove(&c->flink); - wl_list_insert(&c->swallowing->flink, &c->flink); - c->bw = BORDERPX(c); - c->tags = toswallow->tags; - c->isfloating = toswallow->isfloating; - c->geom = toswallow->geom; - setfullscreen(toswallow, 0); - } - - /* Unswallow */ - else if (c->swallowing) { - wl_list_remove(&c->swallowing->link); - wl_list_insert(&c->link, &c->swallowing->link); - wl_list_remove(&c->swallowing->flink); - wl_list_insert(&c->flink, &c->swallowing->flink); - c->swallowing->tags = c->tags; - c->swallowing->swallowedby = NULL; - c->swallowing = NULL; - c->bw = BORDERPX(c); - setfullscreen(c, 0); - } + sel->tags = arg->ui & TAGMASK; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); } -void tag(const Arg *arg) { - Client *sel = focustop(selmon); - if (!sel || (arg->ui & TAGMASK) == 0) - return; - - sel->tags = arg->ui & TAGMASK; - focusclient(focustop(selmon), 1); - arrange(selmon); - printstatus(); +void +tagmon(const Arg *arg) +{ + Client *sel = focustop(selmon); + if (sel) + setmon(sel, dirtomon(arg->i), 0); } -void tagmon(const Arg *arg) { - Client *sel = focustop(selmon); - if (sel) - setmon(sel, dirtomon(arg->i), 0); +void +tile(Monitor *m) +{ + unsigned int mw, my, ty; + int i, n = 0; + Client *c; + + wl_list_for_each(c, &clients, link) + if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) + n++; + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0; + else + mw = m->w.width; + i = my = ty = 0; + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; + if (i < m->nmaster) { + resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw, + .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0); + my += c->geom.height; + } else { + resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty, + .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0); + ty += c->geom.height; + } + i++; + } } -Client *termforwin(Client *c) { - Client *p; - pid_t pid; - pid_t pids[32]; - size_t i, pids_len; - - if (!c->pid || c->isterm) - return NULL; - - /* Get all parent pids */ - pids_len = 0; - pid = c->pid; - while (pids_len < LENGTH(pids)) { - pid = parentpid(pid); - if (!pid) - break; - pids[pids_len++] = pid; - } - - /* Find closest parent */ - for (i = 0; i < pids_len; i++) { - wl_list_for_each(p, &clients, link) { - if (!p->pid || !p->isterm || p->swallowedby) - continue; - if (pids[i] == p->pid) - return p; - } - } - - return NULL; +void +togglefloating(const Arg *arg) +{ + Client *sel = focustop(selmon); + /* return if fullscreen */ + if (sel && !sel->isfullscreen) + setfloating(sel, !sel->isfloating); } -void tile(Monitor *m) { - unsigned int mw, my, ty; - int i, n = 0; - Client *c; - - wl_list_for_each(c, &clients, link) if (VISIBLEON(c, m) && !c->isfloating && - !c->isfullscreen) n++; - if (n == 0) - return; - - if (n > m->nmaster) - mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0; - else - mw = m->w.width; - i = my = ty = 0; - wl_list_for_each(c, &clients, link) { - if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) - continue; - if (i < m->nmaster) { - resize(c, - (struct wlr_box){.x = m->w.x, - .y = m->w.y + my, - .width = mw, - .height = (m->w.height - my) / - (MIN(n, m->nmaster) - i)}, - 0); - my += c->geom.height; - } else { - resize(c, - (struct wlr_box){.x = m->w.x + mw, - .y = m->w.y + ty, - .width = m->w.width - mw, - .height = (m->w.height - ty) / (n - i)}, - 0); - ty += c->geom.height; - } - i++; - } +void +togglefullscreen(const Arg *arg) +{ + Client *sel = focustop(selmon); + if (sel) + setfullscreen(sel, !sel->isfullscreen); } -void togglefloating(const Arg *arg) { - Client *sel = focustop(selmon); - /* return if fullscreen */ - if (sel && !sel->isfullscreen) - setfloating(sel, !sel->isfloating); +void +toggletag(const Arg *arg) +{ + uint32_t newtags; + Client *sel = focustop(selmon); + if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK))) + return; + + sel->tags = newtags; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); } -void togglefullscreen(const Arg *arg) { - Client *sel = focustop(selmon); - if (sel) - setfullscreen(sel, !sel->isfullscreen); +void +toggleview(const Arg *arg) +{ + uint32_t newtagset; + if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0)) + return; + + selmon->tagset[selmon->seltags] = newtagset; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); } -void toggleswallow(const Arg *arg) { - Client *c, *sel = focustop(selmon); - if (!sel) - return; - - if (sel->swallowing) { - swallow(sel, NULL); - } else { - wl_list_for_each(c, &sel->flink, flink) { - if (&c->flink == &fstack) - continue; /* wrap past the sentinel node */ - if (VISIBLEON(c, selmon)) - break; /* found it */ - } - swallow(sel, c); - } +void +unlocksession(struct wl_listener *listener, void *data) +{ + SessionLock *lock = wl_container_of(listener, lock, unlock); + destroylock(lock, 1); } -void toggleautoswallow(const Arg *arg) { - enableautoswallow = !enableautoswallow; +void +unmaplayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *l = wl_container_of(listener, l, unmap); + + l->mapped = 0; + wlr_scene_node_set_enabled(&l->scene->node, 0); + if (l == exclusive_focus) + exclusive_focus = NULL; + if (l->layer_surface->output && (l->mon = l->layer_surface->output->data)) + arrangelayers(l->mon); + if (l->layer_surface->surface == seat->keyboard_state.focused_surface) + focusclient(focustop(selmon), 1); + motionnotify(0, NULL, 0, 0, 0, 0); } -void toggletag(const Arg *arg) { - uint32_t newtags; - Client *sel = focustop(selmon); - if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK))) - return; +void +unmapnotify(struct wl_listener *listener, void *data) +{ + /* Called when the surface is unmapped, and should no longer be shown. */ + Client *c = wl_container_of(listener, c, unmap); + if (c == grabc) { + cursor_mode = CurNormal; + grabc = NULL; + } - sel->tags = newtags; - focusclient(focustop(selmon), 1); - arrange(selmon); - printstatus(); + if (client_is_unmanaged(c)) { + if (c == exclusive_focus) { + exclusive_focus = NULL; + focusclient(focustop(selmon), 1); + } + } else { + wl_list_remove(&c->link); + setmon(c, NULL, 0); + wl_list_remove(&c->flink); + } + + wlr_scene_node_destroy(&c->scene->node); + printstatus(); + motionnotify(0, NULL, 0, 0, 0, 0); } -void toggleview(const Arg *arg) { - uint32_t newtagset; - if (!(newtagset = - selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0)) - return; +void +updatemons(struct wl_listener *listener, void *data) +{ + /* + * Called whenever the output layout changes: adding or removing a + * monitor, changing an output's mode or position, etc. This is where + * the change officially happens and we update geometry, window + * positions, focus, and the stored configuration in wlroots' + * output-manager implementation. + */ + struct wlr_output_configuration_v1 *config + = wlr_output_configuration_v1_create(); + Client *c; + struct wlr_output_configuration_head_v1 *config_head; + Monitor *m; - selmon->tagset[selmon->seltags] = newtagset; - focusclient(focustop(selmon), 1); - arrange(selmon); - printstatus(); + /* First remove from the layout the disabled monitors */ + wl_list_for_each(m, &mons, link) { + if (m->wlr_output->enabled || m->asleep) + continue; + config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); + config_head->state.enabled = 0; + /* Remove this output from the layout to avoid cursor enter inside it */ + wlr_output_layout_remove(output_layout, m->wlr_output); + closemon(m); + m->m = m->w = (struct wlr_box){0}; + } + /* Insert outputs that need to */ + wl_list_for_each(m, &mons, link) { + if (m->wlr_output->enabled + && !wlr_output_layout_get(output_layout, m->wlr_output)) + wlr_output_layout_add_auto(output_layout, m->wlr_output); + } + + /* Now that we update the output layout we can get its box */ + wlr_output_layout_get_box(output_layout, NULL, &sgeom); + + wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y); + wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height); + + /* Make sure the clients are hidden when dwl is locked */ + wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y); + wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); + + wl_list_for_each(m, &mons, link) { + if (!m->wlr_output->enabled) + continue; + config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); + + /* Get the effective monitor geometry to use for surfaces */ + wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m); + m->w = m->m; + wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); + + wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); + wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); + + if (m->lock_surface) { + struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data; + wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); + wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height); + } + + /* Calculate the effective monitor geometry to use for clients */ + arrangelayers(m); + /* Don't move clients to the left output when plugging monitors */ + arrange(m); + /* make sure fullscreen clients have the right size */ + if ((c = focustop(m)) && c->isfullscreen) + resize(c, m->m, 0); + + /* Try to re-set the gamma LUT when updating monitors, + * it's only really needed when enabling a disabled output, but meh. */ + m->gamma_lut_changed = 1; + + config_head->state.x = m->m.x; + config_head->state.y = m->m.y; + + if (!selmon) { + selmon = m; + } + } + + if (selmon && selmon->wlr_output->enabled) { + wl_list_for_each(c, &clients, link) { + if (!c->mon && client_surface(c)->mapped) + setmon(c, selmon, c->tags); + } + focusclient(focustop(selmon), 1); + if (selmon->lock_surface) { + client_notify_enter(selmon->lock_surface->surface, + wlr_seat_get_keyboard(seat)); + client_activate_surface(selmon->lock_surface->surface, 1); + } + } + + /* FIXME: figure out why the cursor image is at 0,0 after turning all + * the monitors on. + * Move the cursor image where it used to be. It does not generate a + * wl_pointer.motion event for the clients, it's only the image what it's + * at the wrong position after all. */ + wlr_cursor_move(cursor, NULL, 0, 0); + + wlr_output_manager_v1_set_configuration(output_mgr, config); } -void unlocksession(struct wl_listener *listener, void *data) { - SessionLock *lock = wl_container_of(listener, lock, unlock); - destroylock(lock, 1); +void +updatetitle(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, set_title); + if (c == focustop(c->mon)) + printstatus(); } -void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *l = wl_container_of(listener, l, unmap); +void +urgent(struct wl_listener *listener, void *data) +{ + struct wlr_xdg_activation_v1_request_activate_event *event = data; + Client *c = NULL; + toplevel_from_wlr_surface(event->surface, &c, NULL); + if (!c || c == focustop(selmon)) + return; - l->mapped = 0; - wlr_scene_node_set_enabled(&l->scene->node, 0); - if (l == exclusive_focus) - exclusive_focus = NULL; - if (l->layer_surface->output && (l->mon = l->layer_surface->output->data)) - arrangelayers(l->mon); - if (l->layer_surface->surface == seat->keyboard_state.focused_surface) - focusclient(focustop(selmon), 1); - motionnotify(0, NULL, 0, 0, 0, 0); + c->isurgent = 1; + printstatus(); + + if (client_surface(c)->mapped) + client_set_border_color(c, urgentcolor); } -void unmapnotify(struct wl_listener *listener, void *data) { - /* Called when the surface is unmapped, and should no longer be shown. */ - Client *c = wl_container_of(listener, c, unmap); - if (c == grabc) { - cursor_mode = CurNormal; - grabc = NULL; - } - - if (c->swallowing) { - swallow(c, NULL); - } else if (c->swallowedby) { - swallow(c->swallowedby, NULL); - } - - if (client_is_unmanaged(c)) { - if (c == exclusive_focus) { - exclusive_focus = NULL; - focusclient(focustop(selmon), 1); - } - } else { - wl_list_remove(&c->link); - setmon(c, NULL, 0); - wl_list_remove(&c->flink); - } - - wlr_scene_node_destroy(&c->scene->node); - printstatus(); - motionnotify(0, NULL, 0, 0, 0, 0); +void +view(const Arg *arg) +{ + if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); } -void updatemons(struct wl_listener *listener, void *data) { - /* - * Called whenever the output layout changes: adding or removing a - * monitor, changing an output's mode or position, etc. This is where - * the change officially happens and we update geometry, window - * positions, focus, and the stored configuration in wlroots' - * output-manager implementation. - */ - struct wlr_output_configuration_v1 *config = - wlr_output_configuration_v1_create(); - Client *c; - struct wlr_output_configuration_head_v1 *config_head; - Monitor *m; +void +virtualkeyboard(struct wl_listener *listener, void *data) +{ + struct wlr_virtual_keyboard_v1 *kb = data; + /* virtual keyboards shouldn't share keyboard group */ + KeyboardGroup *group = createkeyboardgroup(); + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); + LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup); - /* First remove from the layout the disabled monitors */ - wl_list_for_each(m, &mons, link) { - if (m->wlr_output->enabled || m->asleep) - continue; - config_head = - wlr_output_configuration_head_v1_create(config, m->wlr_output); - config_head->state.enabled = 0; - /* Remove this output from the layout to avoid cursor enter inside it */ - wlr_output_layout_remove(output_layout, m->wlr_output); - closemon(m); - m->m = m->w = (struct wlr_box){0}; - } - /* Insert outputs that need to */ - wl_list_for_each(m, &mons, link) { - if (m->wlr_output->enabled && - !wlr_output_layout_get(output_layout, m->wlr_output)) - wlr_output_layout_add_auto(output_layout, m->wlr_output); - } - - /* Now that we update the output layout we can get its box */ - wlr_output_layout_get_box(output_layout, NULL, &sgeom); - - wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y); - wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height); - - /* Make sure the clients are hidden when dwl is locked */ - wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y); - wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); - - wl_list_for_each(m, &mons, link) { - if (!m->wlr_output->enabled) - continue; - config_head = - wlr_output_configuration_head_v1_create(config, m->wlr_output); - - /* Get the effective monitor geometry to use for surfaces */ - wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m); - m->w = m->m; - wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); - - wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); - wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); - - if (m->lock_surface) { - struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data; - wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); - wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, - m->m.height); - } - - /* Calculate the effective monitor geometry to use for clients */ - arrangelayers(m); - /* Don't move clients to the left output when plugging monitors */ - arrange(m); - /* make sure fullscreen clients have the right size */ - if ((c = focustop(m)) && c->isfullscreen) - resize(c, m->m, 0); - - /* Try to re-set the gamma LUT when updating monitors, - * it's only really needed when enabling a disabled output, but meh. */ - m->gamma_lut_changed = 1; - - config_head->state.x = m->m.x; - config_head->state.y = m->m.y; - - if (!selmon) { - selmon = m; - } - } - - if (selmon && selmon->wlr_output->enabled) { - wl_list_for_each(c, &clients, link) { - if (!c->mon && client_surface(c)->mapped) - setmon(c, selmon, c->tags); - } - focusclient(focustop(selmon), 1); - if (selmon->lock_surface) { - client_notify_enter(selmon->lock_surface->surface, - wlr_seat_get_keyboard(seat)); - client_activate_surface(selmon->lock_surface->surface, 1); - } - } - - /* FIXME: figure out why the cursor image is at 0,0 after turning all - * the monitors on. - * Move the cursor image where it used to be. It does not generate a - * wl_pointer.motion event for the clients, it's only the image what it's - * at the wrong position after all. */ - wlr_cursor_move(cursor, NULL, 0, 0); - - wlr_output_manager_v1_set_configuration(output_mgr, config); + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); } -void updatetitle(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, set_title); - if (c == focustop(c->mon)) - printstatus(); +void +virtualpointer(struct wl_listener *listener, void *data) +{ + struct wlr_virtual_pointer_v1_new_pointer_event *event = data; + struct wlr_input_device *device = &event->new_pointer->pointer.base; + + wlr_cursor_attach_input_device(cursor, device); + if (event->suggested_output) + wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); } -void urgent(struct wl_listener *listener, void *data) { - struct wlr_xdg_activation_v1_request_activate_event *event = data; - Client *c = NULL; - toplevel_from_wlr_surface(event->surface, &c, NULL); - if (!c || c == focustop(selmon)) - return; - - c->isurgent = 1; - printstatus(); - - if (client_surface(c)->mapped) - client_set_border_color(c, urgentcolor); +Monitor * +xytomon(double x, double y) +{ + struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); + return o ? o->data : NULL; } -void view(const Arg *arg) { - if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) - return; - selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) - selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; - focusclient(focustop(selmon), 1); - arrange(selmon); - printstatus(); +void +xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny) +{ + struct wlr_scene_node *node, *pnode; + struct wlr_surface *surface = NULL; + Client *c = NULL; + LayerSurface *l = NULL; + int layer; + + for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { + if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) + continue; + + if (node->type == WLR_SCENE_NODE_BUFFER) + surface = wlr_scene_surface_try_from_buffer( + wlr_scene_buffer_from_node(node))->surface; + /* Walk the tree to find a node that knows the client */ + for (pnode = node; pnode && !c; pnode = &pnode->parent->node) + c = pnode->data; + if (c && c->type == LayerShell) { + c = NULL; + l = pnode->data; + } + } + + if (psurface) *psurface = surface; + if (pc) *pc = c; + if (pl) *pl = l; } -void virtualkeyboard(struct wl_listener *listener, void *data) { - struct wlr_virtual_keyboard_v1 *kb = data; - /* virtual keyboards shouldn't share keyboard group */ - KeyboardGroup *group = createkeyboardgroup(); - /* Set the keymap to match the group keymap */ - wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); - LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, - destroykeyboardgroup); +void +zoom(const Arg *arg) +{ + Client *c, *sel = focustop(selmon); - /* Add the new keyboard to the group */ - wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); -} + if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) + return; -void virtualpointer(struct wl_listener *listener, void *data) { - struct wlr_virtual_pointer_v1_new_pointer_event *event = data; - struct wlr_input_device *device = &event->new_pointer->pointer.base; + /* Search for the first tiled window that is not sel, marking sel as + * NULL if we pass it along the way */ + wl_list_for_each(c, &clients, link) { + if (VISIBLEON(c, selmon) && !c->isfloating) { + if (c != sel) + break; + sel = NULL; + } + } - wlr_cursor_attach_input_device(cursor, device); - if (event->suggested_output) - wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); -} + /* Return if no other tiled window was found */ + if (&c->link == &clients) + return; -Monitor *xytomon(double x, double y) { - struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); - return o ? o->data : NULL; -} + /* If we passed sel, move c to the front; otherwise, move sel to the + * front */ + if (!sel) + sel = c; + wl_list_remove(&sel->link); + wl_list_insert(&clients, &sel->link); -void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, - LayerSurface **pl, double *nx, double *ny) { - struct wlr_scene_node *node, *pnode; - struct wlr_surface *surface = NULL; - Client *c = NULL; - LayerSurface *l = NULL; - int layer; - - for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { - if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) - continue; - - if (node->type == WLR_SCENE_NODE_BUFFER) - surface = - wlr_scene_surface_try_from_buffer(wlr_scene_buffer_from_node(node)) - ->surface; - /* Walk the tree to find a node that knows the client */ - for (pnode = node; pnode && !c; pnode = &pnode->parent->node) - c = pnode->data; - if (c && c->type == LayerShell) { - c = NULL; - l = pnode->data; - } - } - - if (psurface) - *psurface = surface; - if (pc) - *pc = c; - if (pl) - *pl = l; -} - -void zoom(const Arg *arg) { - Client *c, *sel = focustop(selmon); - - if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) - return; - - /* Search for the first tiled window that is not sel, marking sel as - * NULL if we pass it along the way */ - wl_list_for_each(c, &clients, link) { - if (VISIBLEON(c, selmon) && !c->isfloating) { - if (c != sel) - break; - sel = NULL; - } - } - - /* Return if no other tiled window was found */ - if (&c->link == &clients) - return; - - /* If we passed sel, move c to the front; otherwise, move sel to the - * front */ - if (!sel) - sel = c; - wl_list_remove(&sel->link); - wl_list_insert(&clients, &sel->link); - - focusclient(sel, 1); - arrange(selmon); + focusclient(sel, 1); + arrange(selmon); } #ifdef XWAYLAND -void activatex11(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, activate); +void +activatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, activate); - /* Only "managed" windows can be activated */ - if (!client_is_unmanaged(c)) - wlr_xwayland_surface_activate(c->surface.xwayland, 1); + /* Only "managed" windows can be activated */ + if (!client_is_unmanaged(c)) + wlr_xwayland_surface_activate(c->surface.xwayland, 1); } -void associatex11(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, associate); +void +associatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, associate); - LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); - LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); + LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); + LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); } -void configurex11(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, configure); - struct wlr_xwayland_surface_configure_event *event = data; - /* TODO: figure out if there is another way to do this */ - if (!c->mon) { - wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y, - event->width, event->height); - return; - } - if (c->isfloating || client_is_unmanaged(c)) - resize(c, - (struct wlr_box){.x = event->x, - .y = event->y, - .width = event->width + c->bw * 2, - .height = event->height + c->bw * 2}, - 0); - else - arrange(c->mon); +void +configurex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, configure); + struct wlr_xwayland_surface_configure_event *event = data; + /* TODO: figure out if there is another way to do this */ + if (!c->mon) { + wlr_xwayland_surface_configure(c->surface.xwayland, + event->x, event->y, event->width, event->height); + return; + } + if (c->isfloating || client_is_unmanaged(c)) + resize(c, (struct wlr_box){.x = event->x, .y = event->y, + .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0); + else + arrange(c->mon); } -void createnotifyx11(struct wl_listener *listener, void *data) { - struct wlr_xwayland_surface *xsurface = data; - Client *c; +void +createnotifyx11(struct wl_listener *listener, void *data) +{ + struct wlr_xwayland_surface *xsurface = data; + Client *c; - /* Allocate a Client for this surface */ - c = xsurface->data = ecalloc(1, sizeof(*c)); - c->surface.xwayland = xsurface; - c->type = X11; - c->bw = client_is_unmanaged(c) ? 0 : borderpx; + /* Allocate a Client for this surface */ + c = xsurface->data = ecalloc(1, sizeof(*c)); + c->surface.xwayland = xsurface; + c->type = X11; + c->bw = client_is_unmanaged(c) ? 0 : borderpx; - /* Listen to the various events it can emit */ - LISTEN(&xsurface->events.associate, &c->associate, associatex11); - LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11); - LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); - LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); - LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, - fullscreennotify); - LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); - LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); + /* Listen to the various events it can emit */ + LISTEN(&xsurface->events.associate, &c->associate, associatex11); + LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11); + LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); + LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); + LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); + LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); + LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); } -void dissociatex11(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, dissociate); - wl_list_remove(&c->map.link); - wl_list_remove(&c->unmap.link); +void +dissociatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, dissociate); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); } -xcb_atom_t getatom(xcb_connection_t *xc, const char *name) { - xcb_atom_t atom = 0; - xcb_intern_atom_reply_t *reply; - xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name); - if ((reply = xcb_intern_atom_reply(xc, cookie, NULL))) - atom = reply->atom; - free(reply); +xcb_atom_t +getatom(xcb_connection_t *xc, const char *name) +{ + xcb_atom_t atom = 0; + xcb_intern_atom_reply_t *reply; + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name); + if ((reply = xcb_intern_atom_reply(xc, cookie, NULL))) + atom = reply->atom; + free(reply); - return atom; + return atom; } -void sethints(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, set_hints); - struct wlr_surface *surface = client_surface(c); - if (c == focustop(selmon)) - return; +void +sethints(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, set_hints); + struct wlr_surface *surface = client_surface(c); + if (c == focustop(selmon)) + return; - c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); - printstatus(); + c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); + printstatus(); - if (c->isurgent && surface && surface->mapped) - client_set_border_color(c, urgentcolor); + if (c->isurgent && surface && surface->mapped) + client_set_border_color(c, urgentcolor); } -void xwaylandready(struct wl_listener *listener, void *data) { - struct wlr_xcursor *xcursor; - xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL); - int err = xcb_connection_has_error(xc); - if (err) { - fprintf(stderr, - "xcb_connect to X server failed with code %d\n. Continuing with " - "degraded functionality.\n", - err); - return; - } +void +xwaylandready(struct wl_listener *listener, void *data) +{ + struct wlr_xcursor *xcursor; + xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL); + int err = xcb_connection_has_error(xc); + if (err) { + fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err); + return; + } - /* Collect atoms we are interested in. If getatom returns 0, we will - * not detect that window type. */ - netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG"); - netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH"); - netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR"); - netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY"); + /* Collect atoms we are interested in. If getatom returns 0, we will + * not detect that window type. */ + netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG"); + netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH"); + netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR"); + netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY"); - /* assign the one and only seat */ - wlr_xwayland_set_seat(xwayland, seat); + /* assign the one and only seat */ + wlr_xwayland_set_seat(xwayland, seat); - /* Set the default XWayland cursor to match the rest of dwl. */ - if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) - wlr_xwayland_set_cursor( - xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4, - xcursor->images[0]->width, xcursor->images[0]->height, - xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); + /* Set the default XWayland cursor to match the rest of dwl. */ + if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) + wlr_xwayland_set_cursor(xwayland, + xcursor->images[0]->buffer, xcursor->images[0]->width * 4, + xcursor->images[0]->width, xcursor->images[0]->height, + xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); - xcb_disconnect(xc); + xcb_disconnect(xc); } #endif -int main(int argc, char *argv[]) { - char *startup_cmd = NULL; - int c; +int +main(int argc, char *argv[]) +{ + char *startup_cmd = NULL; + int c; - while ((c = getopt(argc, argv, "s:hdv")) != -1) { - if (c == 's') - startup_cmd = optarg; - else if (c == 'd') - log_level = WLR_DEBUG; - else if (c == 'v') - die("dwl " VERSION); - else - goto usage; - } - if (optind < argc) - goto usage; + while ((c = getopt(argc, argv, "s:hdv")) != -1) { + if (c == 's') + startup_cmd = optarg; + else if (c == 'd') + log_level = WLR_DEBUG; + else if (c == 'v') + die("dwl " VERSION); + else + goto usage; + } + if (optind < argc) + goto usage; - /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ - if (!getenv("XDG_RUNTIME_DIR")) - die("XDG_RUNTIME_DIR must be set"); - setup(); - run(startup_cmd); - cleanup(); - return EXIT_SUCCESS; + /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ + if (!getenv("XDG_RUNTIME_DIR")) + die("XDG_RUNTIME_DIR must be set"); + setup(); + run(startup_cmd); + cleanup(); + return EXIT_SUCCESS; usage: - die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); + die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); } diff --git a/dwl/dwl-v0.7_bak/CHANGELOG.md b/dwl/dwl-v0.7_bak/CHANGELOG.md new file mode 100644 index 00000000..3a299c46 --- /dev/null +++ b/dwl/dwl-v0.7_bak/CHANGELOG.md @@ -0,0 +1,200 @@ +# Changelog + +* [0.7](#0.7) +* [0.6](#0.6) +* [0.5](#0.5) + + +## 0.7 + +See also [0.6](#0.6) release notes. 0.7 builds against wlroots 0.18.x. + +### Added + +* Add support for the alpha-modifier-v1 protocol ([wlroots!4616][wlroots!4616]). +* dwl now will survive GPU resets ([#601][601]). + +[wlroots!4616]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4616 +[601]: https://codeberg.org/dwl/dwl/issues/601 + + +### Fixed + +* Crash when re-mapping unmapped clients. + + +### Contributors + +Guido Cella +Lennart Jablonka + + +## 0.6 + +### Added + +* Add `rootcolor` to change the default background color ([#544][544]). +* Implement the wlr-virtual-pointer-unstable-v1 protocol ([#574][574]). +* Implement the pointer-constraints and relative-pointer protocols ([#317][317]) +* Implement the wlr-output-power-management protocol ([#599][599]) + +[544]: https://codeberg.org/dwl/dwl/pulls/544 +[574]: https://codeberg.org/dwl/dwl/pulls/574 +[317]: https://codeberg.org/dwl/dwl/issues/317 +[599]: https://codeberg.org/dwl/dwl/issues/559 + + +### Changed + +* Keyboards are now managed through keyboard groups ([#549][549]). +* Only the first matched keybinding is executed. +* Allow toggling the layout before selecting a different one ([#570][570]). +* Fullscreen clients are now rendered above wlr_layer_surfaces in the top layer + ([#609][609]). +* The default menu was changed from `bemenu-run` to `wmenu-run` ([#553][553]). +* The option `sloppyfocus` now replicates the dwm behavior ([#599][599]). +* Allow configure position of monitors with negative values. (-1, -1) is + used to auto-configure them ([#635][635]). +* dwl now kills the entire process group of `startup_cmd` +* The O_NONBLOCK flag is set for stdout. + +[549]: https://codeberg.org/dwl/dwl/pulls/549 +[570]: https://codeberg.org/dwl/dwl/pulls/570 +[609]: https://codeberg.org/dwl/dwl/pulls/609 +[553]: https://codeberg.org/dwl/dwl/issues/553 +[599]: https://codeberg.org/dwl/dwl/pulls/599 +[635]: https://codeberg.org/dwl/dwl/pulls/635 + + +### Removed + +* The SLOC limit is now removed ([#497][497]). + +[497]: https://codeberg.org/dwl/dwl/pulls/497 + + +### Fixed + +* Clients not having the correct border color when mapping. +* Compliance with the xdg-decoration-unstable-v1 ([#546][546]). +* dwl no longer sends negative values in xdg_toplevel.configure events. +* Crashes with disabled monitors ([#472][472]). + +[546]: https://codeberg.org/dwl/dwl/pulls/546 +[472]: https://codeberg.org/dwl/dwl/issues/472 + + +### Contributors + +Ben Jargowsky +Benjamin Chausse +David Donahue +Devin J. Pohly +Dima Krasner +Emil Miler +Forrest Bushstone +Guido Cella +Peter Hofmann +Rutherther +Squibid +choc +fictitiousexistence +korei999 +sewn +thanatos + + +## 0.5 + +### Added + +* Allow configure x and y position of outputs ([#301][301]) +* Implement repeatable keybindings ([#368][368]) +* Print app id in printstatus() output ([#381][381]) +* Display client count in monocle symbol ([#387][387]) +* Export XCURSOR_SIZE to fix apps using an older version of Qt ([#425][425]) +* Support for wp-fractional-scale-v1 (through wlr_scene: [wlroots!3511][wlroots!3511]) +* dwl now sends `wl_surface.preferred_buffer_scale` (through wlr_scene: [wlroots!4269][wlroots!4269]) +* Add support for xdg-shell v6 ([#465][465]) +* Add support for wp-cursor-shape-v1 ([#444][444]) +* Add desktop file ([#484][484]) +* Add macro to easily configure colors ([#466][466]) +* Color of urgent clients are now red ([#494][494]) +* New flag `-d` and option `log_level` to change the wlroots debug level +* Add CHANGELOG.md ([#501][501]) + +[301]: https://github.com/djpohly/dwl/pull/301 +[368]: https://github.com/djpohly/dwl/pull/368 +[381]: https://github.com/djpohly/dwl/pull/381 +[387]: https://github.com/djpohly/dwl/issues/387 +[425]: https://github.com/djpohly/dwl/pull/425 +[wlroots!4269]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4269 +[wlroots!3511]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3511 +[465]: https://github.com/djpohly/dwl/pull/465 +[444]: https://github.com/djpohly/dwl/pull/444 +[484]: https://github.com/djpohly/dwl/pull/484 +[466]: https://github.com/djpohly/dwl/issues/466 +[494]: https://github.com/djpohly/dwl/pull/494 +[501]: https://github.com/djpohly/dwl/pull/501 + + +### Changed + +* Replace `tags` with `TAGCOUNT` in config.def.h ([#403][403]) +* Pop ups are now destroyed when focusing another client ([#408][408]) +* dwl does not longer respect size hints, instead clip windows if they are + larger than they should be ([#455][455]) +* The version of wlr-layer-shell-unstable-v1 was lowered to 3 (from 4) +* Use the same border color as dwm ([#494][494]) + +[403]: https://github.com/djpohly/dwl/pull/403 +[408]: https://github.com/djpohly/dwl/pull/409 +[455]: https://github.com/djpohly/dwl/pull/455 +[494]: https://github.com/djpohly/dwl/pull/494 + + +### Removed + +* Remove unused `rootcolor` option ([#401][401]) +* Remove support for wlr-input-inhibitor-unstable-v1 ([#430][430]) +* Remove support for KDE idle protocol ([#431][431]) + +[401]: https://github.com/djpohly/dwl/pull/401 +[430]: https://github.com/djpohly/dwl/pull/430 +[431]: https://github.com/djpohly/dwl/pull/431 + + +### Fixed + +* Fix crash when creating a layer surface with all outputs disabled + ([#421][421]) +* Fix other clients being shown as focused if the focused client have pop ups + open ([#408][408]) +* Resize fullscreen clients when updating monitor mode +* dwl no longer crash at exit like sometimes did +* Fullscreen background appearing above clients ([#487][487]) +* Fix a segfault when user provides invalid xkb_rules ([#518][518]) + +[421]: https://github.com/djpohly/dwl/pull/421 +[408]: https://github.com/djpohly/dwl/issues/408 +[487]: https://github.com/djpohly/dwl/issues/487 +[518]: https://github.com/djpohly/dwl/pull/518 + + +### Contributors + +* A Frederick Christensen +* Angelo Antony +* Ben Collerson +* Devin J. Pohly +* Forrest Bushstone +* gan-of-culture +* godalming123 +* Job79 +* link2xt +* Micah Gorrell +* Nikita Ivanov +* Palanix +* pino-desktop +* Weiseguy +* Yves Zoundi diff --git a/dwl/dwl-v0.7_bak/LICENSE b/dwl/dwl-v0.7_bak/LICENSE new file mode 100644 index 00000000..658085a4 --- /dev/null +++ b/dwl/dwl-v0.7_bak/LICENSE @@ -0,0 +1,692 @@ +dwl - dwm for Wayland + +Copyright © 2020 dwl team + +See also the files LICENSE.tinywl, LICENSE.dwm and LICENSE.sway. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +---- + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/dwl/dwl-v0.7_bak/LICENSE.dwm b/dwl/dwl-v0.7_bak/LICENSE.dwm new file mode 100644 index 00000000..507e4dce --- /dev/null +++ b/dwl/dwl-v0.7_bak/LICENSE.dwm @@ -0,0 +1,39 @@ +Portions of dwl based on dwm code are used under the following license: + +MIT/X Consortium License + +© 2006-2019 Anselm R Garbe +© 2006-2009 Jukka Salmi +© 2006-2007 Sander van Dijk +© 2007-2011 Peter Hartlich +© 2007-2009 Szabolcs Nagy +© 2007-2009 Christof Musik +© 2007-2009 Premysl Hruby +© 2007-2008 Enno Gottox Boland +© 2008 Martin Hurton +© 2008 Neale Pickett +© 2009 Mate Nagy +© 2010-2016 Hiltjo Posthuma +© 2010-2012 Connor Lane Smith +© 2011 Christoph Lohmann <20h@r-36.net> +© 2015-2016 Quentin Rameau +© 2015-2016 Eric Pruitt +© 2016-2017 Markus Teich + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/dwl/dwl-v0.7_bak/LICENSE.sway b/dwl/dwl-v0.7_bak/LICENSE.sway new file mode 100644 index 00000000..3e0cacc2 --- /dev/null +++ b/dwl/dwl-v0.7_bak/LICENSE.sway @@ -0,0 +1,19 @@ +Copyright (c) 2016-2017 Drew DeVault + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dwl/dwl-v0.7_bak/LICENSE.tinywl b/dwl/dwl-v0.7_bak/LICENSE.tinywl new file mode 100644 index 00000000..70236904 --- /dev/null +++ b/dwl/dwl-v0.7_bak/LICENSE.tinywl @@ -0,0 +1,127 @@ +dwl is originally based on TinyWL, which is used under the following license: + +This work is licensed under CC0, which effectively puts it in the public domain. + +--- + +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/dwl/dwl-v0.7_bak/Makefile b/dwl/dwl-v0.7_bak/Makefile new file mode 100644 index 00000000..3358bae9 --- /dev/null +++ b/dwl/dwl-v0.7_bak/Makefile @@ -0,0 +1,78 @@ +.POSIX: +.SUFFIXES: + +include config.mk + +# flags for compiling +DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \ + -DVERSION=\"$(VERSION)\" $(XWAYLAND) +DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \ + -Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \ + -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \ + -Wfloat-conversion + +# CFLAGS / LDFLAGS +PKGS = wlroots-0.18 wayland-server xkbcommon libinput $(XLIBS) +DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) +LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS) + +all: dwl +dwl: dwl.o util.o + $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ +dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \ + pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \ + wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h +util.o: util.c util.h + +# wayland-scanner is a tool which generates C headers and rigging for Wayland +# protocols, which are specified in XML. wlroots requires you to rig these up +# to your build system yourself and provide them in the include path. +WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner` +WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols` + +cursor-shape-v1-protocol.h: + $(WAYLAND_SCANNER) enum-header \ + $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@ +pointer-constraints-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) enum-header \ + $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@ +wlr-layer-shell-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) enum-header \ + protocols/wlr-layer-shell-unstable-v1.xml $@ +wlr-output-power-management-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/wlr-output-power-management-unstable-v1.xml $@ +xdg-shell-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ + +config.h: + cp config.def.h $@ +clean: + rm -f dwl *.o *-protocol.h + +dist: clean + mkdir -p dwl-$(VERSION) + cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h \ + config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop \ + dwl-$(VERSION) + tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) + rm -rf dwl-$(VERSION) + +install: dwl + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f dwl $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl + mkdir -p $(DESTDIR)$(MANDIR)/man1 + cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1 + chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1 + mkdir -p $(DESTDIR)$(DATADIR)/wayland-sessions + cp -f dwl.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop + chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 \ + $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop + +.SUFFIXES: .c .o +.c.o: + $(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -c $< diff --git a/dwl/dwl-v0.7_bak/README.md b/dwl/dwl-v0.7_bak/README.md new file mode 100644 index 00000000..aa95baba --- /dev/null +++ b/dwl/dwl-v0.7_bak/README.md @@ -0,0 +1,201 @@ +# dwl - dwm for Wayland + +Join us on our IRC channel: [#dwl on Libera Chat] +Or on our [Discord server]. + +dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is +intended to fill the same space in the Wayland world that dwm does in X11, +primarily in terms of functionality, and secondarily in terms of +philosophy. Like dwm, dwl is: + +- Easy to understand, hack on, and extend with patches +- One C source file (or a very small number) configurable via `config.h` +- Tied to as few external dependencies as possible + +## Getting Started: + +### **dwl branch 0.7 and releases based upon 0.7 build against [wlroots] 0.18** + +### Latest semi-stable [release] +This is probably where you want to start. This builds against the dependent +packages' versions currently shipping in major distributions. If your +distribution's wlroots version is older, use an earlier dwl [release] or [0.x +branch]. + +### Development branch [main] +Active development progresses on the `main` branch. The `main` branch is built +against a late (and often changing) git commit of wlroots. While the adventurous +are welcome to use `main`, it is a rocky road. Using `main` requires that the +user be willing to chase git commits of wlroots. Testing development pull +requests may involve merging unmerged pull requests in [wlroots]' git repository +and/or git commits of wayland. + +### Building dwl +dwl has the following dependencies: +- libinput +- wayland +- wlroots (compiled with the libinput backend) +- xkbcommon +- wayland-protocols (compile-time only) +- pkg-config (compile-time only) + +dwl has the following additional dependencies if XWayland support is enabled: +- libxcb +- libxcb-wm +- wlroots (compiled with X11 support) +- Xwayland (runtime only) + +Install these (and their `-devel` versions if your distro has separate +development packages) and run `make`. If you wish to build against a released +version of wlroots (*you probably do*), use a [release] or a [0.x branch]. If +you want to use the unstable development `main` branch, you need to use the git +version of [wlroots]. + +To enable XWayland, you should uncomment its flags in `config.mk`. + +## Configuration + +All configuration is done by editing `config.h` and recompiling, in the same +manner as dwm. There is no way to separately restart the window manager in +Wayland without restarting the entire display server, so any changes will take +effect the next time dwl is executed. + +As in the dwm community, we encourage users to share patches they have +created. Check out the [dwl-patches] repository! + +## Running dwl + +dwl can be run on any of the backends supported by wlroots. This means you can +run it as a separate window inside either an X11 or Wayland session, as well as +directly from a VT console. Depending on your distro's setup, you may need to +add your user to the `video` and `input` groups before you can run dwl on a +VT. If you are using `elogind` or `systemd-logind` you need to install polkit; +otherwise you need to add yourself in the `seat` group and enable/start the +seatd daemon. + +When dwl is run with no arguments, it will launch the server and begin handling +any shortcuts configured in `config.h`. There is no status bar or other +decoration initially; these are instead clients that can be run within the +Wayland session. Do note that the default background color is black. This can be +modified in `config.h`. + +If you would like to run a script or command automatically at startup, you can +specify the command using the `-s` option. This command will be executed as a +shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`, +but differs in that the display server will not shut down when this process +terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait +for it to terminate (if it hasn't already). This makes it ideal for execing into +a user service manager like [s6], [anopa], [runit], [dinit], or [`systemd +--user`]. + +Note: The `-s` command is run as a *child process* of dwl, which means that it +does not have the ability to affect the environment of dwl or of any processes +that it spawns. If you need to set environment variables that affect the entire +dwl session, these must be set prior to running dwl. For example, Wayland +requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager +such as `elogind` or `systemd-logind`. If your system doesn't do this +automatically, you will need to configure it prior to launching `dwl`, e.g.: + + export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u) + mkdir -p $XDG_RUNTIME_DIR + dwl + +### Status information + +Information about selected layouts, current window title, app-id, and +selected/occupied/urgent tags is written to the stdin of the `-s` command (see +the `printstatus()` function for details). This information can be used to +populate an external status bar with a script that parses the +information. Failing to read this information will cause dwl to block, so if you +do want to run a startup command that does not consume the status information, +you can close standard input with the `<&-` shell redirection, for example: + + dwl -s 'foot --server <&-' + +If your startup command is a shell script, you can achieve the same inside the +script with the line + + exec <&- + +To get a list of status bars that work with dwl consult our [wiki]. + +## Replacements for X applications + +You can find a [list of useful resources on our wiki]. + +## Background + +dwl is not meant to provide every feature under the sun. Instead, like dwm, it +sticks to features which are necessary, simple, and straightforward to implement +given the base on which it is built. Implemented default features are: + +- Any features provided by dwm/Xlib: simple window borders, tags, keybindings, + client rules, mouse move/resize. Providing a built-in status bar is an + exception to this goal, to avoid dependencies on font rendering and/or drawing + libraries when an external bar could work well. +- Configurable multi-monitor layout support, including position and rotation +- Configurable HiDPI/multi-DPI support +- Idle-inhibit protocol which lets applications such as mpv disable idle + monitoring +- Provide information to external status bars via stdout/stdin +- Urgency hints via xdg-activate protocol +- Support screen lockers via ext-session-lock-v1 protocol +- Various Wayland protocols +- XWayland support as provided by wlroots (can be enabled in `config.mk`) +- Zero flickering - Wayland users naturally expect that "every frame is perfect" +- Layer shell popups (used by Waybar) +- Damage tracking provided by scenegraph API + +Given the Wayland architecture, dwl has to implement features from dwm **and** +the xorg-server. Because of this, it is impossible to maintain the original +project goal of 2000 SLOC and have a reasonably complete compositor with +features comparable to dwm. However, this does not mean that the code will grow +indiscriminately. We will try to keep the code as small as possible. + +Features under consideration (possibly as patches) are: + +- Protocols made trivial by wlroots +- Implement the text-input and input-method protocols to support IME once ibus + implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and + https://codeberg.org/dwl/dwl/pulls/235) + +Feature *non-goals* for the main codebase include: + +- Client-side decoration (any more than is necessary to tell the clients not to) +- Client-initiated window management, such as move, resize, and close, which can + be done through the compositor +- Animations and visual effects + +## Acknowledgements + +dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots +developers. This was made possible in many cases by looking at how sway +accomplished something, then trying to do the same in as suckless a way as +possible. + +Many thanks to suckless.org and the dwm developers and community for the +inspiration, and to the various contributors to the project, including: + +- **Devin J. Pohly for creating and nurturing the fledgling project** +- Alexander Courtis for the XWayland implementation +- Guido Cella for the layer-shell protocol implementation, patch maintenance, + and for helping to keep the project running +- Stivvo for output management and fullscreen support, and patch maintenance + + +[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User +[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl +[0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1 +[0.x branch]: https://codeberg.org/dwl/dwl/branches +[anopa]: https://jjacky.com/anopa/ +[dinit]: https://davmac.org/projects/dinit/ +[dwl-patches]: https://codeberg.org/dwl/dwl-patches +[list of useful resources on our wiki]: https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x +[main]: https://codeberg.org/dwl/dwl/src/branch/main +[release]: https://codeberg.org/dwl/dwl/releases +[runit]: http://smarden.org/runit/faq.html#userservices +[s6]: https://skarnet.org/software/s6/ +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ +[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars +[Discord server]: https://discord.gg/jJxZnrGPWN +[Wayland]: https://wayland.freedesktop.org/ diff --git a/dwl/dwl-v0.7_bak/client.h b/dwl/dwl-v0.7_bak/client.h new file mode 100644 index 00000000..bc9cad2e --- /dev/null +++ b/dwl/dwl-v0.7_bak/client.h @@ -0,0 +1,420 @@ +/* + * Attempt to consolidate unavoidable suck into one file, away from dwl.c. This + * file is not meant to be pretty. We use a .h file with static inline + * functions instead of a separate .c module, or function pointers like sway, so + * that they will simply compile out if the chosen #defines leave them unused. + */ + +/* Leave these functions first; they're used in the others */ +static inline int +client_is_x11(Client *c) +{ +#ifdef XWAYLAND + return c->type == X11; +#endif + return 0; +} + +static inline struct wlr_surface * +client_surface(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->surface; +#endif + return c->surface.xdg->surface; +} + +static inline int +toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) +{ + struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface; + struct wlr_surface *root_surface; + struct wlr_layer_surface_v1 *layer_surface; + Client *c = NULL; + LayerSurface *l = NULL; + int type = -1; +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface; +#endif + + if (!s) + return -1; + root_surface = wlr_surface_get_root_surface(s); + +#ifdef XWAYLAND + if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) { + c = xsurface->data; + type = c->type; + goto end; + } +#endif + + if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) { + l = layer_surface->data; + type = LayerShell; + goto end; + } + + xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface); + while (xdg_surface) { + tmp_xdg_surface = NULL; + switch (xdg_surface->role) { + case WLR_XDG_SURFACE_ROLE_POPUP: + if (!xdg_surface->popup || !xdg_surface->popup->parent) + return -1; + + tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent); + + if (!tmp_xdg_surface) + return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); + + xdg_surface = tmp_xdg_surface; + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + c = xdg_surface->data; + type = c->type; + goto end; + case WLR_XDG_SURFACE_ROLE_NONE: + return -1; + } + } + +end: + if (pl) + *pl = l; + if (pc) + *pc = c; + return type; +} + +/* The others */ +static inline void +client_activate_surface(struct wlr_surface *s, int activated) +{ + struct wlr_xdg_toplevel *toplevel; +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface; + if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) { + wlr_xwayland_surface_activate(xsurface, activated); + return; + } +#endif + if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s))) + wlr_xdg_toplevel_set_activated(toplevel, activated); +} + +static inline uint32_t +client_set_bounds(Client *c, int32_t width, int32_t height) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return 0; +#endif + if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= + XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0 + && (c->bounds.width != width || c->bounds.height != height)) { + c->bounds.width = width; + c->bounds.height = height; + return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); + } + return 0; +} + +static inline const char * +client_get_appid(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->class; +#endif + return c->surface.xdg->toplevel->app_id; +} + +static inline int +client_get_pid(Client *c) +{ + pid_t pid; +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->pid; +#endif + wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); + return pid; +} + +static inline void +client_get_clip(Client *c, struct wlr_box *clip) +{ + struct wlr_box xdg_geom = {0}; + *clip = (struct wlr_box){ + .x = 0, + .y = 0, + .width = c->geom.width - c->bw, + .height = c->geom.height - c->bw, + }; + +#ifdef XWAYLAND + if (client_is_x11(c)) + return; +#endif + + wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom); + clip->x = xdg_geom.x; + clip->y = xdg_geom.y; +} + +static inline void +client_get_geometry(Client *c, struct wlr_box *geom) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + geom->x = c->surface.xwayland->x; + geom->y = c->surface.xwayland->y; + geom->width = c->surface.xwayland->width; + geom->height = c->surface.xwayland->height; + return; + } +#endif + wlr_xdg_surface_get_geometry(c->surface.xdg, geom); +} + +static inline Client * +client_get_parent(Client *c) +{ + Client *p = NULL; +#ifdef XWAYLAND + if (client_is_x11(c)) { + if (c->surface.xwayland->parent) + toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); + return p; + } +#endif + if (c->surface.xdg->toplevel->parent) + toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); + return p; +} + +static inline int +client_has_children(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return !wl_list_empty(&c->surface.xwayland->children); +#endif + /* surface.xdg->link is never empty because it always contains at least the + * surface itself. */ + return wl_list_length(&c->surface.xdg->link) > 1; +} + +static inline const char * +client_get_title(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->title; +#endif + return c->surface.xdg->toplevel->title; +} + +static inline int +client_is_float_type(Client *c) +{ + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state state; + +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface *surface = c->surface.xwayland; + xcb_size_hints_t *size_hints = surface->size_hints; + size_t i; + if (surface->modal) + return 1; + + for (i = 0; i < surface->window_type_len; i++) + if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] + || surface->window_type[i] == netatom[NetWMWindowTypeSplash] + || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] + || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) + return 1; + + return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 + && (size_hints->max_width == size_hints->min_width + || size_hints->max_height == size_hints->min_height); + } +#endif + + toplevel = c->surface.xdg->toplevel; + state = toplevel->current; + return toplevel->parent || (state.min_width != 0 && state.min_height != 0 + && (state.min_width == state.max_width + || state.min_height == state.max_height)); +} + +static inline int +client_is_rendered_on_mon(Client *c, Monitor *m) +{ + /* This is needed for when you don't want to check formal assignment, + * but rather actual displaying of the pixels. + * Usually VISIBLEON suffices and is also faster. */ + struct wlr_surface_output *s; + int unused_lx, unused_ly; + if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly)) + return 0; + wl_list_for_each(s, &client_surface(c)->current_outputs, link) + if (s->output == m->wlr_output) + return 1; + return 0; +} + +static inline int +client_is_stopped(Client *c) +{ + int pid; + siginfo_t in = {0}; +#ifdef XWAYLAND + if (client_is_x11(c)) + return 0; +#endif + + wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); + if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) { + /* This process is not our child process, while is very unluckely that + * it is stopped, in order to do not skip frames assume that it is. */ + if (errno == ECHILD) + return 1; + } else if (in.si_pid) { + if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) + return 1; + if (in.si_code == CLD_CONTINUED) + return 0; + } + + return 0; +} + +static inline int +client_is_unmanaged(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->override_redirect; +#endif + return 0; +} + +static inline void +client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb) +{ + if (kb) + wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes, + kb->num_keycodes, &kb->modifiers); + else + wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL); +} + +static inline void +client_restack_surface(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + wlr_xwayland_surface_restack(c->surface.xwayland, NULL, + XCB_STACK_MODE_ABOVE); +#endif + return; +} + +static inline void +client_send_close(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + wlr_xwayland_surface_close(c->surface.xwayland); + return; + } +#endif + wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel); +} + +static inline void +client_set_border_color(Client *c, const float color[static 4]) +{ + int i; + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(c->border[i], color); +} + +static inline void +client_set_fullscreen(Client *c, int fullscreen) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen); + return; + } +#endif + wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen); +} + +static inline uint32_t +client_set_size(Client *c, uint32_t width, uint32_t height) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + wlr_xwayland_surface_configure(c->surface.xwayland, + c->geom.x + c->bw, c->geom.y + c->bw, width, height); + return 0; + } +#endif + if ((int32_t)width == c->surface.xdg->toplevel->current.width + && (int32_t)height == c->surface.xdg->toplevel->current.height) + return 0; + return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height); +} + +static inline void +client_set_tiled(Client *c, uint32_t edges) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return; +#endif + if (wl_resource_get_version(c->surface.xdg->toplevel->resource) + >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { + wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); + } else { + wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE); + } +} + +static inline void +client_set_suspended(Client *c, int suspended) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return; +#endif + + wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); +} + +static inline int +client_wants_focus(Client *c) +{ +#ifdef XWAYLAND + return client_is_unmanaged(c) + && wlr_xwayland_or_surface_wants_focus(c->surface.xwayland) + && wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE; +#endif + return 0; +} + +static inline int +client_wants_fullscreen(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->fullscreen; +#endif + return c->surface.xdg->toplevel->requested.fullscreen; +} diff --git a/dwl/dwl-v0.7_bak/config.def.h b/dwl/dwl-v0.7_bak/config.def.h new file mode 100644 index 00000000..0d5fbaf5 --- /dev/null +++ b/dwl/dwl-v0.7_bak/config.def.h @@ -0,0 +1,269 @@ +/* Taken from https://github.com/djpohly/dwl/issues/466 */ +#define COLOR(hex) \ + {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f, \ + ((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f} +/* appearance */ +static const int sloppyfocus = 1; /* focus follows mouse */ +static const int bypass_surface_visibility = + 0; /* 1 means idle inhibitors will disable idle tracking even if it's + surface isn't visible */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const float rootcolor[] = COLOR(0x222222ff); +static const float bordercolor[] = COLOR(0x444444ff); +static const float focuscolor[] = COLOR(0x005577ff); +static const float urgentcolor[] = COLOR(0xff0000ff); +/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old + * behavior */ +static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, + 1.0f}; /* You can also use glsl colors */ +static int enableautoswallow = + 1; /* enables autoswallowing newly spawned clients */ + +/* tagging - TAGCOUNT must be no greater than 31 */ +#define TAGCOUNT (9) + +/* logging */ +static int log_level = WLR_ERROR; + +/* Autostart */ +static const char *const autostart[] = { + "swaybg", + "-i", + "/home/brian/Pictures/leaves.jpg", + "-m", + "fill", + NULL, + "gammastep", + "-b", + "0.95", + "-O", + "5500K", + NULL, + "foot", + "-c", + "/home/brian/.config/foot/bfoot.ini", + "/usr/bin/btop", + NULL, + + NULL /* terminate */ +}; + +/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at + * least one example) */ +static const Rule rules[] = { + /* app_id title tags mask isfloating isterm + noswallow monitor */ + /* examples: */ + {"foot", NULL, 0, 0, 1, 1, -1}, + {"Gimp_EXAMPLE", NULL, 0, 1, 0, 0, + -1}, /* Start on currently visible tags floating, not tiled */ + {"firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1}, /* Start on ONLY tag "9" */ +}; + +/* layout(s) */ +static const Layout layouts[] = { + /* symbol arrange function */ + {"[]=", tile}, + {"><>", NULL}, /* no layout function means floating behavior */ + {"[M]", monocle}, +}; + +/* monitors */ +/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator + * WARNING: negative values other than (-1, -1) cause problems with Xwayland + * clients https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 + */ +/* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be + * used */ +static const MonitorRule monrules[] = { + /* name mfact nmaster scale layout rotate/reflect x y */ + /* example of a HiDPI laptop monitor: + { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, + -1, -1 }, + */ + /* defaults */ + {NULL, 0.50f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1}, +}; + +/* keyboard */ +static const struct xkb_rule_names xkb_rules = { + /* can specify fields: rules, model, layout, variant, options */ + /* example: + .options = "ctrl:nocaps", + */ + .options = NULL, +}; + +static const int repeat_rate = 25; +static const int repeat_delay = 600; + +/* Trackpad */ +static const int tap_to_click = 1; +static const int tap_and_drag = 1; +static const int drag_lock = 1; +static const int natural_scrolling = 0; +static const int disable_while_typing = 1; +static const int left_handed = 0; +static const int middle_button_emulation = 0; +/* You can choose between: +LIBINPUT_CONFIG_SCROLL_NO_SCROLL +LIBINPUT_CONFIG_SCROLL_2FG +LIBINPUT_CONFIG_SCROLL_EDGE +LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN +*/ +static const enum libinput_config_scroll_method scroll_method = + LIBINPUT_CONFIG_SCROLL_2FG; + +/* You can choose between: +LIBINPUT_CONFIG_CLICK_METHOD_NONE +LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS +LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER +*/ +static const enum libinput_config_click_method click_method = + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + +/* You can choose between: +LIBINPUT_CONFIG_SEND_EVENTS_ENABLED +LIBINPUT_CONFIG_SEND_EVENTS_DISABLED +LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE +*/ +static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; + +/* You can choose between: +LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT +LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE +*/ +static const enum libinput_config_accel_profile accel_profile = + LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; +static const double accel_speed = 0.0; + +/* You can choose between: +LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle +LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right +*/ +static const enum libinput_config_tap_button_map button_map = + LIBINPUT_CONFIG_TAP_MAP_LRM; + +static const int hide_cursor_when_typing = 1; + +/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ +#define MODKEY WLR_MODIFIER_LOGO + +#define TAGKEYS(KEY, SKEY, TAG) \ + {MODKEY, KEY, view, {.ui = 1 << TAG}}, \ + {MODKEY | WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG}}, \ + {MODKEY | WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG}}, { \ + MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT, SKEY, toggletag, { \ + .ui = 1 << TAG \ + } \ + } + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) \ + { \ + .v = (const char *[]) { "/bin/sh", "-c", cmd, NULL } \ + } + +/* commands */ +static const char *termcmd[] = {"foot", NULL}; +static const char *menucmd[] = {"wmenu-run", NULL}; +static const char *librewolfcmd[] = {"librewolf-bin", NULL}; +static const char *chromiumcmd[] = {"chromium-bin", NULL}; +static const char *inkscapecmd[] = {"inkscape", NULL}; +static const char *gimpcmd[] = {"gimp", NULL}; +static const char *pcmanfmcmd[] = {"pcmanfm", NULL}; +static const char *keepassxccmd[] = {"keepassxc", NULL}; +static const char *libreofficecmd[] = {"libreoffice-bin", NULL}; +static const char *mousepadcmd[] = {"mousepad", NULL}; +static const char *virtmanagercmd[] = {"virt-manager", NULL}; +static const char *qalculatecmd[] = {"qalculate-qt", NULL}; +static const char *steamcmd[] = {"steam", NULL}; +static const char *thunderbirdcmd[] = {"thunderbird-bin", NULL}; + +static const Key keys[] = { + /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ + /* modifier key function argument */ + {MODKEY, XKB_KEY_Return, spawn, {.v = termcmd}}, + {MODKEY, XKB_KEY_d, spawn, {.v = menucmd}}, + {MODKEY, XKB_KEY_f, spawn, {.v = librewolfcmd}}, + {MODKEY, XKB_KEY_c, spawn, {.v = chromiumcmd}}, + {MODKEY, XKB_KEY_i, spawn, {.v = inkscapecmd}}, + {MODKEY, XKB_KEY_g, spawn, {.v = gimpcmd}}, + {MODKEY, XKB_KEY_p, spawn, {.v = pcmanfmcmd}}, + {MODKEY, XKB_KEY_k, spawn, {.v = keepassxccmd}}, + {MODKEY, XKB_KEY_n, spawn, {.v = libreofficecmd}}, + {MODKEY, XKB_KEY_m, spawn, {.v = mousepadcmd}}, + {MODKEY, XKB_KEY_v, spawn, {.v = virtmanagercmd}}, + {MODKEY, XKB_KEY_u, spawn, {.v = qalculatecmd}}, + {MODKEY, XKB_KEY_s, spawn, {.v = steamcmd}}, + {MODKEY, XKB_KEY_t, spawn, {.v = thunderbirdcmd}}, + {MODKEY, XKB_KEY_Left, setmfact, {.f = -0.0125f}}, + {MODKEY, XKB_KEY_Right, setmfact, {.f = +0.0125f}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Q, killclient, {0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Escape, quit, {0}}, + {MODKEY, XKB_KEY_o, togglefloating, {0}}, + {MODKEY, XKB_KEY_j, focusstack, {.i = +1}}, + {MODKEY, XKB_KEY_k, focusstack, {.i = -1}}, + {MODKEY, XKB_KEY_i, incnmaster, {.i = +1}}, + {MODKEY, XKB_KEY_d, incnmaster, {.i = -1}}, + {MODKEY, XKB_KEY_Return, zoom, {0}}, + {MODKEY, XKB_KEY_Tab, view, {0}}, + // {MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]}}, + // {MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]}}, + // {MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]}}, + {MODKEY, XKB_KEY_space, setlayout, {0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_f, togglefullscreen, {0}}, + {MODKEY, XKB_KEY_a, toggleswallow, {0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow, {0}}, + {MODKEY, XKB_KEY_0, view, {.ui = ~0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0}}, + {MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT}}, + {MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT}}, + {MODKEY | WLR_MODIFIER_SHIFT, + XKB_KEY_less, + tagmon, + {.i = WLR_DIRECTION_LEFT}}, + {MODKEY | WLR_MODIFIER_SHIFT, + XKB_KEY_greater, + tagmon, + {.i = WLR_DIRECTION_RIGHT}}, + TAGKEYS(XKB_KEY_1, XKB_KEY_exclam, 0), + TAGKEYS(XKB_KEY_2, XKB_KEY_at, 1), + TAGKEYS(XKB_KEY_3, XKB_KEY_numbersign, 2), + TAGKEYS(XKB_KEY_4, XKB_KEY_dollar, 3), + TAGKEYS(XKB_KEY_5, XKB_KEY_percent, 4), + TAGKEYS(XKB_KEY_6, XKB_KEY_asciicircum, 5), + TAGKEYS(XKB_KEY_7, XKB_KEY_ampersand, 6), + TAGKEYS(XKB_KEY_8, XKB_KEY_asterisk, 7), + TAGKEYS(XKB_KEY_9, XKB_KEY_parenleft, 8), + + /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ + {WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_Terminate_Server, quit, {0}}, +/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is + * do not remove them. + */ +#define CHVT(n) \ + { \ + WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_XF86Switch_VT_##n, chvt, { \ + .ui = (n) \ + } \ + } + CHVT(1), + CHVT(2), + CHVT(3), + CHVT(4), + CHVT(5), + CHVT(6), + CHVT(7), + CHVT(8), + CHVT(9), + CHVT(10), + CHVT(11), + CHVT(12), +}; + +static const Button buttons[] = { + {MODKEY, BTN_LEFT, moveresize, {.ui = CurMove}}, + {MODKEY, BTN_MIDDLE, togglefloating, {0}}, + {MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize}}, +}; diff --git a/dwl/dwl-v0.7_bak/config.def.h.orig b/dwl/dwl-v0.7_bak/config.def.h.orig new file mode 100644 index 00000000..77498e3a --- /dev/null +++ b/dwl/dwl-v0.7_bak/config.def.h.orig @@ -0,0 +1,269 @@ +/* Taken from https://github.com/djpohly/dwl/issues/466 */ +#define COLOR(hex) \ + {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f, \ + ((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f} +/* appearance */ +static const int sloppyfocus = 1; /* focus follows mouse */ +static const int bypass_surface_visibility = + 0; /* 1 means idle inhibitors will disable idle tracking even if it's + surface isn't visible */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const float rootcolor[] = COLOR(0x222222ff); +static const float bordercolor[] = COLOR(0x444444ff); +static const float focuscolor[] = COLOR(0x005577ff); +static const float urgentcolor[] = COLOR(0xff0000ff); +/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old + * behavior */ +static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, + 1.0f}; /* You can also use glsl colors */ +static int enableautoswallow = + 1; /* enables autoswallowing newly spawned clients */ + +/* tagging - TAGCOUNT must be no greater than 31 */ +#define TAGCOUNT (9) + +/* logging */ +static int log_level = WLR_ERROR; + +/* Autostart */ +static const char *const autostart[] = { + "swaybg", + "-i", + "/home/brian/Pictures/leaves.jpg", + "-m", + "fill", + NULL, + "gammastep", + "-b", + "0.95", + "-O", + "5500K", + NULL, + "foot", + "-c", + "/home/brian/.config/foot/bfoot.ini", + "/usr/bin/btop", + NULL, + + NULL /* terminate */ +}; + +/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at + * least one example) */ +static const Rule rules[] = { + /* app_id title tags mask isfloating isterm + noswallow monitor */ + /* examples: */ + {"foot", NULL, 0, 0, 1, 1, -1}, + {"Gimp_EXAMPLE", NULL, 0, 1, 0, 0, + -1}, /* Start on currently visible tags floating, not tiled */ + {"firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1}, /* Start on ONLY tag "9" */ +}; + +/* layout(s) */ +static const Layout layouts[] = { + /* symbol arrange function */ + {"[]=", tile}, + {"><>", NULL}, /* no layout function means floating behavior */ + {"[M]", monocle}, +}; + +/* monitors */ +/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator + * WARNING: negative values other than (-1, -1) cause problems with Xwayland + * clients https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 + */ +/* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be + * used */ +static const MonitorRule monrules[] = { + /* name mfact nmaster scale layout rotate/reflect x y */ + /* example of a HiDPI laptop monitor: + { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, + -1, -1 }, + */ + /* defaults */ + {NULL, 0.50f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1}, +}; + +/* keyboard */ +static const struct xkb_rule_names xkb_rules = { + /* can specify fields: rules, model, layout, variant, options */ + /* example: + .options = "ctrl:nocaps", + */ + .options = NULL, +}; + +static const int repeat_rate = 25; +static const int repeat_delay = 600; + +/* Trackpad */ +static const int tap_to_click = 1; +static const int tap_and_drag = 1; +static const int drag_lock = 1; +static const int natural_scrolling = 0; +static const int disable_while_typing = 1; +static const int left_handed = 0; +static const int middle_button_emulation = 0; +/* You can choose between: +LIBINPUT_CONFIG_SCROLL_NO_SCROLL +LIBINPUT_CONFIG_SCROLL_2FG +LIBINPUT_CONFIG_SCROLL_EDGE +LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN +*/ +static const enum libinput_config_scroll_method scroll_method = + LIBINPUT_CONFIG_SCROLL_2FG; + +/* You can choose between: +LIBINPUT_CONFIG_CLICK_METHOD_NONE +LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS +LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER +*/ +static const enum libinput_config_click_method click_method = + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + +/* You can choose between: +LIBINPUT_CONFIG_SEND_EVENTS_ENABLED +LIBINPUT_CONFIG_SEND_EVENTS_DISABLED +LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE +*/ +static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; + +/* You can choose between: +LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT +LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE +*/ +static const enum libinput_config_accel_profile accel_profile = + LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; +static const double accel_speed = 0.0; + +/* You can choose between: +LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle +LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right +*/ +static const enum libinput_config_tap_button_map button_map = + LIBINPUT_CONFIG_TAP_MAP_LRM; + +static const int hide_cursor_when_typing = 1; + +/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ +#define MODKEY WLR_MODIFIER_LOGO + +#define TAGKEYS(KEY, SKEY, TAG) \ + {MODKEY, KEY, view, {.ui = 1 << TAG}}, \ + {MODKEY | WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG}}, \ + {MODKEY | WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG}}, { \ + MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT, SKEY, toggletag, { \ + .ui = 1 << TAG \ + } \ + } + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) \ + { \ + .v = (const char *[]) { "/bin/sh", "-c", cmd, NULL } \ + } + +/* commands */ +static const char *termcmd[] = {"foot", NULL}; +static const char *menucmd[] = {"wmenu-run", NULL}; +static const char *librewolfcmd[] = {"librewolf-bin", NULL}; +static const char *chromiumcmd[] = {"chromium-bin", NULL}; +static const char *inkscapecmd[] = {"inkscape", NULL}; +static const char *gimpcmd[] = {"gimp", NULL}; +static const char *pcmanfmcmd[] = {"pcmanfm", NULL}; +static const char *keepassxccmd[] = {"keepassxc", NULL}; +static const char *libreofficecmd[] = {"libreoffice-bin", NULL}; +static const char *mousepadcmd[] = {"mousepad", NULL}; +static const char *virtmanagercmd[] = {"virt-manager", NULL}; +static const char *qalculatecmd[] = {"qalculate-qt", NULL}; +static const char *steamcmd[] = {"steam", NULL}; +static const char *thunderbirdcmd[] = {"thunderbird-bin", NULL}; + +static const Key keys[] = { + /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ + /* modifier key function argument */ + {MODKEY, XKB_KEY_Return, spawn, {.v = termcmd}}, + {MODKEY, XKB_KEY_d, spawn, {.v = menucmd}}, + {MODKEY, XKB_KEY_f, spawn, {.v = librewolfcmd}}, + {MODKEY, XKB_KEY_c, spawn, {.v = chromiumcmd}}, + {MODKEY, XKB_KEY_i, spawn, {.v = inkscapecmd}}, + {MODKEY, XKB_KEY_g, spawn, {.v = gimpcmd}}, + {MODKEY, XKB_KEY_p, spawn, {.v = pcmanfmcmd}}, + {MODKEY, XKB_KEY_k, spawn, {.v = keepassxccmd}}, + {MODKEY, XKB_KEY_n, spawn, {.v = libreofficecmd}}, + {MODKEY, XKB_KEY_m, spawn, {.v = mousepadcmd}}, + {MODKEY, XKB_KEY_v, spawn, {.v = virtmanagercmd}}, + {MODKEY, XKB_KEY_u, spawn, {.v = qalculatecmd}}, + {MODKEY, XKB_KEY_s, spawn, {.v = steamcmd}}, + {MODKEY, XKB_KEY_s, spawn, {.v = thunderbirdcmd}}, + {MODKEY, XKB_KEY_Left, setmfact, {.f = -0.0125f}}, + {MODKEY, XKB_KEY_Right, setmfact, {.f = +0.0125f}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Q, killclient, {0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Escape, quit, {0}}, + {MODKEY, XKB_KEY_o, togglefloating, {0}}, + {MODKEY, XKB_KEY_j, focusstack, {.i = +1}}, + {MODKEY, XKB_KEY_k, focusstack, {.i = -1}}, + {MODKEY, XKB_KEY_i, incnmaster, {.i = +1}}, + {MODKEY, XKB_KEY_d, incnmaster, {.i = -1}}, + {MODKEY, XKB_KEY_Return, zoom, {0}}, + {MODKEY, XKB_KEY_Tab, view, {0}}, + // {MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]}}, + // {MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]}}, + // {MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]}}, + {MODKEY, XKB_KEY_space, setlayout, {0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_f, togglefullscreen, {0}}, + {MODKEY, XKB_KEY_a, toggleswallow, {0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow, {0}}, + {MODKEY, XKB_KEY_0, view, {.ui = ~0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0}}, + {MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT}}, + {MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT}}, + {MODKEY | WLR_MODIFIER_SHIFT, + XKB_KEY_less, + tagmon, + {.i = WLR_DIRECTION_LEFT}}, + {MODKEY | WLR_MODIFIER_SHIFT, + XKB_KEY_greater, + tagmon, + {.i = WLR_DIRECTION_RIGHT}}, + TAGKEYS(XKB_KEY_1, XKB_KEY_exclam, 0), + TAGKEYS(XKB_KEY_2, XKB_KEY_at, 1), + TAGKEYS(XKB_KEY_3, XKB_KEY_numbersign, 2), + TAGKEYS(XKB_KEY_4, XKB_KEY_dollar, 3), + TAGKEYS(XKB_KEY_5, XKB_KEY_percent, 4), + TAGKEYS(XKB_KEY_6, XKB_KEY_asciicircum, 5), + TAGKEYS(XKB_KEY_7, XKB_KEY_ampersand, 6), + TAGKEYS(XKB_KEY_8, XKB_KEY_asterisk, 7), + TAGKEYS(XKB_KEY_9, XKB_KEY_parenleft, 8), + + /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ + {WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_Terminate_Server, quit, {0}}, +/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is + * do not remove them. + */ +#define CHVT(n) \ + { \ + WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_XF86Switch_VT_##n, chvt, { \ + .ui = (n) \ + } \ + } + CHVT(1), + CHVT(2), + CHVT(3), + CHVT(4), + CHVT(5), + CHVT(6), + CHVT(7), + CHVT(8), + CHVT(9), + CHVT(10), + CHVT(11), + CHVT(12), +}; + +static const Button buttons[] = { + {MODKEY, BTN_LEFT, moveresize, {.ui = CurMove}}, + {MODKEY, BTN_MIDDLE, togglefloating, {0}}, + {MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize}}, +}; diff --git a/dwl/dwl-v0.7_bak/config.def.h.rej b/dwl/dwl-v0.7_bak/config.def.h.rej new file mode 100644 index 00000000..2bb4da89 --- /dev/null +++ b/dwl/dwl-v0.7_bak/config.def.h.rej @@ -0,0 +1,34 @@ +--- config.def.h ++++ config.def.h +@@ -13,6 +13,7 @@ static const float focuscolor[] = COLOR(0x005577ff); + static const float urgentcolor[] = COLOR(0xff0000ff); + /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ + static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */ ++static int enableautoswallow = 1; /* enables autoswallowing newly spawned clients */ + + /* tagging - TAGCOUNT must be no greater than 31 */ + #define TAGCOUNT (9) +@@ -22,10 +23,11 @@ static int log_level = WLR_ERROR; + + /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */ + static const Rule rules[] = { +- /* app_id title tags mask isfloating monitor */ ++ /* app_id title tags mask isfloating isterm noswallow monitor */ + /* examples: */ +- { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ +- { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ ++ { "foot", NULL, 0, 0, 1, 1, -1 }, ++ { "Gimp_EXAMPLE", NULL, 0, 1, 0, 0, -1 }, /* Start on currently visible tags floating, not tiled */ ++ { "firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1 }, /* Start on ONLY tag "9" */ + }; + + /* layout(s) */ +@@ -142,6 +144,8 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, ++ { MODKEY, XKB_KEY_a, toggleswallow, {0} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow,{0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, + { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, diff --git a/dwl/dwl-v0.7_bak/config.h b/dwl/dwl-v0.7_bak/config.h new file mode 100644 index 00000000..0d5fbaf5 --- /dev/null +++ b/dwl/dwl-v0.7_bak/config.h @@ -0,0 +1,269 @@ +/* Taken from https://github.com/djpohly/dwl/issues/466 */ +#define COLOR(hex) \ + {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f, \ + ((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f} +/* appearance */ +static const int sloppyfocus = 1; /* focus follows mouse */ +static const int bypass_surface_visibility = + 0; /* 1 means idle inhibitors will disable idle tracking even if it's + surface isn't visible */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const float rootcolor[] = COLOR(0x222222ff); +static const float bordercolor[] = COLOR(0x444444ff); +static const float focuscolor[] = COLOR(0x005577ff); +static const float urgentcolor[] = COLOR(0xff0000ff); +/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old + * behavior */ +static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, + 1.0f}; /* You can also use glsl colors */ +static int enableautoswallow = + 1; /* enables autoswallowing newly spawned clients */ + +/* tagging - TAGCOUNT must be no greater than 31 */ +#define TAGCOUNT (9) + +/* logging */ +static int log_level = WLR_ERROR; + +/* Autostart */ +static const char *const autostart[] = { + "swaybg", + "-i", + "/home/brian/Pictures/leaves.jpg", + "-m", + "fill", + NULL, + "gammastep", + "-b", + "0.95", + "-O", + "5500K", + NULL, + "foot", + "-c", + "/home/brian/.config/foot/bfoot.ini", + "/usr/bin/btop", + NULL, + + NULL /* terminate */ +}; + +/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at + * least one example) */ +static const Rule rules[] = { + /* app_id title tags mask isfloating isterm + noswallow monitor */ + /* examples: */ + {"foot", NULL, 0, 0, 1, 1, -1}, + {"Gimp_EXAMPLE", NULL, 0, 1, 0, 0, + -1}, /* Start on currently visible tags floating, not tiled */ + {"firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1}, /* Start on ONLY tag "9" */ +}; + +/* layout(s) */ +static const Layout layouts[] = { + /* symbol arrange function */ + {"[]=", tile}, + {"><>", NULL}, /* no layout function means floating behavior */ + {"[M]", monocle}, +}; + +/* monitors */ +/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator + * WARNING: negative values other than (-1, -1) cause problems with Xwayland + * clients https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 + */ +/* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be + * used */ +static const MonitorRule monrules[] = { + /* name mfact nmaster scale layout rotate/reflect x y */ + /* example of a HiDPI laptop monitor: + { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, + -1, -1 }, + */ + /* defaults */ + {NULL, 0.50f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1}, +}; + +/* keyboard */ +static const struct xkb_rule_names xkb_rules = { + /* can specify fields: rules, model, layout, variant, options */ + /* example: + .options = "ctrl:nocaps", + */ + .options = NULL, +}; + +static const int repeat_rate = 25; +static const int repeat_delay = 600; + +/* Trackpad */ +static const int tap_to_click = 1; +static const int tap_and_drag = 1; +static const int drag_lock = 1; +static const int natural_scrolling = 0; +static const int disable_while_typing = 1; +static const int left_handed = 0; +static const int middle_button_emulation = 0; +/* You can choose between: +LIBINPUT_CONFIG_SCROLL_NO_SCROLL +LIBINPUT_CONFIG_SCROLL_2FG +LIBINPUT_CONFIG_SCROLL_EDGE +LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN +*/ +static const enum libinput_config_scroll_method scroll_method = + LIBINPUT_CONFIG_SCROLL_2FG; + +/* You can choose between: +LIBINPUT_CONFIG_CLICK_METHOD_NONE +LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS +LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER +*/ +static const enum libinput_config_click_method click_method = + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + +/* You can choose between: +LIBINPUT_CONFIG_SEND_EVENTS_ENABLED +LIBINPUT_CONFIG_SEND_EVENTS_DISABLED +LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE +*/ +static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; + +/* You can choose between: +LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT +LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE +*/ +static const enum libinput_config_accel_profile accel_profile = + LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; +static const double accel_speed = 0.0; + +/* You can choose between: +LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle +LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right +*/ +static const enum libinput_config_tap_button_map button_map = + LIBINPUT_CONFIG_TAP_MAP_LRM; + +static const int hide_cursor_when_typing = 1; + +/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ +#define MODKEY WLR_MODIFIER_LOGO + +#define TAGKEYS(KEY, SKEY, TAG) \ + {MODKEY, KEY, view, {.ui = 1 << TAG}}, \ + {MODKEY | WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG}}, \ + {MODKEY | WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG}}, { \ + MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT, SKEY, toggletag, { \ + .ui = 1 << TAG \ + } \ + } + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) \ + { \ + .v = (const char *[]) { "/bin/sh", "-c", cmd, NULL } \ + } + +/* commands */ +static const char *termcmd[] = {"foot", NULL}; +static const char *menucmd[] = {"wmenu-run", NULL}; +static const char *librewolfcmd[] = {"librewolf-bin", NULL}; +static const char *chromiumcmd[] = {"chromium-bin", NULL}; +static const char *inkscapecmd[] = {"inkscape", NULL}; +static const char *gimpcmd[] = {"gimp", NULL}; +static const char *pcmanfmcmd[] = {"pcmanfm", NULL}; +static const char *keepassxccmd[] = {"keepassxc", NULL}; +static const char *libreofficecmd[] = {"libreoffice-bin", NULL}; +static const char *mousepadcmd[] = {"mousepad", NULL}; +static const char *virtmanagercmd[] = {"virt-manager", NULL}; +static const char *qalculatecmd[] = {"qalculate-qt", NULL}; +static const char *steamcmd[] = {"steam", NULL}; +static const char *thunderbirdcmd[] = {"thunderbird-bin", NULL}; + +static const Key keys[] = { + /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ + /* modifier key function argument */ + {MODKEY, XKB_KEY_Return, spawn, {.v = termcmd}}, + {MODKEY, XKB_KEY_d, spawn, {.v = menucmd}}, + {MODKEY, XKB_KEY_f, spawn, {.v = librewolfcmd}}, + {MODKEY, XKB_KEY_c, spawn, {.v = chromiumcmd}}, + {MODKEY, XKB_KEY_i, spawn, {.v = inkscapecmd}}, + {MODKEY, XKB_KEY_g, spawn, {.v = gimpcmd}}, + {MODKEY, XKB_KEY_p, spawn, {.v = pcmanfmcmd}}, + {MODKEY, XKB_KEY_k, spawn, {.v = keepassxccmd}}, + {MODKEY, XKB_KEY_n, spawn, {.v = libreofficecmd}}, + {MODKEY, XKB_KEY_m, spawn, {.v = mousepadcmd}}, + {MODKEY, XKB_KEY_v, spawn, {.v = virtmanagercmd}}, + {MODKEY, XKB_KEY_u, spawn, {.v = qalculatecmd}}, + {MODKEY, XKB_KEY_s, spawn, {.v = steamcmd}}, + {MODKEY, XKB_KEY_t, spawn, {.v = thunderbirdcmd}}, + {MODKEY, XKB_KEY_Left, setmfact, {.f = -0.0125f}}, + {MODKEY, XKB_KEY_Right, setmfact, {.f = +0.0125f}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Q, killclient, {0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Escape, quit, {0}}, + {MODKEY, XKB_KEY_o, togglefloating, {0}}, + {MODKEY, XKB_KEY_j, focusstack, {.i = +1}}, + {MODKEY, XKB_KEY_k, focusstack, {.i = -1}}, + {MODKEY, XKB_KEY_i, incnmaster, {.i = +1}}, + {MODKEY, XKB_KEY_d, incnmaster, {.i = -1}}, + {MODKEY, XKB_KEY_Return, zoom, {0}}, + {MODKEY, XKB_KEY_Tab, view, {0}}, + // {MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]}}, + // {MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]}}, + // {MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]}}, + {MODKEY, XKB_KEY_space, setlayout, {0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_f, togglefullscreen, {0}}, + {MODKEY, XKB_KEY_a, toggleswallow, {0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow, {0}}, + {MODKEY, XKB_KEY_0, view, {.ui = ~0}}, + {MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0}}, + {MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT}}, + {MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT}}, + {MODKEY | WLR_MODIFIER_SHIFT, + XKB_KEY_less, + tagmon, + {.i = WLR_DIRECTION_LEFT}}, + {MODKEY | WLR_MODIFIER_SHIFT, + XKB_KEY_greater, + tagmon, + {.i = WLR_DIRECTION_RIGHT}}, + TAGKEYS(XKB_KEY_1, XKB_KEY_exclam, 0), + TAGKEYS(XKB_KEY_2, XKB_KEY_at, 1), + TAGKEYS(XKB_KEY_3, XKB_KEY_numbersign, 2), + TAGKEYS(XKB_KEY_4, XKB_KEY_dollar, 3), + TAGKEYS(XKB_KEY_5, XKB_KEY_percent, 4), + TAGKEYS(XKB_KEY_6, XKB_KEY_asciicircum, 5), + TAGKEYS(XKB_KEY_7, XKB_KEY_ampersand, 6), + TAGKEYS(XKB_KEY_8, XKB_KEY_asterisk, 7), + TAGKEYS(XKB_KEY_9, XKB_KEY_parenleft, 8), + + /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ + {WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_Terminate_Server, quit, {0}}, +/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is + * do not remove them. + */ +#define CHVT(n) \ + { \ + WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_XF86Switch_VT_##n, chvt, { \ + .ui = (n) \ + } \ + } + CHVT(1), + CHVT(2), + CHVT(3), + CHVT(4), + CHVT(5), + CHVT(6), + CHVT(7), + CHVT(8), + CHVT(9), + CHVT(10), + CHVT(11), + CHVT(12), +}; + +static const Button buttons[] = { + {MODKEY, BTN_LEFT, moveresize, {.ui = CurMove}}, + {MODKEY, BTN_MIDDLE, togglefloating, {0}}, + {MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize}}, +}; diff --git a/dwl/dwl-v0.7_bak/config.mk b/dwl/dwl-v0.7_bak/config.mk new file mode 100644 index 00000000..fb999508 --- /dev/null +++ b/dwl/dwl-v0.7_bak/config.mk @@ -0,0 +1,17 @@ +_VERSION = 0.7 +VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)` + +PKG_CONFIG = pkg-config + +# paths +PREFIX = /usr/local +MANDIR = $(PREFIX)/share/man +DATADIR = $(PREFIX)/share + +XWAYLAND = +XLIBS = +# Uncomment to build XWayland support +XWAYLAND = -DXWAYLAND +XLIBS = xcb xcb-icccm + +CC = gcc diff --git a/dwl/dwl-v0.7_bak/cursor-shape-v1-protocol.h b/dwl/dwl-v0.7_bak/cursor-shape-v1-protocol.h new file mode 100644 index 00000000..e49c7f52 --- /dev/null +++ b/dwl/dwl-v0.7_bak/cursor-shape-v1-protocol.h @@ -0,0 +1,201 @@ +/* Generated by wayland-scanner 1.24.0 */ + +#ifndef CURSOR_SHAPE_V1_ENUM_PROTOCOL_H +#define CURSOR_SHAPE_V1_ENUM_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ENUM +#define WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ENUM +/** + * @ingroup iface_wp_cursor_shape_device_v1 + * cursor shapes + * + * This enum describes cursor shapes. + * + * The names are taken from the CSS W3C specification: + * https://w3c.github.io/csswg-drafts/css-ui/#cursor + * with a few additions. + * + * Note that there are some groups of cursor shapes that are related: + * The first group is drag-and-drop cursors which are used to indicate + * the selected action during dnd operations. The second group is resize + * cursors which are used to indicate resizing and moving possibilities + * on window borders. It is recommended that the shapes in these groups + * should use visually compatible images and metaphors. + */ +enum wp_cursor_shape_device_v1_shape { + /** + * default cursor + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT = 1, + /** + * a context menu is available for the object under the cursor + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CONTEXT_MENU = 2, + /** + * help is available for the object under the cursor + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP = 3, + /** + * pointer that indicates a link or another interactive element + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER = 4, + /** + * progress indicator + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_PROGRESS = 5, + /** + * program is busy, user should wait + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT = 6, + /** + * a cell or set of cells may be selected + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CELL = 7, + /** + * simple crosshair + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR = 8, + /** + * text may be selected + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT = 9, + /** + * vertical text may be selected + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_VERTICAL_TEXT = 10, + /** + * drag-and-drop: alias of/shortcut to something is to be created + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALIAS = 11, + /** + * drag-and-drop: something is to be copied + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COPY = 12, + /** + * drag-and-drop: something is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE = 13, + /** + * drag-and-drop: the dragged item cannot be dropped at the current cursor location + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NO_DROP = 14, + /** + * drag-and-drop: the requested action will not be carried out + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED = 15, + /** + * drag-and-drop: something can be grabbed + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB = 16, + /** + * drag-and-drop: something is being grabbed + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRABBING = 17, + /** + * resizing: the east border is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE = 18, + /** + * resizing: the north border is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE = 19, + /** + * resizing: the north-east corner is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE = 20, + /** + * resizing: the north-west corner is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE = 21, + /** + * resizing: the south border is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE = 22, + /** + * resizing: the south-east corner is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE = 23, + /** + * resizing: the south-west corner is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE = 24, + /** + * resizing: the west border is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE = 25, + /** + * resizing: the east and west borders are to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE = 26, + /** + * resizing: the north and south borders are to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE = 27, + /** + * resizing: the north-east and south-west corners are to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE = 28, + /** + * resizing: the north-west and south-east corners are to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE = 29, + /** + * resizing: that the item/column can be resized horizontally + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COL_RESIZE = 30, + /** + * resizing: that the item/row can be resized vertically + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ROW_RESIZE = 31, + /** + * something can be scrolled in any direction + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL = 32, + /** + * something can be zoomed in + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN = 33, + /** + * something can be zoomed out + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT = 34, + /** + * drag-and-drop: the user will select which action will be carried out (non-css value) + * @since 2 + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK = 35, + /** + * resizing: something can be moved or resized in any direction (non-css value) + * @since 2 + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE = 36, +}; +/** + * @ingroup iface_wp_cursor_shape_device_v1 + */ +#define WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK_SINCE_VERSION 2 +/** + * @ingroup iface_wp_cursor_shape_device_v1 + */ +#define WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE_SINCE_VERSION 2 +#endif /* WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ENUM */ + +#ifndef WP_CURSOR_SHAPE_DEVICE_V1_ERROR_ENUM +#define WP_CURSOR_SHAPE_DEVICE_V1_ERROR_ENUM +enum wp_cursor_shape_device_v1_error { + /** + * the specified shape value is invalid + */ + WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE = 1, +}; +#endif /* WP_CURSOR_SHAPE_DEVICE_V1_ERROR_ENUM */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dwl/dwl-v0.7_bak/dwl b/dwl/dwl-v0.7_bak/dwl new file mode 100755 index 0000000000000000000000000000000000000000..1299f0ae26a265b433c14396712c7fd73a8d3e8e GIT binary patch literal 299856 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XWAYLAND +#include +#include +#include +#endif + +#include "util.h" + +/* macros */ +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) +#define VISIBLEON(C, M) \ + ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]) && \ + !(C)->swallowedby) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define END(A) ((A) + LENGTH(A)) +#define TAGMASK ((1u << TAGCOUNT) - 1) +#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) +#define LISTEN_STATIC(E, H) \ + do { \ + static struct wl_listener _l = {.notify = (H)}; \ + wl_signal_add((E), &_l); \ + } while (0) +#define BORDERPX(C) (borderpx + ((C)->swallowing ? (C)->swallowing->bw : 0)) + +/* enums */ +enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ +enum { XDGShell, LayerShell, X11 }; /* client types */ +enum { + LyrBg, + LyrBottom, + LyrTile, + LyrFloat, + LyrTop, + LyrFS, + LyrOverlay, + LyrBlock, + NUM_LAYERS +}; /* scene layers */ +#ifdef XWAYLAND +enum { + NetWMWindowTypeDialog, + NetWMWindowTypeSplash, + NetWMWindowTypeToolbar, + NetWMWindowTypeUtility, + NetLast +}; /* EWMH atoms */ +#endif + +typedef union { + int i; + uint32_t ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int mod; + unsigned int button; + void (*func)(const Arg *); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct Client Client; +struct Client { + /* Must keep these three elements in this order */ + unsigned int type; /* XDGShell or X11* */ + struct wlr_box geom; /* layout-relative, includes border */ + Monitor *mon; + struct wlr_scene_tree *scene; + struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ + struct wlr_scene_tree *scene_surface; + struct wl_list link; + struct wl_list flink; + union { + struct wlr_xdg_surface *xdg; + struct wlr_xwayland_surface *xwayland; + } surface; + struct wlr_xdg_toplevel_decoration_v1 *decoration; + struct wl_listener commit; + struct wl_listener map; + struct wl_listener maximize; + struct wl_listener unmap; + struct wl_listener destroy; + struct wl_listener set_title; + struct wl_listener fullscreen; + struct wl_listener set_decoration_mode; + struct wl_listener destroy_decoration; + struct wlr_box prev; /* layout-relative, includes border */ + struct wlr_box bounds; +#ifdef XWAYLAND + struct wl_listener activate; + struct wl_listener associate; + struct wl_listener dissociate; + struct wl_listener configure; + struct wl_listener set_hints; +#endif + unsigned int bw; + uint32_t tags; + int isfloating, isurgent, isfullscreen; + int isterm, noswallow; + uint32_t resize; /* configure serial of a pending resize */ + pid_t pid; + Client *swallowing; /* client being hidden */ + Client *swallowedby; +}; + +typedef struct { + uint32_t mod; + xkb_keysym_t keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + struct wl_list link; + struct wlr_keyboard_group *wlr_group; + + int nsyms; + const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ + uint32_t mods; /* invalid if nsyms == 0 */ + struct wl_event_source *key_repeat_source; + + struct wl_listener modifiers; + struct wl_listener key; + struct wl_listener destroy; +} KeyboardGroup; + +typedef struct { + /* Must keep these three elements in this order */ + unsigned int type; /* LayerShell */ + struct wlr_box geom; + Monitor *mon; + struct wlr_scene_tree *scene; + struct wlr_scene_tree *popups; + struct wlr_scene_layer_surface_v1 *scene_layer; + struct wl_list link; + int mapped; + struct wlr_layer_surface_v1 *layer_surface; + + struct wl_listener destroy; + struct wl_listener unmap; + struct wl_listener surface_commit; +} LayerSurface; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +struct Monitor { + struct wl_list link; + struct wlr_output *wlr_output; + struct wlr_scene_output *scene_output; + struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ + struct wl_listener frame; + struct wl_listener destroy; + struct wl_listener request_state; + struct wl_listener destroy_lock_surface; + struct wlr_session_lock_surface_v1 *lock_surface; + struct wlr_box m; /* monitor area, layout-relative */ + struct wlr_box w; /* window area, layout-relative */ + struct wl_list layers[4]; /* LayerSurface.link */ + const Layout *lt[2]; + unsigned int seltags; + unsigned int sellt; + uint32_t tagset[2]; + float mfact; + int gamma_lut_changed; + int nmaster; + char ltsymbol[16]; + int asleep; +}; + +typedef struct { + const char *name; + float mfact; + int nmaster; + float scale; + const Layout *lt; + enum wl_output_transform rr; + int x, y; +} MonitorRule; + +typedef struct { + struct wlr_pointer_constraint_v1 *constraint; + struct wl_listener destroy; +} PointerConstraint; + +typedef struct { + const char *id; + const char *title; + uint32_t tags; + int isfloating; + int isterm; + int noswallow; + int monitor; +} Rule; + +typedef struct { + struct wlr_scene_tree *scene; + + struct wlr_session_lock_v1 *lock; + struct wl_listener new_surface; + struct wl_listener unlock; + struct wl_listener destroy; +} SessionLock; + +/* function declarations */ +static void applybounds(Client *c, struct wlr_box *bbox); +static void applyrules(Client *c); +static void arrange(Monitor *m); +static void arrangelayer(Monitor *m, struct wl_list *list, + struct wlr_box *usable_area, int exclusive); +static void arrangelayers(Monitor *m); +static void autostartexec(void); +static void axisnotify(struct wl_listener *listener, void *data); +static void buttonpress(struct wl_listener *listener, void *data); +static void chvt(const Arg *arg); +static void checkidleinhibitor(struct wlr_surface *exclude); +static void cleanup(void); +static void cleanupmon(struct wl_listener *listener, void *data); +static void closemon(Monitor *m); +static void commitlayersurfacenotify(struct wl_listener *listener, void *data); +static void commitnotify(struct wl_listener *listener, void *data); +static void commitpopup(struct wl_listener *listener, void *data); +static void createdecoration(struct wl_listener *listener, void *data); +static void createidleinhibitor(struct wl_listener *listener, void *data); +static void createkeyboard(struct wlr_keyboard *keyboard); +static KeyboardGroup *createkeyboardgroup(void); +static void createlayersurface(struct wl_listener *listener, void *data); +static void createlocksurface(struct wl_listener *listener, void *data); +static void createmon(struct wl_listener *listener, void *data); +static void createnotify(struct wl_listener *listener, void *data); +static void createpointer(struct wlr_pointer *pointer); +static void createpointerconstraint(struct wl_listener *listener, void *data); +static void createpopup(struct wl_listener *listener, void *data); +static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); +static void cursorframe(struct wl_listener *listener, void *data); +static void cursorwarptohint(void); +static void destroydecoration(struct wl_listener *listener, void *data); +static void destroydragicon(struct wl_listener *listener, void *data); +static void destroyidleinhibitor(struct wl_listener *listener, void *data); +static void destroylayersurfacenotify(struct wl_listener *listener, void *data); +static void destroylock(SessionLock *lock, int unlocked); +static void destroylocksurface(struct wl_listener *listener, void *data); +static void destroynotify(struct wl_listener *listener, void *data); +static void destroypointerconstraint(struct wl_listener *listener, void *data); +static void destroysessionlock(struct wl_listener *listener, void *data); +static void destroysessionmgr(struct wl_listener *listener, void *data); +static void destroykeyboardgroup(struct wl_listener *listener, void *data); +static Monitor *dirtomon(enum wlr_direction dir); +static void focusclient(Client *c, int lift); +static void focusmon(const Arg *arg); +static void focusstack(const Arg *arg); +static Client *focustop(Monitor *m); +static void fullscreennotify(struct wl_listener *listener, void *data); +static void gpureset(struct wl_listener *listener, void *data); +static void handlecursoractivity(void); +static int hidecursor(void *data); +static void handlesig(int signo); +static void incnmaster(const Arg *arg); +static void inputdevice(struct wl_listener *listener, void *data); +static int keybinding(uint32_t mods, xkb_keysym_t sym); +static void keypress(struct wl_listener *listener, void *data); +static void keypressmod(struct wl_listener *listener, void *data); +static int keyrepeat(void *data); +static void killclient(const Arg *arg); +static void locksession(struct wl_listener *listener, void *data); +static void mapnotify(struct wl_listener *listener, void *data); +static void maximizenotify(struct wl_listener *listener, void *data); +static void monocle(Monitor *m); +static void motionabsolute(struct wl_listener *listener, void *data); +static void motionnotify(uint32_t time, struct wlr_input_device *device, + double sx, double sy, double sx_unaccel, + double sy_unaccel); +static void motionrelative(struct wl_listener *listener, void *data); +static void moveresize(const Arg *arg); +static void outputmgrapply(struct wl_listener *listener, void *data); +static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, + int test); +static void outputmgrtest(struct wl_listener *listener, void *data); +static pid_t parentpid(pid_t pid); +static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, + double sy, uint32_t time); +static void printstatus(void); +static void powermgrsetmode(struct wl_listener *listener, void *data); +static void quit(const Arg *arg); +static void rendermon(struct wl_listener *listener, void *data); +static void requestdecorationmode(struct wl_listener *listener, void *data); +static void requeststartdrag(struct wl_listener *listener, void *data); +static void requestmonstate(struct wl_listener *listener, void *data); +static void resize(Client *c, struct wlr_box geo, int interact); +static void run(char *startup_cmd); +static void setcursor(struct wl_listener *listener, void *data); +static void setcursorshape(struct wl_listener *listener, void *data); +static void setfloating(Client *c, int floating); +static void setfullscreen(Client *c, int fullscreen); +static void setgamma(struct wl_listener *listener, void *data); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setmon(Client *c, Monitor *m, uint32_t newtags); +static void setpsel(struct wl_listener *listener, void *data); +static void setsel(struct wl_listener *listener, void *data); +static void setup(void); +static void spawn(const Arg *arg); +static void startdrag(struct wl_listener *listener, void *data); +static void swallow(Client *c, Client *toswallow); +static void tag(const Arg *arg); +static void tagmon(const Arg *arg); +static Client *termforwin(Client *c); +static void tile(Monitor *m); +static void togglefloating(const Arg *arg); +static void togglefullscreen(const Arg *arg); +static void toggleswallow(const Arg *arg); +static void toggleautoswallow(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unlocksession(struct wl_listener *listener, void *data); +static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); +static void unmapnotify(struct wl_listener *listener, void *data); +static void updatemons(struct wl_listener *listener, void *data); +static void updatetitle(struct wl_listener *listener, void *data); +static void urgent(struct wl_listener *listener, void *data); +static void view(const Arg *arg); +static void virtualkeyboard(struct wl_listener *listener, void *data); +static void virtualpointer(struct wl_listener *listener, void *data); +static Monitor *xytomon(double x, double y); +static void xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny); +static void zoom(const Arg *arg); + +/* variables */ +static const char broken[] = "broken"; +static pid_t child_pid = -1; +static int locked; +static void *exclusive_focus; +static struct wl_display *dpy; +static struct wl_event_loop *event_loop; +static struct wlr_backend *backend; +static struct wlr_scene *scene; +static struct wlr_scene_tree *layers[NUM_LAYERS]; +static struct wlr_scene_tree *drag_icon; +/* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */ +static const int layermap[] = {LyrBg, LyrBottom, LyrTop, LyrOverlay}; +static struct wlr_renderer *drw; +static struct wlr_allocator *alloc; +static struct wlr_compositor *compositor; +static struct wlr_session *session; + +static struct wlr_xdg_shell *xdg_shell; +static struct wlr_xdg_activation_v1 *activation; +static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; +static struct wl_list clients; /* tiling order */ +static struct wl_list fstack; /* focus order */ +static struct wlr_idle_notifier_v1 *idle_notifier; +static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; +static struct wlr_layer_shell_v1 *layer_shell; +static struct wlr_output_manager_v1 *output_mgr; +static struct wlr_gamma_control_manager_v1 *gamma_control_mgr; +static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; +static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; +static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; +static struct wlr_output_power_manager_v1 *power_mgr; + +static struct wlr_pointer_constraints_v1 *pointer_constraints; +static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; +static struct wlr_pointer_constraint_v1 *active_constraint; + +static struct wlr_cursor *cursor; +static struct wlr_xcursor_manager *cursor_mgr; +static bool cursor_hidden = false; +static struct { + enum wp_cursor_shape_device_v1_shape shape; + struct wlr_surface *surface; + int hotspot_x; + int hotspot_y; + struct wl_listener destroy; +} last_cursor; + +static struct wlr_scene_rect *root_bg; +static struct wlr_session_lock_manager_v1 *session_lock_mgr; +static struct wlr_scene_rect *locked_bg; +static struct wlr_session_lock_v1 *cur_lock; +static struct wl_listener lock_listener = {.notify = locksession}; + +static struct wlr_seat *seat; +static KeyboardGroup *kb_group; +static unsigned int cursor_mode; +static Client *grabc; +static int grabcx, grabcy; /* client-relative */ + +static struct wlr_output_layout *output_layout; +static struct wlr_box sgeom; +static struct wl_list mons; +static Monitor *selmon; + +#ifdef XWAYLAND +static void activatex11(struct wl_listener *listener, void *data); +static void associatex11(struct wl_listener *listener, void *data); +static void configurex11(struct wl_listener *listener, void *data); +static void createnotifyx11(struct wl_listener *listener, void *data); +static void dissociatex11(struct wl_listener *listener, void *data); +static xcb_atom_t getatom(xcb_connection_t *xc, const char *name); +static void sethints(struct wl_listener *listener, void *data); +static void xwaylandready(struct wl_listener *listener, void *data); +static struct wlr_xwayland *xwayland; +static xcb_atom_t netatom[NetLast]; +#endif + +static pid_t *autostart_pids; +static size_t autostart_len; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* attempt to encapsulate suck into one file */ +#include "client.h" + +/* function implementations */ +void applybounds(Client *c, struct wlr_box *bbox) { + /* set minimum possible */ + c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); + c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height); + + if (c->geom.x >= bbox->x + bbox->width) + c->geom.x = bbox->x + bbox->width - c->geom.width; + if (c->geom.y >= bbox->y + bbox->height) + c->geom.y = bbox->y + bbox->height - c->geom.height; + if (c->geom.x + c->geom.width <= bbox->x) + c->geom.x = bbox->x; + if (c->geom.y + c->geom.height <= bbox->y) + c->geom.y = bbox->y; +} + +void applyrules(Client *c) { + /* rule matching */ + const char *appid, *title; + uint32_t newtags = 0; + int i; + const Rule *r; + Monitor *mon = selmon, *m; + + c->isfloating = client_is_float_type(c); + if (!(appid = client_get_appid(c))) + appid = broken; + if (!(title = client_get_title(c))) + title = broken; + + c->pid = client_get_pid(c); + + for (r = rules; r < END(rules); r++) { + if ((!r->title || strstr(title, r->title)) && + (!r->id || strstr(appid, r->id))) { + c->isfloating = r->isfloating; + newtags |= r->tags; + c->isterm = r->isterm; + c->noswallow = r->noswallow; + i = 0; + wl_list_for_each(m, &mons, link) { + if (r->monitor == i++) + mon = m; + } + } + } + if (enableautoswallow && !c->noswallow && !c->isfloating && + !c->surface.xdg->initial_commit) { + Client *p = termforwin(c); + if (p) + swallow(c, p); + } + setmon(c, mon, newtags); +} + +void arrange(Monitor *m) { + Client *c; + + if (!m->wlr_output->enabled) + return; + + wl_list_for_each(c, &clients, link) { + if (c->mon == m) { + wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); + client_set_suspended(c, !VISIBLEON(c, m)); + } + } + + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, + (c = focustop(m)) && c->isfullscreen); + + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + + /* We move all clients (except fullscreen and unmanaged) to LyrTile while + * in floating layout to avoid "real" floating clients be always on top */ + wl_list_for_each(c, &clients, link) { + if (c->mon != m || c->scene->node.parent == layers[LyrFS]) + continue; + + wlr_scene_node_reparent( + &c->scene->node, + (!m->lt[m->sellt]->arrange && c->isfloating) ? layers[LyrTile] + : (m->lt[m->sellt]->arrange && c->isfloating) ? layers[LyrFloat] + : c->scene->node.parent); + } + + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); + motionnotify(0, NULL, 0, 0, 0, 0); + checkidleinhibitor(NULL); +} + +void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, + int exclusive) { + LayerSurface *l; + struct wlr_box full_area = m->m; + + wl_list_for_each(l, list, link) { + struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + + if (exclusive != (layer_surface->current.exclusive_zone > 0)) + continue; + + wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, + usable_area); + wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, + l->scene->node.y); + l->geom.x = l->scene->node.x; + l->geom.y = l->scene->node.y; + } +} + +void arrangelayers(Monitor *m) { + int i; + struct wlr_box usable_area = m->m; + LayerSurface *l; + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + if (!m->wlr_output->enabled) + return; + + /* Arrange exclusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer(m, &m->layers[i], &usable_area, 1); + + if (!wlr_box_equal(&usable_area, &m->w)) { + m->w = usable_area; + arrange(m); + } + + /* Arrange non-exlusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer(m, &m->layers[i], &usable_area, 0); + + /* Find topmost keyboard interactive layer, if such a layer exists */ + for (i = 0; i < (int)LENGTH(layers_above_shell); i++) { + wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { + if (locked || !l->layer_surface->current.keyboard_interactive || + !l->mapped) + continue; + /* Deactivate the focused client. */ + focusclient(NULL, 0); + exclusive_focus = l; + client_notify_enter(l->layer_surface->surface, + wlr_seat_get_keyboard(seat)); + return; + } + } +} + +void autostartexec(void) { + const char *const *p; + size_t i = 0; + + /* count entries */ + for (p = autostart; *p; autostart_len++, p++) + while (*++p) + ; + + autostart_pids = calloc(autostart_len, sizeof(pid_t)); + for (p = autostart; *p; i++, p++) { + if ((autostart_pids[i] = fork()) == 0) { + setsid(); + execvp(*p, (char *const *)p); + die("dwl: execvp %s:", *p); + } + /* skip arguments */ + while (*++p) + ; + } +} + +void axisnotify(struct wl_listener *listener, void *data) { + /* This event is forwarded by the cursor when a pointer emits an axis event, + * for example when you move the scroll wheel. */ + struct wlr_pointer_axis_event *event = data; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + handlecursoractivity(); + /* TODO: allow usage of scroll whell for mousebindings, it can be implemented + * checking the event's orientation and the delta of the event */ + /* Notify the client with pointer focus of the axis event. */ + wlr_seat_pointer_notify_axis(seat, event->time_msec, event->orientation, + event->delta, event->delta_discrete, + event->source, event->relative_direction); +} + +void buttonpress(struct wl_listener *listener, void *data) { + struct wlr_pointer_button_event *event = data; + struct wlr_keyboard *keyboard; + uint32_t mods; + Client *c; + const Button *b; + + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + handlecursoractivity(); + + switch (event->state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + cursor_mode = CurPressed; + selmon = xytomon(cursor->x, cursor->y); + if (locked) + break; + + /* Change focus if the button was _pressed_ over a client */ + xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); + if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) + focusclient(c, 1); + + keyboard = wlr_seat_get_keyboard(seat); + mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; + for (b = buttons; b < END(buttons); b++) { + if (CLEANMASK(mods) == CLEANMASK(b->mod) && event->button == b->button && + b->func) { + b->func(&b->arg); + return; + } + } + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + /* If you released any buttons, we exit interactive move/resize mode. */ + /* TODO should reset to the pointer focus's current setcursor */ + if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + cursor_mode = CurNormal; + /* Drop the window off on its new monitor */ + selmon = xytomon(cursor->x, cursor->y); + setmon(grabc, selmon, 0); + return; + } else { + cursor_mode = CurNormal; + } + break; + } + /* If the event wasn't handled by the compositor, notify the client with + * pointer focus that a button press has occurred */ + wlr_seat_pointer_notify_button(seat, event->time_msec, event->button, + event->state); +} + +void chvt(const Arg *arg) { wlr_session_change_vt(session, arg->ui); } + +void checkidleinhibitor(struct wlr_surface *exclude) { + int inhibited = 0, unused_lx, unused_ly; + struct wlr_idle_inhibitor_v1 *inhibitor; + wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { + struct wlr_surface *surface = + wlr_surface_get_root_surface(inhibitor->surface); + struct wlr_scene_tree *tree = surface->data; + if (exclude != surface && + (bypass_surface_visibility || + (!tree || + wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) { + inhibited = 1; + break; + } + } + + wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); +} + +void cleanup(void) { + size_t i; +#ifdef XWAYLAND + wlr_xwayland_destroy(xwayland); + xwayland = NULL; +#endif + wl_display_destroy_clients(dpy); + + /* kill child processes */ + for (i = 0; i < autostart_len; i++) { + if (0 < autostart_pids[i]) { + kill(autostart_pids[i], SIGTERM); + waitpid(autostart_pids[i], NULL, 0); + } + } + + if (child_pid > 0) { + kill(-child_pid, SIGTERM); + waitpid(child_pid, NULL, 0); + } + wlr_xcursor_manager_destroy(cursor_mgr); + + destroykeyboardgroup(&kb_group->destroy, NULL); + + /* If it's not destroyed manually it will cause a use-after-free of wlr_seat. + * Destroy it until it's fixed in the wlroots side */ + wlr_backend_destroy(backend); + + wl_display_destroy(dpy); + /* Destroy after the wayland display (when the monitors are already destroyed) + to avoid destroying them with an invalid scene output. */ + wlr_scene_node_destroy(&scene->tree.node); +} + +void cleanupmon(struct wl_listener *listener, void *data) { + Monitor *m = wl_container_of(listener, m, destroy); + LayerSurface *l, *tmp; + size_t i; + + /* m->layers[i] are intentionally not unlinked */ + for (i = 0; i < LENGTH(m->layers); i++) { + wl_list_for_each_safe(l, tmp, &m->layers[i], link) + wlr_layer_surface_v1_destroy(l->layer_surface); + } + + wl_list_remove(&m->destroy.link); + wl_list_remove(&m->frame.link); + wl_list_remove(&m->link); + wl_list_remove(&m->request_state.link); + m->wlr_output->data = NULL; + wlr_output_layout_remove(output_layout, m->wlr_output); + wlr_scene_output_destroy(m->scene_output); + + closemon(m); + wlr_scene_node_destroy(&m->fullscreen_bg->node); + free(m); +} + +void closemon(Monitor *m) { + /* update selmon if needed and + * move closed monitor's clients to the focused one */ + Client *c; + int i = 0, nmons = wl_list_length(&mons); + if (!nmons) { + selmon = NULL; + } else if (m == selmon) { + do /* don't switch to disabled mons */ + selmon = wl_container_of(mons.next, selmon, link); + while (!selmon->wlr_output->enabled && i++ < nmons); + + if (!selmon->wlr_output->enabled) + selmon = NULL; + } + + wl_list_for_each(c, &clients, link) { + if (c->isfloating && c->geom.x > m->m.width) + resize(c, + (struct wlr_box){.x = c->geom.x - m->w.width, + .y = c->geom.y, + .width = c->geom.width, + .height = c->geom.height}, + 0); + if (c->mon == m) + setmon(c, selmon, c->tags); + } + focusclient(focustop(selmon), 1); + printstatus(); +} + +void commitlayersurfacenotify(struct wl_listener *listener, void *data) { + LayerSurface *l = wl_container_of(listener, l, surface_commit); + struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + struct wlr_scene_tree *scene_layer = + layers[layermap[layer_surface->current.layer]]; + struct wlr_layer_surface_v1_state old_state; + + if (l->layer_surface->initial_commit) { + wlr_fractional_scale_v1_notify_scale(layer_surface->surface, + l->mon->wlr_output->scale); + wlr_surface_set_preferred_buffer_scale( + layer_surface->surface, (int32_t)ceilf(l->mon->wlr_output->scale)); + + /* Temporarily set the layer's current state to pending + * so that we can easily arrange it */ + old_state = l->layer_surface->current; + l->layer_surface->current = l->layer_surface->pending; + arrangelayers(l->mon); + l->layer_surface->current = old_state; + return; + } + + if (layer_surface->current.committed == 0 && + l->mapped == layer_surface->surface->mapped) + return; + l->mapped = layer_surface->surface->mapped; + + if (scene_layer != l->scene->node.parent) { + wlr_scene_node_reparent(&l->scene->node, scene_layer); + wl_list_remove(&l->link); + wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link); + wlr_scene_node_reparent( + &l->popups->node, + (layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP + ? layers[LyrTop] + : scene_layer)); + } + + arrangelayers(l->mon); +} + +void commitnotify(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, commit); + + if (c->surface.xdg->initial_commit) { + /* + * Get the monitor this client will be rendered on + * Note that if the user set a rule in which the client is placed on + * a different monitor based on its title this will likely select + * a wrong monitor. + */ + applyrules(c); + wlr_surface_set_preferred_buffer_scale( + client_surface(c), (int)ceilf(c->mon->wlr_output->scale)); + wlr_fractional_scale_v1_notify_scale(client_surface(c), + c->mon->wlr_output->scale); + setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ + + wlr_xdg_toplevel_set_wm_capabilities( + c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); + if (c->decoration) + requestdecorationmode(&c->set_decoration_mode, c->decoration); + return; + } + + if (client_surface(c)->mapped && c->mon) + resize(c, c->geom, (c->isfloating && !c->isfullscreen)); + + /* mark a pending resize as completed */ + if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) + c->resize = 0; +} + +void commitpopup(struct wl_listener *listener, void *data) { + struct wlr_surface *surface = data; + struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); + LayerSurface *l = NULL; + Client *c = NULL; + struct wlr_box box; + int type = -1; + + if (!popup->base->initial_commit) + return; + + type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); + if (!popup->parent || type < 0) + return; + popup->base->surface->data = + wlr_scene_xdg_surface_create(popup->parent->data, popup->base); + if ((l && !l->mon) || (c && !c->mon)) + return; + box = type == LayerShell ? l->mon->m : c->mon->w; + box.x -= (type == LayerShell ? l->geom.x : c->geom.x); + box.y -= (type == LayerShell ? l->geom.y : c->geom.y); + wlr_xdg_popup_unconstrain_from_box(popup, &box); + wl_list_remove(&listener->link); +} + +void createdecoration(struct wl_listener *listener, void *data) { + struct wlr_xdg_toplevel_decoration_v1 *deco = data; + Client *c = deco->toplevel->base->data; + c->decoration = deco; + + LISTEN(&deco->events.request_mode, &c->set_decoration_mode, + requestdecorationmode); + LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration); + + requestdecorationmode(&c->set_decoration_mode, deco); +} + +void createidleinhibitor(struct wl_listener *listener, void *data) { + struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; + LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor); + + checkidleinhibitor(NULL); +} + +void createkeyboard(struct wlr_keyboard *keyboard) { + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); + + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); +} + +KeyboardGroup *createkeyboardgroup(void) { + KeyboardGroup *group = ecalloc(1, sizeof(*group)); + struct xkb_context *context; + struct xkb_keymap *keymap; + + group->wlr_group = wlr_keyboard_group_create(); + group->wlr_group->data = group; + + /* Prepare an XKB keymap and assign it to the keyboard group. */ + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS))) + die("failed to compile keymap"); + + wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + + wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, + repeat_delay); + + /* Set up listeners for keyboard events */ + LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); + LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, + keypressmod); + + group->key_repeat_source = + wl_event_loop_add_timer(event_loop, keyrepeat, group); + + /* A seat can only have one keyboard, but this is a limitation of the + * Wayland protocol - not wlroots. We assign all connected keyboards to the + * same wlr_keyboard_group, which provides a single wlr_keyboard interface for + * all of them. Set this combined wlr_keyboard as the seat keyboard. + */ + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + return group; +} + +void createlayersurface(struct wl_listener *listener, void *data) { + struct wlr_layer_surface_v1 *layer_surface = data; + LayerSurface *l; + struct wlr_surface *surface = layer_surface->surface; + struct wlr_scene_tree *scene_layer = + layers[layermap[layer_surface->pending.layer]]; + + if (!layer_surface->output && + !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) { + wlr_layer_surface_v1_destroy(layer_surface); + return; + } + + l = layer_surface->data = ecalloc(1, sizeof(*l)); + l->type = LayerShell; + LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); + LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); + LISTEN(&layer_surface->events.destroy, &l->destroy, + destroylayersurfacenotify); + + l->layer_surface = layer_surface; + l->mon = layer_surface->output->data; + l->scene_layer = + wlr_scene_layer_surface_v1_create(scene_layer, layer_surface); + l->scene = l->scene_layer->tree; + l->popups = surface->data = wlr_scene_tree_create( + layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP + ? layers[LyrTop] + : scene_layer); + l->scene->node.data = l->popups->node.data = l; + + wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link); + wlr_surface_send_enter(surface, layer_surface->output); +} + +void createlocksurface(struct wl_listener *listener, void *data) { + SessionLock *lock = wl_container_of(listener, lock, new_surface); + struct wlr_session_lock_surface_v1 *lock_surface = data; + Monitor *m = lock_surface->output->data; + struct wlr_scene_tree *scene_tree = lock_surface->surface->data = + wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface); + m->lock_surface = lock_surface; + + wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); + wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height); + + LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, + destroylocksurface); + + if (m == selmon) + client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat)); +} + +void createmon(struct wl_listener *listener, void *data) { + /* This event is raised by the backend when a new output (aka a display or + * monitor) becomes available. */ + struct wlr_output *wlr_output = data; + const MonitorRule *r; + size_t i; + struct wlr_output_state state; + Monitor *m; + + if (!wlr_output_init_render(wlr_output, alloc, drw)) + return; + + m = wlr_output->data = ecalloc(1, sizeof(*m)); + m->wlr_output = wlr_output; + + for (i = 0; i < LENGTH(m->layers); i++) + wl_list_init(&m->layers[i]); + + wlr_output_state_init(&state); + /* Initialize monitor state using configured rules */ + m->tagset[0] = m->tagset[1] = 1; + for (r = monrules; r < END(monrules); r++) { + if (!r->name || strstr(wlr_output->name, r->name)) { + m->m.x = r->x; + m->m.y = r->y; + m->mfact = r->mfact; + m->nmaster = r->nmaster; + m->lt[0] = r->lt; + m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]]; + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + wlr_output_state_set_scale(&state, r->scale); + wlr_output_state_set_transform(&state, r->rr); + break; + } + } + + /* The mode is a tuple of (width, height, refresh rate), and each + * monitor supports only a specific set of modes. We just pick the + * monitor's preferred mode; a more sophisticated compositor would let + * the user configure it. */ + wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); + + /* Set up event listeners */ + LISTEN(&wlr_output->events.frame, &m->frame, rendermon); + LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); + LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); + + wlr_output_state_set_enabled(&state, 1); + wlr_output_commit_state(wlr_output, &state); + wlr_output_state_finish(&state); + + wl_list_insert(&mons, &m->link); + printstatus(); + + /* The xdg-protocol specifies: + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + * + */ + /* updatemons() will resize and set correct position */ + m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); + + /* Adds this to the output layout in the order it was configured. + * + * The output layout utility automatically adds a wl_output global to the + * display, which Wayland clients can see to find out information about the + * output (such as DPI, scale factor, manufacturer, etc). + */ + m->scene_output = wlr_scene_output_create(scene, wlr_output); + if (m->m.x == -1 && m->m.y == -1) + wlr_output_layout_add_auto(output_layout, wlr_output); + else + wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); +} + +void createnotify(struct wl_listener *listener, void *data) { + /* This event is raised when a client creates a new toplevel (application + * window). */ + struct wlr_xdg_toplevel *toplevel = data; + Client *c = NULL; + + /* Allocate a Client for this surface */ + c = toplevel->base->data = ecalloc(1, sizeof(*c)); + c->surface.xdg = toplevel->base; + c->bw = borderpx; + + LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); + LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); + LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify); + LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, + fullscreennotify); + LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify); + LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle); +} + +void createpointer(struct wlr_pointer *pointer) { + struct libinput_device *device; + if (wlr_input_device_is_libinput(&pointer->base) && + (device = wlr_libinput_get_device_handle(&pointer->base))) { + + if (libinput_device_config_tap_get_finger_count(device)) { + libinput_device_config_tap_set_enabled(device, tap_to_click); + libinput_device_config_tap_set_drag_enabled(device, tap_and_drag); + libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock); + libinput_device_config_tap_set_button_map(device, button_map); + } + + if (libinput_device_config_scroll_has_natural_scroll(device)) + libinput_device_config_scroll_set_natural_scroll_enabled( + device, natural_scrolling); + + if (libinput_device_config_dwt_is_available(device)) + libinput_device_config_dwt_set_enabled(device, disable_while_typing); + + if (libinput_device_config_left_handed_is_available(device)) + libinput_device_config_left_handed_set(device, left_handed); + + if (libinput_device_config_middle_emulation_is_available(device)) + libinput_device_config_middle_emulation_set_enabled( + device, middle_button_emulation); + + if (libinput_device_config_scroll_get_methods(device) != + LIBINPUT_CONFIG_SCROLL_NO_SCROLL) + libinput_device_config_scroll_set_method(device, scroll_method); + + if (libinput_device_config_click_get_methods(device) != + LIBINPUT_CONFIG_CLICK_METHOD_NONE) + libinput_device_config_click_set_method(device, click_method); + + if (libinput_device_config_send_events_get_modes(device)) + libinput_device_config_send_events_set_mode(device, send_events_mode); + + if (libinput_device_config_accel_is_available(device)) { + libinput_device_config_accel_set_profile(device, accel_profile); + libinput_device_config_accel_set_speed(device, accel_speed); + } + } + + wlr_cursor_attach_input_device(cursor, &pointer->base); +} + +void createpointerconstraint(struct wl_listener *listener, void *data) { + PointerConstraint *pointer_constraint = + ecalloc(1, sizeof(*pointer_constraint)); + pointer_constraint->constraint = data; + LISTEN(&pointer_constraint->constraint->events.destroy, + &pointer_constraint->destroy, destroypointerconstraint); +} + +void createpopup(struct wl_listener *listener, void *data) { + /* This event is raised when a client (either xdg-shell or layer-shell) + * creates a new popup. */ + struct wlr_xdg_popup *popup = data; + LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); +} + +void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) { + if (active_constraint == constraint) + return; + + if (active_constraint) + wlr_pointer_constraint_v1_send_deactivated(active_constraint); + + active_constraint = constraint; + wlr_pointer_constraint_v1_send_activated(constraint); +} + +void cursorframe(struct wl_listener *listener, void *data) { + /* This event is forwarded by the cursor when a pointer emits an frame + * event. Frame events are sent after regular pointer events to group + * multiple events together. For instance, two axis events may happen at the + * same time, in which case a frame event won't be sent in between. */ + /* Notify the client with pointer focus of the frame event. */ + wlr_seat_pointer_notify_frame(seat); +} + +void cursorwarptohint(void) { + Client *c = NULL; + double sx = active_constraint->current.cursor_hint.x; + double sy = active_constraint->current.cursor_hint.y; + + toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); + if (c && active_constraint->current.cursor_hint.enabled) { + wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, + sy + c->geom.y + c->bw); + wlr_seat_pointer_warp(active_constraint->seat, sx, sy); + } +} + +void destroydecoration(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, destroy_decoration); + c->decoration = NULL; + + wl_list_remove(&c->destroy_decoration.link); + wl_list_remove(&c->set_decoration_mode.link); +} + +void destroydragicon(struct wl_listener *listener, void *data) { + /* Focus enter isn't sent during drag, so refocus the focused node. */ + focusclient(focustop(selmon), 1); + motionnotify(0, NULL, 0, 0, 0, 0); +} + +void destroyidleinhibitor(struct wl_listener *listener, void *data) { + /* `data` is the wlr_surface of the idle inhibitor being destroyed, + * at this point the idle inhibitor is still in the list of the manager */ + checkidleinhibitor(wlr_surface_get_root_surface(data)); +} + +void destroylayersurfacenotify(struct wl_listener *listener, void *data) { + LayerSurface *l = wl_container_of(listener, l, destroy); + + wl_list_remove(&l->link); + wl_list_remove(&l->destroy.link); + wl_list_remove(&l->unmap.link); + wl_list_remove(&l->surface_commit.link); + wlr_scene_node_destroy(&l->scene->node); + wlr_scene_node_destroy(&l->popups->node); + free(l); +} + +void destroylock(SessionLock *lock, int unlock) { + wlr_seat_keyboard_notify_clear_focus(seat); + if ((locked = !unlock)) + goto destroy; + + wlr_scene_node_set_enabled(&locked_bg->node, 0); + + focusclient(focustop(selmon), 0); + motionnotify(0, NULL, 0, 0, 0, 0); + +destroy: + wl_list_remove(&lock->new_surface.link); + wl_list_remove(&lock->unlock.link); + wl_list_remove(&lock->destroy.link); + + wlr_scene_node_destroy(&lock->scene->node); + cur_lock = NULL; + free(lock); +} + +void destroylocksurface(struct wl_listener *listener, void *data) { + Monitor *m = wl_container_of(listener, m, destroy_lock_surface); + struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface; + + m->lock_surface = NULL; + wl_list_remove(&m->destroy_lock_surface.link); + + if (lock_surface->surface != seat->keyboard_state.focused_surface) + return; + + if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { + surface = wl_container_of(cur_lock->surfaces.next, surface, link); + client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); + } else if (!locked) { + focusclient(focustop(selmon), 1); + } else { + wlr_seat_keyboard_clear_focus(seat); + } +} + +void destroynotify(struct wl_listener *listener, void *data) { + /* Called when the xdg_toplevel is destroyed. */ + Client *c = wl_container_of(listener, c, destroy); + wl_list_remove(&c->destroy.link); + wl_list_remove(&c->set_title.link); + wl_list_remove(&c->fullscreen.link); +#ifdef XWAYLAND + if (c->type != XDGShell) { + wl_list_remove(&c->activate.link); + wl_list_remove(&c->associate.link); + wl_list_remove(&c->configure.link); + wl_list_remove(&c->dissociate.link); + wl_list_remove(&c->set_hints.link); + } else +#endif + { + wl_list_remove(&c->commit.link); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); + } + free(c); +} + +void destroypointerconstraint(struct wl_listener *listener, void *data) { + PointerConstraint *pointer_constraint = + wl_container_of(listener, pointer_constraint, destroy); + + if (active_constraint == pointer_constraint->constraint) { + cursorwarptohint(); + active_constraint = NULL; + } + + wl_list_remove(&pointer_constraint->destroy.link); + free(pointer_constraint); +} + +void destroysessionlock(struct wl_listener *listener, void *data) { + SessionLock *lock = wl_container_of(listener, lock, destroy); + destroylock(lock, 0); +} + +void destroysessionmgr(struct wl_listener *listener, void *data) { + wl_list_remove(&lock_listener.link); + wl_list_remove(&listener->link); +} + +void destroykeyboardgroup(struct wl_listener *listener, void *data) { + KeyboardGroup *group = wl_container_of(listener, group, destroy); + wl_event_source_remove(group->key_repeat_source); + wlr_keyboard_group_destroy(group->wlr_group); + wl_list_remove(&group->key.link); + wl_list_remove(&group->modifiers.link); + wl_list_remove(&group->destroy.link); + free(group); +} + +Monitor *dirtomon(enum wlr_direction dir) { + struct wlr_output *next; + if (!wlr_output_layout_get(output_layout, selmon->wlr_output)) + return selmon; + if ((next = wlr_output_layout_adjacent_output( + output_layout, dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) + return next->data; + if ((next = wlr_output_layout_farthest_output( + output_layout, dir ^ (WLR_DIRECTION_LEFT | WLR_DIRECTION_RIGHT), + selmon->wlr_output, selmon->m.x, selmon->m.y))) + return next->data; + return selmon; +} + +void focusclient(Client *c, int lift) { + struct wlr_surface *old = seat->keyboard_state.focused_surface; + int unused_lx, unused_ly, old_client_type; + Client *old_c = NULL; + LayerSurface *old_l = NULL; + + if (locked) + return; + + /* Raise client in stacking order if requested */ + if (c && lift) + wlr_scene_node_raise_to_top(&c->scene->node); + + if (c && client_surface(c) == old) + return; + + if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == + XDGShell) { + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link) + wlr_xdg_popup_destroy(popup); + } + + /* Put the new client atop the focus stack and select its monitor */ + if (c && !client_is_unmanaged(c)) { + wl_list_remove(&c->flink); + wl_list_insert(&fstack, &c->flink); + selmon = c->mon; + c->isurgent = 0; + client_restack_surface(c); + + /* Don't change border color if there is an exclusive focus or we are + * handling a drag operation */ + if (!exclusive_focus && !seat->drag) + client_set_border_color(c, focuscolor); + } + + /* Deactivate old client if focus is changing */ + if (old && (!c || client_surface(c) != old)) { + /* If an overlay is focused, don't focus or activate the client, + * but only update its position in fstack to render its border with + * focuscolor and focus it after the overlay is closed. */ + if (old_client_type == LayerShell && + wlr_scene_node_coords(&old_l->scene->node, &unused_lx, &unused_ly) && + old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { + return; + } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) { + return; + /* Don't deactivate old client if the new one wants focus, as this causes + * issues with winecfg and probably other clients */ + } else if (old_c && !client_is_unmanaged(old_c) && + (!c || !client_wants_focus(c))) { + client_set_border_color(old_c, bordercolor); + + client_activate_surface(old, 0); + } + } + printstatus(); + + if (!c) { + /* With no client, all we have left is to clear focus */ + wlr_seat_keyboard_notify_clear_focus(seat); + return; + } + + /* Change cursor surface */ + motionnotify(0, NULL, 0, 0, 0, 0); + + /* Have a client, so focus its top-level wlr_surface */ + client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); + + /* Activate the new client */ + client_activate_surface(client_surface(c), 1); +} + +void focusmon(const Arg *arg) { + int i = 0, nmons = wl_list_length(&mons); + if (nmons) { + do /* don't switch to disabled mons */ + selmon = dirtomon(arg->i); + while (!selmon->wlr_output->enabled && i++ < nmons); + } + focusclient(focustop(selmon), 1); +} + +void focusstack(const Arg *arg) { + /* Focus the next or previous client (in tiling order) on selmon */ + Client *c, *sel = focustop(selmon); + if (!sel || (sel->isfullscreen && !client_has_children(sel))) + return; + if (arg->i > 0) { + wl_list_for_each(c, &sel->link, link) { + if (&c->link == &clients) + continue; /* wrap past the sentinel node */ + if (VISIBLEON(c, selmon)) + break; /* found it */ + } + } else { + wl_list_for_each_reverse(c, &sel->link, link) { + if (&c->link == &clients) + continue; /* wrap past the sentinel node */ + if (VISIBLEON(c, selmon)) + break; /* found it */ + } + } + /* If only one client is visible on selmon, then c == sel */ + focusclient(c, 1); +} + +/* We probably should change the name of this, it sounds like + * will focus the topmost client of this mon, when actually will + * only return that client */ +Client *focustop(Monitor *m) { + Client *c; + wl_list_for_each(c, &fstack, flink) { + if (VISIBLEON(c, m)) + return c; + } + return NULL; +} + +void fullscreennotify(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, fullscreen); + setfullscreen(c, client_wants_fullscreen(c)); +} + +void gpureset(struct wl_listener *listener, void *data) { + struct wlr_renderer *old_drw = drw; + struct wlr_allocator *old_alloc = alloc; + struct Monitor *m; + if (!(drw = wlr_renderer_autocreate(backend))) + die("couldn't recreate renderer"); + + if (!(alloc = wlr_allocator_autocreate(backend, drw))) + die("couldn't recreate allocator"); + + LISTEN_STATIC(&drw->events.lost, gpureset); + + wlr_compositor_set_renderer(compositor, drw); + + wl_list_for_each(m, &mons, link) { + wlr_output_init_render(m->wlr_output, alloc, drw); + } + + wlr_allocator_destroy(old_alloc); + wlr_renderer_destroy(old_drw); +} + +void handlesig(int signo) { +#ifdef XWAYLAND + siginfo_t in; + /* wlroots expects to reap the XWayland process itself, so we + * use WNOWAIT to keep the child waitable until we know it's not + * XWayland. + */ + while (!waitid(P_ALL, 0, &in, WEXITED | WNOHANG | WNOWAIT) && in.si_pid && + (!xwayland || in.si_pid != xwayland->server->pid)) + waitpid(in.si_pid, NULL, 0); +#else + while (waitpid(-1, NULL, WNOHANG) > 0) + ; +#endif + if (signo == SIGCHLD) { + pid_t pid, *p, *lim; + while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { + if (pid == child_pid) + child_pid = -1; + if (!(p = autostart_pids)) + continue; + lim = &p[autostart_len]; + + for (; p < lim; p++) { + if (*p == pid) { + *p = -1; + break; + } + } + } + } else if (signo == SIGINT || signo == SIGTERM) { + quit(NULL); + } +} + +void handlecursoractivity(void) { + if (!cursor_hidden) + return; + + cursor_hidden = false; + + if (last_cursor.shape) { + wlr_cursor_set_xcursor(cursor, cursor_mgr, + wlr_cursor_shape_v1_name(last_cursor.shape)); + } else if (last_cursor.surface) { + wlr_cursor_set_surface(cursor, last_cursor.surface, last_cursor.hotspot_x, + last_cursor.hotspot_y); + } else { + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + } +} + +int hidecursor(void *data) { + wlr_cursor_unset_image(cursor); + cursor_hidden = true; + return 1; +} + +void incnmaster(const Arg *arg) { + if (!arg || !selmon) + return; + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +void inputdevice(struct wl_listener *listener, void *data) { + /* This event is raised by the backend when a new input device becomes + * available. */ + struct wlr_input_device *device = data; + uint32_t caps; + + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + createkeyboard(wlr_keyboard_from_input_device(device)); + break; + case WLR_INPUT_DEVICE_POINTER: + createpointer(wlr_pointer_from_input_device(device)); + break; + default: + /* TODO handle other input device types */ + break; + } + + /* We need to let the wlr_seat know what our capabilities are, which is + * communiciated to the client. In dwl we always have a cursor, even if + * there are no pointer devices, so we always include that capability. */ + /* TODO do we actually require a cursor? */ + caps = WL_SEAT_CAPABILITY_POINTER; + if (!wl_list_empty(&kb_group->wlr_group->devices)) + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + wlr_seat_set_capabilities(seat, caps); +} + +int keybinding(uint32_t mods, xkb_keysym_t sym) { + /* + * Here we handle compositor keybindings. This is when the compositor is + * processing keys, rather than passing them on to the client for its own + * processing. + */ + const Key *k; + for (k = keys; k < END(keys); k++) { + if (CLEANMASK(mods) == CLEANMASK(k->mod) && sym == k->keysym && k->func) { + k->func(&k->arg); + return 1; + } + } + return 0; +} + +void keypress(struct wl_listener *listener, void *data) { + int i; + /* This event is raised when a key is pressed or released. */ + KeyboardGroup *group = wl_container_of(listener, group, key); + struct wlr_keyboard_key_event *event = data; + + /* Translate libinput keycode -> xkbcommon */ + uint32_t keycode = event->keycode + 8; + /* Get a list of keysyms based on the keymap for this keyboard */ + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(group->wlr_group->keyboard.xkb_state, + keycode, &syms); + + int handled = 0; + uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); + + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + + /* hide cursor when typing starts */ + if (hide_cursor_when_typing && !cursor_hidden && + event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + hidecursor(NULL); + } + + /* On _press_ if there is no active screen locker, + * attempt to process a compositor keybinding. */ + if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + for (i = 0; i < nsyms; i++) + handled = keybinding(mods, syms[i]) || handled; + } + + if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { + group->mods = mods; + group->keysyms = syms; + group->nsyms = nsyms; + wl_event_source_timer_update(group->key_repeat_source, + group->wlr_group->keyboard.repeat_info.delay); + } else { + group->nsyms = 0; + wl_event_source_timer_update(group->key_repeat_source, 0); + } + + if (handled) + return; + + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + /* Pass unhandled keycodes along to the client. */ + wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, + event->state); +} + +void keypressmod(struct wl_listener *listener, void *data) { + /* This event is raised when a modifier key, such as shift or alt, is + * pressed. We simply communicate this to the client. */ + KeyboardGroup *group = wl_container_of(listener, group, modifiers); + + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + /* Send modifiers to the client. */ + wlr_seat_keyboard_notify_modifiers(seat, + &group->wlr_group->keyboard.modifiers); +} + +int keyrepeat(void *data) { + KeyboardGroup *group = data; + int i; + if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) + return 0; + + wl_event_source_timer_update(group->key_repeat_source, + 1000 / + group->wlr_group->keyboard.repeat_info.rate); + + for (i = 0; i < group->nsyms; i++) + keybinding(group->mods, group->keysyms[i]); + + return 0; +} + +void killclient(const Arg *arg) { + Client *sel = focustop(selmon); + if (sel) + client_send_close(sel); +} + +void locksession(struct wl_listener *listener, void *data) { + struct wlr_session_lock_v1 *session_lock = data; + SessionLock *lock; + wlr_scene_node_set_enabled(&locked_bg->node, 1); + if (cur_lock) { + wlr_session_lock_v1_destroy(session_lock); + return; + } + lock = session_lock->data = ecalloc(1, sizeof(*lock)); + focusclient(NULL, 0); + + lock->scene = wlr_scene_tree_create(layers[LyrBlock]); + cur_lock = lock->lock = session_lock; + locked = 1; + + LISTEN(&session_lock->events.new_surface, &lock->new_surface, + createlocksurface); + LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); + LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession); + + wlr_session_lock_v1_send_locked(session_lock); +} + +void mapnotify(struct wl_listener *listener, void *data) { + /* Called when the surface is mapped, or ready to display on-screen. */ + Client *p = NULL; + Client *w, *c = wl_container_of(listener, c, map); + Monitor *m; + int i; + + /* Create scene tree for this client and its border */ + c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); + wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell); + c->scene_surface = + c->type == XDGShell + ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) + : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); + c->scene->node.data = c->scene_surface->node.data = c; + + client_get_geometry(c, &c->geom); + + /* Handle unmanaged clients first so we can return prior create borders */ + if (client_is_unmanaged(c)) { + /* Unmanaged clients always are floating */ + wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + if (client_wants_focus(c)) { + focusclient(c, 1); + exclusive_focus = c; + } + goto unset_fullscreen; + } + + for (i = 0; i < 4; i++) { + c->border[i] = wlr_scene_rect_create( + c->scene, 0, 0, c->isurgent ? urgentcolor : bordercolor); + c->border[i]->node.data = c; + } + + /* Initialize client geometry with room for border */ + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + WLR_EDGE_RIGHT); + c->geom.width += 2 * c->bw; + c->geom.height += 2 * c->bw; + + /* Insert this client into client lists. */ + wl_list_insert(&clients, &c->link); + wl_list_insert(&fstack, &c->flink); + + /* Set initial monitor, tags, floating status, and focus: + * we always consider floating, clients that have parent and thus + * we set the same tags and monitor than its parent, if not + * try to apply rules for them */ + if ((p = client_get_parent(c))) { + c->isfloating = 1; + setmon(c, p->mon, p->tags); + } else { + applyrules(c); + } + printstatus(); + +unset_fullscreen: + m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); + wl_list_for_each(w, &clients, link) { + if (w != c && w != p && w->isfullscreen && m == w->mon && + (w->tags & c->tags)) + setfullscreen(w, 0); + } +} + +void maximizenotify(struct wl_listener *listener, void *data) { + /* This event is raised when a client would like to maximize itself, + * typically because the user clicked on the maximize button on + * client-side decorations. dwl doesn't support maximization, but + * to conform to xdg-shell protocol we still must send a configure. + * Since xdg-shell protocol v5 we should ignore request of unsupported + * capabilities, just schedule a empty configure when the client uses <5 + * protocol version + * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ + Client *c = wl_container_of(listener, c, maximize); + if (c->surface.xdg->initialized && + wl_resource_get_version(c->surface.xdg->toplevel->resource) < + XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) + wlr_xdg_surface_schedule_configure(c->surface.xdg); +} + +void monocle(Monitor *m) { + Client *c; + int n = 0; + + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; + resize(c, m->w, 0); + n++; + } + if (n) + snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n); + if ((c = focustop(m))) + wlr_scene_node_raise_to_top(&c->scene->node); +} + +void motionabsolute(struct wl_listener *listener, void *data) { + /* This event is forwarded by the cursor when a pointer emits an _absolute_ + * motion event, from 0..1 on each axis. This happens, for example, when + * wlroots is running under a Wayland window rather than KMS+DRM, and you + * move the mouse over the window. You could enter the window from any edge, + * so we have to warp the mouse there. There is also some hardware which + * emits these events. */ + struct wlr_pointer_motion_absolute_event *event = data; + double lx, ly, dx, dy; + + if (!event->time_msec) /* this is 0 with virtual pointers */ + wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); + + wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, + event->y, &lx, &ly); + dx = lx - cursor->x; + dy = ly - cursor->y; + motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); +} + +void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, + double dy, double dx_unaccel, double dy_unaccel) { + double sx = 0, sy = 0, sx_confined, sy_confined; + Client *c = NULL, *w = NULL; + LayerSurface *l = NULL; + struct wlr_surface *surface = NULL; + struct wlr_pointer_constraint_v1 *constraint; + + /* Find the client under the pointer and send the event along. */ + xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + + if (cursor_mode == CurPressed && !seat->drag && + surface != seat->pointer_state.focused_surface && + toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= + 0) { + c = w; + surface = seat->pointer_state.focused_surface; + sx = cursor->x - (l ? l->geom.x : w->geom.x); + sy = cursor->y - (l ? l->geom.y : w->geom.y); + } + + /* time is 0 in internal calls meant to restore pointer focus. */ + if (time) { + wlr_relative_pointer_manager_v1_send_relative_motion( + relative_pointer_mgr, seat, (uint64_t)time * 1000, dx, dy, dx_unaccel, + dy_unaccel); + + wl_list_for_each(constraint, &pointer_constraints->constraints, link) + cursorconstrain(constraint); + + if (active_constraint && cursor_mode != CurResize && + cursor_mode != CurMove) { + toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); + if (c && + active_constraint->surface == seat->pointer_state.focused_surface) { + sx = cursor->x - c->geom.x - c->bw; + sy = cursor->y - c->geom.y - c->bw; + if (wlr_region_confine(&active_constraint->region, sx, sy, sx + dx, + sy + dy, &sx_confined, &sy_confined)) { + dx = sx_confined - sx; + dy = sy_confined - sy; + } + + if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) + return; + } + } + + wlr_cursor_move(cursor, device, dx, dy); + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + handlecursoractivity(); + + /* Update selmon (even while dragging a window) */ + if (sloppyfocus) + selmon = xytomon(cursor->x, cursor->y); + } + + /* Update drag icon's position */ + wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), + (int)round(cursor->y)); + + /* If we are currently grabbing the mouse, handle and return */ + if (cursor_mode == CurMove) { + /* Move the grabbed client to the new position. */ + resize(grabc, + (struct wlr_box){.x = (int)round(cursor->x) - grabcx, + .y = (int)round(cursor->y) - grabcy, + .width = grabc->geom.width, + .height = grabc->geom.height}, + 1); + return; + } else if (cursor_mode == CurResize) { + resize(grabc, + (struct wlr_box){.x = grabc->geom.x, + .y = grabc->geom.y, + .width = (int)round(cursor->x) - grabc->geom.x, + .height = (int)round(cursor->y) - grabc->geom.y}, + 1); + return; + } + + /* If there's no client surface under the cursor, set the cursor image to a + * default. This is what makes the cursor image appear when you move it + * off of a client or over its border. */ + if (!surface && !seat->drag && !cursor_hidden) + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + + pointerfocus(c, surface, sx, sy, time); +} + +void motionrelative(struct wl_listener *listener, void *data) { + /* This event is forwarded by the cursor when a pointer emits a _relative_ + * pointer motion event (i.e. a delta) */ + struct wlr_pointer_motion_event *event = data; + /* The cursor doesn't move unless we tell it to. The cursor automatically + * handles constraining the motion to the output layout, as well as any + * special configuration applied for the specific input device which + * generated the event. You can pass NULL for the device if you want to move + * the cursor around without any input. */ + motionnotify(event->time_msec, &event->pointer->base, event->delta_x, + event->delta_y, event->unaccel_dx, event->unaccel_dy); +} + +void moveresize(const Arg *arg) { + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); + if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) + return; + + /* Float the window and tell motionnotify to grab it */ + setfloating(grabc, 1); + switch (cursor_mode = arg->ui) { + case CurMove: + grabcx = (int)round(cursor->x) - grabc->geom.x; + grabcy = (int)round(cursor->y) - grabc->geom.y; + wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); + break; + case CurResize: + /* Doesn't work for X11 output - the next absolute motion event + * returns the cursor to where it started */ + wlr_cursor_warp_closest(cursor, NULL, grabc->geom.x + grabc->geom.width, + grabc->geom.y + grabc->geom.height); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize"); + break; + } +} + +void outputmgrapply(struct wl_listener *listener, void *data) { + struct wlr_output_configuration_v1 *config = data; + outputmgrapplyortest(config, 0); +} + +void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, + int test) { + /* + * Called when a client such as wlr-randr requests a change in output + * configuration. This is only one way that the layout can be changed, + * so any Monitor information should be updated by updatemons() after an + * output_layout.change event, not here. + */ + struct wlr_output_configuration_head_v1 *config_head; + int ok = 1; + + wl_list_for_each(config_head, &config->heads, link) { + struct wlr_output *wlr_output = config_head->state.output; + Monitor *m = wlr_output->data; + struct wlr_output_state state; + + /* Ensure displays previously disabled by wlr-output-power-management-v1 + * are properly handled*/ + m->asleep = 0; + + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, config_head->state.enabled); + if (!config_head->state.enabled) + goto apply_or_test; + + if (config_head->state.mode) + wlr_output_state_set_mode(&state, config_head->state.mode); + else + wlr_output_state_set_custom_mode(&state, + config_head->state.custom_mode.width, + config_head->state.custom_mode.height, + config_head->state.custom_mode.refresh); + + wlr_output_state_set_transform(&state, config_head->state.transform); + wlr_output_state_set_scale(&state, config_head->state.scale); + wlr_output_state_set_adaptive_sync_enabled( + &state, config_head->state.adaptive_sync_enabled); + + apply_or_test: + ok &= test ? wlr_output_test_state(wlr_output, &state) + : wlr_output_commit_state(wlr_output, &state); + + /* Don't move monitors if position wouldn't change, this to avoid + * wlroots marking the output as manually configured. + * wlr_output_layout_add does not like disabled outputs */ + if (!test && wlr_output->enabled && + (m->m.x != config_head->state.x || m->m.y != config_head->state.y)) + wlr_output_layout_add(output_layout, wlr_output, config_head->state.x, + config_head->state.y); + + wlr_output_state_finish(&state); + } + + if (ok) + wlr_output_configuration_v1_send_succeeded(config); + else + wlr_output_configuration_v1_send_failed(config); + wlr_output_configuration_v1_destroy(config); + + /* https://codeberg.org/dwl/dwl/issues/577 */ + updatemons(NULL, NULL); +} + +void outputmgrtest(struct wl_listener *listener, void *data) { + struct wlr_output_configuration_v1 *config = data; + outputmgrapplyortest(config, 1); +} + +pid_t parentpid(pid_t pid) { + unsigned int v = 0; + FILE *f; + char buf[256]; + snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)pid); + if (!(f = fopen(buf, "r"))) + return 0; + fscanf(f, "%*u %*s %*c %u", &v); + fclose(f); + return (pid_t)v; +} + +void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, + uint32_t time) { + struct timespec now; + + if (surface != seat->pointer_state.focused_surface && sloppyfocus && time && + c && !client_is_unmanaged(c)) + focusclient(c, 0); + + /* If surface is NULL, clear pointer focus */ + if (!surface) { + wlr_seat_pointer_notify_clear_focus(seat); + return; + } + + if (!time) { + clock_gettime(CLOCK_MONOTONIC, &now); + time = now.tv_sec * 1000 + now.tv_nsec / 1000000; + } + + /* Let the client know that the mouse cursor has entered one + * of its surfaces, and make keyboard focus follow if desired. + * wlroots makes this a no-op if surface is already focused */ + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(seat, time, sx, sy); +} + +void printstatus(void) { + Monitor *m = NULL; + Client *c; + uint32_t occ, urg, sel; + const char *appid, *title; + + wl_list_for_each(m, &mons, link) { + occ = urg = 0; + wl_list_for_each(c, &clients, link) { + if (c->mon != m) + continue; + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + if ((c = focustop(m))) { + title = client_get_title(c); + appid = client_get_appid(c); + printf("%s title %s\n", m->wlr_output->name, title ? title : broken); + printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken); + printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen); + printf("%s floating %d\n", m->wlr_output->name, c->isfloating); + sel = c->tags; + } else { + printf("%s title \n", m->wlr_output->name); + printf("%s appid \n", m->wlr_output->name); + printf("%s fullscreen \n", m->wlr_output->name); + printf("%s floating \n", m->wlr_output->name); + sel = 0; + } + + printf("%s selmon %u\n", m->wlr_output->name, m == selmon); + printf("%s tags %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 "\n", + m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); + printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); + } + fflush(stdout); +} + +void powermgrsetmode(struct wl_listener *listener, void *data) { + struct wlr_output_power_v1_set_mode_event *event = data; + struct wlr_output_state state = {0}; + Monitor *m = event->output->data; + + if (!m) + return; + + m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */ + wlr_output_state_set_enabled(&state, event->mode); + wlr_output_commit_state(m->wlr_output, &state); + + m->asleep = !event->mode; +} + +void quit(const Arg *arg) { wl_display_terminate(dpy); } + +void rendermon(struct wl_listener *listener, void *data) { + /* This function is called every time an output is ready to display a frame, + * generally at the output's refresh rate (e.g. 60Hz). */ + Monitor *m = wl_container_of(listener, m, frame); + Client *c; + struct wlr_output_state pending = {0}; + struct wlr_gamma_control_v1 *gamma_control; + struct timespec now; + + /* Render if no XDG clients have an outstanding resize and are visible on + * this monitor. */ + wl_list_for_each(c, &clients, link) { + if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && + !client_is_stopped(c)) + goto skip; + } + + /* + * HACK: The "correct" way to set the gamma is to commit it together with + * the rest of the state in one go, but to do that we would need to rewrite + * wlr_scene_output_commit() in order to add the gamma to the pending + * state before committing, instead try to commit the gamma in one frame, + * and commit the rest of the state in the next one (or in the same frame if + * the gamma can not be committed). + */ + if (m->gamma_lut_changed) { + gamma_control = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, + m->wlr_output); + m->gamma_lut_changed = 0; + + if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) + goto commit; + + if (!wlr_output_test_state(m->wlr_output, &pending)) { + wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); + goto commit; + } + wlr_output_commit_state(m->wlr_output, &pending); + wlr_output_schedule_frame(m->wlr_output); + } else { + commit: + wlr_scene_output_commit(m->scene_output, NULL); + } + +skip: + /* Let clients know a frame has been rendered */ + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_scene_output_send_frame_done(m->scene_output, &now); + wlr_output_state_finish(&pending); +} + +void requestdecorationmode(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, set_decoration_mode); + if (c->surface.xdg->initialized) + wlr_xdg_toplevel_decoration_v1_set_mode( + c->decoration, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +} + +void requeststartdrag(struct wl_listener *listener, void *data) { + struct wlr_seat_request_start_drag_event *event = data; + + if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, event->serial)) + wlr_seat_start_pointer_drag(seat, event->drag, event->serial); + else + wlr_data_source_destroy(event->drag->source); +} + +void requestmonstate(struct wl_listener *listener, void *data) { + struct wlr_output_event_request_state *event = data; + wlr_output_commit_state(event->output, event->state); + updatemons(NULL, NULL); +} + +void resize(Client *c, struct wlr_box geo, int interact) { + struct wlr_box *bbox; + struct wlr_box clip; + + if (!c->mon || !client_surface(c)->mapped) + return; + + bbox = interact ? &sgeom : &c->mon->w; + + client_set_bounds(c, geo.width, geo.height); + c->geom = geo; + applybounds(c, bbox); + + /* Update scene-graph, including borders */ + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); + wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); + wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); + wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); + wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); + wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, + c->bw); + + /* this is a no-op if size hasn't changed */ + c->resize = + client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); + client_get_clip(c, &clip); + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); +} + +void run(char *startup_cmd) { + /* Add a Unix socket to the Wayland display. */ + const char *socket = wl_display_add_socket_auto(dpy); + if (!socket) + die("startup: display_add_socket_auto"); + setenv("WAYLAND_DISPLAY", socket, 1); + + /* Start the backend. This will enumerate outputs and inputs, become the DRM + * master, etc */ + if (!wlr_backend_start(backend)) + die("startup: backend_start"); + + /* Now that the socket exists and the backend is started, run the startup + * command */ + autostartexec(); + if (startup_cmd) { + int piperw[2]; + if (pipe(piperw) < 0) + die("startup: pipe:"); + if ((child_pid = fork()) < 0) + die("startup: fork:"); + if (child_pid == 0) { + setsid(); + dup2(piperw[0], STDIN_FILENO); + close(piperw[0]); + close(piperw[1]); + execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); + die("startup: execl:"); + } + dup2(piperw[1], STDOUT_FILENO); + close(piperw[1]); + close(piperw[0]); + } + + /* Mark stdout as non-blocking to avoid people who does not close stdin + * nor consumes it in their startup script getting dwl frozen */ + if (fd_set_nonblock(STDOUT_FILENO) < 0) + close(STDOUT_FILENO); + + printstatus(); + + /* At this point the outputs are initialized, choose initial selmon based on + * cursor position, and set default cursor image */ + selmon = xytomon(cursor->x, cursor->y); + + /* TODO hack to get cursor to display in its initial location (100, 100) + * instead of (0, 0) and then jumping. still may not be fully + * initialized, as the image/coordinates are not transformed for the + * monitor when displayed here */ + wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + + /* Run the Wayland event loop. This does not return until you exit the + * compositor. Starting the backend rigged up all of the necessary event + * loop configuration to listen to libinput events, DRM events, generate + * frame events at the refresh rate, and so on. */ + wl_display_run(dpy); +} + +void unlastcursor(struct wl_listener *listener, void *data) { + /* When the surface is destroyed, clear our reference to it */ + last_cursor.surface = NULL; + wl_list_remove(&last_cursor.destroy.link); + wl_list_init(&last_cursor.destroy.link); +} + +void setcursor(struct wl_listener *listener, void *data) { + /* This event is raised by the seat when a client provides a cursor image */ + struct wlr_seat_pointer_request_set_cursor_event *event = data; + /* If we're "grabbing" the cursor, don't use the client's image, we will + * restore it after "grabbing" sending a leave event, followed by a enter + * event, which will result in the client requesting set the cursor surface */ + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + /* This can be sent by any client, so we check to make sure this one is + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided surface as the cursor image. It will set the + * hardware cursor on the output that it's currently on and continue to + * do so as the cursor moves between outputs. */ + if (event->seat_client == seat->pointer_state.focused_client) { + last_cursor.shape = 0; + last_cursor.surface = event->surface; + last_cursor.hotspot_x = event->hotspot_x; + last_cursor.hotspot_y = event->hotspot_y; + + wl_list_remove(&last_cursor.destroy.link); + wl_list_init(&last_cursor.destroy.link); + if (event->surface) { + last_cursor.destroy.notify = unlastcursor; + wl_signal_add(&event->surface->events.destroy, &last_cursor.destroy); + } + + if (!cursor_hidden) + wlr_cursor_set_surface(cursor, event->surface, event->hotspot_x, + event->hotspot_y); + } +} + +void setcursorshape(struct wl_listener *listener, void *data) { + struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + /* This can be sent by any client, so we check to make sure this one is + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided cursor shape. */ + if (event->seat_client == seat->pointer_state.focused_client) { + last_cursor.shape = event->shape; + last_cursor.surface = NULL; + + if (!cursor_hidden) + wlr_cursor_set_xcursor(cursor, cursor_mgr, + wlr_cursor_shape_v1_name(event->shape)); + } +} + +void setfloating(Client *c, int floating) { + Client *p = client_get_parent(c); + c->isfloating = floating; + /* If in floating layout do not change the client's layer */ + if (!c->mon || !client_surface(c)->mapped || + !c->mon->lt[c->mon->sellt]->arrange) + return; + wlr_scene_node_reparent( + &c->scene->node, layers[c->isfullscreen || (p && p->isfullscreen) ? LyrFS + : c->isfloating ? LyrFloat + : LyrTile]); + arrange(c->mon); + printstatus(); +} + +void setfullscreen(Client *c, int fullscreen) { + c->isfullscreen = fullscreen; + if (!c->mon || !client_surface(c)->mapped) + return; + c->bw = fullscreen ? 0 : BORDERPX(c); + client_set_fullscreen(c, fullscreen); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ? LyrFS + : c->isfloating ? LyrFloat + : LyrTile]); + + if (fullscreen) { + c->prev = c->geom; + resize(c, c->mon->m, 0); + } else { + /* restore previous size instead of arrange for floating windows since + * client positions are set by the user and cannot be recalculated */ + resize(c, c->prev, 0); + } + arrange(c->mon); + printstatus(); +} + +void setgamma(struct wl_listener *listener, void *data) { + struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; + Monitor *m = event->output->data; + if (!m) + return; + m->gamma_lut_changed = 1; + wlr_output_schedule_frame(m->wlr_output); +} + +void setlayout(const Arg *arg) { + if (!selmon) + return; + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, + LENGTH(selmon->ltsymbol)); + arrange(selmon); + printstatus(); +} + +/* arg > 1.0 will set mfact absolutely */ +void setmfact(const Arg *arg) { + float f; + + if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f; + if (f < 0.1 || f > 0.9) + return; + selmon->mfact = f; + arrange(selmon); +} + +void setmon(Client *c, Monitor *m, uint32_t newtags) { + Monitor *oldmon = c->mon; + + if (oldmon == m) + return; + c->mon = m; + c->prev = c->geom; + + /* Scene graph sends surface leave/enter events on move and resize */ + if (oldmon) + arrange(oldmon); + if (m) { + /* Make sure window actually overlaps with the monitor */ + resize(c, c->geom, 0); + c->tags = newtags + ? newtags + : m->tagset[m->seltags]; /* assign tags of target monitor */ + c->prev.x = (m->w.width - c->prev.width) / 2 + m->m.x; + c->prev.y = (m->w.height - c->prev.height) / 2 + m->m.y; + setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ + setfloating(c, c->isfloating); + } + focusclient(focustop(selmon), 1); + + if (c->swallowing) + setmon(c->swallowing, m, newtags); +} + +void setpsel(struct wl_listener *listener, void *data) { + /* This event is raised by the seat when a client wants to set the selection, + * usually when the user copies something. wlroots allows compositors to + * ignore such requests if they so choose, but in dwl we always honor + */ + struct wlr_seat_request_set_primary_selection_event *event = data; + wlr_seat_set_primary_selection(seat, event->source, event->serial); +} + +void setsel(struct wl_listener *listener, void *data) { + /* This event is raised by the seat when a client wants to set the selection, + * usually when the user copies something. wlroots allows compositors to + * ignore such requests if they so choose, but in dwl we always honor + */ + struct wlr_seat_request_set_selection_event *event = data; + wlr_seat_set_selection(seat, event->source, event->serial); +} + +void setup(void) { + int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; + sigemptyset(&sa.sa_mask); + + for (i = 0; i < (int)LENGTH(sig); i++) + sigaction(sig[i], &sa, NULL); + + wlr_log_init(log_level, NULL); + + /* The Wayland display is managed by libwayland. It handles accepting + * clients from the Unix socket, manging Wayland globals, and so on. */ + dpy = wl_display_create(); + event_loop = wl_display_get_event_loop(dpy); + + /* The backend is a wlroots feature which abstracts the underlying input and + * output hardware. The autocreate option will choose the most suitable + * backend based on the current environment, such as opening an X11 window + * if an X11 server is running. */ + if (!(backend = wlr_backend_autocreate(event_loop, &session))) + die("couldn't create backend"); + + /* Initialize the scene graph used to lay out windows */ + scene = wlr_scene_create(); + root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor); + for (i = 0; i < NUM_LAYERS; i++) + layers[i] = wlr_scene_tree_create(&scene->tree); + drag_icon = wlr_scene_tree_create(&scene->tree); + wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node); + + /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user + * can also specify a renderer using the WLR_RENDERER env var. + * The renderer is responsible for defining the various pixel formats it + * supports for shared memory, this configures that for clients. */ + if (!(drw = wlr_renderer_autocreate(backend))) + die("couldn't create renderer"); + LISTEN_STATIC(&drw->events.lost, gpureset); + + /* Create shm, drm and linux_dmabuf interfaces by ourselves. + * The simplest way is call: + * wlr_renderer_init_wl_display(drw); + * but we need to create manually the linux_dmabuf interface to integrate it + * with wlr_scene. */ + wlr_renderer_init_wl_shm(drw, dpy); + + if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { + wlr_drm_create(dpy, drw); + wlr_scene_set_linux_dmabuf_v1( + scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); + } + + /* Autocreates an allocator for us. + * The allocator is the bridge between the renderer and the backend. It + * handles the buffer creation, allowing wlroots to render onto the + * screen */ + if (!(alloc = wlr_allocator_autocreate(backend, drw))) + die("couldn't create allocator"); + + /* This creates some hands-off wlroots interfaces. The compositor is + * necessary for clients to allocate surfaces and the data device manager + * handles the clipboard. Each of these wlroots interfaces has room for you + * to dig your fingers in and play with their behavior if you want. Note that + * the clients cannot set the selection directly without compositor approval, + * see the setsel() function. */ + compositor = wlr_compositor_create(dpy, 6, drw); + wlr_subcompositor_create(dpy); + wlr_data_device_manager_create(dpy); + wlr_export_dmabuf_manager_v1_create(dpy); + wlr_screencopy_manager_v1_create(dpy); + wlr_data_control_manager_v1_create(dpy); + wlr_primary_selection_v1_device_manager_create(dpy); + wlr_viewporter_create(dpy); + wlr_single_pixel_buffer_manager_v1_create(dpy); + wlr_fractional_scale_manager_v1_create(dpy, 1); + wlr_presentation_create(dpy, backend); + wlr_alpha_modifier_v1_create(dpy); + + /* Initializes the interface used to implement urgency hints */ + activation = wlr_xdg_activation_v1_create(dpy); + LISTEN_STATIC(&activation->events.request_activate, urgent); + + gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy); + LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma); + + power_mgr = wlr_output_power_manager_v1_create(dpy); + LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode); + + /* Creates an output layout, which a wlroots utility for working with an + * arrangement of screens in a physical layout. */ + output_layout = wlr_output_layout_create(dpy); + LISTEN_STATIC(&output_layout->events.change, updatemons); + wlr_xdg_output_manager_v1_create(dpy, output_layout); + + /* Configure a listener to be notified when new outputs are available on the + * backend. */ + wl_list_init(&mons); + LISTEN_STATIC(&backend->events.new_output, createmon); + + /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell + * is a Wayland protocol which is used for application windows. For more + * detail on shells, refer to the article: + * + * https://drewdevault.com/2018/07/29/Wayland-shells.html + */ + wl_list_init(&clients); + wl_list_init(&fstack); + + xdg_shell = wlr_xdg_shell_create(dpy, 6); + LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); + LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup); + + layer_shell = wlr_layer_shell_v1_create(dpy, 3); + LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); + + idle_notifier = wlr_idle_notifier_v1_create(dpy); + + idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); + LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); + + session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); + wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); + LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr); + locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, + (float[4]){0.1f, 0.1f, 0.1f, 1.0f}); + wlr_scene_node_set_enabled(&locked_bg->node, 0); + + /* Use decoration protocols to negotiate server-side decorations */ + wlr_server_decoration_manager_set_default_mode( + wlr_server_decoration_manager_create(dpy), + WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); + LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, + createdecoration); + + pointer_constraints = wlr_pointer_constraints_v1_create(dpy); + LISTEN_STATIC(&pointer_constraints->events.new_constraint, + createpointerconstraint); + + relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); + + /* + * Creates a cursor, which is a wlroots utility for tracking the cursor + * image shown on screen. + */ + cursor = wlr_cursor_create(); + wlr_cursor_attach_output_layout(cursor, output_layout); + + /* Initialize the last_cursor destroy listener link so it's safe to remove + * later */ + wl_list_init(&last_cursor.destroy.link); + + /* Creates an xcursor manager, another wlroots utility which loads up + * Xcursor themes to source cursor images from and makes sure that cursor + * images are available at all scale factors on the screen (necessary for + * HiDPI support). Scaled cursors will be loaded with each output. */ + cursor_mgr = wlr_xcursor_manager_create(NULL, 24); + setenv("XCURSOR_SIZE", "24", 1); + + /* + * wlr_cursor *only* displays an image on screen. It does not move around + * when the pointer moves. However, we can attach input devices to it, and + * it will generate aggregate events for all of them. In these events, we + * can choose how we want to process them, forwarding them to clients and + * moving the cursor around. More detail on this process is described in + * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html + * + * And more comments are sprinkled throughout the notify functions above. + */ + LISTEN_STATIC(&cursor->events.motion, motionrelative); + LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute); + LISTEN_STATIC(&cursor->events.button, buttonpress); + LISTEN_STATIC(&cursor->events.axis, axisnotify); + LISTEN_STATIC(&cursor->events.frame, cursorframe); + + cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); + LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape); + + /* + * Configures a seat, which is a single "seat" at which a user sits and + * operates the computer. This conceptually includes up to one keyboard, + * pointer, touch, and drawing tablet device. We also rig up a listener to + * let us know when new input devices are available on the backend. + */ + LISTEN_STATIC(&backend->events.new_input, inputdevice); + virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); + LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, + virtualkeyboard); + virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy); + LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, + virtualpointer); + + seat = wlr_seat_create(dpy, "seat0"); + LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); + LISTEN_STATIC(&seat->events.request_set_selection, setsel); + LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); + LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); + LISTEN_STATIC(&seat->events.start_drag, startdrag); + + kb_group = createkeyboardgroup(); + wl_list_init(&kb_group->destroy.link); + + output_mgr = wlr_output_manager_v1_create(dpy); + LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); + LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); + + /* Make sure XWayland clients don't connect to the parent X server, + * e.g when running in the x11 backend or the wayland backend and the + * compositor has Xwayland support */ + unsetenv("DISPLAY"); +#ifdef XWAYLAND + /* + * Initialise the XWayland X server. + * It will be started when the first X client is started. + */ + if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) { + LISTEN_STATIC(&xwayland->events.ready, xwaylandready); + LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); + + setenv("DISPLAY", xwayland->display_name, 1); + } else { + fprintf(stderr, + "failed to setup XWayland X server, continuing without it\n"); + } +#endif +} + +void spawn(const Arg *arg) { + if (fork() == 0) { + dup2(STDERR_FILENO, STDOUT_FILENO); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + die("dwl: execvp %s failed:", ((char **)arg->v)[0]); + } +} + +void startdrag(struct wl_listener *listener, void *data) { + struct wlr_drag *drag = data; + if (!drag->icon) + return; + + drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node; + LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); +} + +void swallow(Client *c, Client *toswallow) { + /* Do not allow a client to swallow itself */ + if (c == toswallow) + return; + + /* Swallow */ + if (toswallow && !c->swallowing) { + c->swallowing = toswallow; + toswallow->swallowedby = c; + toswallow->mon = c->mon; + toswallow->mon = c->mon; + wl_list_remove(&c->link); + wl_list_insert(&c->swallowing->link, &c->link); + wl_list_remove(&c->flink); + wl_list_insert(&c->swallowing->flink, &c->flink); + c->bw = BORDERPX(c); + c->tags = toswallow->tags; + c->isfloating = toswallow->isfloating; + c->geom = toswallow->geom; + setfullscreen(toswallow, 0); + } + + /* Unswallow */ + else if (c->swallowing) { + wl_list_remove(&c->swallowing->link); + wl_list_insert(&c->link, &c->swallowing->link); + wl_list_remove(&c->swallowing->flink); + wl_list_insert(&c->flink, &c->swallowing->flink); + c->swallowing->tags = c->tags; + c->swallowing->swallowedby = NULL; + c->swallowing = NULL; + c->bw = BORDERPX(c); + setfullscreen(c, 0); + } +} + +void tag(const Arg *arg) { + Client *sel = focustop(selmon); + if (!sel || (arg->ui & TAGMASK) == 0) + return; + + sel->tags = arg->ui & TAGMASK; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); +} + +void tagmon(const Arg *arg) { + Client *sel = focustop(selmon); + if (sel) + setmon(sel, dirtomon(arg->i), 0); +} + +Client *termforwin(Client *c) { + Client *p; + pid_t pid; + pid_t pids[32]; + size_t i, pids_len; + + if (!c->pid || c->isterm) + return NULL; + + /* Get all parent pids */ + pids_len = 0; + pid = c->pid; + while (pids_len < LENGTH(pids)) { + pid = parentpid(pid); + if (!pid) + break; + pids[pids_len++] = pid; + } + + /* Find closest parent */ + for (i = 0; i < pids_len; i++) { + wl_list_for_each(p, &clients, link) { + if (!p->pid || !p->isterm || p->swallowedby) + continue; + if (pids[i] == p->pid) + return p; + } + } + + return NULL; +} + +void tile(Monitor *m) { + unsigned int mw, my, ty; + int i, n = 0; + Client *c; + + wl_list_for_each(c, &clients, link) if (VISIBLEON(c, m) && !c->isfloating && + !c->isfullscreen) n++; + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0; + else + mw = m->w.width; + i = my = ty = 0; + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; + if (i < m->nmaster) { + resize(c, + (struct wlr_box){.x = m->w.x, + .y = m->w.y + my, + .width = mw, + .height = (m->w.height - my) / + (MIN(n, m->nmaster) - i)}, + 0); + my += c->geom.height; + } else { + resize(c, + (struct wlr_box){.x = m->w.x + mw, + .y = m->w.y + ty, + .width = m->w.width - mw, + .height = (m->w.height - ty) / (n - i)}, + 0); + ty += c->geom.height; + } + i++; + } +} + +void togglefloating(const Arg *arg) { + Client *sel = focustop(selmon); + /* return if fullscreen */ + if (sel && !sel->isfullscreen) + setfloating(sel, !sel->isfloating); +} + +void togglefullscreen(const Arg *arg) { + Client *sel = focustop(selmon); + if (sel) + setfullscreen(sel, !sel->isfullscreen); +} + +void toggleswallow(const Arg *arg) { + Client *c, *sel = focustop(selmon); + if (!sel) + return; + + if (sel->swallowing) { + swallow(sel, NULL); + } else { + wl_list_for_each(c, &sel->flink, flink) { + if (&c->flink == &fstack) + continue; /* wrap past the sentinel node */ + if (VISIBLEON(c, selmon)) + break; /* found it */ + } + swallow(sel, c); + } +} + +void toggleautoswallow(const Arg *arg) { + enableautoswallow = !enableautoswallow; +} + +void toggletag(const Arg *arg) { + uint32_t newtags; + Client *sel = focustop(selmon); + if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK))) + return; + + sel->tags = newtags; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); +} + +void toggleview(const Arg *arg) { + uint32_t newtagset; + if (!(newtagset = + selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0)) + return; + + selmon->tagset[selmon->seltags] = newtagset; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); +} + +void unlocksession(struct wl_listener *listener, void *data) { + SessionLock *lock = wl_container_of(listener, lock, unlock); + destroylock(lock, 1); +} + +void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { + LayerSurface *l = wl_container_of(listener, l, unmap); + + l->mapped = 0; + wlr_scene_node_set_enabled(&l->scene->node, 0); + if (l == exclusive_focus) + exclusive_focus = NULL; + if (l->layer_surface->output && (l->mon = l->layer_surface->output->data)) + arrangelayers(l->mon); + if (l->layer_surface->surface == seat->keyboard_state.focused_surface) + focusclient(focustop(selmon), 1); + motionnotify(0, NULL, 0, 0, 0, 0); +} + +void unmapnotify(struct wl_listener *listener, void *data) { + /* Called when the surface is unmapped, and should no longer be shown. */ + Client *c = wl_container_of(listener, c, unmap); + if (c == grabc) { + cursor_mode = CurNormal; + grabc = NULL; + } + + if (c->swallowing) { + swallow(c, NULL); + } else if (c->swallowedby) { + swallow(c->swallowedby, NULL); + } + + if (client_is_unmanaged(c)) { + if (c == exclusive_focus) { + exclusive_focus = NULL; + focusclient(focustop(selmon), 1); + } + } else { + wl_list_remove(&c->link); + setmon(c, NULL, 0); + wl_list_remove(&c->flink); + } + + wlr_scene_node_destroy(&c->scene->node); + printstatus(); + motionnotify(0, NULL, 0, 0, 0, 0); +} + +void updatemons(struct wl_listener *listener, void *data) { + /* + * Called whenever the output layout changes: adding or removing a + * monitor, changing an output's mode or position, etc. This is where + * the change officially happens and we update geometry, window + * positions, focus, and the stored configuration in wlroots' + * output-manager implementation. + */ + struct wlr_output_configuration_v1 *config = + wlr_output_configuration_v1_create(); + Client *c; + struct wlr_output_configuration_head_v1 *config_head; + Monitor *m; + + /* First remove from the layout the disabled monitors */ + wl_list_for_each(m, &mons, link) { + if (m->wlr_output->enabled || m->asleep) + continue; + config_head = + wlr_output_configuration_head_v1_create(config, m->wlr_output); + config_head->state.enabled = 0; + /* Remove this output from the layout to avoid cursor enter inside it */ + wlr_output_layout_remove(output_layout, m->wlr_output); + closemon(m); + m->m = m->w = (struct wlr_box){0}; + } + /* Insert outputs that need to */ + wl_list_for_each(m, &mons, link) { + if (m->wlr_output->enabled && + !wlr_output_layout_get(output_layout, m->wlr_output)) + wlr_output_layout_add_auto(output_layout, m->wlr_output); + } + + /* Now that we update the output layout we can get its box */ + wlr_output_layout_get_box(output_layout, NULL, &sgeom); + + wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y); + wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height); + + /* Make sure the clients are hidden when dwl is locked */ + wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y); + wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); + + wl_list_for_each(m, &mons, link) { + if (!m->wlr_output->enabled) + continue; + config_head = + wlr_output_configuration_head_v1_create(config, m->wlr_output); + + /* Get the effective monitor geometry to use for surfaces */ + wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m); + m->w = m->m; + wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); + + wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); + wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); + + if (m->lock_surface) { + struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data; + wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); + wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, + m->m.height); + } + + /* Calculate the effective monitor geometry to use for clients */ + arrangelayers(m); + /* Don't move clients to the left output when plugging monitors */ + arrange(m); + /* make sure fullscreen clients have the right size */ + if ((c = focustop(m)) && c->isfullscreen) + resize(c, m->m, 0); + + /* Try to re-set the gamma LUT when updating monitors, + * it's only really needed when enabling a disabled output, but meh. */ + m->gamma_lut_changed = 1; + + config_head->state.x = m->m.x; + config_head->state.y = m->m.y; + + if (!selmon) { + selmon = m; + } + } + + if (selmon && selmon->wlr_output->enabled) { + wl_list_for_each(c, &clients, link) { + if (!c->mon && client_surface(c)->mapped) + setmon(c, selmon, c->tags); + } + focusclient(focustop(selmon), 1); + if (selmon->lock_surface) { + client_notify_enter(selmon->lock_surface->surface, + wlr_seat_get_keyboard(seat)); + client_activate_surface(selmon->lock_surface->surface, 1); + } + } + + /* FIXME: figure out why the cursor image is at 0,0 after turning all + * the monitors on. + * Move the cursor image where it used to be. It does not generate a + * wl_pointer.motion event for the clients, it's only the image what it's + * at the wrong position after all. */ + wlr_cursor_move(cursor, NULL, 0, 0); + + wlr_output_manager_v1_set_configuration(output_mgr, config); +} + +void updatetitle(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, set_title); + if (c == focustop(c->mon)) + printstatus(); +} + +void urgent(struct wl_listener *listener, void *data) { + struct wlr_xdg_activation_v1_request_activate_event *event = data; + Client *c = NULL; + toplevel_from_wlr_surface(event->surface, &c, NULL); + if (!c || c == focustop(selmon)) + return; + + c->isurgent = 1; + printstatus(); + + if (client_surface(c)->mapped) + client_set_border_color(c, urgentcolor); +} + +void view(const Arg *arg) { + if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); +} + +void virtualkeyboard(struct wl_listener *listener, void *data) { + struct wlr_virtual_keyboard_v1 *kb = data; + /* virtual keyboards shouldn't share keyboard group */ + KeyboardGroup *group = createkeyboardgroup(); + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); + LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, + destroykeyboardgroup); + + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); +} + +void virtualpointer(struct wl_listener *listener, void *data) { + struct wlr_virtual_pointer_v1_new_pointer_event *event = data; + struct wlr_input_device *device = &event->new_pointer->pointer.base; + + wlr_cursor_attach_input_device(cursor, device); + if (event->suggested_output) + wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); +} + +Monitor *xytomon(double x, double y) { + struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); + return o ? o->data : NULL; +} + +void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, + LayerSurface **pl, double *nx, double *ny) { + struct wlr_scene_node *node, *pnode; + struct wlr_surface *surface = NULL; + Client *c = NULL; + LayerSurface *l = NULL; + int layer; + + for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { + if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) + continue; + + if (node->type == WLR_SCENE_NODE_BUFFER) + surface = + wlr_scene_surface_try_from_buffer(wlr_scene_buffer_from_node(node)) + ->surface; + /* Walk the tree to find a node that knows the client */ + for (pnode = node; pnode && !c; pnode = &pnode->parent->node) + c = pnode->data; + if (c && c->type == LayerShell) { + c = NULL; + l = pnode->data; + } + } + + if (psurface) + *psurface = surface; + if (pc) + *pc = c; + if (pl) + *pl = l; +} + +void zoom(const Arg *arg) { + Client *c, *sel = focustop(selmon); + + if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) + return; + + /* Search for the first tiled window that is not sel, marking sel as + * NULL if we pass it along the way */ + wl_list_for_each(c, &clients, link) { + if (VISIBLEON(c, selmon) && !c->isfloating) { + if (c != sel) + break; + sel = NULL; + } + } + + /* Return if no other tiled window was found */ + if (&c->link == &clients) + return; + + /* If we passed sel, move c to the front; otherwise, move sel to the + * front */ + if (!sel) + sel = c; + wl_list_remove(&sel->link); + wl_list_insert(&clients, &sel->link); + + focusclient(sel, 1); + arrange(selmon); +} + +#ifdef XWAYLAND +void activatex11(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, activate); + + /* Only "managed" windows can be activated */ + if (!client_is_unmanaged(c)) + wlr_xwayland_surface_activate(c->surface.xwayland, 1); +} + +void associatex11(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, associate); + + LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); + LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); +} + +void configurex11(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, configure); + struct wlr_xwayland_surface_configure_event *event = data; + /* TODO: figure out if there is another way to do this */ + if (!c->mon) { + wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y, + event->width, event->height); + return; + } + if (c->isfloating || client_is_unmanaged(c)) + resize(c, + (struct wlr_box){.x = event->x, + .y = event->y, + .width = event->width + c->bw * 2, + .height = event->height + c->bw * 2}, + 0); + else + arrange(c->mon); +} + +void createnotifyx11(struct wl_listener *listener, void *data) { + struct wlr_xwayland_surface *xsurface = data; + Client *c; + + /* Allocate a Client for this surface */ + c = xsurface->data = ecalloc(1, sizeof(*c)); + c->surface.xwayland = xsurface; + c->type = X11; + c->bw = client_is_unmanaged(c) ? 0 : borderpx; + + /* Listen to the various events it can emit */ + LISTEN(&xsurface->events.associate, &c->associate, associatex11); + LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11); + LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); + LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); + LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, + fullscreennotify); + LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); + LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); +} + +void dissociatex11(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, dissociate); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); +} + +xcb_atom_t getatom(xcb_connection_t *xc, const char *name) { + xcb_atom_t atom = 0; + xcb_intern_atom_reply_t *reply; + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name); + if ((reply = xcb_intern_atom_reply(xc, cookie, NULL))) + atom = reply->atom; + free(reply); + + return atom; +} + +void sethints(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, set_hints); + struct wlr_surface *surface = client_surface(c); + if (c == focustop(selmon)) + return; + + c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); + printstatus(); + + if (c->isurgent && surface && surface->mapped) + client_set_border_color(c, urgentcolor); +} + +void xwaylandready(struct wl_listener *listener, void *data) { + struct wlr_xcursor *xcursor; + xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL); + int err = xcb_connection_has_error(xc); + if (err) { + fprintf(stderr, + "xcb_connect to X server failed with code %d\n. Continuing with " + "degraded functionality.\n", + err); + return; + } + + /* Collect atoms we are interested in. If getatom returns 0, we will + * not detect that window type. */ + netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG"); + netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH"); + netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR"); + netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY"); + + /* assign the one and only seat */ + wlr_xwayland_set_seat(xwayland, seat); + + /* Set the default XWayland cursor to match the rest of dwl. */ + if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) + wlr_xwayland_set_cursor( + xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4, + xcursor->images[0]->width, xcursor->images[0]->height, + xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); + + xcb_disconnect(xc); +} +#endif + +int main(int argc, char *argv[]) { + char *startup_cmd = NULL; + int c; + + while ((c = getopt(argc, argv, "s:hdv")) != -1) { + if (c == 's') + startup_cmd = optarg; + else if (c == 'd') + log_level = WLR_DEBUG; + else if (c == 'v') + die("dwl " VERSION); + else + goto usage; + } + if (optind < argc) + goto usage; + + /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ + if (!getenv("XDG_RUNTIME_DIR")) + die("XDG_RUNTIME_DIR must be set"); + setup(); + run(startup_cmd); + cleanup(); + return EXIT_SUCCESS; + +usage: + die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); +} diff --git a/dwl/dwl-v0.7_bak/dwl.c.orig b/dwl/dwl-v0.7_bak/dwl.c.orig new file mode 100644 index 00000000..a2711f67 --- /dev/null +++ b/dwl/dwl-v0.7_bak/dwl.c.orig @@ -0,0 +1,3215 @@ +/* + * See LICENSE file for copyright and license details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XWAYLAND +#include +#include +#include +#endif + +#include "util.h" + +/* macros */ +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) +#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define END(A) ((A) + LENGTH(A)) +#define TAGMASK ((1u << TAGCOUNT) - 1) +#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) +#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) + +/* enums */ +enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ +enum { XDGShell, LayerShell, X11 }; /* client types */ +enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ +#ifdef XWAYLAND +enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, + NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ +#endif + +typedef union { + int i; + uint32_t ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int mod; + unsigned int button; + void (*func)(const Arg *); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct { + /* Must keep these three elements in this order */ + unsigned int type; /* XDGShell or X11* */ + struct wlr_box geom; /* layout-relative, includes border */ + Monitor *mon; + struct wlr_scene_tree *scene; + struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ + struct wlr_scene_tree *scene_surface; + struct wl_list link; + struct wl_list flink; + union { + struct wlr_xdg_surface *xdg; + struct wlr_xwayland_surface *xwayland; + } surface; + struct wlr_xdg_toplevel_decoration_v1 *decoration; + struct wl_listener commit; + struct wl_listener map; + struct wl_listener maximize; + struct wl_listener unmap; + struct wl_listener destroy; + struct wl_listener set_title; + struct wl_listener fullscreen; + struct wl_listener set_decoration_mode; + struct wl_listener destroy_decoration; + struct wlr_box prev; /* layout-relative, includes border */ + struct wlr_box bounds; +#ifdef XWAYLAND + struct wl_listener activate; + struct wl_listener associate; + struct wl_listener dissociate; + struct wl_listener configure; + struct wl_listener set_hints; +#endif + unsigned int bw; + uint32_t tags; + int isfloating, isurgent, isfullscreen; + uint32_t resize; /* configure serial of a pending resize */ +} Client; + +typedef struct { + uint32_t mod; + xkb_keysym_t keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + struct wl_list link; + struct wlr_keyboard_group *wlr_group; + + int nsyms; + const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ + uint32_t mods; /* invalid if nsyms == 0 */ + struct wl_event_source *key_repeat_source; + + struct wl_listener modifiers; + struct wl_listener key; + struct wl_listener destroy; +} KeyboardGroup; + +typedef struct { + /* Must keep these three elements in this order */ + unsigned int type; /* LayerShell */ + struct wlr_box geom; + Monitor *mon; + struct wlr_scene_tree *scene; + struct wlr_scene_tree *popups; + struct wlr_scene_layer_surface_v1 *scene_layer; + struct wl_list link; + int mapped; + struct wlr_layer_surface_v1 *layer_surface; + + struct wl_listener destroy; + struct wl_listener unmap; + struct wl_listener surface_commit; +} LayerSurface; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +struct Monitor { + struct wl_list link; + struct wlr_output *wlr_output; + struct wlr_scene_output *scene_output; + struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ + struct wl_listener frame; + struct wl_listener destroy; + struct wl_listener request_state; + struct wl_listener destroy_lock_surface; + struct wlr_session_lock_surface_v1 *lock_surface; + struct wlr_box m; /* monitor area, layout-relative */ + struct wlr_box w; /* window area, layout-relative */ + struct wl_list layers[4]; /* LayerSurface.link */ + const Layout *lt[2]; + unsigned int seltags; + unsigned int sellt; + uint32_t tagset[2]; + float mfact; + int gamma_lut_changed; + int nmaster; + char ltsymbol[16]; + int asleep; +}; + +typedef struct { + const char *name; + float mfact; + int nmaster; + float scale; + const Layout *lt; + enum wl_output_transform rr; + int x, y; +} MonitorRule; + +typedef struct { + struct wlr_pointer_constraint_v1 *constraint; + struct wl_listener destroy; +} PointerConstraint; + +typedef struct { + const char *id; + const char *title; + uint32_t tags; + int isfloating; + int monitor; +} Rule; + +typedef struct { + struct wlr_scene_tree *scene; + + struct wlr_session_lock_v1 *lock; + struct wl_listener new_surface; + struct wl_listener unlock; + struct wl_listener destroy; +} SessionLock; + +/* function declarations */ +static void applybounds(Client *c, struct wlr_box *bbox); +static void applyrules(Client *c); +static void arrange(Monitor *m); +static void arrangelayer(Monitor *m, struct wl_list *list, + struct wlr_box *usable_area, int exclusive); +static void arrangelayers(Monitor *m); +static void axisnotify(struct wl_listener *listener, void *data); +static void buttonpress(struct wl_listener *listener, void *data); +static void chvt(const Arg *arg); +static void checkidleinhibitor(struct wlr_surface *exclude); +static void cleanup(void); +static void cleanupmon(struct wl_listener *listener, void *data); +static void closemon(Monitor *m); +static void commitlayersurfacenotify(struct wl_listener *listener, void *data); +static void commitnotify(struct wl_listener *listener, void *data); +static void commitpopup(struct wl_listener *listener, void *data); +static void createdecoration(struct wl_listener *listener, void *data); +static void createidleinhibitor(struct wl_listener *listener, void *data); +static void createkeyboard(struct wlr_keyboard *keyboard); +static KeyboardGroup *createkeyboardgroup(void); +static void createlayersurface(struct wl_listener *listener, void *data); +static void createlocksurface(struct wl_listener *listener, void *data); +static void createmon(struct wl_listener *listener, void *data); +static void createnotify(struct wl_listener *listener, void *data); +static void createpointer(struct wlr_pointer *pointer); +static void createpointerconstraint(struct wl_listener *listener, void *data); +static void createpopup(struct wl_listener *listener, void *data); +static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); +static void cursorframe(struct wl_listener *listener, void *data); +static void cursorwarptohint(void); +static void destroydecoration(struct wl_listener *listener, void *data); +static void destroydragicon(struct wl_listener *listener, void *data); +static void destroyidleinhibitor(struct wl_listener *listener, void *data); +static void destroylayersurfacenotify(struct wl_listener *listener, void *data); +static void destroylock(SessionLock *lock, int unlocked); +static void destroylocksurface(struct wl_listener *listener, void *data); +static void destroynotify(struct wl_listener *listener, void *data); +static void destroypointerconstraint(struct wl_listener *listener, void *data); +static void destroysessionlock(struct wl_listener *listener, void *data); +static void destroysessionmgr(struct wl_listener *listener, void *data); +static void destroykeyboardgroup(struct wl_listener *listener, void *data); +static Monitor *dirtomon(enum wlr_direction dir); +static void focusclient(Client *c, int lift); +static void focusmon(const Arg *arg); +static void focusstack(const Arg *arg); +static Client *focustop(Monitor *m); +static void fullscreennotify(struct wl_listener *listener, void *data); +static void gpureset(struct wl_listener *listener, void *data); +static void handlesig(int signo); +static void incnmaster(const Arg *arg); +static void inputdevice(struct wl_listener *listener, void *data); +static int keybinding(uint32_t mods, xkb_keysym_t sym); +static void keypress(struct wl_listener *listener, void *data); +static void keypressmod(struct wl_listener *listener, void *data); +static int keyrepeat(void *data); +static void killclient(const Arg *arg); +static void locksession(struct wl_listener *listener, void *data); +static void mapnotify(struct wl_listener *listener, void *data); +static void maximizenotify(struct wl_listener *listener, void *data); +static void monocle(Monitor *m); +static void motionabsolute(struct wl_listener *listener, void *data); +static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx, + double sy, double sx_unaccel, double sy_unaccel); +static void motionrelative(struct wl_listener *listener, void *data); +static void moveresize(const Arg *arg); +static void outputmgrapply(struct wl_listener *listener, void *data); +static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); +static void outputmgrtest(struct wl_listener *listener, void *data); +static void pointerfocus(Client *c, struct wlr_surface *surface, + double sx, double sy, uint32_t time); +static void printstatus(void); +static void powermgrsetmode(struct wl_listener *listener, void *data); +static void quit(const Arg *arg); +static void rendermon(struct wl_listener *listener, void *data); +static void requestdecorationmode(struct wl_listener *listener, void *data); +static void requeststartdrag(struct wl_listener *listener, void *data); +static void requestmonstate(struct wl_listener *listener, void *data); +static void resize(Client *c, struct wlr_box geo, int interact); +static void run(char *startup_cmd); +static void setcursor(struct wl_listener *listener, void *data); +static void setcursorshape(struct wl_listener *listener, void *data); +static void setfloating(Client *c, int floating); +static void setfullscreen(Client *c, int fullscreen); +static void setgamma(struct wl_listener *listener, void *data); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setmon(Client *c, Monitor *m, uint32_t newtags); +static void setpsel(struct wl_listener *listener, void *data); +static void setsel(struct wl_listener *listener, void *data); +static void setup(void); +static void spawn(const Arg *arg); +static void startdrag(struct wl_listener *listener, void *data); +static void tag(const Arg *arg); +static void tagmon(const Arg *arg); +static void tile(Monitor *m); +static void togglefloating(const Arg *arg); +static void togglefullscreen(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unlocksession(struct wl_listener *listener, void *data); +static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); +static void unmapnotify(struct wl_listener *listener, void *data); +static void updatemons(struct wl_listener *listener, void *data); +static void updatetitle(struct wl_listener *listener, void *data); +static void urgent(struct wl_listener *listener, void *data); +static void view(const Arg *arg); +static void virtualkeyboard(struct wl_listener *listener, void *data); +static void virtualpointer(struct wl_listener *listener, void *data); +static Monitor *xytomon(double x, double y); +static void xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny); +static void zoom(const Arg *arg); + +/* variables */ +static const char broken[] = "broken"; +static pid_t child_pid = -1; +static int locked; +static void *exclusive_focus; +static struct wl_display *dpy; +static struct wl_event_loop *event_loop; +static struct wlr_backend *backend; +static struct wlr_scene *scene; +static struct wlr_scene_tree *layers[NUM_LAYERS]; +static struct wlr_scene_tree *drag_icon; +/* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */ +static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay }; +static struct wlr_renderer *drw; +static struct wlr_allocator *alloc; +static struct wlr_compositor *compositor; +static struct wlr_session *session; + +static struct wlr_xdg_shell *xdg_shell; +static struct wlr_xdg_activation_v1 *activation; +static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; +static struct wl_list clients; /* tiling order */ +static struct wl_list fstack; /* focus order */ +static struct wlr_idle_notifier_v1 *idle_notifier; +static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; +static struct wlr_layer_shell_v1 *layer_shell; +static struct wlr_output_manager_v1 *output_mgr; +static struct wlr_gamma_control_manager_v1 *gamma_control_mgr; +static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; +static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; +static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; +static struct wlr_output_power_manager_v1 *power_mgr; + +static struct wlr_pointer_constraints_v1 *pointer_constraints; +static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; +static struct wlr_pointer_constraint_v1 *active_constraint; + +static struct wlr_cursor *cursor; +static struct wlr_xcursor_manager *cursor_mgr; + +static struct wlr_scene_rect *root_bg; +static struct wlr_session_lock_manager_v1 *session_lock_mgr; +static struct wlr_scene_rect *locked_bg; +static struct wlr_session_lock_v1 *cur_lock; +static struct wl_listener lock_listener = {.notify = locksession}; + +static struct wlr_seat *seat; +static KeyboardGroup *kb_group; +static unsigned int cursor_mode; +static Client *grabc; +static int grabcx, grabcy; /* client-relative */ + +static struct wlr_output_layout *output_layout; +static struct wlr_box sgeom; +static struct wl_list mons; +static Monitor *selmon; + +#ifdef XWAYLAND +static void activatex11(struct wl_listener *listener, void *data); +static void associatex11(struct wl_listener *listener, void *data); +static void configurex11(struct wl_listener *listener, void *data); +static void createnotifyx11(struct wl_listener *listener, void *data); +static void dissociatex11(struct wl_listener *listener, void *data); +static xcb_atom_t getatom(xcb_connection_t *xc, const char *name); +static void sethints(struct wl_listener *listener, void *data); +static void xwaylandready(struct wl_listener *listener, void *data); +static struct wlr_xwayland *xwayland; +static xcb_atom_t netatom[NetLast]; +#endif + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* attempt to encapsulate suck into one file */ +#include "client.h" + +/* function implementations */ +void +applybounds(Client *c, struct wlr_box *bbox) +{ + /* set minimum possible */ + c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); + c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height); + + if (c->geom.x >= bbox->x + bbox->width) + c->geom.x = bbox->x + bbox->width - c->geom.width; + if (c->geom.y >= bbox->y + bbox->height) + c->geom.y = bbox->y + bbox->height - c->geom.height; + if (c->geom.x + c->geom.width <= bbox->x) + c->geom.x = bbox->x; + if (c->geom.y + c->geom.height <= bbox->y) + c->geom.y = bbox->y; +} + +void +applyrules(Client *c) +{ + /* rule matching */ + const char *appid, *title; + uint32_t newtags = 0; + int i; + const Rule *r; + Monitor *mon = selmon, *m; + + c->isfloating = client_is_float_type(c); + if (!(appid = client_get_appid(c))) + appid = broken; + if (!(title = client_get_title(c))) + title = broken; + + for (r = rules; r < END(rules); r++) { + if ((!r->title || strstr(title, r->title)) + && (!r->id || strstr(appid, r->id))) { + c->isfloating = r->isfloating; + newtags |= r->tags; + i = 0; + wl_list_for_each(m, &mons, link) { + if (r->monitor == i++) + mon = m; + } + } + } + setmon(c, mon, newtags); +} + +void +arrange(Monitor *m) +{ + Client *c; + + if (!m->wlr_output->enabled) + return; + + wl_list_for_each(c, &clients, link) { + if (c->mon == m) { + wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); + client_set_suspended(c, !VISIBLEON(c, m)); + } + } + + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, + (c = focustop(m)) && c->isfullscreen); + + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + + /* We move all clients (except fullscreen and unmanaged) to LyrTile while + * in floating layout to avoid "real" floating clients be always on top */ + wl_list_for_each(c, &clients, link) { + if (c->mon != m || c->scene->node.parent == layers[LyrFS]) + continue; + + wlr_scene_node_reparent(&c->scene->node, + (!m->lt[m->sellt]->arrange && c->isfloating) + ? layers[LyrTile] + : (m->lt[m->sellt]->arrange && c->isfloating) + ? layers[LyrFloat] + : c->scene->node.parent); + } + + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); + motionnotify(0, NULL, 0, 0, 0, 0); + checkidleinhibitor(NULL); +} + +void +arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) +{ + LayerSurface *l; + struct wlr_box full_area = m->m; + + wl_list_for_each(l, list, link) { + struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + + if (exclusive != (layer_surface->current.exclusive_zone > 0)) + continue; + + wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); + wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, l->scene->node.y); + l->geom.x = l->scene->node.x; + l->geom.y = l->scene->node.y; + } +} + +void +arrangelayers(Monitor *m) +{ + int i; + struct wlr_box usable_area = m->m; + LayerSurface *l; + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + if (!m->wlr_output->enabled) + return; + + /* Arrange exclusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer(m, &m->layers[i], &usable_area, 1); + + if (!wlr_box_equal(&usable_area, &m->w)) { + m->w = usable_area; + arrange(m); + } + + /* Arrange non-exlusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer(m, &m->layers[i], &usable_area, 0); + + /* Find topmost keyboard interactive layer, if such a layer exists */ + for (i = 0; i < (int)LENGTH(layers_above_shell); i++) { + wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { + if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped) + continue; + /* Deactivate the focused client. */ + focusclient(NULL, 0); + exclusive_focus = l; + client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); + return; + } + } +} + +void +axisnotify(struct wl_listener *listener, void *data) +{ + /* This event is forwarded by the cursor when a pointer emits an axis event, + * for example when you move the scroll wheel. */ + struct wlr_pointer_axis_event *event = data; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + /* TODO: allow usage of scroll whell for mousebindings, it can be implemented + * checking the event's orientation and the delta of the event */ + /* Notify the client with pointer focus of the axis event. */ + wlr_seat_pointer_notify_axis(seat, + event->time_msec, event->orientation, event->delta, + event->delta_discrete, event->source, event->relative_direction); +} + +void +buttonpress(struct wl_listener *listener, void *data) +{ + struct wlr_pointer_button_event *event = data; + struct wlr_keyboard *keyboard; + uint32_t mods; + Client *c; + const Button *b; + + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + + switch (event->state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + cursor_mode = CurPressed; + selmon = xytomon(cursor->x, cursor->y); + if (locked) + break; + + /* Change focus if the button was _pressed_ over a client */ + xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); + if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) + focusclient(c, 1); + + keyboard = wlr_seat_get_keyboard(seat); + mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; + for (b = buttons; b < END(buttons); b++) { + if (CLEANMASK(mods) == CLEANMASK(b->mod) && + event->button == b->button && b->func) { + b->func(&b->arg); + return; + } + } + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + /* If you released any buttons, we exit interactive move/resize mode. */ + /* TODO should reset to the pointer focus's current setcursor */ + if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + cursor_mode = CurNormal; + /* Drop the window off on its new monitor */ + selmon = xytomon(cursor->x, cursor->y); + setmon(grabc, selmon, 0); + return; + } else { + cursor_mode = CurNormal; + } + break; + } + /* If the event wasn't handled by the compositor, notify the client with + * pointer focus that a button press has occurred */ + wlr_seat_pointer_notify_button(seat, + event->time_msec, event->button, event->state); +} + +void +chvt(const Arg *arg) +{ + wlr_session_change_vt(session, arg->ui); +} + +void +checkidleinhibitor(struct wlr_surface *exclude) +{ + int inhibited = 0, unused_lx, unused_ly; + struct wlr_idle_inhibitor_v1 *inhibitor; + wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { + struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface); + struct wlr_scene_tree *tree = surface->data; + if (exclude != surface && (bypass_surface_visibility || (!tree + || wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) { + inhibited = 1; + break; + } + } + + wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); +} + +void +cleanup(void) +{ +#ifdef XWAYLAND + wlr_xwayland_destroy(xwayland); + xwayland = NULL; +#endif + wl_display_destroy_clients(dpy); + if (child_pid > 0) { + kill(-child_pid, SIGTERM); + waitpid(child_pid, NULL, 0); + } + wlr_xcursor_manager_destroy(cursor_mgr); + + destroykeyboardgroup(&kb_group->destroy, NULL); + + /* If it's not destroyed manually it will cause a use-after-free of wlr_seat. + * Destroy it until it's fixed in the wlroots side */ + wlr_backend_destroy(backend); + + wl_display_destroy(dpy); + /* Destroy after the wayland display (when the monitors are already destroyed) + to avoid destroying them with an invalid scene output. */ + wlr_scene_node_destroy(&scene->tree.node); +} + +void +cleanupmon(struct wl_listener *listener, void *data) +{ + Monitor *m = wl_container_of(listener, m, destroy); + LayerSurface *l, *tmp; + size_t i; + + /* m->layers[i] are intentionally not unlinked */ + for (i = 0; i < LENGTH(m->layers); i++) { + wl_list_for_each_safe(l, tmp, &m->layers[i], link) + wlr_layer_surface_v1_destroy(l->layer_surface); + } + + wl_list_remove(&m->destroy.link); + wl_list_remove(&m->frame.link); + wl_list_remove(&m->link); + wl_list_remove(&m->request_state.link); + m->wlr_output->data = NULL; + wlr_output_layout_remove(output_layout, m->wlr_output); + wlr_scene_output_destroy(m->scene_output); + + closemon(m); + wlr_scene_node_destroy(&m->fullscreen_bg->node); + free(m); +} + +void +closemon(Monitor *m) +{ + /* update selmon if needed and + * move closed monitor's clients to the focused one */ + Client *c; + int i = 0, nmons = wl_list_length(&mons); + if (!nmons) { + selmon = NULL; + } else if (m == selmon) { + do /* don't switch to disabled mons */ + selmon = wl_container_of(mons.next, selmon, link); + while (!selmon->wlr_output->enabled && i++ < nmons); + + if (!selmon->wlr_output->enabled) + selmon = NULL; + } + + wl_list_for_each(c, &clients, link) { + if (c->isfloating && c->geom.x > m->m.width) + resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y, + .width = c->geom.width, .height = c->geom.height}, 0); + if (c->mon == m) + setmon(c, selmon, c->tags); + } + focusclient(focustop(selmon), 1); + printstatus(); +} + +void +commitlayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *l = wl_container_of(listener, l, surface_commit); + struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]]; + struct wlr_layer_surface_v1_state old_state; + + if (l->layer_surface->initial_commit) { + wlr_fractional_scale_v1_notify_scale(layer_surface->surface, l->mon->wlr_output->scale); + wlr_surface_set_preferred_buffer_scale(layer_surface->surface, (int32_t)ceilf(l->mon->wlr_output->scale)); + + /* Temporarily set the layer's current state to pending + * so that we can easily arrange it */ + old_state = l->layer_surface->current; + l->layer_surface->current = l->layer_surface->pending; + arrangelayers(l->mon); + l->layer_surface->current = old_state; + return; + } + + if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) + return; + l->mapped = layer_surface->surface->mapped; + + if (scene_layer != l->scene->node.parent) { + wlr_scene_node_reparent(&l->scene->node, scene_layer); + wl_list_remove(&l->link); + wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link); + wlr_scene_node_reparent(&l->popups->node, (layer_surface->current.layer + < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer)); + } + + arrangelayers(l->mon); +} + +void +commitnotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, commit); + + if (c->surface.xdg->initial_commit) { + /* + * Get the monitor this client will be rendered on + * Note that if the user set a rule in which the client is placed on + * a different monitor based on its title this will likely select + * a wrong monitor. + */ + applyrules(c); + wlr_surface_set_preferred_buffer_scale(client_surface(c), (int)ceilf(c->mon->wlr_output->scale)); + wlr_fractional_scale_v1_notify_scale(client_surface(c), c->mon->wlr_output->scale); + setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ + + wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); + if (c->decoration) + requestdecorationmode(&c->set_decoration_mode, c->decoration); + return; + } + + if (client_surface(c)->mapped && c->mon) + resize(c, c->geom, (c->isfloating && !c->isfullscreen)); + + /* mark a pending resize as completed */ + if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) + c->resize = 0; +} + +void +commitpopup(struct wl_listener *listener, void *data) +{ + struct wlr_surface *surface = data; + struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); + LayerSurface *l = NULL; + Client *c = NULL; + struct wlr_box box; + int type = -1; + + if (!popup->base->initial_commit) + return; + + type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); + if (!popup->parent || type < 0) + return; + popup->base->surface->data = wlr_scene_xdg_surface_create( + popup->parent->data, popup->base); + if ((l && !l->mon) || (c && !c->mon)) + return; + box = type == LayerShell ? l->mon->m : c->mon->w; + box.x -= (type == LayerShell ? l->geom.x : c->geom.x); + box.y -= (type == LayerShell ? l->geom.y : c->geom.y); + wlr_xdg_popup_unconstrain_from_box(popup, &box); + wl_list_remove(&listener->link); +} + +void +createdecoration(struct wl_listener *listener, void *data) +{ + struct wlr_xdg_toplevel_decoration_v1 *deco = data; + Client *c = deco->toplevel->base->data; + c->decoration = deco; + + LISTEN(&deco->events.request_mode, &c->set_decoration_mode, requestdecorationmode); + LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration); + + requestdecorationmode(&c->set_decoration_mode, deco); +} + +void +createidleinhibitor(struct wl_listener *listener, void *data) +{ + struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; + LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor); + + checkidleinhibitor(NULL); +} + +void +createkeyboard(struct wlr_keyboard *keyboard) +{ + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); + + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); +} + +KeyboardGroup * +createkeyboardgroup(void) +{ + KeyboardGroup *group = ecalloc(1, sizeof(*group)); + struct xkb_context *context; + struct xkb_keymap *keymap; + + group->wlr_group = wlr_keyboard_group_create(); + group->wlr_group->data = group; + + /* Prepare an XKB keymap and assign it to the keyboard group. */ + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS))) + die("failed to compile keymap"); + + wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + + wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, repeat_delay); + + /* Set up listeners for keyboard events */ + LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); + LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod); + + group->key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, group); + + /* A seat can only have one keyboard, but this is a limitation of the + * Wayland protocol - not wlroots. We assign all connected keyboards to the + * same wlr_keyboard_group, which provides a single wlr_keyboard interface for + * all of them. Set this combined wlr_keyboard as the seat keyboard. + */ + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + return group; +} + +void +createlayersurface(struct wl_listener *listener, void *data) +{ + struct wlr_layer_surface_v1 *layer_surface = data; + LayerSurface *l; + struct wlr_surface *surface = layer_surface->surface; + struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]]; + + if (!layer_surface->output + && !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) { + wlr_layer_surface_v1_destroy(layer_surface); + return; + } + + l = layer_surface->data = ecalloc(1, sizeof(*l)); + l->type = LayerShell; + LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); + LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); + LISTEN(&layer_surface->events.destroy, &l->destroy, destroylayersurfacenotify); + + l->layer_surface = layer_surface; + l->mon = layer_surface->output->data; + l->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, layer_surface); + l->scene = l->scene_layer->tree; + l->popups = surface->data = wlr_scene_tree_create(layer_surface->current.layer + < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer); + l->scene->node.data = l->popups->node.data = l; + + wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); + wlr_surface_send_enter(surface, layer_surface->output); +} + +void +createlocksurface(struct wl_listener *listener, void *data) +{ + SessionLock *lock = wl_container_of(listener, lock, new_surface); + struct wlr_session_lock_surface_v1 *lock_surface = data; + Monitor *m = lock_surface->output->data; + struct wlr_scene_tree *scene_tree = lock_surface->surface->data + = wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface); + m->lock_surface = lock_surface; + + wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); + wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height); + + LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface); + + if (m == selmon) + client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat)); +} + +void +createmon(struct wl_listener *listener, void *data) +{ + /* This event is raised by the backend when a new output (aka a display or + * monitor) becomes available. */ + struct wlr_output *wlr_output = data; + const MonitorRule *r; + size_t i; + struct wlr_output_state state; + Monitor *m; + + if (!wlr_output_init_render(wlr_output, alloc, drw)) + return; + + m = wlr_output->data = ecalloc(1, sizeof(*m)); + m->wlr_output = wlr_output; + + for (i = 0; i < LENGTH(m->layers); i++) + wl_list_init(&m->layers[i]); + + wlr_output_state_init(&state); + /* Initialize monitor state using configured rules */ + m->tagset[0] = m->tagset[1] = 1; + for (r = monrules; r < END(monrules); r++) { + if (!r->name || strstr(wlr_output->name, r->name)) { + m->m.x = r->x; + m->m.y = r->y; + m->mfact = r->mfact; + m->nmaster = r->nmaster; + m->lt[0] = r->lt; + m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]]; + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + wlr_output_state_set_scale(&state, r->scale); + wlr_output_state_set_transform(&state, r->rr); + break; + } + } + + /* The mode is a tuple of (width, height, refresh rate), and each + * monitor supports only a specific set of modes. We just pick the + * monitor's preferred mode; a more sophisticated compositor would let + * the user configure it. */ + wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); + + /* Set up event listeners */ + LISTEN(&wlr_output->events.frame, &m->frame, rendermon); + LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); + LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); + + wlr_output_state_set_enabled(&state, 1); + wlr_output_commit_state(wlr_output, &state); + wlr_output_state_finish(&state); + + wl_list_insert(&mons, &m->link); + printstatus(); + + /* The xdg-protocol specifies: + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + * + */ + /* updatemons() will resize and set correct position */ + m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); + + /* Adds this to the output layout in the order it was configured. + * + * The output layout utility automatically adds a wl_output global to the + * display, which Wayland clients can see to find out information about the + * output (such as DPI, scale factor, manufacturer, etc). + */ + m->scene_output = wlr_scene_output_create(scene, wlr_output); + if (m->m.x == -1 && m->m.y == -1) + wlr_output_layout_add_auto(output_layout, wlr_output); + else + wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); +} + +void +createnotify(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client creates a new toplevel (application window). */ + struct wlr_xdg_toplevel *toplevel = data; + Client *c = NULL; + + /* Allocate a Client for this surface */ + c = toplevel->base->data = ecalloc(1, sizeof(*c)); + c->surface.xdg = toplevel->base; + c->bw = borderpx; + + LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); + LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); + LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify); + LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); + LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify); + LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle); +} + +void +createpointer(struct wlr_pointer *pointer) +{ + struct libinput_device *device; + if (wlr_input_device_is_libinput(&pointer->base) + && (device = wlr_libinput_get_device_handle(&pointer->base))) { + + if (libinput_device_config_tap_get_finger_count(device)) { + libinput_device_config_tap_set_enabled(device, tap_to_click); + libinput_device_config_tap_set_drag_enabled(device, tap_and_drag); + libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock); + libinput_device_config_tap_set_button_map(device, button_map); + } + + if (libinput_device_config_scroll_has_natural_scroll(device)) + libinput_device_config_scroll_set_natural_scroll_enabled(device, natural_scrolling); + + if (libinput_device_config_dwt_is_available(device)) + libinput_device_config_dwt_set_enabled(device, disable_while_typing); + + if (libinput_device_config_left_handed_is_available(device)) + libinput_device_config_left_handed_set(device, left_handed); + + if (libinput_device_config_middle_emulation_is_available(device)) + libinput_device_config_middle_emulation_set_enabled(device, middle_button_emulation); + + if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) + libinput_device_config_scroll_set_method (device, scroll_method); + + if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) + libinput_device_config_click_set_method (device, click_method); + + if (libinput_device_config_send_events_get_modes(device)) + libinput_device_config_send_events_set_mode(device, send_events_mode); + + if (libinput_device_config_accel_is_available(device)) { + libinput_device_config_accel_set_profile(device, accel_profile); + libinput_device_config_accel_set_speed(device, accel_speed); + } + } + + wlr_cursor_attach_input_device(cursor, &pointer->base); +} + +void +createpointerconstraint(struct wl_listener *listener, void *data) +{ + PointerConstraint *pointer_constraint = ecalloc(1, sizeof(*pointer_constraint)); + pointer_constraint->constraint = data; + LISTEN(&pointer_constraint->constraint->events.destroy, + &pointer_constraint->destroy, destroypointerconstraint); +} + +void +createpopup(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client (either xdg-shell or layer-shell) + * creates a new popup. */ + struct wlr_xdg_popup *popup = data; + LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); +} + +void +cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) +{ + if (active_constraint == constraint) + return; + + if (active_constraint) + wlr_pointer_constraint_v1_send_deactivated(active_constraint); + + active_constraint = constraint; + wlr_pointer_constraint_v1_send_activated(constraint); +} + +void +cursorframe(struct wl_listener *listener, void *data) +{ + /* This event is forwarded by the cursor when a pointer emits an frame + * event. Frame events are sent after regular pointer events to group + * multiple events together. For instance, two axis events may happen at the + * same time, in which case a frame event won't be sent in between. */ + /* Notify the client with pointer focus of the frame event. */ + wlr_seat_pointer_notify_frame(seat); +} + +void +cursorwarptohint(void) +{ + Client *c = NULL; + double sx = active_constraint->current.cursor_hint.x; + double sy = active_constraint->current.cursor_hint.y; + + toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); + if (c && active_constraint->current.cursor_hint.enabled) { + wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw); + wlr_seat_pointer_warp(active_constraint->seat, sx, sy); + } +} + +void +destroydecoration(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, destroy_decoration); + c->decoration = NULL; + + wl_list_remove(&c->destroy_decoration.link); + wl_list_remove(&c->set_decoration_mode.link); +} + +void +destroydragicon(struct wl_listener *listener, void *data) +{ + /* Focus enter isn't sent during drag, so refocus the focused node. */ + focusclient(focustop(selmon), 1); + motionnotify(0, NULL, 0, 0, 0, 0); +} + +void +destroyidleinhibitor(struct wl_listener *listener, void *data) +{ + /* `data` is the wlr_surface of the idle inhibitor being destroyed, + * at this point the idle inhibitor is still in the list of the manager */ + checkidleinhibitor(wlr_surface_get_root_surface(data)); +} + +void +destroylayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *l = wl_container_of(listener, l, destroy); + + wl_list_remove(&l->link); + wl_list_remove(&l->destroy.link); + wl_list_remove(&l->unmap.link); + wl_list_remove(&l->surface_commit.link); + wlr_scene_node_destroy(&l->scene->node); + wlr_scene_node_destroy(&l->popups->node); + free(l); +} + +void +destroylock(SessionLock *lock, int unlock) +{ + wlr_seat_keyboard_notify_clear_focus(seat); + if ((locked = !unlock)) + goto destroy; + + wlr_scene_node_set_enabled(&locked_bg->node, 0); + + focusclient(focustop(selmon), 0); + motionnotify(0, NULL, 0, 0, 0, 0); + +destroy: + wl_list_remove(&lock->new_surface.link); + wl_list_remove(&lock->unlock.link); + wl_list_remove(&lock->destroy.link); + + wlr_scene_node_destroy(&lock->scene->node); + cur_lock = NULL; + free(lock); +} + +void +destroylocksurface(struct wl_listener *listener, void *data) +{ + Monitor *m = wl_container_of(listener, m, destroy_lock_surface); + struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface; + + m->lock_surface = NULL; + wl_list_remove(&m->destroy_lock_surface.link); + + if (lock_surface->surface != seat->keyboard_state.focused_surface) + return; + + if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { + surface = wl_container_of(cur_lock->surfaces.next, surface, link); + client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); + } else if (!locked) { + focusclient(focustop(selmon), 1); + } else { + wlr_seat_keyboard_clear_focus(seat); + } +} + +void +destroynotify(struct wl_listener *listener, void *data) +{ + /* Called when the xdg_toplevel is destroyed. */ + Client *c = wl_container_of(listener, c, destroy); + wl_list_remove(&c->destroy.link); + wl_list_remove(&c->set_title.link); + wl_list_remove(&c->fullscreen.link); +#ifdef XWAYLAND + if (c->type != XDGShell) { + wl_list_remove(&c->activate.link); + wl_list_remove(&c->associate.link); + wl_list_remove(&c->configure.link); + wl_list_remove(&c->dissociate.link); + wl_list_remove(&c->set_hints.link); + } else +#endif + { + wl_list_remove(&c->commit.link); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); + } + free(c); +} + +void +destroypointerconstraint(struct wl_listener *listener, void *data) +{ + PointerConstraint *pointer_constraint = wl_container_of(listener, pointer_constraint, destroy); + + if (active_constraint == pointer_constraint->constraint) { + cursorwarptohint(); + active_constraint = NULL; + } + + wl_list_remove(&pointer_constraint->destroy.link); + free(pointer_constraint); +} + +void +destroysessionlock(struct wl_listener *listener, void *data) +{ + SessionLock *lock = wl_container_of(listener, lock, destroy); + destroylock(lock, 0); +} + +void +destroysessionmgr(struct wl_listener *listener, void *data) +{ + wl_list_remove(&lock_listener.link); + wl_list_remove(&listener->link); +} + +void +destroykeyboardgroup(struct wl_listener *listener, void *data) +{ + KeyboardGroup *group = wl_container_of(listener, group, destroy); + wl_event_source_remove(group->key_repeat_source); + wlr_keyboard_group_destroy(group->wlr_group); + wl_list_remove(&group->key.link); + wl_list_remove(&group->modifiers.link); + wl_list_remove(&group->destroy.link); + free(group); +} + +Monitor * +dirtomon(enum wlr_direction dir) +{ + struct wlr_output *next; + if (!wlr_output_layout_get(output_layout, selmon->wlr_output)) + return selmon; + if ((next = wlr_output_layout_adjacent_output(output_layout, + dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) + return next->data; + if ((next = wlr_output_layout_farthest_output(output_layout, + dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT), + selmon->wlr_output, selmon->m.x, selmon->m.y))) + return next->data; + return selmon; +} + +void +focusclient(Client *c, int lift) +{ + struct wlr_surface *old = seat->keyboard_state.focused_surface; + int unused_lx, unused_ly, old_client_type; + Client *old_c = NULL; + LayerSurface *old_l = NULL; + + if (locked) + return; + + /* Raise client in stacking order if requested */ + if (c && lift) + wlr_scene_node_raise_to_top(&c->scene->node); + + if (c && client_surface(c) == old) + return; + + if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == XDGShell) { + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link) + wlr_xdg_popup_destroy(popup); + } + + /* Put the new client atop the focus stack and select its monitor */ + if (c && !client_is_unmanaged(c)) { + wl_list_remove(&c->flink); + wl_list_insert(&fstack, &c->flink); + selmon = c->mon; + c->isurgent = 0; + client_restack_surface(c); + + /* Don't change border color if there is an exclusive focus or we are + * handling a drag operation */ + if (!exclusive_focus && !seat->drag) + client_set_border_color(c, focuscolor); + } + + /* Deactivate old client if focus is changing */ + if (old && (!c || client_surface(c) != old)) { + /* If an overlay is focused, don't focus or activate the client, + * but only update its position in fstack to render its border with focuscolor + * and focus it after the overlay is closed. */ + if (old_client_type == LayerShell && wlr_scene_node_coords( + &old_l->scene->node, &unused_lx, &unused_ly) + && old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { + return; + } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) { + return; + /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg + * and probably other clients */ + } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) { + client_set_border_color(old_c, bordercolor); + + client_activate_surface(old, 0); + } + } + printstatus(); + + if (!c) { + /* With no client, all we have left is to clear focus */ + wlr_seat_keyboard_notify_clear_focus(seat); + return; + } + + /* Change cursor surface */ + motionnotify(0, NULL, 0, 0, 0, 0); + + /* Have a client, so focus its top-level wlr_surface */ + client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); + + /* Activate the new client */ + client_activate_surface(client_surface(c), 1); +} + +void +focusmon(const Arg *arg) +{ + int i = 0, nmons = wl_list_length(&mons); + if (nmons) { + do /* don't switch to disabled mons */ + selmon = dirtomon(arg->i); + while (!selmon->wlr_output->enabled && i++ < nmons); + } + focusclient(focustop(selmon), 1); +} + +void +focusstack(const Arg *arg) +{ + /* Focus the next or previous client (in tiling order) on selmon */ + Client *c, *sel = focustop(selmon); + if (!sel || (sel->isfullscreen && !client_has_children(sel))) + return; + if (arg->i > 0) { + wl_list_for_each(c, &sel->link, link) { + if (&c->link == &clients) + continue; /* wrap past the sentinel node */ + if (VISIBLEON(c, selmon)) + break; /* found it */ + } + } else { + wl_list_for_each_reverse(c, &sel->link, link) { + if (&c->link == &clients) + continue; /* wrap past the sentinel node */ + if (VISIBLEON(c, selmon)) + break; /* found it */ + } + } + /* If only one client is visible on selmon, then c == sel */ + focusclient(c, 1); +} + +/* We probably should change the name of this, it sounds like + * will focus the topmost client of this mon, when actually will + * only return that client */ +Client * +focustop(Monitor *m) +{ + Client *c; + wl_list_for_each(c, &fstack, flink) { + if (VISIBLEON(c, m)) + return c; + } + return NULL; +} + +void +fullscreennotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, fullscreen); + setfullscreen(c, client_wants_fullscreen(c)); +} + +void +gpureset(struct wl_listener *listener, void *data) +{ + struct wlr_renderer *old_drw = drw; + struct wlr_allocator *old_alloc = alloc; + struct Monitor *m; + if (!(drw = wlr_renderer_autocreate(backend))) + die("couldn't recreate renderer"); + + if (!(alloc = wlr_allocator_autocreate(backend, drw))) + die("couldn't recreate allocator"); + + LISTEN_STATIC(&drw->events.lost, gpureset); + + wlr_compositor_set_renderer(compositor, drw); + + wl_list_for_each(m, &mons, link) { + wlr_output_init_render(m->wlr_output, alloc, drw); + } + + wlr_allocator_destroy(old_alloc); + wlr_renderer_destroy(old_drw); +} + +void +handlesig(int signo) +{ + if (signo == SIGCHLD) { +#ifdef XWAYLAND + siginfo_t in; + /* wlroots expects to reap the XWayland process itself, so we + * use WNOWAIT to keep the child waitable until we know it's not + * XWayland. + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid + && (!xwayland || in.si_pid != xwayland->server->pid)) + waitpid(in.si_pid, NULL, 0); +#else + while (waitpid(-1, NULL, WNOHANG) > 0); +#endif + } else if (signo == SIGINT || signo == SIGTERM) { + quit(NULL); + } +} + +void +incnmaster(const Arg *arg) +{ + if (!arg || !selmon) + return; + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +void +inputdevice(struct wl_listener *listener, void *data) +{ + /* This event is raised by the backend when a new input device becomes + * available. */ + struct wlr_input_device *device = data; + uint32_t caps; + + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + createkeyboard(wlr_keyboard_from_input_device(device)); + break; + case WLR_INPUT_DEVICE_POINTER: + createpointer(wlr_pointer_from_input_device(device)); + break; + default: + /* TODO handle other input device types */ + break; + } + + /* We need to let the wlr_seat know what our capabilities are, which is + * communiciated to the client. In dwl we always have a cursor, even if + * there are no pointer devices, so we always include that capability. */ + /* TODO do we actually require a cursor? */ + caps = WL_SEAT_CAPABILITY_POINTER; + if (!wl_list_empty(&kb_group->wlr_group->devices)) + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + wlr_seat_set_capabilities(seat, caps); +} + +int +keybinding(uint32_t mods, xkb_keysym_t sym) +{ + /* + * Here we handle compositor keybindings. This is when the compositor is + * processing keys, rather than passing them on to the client for its own + * processing. + */ + const Key *k; + for (k = keys; k < END(keys); k++) { + if (CLEANMASK(mods) == CLEANMASK(k->mod) + && sym == k->keysym && k->func) { + k->func(&k->arg); + return 1; + } + } + return 0; +} + +void +keypress(struct wl_listener *listener, void *data) +{ + int i; + /* This event is raised when a key is pressed or released. */ + KeyboardGroup *group = wl_container_of(listener, group, key); + struct wlr_keyboard_key_event *event = data; + + /* Translate libinput keycode -> xkbcommon */ + uint32_t keycode = event->keycode + 8; + /* Get a list of keysyms based on the keymap for this keyboard */ + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms( + group->wlr_group->keyboard.xkb_state, keycode, &syms); + + int handled = 0; + uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); + + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + + /* On _press_ if there is no active screen locker, + * attempt to process a compositor keybinding. */ + if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + for (i = 0; i < nsyms; i++) + handled = keybinding(mods, syms[i]) || handled; + } + + if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { + group->mods = mods; + group->keysyms = syms; + group->nsyms = nsyms; + wl_event_source_timer_update(group->key_repeat_source, + group->wlr_group->keyboard.repeat_info.delay); + } else { + group->nsyms = 0; + wl_event_source_timer_update(group->key_repeat_source, 0); + } + + if (handled) + return; + + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + /* Pass unhandled keycodes along to the client. */ + wlr_seat_keyboard_notify_key(seat, event->time_msec, + event->keycode, event->state); +} + +void +keypressmod(struct wl_listener *listener, void *data) +{ + /* This event is raised when a modifier key, such as shift or alt, is + * pressed. We simply communicate this to the client. */ + KeyboardGroup *group = wl_container_of(listener, group, modifiers); + + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + /* Send modifiers to the client. */ + wlr_seat_keyboard_notify_modifiers(seat, + &group->wlr_group->keyboard.modifiers); +} + +int +keyrepeat(void *data) +{ + KeyboardGroup *group = data; + int i; + if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) + return 0; + + wl_event_source_timer_update(group->key_repeat_source, + 1000 / group->wlr_group->keyboard.repeat_info.rate); + + for (i = 0; i < group->nsyms; i++) + keybinding(group->mods, group->keysyms[i]); + + return 0; +} + +void +killclient(const Arg *arg) +{ + Client *sel = focustop(selmon); + if (sel) + client_send_close(sel); +} + +void +locksession(struct wl_listener *listener, void *data) +{ + struct wlr_session_lock_v1 *session_lock = data; + SessionLock *lock; + wlr_scene_node_set_enabled(&locked_bg->node, 1); + if (cur_lock) { + wlr_session_lock_v1_destroy(session_lock); + return; + } + lock = session_lock->data = ecalloc(1, sizeof(*lock)); + focusclient(NULL, 0); + + lock->scene = wlr_scene_tree_create(layers[LyrBlock]); + cur_lock = lock->lock = session_lock; + locked = 1; + + LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface); + LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); + LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession); + + wlr_session_lock_v1_send_locked(session_lock); +} + +void +mapnotify(struct wl_listener *listener, void *data) +{ + /* Called when the surface is mapped, or ready to display on-screen. */ + Client *p = NULL; + Client *w, *c = wl_container_of(listener, c, map); + Monitor *m; + int i; + + /* Create scene tree for this client and its border */ + c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); + wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell); + c->scene_surface = c->type == XDGShell + ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) + : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); + c->scene->node.data = c->scene_surface->node.data = c; + + client_get_geometry(c, &c->geom); + + /* Handle unmanaged clients first so we can return prior create borders */ + if (client_is_unmanaged(c)) { + /* Unmanaged clients always are floating */ + wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + if (client_wants_focus(c)) { + focusclient(c, 1); + exclusive_focus = c; + } + goto unset_fullscreen; + } + + for (i = 0; i < 4; i++) { + c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, + c->isurgent ? urgentcolor : bordercolor); + c->border[i]->node.data = c; + } + + /* Initialize client geometry with room for border */ + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); + c->geom.width += 2 * c->bw; + c->geom.height += 2 * c->bw; + + /* Insert this client into client lists. */ + wl_list_insert(&clients, &c->link); + wl_list_insert(&fstack, &c->flink); + + /* Set initial monitor, tags, floating status, and focus: + * we always consider floating, clients that have parent and thus + * we set the same tags and monitor than its parent, if not + * try to apply rules for them */ + if ((p = client_get_parent(c))) { + c->isfloating = 1; + setmon(c, p->mon, p->tags); + } else { + applyrules(c); + } + printstatus(); + +unset_fullscreen: + m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); + wl_list_for_each(w, &clients, link) { + if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags)) + setfullscreen(w, 0); + } +} + +void +maximizenotify(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client would like to maximize itself, + * typically because the user clicked on the maximize button on + * client-side decorations. dwl doesn't support maximization, but + * to conform to xdg-shell protocol we still must send a configure. + * Since xdg-shell protocol v5 we should ignore request of unsupported + * capabilities, just schedule a empty configure when the client uses <5 + * protocol version + * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ + Client *c = wl_container_of(listener, c, maximize); + if (c->surface.xdg->initialized + && wl_resource_get_version(c->surface.xdg->toplevel->resource) + < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) + wlr_xdg_surface_schedule_configure(c->surface.xdg); +} + +void +monocle(Monitor *m) +{ + Client *c; + int n = 0; + + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; + resize(c, m->w, 0); + n++; + } + if (n) + snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n); + if ((c = focustop(m))) + wlr_scene_node_raise_to_top(&c->scene->node); +} + +void +motionabsolute(struct wl_listener *listener, void *data) +{ + /* This event is forwarded by the cursor when a pointer emits an _absolute_ + * motion event, from 0..1 on each axis. This happens, for example, when + * wlroots is running under a Wayland window rather than KMS+DRM, and you + * move the mouse over the window. You could enter the window from any edge, + * so we have to warp the mouse there. There is also some hardware which + * emits these events. */ + struct wlr_pointer_motion_absolute_event *event = data; + double lx, ly, dx, dy; + + if (!event->time_msec) /* this is 0 with virtual pointers */ + wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); + + wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, event->y, &lx, &ly); + dx = lx - cursor->x; + dy = ly - cursor->y; + motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); +} + +void +motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, + double dx_unaccel, double dy_unaccel) +{ + double sx = 0, sy = 0, sx_confined, sy_confined; + Client *c = NULL, *w = NULL; + LayerSurface *l = NULL; + struct wlr_surface *surface = NULL; + struct wlr_pointer_constraint_v1 *constraint; + + /* Find the client under the pointer and send the event along. */ + xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + + if (cursor_mode == CurPressed && !seat->drag + && surface != seat->pointer_state.focused_surface + && toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= 0) { + c = w; + surface = seat->pointer_state.focused_surface; + sx = cursor->x - (l ? l->geom.x : w->geom.x); + sy = cursor->y - (l ? l->geom.y : w->geom.y); + } + + /* time is 0 in internal calls meant to restore pointer focus. */ + if (time) { + wlr_relative_pointer_manager_v1_send_relative_motion( + relative_pointer_mgr, seat, (uint64_t)time * 1000, + dx, dy, dx_unaccel, dy_unaccel); + + wl_list_for_each(constraint, &pointer_constraints->constraints, link) + cursorconstrain(constraint); + + if (active_constraint && cursor_mode != CurResize && cursor_mode != CurMove) { + toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); + if (c && active_constraint->surface == seat->pointer_state.focused_surface) { + sx = cursor->x - c->geom.x - c->bw; + sy = cursor->y - c->geom.y - c->bw; + if (wlr_region_confine(&active_constraint->region, sx, sy, + sx + dx, sy + dy, &sx_confined, &sy_confined)) { + dx = sx_confined - sx; + dy = sy_confined - sy; + } + + if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) + return; + } + } + + wlr_cursor_move(cursor, device, dx, dy); + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + + /* Update selmon (even while dragging a window) */ + if (sloppyfocus) + selmon = xytomon(cursor->x, cursor->y); + } + + /* Update drag icon's position */ + wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); + + /* If we are currently grabbing the mouse, handle and return */ + if (cursor_mode == CurMove) { + /* Move the grabbed client to the new position. */ + resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy, + .width = grabc->geom.width, .height = grabc->geom.height}, 1); + return; + } else if (cursor_mode == CurResize) { + resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y, + .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1); + return; + } + + /* If there's no client surface under the cursor, set the cursor image to a + * default. This is what makes the cursor image appear when you move it + * off of a client or over its border. */ + if (!surface && !seat->drag) + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + + pointerfocus(c, surface, sx, sy, time); +} + +void +motionrelative(struct wl_listener *listener, void *data) +{ + /* This event is forwarded by the cursor when a pointer emits a _relative_ + * pointer motion event (i.e. a delta) */ + struct wlr_pointer_motion_event *event = data; + /* The cursor doesn't move unless we tell it to. The cursor automatically + * handles constraining the motion to the output layout, as well as any + * special configuration applied for the specific input device which + * generated the event. You can pass NULL for the device if you want to move + * the cursor around without any input. */ + motionnotify(event->time_msec, &event->pointer->base, event->delta_x, event->delta_y, + event->unaccel_dx, event->unaccel_dy); +} + +void +moveresize(const Arg *arg) +{ + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); + if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) + return; + + /* Float the window and tell motionnotify to grab it */ + setfloating(grabc, 1); + switch (cursor_mode = arg->ui) { + case CurMove: + grabcx = (int)round(cursor->x) - grabc->geom.x; + grabcy = (int)round(cursor->y) - grabc->geom.y; + wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); + break; + case CurResize: + /* Doesn't work for X11 output - the next absolute motion event + * returns the cursor to where it started */ + wlr_cursor_warp_closest(cursor, NULL, + grabc->geom.x + grabc->geom.width, + grabc->geom.y + grabc->geom.height); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize"); + break; + } +} + +void +outputmgrapply(struct wl_listener *listener, void *data) +{ + struct wlr_output_configuration_v1 *config = data; + outputmgrapplyortest(config, 0); +} + +void +outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) +{ + /* + * Called when a client such as wlr-randr requests a change in output + * configuration. This is only one way that the layout can be changed, + * so any Monitor information should be updated by updatemons() after an + * output_layout.change event, not here. + */ + struct wlr_output_configuration_head_v1 *config_head; + int ok = 1; + + wl_list_for_each(config_head, &config->heads, link) { + struct wlr_output *wlr_output = config_head->state.output; + Monitor *m = wlr_output->data; + struct wlr_output_state state; + + /* Ensure displays previously disabled by wlr-output-power-management-v1 + * are properly handled*/ + m->asleep = 0; + + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, config_head->state.enabled); + if (!config_head->state.enabled) + goto apply_or_test; + + if (config_head->state.mode) + wlr_output_state_set_mode(&state, config_head->state.mode); + else + wlr_output_state_set_custom_mode(&state, + config_head->state.custom_mode.width, + config_head->state.custom_mode.height, + config_head->state.custom_mode.refresh); + + wlr_output_state_set_transform(&state, config_head->state.transform); + wlr_output_state_set_scale(&state, config_head->state.scale); + wlr_output_state_set_adaptive_sync_enabled(&state, + config_head->state.adaptive_sync_enabled); + +apply_or_test: + ok &= test ? wlr_output_test_state(wlr_output, &state) + : wlr_output_commit_state(wlr_output, &state); + + /* Don't move monitors if position wouldn't change, this to avoid + * wlroots marking the output as manually configured. + * wlr_output_layout_add does not like disabled outputs */ + if (!test && wlr_output->enabled && (m->m.x != config_head->state.x || m->m.y != config_head->state.y)) + wlr_output_layout_add(output_layout, wlr_output, + config_head->state.x, config_head->state.y); + + wlr_output_state_finish(&state); + } + + if (ok) + wlr_output_configuration_v1_send_succeeded(config); + else + wlr_output_configuration_v1_send_failed(config); + wlr_output_configuration_v1_destroy(config); + + /* https://codeberg.org/dwl/dwl/issues/577 */ + updatemons(NULL, NULL); +} + +void +outputmgrtest(struct wl_listener *listener, void *data) +{ + struct wlr_output_configuration_v1 *config = data; + outputmgrapplyortest(config, 1); +} + +void +pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, + uint32_t time) +{ + struct timespec now; + + if (surface != seat->pointer_state.focused_surface && + sloppyfocus && time && c && !client_is_unmanaged(c)) + focusclient(c, 0); + + /* If surface is NULL, clear pointer focus */ + if (!surface) { + wlr_seat_pointer_notify_clear_focus(seat); + return; + } + + if (!time) { + clock_gettime(CLOCK_MONOTONIC, &now); + time = now.tv_sec * 1000 + now.tv_nsec / 1000000; + } + + /* Let the client know that the mouse cursor has entered one + * of its surfaces, and make keyboard focus follow if desired. + * wlroots makes this a no-op if surface is already focused */ + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(seat, time, sx, sy); +} + +void +printstatus(void) +{ + Monitor *m = NULL; + Client *c; + uint32_t occ, urg, sel; + const char *appid, *title; + + wl_list_for_each(m, &mons, link) { + occ = urg = 0; + wl_list_for_each(c, &clients, link) { + if (c->mon != m) + continue; + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + if ((c = focustop(m))) { + title = client_get_title(c); + appid = client_get_appid(c); + printf("%s title %s\n", m->wlr_output->name, title ? title : broken); + printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken); + printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen); + printf("%s floating %d\n", m->wlr_output->name, c->isfloating); + sel = c->tags; + } else { + printf("%s title \n", m->wlr_output->name); + printf("%s appid \n", m->wlr_output->name); + printf("%s fullscreen \n", m->wlr_output->name); + printf("%s floating \n", m->wlr_output->name); + sel = 0; + } + + printf("%s selmon %u\n", m->wlr_output->name, m == selmon); + printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n", + m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); + printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); + } + fflush(stdout); +} + +void +powermgrsetmode(struct wl_listener *listener, void *data) +{ + struct wlr_output_power_v1_set_mode_event *event = data; + struct wlr_output_state state = {0}; + Monitor *m = event->output->data; + + if (!m) + return; + + m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */ + wlr_output_state_set_enabled(&state, event->mode); + wlr_output_commit_state(m->wlr_output, &state); + + m->asleep = !event->mode; +} + +void +quit(const Arg *arg) +{ + wl_display_terminate(dpy); +} + +void +rendermon(struct wl_listener *listener, void *data) +{ + /* This function is called every time an output is ready to display a frame, + * generally at the output's refresh rate (e.g. 60Hz). */ + Monitor *m = wl_container_of(listener, m, frame); + Client *c; + struct wlr_output_state pending = {0}; + struct wlr_gamma_control_v1 *gamma_control; + struct timespec now; + + /* Render if no XDG clients have an outstanding resize and are visible on + * this monitor. */ + wl_list_for_each(c, &clients, link) { + if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) + goto skip; + } + + /* + * HACK: The "correct" way to set the gamma is to commit it together with + * the rest of the state in one go, but to do that we would need to rewrite + * wlr_scene_output_commit() in order to add the gamma to the pending + * state before committing, instead try to commit the gamma in one frame, + * and commit the rest of the state in the next one (or in the same frame if + * the gamma can not be committed). + */ + if (m->gamma_lut_changed) { + gamma_control + = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output); + m->gamma_lut_changed = 0; + + if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) + goto commit; + + if (!wlr_output_test_state(m->wlr_output, &pending)) { + wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); + goto commit; + } + wlr_output_commit_state(m->wlr_output, &pending); + wlr_output_schedule_frame(m->wlr_output); + } else { +commit: + wlr_scene_output_commit(m->scene_output, NULL); + } + +skip: + /* Let clients know a frame has been rendered */ + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_scene_output_send_frame_done(m->scene_output, &now); + wlr_output_state_finish(&pending); +} + +void +requestdecorationmode(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, set_decoration_mode); + if (c->surface.xdg->initialized) + wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +} + +void +requeststartdrag(struct wl_listener *listener, void *data) +{ + struct wlr_seat_request_start_drag_event *event = data; + + if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, + event->serial)) + wlr_seat_start_pointer_drag(seat, event->drag, event->serial); + else + wlr_data_source_destroy(event->drag->source); +} + +void +requestmonstate(struct wl_listener *listener, void *data) +{ + struct wlr_output_event_request_state *event = data; + wlr_output_commit_state(event->output, event->state); + updatemons(NULL, NULL); +} + +void +resize(Client *c, struct wlr_box geo, int interact) +{ + struct wlr_box *bbox; + struct wlr_box clip; + + if (!c->mon || !client_surface(c)->mapped) + return; + + bbox = interact ? &sgeom : &c->mon->w; + + client_set_bounds(c, geo.width, geo.height); + c->geom = geo; + applybounds(c, bbox); + + /* Update scene-graph, including borders */ + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); + wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); + wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); + wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); + wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); + wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); + + /* this is a no-op if size hasn't changed */ + c->resize = client_set_size(c, c->geom.width - 2 * c->bw, + c->geom.height - 2 * c->bw); + client_get_clip(c, &clip); + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); +} + +void +run(char *startup_cmd) +{ + /* Add a Unix socket to the Wayland display. */ + const char *socket = wl_display_add_socket_auto(dpy); + if (!socket) + die("startup: display_add_socket_auto"); + setenv("WAYLAND_DISPLAY", socket, 1); + + /* Start the backend. This will enumerate outputs and inputs, become the DRM + * master, etc */ + if (!wlr_backend_start(backend)) + die("startup: backend_start"); + + /* Now that the socket exists and the backend is started, run the startup command */ + if (startup_cmd) { + int piperw[2]; + if (pipe(piperw) < 0) + die("startup: pipe:"); + if ((child_pid = fork()) < 0) + die("startup: fork:"); + if (child_pid == 0) { + setsid(); + dup2(piperw[0], STDIN_FILENO); + close(piperw[0]); + close(piperw[1]); + execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); + die("startup: execl:"); + } + dup2(piperw[1], STDOUT_FILENO); + close(piperw[1]); + close(piperw[0]); + } + + /* Mark stdout as non-blocking to avoid people who does not close stdin + * nor consumes it in their startup script getting dwl frozen */ + if (fd_set_nonblock(STDOUT_FILENO) < 0) + close(STDOUT_FILENO); + + printstatus(); + + /* At this point the outputs are initialized, choose initial selmon based on + * cursor position, and set default cursor image */ + selmon = xytomon(cursor->x, cursor->y); + + /* TODO hack to get cursor to display in its initial location (100, 100) + * instead of (0, 0) and then jumping. still may not be fully + * initialized, as the image/coordinates are not transformed for the + * monitor when displayed here */ + wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + + /* Run the Wayland event loop. This does not return until you exit the + * compositor. Starting the backend rigged up all of the necessary event + * loop configuration to listen to libinput events, DRM events, generate + * frame events at the refresh rate, and so on. */ + wl_display_run(dpy); +} + +void +setcursor(struct wl_listener *listener, void *data) +{ + /* This event is raised by the seat when a client provides a cursor image */ + struct wlr_seat_pointer_request_set_cursor_event *event = data; + /* If we're "grabbing" the cursor, don't use the client's image, we will + * restore it after "grabbing" sending a leave event, followed by a enter + * event, which will result in the client requesting set the cursor surface */ + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + /* This can be sent by any client, so we check to make sure this one is + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided surface as the cursor image. It will set the + * hardware cursor on the output that it's currently on and continue to + * do so as the cursor moves between outputs. */ + if (event->seat_client == seat->pointer_state.focused_client) + wlr_cursor_set_surface(cursor, event->surface, + event->hotspot_x, event->hotspot_y); +} + +void +setcursorshape(struct wl_listener *listener, void *data) +{ + struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + /* This can be sent by any client, so we check to make sure this one is + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided cursor shape. */ + if (event->seat_client == seat->pointer_state.focused_client) + wlr_cursor_set_xcursor(cursor, cursor_mgr, + wlr_cursor_shape_v1_name(event->shape)); +} + +void +setfloating(Client *c, int floating) +{ + Client *p = client_get_parent(c); + c->isfloating = floating; + /* If in floating layout do not change the client's layer */ + if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange) + return; + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || + (p && p->isfullscreen) ? LyrFS + : c->isfloating ? LyrFloat : LyrTile]); + arrange(c->mon); + printstatus(); +} + +void +setfullscreen(Client *c, int fullscreen) +{ + c->isfullscreen = fullscreen; + if (!c->mon || !client_surface(c)->mapped) + return; + c->bw = fullscreen ? 0 : borderpx; + client_set_fullscreen(c, fullscreen); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); + + if (fullscreen) { + c->prev = c->geom; + resize(c, c->mon->m, 0); + } else { + /* restore previous size instead of arrange for floating windows since + * client positions are set by the user and cannot be recalculated */ + resize(c, c->prev, 0); + } + arrange(c->mon); + printstatus(); +} + +void +setgamma(struct wl_listener *listener, void *data) +{ + struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; + Monitor *m = event->output->data; + if (!m) + return; + m->gamma_lut_changed = 1; + wlr_output_schedule_frame(m->wlr_output); +} + +void +setlayout(const Arg *arg) +{ + if (!selmon) + return; + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol)); + arrange(selmon); + printstatus(); +} + +/* arg > 1.0 will set mfact absolutely */ +void +setmfact(const Arg *arg) +{ + float f; + + if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f; + if (f < 0.1 || f > 0.9) + return; + selmon->mfact = f; + arrange(selmon); +} + +void +setmon(Client *c, Monitor *m, uint32_t newtags) +{ + Monitor *oldmon = c->mon; + + if (oldmon == m) + return; + c->mon = m; + c->prev = c->geom; + + /* Scene graph sends surface leave/enter events on move and resize */ + if (oldmon) + arrange(oldmon); + if (m) { + /* Make sure window actually overlaps with the monitor */ + resize(c, c->geom, 0); + c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ + setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ + setfloating(c, c->isfloating); + } + focusclient(focustop(selmon), 1); +} + +void +setpsel(struct wl_listener *listener, void *data) +{ + /* This event is raised by the seat when a client wants to set the selection, + * usually when the user copies something. wlroots allows compositors to + * ignore such requests if they so choose, but in dwl we always honor + */ + struct wlr_seat_request_set_primary_selection_event *event = data; + wlr_seat_set_primary_selection(seat, event->source, event->serial); +} + +void +setsel(struct wl_listener *listener, void *data) +{ + /* This event is raised by the seat when a client wants to set the selection, + * usually when the user copies something. wlroots allows compositors to + * ignore such requests if they so choose, but in dwl we always honor + */ + struct wlr_seat_request_set_selection_event *event = data; + wlr_seat_set_selection(seat, event->source, event->serial); +} + +void +setup(void) +{ + int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; + sigemptyset(&sa.sa_mask); + + for (i = 0; i < (int)LENGTH(sig); i++) + sigaction(sig[i], &sa, NULL); + + wlr_log_init(log_level, NULL); + + /* The Wayland display is managed by libwayland. It handles accepting + * clients from the Unix socket, manging Wayland globals, and so on. */ + dpy = wl_display_create(); + event_loop = wl_display_get_event_loop(dpy); + + /* The backend is a wlroots feature which abstracts the underlying input and + * output hardware. The autocreate option will choose the most suitable + * backend based on the current environment, such as opening an X11 window + * if an X11 server is running. */ + if (!(backend = wlr_backend_autocreate(event_loop, &session))) + die("couldn't create backend"); + + /* Initialize the scene graph used to lay out windows */ + scene = wlr_scene_create(); + root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor); + for (i = 0; i < NUM_LAYERS; i++) + layers[i] = wlr_scene_tree_create(&scene->tree); + drag_icon = wlr_scene_tree_create(&scene->tree); + wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node); + + /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user + * can also specify a renderer using the WLR_RENDERER env var. + * The renderer is responsible for defining the various pixel formats it + * supports for shared memory, this configures that for clients. */ + if (!(drw = wlr_renderer_autocreate(backend))) + die("couldn't create renderer"); + LISTEN_STATIC(&drw->events.lost, gpureset); + + /* Create shm, drm and linux_dmabuf interfaces by ourselves. + * The simplest way is call: + * wlr_renderer_init_wl_display(drw); + * but we need to create manually the linux_dmabuf interface to integrate it + * with wlr_scene. */ + wlr_renderer_init_wl_shm(drw, dpy); + + if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { + wlr_drm_create(dpy, drw); + wlr_scene_set_linux_dmabuf_v1(scene, + wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); + } + + /* Autocreates an allocator for us. + * The allocator is the bridge between the renderer and the backend. It + * handles the buffer creation, allowing wlroots to render onto the + * screen */ + if (!(alloc = wlr_allocator_autocreate(backend, drw))) + die("couldn't create allocator"); + + /* This creates some hands-off wlroots interfaces. The compositor is + * necessary for clients to allocate surfaces and the data device manager + * handles the clipboard. Each of these wlroots interfaces has room for you + * to dig your fingers in and play with their behavior if you want. Note that + * the clients cannot set the selection directly without compositor approval, + * see the setsel() function. */ + compositor = wlr_compositor_create(dpy, 6, drw); + wlr_subcompositor_create(dpy); + wlr_data_device_manager_create(dpy); + wlr_export_dmabuf_manager_v1_create(dpy); + wlr_screencopy_manager_v1_create(dpy); + wlr_data_control_manager_v1_create(dpy); + wlr_primary_selection_v1_device_manager_create(dpy); + wlr_viewporter_create(dpy); + wlr_single_pixel_buffer_manager_v1_create(dpy); + wlr_fractional_scale_manager_v1_create(dpy, 1); + wlr_presentation_create(dpy, backend); + wlr_alpha_modifier_v1_create(dpy); + + /* Initializes the interface used to implement urgency hints */ + activation = wlr_xdg_activation_v1_create(dpy); + LISTEN_STATIC(&activation->events.request_activate, urgent); + + gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy); + LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma); + + power_mgr = wlr_output_power_manager_v1_create(dpy); + LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode); + + /* Creates an output layout, which a wlroots utility for working with an + * arrangement of screens in a physical layout. */ + output_layout = wlr_output_layout_create(dpy); + LISTEN_STATIC(&output_layout->events.change, updatemons); + wlr_xdg_output_manager_v1_create(dpy, output_layout); + + /* Configure a listener to be notified when new outputs are available on the + * backend. */ + wl_list_init(&mons); + LISTEN_STATIC(&backend->events.new_output, createmon); + + /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a + * Wayland protocol which is used for application windows. For more + * detail on shells, refer to the article: + * + * https://drewdevault.com/2018/07/29/Wayland-shells.html + */ + wl_list_init(&clients); + wl_list_init(&fstack); + + xdg_shell = wlr_xdg_shell_create(dpy, 6); + LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); + LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup); + + layer_shell = wlr_layer_shell_v1_create(dpy, 3); + LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); + + idle_notifier = wlr_idle_notifier_v1_create(dpy); + + idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); + LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); + + session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); + wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); + LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr); + locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, + (float [4]){0.1f, 0.1f, 0.1f, 1.0f}); + wlr_scene_node_set_enabled(&locked_bg->node, 0); + + /* Use decoration protocols to negotiate server-side decorations */ + wlr_server_decoration_manager_set_default_mode( + wlr_server_decoration_manager_create(dpy), + WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); + LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); + + pointer_constraints = wlr_pointer_constraints_v1_create(dpy); + LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint); + + relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); + + /* + * Creates a cursor, which is a wlroots utility for tracking the cursor + * image shown on screen. + */ + cursor = wlr_cursor_create(); + wlr_cursor_attach_output_layout(cursor, output_layout); + + /* Creates an xcursor manager, another wlroots utility which loads up + * Xcursor themes to source cursor images from and makes sure that cursor + * images are available at all scale factors on the screen (necessary for + * HiDPI support). Scaled cursors will be loaded with each output. */ + cursor_mgr = wlr_xcursor_manager_create(NULL, 24); + setenv("XCURSOR_SIZE", "24", 1); + + /* + * wlr_cursor *only* displays an image on screen. It does not move around + * when the pointer moves. However, we can attach input devices to it, and + * it will generate aggregate events for all of them. In these events, we + * can choose how we want to process them, forwarding them to clients and + * moving the cursor around. More detail on this process is described in + * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html + * + * And more comments are sprinkled throughout the notify functions above. + */ + LISTEN_STATIC(&cursor->events.motion, motionrelative); + LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute); + LISTEN_STATIC(&cursor->events.button, buttonpress); + LISTEN_STATIC(&cursor->events.axis, axisnotify); + LISTEN_STATIC(&cursor->events.frame, cursorframe); + + cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); + LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape); + + /* + * Configures a seat, which is a single "seat" at which a user sits and + * operates the computer. This conceptually includes up to one keyboard, + * pointer, touch, and drawing tablet device. We also rig up a listener to + * let us know when new input devices are available on the backend. + */ + LISTEN_STATIC(&backend->events.new_input, inputdevice); + virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); + LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard); + virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy); + LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, virtualpointer); + + seat = wlr_seat_create(dpy, "seat0"); + LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); + LISTEN_STATIC(&seat->events.request_set_selection, setsel); + LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); + LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); + LISTEN_STATIC(&seat->events.start_drag, startdrag); + + kb_group = createkeyboardgroup(); + wl_list_init(&kb_group->destroy.link); + + output_mgr = wlr_output_manager_v1_create(dpy); + LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); + LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); + + /* Make sure XWayland clients don't connect to the parent X server, + * e.g when running in the x11 backend or the wayland backend and the + * compositor has Xwayland support */ + unsetenv("DISPLAY"); +#ifdef XWAYLAND + /* + * Initialise the XWayland X server. + * It will be started when the first X client is started. + */ + if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) { + LISTEN_STATIC(&xwayland->events.ready, xwaylandready); + LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); + + setenv("DISPLAY", xwayland->display_name, 1); + } else { + fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); + } +#endif +} + +void +spawn(const Arg *arg) +{ + if (fork() == 0) { + dup2(STDERR_FILENO, STDOUT_FILENO); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + die("dwl: execvp %s failed:", ((char **)arg->v)[0]); + } +} + +void +startdrag(struct wl_listener *listener, void *data) +{ + struct wlr_drag *drag = data; + if (!drag->icon) + return; + + drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node; + LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); +} + +void +tag(const Arg *arg) +{ + Client *sel = focustop(selmon); + if (!sel || (arg->ui & TAGMASK) == 0) + return; + + sel->tags = arg->ui & TAGMASK; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); +} + +void +tagmon(const Arg *arg) +{ + Client *sel = focustop(selmon); + if (sel) + setmon(sel, dirtomon(arg->i), 0); +} + +void +tile(Monitor *m) +{ + unsigned int mw, my, ty; + int i, n = 0; + Client *c; + + wl_list_for_each(c, &clients, link) + if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) + n++; + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0; + else + mw = m->w.width; + i = my = ty = 0; + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; + if (i < m->nmaster) { + resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw, + .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0); + my += c->geom.height; + } else { + resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty, + .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0); + ty += c->geom.height; + } + i++; + } +} + +void +togglefloating(const Arg *arg) +{ + Client *sel = focustop(selmon); + /* return if fullscreen */ + if (sel && !sel->isfullscreen) + setfloating(sel, !sel->isfloating); +} + +void +togglefullscreen(const Arg *arg) +{ + Client *sel = focustop(selmon); + if (sel) + setfullscreen(sel, !sel->isfullscreen); +} + +void +toggletag(const Arg *arg) +{ + uint32_t newtags; + Client *sel = focustop(selmon); + if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK))) + return; + + sel->tags = newtags; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); +} + +void +toggleview(const Arg *arg) +{ + uint32_t newtagset; + if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0)) + return; + + selmon->tagset[selmon->seltags] = newtagset; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); +} + +void +unlocksession(struct wl_listener *listener, void *data) +{ + SessionLock *lock = wl_container_of(listener, lock, unlock); + destroylock(lock, 1); +} + +void +unmaplayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *l = wl_container_of(listener, l, unmap); + + l->mapped = 0; + wlr_scene_node_set_enabled(&l->scene->node, 0); + if (l == exclusive_focus) + exclusive_focus = NULL; + if (l->layer_surface->output && (l->mon = l->layer_surface->output->data)) + arrangelayers(l->mon); + if (l->layer_surface->surface == seat->keyboard_state.focused_surface) + focusclient(focustop(selmon), 1); + motionnotify(0, NULL, 0, 0, 0, 0); +} + +void +unmapnotify(struct wl_listener *listener, void *data) +{ + /* Called when the surface is unmapped, and should no longer be shown. */ + Client *c = wl_container_of(listener, c, unmap); + if (c == grabc) { + cursor_mode = CurNormal; + grabc = NULL; + } + + if (client_is_unmanaged(c)) { + if (c == exclusive_focus) { + exclusive_focus = NULL; + focusclient(focustop(selmon), 1); + } + } else { + wl_list_remove(&c->link); + setmon(c, NULL, 0); + wl_list_remove(&c->flink); + } + + wlr_scene_node_destroy(&c->scene->node); + printstatus(); + motionnotify(0, NULL, 0, 0, 0, 0); +} + +void +updatemons(struct wl_listener *listener, void *data) +{ + /* + * Called whenever the output layout changes: adding or removing a + * monitor, changing an output's mode or position, etc. This is where + * the change officially happens and we update geometry, window + * positions, focus, and the stored configuration in wlroots' + * output-manager implementation. + */ + struct wlr_output_configuration_v1 *config + = wlr_output_configuration_v1_create(); + Client *c; + struct wlr_output_configuration_head_v1 *config_head; + Monitor *m; + + /* First remove from the layout the disabled monitors */ + wl_list_for_each(m, &mons, link) { + if (m->wlr_output->enabled || m->asleep) + continue; + config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); + config_head->state.enabled = 0; + /* Remove this output from the layout to avoid cursor enter inside it */ + wlr_output_layout_remove(output_layout, m->wlr_output); + closemon(m); + m->m = m->w = (struct wlr_box){0}; + } + /* Insert outputs that need to */ + wl_list_for_each(m, &mons, link) { + if (m->wlr_output->enabled + && !wlr_output_layout_get(output_layout, m->wlr_output)) + wlr_output_layout_add_auto(output_layout, m->wlr_output); + } + + /* Now that we update the output layout we can get its box */ + wlr_output_layout_get_box(output_layout, NULL, &sgeom); + + wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y); + wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height); + + /* Make sure the clients are hidden when dwl is locked */ + wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y); + wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); + + wl_list_for_each(m, &mons, link) { + if (!m->wlr_output->enabled) + continue; + config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); + + /* Get the effective monitor geometry to use for surfaces */ + wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m); + m->w = m->m; + wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); + + wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); + wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); + + if (m->lock_surface) { + struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data; + wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); + wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height); + } + + /* Calculate the effective monitor geometry to use for clients */ + arrangelayers(m); + /* Don't move clients to the left output when plugging monitors */ + arrange(m); + /* make sure fullscreen clients have the right size */ + if ((c = focustop(m)) && c->isfullscreen) + resize(c, m->m, 0); + + /* Try to re-set the gamma LUT when updating monitors, + * it's only really needed when enabling a disabled output, but meh. */ + m->gamma_lut_changed = 1; + + config_head->state.x = m->m.x; + config_head->state.y = m->m.y; + + if (!selmon) { + selmon = m; + } + } + + if (selmon && selmon->wlr_output->enabled) { + wl_list_for_each(c, &clients, link) { + if (!c->mon && client_surface(c)->mapped) + setmon(c, selmon, c->tags); + } + focusclient(focustop(selmon), 1); + if (selmon->lock_surface) { + client_notify_enter(selmon->lock_surface->surface, + wlr_seat_get_keyboard(seat)); + client_activate_surface(selmon->lock_surface->surface, 1); + } + } + + /* FIXME: figure out why the cursor image is at 0,0 after turning all + * the monitors on. + * Move the cursor image where it used to be. It does not generate a + * wl_pointer.motion event for the clients, it's only the image what it's + * at the wrong position after all. */ + wlr_cursor_move(cursor, NULL, 0, 0); + + wlr_output_manager_v1_set_configuration(output_mgr, config); +} + +void +updatetitle(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, set_title); + if (c == focustop(c->mon)) + printstatus(); +} + +void +urgent(struct wl_listener *listener, void *data) +{ + struct wlr_xdg_activation_v1_request_activate_event *event = data; + Client *c = NULL; + toplevel_from_wlr_surface(event->surface, &c, NULL); + if (!c || c == focustop(selmon)) + return; + + c->isurgent = 1; + printstatus(); + + if (client_surface(c)->mapped) + client_set_border_color(c, urgentcolor); +} + +void +view(const Arg *arg) +{ + if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); +} + +void +virtualkeyboard(struct wl_listener *listener, void *data) +{ + struct wlr_virtual_keyboard_v1 *kb = data; + /* virtual keyboards shouldn't share keyboard group */ + KeyboardGroup *group = createkeyboardgroup(); + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); + LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup); + + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); +} + +void +virtualpointer(struct wl_listener *listener, void *data) +{ + struct wlr_virtual_pointer_v1_new_pointer_event *event = data; + struct wlr_input_device *device = &event->new_pointer->pointer.base; + + wlr_cursor_attach_input_device(cursor, device); + if (event->suggested_output) + wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); +} + +Monitor * +xytomon(double x, double y) +{ + struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); + return o ? o->data : NULL; +} + +void +xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny) +{ + struct wlr_scene_node *node, *pnode; + struct wlr_surface *surface = NULL; + Client *c = NULL; + LayerSurface *l = NULL; + int layer; + + for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { + if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) + continue; + + if (node->type == WLR_SCENE_NODE_BUFFER) + surface = wlr_scene_surface_try_from_buffer( + wlr_scene_buffer_from_node(node))->surface; + /* Walk the tree to find a node that knows the client */ + for (pnode = node; pnode && !c; pnode = &pnode->parent->node) + c = pnode->data; + if (c && c->type == LayerShell) { + c = NULL; + l = pnode->data; + } + } + + if (psurface) *psurface = surface; + if (pc) *pc = c; + if (pl) *pl = l; +} + +void +zoom(const Arg *arg) +{ + Client *c, *sel = focustop(selmon); + + if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) + return; + + /* Search for the first tiled window that is not sel, marking sel as + * NULL if we pass it along the way */ + wl_list_for_each(c, &clients, link) { + if (VISIBLEON(c, selmon) && !c->isfloating) { + if (c != sel) + break; + sel = NULL; + } + } + + /* Return if no other tiled window was found */ + if (&c->link == &clients) + return; + + /* If we passed sel, move c to the front; otherwise, move sel to the + * front */ + if (!sel) + sel = c; + wl_list_remove(&sel->link); + wl_list_insert(&clients, &sel->link); + + focusclient(sel, 1); + arrange(selmon); +} + +#ifdef XWAYLAND +void +activatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, activate); + + /* Only "managed" windows can be activated */ + if (!client_is_unmanaged(c)) + wlr_xwayland_surface_activate(c->surface.xwayland, 1); +} + +void +associatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, associate); + + LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); + LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); +} + +void +configurex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, configure); + struct wlr_xwayland_surface_configure_event *event = data; + /* TODO: figure out if there is another way to do this */ + if (!c->mon) { + wlr_xwayland_surface_configure(c->surface.xwayland, + event->x, event->y, event->width, event->height); + return; + } + if (c->isfloating || client_is_unmanaged(c)) + resize(c, (struct wlr_box){.x = event->x, .y = event->y, + .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0); + else + arrange(c->mon); +} + +void +createnotifyx11(struct wl_listener *listener, void *data) +{ + struct wlr_xwayland_surface *xsurface = data; + Client *c; + + /* Allocate a Client for this surface */ + c = xsurface->data = ecalloc(1, sizeof(*c)); + c->surface.xwayland = xsurface; + c->type = X11; + c->bw = client_is_unmanaged(c) ? 0 : borderpx; + + /* Listen to the various events it can emit */ + LISTEN(&xsurface->events.associate, &c->associate, associatex11); + LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11); + LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); + LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); + LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); + LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); + LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); +} + +void +dissociatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, dissociate); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); +} + +xcb_atom_t +getatom(xcb_connection_t *xc, const char *name) +{ + xcb_atom_t atom = 0; + xcb_intern_atom_reply_t *reply; + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name); + if ((reply = xcb_intern_atom_reply(xc, cookie, NULL))) + atom = reply->atom; + free(reply); + + return atom; +} + +void +sethints(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, set_hints); + struct wlr_surface *surface = client_surface(c); + if (c == focustop(selmon)) + return; + + c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); + printstatus(); + + if (c->isurgent && surface && surface->mapped) + client_set_border_color(c, urgentcolor); +} + +void +xwaylandready(struct wl_listener *listener, void *data) +{ + struct wlr_xcursor *xcursor; + xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL); + int err = xcb_connection_has_error(xc); + if (err) { + fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err); + return; + } + + /* Collect atoms we are interested in. If getatom returns 0, we will + * not detect that window type. */ + netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG"); + netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH"); + netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR"); + netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY"); + + /* assign the one and only seat */ + wlr_xwayland_set_seat(xwayland, seat); + + /* Set the default XWayland cursor to match the rest of dwl. */ + if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) + wlr_xwayland_set_cursor(xwayland, + xcursor->images[0]->buffer, xcursor->images[0]->width * 4, + xcursor->images[0]->width, xcursor->images[0]->height, + xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); + + xcb_disconnect(xc); +} +#endif + +int +main(int argc, char *argv[]) +{ + char *startup_cmd = NULL; + int c; + + while ((c = getopt(argc, argv, "s:hdv")) != -1) { + if (c == 's') + startup_cmd = optarg; + else if (c == 'd') + log_level = WLR_DEBUG; + else if (c == 'v') + die("dwl " VERSION); + else + goto usage; + } + if (optind < argc) + goto usage; + + /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ + if (!getenv("XDG_RUNTIME_DIR")) + die("XDG_RUNTIME_DIR must be set"); + setup(); + run(startup_cmd); + cleanup(); + return EXIT_SUCCESS; + +usage: + die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); +} diff --git a/dwl/dwl-v0.7_bak/dwl.desktop b/dwl/dwl-v0.7_bak/dwl.desktop new file mode 100644 index 00000000..e1380f7a --- /dev/null +++ b/dwl/dwl-v0.7_bak/dwl.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=dwl +Comment=dwm for Wayland +Exec=dwl +Type=Application diff --git a/dwl/dwl-v0.7_bak/dwl.o b/dwl/dwl-v0.7_bak/dwl.o new file mode 100644 index 0000000000000000000000000000000000000000..f6587fe661b1b7fe8cb3c02f4ccba805e4a0eadd GIT binary patch literal 336584 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 UC+{`?xkA2ve62Ed7M}nA0QqP + + + Copyright © 2017 Drew DeVault + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Clients can use this interface to assign the surface_layer role to + wl_surfaces. Such surfaces are assigned to a "layer" of the output and + rendered with a defined z-depth respective to each other. They may also be + anchored to the edges and corners of a screen and specify input handling + semantics. This interface should be suitable for the implementation of + many desktop shell components, and a broad number of other applications + that interact with the desktop. + + + + + Create a layer surface for an existing surface. This assigns the role of + layer_surface, or raises a protocol error if another role is already + assigned. + + Creating a layer surface from a wl_surface which has a buffer attached + or committed is a client error, and any attempts by a client to attach + or manipulate a buffer prior to the first layer_surface.configure call + must also be treated as errors. + + After creating a layer_surface object and setting it up, the client + must perform an initial commit without any buffer attached. + The compositor will reply with a layer_surface.configure event. + The client must acknowledge it and is then allowed to attach a buffer + to map the surface. + + You may pass NULL for output to allow the compositor to decide which + output to use. Generally this will be the one that the user most + recently interacted with. + + Clients can specify a namespace that defines the purpose of the layer + surface. + + + + + + + + + + + + + + + + + These values indicate which layers a surface can be rendered in. They + are ordered by z depth, bottom-most first. Traditional shell surfaces + will typically be rendered between the bottom and top layers. + Fullscreen shell surfaces are typically rendered at the top layer. + Multiple surfaces can share a single layer, and ordering within a + single layer is undefined. + + + + + + + + + + + + + This request indicates that the client will not use the layer_shell + object any more. Objects that have been created through this instance + are not affected. + + + + + + + An interface that may be implemented by a wl_surface, for surfaces that + are designed to be rendered as a layer of a stacked desktop-like + environment. + + Layer surface state (layer, size, anchor, exclusive zone, + margin, interactivity) is double-buffered, and will be applied at the + time wl_surface.commit of the corresponding wl_surface is called. + + Attaching a null buffer to a layer surface unmaps it. + + Unmapping a layer_surface means that the surface cannot be shown by the + compositor until it is explicitly mapped again. The layer_surface + returns to the state it had right after layer_shell.get_layer_surface. + The client can re-map the surface by performing a commit without any + buffer attached, waiting for a configure event and handling it as usual. + + + + + Sets the size of the surface in surface-local coordinates. The + compositor will display the surface centered with respect to its + anchors. + + If you pass 0 for either value, the compositor will assign it and + inform you of the assignment in the configure event. You must set your + anchor to opposite edges in the dimensions you omit; not doing so is a + protocol error. Both values are 0 by default. + + Size is double-buffered, see wl_surface.commit. + + + + + + + + Requests that the compositor anchor the surface to the specified edges + and corners. If two orthogonal edges are specified (e.g. 'top' and + 'left'), then the anchor point will be the intersection of the edges + (e.g. the top left corner of the output); otherwise the anchor point + will be centered on that edge, or in the center if none is specified. + + Anchor is double-buffered, see wl_surface.commit. + + + + + + + Requests that the compositor avoids occluding an area with other + surfaces. The compositor's use of this information is + implementation-dependent - do not assume that this region will not + actually be occluded. + + A positive value is only meaningful if the surface is anchored to one + edge or an edge and both perpendicular edges. If the surface is not + anchored, anchored to only two perpendicular edges (a corner), anchored + to only two parallel edges or anchored to all edges, a positive value + will be treated the same as zero. + + A positive zone is the distance from the edge in surface-local + coordinates to consider exclusive. + + Surfaces that do not wish to have an exclusive zone may instead specify + how they should interact with surfaces that do. If set to zero, the + surface indicates that it would like to be moved to avoid occluding + surfaces with a positive exclusive zone. If set to -1, the surface + indicates that it would not like to be moved to accommodate for other + surfaces, and the compositor should extend it all the way to the edges + it is anchored to. + + For example, a panel might set its exclusive zone to 10, so that + maximized shell surfaces are not shown on top of it. A notification + might set its exclusive zone to 0, so that it is moved to avoid + occluding the panel, but shell surfaces are shown underneath it. A + wallpaper or lock screen might set their exclusive zone to -1, so that + they stretch below or over the panel. + + The default value is 0. + + Exclusive zone is double-buffered, see wl_surface.commit. + + + + + + + Requests that the surface be placed some distance away from the anchor + point on the output, in surface-local coordinates. Setting this value + for edges you are not anchored to has no effect. + + The exclusive zone includes the margin. + + Margin is double-buffered, see wl_surface.commit. + + + + + + + + + + Types of keyboard interaction possible for layer shell surfaces. The + rationale for this is twofold: (1) some applications are not interested + in keyboard events and not allowing them to be focused can improve the + desktop experience; (2) some applications will want to take exclusive + keyboard focus. + + + + + This value indicates that this surface is not interested in keyboard + events and the compositor should never assign it the keyboard focus. + + This is the default value, set for newly created layer shell surfaces. + + This is useful for e.g. desktop widgets that display information or + only have interaction with non-keyboard input devices. + + + + + Request exclusive keyboard focus if this surface is above the shell surface layer. + + For the top and overlay layers, the seat will always give + exclusive keyboard focus to the top-most layer which has keyboard + interactivity set to exclusive. If this layer contains multiple + surfaces with keyboard interactivity set to exclusive, the compositor + determines the one receiving keyboard events in an implementation- + defined manner. In this case, no guarantee is made when this surface + will receive keyboard focus (if ever). + + For the bottom and background layers, the compositor is allowed to use + normal focus semantics. + + This setting is mainly intended for applications that need to ensure + they receive all keyboard events, such as a lock screen or a password + prompt. + + + + + This requests the compositor to allow this surface to be focused and + unfocused by the user in an implementation-defined manner. The user + should be able to unfocus this surface even regardless of the layer + it is on. + + Typically, the compositor will want to use its normal mechanism to + manage keyboard focus between layer shell surfaces with this setting + and regular toplevels on the desktop layer (e.g. click to focus). + Nevertheless, it is possible for a compositor to require a special + interaction to focus or unfocus layer shell surfaces (e.g. requiring + a click even if focus follows the mouse normally, or providing a + keybinding to switch focus between layers). + + This setting is mainly intended for desktop shell components (e.g. + panels) that allow keyboard interaction. Using this option can allow + implementing a desktop shell that can be fully usable without the + mouse. + + + + + + + Set how keyboard events are delivered to this surface. By default, + layer shell surfaces do not receive keyboard events; this request can + be used to change this. + + This setting is inherited by child surfaces set by the get_popup + request. + + Layer surfaces receive pointer, touch, and tablet events normally. If + you do not want to receive them, set the input region on your surface + to an empty region. + + Keyboard interactivity is double-buffered, see wl_surface.commit. + + + + + + + This assigns an xdg_popup's parent to this layer_surface. This popup + should have been created via xdg_surface::get_popup with the parent set + to NULL, and this request must be invoked before committing the popup's + initial state. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + When a configure event is received, if a client commits the + surface in response to the configure event, then the client + must make an ack_configure request sometime before the commit + request, passing along the serial of the configure event. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + + A client is not required to commit immediately after sending + an ack_configure request - it may even ack_configure several times + before its next surface commit. + + A client may send multiple ack_configure requests before committing, but + only the last request sent before a commit indicates which configure + event the client really is responding to. + + + + + + + This request destroys the layer surface. + + + + + + The configure event asks the client to resize its surface. + + Clients should arrange their surface for the new states, and then send + an ack_configure request with the serial sent in this configure event at + some point before committing the new surface. + + The client is free to dismiss all but the last configure event it + received. + + The width and height arguments specify the size of the window in + surface-local coordinates. + + The size is a hint, in the sense that the client is free to ignore it if + it doesn't resize, pick a smaller size (to satisfy aspect ratio or + resize in steps of NxM pixels). If the client picks a smaller size and + is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the + surface will be centered on this axis. + + If the width or height arguments are zero, it means the client should + decide its own window dimension. + + + + + + + + + The closed event is sent by the compositor when the surface will no + longer be shown. The output may have been destroyed or the user may + have asked for it to be removed. Further changes to the surface will be + ignored. The client should destroy the resource after receiving this + event, and create a new surface if they so choose. + + + + + + + + + + + + + + + + + + + + + + Change the layer that the surface is rendered on. + + Layer is double-buffered, see wl_surface.commit. + + + + + diff --git a/dwl/dwl-v0.7_bak/protocols/wlr-output-power-management-unstable-v1.xml b/dwl/dwl-v0.7_bak/protocols/wlr-output-power-management-unstable-v1.xml new file mode 100644 index 00000000..a9778399 --- /dev/null +++ b/dwl/dwl-v0.7_bak/protocols/wlr-output-power-management-unstable-v1.xml @@ -0,0 +1,128 @@ + + + + Copyright © 2019 Purism SPC + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol allows clients to control power management modes + of outputs that are currently part of the compositor space. The + intent is to allow special clients like desktop shells to power + down outputs when the system is idle. + + To modify outputs not currently part of the compositor space see + wlr-output-management. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + + + + + This interface is a manager that allows creating per-output power + management mode controls. + + + + + Create a output power management mode control that can be used to + adjust the power management mode for a given output. + + + + + + + + All objects created by the manager will still remain valid, until their + appropriate destroy request has been called. + + + + + + + This object offers requests to set the power management mode of + an output. + + + + + + + + + + + + + + Set an output's power save mode to the given mode. The mode change + is effective immediately. If the output does not support the given + mode a failed event is sent. + + + + + + + Report the power management mode change of an output. + + The mode event is sent after an output changed its power + management mode. The reason can be a client using set_mode or the + compositor deciding to change an output's mode. + This event is also sent immediately when the object is created + so the client is informed about the current power management mode. + + + + + + + This event indicates that the output power management mode control + is no longer valid. This can happen for a number of reasons, + including: + - The output doesn't support power management + - Another client already has exclusive power management mode control + for this output + - The output disappeared + + Upon receiving this event, the client should destroy this object. + + + + + + Destroys the output power management mode control object. + + + + diff --git a/dwl/dwl-v0.7_bak/swallow.patch b/dwl/dwl-v0.7_bak/swallow.patch new file mode 100644 index 00000000..f9760234 --- /dev/null +++ b/dwl/dwl-v0.7_bak/swallow.patch @@ -0,0 +1,350 @@ +From 7255d7e2e1b87c0583a202ea20c83fa75466c0fc Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Wed, 5 Feb 2025 02:34:39 +0100 +Subject: [PATCH] Swallow: hide the terminal when it spawns a client + +--- + client.h | 12 ++++ + config.def.h | 10 +++- + dwl.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 167 insertions(+), 7 deletions(-) + +diff --git a/client.h b/client.h +index 42f225f..bc9cad2 100644 +--- a/client.h ++++ b/client.h +@@ -131,6 +131,18 @@ client_get_appid(Client *c) + return c->surface.xdg->toplevel->app_id; + } + ++static inline int ++client_get_pid(Client *c) ++{ ++ pid_t pid; ++#ifdef XWAYLAND ++ if (client_is_x11(c)) ++ return c->surface.xwayland->pid; ++#endif ++ wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); ++ return pid; ++} ++ + static inline void + client_get_clip(Client *c, struct wlr_box *clip) + { +diff --git a/config.def.h b/config.def.h +index 22d2171..fb5f8fb 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,7 @@ static const float focuscolor[] = COLOR(0x005577ff); + static const float urgentcolor[] = COLOR(0xff0000ff); + /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ + static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */ ++static int enableautoswallow = 1; /* enables autoswallowing newly spawned clients */ + + /* tagging - TAGCOUNT must be no greater than 31 */ + #define TAGCOUNT (9) +@@ -22,10 +23,11 @@ static int log_level = WLR_ERROR; + + /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */ + static const Rule rules[] = { +- /* app_id title tags mask isfloating monitor */ ++ /* app_id title tags mask isfloating isterm noswallow monitor */ + /* examples: */ +- { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ +- { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ ++ { "foot", NULL, 0, 0, 1, 1, -1 }, ++ { "Gimp_EXAMPLE", NULL, 0, 1, 0, 0, -1 }, /* Start on currently visible tags floating, not tiled */ ++ { "firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1 }, /* Start on ONLY tag "9" */ + }; + + /* layout(s) */ +@@ -142,6 +144,8 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, ++ { MODKEY, XKB_KEY_a, toggleswallow, {0} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow,{0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, + { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, +diff --git a/dwl.c b/dwl.c +index def2562..bbbbe6f 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -73,12 +73,13 @@ + #define MAX(A, B) ((A) > (B) ? (A) : (B)) + #define MIN(A, B) ((A) < (B) ? (A) : (B)) + #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) +-#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) ++#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]) && !(C)->swallowedby) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define END(A) ((A) + LENGTH(A)) + #define TAGMASK ((1u << TAGCOUNT) - 1) + #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) + #define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) ++#define BORDERPX(C) (borderpx + ((C)->swallowing ? (C)->swallowing->bw : 0)) + + /* enums */ + enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ +@@ -104,7 +105,8 @@ typedef struct { + } Button; + + typedef struct Monitor Monitor; +-typedef struct { ++typedef struct Client Client; ++struct Client { + /* Must keep these three elements in this order */ + unsigned int type; /* XDGShell or X11* */ + struct wlr_box geom; /* layout-relative, includes border */ +@@ -140,8 +142,12 @@ typedef struct { + unsigned int bw; + uint32_t tags; + int isfloating, isurgent, isfullscreen; ++ int isterm, noswallow; + uint32_t resize; /* configure serial of a pending resize */ +-} Client; ++ pid_t pid; ++ Client *swallowing; /* client being hidden */ ++ Client *swallowedby; ++}; + + typedef struct { + uint32_t mod; +@@ -230,6 +236,8 @@ typedef struct { + const char *title; + uint32_t tags; + int isfloating; ++ int isterm; ++ int noswallow; + int monitor; + } Rule; + +@@ -311,6 +319,7 @@ static void moveresize(const Arg *arg); + static void outputmgrapply(struct wl_listener *listener, void *data); + static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); + static void outputmgrtest(struct wl_listener *listener, void *data); ++static pid_t parentpid(pid_t pid); + static void pointerfocus(Client *c, struct wlr_surface *surface, + double sx, double sy, uint32_t time); + static void printstatus(void); +@@ -335,11 +344,15 @@ static void setsel(struct wl_listener *listener, void *data); + static void setup(void); + static void spawn(const Arg *arg); + static void startdrag(struct wl_listener *listener, void *data); ++static void swallow(Client *c, Client *toswallow); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); ++static Client *termforwin(Client *c); + static void tile(Monitor *m); + static void togglefloating(const Arg *arg); + static void togglefullscreen(const Arg *arg); ++static void toggleswallow(const Arg *arg); ++static void toggleautoswallow(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unlocksession(struct wl_listener *listener, void *data); +@@ -466,11 +479,15 @@ applyrules(Client *c) + if (!(title = client_get_title(c))) + title = broken; + ++ c->pid = client_get_pid(c); ++ + for (r = rules; r < END(rules); r++) { + if ((!r->title || strstr(title, r->title)) + && (!r->id || strstr(appid, r->id))) { + c->isfloating = r->isfloating; + newtags |= r->tags; ++ c->isterm = r->isterm; ++ c->noswallow = r->noswallow; + i = 0; + wl_list_for_each(m, &mons, link) { + if (r->monitor == i++) +@@ -478,6 +495,12 @@ applyrules(Client *c) + } + } + } ++ if (enableautoswallow && !c->noswallow && !c->isfloating && ++ !c->surface.xdg->initial_commit) { ++ Client *p = termforwin(c); ++ if (p) ++ swallow(c, p); ++ } + setmon(c, mon, newtags); + } + +@@ -2006,6 +2029,20 @@ outputmgrtest(struct wl_listener *listener, void *data) + outputmgrapplyortest(config, 1); + } + ++pid_t ++parentpid(pid_t pid) ++{ ++ unsigned int v = 0; ++ FILE *f; ++ char buf[256]; ++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)pid); ++ if (!(f = fopen(buf, "r"))) ++ return 0; ++ fscanf(f, "%*u %*s %*c %u", &v); ++ fclose(f); ++ return (pid_t)v; ++} ++ + void + pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, + uint32_t time) +@@ -2326,7 +2363,7 @@ setfullscreen(Client *c, int fullscreen) + c->isfullscreen = fullscreen; + if (!c->mon || !client_surface(c)->mapped) + return; +- c->bw = fullscreen ? 0 : borderpx; ++ c->bw = fullscreen ? 0 : BORDERPX(c); + client_set_fullscreen(c, fullscreen); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); +@@ -2404,6 +2441,9 @@ setmon(Client *c, Monitor *m, uint32_t newtags) + setfloating(c, c->isfloating); + } + focusclient(focustop(selmon), 1); ++ ++ if (c->swallowing) ++ setmon(c->swallowing, m, newtags); + } + + void +@@ -2669,6 +2709,44 @@ startdrag(struct wl_listener *listener, void *data) + LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); + } + ++void ++swallow(Client *c, Client *toswallow) ++{ ++ /* Do not allow a client to swallow itself */ ++ if (c == toswallow) ++ return; ++ ++ /* Swallow */ ++ if (toswallow && !c->swallowing) { ++ c->swallowing = toswallow; ++ toswallow->swallowedby = c; ++ toswallow->mon = c->mon; ++ toswallow->mon = c->mon; ++ wl_list_remove(&c->link); ++ wl_list_insert(&c->swallowing->link, &c->link); ++ wl_list_remove(&c->flink); ++ wl_list_insert(&c->swallowing->flink, &c->flink); ++ c->bw = BORDERPX(c); ++ c->tags = toswallow->tags; ++ c->isfloating = toswallow->isfloating; ++ c->geom = toswallow->geom; ++ setfullscreen(toswallow, 0); ++ } ++ ++ /* Unswallow */ ++ else if (c->swallowing) { ++ wl_list_remove(&c->swallowing->link); ++ wl_list_insert(&c->link, &c->swallowing->link); ++ wl_list_remove(&c->swallowing->flink); ++ wl_list_insert(&c->flink, &c->swallowing->flink); ++ c->swallowing->tags = c->tags; ++ c->swallowing->swallowedby = NULL; ++ c->swallowing = NULL; ++ c->bw = BORDERPX(c); ++ setfullscreen(c, 0); ++ } ++} ++ + void + tag(const Arg *arg) + { +@@ -2690,6 +2768,40 @@ tagmon(const Arg *arg) + setmon(sel, dirtomon(arg->i), 0); + } + ++Client * ++termforwin(Client *c) ++{ ++ Client *p; ++ pid_t pid; ++ pid_t pids[32]; ++ size_t i, pids_len; ++ ++ if (!c->pid || c->isterm) ++ return NULL; ++ ++ /* Get all parent pids */ ++ pids_len = 0; ++ pid = c->pid; ++ while (pids_len < LENGTH(pids)) { ++ pid = parentpid(pid); ++ if (!pid) ++ break; ++ pids[pids_len++] = pid; ++ } ++ ++ /* Find closest parent */ ++ for (i = 0; i < pids_len; i++) { ++ wl_list_for_each(p, &clients, link) { ++ if (!p->pid || !p->isterm || p->swallowedby) ++ continue; ++ if (pids[i] == p->pid) ++ return p; ++ } ++ } ++ ++ return NULL; ++} ++ + void + tile(Monitor *m) + { +@@ -2741,6 +2853,32 @@ togglefullscreen(const Arg *arg) + setfullscreen(sel, !sel->isfullscreen); + } + ++void ++toggleswallow(const Arg *arg) ++{ ++ Client *c, *sel = focustop(selmon); ++ if (!sel) ++ return; ++ ++ if (sel->swallowing) { ++ swallow(sel, NULL); ++ } else { ++ wl_list_for_each(c, &sel->flink, flink) { ++ if (&c->flink == &fstack) ++ continue; /* wrap past the sentinel node */ ++ if (VISIBLEON(c, selmon)) ++ break; /* found it */ ++ } ++ swallow(sel, c); ++ } ++} ++ ++void ++toggleautoswallow(const Arg *arg) ++{ ++ enableautoswallow = !enableautoswallow; ++} ++ + void + toggletag(const Arg *arg) + { +@@ -2801,6 +2939,12 @@ unmapnotify(struct wl_listener *listener, void *data) + grabc = NULL; + } + ++ if (c->swallowing) { ++ swallow(c, NULL); ++ } else if (c->swallowedby) { ++ swallow(c->swallowedby, NULL); ++ } ++ + if (client_is_unmanaged(c)) { + if (c == exclusive_focus) { + exclusive_focus = NULL; +-- +2.48.1 + diff --git a/dwl/dwl-v0.7_bak/util.c b/dwl/dwl-v0.7_bak/util.c new file mode 100644 index 00000000..51130af0 --- /dev/null +++ b/dwl/dwl-v0.7_bak/util.c @@ -0,0 +1,51 @@ +/* See LICENSE.dwm file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include "util.h" + +void +die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} + +int +fd_set_nonblock(int fd) { + int flags = fcntl(fd, F_GETFL); + if (flags < 0) { + perror("fcntl(F_GETFL):"); + return -1; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl(F_SETFL):"); + return -1; + } + + return 0; +} diff --git a/dwl/dwl-v0.7_bak/util.h b/dwl/dwl-v0.7_bak/util.h new file mode 100644 index 00000000..226980de --- /dev/null +++ b/dwl/dwl-v0.7_bak/util.h @@ -0,0 +1,5 @@ +/* See LICENSE.dwm file for copyright and license details. */ + +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); +int fd_set_nonblock(int fd); diff --git a/dwl/dwl-v0.7_bak/util.o b/dwl/dwl-v0.7_bak/util.o new file mode 100644 index 0000000000000000000000000000000000000000..c1969d5e3e2bee637606507cc8cccc95a8728681 GIT binary patch literal 9400 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 +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_wlr_output_power_management_unstable_v1 The wlr_output_power_management_unstable_v1 protocol + * Control power management modes of outputs + * + * @section page_desc_wlr_output_power_management_unstable_v1 Description + * + * This protocol allows clients to control power management modes + * of outputs that are currently part of the compositor space. The + * intent is to allow special clients like desktop shells to power + * down outputs when the system is idle. + * + * To modify outputs not currently part of the compositor space see + * wlr-output-management. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + * + * @section page_ifaces_wlr_output_power_management_unstable_v1 Interfaces + * - @subpage page_iface_zwlr_output_power_manager_v1 - manager to create per-output power management + * - @subpage page_iface_zwlr_output_power_v1 - adjust power management mode for an output + * @section page_copyright_wlr_output_power_management_unstable_v1 Copyright + *
+ *
+ * Copyright © 2019 Purism SPC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct zwlr_output_power_manager_v1; +struct zwlr_output_power_v1; + +#ifndef ZWLR_OUTPUT_POWER_MANAGER_V1_INTERFACE +#define ZWLR_OUTPUT_POWER_MANAGER_V1_INTERFACE +/** + * @page page_iface_zwlr_output_power_manager_v1 zwlr_output_power_manager_v1 + * @section page_iface_zwlr_output_power_manager_v1_desc Description + * + * This interface is a manager that allows creating per-output power + * management mode controls. + * @section page_iface_zwlr_output_power_manager_v1_api API + * See @ref iface_zwlr_output_power_manager_v1. + */ +/** + * @defgroup iface_zwlr_output_power_manager_v1 The zwlr_output_power_manager_v1 interface + * + * This interface is a manager that allows creating per-output power + * management mode controls. + */ +extern const struct wl_interface zwlr_output_power_manager_v1_interface; +#endif +#ifndef ZWLR_OUTPUT_POWER_V1_INTERFACE +#define ZWLR_OUTPUT_POWER_V1_INTERFACE +/** + * @page page_iface_zwlr_output_power_v1 zwlr_output_power_v1 + * @section page_iface_zwlr_output_power_v1_desc Description + * + * This object offers requests to set the power management mode of + * an output. + * @section page_iface_zwlr_output_power_v1_api API + * See @ref iface_zwlr_output_power_v1. + */ +/** + * @defgroup iface_zwlr_output_power_v1 The zwlr_output_power_v1 interface + * + * This object offers requests to set the power management mode of + * an output. + */ +extern const struct wl_interface zwlr_output_power_v1_interface; +#endif + +/** + * @ingroup iface_zwlr_output_power_manager_v1 + * @struct zwlr_output_power_manager_v1_interface + */ +struct zwlr_output_power_manager_v1_interface { + /** + * get a power management for an output + * + * Create a output power management mode control that can be used + * to adjust the power management mode for a given output. + */ + void (*get_output_power)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *output); + /** + * destroy the manager + * + * All objects created by the manager will still remain valid, + * until their appropriate destroy request has been called. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); +}; + + +/** + * @ingroup iface_zwlr_output_power_manager_v1 + */ +#define ZWLR_OUTPUT_POWER_MANAGER_V1_GET_OUTPUT_POWER_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_power_manager_v1 + */ +#define ZWLR_OUTPUT_POWER_MANAGER_V1_DESTROY_SINCE_VERSION 1 + +#ifndef ZWLR_OUTPUT_POWER_V1_MODE_ENUM +#define ZWLR_OUTPUT_POWER_V1_MODE_ENUM +enum zwlr_output_power_v1_mode { + /** + * Output is turned off. + */ + ZWLR_OUTPUT_POWER_V1_MODE_OFF = 0, + /** + * Output is turned on, no power saving + */ + ZWLR_OUTPUT_POWER_V1_MODE_ON = 1, +}; +#endif /* ZWLR_OUTPUT_POWER_V1_MODE_ENUM */ + +#ifndef ZWLR_OUTPUT_POWER_V1_MODE_ENUM_IS_VALID +#define ZWLR_OUTPUT_POWER_V1_MODE_ENUM_IS_VALID +/** + * @ingroup iface_zwlr_output_power_v1 + * Validate a zwlr_output_power_v1 mode value. + * + * @return true on success, false on error. + * @ref zwlr_output_power_v1_mode + */ +static inline bool +zwlr_output_power_v1_mode_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_OUTPUT_POWER_V1_MODE_OFF: + return version >= 1; + case ZWLR_OUTPUT_POWER_V1_MODE_ON: + return version >= 1; + default: + return false; + } +} +#endif /* ZWLR_OUTPUT_POWER_V1_MODE_ENUM_IS_VALID */ + +#ifndef ZWLR_OUTPUT_POWER_V1_ERROR_ENUM +#define ZWLR_OUTPUT_POWER_V1_ERROR_ENUM +enum zwlr_output_power_v1_error { + /** + * inexistent power save mode + */ + ZWLR_OUTPUT_POWER_V1_ERROR_INVALID_MODE = 1, +}; +#endif /* ZWLR_OUTPUT_POWER_V1_ERROR_ENUM */ + +#ifndef ZWLR_OUTPUT_POWER_V1_ERROR_ENUM_IS_VALID +#define ZWLR_OUTPUT_POWER_V1_ERROR_ENUM_IS_VALID +/** + * @ingroup iface_zwlr_output_power_v1 + * Validate a zwlr_output_power_v1 error value. + * + * @return true on success, false on error. + * @ref zwlr_output_power_v1_error + */ +static inline bool +zwlr_output_power_v1_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_OUTPUT_POWER_V1_ERROR_INVALID_MODE: + return version >= 1; + default: + return false; + } +} +#endif /* ZWLR_OUTPUT_POWER_V1_ERROR_ENUM_IS_VALID */ + +/** + * @ingroup iface_zwlr_output_power_v1 + * @struct zwlr_output_power_v1_interface + */ +struct zwlr_output_power_v1_interface { + /** + * Set an outputs power save mode + * + * Set an output's power save mode to the given mode. The mode + * change is effective immediately. If the output does not support + * the given mode a failed event is sent. + * @param mode the power save mode to set + */ + void (*set_mode)(struct wl_client *client, + struct wl_resource *resource, + uint32_t mode); + /** + * destroy this power management + * + * Destroys the output power management mode control object. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define ZWLR_OUTPUT_POWER_V1_MODE 0 +#define ZWLR_OUTPUT_POWER_V1_FAILED 1 + +/** + * @ingroup iface_zwlr_output_power_v1 + */ +#define ZWLR_OUTPUT_POWER_V1_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_power_v1 + */ +#define ZWLR_OUTPUT_POWER_V1_FAILED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwlr_output_power_v1 + */ +#define ZWLR_OUTPUT_POWER_V1_SET_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_power_v1 + */ +#define ZWLR_OUTPUT_POWER_V1_DESTROY_SINCE_VERSION 1 + +/** + * @ingroup iface_zwlr_output_power_v1 + * Sends an mode event to the client owning the resource. + * @param resource_ The client's resource + * @param mode the output's new power management mode + */ +static inline void +zwlr_output_power_v1_send_mode(struct wl_resource *resource_, uint32_t mode) +{ + wl_resource_post_event(resource_, ZWLR_OUTPUT_POWER_V1_MODE, mode); +} + +/** + * @ingroup iface_zwlr_output_power_v1 + * Sends an failed event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +zwlr_output_power_v1_send_failed(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, ZWLR_OUTPUT_POWER_V1_FAILED); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dwl/dwl-v0.7_bak/xdg-shell-protocol.h b/dwl/dwl-v0.7_bak/xdg-shell-protocol.h new file mode 100644 index 00000000..8c11cd0b --- /dev/null +++ b/dwl/dwl-v0.7_bak/xdg-shell-protocol.h @@ -0,0 +1,2374 @@ +/* Generated by wayland-scanner 1.24.0 */ + +#ifndef XDG_SHELL_SERVER_PROTOCOL_H +#define XDG_SHELL_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_xdg_shell The xdg_shell protocol + * @section page_ifaces_xdg_shell Interfaces + * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces + * - @subpage page_iface_xdg_positioner - child surface positioner + * - @subpage page_iface_xdg_surface - desktop user interface surface base interface + * - @subpage page_iface_xdg_toplevel - toplevel surface + * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_positioner; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_wm_base; + +#ifndef XDG_WM_BASE_INTERFACE +#define XDG_WM_BASE_INTERFACE +/** + * @page page_iface_xdg_wm_base xdg_wm_base + * @section page_iface_xdg_wm_base_desc Description + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + * @section page_iface_xdg_wm_base_api API + * See @ref iface_xdg_wm_base. + */ +/** + * @defgroup iface_xdg_wm_base The xdg_wm_base interface + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + */ +extern const struct wl_interface xdg_wm_base_interface; +#endif +#ifndef XDG_POSITIONER_INTERFACE +#define XDG_POSITIONER_INTERFACE +/** + * @page page_iface_xdg_positioner xdg_positioner + * @section page_iface_xdg_positioner_desc Description + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + * @section page_iface_xdg_positioner_api API + * See @ref iface_xdg_positioner. + */ +/** + * @defgroup iface_xdg_positioner The xdg_positioner interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + */ +extern const struct wl_interface xdg_positioner_interface; +#endif +#ifndef XDG_SURFACE_INTERFACE +#define XDG_SURFACE_INTERFACE +/** + * @page page_iface_xdg_surface xdg_surface + * @section page_iface_xdg_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + * @section page_iface_xdg_surface_api API + * See @ref iface_xdg_surface. + */ +/** + * @defgroup iface_xdg_surface The xdg_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + */ +extern const struct wl_interface xdg_surface_interface; +#endif +#ifndef XDG_TOPLEVEL_INTERFACE +#define XDG_TOPLEVEL_INTERFACE +/** + * @page page_iface_xdg_toplevel xdg_toplevel + * @section page_iface_xdg_toplevel_desc Description + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * A xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + * @section page_iface_xdg_toplevel_api API + * See @ref iface_xdg_toplevel. + */ +/** + * @defgroup iface_xdg_toplevel The xdg_toplevel interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * A xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + */ +extern const struct wl_interface xdg_toplevel_interface; +#endif +#ifndef XDG_POPUP_INTERFACE +#define XDG_POPUP_INTERFACE +/** + * @page page_iface_xdg_popup xdg_popup + * @section page_iface_xdg_popup_desc Description + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_xdg_popup_api API + * See @ref iface_xdg_popup. + */ +/** + * @defgroup iface_xdg_popup The xdg_popup interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + */ +extern const struct wl_interface xdg_popup_interface; +#endif + +#ifndef XDG_WM_BASE_ERROR_ENUM +#define XDG_WM_BASE_ERROR_ENUM +enum xdg_wm_base_error { + /** + * given wl_surface has another role + */ + XDG_WM_BASE_ERROR_ROLE = 0, + /** + * xdg_wm_base was destroyed before children + */ + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + /** + * the client provided an invalid positioner + */ + XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, + /** + * the client didn’t respond to a ping event in time + */ + XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, +}; +#endif /* XDG_WM_BASE_ERROR_ENUM */ + +#ifndef XDG_WM_BASE_ERROR_ENUM_IS_VALID +#define XDG_WM_BASE_ERROR_ENUM_IS_VALID +/** + * @ingroup iface_xdg_wm_base + * Validate a xdg_wm_base error value. + * + * @return true on success, false on error. + * @ref xdg_wm_base_error + */ +static inline bool +xdg_wm_base_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_WM_BASE_ERROR_ROLE: + return version >= 1; + case XDG_WM_BASE_ERROR_DEFUNCT_SURFACES: + return version >= 1; + case XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP: + return version >= 1; + case XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT: + return version >= 1; + case XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE: + return version >= 1; + case XDG_WM_BASE_ERROR_INVALID_POSITIONER: + return version >= 1; + case XDG_WM_BASE_ERROR_UNRESPONSIVE: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_WM_BASE_ERROR_ENUM_IS_VALID */ + +/** + * @ingroup iface_xdg_wm_base + * @struct xdg_wm_base_interface + */ +struct xdg_wm_base_interface { + /** + * destroy xdg_wm_base + * + * Destroy this xdg_wm_base object. + * + * Destroying a bound xdg_wm_base object while there are surfaces + * still alive created by this xdg_wm_base object instance is + * illegal and will result in a defunct_surfaces error. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * create a positioner object + * + * Create a positioner object. A positioner object is used to + * position surfaces relative to some parent surface. See the + * interface description and xdg_surface.get_popup for details. + */ + void (*create_positioner)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * create a shell surface from a surface + * + * This creates an xdg_surface for the given surface. While + * xdg_surface itself is not a role, the corresponding surface may + * only be assigned a role extending xdg_surface, such as + * xdg_toplevel or xdg_popup. It is illegal to create an + * xdg_surface for a wl_surface which already has an assigned role + * and this will result in a role error. + * + * This creates an xdg_surface for the given surface. An + * xdg_surface is used as basis to define a role to a given + * surface, such as xdg_toplevel or xdg_popup. It also manages + * functionality shared between xdg_surface based surface roles. + * + * See the documentation of xdg_surface for more details about what + * an xdg_surface is and how it is used. + */ + void (*get_xdg_surface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface); + /** + * respond to a ping event + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. See xdg_wm_base.ping and + * xdg_wm_base.error.unresponsive. + * @param serial serial of the ping event + */ + void (*pong)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); +}; + +#define XDG_WM_BASE_PING 0 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PONG_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + * Sends an ping event to the client owning the resource. + * @param resource_ The client's resource + * @param serial pass this to the pong request + */ +static inline void +xdg_wm_base_send_ping(struct wl_resource *resource_, uint32_t serial) +{ + wl_resource_post_event(resource_, XDG_WM_BASE_PING, serial); +} + +#ifndef XDG_POSITIONER_ERROR_ENUM +#define XDG_POSITIONER_ERROR_ENUM +enum xdg_positioner_error { + /** + * invalid input provided + */ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; +#endif /* XDG_POSITIONER_ERROR_ENUM */ + +#ifndef XDG_POSITIONER_ERROR_ENUM_IS_VALID +#define XDG_POSITIONER_ERROR_ENUM_IS_VALID +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner error value. + * + * @return true on success, false on error. + * @ref xdg_positioner_error + */ +static inline bool +xdg_positioner_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POSITIONER_ERROR_INVALID_INPUT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POSITIONER_ERROR_ENUM_IS_VALID */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM +#define XDG_POSITIONER_ANCHOR_ENUM +enum xdg_positioner_anchor { + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_ANCHOR_ENUM */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM_IS_VALID +#define XDG_POSITIONER_ANCHOR_ENUM_IS_VALID +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner anchor value. + * + * @return true on success, false on error. + * @ref xdg_positioner_anchor + */ +static inline bool +xdg_positioner_anchor_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POSITIONER_ANCHOR_NONE: + return version >= 1; + case XDG_POSITIONER_ANCHOR_TOP: + return version >= 1; + case XDG_POSITIONER_ANCHOR_BOTTOM: + return version >= 1; + case XDG_POSITIONER_ANCHOR_LEFT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_RIGHT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POSITIONER_ANCHOR_ENUM_IS_VALID */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM +#define XDG_POSITIONER_GRAVITY_ENUM +enum xdg_positioner_gravity { + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_GRAVITY_ENUM */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM_IS_VALID +#define XDG_POSITIONER_GRAVITY_ENUM_IS_VALID +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner gravity value. + * + * @return true on success, false on error. + * @ref xdg_positioner_gravity + */ +static inline bool +xdg_positioner_gravity_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POSITIONER_GRAVITY_NONE: + return version >= 1; + case XDG_POSITIONER_GRAVITY_TOP: + return version >= 1; + case XDG_POSITIONER_GRAVITY_BOTTOM: + return version >= 1; + case XDG_POSITIONER_GRAVITY_LEFT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_RIGHT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POSITIONER_GRAVITY_ENUM_IS_VALID */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_xdg_positioner + * constraint adjustments + * + * The constraint adjustment value define ways the compositor will adjust + * the position of the surface, if the unadjusted position would result + * in the surface being partly constrained. + * + * Whether a surface is considered 'constrained' is left to the compositor + * to determine. For example, the surface may be partly outside the + * compositor's defined 'work area', thus necessitating the child surface's + * position be adjusted until it is entirely inside the work area. + * + * The adjustments can be combined, according to a defined precedence: 1) + * Flip, 2) Slide, 3) Resize. + */ +enum xdg_positioner_constraint_adjustment { + /** + * don't move the child surface when constrained + * + * Don't alter the surface position even if it is constrained on + * some axis, for example partially outside the edge of an output. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, + /** + * move along the x axis until unconstrained + * + * Slide the surface along the x axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the x + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the x axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + /** + * move along the y axis until unconstrained + * + * Slide the surface along the y axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the y + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the y axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + /** + * invert the anchor and gravity on the x axis + * + * Invert the anchor and gravity on the x axis if the surface is + * constrained on the x axis. For example, if the left edge of the + * surface is constrained, the gravity is 'left' and the anchor is + * 'left', change the gravity to 'right' and the anchor to 'right'. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_x adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + /** + * invert the anchor and gravity on the y axis + * + * Invert the anchor and gravity on the y axis if the surface is + * constrained on the y axis. For example, if the bottom edge of + * the surface is constrained, the gravity is 'bottom' and the + * anchor is 'bottom', change the gravity to 'top' and the anchor + * to 'top'. + * + * The adjusted position is calculated given the original anchor + * rectangle and offset, but with the new flipped anchor and + * gravity values. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_y adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + /** + * horizontally resize the surface + * + * Resize the surface horizontally so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + /** + * vertically resize the surface + * + * Resize the surface vertically so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; +#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM_IS_VALID +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM_IS_VALID +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner constraint_adjustment value. + * + * @return true on success, false on error. + * @ref xdg_positioner_constraint_adjustment + */ +static inline bool +xdg_positioner_constraint_adjustment_is_valid(uint32_t value, uint32_t version) { + uint32_t valid = 0; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y; + return (value & ~valid) == 0; +} +#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM_IS_VALID */ + +/** + * @ingroup iface_xdg_positioner + * @struct xdg_positioner_interface + */ +struct xdg_positioner_interface { + /** + * destroy the xdg_positioner object + * + * Notify the compositor that the xdg_positioner will no longer + * be used. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the size of the to-be positioned rectangle + * + * Set the size of the surface that is to be positioned with the + * positioner object. The size is in surface-local coordinates and + * corresponds to the window geometry. See + * xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is + * raised. + * @param width width of positioned rectangle + * @param height height of positioned rectangle + */ + void (*set_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height); + /** + * set the anchor rectangle within the parent surface + * + * Specify the anchor rectangle within the parent surface that + * the child surface will be placed relative to. The rectangle is + * relative to the window geometry as defined by + * xdg_surface.set_window_geometry of the parent surface. + * + * When the xdg_positioner object is used to position a child + * surface, the anchor rectangle may not extend outside the window + * geometry of the positioned child's parent surface. + * + * If a negative size is set the invalid_input error is raised. + * @param x x position of anchor rectangle + * @param y y position of anchor rectangle + * @param width width of anchor rectangle + * @param height height of anchor rectangle + */ + void (*set_anchor_rect)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * set anchor rectangle anchor + * + * Defines the anchor point for the anchor rectangle. The + * specified anchor is used derive an anchor point that the child + * surface will be positioned relative to. If a corner anchor is + * set (e.g. 'top_left' or 'bottom_right'), the anchor point will + * be at the specified corner; otherwise, the derived anchor point + * will be centered on the specified edge, or in the center of the + * anchor rectangle if no edge is specified. + * @param anchor anchor + */ + void (*set_anchor)(struct wl_client *client, + struct wl_resource *resource, + uint32_t anchor); + /** + * set child surface gravity + * + * Defines in what direction a surface should be positioned, + * relative to the anchor point of the parent surface. If a corner + * gravity is specified (e.g. 'bottom_right' or 'top_left'), then + * the child surface will be placed towards the specified gravity; + * otherwise, the child surface will be centered over the anchor + * point on any axis that had no gravity specified. If the gravity + * is not in the ‘gravity’ enum, an invalid_input error is + * raised. + * @param gravity gravity direction + */ + void (*set_gravity)(struct wl_client *client, + struct wl_resource *resource, + uint32_t gravity); + /** + * set the adjustment to be done when constrained + * + * Specify how the window should be positioned if the originally + * intended position caused the surface to be constrained, meaning + * at least partially outside positioning boundaries set by the + * compositor. The adjustment is set by constructing a bitmask + * describing the adjustment to be made when the surface is + * constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that + * the child surface should not change its position on that axis + * when constrained. + * + * If more than one bit for one axis is set, the order of how + * adjustments are applied is specified in the corresponding + * adjustment descriptions. + * + * The default adjustment is none. + * @param constraint_adjustment bit mask of constraint adjustments + */ + void (*set_constraint_adjustment)(struct wl_client *client, + struct wl_resource *resource, + uint32_t constraint_adjustment); + /** + * set surface position offset + * + * Specify the surface position offset relative to the position + * of the anchor on the anchor rectangle and the anchor on the + * surface. For example if the anchor of the anchor rectangle is at + * (x, y), the surface has the gravity bottom|right, and the offset + * is (ox, oy), the calculated surface position will be (x + ox, y + * + oy). The offset position of the surface is the one used for + * constraint testing. See set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user + * interface element, while aligning the user interface element of + * the parent surface with some user interface element placed + * somewhere in the popup surface. + * @param x surface position x offset + * @param y surface position y offset + */ + void (*set_offset)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y); + /** + * continuously reconstrain the surface + * + * When set reactive, the surface is reconstrained if the + * conditions used for constraining changed, e.g. the parent window + * moved. + * + * If the conditions changed and the popup was reconstrained, an + * xdg_popup.configure event is sent with updated geometry, + * followed by an xdg_surface.configure event. + * @since 3 + */ + void (*set_reactive)(struct wl_client *client, + struct wl_resource *resource); + /** + * + * + * Set the parent window geometry the compositor should use when + * positioning the popup. The compositor may use this information + * to determine the future state the popup should be constrained + * using. If this doesn't match the dimension of the parent the + * popup is eventually positioned against, the behavior is + * undefined. + * + * The arguments are given in the surface-local coordinate space. + * @param parent_width future window geometry width of parent + * @param parent_height future window geometry height of parent + * @since 3 + */ + void (*set_parent_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t parent_width, + int32_t parent_height); + /** + * set parent configure this is a response to + * + * Set the serial of an xdg_surface.configure event this + * positioner will be used in response to. The compositor may use + * this information together with set_parent_size to determine what + * future state the popup should be constrained using. + * @param serial serial of parent configure event + * @since 3 + */ + void (*set_parent_configure)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); +}; + + +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 + +#ifndef XDG_SURFACE_ERROR_ENUM +#define XDG_SURFACE_ERROR_ENUM +enum xdg_surface_error { + /** + * Surface was not fully constructed + */ + XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, + /** + * Surface was already constructed + */ + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, + /** + * Attaching a buffer to an unconfigured surface + */ + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, + /** + * Invalid serial number when acking a configure event + */ + XDG_SURFACE_ERROR_INVALID_SERIAL = 4, + /** + * Width or height was zero or negative + */ + XDG_SURFACE_ERROR_INVALID_SIZE = 5, + /** + * Surface was destroyed before its role object + */ + XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, +}; +#endif /* XDG_SURFACE_ERROR_ENUM */ + +#ifndef XDG_SURFACE_ERROR_ENUM_IS_VALID +#define XDG_SURFACE_ERROR_ENUM_IS_VALID +/** + * @ingroup iface_xdg_surface + * Validate a xdg_surface error value. + * + * @return true on success, false on error. + * @ref xdg_surface_error + */ +static inline bool +xdg_surface_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_SURFACE_ERROR_NOT_CONSTRUCTED: + return version >= 1; + case XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED: + return version >= 1; + case XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER: + return version >= 1; + case XDG_SURFACE_ERROR_INVALID_SERIAL: + return version >= 1; + case XDG_SURFACE_ERROR_INVALID_SIZE: + return version >= 1; + case XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_SURFACE_ERROR_ENUM_IS_VALID */ + +/** + * @ingroup iface_xdg_surface + * @struct xdg_surface_interface + */ +struct xdg_surface_interface { + /** + * destroy the xdg_surface + * + * Destroy the xdg_surface object. An xdg_surface must only be + * destroyed after its role object has been destroyed, otherwise a + * defunct_role_object error is raised. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * assign the xdg_toplevel surface role + * + * This creates an xdg_toplevel object for the given xdg_surface + * and gives the associated wl_surface the xdg_toplevel role. + * + * See the documentation of xdg_toplevel for more details about + * what an xdg_toplevel is and how it is used. + */ + void (*get_toplevel)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * assign the xdg_popup surface role + * + * This creates an xdg_popup object for the given xdg_surface and + * gives the associated wl_surface the xdg_popup role. + * + * If null is passed as a parent, a parent surface must be + * specified using some other protocol, before committing the + * initial state. + * + * See the documentation of xdg_popup for more details about what + * an xdg_popup is and how it is used. + */ + void (*get_popup)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *parent, + struct wl_resource *positioner); + /** + * set the new window geometry + * + * The window geometry of a surface is its "visible bounds" from + * the user's perspective. Client-side decorations often have + * invisible portions like drop-shadows which should be ignored for + * the purposes of aligning, placing and constraining windows. Note + * that in some situations, compositors may clip rendering to the + * window geometry, so the client should avoid putting functional + * elements outside of it. + * + * The window geometry is double-buffered state, see + * wl_surface.commit. + * + * When maintaining a position, the compositor should treat the (x, + * y) coordinate of the window geometry as the top left corner of + * the window. A client changing the (x, y) window geometry + * coordinate should in general not alter the position of the + * window. + * + * Once the window geometry of the surface is set, it is not + * possible to unset it, and it will remain the same until + * set_window_geometry is called again, even if a new subsurface or + * buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * commit. This unset is meant for extremely simple clients. + * + * The arguments are given in the surface-local coordinate space of + * the wl_surface associated with this xdg_surface, and may extend + * outside of the wl_surface itself to mark parts of the subsurface + * tree as part of the window geometry. + * + * When applied, the effective window geometry will be the set + * window geometry clamped to the bounding rectangle of the + * combined geometry of the surface of the xdg_surface and the + * associated subsurfaces. + * + * The effective geometry will not be recalculated unless a new + * call to set_window_geometry is done and the new pending surface + * state is subsequently applied. + * + * The width and height of the effective window geometry must be + * greater than zero. Setting an invalid size will raise an + * invalid_size error. + */ + void (*set_window_geometry)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * ack a configure event + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client must + * make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use + * this information to move a surface to the top left only when the + * client has drawn itself for the maximized or fullscreen state. + * + * If the client receives multiple configure events before it can + * respond to one, it only has to ack the last configure event. + * Acking a configure event that was never sent raises an + * invalid_serial error. + * + * A client is not required to commit immediately after sending an + * ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before + * committing, but only the last request sent before a commit + * indicates which configure event the client really is responding + * to. + * + * Sending an ack_configure request consumes the serial number sent + * with the request, as well as serial numbers sent by all + * configure events sent on this xdg_surface prior to the configure + * event referenced by the committed serial. + * + * It is an error to issue multiple ack_configure requests + * referencing a serial from the same configure event, or to issue + * an ack_configure request referencing a serial from a configure + * event issued before the event identified by the last + * ack_configure request for the same xdg_surface. Doing so will + * raise an invalid_serial error. + * @param serial the serial from the configure event + */ + void (*ack_configure)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); +}; + +#define XDG_SURFACE_CONFIGURE 0 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial of the configure event + */ +static inline void +xdg_surface_send_configure(struct wl_resource *resource_, uint32_t serial) +{ + wl_resource_post_event(resource_, XDG_SURFACE_CONFIGURE, serial); +} + +#ifndef XDG_TOPLEVEL_ERROR_ENUM +#define XDG_TOPLEVEL_ERROR_ENUM +enum xdg_toplevel_error { + /** + * provided value is not a valid variant of the resize_edge enum + */ + XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, + /** + * invalid parent toplevel + */ + XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, + /** + * client provided an invalid min or max size + */ + XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, +}; +#endif /* XDG_TOPLEVEL_ERROR_ENUM */ + +#ifndef XDG_TOPLEVEL_ERROR_ENUM_IS_VALID +#define XDG_TOPLEVEL_ERROR_ENUM_IS_VALID +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel error value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_error + */ +static inline bool +xdg_toplevel_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE: + return version >= 1; + case XDG_TOPLEVEL_ERROR_INVALID_PARENT: + return version >= 1; + case XDG_TOPLEVEL_ERROR_INVALID_SIZE: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_ERROR_ENUM_IS_VALID */ + +#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM +#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM +/** + * @ingroup iface_xdg_toplevel + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum xdg_toplevel_resize_edge { + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ + +#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM_IS_VALID +#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM_IS_VALID +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel resize_edge value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_resize_edge + */ +static inline bool +xdg_toplevel_resize_edge_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_RESIZE_EDGE_NONE: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM_IS_VALID */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM +#define XDG_TOPLEVEL_STATE_ENUM +/** + * @ingroup iface_xdg_toplevel + * types of state on the surface + * + * The different state values used on the surface. This is designed for + * state values like maximized, fullscreen. It is paired with the + * configure event to ensure that both the client and the compositor + * setting the state can be synchronized. + * + * States set in this way are double-buffered, see wl_surface.commit. + */ +enum xdg_toplevel_state { + /** + * the surface is maximized + * the surface is maximized + * + * The surface is maximized. The window geometry specified in the + * configure event must be obeyed by the client, or the + * xdg_wm_base.invalid_surface_state error is raised. + * + * The client should draw without shadow or other decoration + * outside of the window geometry. + */ + XDG_TOPLEVEL_STATE_MAXIMIZED = 1, + /** + * the surface is fullscreen + * the surface is fullscreen + * + * The surface is fullscreen. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. For a surface to cover the whole fullscreened area, + * the geometry dimensions must be obeyed by the client. For more + * details, see xdg_toplevel.set_fullscreen. + */ + XDG_TOPLEVEL_STATE_FULLSCREEN = 2, + /** + * the surface is being resized + * the surface is being resized + * + * The surface is being resized. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. Clients that have aspect ratio or cell sizing + * configuration can use a smaller size, however. + */ + XDG_TOPLEVEL_STATE_RESIZING = 3, + /** + * the surface is now activated + * the surface is now activated + * + * Client window decorations should be painted as if the window + * is active. Do not assume this means that the window actually has + * keyboard or pointer focus. + */ + XDG_TOPLEVEL_STATE_ACTIVATED = 4, + /** + * the surface’s left edge is tiled + * + * The window is currently in a tiled layout and the left edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the left edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_LEFT = 5, + /** + * the surface’s right edge is tiled + * + * The window is currently in a tiled layout and the right edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the right edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, + /** + * the surface’s top edge is tiled + * + * The window is currently in a tiled layout and the top edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the top edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_TOP = 7, + /** + * the surface’s bottom edge is tiled + * + * The window is currently in a tiled layout and the bottom edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the bottom edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, + /** + * surface repaint is suspended + * + * The surface is currently not ordinarily being repainted; for + * example because its content is occluded by another window, or + * its outputs are switched off due to screen locking. + * @since 6 + */ + XDG_TOPLEVEL_STATE_SUSPENDED = 9, + /** + * the surface’s left edge is constrained + * + * The left edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT = 10, + /** + * the surface’s right edge is constrained + * + * The right edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT = 11, + /** + * the surface’s top edge is constrained + * + * The top edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_TOP = 12, + /** + * the surface’s bottom edge is constrained + * + * The bottom edge of the window is currently constrained, + * meaning it shouldn't attempt to resize from that edge. It can + * for example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM = 13, +}; +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_TOP_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM_SINCE_VERSION 7 +#endif /* XDG_TOPLEVEL_STATE_ENUM */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM_IS_VALID +#define XDG_TOPLEVEL_STATE_ENUM_IS_VALID +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel state value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_state + */ +static inline bool +xdg_toplevel_state_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_STATE_MAXIMIZED: + return version >= 1; + case XDG_TOPLEVEL_STATE_FULLSCREEN: + return version >= 1; + case XDG_TOPLEVEL_STATE_RESIZING: + return version >= 1; + case XDG_TOPLEVEL_STATE_ACTIVATED: + return version >= 1; + case XDG_TOPLEVEL_STATE_TILED_LEFT: + return version >= 2; + case XDG_TOPLEVEL_STATE_TILED_RIGHT: + return version >= 2; + case XDG_TOPLEVEL_STATE_TILED_TOP: + return version >= 2; + case XDG_TOPLEVEL_STATE_TILED_BOTTOM: + return version >= 2; + case XDG_TOPLEVEL_STATE_SUSPENDED: + return version >= 6; + case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT: + return version >= 7; + case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT: + return version >= 7; + case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP: + return version >= 7; + case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM: + return version >= 7; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_STATE_ENUM_IS_VALID */ + +#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +enum xdg_toplevel_wm_capabilities { + /** + * show_window_menu is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, + /** + * set_maximized and unset_maximized are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, + /** + * set_fullscreen and unset_fullscreen are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, + /** + * set_minimized is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, +}; +#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */ + +#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM_IS_VALID +#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM_IS_VALID +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel wm_capabilities value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_wm_capabilities + */ +static inline bool +xdg_toplevel_wm_capabilities_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU: + return version >= 1; + case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE: + return version >= 1; + case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN: + return version >= 1; + case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM_IS_VALID */ + +/** + * @ingroup iface_xdg_toplevel + * @struct xdg_toplevel_interface + */ +struct xdg_toplevel_interface { + /** + * destroy the xdg_toplevel + * + * This request destroys the role surface and unmaps the surface; + * see "Unmapping" behavior in interface section for details. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the parent of this surface + * + * Set the "parent" of this surface. This surface should be + * stacked above the parent surface and all other ancestor + * surfaces. + * + * Parent surfaces should be set on dialogs, toolboxes, or other + * "auxiliary" surfaces, so that the parent is raised when the + * dialog is raised. + * + * Setting a null parent for a child surface unsets its parent. + * Setting a null parent for a surface which currently has no + * parent is a no-op. + * + * Only mapped surfaces can have child surfaces. Setting a parent + * which is not mapped is equivalent to setting a null parent. If a + * surface becomes unmapped, its children's parent is set to the + * parent of the now-unmapped surface. If the now-unmapped surface + * has no parent, its children's parent is unset. If the + * now-unmapped surface becomes mapped again, its parent-child + * relationship is not restored. + * + * The parent toplevel must not be one of the child toplevel's + * descendants, and the parent must be different from the child + * toplevel, otherwise the invalid_parent protocol error is raised. + */ + void (*set_parent)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent); + /** + * set surface title + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ + void (*set_title)(struct wl_client *client, + struct wl_resource *resource, + const char *title); + /** + * set application ID + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group + * multiple surfaces together, or to determine how to launch a new + * application. + * + * For D-Bus activatable applications, the app ID is used as the + * D-Bus service name. + * + * The compositor shell will try to group application surfaces + * together by their app ID. As a best practice, it is suggested to + * select app ID's that match the basename of the application's + * .desktop file. For example, "org.freedesktop.FooViewer" where + * the .desktop file is "org.freedesktop.FooViewer.desktop". + * + * Like other properties, a set_app_id request can be sent after + * the xdg_toplevel has been mapped to update the property. + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] https://standards.freedesktop.org/desktop-entry-spec/ + */ + void (*set_app_id)(struct wl_client *client, + struct wl_resource *resource, + const char *app_id); + /** + * show the window menu + * + * Clients implementing client-side decorations might want to + * show a context menu when right-clicking on the decorations, + * giving the user a menu that they can use to maximize or minimize + * the window. + * + * This request asks the compositor to pop up such a window menu at + * the given position, relative to the local surface coordinates of + * the parent surface. There are no guarantees as to what menu + * items the window menu contains, or even if a window menu will be + * drawn at all. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + * @param x the x position to pop up the window menu at + * @param y the y position to pop up the window menu at + */ + void (*show_window_menu)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial, + int32_t x, + int32_t y); + /** + * start an interactive move + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. The + * passed serial is used to determine the type of interactive move + * (touch, pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed + * serial is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, + * such as updating a pointer cursor, during the move. There is no + * guarantee that the device focus will return when the move is + * completed. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + */ + void (*move)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial); + /** + * start an interactive resize + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. The + * passed serial is used to determine the type of interactive + * resize (touch, pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the + * "resize" enum value for more details about what is required. The + * client must also acknowledge configure events using + * "ack_configure". After the resize is completed, the client will + * receive another "configure" event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is + * no guarantee that the device focus will return when the resize + * is completed. + * + * The edges parameter specifies how the surface should be resized, + * and is one of the values of the resize_edge enum. Values not + * matching a variant of the enum will cause the + * invalid_resize_edge protocol error. The compositor may use this + * information to update the surface position for example when + * dragging the top left corner. The compositor may also use this + * information to adapt its behavior, e.g. choose an appropriate + * cursor image. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + * @param edges which edge or corner is being dragged + */ + void (*resize)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial, + uint32_t edges); + /** + * set the maximum size + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor + * does not try to configure the window beyond this size. + * + * The width and height arguments are in window geometry + * coordinates. See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see + * wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. As a + * result, a client wishing to reset the maximum size to an + * unspecified state can use zero for width and height in the + * request. + * + * Requesting a maximum size to be smaller than the minimum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. + * Using strictly negative values for width or height will result + * in a invalid_size error. + */ + void (*set_max_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height); + /** + * set the minimum size + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor + * does not try to configure the window below this size. + * + * The width and height arguments are in window geometry + * coordinates. See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see + * wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. As a + * result, a client wishing to reset the minimum size to an + * unspecified state can use zero for width and height in the + * request. + * + * Requesting a minimum size to be larger than the maximum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. + * Using strictly negative values for width and height will result + * in a invalid_size error. + */ + void (*set_min_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height); + /** + * maximize the window + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the + * compositor will respond by emitting a configure event. Whether + * this configure actually sets the window maximized is subject to + * compositor policies. The client must then update its content, + * drawing in the configured state. The client must also + * acknowledge the configure when committing the new content (see + * ack_configure). + * + * It is up to the compositor to decide how and where to maximize + * the surface, for example which output and what region of the + * screen should be used. + * + * If the surface was already maximized, the compositor will still + * emit a configure event with the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no + * direct effect. It may alter the state the surface is returned to + * when unmaximized unless overridden by the compositor. + */ + void (*set_maximized)(struct wl_client *client, + struct wl_resource *resource); + /** + * unmaximize the window + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the + * compositor will respond by emitting a configure event. Whether + * this actually un-maximizes the window is subject to compositor + * policies. If available and applicable, the compositor will + * include the window geometry dimensions the window had prior to + * being maximized in the configure event. The client must then + * update its content, drawing it in the configured state. The + * client must also acknowledge the configure when committing the + * new content (see ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before + * maximizing, if applicable. + * + * If the surface was already not maximized, the compositor will + * still emit a configure event without the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no + * direct effect. It may alter the state the surface is returned to + * when unmaximized unless overridden by the compositor. + */ + void (*unset_maximized)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the window as fullscreen on an output + * + * Make the surface fullscreen. + * + * After requesting that the surface should be fullscreened, the + * compositor will respond by emitting a configure event. Whether + * the client is actually put into a fullscreen state is subject to + * compositor policies. The client must also acknowledge the + * configure when committing the new content (see ack_configure). + * + * The output passed by the request indicates the client's + * preference as to which display it should be set fullscreen on. + * If this value is NULL, it's up to the compositor to choose which + * display will be used to map this surface. + * + * If the surface doesn't cover the whole output, the compositor + * will position the surface in the center of the output and + * compensate with with border fill covering the rest of the + * output. The content of the border fill is undefined, but should + * be assumed to be in some way that attempts to blend into the + * surrounding area (e.g. solid black). + * + * If the fullscreened surface is not opaque, the compositor must + * make sure that other screen content not part of the same surface + * tree (made up of subsurfaces, popups or similarly coupled + * surfaces) are not visible below the fullscreened surface. + */ + void (*set_fullscreen)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output); + /** + * unset the window as fullscreen + * + * Make the surface no longer fullscreen. + * + * After requesting that the surface should be unfullscreened, the + * compositor will respond by emitting a configure event. Whether + * this actually removes the fullscreen state of the client is + * subject to compositor policies. + * + * Making a surface unfullscreen sets states for the surface based + * on the following: * the state(s) it may have had before becoming + * fullscreen * any state(s) decided by the compositor * any + * state(s) requested by the client while the surface was + * fullscreen + * + * The compositor may include the previous window geometry + * dimensions in the configure event, if applicable. + * + * The client must also acknowledge the configure when committing + * the new content (see ack_configure). + */ + void (*unset_fullscreen)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the window as minimized + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ + void (*set_minimized)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define XDG_TOPLEVEL_CONFIGURE 0 +#define XDG_TOPLEVEL_CLOSE 1 +#define XDG_TOPLEVEL_CONFIGURE_BOUNDS 2 +#define XDG_TOPLEVEL_WM_CAPABILITIES 3 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_toplevel + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_toplevel_send_configure(struct wl_resource *resource_, int32_t width, int32_t height, struct wl_array *states) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE, width, height, states); +} + +/** + * @ingroup iface_xdg_toplevel + * Sends an close event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_toplevel_send_close(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_CLOSE); +} + +/** + * @ingroup iface_xdg_toplevel + * Sends an configure_bounds event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_toplevel_send_configure_bounds(struct wl_resource *resource_, int32_t width, int32_t height) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE_BOUNDS, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * Sends an wm_capabilities event to the client owning the resource. + * @param resource_ The client's resource + * @param capabilities array of 32-bit capabilities + */ +static inline void +xdg_toplevel_send_wm_capabilities(struct wl_resource *resource_, struct wl_array *capabilities) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_WM_CAPABILITIES, capabilities); +} + +#ifndef XDG_POPUP_ERROR_ENUM +#define XDG_POPUP_ERROR_ENUM +enum xdg_popup_error { + /** + * tried to grab after being mapped + */ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; +#endif /* XDG_POPUP_ERROR_ENUM */ + +#ifndef XDG_POPUP_ERROR_ENUM_IS_VALID +#define XDG_POPUP_ERROR_ENUM_IS_VALID +/** + * @ingroup iface_xdg_popup + * Validate a xdg_popup error value. + * + * @return true on success, false on error. + * @ref xdg_popup_error + */ +static inline bool +xdg_popup_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POPUP_ERROR_INVALID_GRAB: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POPUP_ERROR_ENUM_IS_VALID */ + +/** + * @ingroup iface_xdg_popup + * @struct xdg_popup_interface + */ +struct xdg_popup_interface { + /** + * remove xdg_popup interface + * + * This destroys the popup. Explicitly destroying the xdg_popup + * object will also dismiss the popup, and unmap the surface. + * + * If this xdg_popup is not the "topmost" popup, the + * xdg_wm_base.not_the_topmost_popup protocol error will be sent. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * make the popup take an explicit grab + * + * This request makes the created popup take an explicit grab. An + * explicit grab will be dismissed when the user dismisses the + * popup, or when the client destroys the xdg_popup. This can be + * done by the user clicking outside the surface, using the + * keyboard, or even locking the screen through closing the lid or + * a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. The + * serial number of the event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel + * surface or another xdg_popup with an explicit grab. If the + * parent is another xdg_popup it means that the popups are nested, + * with this popup now being the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were + * created in, e.g. the only popup you are allowed to destroy at + * all times is the topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss + * every nested grabbing popup as well. When a compositor dismisses + * popups, it will follow the same dismissing order as required + * from the client. + * + * If the topmost grabbing popup is destroyed, the grab will be + * returned to the parent of the popup, if that parent previously + * had an explicit grab. + * + * If the parent is a grabbing popup which has already been + * dismissed, this popup will be immediately dismissed. If the + * parent is a popup that did not take an explicit grab, an error + * will be raised. + * + * During a popup grab, the client owning the grab will receive + * pointer and touch events for all their surfaces as normal + * (similar to an "owner-events" grab in X11 parlance), while the + * top most grabbing popup will always have keyboard focus. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + */ + void (*grab)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial); + /** + * recalculate the popup's location + * + * Reposition an already-mapped popup. The popup will be placed + * given the details in the passed xdg_positioner object, and a + * xdg_popup.repositioned followed by xdg_popup.configure and + * xdg_surface.configure will be emitted in response. Any + * parameters set by the previous positioner will be discarded. + * + * The passed token will be sent in the corresponding + * xdg_popup.repositioned event. The new popup position will not + * take effect until the corresponding configure event is + * acknowledged by the client. See xdg_popup.repositioned for + * details. The token itself is opaque, and has no other special + * meaning. + * + * If multiple reposition requests are sent, the compositor may + * skip all but the last one. + * + * If the popup is repositioned in response to a configure event + * for its parent, the client should send an + * xdg_positioner.set_parent_configure and possibly an + * xdg_positioner.set_parent_size request to allow the compositor + * to properly constrain the popup. + * + * If the popup is repositioned together with a parent that is + * being resized, but not in response to a configure event, the + * client should send an xdg_positioner.set_parent_size request. + * @param token reposition request token + * @since 3 + */ + void (*reposition)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *positioner, + uint32_t token); +}; + +#define XDG_POPUP_CONFIGURE 0 +#define XDG_POPUP_POPUP_DONE 1 +#define XDG_POPUP_REPOSITIONED 2 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_GRAB_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ +static inline void +xdg_popup_send_configure(struct wl_resource *resource_, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_resource_post_event(resource_, XDG_POPUP_CONFIGURE, x, y, width, height); +} + +/** + * @ingroup iface_xdg_popup + * Sends an popup_done event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_popup_send_popup_done(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, XDG_POPUP_POPUP_DONE); +} + +/** + * @ingroup iface_xdg_popup + * Sends an repositioned event to the client owning the resource. + * @param resource_ The client's resource + * @param token reposition request token + */ +static inline void +xdg_popup_send_repositioned(struct wl_resource *resource_, uint32_t token) +{ + wl_resource_post_event(resource_, XDG_POPUP_REPOSITIONED, token); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dwl/hide-cursor-when-typing.patch b/dwl/hide-cursor-when-typing.patch new file mode 100644 index 00000000..e87e7716 --- /dev/null +++ b/dwl/hide-cursor-when-typing.patch @@ -0,0 +1,204 @@ +From a73f5a4c7dd636d999cfab15610e68e170d2f597 Mon Sep 17 00:00:00 2001 +From: nate zhou +Date: Fri, 10 Apr 2026 19:38:43 +0800 +Subject: [PATCH] Patch: hide-cursor-when-typing-0.8.patch + +--- + config.def.h | 2 ++ + dwl.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 85 insertions(+), 7 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..6205c0a 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -102,6 +102,8 @@ LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right + */ + static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; + ++static const int hide_cursor_when_typing = 1; ++ + /* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ + #define MODKEY WLR_MODIFIER_ALT + +diff --git a/dwl.c b/dwl.c +index 44f3ad9..7325f7a 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -288,6 +288,8 @@ static void focusstack(const Arg *arg); + static Client *focustop(Monitor *m); + static void fullscreennotify(struct wl_listener *listener, void *data); + static void gpureset(struct wl_listener *listener, void *data); ++static void handlecursoractivity(void); ++static int hidecursor(void *data); + static void handlesig(int signo); + static void incnmaster(const Arg *arg); + static void inputdevice(struct wl_listener *listener, void *data); +@@ -389,6 +391,14 @@ static struct wlr_pointer_constraint_v1 *active_constraint; + + static struct wlr_cursor *cursor; + static struct wlr_xcursor_manager *cursor_mgr; ++static bool cursor_hidden = false; ++static struct { ++ enum wp_cursor_shape_device_v1_shape shape; ++ struct wlr_surface *surface; ++ int hotspot_x; ++ int hotspot_y; ++ struct wl_listener destroy; ++} last_cursor; + + static struct wlr_scene_rect *root_bg; + static struct wlr_session_lock_manager_v1 *session_lock_mgr; +@@ -610,6 +620,7 @@ axisnotify(struct wl_listener *listener, void *data) + * for example when you move the scroll wheel. */ + struct wlr_pointer_axis_event *event = data; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++ handlecursoractivity(); + /* TODO: allow usage of scroll wheel for mousebindings, it can be implemented + * by checking the event's orientation and the delta of the event */ + /* Notify the client with pointer focus of the axis event. */ +@@ -628,6 +639,7 @@ buttonpress(struct wl_listener *listener, void *data) + const Button *b; + + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++ handlecursoractivity(); + + switch (event->state) { + case WL_POINTER_BUTTON_STATE_PRESSED: +@@ -1566,6 +1578,33 @@ handlesig(int signo) + quit(NULL); + } + ++void ++handlecursoractivity(void) ++{ ++ if (!cursor_hidden) ++ return; ++ ++ cursor_hidden = false; ++ ++ if (last_cursor.shape) { ++ wlr_cursor_set_xcursor(cursor, cursor_mgr, ++ wlr_cursor_shape_v1_name(last_cursor.shape)); ++ } else if (last_cursor.surface) { ++ wlr_cursor_set_surface(cursor, last_cursor.surface, ++ last_cursor.hotspot_x, last_cursor.hotspot_y); ++ } else { ++ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); ++ } ++} ++ ++int ++hidecursor(void *data) ++{ ++ wlr_cursor_unset_image(cursor); ++ cursor_hidden = true; ++ return 1; ++} ++ + void + incnmaster(const Arg *arg) + { +@@ -1645,6 +1684,11 @@ keypress(struct wl_listener *listener, void *data) + + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + ++ /* hide cursor when typing starts */ ++ if (hide_cursor_when_typing && !cursor_hidden && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { ++ hidecursor(NULL); ++ } ++ + /* On _press_ if there is no active screen locker, + * attempt to process a compositor keybinding. */ + if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { +@@ -1907,6 +1951,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d + + wlr_cursor_move(cursor, device, dx, dy); + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++ handlecursoractivity(); + + /* Update selmon (even while dragging a window) */ + if (sloppyfocus) +@@ -1931,7 +1976,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d + /* If there's no client surface under the cursor, set the cursor image to a + * default. This is what makes the cursor image appear when you move it + * off of a client or over its border. */ +- if (!surface && !seat->drag) ++ if (!surface && !seat->drag && !cursor_hidden) + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + + pointerfocus(c, surface, sx, sy, time); +@@ -2296,6 +2341,15 @@ run(char *startup_cmd) + wl_display_run(dpy); + } + ++void ++unlastcursor(struct wl_listener *listener, void *data) ++{ ++ /* When the surface is destroyed, clear our reference to it */ ++ last_cursor.surface = NULL; ++ wl_list_remove(&last_cursor.destroy.link); ++ wl_list_init(&last_cursor.destroy.link); ++} ++ + void + setcursor(struct wl_listener *listener, void *data) + { +@@ -2311,9 +2365,23 @@ setcursor(struct wl_listener *listener, void *data) + * use the provided surface as the cursor image. It will set the + * hardware cursor on the output that it's currently on and continue to + * do so as the cursor moves between outputs. */ +- if (event->seat_client == seat->pointer_state.focused_client) +- wlr_cursor_set_surface(cursor, event->surface, +- event->hotspot_x, event->hotspot_y); ++ if (event->seat_client == seat->pointer_state.focused_client) { ++ last_cursor.shape = 0; ++ last_cursor.surface = event->surface; ++ last_cursor.hotspot_x = event->hotspot_x; ++ last_cursor.hotspot_y = event->hotspot_y; ++ ++ wl_list_remove(&last_cursor.destroy.link); ++ wl_list_init(&last_cursor.destroy.link); ++ if (event->surface) { ++ last_cursor.destroy.notify = unlastcursor; ++ wl_signal_add(&event->surface->events.destroy, &last_cursor.destroy); ++ } ++ ++ if (!cursor_hidden) ++ wlr_cursor_set_surface(cursor, event->surface, ++ event->hotspot_x, event->hotspot_y); ++ } + } + + void +@@ -2325,9 +2393,14 @@ setcursorshape(struct wl_listener *listener, void *data) + /* This can be sent by any client, so we check to make sure this one + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided cursor shape. */ +- if (event->seat_client == seat->pointer_state.focused_client) +- wlr_cursor_set_xcursor(cursor, cursor_mgr, +- wlr_cursor_shape_v1_name(event->shape)); ++ if (event->seat_client == seat->pointer_state.focused_client) { ++ last_cursor.shape = event->shape; ++ last_cursor.surface = NULL; ++ ++ if (!cursor_hidden) ++ wlr_cursor_set_xcursor(cursor, cursor_mgr, ++ wlr_cursor_shape_v1_name(event->shape)); ++ } + } + + void +@@ -2592,6 +2665,9 @@ setup(void) + cursor = wlr_cursor_create(); + wlr_cursor_attach_output_layout(cursor, output_layout); + ++ /* Initialize the last_cursor destroy listener link so it's safe to remove later */ ++ wl_list_init(&last_cursor.destroy.link); ++ + /* Creates an xcursor manager, another wlroots utility which loads up + * Xcursor themes to source cursor images from and makes sure that cursor + * images are available at all scale factors on the screen (necessary for +-- +2.53.0 +