From da212fe72986b9ec88fc4d5f040cebfa923432b2 Mon Sep 17 00:00:00 2001 From: hujianwei Date: Sun, 30 Oct 2022 13:53:10 +0000 Subject: [PATCH] Fix problems seen with some programs in the wild * subcompositor.c (ViewAttachBuffer): Correctly determine when to recompute view bounds. * subsurface.c (AfterParentCommit): Unskip view first, and commit pending state second. Explain why. * xdg_toplevel.c (Unmap, Map): Add new "initial configure" flag. (Commit): Use it instead of testing current_buffer. Explain why. (XLGetXdgToplevel): Set that flag by default. --- subcompositor.c | 8 +++++--- subsurface.c | 11 +++++++---- xdg_toplevel.c | 38 ++++++++++++++++++++++++++------------ 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/subcompositor.c b/subcompositor.c index df1986b..386655d 100644 --- a/subcompositor.c +++ b/subcompositor.c @@ -1472,12 +1472,14 @@ ViewAttachBuffer (View *view, ExtBuffer *buffer) if (!view->buffer && old && view->subcompositor) /* The view needs a size update, as it is now 0 by 0. */ ViewAfterSizeUpdate (view); - else if (((buffer && !old) + else if ((buffer && !old) || (old && !buffer) || (buffer && old && (XLBufferWidth (buffer) != XLBufferWidth (old) - || XLBufferHeight (buffer) != XLBufferHeight (old)))) - && !IsViewported (view)) + || XLBufferHeight (buffer) != XLBufferHeight (old)) + /* Buffer width and height changes don't matter if the + view has a viewport. */ + && !IsViewported (view))) /* Recompute view and subcompositor bounds. */ ViewAfterSizeUpdate (view); diff --git a/subsurface.c b/subsurface.c index 9c92fd5..38008f2 100644 --- a/subsurface.c +++ b/subsurface.c @@ -600,6 +600,13 @@ AfterParentCommit (Surface *surface, void *data) MoveFractional (subsurface); } + /* Mark the subsurface as unskipped. (IOW, make it visible). This + must come before XLCommitSurface, as doing so will apply the + pending state, which will fail to update the subcompositor bounds + if the subsurface is skipped. */ + ViewUnskip (subsurface->role.surface->view); + ViewUnskip (subsurface->role.surface->under); + /* And any cached surface state too. */ if (subsurface->pending_commit) { @@ -610,10 +617,6 @@ AfterParentCommit (Surface *surface, void *data) MaybeUpdateOutputs (subsurface); } - /* Mark the subsurface as unskipped. (IOW, make it visible). */ - ViewUnskip (subsurface->role.surface->view); - ViewUnskip (subsurface->role.surface->under); - subsurface->pending_commit = False; subsurface->pending_substate.flags = 0; } diff --git a/xdg_toplevel.c b/xdg_toplevel.c index ca3e26e..f640367 100644 --- a/xdg_toplevel.c +++ b/xdg_toplevel.c @@ -44,16 +44,17 @@ typedef enum _DecorationMode DecorationMode; enum { - StateIsMapped = 1, - StatePendingMaxSize = (1 << 1), - StatePendingMinSize = (1 << 2), - StatePendingAckMovement = (1 << 3), - StatePendingResize = (1 << 4), - StatePendingConfigureSize = (1 << 5), - StatePendingConfigureStates = (1 << 6), - StateDecorationModeDirty = (1 << 7), - StateEverMapped = (1 << 8), - StateNeedDecorationConfigure = (1 << 9), + StateIsMapped = 1, + StatePendingMaxSize = (1 << 1), + StatePendingMinSize = (1 << 2), + StatePendingAckMovement = (1 << 3), + StatePendingResize = (1 << 4), + StatePendingConfigureSize = (1 << 5), + StatePendingConfigureStates = (1 << 6), + StateDecorationModeDirty = (1 << 7), + StateEverMapped = (1 << 8), + StateNeedDecorationConfigure = (1 << 9), + StateWaitingForInitialConfigure = (1 << 10), }; enum @@ -1164,7 +1165,7 @@ Unmap (XdgToplevel *toplevel) /* Clear all the state. */ - toplevel->state = 0; + toplevel->state = StateWaitingForInitialConfigure; toplevel->conf_reply = False; toplevel->conf_serial = 0; toplevel->states.size = 0; @@ -1204,6 +1205,7 @@ Map (XdgToplevel *toplevel) SubcompositorGarbage (XLSubcompositorFromXdgRole (toplevel->role)); toplevel->state |= StateIsMapped | StateEverMapped; + toplevel->state &= ~StateWaitingForInitialConfigure; /* Update the width and height from the xdg_surface bounds. */ toplevel->width = XLXdgRoleGetWidth (toplevel->role); @@ -1268,8 +1270,16 @@ Commit (Role *role, Surface *surface, XdgRoleImplementation *impl) toplevel->state &= ~StatePendingMinSize; } - if (!surface->current_state.buffer) + if (!surface->current_state.buffer + /* Whenever any commit happens without the toplevel being + mapped, send the initial configure event. This is because + some clients attach an initial 1x1 buffer and expect the + compositor to do its thing. */ + || (toplevel->state & StateWaitingForInitialConfigure)) { + /* Stop waiting for initial configure. */ + toplevel->state &= ~StateWaitingForInitialConfigure; + /* No buffer was attached, unmap the window and send an empty configure event. */ if (toplevel->state & StateIsMapped) @@ -2282,6 +2292,10 @@ XLGetXdgToplevel (struct wl_client *client, struct wl_resource *resource, return; } + /* Set this flag for some buggy clients. See the comment above the + part of Commit that checks this flag for more details. */ + toplevel->state |= StateWaitingForInitialConfigure; + toplevel->impl.funcs.attach = Attach; toplevel->impl.funcs.commit = Commit; toplevel->impl.funcs.detach = Detach;