From d33a9f8eaaeaf2e7a6bbf0c9f9d57c3334544a2b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 23 Oct 2017 08:59:55 -0400 Subject: [PATCH 1/5] wlr-seat: keyboard redesign --- include/rootston/input.h | 1 + include/wlr/types/wlr_seat.h | 49 +++++----- rootston/keyboard.c | 47 ++++++++-- types/wlr_seat.c | 168 +++++++++++++++-------------------- 4 files changed, 138 insertions(+), 127 deletions(-) diff --git a/include/rootston/input.h b/include/rootston/input.h index ddd5a05d..b55288c9 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -16,6 +16,7 @@ struct roots_keyboard { struct roots_input *input; struct wlr_input_device *device; struct wl_listener key; + struct wl_listener modifiers; struct wl_list link; xkb_keysym_t pressed_keysyms[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP]; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index d267924c..6fda89b9 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -14,7 +14,6 @@ struct wlr_seat_handle { struct wl_resource *wl_resource; struct wlr_seat *wlr_seat; - struct wlr_seat_keyboard *seat_keyboard; struct wl_resource *pointer; struct wl_resource *keyboard; @@ -82,21 +81,16 @@ struct wlr_seat_pointer_state { struct wlr_seat_pointer_grab *default_grab; }; -struct wlr_seat_keyboard { - struct wlr_seat *seat; - struct wlr_keyboard *keyboard; - struct wl_listener key; - struct wl_listener modifiers; - struct wl_listener keymap; - struct wl_listener destroy; - struct wl_list link; -}; - struct wlr_seat_keyboard_state { struct wlr_seat *wlr_seat; + struct wlr_keyboard *keyboard; + struct wlr_seat_handle *focused_handle; struct wlr_surface *focused_surface; + struct wl_listener keyboard_destroy; + struct wl_listener keyboard_keymap; + struct wl_listener surface_destroy; struct wl_listener resource_destroy; @@ -108,7 +102,6 @@ struct wlr_seat { struct wl_global *wl_global; struct wl_display *display; struct wl_list handles; - struct wl_list keyboards; char *name; uint32_t capabilities; struct wlr_data_device *data_device; @@ -254,18 +247,9 @@ void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time, enum wlr_axis_orientation orientation, double value); /** - * Attaches this keyboard to the seat. Key events from this keyboard will be - * propegated to the focused client. + * Set this keyboard as the active keyboard for the seat. */ -void wlr_seat_attach_keyboard(struct wlr_seat *seat, - struct wlr_input_device *dev); - -/** - * Detaches this keyboard from the seat. This is done automatically when the - * keyboard is destroyed; you only need to use this if you want to remove it for - * some other reason. - */ -void wlr_seat_detach_keyboard(struct wlr_seat *seat, struct wlr_keyboard *kb); +void wlr_seat_set_keyboard(struct wlr_seat *seat, struct wlr_input_device *dev); /** * Start a grab of the keyboard of this seat. The grabber is responsible for @@ -282,19 +266,34 @@ void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat); /** * Send the keyboard key to focused keyboard resources. Compositors should use - * `wlr_seat_attach_keyboard()` to automatically handle keyboard events. + * `wlr_seat_notify_key()` to respect keyboard grabs. */ void wlr_seat_keyboard_send_key(struct wlr_seat *seat, uint32_t time, uint32_t key, uint32_t state); +/** + * Notify the seat that a key has been pressed on the keyboard. Defers to any + * keyboard grabs. + */ +void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time, + uint32_t key, uint32_t state); + /** * Send the modifier state to focused keyboard resources. Compositors should use - * `wlr_seat_attach_keyboard()` to automatically handle keyboard events. + * `wlr_seat_keyboard_notify_modifiers()` to respect any keyboard grabs. */ void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group); +/** + * Notify the seat that the modifiers for the keyboard have changed. Defers to + * any keyboard grabs. + */ +void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group); + /** * Notify the seat that the keyboard focus has changed and request it to be the * focused surface for this keyboard. Defers to any current grab of the seat's diff --git a/rootston/keyboard.c b/rootston/keyboard.c index 61604da0..1d4699a9 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -53,7 +53,13 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, } } -static void keyboard_keysym_press(struct roots_keyboard *keyboard, +/** + * Process a keypress from the keyboard. + * + * Returns true if the keysym was handled by a binding and false if the event + * should be propagated to clients. + */ +static bool keyboard_keysym_press(struct roots_keyboard *keyboard, xkb_keysym_t keysym) { ssize_t i = keyboard_pressed_keysym_index(keyboard, keysym); if (i < 0) { @@ -74,7 +80,7 @@ static void keyboard_keysym_press(struct roots_keyboard *keyboard, wlr_session_change_vt(session, vt); } } - return; + return true; } uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); @@ -96,8 +102,11 @@ static void keyboard_keysym_press(struct roots_keyboard *keyboard, if (ok) { keyboard_binding_execute(keyboard, bc->command); + return true; } } + + return false; } static void keyboard_keysym_release(struct roots_keyboard *keyboard, @@ -116,13 +125,36 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) { const xkb_keysym_t *syms; int syms_len = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, keycode, &syms); + + bool handled = false; for (int i = 0; i < syms_len; i++) { if (event->state == WLR_KEY_PRESSED) { - keyboard_keysym_press(keyboard, syms[i]); + bool keysym_handled = keyboard_keysym_press(keyboard, syms[i]); + handled = handled || keysym_handled; } else { // WLR_KEY_RELEASED keyboard_keysym_release(keyboard, syms[i]); } } + + if (!handled) { + wlr_seat_set_keyboard(keyboard->input->wl_seat, keyboard->device); + wlr_seat_keyboard_notify_key(keyboard->input->wl_seat, + (uint32_t)(event->time_usec / 1000), event->keycode, event->state); + } +} + +static void keyboard_modifiers_notify(struct wl_listener *listener, void *data) { + struct roots_keyboard *r_keyboard = + wl_container_of(listener, r_keyboard, modifiers); + struct wlr_seat *seat = r_keyboard->input->wl_seat; + struct wlr_keyboard *keyboard = r_keyboard->device->keyboard; + wlr_seat_set_keyboard(seat, r_keyboard->device); + wlr_seat_keyboard_notify_modifiers(seat, + keyboard->modifiers.depressed, + keyboard->modifiers.latched, + keyboard->modifiers.locked, + keyboard->modifiers.group); + } void keyboard_add(struct wlr_input_device *device, struct roots_input *input) { @@ -133,8 +165,13 @@ void keyboard_add(struct wlr_input_device *device, struct roots_input *input) { device->data = keyboard; keyboard->device = device; keyboard->input = input; + keyboard->key.notify = keyboard_key_notify; wl_signal_add(&device->keyboard->events.key, &keyboard->key); + + keyboard->modifiers.notify = keyboard_modifiers_notify; + wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers); + wl_list_insert(&input->keyboards, &keyboard->link); struct xkb_rule_names rules; @@ -152,14 +189,12 @@ void keyboard_add(struct wlr_input_device *device, struct roots_input *input) { wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); xkb_context_unref(context); - - wlr_seat_attach_keyboard(input->wl_seat, device); } void keyboard_remove(struct wlr_input_device *device, struct roots_input *input) { struct roots_keyboard *keyboard = device->data; - wlr_seat_detach_keyboard(input->wl_seat, device->keyboard); wl_list_remove(&keyboard->key.link); + wl_list_remove(&keyboard->modifiers.link); wl_list_remove(&keyboard->link); free(keyboard); } diff --git a/types/wlr_seat.c b/types/wlr_seat.c index e0fb3e8d..0ffa33ab 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -91,6 +91,24 @@ static void wl_keyboard_destroy(struct wl_resource *resource) { } } +static void seat_handle_send_keymap(struct wlr_seat_handle *handle, + struct wlr_keyboard *keyboard) { + if (!keyboard || !handle->keyboard) { + return; + } + // TODO: We should probably lift all of the keys set by the other + // keyboard + wl_keyboard_send_keymap(handle->keyboard, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd, + keyboard->keymap_size); + + if (wl_resource_get_version(handle->keyboard) >= + WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { + // TODO: Make this better + wl_keyboard_send_repeat_info(handle->keyboard, 25, 600); + } +} + static void wl_seat_get_keyboard(struct wl_client *client, struct wl_resource *_handle, uint32_t id) { struct wlr_seat_handle *handle = wl_resource_get_user_data(_handle); @@ -107,6 +125,11 @@ static void wl_seat_get_keyboard(struct wl_client *client, wl_resource_get_version(_handle), id); wl_resource_set_implementation(handle->keyboard, &wl_keyboard_impl, handle, &wl_keyboard_destroy); + + seat_handle_send_keymap(handle, handle->wlr_seat->keyboard_state.keyboard); + + // TODO possibly handle the case where this keyboard needs an enter + // right away } static const struct wl_touch_interface wl_touch_impl = { @@ -298,7 +321,6 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wlr_seat->display = display; wlr_seat->name = strdup(name); wl_list_init(&wlr_seat->handles); - wl_list_init(&wlr_seat->keyboards); wl_signal_init(&wlr_seat->events.client_bound); wl_signal_init(&wlr_seat->events.client_unbound); @@ -539,26 +561,6 @@ void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time, grab->interface->axis(grab, time, orientation, value); } -static void keyboard_switch_seat_keyboard(struct wlr_seat_handle *handle, - struct wlr_seat_keyboard *seat_kb) { - if (handle->seat_keyboard == seat_kb) { - return; - } - - // TODO: We should probably lift all of the keys set by the other - // keyboard - wl_keyboard_send_keymap(handle->keyboard, - WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, seat_kb->keyboard->keymap_fd, - seat_kb->keyboard->keymap_size); - - if (wl_resource_get_version(handle->keyboard) >= - WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { - // TODO: Make this better - wl_keyboard_send_repeat_info(handle->keyboard, 25, 600); - } - handle->seat_keyboard = seat_kb; -} - void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time, uint32_t key, uint32_t state) { struct wlr_seat_handle *handle = wlr_seat->keyboard_state.focused_handle; @@ -571,89 +573,49 @@ void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time, time, key, state); } -static void keyboard_key_notify(struct wl_listener *listener, void *data) { - struct wlr_seat_keyboard *seat_kb = wl_container_of(listener, seat_kb, key); - struct wlr_seat *seat = seat_kb->seat; - struct wlr_seat_handle *handle = seat->keyboard_state.focused_handle; - if (!handle || !handle->keyboard) { +static void handle_keyboard_keymap(struct wl_listener *listener, void *data) { + struct wlr_seat_keyboard_state *state = + wl_container_of(listener, state, keyboard_keymap); + struct wlr_seat_handle *handle; + wl_list_for_each(handle, &state->wlr_seat->handles, link) { + seat_handle_send_keymap(handle, state->keyboard); + } +} + +static void handle_keyboard_destroy(struct wl_listener *listener, void *data) { + struct wlr_seat_keyboard_state *state = + wl_container_of(listener, state, keyboard_destroy); + state->keyboard = NULL; +} + +void wlr_seat_set_keyboard(struct wlr_seat *seat, + struct wlr_input_device *device) { + if (seat->keyboard_state.keyboard == device->keyboard) { return; } - keyboard_switch_seat_keyboard(handle, seat_kb); - - struct wlr_event_keyboard_key *event = data; - enum wlr_key_state key_state = event->state; - - struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; - grab->interface->key(grab, (uint32_t)(event->time_usec / 1000), - event->keycode, key_state); -} - -static void keyboard_modifiers_notify(struct wl_listener *listener, - void *data) { - struct wlr_seat_keyboard *seat_kb = wl_container_of(listener, seat_kb, - modifiers); - struct wlr_seat *seat = seat_kb->seat; - struct wlr_seat_handle *handle = seat->keyboard_state.focused_handle; - if (!handle || !handle->keyboard) { - return; + if (seat->keyboard_state.keyboard) { + wl_list_remove(&seat->keyboard_state.keyboard_destroy.link); + wl_list_remove(&seat->keyboard_state.keyboard_keymap.link); + seat->keyboard_state.keyboard = NULL; } - keyboard_switch_seat_keyboard(handle, seat_kb); + if (device) { + assert(device->type == WLR_INPUT_DEVICE_KEYBOARD); + wl_signal_add(&device->events.destroy, + &seat->keyboard_state.keyboard_destroy); + seat->keyboard_state.keyboard_destroy.notify = handle_keyboard_destroy; - struct wlr_keyboard *keyboard = seat_kb->keyboard; + wl_signal_add(&device->keyboard->events.keymap, + &seat->keyboard_state.keyboard_keymap); + seat->keyboard_state.keyboard_keymap.notify = handle_keyboard_keymap; - struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; - - grab->interface->modifiers(grab, - keyboard->modifiers.depressed, keyboard->modifiers.latched, - keyboard->modifiers.locked, keyboard->modifiers.group); -} - -static void keyboard_keymap_notify(struct wl_listener *listener, void *data) { - struct wlr_seat_keyboard *seat_kb = wl_container_of( - listener, seat_kb, keymap); - wlr_log(L_DEBUG, "Keymap event for %p", seat_kb); -} - -static void keyboard_destroy_notify(struct wl_listener *listener, void *data) { - struct wlr_seat_keyboard *seat_kb = wl_container_of( - listener, seat_kb, destroy); - wlr_seat_detach_keyboard(seat_kb->seat, seat_kb->keyboard); -} - -void wlr_seat_attach_keyboard(struct wlr_seat *seat, - struct wlr_input_device *dev) { - assert(seat && dev && dev->type == WLR_INPUT_DEVICE_KEYBOARD); - struct wlr_keyboard *kb = dev->keyboard; - struct wlr_seat_keyboard *seat_kb = - calloc(1, sizeof(struct wlr_seat_keyboard)); - seat_kb->keyboard = kb; - seat_kb->seat = seat; - seat_kb->key.notify = keyboard_key_notify; - wl_signal_add(&kb->events.key, &seat_kb->key); - seat_kb->modifiers.notify = keyboard_modifiers_notify; - wl_signal_add(&kb->events.modifiers, &seat_kb->modifiers); - seat_kb->keymap.notify = keyboard_keymap_notify; - wl_signal_add(&kb->events.keymap, &seat_kb->keymap); - // TODO: update keymap as necessary - seat_kb->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&dev->events.destroy, &seat_kb->destroy); - wl_list_insert(&seat->keyboards, &seat_kb->link); -} - -void wlr_seat_detach_keyboard(struct wlr_seat *seat, struct wlr_keyboard *kb) { - struct wlr_seat_keyboard *seat_kb, *_tmp; - wl_list_for_each_safe(seat_kb, _tmp, &seat->keyboards, link) { - if (seat_kb->keyboard == kb) { - wl_list_remove(&seat_kb->link); - wl_list_remove(&seat_kb->key.link); - wl_list_remove(&seat_kb->modifiers.link); - wl_list_remove(&seat_kb->keymap.link); - wl_list_remove(&seat_kb->destroy.link); - free(seat_kb); - break; + struct wlr_seat_handle *handle; + wl_list_for_each(handle, &seat->handles, link) { + seat_handle_send_keymap(handle, device->keyboard); } + + seat->keyboard_state.keyboard = device->keyboard; } } @@ -774,3 +736,17 @@ void wlr_seat_keyboard_clear_focus(struct wlr_seat *wlr_seat) { wl_array_init(&keys); wlr_seat_keyboard_enter(wlr_seat, NULL); } + +void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) { + struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; + grab->interface->modifiers(grab, + mods_depressed, mods_latched, mods_locked, group); +} + +void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time, + uint32_t key, uint32_t state) { + struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; + grab->interface->key(grab, time, key, state); +} From 06d8893543778cac3ed8402916a7fd3bd7c4d78a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 24 Oct 2017 07:24:48 -0400 Subject: [PATCH 2/5] wlr-seat: edit todos --- types/wlr_seat.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 0ffa33ab..b2c8a758 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -104,7 +104,6 @@ static void seat_handle_send_keymap(struct wlr_seat_handle *handle, if (wl_resource_get_version(handle->keyboard) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { - // TODO: Make this better wl_keyboard_send_repeat_info(handle->keyboard, 25, 600); } } @@ -590,6 +589,9 @@ static void handle_keyboard_destroy(struct wl_listener *listener, void *data) { void wlr_seat_set_keyboard(struct wlr_seat *seat, struct wlr_input_device *device) { + // TODO call this on device key event before the event reaches the + // compositor and set a pending keyboard and then send the new keyboard + // state on the next keyboard notify event. if (seat->keyboard_state.keyboard == device->keyboard) { return; } @@ -697,7 +699,8 @@ void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, // enter the current surface if (handle && handle->keyboard) { - // TODO: handle keys properly + // TODO: read the currently pressed keys out of the active keyboard and + // put them in this array struct wl_array keys; wl_array_init(&keys); uint32_t serial = wl_display_next_serial(wlr_seat->display); From fb0c9a356e1b9e86f4b29d3be739e8b17c5771e9 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 28 Oct 2017 11:58:34 +0200 Subject: [PATCH 3/5] Enforce resize bounds in rootston --- rootston/cursor.c | 7 +++++++ rootston/xdg_shell_v6.c | 15 +++++++++++++++ rootston/xwayland.c | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/rootston/cursor.c b/rootston/cursor.c index ece115c4..27f97724 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -160,6 +160,13 @@ void cursor_update_position(struct roots_input *input, uint32_t time) { width += dx; } + if (width < 0) { + width = 0; + } + if (height < 0) { + height = 0; + } + // TODO we might need one configure event for this if (active_x != input->active_view->x || active_y != input->active_view->y) { diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 85871144..4f284851 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -29,6 +29,21 @@ static void resize(struct roots_view *view, uint32_t width, uint32_t height) { assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); struct wlr_xdg_surface_v6 *surf = view->xdg_surface_v6; if (surf->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + struct wlr_xdg_toplevel_v6_state *state = + &surf->toplevel_state->current; + if (width < state->min_width) { + width = state->min_width; + } else if (state->max_width > 0 && + width < state->max_width) { + width = state->max_width; + } + if (height < state->min_height) { + height = state->min_height; + } else if (state->max_height > 0 && + height < state->max_height) { + height = state->max_height; + } + wlr_xdg_toplevel_v6_set_size(surf, width, height); } } diff --git a/rootston/xwayland.c b/rootston/xwayland.c index 8b7c32f4..e1b9d227 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -22,6 +22,24 @@ static void activate(struct roots_view *view, bool active) { static void resize(struct roots_view *view, uint32_t width, uint32_t height) { assert(view->type == ROOTS_XWAYLAND_VIEW); struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; + + struct wlr_xwayland_surface_size_hints *size_hints = + xwayland_surface->size_hints; + if (size_hints != NULL) { + if (width < (uint32_t)size_hints->min_width) { + width = size_hints->min_width; + } else if (size_hints->max_width > 0 && + width > (uint32_t)size_hints->max_width) { + width = size_hints->max_width; + } + if (height < (uint32_t)size_hints->min_height) { + height = size_hints->min_height; + } else if (size_hints->max_height > 0 && + height > (uint32_t)size_hints->max_height) { + height = size_hints->max_height; + } + } + wlr_xwayland_surface_configure(view->desktop->xwayland, xwayland_surface, xwayland_surface->x, xwayland_surface->y, width, height); } From fa9c6ecc53355a53d442036b0a6e98588d2abed7 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 28 Oct 2017 15:09:38 -0400 Subject: [PATCH 4/5] Fix segfault in DRM cursor --- backend/drm/drm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index a3594bb0..27a8490c 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -503,13 +503,6 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, struct wlr_drm_crtc *crtc = conn->crtc; struct wlr_drm_plane *plane = crtc->cursor; - if (!buf && update_pixels) { - // Hide the cursor - plane->cursor_enabled = false; - return drm->iface->crtc_set_cursor(drm, crtc, NULL); - } - plane->cursor_enabled = true; - // We don't have a real cursor plane, so we make a fake one if (!plane) { plane = calloc(1, sizeof(*plane)); @@ -520,6 +513,13 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, crtc->cursor = plane; } + if (!buf && update_pixels) { + // Hide the cursor + plane->cursor_enabled = false; + return drm->iface->crtc_set_cursor(drm, crtc, NULL); + } + plane->cursor_enabled = true; + if (!plane->surf.gbm) { int ret; uint64_t w, h; From 50e86a0efa43fa72bd7d8c2dfc2d124052f74823 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 28 Oct 2017 15:32:08 -0400 Subject: [PATCH 5/5] Allow configuring output mode in rootston Fixes #336 --- include/rootston/config.h | 4 ++++ rootston/config.c | 16 ++++++++++++++++ rootston/output.c | 23 +++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/include/rootston/config.h b/include/rootston/config.h index ecbdd88b..75c04619 100644 --- a/include/rootston/config.h +++ b/include/rootston/config.h @@ -9,6 +9,10 @@ struct output_config { enum wl_output_transform transform; int x, y; struct wl_list link; + struct { + int width, height; + float refresh_rate; + } mode; }; struct device_config { diff --git a/rootston/config.c b/rootston/config.c index 6f81170b..b3fd4f01 100644 --- a/rootston/config.c +++ b/rootston/config.c @@ -1,6 +1,7 @@ #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L #endif +#include #include #include #include @@ -244,6 +245,21 @@ static int config_ini_handler(void *user, const char *section, const char *name, } else { wlr_log(L_ERROR, "got unknown transform value: %s", value); } + } else if (strcmp(name, "mode") == 0) { + char *end; + oc->mode.width = strtol(value, &end, 10); + assert(*end == 'x'); + ++end; + oc->mode.height = strtol(end, &end, 10); + if (*end) { + assert(*end == '@'); + ++end; + oc->mode.refresh_rate = strtof(end, &end); + assert(strcmp("Hz", end) == 0); + } + wlr_log(L_DEBUG, "Configured output %s with mode %dx%d@%f", + oc->name, oc->mode.width, oc->mode.height, + oc->mode.refresh_rate); } } else if (strcmp(section, "cursor") == 0) { if (strcmp(name, "map-to-output") == 0) { diff --git a/rootston/output.c b/rootston/output.c index 5fcd02a2..6bc28996 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -165,6 +165,26 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { output->last_frame = desktop->last_frame = now; } +static void set_mode(struct wlr_output *output, struct output_config *oc) { + struct wlr_output_mode *mode, *best = NULL; + int mhz = (int)(oc->mode.refresh_rate * 1000); + wl_list_for_each(mode, &output->modes, link) { + if (mode->width == oc->mode.width && mode->height == oc->mode.height) { + if (mode->refresh == mhz) { + best = mode; + break; + } + best = mode; + } + } + if (!best) { + wlr_log(L_ERROR, "Configured mode for %s not available", output->name); + } else { + wlr_log(L_DEBUG, "Assigning configured mode to %s", output->name); + wlr_output_set_mode(output, best); + } +} + void output_add_notify(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; struct roots_desktop *desktop = wl_container_of(listener, desktop, output_add); @@ -191,6 +211,9 @@ void output_add_notify(struct wl_listener *listener, void *data) { struct output_config *output_config = config_get_output(config, wlr_output); if (output_config) { + if (output_config->mode.width) { + set_mode(wlr_output, output_config); + } wlr_output_transform(wlr_output, output_config->transform); wlr_output_layout_add(desktop->layout, wlr_output, output_config->x, output_config->y);