aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-09-28 14:34:34 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-09-28 14:34:34 -0700
commitb9a07a67b85e9192faa0e285b4419bd5ef242a03 (patch)
tree6b3426363e22da403967c6d4cbb0b98f39be4b38
parentb58f62d4ef7f6e2442bdf8170f8652ba1e08bd12 (diff)
feat: reorganized code to be more modular
-rw-r--r--sys/cmd/wm/client.c95
-rw-r--r--sys/cmd/wm/input.c285
-rw-r--r--sys/cmd/wm/main.c752
-rw-r--r--sys/cmd/wm/output.c121
-rw-r--r--sys/cmd/wm/rules.mk4
-rw-r--r--sys/cmd/wm/wm.h128
-rw-r--r--sys/cmd/wm/xdg.c76
7 files changed, 766 insertions, 695 deletions
diff --git a/sys/cmd/wm/client.c b/sys/cmd/wm/client.c
new file mode 100644
index 0000000..7d828a0
--- /dev/null
+++ b/sys/cmd/wm/client.c
@@ -0,0 +1,95 @@
+#include "wm.h"
+
+void
+focus(Client *client, struct wlr_surface *new)
+{
+ struct wlr_seat *seat;
+ struct wlr_surface *old;
+ struct wlr_xdg_surface *xdg;
+ struct wlr_keyboard *keyboard;
+
+ if(!client)
+ return;
+
+ seat = server.input.seat;
+ old = seat->keyboard_state.focused_surface;
+ if(old == new)
+ return;
+
+ if(old) {
+ xdg = wlr_xdg_surface_from_wlr_surface(seat->keyboard_state.focused_surface);
+ wlr_xdg_toplevel_set_activated(xdg, false);
+ }
+
+ keyboard = wlr_seat_get_keyboard(seat);
+
+ wl_list_remove(&client->link);
+ wl_list_insert(&server.clients, &client->link);
+
+ wlr_xdg_toplevel_set_activated(client->xdg, true);
+ wlr_seat_keyboard_notify_enter(seat, client->xdg->surface,
+ keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
+}
+
+int
+clienthas(Client *client, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy)
+{
+ double x, y, vsx = lx - client->x, vsy = ly - client->y;
+ struct wlr_surface *find = nil;
+
+ find = wlr_xdg_surface_surface_at(client->xdg, vsx, vsy, &x, &y);
+ if(find) {
+ *sx = x;
+ *sy = y;
+ *surface = find;
+ return true;
+ }
+
+ return false;
+}
+
+Client*
+clientat(double lx, double ly, struct wlr_surface **surface, double *sx, double *sy)
+{
+ Client *it;
+ wl_list_for_each(it, &server.clients, link) {
+ if(clienthas(it, lx, ly, surface, sx, sy))
+ return it;
+ }
+
+ return nil;
+}
+
+void
+setinteractive(Client *client, int mode, uint32 edges) {
+ double bx, by;
+ struct wlr_box box;
+ struct wlr_surface *focused = server.input.seat->pointer_state.focused_surface;
+
+ if(client->xdg->surface != focused)
+ return;
+
+ server.grab.client = client;
+ server.cursor.mode = mode;
+
+ if(mode == CursorMove) {
+ server.grab.x = server.cursor.dot->x - client->x;
+ server.grab.y = server.cursor.dot->y - client->y;
+ } else {
+ wlr_xdg_surface_get_geometry(client->xdg, &box);
+
+ bx = (client->x + box.x) + ((edges & WLR_EDGE_RIGHT) ? box.width : 0);
+ by = (client->y + box.y) + ((edges & WLR_EDGE_BOTTOM) ? box.height : 0);
+
+ server.grab.x = server.cursor.dot->x - bx;
+ server.grab.y = server.cursor.dot->y - by;
+
+ server.grab.box = box;
+ server.grab.box.x += client->x;
+ server.grab.box.y += client->y;
+
+ server.resize = edges;
+ }
+}
+
+
diff --git a/sys/cmd/wm/input.c b/sys/cmd/wm/input.c
new file mode 100644
index 0000000..e155024
--- /dev/null
+++ b/sys/cmd/wm/input.c
@@ -0,0 +1,285 @@
+#include "wm.h"
+
+// -----------------------------------------------------------------------
+// keyboard
+
+static
+void
+keymodifier(struct wl_listener *l, void *data)
+{
+ Keyboard *keyboard = wl_container_of(l, keyboard, event.modify);
+
+ wlr_seat_set_keyboard(server.input.seat, keyboard->device);
+ wlr_seat_keyboard_notify_modifiers(server.input.seat, &keyboard->device->keyboard->modifiers);
+}
+
+static
+int
+keybinding(xkb_keysym_t sym)
+{
+ Client *current, *next;
+
+ switch(sym) {
+ case XKB_KEY_Escape:
+ wl_display_terminate(server.display);
+ break;
+ case XKB_KEY_F1:
+ /* cycle to the next client */
+ if(wl_list_length(&server.clients) < 2) break;
+
+ current = wl_container_of(server.clients.next, current, link);
+ next = wl_container_of(current->link.next, next, link);
+
+ focus(next, next->xdg->surface);
+
+ /* move previous client to the end of the list */
+ wl_list_remove(&current->link);
+ wl_list_insert(server.clients.prev, &current->link);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static
+void
+keypress(struct wl_listener *l, void *data)
+{
+ int i,h,n;
+ uint32 keycode, modifier;
+ const xkb_keysym_t *syms;
+ struct Keyboard *keyboard = wl_container_of(l, keyboard, event.press);
+ struct wlr_event_keyboard_key *event = data;
+ struct wlr_seat *seat = server.input.seat;
+
+ keycode = event->keycode + 8;
+
+ h = 0;
+ n = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, keycode, &syms);
+
+ modifier = wlr_keyboard_get_modifiers(keyboard->device->keyboard);
+ if((modifier & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ for(i=0; i<n; i++)
+ h=keybinding(syms[i]);
+ }
+
+ if(!h) {
+ wlr_seat_set_keyboard(seat, keyboard->device);
+ wlr_seat_keyboard_notify_key(seat, event->time_msec,
+ event->keycode, event->state);
+ }
+}
+
+static
+void
+make_keyboard(struct wlr_input_device *device)
+{
+ Keyboard *keyboard;
+ struct xkb_context *context;
+ struct xkb_keymap *keymap;
+
+ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ keymap = xkb_keymap_new_from_names(context, nil, XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+ wlr_keyboard_set_keymap(device->keyboard, keymap);
+ wlr_keyboard_set_keymap(device->keyboard, keymap);
+
+ xkb_keymap_unref(keymap);
+ xkb_context_unref(context);
+
+ wlr_keyboard_set_repeat_info(device->keyboard, 25, 600);
+
+ keyboard = calloc(1, sizeof(*keyboard));
+ keyboard->device = device;
+
+ keyboard->event.modify.notify = keymodifier;
+ wl_signal_add(&device->keyboard->events.modifiers, &keyboard->event.modify);
+ keyboard->event.press.notify = keypress;
+ wl_signal_add(&device->keyboard->events.key, &keyboard->event.press);
+
+ wlr_seat_set_keyboard(server.input.seat, device);
+ wl_list_insert(&server.input.keyboards, &keyboard->link);
+}
+
+// -----------------------------------------------------------------------
+// cursor
+
+static
+void
+cursormove(uint32 time) {
+ server.grab.x = server.cursor.dot->x - server.grab.x;
+ server.grab.y = server.cursor.dot->y - server.grab.y;
+}
+
+static
+void
+cursorresize(uint32 time)
+{
+ struct wlr_box box;
+ Client *client = server.grab.client;
+ double bx = server.cursor.dot->x - server.grab.x;
+ double by = server.cursor.dot->y - server.grab.y;
+ int new_left = server.grab.box.x;
+ int new_right = server.grab.box.x + server.grab.box.width;
+ int new_top = server.grab.box.y;
+ int new_bottom = server.grab.box.y + server.grab.box.height;
+ int new_width, new_height;
+
+ if(server.resize & WLR_EDGE_TOP) {
+ new_top = by;
+ if (new_top >= new_bottom)
+ new_top = new_bottom - 1;
+ }else if (server.resize & WLR_EDGE_BOTTOM) {
+ new_bottom = by;
+ if (new_bottom <= new_top)
+ new_bottom = new_top + 1;
+ }
+
+ if(server.resize & WLR_EDGE_LEFT) {
+ new_left = bx;
+ if (new_left >= new_right)
+ new_left = new_right - 1;
+ } else if(server.resize & WLR_EDGE_RIGHT) {
+ new_right = bx;
+ if (new_right <= new_left)
+ new_right = new_left + 1;
+ }
+
+ wlr_xdg_surface_get_geometry(client->xdg, &box);
+ client->x = new_left - box.x;
+ client->y = new_top - box.y;
+
+ new_width = new_right - new_left;
+ new_height = new_bottom - new_top;
+ wlr_xdg_toplevel_set_size(client->xdg, new_width, new_height);
+}
+
+static
+void
+docursor(uint32 time)
+{
+ double sx, sy;
+ Client *client;
+ struct wlr_seat *seat;
+ struct wlr_surface *surface;
+
+ if(server.cursor.mode == CursorMove)
+ return cursormove(time);
+ else if(server.cursor.mode == CursorResize)
+ return cursorresize(time);
+
+ /* Otherwise, find the client under the pointer and send the event along. */
+ seat = server.input.seat;
+ surface = nil;
+ client = clientat(server.cursor.dot->x, server.cursor.dot->y, &surface, &sx, &sy);
+ if(!client)
+ wlr_xcursor_manager_set_cursor_image(server.cursor.manager, "left_ptr", server.cursor.dot);
+
+ if(surface) {
+ wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
+ wlr_seat_pointer_notify_motion(seat, time, sx, sy);
+ } else {
+ wlr_seat_pointer_clear_focus(seat);
+ }
+}
+
+void
+cursor_move(struct wl_listener *l, void *data)
+{
+ struct wlr_event_pointer_motion *event = data;
+ wlr_cursor_move(server.cursor.dot, event->device, event->delta_x, event->delta_y);
+ docursor(event->time_msec);
+}
+
+void
+cursor_move_abs(struct wl_listener *l, void *data)
+{
+ struct wlr_event_pointer_motion_absolute *event = data;
+ wlr_cursor_warp_absolute(server.cursor.dot, event->device, event->x, event->y);
+ docursor(event->time_msec);
+}
+
+void
+cursor_button(struct wl_listener *l, void *data)
+{
+ Client *client;
+ double sx, sy;
+ struct wlr_surface *surface;
+ struct wlr_event_pointer_button *event = data;
+
+ wlr_seat_pointer_notify_button(server.input.seat,
+ event->time_msec, event->button, event->state);
+
+ client = clientat(server.cursor.dot->x, server.cursor.dot->y, &surface, &sx, &sy);
+ if (event->state == WLR_BUTTON_RELEASED)
+ server.cursor.mode = CursorPassthrough;
+ else
+ focus(client, surface);
+}
+
+void
+cursor_axis(struct wl_listener *l, void *data)
+{
+ struct wlr_event_pointer_axis *event = data;
+ /* Notify the client with pointer focus of the axis event. */
+ wlr_seat_pointer_notify_axis(server.input.seat,
+ event->time_msec, event->orientation, event->delta,
+ event->delta_discrete, event->source);
+}
+
+void
+cursor_frame(struct wl_listener *l, void *data)
+{
+ wlr_seat_pointer_notify_frame(server.input.seat);
+}
+
+void
+request_cursor(struct wl_listener *l, void *data)
+{
+ struct wlr_seat_pointer_request_set_cursor_event *event = data;
+ struct wlr_seat_client *focused_client = server.input.seat->pointer_state.focused_client;
+ if(focused_client == event->seat_client)
+ wlr_cursor_set_surface(server.cursor.dot, event->surface, event->hotspot_x, event->hotspot_y);
+}
+
+void
+request_set_selection(struct wl_listener *l, void *data)
+{
+ struct wlr_seat_request_set_selection_event *event = data;
+ wlr_seat_set_selection(server.input.seat, event->source, event->serial);
+}
+
+static
+void
+make_pointer(struct wlr_input_device *device)
+{
+ wlr_cursor_attach_input_device(server.cursor.dot, device);
+}
+
+// -----------------------------------------------------------------------
+// generic input
+
+void
+make_input(struct wl_listener *l, void *data)
+{
+ uint32 capability;
+ struct wlr_input_device *device = data;
+
+ switch(device->type) {
+ case WLR_INPUT_DEVICE_KEYBOARD:
+ make_keyboard(device);
+ break;
+ case WLR_INPUT_DEVICE_POINTER:
+ make_pointer(device);
+ /* fallthrough */
+ default:
+ break;
+ }
+
+ capability = WL_SEAT_CAPABILITY_POINTER;
+ if(!wl_list_empty(&server.input.keyboards))
+ capability |= WL_SEAT_CAPABILITY_KEYBOARD;
+ wlr_seat_set_capabilities(server.input.seat, capability);
+}
+
diff --git a/sys/cmd/wm/main.c b/sys/cmd/wm/main.c
index 6f0e5ab..dac0aa3 100644
--- a/sys/cmd/wm/main.c
+++ b/sys/cmd/wm/main.c
@@ -1,676 +1,85 @@
#include "wm.h"
-// -----------------------------------------------------------------------
-// types
-
-enum
-{
- CursorPassthrough,
- CursorMove,
- CursorResize,
-};
-
-typedef struct Keyboard Keyboard;
-typedef struct View View;
-typedef struct Monitor Monitor;
-typedef struct Server Server;
-typedef struct Payload Payload;
-
-struct Keyboard
-{
- struct wl_list link;
- struct wlr_input_device *device;
- struct {
- struct wl_listener press;
- struct wl_listener modify;
- } event;
-};
-
-struct View
-{
- struct wl_list link;
- struct wlr_xdg_surface *xdg;
- struct {
- struct wl_listener map;
- struct wl_listener unmap;
- struct wl_listener destroy;
- struct wl_listener request_move;
- struct wl_listener request_resize;
- } event;
- int x, y, mapped;
-};
-
-struct Monitor
-{
- struct wl_list link;
- struct wlr_output *output;
- struct {
- struct wl_listener render;
- } event;
-};
-
-struct Payload
-{
- View *view;
- struct wlr_output *output;
- struct wlr_renderer *renderer;
- struct timespec *when;
+Server server = {
+ .event = {
+ .make_input = { .notify = make_input },
+ .make_output = { .notify = make_output },
+ .make_xdg_surface = { .notify = make_xdg_surface },
+
+ .cursor_move = { .notify = cursor_move },
+ .cursor_move_abs = { .notify = cursor_move_abs },
+ .cursor_button = { .notify = cursor_button },
+ .cursor_axis = { .notify = cursor_axis },
+ .cursor_frame = { .notify = cursor_frame },
+
+ .request_cursor = { .notify = request_cursor },
+ .request_set_selection = { .notify = request_set_selection },
+ },
};
-struct Server
-{
- struct wl_display *display;
- struct wlr_backend *backend;
- struct wlr_renderer *renderer;
-
- struct {
- struct wlr_xdg_shell *xdg;
- struct wl_list list;
- } shell;
-
- struct {
- View *view;
- double x, y;
- struct wlr_box box;
- } grab;
- uint32 resize;
-
- struct {
- struct wlr_output_layout *layout;
- struct wl_list list;
- } output;
-
- struct {
- struct wlr_cursor *dot;
- struct wlr_xcursor_manager *manager;
- int mode;
- } cursor;
-
- struct {
- struct wlr_seat *seat;
- struct wl_list keyboards;
- } input;
-
- struct {
- struct wl_listener new_output;
- struct wl_listener new_input;
- struct wl_listener cursor_move;
- struct wl_listener cursor_move_abs;
- struct wl_listener cursor_button;
- struct wl_listener cursor_axis;
- struct wl_listener cursor_frame;
- struct wl_listener request_cursor;
- struct wl_listener request_set_selection;
- struct wl_listener new_surface;
- } event;
-};
-static struct Server server;
-
-static
-void
-focus(View *view, struct wlr_surface *new)
-{
- struct wlr_seat *seat;
- struct wlr_surface *old;
- struct wlr_xdg_surface *xdg;
- struct wlr_keyboard *keyboard;
-
- if(!view)
- return;
-
- seat = server.input.seat;
- old = seat->keyboard_state.focused_surface;
- if(old == new)
- return;
-
- if(old) {
- xdg = wlr_xdg_surface_from_wlr_surface(seat->keyboard_state.focused_surface);
- wlr_xdg_toplevel_set_activated(xdg, false);
- }
-
- keyboard = wlr_seat_get_keyboard(seat);
-
- wl_list_remove(&view->link);
- wl_list_insert(&server.shell.list, &view->link);
-
- wlr_xdg_toplevel_set_activated(view->xdg, true);
- wlr_seat_keyboard_notify_enter(seat, view->xdg->surface,
- keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
-}
-
-static
-int
-viewhas(View *view, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy)
-{
- double x, y, vsx = lx - view->x, vsy = ly - view->y;
- struct wlr_surface *find = nil;
-
- find = wlr_xdg_surface_surface_at(view->xdg, vsx, vsy, &x, &y);
- if(find) {
- *sx = x;
- *sy = y;
- *surface = find;
- return true;
- }
-
- return false;
-}
-
-static
-View*
-viewat(double lx, double ly, struct wlr_surface **surface, double *sx, double *sy)
-{
- View *it;
- wl_list_for_each(it, &server.shell.list, link) {
- if(viewhas(it, lx, ly, surface, sx, sy))
- return it;
- }
-
- return nil;
-}
-
// -----------------------------------------------------------------------
-// callbacks
-
-static
-void
-keymodifier(struct wl_listener *l, void *data)
-{
- Keyboard *keyboard = wl_container_of(l, keyboard, event.modify);
-
- wlr_seat_set_keyboard(server.input.seat, keyboard->device);
- wlr_seat_keyboard_notify_modifiers(server.input.seat, &keyboard->device->keyboard->modifiers);
-}
-
-static
-int
-keybinding(xkb_keysym_t sym)
-{
- View *current, *next;
-
- switch(sym) {
- case XKB_KEY_Escape:
- wl_display_terminate(server.display);
- break;
- case XKB_KEY_F1:
- /* cycle to the next view */
- if(wl_list_length(&server.shell.list) < 2) break;
-
- current = wl_container_of(server.shell.list.next, current, link);
- next = wl_container_of(current->link.next, next, link);
-
- focus(next, next->xdg->surface);
-
- /* move previous view to the end of the list */
- wl_list_remove(&current->link);
- wl_list_insert(server.shell.list.prev, &current->link);
- break;
- default:
- return false;
- }
- return true;
-}
-
-static
-void
-keypress(struct wl_listener *l, void *data)
-{
- int i,h,n;
- uint32 keycode, modifier;
- const xkb_keysym_t *syms;
- struct Keyboard *keyboard = wl_container_of(l, keyboard, event.press);
- struct wlr_event_keyboard_key *event = data;
- struct wlr_seat *seat = server.input.seat;
-
- keycode = event->keycode + 8;
-
- h = 0;
- n = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, keycode, &syms);
-
- modifier = wlr_keyboard_get_modifiers(keyboard->device->keyboard);
- if((modifier & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- for(i=0; i<n; i++)
- h=keybinding(syms[i]);
- }
-
- if(!h) {
- wlr_seat_set_keyboard(seat, keyboard->device);
- wlr_seat_keyboard_notify_key(seat, event->time_msec,
- event->keycode, event->state);
- }
-}
-
-static
-void
-new_keyboard(struct wlr_input_device *device)
-{
- Keyboard *keyboard;
- struct xkb_context *context;
- struct xkb_keymap *keymap;
-
- context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
- keymap = xkb_keymap_new_from_names(context, nil, XKB_KEYMAP_COMPILE_NO_FLAGS);
-
- wlr_keyboard_set_keymap(device->keyboard, keymap);
- wlr_keyboard_set_keymap(device->keyboard, keymap);
-
- xkb_keymap_unref(keymap);
- xkb_context_unref(context);
-
- wlr_keyboard_set_repeat_info(device->keyboard, 25, 600);
+// helper functions
- keyboard = calloc(1, sizeof(*keyboard));
- keyboard->device = device;
-
- keyboard->event.modify.notify = keymodifier;
- wl_signal_add(&device->keyboard->events.modifiers, &keyboard->event.modify);
- keyboard->event.press.notify = keypress;
- wl_signal_add(&device->keyboard->events.key, &keyboard->event.press);
-
- wlr_seat_set_keyboard(server.input.seat, device);
- wl_list_insert(&server.input.keyboards, &keyboard->link);
-}
-
-static
-void
-new_pointer(struct wlr_input_device *device)
-{
- wlr_cursor_attach_input_device(server.cursor.dot, device);
-}
-
-static
+static inline
void
-new_input(struct wl_listener *l, void *data)
+init_compositor(void)
{
- uint32 capability;
- struct wlr_input_device *device = data;
-
- switch(device->type) {
- case WLR_INPUT_DEVICE_KEYBOARD:
- new_keyboard(device);
- break;
- case WLR_INPUT_DEVICE_POINTER:
- new_pointer(device);
- /* fallthrough */
- default:
- break;
- }
-
- capability = WL_SEAT_CAPABILITY_POINTER;
- if(!wl_list_empty(&server.input.keyboards))
- capability |= WL_SEAT_CAPABILITY_KEYBOARD;
- wlr_seat_set_capabilities(server.input.seat, capability);
-}
-
-static
-void
-process_cursor_move(uint32 time) {
- server.grab.x = server.cursor.dot->x - server.grab.x;
- server.grab.y = server.cursor.dot->y - server.grab.y;
-}
-
-static
-void
-process_cursor_resize(uint32 time)
-{
- struct wlr_box box;
- View *view = server.grab.view;
- double bx = server.cursor.dot->x - server.grab.x;
- double by = server.cursor.dot->y - server.grab.y;
- int new_left = server.grab.box.x;
- int new_right = server.grab.box.x + server.grab.box.width;
- int new_top = server.grab.box.y;
- int new_bottom = server.grab.box.y + server.grab.box.height;
- int new_width, new_height;
-
- if(server.resize & WLR_EDGE_TOP) {
- new_top = by;
- if (new_top >= new_bottom)
- new_top = new_bottom - 1;
- }else if (server.resize & WLR_EDGE_BOTTOM) {
- new_bottom = by;
- if (new_bottom <= new_top)
- new_bottom = new_top + 1;
- }
-
- if(server.resize & WLR_EDGE_LEFT) {
- new_left = bx;
- if (new_left >= new_right)
- new_left = new_right - 1;
- } else if(server.resize & WLR_EDGE_RIGHT) {
- new_right = bx;
- if (new_right <= new_left)
- new_right = new_left + 1;
- }
-
- wlr_xdg_surface_get_geometry(view->xdg, &box);
- view->x = new_left - box.x;
- view->y = new_top - box.y;
-
- new_width = new_right - new_left;
- new_height = new_bottom - new_top;
- wlr_xdg_toplevel_set_size(view->xdg, new_width, new_height);
-}
-
-static
-void
-process_cursor_motion(uint32 time)
-{
- double sx, sy;
- View *view;
- struct wlr_seat *seat;
- struct wlr_surface *surface;
-
- if(server.cursor.mode == CursorMove)
- return process_cursor_move(time);
- else if(server.cursor.mode == CursorResize)
- return process_cursor_resize(time);
-
- /* Otherwise, find the view under the pointer and send the event along. */
- seat = server.input.seat;
- surface = nil;
- view = viewat(server.cursor.dot->x, server.cursor.dot->y, &surface, &sx, &sy);
- if(!view)
- wlr_xcursor_manager_set_cursor_image(server.cursor.manager, "left_ptr", server.cursor.dot);
-
- if(surface) {
- wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
- wlr_seat_pointer_notify_motion(seat, time, sx, sy);
- } else {
- wlr_seat_pointer_clear_focus(seat);
- }
-}
-
-static
-void
-cursor_move(struct wl_listener *l, void *data)
-{
- struct wlr_event_pointer_motion *event = data;
- wlr_cursor_move(server.cursor.dot, event->device, event->delta_x, event->delta_y);
- process_cursor_motion(event->time_msec);
-}
-
-static
-void
-cursor_move_abs(struct wl_listener *l, void *data)
-{
- struct wlr_event_pointer_motion_absolute *event = data;
- wlr_cursor_warp_absolute(server.cursor.dot, event->device, event->x, event->y);
- process_cursor_motion(event->time_msec);
-}
-
-static
-void
-cursor_button(struct wl_listener *l, void *data)
-{
- View *view;
- double sx, sy;
- struct wlr_surface *surface;
- struct wlr_event_pointer_button *event = data;
-
- wlr_seat_pointer_notify_button(server.input.seat,
- event->time_msec, event->button, event->state);
-
- view = viewat(server.cursor.dot->x, server.cursor.dot->y, &surface, &sx, &sy);
- if (event->state == WLR_BUTTON_RELEASED)
- server.cursor.mode = CursorPassthrough;
- else
- focus(view, surface);
-}
-
-static
-void
-cursor_axis(struct wl_listener *l, void *data)
-{
- struct wlr_event_pointer_axis *event = data;
- /* Notify the client with pointer focus of the axis event. */
- wlr_seat_pointer_notify_axis(server.input.seat,
- event->time_msec, event->orientation, event->delta,
- event->delta_discrete, event->source);
-}
-
-static
-void
-cursor_frame(struct wl_listener *l, void *data)
-{
- wlr_seat_pointer_notify_frame(server.input.seat);
-}
-
-static
-void
-request_cursor(struct wl_listener *l, void *data)
-{
- struct wlr_seat_pointer_request_set_cursor_event *event = data;
- struct wlr_seat_client *focused_client = server.input.seat->pointer_state.focused_client;
- if(focused_client == event->seat_client)
- wlr_cursor_set_surface(server.cursor.dot, event->surface, event->hotspot_x, event->hotspot_y);
-}
-
-static
-void
-request_set_selection(struct wl_listener *l, void *data)
-{
- struct wlr_seat_request_set_selection_event *event = data;
- wlr_seat_set_selection(server.input.seat, event->source, event->serial);
-}
-
-static
-void
-surface_map(struct wl_listener *l, void *data)
-{
- View *view = wl_container_of(l, view, event.map);
- view->mapped = true;
-
- focus(view, view->xdg->surface);
-}
-
-static
-void
-surface_unmap(struct wl_listener *l, void *data)
-{
- View *view = wl_container_of(l, view, event.unmap);
- view->mapped = false;
-}
-
-static
-void
-surface_destroy(struct wl_listener *l, void *data)
-{
- View *view = wl_container_of(l, view, event.destroy);
- wl_list_remove(&view->link);
- free(view);
-}
-
-static
-void
-interactive(View *view, int mode, uint32 edges) {
- double bx, by;
- struct wlr_box box;
- struct wlr_surface *focused = server.input.seat->pointer_state.focused_surface;
-
- if(view->xdg->surface != focused)
- return;
-
- server.grab.view = view;
- server.cursor.mode = mode;
-
- if(mode == CursorMove) {
- server.grab.x = server.cursor.dot->x - view->x;
- server.grab.y = server.cursor.dot->y - view->y;
- } else {
- wlr_xdg_surface_get_geometry(view->xdg, &box);
-
- bx = (view->x + box.x) + ((edges & WLR_EDGE_RIGHT) ? box.width : 0);
- by = (view->y + box.y) + ((edges & WLR_EDGE_BOTTOM) ? box.height : 0);
-
- server.grab.x = server.cursor.dot->x - bx;
- server.grab.y = server.cursor.dot->y - by;
-
- server.grab.box = box;
- server.grab.box.x += view->x;
- server.grab.box.y += view->y;
-
- server.resize = edges;
- }
-}
-
-static
-void
-toplevel_request_move(struct wl_listener *l, void *data)
-{
- View *view = wl_container_of(l, view, event.request_move);
- interactive(view, CursorMove, 0);
-}
-
-static
-void
-toplevel_request_resize(struct wl_listener *l, void *data)
-{
- struct wlr_xdg_toplevel_resize_event *event = data;
- View *view = wl_container_of(l, view, event.request_resize);
- interactive(view, CursorResize, event->edges);
-}
-
-static
-void
-new_surface(struct wl_listener *l, void *data)
-{
- View *view;
- struct wlr_xdg_toplevel *toplevel;
- struct wlr_xdg_surface *xdg = data;
-
- if(xdg->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
- return;
+ server.display = wl_display_create();
+ server.backend = wlr_backend_autocreate(server.display);
+ server.renderer = wlr_backend_get_renderer(server.backend);
- view = calloc(1, sizeof(*view));
- view->xdg = xdg;
+ wlr_renderer_init_wl_display(server.renderer, server.display);
- view->event.map.notify = surface_map;
- wl_signal_add(&xdg->events.map, &view->event.map);
- view->event.unmap.notify = surface_unmap;
- wl_signal_add(&xdg->events.unmap, &view->event.unmap);
- view->event.destroy.notify = surface_destroy;
- wl_signal_add(&xdg->events.destroy, &view->event.destroy);
+ wlr_compositor_create(server.display, server.renderer);
+ wlr_data_device_manager_create(server.display);
- /* cotd */
- toplevel = xdg->toplevel;
- view->event.request_move.notify = toplevel_request_move;
- wl_signal_add(&toplevel->events.request_move, &view->event.request_move);
- view->event.request_resize.notify = toplevel_request_resize;
- wl_signal_add(&toplevel->events.request_resize, &view->event.request_resize);
+ server.output.layout = wlr_output_layout_create();
- /* Add it to the list of views. */
- wl_list_insert(&server.shell.list, &view->link);
+ wl_list_init(&server.output.list);
+ wl_signal_add(&server.backend->events.new_output, &server.event.make_output);
}
-static
+static inline
void
-draw(struct wlr_surface *surface, int sx, int sy, void *data)
+init_desktop(void)
{
- float matrix[9];
- double ox, oy;
- View *view;
- Payload *payload;
- struct wlr_box box;
- struct wlr_output *output;
- struct wlr_texture *texture;
- enum wl_output_transform transform;
-
- payload = data;
- view = payload->view;
- output = payload->output;
-
- texture = wlr_surface_get_texture(surface);
- if(!texture)
- return;
-
- ox = 0, oy = 0;
- wlr_output_layout_output_coords(server.output.layout, output, &ox, &oy);
- ox += view->x + sx, oy += view->y + sy;
-
- box = (struct wlr_box){
- .x = ox * output->scale,
- .y = oy * output->scale,
- .width = surface->current.width * output->scale,
- .height = surface->current.height * output->scale,
- };
+ wl_list_init(&server.clients);
- transform = wlr_output_transform_invert(surface->current.transform);
- wlr_matrix_project_box(matrix, &box, transform, 0, output->transform_matrix);
-
- wlr_render_texture_with_matrix(payload->renderer, texture, matrix, 1);
- wlr_surface_send_frame_done(surface, payload->when);
+ server.shell.xdg = wlr_xdg_shell_create(server.display);
+ wl_signal_add(&server.shell.xdg->events.new_surface, &server.event.make_xdg_surface);
}
-static
+static inline
void
-render(struct wl_listener *l, void *data)
+init_inputs(void)
{
- int width, height;
- struct timespec now;
- View *view;
- Monitor *monitor;
- struct wlr_renderer *renderer;
- float color[4] = {0.3, 0.3, 0.3, 1.0};
-
- monitor = wl_container_of(l, monitor, event.render);
- renderer = server.renderer;
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- if(!wlr_output_attach_render(monitor->output, nil))
- return;
-
- wlr_output_effective_resolution(monitor->output, &width, &height);
-
- /* start of rendering kernel */
- wlr_renderer_begin(renderer, width, height);
- wlr_renderer_clear(renderer, color);
+ server.cursor.dot = wlr_cursor_create();
+ wlr_cursor_attach_output_layout(server.cursor.dot, server.output.layout);
- wl_list_for_each_reverse(view, &server.shell.list, link) {
- if(!view->mapped)
- continue;
+ server.cursor.manager = wlr_xcursor_manager_create(nil, 24);
+ wlr_xcursor_manager_load(server.cursor.manager, 1);
- Payload payload = {
- .output = monitor->output,
- .view = view,
- .renderer = renderer,
- .when = &now,
- };
+ wl_signal_add(&server.cursor.dot->events.motion, &server.event.cursor_move);
+ wl_signal_add(&server.cursor.dot->events.motion_absolute, &server.event.cursor_move_abs);
+ wl_signal_add(&server.cursor.dot->events.button, &server.event.cursor_button);
+ wl_signal_add(&server.cursor.dot->events.axis, &server.event.cursor_axis);
+ wl_signal_add(&server.cursor.dot->events.frame, &server.event.cursor_frame);
- wlr_xdg_surface_for_each_surface(view->xdg, draw, &payload);
- }
+ wl_list_init(&server.input.keyboards);
+ wl_signal_add(&server.backend->events.new_input, &server.event.make_input);
- wlr_output_render_software_cursors(monitor->output, nil);
+ server.input.seat = wlr_seat_create(server.display, "seat0");
- wlr_renderer_end(renderer);
- wlr_output_commit(monitor->output);
+ wl_signal_add(&server.input.seat->events.request_set_cursor, &server.event.request_cursor);
+ wl_signal_add(&server.input.seat->events.request_set_selection, &server.event.request_set_selection);
}
-static
+static inline
void
-new_output(struct wl_listener *l, void *data)
+cleanup(void)
{
- struct wlr_output_mode *mode;
- struct Monitor *monitor;
- struct wlr_output *output = data;
-
- if (!wl_list_empty(&output->modes)) {
- mode = wlr_output_preferred_mode(output);
- wlr_output_set_mode(output, mode);
- wlr_output_enable(output, true);
- if (!wlr_output_commit(output)) {
- return;
- }
- }
-
- monitor = calloc(1, sizeof(*monitor));
- monitor->output = output;
-
- monitor->event.render.notify = render;
- wl_signal_add(&output->events.frame, &monitor->event.render);
- wl_list_insert(&server.output.list, &monitor->link);
-
- wlr_output_layout_add_auto(server.output.layout, output);
+ wl_display_destroy_clients(server.display);
+ wl_display_destroy(server.display);
}
// -----------------------------------------------------------------------
@@ -683,53 +92,9 @@ main(int argc, char *argv[])
wlr_log_init(WLR_DEBUG, nil);
- server.display = wl_display_create();
- server.backend = wlr_backend_autocreate(server.display);
- server.renderer = wlr_backend_get_renderer(server.backend);
-
- wlr_renderer_init_wl_display(server.renderer, server.display);
-
- wlr_compositor_create(server.display, server.renderer);
- wlr_data_device_manager_create(server.display);
-
- server.output.layout = wlr_output_layout_create();
-
- wl_list_init(&server.output.list);
- server.event.new_output.notify = new_output;
- wl_signal_add(&server.backend->events.new_output, &server.event.new_output);
-
- wl_list_init(&server.shell.list);
- server.shell.xdg = wlr_xdg_shell_create(server.display);
- server.event.new_surface.notify = new_surface;
- wl_signal_add(&server.shell.xdg->events.new_surface, &server.event.new_surface);
-
- server.cursor.dot = wlr_cursor_create();
- wlr_cursor_attach_output_layout(server.cursor.dot, server.output.layout);
-
- server.cursor.manager = wlr_xcursor_manager_create(nil, 24);
- wlr_xcursor_manager_load(server.cursor.manager, 1);
-
- server.event.cursor_move.notify = cursor_move;
- wl_signal_add(&server.cursor.dot->events.motion, &server.event.cursor_move);
- server.event.cursor_move_abs.notify = cursor_move_abs;
- wl_signal_add(&server.cursor.dot->events.motion_absolute, &server.event.cursor_move_abs);
- server.event.cursor_button.notify = cursor_button;
- wl_signal_add(&server.cursor.dot->events.button, &server.event.cursor_button);
- server.event.cursor_axis.notify = cursor_axis;
- wl_signal_add(&server.cursor.dot->events.axis, &server.event.cursor_axis);
- server.event.cursor_frame.notify = cursor_frame;
- wl_signal_add(&server.cursor.dot->events.frame, &server.event.cursor_frame);
-
- wl_list_init(&server.input.keyboards);
- server.event.new_input.notify = new_input;
- wl_signal_add(&server.backend->events.new_input, &server.event.new_input);
-
- server.input.seat = wlr_seat_create(server.display, "seat0");
-
- server.event.request_cursor.notify = request_cursor;
- wl_signal_add(&server.input.seat->events.request_set_cursor, &server.event.request_cursor);
- server.event.request_set_selection.notify = request_set_selection;
- wl_signal_add(&server.input.seat->events.request_set_selection, &server.event.request_set_selection);
+ init_compositor();
+ init_desktop();
+ init_inputs();
if(!(socket=(char*)wl_display_add_socket_auto(server.display))) {
wlr_backend_destroy(server.backend);
@@ -745,11 +110,8 @@ main(int argc, char *argv[])
setenv("WAYLAND_DISPLAY", socket, true);
wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
- /* start loop */
- wl_display_run(server.display);
- /* end loop */
+ wl_display_run(server.display); /* event loop */
- wl_display_destroy_clients(server.display);
- wl_display_destroy(server.display);
+ cleanup();
return 0;
}
diff --git a/sys/cmd/wm/output.c b/sys/cmd/wm/output.c
new file mode 100644
index 0000000..3283c41
--- /dev/null
+++ b/sys/cmd/wm/output.c
@@ -0,0 +1,121 @@
+#include "wm.h"
+
+typedef struct Payload Payload;
+struct Payload
+{
+ Client *client;
+ struct wlr_output *output;
+ struct wlr_renderer *renderer;
+ struct timespec *when;
+};
+
+
+static
+void
+draw(struct wlr_surface *surface, int sx, int sy, void *data)
+{
+ float matrix[9];
+ double ox, oy;
+ Client *client;
+ Payload *payload;
+ struct wlr_box box;
+ struct wlr_output *output;
+ struct wlr_texture *texture;
+ enum wl_output_transform transform;
+
+ payload = data;
+ client = payload->client;
+ output = payload->output;
+
+ texture = wlr_surface_get_texture(surface);
+ if(!texture)
+ return;
+
+ ox = 0, oy = 0;
+ wlr_output_layout_output_coords(server.output.layout, output, &ox, &oy);
+ ox += client->x + sx, oy += client->y + sy;
+
+ box = (struct wlr_box){
+ .x = ox * output->scale,
+ .y = oy * output->scale,
+ .width = surface->current.width * output->scale,
+ .height = surface->current.height * output->scale,
+ };
+
+ transform = wlr_output_transform_invert(surface->current.transform);
+ wlr_matrix_project_box(matrix, &box, transform, 0, output->transform_matrix);
+
+ wlr_render_texture_with_matrix(payload->renderer, texture, matrix, 1);
+ wlr_surface_send_frame_done(surface, payload->when);
+}
+
+static
+void
+render(struct wl_listener *l, void *data)
+{
+ int width, height;
+ struct timespec now;
+ Client *client;
+ Monitor *monitor;
+ struct wlr_renderer *renderer;
+ float color[4] = {0.3, 0.3, 0.3, 1.0};
+
+ monitor = wl_container_of(l, monitor, event.render);
+ renderer = server.renderer;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ if(!wlr_output_attach_render(monitor->output, nil))
+ return;
+
+ wlr_output_effective_resolution(monitor->output, &width, &height);
+
+ /* start of rendering kernel */
+ wlr_renderer_begin(renderer, width, height);
+ wlr_renderer_clear(renderer, color);
+
+ wl_list_for_each_reverse(client, &server.clients, link) {
+ if(!client->mapped)
+ continue;
+
+ Payload payload = {
+ .output = monitor->output,
+ .client = client,
+ .renderer = renderer,
+ .when = &now,
+ };
+
+ wlr_xdg_surface_for_each_surface(client->xdg, draw, &payload);
+ }
+
+ wlr_output_render_software_cursors(monitor->output, nil);
+
+ wlr_renderer_end(renderer);
+ wlr_output_commit(monitor->output);
+}
+
+void
+make_output(struct wl_listener *l, void *data)
+{
+ struct wlr_output_mode *mode;
+ struct Monitor *monitor;
+ struct wlr_output *output = data;
+
+ if (!wl_list_empty(&output->modes)) {
+ mode = wlr_output_preferred_mode(output);
+ wlr_output_set_mode(output, mode);
+ wlr_output_enable(output, true);
+ if (!wlr_output_commit(output)) {
+ return;
+ }
+ }
+
+ monitor = calloc(1, sizeof(*monitor));
+ monitor->output = output;
+
+ monitor->event.render.notify = render;
+ wl_signal_add(&output->events.frame, &monitor->event.render);
+ wl_list_insert(&server.output.list, &monitor->link);
+
+ wlr_output_layout_add_auto(server.output.layout, output);
+}
+
diff --git a/sys/cmd/wm/rules.mk b/sys/cmd/wm/rules.mk
index 92e108d..b1ab9c3 100644
--- a/sys/cmd/wm/rules.mk
+++ b/sys/cmd/wm/rules.mk
@@ -3,6 +3,10 @@ include share/push.mk
# Local sources
SRCS_$(d) := \
+ $(d)/input.c \
+ $(d)/output.c \
+ $(d)/xdg.c \
+ $(d)/client.c \
$(d)/main.c
BINS_$(d) := $(d)/wm
diff --git a/sys/cmd/wm/wm.h b/sys/cmd/wm/wm.h
index 356c408..b9731e9 100644
--- a/sys/cmd/wm/wm.h
+++ b/sys/cmd/wm/wm.h
@@ -24,3 +24,131 @@
#include <wlr/util/log.h>
#include <xkbcommon/xkbcommon.h>
+
+// -----------------------------------------------------------------------
+// types
+
+enum
+{
+ CursorPassthrough,
+ CursorMove,
+ CursorResize,
+};
+
+typedef struct Keyboard Keyboard;
+typedef struct Client Client;
+typedef struct Monitor Monitor;
+typedef struct Server Server;
+
+struct Keyboard
+{
+ struct wl_list link;
+ struct wlr_input_device *device;
+ struct {
+ struct wl_listener press;
+ struct wl_listener modify;
+ } event;
+};
+
+struct Client
+{
+ struct wl_list link;
+ struct wlr_xdg_surface *xdg;
+ struct {
+ struct wl_listener map;
+ struct wl_listener unmap;
+ struct wl_listener destroy;
+ struct wl_listener request_move;
+ struct wl_listener request_resize;
+ } event;
+ int x, y, mapped;
+};
+
+struct Monitor
+{
+ struct wl_list link;
+ struct wlr_output *output;
+ struct {
+ struct wl_listener render;
+ } event;
+};
+
+struct Server
+{
+ struct wl_display *display;
+ struct wlr_backend *backend;
+ struct wlr_renderer *renderer;
+
+ struct {
+ struct wlr_xdg_shell *xdg;
+ } shell;
+
+ struct wl_list clients;
+
+ struct {
+ Client *client;
+ double x, y;
+ struct wlr_box box;
+ } grab;
+ uint32 resize;
+
+ struct {
+ struct wlr_output_layout *layout;
+ struct wl_list list;
+ } output;
+
+ struct {
+ struct wlr_cursor *dot;
+ struct wlr_xcursor_manager *manager;
+ int mode;
+ } cursor;
+
+ struct {
+ struct wlr_seat *seat;
+ struct wl_list keyboards;
+ } input;
+
+ struct {
+ struct wl_listener make_output;
+ struct wl_listener make_input;
+ struct wl_listener make_xdg_surface;
+
+ struct wl_listener cursor_move;
+ struct wl_listener cursor_move_abs;
+ struct wl_listener cursor_button;
+ struct wl_listener cursor_axis;
+ struct wl_listener cursor_frame;
+
+ struct wl_listener request_cursor;
+ struct wl_listener request_set_selection;
+ } event;
+};
+
+extern struct Server server;
+
+// -----------------------------------------------------------------------
+// functions
+
+/* output.c */
+void make_output(struct wl_listener *, void *);
+
+/* xdg.c */
+void make_xdg_surface(struct wl_listener *, void *);
+
+/* input.c */
+void make_input(struct wl_listener *, void *);
+
+void cursor_axis(struct wl_listener *, void *);
+void cursor_frame(struct wl_listener *, void *);
+void cursor_button(struct wl_listener *, void *);
+void cursor_move(struct wl_listener *, void *);
+void cursor_move_abs(struct wl_listener *, void *);
+
+void request_cursor(struct wl_listener *, void *);
+void request_set_selection(struct wl_listener *, void *);
+
+/* client.c */
+void focus(Client *client, struct wlr_surface *new);
+Client* clientat(double, double, struct wlr_surface **, double *, double *);
+int clienthas(Client *, double, double, struct wlr_surface **, double *, double *);
+void setinteractive(Client *client, int mode, uint32 edges);
diff --git a/sys/cmd/wm/xdg.c b/sys/cmd/wm/xdg.c
new file mode 100644
index 0000000..3978cbf
--- /dev/null
+++ b/sys/cmd/wm/xdg.c
@@ -0,0 +1,76 @@
+#include "wm.h"
+
+static
+void
+map(struct wl_listener *l, void *data)
+{
+ Client *client = wl_container_of(l, client, event.map);
+ client->mapped = true;
+
+ focus(client, client->xdg->surface);
+}
+
+static
+void
+unmap(struct wl_listener *l, void *data)
+{
+ Client *client = wl_container_of(l, client, event.unmap);
+ client->mapped = false;
+}
+
+static
+void
+destroy(struct wl_listener *l, void *data)
+{
+ Client *client = wl_container_of(l, client, event.destroy);
+ wl_list_remove(&client->link);
+ free(client);
+}
+
+static
+void
+request_move(struct wl_listener *l, void *data)
+{
+ Client *client = wl_container_of(l, client, event.request_move);
+ setinteractive(client, CursorMove, 0);
+}
+
+static
+void
+request_resize(struct wl_listener *l, void *data)
+{
+ struct wlr_xdg_toplevel_resize_event *event = data;
+ Client *client = wl_container_of(l, client, event.request_resize);
+ setinteractive(client, CursorResize, event->edges);
+}
+
+void
+make_xdg_surface(struct wl_listener *l, void *data)
+{
+ Client *client;
+ struct wlr_xdg_toplevel *toplevel;
+ struct wlr_xdg_surface *xdg = data;
+
+ if(xdg->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
+ return;
+
+ client = calloc(1, sizeof(*client));
+ client->xdg = xdg;
+
+ client->event.map.notify = map;
+ wl_signal_add(&xdg->events.map, &client->event.map);
+ client->event.unmap.notify = unmap;
+ wl_signal_add(&xdg->events.unmap, &client->event.unmap);
+ client->event.destroy.notify = destroy;
+ wl_signal_add(&xdg->events.destroy, &client->event.destroy);
+
+ /* cotd */
+ toplevel = xdg->toplevel;
+ client->event.request_move.notify = request_move;
+ wl_signal_add(&toplevel->events.request_move, &client->event.request_move);
+ client->event.request_resize.notify = request_resize;
+ wl_signal_add(&toplevel->events.request_resize, &client->event.request_resize);
+
+ /* Add it to the list of client. */
+ wl_list_insert(&server.clients, &client->link);
+}