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.
This commit is contained in:
oldosfan 2022-09-27 01:37:31 +00:00
parent 0f07b2205b
commit 7f33ba9ae3
13 changed files with 443 additions and 235 deletions

View file

@ -103,6 +103,8 @@ typedef union _RenderTarget RenderTarget;
typedef union _RenderBuffer RenderBuffer; typedef union _RenderBuffer RenderBuffer;
typedef union _RenderFence RenderFence; typedef union _RenderFence RenderFence;
typedef struct _DrawParams DrawParams;
typedef struct _DmaBufAttributes DmaBufAttributes; typedef struct _DmaBufAttributes DmaBufAttributes;
typedef struct _SharedMemoryAttributes SharedMemoryAttributes; typedef struct _SharedMemoryAttributes SharedMemoryAttributes;
@ -120,6 +122,21 @@ enum _Operation
OperationSource, OperationSource,
}; };
enum
{
/* Scale has been set. */
ScaleSet = 1,
};
struct _DrawParams
{
/* Which fields are set. */
int flags;
/* A scale factor to apply to the buffer. */
double scale;
};
struct _SharedMemoryAttributes struct _SharedMemoryAttributes
{ {
/* The format of the buffer. */ /* The format of the buffer. */
@ -241,18 +258,12 @@ struct _RenderFuncs
/* Clear the given rectangle. */ /* Clear the given rectangle. */
void (*clear_rectangle) (RenderTarget, int, int, int, int); void (*clear_rectangle) (RenderTarget, int, int, int, int);
/* Apply a projective transform to the given buffer. The first
argument is a scale factor. */
void (*apply_transform) (RenderBuffer, double);
/* Composite width, height, from the given buffer onto the given /* Composite width, height, from the given buffer onto the given
target, at x, y. The arguments are: buffer, target, operation, target, at x, y. The arguments are: buffer, target, operation,
source_x, source_y, x, y, width, height. */ source_x, source_y, x, y, width, height, params. params
describes how to transform the given buffer. */
void (*composite) (RenderBuffer, RenderTarget, Operation, int, int, void (*composite) (RenderBuffer, RenderTarget, Operation, int, int,
int, int, int, int); int, int, int, int, DrawParams *);
/* Reset the transform for the given buffer. */
void (*reset_transform) (RenderBuffer);
/* Finish rendering, and swap changes to display. May be NULL. */ /* Finish rendering, and swap changes to display. May be NULL. */
void (*finish_render) (RenderTarget); void (*finish_render) (RenderTarget);
@ -349,8 +360,10 @@ struct _BufferFuncs
/* Notice that the given buffer has been damaged. May be NULL. If /* Notice that the given buffer has been damaged. May be NULL. If
the given NULL damage, assume that the entire buffer has been the given NULL damage, assume that the entire buffer has been
damaged. Must be called at least once before any rendering can damaged. Must be called at least once before any rendering can
be performed on the buffer. */ be performed on the buffer. 3rd arg is the scale by which to
void (*update_buffer_for_damage) (RenderBuffer, pixman_region32_t *); divide the buffer. */
void (*update_buffer_for_damage) (RenderBuffer, pixman_region32_t *,
float);
/* Return whether or not the buffer contents can be released early, /* Return whether or not the buffer contents can be released early,
by being copied to an offscreen buffer. */ by being copied to an offscreen buffer. */
@ -376,10 +389,8 @@ extern void RenderStartRender (RenderTarget);
extern void RenderFillBoxesWithTransparency (RenderTarget, pixman_box32_t *, extern void RenderFillBoxesWithTransparency (RenderTarget, pixman_box32_t *,
int, int, int); int, int, int);
extern void RenderClearRectangle (RenderTarget, int, int, int, int); extern void RenderClearRectangle (RenderTarget, int, int, int, int);
extern void RenderApplyTransform (RenderBuffer, double);
extern void RenderComposite (RenderBuffer, RenderTarget, Operation, int, extern void RenderComposite (RenderBuffer, RenderTarget, Operation, int,
int, int, int, int, int); int, int, int, int, int, DrawParams *);
extern void RenderResetTransform (RenderBuffer);
extern void RenderFinishRender (RenderTarget); extern void RenderFinishRender (RenderTarget);
extern int RenderTargetAge (RenderTarget); extern int RenderTargetAge (RenderTarget);
extern RenderFence RenderImportFdFence (int, Bool *); extern RenderFence RenderImportFdFence (int, Bool *);
@ -398,7 +409,8 @@ extern Bool RenderValidateShmParams (uint32_t, uint32_t, uint32_t, int32_t,
int32_t, size_t); int32_t, size_t);
extern void RenderFreeShmBuffer (RenderBuffer); extern void RenderFreeShmBuffer (RenderBuffer);
extern void RenderFreeDmabufBuffer (RenderBuffer); extern void RenderFreeDmabufBuffer (RenderBuffer);
extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *); extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *,
float);
extern Bool RenderCanReleaseNow (RenderBuffer); extern Bool RenderCanReleaseNow (RenderBuffer);
/* Defined in run.c. */ /* Defined in run.c. */
@ -832,6 +844,10 @@ struct _Surface
/* The associated sync acquire fd, or -1. */ /* The associated sync acquire fd, or -1. */
int acquire_fence; int acquire_fence;
/* The scale factor used to convert from surface coordinates to
window coordinates. */
double factor;
}; };
struct _RoleFuncs struct _RoleFuncs
@ -851,6 +867,7 @@ struct _RoleFuncs
void (*post_resize) (Surface *, Role *, int, int, int, int); void (*post_resize) (Surface *, Role *, int, int, int, int);
void (*move_by) (Surface *, Role *, int, int); void (*move_by) (Surface *, Role *, int, int);
void (*rescale) (Surface *, Role *); void (*rescale) (Surface *, Role *);
void (*parent_rescale) (Surface *, Role *);
void (*note_desync_child) (Surface *, Role *); void (*note_desync_child) (Surface *, Role *);
void (*note_child_synced) (Surface *, Role *); void (*note_child_synced) (Surface *, Role *);
}; };

19
dnd.c
View file

@ -885,11 +885,24 @@ HandleMotion (Surface *toplevel, int x, int y, uint32_t action,
/* Find the view underneath the subcompositor. */ /* Find the view underneath the subcompositor. */
view = SubcompositorLookupView (subcompositor, x, y, view = SubcompositorLookupView (subcompositor, x, y,
&x_off, &y_off); &x_off, &y_off);
child = ViewGetData (view);
if (view)
child = ViewGetData (view);
else
/* No child was found. This should be impossible in theory, but
other clients don't respect the window shape when sending DND
events. */
child = NULL;
/* Compute the surface-relative coordinates and scale them. */ /* Compute the surface-relative coordinates and scale them. */
*x_out = (x - x_off) / global_scale_factor;
*y_out = (y - y_off) / global_scale_factor; if (child)
{
/* x_out and y_out are only used if dnd_state.child ends up
non-NULL. */
*x_out = (x - x_off) / child->factor;
*y_out = (y - y_off) / child->factor;
}
if (dnd_state.child == child) if (dnd_state.child == child)
/* If nothing changed, don't do anything. */ /* If nothing changed, don't do anything. */

45
egl.c
View file

@ -126,9 +126,6 @@ struct _EglBuffer
/* The width and height of the buffer. */ /* The width and height of the buffer. */
int width, height; int width, height;
/* The projective scale factor. */
GLfloat scale;
/* Various different buffers. */ /* Various different buffers. */
union { union {
/* The type of the buffer. */ /* The type of the buffer. */
@ -1128,15 +1125,6 @@ ClearRectangle (RenderTarget target, int x, int y, int width, int height)
FillBoxesWithTransparency (target, &box, 1, 0, 0); FillBoxesWithTransparency (target, &box, 1, 0, 0);
} }
static void
ApplyTransform (RenderBuffer buffer, double divisor)
{
EglBuffer *egl_buffer;
egl_buffer = buffer.pointer;
egl_buffer->scale = 1.0f / (GLfloat) divisor;
}
static CompositeProgram * static CompositeProgram *
FindProgram (EglBuffer *buffer) FindProgram (EglBuffer *buffer)
{ {
@ -1177,7 +1165,7 @@ GetTextureTarget (EglBuffer *buffer)
static void static void
Composite (RenderBuffer buffer, RenderTarget target, Composite (RenderBuffer buffer, RenderTarget target,
Operation op, int src_x, int src_y, int x, int y, Operation op, int src_x, int src_y, int x, int y,
int width, int height) int width, int height, DrawParams *params)
{ {
GLfloat verts[8], texcoord[8]; GLfloat verts[8], texcoord[8];
GLfloat x1, x2, y1, y2; GLfloat x1, x2, y1, y2;
@ -1185,6 +1173,7 @@ Composite (RenderBuffer buffer, RenderTarget target,
EglBuffer *egl_buffer; EglBuffer *egl_buffer;
CompositeProgram *program; CompositeProgram *program;
GLenum tex_target; GLenum tex_target;
GLfloat scale;
egl_target = target.pointer; egl_target = target.pointer;
egl_buffer = buffer.pointer; egl_buffer = buffer.pointer;
@ -1244,13 +1233,18 @@ Composite (RenderBuffer buffer, RenderTarget target,
else else
glDisable (GL_BLEND); glDisable (GL_BLEND);
if (params->flags & ScaleSet)
scale = params->scale;
else
scale = 1.0f;
glActiveTexture (GL_TEXTURE0); glActiveTexture (GL_TEXTURE0);
glBindTexture (tex_target, egl_buffer->texture); glBindTexture (tex_target, egl_buffer->texture);
glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram (program->program); glUseProgram (program->program);
glUniform1i (program->texture, 0); glUniform1i (program->texture, 0);
glUniform1f (program->scale, egl_buffer->scale); glUniform1f (program->scale, scale);
glUniform1i (program->invert_y, egl_buffer->flags & InvertY); glUniform1i (program->invert_y, egl_buffer->flags & InvertY);
glVertexAttribPointer (program->position, 2, GL_FLOAT, glVertexAttribPointer (program->position, 2, GL_FLOAT,
GL_FALSE, 0, verts); GL_FALSE, 0, verts);
@ -1268,12 +1262,6 @@ Composite (RenderBuffer buffer, RenderTarget target,
glBindTexture (tex_target, 0); glBindTexture (tex_target, 0);
} }
static void
ResetTransform (RenderBuffer buffer)
{
/* TODO... */
}
static void static void
FinishRender (RenderTarget target) FinishRender (RenderTarget target)
{ {
@ -1421,9 +1409,7 @@ static RenderFuncs egl_render_funcs =
.start_render = StartRender, .start_render = StartRender,
.fill_boxes_with_transparency = FillBoxesWithTransparency, .fill_boxes_with_transparency = FillBoxesWithTransparency,
.clear_rectangle = ClearRectangle, .clear_rectangle = ClearRectangle,
.apply_transform = ApplyTransform,
.composite = Composite, .composite = Composite,
.reset_transform = ResetTransform,
.finish_render = FinishRender, .finish_render = FinishRender,
.target_age = TargetAge, .target_age = TargetAge,
.import_fd_fence = ImportFdFence, .import_fd_fence = ImportFdFence,
@ -1514,7 +1500,6 @@ BufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error)
buffer->texture = EGL_NO_TEXTURE; buffer->texture = EGL_NO_TEXTURE;
buffer->width = attributes->width; buffer->width = attributes->width;
buffer->height = attributes->height; buffer->height = attributes->height;
buffer->scale = 1.0f;
buffer->u.type = DmaBufBuffer; buffer->u.type = DmaBufBuffer;
i = 0; i = 0;
@ -1664,7 +1649,6 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error)
buffer->texture = EGL_NO_TEXTURE; buffer->texture = EGL_NO_TEXTURE;
buffer->width = attributes->width; buffer->width = attributes->width;
buffer->height = attributes->height; buffer->height = attributes->height;
buffer->scale = 1.0f;
buffer->u.type = ShmBuffer; buffer->u.type = ShmBuffer;
/* Record the buffer data. */ /* Record the buffer data. */
@ -2134,22 +2118,19 @@ UpdateBuffer (RenderBuffer buffer, pixman_region32_t *damage)
} }
static void static void
UpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage) UpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage,
float scale)
{ {
EglBuffer *egl_buffer;
pixman_region32_t region; pixman_region32_t region;
egl_buffer = buffer.pointer; if (scale != 1.0f && damage)
if (egl_buffer->scale != 1.0f && damage)
{ {
/* Scale the damage, specified in scaled coordinates, down to /* Scale the damage, specified in scaled coordinates, down to
texture coordinates. */ texture coordinates. */
pixman_region32_init (&region); pixman_region32_init (&region);
XLScaleRegion (&region, damage, XLScaleRegion (&region, damage, 1.0f / scale,
1.0f / egl_buffer->scale, 1.0f / scale);
1.0f / egl_buffer->scale);
UpdateBuffer (buffer, &region); UpdateBuffer (buffer, &region);
pixman_region32_fini (&region); pixman_region32_fini (&region);
} }

View file

@ -35,6 +35,17 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
typedef struct _DrmFormatInfo DrmFormatInfo; typedef struct _DrmFormatInfo DrmFormatInfo;
typedef struct _DmaBufRecord DmaBufRecord; typedef struct _DmaBufRecord DmaBufRecord;
typedef struct _PictureBuffer PictureBuffer;
struct _PictureBuffer
{
/* The XID of the picture. */
Picture picture;
/* The last draw params associated with the picture. */
DrawParams params;
};
struct _DrmFormatInfo struct _DrmFormatInfo
{ {
/* The DRM format code. */ /* The DRM format code. */
@ -290,21 +301,6 @@ ClearRectangle (RenderTarget target, int x, int y, int width, int height)
target.xid, &color, x, y, width, height); target.xid, &color, x, y, width, height);
} }
static void
ApplyTransform (RenderBuffer buffer, double divisor)
{
XTransform transform;
memset (&transform, 0, sizeof transform);
transform.matrix[0][0] = XDoubleToFixed (divisor);
transform.matrix[1][1] = XDoubleToFixed (divisor);
transform.matrix[2][2] = XDoubleToFixed (1);
XRenderSetPictureTransform (compositor.display, buffer.xid,
&transform);
}
static int static int
ConvertOperation (Operation op) ConvertOperation (Operation op)
{ {
@ -320,26 +316,70 @@ ConvertOperation (Operation op)
abort (); abort ();
} }
static double
GetScale (DrawParams *params)
{
if (params->flags & ScaleSet)
return params->scale;
return 1.0;
}
static void
MaybeApplyTransform (PictureBuffer *buffer, DrawParams *params)
{
XTransform transform;
if (GetScale (params) == GetScale (&buffer->params))
/* Nothing changed. */
return;
/* Otherwise, compute and apply the new transform. */
if (!params->flags)
/* No transform of any kind is set, use the identity matrix. */
XRenderSetPictureTransform (compositor.display,
buffer->picture,
&identity_transform);
else
{
memset (&transform, 0, sizeof transform);
transform.matrix[0][0] = XDoubleToFixed (1.0 / params->scale);
transform.matrix[1][1] = XDoubleToFixed (1.0 / params->scale);
transform.matrix[2][2] = XDoubleToFixed (1);
XRenderSetPictureTransform (compositor.display,
buffer->picture,
&transform);
}
/* Save the parameters into buffer. */
buffer->params = *params;
}
static void static void
Composite (RenderBuffer buffer, RenderTarget target, Composite (RenderBuffer buffer, RenderTarget target,
Operation op, int src_x, int src_y, int x, int y, Operation op, int src_x, int src_y, int x, int y,
int width, int height) int width, int height, DrawParams *draw_params)
{ {
PictureBuffer *picture_buffer;
picture_buffer = buffer.pointer;
/* Maybe set the transform if the parameters changed. (draw_params
specifies a transform to apply to the buffer, not to the
target.) */
MaybeApplyTransform (picture_buffer, draw_params);
/* Do the compositing. */
XRenderComposite (compositor.display, ConvertOperation (op), XRenderComposite (compositor.display, ConvertOperation (op),
buffer.xid, None, target.xid, picture_buffer->picture, None, target.xid,
/* src-x, src-y, mask-x, mask-y. */ /* src-x, src-y, mask-x, mask-y. */
src_x, src_y, 0, 0, src_x, src_y, 0, 0,
/* dst-x, dst-y, width, height. */ /* dst-x, dst-y, width, height. */
x, y, width, height); x, y, width, height);
} }
static void
ResetTransform (RenderBuffer buffer)
{
XRenderSetPictureTransform (compositor.display, buffer.xid,
&identity_transform);
}
static int static int
TargetAge (RenderTarget target) TargetAge (RenderTarget target)
{ {
@ -388,9 +428,7 @@ static RenderFuncs picture_render_funcs =
.destroy_render_target = DestroyRenderTarget, .destroy_render_target = DestroyRenderTarget,
.fill_boxes_with_transparency = FillBoxesWithTransparency, .fill_boxes_with_transparency = FillBoxesWithTransparency,
.clear_rectangle = ClearRectangle, .clear_rectangle = ClearRectangle,
.apply_transform = ApplyTransform,
.composite = Composite, .composite = Composite,
.reset_transform = ResetTransform,
.target_age = TargetAge, .target_age = TargetAge,
.import_fd_fence = ImportFdFence, .import_fd_fence = ImportFdFence,
.wait_fence = WaitFence, .wait_fence = WaitFence,
@ -746,6 +784,7 @@ BufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error)
xcb_generic_error_t *xerror; xcb_generic_error_t *xerror;
XRenderPictFormat *format; XRenderPictFormat *format;
XRenderPictureAttributes picture_attrs; XRenderPictureAttributes picture_attrs;
PictureBuffer *buffer;
/* Find the depth and bpp corresponding to the format. */ /* Find the depth and bpp corresponding to the format. */
depth = DepthForDmabufFormat (attributes->drm_format, &bpp); depth = DepthForDmabufFormat (attributes->drm_format, &bpp);
@ -791,12 +830,16 @@ BufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error)
format, 0, &picture_attrs); format, 0, &picture_attrs);
XFreePixmap (compositor.display, pixmap); XFreePixmap (compositor.display, pixmap);
return (RenderBuffer) picture; /* Create the wrapper object. */
buffer = XLCalloc (1, sizeof *buffer);
buffer->picture = picture;
return (RenderBuffer) (void *) buffer;
error: error:
CloseFileDescriptors (attributes); CloseFileDescriptors (attributes);
*error = True; *error = True;
return (RenderBuffer) (XID) None; return (RenderBuffer) NULL;
} }
static void static void
@ -832,6 +875,7 @@ FinishDmaBufRecord (DmaBufRecord *pending, Bool success)
{ {
Picture picture; Picture picture;
XRenderPictureAttributes picture_attrs; XRenderPictureAttributes picture_attrs;
PictureBuffer *buffer;
if (success) if (success)
{ {
@ -844,8 +888,12 @@ FinishDmaBufRecord (DmaBufRecord *pending, Bool success)
&picture_attrs); &picture_attrs);
XFreePixmap (compositor.display, pending->pixmap); XFreePixmap (compositor.display, pending->pixmap);
/* Create the wrapper structure. */
buffer = XLCalloc (1, sizeof *buffer);
buffer->picture = picture;
/* Call the creation success function with the new picture. */ /* Call the creation success function with the new picture. */
pending->success_func ((RenderBuffer) picture, pending->success_func ((RenderBuffer) (void *) buffer,
pending->data); pending->data);
} }
else else
@ -989,6 +1037,7 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error)
Pixmap pixmap; Pixmap pixmap;
Picture picture; Picture picture;
int fd, depth, format, bpp; int fd, depth, format, bpp;
PictureBuffer *buffer;
depth = DepthForFormat (attributes->format, &bpp); depth = DepthForFormat (attributes->format, &bpp);
format = attributes->format; format = attributes->format;
@ -1000,7 +1049,7 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error)
if (fd < 0) if (fd < 0)
{ {
*error = True; *error = True;
return (RenderBuffer) (XID) None; return (RenderBuffer) NULL;
} }
/* Now, allocate the XIDs for the shm segment and pixmap. */ /* Now, allocate the XIDs for the shm segment and pixmap. */
@ -1021,8 +1070,12 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error)
0, &picture_attrs); 0, &picture_attrs);
XFreePixmap (compositor.display, pixmap); XFreePixmap (compositor.display, pixmap);
/* Create the wrapper object. */
buffer = XLCalloc (1, sizeof *buffer);
buffer->picture = picture;
/* Return the picture. */ /* Return the picture. */
return (RenderBuffer) picture; return (RenderBuffer) (void *) buffer;
} }
static int static int
@ -1086,15 +1139,27 @@ ValidateShmParams (uint32_t format, uint32_t width, uint32_t height,
static void static void
FreeShmBuffer (RenderBuffer buffer) FreeShmBuffer (RenderBuffer buffer)
{ {
XRenderFreePicture (compositor.display, buffer.xid); PictureBuffer *picture_buffer;
picture_buffer = buffer.pointer;
XRenderFreePicture (compositor.display,
picture_buffer->picture);
XLFree (picture_buffer);
} }
static void static void
FreeDmabufBuffer (RenderBuffer buffer) FreeDmabufBuffer (RenderBuffer buffer)
{ {
PictureBuffer *picture_buffer;
picture_buffer = buffer.pointer;
/* N.B. that the picture is the only reference to the pixmap /* N.B. that the picture is the only reference to the pixmap
here. */ here. */
XRenderFreePicture (compositor.display, buffer.xid); XRenderFreePicture (compositor.display,
picture_buffer->picture);
XLFree (picture_buffer);
} }
static void static void

View file

@ -60,6 +60,9 @@ struct _Positioner
int refcount; int refcount;
}; };
/* Scale factor used during constraint adjustment calculation. */
static double scale_adjustment_factor;
static void static void
Destroy (struct wl_client *client, struct wl_resource *resource) Destroy (struct wl_client *client, struct wl_resource *resource)
{ {
@ -502,7 +505,7 @@ TryFlipX (Positioner *positioner, int x, int width, int cx, int cwidth,
CalculatePosition (&new, &new_x, NULL); CalculatePosition (&new, &new_x, NULL);
/* Scale that position. */ /* Scale that position. */
new_x *= global_scale_factor; new_x *= scale_adjustment_factor;
/* If new_x is still constrained, use the previous position. */ /* If new_x is still constrained, use the previous position. */
if (new_x + offset < cx if (new_x + offset < cx
@ -598,7 +601,7 @@ TryFlipY (Positioner *positioner, int y, int height, int cy, int cheight,
CalculatePosition (&new, NULL, &new_y); CalculatePosition (&new, NULL, &new_y);
/* Scale that position. */ /* Scale that position. */
new_y *= global_scale_factor; new_y *= scale_adjustment_factor;
/* If new_y is still constrained, use the previous position. */ /* If new_y is still constrained, use the previous position. */
if (new_y + offset < cy if (new_y + offset < cy
@ -670,8 +673,8 @@ GetAdjustmentOffset (Role *parent, int *off_x, int *off_y)
&parent_gy, NULL, NULL); &parent_gy, NULL, NULL);
XLXdgRoleCurrentRootPosition (parent, &root_x, &root_y); XLXdgRoleCurrentRootPosition (parent, &root_x, &root_y);
*off_x = root_x + parent_gx * global_scale_factor; *off_x = root_x + parent_gx * parent->surface->factor;
*off_y = root_y + parent_gy * global_scale_factor; *off_y = root_y + parent_gy * parent->surface->factor;
} }
static void static void
@ -681,13 +684,17 @@ ApplyConstraintAdjustment (Positioner *positioner, Role *parent, int x,
{ {
int width, height, cx, cy, cwidth, cheight, off_x, off_y; int width, height, cx, cy, cwidth, cheight, off_x, off_y;
width = positioner->width * global_scale_factor; width = positioner->width * scale_adjustment_factor;
height = positioner->height * global_scale_factor; height = positioner->height * scale_adjustment_factor;
/* Set the factor describing how to convert surface coordinates to
window ones. */
scale_adjustment_factor = parent->surface->factor;
/* Constraint calculations are simplest if we use scaled /* Constraint calculations are simplest if we use scaled
coordinates, and then unscale them later. */ coordinates, and then unscale them later. */
x *= global_scale_factor; x *= scale_adjustment_factor;
y *= global_scale_factor; y *= scale_adjustment_factor;
if (positioner->constraint_adjustment if (positioner->constraint_adjustment
== XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) == XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE)
@ -733,10 +740,10 @@ ApplyConstraintAdjustment (Positioner *positioner, Role *parent, int x,
off_y, &y, &height); off_y, &y, &height);
finish: finish:
*x_out = x / global_scale_factor; *x_out = x / scale_adjustment_factor;
*y_out = y / global_scale_factor; *y_out = y / scale_adjustment_factor;
*width_out = width / global_scale_factor; *width_out = width / scale_adjustment_factor;
*height_out = height / global_scale_factor; *height_out = height / scale_adjustment_factor;
} }
void void

View file

@ -129,24 +129,13 @@ RenderClearRectangle (RenderTarget target, int x, int y, int width, int height)
render_funcs.clear_rectangle (target, x, y, width, height); render_funcs.clear_rectangle (target, x, y, width, height);
} }
void
RenderApplyTransform (RenderBuffer buffer, double divisor)
{
render_funcs.apply_transform (buffer, divisor);
}
void void
RenderComposite (RenderBuffer source, RenderTarget target, Operation op, RenderComposite (RenderBuffer source, RenderTarget target, Operation op,
int src_x, int src_y, int x, int y, int width, int height) int src_x, int src_y, int x, int y, int width, int height,
DrawParams *draw_params)
{ {
render_funcs.composite (source, target, op, src_x, src_y, x, y, render_funcs.composite (source, target, op, src_x, src_y, x, y,
width, height); width, height, draw_params);
}
void
RenderResetTransform (RenderBuffer buffer)
{
render_funcs.reset_transform (buffer);
} }
void void
@ -251,12 +240,13 @@ RenderFreeDmabufBuffer (RenderBuffer buffer)
} }
void void
RenderUpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage) RenderUpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage,
float scale)
{ {
if (!buffer_funcs.update_buffer_for_damage) if (!buffer_funcs.update_buffer_for_damage)
return; return;
buffer_funcs.update_buffer_for_damage (buffer, damage); buffer_funcs.update_buffer_for_damage (buffer, damage, scale);
} }
Bool Bool

62
seat.c
View file

@ -779,9 +779,10 @@ UpdateCursorOutput (SeatCursor *cursor, int root_x, int root_y)
{ {
int hotspot_x, hotspot_y; int hotspot_x, hotspot_y;
/* Scale the hotspot coordinates up by the scale. */ /* Scale the hotspot coordinates up by the scale factor specified in
hotspot_x = cursor->hotspot_x * global_scale_factor; the surface. */
hotspot_y = cursor->hotspot_y * global_scale_factor; hotspot_x = cursor->hotspot_x * cursor->role.surface->factor;
hotspot_y = cursor->hotspot_y * cursor->role.surface->factor;
/* We use a rectangle 1 pixel wide and tall, originating from the /* We use a rectangle 1 pixel wide and tall, originating from the
hotspot of the pointer. */ hotspot of the pointer. */
@ -991,20 +992,18 @@ ComputeHotspot (SeatCursor *cursor, int min_x, int min_y,
int dx, dy; int dx, dy;
int hotspot_x, hotspot_y; int hotspot_x, hotspot_y;
if (!cursor->role.surface)
return;
/* Scale the hotspot coordinates up by the scale. */ /* Scale the hotspot coordinates up by the scale. */
hotspot_x = cursor->hotspot_x * global_scale_factor; hotspot_x = cursor->hotspot_x * cursor->role.surface->factor;
hotspot_y = cursor->hotspot_y * global_scale_factor; hotspot_y = cursor->hotspot_y * cursor->role.surface->factor;
/* Apply the surface offsets to the hotspot as well. */ /* Apply the surface offsets to the hotspot as well. */
dx = dy = 0; dx = (cursor->role.surface->current_state.x
* cursor->role.surface->factor);
if (cursor->role.surface) dy = (cursor->role.surface->current_state.y
{ * cursor->role.surface->factor);
dx = (cursor->role.surface->current_state.x
* global_scale_factor);
dy = (cursor->role.surface->current_state.y
* global_scale_factor);
}
*x = min_x + hotspot_x - dx; *x = min_x + hotspot_x - dx;
*y = min_y + hotspot_y - dy; *y = min_y + hotspot_y - dy;
@ -2369,7 +2368,7 @@ HandleResizeComplete (Seat *seat)
/* Forward declarations. */ /* Forward declarations. */
static int GetXButton (int); static int GetXButton (int);
static void TransformToView (View *, double, double, double *, double *); static void TransformToSurface (Surface *, double, double, double *, double *);
static void SendButton (Seat *, Surface *, Time, uint32_t, uint32_t, static void SendButton (Seat *, Surface *, Time, uint32_t, uint32_t,
double, double); double, double);
@ -2421,8 +2420,8 @@ HandleRawButton (XIRawEvent *event)
{ {
/* Otherwise, the pointer is on a different screen! */ /* Otherwise, the pointer is on a different screen! */
TransformToView (seat->last_seen_surface->view, TransformToSurface (seat->last_seen_surface,
win_x, win_y, &dispatch_x, &dispatch_y); win_x, win_y, &dispatch_x, &dispatch_y);
SendButton (seat, seat->last_seen_surface, event->time, SendButton (seat, seat->last_seen_surface, event->time,
button, WL_POINTER_BUTTON_STATE_RELEASED, button, WL_POINTER_BUTTON_STATE_RELEASED,
dispatch_x, dispatch_y); dispatch_x, dispatch_y);
@ -3258,11 +3257,15 @@ EnteredSurface (Seat *seat, Surface *surface, Time time,
} }
static void static void
TransformToView (View *view, double event_x, double event_y, TransformToSurface (Surface *surface, double event_x, double event_y,
double *view_x_out, double *view_y_out) double *view_x_out, double *view_y_out)
{ {
int int_x, int_y, x, y; int int_x, int_y, x, y;
double view_x, view_y; double view_x, view_y;
View *view;
/* Use the surface's view. */
view = surface->view;
/* Even though event_x and event_y are doubles, they cannot exceed /* Even though event_x and event_y are doubles, they cannot exceed
65535.0, so this cannot overflow. */ 65535.0, so this cannot overflow. */
@ -3277,8 +3280,8 @@ TransformToView (View *view, double event_x, double event_y,
/* Finally, transform the coordinates by the global output /* Finally, transform the coordinates by the global output
scale. */ scale. */
*view_x_out = view_x / global_scale_factor; *view_x_out = view_x / surface->factor;
*view_y_out = view_y / global_scale_factor; *view_y_out = view_y / surface->factor;
} }
static Bool static Bool
@ -3411,9 +3414,7 @@ DispatchEntryExit (Subcompositor *subcompositor, XIEnterEvent *event)
after_dispatch_set: after_dispatch_set:
TransformToView (dispatch->view, event_x, TransformToSurface (dispatch, event_x, event_y, &x, &y);
event_y, &x, &y);
EnteredSurface (seat, dispatch, event->time, x, y, False); EnteredSurface (seat, dispatch, event->time, x, y, False);
} }
@ -3688,8 +3689,7 @@ DispatchMotion (Subcompositor *subcompositor, XIDeviceEvent *xev)
/* Inside a surface; cancel external drag and drop. */ /* Inside a surface; cancel external drag and drop. */
XLDoDragLeave (seat); XLDoDragLeave (seat);
TransformToView (dispatch->view, event_x, event_y, TransformToSurface (dispatch, event_x, event_y, &x, &y);
&x, &y);
EnteredSurface (seat, dispatch, xev->time, x, y, False); EnteredSurface (seat, dispatch, xev->time, x, y, False);
if (!HandleValuatorMotion (seat, dispatch, x, y, xev)) if (!HandleValuatorMotion (seat, dispatch, x, y, xev))
@ -3753,8 +3753,8 @@ CancelGrab (Seat *seat, Time time, Window source,
/* Finally, translate the coordinates to the target /* Finally, translate the coordinates to the target
view. */ view. */
TransformToView (seat->pointer_unlock_surface->view, TransformToSurface (seat->pointer_unlock_surface,
x, y, &x, &y); x, y, &x, &y);
} }
} }
@ -3925,8 +3925,8 @@ DispatchButton (Subcompositor *subcompositor, XIDeviceEvent *xev)
after_dispatch_set: after_dispatch_set:
TransformToView (dispatch->view, xev->event_x, TransformToSurface (dispatch, xev->event_x, xev->event_y,
xev->event_y, &x, &y); &x, &y);
EnteredSurface (seat, dispatch, xev->time, x, y, EnteredSurface (seat, dispatch, xev->time, x, y,
False); False);
@ -4891,7 +4891,7 @@ ForceEntry (Seat *seat, Window source, double x, double y)
/* Finally, translate the coordinates to the target /* Finally, translate the coordinates to the target
view. */ view. */
TransformToView (surface->view, x, y, &x, &y); TransformToSurface (surface, x, y, &x, &y);
} }
} }
else else

View file

@ -1582,30 +1582,26 @@ ViewSetScale (View *view, int scale)
} }
static double static double
GetTxTy (int scale) GetContentScale (int scale)
{ {
if (scale > 0) if (scale > 0)
return scale + 1; return 1.0 / (scale + 1);
return 1.0 / (-scale + 1); return -scale + 1;
} }
static void static void
ViewApplyTransform (View *view, RenderBuffer buffer) ViewComputeTransform (View *view, DrawParams *params)
{ {
RenderApplyTransform (buffer, GetTxTy (view->scale)); /* First, there is no transform. */
} params->flags = 0;
/* TODO: the callers of this can be optimized by setting the picture if (view->scale)
transform on the attached buffer if that buffer is not attached to {
any other view. */ /* There is a scale, so set it. */
params->flags |= ScaleSet;
static Bool params->scale = GetContentScale (view->scale);
ViewHaveTransform (View *view) }
{
/* view->scale is the amount by which to scale _down_ the view. If
it is 0, then no scaling will be performed. */
return view->scale;
} }
void void
@ -1763,6 +1759,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
RenderBuffer buffer; RenderBuffer buffer;
int min_x, min_y; int min_x, min_y;
int age; int age;
DrawParams draw_params;
/* Just return if no target was specified. */ /* Just return if no target was specified. */
if (!IsTargetAttached (subcompositor)) if (!IsTargetAttached (subcompositor))
@ -1946,7 +1943,8 @@ SubcompositorUpdate (Subcompositor *subcompositor)
when the damage region is empty. */ when the damage region is empty. */
buffer = XLRenderBufferFromBuffer (view->buffer); buffer = XLRenderBufferFromBuffer (view->buffer);
RenderUpdateBufferForDamage (buffer, &list->view->damage); RenderUpdateBufferForDamage (buffer, &list->view->damage,
GetContentScale (list->view->scale));
if (pixman_region32_not_empty (&list->view->damage)) if (pixman_region32_not_empty (&list->view->damage))
{ {
@ -2115,11 +2113,12 @@ SubcompositorUpdate (Subcompositor *subcompositor)
Note that if the subcompositor is not garbaged, then this Note that if the subcompositor is not garbaged, then this
has already been done. */ has already been done. */
RenderUpdateBufferForDamage (buffer, NULL); RenderUpdateBufferForDamage (buffer, NULL, 0.0f);
else if (age < 0 || age > 3) else if (age < 0 || age > 3)
/* The target contents are too old, but the damage can be /* The target contents are too old, but the damage can be
trusted. */ trusted. */
RenderUpdateBufferForDamage (buffer, &view->damage); RenderUpdateBufferForDamage (buffer, &view->damage,
GetContentScale (list->view->scale));
if (!first) if (!first)
{ {
@ -2174,8 +2173,8 @@ SubcompositorUpdate (Subcompositor *subcompositor)
first = view; first = view;
if (ViewHaveTransform (view)) /* Compute the transform and put it in draw_params. */
ViewApplyTransform (view, buffer); ViewComputeTransform (view, &draw_params);
if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3)) if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3))
{ {
@ -2206,8 +2205,8 @@ SubcompositorUpdate (Subcompositor *subcompositor)
BoxStartY (temp_boxes) - min_y + ty, BoxStartY (temp_boxes) - min_y + ty,
/* width. */ /* width. */
BoxWidth (temp_boxes), BoxWidth (temp_boxes),
/* height. */ /* height, draw-params. */
BoxHeight (temp_boxes)); BoxHeight (temp_boxes), &draw_params);
} }
} }
else else
@ -2228,8 +2227,8 @@ SubcompositorUpdate (Subcompositor *subcompositor)
view->abs_y - min_y + ty, view->abs_y - min_y + ty,
/* width. */ /* width. */
ViewWidth (view), ViewWidth (view),
/* height. */ /* height, draw-params. */
ViewHeight (view)); ViewHeight (view), &draw_params);
/* Also adjust the opaque and input regions here. */ /* Also adjust the opaque and input regions here. */
@ -2282,9 +2281,6 @@ SubcompositorUpdate (Subcompositor *subcompositor)
} }
} }
if (ViewHaveTransform (view))
RenderResetTransform (buffer);
next_1: next_1:
list = list->next; list = list->next;
} }
@ -2358,6 +2354,7 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
Operation op; Operation op;
pixman_region32_t temp; pixman_region32_t temp;
RenderBuffer buffer; RenderBuffer buffer;
DrawParams draw_params;
/* Graphics exposures are not yet handled. */ /* Graphics exposures are not yet handled. */
if (event->type == GraphicsExpose) if (event->type == GraphicsExpose)
@ -2438,11 +2435,12 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
buffer = XLRenderBufferFromBuffer (view->buffer); buffer = XLRenderBufferFromBuffer (view->buffer);
boxes = pixman_region32_rectangles (&temp, &nboxes); boxes = pixman_region32_rectangles (&temp, &nboxes);
/* Update the attached buffer from any damage. */ /* Compute the transform. */
RenderUpdateBufferForDamage (buffer, &list->view->damage); ViewComputeTransform (view, &draw_params);
if (ViewHaveTransform (view)) /* Update the attached buffer from any damage. */
ViewApplyTransform (view, buffer); RenderUpdateBufferForDamage (buffer, &list->view->damage,
GetContentScale (list->view->scale));
for (i = 0; i < nboxes; ++i) for (i = 0; i < nboxes; ++i)
RenderComposite (buffer, subcompositor->target, op, RenderComposite (buffer, subcompositor->target, op,
@ -2455,11 +2453,9 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
/* dst-y. */ /* dst-y. */
BoxStartY (boxes[i]) - min_y + ty, BoxStartY (boxes[i]) - min_y + ty,
/* width, height. */ /* width, height. */
BoxWidth (boxes[i]), BoxHeight (boxes[i])); BoxWidth (boxes[i]), BoxHeight (boxes[i]),
/* draw-params. */
/* Undo transforms that were applied. */ &draw_params);
if (ViewHaveTransform (view))
RenderResetTransform (buffer);
/* Free the scratch region used to compute the intersection. */ /* Free the scratch region used to compute the intersection. */
pixman_region32_fini (&temp); pixman_region32_fini (&temp);

View file

@ -488,9 +488,13 @@ MaybeUpdateOutputs (Subsurface *subsurface)
/* Valid base coordinates are not yet available. */ /* Valid base coordinates are not yet available. */
return; return;
if (!subsurface->parent)
/* A valid scale factor is not available. */
return;
/* Compute the positions relative to the parent. */ /* Compute the positions relative to the parent. */
x = subsurface->current_substate.x * global_scale_factor; x = subsurface->current_substate.x * subsurface->parent->factor;
y = subsurface->current_substate.y * global_scale_factor; y = subsurface->current_substate.y * subsurface->parent->factor;
/* And the base X and Y. */ /* And the base X and Y. */
base_x = subsurface->role.surface->output_x; base_x = subsurface->role.surface->output_x;
@ -541,12 +545,12 @@ AfterParentCommit (Surface *surface, void *data)
subsurface->current_substate.y subsurface->current_substate.y
= subsurface->pending_substate.y; = subsurface->pending_substate.y;
/* The X and Y coordinates here are also surface-local and must /* The X and Y coordinates here are also parent-local and must
be scaled by the global scale factor. */ be scaled by the global scale factor. */
ViewMove (subsurface->role.surface->view, ViewMove (subsurface->role.surface->view,
subsurface->current_substate.x * global_scale_factor, subsurface->current_substate.x * subsurface->parent->factor,
subsurface->current_substate.y * global_scale_factor); subsurface->current_substate.y * subsurface->parent->factor);
} }
/* And any cached surface state too. */ /* And any cached surface state too. */
@ -695,8 +699,15 @@ Rescale (Surface *surface, Role *role)
position. */ position. */
ViewMove (surface->view, ViewMove (surface->view,
subsurface->current_substate.x * global_scale_factor, subsurface->current_substate.x * subsurface->parent->factor,
subsurface->current_substate.y * global_scale_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 static void
@ -843,6 +854,7 @@ GetSubsurface (struct wl_client *client, struct wl_resource *resource,
subsurface->role.funcs.early_commit = EarlyCommit; subsurface->role.funcs.early_commit = EarlyCommit;
subsurface->role.funcs.get_window = GetWindow; subsurface->role.funcs.get_window = GetWindow;
subsurface->role.funcs.rescale = Rescale; subsurface->role.funcs.rescale = Rescale;
subsurface->role.funcs.parent_rescale = ParentRescale;
subsurface->role.funcs.note_child_synced = NoteChildSynced; subsurface->role.funcs.note_child_synced = NoteChildSynced;
subsurface->role.funcs.note_desync_child = NoteDesyncChild; subsurface->role.funcs.note_desync_child = NoteDesyncChild;
@ -937,9 +949,9 @@ XLUpdateOutputsForChildren (Surface *parent, int base_x, int base_y)
child = item->data; child = item->data;
subsurface = SubsurfaceFromRole (child->role); subsurface = SubsurfaceFromRole (child->role);
output_x = (subsurface->current_substate.x output_x = (subsurface->current_substate.x
* global_scale_factor); * parent->factor);
output_y = (subsurface->current_substate.y output_y = (subsurface->current_substate.y
* global_scale_factor); * parent->factor);
output_width = ViewWidth (child->view); output_width = ViewWidth (child->view);
output_height = ViewHeight (child->view); output_height = ViewHeight (child->view);

107
surface.c
View file

@ -509,11 +509,92 @@ static void
ApplyScale (Surface *surface) ApplyScale (Surface *surface)
{ {
int scale, effective; int scale, effective;
double b, g, e, d;
XLList *subsurface;
Role *role;
scale = surface->current_state.buffer_scale; scale = surface->current_state.buffer_scale;
effective = GetEffectiveScale (scale); effective = GetEffectiveScale (scale);
ViewSetScale (surface->view, effective); ViewSetScale (surface->view, effective);
/* Now calculate the surface factor, a factor used to scale surface
coordinates to view (X window) coordinates.
The scale we want is the width of the view (area on the X screen)
divided by the surface width, which is the width of the buffer
after it has been shrunk B - 1 times, B being the buffer scale.
However, the size of the view is not available during computation.
So, computing the scale looks something like this:
A = width of buffer <-------------+-- we must reduce these out
B = buffer scale |
C = width of view <---------------+
L = surface width <---------------+
G = global scale
E = scale after accounting for difference between the global
and buffer scales
D = desired scale, otherwise C / surface width
A = 2004
B = 3
G = 2
L = A / B
E = G - B
if E is not less than 0
E = E + 1
else
E = 1 / abs (E - 1)
finally
C = A * E
D = C / L
D = (A * E) / (A / B)
D = B * E
Phew. */
b = scale;
g = global_scale_factor;
e = g - b;
if (e >= 0.0)
e = e + 1;
else
e = 1.0 / fabs (e - 1);
d = b * e;
if (surface->factor != d)
{
/* The scale factor changed. */
surface->factor = d;
/* Notify all subsurfaces to move themselves to a more correct
location. */
subsurface = surface->subsurfaces;
for (; subsurface; subsurface = subsurface->next)
{
/* Get the subsurface role. */
role = subsurface->data;
/* Make sure it still has a surface, since it should not be
in surface->subsurfaces otherwise. */
XLAssert (role->surface != NULL);
/* Call the parent rescale hook. */
if (role->funcs.rescale)
role->funcs.rescale (role->surface, role);
}
}
} }
static void static void
@ -530,7 +611,7 @@ ApplyOpaqueRegion (Surface *surface)
{ {
pixman_region32_init (&temp); pixman_region32_init (&temp);
XLScaleRegion (&temp, &surface->current_state.opaque, XLScaleRegion (&temp, &surface->current_state.opaque,
global_scale_factor, global_scale_factor); surface->factor, surface->factor);
ViewSetOpaque (surface->view, &temp); ViewSetOpaque (surface->view, &temp);
pixman_region32_fini (&temp); pixman_region32_fini (&temp);
} }
@ -550,7 +631,7 @@ ApplyInputRegion (Surface *surface)
{ {
pixman_region32_init (&temp); pixman_region32_init (&temp);
XLScaleRegion (&temp, &surface->current_state.input, XLScaleRegion (&temp, &surface->current_state.input,
global_scale_factor, global_scale_factor); surface->factor, surface->factor);
ViewSetInput (surface->view, &temp); ViewSetInput (surface->view, &temp);
pixman_region32_fini (&temp); pixman_region32_fini (&temp);
} }
@ -566,9 +647,9 @@ HandleScaleChanged (void *data, int new_scale)
/* First, reapply various regions that depend on the surface /* First, reapply various regions that depend on the surface
scale. */ scale. */
ApplyScale (surface);
ApplyInputRegion (surface); ApplyInputRegion (surface);
ApplyOpaqueRegion (surface); ApplyOpaqueRegion (surface);
ApplyScale (surface);
/* Next, call any role-specific hooks. */ /* Next, call any role-specific hooks. */
if (surface->role && surface->role->funcs.rescale) if (surface->role && surface->role->funcs.rescale)
@ -639,7 +720,7 @@ ApplySurfaceDamage (Surface *surface)
{ {
pixman_region32_init (&temp); pixman_region32_init (&temp);
XLScaleRegion (&temp, &surface->current_state.surface, XLScaleRegion (&temp, &surface->current_state.surface,
global_scale_factor, global_scale_factor); surface->factor, surface->factor);
ViewDamage (surface->view, &temp); ViewDamage (surface->view, &temp);
pixman_region32_fini (&temp); pixman_region32_fini (&temp);
} }
@ -788,6 +869,12 @@ InternalCommit (Surface *surface, State *pending)
} }
} }
if (pending->pending & PendingBufferScale)
{
surface->current_state.buffer_scale = pending->buffer_scale;
ApplyScale (surface);
}
if (pending->pending & PendingInputRegion) if (pending->pending & PendingInputRegion)
{ {
pixman_region32_copy (&surface->current_state.input, pixman_region32_copy (&surface->current_state.input,
@ -802,12 +889,6 @@ InternalCommit (Surface *surface, State *pending)
ApplyOpaqueRegion (surface); ApplyOpaqueRegion (surface);
} }
if (pending->pending & PendingBufferScale)
{
surface->current_state.buffer_scale = pending->buffer_scale;
ApplyScale (surface);
}
if (pending->pending & PendingAttachments) if (pending->pending & PendingAttachments)
{ {
surface->current_state.x = pending->x; surface->current_state.x = pending->x;
@ -1151,13 +1232,13 @@ XLCreateSurface (struct wl_client *client,
InitState (&surface->current_state); InitState (&surface->current_state);
InitState (&surface->cached_state); InitState (&surface->cached_state);
/* Apply the scale to initialize the default. */
ApplyScale (surface);
/* Now the default input has been initialized, so apply it to the /* Now the default input has been initialized, so apply it to the
view. */ view. */
ApplyInputRegion (surface); ApplyInputRegion (surface);
/* Likewise for the scale. */
ApplyScale (surface);
/* Initially, allow surfaces to accept any kind of role. */ /* Initially, allow surfaces to accept any kind of role. */
surface->role_type = AnythingType; surface->role_type = AnythingType;

View file

@ -278,6 +278,7 @@ MoveWindow (XdgPopup *popup)
int root_x, root_y, parent_gx, parent_gy; int root_x, root_y, parent_gx, parent_gy;
int geometry_x, geometry_y, x, y; int geometry_x, geometry_y, x, y;
Window window; Window window;
double parent_scale, current_scale;
/* No parent was specified. */ /* No parent was specified. */
if (!popup->parent) if (!popup->parent)
@ -286,6 +287,14 @@ MoveWindow (XdgPopup *popup)
if (!popup->role || !popup->parent) if (!popup->role || !popup->parent)
return; return;
if (!popup->role->surface || !popup->parent->surface)
/* No surface being available means we cannot obtain the window
scale. */
return;
parent_scale = popup->parent->surface->factor;
current_scale = popup->role->surface->factor;
window = XLWindowFromXdgRole (popup->role); window = XLWindowFromXdgRole (popup->role);
XLXdgRoleGetCurrentGeometry (popup->parent, &parent_gx, XLXdgRoleGetCurrentGeometry (popup->parent, &parent_gx,
@ -295,12 +304,18 @@ MoveWindow (XdgPopup *popup)
XLXdgRoleCurrentRootPosition (popup->parent, &root_x, XLXdgRoleCurrentRootPosition (popup->parent, &root_x,
&root_y); &root_y);
parent_gx *= global_scale_factor; /* Parent geometry is relative to the parent coordinate system. */
parent_gy *= global_scale_factor; parent_gx *= parent_scale;
geometry_x *= global_scale_factor; parent_gy *= parent_scale;
geometry_y *= global_scale_factor;
x = popup->x * global_scale_factor; /* geometry_x and geometry_y are relative to the local coordinate
y = popup->y * global_scale_factor; system. */
geometry_x *= current_scale;
geometry_y *= current_scale;
/* X and Y are relative to the parent coordinate system. */
x = popup->x * parent_scale;
y = popup->y * parent_scale;
XMoveWindow (compositor.display, window, XMoveWindow (compositor.display, window,
x + root_x + parent_gx - geometry_x, x + root_x + parent_gx - geometry_x,

View file

@ -1167,8 +1167,8 @@ GetResizeDimensions (Surface *surface, Role *role, int *x_out,
{ {
XLXdgRoleGetCurrentGeometry (role, NULL, NULL, x_out, y_out); XLXdgRoleGetCurrentGeometry (role, NULL, NULL, x_out, y_out);
*x_out *= global_scale_factor; *x_out *= surface->factor;
*y_out *= global_scale_factor; *y_out *= surface->factor;
} }
static void static void
@ -1467,7 +1467,10 @@ XLXdgRoleCalcNewWindowSize (Role *role, int width, int height,
xdg_role = XdgRoleFromRole (role); xdg_role = XdgRoleFromRole (role);
if (!xdg_role->current_state.window_geometry_width) if (!xdg_role->current_state.window_geometry_width
/* If no surface exists, we might as well return immediately,
since the scale factor will not be obtainable. */
|| !role->surface)
{ {
*new_width = width; *new_width = width;
*new_height = height; *new_height = height;
@ -1480,8 +1483,8 @@ XLXdgRoleCalcNewWindowSize (Role *role, int width, int height,
/* Adjust the current_width and current_height by the global scale /* Adjust the current_width and current_height by the global scale
factor. */ factor. */
current_width = (max_x - min_x + 1) / global_scale_factor; current_width = (max_x - min_x + 1) / role->surface->factor;
current_height = (max_y - min_y + 1) / global_scale_factor; current_height = (max_y - min_y + 1) / role->surface->factor;
XLXdgRoleGetCurrentGeometry (role, NULL, NULL, &geometry_width, XLXdgRoleGetCurrentGeometry (role, NULL, NULL, &geometry_width,
&geometry_height); &geometry_height);

View file

@ -362,9 +362,14 @@ NoteConfigureTime (Timer *timer, void *data, struct timespec time)
{ {
XdgToplevel *toplevel; XdgToplevel *toplevel;
int width, height, effective_width, effective_height; int width, height, effective_width, effective_height;
double factor;
toplevel = data; toplevel = data;
/* Obtain the scale factor. toplevel->role->surface should not be
NULL here, as the timer is cancelled upon role detachment. */
factor = toplevel->role->surface->factor;
/* If only the window state changed, call SendStates. */ /* If only the window state changed, call SendStates. */
if (!(toplevel->state & StatePendingConfigureSize)) if (!(toplevel->state & StatePendingConfigureSize))
SendStates (toplevel); SendStates (toplevel);
@ -374,8 +379,8 @@ NoteConfigureTime (Timer *timer, void *data, struct timespec time)
if (toplevel->state & StatePendingConfigureStates) if (toplevel->state & StatePendingConfigureStates)
WriteStates (toplevel); WriteStates (toplevel);
effective_width = toplevel->configure_width / global_scale_factor; effective_width = toplevel->configure_width / factor;
effective_height = toplevel->configure_height / global_scale_factor; effective_height = toplevel->configure_height / factor;
/* Compute the geometry for the configure event based on the /* Compute the geometry for the configure event based on the
current size of the toplevel. */ current size of the toplevel. */
@ -477,9 +482,14 @@ static void
SendStates (XdgToplevel *toplevel) SendStates (XdgToplevel *toplevel)
{ {
int width, height; int width, height;
double factor;
WriteStates (toplevel); WriteStates (toplevel);
/* Obtain the scale factor. toplevel->role->surface should not be
NULL here. */
factor = toplevel->role->surface->factor;
/* Adjust the width and height we're sending by the window /* Adjust the width and height we're sending by the window
geometry. */ geometry. */
if (toplevel->state & StateMissingState) if (toplevel->state & StateMissingState)
@ -487,8 +497,8 @@ SendStates (XdgToplevel *toplevel)
&width, &height); &width, &height);
else else
XLXdgRoleCalcNewWindowSize (toplevel->role, XLXdgRoleCalcNewWindowSize (toplevel->role,
toplevel->width / global_scale_factor, toplevel->width / factor,
toplevel->height / global_scale_factor, toplevel->height / factor,
&width, &height); &width, &height);
SendConfigure (toplevel, width, height); SendConfigure (toplevel, width, height);
@ -505,6 +515,14 @@ RecordStateSize (XdgToplevel *toplevel)
{ {
Bool a, b; Bool a, b;
int width, height; int width, height;
double factor;
if (!toplevel->role->surface)
/* We can't get the scale factor in this case. */
return;
/* Obtain the scale factor. */
factor = toplevel->role->surface->factor;
/* Record the last known size of a toplevel before its state is /* Record the last known size of a toplevel before its state is
changed. That way, we can send xdg_toplevel::configure with the changed. That way, we can send xdg_toplevel::configure with the
@ -521,8 +539,8 @@ RecordStateSize (XdgToplevel *toplevel)
upon minimization. */ upon minimization. */
XLXdgRoleGetCurrentGeometry (toplevel->role, NULL, NULL, XLXdgRoleGetCurrentGeometry (toplevel->role, NULL, NULL,
&width, &height); &width, &height);
width *= global_scale_factor; width *= factor;
height *= global_scale_factor; height *= factor;
} }
else else
{ {
@ -778,10 +796,10 @@ HandleWindowGeometryChange (XdgToplevel *toplevel)
XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y, XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y,
&width, &height); &width, &height);
width *= global_scale_factor; width *= toplevel->role->surface->factor;
height *= global_scale_factor; height *= toplevel->role->surface->factor;
x *= global_scale_factor; x *= toplevel->role->surface->factor;
y *= global_scale_factor; y *= toplevel->role->surface->factor;
dx = SubcompositorWidth (subcompositor) - width; dx = SubcompositorWidth (subcompositor) - width;
dy = SubcompositorHeight (subcompositor) - height; dy = SubcompositorHeight (subcompositor) - height;
@ -795,25 +813,35 @@ HandleWindowGeometryChange (XdgToplevel *toplevel)
/* Initially, specify PSize. After the first MapNotify, also /* Initially, specify PSize. After the first MapNotify, also
specify PPosition so that subsurfaces won't move the window. */ specify PPosition so that subsurfaces won't move the window. */
hints->min_width = toplevel->min_width * global_scale_factor + dx; hints->min_width = (toplevel->min_width
hints->min_height = toplevel->min_height * global_scale_factor + dy; * toplevel->role->surface->factor
+ dx);
hints->min_height = (toplevel->min_height
* toplevel->role->surface->factor
+ dy);
if (toplevel->max_width) if (toplevel->max_width)
{ {
hints->max_width = toplevel->max_width * global_scale_factor + dx; hints->max_width = (toplevel->max_width
hints->max_height = toplevel->max_height * global_scale_factor + dy; * toplevel->role->surface->factor
+ dx);
hints->max_height = (toplevel->max_height
* toplevel->role->surface->factor
+ dy);
hints->flags |= PMaxSize; hints->flags |= PMaxSize;
} }
else else
hints->flags &= ~PMaxSize; hints->flags &= ~PMaxSize;
/* If a global scale factor is set, also set the resize increment to /* If a scale factor is set, also set the resize increment to the
the scale factor. */ scale factor. */
if (global_scale_factor != 1) if (toplevel->role->surface->factor != 1)
{ {
hints->width_inc = global_scale_factor; /* Take the ceiling value, there is no good way of dealing with
hints->height_inc = global_scale_factor; cases where the scale ends up a non-integer value. */
hints->width_inc = ceil (toplevel->role->surface->factor);
hints->height_inc = ceil (toplevel->role->surface->factor);
hints->flags |= PResizeInc; hints->flags |= PResizeInc;
} }
else else
@ -1345,10 +1373,10 @@ NoteWindowPreResize (Role *role, XdgRoleImplementation *impl,
XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y, XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y,
&gwidth, &gheight); &gwidth, &gheight);
dx = width - gwidth * global_scale_factor; dx = width - gwidth * toplevel->role->surface->factor;
dy = height - gheight * global_scale_factor; dy = height - gheight * toplevel->role->surface->factor;
x *= global_scale_factor; x *= toplevel->role->surface->factor;
y *= global_scale_factor; y *= toplevel->role->surface->factor;
ApplyGtkFrameExtents (toplevel, x, y, dx - x, dy - y); ApplyGtkFrameExtents (toplevel, x, y, dx - x, dy - y);
} }