From 231ba42142a887c61192bf1179a1f2f535b98485 Mon Sep 17 00:00:00 2001 From: tomit4 Date: Sun, 7 Jun 2026 08:27:18 -0700 Subject: [PATCH] :wrench: Started working on dwl migration --- dwl/autostart-0.8.patch | 141 + dwl/config.h | 263 ++ dwl/dwl-v0.7.tar.gz | Bin 0 -> 63510 bytes dwl/dwl-v0.7/CHANGELOG.md | 200 + dwl/dwl-v0.7/LICENSE | 692 ++++ dwl/dwl-v0.7/LICENSE.dwm | 39 + dwl/dwl-v0.7/LICENSE.sway | 19 + dwl/dwl-v0.7/LICENSE.tinywl | 127 + dwl/dwl-v0.7/Makefile | 78 + dwl/dwl-v0.7/README.md | 201 + dwl/dwl-v0.7/client.h | 420 +++ dwl/dwl-v0.7/config.def.h | 263 ++ dwl/dwl-v0.7/config.h | 263 ++ dwl/dwl-v0.7/config.mk | 17 + dwl/dwl-v0.7/cursor-shape-v1-protocol.h | 201 + dwl/dwl-v0.7/dwl | Bin 0 -> 268792 bytes dwl/dwl-v0.7/dwl.1 | 158 + dwl/dwl-v0.7/dwl.c | 3285 +++++++++++++++++ dwl/dwl-v0.7/dwl.c.orig | 3215 ++++++++++++++++ dwl/dwl-v0.7/dwl.desktop | 5 + dwl/dwl-v0.7/dwl.o | Bin 0 -> 299536 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/swallow.patch | 350 ++ dwl/dwl-v0.7/util.c | 51 + dwl/dwl-v0.7/util.h | 5 + dwl/dwl-v0.7/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/xdg-shell-protocol.h | 2374 ++++++++++++ dwl/swallow.patch | 350 ++ .../package.accept_keywords/package.unmask | 1 + zshrc.txt | 14 +- 34 files changed, 13774 insertions(+), 1 deletion(-) create mode 100644 dwl/autostart-0.8.patch create mode 100644 dwl/config.h create mode 100644 dwl/dwl-v0.7.tar.gz create mode 100644 dwl/dwl-v0.7/CHANGELOG.md create mode 100644 dwl/dwl-v0.7/LICENSE create mode 100644 dwl/dwl-v0.7/LICENSE.dwm create mode 100644 dwl/dwl-v0.7/LICENSE.sway create mode 100644 dwl/dwl-v0.7/LICENSE.tinywl create mode 100644 dwl/dwl-v0.7/Makefile create mode 100644 dwl/dwl-v0.7/README.md create mode 100644 dwl/dwl-v0.7/client.h create mode 100644 dwl/dwl-v0.7/config.def.h create mode 100644 dwl/dwl-v0.7/config.h create mode 100644 dwl/dwl-v0.7/config.mk create mode 100644 dwl/dwl-v0.7/cursor-shape-v1-protocol.h create mode 100755 dwl/dwl-v0.7/dwl create mode 100644 dwl/dwl-v0.7/dwl.1 create mode 100644 dwl/dwl-v0.7/dwl.c create mode 100644 dwl/dwl-v0.7/dwl.c.orig create mode 100644 dwl/dwl-v0.7/dwl.desktop create mode 100644 dwl/dwl-v0.7/dwl.o create mode 100644 dwl/dwl-v0.7/pointer-constraints-unstable-v1-protocol.h create mode 100644 dwl/dwl-v0.7/protocols/wlr-layer-shell-unstable-v1.xml create mode 100644 dwl/dwl-v0.7/protocols/wlr-output-power-management-unstable-v1.xml create mode 100644 dwl/dwl-v0.7/swallow.patch create mode 100644 dwl/dwl-v0.7/util.c create mode 100644 dwl/dwl-v0.7/util.h create mode 100644 dwl/dwl-v0.7/util.o create mode 100644 dwl/dwl-v0.7/wlr-layer-shell-unstable-v1-protocol.h create mode 100644 dwl/dwl-v0.7/wlr-output-power-management-unstable-v1-protocol.h create mode 100644 dwl/dwl-v0.7/xdg-shell-protocol.h create mode 100644 dwl/swallow.patch diff --git a/dwl/autostart-0.8.patch b/dwl/autostart-0.8.patch new file mode 100644 index 00000000..a1ce9ac9 --- /dev/null +++ b/dwl/autostart-0.8.patch @@ -0,0 +1,141 @@ +From d2e2e61aeb25ad71c2c559994968ba64e0974503 Mon Sep 17 00:00:00 2001 +From: A Frederick Christensen +Date: Fri, 27 Feb 2026 12:23:04 -0600 +Subject: [PATCH] Applied autostart patch + +--- + config.def.h | 6 ++++++ + dwl.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 61 insertions(+), 3 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..6eb0db4 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -20,6 +20,12 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca + /* logging */ + static int log_level = WLR_ERROR; + ++/* Autostart */ ++static const char *const autostart[] = { ++ "wbg", "/path/to/your/image", NULL, ++ NULL /* terminate */ ++}; ++ + 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 */ +diff --git a/dwl.c b/dwl.c +index 44f3ad9..e7b6199 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -246,6 +246,7 @@ 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); +@@ -449,6 +450,9 @@ static struct wl_listener xwayland_ready = {.notify = xwaylandready}; + static struct wlr_xwayland *xwayland; + #endif + ++static pid_t *autostart_pids; ++static size_t autostart_len; ++ + /* configuration, allows nested code to access above variables */ + #include "config.h" + +@@ -603,6 +607,27 @@ arrangelayers(Monitor *m) + } + } + ++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) + { +@@ -699,12 +724,23 @@ checkidleinhibitor(struct wlr_surface *exclude) + void + cleanup(void) + { ++ size_t i; ++ + cleanuplisteners(); + #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); +@@ -1560,10 +1596,25 @@ gpureset(struct wl_listener *listener, void *data) + void + handlesig(int signo) + { +- if (signo == SIGCHLD) +- while (waitpid(-1, NULL, WNOHANG) > 0); +- else if (signo == SIGINT || signo == SIGTERM) ++ 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 +@@ -2250,6 +2301,7 @@ run(char *startup_cmd) + 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) +-- +2.52.0 + diff --git a/dwl/config.h b/dwl/config.h new file mode 100644 index 00000000..69bca091 --- /dev/null +++ b/dwl/config.h @@ -0,0 +1,263 @@ +/* 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; + +/* 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 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.05f}}, + {MODKEY, XKB_KEY_Right, setmfact, {.f = +0.05f}}, + {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.tar.gz b/dwl/dwl-v0.7.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..d7dfc2dcb4a47b1002a3a11173c289d9c3669eef GIT binary patch literal 63510 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 literal 0 HcmV?d00001 diff --git a/dwl/dwl-v0.7/CHANGELOG.md b/dwl/dwl-v0.7/CHANGELOG.md new file mode 100644 index 00000000..3a299c46 --- /dev/null +++ b/dwl/dwl-v0.7/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/LICENSE b/dwl/dwl-v0.7/LICENSE new file mode 100644 index 00000000..658085a4 --- /dev/null +++ b/dwl/dwl-v0.7/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/LICENSE.dwm b/dwl/dwl-v0.7/LICENSE.dwm new file mode 100644 index 00000000..507e4dce --- /dev/null +++ b/dwl/dwl-v0.7/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/LICENSE.sway b/dwl/dwl-v0.7/LICENSE.sway new file mode 100644 index 00000000..3e0cacc2 --- /dev/null +++ b/dwl/dwl-v0.7/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/LICENSE.tinywl b/dwl/dwl-v0.7/LICENSE.tinywl new file mode 100644 index 00000000..70236904 --- /dev/null +++ b/dwl/dwl-v0.7/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/Makefile b/dwl/dwl-v0.7/Makefile new file mode 100644 index 00000000..3358bae9 --- /dev/null +++ b/dwl/dwl-v0.7/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/README.md b/dwl/dwl-v0.7/README.md new file mode 100644 index 00000000..aa95baba --- /dev/null +++ b/dwl/dwl-v0.7/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/client.h b/dwl/dwl-v0.7/client.h new file mode 100644 index 00000000..bc9cad2e --- /dev/null +++ b/dwl/dwl-v0.7/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/config.def.h b/dwl/dwl-v0.7/config.def.h new file mode 100644 index 00000000..4cc09478 --- /dev/null +++ b/dwl/dwl-v0.7/config.def.h @@ -0,0 +1,263 @@ +/* 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; + +/* 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 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), + + /* 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/config.h b/dwl/dwl-v0.7/config.h new file mode 100644 index 00000000..4cc09478 --- /dev/null +++ b/dwl/dwl-v0.7/config.h @@ -0,0 +1,263 @@ +/* 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; + +/* 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 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), + + /* 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/config.mk b/dwl/dwl-v0.7/config.mk new file mode 100644 index 00000000..b2d0221b --- /dev/null +++ b/dwl/dwl-v0.7/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/cursor-shape-v1-protocol.h b/dwl/dwl-v0.7/cursor-shape-v1-protocol.h new file mode 100644 index 00000000..e49c7f52 --- /dev/null +++ b/dwl/dwl-v0.7/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/dwl b/dwl/dwl-v0.7/dwl new file mode 100755 index 0000000000000000000000000000000000000000..54583c55d1a7ec505a1b2690f86a7cac2be42e95 GIT binary patch literal 268792 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%0D38{YDQe3bYcNeLLPcvm34K*v3>;Hm7hh|J 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 literal 0 HcmV?d00001 diff --git a/dwl/dwl-v0.7/dwl.1 b/dwl/dwl-v0.7/dwl.1 new file mode 100644 index 00000000..780c78f4 --- /dev/null +++ b/dwl/dwl-v0.7/dwl.1 @@ -0,0 +1,158 @@ +.Dd January 8, 2021 +.Dt DWL 1 +.Os +.Sh NAME +.Nm dwl +.Nd dwm for Wayland +.Sh SYNOPSIS +.Nm +.Op Fl v +.Op Fl d +.Op Fl s Ar startup command +.Sh DESCRIPTION +.Nm +is a Wayland compositor based on wlroots. +It is intended to fill the same space in the Wayland world that +.Nm dwm +does for X11. +.Pp +When given the +.Fl v +option, +.Nm +writes its name and version to standard error and exits unsuccessfully. +.Pp +When given the +.Fl d +option, +.Nm +enables full wlroots logging, including debug information. +.Pp +When given the +.Fl s +option, +.Nm +starts a shell process running +.Ar command +when starting. +When stopping, it sends +.Dv SIGTERM +to the child process and waits for it to exit. +.Pp +Users are encouraged to customize +.Nm +by editing the sources, in particular +.Pa config.h . +The default key bindings are as follows: +.Bl -tag -width 20n -offset indent -compact +.It Mod-[1-9] +Show only all windows with a tag. +.It Mod-Ctrl-[1-9] +Show all windows with a tag. +.It Mod-Shift-[1-9] +Move window to a single tag. +.It Mod-Ctrl-Shift-[1-9] +Toggle tag for window. +.It Mod-p +Spawn +.Nm wmenu-run . +.It Mod-Shift-Return +Spawn +.Nm foot . +.It Mod-[jk] +Move focus down/up the stack. +.It Mod-[id] +Increase/decrease number of windows in master area. +.It Mod-[hl] +Decrease/increase master area. +.It Mod-Return +Move window on top of stack or switch top of stack with second window. +.It Mod-Tab +Show only all windows with previous tag. +.It Mod-Shift-c +Close window. +.It Mod-t +Switch to tabbed layout. +.It Mod-f +Switch to floating layout. +.It Mod-m +Switch to monocle layout. +.It Mod-Space +Switch to previous layout. +.It Mod-Shift-Space +Toggle floating state of window. +.It Mod-e +Toggle fullscreen state of window. +.It Mod-0 +Show all windows. +.It Mod-Shift-0 +Set all tags for window. +.It Mod-, +Move focus to previous monitor. +.It Mod-. +Move focus to next monitor. +.It Mod-Shift-, +Move window to previous monitor. +.It Mod-Shift-. +Move window to next monitor. +.It Mod-Shift-q +Quit +.Nm . +.El +These might differ depending on your keyboard layout. +.Sh ENVIRONMENT +These environment variables are used by +.Nm : +.Bl -tag -width XDG_RUNTIME_DIR +.It Ev XDG_RUNTIME_DIR +A directory where temporary user files, such as the Wayland socket, +are stored. +.It Ev XDG_CONFIG_DIR +A directory containing configuration of various programs and +libraries, including libxkbcommon. +.It Ev DISPLAY , WAYLAND_DISPLAY , WAYLAND_SOCKET +Tell how to connect to an underlying X11 or Wayland server. +.It Ev WLR_* +Various variables specific to wlroots. +.It Ev XKB_* , XLOCALEDIR , XCOMPOSEFILE +Various variables specific to libxkbcommon. +.It Ev XCURSOR_PATH +List of directories to search for XCursor themes in. +.It Ev HOME +A directory where there are always dear files there for you. +Waiting for you to clean them up. +.El +.Pp +These are set by +.Nm : +.Bl -tag -width WAYLAND_DISPLAY +.It Ev WAYLAND_DISPLAY +Tell how to connect to +.Nm . +.It Ev DISPLAY +If using +.Nm Xwayland , +tell how to connect to the +.Nm Xwayland +server. +.El +.Sh EXAMPLES +Start +.Nm +with s6 in the background: +.Dl dwl \-s \(aqs6\-svscan <&\-\(aq +.Sh SEE ALSO +.Xr foot 1 , +.Xr wmenu 1 , +.Xr dwm 1 , +.Xr xkeyboard-config 7 +.Sh CAVEATS +The child process's standard input is connected with a pipe to +.Nm . +If the child process neither reads from the pipe nor closes its +standard input, +.Nm +will freeze after a while due to it blocking when writing to the full +pipe buffer. +.Sh BUGS +All of them. diff --git a/dwl/dwl-v0.7/dwl.c b/dwl/dwl-v0.7/dwl.c new file mode 100644 index 00000000..fd2e3b2c --- /dev/null +++ b/dwl/dwl-v0.7/dwl.c @@ -0,0 +1,3285 @@ +/* + * 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]) && \ + !(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 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 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); + /* 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) { + 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 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); +} + +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 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(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 */ + 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); + + /* 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/dwl.c.orig b/dwl/dwl-v0.7/dwl.c.orig new file mode 100644 index 00000000..a2711f67 --- /dev/null +++ b/dwl/dwl-v0.7/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/dwl.desktop b/dwl/dwl-v0.7/dwl.desktop new file mode 100644 index 00000000..e1380f7a --- /dev/null +++ b/dwl/dwl-v0.7/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/dwl.o b/dwl/dwl-v0.7/dwl.o new file mode 100644 index 0000000000000000000000000000000000000000..dffbb4f6a34ecba8f61011867eeab666043800ef GIT binary patch literal 299536 zcmeFa2~<dc8&&cbyr< zeVvhU#SKA3a7RZSbsYC4F)k=BxWB5t_a--pzu*6T=X>wGbKaLDN#E}3?&|95s_N?M z>ui5{KT8V>5&y9e^%j|)_*{`Fi?%jC_>z>bsJW<_h+=H;iPF|3Ki;K^AWE%^py*2m zCrMLZC=ZUKw0*NF?=y;aROUCu3(8yNtkf|pu^VRDN-_Mj$eIb?ioYmz?l$aPdAcwc zo8!JIE!W5VoN6MGp>9@eYzIkG4MK=0b-pv@U83kff9&k|{=}DW-@Yjg-bvQV$I!Ew z%Dk-jmr_3yQ(Bedx68TMIHf)*<{B=SH2J9RMcR=p%a){fpC~OU)RB(p zJLGqiskC^W7j%b(EQEH3P5?4Alyr=(>~;Y-9>$qZc<_mAK9S2O*mfxTC7S^lj~YYz z6*QW-jndA(%K~t?QQ8@mTW4mJuprEgQV!OvQR#5$FzHa~5Yn*MYl)M!D}2da#S}f$ z)tRCdt}YZk#MLd3zA%6;k{-2%(Ne`SS4SN7G5nIVL^5=z=whx1?iVJ&5KLu0SJ7uTm<`FY0vUbxeQANNX`uR!UIXA`7(f}w9moolt>Iw@*KXrwr zqIzb&@^vn-&NsukK*rw-I|!y26`=o3F_0dwJ$lOd`jY)uz(oW`cL;(p!GZ{^CWHfmO zHh}I_UNZWrjDE+G3+5Xp(9fDttDuHOzBbrG=6zQt8Sq+0r#Q&GDRp77VkT6~q*znT z3>VTdvlsh=M~Z&UW-P@FCdC2r+`h|UMFU$&Yu$|rb!>A209hh@m+i~e4|Qxu8U;X) zJRqq^&@5K2oClq^xdsJXb&eujUqL{+>0StO%6nQ*r9F|y-ot$rHl$Try$r_#g1`lP z!h{z=4!ti4qu;*hGlYZ{%3ya2pG_${bK90Q|Qv0ldxvmY4%p z2mmjCfaON3%UHm>1n?MEHwk2lk_XA=={mul3f&Gvp_r9-iqrAhM zmCqSsElBOI+C5e0Y5-gWBExWv2wPUVe>B~V4q zTXxRhBmpY;2m+618V z{|e;K966)HJ!n(w~qz8N)IS29MUCbP~D3k;#5{`4yut*^QorDYoZS8Ry3 zRiAX^>4p=y8E6!UvQ_SVSE5P&iYi1GESM3!6!UmISiY)6-v8%Hr9|@Sj}jDm8Rru< znLv&hjXvf$G1r>E1&rqy$a?XorQtmSey1Ug%Y*)O7)U50T^Q9!63F=Q0Ma-zeV#0U`V`x=uiN94>opr^VKq@X!3~OeCSqs{<1`dVN zIxGO=I^|@nq^V3K^0rj$qtqv?AuGAuu=_X}ZGY@yG0MlhbjT2{+(K4L(7>ehs$9UF zt%217>666l;&{bm=@gMgwGKc)Mnk<9TpO%mDW{*X&ro(a3|4kteSl=Mv^K+uF!GC_ zv?;;tjOThluY7SewwQuqSgE*ja(#`(^i4peH|bU|i?p8y#iRhFFz-4MYn=UVTEhAu zpajmJdbYDjF~(#~GXajwd^hMR^YpA9xjMjt4E_BFkRZ%#RvoKnIE!XACQJ>exiDR} zq3RAVM`kaw@Sf;ATSt0g`AV?GKxSdOn<0qo!WrF;W|or}EhknWF=1i~7*9pfUnsS~ zO|Ff0wKh0G*C3z5u2UROfW_&WqTFN0_Lwi*6Vs}^URjwLy}3kPR%*x4AUvhX7{CLsunhFp9AT)X8h$0 z{G}ZNrdB^|qNf9Z-Be)&6R^A-0-2ev`Q%B8oKN(>uotF1j6(!luxe6unuCQRS_+n3 z3FcwVyM$#(^+4E9LDQx+DP;yYNSUG5QbuWpH`$yS*-w(W1=<2qx(OsRFsMUj{;Xy4 zsEWXXCzeOBJFMo&ba9pei`{zp?VFv>SF*gwS90Jvr7pA%^uD9~7d8JF;5t-H`RZJE z9i+6}wS>vR+GL1ibozb(Oj0;YroEw@X^F_m zSuzQSPqD5AB01L*{J*2E5M&_%;pBh{Y$|~z_Wi7UXHqFzP_Q*c;mj!vwhqCV=x=X> z@-DykGzx53x-8WTg^myXU|hKZPl!GWGRT@>z*=NCg}~~KP|Ovl*8xHyrGc#++5S)> z5RpIx-kfK+qy;>wah(qtz?SrrLynLtr*=}<@V2|q4DOkGQFM86Cf}}lmRJN+eF~=f z9aQ0llm=?(F-fauh((+;Cle=)V%QFhET(jz=A1+vh>#<71TGMlK>DfxIdB}HK%U2n zp_Qwk8bw>XqDuq}*|8v?Z!40(BOs;EfsFPFq#qj^#G3i1&=;W%E1|rLKq51K!D>~Q zNU{!{O|bD)-i1l>V7(vQNI?wP{8gBiLMEDr9-V5UpLrU8g`j48D$MvE-w6X zVfDFyE9X38krs*pBgxIUgLgM+@|7*Wqnaes0z?>44qM~6Bo8&WnK41pnPk@JI7hiQ zI|o4J+HGa{!_8D6D3<}=&y+9usVi1HKqK%^R7`ADHihH{Ci_;bMtRSsaO(q~KE-Mj zefYpzp#1g;HZHWf0ty(lHI%~`3bAh@UXP$*d)N^k37yL&j_l&%@M5(h&rZDG4MZTH zrM0oeCTTy=dns|w{o5i@;Ksgo9#KzkOM%=2v&^76~~BLW~Qr)X+bxJPK*L{D5bWeD#s}B0O>BHKUyu_gmnwD zGY=pCn!b(Z4IZHo5nWl-fk(O(vjPPrw1Xq0qUvOENjc+QN})+B(R_xI zylnU~$yxAQ15!BTVqEQ5e{y&Dq1CI%)86^;6UZEO75b=)`w)n90+Eu0#X^Vkfd@Dc zKi(iI0Wd;Sik=uuoa3BDPy4|3jkD)rrS}_H(1?FkiG* z$uBr?m}6wn>f-8D!4qrBia(rWlw#f<6iQakDFA{9oE&J&!9;dM>F5`Z)7{($MjY=^BIlK^SAeN1Xk#l9n76mpaTICpu^Rl3~+hl~ygacLKa1C8~ID!MWwd7G@%>?66 zRX}~tIN@D2kTs`R1zbo54IS5ir+#b+!cf==nNI0gIM(DHKX@uC(Ik=ORZObll&(ce za<&OR7gu^dUFrF3rRVdNo-bB3`5fQ;>qUPh%`V&}6)*FZ7e|Ug~ zjVgRT~6cgYBhu$ToF9Sftzi13Cp6)jBRW} zJ8>1ohbcg!l+ERaY2-)~xAASk66;WDKS06K!uSeF<$P1^|GtI>Iy1xSP|Q>i$EKBO zTsvf$4TG|7|0~5P8JJ9bIsyK2f`XBTl6v6fu;UM9Wl&TX+X&PXb^V zdK^Xf^#WlB>lIdpz&*qH;V__r1}9`cP^hc!0tdjcqzg<)nNg?E#U|Ogb3U*UvlMq? z%-$^cCRi{_ag)UCCBmNHA8Ktfn<2}o)1eFmMiK}N)_=#H4=HTeje;4zN*A2dN1|uT=QF!wm?D+@8qj#agtyqnRdhk!AJAulIL8B}f#u;La9LQ`* z@P>W`TP1JIQ=fDmRapT2qgcfFVORyb(ZkRRdz4DkVZj)5Fo_shA<>XM5*uB?Iu4Bk z0Gw?=Y8v(tSRSMYR3{)rO|!xcsca{wySVBbK`Ac=fCvMChn`58ek8gh#E8N>5H*Hp zflNOZ1)}Qs_HRNN+dlRWZ5R%NlZ(It2)j`m{qMJL`ac0MkeQ3-3__(-%rBVMFNb{C zJG()Q6a@uvP#|Pf@RN!Iy>BaZ`n`NdWOiZ0LRLMf^G{}TOkBr_6}*!04yb@|m&&38 zOi|zr?yO#tsb}W|y}2Zu2DS-~fEw@|tQugFU{KOwaS(CT2*QpWBa$E$?JDL74-O5M zs_a$+Y3m^e4=t=+G&SK7428PbTzYDRNRn9(J7W*kFq4F`$Z3{_Fn*kZd~OOPntuQS zrvdfoZsQavHsPiZG5f`c1W*0rJn5lWqEYd)kCf%`M3n61uuE{%kAPxc3kK4~aCWSC zEM)@7^bavke`kQgz603lcSWAzr@tQG0k#U$UkuZan{@(hWPnkyYV^+t1I%L?pje*@ zH3NUYmHF)SwQd74hRjZg zSU-kG&-{GNjHk�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

DX92|UNoDy0E{4jU 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 + + + 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/protocols/wlr-output-power-management-unstable-v1.xml b/dwl/dwl-v0.7/protocols/wlr-output-power-management-unstable-v1.xml new file mode 100644 index 00000000..a9778399 --- /dev/null +++ b/dwl/dwl-v0.7/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/swallow.patch b/dwl/dwl-v0.7/swallow.patch new file mode 100644 index 00000000..f9760234 --- /dev/null +++ b/dwl/dwl-v0.7/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/util.c b/dwl/dwl-v0.7/util.c new file mode 100644 index 00000000..51130af0 --- /dev/null +++ b/dwl/dwl-v0.7/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/util.h b/dwl/dwl-v0.7/util.h new file mode 100644 index 00000000..226980de --- /dev/null +++ b/dwl/dwl-v0.7/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/util.o b/dwl/dwl-v0.7/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/xdg-shell-protocol.h b/dwl/dwl-v0.7/xdg-shell-protocol.h new file mode 100644 index 00000000..8c11cd0b --- /dev/null +++ b/dwl/dwl-v0.7/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/swallow.patch b/dwl/swallow.patch new file mode 100644 index 00000000..f9760234 --- /dev/null +++ b/dwl/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/gentoo/portage/package.accept_keywords/package.unmask b/gentoo/portage/package.accept_keywords/package.unmask index 1cbb0898..43b0d8a7 100644 --- a/gentoo/portage/package.accept_keywords/package.unmask +++ b/gentoo/portage/package.accept_keywords/package.unmask @@ -24,3 +24,4 @@ gui-libs/scenefx ~amd64 gui-wm/mangowm ~amd64 gui-wm/dwl ~amd64 +gui-apps/wbg ~amd64 diff --git a/zshrc.txt b/zshrc.txt index fa5d582d..f2197146 100644 --- a/zshrc.txt +++ b/zshrc.txt @@ -52,7 +52,19 @@ setopt HIST_REDUCE_BLANKS # Remove superfluous blanks before recording en # setopt HIST_BEEP # Beep when accessing nonexistent history. # creates a .zsh_history file on startup, and clears the history -echo '' | xclip && xclip -selection clipboard /dev/null && history -p && hash -r && /usr/bin/rm $HOME/.zsh_history && touch $HOME/.zsh_history +# echo '' | xclip && xclip -selection clipboard /dev/null && history -p && hash -r && /usr/bin/rm $HOME/.zsh_history && touch $HOME/.zsh_history + +if [[ "$XDG_SESSION_TYPE" == "wayland" ]]; then + command -v wl-copy > /dev/null && wl-copy --clear +elif [[ "$XDG_SESSION_TYPE" == "x11" ]]; then + echo '' | xclip + xclip -selection clipboard /dev/null +fi +history -p +hash -r +/usr/bin/rm "$HOME/.zsh_history" +touch "$HOME/.zsh_history" + # Configure thefuck # eval "$(thefuck --alias)"