diff --git a/Makefile b/Makefile index 536454f..48a0aa7 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ include config.mk -CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99 +CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99 -pedantic WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols) WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner) @@ -15,11 +15,11 @@ clean: rm -f dwl *.o *-protocol.h *-protocol.c install: dwl - install -Dm755 dwl $(PREFIX)/bin/dwl - install -Dm644 dwl.1 $(MANDIR)/man1/dwl.1 + install -Dm755 dwl $(DESTDIR)$(PREFIX)/bin/dwl + install -Dm644 dwl.1 $(DESTDIR)$(MANDIR)/man1/dwl.1 uninstall: - rm -f $(PREFIX)/bin/dwl $(MANDIR)/man1/dwl.1 + rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 .PHONY: all clean install uninstall @@ -59,6 +59,6 @@ idle-protocol.o: idle-protocol.h config.h: | config.def.h cp config.def.h $@ -dwl.o: config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h +dwl.o: config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h util.h -dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o +dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o util.o diff --git a/README.md b/README.md index 13a0000..72488e3 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,10 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s - Any features provided by dwm/Xlib: simple window borders, tags, keybindings, client rules, mouse move/resize. Providing a built-in status bar is an exception to this goal, to avoid dependencies on font rendering and/or drawing libraries when an external bar could work well. - Configurable multi-monitor layout support, including position and rotation - Configurable HiDPI/multi-DPI support +- Idle-inhibit protocol which lets applications such as mpv disable idle monitoring - Provide information to external status bars via stdout/stdin - Urgency hints via xdg-activate protocol +- Support screen lockers via input-inhibitor protocol - Various Wayland protocols - XWayland support as provided by wlroots (can be enabled in `config.mk`) - Zero flickering - Wayland users naturally expect that "every frame is perfect" @@ -25,8 +27,6 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots -- Implement the input-inhibitor protocol to support screen lockers (see https://github.com/djpohly/dwl/pull/132) -- Implement the idle-inhibit protocol which lets applications such as mpv disable idle monitoring (see https://github.com/djpohly/dwl/pull/133) - Implement the text-input and input-method protocols to support IME once ibus implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and https://github.com/djpohly/dwl/pull/12) Feature *non-goals* for the main codebase include: diff --git a/config.def.h b/config.def.h index 9bdf8b5..190b0da 100644 --- a/config.def.h +++ b/config.def.h @@ -13,8 +13,8 @@ static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ /* examples: { "Gimp", NULL, 0, 1, -1 }, - { "firefox", NULL, 1 << 8, 0, -1 }, */ + { "firefox", NULL, 1 << 8, 0, -1 }, }; /* layout(s) */ @@ -25,16 +25,14 @@ static const Layout layouts[] = { { "[M]", monocle }, }; -/* monitors - * The order in which monitors are defined determines their position. - * Non-configured monitors are always added to the left. */ +/* monitors */ static const MonitorRule monrules[] = { - /* name mfact nmaster scale layout rotate/reflect x y */ + /* name mfact nmaster scale layout rotate/reflect */ /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, 0, 0 }, + { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, */ /* defaults */ - { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, 0, 0 }, + { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, }; /* keyboard */ @@ -43,6 +41,7 @@ static const struct xkb_rule_names xkb_rules = { /* example: .options = "ctrl:nocaps", */ + .options = "", }; static const int repeat_rate = 25; diff --git a/dwl.c b/dwl.c index ae5ed93..dd62956 100644 --- a/dwl.c +++ b/dwl.c @@ -3,6 +3,7 @@ */ #define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -10,9 +11,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -21,11 +22,12 @@ #include #include #include -#include #include -#include +#include +#include +#include #include -#include +#include #include #include #include @@ -33,10 +35,10 @@ #include #include #include -#include #include -#include +#include #include +#include #include #include #include @@ -45,7 +47,6 @@ #include #include #include -#include #include #include #ifdef XWAYLAND @@ -53,9 +54,9 @@ #include #endif +#include "util.h" + /* macros */ -#define BARF(fmt, ...) do { fprintf(stderr, fmt "\n", ##__VA_ARGS__); exit(EXIT_FAILURE); } while (0) -#define EBARF(fmt, ...) BARF(fmt ": %s", ##__VA_ARGS__, strerror(errno)) #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) @@ -139,6 +140,7 @@ typedef struct { typedef struct { /* Must be first */ unsigned int type; /* LayerShell */ + int mapped; struct wlr_scene_node *scene; struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; @@ -180,8 +182,6 @@ typedef struct { float scale; const Layout *lt; enum wl_output_transform rr; - int x; - int y; } MonitorRule; typedef struct { @@ -208,12 +208,14 @@ 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 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 createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); -static void createlayersurface(struct wl_listener *listener, void *data); static void createpointer(struct wlr_pointer *pointer); static void cursorframe(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 destroynotify(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); @@ -221,8 +223,8 @@ static void dragicondestroy(struct wl_listener *listener, void *data); 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); 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); @@ -250,13 +252,13 @@ static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); 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, 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); @@ -275,9 +277,9 @@ 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 Monitor *xytomon(double x, double y); static void zoom(const Arg *arg); /* variables */ @@ -295,6 +297,8 @@ static struct wlr_xdg_activation_v1 *activation; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; +static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; +static struct wlr_input_inhibit_manager *input_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; @@ -319,6 +323,8 @@ 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 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}; @@ -620,9 +626,14 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) wlr_scene_node_reparent(layersurface->scene, layers[wlr_layer_surface->current.layer]); - if (!wlr_output) + if (!wlr_output || !(m = wlr_output->data)) return; - m = wlr_output->data; + + if (wlr_layer_surface->current.committed == 0 + && layersurface->mapped == wlr_layer_surface->mapped) + return; + + layersurface->mapped = wlr_layer_surface->mapped; if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { wl_list_remove(&layersurface->link); @@ -642,14 +653,21 @@ commitnotify(struct wl_listener *listener, void *data) c->resize = 0; } +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); + + wlr_idle_set_enabled(idle, seat, 0); +} + void createkeyboard(struct wlr_keyboard *keyboard) { struct xkb_context *context; struct xkb_keymap *keymap; - Keyboard *kb = keyboard->data = calloc(1, sizeof(*kb)); - if (!kb) - EBARF("createkeyboard: calloc"); + Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb)); kb->wlr_keyboard = keyboard; /* Prepare an XKB keymap and assign it to the keyboard. */ @@ -673,6 +691,52 @@ createkeyboard(struct wlr_keyboard *keyboard) 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; + Monitor *m; + struct wlr_layer_surface_v1_state old_state; + + if (!wlr_layer_surface->output) { + wlr_layer_surface->output = selmon->wlr_output; + } + + 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; + wlr_layer_surface->data = layersurface; + m = wlr_layer_surface->output->data; + + layersurface->scene_layer = wlr_scene_layer_surface_v1_create( + layers[wlr_layer_surface->pending.layer], wlr_layer_surface); + layersurface->scene = wlr_layer_surface->surface->data = + layersurface->scene_layer->node; + + layersurface->scene->data = layersurface; + + wl_list_insert(&m->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; + arrangelayers(m); + wlr_layer_surface->current = old_state; +} + void createmon(struct wl_listener *listener, void *data) { @@ -680,9 +744,7 @@ createmon(struct wl_listener *listener, void *data) * monitor) becomes available. */ struct wlr_output *wlr_output = data; const MonitorRule *r; - Monitor *m = wlr_output->data = calloc(1, sizeof(*m)); - if (!m) - EBARF("createmon: calloc"); + Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; wlr_output_init_render(wlr_output, alloc, drw); @@ -767,9 +829,7 @@ createnotify(struct wl_listener *listener, void *data) return; /* Allocate a Client for this surface */ - c = xdg_surface->data = calloc(1, sizeof(*c)); - if (!c) - EBARF("createnotify: calloc"); + c = xdg_surface->data = ecalloc(1, sizeof(*c)); c->surface.xdg = xdg_surface; c->bw = borderpx; @@ -783,53 +843,6 @@ createnotify(struct wl_listener *listener, void *data) c->isfullscreen = 0; } -void -createlayersurface(struct wl_listener *listener, void *data) -{ - struct wlr_layer_surface_v1 *wlr_layer_surface = data; - LayerSurface *layersurface; - Monitor *m; - struct wlr_layer_surface_v1_state old_state; - - if (!wlr_layer_surface->output) { - wlr_layer_surface->output = selmon->wlr_output; - } - - layersurface = calloc(1, sizeof(LayerSurface)); - if (!layersurface) - EBARF("layersurface: calloc"); - 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; - wlr_layer_surface->data = layersurface; - m = wlr_layer_surface->output->data; - - layersurface->scene_layer = wlr_scene_layer_surface_v1_create( - layers[wlr_layer_surface->pending.layer], wlr_layer_surface); - layersurface->scene = wlr_layer_surface->surface->data = - layersurface->scene_layer->node; - layersurface->scene->data = layersurface; - - wl_list_insert(&m->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; - arrangelayers(m); - wlr_layer_surface->current = old_state; -} - void createpointer(struct wlr_pointer *pointer) { @@ -862,6 +875,14 @@ cursorframe(struct wl_listener *listener, void *data) wlr_seat_pointer_notify_frame(seat); } +void +destroyidleinhibitor(struct wl_listener *listener, void *data) +{ + /* I've been testing and at this point the inhibitor has not yet been + * removed from the list, checking if it has at least one item. */ + wlr_idle_set_enabled(idle, seat, wl_list_length(&idle_inhibit_mgr->inhibitors) <= 1); +} + void destroylayersurfacenotify(struct wl_listener *listener, void *data) { @@ -903,57 +924,6 @@ destroynotify(struct wl_listener *listener, void *data) free(c); } -void -dragicondestroy(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(selclient(), 1); - motionnotify(0); -} - -void -togglefullscreen(const Arg *arg) -{ - Client *sel = selclient(); - if (sel) - setfullscreen(sel, !sel->isfullscreen); -} - -void -setfullscreen(Client *c, int fullscreen) -{ - c->isfullscreen = fullscreen; - c->bw = fullscreen ? 0 : borderpx; - client_set_fullscreen(c, fullscreen); - - if (fullscreen) { - c->prev = c->geom; - resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 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.x, c->prev.y, c->prev.width, c->prev.height, 0); - } - arrange(c->mon); - printstatus(); -} - -void -fullscreennotify(struct wl_listener *listener, void *data) -{ - Client *c = wl_container_of(listener, c, fullscreen); - int fullscreen = client_wants_fullscreen(c); - - if (!c->mon) { - /* if the client is not mapped yet, let mapnotify() call setfullscreen() */ - c->isfullscreen = fullscreen; - return; - } - setfullscreen(c, fullscreen); -} - Monitor * dirtomon(enum wlr_direction dir) { @@ -968,6 +938,16 @@ dirtomon(enum wlr_direction dir) return selmon; } +void +dragicondestroy(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(selclient(), 1); + motionnotify(0); +} + void focusclient(Client *c, int lift) { @@ -1021,6 +1001,7 @@ focusclient(Client *c, int lift) } printstatus(); + wlr_idle_set_enabled(idle, seat, wl_list_empty(&idle_inhibit_mgr->inhibitors)); if (!c) { /* With no client, all we have left is to clear focus */ @@ -1082,6 +1063,20 @@ focustop(Monitor *m) return NULL; } +void +fullscreennotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, fullscreen); + int fullscreen = client_wants_fullscreen(c); + + if (!c->mon) { + /* if the client is not mapped yet, let mapnotify() call setfullscreen() */ + c->isfullscreen = fullscreen; + return; + } + setfullscreen(c, fullscreen); +} + void incnmaster(const Arg *arg) { @@ -1159,8 +1154,10 @@ keypress(struct wl_listener *listener, void *data) wlr_idle_notify_activity(idle, seat); - /* On _press_, attempt to process a compositor keybinding. */ - if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + /* On _press_ if there is no active screen locker, + * attempt to process a compositor keybinding. */ + if (!input_inhibit_mgr->active_inhibitor + && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; @@ -1591,22 +1588,22 @@ run(char *startup_cmd) /* Add a Unix socket to the Wayland display. */ const char *socket = wl_display_add_socket_auto(dpy); if (!socket) - BARF("startup: display_add_socket_auto"); + die("startup: display_add_socket_auto"); setenv("WAYLAND_DISPLAY", socket, 1); /* Now that the socket exists, run the startup command */ if (startup_cmd) { int piperw[2]; - pipe(piperw); - startup_pid = fork(); - if (startup_pid < 0) - EBARF("startup: fork"); + if (pipe(piperw) < 0) + die("startup: pipe:"); + if ((startup_pid = fork()) < 0) + die("startup: fork:"); if (startup_pid == 0) { dup2(piperw[0], STDIN_FILENO); close(piperw[0]); close(piperw[1]); execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); - EBARF("startup: execl"); + die("startup: execl:"); } dup2(piperw[1], STDOUT_FILENO); close(piperw[1]); @@ -1619,7 +1616,7 @@ run(char *startup_cmd) /* Start the backend. This will enumerate outputs and inputs, become the DRM * master, etc */ if (!wlr_backend_start(backend)) - BARF("startup: backend_start"); + die("startup: backend_start"); /* Now that outputs are initialized, choose initial selmon based on * cursor position, and set default cursor image */ @@ -1681,6 +1678,25 @@ setfloating(Client *c, int floating) printstatus(); } +void +setfullscreen(Client *c, int fullscreen) +{ + c->isfullscreen = fullscreen; + c->bw = fullscreen ? 0 : borderpx; + client_set_fullscreen(c, fullscreen); + + if (fullscreen) { + c->prev = c->geom; + resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 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.x, c->prev.y, c->prev.width, c->prev.height, 0); + } + arrange(c->mon); + printstatus(); +} + void setlayout(const Arg *arg) { @@ -1779,7 +1795,7 @@ setup(void) * if the backend does not support hardware cursors (some older GPUs * don't). */ if (!(backend = wlr_backend_autocreate(dpy))) - BARF("couldn't create backend"); + die("couldn't create backend"); /* Initialize the scene graph used to lay out windows */ scene = wlr_scene_create(); @@ -1793,12 +1809,12 @@ setup(void) /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) - BARF("couldn't create renderer"); + die("couldn't create renderer"); wlr_renderer_init_wl_display(drw, dpy); /* Create a default allocator */ if (!(alloc = wlr_allocator_autocreate(backend, drw))) - BARF("couldn't create allocator"); + 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 @@ -1842,12 +1858,17 @@ setup(void) idle = wlr_idle_create(dpy); + 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); xdg_shell = wlr_xdg_shell_create(dpy); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); + input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); + /* Use decoration protocols to negotiate server-side decorations */ wlr_server_decoration_manager_set_default_mode( wlr_server_decoration_manager_create(dpy), @@ -1933,7 +1954,7 @@ spawn(const Arg *arg) dup2(STDERR_FILENO, STDOUT_FILENO); setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); - EBARF("dwl: execvp %s failed", ((char **)arg->v)[0]); + die("dwl: execvp %s failed:", ((char **)arg->v)[0]); } } @@ -2013,6 +2034,14 @@ togglefloating(const Arg *arg) setfloating(sel, !sel->isfloating); } +void +togglefullscreen(const Arg *arg) +{ + Client *sel = selclient(); + if (sel) + setfullscreen(sel, !sel->isfullscreen); +} + void toggletag(const Arg *arg) { @@ -2167,6 +2196,13 @@ virtualkeyboard(struct wl_listener *listener, void *data) createkeyboard(device->keyboard); } +Monitor * +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_scene_node * xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny) @@ -2200,13 +2236,6 @@ xytonode(double x, double y, struct wlr_surface **psurface, return node; } -Monitor * -xytomon(double x, double y) -{ - struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); - return o ? o->data : NULL; -} - void zoom(const Arg *arg) { @@ -2269,9 +2298,7 @@ createnotifyx11(struct wl_listener *listener, void *data) setfullscreen(c, 0); /* Allocate a Client for this surface */ - c = xwayland_surface->data = calloc(1, sizeof(*c)); - if (!c) - EBARF("createnotifyx11: calloc"); + c = xwayland_surface->data = ecalloc(1, sizeof(*c)); c->surface.xwayland = xwayland_surface; c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; c->bw = borderpx; @@ -2370,12 +2397,12 @@ main(int argc, char *argv[]) /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ if (!getenv("XDG_RUNTIME_DIR")) - BARF("XDG_RUNTIME_DIR must be set"); + die("XDG_RUNTIME_DIR must be set"); setup(); run(startup_cmd); cleanup(); return EXIT_SUCCESS; usage: - BARF("Usage: %s [-s startup command]", argv[0]); + die("Usage: %s [-s startup command]", argv[0]); } diff --git a/util.c b/util.c new file mode 100644 index 0000000..932f89b --- /dev/null +++ b/util.c @@ -0,0 +1,35 @@ +/* See LICENSE.dwm file for copyright and license details. */ +#include +#include +#include +#include + +#include "util.h" + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} + +void +die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..4c94117 --- /dev/null +++ b/util.h @@ -0,0 +1,4 @@ +/* See LICENSE.dwm file for copyright and license details. */ + +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size);