diff --git a/include/sway/server.h b/include/sway/server.h index 0e4ec2be3..6d15da0f6 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -60,7 +60,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; @@ -171,7 +171,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 960f9d71c..856651a52 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 8bef4c6d4..2388ebcbb 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/xdg_shell.c b/sway/desktop/xdg_shell.c index 377a0f1c9..24fe54dcc 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, @@ -279,6 +286,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 || @@ -409,7 +429,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); @@ -452,10 +471,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); @@ -495,6 +510,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; @@ -507,17 +523,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)); @@ -526,16 +537,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 cc4719d72..23501966d 100644 --- a/sway/server.c +++ b/sway/server.c @@ -140,9 +140,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 ec9e8d689..17fcf0ec6 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->surface->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->surface->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->surface->data; - - struct sway_xdg_decoration *deco = calloc(1, sizeof(*deco)); - if (deco == NULL) { - return; + if (view->wlr_xdg_toplevel->base->init_state == WLR_XDG_SURFACE_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->surface->surface == surface) { - return deco; - } - } - return NULL; }