diff --git a/compositor.h b/compositor.h index 78a4a6a..0172072 100644 --- a/compositor.h +++ b/compositor.h @@ -103,6 +103,8 @@ typedef union _RenderTarget RenderTarget; typedef union _RenderBuffer RenderBuffer; typedef union _RenderFence RenderFence; +typedef struct _DrawParams DrawParams; + typedef struct _DmaBufAttributes DmaBufAttributes; typedef struct _SharedMemoryAttributes SharedMemoryAttributes; @@ -120,6 +122,21 @@ enum _Operation 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 { /* The format of the buffer. */ @@ -241,18 +258,12 @@ struct _RenderFuncs /* Clear the given rectangle. */ 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 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, - int, int, int, int); - - /* Reset the transform for the given buffer. */ - void (*reset_transform) (RenderBuffer); + int, int, int, int, DrawParams *); /* Finish rendering, and swap changes to display. May be NULL. */ void (*finish_render) (RenderTarget); @@ -349,8 +360,10 @@ struct _BufferFuncs /* Notice that the given buffer has been damaged. May be NULL. If the given NULL damage, assume that the entire buffer has been damaged. Must be called at least once before any rendering can - be performed on the buffer. */ - void (*update_buffer_for_damage) (RenderBuffer, pixman_region32_t *); + be performed on the buffer. 3rd arg is the scale by which to + divide the buffer. */ + void (*update_buffer_for_damage) (RenderBuffer, pixman_region32_t *, + float); /* Return whether or not the buffer contents can be released early, by being copied to an offscreen buffer. */ @@ -376,10 +389,8 @@ extern void RenderStartRender (RenderTarget); extern void RenderFillBoxesWithTransparency (RenderTarget, pixman_box32_t *, int, int, int); extern void RenderClearRectangle (RenderTarget, int, int, int, int); -extern void RenderApplyTransform (RenderBuffer, double); extern void RenderComposite (RenderBuffer, RenderTarget, Operation, int, - int, int, int, int, int); -extern void RenderResetTransform (RenderBuffer); + int, int, int, int, int, DrawParams *); extern void RenderFinishRender (RenderTarget); extern int RenderTargetAge (RenderTarget); extern RenderFence RenderImportFdFence (int, Bool *); @@ -398,7 +409,8 @@ extern Bool RenderValidateShmParams (uint32_t, uint32_t, uint32_t, int32_t, int32_t, size_t); extern void RenderFreeShmBuffer (RenderBuffer); extern void RenderFreeDmabufBuffer (RenderBuffer); -extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *); +extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *, + float); extern Bool RenderCanReleaseNow (RenderBuffer); /* Defined in run.c. */ @@ -832,6 +844,10 @@ struct _Surface /* The associated sync acquire fd, or -1. */ int acquire_fence; + + /* The scale factor used to convert from surface coordinates to + window coordinates. */ + double factor; }; struct _RoleFuncs @@ -851,6 +867,7 @@ struct _RoleFuncs void (*post_resize) (Surface *, Role *, int, int, int, int); void (*move_by) (Surface *, Role *, int, int); void (*rescale) (Surface *, Role *); + void (*parent_rescale) (Surface *, Role *); void (*note_desync_child) (Surface *, Role *); void (*note_child_synced) (Surface *, Role *); }; diff --git a/dnd.c b/dnd.c index c2c7e88..7d8f844 100644 --- a/dnd.c +++ b/dnd.c @@ -885,11 +885,24 @@ HandleMotion (Surface *toplevel, int x, int y, uint32_t action, /* Find the view underneath the subcompositor. */ view = SubcompositorLookupView (subcompositor, x, y, &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. */ - *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 nothing changed, don't do anything. */ diff --git a/egl.c b/egl.c index 56f305a..65b8c13 100644 --- a/egl.c +++ b/egl.c @@ -126,9 +126,6 @@ struct _EglBuffer /* The width and height of the buffer. */ int width, height; - /* The projective scale factor. */ - GLfloat scale; - /* Various different buffers. */ union { /* 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); } -static void -ApplyTransform (RenderBuffer buffer, double divisor) -{ - EglBuffer *egl_buffer; - - egl_buffer = buffer.pointer; - egl_buffer->scale = 1.0f / (GLfloat) divisor; -} - static CompositeProgram * FindProgram (EglBuffer *buffer) { @@ -1177,7 +1165,7 @@ GetTextureTarget (EglBuffer *buffer) static void Composite (RenderBuffer buffer, RenderTarget target, 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 x1, x2, y1, y2; @@ -1185,6 +1173,7 @@ Composite (RenderBuffer buffer, RenderTarget target, EglBuffer *egl_buffer; CompositeProgram *program; GLenum tex_target; + GLfloat scale; egl_target = target.pointer; egl_buffer = buffer.pointer; @@ -1244,13 +1233,18 @@ Composite (RenderBuffer buffer, RenderTarget target, else glDisable (GL_BLEND); + if (params->flags & ScaleSet) + scale = params->scale; + else + scale = 1.0f; + glActiveTexture (GL_TEXTURE0); glBindTexture (tex_target, egl_buffer->texture); glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram (program->program); glUniform1i (program->texture, 0); - glUniform1f (program->scale, egl_buffer->scale); + glUniform1f (program->scale, scale); glUniform1i (program->invert_y, egl_buffer->flags & InvertY); glVertexAttribPointer (program->position, 2, GL_FLOAT, GL_FALSE, 0, verts); @@ -1268,12 +1262,6 @@ Composite (RenderBuffer buffer, RenderTarget target, glBindTexture (tex_target, 0); } -static void -ResetTransform (RenderBuffer buffer) -{ - /* TODO... */ -} - static void FinishRender (RenderTarget target) { @@ -1421,9 +1409,7 @@ static RenderFuncs egl_render_funcs = .start_render = StartRender, .fill_boxes_with_transparency = FillBoxesWithTransparency, .clear_rectangle = ClearRectangle, - .apply_transform = ApplyTransform, .composite = Composite, - .reset_transform = ResetTransform, .finish_render = FinishRender, .target_age = TargetAge, .import_fd_fence = ImportFdFence, @@ -1514,7 +1500,6 @@ BufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error) buffer->texture = EGL_NO_TEXTURE; buffer->width = attributes->width; buffer->height = attributes->height; - buffer->scale = 1.0f; buffer->u.type = DmaBufBuffer; i = 0; @@ -1664,7 +1649,6 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error) buffer->texture = EGL_NO_TEXTURE; buffer->width = attributes->width; buffer->height = attributes->height; - buffer->scale = 1.0f; buffer->u.type = ShmBuffer; /* Record the buffer data. */ @@ -2134,22 +2118,19 @@ UpdateBuffer (RenderBuffer buffer, pixman_region32_t *damage) } 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; - egl_buffer = buffer.pointer; - - if (egl_buffer->scale != 1.0f && damage) + if (scale != 1.0f && damage) { /* Scale the damage, specified in scaled coordinates, down to texture coordinates. */ pixman_region32_init (®ion); - XLScaleRegion (®ion, damage, - 1.0f / egl_buffer->scale, - 1.0f / egl_buffer->scale); + XLScaleRegion (®ion, damage, 1.0f / scale, + 1.0f / scale); UpdateBuffer (buffer, ®ion); pixman_region32_fini (®ion); } diff --git a/picture_renderer.c b/picture_renderer.c index 1b483c7..7342495 100644 --- a/picture_renderer.c +++ b/picture_renderer.c @@ -35,6 +35,17 @@ along with 12to11. If not, see . */ typedef struct _DrmFormatInfo DrmFormatInfo; 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 { /* 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); } -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 ConvertOperation (Operation op) { @@ -320,26 +316,70 @@ ConvertOperation (Operation op) 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 Composite (RenderBuffer buffer, RenderTarget target, 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), - buffer.xid, None, target.xid, + picture_buffer->picture, None, target.xid, /* src-x, src-y, mask-x, mask-y. */ src_x, src_y, 0, 0, /* dst-x, dst-y, width, height. */ x, y, width, height); } -static void -ResetTransform (RenderBuffer buffer) -{ - XRenderSetPictureTransform (compositor.display, buffer.xid, - &identity_transform); -} - static int TargetAge (RenderTarget target) { @@ -388,9 +428,7 @@ static RenderFuncs picture_render_funcs = .destroy_render_target = DestroyRenderTarget, .fill_boxes_with_transparency = FillBoxesWithTransparency, .clear_rectangle = ClearRectangle, - .apply_transform = ApplyTransform, .composite = Composite, - .reset_transform = ResetTransform, .target_age = TargetAge, .import_fd_fence = ImportFdFence, .wait_fence = WaitFence, @@ -746,6 +784,7 @@ BufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error) xcb_generic_error_t *xerror; XRenderPictFormat *format; XRenderPictureAttributes picture_attrs; + PictureBuffer *buffer; /* Find the depth and bpp corresponding to the format. */ depth = DepthForDmabufFormat (attributes->drm_format, &bpp); @@ -791,12 +830,16 @@ BufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error) format, 0, &picture_attrs); XFreePixmap (compositor.display, pixmap); - return (RenderBuffer) picture; + /* Create the wrapper object. */ + buffer = XLCalloc (1, sizeof *buffer); + buffer->picture = picture; + + return (RenderBuffer) (void *) buffer; error: CloseFileDescriptors (attributes); *error = True; - return (RenderBuffer) (XID) None; + return (RenderBuffer) NULL; } static void @@ -832,6 +875,7 @@ FinishDmaBufRecord (DmaBufRecord *pending, Bool success) { Picture picture; XRenderPictureAttributes picture_attrs; + PictureBuffer *buffer; if (success) { @@ -844,8 +888,12 @@ FinishDmaBufRecord (DmaBufRecord *pending, Bool success) &picture_attrs); 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. */ - pending->success_func ((RenderBuffer) picture, + pending->success_func ((RenderBuffer) (void *) buffer, pending->data); } else @@ -989,6 +1037,7 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error) Pixmap pixmap; Picture picture; int fd, depth, format, bpp; + PictureBuffer *buffer; depth = DepthForFormat (attributes->format, &bpp); format = attributes->format; @@ -1000,7 +1049,7 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error) if (fd < 0) { *error = True; - return (RenderBuffer) (XID) None; + return (RenderBuffer) NULL; } /* Now, allocate the XIDs for the shm segment and pixmap. */ @@ -1021,8 +1070,12 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error) 0, &picture_attrs); XFreePixmap (compositor.display, pixmap); + /* Create the wrapper object. */ + buffer = XLCalloc (1, sizeof *buffer); + buffer->picture = picture; + /* Return the picture. */ - return (RenderBuffer) picture; + return (RenderBuffer) (void *) buffer; } static int @@ -1086,15 +1139,27 @@ ValidateShmParams (uint32_t format, uint32_t width, uint32_t height, static void 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 FreeDmabufBuffer (RenderBuffer buffer) { + PictureBuffer *picture_buffer; + + picture_buffer = buffer.pointer; + /* N.B. that the picture is the only reference to the pixmap here. */ - XRenderFreePicture (compositor.display, buffer.xid); + XRenderFreePicture (compositor.display, + picture_buffer->picture); + XLFree (picture_buffer); } static void diff --git a/positioner.c b/positioner.c index 36719ad..1f171da 100644 --- a/positioner.c +++ b/positioner.c @@ -60,6 +60,9 @@ struct _Positioner int refcount; }; +/* Scale factor used during constraint adjustment calculation. */ +static double scale_adjustment_factor; + static void 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); /* 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 + offset < cx @@ -598,7 +601,7 @@ TryFlipY (Positioner *positioner, int y, int height, int cy, int cheight, CalculatePosition (&new, NULL, &new_y); /* 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 + offset < cy @@ -670,8 +673,8 @@ GetAdjustmentOffset (Role *parent, int *off_x, int *off_y) &parent_gy, NULL, NULL); XLXdgRoleCurrentRootPosition (parent, &root_x, &root_y); - *off_x = root_x + parent_gx * global_scale_factor; - *off_y = root_y + parent_gy * global_scale_factor; + *off_x = root_x + parent_gx * parent->surface->factor; + *off_y = root_y + parent_gy * parent->surface->factor; } static void @@ -681,13 +684,17 @@ ApplyConstraintAdjustment (Positioner *positioner, Role *parent, int x, { int width, height, cx, cy, cwidth, cheight, off_x, off_y; - width = positioner->width * global_scale_factor; - height = positioner->height * global_scale_factor; + width = positioner->width * scale_adjustment_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 coordinates, and then unscale them later. */ - x *= global_scale_factor; - y *= global_scale_factor; + x *= scale_adjustment_factor; + y *= scale_adjustment_factor; if (positioner->constraint_adjustment == XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) @@ -733,10 +740,10 @@ ApplyConstraintAdjustment (Positioner *positioner, Role *parent, int x, off_y, &y, &height); finish: - *x_out = x / global_scale_factor; - *y_out = y / global_scale_factor; - *width_out = width / global_scale_factor; - *height_out = height / global_scale_factor; + *x_out = x / scale_adjustment_factor; + *y_out = y / scale_adjustment_factor; + *width_out = width / scale_adjustment_factor; + *height_out = height / scale_adjustment_factor; } void diff --git a/renderer.c b/renderer.c index 0a74a0e..3336944 100644 --- a/renderer.c +++ b/renderer.c @@ -129,24 +129,13 @@ RenderClearRectangle (RenderTarget target, int x, int y, int width, int height) render_funcs.clear_rectangle (target, x, y, width, height); } -void -RenderApplyTransform (RenderBuffer buffer, double divisor) -{ - render_funcs.apply_transform (buffer, divisor); -} - void 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, - width, height); -} - -void -RenderResetTransform (RenderBuffer buffer) -{ - render_funcs.reset_transform (buffer); + width, height, draw_params); } void @@ -251,12 +240,13 @@ RenderFreeDmabufBuffer (RenderBuffer buffer) } void -RenderUpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage) +RenderUpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage, + float scale) { if (!buffer_funcs.update_buffer_for_damage) return; - buffer_funcs.update_buffer_for_damage (buffer, damage); + buffer_funcs.update_buffer_for_damage (buffer, damage, scale); } Bool diff --git a/seat.c b/seat.c index 7696a30..111a5ef 100644 --- a/seat.c +++ b/seat.c @@ -779,9 +779,10 @@ UpdateCursorOutput (SeatCursor *cursor, int root_x, int root_y) { int hotspot_x, hotspot_y; - /* Scale the hotspot coordinates up by the scale. */ - hotspot_x = cursor->hotspot_x * global_scale_factor; - hotspot_y = cursor->hotspot_y * global_scale_factor; + /* Scale the hotspot coordinates up by the scale factor specified in + the surface. */ + 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 hotspot of the pointer. */ @@ -991,20 +992,18 @@ ComputeHotspot (SeatCursor *cursor, int min_x, int min_y, int dx, dy; int hotspot_x, hotspot_y; + if (!cursor->role.surface) + return; + /* Scale the hotspot coordinates up by the scale. */ - hotspot_x = cursor->hotspot_x * global_scale_factor; - 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; /* Apply the surface offsets to the hotspot as well. */ - dx = dy = 0; - - if (cursor->role.surface) - { - dx = (cursor->role.surface->current_state.x - * global_scale_factor); - dy = (cursor->role.surface->current_state.y - * global_scale_factor); - } + dx = (cursor->role.surface->current_state.x + * cursor->role.surface->factor); + dy = (cursor->role.surface->current_state.y + * cursor->role.surface->factor); *x = min_x + hotspot_x - dx; *y = min_y + hotspot_y - dy; @@ -2369,7 +2368,7 @@ HandleResizeComplete (Seat *seat) /* Forward declarations. */ 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, double, double); @@ -2421,8 +2420,8 @@ HandleRawButton (XIRawEvent *event) { /* Otherwise, the pointer is on a different screen! */ - TransformToView (seat->last_seen_surface->view, - win_x, win_y, &dispatch_x, &dispatch_y); + TransformToSurface (seat->last_seen_surface, + win_x, win_y, &dispatch_x, &dispatch_y); SendButton (seat, seat->last_seen_surface, event->time, button, WL_POINTER_BUTTON_STATE_RELEASED, dispatch_x, dispatch_y); @@ -3258,11 +3257,15 @@ EnteredSurface (Seat *seat, Surface *surface, Time time, } static void -TransformToView (View *view, double event_x, double event_y, - double *view_x_out, double *view_y_out) +TransformToSurface (Surface *surface, double event_x, double event_y, + double *view_x_out, double *view_y_out) { int int_x, int_y, x, 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 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 scale. */ - *view_x_out = view_x / global_scale_factor; - *view_y_out = view_y / global_scale_factor; + *view_x_out = view_x / surface->factor; + *view_y_out = view_y / surface->factor; } static Bool @@ -3411,9 +3414,7 @@ DispatchEntryExit (Subcompositor *subcompositor, XIEnterEvent *event) after_dispatch_set: - TransformToView (dispatch->view, event_x, - event_y, &x, &y); - + TransformToSurface (dispatch, event_x, event_y, &x, &y); 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. */ XLDoDragLeave (seat); - TransformToView (dispatch->view, event_x, event_y, - &x, &y); + TransformToSurface (dispatch, event_x, event_y, &x, &y); EnteredSurface (seat, dispatch, xev->time, x, y, False); 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 view. */ - TransformToView (seat->pointer_unlock_surface->view, - x, y, &x, &y); + TransformToSurface (seat->pointer_unlock_surface, + x, y, &x, &y); } } @@ -3925,8 +3925,8 @@ DispatchButton (Subcompositor *subcompositor, XIDeviceEvent *xev) after_dispatch_set: - TransformToView (dispatch->view, xev->event_x, - xev->event_y, &x, &y); + TransformToSurface (dispatch, xev->event_x, xev->event_y, + &x, &y); EnteredSurface (seat, dispatch, xev->time, x, y, False); @@ -4891,7 +4891,7 @@ ForceEntry (Seat *seat, Window source, double x, double y) /* Finally, translate the coordinates to the target view. */ - TransformToView (surface->view, x, y, &x, &y); + TransformToSurface (surface, x, y, &x, &y); } } else diff --git a/subcompositor.c b/subcompositor.c index f227145..d5cf26b 100644 --- a/subcompositor.c +++ b/subcompositor.c @@ -1582,30 +1582,26 @@ ViewSetScale (View *view, int scale) } static double -GetTxTy (int scale) +GetContentScale (int scale) { if (scale > 0) - return scale + 1; + return 1.0 / (scale + 1); - return 1.0 / (-scale + 1); + return -scale + 1; } 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 - transform on the attached buffer if that buffer is not attached to - any other view. */ - -static Bool -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; + if (view->scale) + { + /* There is a scale, so set it. */ + params->flags |= ScaleSet; + params->scale = GetContentScale (view->scale); + } } void @@ -1763,6 +1759,7 @@ SubcompositorUpdate (Subcompositor *subcompositor) RenderBuffer buffer; int min_x, min_y; int age; + DrawParams draw_params; /* Just return if no target was specified. */ if (!IsTargetAttached (subcompositor)) @@ -1946,7 +1943,8 @@ SubcompositorUpdate (Subcompositor *subcompositor) when the damage region is empty. */ 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)) { @@ -2115,11 +2113,12 @@ SubcompositorUpdate (Subcompositor *subcompositor) Note that if the subcompositor is not garbaged, then this has already been done. */ - RenderUpdateBufferForDamage (buffer, NULL); + RenderUpdateBufferForDamage (buffer, NULL, 0.0f); else if (age < 0 || age > 3) /* The target contents are too old, but the damage can be trusted. */ - RenderUpdateBufferForDamage (buffer, &view->damage); + RenderUpdateBufferForDamage (buffer, &view->damage, + GetContentScale (list->view->scale)); if (!first) { @@ -2174,8 +2173,8 @@ SubcompositorUpdate (Subcompositor *subcompositor) first = view; - if (ViewHaveTransform (view)) - ViewApplyTransform (view, buffer); + /* Compute the transform and put it in draw_params. */ + ViewComputeTransform (view, &draw_params); if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3)) { @@ -2206,8 +2205,8 @@ SubcompositorUpdate (Subcompositor *subcompositor) BoxStartY (temp_boxes) - min_y + ty, /* width. */ BoxWidth (temp_boxes), - /* height. */ - BoxHeight (temp_boxes)); + /* height, draw-params. */ + BoxHeight (temp_boxes), &draw_params); } } else @@ -2228,8 +2227,8 @@ SubcompositorUpdate (Subcompositor *subcompositor) view->abs_y - min_y + ty, /* width. */ ViewWidth (view), - /* height. */ - ViewHeight (view)); + /* height, draw-params. */ + ViewHeight (view), &draw_params); /* Also adjust the opaque and input regions here. */ @@ -2282,9 +2281,6 @@ SubcompositorUpdate (Subcompositor *subcompositor) } } - if (ViewHaveTransform (view)) - RenderResetTransform (buffer); - next_1: list = list->next; } @@ -2358,6 +2354,7 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event) Operation op; pixman_region32_t temp; RenderBuffer buffer; + DrawParams draw_params; /* Graphics exposures are not yet handled. */ if (event->type == GraphicsExpose) @@ -2438,11 +2435,12 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event) buffer = XLRenderBufferFromBuffer (view->buffer); boxes = pixman_region32_rectangles (&temp, &nboxes); - /* Update the attached buffer from any damage. */ - RenderUpdateBufferForDamage (buffer, &list->view->damage); + /* Compute the transform. */ + ViewComputeTransform (view, &draw_params); - if (ViewHaveTransform (view)) - ViewApplyTransform (view, buffer); + /* Update the attached buffer from any damage. */ + RenderUpdateBufferForDamage (buffer, &list->view->damage, + GetContentScale (list->view->scale)); for (i = 0; i < nboxes; ++i) RenderComposite (buffer, subcompositor->target, op, @@ -2455,11 +2453,9 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event) /* dst-y. */ BoxStartY (boxes[i]) - min_y + ty, /* width, height. */ - BoxWidth (boxes[i]), BoxHeight (boxes[i])); - - /* Undo transforms that were applied. */ - if (ViewHaveTransform (view)) - RenderResetTransform (buffer); + BoxWidth (boxes[i]), BoxHeight (boxes[i]), + /* draw-params. */ + &draw_params); /* Free the scratch region used to compute the intersection. */ pixman_region32_fini (&temp); diff --git a/subsurface.c b/subsurface.c index 1c4cebb..b0d236c 100644 --- a/subsurface.c +++ b/subsurface.c @@ -488,9 +488,13 @@ MaybeUpdateOutputs (Subsurface *subsurface) /* 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 * global_scale_factor; - y = subsurface->current_substate.y * global_scale_factor; + 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; @@ -541,12 +545,12 @@ AfterParentCommit (Surface *surface, void *data) subsurface->current_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. */ ViewMove (subsurface->role.surface->view, - subsurface->current_substate.x * global_scale_factor, - subsurface->current_substate.y * global_scale_factor); + subsurface->current_substate.x * subsurface->parent->factor, + subsurface->current_substate.y * subsurface->parent->factor); } /* And any cached surface state too. */ @@ -695,8 +699,15 @@ Rescale (Surface *surface, Role *role) position. */ ViewMove (surface->view, - subsurface->current_substate.x * global_scale_factor, - subsurface->current_substate.y * global_scale_factor); + 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 @@ -843,6 +854,7 @@ GetSubsurface (struct wl_client *client, struct wl_resource *resource, 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; @@ -937,9 +949,9 @@ XLUpdateOutputsForChildren (Surface *parent, int base_x, int base_y) child = item->data; subsurface = SubsurfaceFromRole (child->role); output_x = (subsurface->current_substate.x - * global_scale_factor); + * parent->factor); output_y = (subsurface->current_substate.y - * global_scale_factor); + * parent->factor); output_width = ViewWidth (child->view); output_height = ViewHeight (child->view); diff --git a/surface.c b/surface.c index e5d118a..1e066f7 100644 --- a/surface.c +++ b/surface.c @@ -509,11 +509,92 @@ static void ApplyScale (Surface *surface) { int scale, effective; + double b, g, e, d; + XLList *subsurface; + Role *role; scale = surface->current_state.buffer_scale; effective = GetEffectiveScale (scale); 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 @@ -530,7 +611,7 @@ ApplyOpaqueRegion (Surface *surface) { pixman_region32_init (&temp); XLScaleRegion (&temp, &surface->current_state.opaque, - global_scale_factor, global_scale_factor); + surface->factor, surface->factor); ViewSetOpaque (surface->view, &temp); pixman_region32_fini (&temp); } @@ -550,7 +631,7 @@ ApplyInputRegion (Surface *surface) { pixman_region32_init (&temp); XLScaleRegion (&temp, &surface->current_state.input, - global_scale_factor, global_scale_factor); + surface->factor, surface->factor); ViewSetInput (surface->view, &temp); pixman_region32_fini (&temp); } @@ -566,9 +647,9 @@ HandleScaleChanged (void *data, int new_scale) /* First, reapply various regions that depend on the surface scale. */ + ApplyScale (surface); ApplyInputRegion (surface); ApplyOpaqueRegion (surface); - ApplyScale (surface); /* Next, call any role-specific hooks. */ if (surface->role && surface->role->funcs.rescale) @@ -639,7 +720,7 @@ ApplySurfaceDamage (Surface *surface) { pixman_region32_init (&temp); XLScaleRegion (&temp, &surface->current_state.surface, - global_scale_factor, global_scale_factor); + surface->factor, surface->factor); ViewDamage (surface->view, &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) { pixman_region32_copy (&surface->current_state.input, @@ -802,12 +889,6 @@ InternalCommit (Surface *surface, State *pending) ApplyOpaqueRegion (surface); } - if (pending->pending & PendingBufferScale) - { - surface->current_state.buffer_scale = pending->buffer_scale; - ApplyScale (surface); - } - if (pending->pending & PendingAttachments) { surface->current_state.x = pending->x; @@ -1151,13 +1232,13 @@ XLCreateSurface (struct wl_client *client, InitState (&surface->current_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 view. */ ApplyInputRegion (surface); - /* Likewise for the scale. */ - ApplyScale (surface); - /* Initially, allow surfaces to accept any kind of role. */ surface->role_type = AnythingType; diff --git a/xdg_popup.c b/xdg_popup.c index e6be419..cccf7ff 100644 --- a/xdg_popup.c +++ b/xdg_popup.c @@ -278,6 +278,7 @@ MoveWindow (XdgPopup *popup) int root_x, root_y, parent_gx, parent_gy; int geometry_x, geometry_y, x, y; Window window; + double parent_scale, current_scale; /* No parent was specified. */ if (!popup->parent) @@ -286,6 +287,14 @@ MoveWindow (XdgPopup *popup) if (!popup->role || !popup->parent) 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); XLXdgRoleGetCurrentGeometry (popup->parent, &parent_gx, @@ -295,12 +304,18 @@ MoveWindow (XdgPopup *popup) XLXdgRoleCurrentRootPosition (popup->parent, &root_x, &root_y); - parent_gx *= global_scale_factor; - parent_gy *= global_scale_factor; - geometry_x *= global_scale_factor; - geometry_y *= global_scale_factor; - x = popup->x * global_scale_factor; - y = popup->y * global_scale_factor; + /* Parent geometry is relative to the parent coordinate system. */ + parent_gx *= parent_scale; + parent_gy *= parent_scale; + + /* geometry_x and geometry_y are relative to the local coordinate + 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, x + root_x + parent_gx - geometry_x, diff --git a/xdg_surface.c b/xdg_surface.c index 2d345d5..5571aa7 100644 --- a/xdg_surface.c +++ b/xdg_surface.c @@ -1167,8 +1167,8 @@ GetResizeDimensions (Surface *surface, Role *role, int *x_out, { XLXdgRoleGetCurrentGeometry (role, NULL, NULL, x_out, y_out); - *x_out *= global_scale_factor; - *y_out *= global_scale_factor; + *x_out *= surface->factor; + *y_out *= surface->factor; } static void @@ -1467,7 +1467,10 @@ XLXdgRoleCalcNewWindowSize (Role *role, int width, int height, 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_height = height; @@ -1480,8 +1483,8 @@ XLXdgRoleCalcNewWindowSize (Role *role, int width, int height, /* Adjust the current_width and current_height by the global scale factor. */ - current_width = (max_x - min_x + 1) / global_scale_factor; - current_height = (max_y - min_y + 1) / global_scale_factor; + current_width = (max_x - min_x + 1) / role->surface->factor; + current_height = (max_y - min_y + 1) / role->surface->factor; XLXdgRoleGetCurrentGeometry (role, NULL, NULL, &geometry_width, &geometry_height); diff --git a/xdg_toplevel.c b/xdg_toplevel.c index 07b37f2..9f2f75d 100644 --- a/xdg_toplevel.c +++ b/xdg_toplevel.c @@ -362,9 +362,14 @@ NoteConfigureTime (Timer *timer, void *data, struct timespec time) { XdgToplevel *toplevel; int width, height, effective_width, effective_height; + double factor; 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 (!(toplevel->state & StatePendingConfigureSize)) SendStates (toplevel); @@ -374,8 +379,8 @@ NoteConfigureTime (Timer *timer, void *data, struct timespec time) if (toplevel->state & StatePendingConfigureStates) WriteStates (toplevel); - effective_width = toplevel->configure_width / global_scale_factor; - effective_height = toplevel->configure_height / global_scale_factor; + effective_width = toplevel->configure_width / factor; + effective_height = toplevel->configure_height / factor; /* Compute the geometry for the configure event based on the current size of the toplevel. */ @@ -477,9 +482,14 @@ static void SendStates (XdgToplevel *toplevel) { int width, height; + double factor; 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 geometry. */ if (toplevel->state & StateMissingState) @@ -487,8 +497,8 @@ SendStates (XdgToplevel *toplevel) &width, &height); else XLXdgRoleCalcNewWindowSize (toplevel->role, - toplevel->width / global_scale_factor, - toplevel->height / global_scale_factor, + toplevel->width / factor, + toplevel->height / factor, &width, &height); SendConfigure (toplevel, width, height); @@ -505,6 +515,14 @@ RecordStateSize (XdgToplevel *toplevel) { Bool a, b; 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 changed. That way, we can send xdg_toplevel::configure with the @@ -521,8 +539,8 @@ RecordStateSize (XdgToplevel *toplevel) upon minimization. */ XLXdgRoleGetCurrentGeometry (toplevel->role, NULL, NULL, &width, &height); - width *= global_scale_factor; - height *= global_scale_factor; + width *= factor; + height *= factor; } else { @@ -778,10 +796,10 @@ HandleWindowGeometryChange (XdgToplevel *toplevel) XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y, &width, &height); - width *= global_scale_factor; - height *= global_scale_factor; - x *= global_scale_factor; - y *= global_scale_factor; + width *= toplevel->role->surface->factor; + height *= toplevel->role->surface->factor; + x *= toplevel->role->surface->factor; + y *= toplevel->role->surface->factor; dx = SubcompositorWidth (subcompositor) - width; dy = SubcompositorHeight (subcompositor) - height; @@ -795,25 +813,35 @@ HandleWindowGeometryChange (XdgToplevel *toplevel) /* Initially, specify PSize. After the first MapNotify, also specify PPosition so that subsurfaces won't move the window. */ - hints->min_width = toplevel->min_width * global_scale_factor + dx; - hints->min_height = toplevel->min_height * global_scale_factor + dy; + hints->min_width = (toplevel->min_width + * toplevel->role->surface->factor + + dx); + hints->min_height = (toplevel->min_height + * toplevel->role->surface->factor + + dy); if (toplevel->max_width) { - hints->max_width = toplevel->max_width * global_scale_factor + dx; - hints->max_height = toplevel->max_height * global_scale_factor + dy; + hints->max_width = (toplevel->max_width + * toplevel->role->surface->factor + + dx); + hints->max_height = (toplevel->max_height + * toplevel->role->surface->factor + + dy); hints->flags |= PMaxSize; } else hints->flags &= ~PMaxSize; - /* If a global scale factor is set, also set the resize increment to - the scale factor. */ + /* If a scale factor is set, also set the resize increment to the + scale factor. */ - if (global_scale_factor != 1) + if (toplevel->role->surface->factor != 1) { - hints->width_inc = global_scale_factor; - hints->height_inc = global_scale_factor; + /* Take the ceiling value, there is no good way of dealing with + 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; } else @@ -1345,10 +1373,10 @@ NoteWindowPreResize (Role *role, XdgRoleImplementation *impl, XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y, &gwidth, &gheight); - dx = width - gwidth * global_scale_factor; - dy = height - gheight * global_scale_factor; - x *= global_scale_factor; - y *= global_scale_factor; + dx = width - gwidth * toplevel->role->surface->factor; + dy = height - gheight * toplevel->role->surface->factor; + x *= toplevel->role->surface->factor; + y *= toplevel->role->surface->factor; ApplyGtkFrameExtents (toplevel, x, y, dx - x, dy - y); }