From 8b74cf1231366a69d05d2cd127a59f31b7cb5b94 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Wed, 12 Feb 2020 21:48:11 -0500 Subject: [PATCH 01/20] wlroots 0.9+ doesn't keep track of resources --- meson.build | 2 +- waybox/output.c | 19 ------------------- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/meson.build b/meson.build index 1c728d3..6d72742 100644 --- a/meson.build +++ b/meson.build @@ -30,7 +30,7 @@ add_project_arguments('-DWL_HIDE_DEPRECATED', language: 'c') inc_dir = include_directories('include') pixman = dependency('pixman-1') -wlroots = dependency('wlroots', version: '>=0.6.0') +wlroots = dependency('wlroots', version: '>=0.9.0') wayland_server = dependency('wayland-server') wayland_client = dependency('wayland-client') wayland_protos = dependency('wayland-protocols', version: '>=1.12') diff --git a/waybox/output.c b/waybox/output.c index b8a4332..421706f 100644 --- a/waybox/output.c +++ b/waybox/output.c @@ -16,25 +16,6 @@ void output_frame_notify(struct wl_listener *listener, void *data) { float color[4] = {0.4f, 0.4f, 0.4f, 1.0f}; wlr_renderer_clear(renderer, color); - struct wl_resource *_surface; - wl_resource_for_each(_surface, &output->server->compositor->surface_resources) { - struct wlr_surface *surface = wlr_surface_from_resource(_surface); - if (!wlr_surface_has_buffer(surface)) { - continue; - } - struct wlr_box render_box = { - .x = 20, .y = 20, - .width = surface->current.width, - .height = surface->current.height - }; - float matrix[16]; - wlr_matrix_project_box(matrix, &render_box, surface->current.transform, - 0, wlr_output->transform_matrix); - struct wlr_texture *texture = wlr_surface_get_texture(surface); - wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f); - wlr_surface_send_frame_done(surface, &now); - } - wlr_output_commit(wlr_output); wlr_renderer_end(renderer); output->last_frame = now; From aa5988ccca3718974d3b7218e9202e187903285d Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 13 Feb 2020 15:06:17 -0500 Subject: [PATCH 02/20] Fix bad indentation --- waybox/server.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/waybox/server.c b/waybox/server.c index 70c9792..d5cc37a 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -14,34 +14,34 @@ static void new_input_notify(struct wl_listener *listener, void *data) { bool init_wb(struct wb_server* server) { - // create display - server->wl_display = wl_display_create(); + // create display + server->wl_display = wl_display_create(); assert(server->wl_display); - // create shared memory - wl_display_init_shm(server->wl_display); + // create shared memory + wl_display_init_shm(server->wl_display); - // event loop stuff - server->wl_event_loop = wl_display_get_event_loop(server->wl_display); + // event loop stuff + server->wl_event_loop = wl_display_get_event_loop(server->wl_display); assert(server->wl_event_loop); - // create backend + // create backend server->backend = wlr_backend_autocreate(server->wl_display, NULL); assert(server->backend); - if(server->backend == NULL){ - printf("Failed to create backend\n"); - return false; - } + if(server->backend == NULL){ + printf("Failed to create backend\n"); + return false; + } server->layout = wlr_output_layout_create(); server->cursor = wb_cursor_create(); wlr_cursor_attach_output_layout(server->cursor->cursor, server->layout); - return true; + return true; } bool start_wb(struct wb_server* server) { - wl_list_init(&server->outputs); + wl_list_init(&server->outputs); server->new_output.notify = new_output_notify; wl_signal_add(&server->backend->events.new_output, &server->new_output); @@ -52,13 +52,13 @@ bool start_wb(struct wb_server* server) { const char *socket = wl_display_add_socket_auto(server->wl_display); assert(socket); - if (!wlr_backend_start(server->backend)) { + if (!wlr_backend_start(server->backend)) { fprintf(stderr, "Failed to start backend\n"); wl_display_destroy(server->wl_display); return false; } - wlr_gamma_control_manager_v1_create(server->wl_display); + wlr_gamma_control_manager_v1_create(server->wl_display); wlr_screencopy_manager_v1_create(server->wl_display); wlr_gtk_primary_selection_device_manager_create(server->wl_display); wlr_idle_create(server->wl_display); @@ -67,18 +67,18 @@ bool start_wb(struct wb_server* server) { wlr_backend_get_renderer(server->backend)); // wlr_xdg_shell_v6_create(server.wl_display); - wlr_idle_create(server->wl_display); + wlr_idle_create(server->wl_display); - return true; + return true; } bool terminate_wb(struct wb_server* server) { - wl_display_destroy(server->wl_display); + wl_display_destroy(server->wl_display); - printf("Display destroyed.\n"); + printf("Display destroyed.\n"); wb_cursor_destroy(server->cursor); wlr_output_layout_destroy(server->layout); - return true; + return true; } From cb67c247185e8ab075e4c219e25d27bb32547a4b Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Mon, 17 Feb 2020 23:43:14 -0500 Subject: [PATCH 03/20] Got basic xdg-shell code --- README.md | 5 +++++ include/waybox/server.h | 1 + waybox/server.c | 7 +++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 39b8e8b..243ea16 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ # waybox An openbox clone on Wayland (WIP) +This is the basic-apps branch, in which I'm working to get simple apps to work. +Currently, I'm targeting wlroots 0.6.0, but after I get the basic functionality +worked out, I want to get it to compile with wlroots 0.10.0. Right now, a +weston-terminal window will show, but it won't receive keyboard input. + ### Goals The main goal of this project is to provide a similar feel to openbox but on wayland diff --git a/include/waybox/server.h b/include/waybox/server.h index bc09448..3a9b63a 100644 --- a/include/waybox/server.h +++ b/include/waybox/server.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "waybox/output.h" #include "waybox/cursor.h" diff --git a/waybox/server.c b/waybox/server.c index 70c9792..53772f5 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -58,6 +58,9 @@ bool start_wb(struct wb_server* server) { return false; } + //printf("Running Wayland compositor on Wayland display '%s'\n", socket); + //setenv("WAYLAND_DISPLAY", socket, true); + wlr_gamma_control_manager_v1_create(server->wl_display); wlr_screencopy_manager_v1_create(server->wl_display); wlr_gtk_primary_selection_device_manager_create(server->wl_display); @@ -66,8 +69,8 @@ bool start_wb(struct wb_server* server) { server->compositor = wlr_compositor_create(server->wl_display, wlr_backend_get_renderer(server->backend)); -// wlr_xdg_shell_v6_create(server.wl_display); - wlr_idle_create(server->wl_display); + wlr_xdg_shell_create(server->wl_display); + //wlr_idle_create(server->wl_display); return true; } From 1cd178e9ce21e581f363fb0fcf1e49919602ac1a Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Tue, 18 Feb 2020 07:37:19 -0500 Subject: [PATCH 04/20] Basic seat support --- include/waybox/seat.h | 16 ++++++++++++++++ include/waybox/server.h | 2 ++ waybox/meson.build | 1 + waybox/seat.c | 15 +++++++++++++++ waybox/server.c | 2 ++ 5 files changed, 36 insertions(+) create mode 100644 include/waybox/seat.h create mode 100644 waybox/seat.c diff --git a/include/waybox/seat.h b/include/waybox/seat.h new file mode 100644 index 0000000..caf13d1 --- /dev/null +++ b/include/waybox/seat.h @@ -0,0 +1,16 @@ +#ifndef _WB_SEAT_H +#define _WB_SEAT_H + +#include + +#include "waybox/server.h" + +struct wb_seat { + struct wlr_seat * seat; +}; + +struct wb_server; +struct wb_seat * wb_seat_create(struct wb_server * server); + +void wb_seat_destroy(struct wb_seat * seat); +#endif diff --git a/include/waybox/server.h b/include/waybox/server.h index 3a9b63a..b288196 100644 --- a/include/waybox/server.h +++ b/include/waybox/server.h @@ -24,6 +24,7 @@ #include "waybox/output.h" #include "waybox/cursor.h" +#include "waybox/seat.h" struct wb_server { struct wl_display *wl_display; @@ -34,6 +35,7 @@ struct wb_server { struct wlr_output_layout *layout; struct wb_cursor *cursor; + struct wb_seat * seat; struct wl_listener new_output; struct wl_listener new_input; diff --git a/waybox/meson.build b/waybox/meson.build index a44d004..55eabf7 100644 --- a/waybox/meson.build +++ b/waybox/meson.build @@ -2,6 +2,7 @@ wb_src = files( 'cursor.c', 'main.c', 'output.c', + 'seat.c', 'server.c', ) diff --git a/waybox/seat.c b/waybox/seat.c new file mode 100644 index 0000000..dbd0f2a --- /dev/null +++ b/waybox/seat.c @@ -0,0 +1,15 @@ +#include + +#include "waybox/seat.h" + +struct wb_seat * wb_seat_create(struct wb_server * server) { + struct wb_seat * seat = malloc(sizeof(struct wb_seat)); + seat->seat = wlr_seat_create(server->wl_display, "seat0"); + wlr_seat_set_capabilities(seat->seat, WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD); + return seat; +} + +void wb_seat_destroy(struct wb_seat * seat) { + wlr_seat_destroy(seat->seat); + free(seat); +} diff --git a/waybox/server.c b/waybox/server.c index 53772f5..8f26142 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -36,6 +36,7 @@ bool init_wb(struct wb_server* server) { server->layout = wlr_output_layout_create(); server->cursor = wb_cursor_create(); wlr_cursor_attach_output_layout(server->cursor->cursor, server->layout); + server->seat = wb_seat_create(server); return true; } @@ -81,6 +82,7 @@ bool terminate_wb(struct wb_server* server) { printf("Display destroyed.\n"); wb_cursor_destroy(server->cursor); + wb_seat_destroy(server->seat); wlr_output_layout_destroy(server->layout); return true; From 64db394085455f0584a26fdc2781037f7fb8a220 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Tue, 18 Feb 2020 15:41:39 -0500 Subject: [PATCH 05/20] Lifted support for keys from tinywl; TODO: don't have all the code in server.c --- include/waybox/seat.h | 14 ++++- meson.build | 1 + protocol/meson.build | 2 - waybox/meson.build | 1 + waybox/seat.c | 5 ++ waybox/server.c | 122 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 3 deletions(-) diff --git a/include/waybox/seat.h b/include/waybox/seat.h index caf13d1..a08f20e 100644 --- a/include/waybox/seat.h +++ b/include/waybox/seat.h @@ -1,16 +1,28 @@ #ifndef _WB_SEAT_H #define _WB_SEAT_H +#include #include #include "waybox/server.h" struct wb_seat { struct wlr_seat * seat; + + struct wl_list keyboards; + struct wl_listener new_input; +}; + +struct wb_keyboard { + struct wl_list link; + struct wb_server * server; + struct wlr_input_device * device; + + struct wl_listener modifiers; + struct wl_listener key; }; struct wb_server; struct wb_seat * wb_seat_create(struct wb_server * server); - void wb_seat_destroy(struct wb_seat * seat); #endif diff --git a/meson.build b/meson.build index 1c728d3..9620f30 100644 --- a/meson.build +++ b/meson.build @@ -34,6 +34,7 @@ wlroots = dependency('wlroots', version: '>=0.6.0') wayland_server = dependency('wayland-server') wayland_client = dependency('wayland-client') wayland_protos = dependency('wayland-protocols', version: '>=1.12') +xkbcommon = dependency('xkbcommon') subdir('protocol') subdir('waybox') diff --git a/protocol/meson.build b/protocol/meson.build index ec66c47..7982dd8 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -24,7 +24,6 @@ protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], 'wlr-gamma-control-unstable-v1.xml', 'gtk-primary-selection.xml', 'idle.xml', @@ -34,7 +33,6 @@ protocols = [ ] client_protocols = [ - [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], 'idle.xml', diff --git a/waybox/meson.build b/waybox/meson.build index 55eabf7..b341eb0 100644 --- a/waybox/meson.build +++ b/waybox/meson.build @@ -10,6 +10,7 @@ wb_dep = [ wayland_server, wlroots, pixman, + xkbcommon, ] executable( diff --git a/waybox/seat.c b/waybox/seat.c index dbd0f2a..3d0bfe3 100644 --- a/waybox/seat.c +++ b/waybox/seat.c @@ -4,8 +4,13 @@ struct wb_seat * wb_seat_create(struct wb_server * server) { struct wb_seat * seat = malloc(sizeof(struct wb_seat)); + + wl_list_init(&seat->keyboards); + //seat->new_input.notify = new_input_notify; + //wl_signal_add(&server->backend->events.new_input, &server->new_input); seat->seat = wlr_seat_create(server->wl_display, "seat0"); wlr_seat_set_capabilities(seat->seat, WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD); + return seat; } diff --git a/waybox/server.c b/waybox/server.c index 8f26142..e04a645 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -1,9 +1,131 @@ #include "waybox/server.h" +#include "waybox/seat.h" + +/* Stolen from wltiny. Customizations will come later. */ +static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym) { + /* + * Here we handle compositor keybindings. This is when the compositor is + * processing keys, rather than passing them on to the client for its own + * processing. + * + * This function assumes Alt is held down. + */ + switch (sym) { + case XKB_KEY_Escape: + wl_display_terminate(server->wl_display); + break; + case XKB_KEY_F1: +#if 0 + /* Cycle to the next view */ + if (wl_list_length(&server->views) < 2) { + break; + } + struct tinywl_view *current_view = wl_container_of( + server->views.next, current_view, link); + struct tinywl_view *next_view = wl_container_of( + current_view->link.next, next_view, link); + focus_view(next_view, next_view->xdg_surface->surface); + /* Move the previous view to the end of the list */ + wl_list_remove(¤t_view->link); + wl_list_insert(server->views.prev, ¤t_view->link); +#endif + break; + default: + return false; + } + return true; +} + +static void keyboard_handle_modifiers( + struct wl_listener *listener, void *data) { + /* This event is raised when a modifier key, such as shift or alt, is + * pressed. We simply communicate this to the client. */ + struct wb_keyboard *keyboard = + wl_container_of(listener, keyboard, modifiers); + /* + * A seat can only have one keyboard, but this is a limitation of the + * Wayland protocol - not wlroots. We assign all connected keyboards to the + * same seat. You can swap out the underlying wlr_keyboard like this and + * wlr_seat handles this transparently. + */ + wlr_seat_set_keyboard(keyboard->server->seat->seat, keyboard->device); + /* Send modifiers to the client. */ + wlr_seat_keyboard_notify_modifiers(keyboard->server->seat->seat, + &keyboard->device->keyboard->modifiers); +} + +static void keyboard_handle_key( + struct wl_listener *listener, void *data) { + /* This event is raised when a key is pressed or released. */ + struct wb_keyboard *keyboard = + wl_container_of(listener, keyboard, key); + struct wb_server *server = keyboard->server; + struct wlr_event_keyboard_key *event = data; + struct wlr_seat *seat = server->seat->seat; + + /* Translate libinput keycode -> xkbcommon */ + uint32_t keycode = event->keycode + 8; + /* Get a list of keysyms based on the keymap for this keyboard */ + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms( + keyboard->device->keyboard->xkb_state, keycode, &syms); + + bool handled = false; + uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + if ((modifiers & WLR_MODIFIER_ALT) && event->state == WLR_KEY_PRESSED) { + /* If alt is held down and this button was _pressed_, we attempt to + * process it as a compositor keybinding. */ + for (int i = 0; i < nsyms; i++) { + handled = handle_keybinding(server, syms[i]); + } + } + + if (!handled) { + /* Otherwise, we pass it along to the client. */ + wlr_seat_set_keyboard(seat, keyboard->device); + wlr_seat_keyboard_notify_key(seat, event->time_msec, + event->keycode, event->state); + } +} + +static void server_new_keyboard(struct wb_server *server, + struct wlr_input_device *device) { + struct wb_keyboard *keyboard = + calloc(1, sizeof(struct wb_keyboard)); + keyboard->server = server; + keyboard->device = device; + + /* We need to prepare an XKB keymap and assign it to the keyboard. This + * assumes the defaults (e.g. layout = "us"). */ + struct xkb_rule_names rules = { 0 }; + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); + + /* Here we set up listeners for keyboard events. */ + keyboard->modifiers.notify = keyboard_handle_modifiers; + wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers); + keyboard->key.notify = keyboard_handle_key; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + + wlr_seat_set_keyboard(server->seat->seat, device); + + /* And add the keyboard to our list of keyboards */ + wl_list_insert(&server->seat->keyboards, &keyboard->link); +} static void new_input_notify(struct wl_listener *listener, void *data) { struct wlr_input_device *device = data; struct wb_server *server = wl_container_of(listener, server, new_input); switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + server_new_keyboard(server, device); + break; case WLR_INPUT_DEVICE_POINTER: wlr_cursor_attach_input_device(server->cursor->cursor, device); break; From f80549948793c380a8da92a2efc0c5e16f0c2e10 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Tue, 18 Feb 2020 15:56:03 -0500 Subject: [PATCH 06/20] Basic data manager (wterm now shows, but input is still not working) --- include/waybox/server.h | 1 + waybox/server.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/waybox/server.h b/include/waybox/server.h index b288196..6636b74 100644 --- a/include/waybox/server.h +++ b/include/waybox/server.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/waybox/server.c b/waybox/server.c index e04a645..feafd68 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -191,7 +191,7 @@ bool start_wb(struct wb_server* server) { server->compositor = wlr_compositor_create(server->wl_display, wlr_backend_get_renderer(server->backend)); - + wlr_data_device_manager_create(server->wl_display); wlr_xdg_shell_create(server->wl_display); //wlr_idle_create(server->wl_display); From 7d76b9ef7691931c769d7775be08eca96bc87a39 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Tue, 18 Feb 2020 17:51:32 -0500 Subject: [PATCH 07/20] Don't segfault on termination --- waybox/server.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/waybox/server.c b/waybox/server.c index feafd68..f0f449f 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -199,13 +199,12 @@ bool start_wb(struct wb_server* server) { } bool terminate_wb(struct wb_server* server) { + wb_cursor_destroy(server->cursor); + wb_seat_destroy(server->seat); + wlr_output_layout_destroy(server->layout); wl_display_destroy(server->wl_display); printf("Display destroyed.\n"); - wb_cursor_destroy(server->cursor); - wb_seat_destroy(server->seat); - wlr_output_layout_destroy(server->layout); - return true; } From fe78796f7fb9aa6ecc5a53d9eccbbb0d75bf4306 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Wed, 19 Feb 2020 14:23:27 -0500 Subject: [PATCH 08/20] Updated README.md; moved the keyboard code from server.c to seat.c --- README.md | 1 + include/waybox/seat.h | 1 - waybox/seat.c | 137 +++++++++++++++++++++++++++++++++++++++++- waybox/server.c | 137 +----------------------------------------- 4 files changed, 138 insertions(+), 138 deletions(-) diff --git a/README.md b/README.md index 243ea16..6686135 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ contributing.](https://github.com/wizbright/waybox/blob/master/CONTRIBUTING.md) * meson * wlroots * wayland +* xkbcommon ### Build instructions diff --git a/include/waybox/seat.h b/include/waybox/seat.h index a08f20e..014cee0 100644 --- a/include/waybox/seat.h +++ b/include/waybox/seat.h @@ -10,7 +10,6 @@ struct wb_seat { struct wlr_seat * seat; struct wl_list keyboards; - struct wl_listener new_input; }; struct wb_keyboard { diff --git a/waybox/seat.c b/waybox/seat.c index 3d0bfe3..91e0e26 100644 --- a/waybox/seat.c +++ b/waybox/seat.c @@ -2,12 +2,145 @@ #include "waybox/seat.h" +/* Stolen from wltiny. Customizations will come later. */ +static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym) { + /* + * Here we handle compositor keybindings. This is when the compositor is + * processing keys, rather than passing them on to the client for its own + * processing. + * + * This function assumes Alt is held down. + */ + switch (sym) { + case XKB_KEY_Escape: + wl_display_terminate(server->wl_display); + break; + case XKB_KEY_F1: +#if 0 + /* Cycle to the next view */ + if (wl_list_length(&server->views) < 2) { + break; + } + struct tinywl_view *current_view = wl_container_of( + server->views.next, current_view, link); + struct tinywl_view *next_view = wl_container_of( + current_view->link.next, next_view, link); + focus_view(next_view, next_view->xdg_surface->surface); + /* Move the previous view to the end of the list */ + wl_list_remove(¤t_view->link); + wl_list_insert(server->views.prev, ¤t_view->link); +#endif + break; + default: + return false; + } + return true; +} + +static void keyboard_handle_modifiers( + struct wl_listener *listener, void *data) { + /* This event is raised when a modifier key, such as shift or alt, is + * pressed. We simply communicate this to the client. */ + struct wb_keyboard *keyboard = + wl_container_of(listener, keyboard, modifiers); + /* + * A seat can only have one keyboard, but this is a limitation of the + * Wayland protocol - not wlroots. We assign all connected keyboards to the + * same seat. You can swap out the underlying wlr_keyboard like this and + * wlr_seat handles this transparently. + */ + wlr_seat_set_keyboard(keyboard->server->seat->seat, keyboard->device); + /* Send modifiers to the client. */ + wlr_seat_keyboard_notify_modifiers(keyboard->server->seat->seat, + &keyboard->device->keyboard->modifiers); +} + +static void keyboard_handle_key( + struct wl_listener *listener, void *data) { + /* This event is raised when a key is pressed or released. */ + struct wb_keyboard *keyboard = + wl_container_of(listener, keyboard, key); + struct wb_server *server = keyboard->server; + struct wlr_event_keyboard_key *event = data; + struct wlr_seat *seat = server->seat->seat; + + /* Translate libinput keycode -> xkbcommon */ + uint32_t keycode = event->keycode + 8; + /* Get a list of keysyms based on the keymap for this keyboard */ + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms( + keyboard->device->keyboard->xkb_state, keycode, &syms); + + bool handled = false; + uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + if ((modifiers & WLR_MODIFIER_ALT) && event->state == WLR_KEY_PRESSED) { + /* If alt is held down and this button was _pressed_, we attempt to + * process it as a compositor keybinding. */ + for (int i = 0; i < nsyms; i++) { + handled = handle_keybinding(server, syms[i]); + } + } + + if (!handled) { + /* Otherwise, we pass it along to the client. */ + wlr_seat_set_keyboard(seat, keyboard->device); + wlr_seat_keyboard_notify_key(seat, event->time_msec, + event->keycode, event->state); + } +} + +static void server_new_keyboard(struct wb_server *server, + struct wlr_input_device *device) { + struct wb_keyboard *keyboard = + calloc(1, sizeof(struct wb_keyboard)); + keyboard->server = server; + keyboard->device = device; + + /* We need to prepare an XKB keymap and assign it to the keyboard. This + * assumes the defaults (e.g. layout = "us"). */ + struct xkb_rule_names rules = { 0 }; + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); + + /* Here we set up listeners for keyboard events. */ + keyboard->modifiers.notify = keyboard_handle_modifiers; + wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers); + keyboard->key.notify = keyboard_handle_key; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + + wlr_seat_set_keyboard(server->seat->seat, device); + + /* And add the keyboard to our list of keyboards */ + wl_list_insert(&server->seat->keyboards, &keyboard->link); +} + +static void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct wb_server *server = wl_container_of(listener, server, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + server_new_keyboard(server, device); + break; + case WLR_INPUT_DEVICE_POINTER: + wlr_cursor_attach_input_device(server->cursor->cursor, device); + break; + default: + break; + } +} + struct wb_seat * wb_seat_create(struct wb_server * server) { struct wb_seat * seat = malloc(sizeof(struct wb_seat)); wl_list_init(&seat->keyboards); - //seat->new_input.notify = new_input_notify; - //wl_signal_add(&server->backend->events.new_input, &server->new_input); + server->new_input.notify = new_input_notify; + wl_signal_add(&server->backend->events.new_input, &server->new_input); seat->seat = wlr_seat_create(server->wl_display, "seat0"); wlr_seat_set_capabilities(seat->seat, WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD); diff --git a/waybox/server.c b/waybox/server.c index f0f449f..2d8a91a 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -1,139 +1,6 @@ #include "waybox/server.h" #include "waybox/seat.h" -/* Stolen from wltiny. Customizations will come later. */ -static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym) { - /* - * Here we handle compositor keybindings. This is when the compositor is - * processing keys, rather than passing them on to the client for its own - * processing. - * - * This function assumes Alt is held down. - */ - switch (sym) { - case XKB_KEY_Escape: - wl_display_terminate(server->wl_display); - break; - case XKB_KEY_F1: -#if 0 - /* Cycle to the next view */ - if (wl_list_length(&server->views) < 2) { - break; - } - struct tinywl_view *current_view = wl_container_of( - server->views.next, current_view, link); - struct tinywl_view *next_view = wl_container_of( - current_view->link.next, next_view, link); - focus_view(next_view, next_view->xdg_surface->surface); - /* Move the previous view to the end of the list */ - wl_list_remove(¤t_view->link); - wl_list_insert(server->views.prev, ¤t_view->link); -#endif - break; - default: - return false; - } - return true; -} - -static void keyboard_handle_modifiers( - struct wl_listener *listener, void *data) { - /* This event is raised when a modifier key, such as shift or alt, is - * pressed. We simply communicate this to the client. */ - struct wb_keyboard *keyboard = - wl_container_of(listener, keyboard, modifiers); - /* - * A seat can only have one keyboard, but this is a limitation of the - * Wayland protocol - not wlroots. We assign all connected keyboards to the - * same seat. You can swap out the underlying wlr_keyboard like this and - * wlr_seat handles this transparently. - */ - wlr_seat_set_keyboard(keyboard->server->seat->seat, keyboard->device); - /* Send modifiers to the client. */ - wlr_seat_keyboard_notify_modifiers(keyboard->server->seat->seat, - &keyboard->device->keyboard->modifiers); -} - -static void keyboard_handle_key( - struct wl_listener *listener, void *data) { - /* This event is raised when a key is pressed or released. */ - struct wb_keyboard *keyboard = - wl_container_of(listener, keyboard, key); - struct wb_server *server = keyboard->server; - struct wlr_event_keyboard_key *event = data; - struct wlr_seat *seat = server->seat->seat; - - /* Translate libinput keycode -> xkbcommon */ - uint32_t keycode = event->keycode + 8; - /* Get a list of keysyms based on the keymap for this keyboard */ - const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms( - keyboard->device->keyboard->xkb_state, keycode, &syms); - - bool handled = false; - uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); - if ((modifiers & WLR_MODIFIER_ALT) && event->state == WLR_KEY_PRESSED) { - /* If alt is held down and this button was _pressed_, we attempt to - * process it as a compositor keybinding. */ - for (int i = 0; i < nsyms; i++) { - handled = handle_keybinding(server, syms[i]); - } - } - - if (!handled) { - /* Otherwise, we pass it along to the client. */ - wlr_seat_set_keyboard(seat, keyboard->device); - wlr_seat_keyboard_notify_key(seat, event->time_msec, - event->keycode, event->state); - } -} - -static void server_new_keyboard(struct wb_server *server, - struct wlr_input_device *device) { - struct wb_keyboard *keyboard = - calloc(1, sizeof(struct wb_keyboard)); - keyboard->server = server; - keyboard->device = device; - - /* We need to prepare an XKB keymap and assign it to the keyboard. This - * assumes the defaults (e.g. layout = "us"). */ - struct xkb_rule_names rules = { 0 }; - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, - XKB_KEYMAP_COMPILE_NO_FLAGS); - - wlr_keyboard_set_keymap(device->keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); - wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); - - /* Here we set up listeners for keyboard events. */ - keyboard->modifiers.notify = keyboard_handle_modifiers; - wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers); - keyboard->key.notify = keyboard_handle_key; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); - - wlr_seat_set_keyboard(server->seat->seat, device); - - /* And add the keyboard to our list of keyboards */ - wl_list_insert(&server->seat->keyboards, &keyboard->link); -} - -static void new_input_notify(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - struct wb_server *server = wl_container_of(listener, server, new_input); - switch (device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - server_new_keyboard(server, device); - break; - case WLR_INPUT_DEVICE_POINTER: - wlr_cursor_attach_input_device(server->cursor->cursor, device); - break; - default: - break; - } -} - bool init_wb(struct wb_server* server) { // create display @@ -169,8 +36,8 @@ bool start_wb(struct wb_server* server) { server->new_output.notify = new_output_notify; wl_signal_add(&server->backend->events.new_output, &server->new_output); - server->new_input.notify = new_input_notify; - wl_signal_add(&server->backend->events.new_input, &server->new_input); + //server->new_input.notify = new_input_notify; + //wl_signal_add(&server->backend->events.new_input, &server->new_input); const char *socket = wl_display_add_socket_auto(server->wl_display); assert(socket); From 874c844ce0c2ac41ffec84306a3445d1cdac2912 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Wed, 19 Feb 2020 18:43:39 -0500 Subject: [PATCH 09/20] Replaced the old mcwayface rendering code with tinywl's xdg_shell code, allowing it to compile with wlroots 0.9.0+ --- README.md | 5 -- include/waybox/output.h | 14 ++++ include/waybox/server.h | 16 ++++ include/waybox/xdg_shell.h | 3 + waybox/meson.build | 1 + waybox/output.c | 112 ++++++++++++++++++++++++--- waybox/server.c | 6 +- waybox/xdg_shell.c | 150 +++++++++++++++++++++++++++++++++++++ 8 files changed, 291 insertions(+), 16 deletions(-) create mode 100644 include/waybox/xdg_shell.h create mode 100644 waybox/xdg_shell.c diff --git a/README.md b/README.md index 6686135..614f1d7 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,6 @@ # waybox An openbox clone on Wayland (WIP) -This is the basic-apps branch, in which I'm working to get simple apps to work. -Currently, I'm targeting wlroots 0.6.0, but after I get the basic functionality -worked out, I want to get it to compile with wlroots 0.10.0. Right now, a -weston-terminal window will show, but it won't receive keyboard input. - ### Goals The main goal of this project is to provide a similar feel to openbox but on wayland diff --git a/include/waybox/output.h b/include/waybox/output.h index b68e240..0a14df8 100644 --- a/include/waybox/output.h +++ b/include/waybox/output.h @@ -28,6 +28,20 @@ struct wb_output { struct wl_list link; }; +struct wb_view { + struct wl_list link; + struct wb_server *server; + struct wlr_xdg_surface *xdg_surface; + + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener destroy; + struct wl_listener request_move; + struct wl_listener request_resize; + bool mapped; + int x, y; +}; + void output_frame_notify(struct wl_listener* listener, void *data); void output_destroy_notify(struct wl_listener* listener, void *data); void new_output_notify(struct wl_listener* listener, void *data); diff --git a/include/waybox/server.h b/include/waybox/server.h index 6636b74..72bd238 100644 --- a/include/waybox/server.h +++ b/include/waybox/server.h @@ -27,6 +27,12 @@ #include "waybox/cursor.h" #include "waybox/seat.h" +enum wb_cursor_mode { + WB_CURSOR_PASSTHROUGH, + WB_CURSOR_MOVE, + WB_CURSOR_RESIZE, +}; + struct wb_server { struct wl_display *wl_display; struct wl_event_loop *wl_event_loop; @@ -38,6 +44,16 @@ struct wb_server { struct wb_cursor *cursor; struct wb_seat * seat; + enum wb_cursor_mode cursor_mode; + struct wb_view *grabbed_view; + double grab_x, grab_y; + int grab_width, grab_height; + uint32_t resize_edges; + + struct wlr_xdg_shell *xdg_shell; + struct wl_listener new_xdg_surface; + struct wl_list views; + struct wl_listener new_output; struct wl_listener new_input; struct wl_list outputs; // wb_output::link diff --git a/include/waybox/xdg_shell.h b/include/waybox/xdg_shell.h new file mode 100644 index 0000000..a53c413 --- /dev/null +++ b/include/waybox/xdg_shell.h @@ -0,0 +1,3 @@ +#include "waybox/server.h" + +void init_xdg_shell(struct wb_server *server); diff --git a/waybox/meson.build b/waybox/meson.build index b341eb0..9a05460 100644 --- a/waybox/meson.build +++ b/waybox/meson.build @@ -4,6 +4,7 @@ wb_src = files( 'output.c', 'seat.c', 'server.c', + 'xdg_shell.c', ) wb_dep = [ diff --git a/waybox/output.c b/waybox/output.c index b8a4332..b728471 100644 --- a/waybox/output.c +++ b/waybox/output.c @@ -1,5 +1,74 @@ #include +struct render_data { + struct wlr_output *output; + struct wlr_renderer *renderer; + struct wb_view *view; + struct timespec *when; +}; + +static void render_surface(struct wlr_surface *surface, int sx, int sy, void *data) { + /* This function is called for every surface that needs to be rendered. */ + struct render_data *rdata = data; + struct wb_view *view = rdata->view; + struct wlr_output *output = rdata->output; + + /* We first obtain a wlr_texture, which is a GPU resource. wlroots + * automatically handles negotiating these with the client. The underlying + * resource could be an opaque handle passed from the client, or the client + * could have sent a pixel buffer which we copied to the GPU, or a few other + * means. You don't have to worry about this, wlroots takes care of it. */ + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (texture == NULL) { + return; + } + + /* The view has a position in layout coordinates. If you have two displays, + * one next to the other, both 1080p, a view on the rightmost display might + * have layout coordinates of 2000,100. We need to translate that to + * output-local coordinates, or (2000 - 1920). */ + double ox = 0, oy = 0; + wlr_output_layout_output_coords( + view->server->layout, output, &ox, &oy); + ox += view->x + sx, oy += view->y + sy; + + /* We also have to apply the scale factor for HiDPI outputs. This is only + * part of the puzzle, TinyWL does not fully support HiDPI. */ + struct wlr_box box = { + .x = ox * output->scale, + .y = oy * output->scale, + .width = surface->current.width * output->scale, + .height = surface->current.height * output->scale, + }; + + /* + * Those familiar with OpenGL are also familiar with the role of matricies + * in graphics programming. We need to prepare a matrix to render the view + * with. wlr_matrix_project_box is a helper which takes a box with a desired + * x, y coordinates, width and height, and an output geometry, then + * prepares an orthographic projection and multiplies the necessary + * transforms to produce a model-view-projection matrix. + * + * Naturally you can do this any way you like, for example to make a 3D + * compositor. + */ + float matrix[9]; + enum wl_output_transform transform = + wlr_output_transform_invert(surface->current.transform); + wlr_matrix_project_box(matrix, &box, transform, 0, + output->transform_matrix); + + /* This takes our matrix, the texture, and an alpha, and performs the actual + * rendering on the GPU. */ + wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1); + + /* This lets the client know that we've displayed that frame and it can + * prepare another one now if it likes. */ + wlr_surface_send_frame_done(surface, rdata->when); +} + + + void output_frame_notify(struct wl_listener *listener, void *data) { struct wb_output *output = wl_container_of(listener, output, frame); // struct wlr_backend *backend = output->server->backend; @@ -10,13 +79,34 @@ void output_frame_notify(struct wl_listener *listener, void *data) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - wlr_output_attach_render(wlr_output, NULL); - wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + if (!wlr_output_attach_render(wlr_output, NULL)) { + return; + } + int width, height; + wlr_output_effective_resolution(output->wlr_output, &width, &height); + wlr_renderer_begin(renderer, width, height); float color[4] = {0.4f, 0.4f, 0.4f, 1.0f}; wlr_renderer_clear(renderer, color); - struct wl_resource *_surface; + struct wb_view *view; + wl_list_for_each_reverse(view, &output->server->views, link) + { + if (!view->mapped) + /* An unmapped view should not be rendered */ + continue; + + struct render_data rdata = { + .output = output->wlr_output, + .renderer = renderer, + .view = view, + .when = &now, + }; + + wlr_xdg_surface_for_each_surface(view->xdg_surface, render_surface, &rdata); + } + + /*struct wl_resource *_surface; wl_resource_for_each(_surface, &output->server->compositor->surface_resources) { struct wlr_surface *surface = wlr_surface_from_resource(_surface); if (!wlr_surface_has_buffer(surface)) { @@ -33,10 +123,10 @@ void output_frame_notify(struct wl_listener *listener, void *data) { struct wlr_texture *texture = wlr_surface_get_texture(surface); wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f); wlr_surface_send_frame_done(surface, &now); - } + }*/ - wlr_output_commit(wlr_output); wlr_renderer_end(renderer); + wlr_output_commit(wlr_output); output->last_frame = now; } @@ -56,11 +146,14 @@ void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; if (!wl_list_empty(&wlr_output->modes)) { - struct wlr_output_mode *mode = - wl_container_of(wlr_output->modes.prev, mode, link); + struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); wlr_output_set_mode(wlr_output, mode); + wlr_output_enable(wlr_output, true); - wlr_output_create_global(wlr_output); + if (!wlr_output_commit(wlr_output)) { + return; + } + //wlr_output_create_global(wlr_output); } struct wb_output *output = calloc(1, sizeof(struct wb_output)); @@ -74,7 +167,8 @@ void new_output_notify(struct wl_listener *listener, void *data) { output->frame.notify = output_frame_notify; wl_signal_add(&wlr_output->events.frame, &output->frame); - wlr_output_layout_add_auto(server->layout, output->wlr_output); + wlr_output_layout_add_auto(server->layout, wlr_output); + wlr_output_create_global(wlr_output); wlr_xcursor_manager_load(server->cursor->xcursor_manager, output->wlr_output->scale); wlr_xcursor_manager_set_cursor_image(server->cursor->xcursor_manager, "left_ptr", server->cursor->cursor); } diff --git a/waybox/server.c b/waybox/server.c index 2d8a91a..5834d5b 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -1,5 +1,6 @@ -#include "waybox/server.h" #include "waybox/seat.h" +#include "waybox/xdg_shell.h" + bool init_wb(struct wb_server* server) { @@ -59,7 +60,8 @@ bool start_wb(struct wb_server* server) { server->compositor = wlr_compositor_create(server->wl_display, wlr_backend_get_renderer(server->backend)); wlr_data_device_manager_create(server->wl_display); - wlr_xdg_shell_create(server->wl_display); + wl_list_init(&server->views); + init_xdg_shell(server); //wlr_idle_create(server->wl_display); return true; diff --git a/waybox/xdg_shell.c b/waybox/xdg_shell.c new file mode 100644 index 0000000..c9a89fb --- /dev/null +++ b/waybox/xdg_shell.c @@ -0,0 +1,150 @@ +#include "waybox/xdg_shell.h" + +static void focus_view(struct wb_view *view, struct wlr_surface *surface) { + /* Note: this function only deals with keyboard focus. */ + if (view == NULL) { + return; + } + struct wb_server *server = view->server; + struct wlr_seat *seat = server->seat->seat; + struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface; + if (prev_surface == surface) { + /* Don't re-focus an already focused surface. */ + return; + } + if (prev_surface) { + /* + * Deactivate the previously focused surface. This lets the client know + * it no longer has focus and the client will repaint accordingly, e.g. + * stop displaying a caret. + */ + struct wlr_xdg_surface *previous = wlr_xdg_surface_from_wlr_surface( + seat->keyboard_state.focused_surface); + wlr_xdg_toplevel_set_activated(previous, false); + } + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat); + /* Move the view to the front */ + wl_list_remove(&view->link); + wl_list_insert(&server->views, &view->link); + /* Activate the new surface */ + wlr_xdg_toplevel_set_activated(view->xdg_surface, true); + /* + * Tell the seat to have the keyboard enter this surface. wlroots will keep + * track of this and automatically send key events to the appropriate + * clients without additional work on your part. + */ + wlr_seat_keyboard_notify_enter(seat, view->xdg_surface->surface, + keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); +} + +static void xdg_surface_map(struct wl_listener *listener, void *data) { + /* Called when the surface is mapped, or ready to display on-screen. */ + struct wb_view *view = wl_container_of(listener, view, map); + view->mapped = true; + focus_view(view, view->xdg_surface->surface); +} + +static void xdg_surface_unmap(struct wl_listener *listener, void *data) { + /* Called when the surface is unmapped, and should no longer be shown. */ + struct wb_view *view = wl_container_of(listener, view, unmap); + view->mapped = false; +} + +static void xdg_surface_destroy(struct wl_listener *listener, void *data) { + /* Called when the surface is destroyed and should never be shown again. */ + struct wb_view *view = wl_container_of(listener, view, destroy); + wl_list_remove(&view->link); + free(view); +} + +static void begin_interactive(struct wb_view *view, + enum wb_cursor_mode mode, uint32_t edges) { + /* This function sets up an interactive move or resize operation, where the + * compositor stops propegating pointer events to clients and instead + * consumes them itself, to move or resize windows. */ + struct wb_server *server = view->server; + struct wlr_surface *focused_surface = + server->seat->seat->pointer_state.focused_surface; + if (view->xdg_surface->surface != focused_surface) { + /* Deny move/resize requests from unfocused clients. */ + return; + } + server->grabbed_view = view; + server->cursor_mode = mode; + struct wlr_box geo_box; + wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box); + if (mode == WB_CURSOR_MOVE) { + server->grab_x = server->cursor->cursor->x - view->x; + server->grab_y = server->cursor->cursor->y - view->y; + } else { + server->grab_x = server->cursor->cursor->x + geo_box.x; + server->grab_y = server->cursor->cursor->y + geo_box.y; + } + server->grab_width = geo_box.width; + server->grab_height = geo_box.height; + server->resize_edges = edges; +} + +static void xdg_toplevel_request_move( + struct wl_listener *listener, void *data) { + /* This event is raised when a client would like to begin an interactive + * move, typically because the user clicked on their client-side + * decorations. Note that a more sophisticated compositor should check the + * provied serial against a list of button press serials sent to this + * client, to prevent the client from requesting this whenever they want. */ + struct wb_view *view = wl_container_of(listener, view, request_move); + begin_interactive(view, WB_CURSOR_MOVE, 0); +} + +static void xdg_toplevel_request_resize( + struct wl_listener *listener, void *data) { + /* This event is raised when a client would like to begin an interactive + * resize, typically because the user clicked on their client-side + * decorations. Note that a more sophisticated compositor should check the + * provied serial against a list of button press serials sent to this + * client, to prevent the client from requesting this whenever they want. */ + struct wlr_xdg_toplevel_resize_event *event = data; + struct wb_view *view = wl_container_of(listener, view, request_resize); + begin_interactive(view, WB_CURSOR_RESIZE, event->edges); +} + +static void server_new_xdg_surface(struct wl_listener *listener, void *data) { + /* This event is raised when wlr_xdg_shell receives a new xdg surface from a + * client, either a toplevel (application window) or popup. */ + struct wb_server *server = + wl_container_of(listener, server, new_xdg_surface); + struct wlr_xdg_surface *xdg_surface = data; + if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + /* Allocate a tinywl_view for this surface */ + struct wb_view *view = + calloc(1, sizeof(struct wb_view)); + view->server = server; + view->xdg_surface = xdg_surface; + + /* Listen to the various events it can emit */ + view->map.notify = xdg_surface_map; + wl_signal_add(&xdg_surface->events.map, &view->map); + view->unmap.notify = xdg_surface_unmap; + wl_signal_add(&xdg_surface->events.unmap, &view->unmap); + view->destroy.notify = xdg_surface_destroy; + wl_signal_add(&xdg_surface->events.destroy, &view->destroy); + + /* cotd */ + struct wlr_xdg_toplevel *toplevel = xdg_surface->toplevel; + view->request_move.notify = xdg_toplevel_request_move; + wl_signal_add(&toplevel->events.request_move, &view->request_move); + view->request_resize.notify = xdg_toplevel_request_resize; + wl_signal_add(&toplevel->events.request_resize, &view->request_resize); + + /* Add it to the list of views. */ + wl_list_insert(&server->views, &view->link); +} + +void init_xdg_shell(struct wb_server *server) { + server->xdg_shell = wlr_xdg_shell_create(server->wl_display); + server->new_xdg_surface.notify = server_new_xdg_surface; + wl_signal_add(&server->xdg_shell->events.new_surface, &server->new_xdg_surface); +} From 9f2ddc48efd6bb48546576dca7e9b5f20cc7d174 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Wed, 19 Feb 2020 22:48:30 -0500 Subject: [PATCH 10/20] Some more keyboard support: no keyboard capability with no keyboards, ctrl+esc and alt+tab for more Openbox-esque behavior --- include/waybox/xdg_shell.h | 1 + waybox/main.c | 4 ++-- waybox/seat.c | 36 ++++++++++++++++++------------------ waybox/xdg_shell.c | 2 +- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/include/waybox/xdg_shell.h b/include/waybox/xdg_shell.h index a53c413..b6660b0 100644 --- a/include/waybox/xdg_shell.h +++ b/include/waybox/xdg_shell.h @@ -1,3 +1,4 @@ #include "waybox/server.h" void init_xdg_shell(struct wb_server *server); +void focus_view(struct wb_view *view, struct wlr_surface *surface); diff --git a/waybox/main.c b/waybox/main.c index cb47e1f..3df99de 100644 --- a/waybox/main.c +++ b/waybox/main.c @@ -6,13 +6,13 @@ #include "waybox/server.h" -struct wl_display* display = NULL; +//struct wl_display* display = NULL; int main(int argc, char **argv){ struct wb_server server = {0}; // Global display - display = server.wl_display; + //display = server.wl_display; if (init_wb(&server) == false) { printf("Failed to create backend\n"); diff --git a/waybox/seat.c b/waybox/seat.c index 91e0e26..58a96a0 100644 --- a/waybox/seat.c +++ b/waybox/seat.c @@ -1,9 +1,8 @@ -#include - #include "waybox/seat.h" +#include "waybox/xdg_shell.h" /* Stolen from wltiny. Customizations will come later. */ -static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym) { +static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32_t modifiers) { /* * Here we handle compositor keybindings. This is when the compositor is * processing keys, rather than passing them on to the client for its own @@ -11,29 +10,25 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym) { * * This function assumes Alt is held down. */ - switch (sym) { - case XKB_KEY_Escape: + + if (modifiers & WLR_MODIFIER_CTRL && sym == XKB_KEY_Escape) { wl_display_terminate(server->wl_display); - break; - case XKB_KEY_F1: -#if 0 + } + else if (modifiers & WLR_MODIFIER_ALT && sym == XKB_KEY_Tab) { /* Cycle to the next view */ if (wl_list_length(&server->views) < 2) { - break; + return false; } - struct tinywl_view *current_view = wl_container_of( + struct wb_view *current_view = wl_container_of( server->views.next, current_view, link); - struct tinywl_view *next_view = wl_container_of( + struct wb_view *next_view = wl_container_of( current_view->link.next, next_view, link); focus_view(next_view, next_view->xdg_surface->surface); /* Move the previous view to the end of the list */ wl_list_remove(¤t_view->link); wl_list_insert(server->views.prev, ¤t_view->link); -#endif - break; - default: - return false; } + else return false; return true; } @@ -73,11 +68,11 @@ static void keyboard_handle_key( bool handled = false; uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); - if ((modifiers & WLR_MODIFIER_ALT) && event->state == WLR_KEY_PRESSED) { + if (event->state == WLR_KEY_PRESSED) { /* If alt is held down and this button was _pressed_, we attempt to * process it as a compositor keybinding. */ for (int i = 0; i < nsyms; i++) { - handled = handle_keybinding(server, syms[i]); + handled = handle_keybinding(server, syms[i], modifiers); } } @@ -133,6 +128,12 @@ static void new_input_notify(struct wl_listener *listener, void *data) { default: break; } + + uint32_t caps = WL_SEAT_CAPABILITY_POINTER; + if (!wl_list_empty(&server->seat->keyboards)) { + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + } + wlr_seat_set_capabilities(server->seat->seat, caps); } struct wb_seat * wb_seat_create(struct wb_server * server) { @@ -142,7 +143,6 @@ struct wb_seat * wb_seat_create(struct wb_server * server) { server->new_input.notify = new_input_notify; wl_signal_add(&server->backend->events.new_input, &server->new_input); seat->seat = wlr_seat_create(server->wl_display, "seat0"); - wlr_seat_set_capabilities(seat->seat, WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD); return seat; } diff --git a/waybox/xdg_shell.c b/waybox/xdg_shell.c index c9a89fb..026a22a 100644 --- a/waybox/xdg_shell.c +++ b/waybox/xdg_shell.c @@ -1,6 +1,6 @@ #include "waybox/xdg_shell.h" -static void focus_view(struct wb_view *view, struct wlr_surface *surface) { +void focus_view(struct wb_view *view, struct wlr_surface *surface) { /* Note: this function only deals with keyboard focus. */ if (view == NULL) { return; From 75706982241334ce8f68ca828189dbb2076d6e70 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Thu, 20 Feb 2020 08:50:08 -0500 Subject: [PATCH 11/20] Implemented Openbox-compatible command-line options; hard-coded Alt+F2 to an application launcher; indicated the real purpose of WL_HIDE_DEPRECATED --- include/waybox/server.h | 6 +++--- meson.build | 3 ++- waybox/main.c | 34 ++++++++++++++++++++++++++++++++-- waybox/seat.c | 8 ++++++++ waybox/server.c | 5 +++-- 5 files changed, 48 insertions(+), 8 deletions(-) diff --git a/include/waybox/server.h b/include/waybox/server.h index 72bd238..b170bdc 100644 --- a/include/waybox/server.h +++ b/include/waybox/server.h @@ -1,9 +1,9 @@ #ifndef SERVER_H #define SERVER_H -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L -#endif +//#ifndef _POSIX_C_SOURCE +//#define _POSIX_C_SOURCE 200809L +//#endif #include #include diff --git a/meson.build b/meson.build index 9620f30..f5414ad 100644 --- a/meson.build +++ b/meson.build @@ -15,6 +15,7 @@ project( add_project_arguments('-Wno-unused-parameter', language: 'c') add_project_arguments('-DWLR_USE_UNSTABLE', language: 'c') +add_project_arguments('-DVERSION="' + meson.project_version() + '"', language: 'c') cc = meson.get_compiler('c') @@ -23,7 +24,7 @@ if cc.get_id() == 'clang' add_project_arguments('-Wno-missing-braces', language: 'c') endif -# Hiding depreciation warnings +# Hide deprecated API add_project_arguments('-DWL_HIDE_DEPRECATED', language: 'c') # Adding include directory diff --git a/waybox/main.c b/waybox/main.c index 3df99de..f53eab3 100644 --- a/waybox/main.c +++ b/waybox/main.c @@ -1,6 +1,8 @@ -#define _POSIX_C_SOURCE 200809L +//#define _POSIX_C_SOURCE 200809L #include -#include +//#include +#include +#include #include #include @@ -9,6 +11,28 @@ //struct wl_display* display = NULL; int main(int argc, char **argv){ + char *startup_cmd; + if (argc > 0) { + int i; + for (i = 0; i < argc; i++) + { + if (!strcmp("--debug", argv[i]) || !strcmp("-v", argv[i]) || !strcmp("--exit", argv[i])) { + printf("Warning: option %s is currently unimplemented\n", argv[i]); + } + else if ((!strcmp("--startup", argv[i]) || !strcmp("-s", argv[i])) && i < argc) { + startup_cmd = argv[i + 1]; + } + else if (!strcmp("--version", argv[i]) || !strcmp("-V", argv[i])) { + printf(VERSION "\n"); + return 0; + } + else if (argv[i][0] == '-') { + printf("Usage: %s [--debug] [--exit] [--help] [--startup CMD] [--version]\n", argv[0]); + return strcmp("--help", argv[i]) != 0 && strcmp("-h", argv[i]) != 0; + } + } + } + struct wb_server server = {0}; // Global display @@ -25,6 +49,12 @@ int main(int argc, char **argv){ exit(EXIT_FAILURE); } + if (startup_cmd) { + if (fork() == 0){ + execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); + } + } + wl_display_run(server.wl_display); terminate_wb(&server); diff --git a/waybox/seat.c b/waybox/seat.c index 58a96a0..7655db0 100644 --- a/waybox/seat.c +++ b/waybox/seat.c @@ -1,3 +1,5 @@ +#include + #include "waybox/seat.h" #include "waybox/xdg_shell.h" @@ -28,6 +30,12 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32 wl_list_remove(¤t_view->link); wl_list_insert(server->views.prev, ¤t_view->link); } + else if (modifiers & WLR_MODIFIER_ALT && sym == XKB_KEY_F2) + { + if (fork() == 0) { + execl("/bin/sh", "/bin/sh", "-c", "(obrun || bemenu-run || synapse || gmrun || gnome-do || dmenu_run) 2>/dev/null", NULL); + } + } else return false; return true; } diff --git a/waybox/server.c b/waybox/server.c index 5834d5b..d7e5b0a 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200112L #include "waybox/seat.h" #include "waybox/xdg_shell.h" @@ -49,8 +50,8 @@ bool start_wb(struct wb_server* server) { return false; } - //printf("Running Wayland compositor on Wayland display '%s'\n", socket); - //setenv("WAYLAND_DISPLAY", socket, true); + printf("Running Wayland compositor on Wayland display '%s'\n", socket); + setenv("WAYLAND_DISPLAY", socket, true); wlr_gamma_control_manager_v1_create(server->wl_display); wlr_screencopy_manager_v1_create(server->wl_display); From 719119137746f4bd68837439e2ac3d0ea2c29246 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Thu, 20 Feb 2020 09:04:56 -0500 Subject: [PATCH 12/20] Let setting the keyboard layout through the XKB_DEFAULT_* environment variables --- waybox/seat.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/waybox/seat.c b/waybox/seat.c index 7655db0..1928fb2 100644 --- a/waybox/seat.c +++ b/waybox/seat.c @@ -99,9 +99,14 @@ static void server_new_keyboard(struct wb_server *server, keyboard->server = server; keyboard->device = device; - /* We need to prepare an XKB keymap and assign it to the keyboard. This - * assumes the defaults (e.g. layout = "us"). */ - struct xkb_rule_names rules = { 0 }; + /* We need to prepare an XKB keymap and assign it to the keyboard. */ + struct xkb_rule_names rules = { + .rules = getenv("XKB_DEFAULT_RULES"), + .model = getenv("XKB_DEFAULT_MODEL"), + .layout = getenv("XKB_DEFAULT_LAYOUT"), + .variant = getenv("XKB_DEFAULT_VARIANT"), + .options = getenv("XKB_DEFAULT_OPTIONS"), + }; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); From 0bb5787a108914513ab97d3c08a035e12ed8b9e6 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Thu, 20 Feb 2020 10:18:25 -0500 Subject: [PATCH 13/20] Focus previous view on close --- waybox/xdg_shell.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/waybox/xdg_shell.c b/waybox/xdg_shell.c index 026a22a..ac77ca6 100644 --- a/waybox/xdg_shell.c +++ b/waybox/xdg_shell.c @@ -48,6 +48,11 @@ static void xdg_surface_unmap(struct wl_listener *listener, void *data) { /* Called when the surface is unmapped, and should no longer be shown. */ struct wb_view *view = wl_container_of(listener, view, unmap); view->mapped = false; + + /* Focus previous view's surface, if any */ + if (view->server->views.prev) { + focus_view((struct wb_view *) view->server->views.prev, ((struct wb_view *) view->server->views.prev)->xdg_surface->surface); + } } static void xdg_surface_destroy(struct wl_listener *listener, void *data) { From 43fcf1ebf1d1043f2e4f564d63820a5b66242c82 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Fri, 21 Feb 2020 16:49:29 -0500 Subject: [PATCH 14/20] Mouse support --- include/waybox/cursor.h | 8 ++ include/waybox/xdg_shell.h | 3 + waybox/cursor.c | 150 +++++++++++++++++++++++++++++++++++++ waybox/server.c | 1 + waybox/xdg_shell.c | 44 +++++++++++ 5 files changed, 206 insertions(+) diff --git a/include/waybox/cursor.h b/include/waybox/cursor.h index 370c8b5..37fb191 100644 --- a/include/waybox/cursor.h +++ b/include/waybox/cursor.h @@ -4,12 +4,20 @@ #include #include +#include "waybox/server.h" + struct wb_cursor { struct wlr_cursor *cursor; struct wlr_xcursor_manager *xcursor_manager; + struct wb_server *server; + struct wl_listener cursor_motion; struct wl_listener cursor_motion_absolute; + + struct wl_listener cursor_button; + struct wl_listener cursor_axis; + struct wl_listener cursor_frame; }; struct wb_cursor *wb_cursor_create(); diff --git a/include/waybox/xdg_shell.h b/include/waybox/xdg_shell.h index b6660b0..08833bb 100644 --- a/include/waybox/xdg_shell.h +++ b/include/waybox/xdg_shell.h @@ -2,3 +2,6 @@ void init_xdg_shell(struct wb_server *server); void focus_view(struct wb_view *view, struct wlr_surface *surface); +struct wb_view *desktop_view_at( + struct wb_server *server, double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy); diff --git a/waybox/cursor.c b/waybox/cursor.c index fb769a4..f582817 100644 --- a/waybox/cursor.c +++ b/waybox/cursor.c @@ -1,16 +1,157 @@ #include #include "waybox/cursor.h" +#include "waybox/xdg_shell.h" + +static void process_cursor_move(struct wb_server *server, uint32_t time) { + /* Move the grabbed view to the new position. */ + server->grabbed_view->x = server->cursor->cursor->x - server->grab_x; + server->grabbed_view->y = server->cursor->cursor->y - server->grab_y; +} + +static void process_cursor_resize(struct wb_server *server, uint32_t time) { + /* + * Resizing the grabbed view can be a little bit complicated, because we + * could be resizing from any corner or edge. This not only resizes the view + * on one or two axes, but can also move the view if you resize from the top + * or left edges (or top-left corner). + * + * Note that I took some shortcuts here. In a more fleshed-out compositor, + * you'd wait for the client to prepare a buffer at the new size, then + * commit any movement that was prepared. + */ + struct wb_view *view = server->grabbed_view; + double dx = server->cursor->cursor->x - server->grab_x; + double dy = server->cursor->cursor->y - server->grab_y; + double x = view->x; + double y = view->y; + int width = server->grab_width; + int height = server->grab_height; + if (server->resize_edges & WLR_EDGE_TOP) { + y = server->grab_y + dy; + height -= dy; + if (height < 1) { + y += height; + } + } else if (server->resize_edges & WLR_EDGE_BOTTOM) { + height += dy; + } + if (server->resize_edges & WLR_EDGE_LEFT) { + x = server->grab_x + dx; + width -= dx; + if (width < 1) { + x += width; + } + } else if (server->resize_edges & WLR_EDGE_RIGHT) { + width += dx; + } + view->x = x; + view->y = y; + wlr_xdg_toplevel_set_size(view->xdg_surface, width, height); +} + +static void process_cursor_motion(struct wb_server *server, uint32_t time) { + /* If the mode is non-passthrough, delegate to those functions. */ + if (server->cursor_mode == WB_CURSOR_MOVE) { + process_cursor_move(server, time); + return; + } else if (server->cursor_mode == WB_CURSOR_RESIZE) { + process_cursor_resize(server, time); + return; + } + + /* Otherwise, find the view under the pointer and send the event along. */ + double sx, sy; + struct wlr_seat *seat = server->seat->seat; + struct wlr_surface *surface = NULL; + struct wb_view *view = desktop_view_at(server, + server->cursor->cursor->x, server->cursor->cursor->y, &surface, &sx, &sy); + if (!view) { + /* If there's no view under the cursor, set the cursor image to a + * default. This is what makes the cursor image appear when you move it + * around the screen, not over any views. */ + wlr_xcursor_manager_set_cursor_image( + server->cursor->xcursor_manager, "left_ptr", server->cursor->cursor); + } + if (surface) { + bool focus_changed = seat->pointer_state.focused_surface != surface; + /* + * "Enter" the surface if necessary. This lets the client know that the + * cursor has entered one of its surfaces. + * + * Note that this gives the surface "pointer focus", which is distinct + * from keyboard focus. You get pointer focus by moving the pointer over + * a window. + */ + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + if (!focus_changed) { + /* The enter event contains coordinates, so we only need to notify + * on motion if the focus did not change. */ + wlr_seat_pointer_notify_motion(seat, time, sx, sy); + } + } else { + /* Clear pointer focus so future button events and such are not sent to + * the last client to have the cursor over it. */ + wlr_seat_pointer_clear_focus(seat); + } +} static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct wb_cursor *cursor = wl_container_of(listener, cursor, cursor_motion); struct wlr_event_pointer_motion *event = data; wlr_cursor_move(cursor->cursor, event->device, event->delta_x, event->delta_y); + process_cursor_motion(cursor->server, event->time_msec); } static void handle_cursor_motion_absolute(struct wl_listener *listener, void *data) { struct wb_cursor *cursor = wl_container_of(listener, cursor, cursor_motion_absolute); struct wlr_event_pointer_motion_absolute *event = data; wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); + process_cursor_motion(cursor->server, event->time_msec); +} + +static void handle_cursor_button(struct wl_listener *listener, void *data) { + /* This event is forwarded by the cursor when a pointer emits a button + * event. */ + struct wb_cursor *cursor = + wl_container_of(listener, cursor, cursor_button); + struct wlr_event_pointer_button *event = data; + /* Notify the client with pointer focus that a button press has occurred */ + wlr_seat_pointer_notify_button(cursor->server->seat->seat, + event->time_msec, event->button, event->state); + double sx, sy; + struct wlr_surface *surface; + struct wb_view *view = desktop_view_at(cursor->server, + cursor->server->cursor->cursor->x, cursor->server->cursor->cursor->y, &surface, &sx, &sy); + if (event->state == WLR_BUTTON_RELEASED) { + /* If you released any buttons, we exit interactive move/resize mode. */ + cursor->server->cursor_mode = WB_CURSOR_PASSTHROUGH; + } else { + /* Focus that client if the button was _pressed_ */ + focus_view(view, surface); + } +} + +static void handle_cursor_axis(struct wl_listener *listener, void *data) { + /* This event is forwarded by the cursor when a pointer emits an axis event, + * for example when you move the scroll wheel. */ + struct wb_cursor *cursor = + wl_container_of(listener, cursor, cursor_axis); + struct wlr_event_pointer_axis *event = data; + /* Notify the client with pointer focus of the axis event. */ + wlr_seat_pointer_notify_axis(cursor->server->seat->seat, + event->time_msec, event->orientation, event->delta, + event->delta_discrete, event->source); +} + +static void handle_cursor_frame(struct wl_listener *listener, void *data) { + /* This event is forwarded by the cursor when a pointer emits an frame + * event. Frame events are sent after regular pointer events to group + * multiple events together. For instance, two axis events may happen at the + * same time, in which case a frame event won't be sent in between. */ + struct wb_cursor *cursor = + wl_container_of(listener, cursor, cursor_frame); + /* Notify the client with pointer focus of the frame event. */ + wlr_seat_pointer_notify_frame(cursor->server->seat->seat); } struct wb_cursor *wb_cursor_create() { @@ -24,6 +165,15 @@ struct wb_cursor *wb_cursor_create() { cursor->cursor_motion_absolute.notify = handle_cursor_motion_absolute; wl_signal_add(&cursor->cursor->events.motion_absolute, &cursor->cursor_motion_absolute); + cursor->cursor_button.notify = handle_cursor_button; + wl_signal_add(&cursor->cursor->events.button, &cursor->cursor_button); + + cursor->cursor_axis.notify = handle_cursor_axis; + wl_signal_add(&cursor->cursor->events.axis, &cursor->cursor_axis); + + cursor->cursor_frame.notify = handle_cursor_frame; + wl_signal_add(&cursor->cursor->events.frame, &cursor->cursor_frame); + return cursor; } diff --git a/waybox/server.c b/waybox/server.c index d7e5b0a..bf1c846 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -26,6 +26,7 @@ bool init_wb(struct wb_server* server) { server->layout = wlr_output_layout_create(); server->cursor = wb_cursor_create(); + server->cursor->server = server; wlr_cursor_attach_output_layout(server->cursor->cursor, server->layout); server->seat = wb_seat_create(server); diff --git a/waybox/xdg_shell.c b/waybox/xdg_shell.c index ac77ca6..0d7618d 100644 --- a/waybox/xdg_shell.c +++ b/waybox/xdg_shell.c @@ -148,6 +148,50 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { wl_list_insert(&server->views, &view->link); } +bool view_at(struct wb_view *view, + double lx, double ly, struct wlr_surface **surface, + double *sx, double *sy) { + /* + * XDG toplevels may have nested surfaces, such as popup windows for context + * menus or tooltips. This function tests if any of those are underneath the + * coordinates lx and ly (in output Layout Coordinates). If so, it sets the + * surface pointer to that wlr_surface and the sx and sy coordinates to the + * coordinates relative to that surface's top-left corner. + */ + double view_sx = lx - view->x; + double view_sy = ly - view->y; + + //struct wlr_surface_state *state = &view->xdg_surface->surface->current; + + double _sx, _sy; + struct wlr_surface *_surface = NULL; + _surface = wlr_xdg_surface_surface_at( + view->xdg_surface, view_sx, view_sy, &_sx, &_sy); + + if (_surface != NULL) { + *sx = _sx; + *sy = _sy; + *surface = _surface; + return true; + } + + return false; +} + +struct wb_view *desktop_view_at( + struct wb_server *server, double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy) { + /* This iterates over all of our surfaces and attempts to find one under the + * cursor. This relies on server->views being ordered from top-to-bottom. */ + struct wb_view *view; + wl_list_for_each(view, &server->views, link) { + if (view_at(view, lx, ly, surface, sx, sy)) { + return view; + } + } + return NULL; +} + void init_xdg_shell(struct wb_server *server) { server->xdg_shell = wlr_xdg_shell_create(server->wl_display); server->new_xdg_surface.notify = server_new_xdg_surface; From 8bc4352eb81b251be3e5d6825c9d579ae379f467 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Sat, 22 Feb 2020 07:13:43 -0500 Subject: [PATCH 15/20] Cleanup --- include/waybox/cursor.h | 7 ++++++ include/waybox/seat.h | 10 ++++---- include/waybox/server.h | 19 +++++---------- waybox/cursor.c | 21 ++++------------- waybox/main.c | 12 ++-------- waybox/output.c | 31 +++--------------------- waybox/seat.c | 13 ++++------- waybox/server.c | 52 ++++++++++++++++++----------------------- waybox/xdg_shell.c | 21 ++++++----------- 9 files changed, 62 insertions(+), 124 deletions(-) diff --git a/include/waybox/cursor.h b/include/waybox/cursor.h index 37fb191..5ba3838 100644 --- a/include/waybox/cursor.h +++ b/include/waybox/cursor.h @@ -6,12 +6,19 @@ #include "waybox/server.h" +enum wb_cursor_mode { + WB_CURSOR_PASSTHROUGH, + WB_CURSOR_MOVE, + WB_CURSOR_RESIZE, +}; + struct wb_cursor { struct wlr_cursor *cursor; struct wlr_xcursor_manager *xcursor_manager; struct wb_server *server; + enum wb_cursor_mode cursor_mode; struct wl_listener cursor_motion; struct wl_listener cursor_motion_absolute; diff --git a/include/waybox/seat.h b/include/waybox/seat.h index 014cee0..a348846 100644 --- a/include/waybox/seat.h +++ b/include/waybox/seat.h @@ -7,21 +7,21 @@ #include "waybox/server.h" struct wb_seat { - struct wlr_seat * seat; + struct wlr_seat *seat; struct wl_list keyboards; }; struct wb_keyboard { struct wl_list link; - struct wb_server * server; - struct wlr_input_device * device; + struct wb_server *server; + struct wlr_input_device *device; struct wl_listener modifiers; struct wl_listener key; }; struct wb_server; -struct wb_seat * wb_seat_create(struct wb_server * server); -void wb_seat_destroy(struct wb_seat * seat); +struct wb_seat *wb_seat_create(struct wb_server *server); +void wb_seat_destroy(struct wb_seat *seat); #endif diff --git a/include/waybox/server.h b/include/waybox/server.h index b170bdc..7636207 100644 --- a/include/waybox/server.h +++ b/include/waybox/server.h @@ -1,14 +1,13 @@ #ifndef SERVER_H #define SERVER_H -//#ifndef _POSIX_C_SOURCE -//#define _POSIX_C_SOURCE 200809L -//#endif +#ifdef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif +#define _POSIX_C_SOURCE 200112L #include #include -#include -#include #include #include @@ -27,24 +26,18 @@ #include "waybox/cursor.h" #include "waybox/seat.h" -enum wb_cursor_mode { - WB_CURSOR_PASSTHROUGH, - WB_CURSOR_MOVE, - WB_CURSOR_RESIZE, -}; - struct wb_server { struct wl_display *wl_display; struct wl_event_loop *wl_event_loop; struct wlr_backend *backend; struct wlr_compositor *compositor; + struct wlr_renderer *renderer; struct wlr_output_layout *layout; struct wb_cursor *cursor; - struct wb_seat * seat; + struct wb_seat *seat; - enum wb_cursor_mode cursor_mode; struct wb_view *grabbed_view; double grab_x, grab_y; int grab_width, grab_height; diff --git a/waybox/cursor.c b/waybox/cursor.c index f582817..2e6520b 100644 --- a/waybox/cursor.c +++ b/waybox/cursor.c @@ -9,16 +9,6 @@ static void process_cursor_move(struct wb_server *server, uint32_t time) { } static void process_cursor_resize(struct wb_server *server, uint32_t time) { - /* - * Resizing the grabbed view can be a little bit complicated, because we - * could be resizing from any corner or edge. This not only resizes the view - * on one or two axes, but can also move the view if you resize from the top - * or left edges (or top-left corner). - * - * Note that I took some shortcuts here. In a more fleshed-out compositor, - * you'd wait for the client to prepare a buffer at the new size, then - * commit any movement that was prepared. - */ struct wb_view *view = server->grabbed_view; double dx = server->cursor->cursor->x - server->grab_x; double dy = server->cursor->cursor->y - server->grab_y; @@ -51,10 +41,10 @@ static void process_cursor_resize(struct wb_server *server, uint32_t time) { static void process_cursor_motion(struct wb_server *server, uint32_t time) { /* If the mode is non-passthrough, delegate to those functions. */ - if (server->cursor_mode == WB_CURSOR_MOVE) { + if (server->cursor->cursor_mode == WB_CURSOR_MOVE) { process_cursor_move(server, time); return; - } else if (server->cursor_mode == WB_CURSOR_RESIZE) { + } else if (server->cursor->cursor_mode == WB_CURSOR_RESIZE) { process_cursor_resize(server, time); return; } @@ -77,10 +67,6 @@ static void process_cursor_motion(struct wb_server *server, uint32_t time) { /* * "Enter" the surface if necessary. This lets the client know that the * cursor has entered one of its surfaces. - * - * Note that this gives the surface "pointer focus", which is distinct - * from keyboard focus. You get pointer focus by moving the pointer over - * a window. */ wlr_seat_pointer_notify_enter(seat, surface, sx, sy); if (!focus_changed) { @@ -124,7 +110,7 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { cursor->server->cursor->cursor->x, cursor->server->cursor->cursor->y, &surface, &sx, &sy); if (event->state == WLR_BUTTON_RELEASED) { /* If you released any buttons, we exit interactive move/resize mode. */ - cursor->server->cursor_mode = WB_CURSOR_PASSTHROUGH; + cursor->cursor_mode = WB_CURSOR_PASSTHROUGH; } else { /* Focus that client if the button was _pressed_ */ focus_view(view, surface); @@ -158,6 +144,7 @@ struct wb_cursor *wb_cursor_create() { struct wb_cursor *cursor = malloc(sizeof(struct wb_cursor)); cursor->cursor = wlr_cursor_create(); cursor->xcursor_manager = wlr_xcursor_manager_create("default", 24); + wlr_xcursor_manager_load(cursor->xcursor_manager, 1); cursor->cursor_motion.notify = handle_cursor_motion; wl_signal_add(&cursor->cursor->events.motion, &cursor->cursor_motion); diff --git a/waybox/main.c b/waybox/main.c index f53eab3..11f17dc 100644 --- a/waybox/main.c +++ b/waybox/main.c @@ -1,17 +1,12 @@ -//#define _POSIX_C_SOURCE 200809L #include -//#include #include #include #include -#include #include "waybox/server.h" -//struct wl_display* display = NULL; - int main(int argc, char **argv){ - char *startup_cmd; + char *startup_cmd = NULL; if (argc > 0) { int i; for (i = 0; i < argc; i++) @@ -35,9 +30,6 @@ int main(int argc, char **argv){ struct wb_server server = {0}; - // Global display - //display = server.wl_display; - if (init_wb(&server) == false) { printf("Failed to create backend\n"); exit(EXIT_FAILURE); @@ -50,7 +42,7 @@ int main(int argc, char **argv){ } if (startup_cmd) { - if (fork() == 0){ + if (fork() == 0) { execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); } } diff --git a/waybox/output.c b/waybox/output.c index b728471..ba71280 100644 --- a/waybox/output.c +++ b/waybox/output.c @@ -1,4 +1,4 @@ -#include +#include "waybox/output.h" struct render_data { struct wlr_output *output; @@ -33,7 +33,7 @@ static void render_surface(struct wlr_surface *surface, int sx, int sy, void *da ox += view->x + sx, oy += view->y + sy; /* We also have to apply the scale factor for HiDPI outputs. This is only - * part of the puzzle, TinyWL does not fully support HiDPI. */ + * part of the puzzle, Waybox does not fully support HiDPI. */ struct wlr_box box = { .x = ox * output->scale, .y = oy * output->scale, @@ -42,7 +42,7 @@ static void render_surface(struct wlr_surface *surface, int sx, int sy, void *da }; /* - * Those familiar with OpenGL are also familiar with the role of matricies + * Those familiar with OpenGL are also familiar with the role of matrices * in graphics programming. We need to prepare a matrix to render the view * with. wlr_matrix_project_box is a helper which takes a box with a desired * x, y coordinates, width and height, and an output geometry, then @@ -67,11 +67,8 @@ static void render_surface(struct wlr_surface *surface, int sx, int sy, void *da wlr_surface_send_frame_done(surface, rdata->when); } - - void output_frame_notify(struct wl_listener *listener, void *data) { struct wb_output *output = wl_container_of(listener, output, frame); -// struct wlr_backend *backend = output->server->backend; struct wlr_output *wlr_output = data; struct wlr_renderer *renderer = wlr_backend_get_renderer( wlr_output->backend); @@ -106,25 +103,6 @@ void output_frame_notify(struct wl_listener *listener, void *data) { wlr_xdg_surface_for_each_surface(view->xdg_surface, render_surface, &rdata); } - /*struct wl_resource *_surface; - wl_resource_for_each(_surface, &output->server->compositor->surface_resources) { - struct wlr_surface *surface = wlr_surface_from_resource(_surface); - if (!wlr_surface_has_buffer(surface)) { - continue; - } - struct wlr_box render_box = { - .x = 20, .y = 20, - .width = surface->current.width, - .height = surface->current.height - }; - float matrix[16]; - wlr_matrix_project_box(matrix, &render_box, surface->current.transform, - 0, wlr_output->transform_matrix); - struct wlr_texture *texture = wlr_surface_get_texture(surface); - wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f); - wlr_surface_send_frame_done(surface, &now); - }*/ - wlr_renderer_end(renderer); wlr_output_commit(wlr_output); output->last_frame = now; @@ -153,7 +131,6 @@ void new_output_notify(struct wl_listener *listener, void *data) { if (!wlr_output_commit(wlr_output)) { return; } - //wlr_output_create_global(wlr_output); } struct wb_output *output = calloc(1, sizeof(struct wb_output)); @@ -169,6 +146,4 @@ void new_output_notify(struct wl_listener *listener, void *data) { wlr_output_layout_add_auto(server->layout, wlr_output); wlr_output_create_global(wlr_output); - wlr_xcursor_manager_load(server->cursor->xcursor_manager, output->wlr_output->scale); - wlr_xcursor_manager_set_cursor_image(server->cursor->xcursor_manager, "left_ptr", server->cursor->cursor); } diff --git a/waybox/seat.c b/waybox/seat.c index 1928fb2..18672e0 100644 --- a/waybox/seat.c +++ b/waybox/seat.c @@ -3,14 +3,11 @@ #include "waybox/seat.h" #include "waybox/xdg_shell.h" -/* Stolen from wltiny. Customizations will come later. */ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32_t modifiers) { /* * Here we handle compositor keybindings. This is when the compositor is * processing keys, rather than passing them on to the client for its own * processing. - * - * This function assumes Alt is held down. */ if (modifiers & WLR_MODIFIER_CTRL && sym == XKB_KEY_Escape) { @@ -92,7 +89,7 @@ static void keyboard_handle_key( } } -static void server_new_keyboard(struct wb_server *server, +static void handle_new_keyboard(struct wb_server *server, struct wlr_input_device *device) { struct wb_keyboard *keyboard = calloc(1, sizeof(struct wb_keyboard)); @@ -133,7 +130,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) { struct wb_server *server = wl_container_of(listener, server, new_input); switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: - server_new_keyboard(server, device); + handle_new_keyboard(server, device); break; case WLR_INPUT_DEVICE_POINTER: wlr_cursor_attach_input_device(server->cursor->cursor, device); @@ -149,8 +146,8 @@ static void new_input_notify(struct wl_listener *listener, void *data) { wlr_seat_set_capabilities(server->seat->seat, caps); } -struct wb_seat * wb_seat_create(struct wb_server * server) { - struct wb_seat * seat = malloc(sizeof(struct wb_seat)); +struct wb_seat *wb_seat_create(struct wb_server *server) { + struct wb_seat *seat = malloc(sizeof(struct wb_seat)); wl_list_init(&seat->keyboards); server->new_input.notify = new_input_notify; @@ -160,7 +157,7 @@ struct wb_seat * wb_seat_create(struct wb_server * server) { return seat; } -void wb_seat_destroy(struct wb_seat * seat) { +void wb_seat_destroy(struct wb_seat *seat) { wlr_seat_destroy(seat->seat); free(seat); } diff --git a/waybox/server.c b/waybox/server.c index bf1c846..5f089e6 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -1,28 +1,26 @@ -#define _POSIX_C_SOURCE 200112L -#include "waybox/seat.h" +#include "waybox/server.h" #include "waybox/xdg_shell.h" - bool init_wb(struct wb_server* server) { - // create display - server->wl_display = wl_display_create(); + // create display + server->wl_display = wl_display_create(); assert(server->wl_display); - // create shared memory - wl_display_init_shm(server->wl_display); - - // event loop stuff - server->wl_event_loop = wl_display_get_event_loop(server->wl_display); + // event loop stuff + server->wl_event_loop = wl_display_get_event_loop(server->wl_display); assert(server->wl_event_loop); - // create backend + // create backend server->backend = wlr_backend_autocreate(server->wl_display, NULL); assert(server->backend); - if(server->backend == NULL){ - printf("Failed to create backend\n"); - return false; - } + if (server->backend == NULL) { + printf("Failed to create backend\n"); + return false; + } + + server->renderer = wlr_backend_get_renderer(server->backend); + wlr_renderer_init_wl_display(server->renderer, server->wl_display); server->layout = wlr_output_layout_create(); server->cursor = wb_cursor_create(); @@ -30,52 +28,48 @@ bool init_wb(struct wb_server* server) { wlr_cursor_attach_output_layout(server->cursor->cursor, server->layout); server->seat = wb_seat_create(server); - return true; + return true; } bool start_wb(struct wb_server* server) { - wl_list_init(&server->outputs); + wl_list_init(&server->outputs); server->new_output.notify = new_output_notify; wl_signal_add(&server->backend->events.new_output, &server->new_output); - //server->new_input.notify = new_input_notify; - //wl_signal_add(&server->backend->events.new_input, &server->new_input); - const char *socket = wl_display_add_socket_auto(server->wl_display); assert(socket); - if (!wlr_backend_start(server->backend)) { + if (!wlr_backend_start(server->backend)) { fprintf(stderr, "Failed to start backend\n"); wl_display_destroy(server->wl_display); return false; } - printf("Running Wayland compositor on Wayland display '%s'\n", socket); - setenv("WAYLAND_DISPLAY", socket, true); + printf("Running Wayland compositor on Wayland display '%s'\n", socket); + setenv("WAYLAND_DISPLAY", socket, true); - wlr_gamma_control_manager_v1_create(server->wl_display); + wlr_gamma_control_manager_v1_create(server->wl_display); wlr_screencopy_manager_v1_create(server->wl_display); wlr_gtk_primary_selection_device_manager_create(server->wl_display); wlr_idle_create(server->wl_display); server->compositor = wlr_compositor_create(server->wl_display, - wlr_backend_get_renderer(server->backend)); + server->renderer); wlr_data_device_manager_create(server->wl_display); wl_list_init(&server->views); init_xdg_shell(server); - //wlr_idle_create(server->wl_display); - return true; + return true; } bool terminate_wb(struct wb_server* server) { wb_cursor_destroy(server->cursor); wb_seat_destroy(server->seat); wlr_output_layout_destroy(server->layout); - wl_display_destroy(server->wl_display); + wl_display_destroy(server->wl_display); - printf("Display destroyed.\n"); + printf("Display destroyed.\n"); return true; } diff --git a/waybox/xdg_shell.c b/waybox/xdg_shell.c index 0d7618d..4a92acd 100644 --- a/waybox/xdg_shell.c +++ b/waybox/xdg_shell.c @@ -65,7 +65,7 @@ static void xdg_surface_destroy(struct wl_listener *listener, void *data) { static void begin_interactive(struct wb_view *view, enum wb_cursor_mode mode, uint32_t edges) { /* This function sets up an interactive move or resize operation, where the - * compositor stops propegating pointer events to clients and instead + * compositor stops propagating pointer events to clients and instead * consumes them itself, to move or resize windows. */ struct wb_server *server = view->server; struct wlr_surface *focused_surface = @@ -75,7 +75,7 @@ static void begin_interactive(struct wb_view *view, return; } server->grabbed_view = view; - server->cursor_mode = mode; + server->cursor->cursor_mode = mode; struct wlr_box geo_box; wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box); if (mode == WB_CURSOR_MOVE) { @@ -94,9 +94,7 @@ static void xdg_toplevel_request_move( struct wl_listener *listener, void *data) { /* This event is raised when a client would like to begin an interactive * move, typically because the user clicked on their client-side - * decorations. Note that a more sophisticated compositor should check the - * provied serial against a list of button press serials sent to this - * client, to prevent the client from requesting this whenever they want. */ + * decorations. */ struct wb_view *view = wl_container_of(listener, view, request_move); begin_interactive(view, WB_CURSOR_MOVE, 0); } @@ -105,15 +103,13 @@ static void xdg_toplevel_request_resize( struct wl_listener *listener, void *data) { /* This event is raised when a client would like to begin an interactive * resize, typically because the user clicked on their client-side - * decorations. Note that a more sophisticated compositor should check the - * provied serial against a list of button press serials sent to this - * client, to prevent the client from requesting this whenever they want. */ + * decorations. */ struct wlr_xdg_toplevel_resize_event *event = data; struct wb_view *view = wl_container_of(listener, view, request_resize); begin_interactive(view, WB_CURSOR_RESIZE, event->edges); } -static void server_new_xdg_surface(struct wl_listener *listener, void *data) { +static void handle_new_xdg_surface(struct wl_listener *listener, void *data) { /* This event is raised when wlr_xdg_shell receives a new xdg surface from a * client, either a toplevel (application window) or popup. */ struct wb_server *server = @@ -123,7 +119,7 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { return; } - /* Allocate a tinywl_view for this surface */ + /* Allocate a wb_view for this surface */ struct wb_view *view = calloc(1, sizeof(struct wb_view)); view->server = server; @@ -137,7 +133,6 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { view->destroy.notify = xdg_surface_destroy; wl_signal_add(&xdg_surface->events.destroy, &view->destroy); - /* cotd */ struct wlr_xdg_toplevel *toplevel = xdg_surface->toplevel; view->request_move.notify = xdg_toplevel_request_move; wl_signal_add(&toplevel->events.request_move, &view->request_move); @@ -161,8 +156,6 @@ bool view_at(struct wb_view *view, double view_sx = lx - view->x; double view_sy = ly - view->y; - //struct wlr_surface_state *state = &view->xdg_surface->surface->current; - double _sx, _sy; struct wlr_surface *_surface = NULL; _surface = wlr_xdg_surface_surface_at( @@ -194,6 +187,6 @@ struct wb_view *desktop_view_at( void init_xdg_shell(struct wb_server *server) { server->xdg_shell = wlr_xdg_shell_create(server->wl_display); - server->new_xdg_surface.notify = server_new_xdg_surface; + server->new_xdg_surface.notify = handle_new_xdg_surface; wl_signal_add(&server->xdg_shell->events.new_surface, &server->new_xdg_surface); } From cd96e1c124f2f4d0002106a2c37363d7e62929e4 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Sat, 22 Feb 2020 21:30:44 -0500 Subject: [PATCH 16/20] More cleanups; added missing request_cursor functionality --- include/waybox/cursor.h | 4 +++- include/waybox/output.h | 1 - include/waybox/server.h | 2 -- waybox/cursor.c | 29 ++++++++++++++++++++++++++++- waybox/output.c | 2 -- waybox/server.c | 22 ++++++++++++---------- 6 files changed, 43 insertions(+), 17 deletions(-) diff --git a/include/waybox/cursor.h b/include/waybox/cursor.h index 5ba3838..ac99f68 100644 --- a/include/waybox/cursor.h +++ b/include/waybox/cursor.h @@ -25,9 +25,11 @@ struct wb_cursor { struct wl_listener cursor_button; struct wl_listener cursor_axis; struct wl_listener cursor_frame; + + struct wl_listener request_cursor; }; -struct wb_cursor *wb_cursor_create(); +struct wb_cursor *wb_cursor_create(struct wb_server *server); void wb_cursor_destroy(struct wb_cursor *cursor); #endif // cursor.h diff --git a/include/waybox/output.h b/include/waybox/output.h index 0a14df8..0d692be 100644 --- a/include/waybox/output.h +++ b/include/waybox/output.h @@ -20,7 +20,6 @@ struct wb_output { struct wlr_output *wlr_output; struct wb_server *server; - struct timespec last_frame; struct wl_listener destroy; struct wl_listener frame; diff --git a/include/waybox/server.h b/include/waybox/server.h index 7636207..88680e0 100644 --- a/include/waybox/server.h +++ b/include/waybox/server.h @@ -6,7 +6,6 @@ #endif #define _POSIX_C_SOURCE 200112L -#include #include #include @@ -28,7 +27,6 @@ struct wb_server { struct wl_display *wl_display; - struct wl_event_loop *wl_event_loop; struct wlr_backend *backend; struct wlr_compositor *compositor; diff --git a/waybox/cursor.c b/waybox/cursor.c index 2e6520b..e040b46 100644 --- a/waybox/cursor.c +++ b/waybox/cursor.c @@ -140,9 +140,30 @@ static void handle_cursor_frame(struct wl_listener *listener, void *data) { wlr_seat_pointer_notify_frame(cursor->server->seat->seat); } -struct wb_cursor *wb_cursor_create() { +static void handle_cursor_request(struct wl_listener *listener, void *data) { + struct wb_cursor *cursor = wl_container_of( + listener, cursor, request_cursor); + /* This event is rasied by the seat when a client provides a cursor image */ + struct wlr_seat_pointer_request_set_cursor_event *event = data; + struct wlr_seat_client *focused_client = + cursor->server->seat->seat->pointer_state.focused_client; + /* This can be sent by any client, so we check to make sure this one is + * actually has pointer focus first. */ + if (focused_client == event->seat_client) { + /* Once we've vetted the client, we can tell the cursor to use the + * provided surface as the cursor image. It will set the hardware cursor + * on the output that it's currently on and continue to do so as the + * cursor moves between outputs. */ + wlr_cursor_set_surface(cursor->cursor, event->surface, + event->hotspot_x, event->hotspot_y); + } +} + +struct wb_cursor *wb_cursor_create(struct wb_server *server) { struct wb_cursor *cursor = malloc(sizeof(struct wb_cursor)); cursor->cursor = wlr_cursor_create(); + cursor->server = server; + cursor->xcursor_manager = wlr_xcursor_manager_create("default", 24); wlr_xcursor_manager_load(cursor->xcursor_manager, 1); @@ -161,6 +182,12 @@ struct wb_cursor *wb_cursor_create() { cursor->cursor_frame.notify = handle_cursor_frame; wl_signal_add(&cursor->cursor->events.frame, &cursor->cursor_frame); + cursor->request_cursor.notify = handle_cursor_request; + wl_signal_add(&server->seat->seat->events.request_set_cursor, + &cursor->request_cursor); + + wlr_cursor_attach_output_layout(cursor->cursor, server->layout); + return cursor; } diff --git a/waybox/output.c b/waybox/output.c index ba71280..dddba71 100644 --- a/waybox/output.c +++ b/waybox/output.c @@ -105,7 +105,6 @@ void output_frame_notify(struct wl_listener *listener, void *data) { wlr_renderer_end(renderer); wlr_output_commit(wlr_output); - output->last_frame = now; } void output_destroy_notify(struct wl_listener *listener, void *data) { @@ -134,7 +133,6 @@ void new_output_notify(struct wl_listener *listener, void *data) { } struct wb_output *output = calloc(1, sizeof(struct wb_output)); - clock_gettime(CLOCK_MONOTONIC, &output->last_frame); output->server = server; output->wlr_output = wlr_output; wl_list_insert(&server->outputs, &output->link); diff --git a/waybox/server.c b/waybox/server.c index 5f089e6..dbba7b7 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -5,15 +5,13 @@ bool init_wb(struct wb_server* server) { // create display server->wl_display = wl_display_create(); - assert(server->wl_display); - - // event loop stuff - server->wl_event_loop = wl_display_get_event_loop(server->wl_display); - assert(server->wl_event_loop); + if (server->wl_display == NULL) { + fprintf(stderr, "Failed to connect to a Wayland display\n"); + return false; + } // create backend server->backend = wlr_backend_autocreate(server->wl_display, NULL); - assert(server->backend); if (server->backend == NULL) { printf("Failed to create backend\n"); return false; @@ -23,10 +21,8 @@ bool init_wb(struct wb_server* server) { wlr_renderer_init_wl_display(server->renderer, server->wl_display); server->layout = wlr_output_layout_create(); - server->cursor = wb_cursor_create(); - server->cursor->server = server; - wlr_cursor_attach_output_layout(server->cursor->cursor, server->layout); server->seat = wb_seat_create(server); + server->cursor = wb_cursor_create(server); return true; } @@ -38,10 +34,15 @@ bool start_wb(struct wb_server* server) { wl_signal_add(&server->backend->events.new_output, &server->new_output); const char *socket = wl_display_add_socket_auto(server->wl_display); - assert(socket); + if (!socket) + { + wlr_backend_destroy(server->backend); + return false; + } if (!wlr_backend_start(server->backend)) { fprintf(stderr, "Failed to start backend\n"); + wlr_backend_destroy(server->backend); wl_display_destroy(server->wl_display); return false; } @@ -64,6 +65,7 @@ bool start_wb(struct wb_server* server) { } bool terminate_wb(struct wb_server* server) { + wl_display_destroy_clients(server->wl_display); wb_cursor_destroy(server->cursor); wb_seat_destroy(server->seat); wlr_output_layout_destroy(server->layout); From 83e87cd3de612ef6938cf45290ab77ec15d63094 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Sun, 23 Feb 2020 08:15:29 -0500 Subject: [PATCH 17/20] Less flaky refocus code --- waybox/xdg_shell.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/waybox/xdg_shell.c b/waybox/xdg_shell.c index 4a92acd..4fa8889 100644 --- a/waybox/xdg_shell.c +++ b/waybox/xdg_shell.c @@ -49,9 +49,16 @@ static void xdg_surface_unmap(struct wl_listener *listener, void *data) { struct wb_view *view = wl_container_of(listener, view, unmap); view->mapped = false; - /* Focus previous view's surface, if any */ - if (view->server->views.prev) { - focus_view((struct wb_view *) view->server->views.prev, ((struct wb_view *) view->server->views.prev)->xdg_surface->surface); + struct wb_view *current_view = (struct wb_view *) view->server->views.next; + struct wb_view *next_view = (struct wb_view *) current_view->link.next; + + /* If the current view is mapped, focus it. */ + if (current_view->mapped) { + focus_view(current_view, current_view->xdg_surface->surface); + } + /* Otherwise, focus the next view, if any. */ + else if (next_view->xdg_surface->surface) { + focus_view(next_view, next_view->xdg_surface->surface); } } From 40dfbad423246c80d446b6018f524e3a5960281f Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Sun, 23 Feb 2020 10:38:05 -0500 Subject: [PATCH 18/20] More cleanup --- waybox/cursor.c | 2 +- waybox/output.c | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/waybox/cursor.c b/waybox/cursor.c index e040b46..2c96d10 100644 --- a/waybox/cursor.c +++ b/waybox/cursor.c @@ -164,7 +164,7 @@ struct wb_cursor *wb_cursor_create(struct wb_server *server) { cursor->cursor = wlr_cursor_create(); cursor->server = server; - cursor->xcursor_manager = wlr_xcursor_manager_create("default", 24); + cursor->xcursor_manager = wlr_xcursor_manager_create(NULL, 24); wlr_xcursor_manager_load(cursor->xcursor_manager, 1); cursor->cursor_motion.notify = handle_cursor_motion; diff --git a/waybox/output.c b/waybox/output.c index dddba71..2eed274 100644 --- a/waybox/output.c +++ b/waybox/output.c @@ -69,14 +69,12 @@ static void render_surface(struct wlr_surface *surface, int sx, int sy, void *da void output_frame_notify(struct wl_listener *listener, void *data) { struct wb_output *output = wl_container_of(listener, output, frame); - struct wlr_output *wlr_output = data; - struct wlr_renderer *renderer = wlr_backend_get_renderer( - wlr_output->backend); + struct wlr_renderer *renderer = output->server->renderer; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - if (!wlr_output_attach_render(wlr_output, NULL)) { + if (!wlr_output_attach_render(output->wlr_output, NULL)) { return; } int width, height; @@ -103,8 +101,9 @@ void output_frame_notify(struct wl_listener *listener, void *data) { wlr_xdg_surface_for_each_surface(view->xdg_surface, render_surface, &rdata); } + wlr_output_render_software_cursors(output->wlr_output, NULL); wlr_renderer_end(renderer); - wlr_output_commit(wlr_output); + wlr_output_commit(output->wlr_output); } void output_destroy_notify(struct wl_listener *listener, void *data) { From 810414cabae592c913a5a1125532a4b6e8306cf5 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Sun, 23 Feb 2020 11:09:18 -0500 Subject: [PATCH 19/20] Actually use the user's preferred Xcursor theme/size --- waybox/cursor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/waybox/cursor.c b/waybox/cursor.c index 2c96d10..739f904 100644 --- a/waybox/cursor.c +++ b/waybox/cursor.c @@ -164,7 +164,8 @@ struct wb_cursor *wb_cursor_create(struct wb_server *server) { cursor->cursor = wlr_cursor_create(); cursor->server = server; - cursor->xcursor_manager = wlr_xcursor_manager_create(NULL, 24); + const char *xcursor_size = getenv("XCURSOR_SIZE"); + cursor->xcursor_manager = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"), xcursor_size ? atoi(xcursor_size) : 24); wlr_xcursor_manager_load(cursor->xcursor_manager, 1); cursor->cursor_motion.notify = handle_cursor_motion; From a40ab2c30944702d339d385f01c5a4c2e26d4d98 Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Sun, 23 Feb 2020 22:41:48 -0500 Subject: [PATCH 20/20] Finally got weston-terminal to start again (it's been segfaulting since seat support was added) --- waybox/server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/waybox/server.c b/waybox/server.c index dbba7b7..987f136 100644 --- a/waybox/server.c +++ b/waybox/server.c @@ -20,6 +20,8 @@ bool init_wb(struct wb_server* server) { server->renderer = wlr_backend_get_renderer(server->backend); wlr_renderer_init_wl_display(server->renderer, server->wl_display); + server->compositor = wlr_compositor_create(server->wl_display, + server->renderer); server->layout = wlr_output_layout_create(); server->seat = wb_seat_create(server); server->cursor = wb_cursor_create(server); @@ -55,8 +57,6 @@ bool start_wb(struct wb_server* server) { wlr_gtk_primary_selection_device_manager_create(server->wl_display); wlr_idle_create(server->wl_display); - server->compositor = wlr_compositor_create(server->wl_display, - server->renderer); wlr_data_device_manager_create(server->wl_display); wl_list_init(&server->views); init_xdg_shell(server);