diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README.md | 14 | ||||
-rw-r--r-- | config.def.h | 5 | ||||
-rw-r--r-- | dwl.c | 319 |
4 files changed, 201 insertions, 141 deletions
@@ -54,9 +54,7 @@ clean: rm -f dwl *.o *-protocol.h *-protocol.c install: dwl - mkdir -p $(PREFIX)/bin - cp -f dwl $(PREFIX)/bin - chmod 755 $(PREFIX)/bin/dwl + install -D dwl $(PREFIX)/bin/dwl .DEFAULT_GOAL=dwl .PHONY: clean @@ -3,7 +3,8 @@ dwl is a compact, hackable compositor for Wayland based on [wlroots](https://github.com/swaywm/wlroots). It is intended to fill the same space in the Wayland world that dwm does in X11, primarily in terms of philosophy, and secondarily in terms of functionality. Like dwm, dwl is: - Easy to understand, hack on, and extend with patches -- One C source file configurable via `config.h` +- One C source file (or a very small number) configurable via `config.h` +- Limited to 2000 SLOC to promote hackability - Tied to as few external dependencies as possible dwl is not meant to provide every feature under the sun. Instead, like dwm, it sticks to features which are necessary, simple, and straightforward to implement given the base on which it is built. Implemented default features are: @@ -56,6 +57,12 @@ Note: Wayland requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a s You can find a [list of Wayland applications on the sway wiki](https://github.com/swaywm/sway/wiki/i3-Migration-Guide). +dwl is a work in progress, and it has not yet reached its feature goals in a number of ways: + +- A window's texture is scaled for its "home" monitor only (noticeable when window sits across a monitor boundary) +- Urgent/attention/focus-request ([not yet supported](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/9) by xdg-shell protocol) +- Damage tracking + ## IRC channel dwl's IRC channel is #dwl on irc.freenode.net. @@ -64,4 +71,7 @@ dwl's IRC channel is #dwl on irc.freenode.net. dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots developers. This was made possible in many cases by looking at how sway accomplished something, then trying to do the same in as suckless a way as possible. -Many thanks to suckless.org and the dwm developers and community for the inspiration, and to Devin J. Pohly for creating dwl. +Many thanks to suckless.org and the dwm developers and community for the inspiration, and to the various contributors to the project, including: + +- Alexander Courtis for the XWayland implementation +- Guido Cella for the layer-shell protocol implementation and for helping to keep the project running diff --git a/config.def.h b/config.def.h index b7e067d..64dfea8 100644 --- a/config.def.h +++ b/config.def.h @@ -48,8 +48,8 @@ static const int repeat_rate = 25; static const int repeat_delay = 600; /* Trackpad */ -static const bool tap_to_click = true; -static const bool natural_scrolling = false; +static const bool tap_to_click = 1; +static const bool natural_scrolling = 1; #define MODKEY WLR_MODIFIER_ALT #define TAGKEYS(KEY,SKEY,TAG) \ @@ -82,6 +82,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} }, @@ -57,7 +57,7 @@ #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1 << LENGTH(tags)) - 1) -#define ROUND(X) ((X)>=0?(long)((X)+0.5):(long)((X)-0.5)) +#define ROUND(X) ((int)((X)+0.5)) #ifdef XWAYLAND #define WLR_SURFACE(C) ((C)->type != XDGShell ? (C)->surface.xwayland->surface : (C)->surface.xdg->surface) #else @@ -113,13 +113,13 @@ typedef struct { #endif int bw; unsigned int tags; - bool isfloating; + int isfloating; uint32_t resize; /* configure serial of a pending resize */ - int oldx; - int oldy; - int oldwidth; - int oldheight; - bool isfullscreen; + int prevx; + int prevy; + int prevwidth; + int prevheight; + int isfullscreen; } Client; typedef struct { @@ -175,6 +175,7 @@ struct Monitor { unsigned int tagset[2]; double mfact; int nmaster; + Client *fullscreenclient; int position; }; @@ -191,7 +192,7 @@ typedef struct { const char *id; const char *title; unsigned int tags; - bool isfloating; + int isfloating; int monitor; } Rule; @@ -211,7 +212,7 @@ static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor, static void applyrules(Client *c); static void arrange(Monitor *m); static void arrangelayer(Monitor *m, struct wl_list *list, - struct wlr_box *usable_area, bool exclusive); + 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); @@ -233,7 +234,7 @@ static void destroylayersurfacenotify(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 Monitor *dirtomon(int dir); -static void focusclient(Client *c, bool lift); +static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); static void fullscreennotify(struct wl_listener *listener, void *data); @@ -241,19 +242,20 @@ static Client *focustop(Monitor *m); static void getxdecomode(struct wl_listener *listener, void *data); static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); -static bool keybinding(uint32_t mods, xkb_keysym_t sym); +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 void killclient(const Arg *arg); static void maplayersurfacenotify(struct wl_listener *listener, void *data); static void mapnotify(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); 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, bool test); +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); @@ -262,15 +264,15 @@ static void render(struct wlr_surface *surface, int sx, int sy, void *data); static void renderclients(Monitor *m, struct timespec *now); static void renderlayer(struct wl_list *layer_surfaces, struct timespec *now); static void rendermon(struct wl_listener *listener, void *data); -static void resize(Client *c, int x, int y, int w, int h, bool interact); +static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); static void scalebox(struct wlr_box *box, float scale); static Client *selclient(void); 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, bool floating); -static void setfullscreen(Client *c, bool fullscreen); +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); @@ -281,6 +283,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 unmaplayersurface(LayerSurface *layersurface); @@ -299,7 +302,7 @@ static void zoom(const Arg *arg); static const char broken[] = "broken"; static struct wl_display *dpy; static struct wlr_backend *backend; -static struct wlr_renderer *renderer; +static struct wlr_renderer *drw; static struct wlr_compositor *compositor; static struct wlr_xdg_shell *xdg_shell; @@ -315,6 +318,10 @@ static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; +#ifdef XWAYLAND +static struct wlr_xcursor *xcursor; +static struct wlr_xcursor_manager *xcursor_mgr; +#endif static struct wlr_seat *seat; static struct wl_list keyboards; @@ -500,11 +507,13 @@ arrange(Monitor *m) { if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); + else if (m->fullscreenclient) + maximizeclient(m->fullscreenclient); /* TODO recheck pointer focus here... or in resize()? */ } void -arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool exclusive) +arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) { LayerSurface *layersurface; struct wlr_box full_area = m->m; @@ -586,13 +595,13 @@ arrangelayers(Monitor *m) // Arrange exclusive surfaces from top->bottom arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, true); + &usable_area, 1); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, true); + &usable_area, 1); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, true); + &usable_area, 1); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, true); + &usable_area, 1); if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) { m->w = usable_area; @@ -601,13 +610,13 @@ arrangelayers(Monitor *m) // Arrange non-exlusive surfaces from top->bottom arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, false); + &usable_area, 0); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, false); + &usable_area, 0); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, false); + &usable_area, 0); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, false); + &usable_area, 0); // Find topmost keyboard interactive layer, if such a layer exists uint32_t layers_above_shell[] = { @@ -623,7 +632,7 @@ arrangelayers(Monitor *m) if (layersurface->layer_surface->current.keyboard_interactive && layersurface->layer_surface->mapped) { // Deactivate the focused client. - focusclient(NULL, false); + focusclient(NULL, 0); wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); return; @@ -657,7 +666,7 @@ buttonpress(struct wl_listener *listener, void *data) /* Change focus if the button was _pressed_ over a client */ Client *c; if ((c = xytoclient(cursor->x, cursor->y))) - focusclient(c, true); + focusclient(c, 1); struct wlr_keyboard* keyboard = wlr_seat_get_keyboard(seat); uint32_t mods = wlr_keyboard_get_modifiers(keyboard); @@ -739,7 +748,7 @@ cleanupmon(struct wl_listener *listener, void *data) do // don't switch to disabled mons selmon = wl_container_of(mons.prev, selmon, link); while (!selmon->wlr_output->enabled && i++ < nmons); - focusclient(focustop(selmon), true); + focusclient(focustop(selmon), 1); closemon(m); free(m); } @@ -753,7 +762,7 @@ closemon(Monitor *m) wl_list_for_each(c, &clients, link) { if (c->isfloating && c->geom.x > m->m.width) resize(c, c->geom.x - m->w.width, c->geom.y, - c->geom.width, c->geom.height, false); + c->geom.width, c->geom.height, 0); if (c->mon == m) setmon(c, selmon, c->tags); } @@ -851,7 +860,7 @@ createmon(struct wl_listener *listener, void *data) break; } } - wlr_output_enable_adaptive_sync(wlr_output, true); + wlr_output_enable_adaptive_sync(wlr_output, 1); /* Set up event listeners */ m->frame.notify = rendermon; wl_signal_add(&wlr_output->events.frame, &m->frame); @@ -870,7 +879,7 @@ createmon(struct wl_listener *listener, void *data) wl_list_insert(&mons, &m->link); } - wlr_output_enable(wlr_output, true); + wlr_output_enable(wlr_output, 1); if (!wlr_output_commit(wlr_output)) return; @@ -901,7 +910,7 @@ createmon(struct wl_listener *listener, void *data) wl_list_for_each(c, &clients, link) { if (c->isfloating) resize(c, c->geom.x + m->w.width, c->geom.y, - c->geom.width, c->geom.height, false); + c->geom.width, c->geom.height, 0); } return; } @@ -919,7 +928,7 @@ createnotify(struct wl_listener *listener, void *data) return; wl_list_for_each(c, &clients, link) if (c->isfullscreen && VISIBLEON(c, c->mon)) - setfullscreen(c, false); + setfullscreen(c, 0); /* Allocate a Client for this surface */ c = xdg_surface->data = calloc(1, sizeof(*c)); @@ -942,7 +951,7 @@ createnotify(struct wl_listener *listener, void *data) c->fullscreen.notify = fullscreennotify; wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen); - c->isfullscreen = false; + c->isfullscreen = 0; } void @@ -985,14 +994,16 @@ createlayersurface(struct wl_listener *listener, void *data) void createpointer(struct wlr_input_device *device) { - struct libinput_device *libinput_device = (struct libinput_device*) + if (wlr_input_device_is_libinput(device)) { + struct libinput_device *libinput_device = (struct libinput_device*) wlr_libinput_get_device_handle(device); - if (tap_to_click && libinput_device_config_tap_get_finger_count(libinput_device)) - libinput_device_config_tap_set_enabled(libinput_device, LIBINPUT_CONFIG_TAP_ENABLED); + if (tap_to_click && libinput_device_config_tap_get_finger_count(libinput_device)) + libinput_device_config_tap_set_enabled(libinput_device, LIBINPUT_CONFIG_TAP_ENABLED); - 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_scroll_has_natural_scroll(libinput_device)) + libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, natural_scrolling); + } /* We don't do anything special with pointers. All of our pointer handling * is proxied through wlr_cursor. On another compositor, you might take this @@ -1077,7 +1088,21 @@ destroyxdeco(struct wl_listener *listener, void *data) } void -setfullscreen(Client *c, bool fullscreen) +togglefullscreen(const Arg *arg) +{ + Client *sel = selclient(); + setfullscreen(sel, !sel->isfullscreen); +} + +void +maximizeclient(Client *c) +{ + 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; @@ -1089,16 +1114,19 @@ setfullscreen(Client *c, bool 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->oldx = c->geom.x; - c->oldy = c->geom.y; - c->oldheight = c->geom.height; - c->oldwidth = c->geom.width; - resize(c, c->mon->m.x, c->mon->m.y, - c->mon->m.width, c->mon->m.height, false); + c->prevx = c->geom.x; + c->prevy = c->geom.y; + c->prevheight = c->geom.height; + c->prevwidth = c->geom.width; + c->mon->fullscreenclient = c; + maximizeclient(c); } else { - resize(c, c->oldx, c->oldy, c->oldwidth, c->oldheight, false); + /* 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); } } @@ -1126,7 +1154,7 @@ dirtomon(int dir) } void -focusclient(Client *c, bool lift) +focusclient(Client *c, int lift) { /* Raise client in stacking order if requested */ if (c && lift) { @@ -1150,11 +1178,11 @@ focusclient(Client *c, bool lift) if (old && (!c || WLR_SURFACE(c) != old)) { if (wlr_surface_is_xdg_surface(old)) wlr_xdg_toplevel_set_activated( - wlr_xdg_surface_from_wlr_surface(old), false); + wlr_xdg_surface_from_wlr_surface(old), 0); #ifdef XWAYLAND else if (wlr_surface_is_xwayland_surface(old)) wlr_xwayland_surface_activate( - wlr_xwayland_surface_from_wlr_surface(old), false); + wlr_xwayland_surface_from_wlr_surface(old), 0); #endif /* 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 @@ -1187,10 +1215,10 @@ focusclient(Client *c, bool lift) /* Activate the new client */ #ifdef XWAYLAND if (c->type != XDGShell) - wlr_xwayland_surface_activate(c->surface.xwayland, true); + wlr_xwayland_surface_activate(c->surface.xwayland, 1); else #endif - wlr_xdg_toplevel_set_activated(c->surface.xdg, true); + wlr_xdg_toplevel_set_activated(c->surface.xdg, 1); } void @@ -1199,7 +1227,7 @@ focusmon(const Arg *arg) do selmon = dirtomon(arg->i); while (!selmon->wlr_output->enabled); - focusclient(focustop(selmon), true); + focusclient(focustop(selmon), 1); } void @@ -1225,7 +1253,7 @@ focusstack(const Arg *arg) } } /* If only one client is visible on selmon, then c == sel */ - focusclient(c, true); + focusclient(c, 1); } Client * @@ -1280,7 +1308,7 @@ inputdevice(struct wl_listener *listener, void *data) wlr_seat_set_capabilities(seat, caps); } -bool +int keybinding(uint32_t mods, xkb_keysym_t sym) { /* @@ -1288,13 +1316,13 @@ keybinding(uint32_t mods, xkb_keysym_t sym) * processing keys, rather than passing them on to the client for its own * processing. */ - bool handled = false; + 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 = true; + handled = 1; } } return handled; @@ -1303,6 +1331,7 @@ keybinding(uint32_t mods, xkb_keysym_t sym) void 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_event_keyboard_key *event = data; @@ -1314,14 +1343,14 @@ keypress(struct wl_listener *listener, void *data) int nsyms = xkb_state_key_get_syms( kb->device->keyboard->xkb_state, keycode, &syms); - bool handled = false; + int handled = 0; uint32_t mods = wlr_keyboard_get_modifiers(kb->device->keyboard); wlr_idle_notify_activity(idle, seat); /* On _press_, attempt to process a compositor keybinding. */ - if (event->state == WLR_KEY_PRESSED) - for (int i = 0; i < nsyms; i++) + if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; if (!handled) { @@ -1377,7 +1406,7 @@ void mapnotify(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) { @@ -1408,6 +1437,14 @@ mapnotify(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->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 @@ -1418,11 +1455,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, false); - return; - } - resize(c, m->w.x, m->w.y, m->w.width, m->w.height, false); + if (c->isfullscreen) + maximizeclient(c); + else + resize(c, m->w.x, m->w.y, m->w.width, m->w.height, 0); } } @@ -1456,12 +1492,12 @@ motionnotify(uint32_t time) if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ resize(grabc, cursor->x - grabcx, cursor->y - grabcy, - grabc->geom.width, grabc->geom.height, true); + grabc->geom.width, grabc->geom.height, 1); return; } else if (cursor_mode == CurResize) { resize(grabc, grabc->geom.x, grabc->geom.y, cursor->x - grabc->geom.x, - cursor->y - grabc->geom.y, true); + cursor->y - grabc->geom.y, 1); return; } @@ -1537,7 +1573,7 @@ moveresize(const Arg *arg) return; /* Float the window and tell motionnotify to grab it */ - setfloating(grabc, true); + setfloating(grabc, 1); switch (cursor_mode = arg->ui) { case CurMove: grabcx = cursor->x - grabc->geom.x; @@ -1560,14 +1596,14 @@ void outputmgrapply(struct wl_listener *listener, void *data) { struct wlr_output_configuration_v1 *config = data; - outputmgrapplyortest(config, false); + outputmgrapplyortest(config, 0); } void -outputmgrapplyortest(struct wlr_output_configuration_v1 *config, bool test) +outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) { struct wlr_output_configuration_head_v1 *config_head; - bool ok = true; + int ok = 1; wl_list_for_each(config_head, &config->heads, link) { struct wlr_output *wlr_output = config_head->state.output; @@ -1619,7 +1655,7 @@ void outputmgrtest(struct wl_listener *listener, void *data) { struct wlr_output_configuration_v1 *config = data; - outputmgrapplyortest(config, true); + outputmgrapplyortest(config, 1); } void @@ -1636,7 +1672,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, return; } - bool internal_call = !time; + int internal_call = !time; if (!time) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -1662,7 +1698,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, #endif if (sloppyfocus && !internal_call) - focusclient(c, false); + focusclient(c, 0); } void @@ -1723,7 +1759,7 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) /* This takes our matrix, the texture, and an alpha, and performs the actual * rendering on the GPU. */ - wlr_render_texture_with_matrix(renderer, texture, matrix, 1); + wlr_render_texture_with_matrix(drw, texture, matrix, 1); /* This lets the client know that we've displayed that frame and it can * prepare another one now if it likes. */ @@ -1734,6 +1770,12 @@ void renderclients(Monitor *m, struct timespec *now) { Client *c, *sel = selclient(); + const float *color; + double ox, oy; + int i, w, h; + struct render_data rdata; + struct wlr_box *borders; + struct wlr_surface *surface; /* Each subsequent window we render is rendered on top of the last. Because * our stacking list is ordered front-to-back, we iterate over it backwards. */ wl_list_for_each_reverse(c, &stack, slink) { @@ -1742,36 +1784,36 @@ renderclients(Monitor *m, struct timespec *now) output_layout, m->wlr_output, &c->geom)) continue; - struct wlr_surface *surface = WLR_SURFACE(c); - double ox = c->geom.x, oy = c->geom.y; + surface = WLR_SURFACE(c); + ox = c->geom.x, oy = c->geom.y; wlr_output_layout_output_coords(output_layout, m->wlr_output, &ox, &oy); - int w = surface->current.width; - int h = surface->current.height; - struct wlr_box *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 */ - const float *color = (c == sel) ? focuscolor : bordercolor; - for (int i = 0; i < 4; i++) { - scalebox(&borders[i], m->wlr_output->scale); - wlr_render_rect(renderer, &borders[i], color, - m->wlr_output->transform_matrix); + 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); + } } /* This calls our render function for each surface among the * xdg_surface's toplevel and popups. */ - struct render_data rdata = { - .output = m->wlr_output, - .when = now, - .x = c->geom.x + c->bw, - .y = c->geom.y + c->bw, - }; + rdata.output = m->wlr_output; + rdata.when = now; + rdata.x = c->geom.x + c->bw; + rdata.y = c->geom.y + c->bw; #ifdef XWAYLAND if (c->type != XDGShell) wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata); @@ -1810,11 +1852,11 @@ rendermon(struct wl_listener *listener, void *data) /* Do not render if any XDG clients have an outstanding resize. */ Client *c; - bool render = true; + int render = 1; wl_list_for_each(c, &stack, slink) { if (c->resize) { wlr_surface_send_frame_done(WLR_SURFACE(c), &now); - render = false; + render = 0; } } @@ -1824,8 +1866,8 @@ rendermon(struct wl_listener *listener, void *data) if (render) { /* Begin the renderer (calls glViewport and some other GL sanity checks) */ - wlr_renderer_begin(renderer, m->wlr_output->width, m->wlr_output->height); - wlr_renderer_clear(renderer, rootcolor); + wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height); + wlr_renderer_clear(drw, rootcolor); renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &now); renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now); @@ -1846,14 +1888,14 @@ rendermon(struct wl_listener *listener, void *data) /* Conclude rendering and swap the buffers, showing the final frame * on-screen. */ - wlr_renderer_end(renderer); + wlr_renderer_end(drw); } wlr_output_commit(m->wlr_output); } void -resize(Client *c, int x, int y, int w, int h, bool interact) +resize(Client *c, int x, int y, int w, int h, int interact) { /* * Note that I took some shortcuts here. In a more fleshed-out @@ -1967,10 +2009,8 @@ setcursor(struct wl_listener *listener, void *data) } void -setfloating(Client *c, bool floating) +setfloating(Client *c, int floating) { - if (c->isfloating == floating) - return; c->isfloating = floating; arrange(c->mon); } @@ -2020,7 +2060,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags) c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ arrange(m); } - focusclient(focustop(selmon), true); + focusclient(focustop(selmon), 1); } void @@ -2069,8 +2109,8 @@ setup(void) /* If we don't provide a renderer, autocreate makes a GLES2 renderer for us. * The renderer is responsible for defining the various pixel formats it * supports for shared memory, this configures that for clients. */ - renderer = wlr_backend_get_renderer(backend); - wlr_renderer_init_wl_display(renderer, dpy); + drw = wlr_backend_get_renderer(backend); + wlr_renderer_init_wl_display(drw, dpy); /* This creates some hands-off wlroots interfaces. The compositor is * necessary for clients to allocate surfaces and the data device manager @@ -2078,7 +2118,7 @@ setup(void) * 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, renderer); + 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); @@ -2180,12 +2220,26 @@ setup(void) * Initialise the XWayland X server. * It will be started when the first X client is started. */ - xwayland = wlr_xwayland_create(dpy, compositor, true); + 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, true); + /* + * Create the XWayland cursor manager at scale 1, setting its default + * pointer to match the rest of dwl. + */ + xcursor_mgr = wlr_xcursor_manager_create(NULL, 24); + wlr_xcursor_manager_load(xcursor_mgr, 1); + xcursor = wlr_xcursor_manager_get_xcursor(xcursor_mgr, "left_ptr", 1); + if (xcursor) { + 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); + } + + setenv("DISPLAY", xwayland->display_name, 1); } else { fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); } @@ -2217,7 +2271,7 @@ tag(const Arg *arg) Client *sel = selclient(); if (sel && arg->ui & TAGMASK) { sel->tags = arg->ui & TAGMASK; - focusclient(focustop(selmon), true); + focusclient(focustop(selmon), 1); arrange(selmon); } } @@ -2251,18 +2305,15 @@ 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, false); - 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, false); + resize(c, m->w.x, m->w.y + my, mw, h, 0); my += c->geom.height; } else { h = (m->w.height - ty) / (n - i); - resize(c, m->w.x + mw, m->w.y + ty, m->w.width - mw, h, false); + resize(c, m->w.x + mw, m->w.y + ty, m->w.width - mw, h, 0); ty += c->geom.height; } i++; @@ -2288,7 +2339,7 @@ toggletag(const Arg *arg) unsigned int newtags = sel->tags ^ (arg->ui & TAGMASK); if (newtags) { sel->tags = newtags; - focusclient(focustop(selmon), true); + focusclient(focustop(selmon), 1); arrange(selmon); } } @@ -2300,7 +2351,7 @@ toggleview(const Arg *arg) if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; - focusclient(focustop(selmon), true); + focusclient(focustop(selmon), 1); arrange(selmon); } } @@ -2308,10 +2359,10 @@ toggleview(const Arg *arg) void unmaplayersurface(LayerSurface *layersurface) { - layersurface->layer_surface->mapped = false; + layersurface->layer_surface->mapped = 0; if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) - focusclient(selclient(), true); + focusclient(selclient(), 1); motionnotify(0); } @@ -2372,7 +2423,7 @@ view(const Arg *arg) selmon->seltags ^= 1; /* toggle sel tagset */ if (arg->ui & TAGMASK) selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; - focusclient(focustop(selmon), true); + focusclient(focustop(selmon), 1); arrange(selmon); } @@ -2452,7 +2503,7 @@ zoom(const Arg *arg) wl_list_remove(&sel->link); wl_list_insert(&clients, &sel->link); - focusclient(sel, true); + focusclient(sel, 1); arrange(selmon); } @@ -2464,7 +2515,7 @@ activatex11(struct wl_listener *listener, void *data) /* Only "managed" windows can be activated */ if (c->type == X11Managed) - wlr_xwayland_surface_activate(c->surface.xwayland, true); + wlr_xwayland_surface_activate(c->surface.xwayland, 1); } void @@ -2482,7 +2533,7 @@ createnotifyx11(struct wl_listener *listener, void *data) Client *c; wl_list_for_each(c, &clients, link) if (c->isfullscreen && VISIBLEON(c, c->mon)) - setfullscreen(c, false); + setfullscreen(c, 0); /* Allocate a Client for this surface */ struct wlr_xwayland_surface *xwayland_surface = data; @@ -2505,7 +2556,7 @@ createnotifyx11(struct wl_listener *listener, void *data) c->fullscreen.notify = fullscreennotify; wl_signal_add(&xwayland_surface->events.request_fullscreen, &c->fullscreen); - c->isfullscreen = false; + c->isfullscreen = 0; } Atom @@ -2557,7 +2608,7 @@ updatewindowtype(Client *c) c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] || c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] || c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility]) - c->isfloating = true; + c->isfloating = 1; } void |