diff --git a/include/sway/server.h b/include/sway/server.h index be5c8d72..1b3166ce 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -59,7 +59,7 @@ struct sway_server { struct wl_listener layer_shell_surface; struct wlr_xdg_shell *xdg_shell; - struct wl_listener xdg_shell_surface; + struct wl_listener xdg_shell_toplevel; struct wlr_tablet_manager_v2 *tablet_v2; @@ -176,7 +176,7 @@ void handle_new_output(struct wl_listener *listener, void *data); void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data); void handle_layer_shell_surface(struct wl_listener *listener, void *data); void sway_session_lock_init(void); -void handle_xdg_shell_surface(struct wl_listener *listener, void *data); +void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data); #if HAVE_XWAYLAND void handle_xwayland_surface(struct wl_listener *listener, void *data); #endif diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 960f9d71..856651a5 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -226,6 +226,7 @@ struct sway_xdg_popup { struct wlr_xdg_popup *wlr_xdg_popup; + struct wl_listener surface_commit; struct wl_listener new_popup; struct wl_listener destroy; }; diff --git a/include/sway/xdg_decoration.h b/include/sway/xdg_decoration.h index 8bef4c6d..2388ebcb 100644 --- a/include/sway/xdg_decoration.h +++ b/include/sway/xdg_decoration.h @@ -16,4 +16,6 @@ struct sway_xdg_decoration { struct sway_xdg_decoration *xdg_decoration_from_surface( struct wlr_surface *surface); +void set_xdg_decoration_mode(struct sway_xdg_decoration *deco); + #endif diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 8c6cedfe..979c4449 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -542,6 +542,26 @@ static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { output_damage_surface(output, ox, oy, surface, whole); } +static void popup_unconstrain(struct sway_layer_popup *popup) { + struct sway_layer_surface *layer = popup_get_layer(popup); + struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; + + struct wlr_output *wlr_output = layer->layer_surface->output; + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); + struct sway_output *output = wlr_output->data; + + // the output box expressed in the coordinate system of the toplevel parent + // of the popup + struct wlr_box output_toplevel_sx_box = { + .x = -layer->geo.x, + .y = -layer->geo.y, + .width = output->width, + .height = output->height, + }; + + wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); +} + static void popup_handle_map(struct wl_listener *listener, void *data) { struct sway_layer_popup *popup = wl_container_of(listener, popup, map); struct sway_layer_surface *layer = popup_get_layer(popup); @@ -558,6 +578,9 @@ static void popup_handle_unmap(struct wl_listener *listener, void *data) { static void popup_handle_commit(struct wl_listener *listener, void *data) { struct sway_layer_popup *popup = wl_container_of(listener, popup, commit); + if (popup->wlr_popup->base->initial_commit) { + popup_unconstrain(popup); + } popup_damage(popup, false); } @@ -572,26 +595,6 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { free(popup); } -static void popup_unconstrain(struct sway_layer_popup *popup) { - struct sway_layer_surface *layer = popup_get_layer(popup); - struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; - - struct wlr_output *wlr_output = layer->layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - struct sway_output *output = wlr_output->data; - - // the output box expressed in the coordinate system of the toplevel parent - // of the popup - struct wlr_box output_toplevel_sx_box = { - .x = -layer->geo.x, - .y = -layer->geo.y, - .width = output->width, - .height = output->height, - }; - - wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); -} - static void popup_handle_new_popup(struct wl_listener *listener, void *data); static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, @@ -617,8 +620,6 @@ static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, popup->new_popup.notify = popup_handle_new_popup; wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); - popup_unconstrain(popup); - return popup; } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 4c59b42a..63a0835b 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -38,6 +38,7 @@ static void popup_destroy(struct sway_view_child *child) { return; } struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; + wl_list_remove(&popup->surface_commit.link); wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->destroy.link); free(popup); @@ -51,18 +52,6 @@ static const struct sway_view_child_impl popup_impl = { static struct sway_xdg_popup *popup_create( struct wlr_xdg_popup *wlr_popup, struct sway_view *view); -static void popup_handle_new_popup(struct wl_listener *listener, void *data) { - struct sway_xdg_popup *popup = - wl_container_of(listener, popup, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - popup_create(wlr_popup, popup->child.view); -} - -static void popup_handle_destroy(struct wl_listener *listener, void *data) { - struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); - view_child_destroy(&popup->child); -} - static void popup_unconstrain(struct sway_xdg_popup *popup) { struct sway_view *view = popup->child.view; struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; @@ -87,6 +76,25 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) { wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); } +static void popup_handle_surface_commit(struct wl_listener *listener, void *data) { + struct sway_xdg_popup *popup = wl_container_of(listener, popup, surface_commit); + if (popup->wlr_xdg_popup->base->initial_commit) { + popup_unconstrain(popup); + } +} + +static void popup_handle_new_popup(struct wl_listener *listener, void *data) { + struct sway_xdg_popup *popup = + wl_container_of(listener, popup, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + popup_create(wlr_popup, popup->child.view); +} + +static void popup_handle_destroy(struct wl_listener *listener, void *data) { + struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); + view_child_destroy(&popup->child); +} + static struct sway_xdg_popup *popup_create( struct wlr_xdg_popup *wlr_popup, struct sway_view *view) { struct wlr_xdg_surface *xdg_surface = wlr_popup->base; @@ -97,22 +105,21 @@ static struct sway_xdg_popup *popup_create( return NULL; } view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); - popup->wlr_xdg_popup = xdg_surface->popup; + popup->wlr_xdg_popup = wlr_popup; + wl_signal_add(&xdg_surface->surface->events.commit, &popup->surface_commit); + popup->surface_commit.notify = popup_handle_surface_commit; wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); popup->new_popup.notify = popup_handle_new_popup; - wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); + wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); popup->destroy.notify = popup_handle_destroy; wl_signal_add(&xdg_surface->surface->events.map, &popup->child.surface_map); wl_signal_add(&xdg_surface->surface->events.unmap, &popup->child.surface_unmap); - popup_unconstrain(popup); - return popup; } - static struct sway_xdg_shell_view *xdg_shell_view_from_view( struct sway_view *view) { if (!sway_assert(view->type == SWAY_VIEW_XDG_SHELL, @@ -286,6 +293,19 @@ static void handle_commit(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_view->view; struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base; + if (xdg_surface->initial_commit) { + if (view->xdg_decoration != NULL) { + set_xdg_decoration_mode(view->xdg_decoration); + } + // XXX: https://github.com/swaywm/sway/issues/2176 + wlr_xdg_surface_schedule_configure(xdg_surface); + return; + } + + if (!xdg_surface->surface->mapped) { + return; + } + struct wlr_box new_geo; wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); bool new_size = new_geo.width != view->geometry.width || @@ -421,7 +441,6 @@ static void handle_unmap(struct wl_listener *listener, void *data) { view_unmap(view); - wl_list_remove(&xdg_shell_view->commit.link); wl_list_remove(&xdg_shell_view->new_popup.link); wl_list_remove(&xdg_shell_view->request_maximize.link); wl_list_remove(&xdg_shell_view->request_fullscreen.link); @@ -464,10 +483,6 @@ static void handle_map(struct wl_listener *listener, void *data) { transaction_commit_dirty(); - xdg_shell_view->commit.notify = handle_commit; - wl_signal_add(&toplevel->base->surface->events.commit, - &xdg_shell_view->commit); - xdg_shell_view->new_popup.notify = handle_new_popup; wl_signal_add(&toplevel->base->events.new_popup, &xdg_shell_view->new_popup); @@ -507,6 +522,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_view->destroy.link); wl_list_remove(&xdg_shell_view->map.link); wl_list_remove(&xdg_shell_view->unmap.link); + wl_list_remove(&xdg_shell_view->commit.link); view->wlr_xdg_toplevel = NULL; if (view->xdg_decoration) { view->xdg_decoration->view = NULL; @@ -519,17 +535,12 @@ struct sway_view *view_from_wlr_xdg_surface( return xdg_surface->data; } -void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { - struct wlr_xdg_surface *xdg_surface = data; - - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - sway_log(SWAY_DEBUG, "New xdg_shell popup"); - return; - } +void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) { + struct wlr_xdg_toplevel *xdg_toplevel = data; sway_log(SWAY_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'", - xdg_surface->toplevel->title, xdg_surface->toplevel->app_id); - wlr_xdg_surface_ping(xdg_surface); + xdg_toplevel->title, xdg_toplevel->app_id); + wlr_xdg_surface_ping(xdg_toplevel->base); struct sway_xdg_shell_view *xdg_shell_view = calloc(1, sizeof(struct sway_xdg_shell_view)); @@ -538,16 +549,20 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { } view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl); - xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel; + xdg_shell_view->view.wlr_xdg_toplevel = xdg_toplevel; xdg_shell_view->map.notify = handle_map; - wl_signal_add(&xdg_surface->surface->events.map, &xdg_shell_view->map); + wl_signal_add(&xdg_toplevel->base->surface->events.map, &xdg_shell_view->map); xdg_shell_view->unmap.notify = handle_unmap; - wl_signal_add(&xdg_surface->surface->events.unmap, &xdg_shell_view->unmap); + wl_signal_add(&xdg_toplevel->base->surface->events.unmap, &xdg_shell_view->unmap); + + xdg_shell_view->commit.notify = handle_commit; + wl_signal_add(&xdg_toplevel->base->surface->events.commit, + &xdg_shell_view->commit); xdg_shell_view->destroy.notify = handle_destroy; - wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy); + wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy); - xdg_surface->data = xdg_shell_view; + xdg_toplevel->base->data = xdg_shell_view; } diff --git a/sway/server.c b/sway/server.c index e4f8a7c8..be521621 100644 --- a/sway/server.c +++ b/sway/server.c @@ -185,9 +185,9 @@ bool server_init(struct sway_server *server) { server->xdg_shell = wlr_xdg_shell_create(server->wl_display, SWAY_XDG_SHELL_VERSION); - wl_signal_add(&server->xdg_shell->events.new_surface, - &server->xdg_shell_surface); - server->xdg_shell_surface.notify = handle_xdg_shell_surface; + wl_signal_add(&server->xdg_shell->events.new_toplevel, + &server->xdg_shell_toplevel); + server->xdg_shell_toplevel.notify = handle_xdg_shell_toplevel; server->tablet_v2 = wlr_tablet_v2_create(server->wl_display); diff --git a/sway/xdg_decoration.c b/sway/xdg_decoration.c index f7f5f5ed..fa8c6279 100644 --- a/sway/xdg_decoration.c +++ b/sway/xdg_decoration.c @@ -23,32 +23,7 @@ static void xdg_decoration_handle_request_mode(struct wl_listener *listener, void *data) { struct sway_xdg_decoration *deco = wl_container_of(listener, deco, request_mode); - struct sway_view *view = deco->view; - enum wlr_xdg_toplevel_decoration_v1_mode mode = - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; - enum wlr_xdg_toplevel_decoration_v1_mode client_mode = - deco->wlr_xdg_decoration->requested_mode; - - bool floating; - if (view->container) { - floating = container_is_floating(view->container); - bool csd = false; - csd = client_mode == - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; - view_update_csd_from_client(view, csd); - arrange_container(view->container); - transaction_commit_dirty(); - } else { - floating = view->impl->wants_floating && - view->impl->wants_floating(view); - } - - if (floating && client_mode) { - mode = client_mode; - } - - wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration, - mode); + set_xdg_decoration_mode(deco); } void handle_xdg_decoration(struct wl_listener *listener, void *data) { @@ -72,7 +47,7 @@ void handle_xdg_decoration(struct wl_listener *listener, void *data) { wl_list_insert(&server.xdg_decorations, &deco->link); - xdg_decoration_handle_request_mode(&deco->request_mode, wlr_deco); + set_xdg_decoration_mode(deco); } struct sway_xdg_decoration *xdg_decoration_from_surface( @@ -85,3 +60,33 @@ struct sway_xdg_decoration *xdg_decoration_from_surface( } return NULL; } + +void set_xdg_decoration_mode(struct sway_xdg_decoration *deco) { + struct sway_view *view = deco->view; + enum wlr_xdg_toplevel_decoration_v1_mode mode = + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + enum wlr_xdg_toplevel_decoration_v1_mode client_mode = + deco->wlr_xdg_decoration->requested_mode; + + bool floating; + if (view->container) { + floating = container_is_floating(view->container); + bool csd = false; + csd = client_mode == + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + view_update_csd_from_client(view, csd); + arrange_container(view->container); + transaction_commit_dirty(); + } else { + floating = view->impl->wants_floating && + view->impl->wants_floating(view); + } + + if (floating && client_mode) { + mode = client_mode; + } + + if (view->wlr_xdg_toplevel->base->initialized) { + wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration, mode); + } +}