surface-actor/wayland: Implement stable size and position rounding
Implement the stable rounding algorithm as described in the discussions for the fractional-scale-v1 protocol. This adds an override of the ClutterActor::apply_transform vfunc for MetaSurfaceActorWayland that ensures the size and position of the contents of the surface are rounded according to the stable rounding algorithm. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2726>
This commit is contained in:
parent
ed90c78872
commit
e94b527777
5 changed files with 139 additions and 0 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue