From 60f0b667b195e7479da944fa2b960c3377d4f144 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Fri, 4 Sep 2020 12:44:09 +0200 Subject: [PATCH 01/21] Basic fullscreen --- dwl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dwl.c b/dwl.c index 730e46a..39c34a0 100644 --- a/dwl.c +++ b/dwl.c @@ -96,6 +96,7 @@ typedef struct { struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; + struct wl_listener fullscreen; struct wlr_box geom; /* layout-relative, includes border */ Monitor *mon; #ifdef XWAYLAND @@ -192,6 +193,7 @@ static void createxdeco(struct wl_listener *listener, void *data); static void cursorframe(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroyxdeco(struct wl_listener *listener, void *data); +static void fullscreenotify(struct wl_listener *listener, void *data); static Monitor *dirtomon(int dir); static void focusclient(Client *old, Client *c, int lift); static void focusmon(const Arg *arg); @@ -598,6 +600,9 @@ createnotify(struct wl_listener *listener, void *data) wl_signal_add(&xdg_surface->events.unmap, &c->unmap); c->destroy.notify = destroynotify; wl_signal_add(&xdg_surface->events.destroy, &c->destroy); + + wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen); + c->fullscreen.notify = fullscreenotify; } void @@ -664,6 +669,12 @@ destroyxdeco(struct wl_listener *listener, void *data) free(d); } +void +fullscreenotify(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, fullscreen); + wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, true); +} + Monitor * dirtomon(int dir) { From 06982a56b554947e651f37b4ff05b2010935a270 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Fri, 4 Sep 2020 14:04:19 +0200 Subject: [PATCH 02/21] Toggle fullscreen --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 39c34a0..73d31ab 100644 --- a/dwl.c +++ b/dwl.c @@ -672,7 +672,7 @@ destroyxdeco(struct wl_listener *listener, void *data) void fullscreenotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, fullscreen); - wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, true); + wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, !c->surface.xdg->toplevel->current.fullscreen); } Monitor * From 4b1ab7804bdfd0f8351e70fcbd5778bb5d00c309 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Fri, 4 Sep 2020 17:09:12 +0200 Subject: [PATCH 03/21] No borders on fullscreen windows Some code has been borrowed from the smartBorders patch --- dwl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 73d31ab..e516316 100644 --- a/dwl.c +++ b/dwl.c @@ -672,7 +672,9 @@ destroyxdeco(struct wl_listener *listener, void *data) void fullscreenotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, fullscreen); - wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, !c->surface.xdg->toplevel->current.fullscreen); + wlr_xdg_toplevel_set_fullscreen( + c->surface.xdg, !c->surface.xdg->toplevel->current.fullscreen); + c->bw = (int)c->surface.xdg->toplevel->current.fullscreen * borderpx; } Monitor * @@ -1193,6 +1195,10 @@ renderclients(Monitor *m, struct timespec *now) ox = c->geom.x, oy = c->geom.y; wlr_output_layout_output_coords(output_layout, m->wlr_output, &ox, &oy); + + if (c->bw == 0) + goto render; + w = surface->current.width; h = surface->current.height; borders = (struct wlr_box[4]) { @@ -1210,6 +1216,7 @@ renderclients(Monitor *m, struct timespec *now) m->wlr_output->transform_matrix); } + render: /* This calls our render function for each surface among the * xdg_surface's toplevel and popups. */ rdata.output = m->wlr_output; From 43bd806291ab1b4bf46cbe35cddebba9af97fd54 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Fri, 4 Sep 2020 17:11:26 +0200 Subject: [PATCH 04/21] Restore windows after fullscreen Store position and size of windows before going fullscreen. This is more efficient than arrange() and also works with floating windows All the clients keep their original position because arrange() isn't used after quitting fullscreen --- dwl.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dwl.c b/dwl.c index e516316..f139bf6 100644 --- a/dwl.c +++ b/dwl.c @@ -106,6 +106,10 @@ typedef struct { unsigned int tags; int isfloating; uint32_t resize; /* configure serial of a pending resize */ + int prevx; + int prevy; + int prevwidth; + int prevheight; } Client; typedef struct { @@ -675,6 +679,16 @@ fullscreenotify(struct wl_listener *listener, void *data) { wlr_xdg_toplevel_set_fullscreen( c->surface.xdg, !c->surface.xdg->toplevel->current.fullscreen); c->bw = (int)c->surface.xdg->toplevel->current.fullscreen * borderpx; + + if (c->surface.xdg->toplevel->current.fullscreen) { /* fullscreen off */ + resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0); + } else { /* fullscreen on */ + c->prevx = c->geom.x; + c->prevy = c->geom.y; + c->prevheight = c->geom.height; + c->prevwidth = c->geom.width; + resize(c, c->mon->w.x, c->mon->w.y, c->mon->w.width, c->mon->w.height, 0); + } } Monitor * From aeae3dadbb94b77ecd45f1ab89769496c71d3782 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Sat, 5 Sep 2020 10:37:59 +0200 Subject: [PATCH 05/21] Unlink fullscreen --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index f139bf6..4911905 100644 --- a/dwl.c +++ b/dwl.c @@ -653,6 +653,7 @@ destroynotify(struct wl_listener *listener, void *data) wl_list_remove(&c->map.link); wl_list_remove(&c->unmap.link); wl_list_remove(&c->destroy.link); + wl_list_remove(&c->fullscreen.link); #ifdef XWAYLAND if (c->type == X11Managed) wl_list_remove(&c->activate.link); From dd2adb38ae69a59de2d1fb65452f4db459cc5c6b Mon Sep 17 00:00:00 2001 From: Stivvo Date: Fri, 4 Sep 2020 19:20:07 +0200 Subject: [PATCH 06/21] Fullscreen xwayland --- dwl.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 4911905..8bd1725 100644 --- a/dwl.c +++ b/dwl.c @@ -110,6 +110,7 @@ typedef struct { int prevy; int prevwidth; int prevheight; + bool isfullscreen; } Client; typedef struct { @@ -293,6 +294,7 @@ static struct wl_listener request_set_sel = {.notify = setsel}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); +static void fullscreenotifyx11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); static void renderindependents(struct wlr_output *output, struct timespec *now); static void updatewindowtype(Client *c); @@ -605,8 +607,8 @@ createnotify(struct wl_listener *listener, void *data) c->destroy.notify = destroynotify; wl_signal_add(&xdg_surface->events.destroy, &c->destroy); - wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen); c->fullscreen.notify = fullscreenotify; + wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen); } void @@ -1847,6 +1849,34 @@ createnotifyx11(struct wl_listener *listener, void *data) wl_signal_add(&xwayland_surface->events.request_activate, &c->activate); c->destroy.notify = destroynotify; wl_signal_add(&xwayland_surface->events.destroy, &c->destroy); + + c->fullscreen.notify = fullscreenotifyx11; + wl_signal_add(&xwayland_surface->events.request_fullscreen, &c->fullscreen); + c->isfullscreen = false; +} + +void +fullscreenotifyx11(struct wl_listener *listener, void *data) { + FILE *xway = fopen("/tmp/dwl/xway", "a"); + Client *c; + c = wl_container_of(listener, c, fullscreen); + c->isfullscreen = !c->isfullscreen; + wlr_xwayland_surface_set_fullscreen( + c->surface.xwayland, c->isfullscreen); + c->bw = ((int)(!c->isfullscreen)) * borderpx; + + fprintf(xway, "fullscreen: %d\n", c->surface.xwayland->fullscreen); + fclose(xway); + + if (c->isfullscreen) { /* fullscreen off */ + c->prevx = c->geom.x; + c->prevy = c->geom.y; + c->prevheight = c->geom.height; + c->prevwidth = c->geom.width; + resize(c, c->mon->w.x, c->mon->w.y, c->mon->w.width, c->mon->w.height, 0); + } else { /* fullscreen on */ + resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 1); + } } Atom From bd222cb75d9ee43ca0a35b158b5a00e9665ecef8 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Fri, 4 Sep 2020 19:56:16 +0200 Subject: [PATCH 07/21] Same fscreen func for xdg and xwayland --- dwl.c | 46 ++++++++++++++-------------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/dwl.c b/dwl.c index 8bd1725..6354072 100644 --- a/dwl.c +++ b/dwl.c @@ -294,7 +294,6 @@ static struct wl_listener request_set_sel = {.notify = setsel}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); -static void fullscreenotifyx11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); static void renderindependents(struct wlr_output *output, struct timespec *now); static void updatewindowtype(Client *c); @@ -609,6 +608,7 @@ createnotify(struct wl_listener *listener, void *data) c->fullscreen.notify = fullscreenotify; wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen); + c->isfullscreen = false; } void @@ -679,18 +679,24 @@ destroyxdeco(struct wl_listener *listener, void *data) void fullscreenotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, fullscreen); - wlr_xdg_toplevel_set_fullscreen( - c->surface.xdg, !c->surface.xdg->toplevel->current.fullscreen); - c->bw = (int)c->surface.xdg->toplevel->current.fullscreen * borderpx; + c->isfullscreen = !c->isfullscreen; - if (c->surface.xdg->toplevel->current.fullscreen) { /* fullscreen off */ - resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0); - } else { /* fullscreen on */ +#ifdef XWAYLAND + if (c->type == X11Managed) + wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, c->isfullscreen); + else +#endif + wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, c->isfullscreen); + + c->bw = ((int)(!c->isfullscreen)) * borderpx; + if (c->isfullscreen) { c->prevx = c->geom.x; c->prevy = c->geom.y; c->prevheight = c->geom.height; c->prevwidth = c->geom.width; resize(c, c->mon->w.x, c->mon->w.y, c->mon->w.width, c->mon->w.height, 0); + } else { + resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0); } } @@ -1850,35 +1856,11 @@ createnotifyx11(struct wl_listener *listener, void *data) c->destroy.notify = destroynotify; wl_signal_add(&xwayland_surface->events.destroy, &c->destroy); - c->fullscreen.notify = fullscreenotifyx11; + c->fullscreen.notify = fullscreenotify; wl_signal_add(&xwayland_surface->events.request_fullscreen, &c->fullscreen); c->isfullscreen = false; } -void -fullscreenotifyx11(struct wl_listener *listener, void *data) { - FILE *xway = fopen("/tmp/dwl/xway", "a"); - Client *c; - c = wl_container_of(listener, c, fullscreen); - c->isfullscreen = !c->isfullscreen; - wlr_xwayland_surface_set_fullscreen( - c->surface.xwayland, c->isfullscreen); - c->bw = ((int)(!c->isfullscreen)) * borderpx; - - fprintf(xway, "fullscreen: %d\n", c->surface.xwayland->fullscreen); - fclose(xway); - - if (c->isfullscreen) { /* fullscreen off */ - c->prevx = c->geom.x; - c->prevy = c->geom.y; - c->prevheight = c->geom.height; - c->prevwidth = c->geom.width; - resize(c, c->mon->w.x, c->mon->w.y, c->mon->w.width, c->mon->w.height, 0); - } else { /* fullscreen on */ - resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 1); - } -} - Atom getatom(xcb_connection_t *xc, const char *name) { From 73d717a9246320ad9fccd0a0fe7726ef937e7fc2 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Fri, 4 Sep 2020 19:58:00 +0200 Subject: [PATCH 08/21] isfullscreen int --- dwl.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 6354072..bdc1e69 100644 --- a/dwl.c +++ b/dwl.c @@ -110,7 +110,7 @@ typedef struct { int prevy; int prevwidth; int prevheight; - bool isfullscreen; + int isfullscreen; } Client; typedef struct { @@ -608,7 +608,7 @@ createnotify(struct wl_listener *listener, void *data) c->fullscreen.notify = fullscreenotify; wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen); - c->isfullscreen = false; + c->isfullscreen = 0; } void @@ -677,7 +677,8 @@ destroyxdeco(struct wl_listener *listener, void *data) } void -fullscreenotify(struct wl_listener *listener, void *data) { +fullscreenotify(struct wl_listener *listener, void *data) +{ Client *c = wl_container_of(listener, c, fullscreen); c->isfullscreen = !c->isfullscreen; @@ -1858,7 +1859,7 @@ createnotifyx11(struct wl_listener *listener, void *data) c->fullscreen.notify = fullscreenotify; wl_signal_add(&xwayland_surface->events.request_fullscreen, &c->fullscreen); - c->isfullscreen = false; + c->isfullscreen = 0; } Atom From d9cf3e064c0972102921dae2280fff1c5272b435 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Fri, 4 Sep 2020 23:32:29 +0200 Subject: [PATCH 09/21] Handle new windows Windows lose fullscreen state when a new window is created in the same tag --- dwl.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index bdc1e69..c72533a 100644 --- a/dwl.c +++ b/dwl.c @@ -198,11 +198,11 @@ static void createxdeco(struct wl_listener *listener, void *data); static void cursorframe(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroyxdeco(struct wl_listener *listener, void *data); -static void fullscreenotify(struct wl_listener *listener, void *data); static Monitor *dirtomon(int dir); static void focusclient(Client *old, Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); +static void fullscreenotify(struct wl_listener *listener, void *data); static Client *focustop(Monitor *m); static void getxdecomode(struct wl_listener *listener, void *data); static void incnmaster(const Arg *arg); @@ -217,6 +217,7 @@ 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 quitfullscreen(Client *c); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void quit(const Arg *arg); @@ -576,6 +577,24 @@ createmon(struct wl_listener *listener, void *data) sgeom = *wlr_output_layout_get_box(output_layout, NULL); } +void +quitfullscreen(Client *c) +{ + wl_list_for_each(c, &clients, link) { + if (c->isfullscreen && VISIBLEON(c, c->mon)) { +#ifdef XWAYLAND + if (c->type == X11Managed) + wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, false); + else +#endif + wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, false); + c->bw = borderpx; + resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0); + c->isfullscreen = 0; + } + } +} + void createnotify(struct wl_listener *listener, void *data) { @@ -591,6 +610,7 @@ createnotify(struct wl_listener *listener, void *data) c = xdg_surface->data = calloc(1, sizeof(*c)); c->surface.xdg = xdg_surface; c->bw = borderpx; + quitfullscreen(c); /* Tell the client not to try anything fancy */ wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | @@ -635,7 +655,6 @@ createxdeco(struct wl_listener *listener, void *data) getxdecomode(&d->request_mode, wlr_deco); } - void cursorframe(struct wl_listener *listener, void *data) { @@ -1846,6 +1865,7 @@ createnotifyx11(struct wl_listener *listener, void *data) c->surface.xwayland = xwayland_surface; c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; c->bw = borderpx; + quitfullscreen(c); /* Listen to the various events it can emit */ c->map.notify = maprequest; From 621d4c9173af194f703a6f197a50e597a8a20498 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Sat, 5 Sep 2020 11:22:24 +0200 Subject: [PATCH 10/21] Toggle fullscreen on all clients mod+e allows to toggle fullscreen any client, even those who don't support it themselves --- config.def.h | 1 + dwl.c | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/config.def.h b/config.def.h index 53021cf..d821a96 100644 --- a/config.def.h +++ b/config.def.h @@ -75,6 +75,7 @@ static const Key keys[] = { { 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 = -1} }, diff --git a/dwl.c b/dwl.c index c72533a..79a1116 100644 --- a/dwl.c +++ b/dwl.c @@ -232,6 +232,7 @@ static void setcursor(struct wl_listener *listener, void *data); static void setpsel(struct wl_listener *listener, void *data); static void setsel(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); @@ -242,6 +243,7 @@ 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 unmapnotify(struct wl_listener *listener, void *data); @@ -696,10 +698,16 @@ destroyxdeco(struct wl_listener *listener, void *data) } void -fullscreenotify(struct wl_listener *listener, void *data) +togglefullscreen(const Arg *arg) { - Client *c = wl_container_of(listener, c, fullscreen); - c->isfullscreen = !c->isfullscreen; + Client *sel = selclient(); + setfullscreen(sel, !sel->isfullscreen); +} + +void +setfullscreen(Client *c, int fullscreen) +{ + c->isfullscreen = fullscreen; #ifdef XWAYLAND if (c->type == X11Managed) @@ -720,6 +728,13 @@ fullscreenotify(struct wl_listener *listener, void *data) } } +void +fullscreenotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, fullscreen); + setfullscreen(c, !c->isfullscreen); +} + Monitor * dirtomon(int dir) { From d8570d5ceb1c4e54854c38437fe1d24d8914e09c Mon Sep 17 00:00:00 2001 From: Stivvo Date: Sun, 6 Sep 2020 10:27:24 +0200 Subject: [PATCH 11/21] Allow borderpx = 0 --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 79a1116..0822508 100644 --- a/dwl.c +++ b/dwl.c @@ -1254,7 +1254,7 @@ renderclients(Monitor *m, struct timespec *now) wlr_output_layout_output_coords(output_layout, m->wlr_output, &ox, &oy); - if (c->bw == 0) + if (c->isfullscreen || borderpx == 0) goto render; w = surface->current.width; @@ -1274,7 +1274,7 @@ renderclients(Monitor *m, struct timespec *now) m->wlr_output->transform_matrix); } - render: +render: /* This calls our render function for each surface among the * xdg_surface's toplevel and popups. */ rdata.output = m->wlr_output; From 8d8d24db09625d6cf83debe068e7334fd8178eea Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 10 Sep 2020 09:09:46 +0200 Subject: [PATCH 12/21] fix typo --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 0822508..d143dd6 100644 --- a/dwl.c +++ b/dwl.c @@ -202,7 +202,7 @@ static Monitor *dirtomon(int dir); static void focusclient(Client *old, Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); -static void fullscreenotify(struct wl_listener *listener, void *data); +static void fullscreennotify(struct wl_listener *listener, void *data); static Client *focustop(Monitor *m); static void getxdecomode(struct wl_listener *listener, void *data); static void incnmaster(const Arg *arg); @@ -628,7 +628,7 @@ createnotify(struct wl_listener *listener, void *data) c->destroy.notify = destroynotify; wl_signal_add(&xdg_surface->events.destroy, &c->destroy); - c->fullscreen.notify = fullscreenotify; + c->fullscreen.notify = fullscreennotify; wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen); c->isfullscreen = 0; } @@ -729,7 +729,7 @@ setfullscreen(Client *c, int fullscreen) } void -fullscreenotify(struct wl_listener *listener, void *data) +fullscreennotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, fullscreen); setfullscreen(c, !c->isfullscreen); @@ -1892,7 +1892,7 @@ createnotifyx11(struct wl_listener *listener, void *data) c->destroy.notify = destroynotify; wl_signal_add(&xwayland_surface->events.destroy, &c->destroy); - c->fullscreen.notify = fullscreenotify; + c->fullscreen.notify = fullscreennotify; wl_signal_add(&xwayland_surface->events.request_fullscreen, &c->fullscreen); c->isfullscreen = 0; } From 2b286ffeeda4fcd618c8f6a3c86efb8e96050bd2 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Wed, 16 Sep 2020 09:20:07 +0200 Subject: [PATCH 13/21] use m->m (fullscreen on top of layers) --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index d143dd6..1177fa8 100644 --- a/dwl.c +++ b/dwl.c @@ -722,7 +722,7 @@ setfullscreen(Client *c, int fullscreen) c->prevy = c->geom.y; c->prevheight = c->geom.height; c->prevwidth = c->geom.width; - resize(c, c->mon->w.x, c->mon->w.y, c->mon->w.width, c->mon->w.height, 0); + resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); } else { resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0); } From 172bcfd3ffcbaafb5198b162f8b704b0172fe9a0 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Thu, 8 Oct 2020 21:04:28 +0200 Subject: [PATCH 14/21] Set fullscreen simpler --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 1177fa8..d7cc46f 100644 --- a/dwl.c +++ b/dwl.c @@ -708,16 +708,16 @@ void setfullscreen(Client *c, int fullscreen) { c->isfullscreen = fullscreen; + c->bw = (1 - fullscreen) * borderpx; #ifdef XWAYLAND if (c->type == X11Managed) - wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, c->isfullscreen); + wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen); else #endif - wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, c->isfullscreen); + wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, fullscreen); - c->bw = ((int)(!c->isfullscreen)) * borderpx; - if (c->isfullscreen) { + if (fullscreen) { c->prevx = c->geom.x; c->prevy = c->geom.y; c->prevheight = c->geom.height; From a2ed3d45bb1e2cd8c7f1df54283b3188c3b23841 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Thu, 8 Oct 2020 21:04:53 +0200 Subject: [PATCH 15/21] Keep windows fullscreen after redraw This fixes the bug that happens when changing workspace (or any time arrange() is called) where there are fullscreen windows, which are still fullscreen but leave the space for layer surfaces like waybar (which should be hidden when going fullscreen) Also as soon one fullscreen window is found hte function returns to improve efficiency --- dwl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dwl.c b/dwl.c index d7cc46f..c0182c5 100644 --- a/dwl.c +++ b/dwl.c @@ -1017,6 +1017,10 @@ monocle(Monitor *m) wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating) continue; + if (c->isfullscreen) { + resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); + return; + } resize(c, m->w.x, m->w.y, m->w.width, m->w.height, 0); } } @@ -1728,6 +1732,10 @@ tile(Monitor *m) wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating) continue; + if (c->isfullscreen) { + resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); + return; + } if (i < m->nmaster) { h = (m->w.height - my) / (MIN(n, m->nmaster) - i); resize(c, m->w.x, m->w.y + my, mw, h, 0); From 0ad8473a57708b0c7145a4e6ae8590fb6a035701 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Wed, 14 Oct 2020 15:46:35 +0200 Subject: [PATCH 16/21] Delete quitfullscreen() quitfullscreen() was replicating the functionalities of setfullscreen(c, 0) Reusing setfullscreen() in quitfullscreen() leads to a 3 line function, which is useless since quitfullscreen() is used once anyway --- dwl.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/dwl.c b/dwl.c index c0182c5..e0e3b30 100644 --- a/dwl.c +++ b/dwl.c @@ -217,7 +217,6 @@ 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 quitfullscreen(Client *c); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void quit(const Arg *arg); @@ -579,24 +578,6 @@ createmon(struct wl_listener *listener, void *data) sgeom = *wlr_output_layout_get_box(output_layout, NULL); } -void -quitfullscreen(Client *c) -{ - wl_list_for_each(c, &clients, link) { - if (c->isfullscreen && VISIBLEON(c, c->mon)) { -#ifdef XWAYLAND - if (c->type == X11Managed) - wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, false); - else -#endif - wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, false); - c->bw = borderpx; - resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0); - c->isfullscreen = 0; - } - } -} - void createnotify(struct wl_listener *listener, void *data) { @@ -608,11 +589,14 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) return; + wl_list_for_each(c, &clients, link) + if (c->isfullscreen && VISIBLEON(c, c->mon)) + setfullscreen(c, 0); + /* Allocate a Client for this surface */ c = xdg_surface->data = calloc(1, sizeof(*c)); c->surface.xdg = xdg_surface; c->bw = borderpx; - quitfullscreen(c); /* Tell the client not to try anything fancy */ wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | From c98686cf1618da2e581f46d4723016365606b591 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Wed, 14 Oct 2020 17:28:51 +0200 Subject: [PATCH 17/21] Quit fullscreen on new x11 window After the removal of quitfullscreen() dwl wouldn't compile widh xwayland enabled because createnotifyx11 was still using the old function --- dwl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index e0e3b30..05739a8 100644 --- a/dwl.c +++ b/dwl.c @@ -588,7 +588,6 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) return; - wl_list_for_each(c, &clients, link) if (c->isfullscreen && VISIBLEON(c, c->mon)) setfullscreen(c, 0); @@ -1242,7 +1241,7 @@ renderclients(Monitor *m, struct timespec *now) wlr_output_layout_output_coords(output_layout, m->wlr_output, &ox, &oy); - if (c->isfullscreen || borderpx == 0) + if (c->isfullscreen) goto render; w = surface->current.width; @@ -1866,13 +1865,15 @@ createnotifyx11(struct wl_listener *listener, void *data) { struct wlr_xwayland_surface *xwayland_surface = data; Client *c; + wl_list_for_each(c, &clients, link) + if (c->isfullscreen && VISIBLEON(c, c->mon)) + setfullscreen(c, 0); /* Allocate a Client for this surface */ c = xwayland_surface->data = calloc(1, sizeof(*c)); c->surface.xwayland = xwayland_surface; c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; c->bw = borderpx; - quitfullscreen(c); /* Listen to the various events it can emit */ c->map.notify = maprequest; From fcc869ed8480c21cd8b36d9fc3bd8dd3b8cee981 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Sat, 24 Oct 2020 16:51:22 +0200 Subject: [PATCH 18/21] Readme: achieve fullscreen + allow borderpx = 0 --- README.md | 1 - dwl.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3251ccf..1439a0b 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,6 @@ dwl is a work in progress, and it has not yet reached its feature goals in a num - Statusbar support (built-in or external) - layer-shell - Damage tracking -- Fullscreen/fixed windows (or whatever the Wayland analogues are) ## Acknowledgements diff --git a/dwl.c b/dwl.c index 05739a8..1a26ab6 100644 --- a/dwl.c +++ b/dwl.c @@ -700,6 +700,7 @@ setfullscreen(Client *c, int fullscreen) #endif wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, fullscreen); + // restore previous size instead of arrange to work with floating windows if (fullscreen) { c->prevx = c->geom.x; c->prevy = c->geom.y; @@ -1240,8 +1241,7 @@ renderclients(Monitor *m, struct timespec *now) ox = c->geom.x, oy = c->geom.y; wlr_output_layout_output_coords(output_layout, m->wlr_output, &ox, &oy); - - if (c->isfullscreen) + if (c->bw == 0) goto render; w = surface->current.width; From 86ba4c8526d8b96eb0caaa60f8f42edb51b2b558 Mon Sep 17 00:00:00 2001 From: Stivvo Date: Thu, 24 Dec 2020 00:34:33 +0100 Subject: [PATCH 19/21] Remove goto render (easier merge) --- dwl.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/dwl.c b/dwl.c index 1a26ab6..8e1e384 100644 --- a/dwl.c +++ b/dwl.c @@ -1241,27 +1241,26 @@ renderclients(Monitor *m, struct timespec *now) ox = c->geom.x, oy = c->geom.y; wlr_output_layout_output_coords(output_layout, m->wlr_output, &ox, &oy); - if (c->bw == 0) - goto render; - w = surface->current.width; - h = surface->current.height; - borders = (struct wlr_box[4]) { - {ox, oy, w + 2 * c->bw, c->bw}, /* top */ - {ox, oy + c->bw, c->bw, h}, /* left */ - {ox + c->bw + w, oy + c->bw, c->bw, h}, /* right */ - {ox, oy + c->bw + h, w + 2 * c->bw, c->bw}, /* bottom */ - }; + if (c->bw) { + w = surface->current.width; + h = surface->current.height; + borders = (struct wlr_box[4]) { + {ox, oy, w + 2 * c->bw, c->bw}, /* top */ + {ox, oy + c->bw, c->bw, h}, /* left */ + {ox + c->bw + w, oy + c->bw, c->bw, h}, /* right */ + {ox, oy + c->bw + h, w + 2 * c->bw, c->bw}, /* bottom */ + }; - /* Draw window borders */ - color = (c == sel) ? focuscolor : bordercolor; - for (i = 0; i < 4; i++) { - scalebox(&borders[i], m->wlr_output->scale); - wlr_render_rect(drw, &borders[i], color, - m->wlr_output->transform_matrix); + /* Draw window borders */ + color = (c == sel) ? focuscolor : bordercolor; + for (i = 0; i < 4; i++) { + scalebox(&borders[i], m->wlr_output->scale); + wlr_render_rect(drw, &borders[i], color, + m->wlr_output->transform_matrix); + } } -render: /* This calls our render function for each surface among the * xdg_surface's toplevel and popups. */ rdata.output = m->wlr_output; From 707c1710b7df87ee61db26b325eaa6529beba9ac Mon Sep 17 00:00:00 2001 From: Stivvo Date: Thu, 24 Dec 2020 01:02:45 +0100 Subject: [PATCH 20/21] quitallfullscreen() even when enabling fullscreen Disable fullscreen on all visible clients in that monitor also before enabling it on another client. quitallfullscreen() is reintroduced becouse is now more useful set c->isfullscreen later to avoid making quitallfullscreen() disable fullscreen on the current client --- dwl.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index 8e1e384..5e1591b 100644 --- a/dwl.c +++ b/dwl.c @@ -220,6 +220,7 @@ static void moveresize(const Arg *arg); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void quit(const Arg *arg); +static void quitallfullscreen(); static void render(struct wlr_surface *surface, int sx, int sy, void *data); static void renderclients(Monitor *m, struct timespec *now); static void rendermon(struct wl_listener *listener, void *data); @@ -588,9 +589,7 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) return; - wl_list_for_each(c, &clients, link) - if (c->isfullscreen && VISIBLEON(c, c->mon)) - setfullscreen(c, 0); + quitallfullscreen(); /* Allocate a Client for this surface */ c = xdg_surface->data = calloc(1, sizeof(*c)); @@ -687,10 +686,18 @@ togglefullscreen(const Arg *arg) setfullscreen(sel, !sel->isfullscreen); } +void +quitallfullscreen() +{ + Client *c; + wl_list_for_each(c, &clients, link) + if (c->isfullscreen && VISIBLEON(c, selmon)) + setfullscreen(c, 0); +} + void setfullscreen(Client *c, int fullscreen) { - c->isfullscreen = fullscreen; c->bw = (1 - fullscreen) * borderpx; #ifdef XWAYLAND @@ -702,6 +709,7 @@ setfullscreen(Client *c, int fullscreen) // restore previous size instead of arrange to work with floating windows if (fullscreen) { + quitallfullscreen(); c->prevx = c->geom.x; c->prevy = c->geom.y; c->prevheight = c->geom.height; @@ -710,6 +718,7 @@ setfullscreen(Client *c, int fullscreen) } else { resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0); } + c->isfullscreen = fullscreen; } void @@ -1864,9 +1873,7 @@ createnotifyx11(struct wl_listener *listener, void *data) { struct wlr_xwayland_surface *xwayland_surface = data; Client *c; - wl_list_for_each(c, &clients, link) - if (c->isfullscreen && VISIBLEON(c, c->mon)) - setfullscreen(c, 0); + quitallfullscreen(); /* Allocate a Client for this surface */ c = xwayland_surface->data = calloc(1, sizeof(*c)); From d21d5ee26227e6ec70973cfdac326f4828b7237c Mon Sep 17 00:00:00 2001 From: Stivvo Date: Thu, 24 Dec 2020 17:30:12 +0100 Subject: [PATCH 21/21] Change fullscreen policies When a new client is spawned, fullscreen isn't disabled for all clients in that monitor any more. Instead, all fullscreen clients are kept fullscreen, while other clients spawn in the background. When fullscreen is disabled, all clients are rearranged. This is made to make dwl more flexible allowing multiple fullscreen clients at the same time, have floating clients on top of a fullscreen one and let stuff happen without quitting fullscreen, like many other WMs and DEs. --- dwl.c | 55 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/dwl.c b/dwl.c index 5e1591b..20d1c98 100644 --- a/dwl.c +++ b/dwl.c @@ -152,6 +152,7 @@ struct Monitor { unsigned int tagset[2]; double mfact; int nmaster; + Client *fullscreenclient; }; typedef struct { @@ -212,6 +213,7 @@ static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); static void killclient(const Arg *arg); static void maprequest(struct wl_listener *listener, void *data); +static void maximizeclient(Client *c); static void monocle(Monitor *m); static void motionabsolute(struct wl_listener *listener, void *data); static void motionnotify(uint32_t time); @@ -220,7 +222,6 @@ static void moveresize(const Arg *arg); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void quit(const Arg *arg); -static void quitallfullscreen(); static void render(struct wlr_surface *surface, int sx, int sy, void *data); static void renderclients(Monitor *m, struct timespec *now); static void rendermon(struct wl_listener *listener, void *data); @@ -380,6 +381,8 @@ arrange(Monitor *m) m->w = m->m; if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); + else if (m->fullscreenclient) + maximizeclient(m->fullscreenclient); /* XXX recheck pointer focus here... or in resize()? */ } @@ -589,7 +592,6 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) return; - quitallfullscreen(); /* Allocate a Client for this surface */ c = xdg_surface->data = calloc(1, sizeof(*c)); @@ -687,17 +689,16 @@ togglefullscreen(const Arg *arg) } void -quitallfullscreen() +maximizeclient(Client *c) { - Client *c; - wl_list_for_each(c, &clients, link) - if (c->isfullscreen && VISIBLEON(c, selmon)) - setfullscreen(c, 0); + resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); + /* used for fullscreen clients */ } void setfullscreen(Client *c, int fullscreen) { + c->isfullscreen = fullscreen; c->bw = (1 - fullscreen) * borderpx; #ifdef XWAYLAND @@ -707,18 +708,20 @@ setfullscreen(Client *c, int fullscreen) #endif wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, fullscreen); - // restore previous size instead of arrange to work with floating windows if (fullscreen) { - quitallfullscreen(); c->prevx = c->geom.x; c->prevy = c->geom.y; c->prevheight = c->geom.height; c->prevwidth = c->geom.width; - resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); + c->mon->fullscreenclient = c; + maximizeclient(c); } 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->prevx, c->prevy, c->prevwidth, c->prevheight, 0); + c->mon->fullscreenclient = NULL; + arrange(c->mon); } - c->isfullscreen = fullscreen; } void @@ -969,7 +972,7 @@ void maprequest(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ - Client *c = wl_container_of(listener, c, map); + Client *c = wl_container_of(listener, c, map), *oldfocus = selclient(); #ifdef XWAYLAND if (c->type == X11Unmanaged) { @@ -1000,6 +1003,14 @@ maprequest(struct wl_listener *listener, void *data) /* Set initial monitor, tags, floating status, and focus */ applyrules(c); + + if (c->mon->fullscreenclient && c->mon->fullscreenclient == oldfocus + && !c->isfloating && c->mon->lt[c->mon->sellt]->arrange) { + maximizeclient(c->mon->fullscreenclient); + focusclient(c, c->mon->fullscreenclient, 1); + /* give the focus back the fullscreen client on that monitor if exists, + * is focused and the new client isn't floating */ + } } void @@ -1010,11 +1021,10 @@ monocle(Monitor *m) wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating) continue; - if (c->isfullscreen) { - resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); - return; - } - resize(c, m->w.x, m->w.y, m->w.width, m->w.height, 0); + if (c->isfullscreen) + maximizeclient(c); + else + resize(c, m->w.x, m->w.y, m->w.width, m->w.height, 0); } } @@ -1452,8 +1462,6 @@ setcursor(struct wl_listener *listener, void *data) void setfloating(Client *c, int floating) { - if (c->isfloating == floating) - return; c->isfloating = floating; arrange(c->mon); } @@ -1723,11 +1731,9 @@ tile(Monitor *m) wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating) continue; - if (c->isfullscreen) { - resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); - return; - } - if (i < m->nmaster) { + if (c->isfullscreen) + maximizeclient(c); + else if (i < m->nmaster) { h = (m->w.height - my) / (MIN(n, m->nmaster) - i); resize(c, m->w.x, m->w.y + my, mw, h, 0); my += c->geom.height; @@ -1873,7 +1879,6 @@ createnotifyx11(struct wl_listener *listener, void *data) { struct wlr_xwayland_surface *xwayland_surface = data; Client *c; - quitallfullscreen(); /* Allocate a Client for this surface */ c = xwayland_surface->data = calloc(1, sizeof(*c));