#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 *shell; struct wlr_output_layout *layout; struct wlr_seat *seat; 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; } 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 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}, }, }; static Monitor *monitor; static struct { Client *c; int x, y; } grab; static Mouse mouse = { .ev = { .axis = {.notify=ev·mousescroll}, .button = {.notify=ev·mouseclick}, .frame = {.notify=ev·mouseframe}, .motion = {.notify=ev·mouserelmove}, .absmotion = {.notify=ev·mouseabsmove}, }, }; static Keyboard keyboard = { .ev = { .modifier = {.notify=ev·modifier}, .keypress = {.notify=ev·keypress}, }, }; // ----------------------------------------------------------------------- // 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 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, c->dim.height - 2 * c->bw); } static Client * getclient(void) { Client *c; c = wl_container_of(dway.focus.next, c, pos.focus); if (wl_list_empty(&dway.focus) || !VISIBLEON(c, monitor)) return nil; return c; } static Client * getclientat(double x, double y) { Client *c; wl_list_for_each(c, &dway.stack, pos.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, pos.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 *previous; 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) { previous = wlr_xdg_surface_from_wlr_surface(dway.seat->keyboard_state.focused_surface); wlr_xdg_toplevel_set_activated(previous, 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->pos.focus); wl_list_insert(&dway.focus, &c->pos.focus); if (lift) { wl_list_remove(&c->pos.stack); wl_list_insert(&dway.stack, &c->pos.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 * getmonitorat(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; struct wlr_output *odev; struct wlr_output_mode *mode; odev = arg; if (!wl_list_empty(&odev->modes)) { mode = wl_container_of(odev->modes.prev, mode, link); wlr_output_set_mode(odev, mode); wlr_output_enable(odev, true); if (!wlr_output_commit(odev)) return; } m = calloc(1, sizeof(*m)); m->dev = odev; wl_list_insert(&dway.odevs, &m->link); /* install callbacks */ m->ev.free.notify = ev·freemonitor; wl_signal_add(&odev->events.destroy, &m->ev.free); m->ev.draw.notify = ev·render; wl_signal_add(&odev->events.frame, &m->ev.draw); } static void ev·freemonitor(struct wl_listener *ev, void *arg) { Monitor *m; m = wl_container_of(ev, m, ev.free); 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, pos.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 wlr_output *odev; struct timespec now; odev = arg; 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); } /* 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; wlr_xdg_toplevel_set_tiled(surf, WLR_EDGE_ALL); /* install callbacks */ c->ev.map.notify = ev·mapclient; wl_signal_add(&surf->events.map, &c->ev.map); c->ev.unmap.notify = ev·unmapclient; wl_signal_add(&surf->events.unmap, &c->ev.unmap); c->ev.free.notify = ev·freeclient; wl_signal_add(&surf->events.unmap, &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->pos.tiles); wl_list_insert(&dway.stack, &c->pos.stack); wl_list_insert(&dway.focus, &c->pos.focus); wlr_xdg_surface_get_geometry(c->surf, &c->dim); } static void ev·unmapclient(struct wl_listener *ev, void *arg) { Client *c; c = wl_container_of(ev, c, ev.unmap); wl_list_remove(&c->pos.tiles); wl_list_remove(&c->pos.stack); wl_list_remove(&c->pos.focus); } static void ev·freeclient(struct wl_listener *ev, void *arg) { Client *c; c = wl_container_of(ev, c, ev.unmap); free(c); } /* 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·mouseclick(struct wl_listener *ev, void *arg) { struct wlr_surface *surf; struct wlr_keyboard *keyboard; struct wlr_event_pointer_button *button; button = arg; } 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; 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 = getclientat(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 *mv; mv = arg; wlr_cursor_warp_absolute(mouse.cursor, mv->device, mv->delta_x, mv->delta_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->pos.tiles, pos.tiles) { if (&c->pos.tiles == &dway.tiles) continue; if (VISIBLEON(c, monitor)) break; } } else { wl_list_for_each_reverse(c, &sel->pos.tiles, pos.tiles) { if (&c->pos.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, NULL, 1); } static void moveresize(const Arg *arg) { grab.c = getclientat(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) { if (fork() == 0) { setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); fatal("dwl: execvp %s", ((char **)arg->v)[0]); } } 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, pos.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, pos.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.ev.loop = wl_display_get_event_loop(dway.display); if (!dway.ev.loop) fatal("failed to initialize event loop"); 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 & layout */ dway.compositor = wlr_compositor_create(dway.display, dway.draw); if (!dway.compositor) fatal("failed to initialize compositor"); wlr_data_device_manager_create(dway.display); dway.layout = wlr_output_layout_create(); /* grab output devices */ wl_list_init(&dway.odevs); wl_signal_add(&dway.backend->events.new_output, &dway.ev.odev); dway.shell = wlr_xdg_shell_create(dway.display); wl_signal_add(&dway.shell->events.new_surface, &dway.ev.client); /* initialize window structures */ wl_list_init(&dway.tiles); wl_list_init(&dway.stack); wl_list_init(&dway.focus); /* grab input devices and install callbacks */ 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); 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); wlr_xcursor_manager_load(mouse.manager, 1); /* 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); } 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 = getmonitorat(mouse.cursor->x, mouse.cursor->y); 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, true); wlr_log(WLR_INFO, "running dway on WAYLAND_DISPLAY\n"); wl_display_run(dway.display); } void cleanup(void) { wlr_backend_destroy(dway.backend); wl_display_destroy(dway.display); } 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; }