From 032bf3e951aaf3bd17c8f87ce9dff1a975d25a1d Mon Sep 17 00:00:00 2001 From: ayham Date: Wed, 22 Feb 2023 17:13:57 +0300 Subject: [PATCH] add clang-format'ing --- .clang-format | 11 + config.def.h | 190 ++- dwl.c | 4519 +++++++++++++++++++++++++------------------------ 3 files changed, 2400 insertions(+), 2320 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5fe2f94 --- /dev/null +++ b/.clang-format @@ -0,0 +1,11 @@ +BasedOnStyle: GNU +UseTab: AlignWithSpaces +IndentWidth: 4 +AllowShortIfStatementsOnASingleLine: false +BreakBeforeBraces: Linux +IndentCaseLabels: false +ColumnLimit: 100 +AlignConsecutiveStyle: Consecutive +AlignTrailingComments: + Kind: Always + OverEmptyLines: 2 diff --git a/config.def.h b/config.def.h index 419e6ef..01cc9b2 100644 --- a/config.def.h +++ b/config.def.h @@ -1,49 +1,52 @@ /* 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[] = {0.3, 0.3, 0.3, 1.0}; -static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; -static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; -/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ -static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; +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[] = { 0.3, 0.3, 0.3, 1.0 }; +static const float bordercolor[] = { 0.5, 0.5, 0.5, 1.0 }; +static const float focuscolor[] = { 1.0, 0.0, 0.0, 1.0 }; +/* To conform the xdg-protocol, set the alpha to zero to restore the old + * behavior */ +static const float fullscreen_bg[] = { 0.1, 0.1, 0.1, 1.0 }; /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; static const Rule rules[] = { - /* app_id title tags mask isfloating monitor */ - /* examples: - { "Gimp", NULL, 0, 1, -1 }, - */ - { "firefox", NULL, 1 << 8, 0, -1 }, + /* app_id title tags mask isfloating monitor */ + /* examples: + { "Gimp", NULL, 0, 1, -1 }, + */ + { "firefox", NULL, 1 << 8, 0, -1 }, }; /* layout(s) */ static const Layout layouts[] = { - /* symbol arrange function */ - { "[]=", tile }, - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, + /* symbol arrange function */ + { "[]=", tile }, + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, }; /* monitors */ static const MonitorRule monrules[] = { - /* name mfact nmaster scale layout rotate/reflect x y */ - /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL -1, -1 }, - */ - /* defaults */ - { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, + /* name mfact nmaster scale layout rotate/reflect x y */ + /* example of a HiDPI laptop monitor: + { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL + -1, -1 }, + */ + /* defaults */ + { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, }; /* keyboard */ static const struct xkb_rule_names xkb_rules = { - /* can specify fields: rules, model, layout, variant, options */ - /* example: - .options = "ctrl:nocaps", - */ - .options = NULL, + /* can specify fields: rules, model, layout, variant, options */ + /* example: + .options = "ctrl:nocaps", + */ + .options = NULL, }; static const int repeat_rate = 25; @@ -66,9 +69,9 @@ 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 +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; @@ -94,65 +97,92 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA /* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ #define MODKEY WLR_MODIFIER_ALT -#define TAGKEYS(KEY,SKEY,TAG) \ - { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ - { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \ - { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \ - { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} } +#define TAGKEYS(KEY, SKEY, TAG) \ + { MODKEY, KEY, view, { .ui = 1 << TAG } }, { MODKEY | WLR_MODIFIER_CTRL, KEY, toggleview, { .ui = 1 << TAG } }, \ + { MODKEY | WLR_MODIFIER_SHIFT, SKEY, tag, { .ui = 1 << TAG } }, \ + { \ + MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT, SKEY, toggletag, \ + { \ + .ui = 1 << TAG \ + } \ + } /* helper for spawning shell commands in the pre dwm-5.0 fashion */ -#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } +#define SHCMD(cmd) \ + { \ + .v = (const char *[]) \ + { \ + "/bin/sh", "-c", cmd, NULL \ + } \ + } /* commands */ static const char *termcmd[] = { "foot", NULL }; static const char *menucmd[] = { "bemenu-run", NULL }; static const Key keys[] = { - /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ - /* modifier key function argument */ - { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, - { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, - { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, - { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, - { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, - { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} }, - { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} }, - { MODKEY, XKB_KEY_Return, zoom, {0} }, - { MODKEY, XKB_KEY_Tab, view, {0} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} }, - { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, - { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, - { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, - { MODKEY, XKB_KEY_space, setlayout, {0} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, - { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, - { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, - { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, - { MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} }, - TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0), - TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), - TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), - TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3), - TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4), - TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5), - TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6), - TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7), - TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8), - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} }, + /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ + /* modifier key function argument + */ + { MODKEY, XKB_KEY_p, spawn, { .v = menucmd } }, + { MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, { .v = termcmd } }, + { MODKEY, XKB_KEY_j, focusstack, { .i = +1 } }, + { MODKEY, XKB_KEY_k, focusstack, { .i = -1 } }, + { MODKEY, XKB_KEY_i, incnmaster, { .i = +1 } }, + { MODKEY, XKB_KEY_d, incnmaster, { .i = -1 } }, + { MODKEY, XKB_KEY_h, setmfact, { .f = -0.05 } }, + { MODKEY, XKB_KEY_l, setmfact, { .f = +0.05 } }, + { MODKEY, XKB_KEY_Return, zoom, { 0 } }, + { MODKEY, XKB_KEY_Tab, view, { 0 } }, + { MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, { 0 } }, + { MODKEY, XKB_KEY_t, setlayout, { .v = &layouts[0] } }, + { MODKEY, XKB_KEY_f, setlayout, { .v = &layouts[1] } }, + { MODKEY, XKB_KEY_m, setlayout, { .v = &layouts[2] } }, + { MODKEY, XKB_KEY_space, setlayout, { 0 } }, + { MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, { 0 } }, + { MODKEY, XKB_KEY_e, togglefullscreen, { 0 } }, + { MODKEY, XKB_KEY_0, view, { .ui = ~0 } }, + { MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, { .ui = ~0 } }, + { MODKEY, XKB_KEY_comma, focusmon, { .i = WLR_DIRECTION_LEFT } }, + { MODKEY, XKB_KEY_period, focusmon, { .i = WLR_DIRECTION_RIGHT } }, + { MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, { .i = WLR_DIRECTION_LEFT } }, + { MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, { .i = WLR_DIRECTION_RIGHT } }, + TAGKEYS (XKB_KEY_1, XKB_KEY_exclam, 0), + TAGKEYS (XKB_KEY_2, XKB_KEY_at, 1), + TAGKEYS (XKB_KEY_3, XKB_KEY_numbersign, 2), + TAGKEYS (XKB_KEY_4, XKB_KEY_dollar, 3), + TAGKEYS (XKB_KEY_5, XKB_KEY_percent, 4), + TAGKEYS (XKB_KEY_6, XKB_KEY_asciicircum, 5), + TAGKEYS (XKB_KEY_7, XKB_KEY_ampersand, 6), + TAGKEYS (XKB_KEY_8, XKB_KEY_asterisk, 7), + TAGKEYS (XKB_KEY_9, XKB_KEY_parenleft, 8), + { MODKEY | WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, { 0 } }, - /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ - { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} }, -#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} } - CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6), - CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12), + /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ + { WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_Terminate_Server, quit, { 0 } }, +#define CHVT(n) \ + { \ + WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, XKB_KEY_XF86Switch_VT_##n, chvt, \ + { \ + .ui = (n) \ + } \ + } + CHVT (1), + CHVT (2), + CHVT (3), + CHVT (4), + CHVT (5), + CHVT (6), + CHVT (7), + CHVT (8), + CHVT (9), + CHVT (10), + CHVT (11), + CHVT (12), }; static const Button buttons[] = { - { MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} }, - { MODKEY, BTN_MIDDLE, togglefloating, {0} }, - { MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} }, + { MODKEY, BTN_LEFT, moveresize, { .ui = CurMove } }, + { MODKEY, BTN_MIDDLE, togglefloating, { 0 } }, + { MODKEY, BTN_RIGHT, moveresize, { .ui = CurResize } }, }; diff --git a/dwl.c b/dwl.c index 8043bf9..b80bbdd 100644 --- a/dwl.c +++ b/dwl.c @@ -53,275 +53,293 @@ #include #include #ifdef XWAYLAND -#include #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 ((1 << LENGTH(tags)) - 1) -#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) -#define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) +#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 ((1 << LENGTH (tags)) - 1) +#define LISTEN(E, L, H) wl_signal_add ((E), ((L)->notify = (H), (L))) +#define IDLE_NOTIFY_ACTIVITY \ + wlr_idle_notify_activity (idle, seat), \ + wlr_idle_notifier_v1_notify_activity (idle_notifier, seat) /* enums */ -enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ +enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, LyrBlock, NUM_LAYERS }; /* scene layers */ +enum { + LyrBg, + LyrBottom, + LyrTop, + LyrOverlay, + LyrTile, + LyrFloat, + LyrFS, + LyrDragIcon, + LyrBlock, + NUM_LAYERS +}; /* scene layers */ #ifdef XWAYLAND -enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, - NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ +enum { + NetWMWindowTypeDialog, + NetWMWindowTypeSplash, + NetWMWindowTypeToolbar, + NetWMWindowTypeUtility, + NetLast +}; /* EWMH atoms */ #endif typedef union { - int i; - unsigned int ui; - float f; - const void *v; + int i; + unsigned int ui; + float f; + const void *v; } Arg; typedef struct { - unsigned int mod; - unsigned int button; - void (*func)(const Arg *); - const Arg arg; + unsigned int mod; + unsigned int button; + void (*func) (const Arg *); + const Arg arg; } Button; typedef struct Monitor Monitor; typedef struct { - /* 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 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 wlr_box prev; /* layout-relative, includes border */ + /* 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 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 wlr_box prev; /* layout-relative, includes border */ #ifdef XWAYLAND - struct wl_listener activate; - struct wl_listener configure; - struct wl_listener set_hints; + struct wl_listener activate; + struct wl_listener configure; + struct wl_listener set_hints; #endif - unsigned int bw; - unsigned int tags; - int isfloating, isurgent, isfullscreen; - uint32_t resize; /* configure serial of a pending resize */ + unsigned int bw; + unsigned int tags; + int isfloating, isurgent, isfullscreen; + uint32_t resize; /* configure serial of a pending resize */ } Client; typedef struct { - uint32_t mod; - xkb_keysym_t keysym; - void (*func)(const Arg *); - const Arg arg; + uint32_t mod; + xkb_keysym_t keysym; + void (*func) (const Arg *); + const Arg arg; } Key; typedef struct { - struct wl_list link; - struct wlr_keyboard *wlr_keyboard; + struct wl_list link; + struct wlr_keyboard *wlr_keyboard; - int nsyms; - const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ - uint32_t mods; /* invalid if nsyms == 0 */ - struct wl_event_source *key_repeat_source; + int nsyms; + const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ + uint32_t mods; /* invalid if nsyms == 0 */ + struct wl_event_source *key_repeat_source; - struct wl_listener modifiers; - struct wl_listener key; - struct wl_listener destroy; + struct wl_listener modifiers; + struct wl_listener key; + struct wl_listener destroy; } Keyboard; typedef struct { - /* Must keep these three elements in this order */ - unsigned int type; /* LayerShell */ - struct wlr_box geom; - Monitor *mon; - struct wlr_scene_tree *scene; - struct wlr_scene_tree *popups; - struct wlr_scene_layer_surface_v1 *scene_layer; - struct wl_list link; - int mapped; - struct wlr_layer_surface_v1 *layer_surface; + /* Must keep these three elements in this order */ + unsigned int type; /* LayerShell */ + struct wlr_box geom; + Monitor *mon; + struct wlr_scene_tree *scene; + struct wlr_scene_tree *popups; + struct wlr_scene_layer_surface_v1 *scene_layer; + struct wl_list link; + int mapped; + struct wlr_layer_surface_v1 *layer_surface; - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener surface_commit; + struct wl_listener destroy; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener surface_commit; } LayerSurface; typedef struct { - const char *symbol; - void (*arrange)(Monitor *); + const char *symbol; + void (*arrange) (Monitor *); } Layout; struct Monitor { - struct wl_list link; - struct wlr_output *wlr_output; - struct wlr_scene_output *scene_output; - struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ - struct wl_listener frame; - struct wl_listener destroy; - struct wl_listener 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; - unsigned int tagset[2]; - double mfact; - int nmaster; + 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 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; + unsigned int tagset[2]; + double mfact; + int nmaster; }; typedef struct { - const char *name; - float mfact; - int nmaster; - float scale; - const Layout *lt; - enum wl_output_transform rr; - int x, y; + const char *name; + float mfact; + int nmaster; + float scale; + const Layout *lt; + enum wl_output_transform rr; + int x, y; } MonitorRule; typedef struct { - const char *id; - const char *title; - unsigned int tags; - int isfloating; - int monitor; + const char *id; + const char *title; + unsigned int tags; + int isfloating; + int monitor; } Rule; typedef struct { - struct wlr_scene_tree *scene; + struct wlr_scene_tree *scene; - struct wlr_session_lock_v1 *lock; - struct wl_listener new_surface; - struct wl_listener unlock; - struct wl_listener destroy; + struct wlr_session_lock_v1 *lock; + struct wl_listener new_surface; + struct wl_listener unlock; + struct wl_listener destroy; } SessionLock; /* function declarations */ -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 cleanupkeyboard(struct wl_listener *listener, void *data); -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 createdecoration(struct wl_listener *listener, void *data); -static void createidleinhibitor(struct wl_listener *listener, void *data); -static void createkeyboard(struct wlr_keyboard *keyboard); -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 cursorframe(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 destroysessionlock(struct wl_listener *listener, void *data); -static void destroysessionmgr(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 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 maplayersurfacenotify(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); -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 quit(const Arg *arg); -static void quitsignal(int signo); -static void rendermon(struct wl_listener *listener, void *data); -static void requeststartdrag(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 setfloating(Client *c, int floating); -static void setfullscreen(Client *c, int fullscreen); -static void setlayout(const Arg *arg); -static void setmfact(const Arg *arg); -static void setmon(Client *c, Monitor *m, unsigned int 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 Monitor *xytomon(double x, double y); -static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface, - Client **pc, LayerSurface **pl, double *nx, double *ny); -static void zoom(const Arg *arg); +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 cleanupkeyboard (struct wl_listener *listener, void *data); +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 createdecoration (struct wl_listener *listener, void *data); +static void createidleinhibitor (struct wl_listener *listener, void *data); +static void createkeyboard (struct wlr_keyboard *keyboard); +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 cursorframe (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 destroysessionlock (struct wl_listener *listener, void *data); +static void destroysessionmgr (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 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 maplayersurfacenotify (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); +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 quit (const Arg *arg); +static void quitsignal (int signo); +static void rendermon (struct wl_listener *listener, void *data); +static void requeststartdrag (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 setfloating (Client *c, int floating); +static void setfullscreen (Client *c, int fullscreen); +static void setlayout (const Arg *arg); +static void setmfact (const Arg *arg); +static void setmon (Client *c, Monitor *m, unsigned int 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 Monitor *xytomon (double x, double y); +static struct wlr_scene_node *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 const char broken[] = "broken"; static const char *cursor_image = "left_ptr"; -static pid_t child_pid = -1; +static pid_t child_pid = -1; static int locked; static void *exclusive_focus; static struct wl_display *dpy; @@ -364,42 +382,42 @@ static struct wl_list mons; static Monitor *selmon; /* global event handlers */ -static struct wl_listener cursor_axis = {.notify = axisnotify}; -static struct wl_listener cursor_button = {.notify = buttonpress}; -static struct wl_listener cursor_frame = {.notify = cursorframe}; -static struct wl_listener cursor_motion = {.notify = motionrelative}; -static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; -static struct wl_listener drag_icon_destroy = {.notify = destroydragicon}; -static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor}; -static struct wl_listener idle_inhibitor_destroy = {.notify = destroyidleinhibitor}; -static struct wl_listener layout_change = {.notify = updatemons}; -static struct wl_listener new_input = {.notify = inputdevice}; -static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; -static struct wl_listener new_output = {.notify = createmon}; -static struct wl_listener new_xdg_surface = {.notify = createnotify}; -static struct wl_listener new_xdg_decoration = {.notify = createdecoration}; -static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; -static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; -static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; -static struct wl_listener request_activate = {.notify = urgent}; -static struct wl_listener request_cursor = {.notify = setcursor}; -static struct wl_listener request_set_psel = {.notify = setpsel}; -static struct wl_listener request_set_sel = {.notify = setsel}; -static struct wl_listener request_start_drag = {.notify = requeststartdrag}; -static struct wl_listener start_drag = {.notify = startdrag}; -static struct wl_listener session_lock_create_lock = {.notify = locksession}; -static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmgr}; +static struct wl_listener cursor_axis = { .notify = axisnotify }; +static struct wl_listener cursor_button = { .notify = buttonpress }; +static struct wl_listener cursor_frame = { .notify = cursorframe }; +static struct wl_listener cursor_motion = { .notify = motionrelative }; +static struct wl_listener cursor_motion_absolute = { .notify = motionabsolute }; +static struct wl_listener drag_icon_destroy = { .notify = destroydragicon }; +static struct wl_listener idle_inhibitor_create = { .notify = createidleinhibitor }; +static struct wl_listener idle_inhibitor_destroy = { .notify = destroyidleinhibitor }; +static struct wl_listener layout_change = { .notify = updatemons }; +static struct wl_listener new_input = { .notify = inputdevice }; +static struct wl_listener new_virtual_keyboard = { .notify = virtualkeyboard }; +static struct wl_listener new_output = { .notify = createmon }; +static struct wl_listener new_xdg_surface = { .notify = createnotify }; +static struct wl_listener new_xdg_decoration = { .notify = createdecoration }; +static struct wl_listener new_layer_shell_surface = { .notify = createlayersurface }; +static struct wl_listener output_mgr_apply = { .notify = outputmgrapply }; +static struct wl_listener output_mgr_test = { .notify = outputmgrtest }; +static struct wl_listener request_activate = { .notify = urgent }; +static struct wl_listener request_cursor = { .notify = setcursor }; +static struct wl_listener request_set_psel = { .notify = setpsel }; +static struct wl_listener request_set_sel = { .notify = setsel }; +static struct wl_listener request_start_drag = { .notify = requeststartdrag }; +static struct wl_listener start_drag = { .notify = startdrag }; +static struct wl_listener session_lock_create_lock = { .notify = locksession }; +static struct wl_listener session_lock_mgr_destroy = { .notify = destroysessionmgr }; #ifdef XWAYLAND -static void activatex11(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 Atom getatom(xcb_connection_t *xc, const char *name); -static void sethints(struct wl_listener *listener, void *data); -static void sigchld(int unused); -static void xwaylandready(struct wl_listener *listener, void *data); -static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; -static struct wl_listener xwayland_ready = {.notify = xwaylandready}; +static void activatex11 (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 Atom getatom (xcb_connection_t *xc, const char *name); +static void sethints (struct wl_listener *listener, void *data); +static void sigchld (int unused); +static void xwaylandready (struct wl_listener *listener, void *data); +static struct wl_listener new_xwayland_surface = { .notify = createnotifyx11 }; +static struct wl_listener xwayland_ready = { .notify = xwaylandready }; static struct wlr_xwayland *xwayland; static Atom netatom[NetLast]; #endif @@ -411,2420 +429,2441 @@ static Atom netatom[NetLast]; #include "client.h" /* compile-time check if all tags fit into an unsigned int bit array. */ -struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; +struct NumTags { + char limitexceeded[LENGTH (tags) > 31 ? -1 : 1]; +}; /* function implementations */ void -applybounds(Client *c, struct wlr_box *bbox) +applybounds (Client *c, struct wlr_box *bbox) { - if (!c->isfullscreen) { - struct wlr_box min = {0}, max = {0}; - client_get_size_hints(c, &max, &min); - /* try to set size hints */ - c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); - c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); - /* Some clients set their max size to INT_MAX, which does not violate the - * protocol but its unnecesary, as they can set their max size to zero. */ - if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ - c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); - if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ - c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height); + if (!c->isfullscreen) { + struct wlr_box min = { 0 }, max = { 0 }; + client_get_size_hints (c, &max, &min); + /* try to set size hints */ + c->geom.width = MAX (min.width + (2 * (int)c->bw), c->geom.width); + c->geom.height = MAX (min.height + (2 * (int)c->bw), c->geom.height); + /* Some clients set their max size to INT_MAX, which does not + * violate the protocol but its unnecesary, as they can set their + * max size to zero. + */ + if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ + c->geom.width = MIN (max.width + (2 * c->bw), c->geom.width); + if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ + c->geom.height = MIN (max.height + (2 * 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 + 2 * c->bw <= bbox->x) + c->geom.x = bbox->x; + if (c->geom.y + c->geom.height + 2 * c->bw <= bbox->y) + c->geom.y = bbox->y; +} + +void +applyrules (Client *c) +{ + /* rule matching */ + const char *appid, *title; + unsigned int i, newtags = 0; + 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; } - - 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 + 2 * c->bw <= bbox->x) - c->geom.x = bbox->x; - if (c->geom.y + c->geom.height + 2 * c->bw <= bbox->y) - c->geom.y = bbox->y; + } + wlr_scene_node_reparent (&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); + setmon (c, mon, newtags); } void -applyrules(Client *c) +arrange (Monitor *m) { - /* rule matching */ - const char *appid, *title; - unsigned int i, newtags = 0; - const Rule *r; - Monitor *mon = selmon, *m; + Client *c; + wl_list_for_each (c, &clients, link) if (c->mon == m) + wlr_scene_node_set_enabled (&c->scene->node, VISIBLEON (c, m)); - c->isfloating = client_is_float_type(c); - if (!(appid = client_get_appid(c))) - appid = broken; - if (!(title = client_get_title(c))) - title = broken; + wlr_scene_node_set_enabled (&m->fullscreen_bg->node, (c = focustop (m)) && c->isfullscreen); - 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; - } - } - wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); - setmon(c, mon, newtags); + if (m && m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange (m); + motionnotify (0); + checkidleinhibitor (NULL); } void -arrange(Monitor *m) +arrangelayer (Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) { - Client *c; - wl_list_for_each(c, &clients, link) - if (c->mon == m) - wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); + LayerSurface *layersurface; + struct wlr_box full_area = m->m; - wlr_scene_node_set_enabled(&m->fullscreen_bg->node, - (c = focustop(m)) && c->isfullscreen); + wl_list_for_each (layersurface, list, link) + { + struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; + struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; - if (m && m->lt[m->sellt]->arrange) - m->lt[m->sellt]->arrange(m); - motionnotify(0); - checkidleinhibitor(NULL); + if (exclusive != (state->exclusive_zone > 0)) + continue; + + wlr_scene_layer_surface_v1_configure (layersurface->scene_layer, &full_area, usable_area); + wlr_scene_node_set_position (&layersurface->popups->node, layersurface->scene->node.x, + layersurface->scene->node.y); + layersurface->geom.x = layersurface->scene->node.x; + layersurface->geom.y = layersurface->scene->node.y; + } } void -arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) +arrangelayers (Monitor *m) { - LayerSurface *layersurface; - struct wlr_box full_area = m->m; + int i; + struct wlr_box usable_area = m->m; + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + LayerSurface *layersurface; + if (!m->wlr_output->enabled) + return; - wl_list_for_each(layersurface, list, link) { - struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; - struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; + /* Arrange exclusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer (m, &m->layers[i], &usable_area, 1); - if (exclusive != (state->exclusive_zone > 0)) - continue; + if (memcmp (&usable_area, &m->w, sizeof (struct wlr_box))) { + m->w = usable_area; + arrange (m); + } - wlr_scene_layer_surface_v1_configure(layersurface->scene_layer, &full_area, usable_area); - wlr_scene_node_set_position(&layersurface->popups->node, - layersurface->scene->node.x, layersurface->scene->node.y); - layersurface->geom.x = layersurface->scene->node.x; - layersurface->geom.y = layersurface->scene->node.y; - } -} + /* Arrange non-exlusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer (m, &m->layers[i], &usable_area, 0); -void -arrangelayers(Monitor *m) -{ - int i; - struct wlr_box usable_area = m->m; - uint32_t layers_above_shell[] = { - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - ZWLR_LAYER_SHELL_V1_LAYER_TOP, - }; - LayerSurface *layersurface; - if (!m->wlr_output->enabled) + /* Find topmost keyboard interactive layer, if such a layer exists */ + for (i = 0; i < LENGTH (layers_above_shell); i++) { + wl_list_for_each_reverse (layersurface, &m->layers[layers_above_shell[i]], link) + { + if (!locked && layersurface->layer_surface->current.keyboard_interactive + && layersurface->mapped) { + /* Deactivate the focused client. */ + focusclient (NULL, 0); + exclusive_focus = layersurface; + client_notify_enter (layersurface->layer_surface->surface, + wlr_seat_get_keyboard (seat)); return; - - /* Arrange exclusive surfaces from top->bottom */ - for (i = 3; i >= 0; i--) - arrangelayer(m, &m->layers[i], &usable_area, 1); - - if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) { - 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); +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; + IDLE_NOTIFY_ACTIVITY; + /* 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); +} - /* Find topmost keyboard interactive layer, if such a layer exists */ - for (i = 0; i < LENGTH(layers_above_shell); i++) { - wl_list_for_each_reverse(layersurface, - &m->layers[layers_above_shell[i]], link) { - if (!locked && layersurface->layer_surface->current.keyboard_interactive - && layersurface->mapped) { - /* Deactivate the focused client. */ - focusclient(NULL, 0); - exclusive_focus = layersurface; - client_notify_enter(layersurface->layer_surface->surface, wlr_seat_get_keyboard(seat)); - return; - } - } +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; + + IDLE_NOTIFY_ACTIVITY; + + switch (event->state) { + case WLR_BUTTON_PRESSED: + cursor_mode = CurPressed; + 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; + } } -} - -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; - IDLE_NOTIFY_ACTIVITY; - /* 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); -} - -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; - - IDLE_NOTIFY_ACTIVITY; - - switch (event->state) { - case WLR_BUTTON_PRESSED: - cursor_mode = CurPressed; - 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 WLR_BUTTON_RELEASED: - /* If you released any buttons, we exit interactive move/resize mode. */ - if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { - cursor_mode = CurNormal; - /* Clear the pointer focus, this way if the cursor is over a surface - * we will send an enter event after which the client will provide us - * a cursor surface */ - wlr_seat_pointer_clear_focus(seat); - motionnotify(0); - /* Drop the window off on its new monitor */ - selmon = xytomon(cursor->x, cursor->y); - setmon(grabc, selmon, 0); - return; - } else { - cursor_mode = CurNormal; - } - break; + break; + case WLR_BUTTON_RELEASED: + /* If you released any buttons, we exit interactive move/resize + * mode. */ + if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { + cursor_mode = CurNormal; + /* Clear the pointer focus, this way if the cursor is over + * a surface we will send an enter event after which the + * client will provide us a cursor surface */ + wlr_seat_pointer_clear_focus (seat); + motionnotify (0); + /* Drop the window off on its new monitor */ + selmon = xytomon (cursor->x, cursor->y); + setmon (grabc, selmon, 0); + return; + } else { + cursor_mode = CurNormal; } - /* 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); + 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) +chvt (const Arg *arg) { - wlr_session_change_vt(wlr_backend_get_session(backend), arg->ui); + wlr_session_change_vt (wlr_backend_get_session (backend), arg->ui); } void -checkidleinhibitor(struct wlr_surface *exclude) +checkidleinhibitor (struct wlr_surface *exclude) { - int inhibited = 0; - 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 - || tree->node.enabled))) { - inhibited = 1; - break; - } + int inhibited = 0; + 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 || tree->node.enabled))) { + inhibited = 1; + break; } + } - wlr_idle_set_enabled(idle, NULL, !inhibited); - wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); + wlr_idle_set_enabled (idle, NULL, !inhibited); + wlr_idle_notifier_v1_set_inhibited (idle_notifier, inhibited); } void -cleanup(void) +cleanup (void) { #ifdef XWAYLAND - wlr_xwayland_destroy(xwayland); + wlr_xwayland_destroy (xwayland); #endif - wl_display_destroy_clients(dpy); - if (child_pid > 0) { - kill(child_pid, SIGTERM); - waitpid(child_pid, NULL, 0); + wl_display_destroy_clients (dpy); + if (child_pid > 0) { + kill (child_pid, SIGTERM); + waitpid (child_pid, NULL, 0); + } + wlr_backend_destroy (backend); + wlr_renderer_destroy (drw); + wlr_allocator_destroy (alloc); + wlr_xcursor_manager_destroy (cursor_mgr); + wlr_cursor_destroy (cursor); + wlr_output_layout_destroy (output_layout); + wlr_seat_destroy (seat); + wl_display_destroy (dpy); +} + +void +cleanupkeyboard (struct wl_listener *listener, void *data) +{ + Keyboard *kb = wl_container_of (listener, kb, destroy); + + wl_event_source_remove (kb->key_repeat_source); + wl_list_remove (&kb->link); + wl_list_remove (&kb->modifiers.link); + wl_list_remove (&kb->key.link); + wl_list_remove (&kb->destroy.link); + free (kb); +} + +void +cleanupmon (struct wl_listener *listener, void *data) +{ + Monitor *m = wl_container_of (listener, m, destroy); + LayerSurface *l, *tmp; + int i; + + for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; 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); + m->wlr_output->data = NULL; + wlr_output_layout_remove (output_layout, m->wlr_output); + wlr_scene_output_destroy (m->scene_output); + wlr_scene_node_destroy (&m->fullscreen_bg->node); + + closemon (m); + free (m); +} + +void +closemon (Monitor *m) +{ + /* update selmon if needed and + * move closed monitor's clients to the focused one */ + Client *c; + if (wl_list_empty (&mons)) { + selmon = NULL; + } else if (m == selmon) { + int nmons = wl_list_length (&mons), i = 0; + do /* don't switch to disabled mons */ + selmon = wl_container_of (mons.next, selmon, link); + while (!selmon->wlr_output->enabled && i++ < nmons); + } + + 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 *layersurface = wl_container_of (listener, layersurface, surface_commit); + struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; + struct wlr_output *wlr_output = wlr_layer_surface->output; + + /* For some reason this layersurface have no monitor, this can be because + * its monitor has just been destroyed */ + if (!wlr_output || !(layersurface->mon = wlr_output->data)) + return; + + if (layers[wlr_layer_surface->current.layer] != layersurface->scene->node.parent) { + wlr_scene_node_reparent (&layersurface->scene->node, + layers[wlr_layer_surface->current.layer]); + wlr_scene_node_reparent (&layersurface->popups->node, + layers[wlr_layer_surface->current.layer]); + wl_list_remove (&layersurface->link); + wl_list_insert (&layersurface->mon->layers[wlr_layer_surface->current.layer], + &layersurface->link); + } + if (wlr_layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + wlr_scene_node_reparent (&layersurface->popups->node, layers[LyrTop]); + + if (wlr_layer_surface->current.committed == 0 + && layersurface->mapped == wlr_layer_surface->mapped) + return; + layersurface->mapped = wlr_layer_surface->mapped; + + arrangelayers (layersurface->mon); +} + +void +commitnotify (struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of (listener, c, commit); + struct wlr_box box = { 0 }; + client_get_geometry (c, &box); + + if (c->mon && !wlr_box_empty (&box) + && (box.width != c->geom.width - 2 * c->bw || box.height != c->geom.height - 2 * c->bw)) + c->isfloating ? resize (c, c->geom, 1) : arrange (c->mon); + + /* mark a pending resize as completed */ + if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) + c->resize = 0; +} + +void +createdecoration (struct wl_listener *listener, void *data) +{ + struct wlr_xdg_toplevel_decoration_v1 *dec = data; + wlr_xdg_toplevel_decoration_v1_set_mode (dec, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +} + +void +createidleinhibitor (struct wl_listener *listener, void *data) +{ + struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; + wl_signal_add (&idle_inhibitor->events.destroy, &idle_inhibitor_destroy); + + checkidleinhibitor (NULL); +} + +void +createkeyboard (struct wlr_keyboard *keyboard) +{ + struct xkb_context *context; + struct xkb_keymap *keymap; + Keyboard *kb = keyboard->data = ecalloc (1, sizeof (*kb)); + kb->wlr_keyboard = keyboard; + + /* Prepare an XKB keymap and assign it to the keyboard. */ + context = xkb_context_new (XKB_CONTEXT_NO_FLAGS); + keymap = xkb_keymap_new_from_names (context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + + wlr_keyboard_set_keymap (keyboard, keymap); + xkb_keymap_unref (keymap); + xkb_context_unref (context); + wlr_keyboard_set_repeat_info (keyboard, repeat_rate, repeat_delay); + + /* Here we set up listeners for keyboard events. */ + LISTEN (&keyboard->events.modifiers, &kb->modifiers, keypressmod); + LISTEN (&keyboard->events.key, &kb->key, keypress); + LISTEN (&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard); + + wlr_seat_set_keyboard (seat, keyboard); + + kb->key_repeat_source + = wl_event_loop_add_timer (wl_display_get_event_loop (dpy), keyrepeat, kb); + + /* And add the keyboard to our list of keyboards */ + wl_list_insert (&keyboards, &kb->link); +} + +void +createlayersurface (struct wl_listener *listener, void *data) +{ + struct wlr_layer_surface_v1 *wlr_layer_surface = data; + LayerSurface *layersurface; + struct wlr_layer_surface_v1_state old_state; + + if (!wlr_layer_surface->output) + wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL; + + if (!wlr_layer_surface->output) + wlr_layer_surface_v1_destroy (wlr_layer_surface); + + layersurface = ecalloc (1, sizeof (LayerSurface)); + layersurface->type = LayerShell; + LISTEN (&wlr_layer_surface->surface->events.commit, &layersurface->surface_commit, + commitlayersurfacenotify); + LISTEN (&wlr_layer_surface->events.destroy, &layersurface->destroy, destroylayersurfacenotify); + LISTEN (&wlr_layer_surface->events.map, &layersurface->map, maplayersurfacenotify); + LISTEN (&wlr_layer_surface->events.unmap, &layersurface->unmap, unmaplayersurfacenotify); + + layersurface->layer_surface = wlr_layer_surface; + layersurface->mon = wlr_layer_surface->output->data; + wlr_layer_surface->data = layersurface; + + layersurface->scene_layer = wlr_scene_layer_surface_v1_create ( + layers[wlr_layer_surface->pending.layer], wlr_layer_surface); + layersurface->scene = layersurface->scene_layer->tree; + layersurface->popups = wlr_layer_surface->surface->data + = wlr_scene_tree_create (layers[wlr_layer_surface->pending.layer]); + + layersurface->scene->node.data = layersurface; + + wl_list_insert (&layersurface->mon->layers[wlr_layer_surface->pending.layer], + &layersurface->link); + + /* Temporarily set the layer's current state to pending + * so that we can easily arrange it + */ + old_state = wlr_layer_surface->current; + wlr_layer_surface->current = wlr_layer_surface->pending; + layersurface->mapped = 1; + arrangelayers (layersurface->mon); + wlr_layer_surface->current = old_state; +} + +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; + Monitor *m = wlr_output->data = ecalloc (1, sizeof (*m)); + m->wlr_output = wlr_output; + + wlr_output_init_render (wlr_output, alloc, drw); + + /* Initialize monitor state using configured rules */ + for (i = 0; i < LENGTH (m->layers); i++) + wl_list_init (&m->layers[i]); + m->tagset[0] = m->tagset[1] = 1; + for (r = monrules; r < END (monrules); r++) { + if (!r->name || strstr (wlr_output->name, r->name)) { + m->mfact = r->mfact; + m->nmaster = r->nmaster; + wlr_output_set_scale (wlr_output, r->scale); + wlr_xcursor_manager_load (cursor_mgr, r->scale); + m->lt[0] = m->lt[1] = r->lt; + wlr_output_set_transform (wlr_output, r->rr); + m->m.x = r->x; + m->m.y = r->y; + break; } - wlr_backend_destroy(backend); - wlr_renderer_destroy(drw); - wlr_allocator_destroy(alloc); - wlr_xcursor_manager_destroy(cursor_mgr); - wlr_cursor_destroy(cursor); - wlr_output_layout_destroy(output_layout); - wlr_seat_destroy(seat); - wl_display_destroy(dpy); + } + + /* 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_set_mode (wlr_output, 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); + + wlr_output_enable (wlr_output, 1); + if (!wlr_output_commit (wlr_output)) + return; + + /* Try to enable adaptive sync, note that not all monitors support it. + * wlr_output_commit() will deactivate it in case it cannot be enabled */ + wlr_output_enable_adaptive_sync (wlr_output, 1); + wlr_output_commit (wlr_output); + + 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 in. + * + * 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 < 0 || m->m.y < 0) + 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 -cleanupkeyboard(struct wl_listener *listener, void *data) +createnotify (struct wl_listener *listener, void *data) { - Keyboard *kb = wl_container_of(listener, kb, destroy); + /* This event is raised when wlr_xdg_shell receives a new xdg surface from + * a client, either a toplevel (application window) or popup, or when + * wlr_layer_shell receives a new popup from a layer. If you want to do + * something tricky with popups you should check if its parent is + * wlr_xdg_shell or wlr_layer_shell */ + struct wlr_xdg_surface *xdg_surface = data; + Client *c = NULL; + LayerSurface *l = NULL; - wl_event_source_remove(kb->key_repeat_source); - wl_list_remove(&kb->link); - wl_list_remove(&kb->modifiers.link); - wl_list_remove(&kb->key.link); - wl_list_remove(&kb->destroy.link); - free(kb); + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + struct wlr_box box; + int type = toplevel_from_wlr_surface (xdg_surface->surface, &c, &l); + if (!xdg_surface->popup->parent || type < 0) + return; + xdg_surface->surface->data + = wlr_scene_xdg_surface_create (xdg_surface->popup->parent->data, xdg_surface); + 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 (xdg_surface->popup, &box); + return; + } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) + return; + + /* Allocate a Client for this surface */ + c = xdg_surface->data = ecalloc (1, sizeof (*c)); + c->surface.xdg = xdg_surface; + c->bw = borderpx; + + LISTEN (&xdg_surface->events.map, &c->map, mapnotify); + LISTEN (&xdg_surface->events.unmap, &c->unmap, unmapnotify); + LISTEN (&xdg_surface->events.destroy, &c->destroy, destroynotify); + LISTEN (&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); + LISTEN (&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); + LISTEN (&xdg_surface->toplevel->events.request_maximize, &c->maximize, maximizenotify); } void -cleanupmon(struct wl_listener *listener, void *data) +createpointer (struct wlr_pointer *pointer) { - Monitor *m = wl_container_of(listener, m, destroy); - LayerSurface *l, *tmp; - int i; + if (wlr_input_device_is_libinput (&pointer->base)) { + struct libinput_device *libinput_device + = (struct libinput_device *)wlr_libinput_get_device_handle (&pointer->base); - for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; 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); - m->wlr_output->data = NULL; - wlr_output_layout_remove(output_layout, m->wlr_output); - wlr_scene_output_destroy(m->scene_output); - wlr_scene_node_destroy(&m->fullscreen_bg->node); - - closemon(m); - free(m); -} - -void -closemon(Monitor *m) -{ - /* update selmon if needed and - * move closed monitor's clients to the focused one */ - Client *c; - if (wl_list_empty(&mons)) { - selmon = NULL; - } else if (m == selmon) { - int nmons = wl_list_length(&mons), i = 0; - do /* don't switch to disabled mons */ - selmon = wl_container_of(mons.next, selmon, link); - while (!selmon->wlr_output->enabled && i++ < nmons); + if (libinput_device_config_tap_get_finger_count (libinput_device)) { + libinput_device_config_tap_set_enabled (libinput_device, tap_to_click); + libinput_device_config_tap_set_drag_enabled (libinput_device, tap_and_drag); + libinput_device_config_tap_set_drag_lock_enabled (libinput_device, drag_lock); + libinput_device_config_tap_set_button_map (libinput_device, button_map); } - 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); + if (libinput_device_config_scroll_has_natural_scroll (libinput_device)) + libinput_device_config_scroll_set_natural_scroll_enabled (libinput_device, + natural_scrolling); + + if (libinput_device_config_dwt_is_available (libinput_device)) + libinput_device_config_dwt_set_enabled (libinput_device, disable_while_typing); + + if (libinput_device_config_left_handed_is_available (libinput_device)) + libinput_device_config_left_handed_set (libinput_device, left_handed); + + if (libinput_device_config_middle_emulation_is_available (libinput_device)) + libinput_device_config_middle_emulation_set_enabled (libinput_device, + middle_button_emulation); + + if (libinput_device_config_scroll_get_methods (libinput_device) + != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) + libinput_device_config_scroll_set_method (libinput_device, scroll_method); + + if (libinput_device_config_click_get_methods (libinput_device) + != LIBINPUT_CONFIG_CLICK_METHOD_NONE) + libinput_device_config_click_set_method (libinput_device, click_method); + + if (libinput_device_config_send_events_get_modes (libinput_device)) + libinput_device_config_send_events_set_mode (libinput_device, send_events_mode); + + if (libinput_device_config_accel_is_available (libinput_device)) { + libinput_device_config_accel_set_profile (libinput_device, accel_profile); + libinput_device_config_accel_set_speed (libinput_device, accel_speed); } - focusclient(focustop(selmon), 1); - printstatus(); + } + + wlr_cursor_attach_input_device (cursor, &pointer->base); } void -commitlayersurfacenotify(struct wl_listener *listener, void *data) +cursorframe (struct wl_listener *listener, void *data) { - LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); - struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; - struct wlr_output *wlr_output = wlr_layer_surface->output; - - /* For some reason this layersurface have no monitor, this can be because - * its monitor has just been destroyed */ - if (!wlr_output || !(layersurface->mon = wlr_output->data)) - return; - - if (layers[wlr_layer_surface->current.layer] != layersurface->scene->node.parent) { - wlr_scene_node_reparent(&layersurface->scene->node, - layers[wlr_layer_surface->current.layer]); - wlr_scene_node_reparent(&layersurface->popups->node, - layers[wlr_layer_surface->current.layer]); - wl_list_remove(&layersurface->link); - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], - &layersurface->link); - } - if (wlr_layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - wlr_scene_node_reparent(&layersurface->popups->node, layers[LyrTop]); - - if (wlr_layer_surface->current.committed == 0 - && layersurface->mapped == wlr_layer_surface->mapped) - return; - layersurface->mapped = wlr_layer_surface->mapped; - - arrangelayers(layersurface->mon); + /* 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 -commitnotify(struct wl_listener *listener, void *data) +destroydragicon (struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, commit); - struct wlr_box box = {0}; - client_get_geometry(c, &box); - - if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw - || box.height != c->geom.height - 2 * c->bw)) - c->isfloating ? resize(c, c->geom, 1) : arrange(c->mon); - - /* mark a pending resize as completed */ - if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) - c->resize = 0; + struct wlr_drag_icon *icon = data; + wlr_scene_node_destroy (icon->data); + /* Focus enter isn't sent during drag, so refocus the focused node. */ + focusclient (focustop (selmon), 1); + motionnotify (0); } void -createdecoration(struct wl_listener *listener, void *data) +destroyidleinhibitor (struct wl_listener *listener, void *data) { - struct wlr_xdg_toplevel_decoration_v1 *dec = data; - wlr_xdg_toplevel_decoration_v1_set_mode(dec, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + /* `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 -createidleinhibitor(struct wl_listener *listener, void *data) +destroylayersurfacenotify (struct wl_listener *listener, void *data) { - struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; - wl_signal_add(&idle_inhibitor->events.destroy, &idle_inhibitor_destroy); + LayerSurface *layersurface = wl_container_of (listener, layersurface, destroy); - checkidleinhibitor(NULL); + wl_list_remove (&layersurface->link); + wl_list_remove (&layersurface->destroy.link); + wl_list_remove (&layersurface->map.link); + wl_list_remove (&layersurface->unmap.link); + wl_list_remove (&layersurface->surface_commit.link); + wlr_scene_node_destroy (&layersurface->scene->node); + free (layersurface); } void -createkeyboard(struct wlr_keyboard *keyboard) +destroylock (SessionLock *lock, int unlock) { - struct xkb_context *context; - struct xkb_keymap *keymap; - Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb)); - kb->wlr_keyboard = keyboard; + wlr_seat_keyboard_notify_clear_focus (seat); + if ((locked = !unlock)) + goto destroy; - /* Prepare an XKB keymap and assign it to the keyboard. */ - context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - keymap = xkb_keymap_new_from_names(context, &xkb_rules, - XKB_KEYMAP_COMPILE_NO_FLAGS); + wlr_scene_node_set_enabled (&locked_bg->node, 0); - wlr_keyboard_set_keymap(keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); - wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); - - /* Here we set up listeners for keyboard events. */ - LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod); - LISTEN(&keyboard->events.key, &kb->key, keypress); - LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard); - - wlr_seat_set_keyboard(seat, keyboard); - - kb->key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, kb); - - /* And add the keyboard to our list of keyboards */ - wl_list_insert(&keyboards, &kb->link); -} - -void -createlayersurface(struct wl_listener *listener, void *data) -{ - struct wlr_layer_surface_v1 *wlr_layer_surface = data; - LayerSurface *layersurface; - struct wlr_layer_surface_v1_state old_state; - - if (!wlr_layer_surface->output) - wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL; - - if (!wlr_layer_surface->output) - wlr_layer_surface_v1_destroy(wlr_layer_surface); - - layersurface = ecalloc(1, sizeof(LayerSurface)); - layersurface->type = LayerShell; - LISTEN(&wlr_layer_surface->surface->events.commit, - &layersurface->surface_commit, commitlayersurfacenotify); - LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, - destroylayersurfacenotify); - LISTEN(&wlr_layer_surface->events.map, &layersurface->map, - maplayersurfacenotify); - LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap, - unmaplayersurfacenotify); - - layersurface->layer_surface = wlr_layer_surface; - layersurface->mon = wlr_layer_surface->output->data; - wlr_layer_surface->data = layersurface; - - layersurface->scene_layer = wlr_scene_layer_surface_v1_create( - layers[wlr_layer_surface->pending.layer], wlr_layer_surface); - layersurface->scene = layersurface->scene_layer->tree; - layersurface->popups = wlr_layer_surface->surface->data = - wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer]); - - layersurface->scene->node.data = layersurface; - - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->pending.layer], - &layersurface->link); - - /* Temporarily set the layer's current state to pending - * so that we can easily arrange it - */ - old_state = wlr_layer_surface->current; - wlr_layer_surface->current = wlr_layer_surface->pending; - layersurface->mapped = 1; - arrangelayers(layersurface->mon); - wlr_layer_surface->current = old_state; -} - -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; - Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); - m->wlr_output = wlr_output; - - wlr_output_init_render(wlr_output, alloc, drw); - - /* Initialize monitor state using configured rules */ - for (i = 0; i < LENGTH(m->layers); i++) - wl_list_init(&m->layers[i]); - m->tagset[0] = m->tagset[1] = 1; - for (r = monrules; r < END(monrules); r++) { - if (!r->name || strstr(wlr_output->name, r->name)) { - m->mfact = r->mfact; - m->nmaster = r->nmaster; - wlr_output_set_scale(wlr_output, r->scale); - wlr_xcursor_manager_load(cursor_mgr, r->scale); - m->lt[0] = m->lt[1] = r->lt; - wlr_output_set_transform(wlr_output, r->rr); - m->m.x = r->x; - m->m.y = r->y; - 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_set_mode(wlr_output, 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); - - wlr_output_enable(wlr_output, 1); - if (!wlr_output_commit(wlr_output)) - return; - - /* Try to enable adaptive sync, note that not all monitors support it. - * wlr_output_commit() will deactivate it in case it cannot be enabled */ - wlr_output_enable_adaptive_sync(wlr_output, 1); - wlr_output_commit(wlr_output); - - 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 in. - * - * 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 < 0 || m->m.y < 0) - 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 wlr_xdg_shell receives a new xdg surface from a - * client, either a toplevel (application window) or popup, - * or when wlr_layer_shell receives a new popup from a layer. - * If you want to do something tricky with popups you should check if - * its parent is wlr_xdg_shell or wlr_layer_shell */ - struct wlr_xdg_surface *xdg_surface = data; - Client *c = NULL; - LayerSurface *l = NULL; - - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - struct wlr_box box; - int type = toplevel_from_wlr_surface(xdg_surface->surface, &c, &l); - if (!xdg_surface->popup->parent || type < 0) - return; - xdg_surface->surface->data = wlr_scene_xdg_surface_create( - xdg_surface->popup->parent->data, xdg_surface); - 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(xdg_surface->popup, &box); - return; - } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) - return; - - /* Allocate a Client for this surface */ - c = xdg_surface->data = ecalloc(1, sizeof(*c)); - c->surface.xdg = xdg_surface; - c->bw = borderpx; - - LISTEN(&xdg_surface->events.map, &c->map, mapnotify); - LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); - LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, - fullscreennotify); - LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize, - maximizenotify); -} - -void -createpointer(struct wlr_pointer *pointer) -{ - if (wlr_input_device_is_libinput(&pointer->base)) { - struct libinput_device *libinput_device = (struct libinput_device*) - wlr_libinput_get_device_handle(&pointer->base); - - if (libinput_device_config_tap_get_finger_count(libinput_device)) { - libinput_device_config_tap_set_enabled(libinput_device, tap_to_click); - libinput_device_config_tap_set_drag_enabled(libinput_device, tap_and_drag); - libinput_device_config_tap_set_drag_lock_enabled(libinput_device, drag_lock); - libinput_device_config_tap_set_button_map(libinput_device, button_map); - } - - if (libinput_device_config_scroll_has_natural_scroll(libinput_device)) - libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, natural_scrolling); - - if (libinput_device_config_dwt_is_available(libinput_device)) - libinput_device_config_dwt_set_enabled(libinput_device, disable_while_typing); - - if (libinput_device_config_left_handed_is_available(libinput_device)) - libinput_device_config_left_handed_set(libinput_device, left_handed); - - if (libinput_device_config_middle_emulation_is_available(libinput_device)) - libinput_device_config_middle_emulation_set_enabled(libinput_device, middle_button_emulation); - - if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) - libinput_device_config_scroll_set_method (libinput_device, scroll_method); - - if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) - libinput_device_config_click_set_method (libinput_device, click_method); - - if (libinput_device_config_send_events_get_modes(libinput_device)) - libinput_device_config_send_events_set_mode(libinput_device, send_events_mode); - - if (libinput_device_config_accel_is_available(libinput_device)) { - libinput_device_config_accel_set_profile(libinput_device, accel_profile); - libinput_device_config_accel_set_speed(libinput_device, accel_speed); - } - } - - wlr_cursor_attach_input_device(cursor, &pointer->base); -} - -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 -destroydragicon(struct wl_listener *listener, void *data) -{ - struct wlr_drag_icon *icon = data; - wlr_scene_node_destroy(icon->data); - /* Focus enter isn't sent during drag, so refocus the focused node. */ - focusclient(focustop(selmon), 1); - motionnotify(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 *layersurface = wl_container_of(listener, layersurface, destroy); - - wl_list_remove(&layersurface->link); - wl_list_remove(&layersurface->destroy.link); - wl_list_remove(&layersurface->map.link); - wl_list_remove(&layersurface->unmap.link); - wl_list_remove(&layersurface->surface_commit.link); - wlr_scene_node_destroy(&layersurface->scene->node); - free(layersurface); -} - -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); + focusclient (focustop (selmon), 0); + motionnotify (0); destroy: - wl_list_remove(&lock->new_surface.link); - wl_list_remove(&lock->unlock.link); - wl_list_remove(&lock->destroy.link); + wl_list_remove (&lock->new_surface.link); + wl_list_remove (&lock->unlock.link); + wl_list_remove (&lock->destroy.link); - wlr_scene_node_destroy(&lock->scene->node); - cur_lock = NULL; - free(lock); + wlr_scene_node_destroy (&lock->scene->node); + cur_lock = NULL; + free (lock); } void -destroylocksurface(struct wl_listener *listener, void *data) +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; + Monitor *m = wl_container_of (listener, m, destroy_lock_surface); + struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface; - m->lock_surface = NULL; - wl_list_remove(&m->destroy_lock_surface.link); + m->lock_surface = NULL; + wl_list_remove (&m->destroy_lock_surface.link); - if (lock_surface->surface == seat->keyboard_state.focused_surface) { - if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { - surface = wl_container_of(cur_lock->surfaces.next, surface, link); - client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); - } else if (!locked) { - focusclient(focustop(selmon), 1); - } else { - wlr_seat_keyboard_clear_focus(seat); - } + if (lock_surface->surface == seat->keyboard_state.focused_surface) { + 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) +destroynotify (struct wl_listener *listener, void *data) { - /* Called when the surface is destroyed and should never be shown again. */ - Client *c = wl_container_of(listener, c, destroy); - wl_list_remove(&c->map.link); - wl_list_remove(&c->unmap.link); - wl_list_remove(&c->destroy.link); - wl_list_remove(&c->set_title.link); - wl_list_remove(&c->fullscreen.link); + /* Called when the surface is destroyed and should never be shown again. */ + Client *c = wl_container_of (listener, c, destroy); + wl_list_remove (&c->map.link); + wl_list_remove (&c->unmap.link); + 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->configure.link); - wl_list_remove(&c->set_hints.link); - wl_list_remove(&c->activate.link); - } + if (c->type != XDGShell) { + wl_list_remove (&c->configure.link); + wl_list_remove (&c->set_hints.link); + wl_list_remove (&c->activate.link); + } #endif - free(c); + free (c); } void -destroysessionlock(struct wl_listener *listener, void *data) +destroysessionlock (struct wl_listener *listener, void *data) { - SessionLock *lock = wl_container_of(listener, lock, destroy); - destroylock(lock, 0); + SessionLock *lock = wl_container_of (listener, lock, destroy); + destroylock (lock, 0); } void -destroysessionmgr(struct wl_listener *listener, void *data) +destroysessionmgr (struct wl_listener *listener, void *data) { - wl_list_remove(&session_lock_create_lock.link); - wl_list_remove(&session_lock_mgr_destroy.link); + wl_list_remove (&session_lock_create_lock.link); + wl_list_remove (&session_lock_mgr_destroy.link); } Monitor * -dirtomon(enum wlr_direction dir) +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; + 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) +focusclient (Client *c, int lift) { - struct wlr_surface *old = seat->keyboard_state.focused_surface; - int i; + struct wlr_surface *old = seat->keyboard_state.focused_surface; + int i; - if (locked) - return; + if (locked) + return; - /* Raise client in stacking order if requested */ - if (c && lift) - wlr_scene_node_raise_to_top(&c->scene->node); + /* Raise client in stacking order if requested */ + if (c && lift) + wlr_scene_node_raise_to_top (&c->scene->node); - if (c && client_surface(c) == old) - return; + if (c && client_surface (c) == old) + return; - /* Put the new client atop the focus stack and select its monitor */ - if (c && !client_is_unmanaged(c)) { - wl_list_remove(&c->flink); - wl_list_insert(&fstack, &c->flink); - selmon = c->mon; - c->isurgent = 0; - client_restack_surface(c); + /* Put the new client atop the focus stack and select its monitor */ + if (c && !client_is_unmanaged (c)) { + wl_list_remove (&c->flink); + wl_list_insert (&fstack, &c->flink); + selmon = c->mon; + c->isurgent = 0; + client_restack_surface (c); - /* Don't change border color if there is an exclusive focus or we are - * handling a drag operation */ - if (!exclusive_focus && !seat->drag) - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(c->border[i], focuscolor); + /* Don't change border color if there is an exclusive focus or we + * are handling a drag operation */ + if (!exclusive_focus && !seat->drag) + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color (c->border[i], 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. */ + Client *w = NULL; + LayerSurface *l = NULL; + int type = toplevel_from_wlr_surface (old, &w, &l); + if (type == LayerShell && l->scene->node.enabled + && l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { + return; + } else if (w && w == exclusive_focus && client_wants_focus (w)) { + return; + /* Don't deactivate old client if the new one wants focus, + * as this causes issues with winecfg and probably other + * clients */ + } else if (w && !client_is_unmanaged (w) && (!c || !client_wants_focus (c))) { + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color (w->border[i], bordercolor); + + client_activate_surface (old, 0); } + } + printstatus (); - /* 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. */ - Client *w = NULL; - LayerSurface *l = NULL; - int type = toplevel_from_wlr_surface(old, &w, &l); - if (type == LayerShell && l->scene->node.enabled - && l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { - return; - } else if (w && w == exclusive_focus && client_wants_focus(w)) { - return; - /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg - * and probably other clients */ - } else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) { - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(w->border[i], bordercolor); + if (!c) { + /* With no client, all we have left is to clear focus */ + wlr_seat_keyboard_notify_clear_focus (seat); + return; + } - client_activate_surface(old, 0); - } - } - printstatus(); + /* Change cursor surface */ + motionnotify (0); - if (!c) { - /* With no client, all we have left is to clear focus */ - wlr_seat_keyboard_notify_clear_focus(seat); - return; - } + /* Have a client, so focus its top-level wlr_surface */ + client_notify_enter (client_surface (c), wlr_seat_get_keyboard (seat)); - /* Change cursor surface */ - motionnotify(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); + /* Activate the new client */ + client_activate_surface (client_surface (c), 1); } void -focusmon(const Arg *arg) +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); + 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) +focusstack (const Arg *arg) { - /* Focus the next or previous client (in tiling order) on selmon */ - Client *c, *sel = focustop(selmon); - if (!sel || sel->isfullscreen) - 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 */ - } + /* Focus the next or previous client (in tiling order) on selmon */ + Client *c, *sel = focustop (selmon); + if (!sel || sel->isfullscreen) + 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 */ } - /* If only one client is visible on selmon, then c == sel */ - focusclient(c, 1); + } 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) +focustop (Monitor *m) { - Client *c; - wl_list_for_each(c, &fstack, flink) - if (VISIBLEON(c, m)) - return c; - return NULL; + 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) +fullscreennotify (struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, fullscreen); - setfullscreen(c, client_wants_fullscreen(c)); + Client *c = wl_container_of (listener, c, fullscreen); + setfullscreen (c, client_wants_fullscreen (c)); } void -incnmaster(const Arg *arg) +incnmaster (const Arg *arg) { - if (!arg || !selmon) - return; - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); - arrange(selmon); + if (!arg || !selmon) + return; + selmon->nmaster = MAX (selmon->nmaster + arg->i, 0); + arrange (selmon); } void -inputdevice(struct wl_listener *listener, void *data) +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; + /* This event is raised by the backend when a new input device becomes + * available. */ + struct wlr_input_device *device = data; + uint32_t caps; - switch (device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - createkeyboard(wlr_keyboard_from_input_device(device)); - break; - case WLR_INPUT_DEVICE_POINTER: - createpointer(wlr_pointer_from_input_device(device)); - break; - default: - /* TODO handle other input device types */ - break; - } + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + createkeyboard (wlr_keyboard_from_input_device (device)); + break; + case WLR_INPUT_DEVICE_POINTER: + createpointer (wlr_pointer_from_input_device (device)); + break; + default: + /* TODO handle other input device types */ + break; + } - /* We need to let the wlr_seat know what our capabilities are, which is - * communiciated to the client. In dwl we always have a cursor, even if - * there are no pointer devices, so we always include that capability. */ - /* TODO do we actually require a cursor? */ - caps = WL_SEAT_CAPABILITY_POINTER; - if (!wl_list_empty(&keyboards)) - caps |= WL_SEAT_CAPABILITY_KEYBOARD; - wlr_seat_set_capabilities(seat, caps); + /* We need to let the wlr_seat know what our capabilities are, which is + * communiciated to the client. In dwl we always have a cursor, even if + * there are no pointer devices, so we always include that capability. */ + /* TODO do we actually require a cursor? */ + caps = WL_SEAT_CAPABILITY_POINTER; + if (!wl_list_empty (&keyboards)) + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + wlr_seat_set_capabilities (seat, caps); } int -keybinding(uint32_t mods, xkb_keysym_t sym) +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. - */ - int handled = 0; - 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); - handled = 1; - } + /* + * 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. + */ + int handled = 0; + 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); + handled = 1; } - return handled; + } + return handled; } void -keypress(struct wl_listener *listener, void *data) +keypress (struct wl_listener *listener, void *data) { - int i; - /* This event is raised when a key is pressed or released. */ - Keyboard *kb = wl_container_of(listener, kb, key); - struct wlr_keyboard_key_event *event = data; + int i; + /* This event is raised when a key is pressed or released. */ + Keyboard *kb = wl_container_of (listener, kb, 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( - kb->wlr_keyboard->xkb_state, keycode, &syms); + /* Translate libinput keycode -> xkbcommon */ + uint32_t keycode = event->keycode + 8; + /* Get a list of keysyms based on the keymap for this keyboard */ + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms (kb->wlr_keyboard->xkb_state, keycode, &syms); - int handled = 0; - uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); + int handled = 0; + uint32_t mods = wlr_keyboard_get_modifiers (kb->wlr_keyboard); - IDLE_NOTIFY_ACTIVITY; + IDLE_NOTIFY_ACTIVITY; - /* On _press_ if there is no active screen locker, - * attempt to process a compositor keybinding. */ - if (!locked && !input_inhibit_mgr->active_inhibitor - && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) - for (i = 0; i < nsyms; i++) - handled = keybinding(mods, syms[i]) || handled; + /* On _press_ if there is no active screen locker, + * attempt to process a compositor keybinding. */ + if (!locked && !input_inhibit_mgr->active_inhibitor + && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + for (i = 0; i < nsyms; i++) + handled = keybinding (mods, syms[i]) || handled; - if (handled && kb->wlr_keyboard->repeat_info.delay > 0) { - kb->mods = mods; - kb->keysyms = syms; - kb->nsyms = nsyms; - wl_event_source_timer_update(kb->key_repeat_source, - kb->wlr_keyboard->repeat_info.delay); - } else { - kb->nsyms = 0; - wl_event_source_timer_update(kb->key_repeat_source, 0); - } + if (handled && kb->wlr_keyboard->repeat_info.delay > 0) { + kb->mods = mods; + kb->keysyms = syms; + kb->nsyms = nsyms; + wl_event_source_timer_update (kb->key_repeat_source, kb->wlr_keyboard->repeat_info.delay); + } else { + kb->nsyms = 0; + wl_event_source_timer_update (kb->key_repeat_source, 0); + } - if (!handled) { - /* Pass unhandled keycodes along to the client. */ - wlr_seat_set_keyboard(seat, kb->wlr_keyboard); - wlr_seat_keyboard_notify_key(seat, event->time_msec, - event->keycode, event->state); - } + if (!handled) { + /* Pass unhandled keycodes along to the client. */ + wlr_seat_set_keyboard (seat, kb->wlr_keyboard); + wlr_seat_keyboard_notify_key (seat, event->time_msec, event->keycode, event->state); + } } void -keypressmod(struct wl_listener *listener, void *data) +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. */ - Keyboard *kb = wl_container_of(listener, kb, modifiers); - /* - * 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 seat. You can swap out the underlying wlr_keyboard like this and - * wlr_seat handles this transparently. - */ - wlr_seat_set_keyboard(seat, kb->wlr_keyboard); - /* Send modifiers to the client. */ - wlr_seat_keyboard_notify_modifiers(seat, - &kb->wlr_keyboard->modifiers); + /* This event is raised when a modifier key, such as shift or alt, is + * pressed. We simply communicate this to the client. */ + Keyboard *kb = wl_container_of (listener, kb, modifiers); + /* + * 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 seat. You can swap out the underlying wlr_keyboard like this and + * wlr_seat handles this transparently. + */ + wlr_seat_set_keyboard (seat, kb->wlr_keyboard); + /* Send modifiers to the client. */ + wlr_seat_keyboard_notify_modifiers (seat, &kb->wlr_keyboard->modifiers); } int -keyrepeat(void *data) +keyrepeat (void *data) { - Keyboard *kb = data; - int i; - if (kb->nsyms && kb->wlr_keyboard->repeat_info.rate > 0) { - wl_event_source_timer_update(kb->key_repeat_source, - 1000 / kb->wlr_keyboard->repeat_info.rate); + Keyboard *kb = data; + int i; + if (kb->nsyms && kb->wlr_keyboard->repeat_info.rate > 0) { + wl_event_source_timer_update (kb->key_repeat_source, + 1000 / kb->wlr_keyboard->repeat_info.rate); - for (i = 0; i < kb->nsyms; i++) - keybinding(kb->mods, kb->keysyms[i]); - } + for (i = 0; i < kb->nsyms; i++) + keybinding (kb->mods, kb->keysyms[i]); + } - return 0; + return 0; } void -killclient(const Arg *arg) +killclient (const Arg *arg) { - Client *sel = focustop(selmon); - if (sel) - client_send_close(sel); + Client *sel = focustop (selmon); + if (sel) + client_send_close (sel); } void -locksession(struct wl_listener *listener, void *data) +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 = ecalloc(1, sizeof(*lock)); - focusclient(NULL, 0); + 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 = ecalloc (1, sizeof (*lock)); + focusclient (NULL, 0); - lock->scene = wlr_scene_tree_create(layers[LyrBlock]); - cur_lock = lock->lock = session_lock; - locked = 1; - session_lock->data = lock; + lock->scene = wlr_scene_tree_create (layers[LyrBlock]); + cur_lock = lock->lock = session_lock; + locked = 1; + session_lock->data = lock; - LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface); - LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); - LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession); + LISTEN (&session_lock->events.new_surface, &lock->new_surface, createlocksurface); + LISTEN (&session_lock->events.destroy, &lock->destroy, destroysessionlock); + LISTEN (&session_lock->events.unlock, &lock->unlock, unlocksession); - wlr_session_lock_v1_send_locked(session_lock); + wlr_session_lock_v1_send_locked (session_lock); } void -maplayersurfacenotify(struct wl_listener *listener, void *data) +maplayersurfacenotify (struct wl_listener *listener, void *data) { - LayerSurface *l = wl_container_of(listener, l, map); - wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output); - motionnotify(0); + LayerSurface *l = wl_container_of (listener, l, map); + wlr_surface_send_enter (l->layer_surface->surface, l->mon->wlr_output); + motionnotify (0); } void -mapnotify(struct wl_listener *listener, void *data) +mapnotify (struct wl_listener *listener, void *data) { - /* Called when the surface is mapped, or ready to display on-screen. */ - Client *p, *w, *c = wl_container_of(listener, c, map); - Monitor *m; - int i; + /* Called when the surface is mapped, or ready to display on-screen. */ + Client *p, *w, *c = wl_container_of (listener, c, map); + Monitor *m; + int i; - /* Create scene tree for this client and its border */ - c->scene = 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)); - if (client_surface(c)) { - client_surface(c)->data = c->scene; - /* Ideally we should do this in createnotify{,x11} but at that moment - * wlr_xwayland_surface doesn't have wlr_surface yet. */ - LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); + /* Create scene tree for this client and its border */ + c->scene = 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)); + if (client_surface (c)) { + client_surface (c)->data = c->scene; + /* Ideally we should do this in createnotify{,x11} but at that + * moment wlr_xwayland_surface doesn't have wlr_surface yet. */ + LISTEN (&client_surface (c)->events.commit, &c->commit, commitnotify); + } + c->scene->node.data = c->scene_surface->node.data = c; + + /* Handle unmanaged clients first so we can return prior create borders */ + if (client_is_unmanaged (c)) { + client_get_geometry (c, &c->geom); + /* 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 + borderpx, c->geom.y + borderpx); + if (client_wants_focus (c)) { + focusclient (c, 1); + exclusive_focus = c; } - c->scene->node.data = c->scene_surface->node.data = c; + goto unset_fullscreen; + } - /* Handle unmanaged clients first so we can return prior create borders */ - if (client_is_unmanaged(c)) { - client_get_geometry(c, &c->geom); - /* 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 + borderpx, - c->geom.y + borderpx); - 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, bordercolor); + c->border[i]->node.data = c; + } - for (i = 0; i < 4; i++) { - c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, 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); + client_get_geometry (c, &c->geom); + c->geom.width += 2 * c->bw; + c->geom.height += 2 * c->bw; - /* Initialize client geometry with room for border */ - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); - client_get_geometry(c, &c->geom); - c->geom.width += 2 * c->bw; - c->geom.height += 2 * c->bw; + /* Insert this client into client lists. */ + wl_list_insert (&clients, &c->link); + wl_list_insert (&fstack, &c->flink); - /* Insert this client into client lists. */ - wl_list_insert(&clients, &c->link); - wl_list_insert(&fstack, &c->flink); - - /* Set initial monitor, tags, floating status, and focus: - * we always consider floating, clients that have parent and thus - * we set the same tags and monitor than its parent, if not - * try to apply rules for them */ - /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */ - if (c->type == XDGShell && (p = client_get_parent(c))) { - c->isfloating = 1; - wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); - setmon(c, p->mon, p->tags); - } else { - applyrules(c); - } - printstatus(); + /* Set initial monitor, tags, floating status, and focus: + * we always consider floating, clients that have parent and thus + * we set the same tags and monitor than its parent, if not + * try to apply rules for them */ + /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */ + if (c->type == XDGShell && (p = client_get_parent (c))) { + c->isfloating = 1; + wlr_scene_node_reparent (&c->scene->node, layers[LyrFloat]); + 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->isfullscreen && m == w->mon && (w->tags & c->tags)) - setfullscreen(w, 0); + m = c->mon ? c->mon : xytomon (c->geom.x, c->geom.y); + wl_list_for_each (w, &clients, link) if (w != c && w->isfullscreen && m == w->mon + && (w->tags & c->tags)) setfullscreen (w, 0); } void -maximizenotify(struct wl_listener *listener, void *data) +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. - * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ - Client *c = wl_container_of(listener, c, maximize); - wlr_xdg_surface_schedule_configure(c->surface.xdg); + /* 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. + * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ + Client *c = wl_container_of (listener, c, maximize); + wlr_xdg_surface_schedule_configure (c->surface.xdg); } void -monocle(Monitor *m) +monocle (Monitor *m) { - Client *c; + Client *c; - wl_list_for_each(c, &clients, link) { - if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) - continue; - resize(c, m->w, 0); + wl_list_for_each (c, &clients, link) + { + if (!VISIBLEON (c, m) || c->isfloating || c->isfullscreen) + continue; + resize (c, m->w, 0); + } + 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; + wlr_cursor_warp_absolute (cursor, &event->pointer->base, event->x, event->y); + motionnotify (event->time_msec); +} + +void +motionnotify (uint32_t time) +{ + double sx = 0, sy = 0; + Client *c = NULL, *w = NULL; + LayerSurface *l = NULL; + int type; + struct wlr_surface *surface = NULL; + struct wlr_drag_icon *icon; + + /* time is 0 in internal calls meant to restore pointer focus. */ + if (time) { + IDLE_NOTIFY_ACTIVITY; + + /* Update selmon (even while dragging a window) */ + if (sloppyfocus) + selmon = xytomon (cursor->x, cursor->y); + } + + /* Update drag icon's position if any */ + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position (icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); + /* 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 = cursor->x - grabcx, + .y = 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 = cursor->x - grabc->geom.x, + .height = cursor->y - grabc->geom.y }, + 1); + return; + } + + /* 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) { + if ((type = toplevel_from_wlr_surface (seat->pointer_state.focused_surface, &w, &l)) >= 0) { + c = w; + surface = seat->pointer_state.focused_surface; + sx = cursor->x - (type == LayerShell ? l->geom.x : w->geom.x); + sy = cursor->y - (type == LayerShell ? l->geom.y : w->geom.y); } - if ((c = focustop(m))) - wlr_scene_node_raise_to_top(&c->scene->node); + } + + /* If there's no client surface under the cursor, set the cursor image to a + * default. This is what makes the cursor image appear when you move it + * off of a client or over its border. */ + if (!surface && !seat->drag && (!cursor_image || strcmp (cursor_image, "left_ptr"))) + wlr_xcursor_manager_set_cursor_image (cursor_mgr, (cursor_image = "left_ptr"), cursor); + + pointerfocus (c, surface, sx, sy, time); } void -motionabsolute(struct wl_listener *listener, void *data) +motionrelative (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; - wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); - motionnotify(event->time_msec); + /* 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. */ + wlr_cursor_move (cursor, &event->pointer->base, event->delta_x, event->delta_y); + motionnotify (event->time_msec); } void -motionnotify(uint32_t time) +moveresize (const Arg *arg) { - double sx = 0, sy = 0; - Client *c = NULL, *w = NULL; - LayerSurface *l = NULL; - int type; - struct wlr_surface *surface = NULL; - struct wlr_drag_icon *icon; + 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; - /* time is 0 in internal calls meant to restore pointer focus. */ - if (time) { - IDLE_NOTIFY_ACTIVITY; - - /* Update selmon (even while dragging a window) */ - if (sloppyfocus) - selmon = xytomon(cursor->x, cursor->y); - } - - /* Update drag icon's position if any */ - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); - /* 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 = cursor->x - grabcx, .y = 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 = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1); - return; - } - - /* 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) { - if ((type = toplevel_from_wlr_surface( - seat->pointer_state.focused_surface, &w, &l)) >= 0) { - c = w; - surface = seat->pointer_state.focused_surface; - sx = cursor->x - (type == LayerShell ? l->geom.x : w->geom.x); - sy = cursor->y - (type == LayerShell ? l->geom.y : w->geom.y); - } - } - - /* If there's no client surface under the cursor, set the cursor image to a - * default. This is what makes the cursor image appear when you move it - * off of a client or over its border. */ - if (!surface && !seat->drag && (!cursor_image || strcmp(cursor_image, "left_ptr"))) - wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor); - - pointerfocus(c, surface, sx, sy, time); + /* Float the window and tell motionnotify to grab it */ + setfloating (grabc, 1); + switch (cursor_mode = arg->ui) { + case CurMove: + grabcx = cursor->x - grabc->geom.x; + grabcy = cursor->y - grabc->geom.y; + wlr_xcursor_manager_set_cursor_image (cursor_mgr, (cursor_image = "fleur"), cursor); + 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_xcursor_manager_set_cursor_image (cursor_mgr, (cursor_image = "bottom_right_corner"), + cursor); + break; + } } void -motionrelative(struct wl_listener *listener, void *data) +outputmgrapply (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. */ - wlr_cursor_move(cursor, &event->pointer->base, event->delta_x, event->delta_y); - motionnotify(event->time_msec); + struct wlr_output_configuration_v1 *config = data; + outputmgrapplyortest (config, 0); } void -moveresize(const Arg *arg) +outputmgrapplyortest (struct wlr_output_configuration_v1 *config, int test) { - 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; + /* + * 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; - /* Float the window and tell motionnotify to grab it */ - setfloating(grabc, 1); - switch (cursor_mode = arg->ui) { - case CurMove: - grabcx = cursor->x - grabc->geom.x; - grabcy = cursor->y - grabc->geom.y; - wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "fleur"), cursor); - 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_xcursor_manager_set_cursor_image(cursor_mgr, - (cursor_image = "bottom_right_corner"), cursor); - break; - } -} + wl_list_for_each (config_head, &config->heads, link) + { + struct wlr_output *wlr_output = config_head->state.output; + Monitor *m = wlr_output->data; -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; - - wlr_output_enable(wlr_output, config_head->state.enabled); - if (!config_head->state.enabled) - goto apply_or_test; - if (config_head->state.mode) - wlr_output_set_mode(wlr_output, config_head->state.mode); - else - wlr_output_set_custom_mode(wlr_output, - config_head->state.custom_mode.width, - config_head->state.custom_mode.height, - config_head->state.custom_mode.refresh); - - /* Don't move monitors if position wouldn't change, this to avoid - * wlroots marking the output as manually configured */ - if (m->m.x != config_head->state.x || m->m.y != config_head->state.y) - wlr_output_layout_move(output_layout, wlr_output, - config_head->state.x, config_head->state.y); - wlr_output_set_transform(wlr_output, config_head->state.transform); - wlr_output_set_scale(wlr_output, config_head->state.scale); - wlr_output_enable_adaptive_sync(wlr_output, - config_head->state.adaptive_sync_enabled); - -apply_or_test: - if (test) { - ok &= wlr_output_test(wlr_output); - wlr_output_rollback(wlr_output); - } else { - ok &= wlr_output_commit(wlr_output); - } - } - - if (ok) - wlr_output_configuration_v1_send_succeeded(config); + wlr_output_enable (wlr_output, config_head->state.enabled); + if (!config_head->state.enabled) + goto apply_or_test; + if (config_head->state.mode) + wlr_output_set_mode (wlr_output, config_head->state.mode); else - wlr_output_configuration_v1_send_failed(config); - wlr_output_configuration_v1_destroy(config); + wlr_output_set_custom_mode (wlr_output, config_head->state.custom_mode.width, + config_head->state.custom_mode.height, + config_head->state.custom_mode.refresh); - /* TODO: use a wrapper function? */ - updatemons(NULL, NULL); -} + /* Don't move monitors if position wouldn't change, this to avoid + * wlroots marking the output as manually configured */ + if (m->m.x != config_head->state.x || m->m.y != config_head->state.y) + wlr_output_layout_move (output_layout, wlr_output, config_head->state.x, + config_head->state.y); + wlr_output_set_transform (wlr_output, config_head->state.transform); + wlr_output_set_scale (wlr_output, config_head->state.scale); + wlr_output_enable_adaptive_sync (wlr_output, config_head->state.adaptive_sync_enabled); -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; - int internal_call = !time; - - if (sloppyfocus && !internal_call && 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 (internal_call) { - 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; - unsigned int 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 %u\n", m->wlr_output->name, c->isfullscreen); - printf("%s floating %u\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 %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags], - sel, urg); - printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol); - } - fflush(stdout); -} - -void -quit(const Arg *arg) -{ - wl_display_terminate(dpy); -} - -void -quitsignal(int signo) -{ - quit(NULL); -} - -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 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; - if (!wlr_scene_output_commit(m->scene_output)) - return; -skip: - /* Let clients know a frame has been rendered */ - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_scene_output_send_frame_done(m->scene_output, &now); -} - -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 -resize(Client *c, struct wlr_box geo, int interact) -{ - struct wlr_box *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); -} - -void -run(char *startup_cmd) -{ - /* Add a Unix socket to the Wayland display. */ - const char *socket = wl_display_add_socket_auto(dpy); - struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SIG_IGN}; - sigemptyset(&sa.sa_mask); - 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) { - 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]); - } - /* If nobody is reading the status output, don't terminate */ - sigaction(SIGPIPE, &sa, NULL); - 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_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, cursor); - - /* 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; - cursor_image = NULL; - /* 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 -setfloating(Client *c, int floating) -{ - c->isfloating = floating; - wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); - arrange(c->mon); - printstatus(); -} - -void -setfullscreen(Client *c, int fullscreen) -{ - c->isfullscreen = fullscreen; - if (!c->mon) - return; - c->bw = fullscreen ? 0 : borderpx; - client_set_fullscreen(c, fullscreen); - wlr_scene_node_reparent(&c->scene->node, layers[fullscreen - ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); - - if (fullscreen) { - c->prev = c->geom; - resize(c, c->mon->m, 0); + apply_or_test: + if (test) { + ok &= wlr_output_test (wlr_output); + wlr_output_rollback (wlr_output); } 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); + ok &= wlr_output_commit (wlr_output); } - arrange(c->mon); - printstatus(); + } + + if (ok) + wlr_output_configuration_v1_send_succeeded (config); + else + wlr_output_configuration_v1_send_failed (config); + wlr_output_configuration_v1_destroy (config); + + /* TODO: use a wrapper function? */ + updatemons (NULL, NULL); } void -setlayout(const Arg *arg) +outputmgrtest (struct wl_listener *listener, void *data) { - 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; - /* TODO change layout symbol? */ - arrange(selmon); - printstatus(); + 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; + int internal_call = !time; + + if (sloppyfocus && !internal_call && 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 (internal_call) { + 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; + unsigned int 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 %u\n", m->wlr_output->name, c->isfullscreen); + printf ("%s floating %u\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 %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); + printf ("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol); + } + fflush (stdout); +} + +void +quit (const Arg *arg) +{ + wl_display_terminate (dpy); +} + +void +quitsignal (int signo) +{ + quit (NULL); +} + +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 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; + if (!wlr_scene_output_commit (m->scene_output)) + return; +skip: + /* Let clients know a frame has been rendered */ + clock_gettime (CLOCK_MONOTONIC, &now); + wlr_scene_output_send_frame_done (m->scene_output, &now); +} + +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 +resize (Client *c, struct wlr_box geo, int interact) +{ + struct wlr_box *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); +} + +void +run (char *startup_cmd) +{ + /* Add a Unix socket to the Wayland display. */ + const char *socket = wl_display_add_socket_auto (dpy); + struct sigaction sa = { .sa_flags = SA_RESTART, .sa_handler = SIG_IGN }; + sigemptyset (&sa.sa_mask); + 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) { + 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]); + } + /* If nobody is reading the status output, don't terminate */ + sigaction (SIGPIPE, &sa, NULL); + 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_xcursor_manager_set_cursor_image (cursor_mgr, cursor_image, cursor); + + /* 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; + cursor_image = NULL; + /* 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 +setfloating (Client *c, int floating) +{ + c->isfloating = floating; + wlr_scene_node_reparent (&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); + arrange (c->mon); + printstatus (); +} + +void +setfullscreen (Client *c, int fullscreen) +{ + c->isfullscreen = fullscreen; + if (!c->mon) + return; + c->bw = fullscreen ? 0 : borderpx; + client_set_fullscreen (c, fullscreen); + wlr_scene_node_reparent (&c->scene->node, layers[fullscreen ? 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 +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; + /* TODO change layout symbol? */ + arrange (selmon); + printstatus (); } /* arg > 1.0 will set mfact absolutely */ void -setmfact(const Arg *arg) +setmfact (const Arg *arg) { - float f; + float f; - if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) - return; - f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; - if (f < 0.1 || f > 0.9) - return; - selmon->mfact = f; - arrange(selmon); + if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; + selmon->mfact = f; + arrange (selmon); } void -setmon(Client *c, Monitor *m, unsigned int newtags) +setmon (Client *c, Monitor *m, unsigned int newtags) { - Monitor *oldmon = c->mon; + Monitor *oldmon = c->mon; - if (oldmon == m) - return; - c->mon = m; - c->prev = c->geom; + if (oldmon == m) + return; + c->mon = m; + c->prev = c->geom; - /* TODO leave/enter is not optimal but works */ - if (oldmon) { - wlr_surface_send_leave(client_surface(c), oldmon->wlr_output); - arrange(oldmon); - } - if (m) { - /* Make sure window actually overlaps with the monitor */ - resize(c, c->geom, 0); - wlr_surface_send_enter(client_surface(c), m->wlr_output); - c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ - setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ - } - focusclient(focustop(selmon), 1); + /* TODO leave/enter is not optimal but works */ + if (oldmon) { + wlr_surface_send_leave (client_surface (c), oldmon->wlr_output); + arrange (oldmon); + } + if (m) { + /* Make sure window actually overlaps with the monitor */ + resize (c, c->geom, 0); + wlr_surface_send_enter (client_surface (c), m->wlr_output); + c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of + target monitor */ + setfullscreen (c, c->isfullscreen); /* This will call arrange(c->mon) */ + } + focusclient (focustop (selmon), 1); } void -setpsel(struct wl_listener *listener, void *data) +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); + /* 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) +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); + /* 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) +setup (void) { - struct sigaction sa_term = {.sa_flags = SA_RESTART, .sa_handler = quitsignal}; - struct sigaction sa_sigchld = { + struct sigaction sa_term = { .sa_flags = SA_RESTART, .sa_handler = quitsignal }; + struct sigaction sa_sigchld = { #ifdef XWAYLAND - .sa_flags = SA_RESTART, - .sa_handler = sigchld, + .sa_flags = SA_RESTART, + .sa_handler = sigchld, #else - .sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART, - .sa_handler = SIG_IGN, + .sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART, + .sa_handler = SIG_IGN, #endif - }; - sigemptyset(&sa_term.sa_mask); - sigemptyset(&sa_sigchld.sa_mask); - /* 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(); + }; + sigemptyset (&sa_term.sa_mask); + sigemptyset (&sa_sigchld.sa_mask); + /* 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 (); - /* Set up signal handlers */ - sigaction(SIGCHLD, &sa_sigchld, NULL); - sigaction(SIGINT, &sa_term, NULL); - sigaction(SIGTERM, &sa_term, NULL); + /* Set up signal handlers */ + sigaction (SIGCHLD, &sa_sigchld, NULL); + sigaction (SIGINT, &sa_term, NULL); + sigaction (SIGTERM, &sa_term, NULL); - /* 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. The NULL argument here optionally allows you - * to pass in a custom renderer if wlr_renderer doesn't meet your needs. The - * backend uses the renderer, for example, to fall back to software cursors - * if the backend does not support hardware cursors (some older GPUs - * don't). */ - if (!(backend = wlr_backend_autocreate(dpy))) - die("couldn't create backend"); + /* The backend is a wlroots feature which abstracts the underlying input + * and output hardware. The autocreate option will choose the most suitable + * backend based on the current environment, such as opening an X11 window + * if an X11 server is running. The NULL argument here optionally allows + * you to pass in a custom renderer if wlr_renderer doesn't meet your + * needs. The backend uses the renderer, for example, to fall back to + * software cursors if the backend does not support hardware cursors (some + * older GPUs don't). */ + if (!(backend = wlr_backend_autocreate (dpy))) + die ("couldn't create backend"); - /* Initialize the scene graph used to lay out windows */ - scene = wlr_scene_create(); - layers[LyrBg] = wlr_scene_tree_create(&scene->tree); - layers[LyrBottom] = wlr_scene_tree_create(&scene->tree); - layers[LyrTile] = wlr_scene_tree_create(&scene->tree); - layers[LyrFloat] = wlr_scene_tree_create(&scene->tree); - layers[LyrFS] = wlr_scene_tree_create(&scene->tree); - layers[LyrTop] = wlr_scene_tree_create(&scene->tree); - layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree); - layers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree); - layers[LyrBlock] = wlr_scene_tree_create(&scene->tree); + /* Initialize the scene graph used to lay out windows */ + scene = wlr_scene_create (); + layers[LyrBg] = wlr_scene_tree_create (&scene->tree); + layers[LyrBottom] = wlr_scene_tree_create (&scene->tree); + layers[LyrTile] = wlr_scene_tree_create (&scene->tree); + layers[LyrFloat] = wlr_scene_tree_create (&scene->tree); + layers[LyrFS] = wlr_scene_tree_create (&scene->tree); + layers[LyrTop] = wlr_scene_tree_create (&scene->tree); + layers[LyrOverlay] = wlr_scene_tree_create (&scene->tree); + layers[LyrDragIcon] = wlr_scene_tree_create (&scene->tree); + layers[LyrBlock] = wlr_scene_tree_create (&scene->tree); - /* Create a renderer with the default implementation */ - if (!(drw = wlr_renderer_autocreate(backend))) - die("couldn't create renderer"); - wlr_renderer_init_wl_display(drw, dpy); + /* Create a renderer with the default implementation */ + if (!(drw = wlr_renderer_autocreate (backend))) + die ("couldn't create renderer"); + wlr_renderer_init_wl_display (drw, dpy); - /* Create a default allocator */ - if (!(alloc = wlr_allocator_autocreate(backend, drw))) - die("couldn't create allocator"); + /* Create a default allocator */ + 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, drw); - wlr_export_dmabuf_manager_v1_create(dpy); - wlr_screencopy_manager_v1_create(dpy); - wlr_data_control_manager_v1_create(dpy); - wlr_data_device_manager_create(dpy); - wlr_gamma_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_subcompositor_create(dpy); + /* This creates some hands-off wlroots interfaces. The compositor is + * necessary for clients to allocate surfaces and the data device manager + * handles the clipboard. Each of these wlroots interfaces has room for you + * to dig your fingers in and play with their behavior if you want. Note + * that the clients cannot set the selection directly without compositor + * approval, see the setsel() function. */ + compositor = wlr_compositor_create (dpy, drw); + wlr_export_dmabuf_manager_v1_create (dpy); + wlr_screencopy_manager_v1_create (dpy); + wlr_data_control_manager_v1_create (dpy); + wlr_data_device_manager_create (dpy); + wlr_gamma_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_subcompositor_create (dpy); - /* Initializes the interface used to implement urgency hints */ - activation = wlr_xdg_activation_v1_create(dpy); - wl_signal_add(&activation->events.request_activate, &request_activate); + /* Initializes the interface used to implement urgency hints */ + activation = wlr_xdg_activation_v1_create (dpy); + wl_signal_add (&activation->events.request_activate, &request_activate); - /* 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(); - wl_signal_add(&output_layout->events.change, &layout_change); - wlr_xdg_output_manager_v1_create(dpy, output_layout); + /* Creates an output layout, which a wlroots utility for working with an + * arrangement of screens in a physical layout. */ + output_layout = wlr_output_layout_create (); + wl_signal_add (&output_layout->events.change, &layout_change); + 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); - wl_signal_add(&backend->events.new_output, &new_output); + /* Configure a listener to be notified when new outputs are available on + * the backend. */ + wl_list_init (&mons); + wl_signal_add (&backend->events.new_output, &new_output); - /* Set up our client lists and the xdg-shell. The xdg-shell is a - * Wayland protocol which is used for application windows. For more - * detail on shells, refer to the article: - * - * https://drewdevault.com/2018/07/29/Wayland-shells.html - */ - wl_list_init(&clients); - wl_list_init(&fstack); + /* Set up our client lists and the xdg-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); - idle = wlr_idle_create(dpy); - idle_notifier = wlr_idle_notifier_v1_create(dpy); + idle = wlr_idle_create (dpy); + idle_notifier = wlr_idle_notifier_v1_create (dpy); - idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); - wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); + idle_inhibit_mgr = wlr_idle_inhibit_v1_create (dpy); + wl_signal_add (&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); - layer_shell = wlr_layer_shell_v1_create(dpy); - wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); + layer_shell = wlr_layer_shell_v1_create (dpy); + wl_signal_add (&layer_shell->events.new_surface, &new_layer_shell_surface); - xdg_shell = wlr_xdg_shell_create(dpy, 4); - wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); + xdg_shell = wlr_xdg_shell_create (dpy, 4); + wl_signal_add (&xdg_shell->events.new_surface, &new_xdg_surface); - input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); - session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); - wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock); - wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy); - locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, - (float [4]){0.1, 0.1, 0.1, 1.0}); - wlr_scene_node_set_enabled(&locked_bg->node, 0); + input_inhibit_mgr = wlr_input_inhibit_manager_create (dpy); + session_lock_mgr = wlr_session_lock_manager_v1_create (dpy); + wl_signal_add (&session_lock_mgr->events.new_lock, &session_lock_create_lock); + wl_signal_add (&session_lock_mgr->events.destroy, &session_lock_mgr_destroy); + locked_bg = wlr_scene_rect_create (layers[LyrBlock], sgeom.width, sgeom.height, + (float[4]){ 0.1, 0.1, 0.1, 1.0 }); + 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); - wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration); + /* 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); + wl_signal_add (&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration); - /* - * Creates a cursor, which is a wlroots utility for tracking the cursor - * image shown on screen. - */ - cursor = wlr_cursor_create(); - wlr_cursor_attach_output_layout(cursor, output_layout); + /* + * Creates a cursor, which is a wlroots utility for tracking the cursor + * image shown on screen. + */ + cursor = wlr_cursor_create (); + wlr_cursor_attach_output_layout (cursor, output_layout); - /* Creates an xcursor manager, another wlroots utility which loads up - * Xcursor themes to source cursor images from and makes sure that cursor - * images are available at all scale factors on the screen (necessary for - * HiDPI support). Scaled cursors will be loaded with each output. */ - cursor_mgr = wlr_xcursor_manager_create(NULL, 24); + /* 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); - /* - * 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 my - * input handling blog post: - * - * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html - * - * And more comments are sprinkled throughout the notify functions above. - */ - wl_signal_add(&cursor->events.motion, &cursor_motion); - wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute); - wl_signal_add(&cursor->events.button, &cursor_button); - wl_signal_add(&cursor->events.axis, &cursor_axis); - wl_signal_add(&cursor->events.frame, &cursor_frame); + /* + * 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 my + * input handling blog post: + * + * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html + * + * And more comments are sprinkled throughout the notify functions above. + */ + wl_signal_add (&cursor->events.motion, &cursor_motion); + wl_signal_add (&cursor->events.motion_absolute, &cursor_motion_absolute); + wl_signal_add (&cursor->events.button, &cursor_button); + wl_signal_add (&cursor->events.axis, &cursor_axis); + wl_signal_add (&cursor->events.frame, &cursor_frame); - /* - * 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. - */ - wl_list_init(&keyboards); - wl_signal_add(&backend->events.new_input, &new_input); - virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); - wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, - &new_virtual_keyboard); - seat = wlr_seat_create(dpy, "seat0"); - wl_signal_add(&seat->events.request_set_cursor, &request_cursor); - wl_signal_add(&seat->events.request_set_selection, &request_set_sel); - wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel); - wl_signal_add(&seat->events.request_start_drag, &request_start_drag); - wl_signal_add(&seat->events.start_drag, &start_drag); + /* + * 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. + */ + wl_list_init (&keyboards); + wl_signal_add (&backend->events.new_input, &new_input); + virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create (dpy); + wl_signal_add (&virtual_keyboard_mgr->events.new_virtual_keyboard, &new_virtual_keyboard); + seat = wlr_seat_create (dpy, "seat0"); + wl_signal_add (&seat->events.request_set_cursor, &request_cursor); + wl_signal_add (&seat->events.request_set_selection, &request_set_sel); + wl_signal_add (&seat->events.request_set_primary_selection, &request_set_psel); + wl_signal_add (&seat->events.request_start_drag, &request_start_drag); + wl_signal_add (&seat->events.start_drag, &start_drag); - output_mgr = wlr_output_manager_v1_create(dpy); - wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); - wl_signal_add(&output_mgr->events.test, &output_mgr_test); + output_mgr = wlr_output_manager_v1_create (dpy); + wl_signal_add (&output_mgr->events.apply, &output_mgr_apply); + wl_signal_add (&output_mgr->events.test, &output_mgr_test); - wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); + wlr_scene_set_presentation (scene, wlr_presentation_create (dpy, backend)); #ifdef XWAYLAND - /* - * Initialise the XWayland X server. - * It will be started when the first X client is started. - */ - xwayland = wlr_xwayland_create(dpy, compositor, 1); - if (xwayland) { - wl_signal_add(&xwayland->events.ready, &xwayland_ready); - wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface); + /* + * Initialise the XWayland X server. + * It will be started when the first X client is started. + */ + xwayland = wlr_xwayland_create (dpy, compositor, 1); + if (xwayland) { + wl_signal_add (&xwayland->events.ready, &xwayland_ready); + wl_signal_add (&xwayland->events.new_surface, &new_xwayland_surface); - setenv("DISPLAY", xwayland->display_name, 1); - } else { - fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); - } + setenv ("DISPLAY", xwayland->display_name, 1); + } else { + fprintf (stderr, "failed to setup XWayland X server, continuing without it\n"); + } #endif } void -spawn(const Arg *arg) +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]); - } + 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) +startdrag (struct wl_listener *listener, void *data) { - struct wlr_drag *drag = data; + struct wlr_drag *drag = data; - if (!drag->icon) - return; + if (!drag->icon) + return; - drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrDragIcon], drag->icon->surface); - motionnotify(0); - wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); + drag->icon->data = wlr_scene_subsurface_tree_create (layers[LyrDragIcon], drag->icon->surface); + motionnotify (0); + wl_signal_add (&drag->icon->events.destroy, &drag_icon_destroy); } void -tag(const Arg *arg) +tag (const Arg *arg) { - Client *sel = focustop(selmon); - if (sel && arg->ui & TAGMASK) { - sel->tags = arg->ui & TAGMASK; - focusclient(focustop(selmon), 1); - arrange(selmon); - } - printstatus(); + Client *sel = focustop (selmon); + if (sel && arg->ui & TAGMASK) { + sel->tags = arg->ui & TAGMASK; + focusclient (focustop (selmon), 1); + arrange (selmon); + } + printstatus (); } void -tagmon(const Arg *arg) +tagmon (const Arg *arg) { - Client *sel = focustop(selmon); - if (sel) - setmon(sel, dirtomon(arg->i), 0); + Client *sel = focustop (selmon); + if (sel) + setmon (sel, dirtomon (arg->i), 0); } void -tile(Monitor *m) +tile (Monitor *m) { - unsigned int i, n = 0, mw, my, ty; - Client *c; + unsigned int i, n = 0, mw, my, ty; + Client *c; - wl_list_for_each(c, &clients, link) - if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) - n++; - if (n == 0) - return; + 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 ? 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) -{ - unsigned int newtags; - Client *sel = focustop(selmon); - if (!sel) - return; - newtags = sel->tags ^ (arg->ui & TAGMASK); - if (newtags) { - sel->tags = newtags; - focusclient(focustop(selmon), 1); - arrange(selmon); - } - printstatus(); -} - -void -toggleview(const Arg *arg) -{ - unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; - - if (newtagset) { - 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 *layersurface = wl_container_of(listener, layersurface, unmap); - - layersurface->mapped = 0; - wlr_scene_node_set_enabled(&layersurface->scene->node, 0); - if (layersurface == exclusive_focus) - exclusive_focus = NULL; - if (layersurface->layer_surface->output - && (layersurface->mon = layersurface->layer_surface->output->data)) - arrangelayers(layersurface->mon); - if (layersurface->layer_surface->surface == - seat->keyboard_state.focused_surface) - focusclient(focustop(selmon), 1); - motionnotify(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; - if (client_surface(c) == seat->keyboard_state.focused_surface) - focusclient(focustop(selmon), 1); + if (n > m->nmaster) + mw = m->nmaster ? 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 { - wl_list_remove(&c->link); - setmon(c, NULL, 0); - wl_list_remove(&c->flink); + 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; } - - wl_list_remove(&c->commit.link); - wlr_scene_node_destroy(&c->scene->node); - printstatus(); - motionnotify(0); + i++; + } } void -updatemons(struct wl_listener *listener, void *data) +togglefloating (const Arg *arg) { - /* - * 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. + 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) +{ + unsigned int newtags; + Client *sel = focustop (selmon); + if (!sel) + return; + newtags = sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + sel->tags = newtags; + focusclient (focustop (selmon), 1); + arrange (selmon); + } + printstatus (); +} + +void +toggleview (const Arg *arg) +{ + unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; + + if (newtagset) { + 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 *layersurface = wl_container_of (listener, layersurface, unmap); + + layersurface->mapped = 0; + wlr_scene_node_set_enabled (&layersurface->scene->node, 0); + if (layersurface == exclusive_focus) + exclusive_focus = NULL; + if (layersurface->layer_surface->output + && (layersurface->mon = layersurface->layer_surface->output->data)) + arrangelayers (layersurface->mon); + if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) + focusclient (focustop (selmon), 1); + motionnotify (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; + if (client_surface (c) == seat->keyboard_state.focused_surface) + focusclient (focustop (selmon), 1); + } else { + wl_list_remove (&c->link); + setmon (c, NULL, 0); + wl_list_remove (&c->flink); + } + + wl_list_remove (&c->commit.link); + wlr_scene_node_destroy (&c->scene->node); + printstatus (); + motionnotify (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) + 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 */ - struct wlr_output_configuration_v1 *config = - wlr_output_configuration_v1_create(); - Client *c; - struct wlr_output_configuration_head_v1 *config_head; - Monitor *m; + wlr_output_layout_remove (output_layout, m->wlr_output); + closemon (m); + memset (&m->m, 0, sizeof (m->m)); + memset (&m->w, 0, sizeof (m->w)); + } + /* 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); - /* First remove from the layout the disabled monitors */ - 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); - 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); - memset(&m->m, 0, sizeof(m->m)); - memset(&m->w, 0, sizeof(m->w)); - } - /* 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); - /* Now that we update the output layout we can get its box */ - wlr_output_layout_get_box(output_layout, NULL, &sgeom); + /* 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); - /* 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); - 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)); + wlr_output_layout_get_box (output_layout, m->wlr_output, &(m->w)); + wlr_scene_output_set_position (m->scene_output, m->m.x, m->m.y); - /* Get the effective monitor geometry to use for surfaces */ - wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m)); - wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w)); - 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); - 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); - - config_head->state.enabled = 1; - config_head->state.mode = m->wlr_output->current_mode; - config_head->state.x = m->m.x; - config_head->state.y = m->m.y; + 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); } - if (selmon && selmon->wlr_output->enabled) { - wl_list_for_each(c, &clients, link) - if (!c->mon && client_is_mapped(c)) - setmon(c, selmon, c->tags); - if (selmon->lock_surface) - client_notify_enter(selmon->lock_surface->surface, - wlr_seat_get_keyboard(seat)); - } + /* Calculate the effective monitor geometry to use for clients */ + arrangelayers (m); + /* Don't move clients to the left output when plugging monitors */ + arrange (m); - wlr_output_manager_v1_set_configuration(output_mgr, config); + config_head->state.enabled = 1; + config_head->state.mode = m->wlr_output->current_mode; + config_head->state.x = m->m.x; + config_head->state.y = m->m.y; + } + + if (selmon && selmon->wlr_output->enabled) { + wl_list_for_each (c, &clients, link) if (!c->mon && client_is_mapped (c)) + setmon (c, selmon, c->tags); + if (selmon->lock_surface) + client_notify_enter (selmon->lock_surface->surface, wlr_seat_get_keyboard (seat)); + } + + wlr_output_manager_v1_set_configuration (output_mgr, config); } void -updatetitle(struct wl_listener *listener, void *data) +updatetitle (struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, set_title); - if (c == focustop(c->mon)) - printstatus(); + Client *c = wl_container_of (listener, c, set_title); + if (c == focustop (c->mon)) + printstatus (); } void -urgent(struct wl_listener *listener, void *data) +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)) { - c->isurgent = 1; - printstatus(); - } + 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)) { + c->isurgent = 1; + printstatus (); + } } void -view(const Arg *arg) +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(); + 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) +virtualkeyboard (struct wl_listener *listener, void *data) { - struct wlr_virtual_keyboard_v1 *keyboard = data; - createkeyboard(&keyboard->keyboard); + struct wlr_virtual_keyboard_v1 *keyboard = data; + createkeyboard (&keyboard->keyboard); } Monitor * -xytomon(double x, double y) +xytomon (double x, double y) { - struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); - return o ? o->data : NULL; + struct wlr_output *o = wlr_output_layout_output_at (output_layout, x, y); + return o ? o->data : NULL; } struct wlr_scene_node * -xytonode(double x, double y, struct wlr_surface **psurface, - Client **pc, LayerSurface **pl, double *nx, double *ny) +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; - const int *layer; - int focus_order[] = { LyrBlock, LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg }; + struct wlr_scene_node *node, *pnode; + struct wlr_surface *surface = NULL; + Client *c = NULL; + LayerSurface *l = NULL; + const int *layer; + int focus_order[] + = { LyrBlock, LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg }; - for (layer = focus_order; layer < END(focus_order); layer++) { - if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) { - if (node->type == WLR_SCENE_NODE_BUFFER) - surface = wlr_scene_surface_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 (surface) - break; + for (layer = focus_order; layer < END (focus_order); layer++) { + if ((node = wlr_scene_node_at (&layers[*layer]->node, x, y, nx, ny))) { + if (node->type == WLR_SCENE_NODE_BUFFER) + surface + = wlr_scene_surface_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 (surface) + break; + } - if (psurface) *psurface = surface; - if (pc) *pc = c; - if (pl) *pl = l; - return node; + if (psurface) + *psurface = surface; + if (pc) + *pc = c; + if (pl) + *pl = l; + return node; } void -zoom(const Arg *arg) +zoom (const Arg *arg) { - Client *c, *sel = focustop(selmon); + Client *c, *sel = focustop (selmon); - if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) - return; + 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; - } + /* 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; + /* 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); + /* If we passed sel, move c to the front; otherwise, move sel to the + * front */ + if (!sel) + sel = c; + wl_list_remove (&sel->link); + wl_list_insert (&clients, &sel->link); - focusclient(sel, 1); - arrange(selmon); + focusclient (sel, 1); + arrange (selmon); } #ifdef XWAYLAND void -activatex11(struct wl_listener *listener, void *data) +activatex11 (struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, activate); + Client *c = wl_container_of (listener, c, activate); - /* Only "managed" windows can be activated */ - if (c->type == X11Managed) - wlr_xwayland_surface_activate(c->surface.xwayland, 1); + /* Only "managed" windows can be activated */ + if (c->type == X11Managed) + wlr_xwayland_surface_activate (c->surface.xwayland, 1); } void -configurex11(struct wl_listener *listener, void *data) +configurex11 (struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, configure); - struct wlr_xwayland_surface_configure_event *event = data; - if (!c->mon) - return; - if (c->isfloating || c->type == X11Unmanaged) - resize(c, (struct wlr_box){.x = event->x, .y = event->y, - .width = event->width, .height = event->height}, 0); - else - arrange(c->mon); + Client *c = wl_container_of (listener, c, configure); + struct wlr_xwayland_surface_configure_event *event = data; + if (!c->mon) + return; + if (c->isfloating || c->type == X11Unmanaged) + resize (c, + (struct wlr_box){ + .x = event->x, .y = event->y, .width = event->width, .height = event->height }, + 0); + else + arrange (c->mon); } void -createnotifyx11(struct wl_listener *listener, void *data) +createnotifyx11 (struct wl_listener *listener, void *data) { - struct wlr_xwayland_surface *xsurface = data; - Client *c; + 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 = xsurface->override_redirect ? X11Unmanaged : X11Managed; - c->bw = borderpx; + /* Allocate a Client for this surface */ + c = xsurface->data = ecalloc (1, sizeof (*c)); + c->surface.xwayland = xsurface; + c->type = xsurface->override_redirect ? X11Unmanaged : X11Managed; + c->bw = borderpx; - /* Listen to the various events it can emit */ - LISTEN(&xsurface->events.map, &c->map, mapnotify); - LISTEN(&xsurface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); - LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); - LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); - LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); - LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); + /* Listen to the various events it can emit */ + LISTEN (&xsurface->events.map, &c->map, mapnotify); + LISTEN (&xsurface->events.unmap, &c->unmap, unmapnotify); + LISTEN (&xsurface->events.request_activate, &c->activate, activatex11); + LISTEN (&xsurface->events.request_configure, &c->configure, configurex11); + LISTEN (&xsurface->events.set_hints, &c->set_hints, sethints); + LISTEN (&xsurface->events.set_title, &c->set_title, updatetitle); + LISTEN (&xsurface->events.destroy, &c->destroy, destroynotify); + LISTEN (&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); } Atom -getatom(xcb_connection_t *xc, const char *name) +getatom (xcb_connection_t *xc, const char *name) { - Atom 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); + Atom atom = 0; + xcb_intern_atom_reply_t *reply; + xcb_intern_atom_cookie_t cookie = xcb_intern_atom (xc, 0, strlen (name), name); + if ((reply = xcb_intern_atom_reply (xc, cookie, NULL))) + atom = reply->atom; + free (reply); - return atom; + return atom; } void -sethints(struct wl_listener *listener, void *data) +sethints (struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, set_hints); - if (c != focustop(selmon)) { - c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); - printstatus(); - } + Client *c = wl_container_of (listener, c, set_hints); + if (c != focustop (selmon)) { + c->isurgent = xcb_icccm_wm_hints_get_urgency (c->surface.xwayland->hints); + printstatus (); + } } void -sigchld(int unused) +sigchld (int unused) { - siginfo_t in; - /* We should be able to remove this function in favor of a simple - * struct sigaction sa = {.sa_handler = SIG_IGN}; - * sigaction(SIGCHLD, &sa, NULL); - * but the Xwayland implementation in wlroots currently prevents us from - * setting our own disposition for SIGCHLD. - */ - /* WNOWAIT leaves the child in a waitable state, in case this is the - * XWayland process - */ - while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); + siginfo_t in; + /* We should be able to remove this function in favor of a simple + * struct sigaction sa = {.sa_handler = SIG_IGN}; + * sigaction(SIGCHLD, &sa, NULL); + * but the Xwayland implementation in wlroots currently prevents us from + * setting our own disposition for SIGCHLD. + */ + /* WNOWAIT leaves the child in a waitable state, in case this is the + * XWayland process + */ + 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); } void -xwaylandready(struct wl_listener *listener, void *data) +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; - } + struct wlr_xcursor *xcursor; + xcb_connection_t *xc = xcb_connect (xwayland->display_name, NULL); + int err = xcb_connection_has_error (xc); + if (err) { + fprintf (stderr, + "xcb_connect to X server failed with code %d\n. Continuing " + "with degraded functionality.\n", + err); + return; + } - /* Collect atoms we are interested in. If getatom returns 0, we will - * not detect that window type. */ - netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG"); - netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH"); - netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR"); - netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY"); + /* Collect atoms we are interested in. If getatom returns 0, we will + * not detect that window type. */ + netatom[NetWMWindowTypeDialog] = getatom (xc, "_NET_WM_WINDOW_TYPE_DIALOG"); + netatom[NetWMWindowTypeSplash] = getatom (xc, "_NET_WM_WINDOW_TYPE_SPLASH"); + netatom[NetWMWindowTypeToolbar] = getatom (xc, "_NET_WM_WINDOW_TYPE_TOOLBAR"); + netatom[NetWMWindowTypeUtility] = getatom (xc, "_NET_WM_WINDOW_TYPE_UTILITY"); - /* assign the one and only seat */ - wlr_xwayland_set_seat(xwayland, seat); + /* assign the one and only seat */ + wlr_xwayland_set_seat (xwayland, seat); - /* Set the default XWayland cursor to match the rest of dwl. */ - if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "left_ptr", 1))) - wlr_xwayland_set_cursor(xwayland, - xcursor->images[0]->buffer, xcursor->images[0]->width * 4, - xcursor->images[0]->width, xcursor->images[0]->height, - xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); + /* Set the default XWayland cursor to match the rest of dwl. */ + if ((xcursor = wlr_xcursor_manager_get_xcursor (cursor_mgr, "left_ptr", 1))) + wlr_xwayland_set_cursor (xwayland, xcursor->images[0]->buffer, + xcursor->images[0]->width * 4, xcursor->images[0]->width, + xcursor->images[0]->height, xcursor->images[0]->hotspot_x, + xcursor->images[0]->hotspot_y); - xcb_disconnect(xc); + xcb_disconnect (xc); } #endif int -main(int argc, char *argv[]) +main (int argc, char *argv[]) { - char *startup_cmd = NULL; - int c; + char *startup_cmd = NULL; + int c; - while ((c = getopt(argc, argv, "s:hv")) != -1) { - if (c == 's') - startup_cmd = optarg; - else if (c == 'v') - die("dwl " VERSION); - else - goto usage; - } - if (optind < argc) - goto usage; + while ((c = getopt (argc, argv, "s:hv")) != -1) { + if (c == 's') + startup_cmd = optarg; + else if (c == 'v') + die ("dwl " VERSION); + else + goto usage; + } + if (optind < argc) + goto usage; - /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ - if (!getenv("XDG_RUNTIME_DIR")) - die("XDG_RUNTIME_DIR must be set"); - setup(); - run(startup_cmd); - cleanup(); - return EXIT_SUCCESS; + /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket + */ + if (!getenv ("XDG_RUNTIME_DIR")) + die ("XDG_RUNTIME_DIR must be set"); + setup (); + run (startup_cmd); + cleanup (); + return EXIT_SUCCESS; usage: - die("Usage: %s [-v] [-s startup command]", argv[0]); + die ("Usage: %s [-v] [-s startup command]", argv[0]); }