This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch wl/browser-all
in repository enlightenment.
View the commit online.
commit 7907e997f489856c479ed715c98682b40abbba6d
Author: Cedric BAIL <[email protected]>
AuthorDate: Sat Aug 15 12:40:51 2026 -0600
e_comp_wl - honour wl_surface.set_buffer_transform
A client that has already rotated or mirrored the content it drew says so
with set_buffer_transform, and the compositor puts it back the right way up
by applying the inverse. E parsed the request and dropped it, so such a
surface came out both the wrong shape and the wrong way round.
The algebra is small. Writing R for a quarter turn and F for a mirror in the
vertical axis, transform k is R^k for the first four and R^k.F for the
flipped four - the protocol's "flip around a vertical axis followed by
rotation". The rotations invert the obvious way, 1 and 3 trading places; the
flipped four are each their own inverse, because F.R^m = R^-m.F makes
(R^k.F)^2 the identity. Which Evas orientation expresses each of those is not
something the enum names settle, so the table was fixed by measurement rather
than by reading: a 200x100 buffer painted as four coloured quadrants, shown
under all eight transforms, with the size and the four corners read back off
the screen. Non-square on purpose - a quarter turn has to come back as a
100x200 window, so one run checks the axis swap and the orientation together.
wlcs has no coverage of buffer transforms at all, so nothing else would have
caught a mapping that was merely plausible.
Two places had to move for it to work at all:
The turn is applied in e_comp_object_render, after evas_object_image_data_set
rather than in e_comp_object_dirty before it. E copies the client's pixels
into an image of its own through evas' stride, so turning the image first
makes that copy fill rows as though they were already the turned ones, which
interleaves them instead of rotating anything.
And it is refused outright on a client passing dmabuf. Such a buffer reaches
evas as a native surface, and evas' engine-side orientation call rebuilds the
image from an RGBA_Image that a native surface has not got. The GL draw path
could rotate texture coordinates instead, but skips doing so whenever the
surface is y-inverted - the usual dmabuf case - behind a long-standing FIXME.
Refusing it whole leaves a window the shape of the buffer showing the
buffer's own pixels; honouring only the size swap would leave a window of the
right shape showing content that was never turned, which is worse.
Damage and the opaque region are handled the same way for the same reason: a
rectangle in buffer coordinates names the wrong pixels once the buffer is
turned, so damage repaints the lot and the opaque region - an optimisation
only - is dropped. Nothing is drawn wrong either way.
Two more things E-17 left behind go with it.
A commit that changes the surface size without attaching a buffer now
resizes. Every resize in the commit path hung off new_attach, with a
viewport-shaped escape hatch bolted on beside it; but a viewport is not the
only thing that can change the size without a new buffer. A surface that has
moved to an output of a different scale is another, because the size is
worked out from that scale, and it showed up as a window that kept the old
output's size until the client happened to attach again. Rather than
enumerate the causes, compare the size this commit computed against the size
the last one computed. Comparing against ec->client instead would fight a
resize E drove itself: a maximise leaves ec->client already changed with the
client yet to catch up, and re-imposing the buffer's size there would undo
it.
And the offset carried by wl_surface.attach is scaled before it moves a drag
icon. It arrives in surface-local units while a drag is moved about the
canvas in screen pixels - the same difference the size on the very next line
has already had taken out of it.
Measured: wlcs 754 passed / 15 failed, failure set identical to the branch
point. All eight transforms correct on pixels, and the buffer-scale matrix
re-measured on a patterned buffer rather than a flat colour - a surface
painted one colour only tells you how big it came out, and "downscaled the
whole buffer" and "showed a corner of it at 1:1" are the same size.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FtoiXoSKUmZb6Aix6U3GZS
---
src/bin/e_comp_object.c | 44 +++++++++
src/bin/e_comp_object.h | 1 +
src/bin/e_comp_wl.c | 247 +++++++++++++++++++++++++++++++++++++++++-------
src/bin/e_comp_wl.h | 24 ++++-
4 files changed, 279 insertions(+), 37 deletions(-)
diff --git a/src/bin/e_comp_object.c b/src/bin/e_comp_object.c
index d4d7074da..4c680350c 100644
--- a/src/bin/e_comp_object.c
+++ b/src/bin/e_comp_object.c
@@ -80,6 +80,13 @@ typedef struct _E_Comp_Object
int x, y, w, h;
} content_crop;
+ /* How the buffer has to be turned to be the right way up on screen. A
+ * wl_surface that has told us it drew its content rotated or mirrored is
+ * the only thing that sets this; EVAS_IMAGE_ORIENT_NONE is everything
+ * else. Applied before the crop above, which is therefore in the
+ * coordinates of the turned buffer rather than the raw one. */
+ Evas_Image_Orient content_orient;
+
Eina_Stringshare *frame_theme;
Eina_Stringshare *frame_name;
Eina_Stringshare *visibility_effect; //effect when toggling visibility
@@ -4191,6 +4198,38 @@ _e_comp_object_content_crop_apply(E_Comp_Object *cw, Evas_Object *o)
cw->content_crop.w, cw->content_crop.h);
}
+/* Turn the buffer to the orientation asked for, for the same reason and on
+ * the same schedule as the crop above. evas ignores a repeat of the
+ * orientation already in force, so this costs nothing on the common path
+ * where nothing ever asked for one. */
+static void
+_e_comp_object_content_orient_apply(E_Comp_Object *cw, Evas_Object *o)
+{
+ /* Never on a native surface: evas turns an image by rebuilding it from the
+ * RGBA_Image behind it, and a native surface has none, so the engine would
+ * follow a NULL. The caller is expected to have decided not to ask for an
+ * orientation at all in that case - this is the backstop. */
+ if (cw->native) return;
+ evas_object_image_orient_set(o, cw->content_orient);
+}
+
+/* How to turn the buffer to put it on screen the right way up. */
+E_API void
+e_comp_object_content_orient_set(Evas_Object *obj, Evas_Image_Orient orient)
+{
+ Eina_List *l;
+ Evas_Object *o;
+
+ API_ENTRY;
+ if (cw->content_orient == orient) return;
+
+ cw->content_orient = orient;
+
+ _e_comp_object_content_orient_apply(cw, cw->obj);
+ EINA_LIST_FOREACH(cw->obj_mirror, l, o)
+ _e_comp_object_content_orient_apply(cw, o);
+}
+
/* The sub-rectangle of the buffer to show, in buffer pixels. A zero or
* negative extent goes back to showing all of it. */
E_API void
@@ -4429,6 +4468,11 @@ e_comp_object_render(Evas_Object *obj)
end:
eina_iterator_free(it);
evas_object_image_data_set(cw->obj, cw->blanked ? NULL : pix);
+ /* Only now, because the copy above writes through evas' own stride: an
+ * image that had already been turned would have been filled row by row as
+ * though the client's rows were the turned ones, which interleaves them
+ * rather than rotating anything. */
+ _e_comp_object_content_orient_apply(cw, cw->obj);
_e_comp_object_alpha_set(cw);
E_FREE_FUNC(cw->pending_updates, eina_tiler_free);
diff --git a/src/bin/e_comp_object.h b/src/bin/e_comp_object.h
index 9ce6510b6..14f2a8f49 100644
--- a/src/bin/e_comp_object.h
+++ b/src/bin/e_comp_object.h
@@ -90,6 +90,7 @@ E_API Evas_Object *e_comp_object_agent_add(Evas_Object *obj);
E_API void e_comp_object_blank(Evas_Object *obj, Eina_Bool set);
E_API void e_comp_object_dirty(Evas_Object *obj);
E_API void e_comp_object_content_crop_set(Evas_Object *obj, int x, int y, int w, int h);
+E_API void e_comp_object_content_orient_set(Evas_Object *obj, Evas_Image_Orient orient);
E_API Eina_Bool e_comp_object_render(Evas_Object *obj);
E_API Eina_Bool e_comp_object_effect_allowed_get(Evas_Object *obj);
E_API Eina_Bool e_comp_object_effect_set(Evas_Object *obj, const char *effect);
diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c
index 2d2b74eee..28e96a6ff 100644
--- a/src/bin/e_comp_wl.c
+++ b/src/bin/e_comp_wl.c
@@ -1534,6 +1534,109 @@ e_comp_wl_client_scale_get(const E_Client *ec)
return 1;
}
+/* wl_surface.set_buffer_scale and set_buffer_transform as last latched.
+ *
+ * Neither can be read back over the wire, so without these the only way to
+ * find out what a compositor did with them is to look at the screen. They
+ * exist for the test module, which is out of tree as far as the struct is
+ * concerned - E_Comp_Client_Data is opaque to a module. */
+E_API int
+e_comp_wl_client_buffer_scale_get(const E_Client *ec)
+{
+ if ((!ec) || (!ec->comp_data)) return 1;
+ return (ec->comp_data->buffer_scale > 0) ? ec->comp_data->buffer_scale : 1;
+}
+
+E_API int
+e_comp_wl_client_buffer_transform_get(const E_Client *ec)
+{
+ if ((!ec) || (!ec->comp_data)) return WL_OUTPUT_TRANSFORM_NORMAL;
+ return ec->comp_data->buffer_transform;
+}
+
+/* The buffer transform actually in force, which is not always the one that
+ * was asked for.
+ *
+ * Turning the buffer is done by evas, and for a client whose pixels E copies
+ * into an image of its own that is a rotation of the copy - which works, and
+ * is measured. A client passing dmabuf has no copy: its buffer reaches evas
+ * as a native surface wrapping a texture, and evas' engine-side orientation
+ * call is written for CPU images - it would rebuild the image from an
+ * RGBA_Image that a native surface does not have. The GL draw path can rotate
+ * texture coordinates instead, but declines to whenever the native surface is
+ * y-inverted, which is the usual case for dmabuf; the FIXME saying as much
+ * has been in evas_gl_context.c for years.
+ *
+ * So on that path the transform is refused whole rather than applied by
+ * halves. Refusing it leaves a window the shape of the buffer showing the
+ * buffer's own pixels; honouring only the size swap would leave a window of
+ * the right shape showing content that was never turned, which is worse.
+ */
+static int
+_e_comp_wl_buffer_transform_get(const E_Client *ec)
+{
+ if (ec->comp_data->buffer_transform == WL_OUTPUT_TRANSFORM_NORMAL)
+ return WL_OUTPUT_TRANSFORM_NORMAL;
+ if (!e_pixmap_is_pixels(ec->pixmap)) return WL_OUTPUT_TRANSFORM_NORMAL;
+ return ec->comp_data->buffer_transform;
+}
+
+/* Whether a buffer transform exchanges the two axes, which decides whether
+ * the surface is the buffer's size or the buffer's size turned on its side. */
+static Eina_Bool
+_e_comp_wl_transform_swaps_axes(int transform)
+{
+ switch (transform)
+ {
+ case WL_OUTPUT_TRANSFORM_90:
+ case WL_OUTPUT_TRANSFORM_270:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ return EINA_TRUE;
+ default:
+ return EINA_FALSE;
+ }
+}
+
+/* wl_surface.set_buffer_transform names the transform the client has ALREADY
+ * applied to the content it put in the buffer, so putting it back on screen
+ * the right way up means applying the inverse.
+ *
+ * Writing R for a quarter turn and F for a mirror about the vertical axis,
+ * transform k is R^k for k in 0..3 and R^k.F for the flipped four - the
+ * protocol's "flip around a vertical axis followed by rotation". The
+ * rotations invert the obvious way, 1 and 3 trading places and 2 being its
+ * own inverse. The flipped four are each their own inverse: F.R^m = R^-m.F,
+ * so (R^k.F)^2 is the identity for every k.
+ *
+ * Which Evas orientation expresses each of those is not something the enum
+ * names settle - EVAS_IMAGE_FLIP_TRANSPOSE is documented as the reflection
+ * in one diagonal and EVAS_IMAGE_FLIP_TRANSVERSE the other, but which
+ * diagonal each one means differs from the usual convention, and rotate-then-
+ * flip is a different orientation from flip-then-rotate. The table below was
+ * settled by displaying a buffer with four differently coloured quadrants
+ * under each of the eight transforms and reading the corners back off the
+ * screen; see the note in the commit that introduced it. */
+static Evas_Image_Orient
+_e_comp_wl_transform_to_orient(int transform)
+{
+ static const Evas_Image_Orient orients[8] =
+ {
+ [WL_OUTPUT_TRANSFORM_NORMAL] = EVAS_IMAGE_ORIENT_NONE,
+ [WL_OUTPUT_TRANSFORM_90] = EVAS_IMAGE_ORIENT_90,
+ [WL_OUTPUT_TRANSFORM_180] = EVAS_IMAGE_ORIENT_180,
+ [WL_OUTPUT_TRANSFORM_270] = EVAS_IMAGE_ORIENT_270,
+ [WL_OUTPUT_TRANSFORM_FLIPPED] = EVAS_IMAGE_FLIP_HORIZONTAL,
+ [WL_OUTPUT_TRANSFORM_FLIPPED_90] = EVAS_IMAGE_FLIP_TRANSPOSE,
+ [WL_OUTPUT_TRANSFORM_FLIPPED_180] = EVAS_IMAGE_FLIP_VERTICAL,
+ [WL_OUTPUT_TRANSFORM_FLIPPED_270] = EVAS_IMAGE_FLIP_TRANSVERSE,
+ };
+
+ if ((transform < 0) || (transform > WL_OUTPUT_TRANSFORM_FLIPPED_270))
+ return EVAS_IMAGE_ORIENT_NONE;
+ return orients[transform];
+}
+
/* wp_viewport's two commit-time errors.
*
* Neither can be answered when the request arrives. out_of_buffer needs the
@@ -1573,6 +1676,16 @@ _e_comp_wl_viewport_state_check(E_Client *ec, E_Comp_Wl_Surface_State *state)
else if (!e_pixmap_size_get(ec->pixmap, &bw, &bh)) return EINA_TRUE;
if ((bw < 1) || (bh < 1)) return EINA_TRUE;
+ /* A quarter-turn buffer transform is applied before the source rectangle
+ * is read, so it is the turned buffer the source has to fit inside. */
+ if (_e_comp_wl_transform_swaps_axes(state->buffer_transform))
+ {
+ int t = bw;
+
+ bw = bh;
+ bh = t;
+ }
+
/* Source coordinates are surface-local, so the buffer has to be brought
* into the same space before the two can be compared. */
if ((wl_fixed_to_double(v->src.x) + wl_fixed_to_double(v->src.w) >
@@ -1698,8 +1811,10 @@ _e_comp_wl_surface_state_size_update(E_Client *ec, E_Comp_Wl_Surface_State *stat
* buffer scale comes off first, and a viewport's source and destination
* are both expressed in what is left. */
scale = (ec->comp_data->buffer_scale > 0) ? ec->comp_data->buffer_scale : 1;
- state->bw = raw_w / scale;
- state->bh = raw_h / scale;
+ if (_e_comp_wl_transform_swaps_axes(_e_comp_wl_buffer_transform_get(ec)))
+ state->bw = raw_h / scale, state->bh = raw_w / scale;
+ else
+ state->bw = raw_w / scale, state->bh = raw_h / scale;
/* A viewport decides the surface size instead of the buffer. This is the
* one place that has to know, because bw/bh is what everything downstream
@@ -1742,6 +1857,13 @@ _e_comp_wl_surface_state_size_update(E_Client *ec, E_Comp_Wl_Surface_State *stat
else
ec->content_size.w = ec->content_size.h = 0;
+ /* Turning the buffer the right way up has to happen before the crop is
+ * worked out, because the source rectangle is given in coordinates that
+ * already have the transform applied - which is also why the crop below
+ * needs no transforming of its own. */
+ e_comp_object_content_orient_set(ec->frame,
+ _e_comp_wl_transform_to_orient(_e_comp_wl_buffer_transform_get(ec)));
+
/* The source rectangle is what the surface actually shows. Sizing the
* client above only decides how big the result is drawn - without this the
* whole buffer would be squeezed into it instead of the part the client
@@ -1798,6 +1920,7 @@ _e_comp_wl_surface_state_init(E_Comp_Wl_Surface_State *state)
_e_comp_wl_surface_state_cb_buffer_destroy;
state->sx = state->sy = 0;
state->buffer_scale = 1;
+ state->buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL;
state->input = NULL;
@@ -1897,9 +2020,10 @@ static void
_e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
{
Eina_Bool first = EINA_FALSE;
- Eina_Bool vp_latched = EINA_FALSE, vp_resize = EINA_FALSE;
+ Eina_Bool vp_resize = EINA_FALSE;
Eina_Rectangle *dmg;
int x = 0, y = 0, w, h;
+ int prev_bw, prev_bh;
first = !e_pixmap_usable_get(ec->pixmap);
#ifndef HAVE_WAYLAND_ONLY
@@ -1929,9 +2053,9 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
{
ec->comp_data->viewport = state->viewport;
state->viewport_changed = 0;
- vp_latched = EINA_TRUE;
}
ec->comp_data->buffer_scale = state->buffer_scale;
+ ec->comp_data->buffer_transform = state->buffer_transform;
if (ec->ignored && ec->comp_data->shell.surface)
{
@@ -2009,15 +2133,23 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
ec->comp_data->shell.set.unmaximize =
ec->comp_data->shell.set.minimize = 0;
}
+ prev_bw = ec->comp_data->last_bw, prev_bh = ec->comp_data->last_bh;
_e_comp_wl_surface_state_size_update(ec, state);
+ ec->comp_data->last_bw = state->bw, ec->comp_data->last_bh = state->bh;
- /* A viewport needs no buffer to change the surface size, and every resize
- * below hangs off new_attach - so a commit that only moves the viewport
- * would resize nothing at all. Give it its own reason to resize, without
- * dragging in the placement and focus work that goes with a new buffer. */
- vp_resize = vp_latched && (!state->new_attach) &&
+ /* Every resize below hangs off new_attach, so a commit that changes the
+ * surface's size without attaching a buffer would resize nothing at all.
+ * A wp_viewport is one way to do that; so is the surface having moved to
+ * an output of a different scale since the last commit, because the size
+ * is worked out from that scale. Rather than enumerate the causes, notice
+ * the effect: the size this commit computed differs from the one the last
+ * commit computed. Comparing against our own previous answer rather than
+ * against ec->client is what keeps this from fighting a resize E drove
+ * itself - a maximise leaves ec->client already changed and the client yet
+ * to catch up, and re-imposing the buffer's size there would undo it. */
+ vp_resize = (!state->new_attach) &&
e_pixmap_usable_get(ec->pixmap) &&
- ((state->bw != ec->client.w) || (state->bh != ec->client.h));
+ ((state->bw != prev_bw) || (state->bh != prev_bh));
if (state->new_attach)
{
@@ -2197,10 +2329,18 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
if (e_comp_wl->drag && e_comp_wl->drag_client &&
(e_comp_wl->drag_client == ec))
{
- e_comp_wl->drag->dx -= state->sx;
- e_comp_wl->drag->dy -= state->sy;
+ /* The offset came in with wl_surface.attach, so it is in
+ * surface-local units, while a drag is moved about the
+ * canvas in screen pixels - the same difference the size
+ * just below has already had taken out of it by
+ * _e_comp_wl_surface_state_size_update(). */
+ int dscale = e_comp_wl_client_scale_get(ec);
+ int dx = state->sx * dscale, dy = state->sy * dscale;
+
+ e_comp_wl->drag->dx -= dx;
+ e_comp_wl->drag->dy -= dy;
e_drag_move(e_comp_wl->drag,
- e_comp_wl->drag->x + state->sx, e_comp_wl->drag->y + state->sy);
+ e_comp_wl->drag->x + dx, e_comp_wl->drag->y + dy);
e_drag_resize(e_comp_wl->drag, state->bw, state->bh);
}
else
@@ -2242,25 +2382,55 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
/* put state damages into surface */
if ((!e_comp->nocomp) && (ec->frame))
{
- EINA_LIST_FREE(state->buffer_damages, dmg)
+ /* Damage is tracked against the raw buffer, and a buffer transform
+ * moves every pixel of it somewhere else, so a rectangle in either
+ * space names the wrong part of the other one. Rather than carry the
+ * transform through two more coordinate conversions for something no
+ * desktop client asks for, repaint the lot: damaging too much costs
+ * a frame's work, damaging too little leaves the screen wrong. */
+ if (_e_comp_wl_buffer_transform_get(ec) != WL_OUTPUT_TRANSFORM_NORMAL)
{
- e_comp_object_damage(ec->frame, dmg->x, dmg->y, dmg->w, dmg->h);
- eina_rectangle_free(dmg);
- }
- EINA_LIST_FREE(state->damages, dmg)
- {
- Eina_Rectangle r = *dmg;
+ int bw = 0, bh = 0;
- _e_comp_wl_surface_damage_to_buffer(ec, state, &r);
- e_comp_object_damage(ec->frame, r.x, r.y, r.w, r.h);
- eina_rectangle_free(dmg);
+ EINA_LIST_FREE(state->buffer_damages, dmg)
+ eina_rectangle_free(dmg);
+ EINA_LIST_FREE(state->damages, dmg)
+ eina_rectangle_free(dmg);
+ if (e_pixmap_size_get(ec->pixmap, &bw, &bh))
+ e_comp_object_damage(ec->frame, 0, 0, bw, bh);
+ }
+ else
+ {
+ EINA_LIST_FREE(state->buffer_damages, dmg)
+ {
+ e_comp_object_damage(ec->frame, dmg->x, dmg->y, dmg->w, dmg->h);
+ eina_rectangle_free(dmg);
+ }
+ EINA_LIST_FREE(state->damages, dmg)
+ {
+ Eina_Rectangle r = *dmg;
+
+ _e_comp_wl_surface_damage_to_buffer(ec, state, &r);
+ e_comp_object_damage(ec->frame, r.x, r.y, r.w, r.h);
+ eina_rectangle_free(dmg);
+ }
}
}
/* put state opaque into surface */
if (state->opaque)
{
- if (!eina_tiler_empty(state->opaque))
+ /* The opaque region is only an optimisation - it says where blending
+ * can be skipped - so a transform that would put it over the wrong
+ * part of the buffer is answered by declaring nothing opaque rather
+ * than by mapping it. Nothing is drawn wrong either way. */
+ if (_e_comp_wl_buffer_transform_get(ec) != WL_OUTPUT_TRANSFORM_NORMAL)
+ {
+ e_pixmap_image_opaque_set(ec->pixmap, 0, 0, 0, 0);
+ eina_tiler_free(state->opaque);
+ state->opaque = NULL;
+ }
+ else if (!eina_tiler_empty(state->opaque))
{
Eina_Rectangle *rect;
Eina_Iterator *itr;
@@ -2670,17 +2840,28 @@ _e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_res
}
static void
-_e_comp_wl_surface_cb_buffer_transform_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, int32_t transform EINA_UNUSED)
+_e_comp_wl_surface_cb_buffer_transform_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t transform)
{
- /* DBG("Surface Buffer Transform: %d", wl_resource_get_id(resource)); */
+ E_Client *ec;
+
+ if (!(ec = wl_resource_get_user_data(resource))) return;
+ if (e_object_is_del(E_OBJECT(ec))) return;
+
+ /* The enum has exactly eight values and the protocol makes anything else a
+ * fatal error, so range-check here rather than leaving a bad value to be
+ * discovered by whatever indexes a table with it later. */
+ if ((transform < WL_OUTPUT_TRANSFORM_NORMAL) ||
+ (transform > WL_OUTPUT_TRANSFORM_FLIPPED_270))
+ {
+ wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_TRANSFORM,
+ "buffer transform %d is not a valid "
+ "wl_output.transform value", transform);
+ return;
+ }
+
+ ec->comp_data->pending.buffer_transform = transform;
}
-/* We still do not scale rendering by the buffer scale - that is E-17, and
- * until it lands wl_output keeps claiming scale 1 so that no client asks for
- * a scaled buffer in the first place. What changed is that the value is now
- * remembered rather than dropped, because wp_viewport's source rectangle is
- * given in coordinates that already have the buffer scale applied, and a
- * crop cannot be turned back into buffer pixels without it. */
static void
_e_comp_wl_surface_cb_buffer_scale_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t scale)
{
@@ -3047,6 +3228,7 @@ _e_comp_wl_subsurface_commit_to_cache(E_Client *ec)
cdata->pending.viewport_changed = 0;
}
sdata->cached.buffer_scale = cdata->pending.buffer_scale;
+ sdata->cached.buffer_transform = cdata->pending.buffer_transform;
sdata->cached.has_data = EINA_TRUE;
}
@@ -3458,6 +3640,7 @@ _e_comp_wl_client_cb_new(void *data EINA_UNUSED, E_Client *ec)
wl_signal_init(&ec->comp_data->destroy_signal);
_e_comp_wl_surface_state_init(&ec->comp_data->pending);
ec->comp_data->buffer_scale = 1;
+ ec->comp_data->buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL;
/* set initial client properties */
ec->argb = EINA_TRUE;
diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h
index 08deb76ac..1b383bb8a 100644
--- a/src/bin/e_comp_wl.h
+++ b/src/bin/e_comp_wl.h
@@ -117,11 +117,12 @@ struct _E_Comp_Wl_Surface_State
Eina_List *damages, *buffer_damages, *frames;
Eina_Tiler *input, *opaque;
E_Comp_Wl_Viewport_State viewport;
- /* wl_surface.set_buffer_scale. Double buffered like everything else here,
- * and never below 1. We do not scale rendering by it - that is E-17 - but
- * a viewport's source rectangle is in coordinates that already have it
- * applied, so cropping cannot be worked out without knowing it. */
+ /* wl_surface.set_buffer_scale and set_buffer_transform. Double buffered
+ * like everything else here; the scale is never below 1 and the transform
+ * is always a valid WL_OUTPUT_TRANSFORM_* value, both being checked when
+ * the request arrives rather than here. */
int buffer_scale;
+ int buffer_transform;
Eina_Bool new_attach E_BITFIELD;
Eina_Bool has_data E_BITFIELD;
/* Whether viewport above is a request waiting for a commit, as opposed to
@@ -383,8 +384,19 @@ struct _E_Comp_Wl_Client_Data
* is latched from there on commit. */
struct wl_resource *viewport_resource;
E_Comp_Wl_Viewport_State viewport;
- /* wl_surface.set_buffer_scale currently in effect. Never below 1. */
+ /* wl_surface.set_buffer_scale and set_buffer_transform currently in
+ * effect. The scale is never below 1; the transform is the value the
+ * client says it has ALREADY applied, so displaying the buffer means
+ * applying the inverse. */
int buffer_scale;
+ int buffer_transform;
+
+ /* The surface size the previous commit worked out. Kept so that a commit
+ * which changes the size without attaching a buffer can be told from one
+ * that changes nothing - compared against the freshly computed size rather
+ * than against ec->client, which E moves about for its own reasons
+ * (maximise, fullscreen) while the client has yet to catch up. */
+ int last_bw, last_bh;
struct
{
@@ -507,6 +519,8 @@ E_API double e_comp_wl_idle_time_get(void);
E_API Eina_Bool e_comp_wl_output_init(const char *id, const char *make, const char *model, int x, int y, int w, int h, int pw, int ph, unsigned int refresh, unsigned int subpixel, unsigned int transform, unsigned int num);
E_API void e_comp_wl_output_remove(const char *id);
E_API int e_comp_wl_client_scale_get(const E_Client *ec);
+E_API int e_comp_wl_client_buffer_scale_get(const E_Client *ec);
+E_API int e_comp_wl_client_buffer_transform_get(const E_Client *ec);
EINTERN Eina_Bool e_comp_wl_key_down(Ecore_Event_Key *ev, E_Client *ec);
EINTERN Eina_Bool e_comp_wl_key_up(Ecore_Event_Key *ev, E_Client *ec);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.