From cfd02918c0d5dc539bc8858c7d0fab378145b38c Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 9 Jun 2018 13:26:03 +0100 Subject: [PATCH 1/5] Render drag icons --- include/sway/input/seat.h | 20 ++++++++ include/sway/tree/layout.h | 1 + sway/desktop/output.c | 34 +++++++++++++ sway/input/cursor.c | 62 ++++++++++++++++-------- sway/input/seat.c | 98 ++++++++++++++++++++++++++++++++++++-- sway/tree/layout.c | 1 + 6 files changed, 193 insertions(+), 23 deletions(-) diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 2e4da438..1f7792ba 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -21,6 +21,19 @@ struct sway_seat_container { struct wl_listener destroy; }; +struct sway_drag_icon { + struct sway_seat *seat; + struct wlr_drag_icon *wlr_drag_icon; + struct wl_list link; // sway_root::drag_icons + + double x, y; // in layout-local coordinates + + struct wl_listener surface_commit; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener destroy; +}; + struct sway_seat { struct wlr_seat *wlr_seat; struct sway_cursor *cursor; @@ -35,8 +48,13 @@ struct sway_seat { // If exclusive_client is set, no other clients will receive input events struct wl_client *exclusive_client; + // Last touch point + int32_t touch_id; + double touch_x, touch_y; + struct wl_listener focus_destroy; struct wl_listener new_container; + struct wl_listener new_drag_icon; struct wl_list devices; // sway_seat_device::link @@ -114,4 +132,6 @@ struct seat_config *seat_get_config(struct sway_seat *seat); bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface); +void drag_icon_update_position(struct sway_drag_icon *icon); + #endif diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index cd131056..ba265623 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -28,6 +28,7 @@ struct sway_root { struct wl_listener output_layout_change; struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link + struct wl_list drag_icons; // sway_drag_icon::link struct wlr_texture *debug_tree; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index bd1d760d..29666c00 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -161,6 +161,21 @@ static void unmanaged_for_each_surface(struct wl_list *unmanaged, } } +static void drag_icons_for_each_surface(struct wl_list *drag_icons, + struct sway_output *output, struct root_geometry *geo, + wlr_surface_iterator_func_t iterator, void *user_data) { + struct sway_drag_icon *drag_icon; + wl_list_for_each(drag_icon, drag_icons, link) { + double ox = drag_icon->x - output->swayc->x; + double oy = drag_icon->y - output->swayc->y; + + if (drag_icon->wlr_drag_icon->mapped) { + surface_for_each_surface(drag_icon->wlr_drag_icon->surface, + ox, oy, geo, iterator, user_data); + } + } +} + static void scale_box(struct wlr_box *box, float scale) { box->x *= scale; box->y *= scale; @@ -270,6 +285,17 @@ static void render_unmanaged(struct sway_output *output, render_surface_iterator, &data); } +static void render_drag_icons(struct sway_output *output, + pixman_region32_t *damage, struct wl_list *drag_icons) { + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + drag_icons_for_each_surface(drag_icons, output, &data.root_geo, + render_surface_iterator, &data); +} + static void render_rect(struct wlr_output *wlr_output, pixman_region32_t *output_damage, const struct wlr_box *_box, float color[static 4]) { @@ -911,6 +937,7 @@ static void render_output(struct sway_output *output, struct timespec *when, } render_layer(output, damage, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + render_drag_icons(output, damage, &root_container.sway_root->drag_icons); renderer_end: if (root_container.sway_root->debug_tree) { @@ -961,6 +988,12 @@ static void send_frame_done_unmanaged(struct send_frame_done_data *data, send_frame_done_iterator, data); } +static void send_frame_done_drag_icons(struct send_frame_done_data *data, + struct wl_list *drag_icons) { + drag_icons_for_each_surface(drag_icons, data->output, &data->root_geo, + send_frame_done_iterator, data); +} + static void send_frame_done_container_iterator(struct sway_container *con, void *_data) { struct send_frame_done_data *data = _data; @@ -1014,6 +1047,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { send_frame_done_layer(&data, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + send_frame_done_drag_icons(&data, &root_container.sway_root->drag_icons); } static void damage_handle_frame(struct wl_listener *listener, void *data) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 4100479c..37a87756 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -144,21 +144,22 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, time_msec = get_current_time_msec(); } - struct wlr_seat *seat = cursor->seat->wlr_seat; + struct sway_seat *seat = cursor->seat; + struct wlr_seat *wlr_seat = seat->wlr_seat; struct wlr_surface *surface = NULL; double sx, sy; // Find the container beneath the pointer's previous position - struct sway_container *prev_c = container_at_coords(cursor->seat, + struct sway_container *prev_c = container_at_coords(seat, cursor->previous.x, cursor->previous.y, &surface, &sx, &sy); // Update the stored previous position cursor->previous.x = cursor->cursor->x; cursor->previous.y = cursor->cursor->y; - struct sway_container *c = container_at_coords(cursor->seat, + struct sway_container *c = container_at_coords(seat, cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); if (c && config->focus_follows_mouse && allow_refocusing) { - struct sway_container *focus = seat_get_focus(cursor->seat); + struct sway_container *focus = seat_get_focus(seat); if (focus && c->type == C_WORKSPACE) { // Only follow the mouse if it would move to a new output // Otherwise we'll focus the workspace, which is probably wrong @@ -170,20 +171,20 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, output = container_parent(c, C_OUTPUT); } if (output != focus) { - seat_set_focus_warp(cursor->seat, c, false); + seat_set_focus_warp(seat, c, false); } } else if (c->type == C_VIEW) { // Focus c if both of the following are true: // - cursor is over a new view, i.e. entered a new window; and // - the new view is visible, i.e. not hidden in a stack or tab. if (c != prev_c && view_is_visible(c->sway_view)) { - seat_set_focus_warp(cursor->seat, c, false); + seat_set_focus_warp(seat, c, false); } else { struct sway_container *next_focus = - seat_get_focus_inactive(cursor->seat, &root_container); + seat_get_focus_inactive(seat, &root_container); if (next_focus && next_focus->type == C_VIEW && view_is_visible(next_focus->sway_view)) { - seat_set_focus_warp(cursor->seat, next_focus, false); + seat_set_focus_warp(seat, next_focus, false); } } } @@ -202,12 +203,18 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, // send pointer enter/leave if (surface != NULL) { - if (seat_is_input_allowed(cursor->seat, surface)) { - wlr_seat_pointer_notify_enter(seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(seat, time_msec, sx, sy); + if (seat_is_input_allowed(seat, surface)) { + wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(wlr_seat, time_msec, sx, sy); } } else { - wlr_seat_pointer_clear_focus(seat); + wlr_seat_pointer_clear_focus(wlr_seat); + } + + struct wlr_drag_icon *wlr_drag_icon; + wl_list_for_each(wlr_drag_icon, &wlr_seat->drag_icons, link) { + struct sway_drag_icon *drag_icon = wlr_drag_icon->data; + drag_icon_update_position(drag_icon); } } @@ -293,22 +300,27 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat); struct wlr_event_touch_down *event = data; - struct wlr_seat *seat = cursor->seat->wlr_seat; + struct sway_seat *seat = cursor->seat; + struct wlr_seat *wlr_seat = seat->wlr_seat; struct wlr_surface *surface = NULL; double lx, ly; wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, event->x, event->y, &lx, &ly); double sx, sy; - container_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy); + container_at_coords(seat, lx, ly, &surface, &sx, &sy); + + seat->touch_id = event->touch_id; + seat->touch_x = lx; + seat->touch_y = ly; if (!surface) { return; } // TODO: fall back to cursor simulation if client has not bound to touch - if (seat_is_input_allowed(cursor->seat, surface)) { - wlr_seat_touch_notify_down(seat, surface, event->time_msec, + if (seat_is_input_allowed(seat, surface)) { + wlr_seat_touch_notify_down(wlr_seat, surface, event->time_msec, event->touch_id, sx, sy); cursor->image_client = NULL; wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); @@ -330,7 +342,8 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat); struct wlr_event_touch_motion *event = data; - struct wlr_seat *seat = cursor->seat->wlr_seat; + struct sway_seat *seat = cursor->seat; + struct wlr_seat *wlr_seat = seat->wlr_seat; struct wlr_surface *surface = NULL; double lx, ly; @@ -339,14 +352,25 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { double sx, sy; container_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy); + if (seat->touch_id == event->touch_id) { + seat->touch_x = lx; + seat->touch_y = ly; + + struct wlr_drag_icon *wlr_drag_icon; + wl_list_for_each(wlr_drag_icon, &wlr_seat->drag_icons, link) { + struct sway_drag_icon *drag_icon = wlr_drag_icon->data; + drag_icon_update_position(drag_icon); + } + } + if (!surface) { return; } // TODO: fall back to cursor simulation if client has not bound to touch if (seat_is_input_allowed(cursor->seat, surface)) { - wlr_seat_touch_notify_motion( - seat, event->time_msec, event->touch_id, sx, sy); + wlr_seat_touch_notify_motion(wlr_seat, event->time_msec, + event->touch_id, sx, sy); } } diff --git a/sway/input/seat.c b/sway/input/seat.c index 071ef020..1ea36466 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -6,21 +6,22 @@ #include #include #include +#include "log.h" #include "sway/debug.h" -#include "sway/tree/container.h" -#include "sway/tree/workspace.h" -#include "sway/input/seat.h" +#include "sway/desktop.h" #include "sway/input/cursor.h" #include "sway/input/input-manager.h" #include "sway/input/keyboard.h" +#include "sway/input/seat.h" #include "sway/ipc-server.h" #include "sway/layers.h" #include "sway/output.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" +#include "sway/tree/container.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" -#include "log.h" +#include "sway/tree/workspace.h" static void seat_device_destroy(struct sway_seat_device *seat_device) { if (!seat_device) { @@ -40,6 +41,8 @@ void seat_destroy(struct sway_seat *seat) { seat_device_destroy(seat_device); } sway_cursor_destroy(seat->cursor); + wl_list_remove(&seat->new_container.link); + wl_list_remove(&seat->new_drag_icon.link); wl_list_remove(&seat->link); wlr_seat_destroy(seat->wlr_seat); } @@ -234,6 +237,90 @@ static void handle_new_container(struct wl_listener *listener, void *data) { seat_container_from_container(seat, con); } +static void drag_icon_damage_whole(struct sway_drag_icon *icon) { + if (!icon->wlr_drag_icon->mapped) { + return; + } + desktop_damage_surface(icon->wlr_drag_icon->surface, icon->x, icon->y, true); +} + +void drag_icon_update_position(struct sway_drag_icon *icon) { + drag_icon_damage_whole(icon); + + struct wlr_drag_icon *wlr_icon = icon->wlr_drag_icon; + struct sway_seat *seat = icon->seat; + struct wlr_cursor *cursor = seat->cursor->cursor; + if (wlr_icon->is_pointer) { + icon->x = cursor->x + wlr_icon->sx; + icon->y = cursor->y + wlr_icon->sy; + } else { + struct wlr_touch_point *point = + wlr_seat_touch_get_point(seat->wlr_seat, wlr_icon->touch_id); + if (point == NULL) { + return; + } + icon->x = seat->touch_x + wlr_icon->sx; + icon->y = seat->touch_y + wlr_icon->sy; + } + + drag_icon_damage_whole(icon); +} + +static void drag_icon_handle_surface_commit(struct wl_listener *listener, + void *data) { + struct sway_drag_icon *icon = + wl_container_of(listener, icon, surface_commit); + drag_icon_update_position(icon); +} + +static void drag_icon_handle_map(struct wl_listener *listener, void *data) { + struct sway_drag_icon *icon = wl_container_of(listener, icon, map); + drag_icon_damage_whole(icon); +} + +static void drag_icon_handle_unmap(struct wl_listener *listener, void *data) { + struct sway_drag_icon *icon = wl_container_of(listener, icon, unmap); + drag_icon_damage_whole(icon); +} + +static void drag_icon_handle_destroy(struct wl_listener *listener, + void *data) { + struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy); + icon->wlr_drag_icon->data = NULL; + wl_list_remove(&icon->link); + wl_list_remove(&icon->surface_commit.link); + wl_list_remove(&icon->unmap.link); + wl_list_remove(&icon->destroy.link); + free(icon); +} + +static void handle_new_drag_icon(struct wl_listener *listener, void *data) { + struct sway_seat *seat = wl_container_of(listener, seat, new_drag_icon); + struct wlr_drag_icon *wlr_drag_icon = data; + + struct sway_drag_icon *icon = calloc(1, sizeof(struct sway_drag_icon)); + if (icon == NULL) { + wlr_log(L_ERROR, "Allocation failed"); + return; + } + icon->seat = seat; + icon->wlr_drag_icon = wlr_drag_icon; + wlr_drag_icon->data = icon; + + icon->surface_commit.notify = drag_icon_handle_surface_commit; + wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); + icon->unmap.notify = drag_icon_handle_unmap; + wl_signal_add(&wlr_drag_icon->events.unmap, &icon->unmap); + icon->map.notify = drag_icon_handle_map; + wl_signal_add(&wlr_drag_icon->events.map, &icon->map); + icon->destroy.notify = drag_icon_handle_destroy; + wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); + + wl_list_insert(&root_container.sway_root->drag_icons, &icon->link); + + drag_icon_update_position(icon); +} + static void collect_focus_iter(struct sway_container *con, void *data) { struct sway_seat *seat = data; if (con->type > C_WORKSPACE) { @@ -278,6 +365,9 @@ struct sway_seat *seat_create(struct sway_input_manager *input, &seat->new_container); seat->new_container.notify = handle_new_container; + wl_signal_add(&seat->wlr_seat->events.new_drag_icon, &seat->new_drag_icon); + seat->new_drag_icon.notify = handle_new_drag_icon; + seat->input = input; wl_list_init(&seat->devices); diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 6d4cd088..f56fbffa 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -37,6 +37,7 @@ void layout_init(void) { root_container.sway_root->output_layout = wlr_output_layout_create(); wl_list_init(&root_container.sway_root->outputs); wl_list_init(&root_container.sway_root->xwayland_unmanaged); + wl_list_init(&root_container.sway_root->drag_icons); wl_signal_init(&root_container.sway_root->events.new_container); root_container.sway_root->output_layout_change.notify = From b23cd827cf934ef7f631b7c448e7afa4147c1936 Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Tue, 12 Jun 2018 10:37:47 -0400 Subject: [PATCH 2/5] Sort binding key lists Sort the list comprising the set of keys for the binding in ascending order. (Keyboard shortcuts depend only on the set of simultaneously pressed keys, not their order, so this change should have no external effect.) This simplifies comparisons between bindings. --- include/sway/config.h | 2 +- sway/commands/bind.c | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 81e9c382..e75b0664 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -30,7 +30,7 @@ struct sway_binding { bool release; bool locked; bool bindcode; - list_t *keys; + list_t *keys; // sorted in ascending order uint32_t modifiers; char *command; }; diff --git a/sway/commands/bind.c b/sway/commands/bind.c index d0e3e22f..821f9cd1 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -32,7 +32,7 @@ void free_sway_binding(struct sway_binding *binding) { * Note that keyboard layout is not considered, so the bindings might actually * not be equivalent on some layouts. */ -bool binding_key_compare(struct sway_binding *binding_a, +static bool binding_key_compare(struct sway_binding *binding_a, struct sway_binding *binding_b) { if (binding_a->release != binding_b->release) { return false; @@ -50,18 +50,12 @@ bool binding_key_compare(struct sway_binding *binding_a, return false; } + // Keys are sorted int keys_len = binding_a->keys->length; for (int i = 0; i < keys_len; ++i) { - uint32_t key_a = *(uint32_t*)binding_a->keys->items[i]; - bool found = false; - for (int j = 0; j < keys_len; ++j) { - uint32_t key_b = *(uint32_t*)binding_b->keys->items[j]; - if (key_b == key_a) { - found = true; - break; - } - } - if (!found) { + uint32_t key_a = *(uint32_t *)binding_a->keys->items[i]; + uint32_t key_b = *(uint32_t *)binding_b->keys->items[i]; + if (key_a != key_b) { return false; } } @@ -69,6 +63,12 @@ bool binding_key_compare(struct sway_binding *binding_a, return true; } +static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) { + uint32_t key_a = **(uint32_t **)keyp_a; + uint32_t key_b = **(uint32_t **)keyp_b; + return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0); +} + static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, bool bindcode) { const char *bindtype = bindcode ? "bindcode" : "bindsym"; @@ -169,6 +169,9 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, free_flat_list(split); binding->order = binding_order++; + // sort ascending + list_qsort(binding->keys, key_qsort_cmp); + list_t *mode_bindings; if (bindcode) { mode_bindings = config->current_mode->keycode_bindings; From ca061ba8bf94e1d09e1d912871841212778044ed Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Tue, 12 Jun 2018 11:07:11 -0400 Subject: [PATCH 3/5] Fix keyboard shortcut handling inconsistencies * Ensure that modifier keys are identified even when the next key does not produce a keysym. This requires that modifier change tracking be done for each sway_shortcut_state. * Permit regular and --release shortcuts on the same key combination. Distinct bindings are identified for press and release cases; note that the release binding needs to be identified for both key press and key release events. * Maintain ascending sort order for the shortcut state list, and keep track of the number of pressed key ids, for simpler (and hence faster) searching of the list of key bindings. * Move binding duplicate detection into get_active_binding to avoid duplicating error messages. --- include/sway/input/keyboard.h | 5 +- sway/input/keyboard.c | 220 ++++++++++++++++++---------------- 2 files changed, 122 insertions(+), 103 deletions(-) diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h index e99a54b1..6713398e 100644 --- a/include/sway/input/keyboard.h +++ b/include/sway/input/keyboard.h @@ -21,7 +21,9 @@ struct sway_shortcut_state { * including duplicates when a keycode generates multiple key ids. */ uint32_t pressed_keycodes[SWAY_KEYBOARD_PRESSED_KEYS_CAP]; - int last_key_index; + uint32_t last_keycode; + uint32_t last_raw_modifiers; + size_t npressed; }; struct sway_keyboard { @@ -36,7 +38,6 @@ struct sway_keyboard { struct sway_shortcut_state state_keysyms_raw; struct sway_shortcut_state state_keycodes; struct sway_binding *held_binding; - uint32_t last_modifiers; }; struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index d90655f2..9e093828 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -10,85 +10,111 @@ #include "log.h" /** - * Update the shortcut model state in response to new input + * Remove all key ids associated to a keycode from the list of pressed keys */ -static void update_shortcut_state(struct sway_shortcut_state *state, - struct wlr_event_keyboard_key *event, uint32_t new_key, - bool last_key_was_a_modifier) { - if (event->state == WLR_KEY_PRESSED) { - if (last_key_was_a_modifier && state->last_key_index >= 0) { - // Last pressed key before this one was a modifier - state->pressed_keycodes[state->last_key_index] = 0; - state->pressed_keys[state->last_key_index] = 0; - state->last_key_index = -1; +static void state_erase_key(struct sway_shortcut_state *state, + uint32_t keycode) { + size_t j = 0; + for (size_t i = 0; i < state->npressed; ++i) { + if (i > j) { + state->pressed_keys[j] = state->pressed_keys[i]; + state->pressed_keycodes[j] = state->pressed_keycodes[i]; } - - // Add current key to set; there may be duplicates - for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) { - if (!state->pressed_keys[i]) { - state->pressed_keys[i] = new_key; - state->pressed_keycodes[i] = event->keycode; - state->last_key_index = i; - break; - } - } - } else { - for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) { - // The same keycode may match multiple keysyms. - if (state->pressed_keycodes[i] == event->keycode) { - state->pressed_keys[i] = 0; - state->pressed_keycodes[i] = 0; - } + if (state->pressed_keycodes[i] != keycode) { + ++j; } } + while(state->npressed > j) { + --state->npressed; + state->pressed_keys[state->npressed] = 0; + state->pressed_keycodes[state->npressed] = 0; + } } /** - * - * Returns a binding which matches the shortcut model state (ignoring the - * `release` flag). + * Add a key id (with associated keycode) to the list of pressed keys, + * if the list is not full. */ -static struct sway_binding *get_active_binding( - struct sway_shortcut_state *state, list_t *bindings, - uint32_t modifiers, bool locked) { - int npressed_keys = 0; - for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) { - if (state->pressed_keys[i]) { - ++npressed_keys; - } +static void state_add_key(struct sway_shortcut_state *state, + uint32_t keycode, uint32_t key_id) { + if (state->npressed >= SWAY_KEYBOARD_PRESSED_KEYS_CAP) { + return; } + size_t i = 0; + while (i < state->npressed && state->pressed_keys[i] < key_id) { + ++i; + } + size_t j = state->npressed; + while (j > i) { + state->pressed_keys[j] = state->pressed_keys[j - 1]; + state->pressed_keycodes[j] = state->pressed_keycodes[j - 1]; + --j; + } + state->pressed_keys[i] = key_id; + state->pressed_keycodes[i] = keycode; + state->npressed++; +} + +/** + * Update the shortcut model state in response to new input + */ +static void update_shortcut_state(struct sway_shortcut_state *state, + struct wlr_event_keyboard_key *event, uint32_t new_key, + uint32_t raw_modifiers) { + bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers; + state->last_raw_modifiers = raw_modifiers; + + if (event->state == WLR_KEY_PRESSED) { + if (last_key_was_a_modifier && state->last_keycode) { + // Last pressed key before this one was a modifier + state_erase_key(state, state->last_keycode); + } + + // Add current key to set; there may be duplicates + state_add_key(state, event->keycode, new_key); + state->last_keycode = event->keycode; + } else { + state_erase_key(state, event->keycode); + } +} + +/** + * If one exists, finds a binding which matches the shortcut model state, + * current modifiers, release state, and locked state. + */ +static void get_active_binding(const struct sway_shortcut_state *state, + list_t *bindings, struct sway_binding **current_binding, + uint32_t modifiers, bool release, bool locked) { for (int i = 0; i < bindings->length; ++i) { struct sway_binding *binding = bindings->items[i]; if (modifiers ^ binding->modifiers || - npressed_keys != binding->keys->length || - locked > binding->locked) { + state->npressed != (size_t)binding->keys->length || + locked > binding->locked || + release != binding->release) { continue; } bool match = true; - for (int j = 0; j < binding->keys->length; ++j) { + for (size_t j = 0; j < state->npressed; j++) { uint32_t key = *(uint32_t *)binding->keys->items[j]; - - bool key_found = false; - for (int k = 0; k < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++k) { - if (state->pressed_keys[k] == key) { - key_found = true; - break; - } - } - if (!key_found) { + if (key != state->pressed_keys[j]) { match = false; break; } } - - if (match) { - return binding; + if (!match) { + continue; } - } - return NULL; + if (*current_binding && *current_binding != binding) { + wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d", + (*current_binding)->order, binding->order); + } else { + *current_binding = binding; + } + return; + } } /** @@ -204,69 +230,65 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { size_t raw_keysyms_len = keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &raw_modifiers); - struct wlr_input_device *device = - keyboard->seat_device->input_device->wlr_device; - uint32_t code_modifiers = wlr_keyboard_get_modifiers(device->keyboard); - - bool last_key_was_a_modifier = code_modifiers != keyboard->last_modifiers; - keyboard->last_modifiers = code_modifiers; + uint32_t code_modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard); // Update shortcut model state update_shortcut_state(&keyboard->state_keycodes, event, - (uint32_t)keycode, last_key_was_a_modifier); + (uint32_t)keycode, code_modifiers); for (size_t i = 0; i < translated_keysyms_len; ++i) { update_shortcut_state(&keyboard->state_keysyms_translated, event, (uint32_t)translated_keysyms[i], - last_key_was_a_modifier && i == 0); + code_modifiers); } for (size_t i = 0; i < raw_keysyms_len; ++i) { update_shortcut_state(&keyboard->state_keysyms_raw, event, (uint32_t)raw_keysyms[i], - last_key_was_a_modifier && i == 0); + code_modifiers); } - // identify which binding should be executed. - struct sway_binding *binding = get_active_binding( - &keyboard->state_keycodes, - config->current_mode->keycode_bindings, - code_modifiers, input_inhibited); - struct sway_binding *translated_binding = get_active_binding( - &keyboard->state_keysyms_translated, - config->current_mode->keysym_bindings, - translated_modifiers, input_inhibited); - if (translated_binding && !binding) { - binding = translated_binding; - } else if (binding && translated_binding && binding != translated_binding) { - wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d", - binding->order, translated_binding->order); - } - struct sway_binding *raw_binding = get_active_binding( - &keyboard->state_keysyms_raw, - config->current_mode->keysym_bindings, - raw_modifiers, input_inhibited); - if (raw_binding && !binding) { - binding = raw_binding; - } else if (binding && raw_binding && binding != raw_binding) { - wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d", - binding->order, raw_binding->order); - } bool handled = false; - // Execute the identified binding if need be. - if (keyboard->held_binding && binding != keyboard->held_binding && + // Identify active release binding + struct sway_binding *binding_released = NULL; + get_active_binding(&keyboard->state_keycodes, + config->current_mode->keycode_bindings, &binding_released, + code_modifiers, true, input_inhibited); + get_active_binding(&keyboard->state_keysyms_translated, + config->current_mode->keysym_bindings, &binding_released, + translated_modifiers, true, input_inhibited); + get_active_binding(&keyboard->state_keysyms_raw, + config->current_mode->keysym_bindings, &binding_released, + raw_modifiers, true, input_inhibited); + + // Execute stored release binding once no longer active + if (keyboard->held_binding && binding_released != keyboard->held_binding && event->state == WLR_KEY_RELEASED) { keyboard_execute_command(keyboard, keyboard->held_binding); handled = true; } - if (binding != keyboard->held_binding) { + if (binding_released != keyboard->held_binding) { keyboard->held_binding = NULL; } - if (binding && event->state == WLR_KEY_PRESSED) { - if (binding->release) { - keyboard->held_binding = binding; - } else { - keyboard_execute_command(keyboard, binding); + if (binding_released && event->state == WLR_KEY_PRESSED) { + keyboard->held_binding = binding_released; + } + + // Identify and execute active pressed binding + if (event->state == WLR_KEY_PRESSED) { + struct sway_binding *binding_pressed = NULL; + get_active_binding(&keyboard->state_keycodes, + config->current_mode->keycode_bindings, &binding_pressed, + code_modifiers, false, input_inhibited); + get_active_binding(&keyboard->state_keysyms_translated, + config->current_mode->keysym_bindings, &binding_pressed, + translated_modifiers, false, input_inhibited); + get_active_binding(&keyboard->state_keysyms_raw, + config->current_mode->keysym_bindings, &binding_pressed, + raw_modifiers, false, input_inhibited); + + if (binding_pressed) { + keyboard_execute_command(keyboard, binding_pressed); handled = true; } } @@ -315,10 +337,6 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, wl_list_init(&keyboard->keyboard_key.link); wl_list_init(&keyboard->keyboard_modifiers.link); - keyboard->state_keycodes.last_key_index = -1; - keyboard->state_keysyms_raw.last_key_index = -1; - keyboard->state_keysyms_translated.last_key_index = -1; - return keyboard; } From 088cae45c8467b0c7a06301d9aec18f2aab55a1d Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 13 Jun 2018 19:47:43 +0100 Subject: [PATCH 4/5] Update for swaywm/wlroots#1060 --- sway/desktop/output.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 29666c00..d4115be8 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -240,7 +240,8 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, pixman_region32_t *output_damage = data->damage; float alpha = data->alpha; - if (!wlr_surface_has_buffer(surface)) { + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (texture == NULL) { return; } @@ -259,8 +260,7 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, wlr_matrix_project_box(matrix, &box, transform, rotation, wlr_output->transform_matrix); - render_texture(wlr_output, output_damage, surface->texture, &box, matrix, - alpha); + render_texture(wlr_output, output_damage, texture, &box, matrix, alpha); } static void render_layer(struct sway_output *output, From 7ed81cfd36dc92202e72d044fa2000736671d938 Mon Sep 17 00:00:00 2001 From: "Alex Xu (Hello71)" Date: Sun, 17 Jun 2018 13:57:40 -0400 Subject: [PATCH 5/5] swayidle: fix stack overflow on sleep --- swayidle/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/swayidle/main.c b/swayidle/main.c index d83ab98d..7666578f 100644 --- a/swayidle/main.c +++ b/swayidle/main.c @@ -127,7 +127,8 @@ void acquire_sleep_lock() { static int prepare_for_sleep(sd_bus_message *msg, void *userdata, sd_bus_error *ret_error) { - bool going_down = true; + /* "b" apparently reads into an int, not a bool */ + int going_down = 1; int ret = sd_bus_message_read(msg, "b", &going_down); if (ret < 0) { wlr_log(L_ERROR, "Failed to parse D-Bus response for Inhibit: %s",