From b9a07a67b85e9192faa0e285b4419bd5ef242a03 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Tue, 28 Sep 2021 14:34:34 -0700 Subject: feat: reorganized code to be more modular --- sys/cmd/wm/client.c | 95 +++++++ sys/cmd/wm/input.c | 285 ++++++++++++++++++++ sys/cmd/wm/main.c | 752 ++++------------------------------------------------ sys/cmd/wm/output.c | 121 +++++++++ sys/cmd/wm/rules.mk | 4 + sys/cmd/wm/wm.h | 128 +++++++++ sys/cmd/wm/xdg.c | 76 ++++++ 7 files changed, 766 insertions(+), 695 deletions(-) create mode 100644 sys/cmd/wm/client.c create mode 100644 sys/cmd/wm/input.c create mode 100644 sys/cmd/wm/output.c create mode 100644 sys/cmd/wm/xdg.c (limited to 'sys/cmd') 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(¤t->link); + wl_list_insert(server.clients.prev, ¤t->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; idevice); + 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(¤t->link); - wl_list_insert(server.shell.list.prev, ¤t->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; idevice); - 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 #include + +// ----------------------------------------------------------------------- +// 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); +} -- cgit v1.2.1