Merge branch 'defunct-surfaces-fix' into 'main'

Fixes for xdg-shell when clients are tearing down

See merge request wayland/weston!1960
This commit is contained in:
Leandro Ribeiro 2026-02-03 01:49:03 +00:00
commit 4d3c600b39
5 changed files with 141 additions and 57 deletions

View file

@ -324,13 +324,15 @@ weston_desktop_surface_add_resource(struct weston_desktop_surface *surface,
weston_desktop_client_get_client(surface->client);
struct wl_resource *resource;
if (!client_resource)
return NULL;
resource = wl_resource_create(wl_client,
interface,
wl_resource_get_version(client_resource),
id);
if (resource == NULL) {
wl_client_post_no_memory(wl_client);
weston_desktop_surface_destroy(surface);
return NULL;
}
if (destroy == NULL)

View file

@ -674,9 +674,10 @@ weston_desktop_xdg_toplevel_committed(struct weston_desktop_xdg_toplevel *toplev
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
wl_resource_post_error(client_resource,
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
"xdg_surface buffer does not match the configured state");
if (client_resource)
wl_resource_post_error(client_resource,
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
"xdg_surface buffer does not match the configured state");
return;
}
@ -856,9 +857,10 @@ weston_desktop_xdg_popup_protocol_grab(struct wl_client *wl_client,
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
wl_resource_post_error(client_resource,
ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was not created on the topmost popup");
if (client_resource)
wl_resource_post_error(client_resource,
ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was not created on the topmost popup");
return;
}
@ -934,9 +936,10 @@ weston_desktop_xdg_popup_destroy(struct weston_desktop_xdg_popup *popup)
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
wl_resource_post_error(client_resource,
ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was destroyed while it was not the topmost popup.");
if (client_resource)
wl_resource_post_error(client_resource,
ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was destroyed while it was not the topmost popup.");
}
weston_desktop_surface_popup_ungrab(popup->base.desktop_surface,
@ -1257,9 +1260,11 @@ weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
weston_desktop_surface_get_client(dsurface);
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
wl_resource_post_error(client_resource,
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
"Wrong configure serial: %u", serial);
if (client_resource)
wl_resource_post_error(client_resource,
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
"Wrong configure serial: %u", serial);
return;
}
@ -1286,9 +1291,13 @@ weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
{
struct weston_desktop_client *client =
weston_desktop_surface_get_client(dsurface);
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
zxdg_shell_v6_send_ping(weston_desktop_client_get_resource(client),
serial);
if (!client_resource)
return;
zxdg_shell_v6_send_ping(client_resource, serial);
}
static void
@ -1492,13 +1501,18 @@ weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
&zxdg_surface_v6_interface,
&weston_desktop_xdg_surface_implementation,
id, weston_desktop_xdg_surface_resource_destroy);
if (surface->resource == NULL)
if (surface->resource == NULL) {
weston_desktop_surface_destroy(surface->desktop_surface);
free(surface);
return;
}
if (weston_surface_has_content(wsurface)) {
wl_resource_post_error(surface->resource,
ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
"xdg_surface must not have a buffer at creation");
weston_desktop_surface_destroy(surface->desktop_surface);
free(surface);
return;
}
}
@ -1514,8 +1528,27 @@ weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
weston_desktop_client_pong(client, serial);
}
static void
weston_desktop_xdg_shell_protocol_destroy(struct wl_client *wl_client,
struct wl_resource *resource)
{
struct weston_desktop_client *client =
wl_resource_get_user_data(resource);
struct wl_list *surface_list =
weston_desktop_client_get_surface_list(client);
if (!wl_list_empty(surface_list)) {
wl_resource_post_error(resource,
ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES,
"xdg_wm_base being destroyed before child surfaces");
return;
}
weston_desktop_destroy_request(wl_client, resource);
}
static const struct zxdg_shell_v6_interface weston_desktop_xdg_shell_implementation = {
.destroy = weston_desktop_destroy_request,
.destroy = weston_desktop_xdg_shell_protocol_destroy,
.create_positioner = weston_desktop_xdg_shell_protocol_create_positioner,
.get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
.pong = weston_desktop_xdg_shell_protocol_pong,

View file

@ -1082,6 +1082,10 @@ weston_desktop_xdg_toplevel_committed(struct weston_desktop_xdg_toplevel *toplev
{
struct weston_surface *wsurface =
weston_desktop_surface_get_surface(toplevel->base.desktop_surface);
struct weston_desktop_client *client =
weston_desktop_surface_get_client(toplevel->base.desktop_surface);
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
if (!weston_surface_has_content(wsurface) && !toplevel->added) {
weston_desktop_xdg_toplevel_ensure_added(toplevel);
@ -1101,36 +1105,28 @@ weston_desktop_xdg_toplevel_committed(struct weston_desktop_xdg_toplevel *toplev
if (toplevel->next.state.maximized &&
(toplevel->next.size.width != geometry.width ||
toplevel->next.size.height != geometry.height)) {
struct weston_desktop_client *client =
weston_desktop_surface_get_client(toplevel->base.desktop_surface);
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
"xdg_surface geometry (%" PRIi32 " x %" PRIi32 ") "
"does not match the configured maximized state (%" PRIi32 " x %" PRIi32 ")",
geometry.width, geometry.height,
toplevel->next.size.width,
toplevel->next.size.height);
if (client_resource)
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
"xdg_surface geometry (%" PRIi32 " x %" PRIi32 ") "
"does not match the configured maximized state (%" PRIi32 " x %" PRIi32 ")",
geometry.width, geometry.height,
toplevel->next.size.width,
toplevel->next.size.height);
return;
}
if (toplevel->next.state.fullscreen &&
(toplevel->next.size.width < geometry.width ||
toplevel->next.size.height < geometry.height)) {
struct weston_desktop_client *client =
weston_desktop_surface_get_client(toplevel->base.desktop_surface);
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
"xdg_surface geometry (%" PRIi32 " x %" PRIi32 ") "
"is larger than the configured fullscreen state (%" PRIi32 " x %" PRIi32 ")",
geometry.width, geometry.height,
toplevel->next.size.width,
toplevel->next.size.height);
if (client_resource)
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
"xdg_surface geometry (%" PRIi32 " x %" PRIi32 ") "
"is larger than the configured fullscreen state (%" PRIi32 " x %" PRIi32 ")",
geometry.width, geometry.height,
toplevel->next.size.width,
toplevel->next.size.height);
return;
}
@ -1299,9 +1295,10 @@ weston_desktop_xdg_popup_protocol_grab(struct wl_client *wl_client,
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was not created on the topmost popup");
if (client_resource)
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was not created on the topmost popup");
return;
}
@ -1437,9 +1434,10 @@ weston_desktop_xdg_popup_destroy(struct weston_desktop_xdg_popup *popup)
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was destroyed while it was not the topmost popup.");
if (client_resource)
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was destroyed while it was not the topmost popup.");
}
weston_desktop_surface_popup_ungrab(popup->base.desktop_surface,
@ -1830,9 +1828,11 @@ weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
weston_desktop_surface_get_client(dsurface);
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
"Wrong configure serial: %u", serial);
if (client_resource)
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
"Wrong configure serial: %u", serial);
return;
}
@ -1859,9 +1859,13 @@ weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
{
struct weston_desktop_client *client =
weston_desktop_surface_get_client(dsurface);
struct wl_resource *client_resource =
weston_desktop_client_get_resource(client);
xdg_wm_base_send_ping(weston_desktop_client_get_resource(client),
serial);
if (!client_resource)
return;
xdg_wm_base_send_ping(client_resource, serial);
}
static void
@ -2087,8 +2091,11 @@ weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
&xdg_surface_interface,
&weston_desktop_xdg_surface_implementation,
id, weston_desktop_xdg_surface_resource_destroy);
if (surface->resource == NULL)
if (surface->resource == NULL) {
weston_desktop_surface_destroy(surface->desktop_surface);
free(surface);
return;
}
}
static void
@ -2102,8 +2109,27 @@ weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
weston_desktop_client_pong(client, serial);
}
static void
weston_desktop_xdg_shell_protocol_destroy(struct wl_client *wl_client,
struct wl_resource *resource)
{
struct weston_desktop_client *client =
wl_resource_get_user_data(resource);
struct wl_list *surface_list =
weston_desktop_client_get_surface_list(client);
if (!wl_list_empty(surface_list)) {
wl_resource_post_error(resource,
XDG_WM_BASE_ERROR_DEFUNCT_SURFACES,
"xdg_wm_base being destroyed before child surfaces");
return;
}
weston_desktop_destroy_request(wl_client, resource);
}
static const struct xdg_wm_base_interface weston_desktop_xdg_shell_implementation = {
.destroy = weston_desktop_destroy_request,
.destroy = weston_desktop_xdg_shell_protocol_destroy,
.create_positioner = weston_desktop_xdg_shell_protocol_create_positioner,
.get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
.pong = weston_desktop_xdg_shell_protocol_pong,

View file

@ -372,9 +372,9 @@ if get_option('shell-desktop')
],
},
{
'name': 'xdg-shell-initial-commit',
'name': 'xdg-shell-test',
'sources': [
'xdg-shell-intial-commit.c',
'xdg-shell-test.c',
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
],

View file

@ -48,7 +48,7 @@ fixture_setup(struct weston_test_harness *harness)
setup.renderer = WESTON_RENDERER_PIXMAN;
setup.width = 320;
setup.height = 240;
setup.shell = SHELL_DESKTOP;
setup.shell = SHELL_TEST_DESKTOP;
setup.logging_scopes = "proto,log,test-harness-plugin";
setup.refresh = HIGHEST_OUTPUT_REFRESH;
@ -182,3 +182,26 @@ TEST(initial_commit_without_a_buffer_subsurface)
return RESULT_OK;
}
TEST(defunct_surfaces)
{
struct xdg_client *xdg_client = create_xdg_client();
struct xdg_surface_data *xdg_surface = create_xdg_surface(xdg_client);
xdg_surface_make_toplevel(xdg_surface, "weston.test", "xdg-test");
xdg_surface_wait_configure(xdg_surface);
xdg_surface_commit_solid(xdg_surface, 255, 128, 255);
wl_display_roundtrip(xdg_client->client->wl_display);
/* Destroy xdg_wm_base without destroying its children. */
xdg_wm_base_destroy(xdg_client->xdg_wm_base);
expect_protocol_error(xdg_client->client, NULL, XDG_WM_BASE_ERROR_DEFUNCT_SURFACES);
destroy_xdg_surface(xdg_surface);
client_destroy(xdg_client->client);
free(xdg_client);
return RESULT_OK;
}