From 0a8f62d8c7116be9e344f351df679599908fb29c Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Thu, 4 Jun 2020 19:10:07 -0700 Subject: refactored --- sys/cmd/dway/config.h | 89 --- sys/cmd/dway/dway.c | 1478 ---------------------------------------------- sys/cmd/dway/dway.h | 276 --------- sys/cmd/dwm/client.c | 254 ++++++++ sys/cmd/dwm/config.h | 91 +++ sys/cmd/dwm/decoration.c | 52 ++ sys/cmd/dwm/dwm.c | 184 ++++++ sys/cmd/dwm/dwm.h | 346 +++++++++++ sys/cmd/dwm/func.c | 217 +++++++ sys/cmd/dwm/input.c | 333 +++++++++++ sys/cmd/dwm/layer.c | 329 +++++++++++ sys/cmd/dwm/layout.c | 37 ++ sys/cmd/dwm/output.c | 257 ++++++++ sys/cmd/dwm/rules.mk | 50 ++ sys/cmd/dwm/util.c | 22 + sys/cmd/rules.mk | 2 +- 16 files changed, 2173 insertions(+), 1844 deletions(-) delete mode 100644 sys/cmd/dway/config.h delete mode 100644 sys/cmd/dway/dway.c delete mode 100644 sys/cmd/dway/dway.h create mode 100644 sys/cmd/dwm/client.c create mode 100644 sys/cmd/dwm/config.h create mode 100644 sys/cmd/dwm/decoration.c create mode 100644 sys/cmd/dwm/dwm.c create mode 100644 sys/cmd/dwm/dwm.h create mode 100644 sys/cmd/dwm/func.c create mode 100644 sys/cmd/dwm/input.c create mode 100644 sys/cmd/dwm/layer.c create mode 100644 sys/cmd/dwm/layout.c create mode 100644 sys/cmd/dwm/output.c create mode 100644 sys/cmd/dwm/rules.mk create mode 100644 sys/cmd/dwm/util.c diff --git a/sys/cmd/dway/config.h b/sys/cmd/dway/config.h deleted file mode 100644 index cd27147..0000000 --- a/sys/cmd/dway/config.h +++ /dev/null @@ -1,89 +0,0 @@ -/* global appearance */ - -static const int sloppyfocus = 1; /* focus follows mouse */ -static const uint borderwidth = 1; /* width window borders (pixel) */ -static const uint gapwidth = 4; /* width of gaps(pixel) */ -static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; -static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; - -/* tagging */ -static const byte *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; - -static const Rule apprules[] = { - /* app_id title tags mask isfloating monitor */ -}; - -static const Layout layouts[] = { - /* symbol arrange function */ - { "[]=", tile }, - { "><>", nil }, /* no layout function means floating behavior */ -}; - -/* monitors */ -static const MonitorRule monitorrules[] = { - /* 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 }, - */ - { nil, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, -}; - -/* keyboard */ -static const struct xkb_rule_names xkb_rules = { - /* can specify fields: rules, model, layout, variant, options */ - /* example: - .options = "ctrl:nocaps", - */ -}; - -#define MODKEY WLR_MODIFIER_LOGO -#define TAGKEYS(KEY,SKEY,TAG) \ - { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ - { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \ - { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \ - { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} } - -/* commands */ -static const byte *termcmd[] = { "alacritty", 0 }; - -/* keymaps */ -static const Key keys[] = { - /* modifier key function argument */ - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, - { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, - { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, - { MODKEY, XKB_KEY_i, incmaster, {.i = +1} }, - { MODKEY, XKB_KEY_d, incmaster, {.i = -1} }, - { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} }, - { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} }, - { MODKEY, XKB_KEY_Tab, view, {0} }, - { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, - { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, - { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, - { MODKEY, XKB_KEY_comma, focusmonitor, {.i = -1} }, - { MODKEY, XKB_KEY_period, focusmonitor, {.i = +1} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmonitor, {.i = -1} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmonitor, {.i = +1} }, - TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0), - TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), - TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), - TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3), - TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4), - TAGKEYS( XKB_KEY_6, XKB_KEY_caret, 5), - TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6), - TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7), - TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8), - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} }, - { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} }, -#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} } - CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6), - CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12), -}; - -static const Button buttons[] = { - { MODKEY, BTN_LEFT, moveresize, {.ui = MouseMove} }, - { MODKEY, BTN_MIDDLE, togglefloating, {0} }, - { MODKEY, BTN_RIGHT, moveresize, {.ui = MouseResize} }, -}; 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 = ""; - -// ----------------------------------------------------------------------- -// 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/dway/dway.h b/sys/cmd/dway/dway.h deleted file mode 100644 index ad2dfb3..0000000 --- a/sys/cmd/dway/dway.h +++ /dev/null @@ -1,276 +0,0 @@ -#pragma once - -#include -#include - -#include - -#define WLR_USE_UNSTABLE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xdg-shell.h" -#include "wlr-layer-shell.h" - -#include -#include -#include -#include - -/* main types */ - -typedef union Arg Arg; -typedef struct Button Button; -typedef struct Mouse Mouse; -typedef struct Key Key; -typedef struct Keyboard Keyboard; -typedef struct Monitor Monitor; -typedef struct Layout Layout; -typedef struct Client Client; -typedef struct Deco Deco; -typedef struct Layer Layer; -typedef struct Payload Payload; - -typedef struct Rule Rule; -typedef struct MonitorRule MonitorRule; - -union Arg -{ - int i; - uint ui; - float f; - const void *v; -}; - -struct Button -{ - uint mod; - uint kind; - void (*func)(const Arg *); - Arg arg; -}; - -enum -{ - MouseNormal=0, MouseMove, MouseResize, -}; - -struct Mouse -{ - uint mode; - struct wlr_xcursor_manager *manager; - 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; - } ev; -}; - -struct Key -{ - uint32 mod; - xkb_keysym_t sym; - void (*func)(const Arg *); - Arg arg; -}; - -struct Keyboard -{ - struct wl_list link; - struct wlr_input_device *dev; - struct { - struct wl_listener modifier; - struct wl_listener keypress; - } ev; -}; - -struct Layer -{ - struct wl_list link; - struct wlr_layer_surface_v1 *surf; - - struct { - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener free; - struct wl_listener commit; - struct wl_listener kill; - /* struct wl_listener popup; */ - } ev; - - struct wlr_box dim; - enum zwlr_layer_shell_v1_layer z; -}; - -struct Monitor -{ - struct wl_list link; - struct wlr_output *dev; - struct { - struct wl_listener draw; - struct wl_listener free; - } ev; - struct { - struct wl_signal kill; - } sig; - struct { - struct wlr_box all; - struct wlr_box win; - } area; - - Layer layers[4]; - const Layout *lt[2]; - uint seltags; - uint sellt; - uint tagset[2]; - double mfact; - int nmaster; -}; - -struct Layout -{ - char *sym; - void (*arrange)(Monitor *); -}; - -struct MonitorRule { - char *name; - float mfact; - int nmaster; - float scale; - const Layout *lt; - enum wl_output_transform rr; -}; - -struct Rule { - char *id; - char *title; - uint tags; - int floating; - int monitor; -}; - -struct Client -{ - struct wlr_xdg_surface *surf; - struct wlr_box dim; - struct { - struct wl_list tiles; - struct wl_list stack; - struct wl_list focus; - } link; - struct { - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener free; - } ev; - int bw; - uint tags; - int floating; - Monitor *m; -}; - -struct Deco -{ - struct wl_list link; - struct wlr_server_decoration *wlr; - - struct { - struct wl_listener free; - struct wl_listener mode; - } ev; -}; - -struct Payload -{ - struct wlr_output *dev; - struct timespec *now; - 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); - -/* layouts */ -static 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); 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 = ""; + +// ----------------------------------------------------------------------- +// 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/dwm/config.h b/sys/cmd/dwm/config.h new file mode 100644 index 0000000..c0e142c --- /dev/null +++ b/sys/cmd/dwm/config.h @@ -0,0 +1,91 @@ +/* global appearance */ + +static const int sloppyfocus = 1; /* focus follows mouse */ +static const uint borderwidth = 1; /* width window borders (pixel) */ +static const uint gapwidth = 4; /* width of gaps(pixel) */ +static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; +static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; + +/* tagging */ +static const byte *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule apprules[] = { + /* app_id title tags mask isfloating monitor */ +}; + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, + { "><>", nil }, /* no layout function means floating behavior */ +}; + +/* monitors */ +static const MonitorRule monitorrules[] = { + /* 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 }, + */ + { nil, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, +}; + +/* keyboard */ +static const struct xkb_rule_names xkb_rules = { + /* can specify fields: rules, model, layout, variant, options */ + /* example: + .options = "ctrl:nocaps", + */ +}; + +#define MODKEY WLR_MODIFIER_LOGO +#define TAGKEYS(KEY,SKEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} } + +/* 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} }, + { MODKEY, XKB_KEY_i, incmaster, {.i = +1} }, + { MODKEY, XKB_KEY_d, incmaster, {.i = -1} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} }, + { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} }, + { MODKEY, XKB_KEY_Tab, view, {0} }, + { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, + { MODKEY, XKB_KEY_comma, focusmonitor, {.i = -1} }, + { MODKEY, XKB_KEY_period, focusmonitor, {.i = +1} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmonitor, {.i = -1} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmonitor, {.i = +1} }, + TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0), + TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), + TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), + TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3), + TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4), + TAGKEYS( XKB_KEY_6, XKB_KEY_caret, 5), + TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6), + TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7), + TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8), + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} }, + { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} }, +#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} } + CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6), + CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12), +}; + +static const Button buttons[] = { + { MODKEY, BTN_LEFT, moveresize, {.ui = MouseMove} }, + { MODKEY, BTN_MIDDLE, togglefloating, {0} }, + { MODKEY, BTN_RIGHT, moveresize, {.ui = MouseResize} }, +}; 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/dwm/dwm.h b/sys/cmd/dwm/dwm.h new file mode 100644 index 0000000..148ca89 --- /dev/null +++ b/sys/cmd/dwm/dwm.h @@ -0,0 +1,346 @@ +#pragma once + +#include +#include + +#include + +#define WLR_USE_UNSTABLE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xdg-shell.h" +#include "wlr-layer-shell.h" + +#include +#include +#include +#include + + +/* 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; +typedef struct Layout Layout; +typedef struct Client Client; +typedef struct Deco Deco; +typedef struct Layer Layer; +typedef struct Payload Payload; + +typedef struct Rule Rule; +typedef struct MonitorRule MonitorRule; + +typedef struct WindowManager WindowManager; + +union Arg +{ + int i; + uint ui; + float f; + const void *v; +}; + +struct Button +{ + uint mod; + uint kind; + void (*func)(const Arg *); + Arg arg; +}; + +enum +{ + MouseNormal=0, MouseMove, MouseResize, +}; + +struct Mouse +{ + uint mode; + struct wlr_xcursor_manager *manager; + 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; + xkb_keysym_t sym; + void (*func)(const Arg *); + Arg arg; +}; + +struct Keyboard +{ + struct wl_list link; + struct wlr_input_device *dev; + struct { + struct wl_listener modifier; + struct wl_listener keypress; + } ev; +}; + +struct Layer +{ + struct wl_list link; + struct wlr_layer_surface_v1 *surf; + + struct { + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener free; + struct wl_listener commit; + struct wl_listener detach; + /* struct wl_listener popup; */ + } ev; + + struct wlr_box dim; + enum zwlr_layer_shell_v1_layer z; +}; +struct Monitor { + struct wl_list link; + struct wlr_output *dev; + struct { + struct wl_listener draw; + struct wl_listener free; + } ev; + struct { + struct wl_signal kill; + } sig; + struct { + struct wlr_box all; + struct wlr_box win; + } area; + + struct wl_list layers[4]; + struct wlr_output_damage damage; + + const Layout *lt[2]; + uint seltags; + uint sellt; + uint tagset[2]; + double mfact; + int nmaster; +}; + +struct Layout +{ + char *sym; + void (*arrange)(Monitor *); +}; + +struct MonitorRule { + char *name; + float mfact; + int nmaster; + float scale; + const Layout *lt; + enum wl_output_transform rr; +}; + +struct Rule { + char *id; + char *title; + uint tags; + int floating; + int monitor; +}; + +struct Client +{ + struct wlr_xdg_surface *surf; + struct wlr_box dim; + struct { + struct wl_list tiles; + struct wl_list stack; + struct wl_list focus; + } link; + struct { + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener free; + } ev; + int bw; + uint tags; + int floating; + Monitor *m; +}; + +struct Deco +{ + struct wl_list link; + struct wlr_server_decoration *wlr; + + struct { + struct wl_listener free; + struct wl_listener mode; + } ev; +}; + +struct Payload +{ + struct wlr_output *dev; + struct timespec *now; + int x, y; +}; + +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 */ +void tile(Monitor *m); + +#include "config.h" + +// ----------------------------------------------------------------------- +// 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 -- cgit v1.2.1