xwm: Add command line option to disable window decor

Our window decor uses cairo-xcb. cairo-xcb stores xcb_connection_t
internally and uses them as kind of a hash key for internal bookkeeping.
This needs to be torn down with a cairo_device_finish, when the last
cairo surface is destroyed, and we are not properly handling that.

Because of this weston bug, if the Xwayland server dies, is restarted,
and the weston X window manager gets the same xcb_connection_t pointer
value for a new connection that it had for a previous connection,
cairo-xcb will use stale state and crash.

Weston is used in some places (like Mesa CI) where Xwayland crashes are
more common than one might usually expect, and weston needs to be robust
against these failures. It's ok to have no window frames in xwl in these
cases, because nobody is interacting with the windows.

The '--no-xwm-decorations' command line option will now remove
cairo-xcb from use entirely, so this crash can no longer happen.

We should still fix the bugs in our cairo usage, but I think long term
it's still ok to have a way to disable this and reduce complexity.

Ref #1042

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
This commit is contained in:
Derek Foreman 2025-07-23 09:31:22 -05:00
parent 98d4438265
commit 6b1b3d167d
3 changed files with 51 additions and 18 deletions

View file

@ -721,6 +721,7 @@ usage(int error_code)
" -i, --idle-time=SECS\tIdle time in seconds\n"
#if defined(BUILD_XWAYLAND)
" --xwayland\t\tLoad the xwayland module\n"
" --no-xwm-decorations\tDisable Xwayland window decor\n"
#endif
" --modules\t\tLoad the comma-separated list of modules\n"
" --log=FILE\t\tLog to the given file\n"
@ -4532,6 +4533,7 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
char *renderer = NULL;
char *shell = NULL;
bool xwayland = false;
bool no_xwm_decorations = false;
char *modules = NULL;
char *option_modules = NULL;
char *log = NULL;
@ -4574,6 +4576,7 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
{ WESTON_OPTION_INTEGER, "idle-time", 'i', &idle_time },
#if defined(BUILD_XWAYLAND)
{ WESTON_OPTION_BOOLEAN, "xwayland", 0, &xwayland },
{ WESTON_OPTION_BOOLEAN, "no-xwm-decorations", 0, &no_xwm_decorations },
#endif
{ WESTON_OPTION_STRING, "modules", 0, &option_modules },
{ WESTON_OPTION_STRING, "log", 0, &log },
@ -4847,6 +4850,7 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
if (!wet_xwl)
goto out;
}
wet.compositor->no_xwm_decorations = no_xwm_decorations;
weston_config_section_get_string(section, "modules", &modules, "");
if (load_modules(wet.compositor, modules, &argc, argv) < 0)

View file

@ -1425,6 +1425,8 @@ struct weston_compositor {
/* if set use this placeholder-color to use instead of the default
* grenadier one */
uint32_t placeholder_color;
bool no_xwm_decorations;
};
struct weston_solid_buffer_values {

View file

@ -663,8 +663,15 @@ static void
weston_wm_window_get_frame_size(struct weston_wm_window *window,
int *width, int *height)
{
struct weston_compositor *comp = window->wm->server->compositor;
struct theme *t = window->wm->theme;
if (comp->no_xwm_decorations) {
*width = window->width;
*height = window->height;
return;
}
if (window->fullscreen) {
*width = window->width;
*height = window->height;
@ -681,8 +688,15 @@ static void
weston_wm_window_get_child_position(struct weston_wm_window *window,
int *x, int *y)
{
struct weston_compositor *comp = window->wm->server->compositor;
struct theme *t = window->wm->theme;
if (comp->no_xwm_decorations) {
*x = 0;
*y = 0;
return;
}
if (window->fullscreen) {
*x = 0;
*y = 0;
@ -1096,6 +1110,9 @@ weston_wm_window_set_net_frame_extents(struct weston_wm_window *window)
uint32_t property[4];
int top = 0, bottom = 0, left = 0, right = 0;
if (!window->frame)
return;
if (!window->fullscreen)
frame_decoration_sizes(window->frame, &top, &bottom, &left, &right);
@ -1149,6 +1166,7 @@ static void
weston_wm_window_create_frame(struct weston_wm_window *window)
{
struct weston_wm *wm = window->wm;
struct weston_compositor *comp = wm->server->compositor;
uint32_t values[3];
int x, y, width, height;
int buttons = FRAME_BUTTON_CLOSE;
@ -1159,14 +1177,19 @@ weston_wm_window_create_frame(struct weston_wm_window *window)
if (window->decorate & MWM_DECOR_MINIMIZE)
buttons |= FRAME_BUTTON_MINIMIZE;
window->frame = frame_create(window->wm->theme,
window->width, window->height,
buttons, window->name, NULL);
window->frame = NULL;
if (!window->frame)
return;
if (!comp->no_xwm_decorations) {
window->frame = frame_create(window->wm->theme,
window->width, window->height,
buttons, window->name, NULL);
frame_resize_inside(window->frame, window->width, window->height);
if (!window->frame)
return;
}
if (window->frame)
frame_resize_inside(window->frame, window->width, window->height);
weston_wm_window_get_frame_size(window, &width, &height);
weston_wm_window_get_child_position(window, &x, &y);
@ -1204,13 +1227,14 @@ weston_wm_window_create_frame(struct weston_wm_window *window)
weston_wm_configure_window(wm, window->id,
XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
window->cairo_surface =
cairo_xcb_surface_create_with_xrender_format(wm->conn,
wm->screen,
window->frame_id,
&wm->format_rgba,
width, height);
window->cairo_surface = NULL;
if (!comp->no_xwm_decorations)
window->cairo_surface =
cairo_xcb_surface_create_with_xrender_format(wm->conn,
wm->screen,
window->frame_id,
&wm->format_rgba,
width, height);
hash_table_insert(wm->window_hash, window->frame_id, window);
weston_wm_window_send_configure_notify(window);
}
@ -1369,6 +1393,9 @@ weston_wm_window_draw_decoration(struct weston_wm_window *window)
int width, height;
const char *how;
if (!window->frame)
return;
weston_wm_window_get_frame_size(window, &width, &height);
cairo_xcb_surface_set_size(window->cairo_surface, width, height);
@ -1426,7 +1453,7 @@ weston_wm_window_set_pending_state(struct weston_wm_window *window)
window->height + 2);
}
if (window->decorate && !window->fullscreen) {
if (window->decorate && !window->fullscreen && window->frame) {
frame_input_rect(window->frame, &input_x, &input_y,
&input_w, &input_h);
} else {
@ -2282,7 +2309,7 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
"PRESS" : "RELEASE", button->detail);
if (!wm_lookup_window(wm, button->event, &window) ||
!window->decorate)
!window->decorate || !window->frame)
return;
if (button->detail != 1 && button->detail != 2)
@ -2380,7 +2407,7 @@ weston_wm_handle_motion(struct weston_wm *wm, xcb_generic_event_t *event)
int cursor;
if (!wm_lookup_window(wm, motion->event, &window) ||
!window->decorate)
!window->decorate || !window->frame)
return;
location = frame_pointer_motion(window->frame, NULL,
@ -2401,7 +2428,7 @@ weston_wm_handle_enter(struct weston_wm *wm, xcb_generic_event_t *event)
int cursor;
if (!wm_lookup_window(wm, enter->event, &window) ||
!window->decorate)
!window->decorate || !window->frame)
return;
location = frame_pointer_enter(window->frame, NULL,
@ -2420,7 +2447,7 @@ weston_wm_handle_leave(struct weston_wm *wm, xcb_generic_event_t *event)
struct weston_wm_window *window;
if (!wm_lookup_window(wm, leave->event, &window) ||
!window->decorate)
!window->decorate || !window->frame)
return;
frame_pointer_leave(window->frame, NULL);