From c8224270914909c02180e4892132fde3fa5cedb9 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Thu, 25 Jun 2020 15:26:16 -0400 Subject: [PATCH 1/5] input/pointer: correctly handle bindings for synthetic events This commit addresses a regression introduced in 8fa74ad. Fixes #5481. --- sway/input/seatop_default.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index a1b4aeb2a..55c9159ac 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -280,8 +280,9 @@ static bool trigger_pointer_button_binding(struct sway_seat *seat, enum wlr_button_state state, uint32_t modifiers, bool on_titlebar, bool on_border, bool on_contents, bool on_workspace) { // We can reach this for non-pointer devices if we're currently emulating - // pointer input for one. Emulated input should not trigger bindings. - if (device->type != WLR_INPUT_DEVICE_POINTER) { + // pointer input for one. Emulated input should not trigger bindings. The + // device can be NULL if this is synthetic (e.g. swaymsg-generated) input. + if (device && device->type != WLR_INPUT_DEVICE_POINTER) { return false; } From bb85b9070d05cc707146aafec56b7452441a4bd2 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Fri, 26 Jun 2020 20:12:28 -0400 Subject: [PATCH 2/5] tree/view: fix smart borders with tabbed/stacked ancestor Fixes #5484. --- sway/tree/view.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index 6dccaa2e6..fb397c422 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -211,6 +211,23 @@ bool view_ancestor_is_only_visible(struct sway_view *view) { return only_visible; } +static bool view_is_only_visible(struct sway_view *view) { + struct sway_container *con = view->container; + while (con) { + enum sway_container_layout layout = container_parent_layout(con); + if (layout != L_TABBED && layout != L_STACKED) { + list_t *siblings = container_get_siblings(con); + if (siblings && siblings->length > 1) { + return false; + } + } + + con = con->parent; + } + + return true; +} + static bool gaps_to_edge(struct sway_view *view) { struct side_gaps gaps = view->container->workspace->current_gaps; return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0; @@ -245,25 +262,31 @@ void view_autoconfigure(struct sway_view *view) { double y_offset = 0; if (!container_is_floating(con) && ws) { - - bool smart = config->hide_edge_borders_smart == ESMART_ON || - (config->hide_edge_borders_smart == ESMART_NO_GAPS && - !gaps_to_edge(view)); - bool hide_smart = smart && view_ancestor_is_only_visible(view); - if (config->hide_edge_borders == E_BOTH - || config->hide_edge_borders == E_VERTICAL || hide_smart) { + || config->hide_edge_borders == E_VERTICAL) { con->border_left = con->x != ws->x; int right_x = con->x + con->width; con->border_right = right_x != ws->x + ws->width; } + if (config->hide_edge_borders == E_BOTH - || config->hide_edge_borders == E_HORIZONTAL || hide_smart) { + || config->hide_edge_borders == E_HORIZONTAL) { con->border_top = con->y != ws->y; int bottom_y = con->y + con->height; con->border_bottom = bottom_y != ws->y + ws->height; } + bool smart = config->hide_edge_borders_smart == ESMART_ON || + (config->hide_edge_borders_smart == ESMART_NO_GAPS && + !gaps_to_edge(view)); + if (smart) { + bool show_border = !view_is_only_visible(view); + con->border_left &= show_border; + con->border_right &= show_border; + con->border_top &= show_border; + con->border_bottom &= show_border; + } + // In a tabbed or stacked container, the container's y is the top of the // title area. We have to offset the surface y by the height of the title, // bar, and disable any top border because we'll always have the title bar. From d0f7e0f481a2b2e03a700d55570a3f85655ef03c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 28 Jun 2020 19:05:04 +0200 Subject: [PATCH 3/5] transaction: Mark client resize immediately ready If a client commits a new size on its own, we create a transaction for the resize like any other. However, this involves sending a configure and waiting for the ack, and wlroots will not send configure events when there has been no change. This leads to transactions timing out. Instead, just mark the view ready immediately by size when the client is already ready, so that we avoid waiting for an ack that will never come. Closes: https://github.com/swaywm/sway/issues/5490 --- sway/desktop/transaction.c | 5 +++-- sway/desktop/xdg_shell.c | 2 ++ sway/desktop/xwayland.c | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 7b9ab5867..2b268e2c2 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -501,7 +501,7 @@ void transaction_notify_view_ready_by_serial(struct sway_view *view, uint32_t serial) { struct sway_transaction_instruction *instruction = view->container->node.instruction; - if (instruction->serial == serial) { + if (instruction != NULL && instruction->serial == serial) { set_instruction_ready(instruction); } } @@ -510,7 +510,8 @@ void transaction_notify_view_ready_by_size(struct sway_view *view, int width, int height) { struct sway_transaction_instruction *instruction = view->container->node.instruction; - if (instruction->container_state.content_width == width && + if (instruction != NULL && + instruction->container_state.content_width == width && instruction->container_state.content_height == height) { set_instruction_ready(instruction); } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 2bf026f76..df751ef6f 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -293,6 +293,8 @@ static void handle_commit(struct wl_listener *listener, void *data) { memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); desktop_damage_view(view); transaction_commit_dirty(); + transaction_notify_view_ready_by_size(view, + new_geo.width, new_geo.height); } else { memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 743e85bcb..c972fd3a7 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -383,6 +383,8 @@ static void handle_commit(struct wl_listener *listener, void *data) { memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); desktop_damage_view(view); transaction_commit_dirty(); + transaction_notify_view_ready_by_size(view, + new_geo.width, new_geo.height); } else { memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); } From 492267a5d6924e4f3a2e2326240eb064c3d2d7c2 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 28 Jun 2020 15:33:03 +0200 Subject: [PATCH 4/5] seat: Refocus seat when wlr_drag is destroyed wlr_drag installs grabs for the full duration of the drag, leading to the drag target not being focused when the drag ends. This leads to unexpected focus behavior, especially for the keyboard which requires toggling focus away and back to set. We can only fix the focus once the grabs are released, so refocus the seat when the wlr_drag destroy event is received. Closes: https://github.com/swaywm/sway/issues/5116 --- include/sway/input/seat.h | 6 ++++++ sway/input/seat.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 37de12238..2256fff18 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -64,6 +64,12 @@ struct sway_drag_icon { struct wl_listener destroy; }; +struct sway_drag { + struct sway_seat *seat; + struct wlr_drag *wlr_drag; + struct wl_listener destroy; +}; + struct sway_seat { struct wlr_seat *wlr_seat; struct sway_cursor *cursor; diff --git a/sway/input/seat.c b/sway/input/seat.c index aa56394a9..a54bc2e7d 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -402,6 +402,31 @@ static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) { free(icon); } +static void drag_handle_destroy(struct wl_listener *listener, void *data) { + struct sway_drag *drag = wl_container_of(listener, drag, destroy); + + // Focus enter isn't sent during drag, so refocus the focused node, layer + // surface or unmanaged surface. + struct sway_seat *seat = drag->seat; + struct sway_node *focus = seat_get_focus(seat); + if (focus) { + seat_set_focus(seat, NULL); + seat_set_focus(seat, focus); + } else if (seat->focused_layer) { + struct wlr_layer_surface_v1 *layer = seat->focused_layer; + seat_set_focus_layer(seat, NULL); + seat_set_focus_layer(seat, layer); + } else { + struct wlr_surface *unmanaged = seat->wlr_seat->keyboard_state.focused_surface; + seat_set_focus_surface(seat, NULL, false); + seat_set_focus_surface(seat, unmanaged, false); + } + + drag->wlr_drag->data = NULL; + wl_list_remove(&drag->destroy.link); + free(drag); +} + static void handle_request_start_drag(struct wl_listener *listener, void *data) { struct sway_seat *seat = wl_container_of(listener, seat, request_start_drag); @@ -431,6 +456,19 @@ static void handle_request_start_drag(struct wl_listener *listener, static void handle_start_drag(struct wl_listener *listener, void *data) { struct sway_seat *seat = wl_container_of(listener, seat, start_drag); struct wlr_drag *wlr_drag = data; + + struct sway_drag *drag = calloc(1, sizeof(struct sway_drag)); + if (drag == NULL) { + sway_log(SWAY_ERROR, "Allocation failed"); + return; + } + drag->seat = seat; + drag->wlr_drag = wlr_drag; + wlr_drag->data = drag; + + drag->destroy.notify = drag_handle_destroy; + wl_signal_add(&wlr_drag->events.destroy, &drag->destroy); + struct wlr_drag_icon *wlr_drag_icon = wlr_drag->icon; if (wlr_drag_icon == NULL) { return; From 76adcc3fd3aca74bf45db69d6dbcf3a8443ff159 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 30 Jun 2020 16:05:06 +0200 Subject: [PATCH 5/5] output: simplify loop over layer surfaces --- sway/desktop/output.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 2a2e332a1..4a51b5cc7 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -434,18 +434,10 @@ struct sway_workspace *output_get_active_workspace(struct sway_output *output) { } bool output_has_opaque_overlay_layer_surface(struct sway_output *output) { - struct wlr_layer_surface_v1 *wlr_layer_surface_v1; - wl_list_for_each(wlr_layer_surface_v1, &server.layer_shell->surfaces, link) { - if (wlr_layer_surface_v1->output != output->wlr_output || - wlr_layer_surface_v1->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) { - continue; - } - struct wlr_surface *wlr_surface = wlr_layer_surface_v1->surface; - struct sway_layer_surface *sway_layer_surface = - layer_from_wlr_layer_surface_v1(wlr_layer_surface_v1); - if (sway_layer_surface == NULL) { - continue; - } + struct sway_layer_surface *sway_layer_surface; + wl_list_for_each(sway_layer_surface, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) { + struct wlr_surface *wlr_surface = sway_layer_surface->layer_surface->surface; pixman_box32_t output_box = { .x2 = output->width, .y2 = output->height,