wayland: Fix subsurface positioning on HiDPI

Keep the active position state in its original coordinate space, and
synchronize the surface actor with it when it changes and when
synchronizing the rest of the surface state, in case the surface scale
had changed.

https://bugzilla.gnome.org/show_bug.cgi?id=745655
This commit is contained in:
Jonas Ådahl 2015-03-05 11:11:09 +08:00
parent 117f57f74c
commit 3b993131e8
4 changed files with 64 additions and 17 deletions

View File

@ -102,6 +102,45 @@ meta_surface_actor_wayland_get_scale (MetaSurfaceActorWayland *actor)
return (double)output_scale / (double)priv->surface->scale;
}
static void
logical_to_actor_position (MetaSurfaceActorWayland *self,
int *x,
int *y)
{
MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface (self);
MetaWindow *toplevel_window;
int monitor_scale = 1;
toplevel_window = meta_wayland_surface_get_toplevel_window (surface);
if (toplevel_window)
monitor_scale = meta_window_wayland_get_main_monitor_scale (toplevel_window);
*x = *x * monitor_scale;
*y = *y * monitor_scale;
}
void
meta_surface_actor_wayland_sync_subsurface_state (MetaSurfaceActorWayland *self)
{
MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface (self);
MetaWindow *window;
int x = surface->offset_x + surface->sub.x;
int y = surface->offset_y + surface->sub.y;
window = meta_wayland_surface_get_toplevel_window (surface);
if (window && window->client_type == META_WINDOW_CLIENT_TYPE_X11)
{
/* Bail directly if this is part of a Xwayland window and warn
* if there happen to be offsets anyway since that is not supposed
* to happen. */
g_warn_if_fail (x == 0 && y == 0);
return;
}
logical_to_actor_position (self, &x, &y);
clutter_actor_set_position (CLUTTER_ACTOR (self), x, y);
}
void
meta_surface_actor_wayland_sync_state (MetaSurfaceActorWayland *self)
{
@ -148,22 +187,28 @@ meta_surface_actor_wayland_sync_state (MetaSurfaceActorWayland *self)
scaled_opaque_region);
cairo_region_destroy (scaled_opaque_region);
}
meta_surface_actor_wayland_sync_subsurface_state (self);
}
void
meta_surface_actor_wayland_sync_state_recursive (MetaSurfaceActorWayland *self)
{
MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface (self);
MetaWindow *window = meta_wayland_surface_get_toplevel_window (surface);
GList *iter;
meta_surface_actor_wayland_sync_state (self);
for (iter = surface->subsurfaces; iter != NULL; iter = iter->next)
if (window && window->client_type != META_WINDOW_CLIENT_TYPE_X11)
{
MetaWaylandSurface *subsurf = iter->data;
for (iter = surface->subsurfaces; iter != NULL; iter = iter->next)
{
MetaWaylandSurface *subsurf = iter->data;
meta_surface_actor_wayland_sync_state_recursive (
META_SURFACE_ACTOR_WAYLAND (subsurf->surface_actor));
meta_surface_actor_wayland_sync_state_recursive (
META_SURFACE_ACTOR_WAYLAND (subsurf->surface_actor));
}
}
}

View File

@ -70,6 +70,8 @@ void meta_surface_actor_wayland_sync_state (MetaSurfaceActorWayland *self);
void meta_surface_actor_wayland_sync_state_recursive (MetaSurfaceActorWayland *self);
void meta_surface_actor_wayland_sync_subsurface_state (MetaSurfaceActorWayland *self);
gboolean meta_surface_actor_wayland_is_on_monitor (MetaSurfaceActorWayland *self,
MetaMonitorInfo *monitor);

View File

@ -382,18 +382,13 @@ static void
subsurface_surface_commit (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
{
MetaSurfaceActor *surface_actor = surface->surface_actor;
float x, y;
MetaSurfaceActorWayland *surface_actor =
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
if (surface->buffer != NULL)
clutter_actor_show (CLUTTER_ACTOR (surface_actor));
else
clutter_actor_hide (CLUTTER_ACTOR (surface_actor));
clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y);
x += pending->dx;
y += pending->dy;
clutter_actor_set_position (CLUTTER_ACTOR (surface_actor), x, y);
}
/* A non-subsurface is always desynchronized.
@ -427,9 +422,8 @@ parent_surface_state_applied (gpointer data, gpointer user_data)
if (surface->sub.pending_pos)
{
clutter_actor_set_position (CLUTTER_ACTOR (surface->surface_actor),
surface->sub.pending_x,
surface->sub.pending_y);
surface->sub.x = surface->sub.pending_x;
surface->sub.y = surface->sub.pending_y;
surface->sub.pending_pos = FALSE;
}
@ -477,6 +471,9 @@ parent_surface_state_applied (gpointer data, gpointer user_data)
if (is_surface_effectively_synchronized (surface))
apply_pending_state (surface, &surface->sub.pending);
meta_surface_actor_wayland_sync_subsurface_state (
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
}
static void
@ -522,9 +519,6 @@ apply_pending_state (MetaWaylandSurface *surface,
surface->input_region = cairo_region_reference (pending->input_region);
}
meta_surface_actor_wayland_sync_state (
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
/* wl_surface.frame */
wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list);
wl_list_init (&pending->frame_callback_list);
@ -549,6 +543,9 @@ apply_pending_state (MetaWaylandSurface *surface,
break;
}
meta_surface_actor_wayland_sync_state (
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
pending_state_reset (pending);
g_list_foreach (surface->subsurfaces, parent_surface_state_applied, NULL);

View File

@ -136,6 +136,9 @@ struct _MetaWaylandSurface
MetaWaylandSurface *parent;
struct wl_listener parent_destroy_listener;
int x;
int y;
/* When the surface is synchronous, its state will be applied
* when the parent is committed. This is done by moving the
* "real" pending state below to here when this surface is