aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-06-04 19:10:07 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-06-04 19:10:07 -0700
commit0a8f62d8c7116be9e344f351df679599908fb29c (patch)
treebcf7fcf995b4cb97cec0b947e2b299d6bcc8ae1d /sys/cmd
parentea50cbe1bf103372a3461c80cb172f4fb4167088 (diff)
refactored
Diffstat (limited to 'sys/cmd')
-rw-r--r--sys/cmd/dway/dway.c1478
-rw-r--r--sys/cmd/dwm/client.c254
-rw-r--r--sys/cmd/dwm/config.h (renamed from sys/cmd/dway/config.h)2
-rw-r--r--sys/cmd/dwm/decoration.c52
-rw-r--r--sys/cmd/dwm/dwm.c184
-rw-r--r--sys/cmd/dwm/dwm.h (renamed from sys/cmd/dway/dway.h)188
-rw-r--r--sys/cmd/dwm/func.c217
-rw-r--r--sys/cmd/dwm/input.c333
-rw-r--r--sys/cmd/dwm/layer.c329
-rw-r--r--sys/cmd/dwm/layout.c37
-rw-r--r--sys/cmd/dwm/output.c257
-rw-r--r--sys/cmd/dwm/rules.mk50
-rw-r--r--sys/cmd/dwm/util.c22
-rw-r--r--sys/cmd/rules.mk2
14 files changed, 1867 insertions, 1538 deletions
diff --git a/sys/cmd/dway/dway.c b/sys/cmd/dway/dway.c
deleted file mode 100644
index 5eed96a..0000000
--- a/sys/cmd/dway/dway.c
+++ /dev/null
@@ -1,1478 +0,0 @@
-#include "dway.h"
-
-#define VISIBLEON(C, M) ((C)->m == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
-#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
-#define TAGMASK ((1 << arrlen(tags)) - 1)
-
-/* global state */
-static struct
-{
- struct wl_display *display;
- struct wlr_backend *backend;
- struct wlr_renderer *draw;
- struct wlr_compositor *compositor;
- struct wlr_xdg_shell *xdgsh;
- struct wlr_layer_shell_v1 *laysh;
- struct wlr_output_layout *layout;
- struct wlr_idle *idle;
- struct wlr_seat *seat;
-
- struct {
- struct wlr_server_decoration_manager *deco;
- struct wlr_xdg_decoration_manager *xdeco;
- } mngr;
-
- struct {
- struct wl_event_loop *loop;
- /* i/o devices */
- struct wl_listener idev;
- struct wl_listener odev;
- struct wl_listener client;
- struct wl_listener cursor;
- struct wl_listener sel;
- struct wl_listener psel;
- /* shells */
- struct wl_listener layer;
- struct wl_listener deco;
- } ev;
-
- struct {
- struct wl_list odevs;
- struct wl_list idevs;
- struct wl_list tiles; /* order of tiles */
- struct wl_list stack; /* order w/in stack */
- struct wl_list focus; /* order of focus */
- struct wl_list keyboards;
- struct wl_list decos;
- };
-
- /* geometry of union of output devices */
- struct wlr_box dim;
-} dway =
-{
- .ev = {
- .odev = {.notify=ev·newmonitor},
- .idev = {.notify=ev·newidev},
- .client = {.notify=ev·newclient},
- .cursor = {.notify=ev·setcursor},
- .sel = {.notify=ev·setsel},
- .psel = {.notify=ev·setpsel},
- .layer = {.notify=ev·newlayershell},
- .deco = {.notify=ev·newdecoration},
- },
-};
-
-static Monitor *monitor;
-static struct
-{
- Client *c;
- int x, y;
-} grab;
-
-static Mouse mouse = {
- .ev = {
- .axis = {.notify=ev·mousescroll},
- .button = {.notify=ev·mousebutton},
- .frame = {.notify=ev·mouseframe},
- .motion = {.notify=ev·mouserelmove},
- .absmotion = {.notify=ev·mouseabsmove},
- },
-};
-
-static Keyboard keyboard = {
- .ev = {
- .modifier = {.notify=ev·modifier},
- .keypress = {.notify=ev·keypress},
- },
-};
-
-static char *broken = "<broken>";
-
-// -----------------------------------------------------------------------
-// utility functions
-
-static void arrange(Monitor *m);
-
-/* misc */
-static
-void
-fatal(byte *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
-
- verrorf(fmt, args);
-
- va_end(args);
- exit(1);
-}
-
-static
-void
-scale(struct wlr_box *box, float by)
-{
- box->x *= by;
- box->y *= by;
- box->height *= by;
- box->width *= by;
-}
-
-/* client operations */
-static
-void
-applybounds(Client *c, struct wlr_box *bbox)
-{
- c->dim.width = MAX(1, c->dim.width);
- c->dim.height = MAX(1, c->dim.height);
-
- if (c->dim.x >= bbox->x + bbox->width)
- c->dim.x = bbox->x + bbox->width - c->dim.width;
- if (c->dim.y >= bbox->y + bbox->height)
- c->dim.y = bbox->y + bbox->height - c->dim.height;
- if (c->dim.x + c->dim.width + 2 * c->bw <= bbox->x)
- c->dim.x = bbox->x;
- if (c->dim.y + c->dim.height + 2 * c->bw <= bbox->y)
- c->dim.y = bbox->y;
-}
-
-static void setmonitor(Client *c, Monitor *m, uint newtags);
-
-static
-void
-applyrules(Client *c)
-{
- char *id, *title;
- uint i, newtags = 0;
- const Rule *r;
- Monitor *m, *it;
-
- m = monitor;
- /* rule matching */
- c->floating = 0;
- if (!(id = c->surf->toplevel->app_id))
- id = broken;
- if (!(title = c->surf->toplevel->title))
- title = broken;
-
- for (r = apprules; r < arrend(apprules); r++) {
- if ((!r->title || strstr(title, r->title))
- && (!r->id || strstr(id, r->id)))
- {
- c->floating = r->floating;
- newtags |= r->tags;
- i = 0;
- wl_list_for_each(it, &dway.odevs, link)
- if (r->monitor == i++)
- m = it;
- }
- }
- setmonitor(c, m, newtags);
-}
-
-static
-void
-resize(Client *c, int x, int y, int w, int h, int interact)
-{
- struct wlr_box *bbox;
-
- bbox = interact ? &dway.dim : &c->m->area.win;
- c->dim.x = x;
- c->dim.y = y;
- c->dim.width = w;
- c->dim.height = h;
-
- applybounds(c, bbox);
- /* wlroots makes this a no-op if size hasn't changed */
- wlr_xdg_toplevel_set_size(c->surf, c->dim.width - 2*c->bw - gapwidth, c->dim.height - 2*c->bw - gapwidth);
-}
-
-static
-Client *
-getclient(void)
-{
- Client *c;
-
- c = wl_container_of(dway.focus.next, c, link.focus);
- if (wl_list_empty(&dway.focus) || !VISIBLEON(c, monitor))
- return nil;
-
- return c;
-}
-
-static
-Client *
-clientat(double x, double y)
-{
- Client *c;
- wl_list_for_each(c, &dway.stack, link.stack)
- if (VISIBLEON(c, c->m) && wlr_box_contains_point(&c->dim, x, y))
- return c;
- return nil;
-}
-
-
-static
-Client *
-lastfocus(void)
-{
- Client *c;
- wl_list_for_each(c, &dway.focus, link.focus)
- if (VISIBLEON(c, monitor))
- return c;
-
- return nil;
-}
-
-static
-void
-setfocus(Client *c, struct wlr_surface *surf, int lift)
-{
- struct wlr_surface *prev_surface;
- struct wlr_xdg_surface *prev;
- struct wlr_keyboard *kb;
-
- if (c) {
- if (!surf)
- surf = c->surf->surface;
- monitor = c->m;
- }
-
- prev_surface = dway.seat->keyboard_state.focused_surface;
- if (prev_surface == surf)
- return;
-
- if (prev_surface) {
- prev = wlr_xdg_surface_from_wlr_surface(dway.seat->keyboard_state.focused_surface);
- wlr_xdg_toplevel_set_activated(prev, 0);
- }
-
- kb = wlr_seat_get_keyboard(dway.seat);
- wlr_seat_keyboard_notify_enter(dway.seat, surf, kb->keycodes, kb->num_keycodes, &kb->modifiers);
-
- if (c) {
- wl_list_remove(&c->link.focus);
- wl_list_insert(&dway.focus, &c->link.focus);
- if (lift) {
- wl_list_remove(&c->link.stack);
- wl_list_insert(&dway.stack, &c->link.stack);
- }
- wlr_xdg_toplevel_set_activated(c->surf, 1);
- }
-}
-
-static
-void
-setfloating(Client *c, int f)
-{
- if (c->floating == f)
- return;
-
- c->floating = f;
- arrange(c->m);
-}
-
-static
-void
-pointerfocus(Client *c, struct wlr_surface *surf, double sx, double sy, uint32 time)
-{
- if (c && !surf)
- surf = c->surf->surface;
-
- if (surf && surf == dway.seat->pointer_state.focused_surface) {
- wlr_seat_pointer_notify_motion(dway.seat, time, sx, sy);
- return;
- }
-
- wlr_seat_pointer_notify_enter(dway.seat, surf, sx, sy);
- /* If keyboard focus follows mouse, enforce that */
- if (sloppyfocus && surf)
- setfocus(c, surf, 0);
-}
-
-/* monitor operations */
-static
-void
-arrange(Monitor *m)
-{
- m->area.all = *wlr_output_layout_get_box(dway.layout, m->dev);
- m->area.win = m->area.all;
- if (m->lt[m->sellt]->arrange)
- m->lt[m->sellt]->arrange(m);
-}
-
-static
-void
-setmonitor(Client *c, Monitor *m, uint newtags)
-{
- int hadfocus;
- Monitor *old;
-
- old = c->m;
- if (old == m)
- return;
-
- hadfocus = (c == getclient());
-
- c->m = m;
- if (old) {
- wlr_surface_send_leave(c->surf->surface, old->dev);
- arrange(old);
- }
-
- if (m) {
- applybounds(c, &m->area.all);
- wlr_surface_send_enter(c->surf->surface, m->dev);
- c->tags = newtags ? newtags : m->tagset[m->seltags];
- arrange(m);
- }
-
- if (hadfocus || (c == getclient()))
- setfocus(lastfocus(), nil, 1);
-}
-
-static
-Monitor*
-getmonitor(int dir)
-{
- Monitor *m;
-
- if (dir > 0) {
- if (monitor->link.next == &dway.odevs)
- return wl_container_of(dway.odevs.next, m, link);
- return wl_container_of(monitor->link.next, m, link);
- }
- if (monitor->link.prev == &dway.odevs)
- return wl_container_of(dway.odevs.prev, m, link);
- return wl_container_of(monitor->link.prev, m, link);
-}
-
-static
-Monitor *
-monitorat(double x, double y)
-{
- struct wlr_output *dev;
-
- dev = wlr_output_layout_output_at(dway.layout, x, y);
- return dev ? dev->data : nil;
-}
-
-// -----------------------------------------------------------------------
-// event callbacks
-
-/* output devices */
-static
-void
-ev·newmonitor(struct wl_listener *ev, void *arg)
-{
- Monitor *m;
- const MonitorRule *r;
- struct wlr_output *dev;
- struct wlr_output_mode *mode;
-
- dev = arg;
- wlr_output_set_mode(dev, wlr_output_preferred_mode(dev));
-
- m = dev->data = calloc(1, sizeof(*m));
- m->dev = dev;
- m->tagset[0] = m->tagset[1] = 1;
- /* look for rules to apply */
- for (r = monitorrules; r < arrend(monitorrules); r++) {
- if (!r->name || strstr(dev->name, r->name)) {
- m->mfact = r->mfact;
- m->nmaster = r->nmaster;
- wlr_output_set_scale(dev, r->scale);
- wlr_xcursor_manager_load(mouse.manager, r->scale);
- m->lt[0] = m->lt[1] = r->lt;
- wlr_output_set_transform(dev, r->rr);
- break;
- }
- }
-
- /* install callbacks */
- m->ev.draw.notify = ev·render;
- m->ev.free.notify = ev·freemonitor;
-
- wl_signal_add(&dev->events.frame, &m->ev.draw);
- wl_signal_add(&dev->events.destroy, &m->ev.free);
-
- wl_list_insert(&dway.odevs, &m->link);
-
- wlr_output_enable(dev, 1);
- if (!wlr_output_commit(dev))
- return;
-
- wl_signal_init(&m->sig.kill);
-
- wlr_output_layout_add_auto(dway.layout, dev);
- dway.dim = *wlr_output_layout_get_box(dway.layout, nil);
-}
-
-static
-void
-ev·freemonitor(struct wl_listener *ev, void *arg)
-{
- Monitor *m;
-
- m = wl_container_of(ev, m, ev.free);
- wl_signal_emit(&m->sig.kill, m);
-
- wl_list_remove(&m->link);
- wl_list_remove(&m->ev.draw.link);
- wl_list_remove(&m->ev.free.link);
-
- free(m);
-}
-
-static
-void
-render(struct wlr_surface *surf, int sx, int sy, void *arg)
-{
- Payload *data;
- double x, y;
- float mtx[9];
- struct wlr_box box;
- struct wlr_output *dev;
- struct wlr_texture *tex;
- enum wl_output_transform transform;
-
- data = arg;
- dev = data->dev;
-
- tex = wlr_surface_get_texture(surf);
- if (!tex)
- return;
-
- /* convert to device local coord */
- wlr_output_layout_output_coords(dway.layout, dev, &x, &y);
-
- box.x = x + data->x + sx;
- box.y = y + data->y + sy;
- box.width = surf->current.width;
- box.height = surf->current.height;
- scale(&box, dev->scale);
-
- /* orthographic projection */
- transform = wlr_output_transform_invert(surf->current.transform);
- wlr_matrix_project_box(mtx, &box, transform, 0, dev->transform_matrix);
-
- /* render with GPU */
- wlr_render_texture_with_matrix(dway.draw, tex, mtx, 1);
-
- /* notify the client we are done */
- wlr_surface_send_frame_done(surf, data->now);
-}
-
-static
-void
-renderclients(Monitor *m, struct timespec *now)
-{
- Client *c;
- double x, y;
- int i, w, h;
- Payload data;
- struct wlr_box *borders;
-
- wl_list_for_each_reverse(c, &dway.stack, link.stack) {
- if (!VISIBLEON(c, c->m) || !wlr_output_layout_intersects(dway.layout, m->dev, &c->dim))
- continue;
-
- x = c->dim.x;
- y = c->dim.y;
-
- wlr_output_layout_output_coords(dway.layout, m->dev, &x, &y);
-
- w = c->surf->surface->current.width;
- h = c->surf->surface->current.height;
-
- borders = (struct wlr_box[4]) {
- {x, y, w + 2 * c->bw, c->bw}, /* top */
- {x, y + c->bw, c->bw, h}, /* left */
- {x + c->bw + w, y + c->bw, c->bw, h}, /* right */
- {x, y + c->bw + h, w + 2 * c->bw, c->bw}, /* bottom */
- };
- for (i = 0; i < 4; i++) {
- scale(&borders[i], m->dev->scale);
- wlr_render_rect(dway.draw, &borders[i], bordercolor, m->dev->transform_matrix);
- }
-
- data.dev = m->dev;
- data.now = now;
- data.x = c->dim.x + c->bw;
- data.y = c->dim.y + c->bw;
-
- wlr_xdg_surface_for_each_surface(c->surf, render, &data);
- }
-}
-
-static
-void
-ev·render(struct wl_listener *ev, void *arg)
-{
- int w, h;
- Monitor *m;
- struct timespec now;
-
- m = wl_container_of(ev, m, ev.draw);
-
- if (!wlr_output_attach_render(m->dev, nil))
- return;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- wlr_output_effective_resolution(m->dev, &w, &h);
-
- wlr_renderer_begin(dway.draw, w, h);
- wlr_renderer_clear(dway.draw, rootcolor);
-
- renderclients(m, &now);
-
- wlr_output_render_software_cursors(m->dev, nil);
-
- wlr_renderer_end(dway.draw);
- wlr_output_commit(m->dev);
-}
-
-/* wlr-layers */
-static
-void
-ev·newlayershell(struct wl_listener *ev, void *arg)
-{
- Layer *layer;
- struct wlr_layer_surface_v1 *surf;
-
- surf = arg;
- if (!surf->output)
- surf->output = monitor->dev;
-
- layer = surf->data = calloc(1, sizeof(*layer));
- layer->surf = surf;
-
- /* install callbacks */
- layer->ev.free.notify = ev·freelayershell;
- layer->ev.map.notify = ev·maplayershell;
- layer->ev.unmap.notify = ev·unmaplayershell;
- layer->ev.commit.notify = ev·commitlayershell;
- layer->ev.kill.notify = ev·killlayershell;
-
- wl_signal_add(&surf->events.destroy, &layer->ev.free);
- wl_signal_add(&surf->events.map, &layer->ev.map);
- wl_signal_add(&surf->events.unmap, &layer->ev.unmap);
- wl_signal_add(&surf->surface->events.commit, &layer->ev.commit);
- wl_signal_add(&monitor->sig.kill, &layer->ev.kill);
-}
-
-static
-void
-ev·maplayershell(struct wl_listener *ev, void *arg)
-{
- Layer *l;
- Monitor *m;
-
- l = wl_container_of(ev, l, ev.map);
- m = l->surf->output->data;
- /* TODO: damage */
- wlr_surface_send_enter(l->surf->surface, l->surf->output);
- /* TODO: cursor */
-}
-
-static
-void
-ev·unmaplayershell(struct wl_listener *ev, void *arg)
-{
- /* TODO: fill in */
-}
-
-static
-void
-ev·commitlayershell(struct wl_listener *ev, void *arg)
-{
- /* TODO: fill in */
-}
-
-static
-void
-ev·freelayershell(struct wl_listener *ev, void *arg)
-{
- Layer *l;
-
- l = wl_container_of(ev, l, ev.map);
-
- wl_list_remove(&l->link);
- wl_list_remove(&l->ev.free.link);
- wl_list_remove(&l->ev.map.link);
- wl_list_remove(&l->ev.unmap.link);
- wl_list_remove(&l->ev.kill.link);
- wl_list_remove(&l->ev.commit.link);
-
- free(l);
-}
-
-static
-void
-ev·killlayershell(struct wl_listener *ev, void *arg)
-{
-
-}
-
-/* decorations */
-static
-void
-ev·newdecoration(struct wl_listener *ev, void *arg)
-{
- struct wlr_server_decoration *wlr;
- Deco *deco;
-
- wlr = arg;
-
- deco = calloc(1, sizeof(*deco));
- if (!deco)
- return;
-
- deco->wlr = wlr;
-
- wl_signal_add(&wlr->events.destroy, &deco->ev.free);
- deco->ev.free.notify = ev·freedecoration;
-
- wl_signal_add(&wlr->events.mode, &deco->ev.mode);
- deco->ev.mode.notify = ev·modedecoration;
-
- wl_list_insert(&dway.decos, &deco->link);
-}
-
-static
-void
-ev·freedecoration(struct wl_listener *ev, void *arg)
-{
- Deco *deco;
-
- deco = wl_container_of(ev, deco, ev.free);
-
- wl_list_remove(&deco->ev.free.link);
- wl_list_remove(&deco->ev.mode.link);
- wl_list_remove(&deco->link);
- free(deco);
-}
-static
-void
-ev·modedecoration(struct wl_listener *ev, void *arg)
-{
- /* no op */
-}
-
-/* xdg-surfaces */
-
-#define WLR_EDGE_ALL WLR_EDGE_TOP|WLR_EDGE_BOTTOM|WLR_EDGE_LEFT|WLR_EDGE_RIGHT
-static
-void
-ev·newclient(struct wl_listener *ev, void *arg)
-{
- Client *c;
- struct wlr_xdg_surface *surf;
-
- surf = arg;
- if (surf->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
- return;
-
- c = surf->data = calloc(1, sizeof(*c));
- c->surf = surf;
- c->bw = borderwidth;
-
- wlr_xdg_toplevel_set_tiled(surf, WLR_EDGE_ALL);
-
- /* install callbacks */
- c->ev.map.notify = ev·mapclient;
- c->ev.unmap.notify = ev·unmapclient;
- c->ev.free.notify = ev·freeclient;
-
- wl_signal_add(&surf->events.map, &c->ev.map);
- wl_signal_add(&surf->events.unmap, &c->ev.unmap);
- wl_signal_add(&surf->events.destroy, &c->ev.free);
-}
-
-static
-void
-ev·mapclient(struct wl_listener *ev, void *arg)
-{
- Client *c;
-
- c = wl_container_of(ev, c, ev.map);
-
- wl_list_insert(&dway.tiles, &c->link.tiles);
- wl_list_insert(&dway.focus, &c->link.focus);
- wl_list_insert(&dway.stack, &c->link.stack);
-
- wlr_xdg_surface_get_geometry(c->surf, &c->dim);
-
- c->dim.width += 2 * c->bw;
- c->dim.height += 2 * c->bw;
-
- applyrules(c);
-}
-
-static
-void
-ev·unmapclient(struct wl_listener *ev, void *arg)
-{
- Monitor *m;
- Client *c;
-
- c = wl_container_of(ev, c, ev.unmap);
- m = c->m;
- setmonitor(c, nil, 0);
-
- wl_list_remove(&c->link.tiles);
- wl_list_remove(&c->link.stack);
- wl_list_remove(&c->link.focus);
-
- c->surf = nil;
- arrange(m);
-}
-
-static
-void
-ev·freeclient(struct wl_listener *ev, void *arg)
-{
- Client *c;
- c = wl_container_of(ev, c, ev.free);
- free(c);
-}
-
-/* server decorations */
-
-/* cursor images */
-
-static
-void
-ev·setcursor(struct wl_listener *ev, void *arg)
-{
- struct wlr_seat_pointer_request_set_cursor_event *cur;
-
- cur = arg;
- if (mouse.mode != MouseNormal)
- return;
-
- if (cur->seat_client == dway.seat->pointer_state.focused_client)
- wlr_cursor_set_surface(mouse.cursor, cur->surface, cur->hotspot_x, cur->hotspot_y);
-}
-
-static
-void
-ev·setpsel(struct wl_listener *ev, void *arg)
-{
- struct wlr_seat_request_set_primary_selection_event *psel;
-
- psel = arg;
- wlr_seat_set_primary_selection(dway.seat, psel->source, psel->serial);
-}
-
-static
-void
-ev·setsel(struct wl_listener *ev, void *arg)
-{
- struct wlr_seat_request_set_selection_event *sel;
-
- sel = arg;
- wlr_seat_set_selection(dway.seat, sel->source, sel->serial);
-}
-
-/* input devices */
-
-static
-void
-newkeyboard(struct wlr_input_device *dev)
-{
- Keyboard *kb;
- struct xkb_context *ctx;
- struct xkb_keymap *map;
-
- kb = dev->data = calloc(1, sizeof(*kb));
- kb->dev = dev;
-
- ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
- map = xkb_map_new_from_names(ctx, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
-
- wlr_keyboard_set_keymap(dev->keyboard, map);
- xkb_keymap_unref(map);
- xkb_context_unref(ctx);
-
- wlr_keyboard_set_repeat_info(dev->keyboard, 25, 600);
-
- kb->ev.modifier.notify = ev·modifier;
- wl_signal_add(&dev->keyboard->events.modifiers, &kb->ev.modifier);
- kb->ev.keypress.notify = ev·keypress;
- wl_signal_add(&dev->keyboard->events.key, &kb->ev.keypress);
-
- wlr_seat_set_keyboard(dway.seat, dev);
-
- wl_list_insert(&dway.keyboards, &kb->link);
-}
-
-static
-void
-newmouse(struct wlr_input_device *dev)
-{
- wlr_cursor_attach_input_device(mouse.cursor, dev);
-}
-
-static
-void
-ev·newidev(struct wl_listener *ev, void *arg)
-{
- uint32 c;
- struct wlr_input_device *dev;
-
- dev = arg;
- switch (dev->type) {
- case WLR_INPUT_DEVICE_KEYBOARD:
- newkeyboard(dev);
- break;
- case WLR_INPUT_DEVICE_POINTER:
- newmouse(dev);
- break;
- default:
- ;
- }
-
- c = WL_SEAT_CAPABILITY_POINTER;
- if (!wl_list_empty(&dway.keyboards))
- c |= WL_SEAT_CAPABILITY_KEYBOARD;
- wlr_seat_set_capabilities(dway.seat, c);
-}
-
-/* mouse input */
-
-static
-void
-ev·mousescroll(struct wl_listener *ev, void *arg)
-{
- struct wlr_event_pointer_axis *axis;
-
- axis = arg;
- wlr_seat_pointer_notify_axis(dway.seat,
- axis->time_msec,
- axis->orientation,
- axis->delta,
- axis->delta_discrete,
- axis->source);
-}
-
-static
-void
-ev·mousebutton(struct wl_listener *ev, void *arg)
-{
- uint32 mods;
- Client *c;
- const Button *b;
- struct wlr_surface *surf;
- struct wlr_keyboard *keyb;
- struct wlr_event_pointer_button *button;
-
- button = arg;
- switch (button->state) {
- case WLR_BUTTON_PRESSED:
- if ((c = clientat(mouse.cursor->x, mouse.cursor->y))) {
- surf = wlr_xdg_surface_surface_at(c->surf,
- mouse.cursor->x - c->dim.x - c->bw,
- mouse.cursor->y - c->dim.y - c->bw,
- nil, nil
- );
- setfocus(c, surf, 1);
- }
-
- keyb = wlr_seat_get_keyboard(dway.seat);
- mods = wlr_keyboard_get_modifiers(keyb);
- for (b = buttons; b < arrend(buttons); b++) {
- if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
- button->button == b->kind && b->func) {
- b->func(&b->arg);
- return;
- }
- }
- break;
-
- case WLR_BUTTON_RELEASED:
- if (mouse.mode != MouseNormal) {
- wlr_xcursor_manager_set_cursor_image(mouse.manager, "left_ptr", mouse.cursor);
- mouse.mode = MouseNormal;
- monitor = monitorat(mouse.cursor->x, mouse.cursor->y);
- setmonitor(grab.c, monitor, 0);
- }
- }
-
- wlr_seat_pointer_notify_button(dway.seat, button->time_msec, button->button, button->state);
-}
-
-static
-void
-ev·mouseframe(struct wl_listener *ev, void *arg)
-{
- wlr_seat_pointer_notify_frame(dway.seat);
-}
-
-static
-void
-mousemoved(uint32 time)
-{
- Client *c;
- double sx, sy;
- struct wlr_surface *surf;
-
- if (sloppyfocus)
- monitor = monitorat(mouse.cursor->x, mouse.cursor->y);
-
- switch (mouse.mode) {
- case MouseMove:
- resize(grab.c,
- mouse.cursor->x - grab.x,
- mouse.cursor->y - grab.y,
- grab.c->dim.width, grab.c->dim.height, 1);
- return;
-
- case MouseResize:
- resize(grab.c,
- grab.c->dim.x, grab.c->dim.y,
- mouse.cursor->x - grab.c->dim.x,
- mouse.cursor->y - grab.c->dim.y, 1);
- return;
-
- case MouseNormal:
- default:
- ;
- }
-
- surf = nil;
- if ((c = clientat(mouse.cursor->x, mouse.cursor->y)))
- surf = wlr_xdg_surface_surface_at(c->surf,
- mouse.cursor->x - c->dim.x - c->bw,
- mouse.cursor->y - c->dim.y - c->bw,
- &sx, &sy);
-
- if (!surf)
- wlr_xcursor_manager_set_cursor_image(mouse.manager, "left_ptr", mouse.cursor);
-
- pointerfocus(c, surf, sx, sy, time);
-}
-
-static
-void
-ev·mouserelmove(struct wl_listener *ev, void *arg)
-{
- struct wlr_event_pointer_motion *mv;
-
- mv = arg;
- wlr_cursor_move(mouse.cursor, mv->device, mv->delta_x, mv->delta_y);
- mousemoved(mv->time_msec);
-}
-
-static
-void
-ev·mouseabsmove(struct wl_listener *ev, void *arg)
-{
- struct wlr_event_pointer_motion_absolute *mv;
-
- mv = arg;
- wlr_cursor_warp_absolute(mouse.cursor, mv->device, mv->x, mv->y);
- mousemoved(mv->time_msec);
-}
-
-/* keyboard input */
-
-static
-int
-dokey(uint32 mods, xkb_keysym_t sym)
-{
- int h;
- const Key *k, *e;
-
- h = 0;
- for (k = keys, e = arrend(keys); k < e; k++)
- if (CLEANMASK(mods) == CLEANMASK(k->mod) && sym == k->sym && k->func) {
- k->func(&k->arg);
- h = 1;
- }
-
- return h;
-}
-
-static
-void
-ev·modifier(struct wl_listener *ev, void *arg)
-{
- Keyboard *kb;
-
- kb = wl_container_of(ev, kb, ev.modifier);
- wlr_seat_set_keyboard(dway.seat, kb->dev);
-
- wlr_seat_keyboard_notify_modifiers(dway.seat, &kb->dev->keyboard->modifiers);
-}
-
-static
-void
-ev·keypress(struct wl_listener *ev, void *arg)
-{
- Keyboard *kb;
- int i, n, hit;
- uint32 code, mods;
- const xkb_keysym_t *syms;
- struct wlr_event_keyboard_key *key;
-
- key = arg;
- kb = wl_container_of(ev, kb, ev.keypress);
-
- code = key->keycode + 8;
- n = xkb_state_key_get_syms(kb->dev->keyboard->xkb_state, code, &syms);
- mods = wlr_keyboard_get_modifiers(kb->dev->keyboard);
-
- hit = 0;
- if (key->state == WLR_KEY_PRESSED)
- for (i = 0; i < n; i++)
- hit += dokey(mods, syms[i]);
-
- /* if no binding found, pass the event to the client */
- if (!hit) {
- wlr_seat_set_keyboard(dway.seat, kb->dev);
- wlr_seat_keyboard_notify_key(dway.seat, key->time_msec, key->keycode, key->state);
- }
-}
-
-// -----------------------------------------------------------------------
-// user hook functions
-
-static
-void
-chvt(const Arg *arg)
-{
- struct wlr_session *s;
-
- s = wlr_backend_get_session(dway.backend);
- if (!s)
- return;
-
- wlr_session_change_vt(s, arg->ui);
-}
-
-static
-void
-incmaster(const Arg *arg)
-{
- monitor->nmaster = MAX(monitor->nmaster + arg->i, 0);
- arrange(monitor);
-}
-
-static
-void
-focusmonitor(const Arg *arg)
-{
- Monitor *m;
-
- m = getmonitor(arg->i);
-
- if (m == monitor)
- return;
-
- monitor = m;
- setfocus(lastfocus(), nil, 1);
-}
-
-static
-void
-focusstack(const Arg *arg)
-{
- Client *c, *sel;
-
- sel = getclient();
- if (!sel)
- return;
-
- if (arg->i > 0) {
- wl_list_for_each(c, &sel->link.tiles, link.tiles) {
- if (&c->link.tiles == &dway.tiles)
- continue;
- if (VISIBLEON(c, monitor))
- break;
- }
- } else {
- wl_list_for_each_reverse(c, &sel->link.tiles, link.tiles) {
- if (&c->link.tiles == &dway.tiles)
- continue; /* wrap past the sentinel node */
- if (VISIBLEON(c, monitor))
- break; /* found it */
- }
- }
- /* If only one client is visible on selmon, then c == sel */
- setfocus(c, nil, 1);
-}
-
-static
-void
-moveresize(const Arg *arg)
-{
- grab.c = clientat(mouse.cursor->x, mouse.cursor->y);
- if (!grab.c)
- return;
-
- /* Float the window and tell motionnotify to grab it */
- setfloating(grab.c, 1);
- switch (mouse.mode = arg->ui) {
- case MouseMove:
- grab.x = mouse.cursor->x - grab.c->dim.x;
- grab.y = mouse.cursor->y - grab.c->dim.y;
- wlr_xcursor_manager_set_cursor_image(mouse.manager, "fleur", mouse.cursor);
- break;
- case MouseResize:
- wlr_cursor_warp_closest(mouse.cursor, nil,
- grab.c->dim.x + grab.c->dim.width,
- grab.c->dim.y + grab.c->dim.height);
- wlr_xcursor_manager_set_cursor_image(mouse.manager, "bottom_right_corner", mouse.cursor);
- break;
- }
-}
-
-static
-void
-quit(const Arg *arg)
-{
- wl_display_terminate(dway.display);
-}
-
-static
-void
-setlayout(const Arg *arg)
-{
- if (!arg || !arg->v || arg->v != monitor->lt[monitor->sellt])
- monitor->sellt ^= 1;
- if (arg && arg->v)
- monitor->lt[monitor->sellt] = (Layout *)arg->v;
-
- arrange(monitor);
-}
-
-static
-void
-setmfact(const Arg *arg)
-{
- float f;
-
- if (!arg || !monitor->lt[monitor->sellt]->arrange)
- return;
- f = arg->f < 1.0 ? arg->f + monitor->mfact : arg->f - 1.0;
- if (f < 0.1 || f > 0.9)
- return;
- monitor->mfact = f;
- arrange(monitor);
-}
-
-static
-void
-spawn(const Arg *arg)
-{
- pid_t pid;
- if ((pid=fork()) == 0) {
- setsid();
-
- printf("running %s\n", ((char**)arg->v)[0]);
- execvp(((char **)arg->v)[0], (char **)arg->v);
-
- fprintf(stderr, "dwl: execvp %s", ((char **)arg->v)[0]);
- perror(" failed");
- exit(EXIT_FAILURE);
- } else if (pid < 0)
- fatal("failed to fork");
-}
-
-static
-void
-tag(const Arg *arg)
-{
- Client *c;
-
- c = getclient();
- if (c && arg->ui & TAGMASK) {
- c->tags = arg->ui & TAGMASK;
- setfocus(lastfocus(), nil, 1);
- arrange(monitor);
- }
-}
-
-static
-void
-tagmonitor(const Arg *arg)
-{
- Client *c;
-
- c = getclient();
- if (!c)
- return;
- setmonitor(c, getmonitor(arg->i), 0);
-}
-
-static
-void
-togglefloating(const Arg *arg)
-{
- Client *c;
-
- c = getclient();
- if (!c)
- return;
-
- setfloating(c, !c->floating);
-}
-
-static
-void
-toggletag(const Arg *arg)
-{
- Client *c;
- uint newtags;
-
- c = getclient();
- if (!c)
- return;
- newtags = c->tags ^ (arg->ui & TAGMASK);
- if (newtags) {
- c->tags = newtags;
- setfocus(lastfocus(), nil, 1);
- arrange(monitor);
- }
-}
-
-static
-void
-toggleview(const Arg *arg)
-{
- uint newtagset;
-
- newtagset = monitor->tagset[monitor->seltags] ^ (arg->ui & TAGMASK);
-
- if (newtagset) {
- monitor->tagset[monitor->seltags] = newtagset;
- setfocus(lastfocus(), nil, 1);
- arrange(monitor);
- }
-}
-
-static
-void
-view(const Arg *arg)
-{
- if ((arg->ui & TAGMASK) == monitor->tagset[monitor->seltags])
- return;
-
- monitor->seltags ^= 1; /* toggle sel tagset */
- if (arg->ui & TAGMASK)
- monitor->tagset[monitor->seltags] = arg->ui & TAGMASK;
- setfocus(lastfocus(), nil, 1);
-
- arrange(monitor);
-}
-
-// -----------------------------------------------------------------------
-// layouts
-
-static
-void
-tile(Monitor *m)
-{
- Client *c;
- uint i, n, h, mw, my, ty;
-
- n = 0;
- wl_list_for_each(c, &dway.tiles, link.tiles)
- if (VISIBLEON(c, m) && !c->floating)
- n++;
-
- if (n == 0)
- return;
-
- if (n > m->nmaster)
- mw = m->nmaster ? m->area.win.width * m->mfact : 0;
- else
- mw = m->area.win.width;
-
- i = my = ty = 0;
- wl_list_for_each(c, &dway.tiles, link.tiles) {
- if (!VISIBLEON(c, m) || c->floating)
- continue;
- if (i < m->nmaster) {
- h = (m->area.win.height - my) / (MIN(n, m->nmaster) - i);
- resize(c, m->area.win.x, m->area.win.y + my, mw, h, 0);
- my += c->dim.height;
- } else {
- h = (m->area.win.height - ty) / (n - i);
- resize(c, m->area.win.x + mw, m->area.win.y + ty, m->area.win.width - mw, h, 0);
- ty += c->dim.height;
- }
- i++;
- }
-}
-
-// -----------------------------------------------------------------------
-// main point of entry
-
-void
-setup(void)
-{
- /* wayland boilerplate */
- dway.display = wl_display_create();
- if (!dway.display)
- fatal("failed to initialize display");
-
- dway.backend = wlr_backend_autocreate(dway.display, nil);
- if (!dway.backend)
- fatal("failed to create backend");
-
- dway.draw = wlr_backend_get_renderer(dway.backend);
- if (!dway.draw)
- fatal("failed to initialize renderer");
- wlr_renderer_init_wl_display(dway.draw, dway.display);
-
- /* intialize the compositor and some automated handlers */
- dway.compositor = wlr_compositor_create(dway.display, dway.draw);
-
- wlr_data_device_manager_create(dway.display);
- wlr_gamma_control_manager_v1_create(dway.display);
- wlr_gtk_primary_selection_device_manager_create(dway.display);
-
- /* middle management */
- wlr_export_dmabuf_manager_v1_create(dway.display);
- wlr_screencopy_manager_v1_create(dway.display);
- wlr_data_control_manager_v1_create(dway.display);
- wlr_primary_selection_v1_device_manager_create(dway.display);
-
- dway.ev.loop = wl_display_get_event_loop(dway.display);
- if (!dway.ev.loop)
- fatal("failed to initialize event loop");
-
- dway.layout = wlr_output_layout_create();
- wlr_xdg_output_manager_v1_create(dway.display, dway.layout);
-
- /* grab output devices */
- wl_list_init(&dway.odevs);
- wl_signal_add(&dway.backend->events.new_output, &dway.ev.odev);
-
- /* initialize window structures */
- wl_list_init(&dway.tiles);
- wl_list_init(&dway.stack);
- wl_list_init(&dway.focus);
- wl_list_init(&dway.decos);
-
- /* layer shell */
- dway.laysh = wlr_layer_shell_v1_create(dway.display);
- wl_signal_add(&dway.laysh->events.new_surface, &dway.ev.layer);
-
- /* xdg shell */
- dway.xdgsh = wlr_xdg_shell_create(dway.display);
- wl_signal_add(&dway.xdgsh->events.new_surface, &dway.ev.client);
-
- /* decorations */
- dway.mngr.deco = wlr_server_decoration_manager_create(dway.display);
- wlr_server_decoration_manager_set_default_mode(dway.mngr.deco, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
- wl_signal_add(&dway.mngr.deco->events.new_decoration, &dway.ev.deco);
- wl_list_init(&dway.decos);
-
- dway.mngr.deco = wlr_server_decoration_manager_create(dway.display);
-
- /* grab input devices and install callbacks */
- mouse.cursor = wlr_cursor_create();
- if (!mouse.cursor)
- fatal("no mouse found");
- wlr_cursor_attach_output_layout(mouse.cursor, dway.layout);
- mouse.manager = wlr_xcursor_manager_create(nil, 24);
-
- /* attach the static cursor object to event handlers */
- wl_signal_add(&mouse.cursor->events.axis, &mouse.ev.axis);
- wl_signal_add(&mouse.cursor->events.frame, &mouse.ev.frame);
- wl_signal_add(&mouse.cursor->events.button, &mouse.ev.button);
- wl_signal_add(&mouse.cursor->events.motion, &mouse.ev.motion);
- wl_signal_add(&mouse.cursor->events.motion_absolute, &mouse.ev.absmotion);
-
- wl_list_init(&dway.idevs);
- wl_list_init(&dway.keyboards);
- wl_signal_add(&dway.backend->events.new_input, &dway.ev.idev);
-
- dway.seat = wlr_seat_create(dway.display, "seat0");
- wl_signal_add(&dway.seat->events.request_set_cursor, &dway.ev.cursor);
- wl_signal_add(&dway.seat->events.request_set_selection, &dway.ev.sel);
- wl_signal_add(&dway.seat->events.request_set_primary_selection, &dway.ev.psel);
-}
-
-void
-run(void)
-{
- byte *socket;
- pid_t start = -1;
-
- socket = (byte*)wl_display_add_socket_auto(dway.display);
- if (!socket) {
- wlr_backend_destroy(dway.backend);
- fatal("could not open socket");
- }
-
- if (!wlr_backend_start(dway.backend)) {
- wlr_backend_destroy(dway.backend);
- wl_display_destroy(dway.display);
- fatal("failed to start backend");
- }
-
- monitor = monitorat(mouse.cursor->x, mouse.cursor->y);
- if (!monitor)
- fatal("no monitor found");
-
- wlr_cursor_warp_closest(mouse.cursor, nil, mouse.cursor->x, mouse.cursor->y);
- wlr_xcursor_manager_set_cursor_image(mouse.manager, "left_ptr", mouse.cursor);
-
- setenv("WAYLAND_DISPLAY", socket, 1);
-
- wlr_log(WLR_INFO, "running dway on WAYLAND_DISPLAY\n");
- wl_display_run(dway.display);
-}
-
-void
-cleanup(void)
-{
- wl_display_destroy_clients(dway.display);
- wl_display_destroy(dway.display);
- wlr_backend_destroy(dway.backend);
-}
-
-void
-usage(void)
-{
- printf("usage: %s [-qvd] [-s startup_cmd]\n", argv0);
- exit(1);
-}
-
-int
-main(int argc, byte *argv[])
-{
- byte *cmd;
- enum wlr_log_importance lvl;
-
- cmd = nil;
- lvl = WLR_ERROR;
-
- ARGBEGIN {
- case 'q':
- lvl = WLR_SILENT;
- break;
- case 'v':
- lvl = WLR_INFO;
- break;
- case 'd':
- lvl = WLR_DEBUG;
- break;
- case 's':
- cmd = EARGF(usage());
- break;
- default:
- usage();
- } ARGEND;
-
- wlr_log_init(lvl, nil);
-
- setup();
- run();
- cleanup();
-
- return 0;
-}
diff --git a/sys/cmd/dwm/client.c b/sys/cmd/dwm/client.c
new file mode 100644
index 0000000..cc9730b
--- /dev/null
+++ b/sys/cmd/dwm/client.c
@@ -0,0 +1,254 @@
+#include "dwm.h"
+
+#define WLR_EDGE_ALL WLR_EDGE_TOP|WLR_EDGE_BOTTOM|WLR_EDGE_LEFT|WLR_EDGE_RIGHT
+
+
+/* local callbacks */
+static void map(struct wl_listener *ev, void *arg);
+static void unmap(struct wl_listener *ev, void *arg);
+static void delete(struct wl_listener *ev, void *arg);
+
+/* globals */
+static char *broken = "<broken>";
+
+// -----------------------------------------------------------------------
+// methods
+
+void
+applybounds(Client *c, struct wlr_box *bbox)
+{
+ c->dim.width = MAX(1, c->dim.width);
+ c->dim.height = MAX(1, c->dim.height);
+
+ if (c->dim.x >= bbox->x + bbox->width)
+ c->dim.x = bbox->x + bbox->width - c->dim.width;
+ if (c->dim.y >= bbox->y + bbox->height)
+ c->dim.y = bbox->y + bbox->height - c->dim.height;
+ if (c->dim.x + c->dim.width + 2 * c->bw <= bbox->x)
+ c->dim.x = bbox->x;
+ if (c->dim.y + c->dim.height + 2 * c->bw <= bbox->y)
+ c->dim.y = bbox->y;
+}
+
+void
+applyrules(Client *c)
+{
+ char *id, *title;
+ uint i, newtags = 0;
+ const Rule *r;
+ Monitor *m, *it;
+
+ m = monitor;
+ /* rule matching */
+ c->floating = 0;
+ if (!(id = c->surf->toplevel->app_id))
+ id = broken;
+ if (!(title = c->surf->toplevel->title))
+ title = broken;
+
+ for (r = apprules; r < arrend(apprules); r++) {
+ if ((!r->title || strstr(title, r->title))
+ && (!r->id || strstr(id, r->id)))
+ {
+ c->floating = r->floating;
+ newtags |= r->tags;
+ i = 0;
+ wl_list_for_each(it, &dwm.odevs, link)
+ if (r->monitor == i++)
+ m = it;
+ }
+ }
+ setmonitor(c, m, newtags);
+}
+
+void
+resize(Client *c, int x, int y, int w, int h, int interact)
+{
+ struct wlr_box *bbox;
+
+ bbox = interact ? &dwm.dim : &c->m->area.win;
+ c->dim.x = x;
+ c->dim.y = y;
+ c->dim.width = w;
+ c->dim.height = h;
+
+ applybounds(c, bbox);
+ /* wlroots makes this a no-op if size hasn't changed */
+ wlr_xdg_toplevel_set_size(c->surf, c->dim.width - 2*c->bw - gapwidth, c->dim.height - 2*c->bw - gapwidth);
+}
+
+Client *
+getclient(void)
+{
+ Client *c;
+
+ c = wl_container_of(dwm.focus.next, c, link.focus);
+ if (wl_list_empty(&dwm.focus) || !VISIBLEON(c, monitor))
+ return nil;
+
+ return c;
+}
+
+Client *
+clientat(double x, double y)
+{
+ Client *c;
+ wl_list_for_each(c, &dwm.stack, link.stack)
+ if (VISIBLEON(c, c->m) && wlr_box_contains_point(&c->dim, x, y))
+ return c;
+ return nil;
+}
+
+
+Client *
+lastfocus(void)
+{
+ Client *c;
+ wl_list_for_each(c, &dwm.focus, link.focus)
+ if (VISIBLEON(c, monitor))
+ return c;
+
+ return nil;
+}
+
+void
+setfocus(Client *c, struct wlr_surface *surf, int lift)
+{
+ struct wlr_surface *prev_surface;
+ struct wlr_xdg_surface *prev;
+ struct wlr_keyboard *kb;
+
+ if (c) {
+ if (!surf)
+ surf = c->surf->surface;
+ monitor = c->m;
+ }
+
+ prev_surface = dwm.seat->keyboard_state.focused_surface;
+ if (prev_surface == surf)
+ return;
+
+ if (prev_surface) {
+ prev = wlr_xdg_surface_from_wlr_surface(dwm.seat->keyboard_state.focused_surface);
+ wlr_xdg_toplevel_set_activated(prev, 0);
+ }
+
+ kb = wlr_seat_get_keyboard(dwm.seat);
+ wlr_seat_keyboard_notify_enter(dwm.seat, surf, kb->keycodes, kb->num_keycodes, &kb->modifiers);
+
+ if (c) {
+ wl_list_remove(&c->link.focus);
+ wl_list_insert(&dwm.focus, &c->link.focus);
+ if (lift) {
+ wl_list_remove(&c->link.stack);
+ wl_list_insert(&dwm.stack, &c->link.stack);
+ }
+ wlr_xdg_toplevel_set_activated(c->surf, 1);
+ }
+}
+
+void
+setfloating(Client *c, int f)
+{
+ if (c->floating == f)
+ return;
+
+ c->floating = f;
+ arrange(c->m);
+}
+
+void
+pointerfocus(Client *c, struct wlr_surface *surf, double sx, double sy, uint32 time)
+{
+ if (c && !surf)
+ surf = c->surf->surface;
+
+ if (surf && surf == dwm.seat->pointer_state.focused_surface) {
+ wlr_seat_pointer_notify_motion(dwm.seat, time, sx, sy);
+ return;
+ }
+
+ wlr_seat_pointer_notify_enter(dwm.seat, surf, sx, sy);
+ /* If keyboard focus follows mouse, enforce that */
+ if (sloppyfocus && surf)
+ setfocus(c, surf, 0);
+}
+
+
+// -----------------------------------------------------------------------
+// callback function implementations
+
+/* xdg-surfaces */
+void
+ev·newclient(struct wl_listener *ev, void *arg)
+{
+ Client *c;
+ struct wlr_xdg_surface *surf;
+
+ surf = arg;
+ if (surf->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
+ return;
+
+ c = surf->data = calloc(1, sizeof(*c));
+ c->surf = surf;
+ c->bw = borderwidth;
+
+ wlr_xdg_toplevel_set_tiled(surf, WLR_EDGE_ALL);
+
+ /* install callbacks */
+ c->ev.map.notify = map;
+ c->ev.unmap.notify = unmap;
+ c->ev.free.notify = delete;
+
+ wl_signal_add(&surf->events.map, &c->ev.map);
+ wl_signal_add(&surf->events.unmap, &c->ev.unmap);
+ wl_signal_add(&surf->events.destroy, &c->ev.free);
+}
+
+static
+void
+map(struct wl_listener *ev, void *arg)
+{
+ Client *c;
+
+ c = wl_container_of(ev, c, ev.map);
+
+ wl_list_insert(&dwm.tiles, &c->link.tiles);
+ wl_list_insert(&dwm.focus, &c->link.focus);
+ wl_list_insert(&dwm.stack, &c->link.stack);
+
+ wlr_xdg_surface_get_geometry(c->surf, &c->dim);
+
+ c->dim.width += 2 * c->bw;
+ c->dim.height += 2 * c->bw;
+
+ applyrules(c);
+}
+
+static
+void
+unmap(struct wl_listener *ev, void *arg)
+{
+ Monitor *m;
+ Client *c;
+
+ c = wl_container_of(ev, c, ev.unmap);
+ m = c->m;
+ setmonitor(c, nil, 0);
+
+ wl_list_remove(&c->link.tiles);
+ wl_list_remove(&c->link.stack);
+ wl_list_remove(&c->link.focus);
+
+ c->surf = nil;
+ arrange(m);
+}
+
+static
+void
+delete(struct wl_listener *ev, void *arg)
+{
+ Client *c;
+ c = wl_container_of(ev, c, ev.free);
+ free(c);
+}
diff --git a/sys/cmd/dway/config.h b/sys/cmd/dwm/config.h
index cd27147..c0e142c 100644
--- a/sys/cmd/dway/config.h
+++ b/sys/cmd/dwm/config.h
@@ -45,10 +45,12 @@ static const struct xkb_rule_names xkb_rules = {
/* commands */
static const byte *termcmd[] = { "alacritty", 0 };
+static const byte *menucmd[] = { "waybar", 0 };
/* keymaps */
static const Key keys[] = {
/* modifier key function argument */
+ { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
diff --git a/sys/cmd/dwm/decoration.c b/sys/cmd/dwm/decoration.c
new file mode 100644
index 0000000..af0dc5f
--- /dev/null
+++ b/sys/cmd/dwm/decoration.c
@@ -0,0 +1,52 @@
+#include "dwm.h"
+
+/* internal callbacks */
+static void mode(struct wl_listener *ev, void *arg);
+static void delete(struct wl_listener *ev, void *arg);
+
+// -----------------------------------------------------------------------
+// implementations
+
+void
+ev·newdecoration(struct wl_listener *ev, void *arg)
+{
+ struct wlr_server_decoration *wlr;
+ Deco *deco;
+
+ wlr = arg;
+
+ deco = calloc(1, sizeof(*deco));
+ if (!deco)
+ return;
+
+ deco->wlr = wlr;
+
+ wl_signal_add(&wlr->events.destroy, &deco->ev.free);
+ deco->ev.free.notify = delete;
+
+ wl_signal_add(&wlr->events.mode, &deco->ev.mode);
+ deco->ev.mode.notify = mode;
+
+ wl_list_insert(&dwm.decos, &deco->link);
+}
+
+static
+void
+delete(struct wl_listener *ev, void *arg)
+{
+ Deco *deco;
+
+ deco = wl_container_of(ev, deco, ev.free);
+
+ wl_list_remove(&deco->ev.free.link);
+ wl_list_remove(&deco->ev.mode.link);
+ wl_list_remove(&deco->link);
+ free(deco);
+}
+
+static
+void
+mode(struct wl_listener *ev, void *arg)
+{
+ /* no op */
+}
diff --git a/sys/cmd/dwm/dwm.c b/sys/cmd/dwm/dwm.c
new file mode 100644
index 0000000..a915cde
--- /dev/null
+++ b/sys/cmd/dwm/dwm.c
@@ -0,0 +1,184 @@
+#include "dwm.h"
+
+/* globals */
+WindowManager dwm = {
+ 0,
+ .ev = {
+ .loop = nil,
+ .output = {.notify=ev·newmonitor},
+ .input = {.notify=ev·newinput},
+ .client = {.notify=ev·newclient},
+ .layer = {.notify=ev·newlayershell},
+ .deco = {.notify=ev·newdecoration},
+ },
+};
+
+void
+setup(void)
+{
+ /* wayland boilerplate */
+ dwm.display = wl_display_create();
+ if (!dwm.display)
+ fatal("failed to initialize display");
+
+ dwm.backend = wlr_backend_autocreate(dwm.display, nil);
+ if (!dwm.backend)
+ fatal("failed to create backend");
+
+ dwm.draw = wlr_backend_get_renderer(dwm.backend);
+ if (!dwm.draw)
+ fatal("failed to initialize renderer");
+ wlr_renderer_init_wl_display(dwm.draw, dwm.display);
+
+ /* intialize the compositor and some automated handlers */
+ dwm.compositor = wlr_compositor_create(dwm.display, dwm.draw);
+
+ wlr_data_device_manager_create(dwm.display);
+ wlr_gamma_control_manager_v1_create(dwm.display);
+ wlr_gtk_primary_selection_device_manager_create(dwm.display);
+
+ /* middle management */
+ wlr_export_dmabuf_manager_v1_create(dwm.display);
+ wlr_screencopy_manager_v1_create(dwm.display);
+ wlr_data_control_manager_v1_create(dwm.display);
+ wlr_primary_selection_v1_device_manager_create(dwm.display);
+
+ dwm.ev.loop = wl_display_get_event_loop(dwm.display);
+ if (!dwm.ev.loop)
+ fatal("failed to initialize event loop");
+
+ dwm.layout = wlr_output_layout_create();
+ wlr_xdg_output_manager_v1_create(dwm.display, dwm.layout);
+
+ /* grab output devices */
+ wl_list_init(&dwm.odevs);
+ wl_signal_add(&dwm.backend->events.new_output, &dwm.ev.output);
+
+ /* initialize window structures */
+ wl_list_init(&dwm.tiles);
+ wl_list_init(&dwm.stack);
+ wl_list_init(&dwm.focus);
+ wl_list_init(&dwm.decos);
+
+ /* layer shell */
+ dwm.laysh = wlr_layer_shell_v1_create(dwm.display);
+ wl_signal_add(&dwm.laysh->events.new_surface, &dwm.ev.layer);
+
+ /* xdg shell */
+ dwm.xdgsh = wlr_xdg_shell_create(dwm.display);
+ wl_signal_add(&dwm.xdgsh->events.new_surface, &dwm.ev.client);
+
+ /* decorations */
+ dwm.mngr.deco = wlr_server_decoration_manager_create(dwm.display);
+ wlr_server_decoration_manager_set_default_mode(dwm.mngr.deco, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
+ wl_signal_add(&dwm.mngr.deco->events.new_decoration, &dwm.ev.deco);
+ wl_list_init(&dwm.decos);
+
+ dwm.mngr.deco = wlr_server_decoration_manager_create(dwm.display);
+
+ /* grab input devices and install callbacks */
+ mouse.cursor = wlr_cursor_create();
+ if (!mouse.cursor)
+ fatal("no mouse found");
+ wlr_cursor_attach_output_layout(mouse.cursor, dwm.layout);
+ mouse.manager = wlr_xcursor_manager_create(nil, 24);
+
+ /* attach the static cursor object to event handlers */
+ wl_signal_add(&mouse.cursor->events.axis, &mouse.ev.axis);
+ wl_signal_add(&mouse.cursor->events.frame, &mouse.ev.frame);
+ wl_signal_add(&mouse.cursor->events.button, &mouse.ev.button);
+ wl_signal_add(&mouse.cursor->events.motion, &mouse.ev.motion);
+ wl_signal_add(&mouse.cursor->events.motion_absolute, &mouse.ev.absmotion);
+
+ wl_list_init(&dwm.idevs);
+ wl_list_init(&dwm.keyboards);
+
+ wl_signal_add(&dwm.backend->events.new_input, &dwm.ev.input);
+
+ dwm.seat = wlr_seat_create(dwm.display, "seat0");
+
+ wl_signal_add(&dwm.seat->events.request_set_cursor, &mouse.ev.cursor);
+ wl_signal_add(&dwm.seat->events.request_set_selection, &mouse.ev.sel);
+ wl_signal_add(&dwm.seat->events.request_set_primary_selection, &mouse.ev.psel);
+}
+
+void
+run(void)
+{
+ byte *socket;
+ pid_t start = -1;
+
+ socket = (byte*)wl_display_add_socket_auto(dwm.display);
+ if (!socket) {
+ wlr_backend_destroy(dwm.backend);
+ fatal("could not open socket");
+ }
+
+ if (!wlr_backend_start(dwm.backend)) {
+ wlr_backend_destroy(dwm.backend);
+ wl_display_destroy(dwm.display);
+ fatal("failed to start backend");
+ }
+
+ monitor = monitorat(mouse.cursor->x, mouse.cursor->y);
+ if (!monitor)
+ fatal("no monitor found");
+
+ wlr_cursor_warp_closest(mouse.cursor, nil, mouse.cursor->x, mouse.cursor->y);
+ wlr_xcursor_manager_set_cursor_image(mouse.manager, "left_ptr", mouse.cursor);
+
+ setenv("WAYLAND_DISPLAY", socket, 1);
+
+ wlr_log(WLR_INFO, "running dwm on WAYLAND_DISPLAY\n");
+ wl_display_run(dwm.display);
+}
+
+void
+cleanup(void)
+{
+ wl_display_destroy_clients(dwm.display);
+ wl_display_destroy(dwm.display);
+ wlr_backend_destroy(dwm.backend);
+}
+
+void
+usage(void)
+{
+ printf("usage: %s [-qvd] [-s startup_cmd]\n", argv0);
+ exit(1);
+}
+
+int
+main(int argc, byte *argv[])
+{
+ byte *cmd;
+ enum wlr_log_importance lvl;
+
+ cmd = nil;
+ lvl = WLR_ERROR;
+
+ ARGBEGIN {
+ case 'q':
+ lvl = WLR_SILENT;
+ break;
+ case 'v':
+ lvl = WLR_INFO;
+ break;
+ case 'd':
+ lvl = WLR_DEBUG;
+ break;
+ case 's':
+ cmd = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ wlr_log_init(lvl, nil);
+
+ setup();
+ run();
+ cleanup();
+
+ return 0;
+}
diff --git a/sys/cmd/dway/dway.h b/sys/cmd/dwm/dwm.h
index ad2dfb3..148ca89 100644
--- a/sys/cmd/dway/dway.h
+++ b/sys/cmd/dwm/dwm.h
@@ -21,6 +21,7 @@
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_primary_selection.h>
@@ -42,11 +43,18 @@
#include <xkbcommon/xkbcommon.h>
#include <linux/input-event-codes.h>
+
+/* global macros */
+#define VISIBLEON(C, M) ((C)->m == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
+#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
+#define TAGMASK ((1 << arrlen(tags)) - 1)
+
/* main types */
typedef union Arg Arg;
typedef struct Button Button;
typedef struct Mouse Mouse;
+typedef struct Grab Grab;
typedef struct Key Key;
typedef struct Keyboard Keyboard;
typedef struct Monitor Monitor;
@@ -59,6 +67,8 @@ typedef struct Payload Payload;
typedef struct Rule Rule;
typedef struct MonitorRule MonitorRule;
+typedef struct WindowManager WindowManager;
+
union Arg
{
int i;
@@ -84,16 +94,25 @@ struct Mouse
{
uint mode;
struct wlr_xcursor_manager *manager;
- struct wlr_cursor *cursor;
+ struct wlr_cursor *cursor;
struct {
struct wl_listener axis;
struct wl_listener frame;
struct wl_listener button;
struct wl_listener motion;
struct wl_listener absmotion;
+ struct wl_listener cursor;
+ struct wl_listener sel;
+ struct wl_listener psel;
} ev;
};
+struct Grab
+{
+ Client *c;
+ int x, y;
+};
+
struct Key
{
uint32 mod;
@@ -122,16 +141,14 @@ struct Layer
struct wl_listener unmap;
struct wl_listener free;
struct wl_listener commit;
- struct wl_listener kill;
+ struct wl_listener detach;
/* struct wl_listener popup; */
} ev;
struct wlr_box dim;
enum zwlr_layer_shell_v1_layer z;
};
-
-struct Monitor
-{
+struct Monitor {
struct wl_list link;
struct wlr_output *dev;
struct {
@@ -146,7 +163,9 @@ struct Monitor
struct wlr_box win;
} area;
- Layer layers[4];
+ struct wl_list layers[4];
+ struct wlr_output_damage damage;
+
const Layout *lt[2];
uint seltags;
uint sellt;
@@ -216,61 +235,112 @@ struct Payload
int x, y;
};
-/* hooks provided to config */
-static void chvt(const Arg *arg);
-static void incmaster(const Arg *arg);
-static void focusmonitor(const Arg *arg);
-static void focusstack(const Arg *arg);
-static void moveresize(const Arg *arg);
-static void quit(const Arg *arg);
-static void setlayout(const Arg *arg);
-static void setmfact(const Arg *arg);
-static void spawn(const Arg *arg);
-static void tag(const Arg *arg);
-static void tagmonitor(const Arg *arg);
-static void togglefloating(const Arg *arg);
-static void toggletag(const Arg *arg);
-static void toggleview(const Arg *arg);
-static void view(const Arg *arg);
+struct WindowManager
+{
+ struct wl_display *display;
+ struct wlr_backend *backend;
+ struct wlr_renderer *draw;
+ struct wlr_compositor *compositor;
+ struct wlr_xdg_shell *xdgsh;
+ struct wlr_layer_shell_v1 *laysh;
+ struct wlr_output_layout *layout;
+ struct wlr_idle *idle;
+ struct wlr_seat *seat;
+
+ struct {
+ struct wlr_server_decoration_manager *deco;
+ struct wlr_xdg_decoration_manager *xdeco;
+ } mngr;
+
+ struct {
+ struct wl_event_loop *loop;
+ /* i/o devices */
+ struct wl_listener input;
+ struct wl_listener output;
+ struct wl_listener client;
+ /* shells */
+ struct wl_listener layer;
+ struct wl_listener deco;
+ } ev;
+
+ struct {
+ struct wl_list odevs;
+ struct wl_list idevs;
+ struct wl_list tiles; /* order of tiles */
+ struct wl_list stack; /* order w/in stack */
+ struct wl_list focus; /* order of focus */
+ struct wl_list keyboards;
+ struct wl_list decos;
+ };
+
+ /* geometry of union of output devices */
+ struct wlr_box dim;
+};
+
+/* funcs.c */
+void chvt(const Arg *arg);
+void incmaster(const Arg *arg);
+void focusmonitor(const Arg *arg);
+void focusstack(const Arg *arg);
+void moveresize(const Arg *arg);
+void quit(const Arg *arg);
+void setlayout(const Arg *arg);
+void setmfact(const Arg *arg);
+void spawn(const Arg *arg);
+void tag(const Arg *arg);
+void tagmonitor(const Arg *arg);
+void togglefloating(const Arg *arg);
+void toggletag(const Arg *arg);
+void toggleview(const Arg *arg);
+void view(const Arg *arg);
/* layouts */
-static void tile(Monitor *m);
+void tile(Monitor *m);
#include "config.h"
-/* callback functions */
-static void ev·newmonitor(struct wl_listener *ev, void *arg);
-static void ev·freemonitor(struct wl_listener *ev, void *arg);
-
-static void ev·newidev(struct wl_listener *ev, void *arg);
-static void ev·freeidev(struct wl_listener *ev, void *arg);
-
-static void ev·render(struct wl_listener *ev, void *arg);
-static void ev·newclient(struct wl_listener *ev, void *arg);
-static void ev·mapclient(struct wl_listener *ev, void *arg);
-static void ev·unmapclient(struct wl_listener *ev, void *arg);
-static void ev·freeclient(struct wl_listener *ev, void *arg);
-
-static void ev·newdecoration(struct wl_listener *ev, void *arg);
-static void ev·freedecoration(struct wl_listener *ev, void *arg);
-static void ev·modedecoration(struct wl_listener *ev, void *arg);
-
-static void ev·newlayershell(struct wl_listener *ev, void *arg);
-static void ev·freelayershell(struct wl_listener *ev, void *arg);
-static void ev·maplayershell(struct wl_listener *ev, void *arg);
-static void ev·unmaplayershell(struct wl_listener *ev, void *arg);
-static void ev·commitlayershell(struct wl_listener *ev, void *arg);
-static void ev·killlayershell(struct wl_listener *ev, void *arg);
-
-static void ev·setcursor(struct wl_listener *ev, void *arg);
-static void ev·setsel(struct wl_listener *ev, void *arg);
-static void ev·setpsel(struct wl_listener *ev, void *arg);
-
-static void ev·mousescroll(struct wl_listener *ev, void *arg);
-static void ev·mouseframe(struct wl_listener *ev, void *arg);
-static void ev·mousebutton(struct wl_listener *ev, void *arg);
-static void ev·mouserelmove(struct wl_listener *ev, void *arg);
-static void ev·mouseabsmove(struct wl_listener *ev, void *arg);
-
-static void ev·keypress(struct wl_listener *ev, void *arg);
-static void ev·modifier(struct wl_listener *ev, void *arg);
+// -----------------------------------------------------------------------
+// global variables
+
+extern Mouse mouse;
+extern Grab grab;
+extern Monitor *monitor; /* currently focused */
+extern WindowManager dwm;
+
+// -----------------------------------------------------------------------
+// global functions
+
+/* util.c */
+void fatal(byte *fmt, ...);
+void scale(struct wlr_box *box, float by);
+
+/* input.c */
+void ev·newinput(struct wl_listener *ev, void *arg);
+
+/* client.c */
+void ev·newclient(struct wl_listener *ev, void *arg);
+
+void applybounds(Client *c, struct wlr_box *bbox);
+void applyrules(Client *c);
+Client *clientat(double x, double y);
+Client *getclient(void);
+Client *lastfocus(void);
+void resize(Client *c, int x, int y, int w, int h, int interact);
+void setfocus(Client *c, struct wlr_surface *surf, int lift);
+void setfloating(Client *c, int f);
+void pointerfocus(Client *c, struct wlr_surface *surf, double sx, double sy, uint32 time);
+
+/* output.c */
+void ev·newmonitor(struct wl_listener *ev, void *arg);
+
+void arrange(Monitor *m);
+void setmonitor(Client *c, Monitor *m, uint newtags);
+Monitor *getmonitor(int dir);
+Monitor *monitorat(double x, double y);
+
+/* layer.c */
+void ev·newlayershell(struct wl_listener *ev, void *arg);
+void arrangelayers(Monitor *m);
+
+/* decoration.c */
+void ev·newdecoration(struct wl_listener *ev, void *arg);
diff --git a/sys/cmd/dwm/func.c b/sys/cmd/dwm/func.c
new file mode 100644
index 0000000..5b0df24
--- /dev/null
+++ b/sys/cmd/dwm/func.c
@@ -0,0 +1,217 @@
+#include "dwm.h"
+
+void
+chvt(const Arg *arg)
+{
+ struct wlr_session *s;
+
+ s = wlr_backend_get_session(dwm.backend);
+ if (!s)
+ return;
+
+ wlr_session_change_vt(s, arg->ui);
+}
+
+void
+incmaster(const Arg *arg)
+{
+ monitor->nmaster = MAX(monitor->nmaster + arg->i, 0);
+ arrange(monitor);
+}
+
+void
+focusmonitor(const Arg *arg)
+{
+ Monitor *m;
+
+ m = getmonitor(arg->i);
+
+ if (m == monitor)
+ return;
+
+ monitor = m;
+ setfocus(lastfocus(), nil, 1);
+}
+
+void
+focusstack(const Arg *arg)
+{
+ Client *c, *sel;
+
+ sel = getclient();
+ if (!sel)
+ return;
+
+ if (arg->i > 0) {
+ wl_list_for_each(c, &sel->link.tiles, link.tiles) {
+ if (&c->link.tiles == &dwm.tiles)
+ continue;
+ if (VISIBLEON(c, monitor))
+ break;
+ }
+ } else {
+ wl_list_for_each_reverse(c, &sel->link.tiles, link.tiles) {
+ if (&c->link.tiles == &dwm.tiles)
+ continue; /* wrap past the sentinel node */
+ if (VISIBLEON(c, monitor))
+ break; /* found it */
+ }
+ }
+ /* If only one client is visible on selmon, then c == sel */
+ setfocus(c, nil, 1);
+}
+
+void
+moveresize(const Arg *arg)
+{
+ grab.c = clientat(mouse.cursor->x, mouse.cursor->y);
+ if (!grab.c)
+ return;
+
+ /* Float the window and tell motionnotify to grab it */
+ setfloating(grab.c, 1);
+ switch (mouse.mode = arg->ui) {
+ case MouseMove:
+ grab.x = mouse.cursor->x - grab.c->dim.x;
+ grab.y = mouse.cursor->y - grab.c->dim.y;
+ wlr_xcursor_manager_set_cursor_image(mouse.manager, "fleur", mouse.cursor);
+ break;
+ case MouseResize:
+ wlr_cursor_warp_closest(mouse.cursor, nil,
+ grab.c->dim.x + grab.c->dim.width,
+ grab.c->dim.y + grab.c->dim.height);
+ wlr_xcursor_manager_set_cursor_image(mouse.manager, "bottom_right_corner", mouse.cursor);
+ break;
+ }
+}
+
+void
+quit(const Arg *arg)
+{
+ wl_display_terminate(dwm.display);
+}
+
+void
+setlayout(const Arg *arg)
+{
+ if (!arg || !arg->v || arg->v != monitor->lt[monitor->sellt])
+ monitor->sellt ^= 1;
+ if (arg && arg->v)
+ monitor->lt[monitor->sellt] = (Layout *)arg->v;
+
+ arrange(monitor);
+}
+
+void
+setmfact(const Arg *arg)
+{
+ float f;
+
+ if (!arg || !monitor->lt[monitor->sellt]->arrange)
+ return;
+ f = arg->f < 1.0 ? arg->f + monitor->mfact : arg->f - 1.0;
+ if (f < 0.1 || f > 0.9)
+ return;
+ monitor->mfact = f;
+ arrange(monitor);
+}
+
+void
+spawn(const Arg *arg)
+{
+ pid_t pid;
+ if ((pid=fork()) == 0) {
+ setsid();
+
+ printf("running %s\n", ((char**)arg->v)[0]);
+ execvp(((char **)arg->v)[0], (char **)arg->v);
+
+ fprintf(stderr, "dwl: execvp %s", ((char **)arg->v)[0]);
+ perror(" failed");
+ exit(EXIT_FAILURE);
+ } else if (pid < 0)
+ fatal("failed to fork");
+}
+
+void
+tag(const Arg *arg)
+{
+ Client *c;
+
+ c = getclient();
+ if (c && arg->ui & TAGMASK) {
+ c->tags = arg->ui & TAGMASK;
+ setfocus(lastfocus(), nil, 1);
+ arrange(monitor);
+ }
+}
+
+void
+tagmonitor(const Arg *arg)
+{
+ Client *c;
+
+ c = getclient();
+ if (!c)
+ return;
+ setmonitor(c, getmonitor(arg->i), 0);
+}
+
+void
+togglefloating(const Arg *arg)
+{
+ Client *c;
+
+ c = getclient();
+ if (!c)
+ return;
+
+ setfloating(c, !c->floating);
+}
+
+void
+toggletag(const Arg *arg)
+{
+ Client *c;
+ uint newtags;
+
+ c = getclient();
+ if (!c)
+ return;
+ newtags = c->tags ^ (arg->ui & TAGMASK);
+ if (newtags) {
+ c->tags = newtags;
+ setfocus(lastfocus(), nil, 1);
+ arrange(monitor);
+ }
+}
+
+void
+toggleview(const Arg *arg)
+{
+ uint newtagset;
+
+ newtagset = monitor->tagset[monitor->seltags] ^ (arg->ui & TAGMASK);
+
+ if (newtagset) {
+ monitor->tagset[monitor->seltags] = newtagset;
+ setfocus(lastfocus(), nil, 1);
+ arrange(monitor);
+ }
+}
+
+void
+view(const Arg *arg)
+{
+ if ((arg->ui & TAGMASK) == monitor->tagset[monitor->seltags])
+ return;
+
+ monitor->seltags ^= 1; /* toggle sel tagset */
+ if (arg->ui & TAGMASK)
+ monitor->tagset[monitor->seltags] = arg->ui & TAGMASK;
+ setfocus(lastfocus(), nil, 1);
+
+ arrange(monitor);
+}
+
+
diff --git a/sys/cmd/dwm/input.c b/sys/cmd/dwm/input.c
new file mode 100644
index 0000000..b035e9a
--- /dev/null
+++ b/sys/cmd/dwm/input.c
@@ -0,0 +1,333 @@
+#include "dwm.h"
+
+/* local callbacks */
+static void scroll(struct wl_listener *ev, void *arg);
+static void frame(struct wl_listener *ev, void *arg);
+static void click(struct wl_listener *ev, void *arg);
+static void relmove(struct wl_listener *ev, void *arg);
+static void absmove(struct wl_listener *ev, void *arg);
+
+static void setcursor(struct wl_listener *ev, void *arg);
+static void setsel(struct wl_listener *ev, void *arg);
+static void setpsel(struct wl_listener *ev, void *arg);
+
+static void keypress(struct wl_listener *ev, void *arg);
+static void modifier(struct wl_listener *ev, void *arg);
+
+/* global variables */
+Mouse mouse = {
+ .mode = 0,
+ .manager = nil,
+ .cursor = nil,
+ .ev = {
+ .axis = {.notify=scroll},
+ .button = {.notify=click},
+ .frame = {.notify=frame},
+ .motion = {.notify=relmove},
+ .absmotion = {.notify=absmove},
+ .cursor = {.notify=setcursor},
+ .sel = {.notify=setsel},
+ .psel = {.notify=setpsel},
+ },
+};
+
+Grab grab = { 0 };
+
+// -----------------------------------------------------------------------
+// callback function implementations
+
+/* input devices */
+static
+void
+newkeyboard(struct wlr_input_device *dev)
+{
+ Keyboard *kb;
+ struct xkb_context *ctx;
+ struct xkb_keymap *map;
+
+ kb = dev->data = calloc(1, sizeof(*kb));
+ kb->dev = dev;
+
+ ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ map = xkb_map_new_from_names(ctx, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+ wlr_keyboard_set_keymap(dev->keyboard, map);
+ xkb_keymap_unref(map);
+ xkb_context_unref(ctx);
+
+ wlr_keyboard_set_repeat_info(dev->keyboard, 25, 600);
+
+ /* install callbacks */
+ kb->ev.modifier.notify = modifier;
+ kb->ev.keypress.notify = keypress;
+
+ wl_signal_add(&dev->keyboard->events.modifiers, &kb->ev.modifier);
+ wl_signal_add(&dev->keyboard->events.key, &kb->ev.keypress);
+
+ /* NOTE: we only look at the last keyboard given right now */
+ wlr_seat_set_keyboard(dwm.seat, dev);
+
+ wl_list_insert(&dwm.keyboards, &kb->link);
+}
+
+static
+void
+newmouse(struct wlr_input_device *dev)
+{
+ /* NOTE: we only look at one mouse right now */
+ wlr_cursor_attach_input_device(mouse.cursor, dev);
+}
+
+void
+ev·newinput(struct wl_listener *ev, void *arg)
+{
+ uint32 c;
+ struct wlr_input_device *dev;
+
+ dev = arg;
+ switch (dev->type) {
+ case WLR_INPUT_DEVICE_KEYBOARD:
+ newkeyboard(dev);
+ break;
+ case WLR_INPUT_DEVICE_POINTER:
+ newmouse(dev);
+ break;
+ default:
+ ;
+ }
+
+ c = WL_SEAT_CAPABILITY_POINTER;
+ if (!wl_list_empty(&dwm.keyboards))
+ c |= WL_SEAT_CAPABILITY_KEYBOARD;
+ wlr_seat_set_capabilities(dwm.seat, c);
+}
+
+/* mouse input */
+
+static
+void
+scroll(struct wl_listener *ev, void *arg)
+{
+ struct wlr_event_pointer_axis *axis;
+
+ axis = arg;
+ wlr_seat_pointer_notify_axis(dwm.seat,
+ axis->time_msec,
+ axis->orientation,
+ axis->delta,
+ axis->delta_discrete,
+ axis->source);
+}
+
+void
+click(struct wl_listener *ev, void *arg)
+{
+ uint32 mods;
+ Client *c;
+ const Button *b;
+ struct wlr_surface *surf;
+ struct wlr_keyboard *keyb;
+ struct wlr_event_pointer_button *button;
+
+ button = arg;
+ switch (button->state) {
+ case WLR_BUTTON_PRESSED:
+ if ((c = clientat(mouse.cursor->x, mouse.cursor->y))) {
+ surf = wlr_xdg_surface_surface_at(c->surf,
+ mouse.cursor->x - c->dim.x - c->bw,
+ mouse.cursor->y - c->dim.y - c->bw,
+ nil, nil
+ );
+ setfocus(c, surf, 1);
+ }
+
+ keyb = wlr_seat_get_keyboard(dwm.seat);
+ mods = wlr_keyboard_get_modifiers(keyb);
+ for (b = buttons; b < arrend(buttons); b++) {
+ if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
+ button->button == b->kind && b->func) {
+ b->func(&b->arg);
+ return;
+ }
+ }
+ break;
+
+ case WLR_BUTTON_RELEASED:
+ if (mouse.mode != MouseNormal) {
+ wlr_xcursor_manager_set_cursor_image(mouse.manager, "left_ptr", mouse.cursor);
+ mouse.mode = MouseNormal;
+ monitor = monitorat(mouse.cursor->x, mouse.cursor->y);
+ setmonitor(grab.c, monitor, 0);
+ }
+ }
+
+ wlr_seat_pointer_notify_button(dwm.seat, button->time_msec, button->button, button->state);
+}
+
+static
+void
+frame(struct wl_listener *ev, void *arg)
+{
+ wlr_seat_pointer_notify_frame(dwm.seat);
+}
+
+static
+void
+notify(uint32 time)
+{
+ Client *c;
+ double sx, sy;
+ struct wlr_surface *surf;
+
+ if (sloppyfocus)
+ monitor = monitorat(mouse.cursor->x, mouse.cursor->y);
+
+ switch (mouse.mode) {
+ case MouseMove:
+ resize(grab.c,
+ mouse.cursor->x - grab.x,
+ mouse.cursor->y - grab.y,
+ grab.c->dim.width, grab.c->dim.height, 1);
+ return;
+
+ case MouseResize:
+ resize(grab.c,
+ grab.c->dim.x, grab.c->dim.y,
+ mouse.cursor->x - grab.c->dim.x,
+ mouse.cursor->y - grab.c->dim.y, 1);
+ return;
+
+ case MouseNormal:
+ default:
+ ;
+ }
+
+ surf = nil;
+ if ((c = clientat(mouse.cursor->x, mouse.cursor->y)))
+ surf = wlr_xdg_surface_surface_at(c->surf,
+ mouse.cursor->x - c->dim.x - c->bw,
+ mouse.cursor->y - c->dim.y - c->bw,
+ &sx, &sy);
+
+ if (!surf)
+ wlr_xcursor_manager_set_cursor_image(mouse.manager, "left_ptr", mouse.cursor);
+
+ pointerfocus(c, surf, sx, sy, time);
+}
+
+static
+void
+relmove(struct wl_listener *ev, void *arg)
+{
+ struct wlr_event_pointer_motion *mv;
+
+ mv = arg;
+ wlr_cursor_move(mouse.cursor, mv->device, mv->delta_x, mv->delta_y);
+ notify(mv->time_msec);
+}
+
+static
+void
+absmove(struct wl_listener *ev, void *arg)
+{
+ struct wlr_event_pointer_motion_absolute *mv;
+
+ mv = arg;
+ wlr_cursor_warp_absolute(mouse.cursor, mv->device, mv->x, mv->y);
+ notify(mv->time_msec);
+}
+
+/* cursor images */
+static
+void
+setcursor(struct wl_listener *ev, void *arg)
+{
+ struct wlr_seat_pointer_request_set_cursor_event *cur;
+
+ cur = arg;
+ if (mouse.mode != MouseNormal)
+ return;
+
+ if (cur->seat_client == dwm.seat->pointer_state.focused_client)
+ wlr_cursor_set_surface(mouse.cursor, cur->surface, cur->hotspot_x, cur->hotspot_y);
+}
+
+static
+void
+setpsel(struct wl_listener *ev, void *arg)
+{
+ struct wlr_seat_request_set_primary_selection_event *psel;
+
+ psel = arg;
+ wlr_seat_set_primary_selection(dwm.seat, psel->source, psel->serial);
+}
+
+static
+void
+setsel(struct wl_listener *ev, void *arg)
+{
+ struct wlr_seat_request_set_selection_event *sel;
+
+ sel = arg;
+ wlr_seat_set_selection(dwm.seat, sel->source, sel->serial);
+}
+
+/* keyboards */
+
+static
+int
+dokey(uint32 mods, xkb_keysym_t sym)
+{
+ int h;
+ const Key *k, *e;
+
+ h = 0;
+ for (k = keys, e = arrend(keys); k < e; k++)
+ if (CLEANMASK(mods) == CLEANMASK(k->mod) && sym == k->sym && k->func) {
+ k->func(&k->arg);
+ h = 1;
+ }
+
+ return h;
+}
+
+static
+void
+modifier(struct wl_listener *ev, void *arg)
+{
+ Keyboard *kb;
+
+ kb = wl_container_of(ev, kb, ev.modifier);
+ wlr_seat_set_keyboard(dwm.seat, kb->dev);
+
+ wlr_seat_keyboard_notify_modifiers(dwm.seat, &kb->dev->keyboard->modifiers);
+}
+
+static
+void
+keypress(struct wl_listener *ev, void *arg)
+{
+ Keyboard *kb;
+ int i, n, hit;
+ uint32 code, mods;
+ const xkb_keysym_t *syms;
+ struct wlr_event_keyboard_key *key;
+
+ key = arg;
+ kb = wl_container_of(ev, kb, ev.keypress);
+
+ code = key->keycode + 8;
+ n = xkb_state_key_get_syms(kb->dev->keyboard->xkb_state, code, &syms);
+ mods = wlr_keyboard_get_modifiers(kb->dev->keyboard);
+
+ hit = 0;
+ if (key->state == WLR_KEY_PRESSED)
+ for (i = 0; i < n; i++)
+ hit += dokey(mods, syms[i]);
+
+ /* if no binding found, pass the event to the client */
+ if (!hit) {
+ wlr_seat_set_keyboard(dwm.seat, kb->dev);
+ wlr_seat_keyboard_notify_key(dwm.seat, key->time_msec, key->keycode, key->state);
+ }
+}
diff --git a/sys/cmd/dwm/layer.c b/sys/cmd/dwm/layer.c
new file mode 100644
index 0000000..4c1ddcb
--- /dev/null
+++ b/sys/cmd/dwm/layer.c
@@ -0,0 +1,329 @@
+#include "dwm.h"
+
+/* local callbacks */
+static void delete(struct wl_listener *ev, void *arg);
+static void map(struct wl_listener *ev, void *arg);
+static void unmap(struct wl_listener *ev, void *arg);
+static void commit(struct wl_listener *ev, void *arg);
+static void detach(struct wl_listener *ev, void *arg);
+
+// -----------------------------------------------------------------------
+// methods
+
+static
+void
+applyexclusive(struct wlr_box *area, uint32 anchor, int ex, int32 mt, int32 mr, int32 mb, int32 ml)
+{
+ if (ex <= 0)
+ return;
+ struct {
+ uint32 singular_anchor;
+ uint32 anchor_triplet;
+ int *positive_axis;
+ int *negative_axis;
+ int margin;
+ } edges[] = {
+ // Top
+ {
+ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
+ .anchor_triplet =
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
+ .positive_axis = &area->y,
+ .negative_axis = &area->height,
+ .margin = mt,
+ },
+ // Bottom
+ {
+ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
+ .anchor_triplet =
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
+ .positive_axis = NULL,
+ .negative_axis = &area->height,
+ .margin = mb,
+ },
+ // Left
+ {
+ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT,
+ .anchor_triplet =
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
+ .positive_axis = &area->x,
+ .negative_axis = &area->width,
+ .margin = ml,
+ },
+ // Right
+ {
+ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
+ .anchor_triplet =
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
+ .positive_axis = NULL,
+ .negative_axis = &area->width,
+ .margin = mr,
+ },
+ };
+ for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) {
+ if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet)
+ && ex + edges[i].margin > 0) {
+ if (edges[i].positive_axis) {
+ *edges[i].positive_axis += ex + edges[i].margin;
+ }
+ if (edges[i].negative_axis) {
+ *edges[i].negative_axis -= ex + edges[i].margin;
+ }
+ break;
+ }
+ }
+}
+
+static
+void
+arrangelayer(Monitor *m, struct wl_list *layers, struct wlr_box *area, int ex)
+{
+ Layer *l;
+ uint32 horiz, vert;
+ struct wlr_box fullarea;
+ struct wlr_box box;
+ struct wlr_layer_surface_v1 *layer;
+ struct wlr_layer_surface_v1_state *state;
+
+ wlr_output_effective_resolution(m->dev, &fullarea.width, &fullarea.height);
+ wl_list_for_each(l, layers, link) {
+ layer = l->surf;
+ state = &layer->current;
+
+ if (ex != (state->exclusive_zone > 0))
+ continue;
+
+ struct wlr_box bounds;
+ if (state->exclusive_zone == -1)
+ bounds = fullarea;
+ else
+ bounds = *area;
+
+ box = (struct wlr_box){
+ .width = state->desired_width,
+ .height = state->desired_height
+ };
+
+ // Horizontal axis
+ horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
+ if ((state->anchor & horiz) && box.width == 0) {
+ box.x = bounds.x;
+ box.width = bounds.width;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
+ box.x = bounds.x;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
+ box.x = bounds.x + (bounds.width - box.width);
+ } else {
+ box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
+ }
+ // Vertical axis
+ vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
+ if ((state->anchor & vert) && box.height == 0) {
+ box.y = bounds.y;
+ box.height = bounds.height;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
+ box.y = bounds.y;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
+ box.y = bounds.y + (bounds.height - box.height);
+ } else {
+ box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
+ }
+ // Margin
+ if ((state->anchor & horiz) == horiz) {
+ box.x += state->margin.left;
+ box.width -= state->margin.left + state->margin.right;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
+ box.x += state->margin.left;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
+ box.x -= state->margin.right;
+ }
+ if ((state->anchor & vert) == vert) {
+ box.y += state->margin.top;
+ box.height -= state->margin.top + state->margin.bottom;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
+ box.y += state->margin.top;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
+ box.y -= state->margin.bottom;
+ }
+ if (box.width < 0 || box.height < 0) {
+ // TODO: Bubble up a protocol error?
+ wlr_layer_surface_v1_close(layer);
+ continue;
+ }
+ l->dim= box;
+ applyexclusive(area, state->anchor, state->exclusive_zone,
+ state->margin.top, state->margin.right, state->margin.bottom, state->margin.left);
+
+ wlr_layer_surface_v1_configure(layer, box.width, box.height);
+ }
+}
+
+void
+arrangelayers(Monitor *m)
+{
+ int i;
+ Layer *it, *top;
+ struct wlr_box area;
+
+ wlr_output_effective_resolution(m->dev, &area.width, &area.height);
+
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &area, 1);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &area, 1);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &area, 1);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &area, 1);
+
+ if (memcmp(&area, &m->area.win, sizeof(struct wlr_box)) != 0) {
+ memcpy(&m->area.win, &area, sizeof(struct wlr_box));
+ arrange(m);
+ }
+
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &area, 0);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &area, 0);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &area, 0);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &area, 0);
+
+ uint32 layers[] = {
+ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
+ ZWLR_LAYER_SHELL_V1_LAYER_TOP,
+ };
+
+ top = nil;
+ for (i = 0; i < arrlen(layers); i++) {
+ wl_list_for_each_reverse(it, &m->layers[layers[i]], link) {
+ if (it->surf->current.keyboard_interactive && it->surf->mapped) {
+ top = it;
+ break;
+ }
+ }
+ if (top)
+ break;
+ }
+ /* TODO: set focus here? */
+}
+
+
+// -----------------------------------------------------------------------
+// implementations
+
+void
+ev·newlayershell(struct wl_listener *ev, void *arg)
+{
+ Monitor *m;
+ Layer *layer;
+ struct wlr_layer_surface_v1 *surf;
+ struct wlr_layer_surface_v1_state old;
+
+ surf = arg;
+ if (!surf->output)
+ surf->output = monitor->dev;
+
+ layer = surf->data = calloc(1, sizeof(*layer));
+ layer->surf = surf;
+
+ /* install callbacks */
+ layer->ev.free.notify = delete;
+ layer->ev.map.notify = map;
+ layer->ev.unmap.notify = unmap;
+ layer->ev.commit.notify = commit;
+ layer->ev.detach.notify = detach;
+
+ wl_signal_add(&surf->events.destroy, &layer->ev.free);
+ wl_signal_add(&surf->events.map, &layer->ev.map);
+ wl_signal_add(&surf->events.unmap, &layer->ev.unmap);
+ wl_signal_add(&surf->surface->events.commit, &layer->ev.commit);
+ wl_signal_add(&monitor->sig.kill, &layer->ev.detach);
+
+ m = surf->output->data;
+ wl_list_insert(&m->layers[surf->client_pending.layer], &layer->link);
+
+ /* song and dance: set as pending, arrange, then reset */
+ old = surf->current;
+ surf->current = surf->client_pending;
+ arrangelayers(m);
+}
+
+static
+void
+delete(struct wl_listener *ev, void *arg)
+{
+ Layer *l;
+
+ l = wl_container_of(ev, l, ev.map);
+
+ wl_list_remove(&l->link);
+ wl_list_remove(&l->ev.free.link);
+ wl_list_remove(&l->ev.map.link);
+ wl_list_remove(&l->ev.unmap.link);
+ wl_list_remove(&l->ev.detach.link);
+ wl_list_remove(&l->ev.commit.link);
+
+ free(l);
+}
+
+static
+void
+detach(struct wl_listener *ev, void *arg)
+{
+ /* no op */
+}
+
+
+static
+void
+map(struct wl_listener *ev, void *arg)
+{
+ Layer *l;
+ Monitor *m;
+
+ l = wl_container_of(ev, l, ev.map);
+ m = l->surf->output->data;
+ /* TODO: damage */
+ wlr_surface_send_enter(l->surf->surface, l->surf->output);
+ /* TODO: cursor */
+}
+
+static
+void
+unmap(struct wl_listener *ev, void *arg)
+{
+ /* TODO: fill in */
+}
+
+static
+void
+commit(struct wl_listener *ev, void *arg)
+{
+ Layer *l;
+ Monitor *m;
+ char newdim, newlayer;
+ struct wlr_box old;
+ struct wlr_layer_surface_v1 *surf;
+ struct wlr_output *dev;
+
+ l = wl_container_of(ev, l, ev.commit);
+ surf = l->surf;
+ dev = surf->output;
+
+ m = dev->data;
+ old = l->dim;
+ arrangelayers(m);
+
+ newdim = memcmp(&old, &l->dim, sizeof(struct wlr_box)) != 0;
+ newlayer = l->z != surf->current.layer;
+
+ if (newdim) {
+ wl_list_remove(&l->link);
+ wl_list_insert(&m->layers[surf->current.layer], &l->link);
+ l->z = surf->current.layer;
+ }
+}
diff --git a/sys/cmd/dwm/layout.c b/sys/cmd/dwm/layout.c
new file mode 100644
index 0000000..f7a2c60
--- /dev/null
+++ b/sys/cmd/dwm/layout.c
@@ -0,0 +1,37 @@
+#include "dwm.h"
+
+void
+tile(Monitor *m)
+{
+ Client *c;
+ uint i, n, h, mw, my, ty;
+
+ n = 0;
+ wl_list_for_each(c, &dwm.tiles, link.tiles)
+ if (VISIBLEON(c, m) && !c->floating)
+ n++;
+
+ if (n == 0)
+ return;
+
+ if (n > m->nmaster)
+ mw = m->nmaster ? m->area.win.width * m->mfact : 0;
+ else
+ mw = m->area.win.width;
+
+ i = my = ty = 0;
+ wl_list_for_each(c, &dwm.tiles, link.tiles) {
+ if (!VISIBLEON(c, m) || c->floating)
+ continue;
+ if (i < m->nmaster) {
+ h = (m->area.win.height - my) / (MIN(n, m->nmaster) - i);
+ resize(c, m->area.win.x, m->area.win.y + my, mw, h, 0);
+ my += c->dim.height;
+ } else {
+ h = (m->area.win.height - ty) / (n - i);
+ resize(c, m->area.win.x + mw, m->area.win.y + ty, m->area.win.width - mw, h, 0);
+ ty += c->dim.height;
+ }
+ i++;
+ }
+}
diff --git a/sys/cmd/dwm/output.c b/sys/cmd/dwm/output.c
new file mode 100644
index 0000000..918d9a6
--- /dev/null
+++ b/sys/cmd/dwm/output.c
@@ -0,0 +1,257 @@
+#include "dwm.h"
+
+/* local callbacks */
+static void delete(struct wl_listener *ev, void *arg);
+static void draw(struct wl_listener *ev, void *arg);
+
+/* global variables */
+Monitor *monitor = nil;
+
+// -----------------------------------------------------------------------
+// methods
+
+void
+damageat(Monitor* m, double x, double y)
+{
+ /* TODO: don't damage the whole screen */
+ wlr_output_damage_add_whole(&m->damage);
+}
+
+void
+arrange(Monitor *m)
+{
+ m->area.all = *wlr_output_layout_get_box(dwm.layout, m->dev);
+ m->area.win = m->area.all;
+ if (m->lt[m->sellt]->arrange)
+ m->lt[m->sellt]->arrange(m);
+}
+
+void
+setmonitor(Client *c, Monitor *m, uint newtags)
+{
+ int hadfocus;
+ Monitor *old;
+
+ old = c->m;
+ if (old == m)
+ return;
+
+ hadfocus = (c == getclient());
+
+ c->m = m;
+ if (old) {
+ wlr_surface_send_leave(c->surf->surface, old->dev);
+ arrange(old);
+ }
+
+ if (m) {
+ applybounds(c, &m->area.all);
+ wlr_surface_send_enter(c->surf->surface, m->dev);
+ c->tags = newtags ? newtags : m->tagset[m->seltags];
+ arrange(m);
+ }
+
+ if (hadfocus || (c == getclient()))
+ setfocus(lastfocus(), nil, 1);
+}
+
+Monitor*
+getmonitor(int dir)
+{
+ Monitor *m;
+
+ if (dir > 0) {
+ if (monitor->link.next == &dwm.odevs)
+ return wl_container_of(dwm.odevs.next, m, link);
+ return wl_container_of(monitor->link.next, m, link);
+ }
+ if (monitor->link.prev == &dwm.odevs)
+ return wl_container_of(dwm.odevs.prev, m, link);
+ return wl_container_of(monitor->link.prev, m, link);
+}
+
+Monitor *
+monitorat(double x, double y)
+{
+ struct wlr_output *dev;
+
+ dev = wlr_output_layout_output_at(dwm.layout, x, y);
+ return dev ? dev->data : nil;
+}
+
+// -----------------------------------------------------------------------
+// callback function implementations
+void
+ev·newmonitor(struct wl_listener *ev, void *arg)
+{
+ Monitor *m;
+ const MonitorRule *r;
+ struct wlr_output *dev;
+ struct wlr_output_mode *mode;
+
+ dev = arg;
+ wlr_output_set_mode(dev, wlr_output_preferred_mode(dev));
+
+ m = dev->data = calloc(1, sizeof(*m));
+ m->dev = dev;
+ m->tagset[0] = m->tagset[1] = 1;
+ /* look for rules to apply */
+ for (r = monitorrules; r < arrend(monitorrules); r++) {
+ if (!r->name || strstr(dev->name, r->name)) {
+ m->mfact = r->mfact;
+ m->nmaster = r->nmaster;
+ wlr_output_set_scale(dev, r->scale);
+ wlr_xcursor_manager_load(mouse.manager, r->scale);
+ m->lt[0] = m->lt[1] = r->lt;
+ wlr_output_set_transform(dev, r->rr);
+ break;
+ }
+ }
+
+ /* install callbacks */
+ m->ev.draw.notify = draw;
+ m->ev.free.notify = delete;
+
+ wl_signal_add(&dev->events.frame, &m->ev.draw);
+ wl_signal_add(&dev->events.destroy, &m->ev.free);
+
+ wl_list_insert(&dwm.odevs, &m->link);
+
+ wl_list_init(&m->layers[0]);
+ wl_list_init(&m->layers[1]);
+ wl_list_init(&m->layers[2]);
+ wl_list_init(&m->layers[3]);
+
+ wlr_output_enable(dev, 1);
+ if (!wlr_output_commit(dev))
+ return;
+
+ wl_signal_init(&m->sig.kill);
+
+ wlr_output_layout_add_auto(dwm.layout, dev);
+ dwm.dim = *wlr_output_layout_get_box(dwm.layout, nil);
+}
+
+static
+void
+delete(struct wl_listener *ev, void *arg)
+{
+ Monitor *m;
+
+ m = wl_container_of(ev, m, ev.free);
+ wl_signal_emit(&m->sig.kill, m);
+
+ wl_list_remove(&m->link);
+ wl_list_remove(&m->ev.draw.link);
+ wl_list_remove(&m->ev.free.link);
+
+ free(m);
+}
+
+static
+void
+render(struct wlr_surface *surf, int sx, int sy, void *arg)
+{
+ Payload *data;
+ double x, y;
+ float mtx[9];
+ struct wlr_box box;
+ struct wlr_output *dev;
+ struct wlr_texture *tex;
+ enum wl_output_transform transform;
+
+ data = arg;
+ dev = data->dev;
+
+ tex = wlr_surface_get_texture(surf);
+ if (!tex)
+ return;
+
+ /* convert to device local coord */
+ wlr_output_layout_output_coords(dwm.layout, dev, &x, &y);
+
+ box.x = x + data->x + sx;
+ box.y = y + data->y + sy;
+ box.width = surf->current.width;
+ box.height = surf->current.height;
+ scale(&box, dev->scale);
+
+ /* orthographic projection */
+ transform = wlr_output_transform_invert(surf->current.transform);
+ wlr_matrix_project_box(mtx, &box, transform, 0, dev->transform_matrix);
+
+ /* render with GPU */
+ wlr_render_texture_with_matrix(dwm.draw, tex, mtx, 1);
+
+ /* notify the client we are done */
+ wlr_surface_send_frame_done(surf, data->now);
+}
+
+static
+void
+renderclients(Monitor *m, struct timespec *now)
+{
+ Client *c;
+ double x, y;
+ int i, w, h;
+ Payload data;
+ struct wlr_box *borders;
+
+ wl_list_for_each_reverse(c, &dwm.stack, link.stack) {
+ if (!VISIBLEON(c, c->m) || !wlr_output_layout_intersects(dwm.layout, m->dev, &c->dim))
+ continue;
+
+ x = c->dim.x;
+ y = c->dim.y;
+
+ wlr_output_layout_output_coords(dwm.layout, m->dev, &x, &y);
+
+ w = c->surf->surface->current.width;
+ h = c->surf->surface->current.height;
+
+ borders = (struct wlr_box[4]) {
+ {x, y, w + 2 * c->bw, c->bw}, /* top */
+ {x, y + c->bw, c->bw, h}, /* left */
+ {x + c->bw + w, y + c->bw, c->bw, h}, /* right */
+ {x, y + c->bw + h, w + 2 * c->bw, c->bw}, /* bottom */
+ };
+ for (i = 0; i < 4; i++) {
+ scale(&borders[i], m->dev->scale);
+ wlr_render_rect(dwm.draw, &borders[i], bordercolor, m->dev->transform_matrix);
+ }
+
+ data.dev = m->dev;
+ data.now = now;
+ data.x = c->dim.x + c->bw;
+ data.y = c->dim.y + c->bw;
+
+ wlr_xdg_surface_for_each_surface(c->surf, render, &data);
+ }
+}
+
+static
+void
+draw(struct wl_listener *ev, void *arg)
+{
+ int w, h;
+ Monitor *m;
+ struct timespec now;
+
+ m = wl_container_of(ev, m, ev.draw);
+
+ if (!wlr_output_attach_render(m->dev, nil))
+ return;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ wlr_output_effective_resolution(m->dev, &w, &h);
+
+ wlr_renderer_begin(dwm.draw, w, h);
+ wlr_renderer_clear(dwm.draw, rootcolor);
+
+ renderclients(m, &now);
+
+ wlr_output_render_software_cursors(m->dev, nil);
+
+ wlr_renderer_end(dwm.draw);
+ wlr_output_commit(m->dev);
+}
diff --git a/sys/cmd/dwm/rules.mk b/sys/cmd/dwm/rules.mk
new file mode 100644
index 0000000..610987a
--- /dev/null
+++ b/sys/cmd/dwm/rules.mk
@@ -0,0 +1,50 @@
+include share/push.mk
+
+WL_DIR = $(shell pkg-config --variable=pkgdatadir wayland-protocols)
+WL_SCAN = $(shell pkg-config --variable=wayland_scanner wayland-scanner)
+PROTO_DIR := $(d)/protocols
+
+# Local sources
+SRCS_$(d) := \
+ $(d)/xdg-shell.c \
+ $(d)/wlr-layer-shell.c \
+ $(d)/util.c \
+ $(d)/output.c \
+ $(d)/input.c \
+ $(d)/client.c \
+ $(d)/decoration.c \
+ $(d)/layer.c \
+ $(d)/layout.c \
+ $(d)/func.c \
+ $(d)/dwm.c
+
+BINS_$(d) := $(d)/dwm
+
+include share/paths.mk
+
+# Local rules
+$(d)/xdg-shell.h:
+ $(WL_SCAN) server-header $(WL_DIR)/stable/xdg-shell/xdg-shell.xml $@
+
+$(d)/xdg-shell.c: $(d)/xdg-shell.h
+ $(WL_SCAN) private-code $(WL_DIR)/stable/xdg-shell/xdg-shell.xml $@
+
+# could make this a patterned rule...
+$(d)/wlr-layer-shell.h: $(PROTO_DIR)/wlr-layer-shell-unstable-v1.xml
+ $(WL_SCAN) server-header $(PROTO_DIR)/wlr-layer-shell-unstable-v1.xml $@
+
+$(d)/wlr-layer-shell.c: $(d)/wlr-layer-shell.h
+ $(WL_SCAN) private-code $(PROTO_DIR)/wlr-layer-shell-unstable-v1.xml $@
+
+include share/dynamic.mk
+$(BINS_$(d)): TCFLAGS := $(shell pkg-config --cflags xkbcommon) \
+ $(shell pkg-config --cflags wlroots) \
+ $(shell pkg-config --cflags wayland-server)
+$(BINS_$(d)): TCLIBS := $(shell pkg-config --libs xkbcommon) \
+ $(shell pkg-config --libs wlroots) \
+ $(shell pkg-config --libs wayland-server)
+
+$(BINS_$(d)): $(OBJS_$(d)) $(OBJ_DIR)/libn/libn.a
+ $(COMPLINK)
+
+include share/pop.mk
diff --git a/sys/cmd/dwm/util.c b/sys/cmd/dwm/util.c
new file mode 100644
index 0000000..1875d89
--- /dev/null
+++ b/sys/cmd/dwm/util.c
@@ -0,0 +1,22 @@
+#include "dwm.h"
+
+void
+fatal(byte *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ verrorf(fmt, args);
+
+ va_end(args);
+ exit(1);
+}
+
+void
+scale(struct wlr_box *box, float by)
+{
+ box->x *= by;
+ box->y *= by;
+ box->height *= by;
+ box->width *= by;
+}
diff --git a/sys/cmd/rules.mk b/sys/cmd/rules.mk
index 2ed048e..1a6bd88 100644
--- a/sys/cmd/rules.mk
+++ b/sys/cmd/rules.mk
@@ -14,7 +14,7 @@ include $(DIR)/rules.mk
# DIR := $(d)/rc
# include $(DIR)/rules.mk
-DIR := $(d)/dway
+DIR := $(d)/dwm
include $(DIR)/rules.mk
DIR := $(d)/term