diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index f349f711b..68e4a74fc 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -188,7 +188,8 @@ xwl_present_reset_timer(struct xwl_present_window *xwl_present_window) CARD32 timeout; if (xwl_window && xwl_window->frame_callback && - !xorg_list_is_empty(&xwl_present_window->frame_callback_list)) + !xorg_list_is_empty(&xwl_present_window->frame_callback_list) && + !xwl_window->suspended) timeout = TIMER_LEN_FLIP; else timeout = TIMER_LEN_COPY; diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c index 5ccf0ee50..320b24e32 100644 --- a/hw/xwayland/xwayland-screen.c +++ b/hw/xwayland/xwayland-screen.c @@ -171,7 +171,6 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure, { ScreenPtr screen = closure; PropertyStateRec *rec = calldata; - struct xwl_screen *xwl_screen; struct xwl_window *xwl_window; if (rec->win->drawable.pScreen != screen) @@ -181,10 +180,7 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure, if (!xwl_window) return; - xwl_screen = xwl_screen_get(screen); - - if (rec->prop->propertyName == xwl_screen->allow_commits_prop) - xwl_window_update_property(xwl_window, rec); + xwl_window_update_property(xwl_window, rec); } #ifdef XACE @@ -204,7 +200,8 @@ xwl_access_property_callback(CallbackListPtr *pcbl, void *closure, ScreenPtr pScreen = closure; struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); - if (prop->propertyName == xwl_screen->allow_commits_prop) { + if (prop->propertyName == xwl_screen->allow_commits_prop || + prop->propertyName == xwl_screen->suspended_prop) { /* Only the WM and the Xserver itself */ if (client != serverClient && client->index != xwl_screen->wm_client_id && @@ -871,6 +868,7 @@ Bool xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) { static const char allow_commits[] = "_XWAYLAND_ALLOW_COMMITS"; + static const char suspended[] = "_XWAYLAND_SUSPENDED"; struct xwl_screen *xwl_screen; Pixel red_mask, blue_mask, green_mask; int ret, bpc, green_bpc, i; @@ -1181,6 +1179,12 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) if (xwl_screen->allow_commits_prop == BAD_RESOURCE) return FALSE; + xwl_screen->suspended_prop = MakeAtom(suspended, + strlen(suspended), + TRUE); + if (xwl_screen->suspended_prop == BAD_RESOURCE) + return FALSE; + AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen); AddCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, pScreen); #ifdef XACE diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h index ffbaa09e7..538e8db8d 100644 --- a/hw/xwayland/xwayland-screen.h +++ b/hw/xwayland/xwayland-screen.h @@ -141,6 +141,7 @@ struct xwl_screen { struct glamor_context *glamor_ctx; Atom allow_commits_prop; + Atom suspended_prop; /* The preferred GLVND vendor. If NULL, "mesa" is assumed. */ const char *glvnd_vendor; diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index 9c3efa0b6..06b007eb7 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -172,17 +172,67 @@ xwl_window_set_allow_commits_from_property(struct xwl_window *xwl_window, xwl_window_set_allow_commits(xwl_window, !!propdata[0], "from property"); } +static void +xwl_window_set_suspended(struct xwl_window *xwl_window, Bool suspended, + const char *debug_msg) +{ + xwl_window->suspended = suspended; + DebugF("XWAYLAND: win %d suspended = %u (%s)\n", + xwl_window->toplevel->drawable.id, suspended, debug_msg); +} + +static void +xwl_window_reset_suspended(struct xwl_window *xwl_window, const char *debug_msg) +{ + xwl_window_set_suspended(xwl_window, FALSE, debug_msg); +} + +static void +xwl_window_set_suspended_from_property(struct xwl_window *xwl_window, PropertyPtr prop) +{ + static Bool warned = FALSE; + CARD32 *propdata; + + if (prop->propertyName != xwl_window->xwl_screen->suspended_prop) + FatalError("Xwayland internal error: prop mismatch in %s.\n", __func__); + + if (prop->type != XA_CARDINAL || prop->format != 32 || prop->size != 1) { + /* Not properly set, so fall back to the default value */ + xwl_window_reset_suspended(xwl_window, "WM fault"); + + if (!warned) { + LogMessageVerb(X_WARNING, 0, "Window manager is misusing property %s.\n", + NameForAtom(prop->propertyName)); + warned = TRUE; + } + return; + } + + propdata = prop->data; + xwl_window_set_suspended(xwl_window, !!propdata[0], "from property"); +} + void xwl_window_update_property(struct xwl_window *xwl_window, PropertyStateRec *propstate) { + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + switch (propstate->state) { case PropertyNewValue: - xwl_window_set_allow_commits_from_property(xwl_window, propstate->prop); + if (propstate->prop->propertyName == xwl_screen->allow_commits_prop) { + xwl_window_set_allow_commits_from_property(xwl_window, propstate->prop); + } else if (propstate->prop->propertyName == xwl_screen->suspended_prop) { + xwl_window_set_suspended_from_property(xwl_window, propstate->prop); + } break; case PropertyDelete: - xwl_window_set_allow_commits(xwl_window, TRUE, "property deleted"); + if (propstate->prop->propertyName == xwl_screen->allow_commits_prop) { + xwl_window_set_allow_commits(xwl_window, TRUE, "property deleted"); + } else if (propstate->prop->propertyName == xwl_screen->suspended_prop) { + xwl_window_reset_suspended(xwl_window, "property deleted"); + } break; default: diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h index 0e8e54922..0323005d0 100644 --- a/hw/xwayland/xwayland-window.h +++ b/hw/xwayland/xwayland-window.h @@ -90,6 +90,7 @@ struct xwl_window { struct xorg_list link_damage; struct xorg_list link_window; struct wl_callback *frame_callback; + Bool suspended; Bool allow_commits; struct xorg_list window_buffers_available; struct xorg_list window_buffers_unavailable;