diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c index a9e5ea3d9..22266a988 100644 --- a/src/compositor/meta-surface-actor-wayland.c +++ b/src/compositor/meta-surface-actor-wayland.c @@ -36,6 +36,7 @@ #include "compositor/region-utils.h" #include "wayland/meta-wayland-buffer.h" #include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-subsurface.h" #include "wayland/meta-window-wayland.h" struct _MetaSurfaceActorWayland @@ -162,6 +163,106 @@ meta_surface_actor_wayland_is_view_primary (MetaSurfaceActor *actor, return current_primary_view == stage_view; } +static void +meta_surface_actor_wayland_apply_transform (ClutterActor *actor, + graphene_matrix_t *matrix) +{ + MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor); + ClutterActorClass *parent_class = + CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class); + MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface (self); + MetaWaylandSurface *root_surface; + MetaWindow *window; + MetaLogicalMonitor *logical_monitor; + ClutterActorBox *allocation; + float scale; + float actor_width, actor_height; + float adj_actor_width, adj_actor_height; + float adj_actor_x, adj_actor_y; + float width_scale, height_scale; + float x_off, y_off; + + if (!surface) + goto out; + + root_surface = surface; + while (root_surface->output_state.parent) + root_surface = root_surface->output_state.parent; + + window = meta_wayland_surface_get_window (root_surface); + if (!window) + goto out; + + if (!META_IS_WINDOW_WAYLAND (window)) + goto out; + + logical_monitor = meta_window_get_highest_scale_monitor (window); + if (!logical_monitor) + goto out; + + scale = meta_logical_monitor_get_scale (logical_monitor); + + g_object_get (actor, "allocation", &allocation, NULL); + + actor_width = clutter_actor_box_get_width (allocation); + actor_height = clutter_actor_box_get_height (allocation); + + if (actor_width == 0.0 || actor_height == 0.0) + goto out; + + /* We rely on MetaSurfaceActorContainerWayland to ensure that the toplevel + * surface on-display position is aligned to the physical pixel boundary. + */ + if (META_IS_WAYLAND_SUBSURFACE (surface->role)) + { + adj_actor_width = + roundf ((surface->sub.x + actor_width) * scale) / scale - + roundf (surface->sub.x * scale) / scale; + adj_actor_height = + roundf ((surface->sub.y + actor_height) * scale) / scale - + roundf (surface->sub.y * scale) / scale; + + adj_actor_x = adj_actor_y = 0.0; + + do + { + adj_actor_x += roundf (surface->sub.x * scale) / scale; + adj_actor_y += roundf (surface->sub.y * scale) / scale; + + surface = surface->output_state.parent; + } + while (surface); + } + else + { + adj_actor_width = roundf (actor_width * scale) / scale; + adj_actor_height = roundf (actor_height * scale) / scale; + adj_actor_x = allocation->x1; + adj_actor_y = allocation->y1; + } + + width_scale = adj_actor_width / actor_width; + height_scale = adj_actor_height / actor_height; + + if (!G_APPROX_VALUE (width_scale, 1.0, FLT_EPSILON) || + !G_APPROX_VALUE (height_scale, 1.0, FLT_EPSILON)) + graphene_matrix_scale (matrix, width_scale, height_scale, 1.0); + + parent_class->apply_transform (actor, matrix); + + x_off = adj_actor_x - allocation->x1; + y_off = adj_actor_y - allocation->y1; + + if (!G_APPROX_VALUE (x_off, 0.0, FLT_EPSILON) || + !G_APPROX_VALUE (y_off, 0.0, FLT_EPSILON)) + graphene_matrix_translate (matrix, &GRAPHENE_POINT3D_INIT (x_off, y_off, 0.0)); + + return; + +out: + parent_class->apply_transform (actor, matrix); +} + static void meta_surface_actor_wayland_dispose (GObject *object) { @@ -186,11 +287,14 @@ static void meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass) { MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage; surface_actor_class->is_opaque = meta_surface_actor_wayland_is_opaque; + actor_class->apply_transform = meta_surface_actor_wayland_apply_transform; + object_class->dispose = meta_surface_actor_wayland_dispose; } diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c index db1b21908..0bd285731 100644 --- a/src/wayland/meta-wayland-shell-surface.c +++ b/src/wayland/meta-wayland-shell-surface.c @@ -37,6 +37,7 @@ typedef struct _MetaWaylandShellSurfacePrivate MetaWindow *window; gulong unmanaging_handler_id; + gulong highest_scale_monitor_handler_id; } MetaWaylandShellSurfacePrivate; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWaylandShellSurface, @@ -106,6 +107,8 @@ clear_window (MetaWaylandShellSurface *shell_surface) g_clear_signal_handler (&priv->unmanaging_handler_id, priv->window); + g_clear_signal_handler (&priv->highest_scale_monitor_handler_id, + priv->window); priv->window = NULL; surface_actor = meta_wayland_surface_get_actor (surface); @@ -138,6 +141,12 @@ meta_wayland_shell_surface_set_window (MetaWaylandShellSurface *shell_surface, priv->window = window; + priv->highest_scale_monitor_handler_id = + g_signal_connect_swapped (window, "highest-scale-monitor-changed", + G_CALLBACK (meta_wayland_surface_notify_highest_scale_monitor), + surface); + meta_wayland_surface_notify_highest_scale_monitor (surface); + surface_actor = meta_wayland_surface_get_actor (surface); if (surface_actor) clutter_actor_set_reactive (CLUTTER_ACTOR (surface_actor), TRUE); diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c index a97971352..98cb6591c 100644 --- a/src/wayland/meta-wayland-subsurface.c +++ b/src/wayland/meta-wayland-subsurface.c @@ -90,6 +90,8 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface) clutter_actor_show (actor); else clutter_actor_hide (actor); + + clutter_actor_notify_transform_invalid (actor); } static gboolean @@ -555,6 +557,8 @@ wl_subcompositor_get_subsurface (struct wl_client *client, surface->sub.synchronous = TRUE; surface->protocol_state.parent = parent; + meta_wayland_surface_notify_highest_scale_monitor (surface); + reference = g_node_last_child (parent->protocol_state.subsurface_branch_node)->data; queue_subsurface_placement (surface, reference, diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 7e8a78d21..43ae4c617 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -2410,3 +2410,23 @@ meta_wayland_surface_is_xwayland (MetaWaylandSurface *surface) return FALSE; #endif } + +static void +output_state_handle_highest_scale_monitor (MetaWaylandSurface *surface) +{ + MetaWaylandSurface *subsurface_surface; + MetaSurfaceActor *actor = meta_wayland_surface_get_actor (surface); + + if (actor) + clutter_actor_notify_transform_invalid (CLUTTER_ACTOR (actor)); + + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state, + subsurface_surface) + output_state_handle_highest_scale_monitor (subsurface_surface); +} + +void +meta_wayland_surface_notify_highest_scale_monitor (MetaWaylandSurface *surface) +{ + output_state_handle_highest_scale_monitor (surface); +} diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 63f160894..71d623bde 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -414,6 +414,8 @@ struct wl_resource * meta_wayland_surface_get_resource (MetaWaylandSurface *surf MetaWaylandCompositor * meta_wayland_surface_get_compositor (MetaWaylandSurface *surface); +void meta_wayland_surface_notify_highest_scale_monitor (MetaWaylandSurface *surface); + static inline MetaWaylandSurfaceState * meta_wayland_surface_state_new (void) {