12to11/subsurface.c
oldosfan 7f33ba9ae3 Improve handling buffer scale factors
* compositor.h (struct _DrawParams): New structure.
(struct _RenderFuncs): Remove `apply_transform' and
`reset_transform'.  Make `composite' accept DrawParams.
(struct _BufferFuncs): Give scale to update_buffer_for_damage.
(struct _Surface): New field `factor'.
(struct _RoleFuncs): New callback `parent_rescale'.
* dnd.c (HandleMotion): Fix some aspects of scale handling.
* egl.c (struct _EglBuffer): Remove `scale' field.
(ApplyTransform): Delete function.
(Composite): Pass scale specified in params as uniform to
program.
(ResetTransform): Delete function.
(egl_render_funcs): Delete apply_transform and reset_transform.
(BufferFromDmaBuf, BufferFromShm): Stop setting scale attribute.
(UpdateBufferForDamage): Accept new arg `scale' and use it.

* picture_renderer.c (struct _PictureBuffer): New structure.
Store picture and last seen draw parameters.
(ApplyTransform): Delete function.
(GetScale): New function.
(MaybeApplyTransform): New function.
(Composite): Recompute and set pictures if draw parameters
change.
(ResetTransform): Delete function.
(picture_render_funcs): Remove unused hooks.
(BufferFromDmaBuf, FinishDmaBufRecord, BufferFromShm)
(FreeShmBuffer, FreeDmabufBuffer): Replace xid with wrapper
structure.

* positioner.c (TryFlipX, TryFlipY, GetAdjustmentOffset)
(ApplyConstraintAdjustment):
* renderer.c (RenderApplyTransform, RenderComposite)
(RenderResetTransform, RenderFinishRender)
(RenderUpdateBufferForDamage):
* seat.c (UpdateCursorOutput, ComputeHotspot, HandleRawButton)
(TransformToView, DispatchEntryExit, DispatchMotion, CancelGrab)
(DispatchButton, ForceEntry):
* subcompositor.c (GetTxTy, ViewApplyTransform, ViewHaveTransform)
(ViewComputeTransform, SubcompositorUpdate,
SubcompositorExpose):
* subsurface.c (MaybeUpdateOutputs, AfterParentCommit, Rescale)
(Teardown, GetSubsurface, XLUpdateOutputsForChildren): Use
surface-specific scale factors.
* surface.c (ApplyScale): Compute a new scale factor to convert
between window and surface scale.
(ApplyOpaqueRegion, ApplyInputRegion, HandleScaleChanged)
(ApplySurfaceDamage, InternalCommit, XLCreateSurface): Use new
factors instead.
* xdg_popup.c (MoveWindow):
* xdg_surface.c (GetResizeDimensions,
XLXdgRoleCalcNewWindowSize):
* xdg_toplevel.c (NoteConfigureTime, SendStates, RecordStateSize)
(HandleWindowGeometryChange, NoteWindowPreResize): Use
surface-specific scale factors.
2022-09-27 01:37:31 +00:00

992 lines
24 KiB
C

/* Wayland compositor running on top of an X server.
Copyright (C) 2022 to various contributors.
This file is part of 12to11.
12to11 is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
12to11 is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
#include <string.h>
#include <stdlib.h>
#include "compositor.h"
enum
{
PendingPosition = 1,
};
enum _SurfaceActionType
{
Sentinel,
PlaceAboveOther,
PlaceBelowOther,
};
typedef enum _SurfaceActionType SurfaceActionType;
typedef struct _Subsurface Subsurface;
typedef struct _Substate Substate;
typedef struct _SurfaceAction SurfaceAction;
typedef struct _SurfaceActionClientData SurfaceActionClientData;
#define SubsurfaceFromRole(role) ((Subsurface *) (role))
struct _SurfaceAction
{
/* What this action is. */
SurfaceActionType type;
/* What subsurface this action applies to. */
Subsurface *subsurface;
/* What surface is the "other" surface. */
Surface *other;
/* Surface destroy listener. */
DestroyCallback *destroy_listener;
/* The next and last surface actions in this list. */
SurfaceAction *next, *last;
};
struct _Substate
{
/* The position of the subsurface relative to the parent. */
int x, y;
/* Various flags. */
int flags;
};
struct _Subsurface
{
/* The role object itself. */
Role role;
/* The parent surface. */
Surface *parent;
/* The number of references to this subsurface. */
int refcount;
/* Pending substate. */
Substate pending_substate;
/* Current substate. */
Substate current_substate;
/* Commit callback attached to the parent. */
CommitCallback *commit_callback;
/* Whether or not this is synchronous. */
Bool synchronous;
/* Whether or not a commit is pending. */
Bool pending_commit;
/* The last dimensions and position that were used to update this
surface's outputs. */
int output_x, output_y, output_width, output_height;
};
struct _SurfaceActionClientData
{
/* Any pending subsurface actions. */
SurfaceAction actions;
};
/* The global wl_subcompositor resource. */
struct wl_global *global_subcompositor;
static void
UnlinkSurfaceAction (SurfaceAction *subaction)
{
subaction->last->next = subaction->next;
subaction->next->last = subaction->last;
}
static void
HandleOtherSurfaceDestroyed (void *data)
{
SurfaceAction *action;
action = data;
UnlinkSurfaceAction (action);
XLFree (action);
}
static void
DestroySurfaceAction (SurfaceAction *subaction)
{
XLSurfaceCancelRunOnFree (subaction->destroy_listener);
UnlinkSurfaceAction (subaction);
XLFree (subaction);
}
static Bool
CheckSiblingRelationship (Subsurface *subsurface, Surface *other)
{
Subsurface *other_subsurface;
if (other->role_type != SubsurfaceType
/* The role might've been detached from the other surface. */
|| !other->role)
return False;
other_subsurface = SubsurfaceFromRole (other->role);
if (other_subsurface->parent != subsurface->parent)
return False;
return True;
}
static void
ParentBelow (View *parent, View *below, Surface *surface)
{
ViewInsertBefore (parent, surface->view, below);
ViewInsertBefore (parent, surface->under, surface->view);
}
static void
ParentAbove (View *parent, View *above, Surface *surface)
{
ViewInsertAfter (parent, surface->under, above);
ViewInsertAfter (parent, surface->view, surface->under);
}
static void
ParentStart (View *parent, Surface *surface)
{
ViewInsert (parent, surface->under);
ViewInsert (parent, surface->view);
}
static void
RunOneSurfaceAction (Subsurface *subsurface, SurfaceAction *subaction)
{
View *target;
if (!subsurface->role.surface || !subsurface->parent)
return;
if (subaction->type == PlaceAboveOther)
{
if (subaction->other != subsurface->parent
&& !CheckSiblingRelationship (subsurface, subaction->other))
/* The hierarchy changed in some unacceptable way between the
action being recorded and the commit of the parent.
Ignore. */
return;
/* Determine the target under which to place the view. If
subaction->other is underneath the parent, then this will
actually be subsurface->parent->under. */
target = ViewGetParent (subaction->other->view);
/* After that, unparent the views. */
ViewUnparent (subsurface->role.surface->view);
ViewUnparent (subsurface->role.surface->under);
if (subaction->other == subsurface->parent)
/* Re-insert this view at the beginning of the parent. */
ParentStart (subsurface->parent->view,
subsurface->role.surface);
else
/* Re-insert this view in front of the other surface. */
ParentAbove (target, subaction->other->view,
subsurface->role.surface);
}
else if (subaction->type == PlaceBelowOther)
{
if (subaction->other != subsurface->parent
&& !CheckSiblingRelationship (subsurface, subaction->other))
return;
target = ViewGetParent (subaction->other->view);
ViewUnparent (subsurface->role.surface->view);
ViewUnparent (subsurface->role.surface->under);
if (subaction->other != subsurface->parent)
/* Re-insert this view before the other surface. */
ParentBelow (target, subaction->other->under,
subsurface->role.surface);
else
/* Re-insert this view below the parent surface. */
ParentStart (subsurface->parent->under,
subsurface->role.surface);
}
}
static void
FreeSurfaceActions (SurfaceAction *first)
{
SurfaceAction *action, *last;
action = first->next;
while (action != first)
{
last = action;
action = action->next;
DestroySurfaceAction (last);
}
}
static void
FreeSubsurfaceData (void *data)
{
SurfaceActionClientData *client;
client = data;
FreeSurfaceActions (&client->actions);
}
static SurfaceAction *
AddSurfaceAction (Subsurface *subsurface, Surface *other,
SurfaceActionType type)
{
SurfaceAction *action;
SurfaceActionClientData *client;
action = XLMalloc (sizeof *action);
action->subsurface = subsurface;
action->type = type;
action->other = other;
action->destroy_listener
= XLSurfaceRunOnFree (other, HandleOtherSurfaceDestroyed,
action);
client = XLSurfaceGetClientData (subsurface->parent,
SubsurfaceData,
sizeof *client,
FreeSubsurfaceData);
if (!client->actions.next)
{
/* Client is not yet initialized, so initialize the sentinel
node. */
client->actions.next = &client->actions;
client->actions.last = &client->actions;
client->actions.type = Sentinel;
}
action->next = client->actions.next;
action->last = &client->actions;
client->actions.next->last = action;
client->actions.next = action;
return action;
}
static void
RunSurfaceActions (SurfaceAction *first)
{
SurfaceAction *action, *last;
action = first->last;
while (action != first)
{
last = action;
/* Run the actions backwards so they appear in the right
order. */
action = action->last;
RunOneSurfaceAction (last->subsurface, last);
DestroySurfaceAction (last);
}
}
static void
DestroySubsurface (struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
SetPosition (struct wl_client *client, struct wl_resource *resource,
int32_t x, int32_t y)
{
Subsurface *subsurface;
subsurface = wl_resource_get_user_data (resource);
subsurface->pending_substate.x = x;
subsurface->pending_substate.y = y;
subsurface->pending_substate.flags |= PendingPosition;
}
static void
PlaceAbove (struct wl_client *client, struct wl_resource *resource,
struct wl_resource *surface_resource)
{
Subsurface *subsurface;
Surface *other;
subsurface = wl_resource_get_user_data (resource);
other = wl_resource_get_user_data (surface_resource);
if (other != subsurface->parent
&& !CheckSiblingRelationship (subsurface, other))
{
wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE,
"surface is not a sibling or the parent");
return;
}
AddSurfaceAction (subsurface, other, PlaceAboveOther);
}
static void
PlaceBelow (struct wl_client *client, struct wl_resource *resource,
struct wl_resource *surface_resource)
{
Subsurface *subsurface;
Surface *other;
subsurface = wl_resource_get_user_data (resource);
other = wl_resource_get_user_data (surface_resource);
if (other != subsurface->parent
|| !CheckSiblingRelationship (subsurface, other))
{
wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE,
"surface is not a sibling or the parent");
return;
}
AddSurfaceAction (subsurface, other, PlaceBelowOther);
}
static void
NoteDesyncChild (Surface *surface, Role *role)
{
Subsurface *subsurface;
subsurface = SubsurfaceFromRole (role);
if (!subsurface->parent || !subsurface->parent->role
|| !subsurface->parent->role->funcs.note_desync_child)
return;
subsurface->parent->role->funcs.note_desync_child (subsurface->parent,
subsurface->parent->role);
}
static void
NoteChildSynced (Surface *surface, Role *role)
{
Subsurface *subsurface;
subsurface = SubsurfaceFromRole (role);
if (!subsurface->parent || !subsurface->parent->role
|| !subsurface->parent->role->funcs.note_child_synced)
return;
subsurface->parent->role->funcs.note_child_synced (subsurface->parent,
subsurface->parent->role);
}
static void
SetSync (struct wl_client *client, struct wl_resource *resource)
{
Subsurface *subsurface;
subsurface = wl_resource_get_user_data (resource);
if (subsurface->role.surface
&& !subsurface->synchronous)
NoteChildSynced (subsurface->role.surface,
&subsurface->role);
subsurface->synchronous = True;
}
static void
SetDesync (struct wl_client *client, struct wl_resource *resource)
{
Subsurface *subsurface;
subsurface = wl_resource_get_user_data (resource);
if (subsurface->role.surface
&& subsurface->synchronous)
NoteDesyncChild (subsurface->role.surface,
&subsurface->role);
subsurface->synchronous = False;
if (subsurface->pending_commit
&& subsurface->role.surface)
XLCommitSurface (subsurface->role.surface, False);
subsurface->pending_commit = False;
}
static const struct wl_subsurface_interface wl_subsurface_impl =
{
.destroy = DestroySubsurface,
.set_position = SetPosition,
.place_above = PlaceAbove,
.place_below = PlaceBelow,
.set_sync = SetSync,
.set_desync = SetDesync,
};
static void
DestroyBacking (Subsurface *subsurface)
{
if (--subsurface->refcount)
return;
XLFree (subsurface);
}
static Bool
EarlyCommit (Surface *surface, Role *role)
{
Subsurface *subsurface;
subsurface = SubsurfaceFromRole (role);
/* If the role is synchronous, don't commit until the parent
commits. */
if (subsurface->synchronous)
{
subsurface->pending_commit = True;
return False;
}
return True;
}
static void
MaybeUpdateOutputs (Subsurface *subsurface)
{
int x, y, width, height, base_x, base_y;
if (subsurface->role.surface->output_x == INT_MIN
|| subsurface->role.surface->output_y == INT_MIN)
/* Valid base coordinates are not yet available. */
return;
if (!subsurface->parent)
/* A valid scale factor is not available. */
return;
/* Compute the positions relative to the parent. */
x = subsurface->current_substate.x * subsurface->parent->factor;
y = subsurface->current_substate.y * subsurface->parent->factor;
/* And the base X and Y. */
base_x = subsurface->role.surface->output_x;
base_y = subsurface->role.surface->output_y;
/* Compute the absolute width and height of the surface
contents. */
width = ViewWidth (subsurface->role.surface->view);
height = ViewHeight (subsurface->role.surface->view);
/* If nothing really changed, return. */
if (x == subsurface->output_x
&& y == subsurface->output_y
&& width == subsurface->output_width
&& height == subsurface->output_height)
return;
/* Otherwise, recompute the outputs this subsurface overlaps and
record those values. */
subsurface->output_x = x;
subsurface->output_y = y;
subsurface->output_width = width;
subsurface->output_height = height;
/* Recompute overlaps. */
XLUpdateSurfaceOutputs (subsurface->role.surface,
x + base_x, y + base_y,
width, height);
}
static void
AfterParentCommit (Surface *surface, void *data)
{
Subsurface *subsurface;
subsurface = data;
/* The surface might've been destroyed already. */
if (!subsurface->role.surface)
return;
/* Apply pending state. */
if (subsurface->pending_substate.flags & PendingPosition)
{
subsurface->current_substate.x
= subsurface->pending_substate.x;
subsurface->current_substate.y
= subsurface->pending_substate.y;
/* The X and Y coordinates here are also parent-local and must
be scaled by the global scale factor. */
ViewMove (subsurface->role.surface->view,
subsurface->current_substate.x * subsurface->parent->factor,
subsurface->current_substate.y * subsurface->parent->factor);
}
/* And any cached surface state too. */
if (subsurface->pending_commit)
{
XLCommitSurface (subsurface->role.surface, False);
/* If the size changed, update the outputs this surface is in
the scanout area of. */
MaybeUpdateOutputs (subsurface);
}
subsurface->pending_commit = False;
subsurface->pending_substate.flags = 0;
}
static Bool
Subframe (Surface *surface, Role *role)
{
Subsurface *subsurface;
subsurface = SubsurfaceFromRole (role);
if (!subsurface->parent || !subsurface->parent->role
|| !subsurface->parent->role->funcs.subframe)
return True;
return subsurface->parent->role->funcs.subframe (subsurface->parent,
subsurface->parent->role);
}
static void
EndSubframe (Surface *surface, Role *role)
{
Subsurface *subsurface;
subsurface = SubsurfaceFromRole (role);
if (!subsurface->parent || !subsurface->parent->role
|| !subsurface->parent->role->funcs.end_subframe)
return;
subsurface->parent->role->funcs.end_subframe (subsurface->parent,
subsurface->parent->role);
}
static Window
GetWindow (Surface *surface, Role *role)
{
Subsurface *subsurface;
subsurface = SubsurfaceFromRole (role);
if (!subsurface->parent || !subsurface->parent->role
|| !subsurface->parent->role->funcs.get_window)
return None;
return
subsurface->parent->role->funcs.get_window (subsurface->parent,
subsurface->parent->role);
}
static void
Commit (Surface *surface, Role *role)
{
Subcompositor *subcompositor;
Subsurface *subsurface;
subcompositor = ViewGetSubcompositor (surface->view);
subsurface = SubsurfaceFromRole (role);
if (!subcompositor)
return;
/* If no buffer is attached, unmap the views. */
if (!surface->current_state.buffer)
{
ViewUnmap (surface->under);
ViewUnmap (surface->view);
}
else
/* Once a buffer is attached to the view, it is automatically
mapped. */
ViewMap (surface->under);
if (!subsurface->synchronous)
{
/* If the surface is asynchronous, draw this subframe now.
Otherwise it is synchronous, so we should wait for the
toplevel to end the frame. */
if (Subframe (surface, role))
{
SubcompositorUpdate (subcompositor);
EndSubframe (surface, role);
}
/* If the size changed, update the outputs this surface is in
the scanout area of. */
MaybeUpdateOutputs (subsurface);
}
}
static Bool
Setup (Surface *surface, Role *role)
{
Subsurface *subsurface;
View *parent_view;
surface->role_type = SubsurfaceType;
subsurface = SubsurfaceFromRole (role);
subsurface->refcount++;
subsurface->output_x = INT_MIN;
subsurface->output_y = INT_MIN;
role->surface = surface;
parent_view = subsurface->parent->view;
/* Set the subcompositor here. If the role providing the
subcompositor hasn't been attached to the parent, then when it is
it will call ViewSetSubcompositor on the parent's view. */
ViewSetSubcompositor (surface->under,
ViewGetSubcompositor (parent_view));
ViewInsert (parent_view, surface->under);
ViewSetSubcompositor (surface->view,
ViewGetSubcompositor (parent_view));
ViewInsert (parent_view, surface->view);
/* Now add the subsurface to the parent's list of subsurfaces. */
subsurface->parent->subsurfaces
= XLListPrepend (subsurface->parent->subsurfaces,
surface);
return True;
}
static void
Rescale (Surface *surface, Role *role)
{
Subsurface *subsurface;
subsurface = SubsurfaceFromRole (role);
/* The scale factor changed; move the subsurface to the new correct
position. */
ViewMove (surface->view,
subsurface->current_substate.x * subsurface->parent->factor,
subsurface->current_substate.y * subsurface->parent->factor);
}
static void
ParentRescale (Surface *surface, Role *role)
{
/* This is called when the scale factor of the parent changes. */
Rescale (surface, role);
}
static void
Teardown (Surface *surface, Role *role)
{
Subsurface *subsurface;
SurfaceActionClientData *client;
SurfaceAction *action;
Subcompositor *subcompositor;
subsurface = SubsurfaceFromRole (role);
/* If this subsurface is desynchronous, tell the toplevel parent
that it is now gone. */
if (!subsurface->synchronous)
NoteDesyncChild (role->surface, role);
role->surface = NULL;
if (subsurface->parent)
{
subcompositor = ViewGetSubcompositor (surface->view);
ViewUnparent (surface->view);
ViewSetSubcompositor (surface->view, NULL);
ViewUnparent (surface->under);
ViewSetSubcompositor (surface->under, NULL);
client = subsurface->parent->client_data[SubsurfaceData];
if (client)
{
/* Free all subsurface actions involving this
subsurface. */
action = client->actions.next;
while (action != &client->actions)
{
if (action->subsurface == subsurface)
DestroySurfaceAction (action);
}
}
subsurface->parent->subsurfaces
= XLListRemove (subsurface->parent->subsurfaces, surface);
XLSurfaceCancelCommitCallback (subsurface->commit_callback);
/* According to the spec, this removal should take effect
immediately. */
if (subcompositor
&& Subframe (surface, role))
{
SubcompositorUpdate (subcompositor);
EndSubframe (surface, role);
}
}
DestroyBacking (subsurface);
}
static void
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
{
Subsurface *subsurface;
subsurface = SubsurfaceFromRole (role);
if (!subsurface->parent || !subsurface->parent->role)
{
XLReleaseBuffer (buffer);
return;
}
subsurface->parent->role->funcs.release_buffer (subsurface->parent,
subsurface->parent->role,
buffer);
}
static void
HandleSubsurfaceResourceDestroy (struct wl_resource *resource)
{
Subsurface *subsurface;
subsurface = wl_resource_get_user_data (resource);
DestroyBacking (subsurface);
}
static void
GetSubsurface (struct wl_client *client, struct wl_resource *resource,
uint32_t id, struct wl_resource *surface_resource,
struct wl_resource *parent_resource)
{
Surface *surface, *parent;
Subsurface *subsurface;
surface = wl_resource_get_user_data (surface_resource);
parent = wl_resource_get_user_data (parent_resource);
/* If the surface already has a role, don't attach this subsurface.
Likewise if the surface previously held some other role. */
if (surface->role || (surface->role_type != AnythingType
&& surface->role_type != SubsurfaceType))
{
wl_resource_post_error (resource, WL_DISPLAY_ERROR_IMPLEMENTATION,
"trying to attach subsurface to surface with role");
return;
}
subsurface = XLSafeMalloc (sizeof *subsurface);
if (!subsurface)
{
wl_resource_post_no_memory (resource);
return;
}
memset (subsurface, 0, sizeof *subsurface);
subsurface->role.resource
= wl_resource_create (client, &wl_subsurface_interface,
wl_resource_get_version (resource),
id);
if (!subsurface->role.resource)
{
XLFree (subsurface);
wl_resource_post_no_memory (resource);
return;
}
wl_resource_set_implementation (subsurface->role.resource, &wl_subsurface_impl,
subsurface, HandleSubsurfaceResourceDestroy);
/* Now the wl_resource holds a reference to the subsurface. */
subsurface->refcount++;
subsurface->role.funcs.commit = Commit;
subsurface->role.funcs.teardown = Teardown;
subsurface->role.funcs.setup = Setup;
subsurface->role.funcs.release_buffer = ReleaseBuffer;
subsurface->role.funcs.subframe = Subframe;
subsurface->role.funcs.end_subframe = EndSubframe;
subsurface->role.funcs.early_commit = EarlyCommit;
subsurface->role.funcs.get_window = GetWindow;
subsurface->role.funcs.rescale = Rescale;
subsurface->role.funcs.parent_rescale = ParentRescale;
subsurface->role.funcs.note_child_synced = NoteChildSynced;
subsurface->role.funcs.note_desync_child = NoteDesyncChild;
subsurface->parent = parent;
subsurface->commit_callback
= XLSurfaceRunAtCommit (parent, AfterParentCommit, subsurface);
subsurface->synchronous = True;
if (!XLSurfaceAttachRole (surface, &subsurface->role))
abort ();
}
static void
DestroySubcompositor (struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct wl_subcompositor_interface wl_subcompositor_impl =
{
.destroy = DestroySubcompositor,
.get_subsurface = GetSubsurface,
};
static void
HandleBind (struct wl_client *client, void *data,
uint32_t version, uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &wl_subcompositor_interface,
version, id);
if (!resource)
{
wl_client_post_no_memory (client);
return;
}
wl_resource_set_implementation (resource, &wl_subcompositor_impl,
NULL, NULL);
}
void
XLInitSubsurfaces (void)
{
global_subcompositor
= wl_global_create (compositor.wl_display,
&wl_subcompositor_interface,
1, NULL, HandleBind);
}
void
XLSubsurfaceParentDestroyed (Role *role)
{
Subsurface *subsurface;
subsurface = SubsurfaceFromRole (role);
subsurface->parent = NULL;
/* The callback is freed with the parent. */
subsurface->commit_callback = NULL;
if (subsurface->role.surface)
{
ViewUnparent (subsurface->role.surface->view);
ViewUnparent (subsurface->role.surface->under);
}
}
void
XLSubsurfaceHandleParentCommit (Surface *parent)
{
SurfaceActionClientData *client;
client = parent->client_data[SubsurfaceData];
if (client)
RunSurfaceActions (&client->actions);
}
void
XLUpdateOutputsForChildren (Surface *parent, int base_x, int base_y)
{
XLList *item;
Subsurface *subsurface;
Surface *child;
int output_x, output_y, output_width, output_height;
for (item = parent->subsurfaces; item; item = item->next)
{
child = item->data;
subsurface = SubsurfaceFromRole (child->role);
output_x = (subsurface->current_substate.x
* parent->factor);
output_y = (subsurface->current_substate.y
* parent->factor);
output_width = ViewWidth (child->view);
output_height = ViewHeight (child->view);
XLUpdateSurfaceOutputs (child,
base_x + output_x,
base_y + output_y,
output_width,
output_height);
/* Record those values in the child. */
subsurface->output_x = output_x;
subsurface->output_y = output_y;
subsurface->output_width = output_width;
subsurface->output_height = output_height;
}
}
void
XLUpdateDesynchronousChildren (Surface *parent, int *n_children)
{
XLList *item;
Subsurface *subsurface;
Surface *child;
for (item = parent->subsurfaces; item; item = item->next)
{
child = item->data;
subsurface = SubsurfaceFromRole (child->role);
if (!subsurface->synchronous)
/* The subsurface is desynchronous, so add it to the number of
desynchronous children. */
*n_children += 1;
/* Update these numbers recursively as well. */
XLUpdateDesynchronousChildren (child, n_children);
}
}