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/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, 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)); } 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; 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; } diff --git a/sway/tree/view.c b/sway/tree/view.c index 01841d131..9706de42b 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.