summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Ådahl <jadahl@gmail.com>2015-03-23 21:22:19 +0800
committerJonas Ådahl <jadahl@gmail.com>2015-07-16 11:54:14 +0800
commitf6c9261bf669bc1f3f0f8e957843bdeff025daad (patch)
treefd0c5a61b20493b376e455ab8b688fae3a098b16
parent14b0a83f64134fd6669d580558e10b4a225cb1d6 (diff)
downloadmutter-f6c9261bf669bc1f3f0f8e957843bdeff025daad.tar.gz
wayland: Scale window geometry rects given the main output
Since we scale surface actors given what main output their toplevel window is on, also scale the window geometry coordinates and sizes (window->rect size and window->custom_frame_extents.top/left) in order to make the window geometry represent what is being rendered on the stage. https://bugzilla.gnome.org/show_bug.cgi?id=744934
-rw-r--r--src/core/window-private.h3
-rw-r--r--src/core/window.c9
-rw-r--r--src/wayland/meta-wayland-surface.c6
-rw-r--r--src/wayland/meta-window-wayland.c129
-rw-r--r--src/x11/window-x11.c8
5 files changed, 142 insertions, 13 deletions
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 2a96cc83a..be390ae1d 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -482,6 +482,7 @@ struct _MetaWindowClass
gboolean (*update_icon) (MetaWindow *window,
cairo_surface_t **icon,
cairo_surface_t **mini_icon);
+ void (*update_main_monitor) (MetaWindow *window);
void (*main_monitor_changed) (MetaWindow *window,
const MetaMonitorInfo *old);
};
@@ -695,4 +696,6 @@ void meta_window_set_alive (MetaWindow *window, gboolean is_alive);
gboolean meta_window_has_pointer (MetaWindow *window);
+void meta_window_emit_size_changed (MetaWindow *window);
+
#endif
diff --git a/src/core/window.c b/src/core/window.c
index 6b5836783..71777aad6 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -3547,8 +3547,7 @@ meta_window_update_monitor (MetaWindow *window,
const MetaMonitorInfo *old;
old = window->monitor;
- window->monitor = meta_screen_calculate_monitor_for_window (window->screen,
- window);
+ META_WINDOW_GET_CLASS (window)->update_main_monitor (window);
if (old != window->monitor)
{
meta_window_on_all_workspaces_changed (window);
@@ -7855,3 +7854,9 @@ meta_window_grab_op_ended (MetaWindow *window,
{
META_WINDOW_GET_CLASS (window)->grab_op_ended (window, op);
}
+
+void
+meta_window_emit_size_changed (MetaWindow *window)
+{
+ g_signal_emit (window, window_signals[SIZE_CHANGED], 0);
+}
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index fe0daffba..accec6a94 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -2137,12 +2137,6 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
wl_array_init (&states);
fill_states (&states, surface->window);
- /* new_width and new_height comes from window->rect, which is based on
- * the buffer size, not the surface size. The configure event requires
- * surface size. */
- new_width /= surface->scale;
- new_height /= surface->scale;
-
xdg_surface_send_configure (surface->xdg_surface, new_width, new_height, &states, serial);
wl_array_release (&states);
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;
diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
index bac473d8b..c883c6f46 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -1472,6 +1472,13 @@ meta_window_x11_update_icon (MetaWindow *window,
}
static void
+meta_window_x11_update_main_monitor (MetaWindow *window)
+{
+ window->monitor = meta_screen_calculate_monitor_for_window (window->screen,
+ window);
+}
+
+static void
meta_window_x11_main_monitor_changed (MetaWindow *window,
const MetaMonitorInfo *old)
{
@@ -1495,6 +1502,7 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
window_class->update_struts = meta_window_x11_update_struts;
window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints;
window_class->update_icon = meta_window_x11_update_icon;
+ window_class->update_main_monitor = meta_window_x11_update_main_monitor;
window_class->main_monitor_changed = meta_window_x11_main_monitor_changed;
}