summaryrefslogtreecommitdiff
path: root/src/wayland/meta-window-wayland.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wayland/meta-window-wayland.c')
-rw-r--r--src/wayland/meta-window-wayland.c129
1 files changed, 124 insertions, 5 deletions
diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
index f19dd4c15..10a006d52 100644
--- a/src/wayland/meta-window-wayland.c
+++ b/src/wayland/meta-window-wayland.c
@@ -166,9 +166,20 @@ meta_window_wayland_move_resize_internal (MetaWindow *window,
{
MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);
gboolean can_move_now;
+ int configured_width;
+ int configured_height;
+ int monitor_scale;
g_assert (window->frame == NULL);
+ /* The scale the window is drawn in might change depending on what monitor it
+ * is mainly on. Scale the configured rectangle to be in logical pixel
+ * coordinate space so that we can have a scale independent size to pass
+ * to the Wayland surface. */
+ monitor_scale = meta_window_wayland_get_main_monitor_scale (window);
+ configured_width = constrained_rect.width / monitor_scale;
+ configured_height = constrained_rect.height / monitor_scale;
+
/* For wayland clients, the size is completely determined by the client,
* and while this allows to avoid some trickery with frames and the resulting
* lagging, we also need to insist a bit when the constraints would apply
@@ -223,8 +234,8 @@ meta_window_wayland_move_resize_internal (MetaWindow *window,
return;
meta_wayland_surface_configure_notify (window->surface,
- constrained_rect.width,
- constrained_rect.height,
+ configured_width,
+ configured_height,
&wl_window->pending_configure_serial);
/* We need to wait until the resize completes before we can move */
@@ -238,8 +249,8 @@ meta_window_wayland_move_resize_internal (MetaWindow *window,
}
}
- wl_window->last_sent_width = constrained_rect.width;
- wl_window->last_sent_height = constrained_rect.height;
+ wl_window->last_sent_width = configured_width;
+ wl_window->last_sent_height = configured_height;
if (can_move_now)
{
@@ -278,11 +289,100 @@ meta_window_wayland_move_resize_internal (MetaWindow *window,
}
static void
+scale_rect_size (MetaRectangle *rect, float scale)
+{
+ rect->width = (int)(rect->width * scale);
+ rect->height = (int)(rect->height * scale);
+}
+
+static void
+meta_window_wayland_update_main_monitor (MetaWindow *window)
+{
+ const MetaMonitorInfo *from;
+ const MetaMonitorInfo *to;
+ const MetaMonitorInfo *scaled_new;
+ float scale;
+ MetaRectangle rect;
+
+ /* Require both the current and the new monitor would be the new main monitor,
+ * even given the resulting scale the window would end up having. This is
+ * needed to avoid jumping back and forth between the new and the old, since
+ * changing main monitor may cause the window to be resized so that it no
+ * longer have that same new main monitor. */
+ from = window->monitor;
+ to = meta_screen_calculate_monitor_for_window (window->screen, window);
+
+ if (from == to)
+ return;
+
+ /* If we are setting the first output, unsetting the output, or the new has
+ * the same scale as the old no need to do any further checking. */
+ if (from == NULL || to == NULL || from->scale == to->scale)
+ {
+ window->monitor = to;
+ return;
+ }
+
+ /* To avoid a window alternating between two main monitors because scaling
+ * changes the main monitor, wait until both the current and the new scale
+ * will result in the same main monitor. */
+ scale = (float)to->scale / from->scale;
+ rect = window->rect;
+ scale_rect_size (&rect, scale);
+ scaled_new = meta_screen_get_monitor_for_rect (window->screen, &rect);
+ if (to != scaled_new)
+ return;
+
+ window->monitor = to;
+}
+
+static void
meta_window_wayland_main_monitor_changed (MetaWindow *window,
const MetaMonitorInfo *old)
{
- MetaWaylandSurface *surface = window->surface;
+ float scale_factor;
+ MetaWaylandSurface *surface;
+
+ /* This function makes sure that window geometry, window actor geometry and
+ * surface actor geometry gets set according the old and current main monitor
+ * scale. If there either is no past or current main monitor, or if the scale
+ * didn't change, there is nothing to do. */
+ if (old == NULL ||
+ window->monitor == NULL ||
+ old->scale == window->monitor->scale)
+ return;
+ /* MetaWindow keeps its rectangles in the physical pixel coordinate space.
+ * When the main monitor of a window changes, it can cause the corresponding
+ * window surfaces to be scaled given the monitor scale, so we need to scale
+ * the rectangles in MetaWindow accordingly. */
+
+ scale_factor = (float)window->monitor->scale / old->scale;
+
+ /* Window size. */
+ scale_rect_size (&window->rect, scale_factor);
+
+ /* Window geometry offset (XXX: Need a better place, see
+ * meta_window_wayland_move_resize). */
+ window->custom_frame_extents.left =
+ (int)(scale_factor * window->custom_frame_extents.left);
+ window->custom_frame_extents.top =
+ (int)(scale_factor * window->custom_frame_extents.top);
+
+ /* Buffer rect. */
+ scale_rect_size (&window->buffer_rect, scale_factor);
+ window->buffer_rect.x =
+ window->rect.x - window->custom_frame_extents.left;
+ window->buffer_rect.y =
+ window->rect.y - window->custom_frame_extents.top;
+
+ meta_compositor_sync_window_geometry (window->display->compositor,
+ window,
+ TRUE);
+
+ /* The surface actor needs to update the scale recursively for itself and all
+ * its subsurfaces */
+ surface = window->surface;
if (surface)
{
MetaSurfaceActorWayland *actor =
@@ -290,6 +390,8 @@ meta_window_wayland_main_monitor_changed (MetaWindow *window,
meta_surface_actor_wayland_sync_state_recursive (actor);
}
+
+ meta_window_emit_size_changed (window);
}
static void
@@ -330,6 +432,7 @@ meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
window_class->grab_op_began = meta_window_wayland_grab_op_began;
window_class->grab_op_ended = meta_window_wayland_grab_op_ended;
window_class->move_resize_internal = meta_window_wayland_move_resize_internal;
+ window_class->update_main_monitor = meta_window_wayland_update_main_monitor;
window_class->main_monitor_changed = meta_window_wayland_main_monitor_changed;
}
@@ -434,6 +537,22 @@ meta_window_wayland_move_resize (MetaWindow *window,
int gravity;
MetaRectangle rect;
MetaMoveResizeFlags flags;
+ int monitor_scale;
+
+ /* new_geom is in the logical pixel coordinate space, but MetaWindow wants its
+ * rects to represent what in turn will end up on the stage, i.e. we need to
+ * scale new_geom to physical pixels given what buffer scale and texture scale
+ * is in use. */
+ monitor_scale = meta_window_wayland_get_main_monitor_scale (window);
+ new_geom.x *= monitor_scale;
+ new_geom.y *= monitor_scale;
+ new_geom.width *= monitor_scale;
+ new_geom.height *= monitor_scale;
+
+ /* The (dx, dy) offset is also in logical pixel coordinate space and needs
+ * to be scaled in the same way as new_geom. */
+ dx *= monitor_scale;
+ dy *= monitor_scale;
/* XXX: Find a better place to store the window geometry offsets. */
window->custom_frame_extents.left = new_geom.x;