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,36 +542,6 @@ static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { output_damage_surface(output, ox, oy, surface, whole); } -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); - struct wlr_output *wlr_output = layer->layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - surface_enter_output(popup->wlr_popup->base->surface, wlr_output->data); - popup_damage(popup, true); -} - -static void popup_handle_unmap(struct wl_listener *listener, void *data) { - struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap); - popup_damage(popup, true); -} - -static void popup_handle_commit(struct wl_listener *listener, void *data) { - struct sway_layer_popup *popup = wl_container_of(listener, popup, commit); - popup_damage(popup, false); -} - -static void popup_handle_destroy(struct wl_listener *listener, void *data) { - struct sway_layer_popup *popup = - wl_container_of(listener, popup, destroy); - - wl_list_remove(&popup->map.link); - wl_list_remove(&popup->unmap.link); - wl_list_remove(&popup->destroy.link); - wl_list_remove(&popup->commit.link); - 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; @@ -592,6 +562,39 @@ static void popup_unconstrain(struct sway_layer_popup *popup) { 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); + struct wlr_output *wlr_output = layer->layer_surface->output; + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); + surface_enter_output(popup->wlr_popup->base->surface, wlr_output->data); + popup_damage(popup, true); +} + +static void popup_handle_unmap(struct wl_listener *listener, void *data) { + struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap); + popup_damage(popup, true); +} + +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); +} + +static void popup_handle_destroy(struct wl_listener *listener, void *data) { + struct sway_layer_popup *popup = + wl_container_of(listener, popup, destroy); + + wl_list_remove(&popup->map.link); + wl_list_remove(&popup->unmap.link); + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->commit.link); + free(popup); +} + 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,6 +23,45 @@ 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); + set_xdg_decoration_mode(deco); +} + +void handle_xdg_decoration(struct wl_listener *listener, void *data) { + struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; + struct sway_xdg_shell_view *xdg_shell_view = wlr_deco->toplevel->base->data; + + struct sway_xdg_decoration *deco = calloc(1, sizeof(*deco)); + if (deco == NULL) { + return; + } + + deco->view = &xdg_shell_view->view; + deco->view->xdg_decoration = deco; + deco->wlr_xdg_decoration = wlr_deco; + + wl_signal_add(&wlr_deco->events.destroy, &deco->destroy); + deco->destroy.notify = xdg_decoration_handle_destroy; + + wl_signal_add(&wlr_deco->events.request_mode, &deco->request_mode); + deco->request_mode.notify = xdg_decoration_handle_request_mode; + + wl_list_insert(&server.xdg_decorations, &deco->link); + + set_xdg_decoration_mode(deco); +} + +struct sway_xdg_decoration *xdg_decoration_from_surface( + struct wlr_surface *surface) { + struct sway_xdg_decoration *deco; + wl_list_for_each(deco, &server.xdg_decorations, link) { + if (deco->wlr_xdg_decoration->toplevel->base->surface == surface) { + return deco; + } + } + 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; @@ -47,41 +86,7 @@ static void xdg_decoration_handle_request_mode(struct wl_listener *listener, mode = client_mode; } - wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration, - mode); -} - -void handle_xdg_decoration(struct wl_listener *listener, void *data) { - struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; - struct sway_xdg_shell_view *xdg_shell_view = wlr_deco->toplevel->base->data; - - struct sway_xdg_decoration *deco = calloc(1, sizeof(*deco)); - if (deco == NULL) { - return; + if (view->wlr_xdg_toplevel->base->initialized) { + wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration, mode); } - - deco->view = &xdg_shell_view->view; - deco->view->xdg_decoration = deco; - deco->wlr_xdg_decoration = wlr_deco; - - wl_signal_add(&wlr_deco->events.destroy, &deco->destroy); - deco->destroy.notify = xdg_decoration_handle_destroy; - - wl_signal_add(&wlr_deco->events.request_mode, &deco->request_mode); - deco->request_mode.notify = xdg_decoration_handle_request_mode; - - wl_list_insert(&server.xdg_decorations, &deco->link); - - xdg_decoration_handle_request_mode(&deco->request_mode, wlr_deco); -} - -struct sway_xdg_decoration *xdg_decoration_from_surface( - struct wlr_surface *surface) { - struct sway_xdg_decoration *deco; - wl_list_for_each(deco, &server.xdg_decorations, link) { - if (deco->wlr_xdg_decoration->toplevel->base->surface == surface) { - return deco; - } - } - return NULL; }