[mutter] Add support for scaled logical monitor framebuffers



commit 8163ca68212ea17f40132eaac812a7b972d7fc47
Author: Jonas Ådahl <jadahl gmail com>
Date:   Fri Feb 24 18:10:52 2017 +0800

    Add support for scaled logical monitor framebuffers
    
    This commit adds support for rendering onto enlarged per logical
    monitor framebuffers, using the scaled clutter stage views, for HiDPI
    enabled logical monitors.
    
    This works by scaling the mode of the monitors in a logical monitors by
    the scale, no longer relying on scaling the window actors and window
    geometry for making windows have the correct size on HiDPI monitors.
    
    It is disabled by default, as in automatically created configurations
    will still use the old mode. This is partly because Xwayland clients
    will not yet work good enough to make it feasible.
    
    To enable, add the 'scale-monitor-framebuffer' keyword to the
    org.gnome.mutter.experimental-features gsettings array.
    
    It is still possible to specify the mode via the new D-Bus API, which
    has been adapted.
    
    The adaptations to the D-Bus API means the caller need to be aware of
    how to position logical monitors on the stage grid. This depends on the
    'layout-mode' property that is used (see the DisplayConfig D-Bus
    documentation).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=777732

 data/org.gnome.mutter.gschema.xml.in              |    9 +-
 src/backends/meta-backend-private.h               |    3 +
 src/backends/meta-backend.c                       |   21 +++-
 src/backends/meta-logical-monitor.c               |    2 +-
 src/backends/meta-logical-monitor.h               |    6 +-
 src/backends/meta-monitor-config-manager.c        |   83 +++++++---
 src/backends/meta-monitor-config-manager.h        |   10 +-
 src/backends/meta-monitor-config-store.c          |   64 ++++++--
 src/backends/meta-monitor-config-store.h          |    2 +
 src/backends/meta-monitor-manager-dummy.c         |   35 ++++-
 src/backends/meta-monitor-manager-private.h       |   17 ++-
 src/backends/meta-monitor-manager.c               |  117 ++++++++++++--
 src/backends/native/meta-cursor-renderer-native.c |  182 +++++++++++++++++---
 src/backends/native/meta-monitor-manager-kms.c    |   20 +++
 src/backends/native/meta-renderer-native.c        |   19 ++-
 src/backends/x11/meta-monitor-manager-xrandr.c    |   11 ++
 src/backends/x11/meta-renderer-x11.c              |   13 +-
 src/compositor/meta-surface-actor-wayland.c       |   10 +-
 src/core/screen.c                                 |   73 ++++++++-
 src/org.gnome.Mutter.DisplayConfig.xml            |   31 ++++
 src/tests/meta-monitor-manager-test.c             |   33 ++++-
 src/tests/monitor-store-unit-tests.c              |    4 +-
 src/tests/monitor-unit-tests.c                    |   24 ++-
 src/tests/unit-tests.c                            |    7 +
 src/wayland/meta-wayland-surface-role-cursor.c    |    6 +-
 src/wayland/meta-window-wayland.c                 |   41 ++++-
 26 files changed, 723 insertions(+), 120 deletions(-)
---
diff --git a/data/org.gnome.mutter.gschema.xml.in b/data/org.gnome.mutter.gschema.xml.in
index 56f16cb..0f2cd4d 100644
--- a/data/org.gnome.mutter.gschema.xml.in
+++ b/data/org.gnome.mutter.gschema.xml.in
@@ -112,7 +112,14 @@
         available, or configurable. Don't expect adding anything in this
         setting to be future proof.
 
-        Currently possible keywords: (none)
+        Currently possible keywords:
+
+        * "scale-monitor-framebuffer" - makes mutter default to layout logical
+                                        monitors in a logical pixel coordinate
+                                        space, while scaling monitor
+                                        framebuffers instead of window content,
+                                        to manage HiDPI monitors. Does not
+                                        require a restart.
       </description>
     </key>
 
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index c8d618e..9c1f2a0 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -100,6 +100,7 @@ struct _MetaBackendClass
 typedef enum _MetaExperimentalFeature
 {
   META_EXPERIMENTAL_FEATURE_NONE = 0,
+  META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER = (1 << 0)
 } MetaExperimentalFeature;
 
 void meta_init_backend (GType backend_gtype);
@@ -161,6 +162,8 @@ void meta_backend_enable_experimental_feature (MetaBackend            *backend,
 
 gboolean meta_is_stage_views_enabled (void);
 
+gboolean meta_is_stage_views_scaled (void);
+
 MetaInputSettings *meta_backend_get_input_settings (MetaBackend *backend);
 
 #endif /* META_BACKEND_PRIVATE_H */
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 0360e32..822ddc0 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -428,7 +428,10 @@ experimental_features_handler (GVariant *features_variant,
   while (g_variant_iter_loop (&features_iter, "s", &feature))
     {
       /* So far no experimental features defined. */
-      g_info ("Unknown experimental feature '%s'\n", feature);
+      if (g_str_equal (feature, "scale-monitor-framebuffer"))
+        features |= META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER;
+      else
+        g_info ("Unknown experimental feature '%s'\n", feature);
     }
 
   if (features != priv->experimental_features)
@@ -968,6 +971,22 @@ meta_is_stage_views_enabled (void)
   return !g_str_equal (mutter_stage_views, "0");
 }
 
+gboolean
+meta_is_stage_views_scaled (void)
+{
+  MetaBackend *backend = meta_get_backend ();
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaLogicalMonitorLayoutMode layout_mode;
+
+  if (!meta_is_stage_views_enabled ())
+    return FALSE;
+
+  layout_mode = monitor_manager->layout_mode;
+
+  return layout_mode == META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
+}
+
 MetaInputSettings *
 meta_backend_get_input_settings (MetaBackend *backend)
 {
diff --git a/src/backends/meta-logical-monitor.c b/src/backends/meta-logical-monitor.c
index d69f5c4..f1e2a0f 100644
--- a/src/backends/meta-logical-monitor.c
+++ b/src/backends/meta-logical-monitor.c
@@ -78,7 +78,7 @@ meta_logical_monitor_new (MetaMonitorManager       *monitor_manager,
 
   logical_monitor->number = monitor_number;
   logical_monitor->winsys_id = main_output->winsys_id;
-  logical_monitor->scale = logical_monitor_config->scale,
+  logical_monitor->scale = logical_monitor_config->scale;
   logical_monitor->in_fullscreen = -1;
   logical_monitor->rect = logical_monitor_config->layout;
 
diff --git a/src/backends/meta-logical-monitor.h b/src/backends/meta-logical-monitor.h
index de1af1b..f9f99cf 100644
--- a/src/backends/meta-logical-monitor.h
+++ b/src/backends/meta-logical-monitor.h
@@ -60,9 +60,9 @@ G_DECLARE_FINAL_TYPE (MetaLogicalMonitor, meta_logical_monitor,
                       META, LOGICAL_MONITOR,
                       GObject)
 
-MetaLogicalMonitor * meta_logical_monitor_new (MetaMonitorManager          *monitor_manager,
-                                               MetaLogicalMonitorConfig    *logical_monitor_config,
-                                               int                          monitor_number);
+MetaLogicalMonitor * meta_logical_monitor_new (MetaMonitorManager       *monitor_manager,
+                                               MetaLogicalMonitorConfig *logical_monitor_config,
+                                               int                       monitor_number);
 
 MetaLogicalMonitor * meta_logical_monitor_new_derived (MetaMonitorManager *monitor_manager,
                                                        MetaMonitor        *monitor,
diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
index d64c700..7165296 100644
--- a/src/backends/meta-monitor-config-manager.c
+++ b/src/backends/meta-monitor-config-manager.c
@@ -51,8 +51,8 @@ meta_monitor_config_manager_new (MetaMonitorManager *monitor_manager)
 
   config_manager = g_object_new (META_TYPE_MONITOR_CONFIG_MANAGER, NULL);
   config_manager->monitor_manager = monitor_manager;
-  config_manager->config_store = g_object_new (META_TYPE_MONITOR_CONFIG_STORE,
-                                               NULL);
+  config_manager->config_store =
+    meta_monitor_config_store_new (monitor_manager);
 
   return config_manager;
 }
@@ -461,10 +461,11 @@ create_monitor_config (MetaMonitor     *monitor,
 }
 
 static MetaLogicalMonitorConfig *
-create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager,
-                                         MetaMonitor        *monitor,
-                                         int                 x,
-                                         int                 y)
+create_preferred_logical_monitor_config (MetaMonitorManager          *monitor_manager,
+                                         MetaMonitor                 *monitor,
+                                         int                          x,
+                                         int                          y,
+                                         MetaLogicalMonitorLayoutMode layout_mode)
 {
   MetaMonitorMode *mode;
   int width, height;
@@ -478,6 +479,16 @@ create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager,
                                                              monitor,
                                                              mode);
 
+  switch (layout_mode)
+    {
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
+      width /= scale;
+      height /= scale;
+      break;
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
+      break;
+    }
+
   monitor_config = create_monitor_config (monitor, mode);
 
   logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
@@ -501,6 +512,7 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana
   MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
   GList *logical_monitor_configs;
   MetaMonitor *primary_monitor;
+  MetaLogicalMonitorLayoutMode layout_mode;
   MetaLogicalMonitorConfig *primary_logical_monitor_config;
   int x;
   GList *monitors;
@@ -510,10 +522,13 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana
   if (!primary_monitor)
     return NULL;
 
+  layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
+
   primary_logical_monitor_config =
     create_preferred_logical_monitor_config (monitor_manager,
                                              primary_monitor,
-                                             0, 0);
+                                             0, 0,
+                                             layout_mode);
   primary_logical_monitor_config->is_primary = TRUE;
   logical_monitor_configs = g_list_append (NULL,
                                            primary_logical_monitor_config);
@@ -535,14 +550,15 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana
       logical_monitor_config =
         create_preferred_logical_monitor_config (monitor_manager,
                                                  monitor,
-                                                 x, 0);
+                                                 x, 0,
+                                                 layout_mode);
       logical_monitor_configs = g_list_append (logical_monitor_configs,
                                                logical_monitor_config);
 
       x += logical_monitor_config->layout.width;
     }
 
-  return meta_monitors_config_new (logical_monitor_configs);
+  return meta_monitors_config_new (logical_monitor_configs, layout_mode);
 }
 
 MetaMonitorsConfig *
@@ -551,21 +567,25 @@ meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_ma
   MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
   MetaMonitor *primary_monitor;
   GList *logical_monitor_configs;
+  MetaLogicalMonitorLayoutMode layout_mode;
   MetaLogicalMonitorConfig *primary_logical_monitor_config;
 
   primary_monitor = find_primary_monitor (monitor_manager);
   if (!primary_monitor)
     return NULL;
 
+  layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
+
   primary_logical_monitor_config =
     create_preferred_logical_monitor_config (monitor_manager,
                                              primary_monitor,
-                                             0, 0);
+                                             0, 0,
+                                             layout_mode);
   primary_logical_monitor_config->is_primary = TRUE;
   logical_monitor_configs = g_list_append (NULL,
                                            primary_logical_monitor_config);
 
-  return meta_monitors_config_new (logical_monitor_configs);
+  return meta_monitors_config_new (logical_monitor_configs, layout_mode);
 }
 
 MetaMonitorsConfig *
@@ -574,6 +594,7 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
   MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
   MetaLogicalMonitorConfig *primary_logical_monitor_config = NULL;
   MetaMonitor *primary_monitor;
+  MetaLogicalMonitorLayoutMode layout_mode;
   GList *logical_monitor_configs;
   GList *region;
   GList *monitors;
@@ -583,6 +604,8 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
   if (!primary_monitor)
     return NULL;
 
+  layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
+
   logical_monitor_configs = NULL;
   region = NULL;
   monitors = meta_monitor_manager_get_monitors (monitor_manager);
@@ -598,7 +621,8 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
       logical_monitor_config =
         create_preferred_logical_monitor_config (monitor_manager,
                                                  monitor,
-                                                 x, y);
+                                                 x, y,
+                                                 layout_mode);
       logical_monitor_configs = g_list_append (logical_monitor_configs,
                                                logical_monitor_config);
 
@@ -629,7 +653,7 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
 
   primary_logical_monitor_config->is_primary = TRUE;
 
-  return meta_monitors_config_new (logical_monitor_configs);
+  return meta_monitors_config_new (logical_monitor_configs, layout_mode);
 }
 
 void
@@ -774,13 +798,15 @@ meta_monitors_config_key_equal (gconstpointer data_a,
 }
 
 MetaMonitorsConfig *
-meta_monitors_config_new (GList *logical_monitor_configs)
+meta_monitors_config_new (GList                       *logical_monitor_configs,
+                          MetaLogicalMonitorLayoutMode layout_mode)
 {
   MetaMonitorsConfig *config;
 
   config = g_object_new (META_TYPE_MONITORS_CONFIG, NULL);
   config->logical_monitor_configs = logical_monitor_configs;
   config->key = meta_monitors_config_key_new (logical_monitor_configs);
+  config->layout_mode = layout_mode;
 
   return config;
 }
@@ -862,12 +888,13 @@ meta_verify_monitor_config (MetaMonitorConfig *monitor_config,
 }
 
 gboolean
-meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config,
-                                    GError                  **error)
+meta_verify_logical_monitor_config (MetaLogicalMonitorConfig    *logical_monitor_config,
+                                    MetaLogicalMonitorLayoutMode layout_mode,
+                                    GError                     **error)
 {
   GList *l;
-  int layout_width;
-  int layout_height;
+  int expected_mode_width = 0;
+  int expected_mode_height = 0;
 
   if (logical_monitor_config->scale < 1)
     {
@@ -894,14 +921,26 @@ meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_co
       return FALSE;
     }
 
-  layout_width = logical_monitor_config->layout.width;
-  layout_height = logical_monitor_config->layout.height;
+  switch (layout_mode)
+    {
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
+      expected_mode_width = (logical_monitor_config->layout.width *
+                             logical_monitor_config->scale);
+      expected_mode_height = (logical_monitor_config->layout.height *
+                              logical_monitor_config->scale);
+      break;
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
+      expected_mode_width = logical_monitor_config->layout.width;
+      expected_mode_height = logical_monitor_config->layout.height;
+      break;
+    }
+
   for (l = logical_monitor_config->monitor_configs; l; l = l->next)
     {
       MetaMonitorConfig *monitor_config = l->data;
 
-      if (monitor_config->mode_spec->width != layout_width ||
-          monitor_config->mode_spec->height != layout_height)
+      if (monitor_config->mode_spec->width != expected_mode_width ||
+          monitor_config->mode_spec->height != expected_mode_height)
         {
           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                        "Monitor modes in logical monitor conflict");
diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
index baa119e..de79114 100644
--- a/src/backends/meta-monitor-config-manager.h
+++ b/src/backends/meta-monitor-config-manager.h
@@ -56,6 +56,8 @@ struct _MetaMonitorsConfig
 
   MetaMonitorsConfigKey *key;
   GList *logical_monitor_configs;
+
+  MetaLogicalMonitorLayoutMode layout_mode;
 };
 
 #define META_TYPE_MONITORS_CONFIG (meta_monitors_config_get_type ())
@@ -85,7 +87,8 @@ void meta_monitor_config_manager_set_current (MetaMonitorConfigManager *config_m
 
 MetaMonitorsConfig * meta_monitor_config_manager_get_current (MetaMonitorConfigManager *config_manager);
 
-MetaMonitorsConfig * meta_monitors_config_new (GList *logical_monitor_configs);
+MetaMonitorsConfig * meta_monitors_config_new (GList                       *logical_monitor_configs,
+                                               MetaLogicalMonitorLayoutMode layout_mode);
 
 unsigned int meta_monitors_config_key_hash (gconstpointer config_key);
 
@@ -107,8 +110,9 @@ gboolean meta_verify_monitor_spec (MetaMonitorSpec *monitor_spec,
 gboolean meta_verify_monitor_config (MetaMonitorConfig *monitor_config,
                                      GError           **error);
 
-gboolean meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config,
-                                             GError                  **error);
+gboolean meta_verify_logical_monitor_config (MetaLogicalMonitorConfig    *logical_monitor_config,
+                                             MetaLogicalMonitorLayoutMode layout_mode,
+                                             GError                     **error);
 
 gboolean meta_verify_monitors_config (MetaMonitorsConfig *config,
                                       GError            **error);
diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
index 44bdce7..9b02bc0 100644
--- a/src/backends/meta-monitor-config-store.c
+++ b/src/backends/meta-monitor-config-store.c
@@ -81,6 +81,8 @@ struct _MetaMonitorConfigStore
 {
   GObject parent;
 
+  MetaMonitorManager *monitor_manager;
+
   GHashTable *configs;
 };
 
@@ -355,11 +357,13 @@ handle_start_element (GMarkupParseContext  *context,
 }
 
 static gboolean
-derive_logical_monitor_layout (MetaLogicalMonitorConfig *logical_monitor_config,
-                               GError                  **error)
+derive_logical_monitor_layout (MetaLogicalMonitorConfig    *logical_monitor_config,
+                               MetaLogicalMonitorLayoutMode layout_mode,
+                               GError                     **error)
 {
   MetaMonitorConfig *monitor_config;
   int mode_width, mode_height;
+  int width = 0, height = 0;
   GList *l;
 
   monitor_config = logical_monitor_config->monitor_configs->data;
@@ -379,8 +383,19 @@ derive_logical_monitor_layout (MetaLogicalMonitorConfig *logical_monitor_config,
         }
     }
 
-  logical_monitor_config->layout.width = mode_width;
-  logical_monitor_config->layout.height = mode_height;
+  switch (layout_mode)
+    {
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
+      width = mode_width / logical_monitor_config->scale;
+      height = mode_height / logical_monitor_config->scale;
+      break;
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
+      width = mode_width;
+      height = mode_height;
+    }
+
+  logical_monitor_config->layout.width = width;
+  logical_monitor_config->layout.height = height;
 
   return TRUE;
 }
@@ -491,12 +506,6 @@ handle_end_element (GMarkupParseContext  *context,
         if (logical_monitor_config->scale == 0)
           logical_monitor_config->scale = 1;
 
-        if (!derive_logical_monitor_layout (logical_monitor_config, error))
-          return;
-
-        if (!meta_verify_logical_monitor_config (logical_monitor_config, error))
-          return;
-
         parser->current_logical_monitor_configs =
           g_list_append (parser->current_logical_monitor_configs,
                          logical_monitor_config);
@@ -508,12 +517,34 @@ handle_end_element (GMarkupParseContext  *context,
 
     case STATE_CONFIGURATION:
       {
+        MetaMonitorConfigStore *store = parser->config_store;
         MetaMonitorsConfig *config;
+        GList *l;
+        MetaLogicalMonitorLayoutMode layout_mode;
 
         g_assert (g_str_equal (element_name, "configuration"));
 
+        layout_mode =
+          meta_monitor_manager_get_default_layout_mode (store->monitor_manager);
+
+        for (l = parser->current_logical_monitor_configs; l; l = l->next)
+          {
+            MetaLogicalMonitorConfig *logical_monitor_config = l->data;
+
+            if (!derive_logical_monitor_layout (logical_monitor_config,
+                                                layout_mode,
+                                                error))
+              return;
+
+            if (!meta_verify_logical_monitor_config (logical_monitor_config,
+                                                     layout_mode,
+                                                     error))
+              return;
+          }
+
         config =
-          meta_monitors_config_new (parser->current_logical_monitor_configs);
+          meta_monitors_config_new (parser->current_logical_monitor_configs,
+                                    layout_mode);
 
         if (!meta_verify_monitors_config (config, error))
           {
@@ -852,6 +883,17 @@ meta_monitor_config_store_get_config_count (MetaMonitorConfigStore *config_store
   return (int) g_hash_table_size (config_store->configs);
 }
 
+MetaMonitorConfigStore *
+meta_monitor_config_store_new (MetaMonitorManager *monitor_manager)
+{
+  MetaMonitorConfigStore *store;
+
+  store = g_object_new (META_TYPE_MONITOR_CONFIG_STORE, NULL);
+  store->monitor_manager = monitor_manager;
+
+  return store;
+}
+
 static void
 meta_monitor_config_store_dispose (GObject *object)
 {
diff --git a/src/backends/meta-monitor-config-store.h b/src/backends/meta-monitor-config-store.h
index 3dc94db..7451fc1 100644
--- a/src/backends/meta-monitor-config-store.h
+++ b/src/backends/meta-monitor-config-store.h
@@ -30,6 +30,8 @@
 G_DECLARE_FINAL_TYPE (MetaMonitorConfigStore, meta_monitor_config_store,
                       META, MONITOR_CONFIG_STORE, GObject)
 
+MetaMonitorConfigStore * meta_monitor_config_store_new (MetaMonitorManager *monitor_manager);
+
 MetaMonitorsConfig * meta_monitor_config_store_lookup (MetaMonitorConfigStore *config_store,
                                                        MetaMonitorsConfigKey  *key);
 
diff --git a/src/backends/meta-monitor-manager-dummy.c b/src/backends/meta-monitor-manager-dummy.c
index 8c8134b..2c31d62 100644
--- a/src/backends/meta-monitor-manager-dummy.c
+++ b/src/backends/meta-monitor-manager-dummy.c
@@ -605,10 +605,30 @@ meta_monitor_manager_dummy_get_supported_scales (MetaMonitorManager *manager,
   *n_scales = G_N_ELEMENTS (supported_scales_dummy);
 }
 
+static gboolean
+is_monitor_framebuffers_scaled (void)
+{
+  MetaBackend *backend = meta_get_backend ();
+
+  return meta_backend_is_experimental_feature_enabled (
+    backend,
+    META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
+}
+
 static MetaMonitorManagerCapability
 meta_monitor_manager_dummy_get_capabilities (MetaMonitorManager *manager)
 {
-  return META_MONITOR_MANAGER_CAPABILITY_MIRRORING;
+  MetaMonitorManagerCapability capabilities =
+    META_MONITOR_MANAGER_CAPABILITY_NONE;
+
+  capabilities |= META_MONITOR_MANAGER_CAPABILITY_MIRRORING;
+
+  if (meta_backend_is_experimental_feature_enabled (
+        meta_get_backend (),
+        META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
+    capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE;
+
+  return capabilities;
 }
 
 static gboolean
@@ -625,6 +645,18 @@ meta_monitor_manager_dummy_get_max_screen_size (MetaMonitorManager *manager,
   return TRUE;
 }
 
+static MetaLogicalMonitorLayoutMode
+meta_monitor_manager_dummy_get_default_layout_mode (MetaMonitorManager *manager)
+{
+  if (!meta_is_stage_views_enabled ())
+    return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+
+  if (is_monitor_framebuffers_scaled ())
+    return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
+  else
+    return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+}
+
 static void
 meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass)
 {
@@ -639,6 +671,7 @@ meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass)
   manager_class->get_supported_scales = meta_monitor_manager_dummy_get_supported_scales;
   manager_class->get_capabilities = meta_monitor_manager_dummy_get_capabilities;
   manager_class->get_max_screen_size = meta_monitor_manager_dummy_get_max_screen_size;
+  manager_class->get_default_layout_mode = meta_monitor_manager_dummy_get_default_layout_mode;
 }
 
 static void
diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h
index 1e0e611..4dc1139 100644
--- a/src/backends/meta-monitor-manager-private.h
+++ b/src/backends/meta-monitor-manager-private.h
@@ -71,7 +71,8 @@ typedef struct _MetaTileInfo MetaTileInfo;
 typedef enum _MetaMonitorManagerCapability
 {
   META_MONITOR_MANAGER_CAPABILITY_NONE = 0,
-  META_MONITOR_MANAGER_CAPABILITY_MIRRORING = (1 << 0)
+  META_MONITOR_MANAGER_CAPABILITY_MIRRORING = (1 << 0),
+  META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE = (1 << 1)
 } MetaMonitorManagerCapability;
 
 /* Equivalent to the 'method' enum in org.gnome.Mutter.DisplayConfig */
@@ -82,6 +83,13 @@ typedef enum _MetaMonitorsConfigMethod
   META_MONITORS_CONFIG_METHOD_PERSISTENT = 2
 } MetaMonitorsConfigMethod;
 
+/* Equivalent to the 'layout-mode' enum in org.gnome.Mutter.DisplayConfig */
+typedef enum _MetaLogicalMonitorLayoutMode
+{
+  META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL = 1,
+  META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL = 2
+} MetaLogicalMonitorLayoutMode;
+
 typedef enum
 {
   META_MONITOR_TRANSFORM_NORMAL,
@@ -274,6 +282,8 @@ struct _MetaMonitorManager
 
   MetaPowerSave power_save_mode;
 
+  MetaLogicalMonitorLayoutMode layout_mode;
+
   int screen_width;
   int screen_height;
 
@@ -376,6 +386,8 @@ struct _MetaMonitorManagerClass
   gboolean (*get_max_screen_size) (MetaMonitorManager *,
                                    int                *,
                                    int                *);
+
+  MetaLogicalMonitorLayoutMode (*get_default_layout_mode) (MetaMonitorManager *);
 };
 
 void                meta_monitor_manager_rebuild (MetaMonitorManager *manager,
@@ -479,6 +491,9 @@ gboolean           meta_monitor_manager_get_max_screen_size (MetaMonitorManager
                                                              int                *max_width,
                                                              int                *max_height);
 
+MetaLogicalMonitorLayoutMode
+                   meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager);
+
 void meta_monitor_manager_clear_output (MetaOutput *output);
 void meta_monitor_manager_clear_mode (MetaCrtcMode *mode);
 void meta_monitor_manager_clear_crtc (MetaCrtc *crtc);
diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
index 0af01f1..4cd65c3 100644
--- a/src/backends/meta-monitor-manager.c
+++ b/src/backends/meta-monitor-manager.c
@@ -319,6 +319,16 @@ meta_monitor_manager_get_max_screen_size (MetaMonitorManager *manager,
   return manager_class->get_max_screen_size (manager, max_width, max_height);
 }
 
+
+MetaLogicalMonitorLayoutMode
+meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager)
+{
+  MetaMonitorManagerClass *manager_class =
+    META_MONITOR_MANAGER_GET_CLASS (manager);
+
+  return manager_class->get_default_layout_mode (manager);
+}
+
 static void
 meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager)
 {
@@ -1397,6 +1407,13 @@ meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton,
                              g_variant_new_boolean (FALSE));
     }
 
+  if (capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
+    {
+      g_variant_builder_add (&properties_builder, "{sv}",
+                             "layout-mode",
+                             g_variant_new_uint32 (manager->layout_mode));
+    }
+
   if (meta_monitor_manager_get_max_screen_size (manager,
                                                 &max_screen_width,
                                                 &max_screen_height))
@@ -1593,10 +1610,12 @@ create_monitor_config_from_variant (MetaMonitorManager *manager,
 }
 
 static gboolean
-derive_logical_monitor_size (GList  *monitor_configs,
-                             int    *width,
-                             int    *height,
-                             GError **error)
+derive_logical_monitor_size (GList                       *monitor_configs,
+                             int                         *width,
+                             int                         *height,
+                             double                       scale,
+                             MetaLogicalMonitorLayoutMode layout_mode,
+                             GError                     **error)
 {
   MetaMonitorConfig *monitor_config;
 
@@ -1608,16 +1627,27 @@ derive_logical_monitor_size (GList  *monitor_configs,
     }
 
   monitor_config = monitor_configs->data;
-  *width = monitor_config->mode_spec->width;
-  *height = monitor_config->mode_spec->height;
 
-  return TRUE;
+  switch (layout_mode)
+    {
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
+      *width = monitor_config->mode_spec->width / scale;
+      *height = monitor_config->mode_spec->height / scale;
+      return TRUE;
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
+      *width = monitor_config->mode_spec->width;
+      *height = monitor_config->mode_spec->height;
+      return TRUE;
+    }
+
+  g_assert_not_reached ();
 }
 
 static MetaLogicalMonitorConfig *
-create_logical_monitor_config_from_variant (MetaMonitorManager *manager,
-                                            GVariant           *logical_monitor_config_variant,
-                                            GError            **error)
+create_logical_monitor_config_from_variant (MetaMonitorManager          *manager,
+                                            GVariant                    *logical_monitor_config_variant,
+                                            MetaLogicalMonitorLayoutMode layout_mode,
+                                            GError                     **error)
 {
   MetaLogicalMonitorConfig *logical_monitor_config;
   int x, y, width, height;
@@ -1658,7 +1688,8 @@ create_logical_monitor_config_from_variant (MetaMonitorManager *manager,
     }
   g_variant_iter_free (monitor_configs_iter);
 
-  if (!derive_logical_monitor_size (monitor_configs, &width, &height, error))
+  if (!derive_logical_monitor_size (monitor_configs, &width, &height,
+                                    scale, layout_mode, error))
     goto err;
 
   logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
@@ -1674,7 +1705,9 @@ create_logical_monitor_config_from_variant (MetaMonitorManager *manager,
     .monitor_configs = monitor_configs
   };
 
-  if (!meta_verify_logical_monitor_config (logical_monitor_config, error))
+  if (!meta_verify_logical_monitor_config (logical_monitor_config,
+                                           layout_mode,
+                                           error))
     {
       meta_logical_monitor_config_free (logical_monitor_config);
       return NULL;
@@ -1688,6 +1721,19 @@ err:
 }
 
 static gboolean
+is_valid_layout_mode (MetaLogicalMonitorLayoutMode layout_mode)
+{
+  switch (layout_mode)
+    {
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
+    case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
 meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skeleton,
                                                    GDBusMethodInvocation *invocation,
                                                    guint                  serial,
@@ -1696,6 +1742,9 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
                                                    GVariant              *properties_variant)
 {
   MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
+  MetaMonitorManagerCapability capabilities;
+  GVariant *layout_mode_variant = NULL;
+  MetaLogicalMonitorLayoutMode layout_mode;
   GVariantIter logical_monitor_configs_iter;
   MetaMonitorsConfig *config;
   GList *logical_monitor_configs = NULL;
@@ -1717,6 +1766,39 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
       return TRUE;
     }
 
+  capabilities = meta_monitor_manager_get_capabilities (manager);
+
+  if (properties_variant)
+    layout_mode_variant = g_variant_lookup_value (properties_variant,
+                                                  "layout-mode",
+                                                  G_VARIANT_TYPE ("u"));
+
+  if (layout_mode_variant &&
+      capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
+    {
+      g_variant_get (layout_mode_variant, "u", &layout_mode);
+    }
+  else if (!layout_mode_variant)
+    {
+      layout_mode =
+        meta_monitor_manager_get_default_layout_mode (manager);
+    }
+  else
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Can't set layout mode");
+      return TRUE;
+    }
+
+  if (!is_valid_layout_mode (layout_mode))
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_ACCESS_DENIED,
+                                             "Invalid layout mode specified");
+      return TRUE;
+    }
+
   g_variant_iter_init (&logical_monitor_configs_iter,
                        logical_monitor_configs_variant);
   while (TRUE)
@@ -1731,6 +1813,7 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
       logical_monitor_config =
         create_logical_monitor_config_from_variant (manager,
                                                     logical_monitor_config_variant,
+                                                    layout_mode,
                                                     &error);
       if (!logical_monitor_config)
         {
@@ -1747,7 +1830,7 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
                                                logical_monitor_config);
     }
 
-  config = meta_monitors_config_new (logical_monitor_configs);
+  config = meta_monitors_config_new (logical_monitor_configs, layout_mode);
   if (!meta_verify_monitors_config (config, &error))
     {
       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@@ -2416,6 +2499,12 @@ void
 meta_monitor_manager_update_logical_state (MetaMonitorManager *manager,
                                            MetaMonitorsConfig *config)
 {
+  if (config)
+    manager->layout_mode = config->layout_mode;
+  else
+    manager->layout_mode =
+      meta_monitor_manager_get_default_layout_mode (manager);
+
   meta_monitor_manager_rebuild_logical_monitors (manager, config);
 }
 
@@ -2455,6 +2544,8 @@ meta_monitor_manager_update_monitor_modes_derived (MetaMonitorManager *manager)
 void
 meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager)
 {
+  manager->layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+
   meta_monitor_manager_rebuild_logical_monitors_derived (manager);
 }
 
diff --git a/src/backends/native/meta-cursor-renderer-native.c 
b/src/backends/native/meta-cursor-renderer-native.c
index 7028997..5dbfadb 100644
--- a/src/backends/native/meta-cursor-renderer-native.c
+++ b/src/backends/native/meta-cursor-renderer-native.c
@@ -35,6 +35,8 @@
 #include <meta/meta-backend.h>
 
 #include "backends/meta-backend-private.h"
+#include "backends/meta-logical-monitor.h"
+#include "backends/meta-monitor.h"
 #include "backends/meta-monitor-manager-private.h"
 #include "backends/native/meta-renderer-native.h"
 #include "meta/boxes.h"
@@ -214,50 +216,125 @@ set_crtc_cursor (MetaCursorRendererNative *native,
     }
 }
 
+typedef struct
+{
+  MetaCursorRendererNative *in_cursor_renderer_native;
+  MetaLogicalMonitor *in_logical_monitor;
+  MetaRectangle in_local_cursor_rect;
+  MetaCursorSprite *in_cursor_sprite;
+
+  gboolean out_painted;
+} UpdateCrtcCursorData;
+
+static gboolean
+update_monitor_crtc_cursor (MetaMonitor         *monitor,
+                            MetaMonitorMode     *monitor_mode,
+                            MetaMonitorCrtcMode *monitor_crtc_mode,
+                            gpointer             user_data,
+                            GError             **error)
+{
+  UpdateCrtcCursorData *data = user_data;
+  MetaCursorRendererNative *cursor_renderer_native =
+    data->in_cursor_renderer_native;
+  MetaCursorRendererNativePrivate *priv =
+    meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
+  MetaRectangle scaled_crtc_rect;
+  int scale;
+
+  if (meta_is_stage_views_scaled ())
+    scale = meta_logical_monitor_get_scale (data->in_logical_monitor);
+  else
+    scale = 1;
+
+  scaled_crtc_rect = (MetaRectangle) {
+    .x = monitor_crtc_mode->x / scale,
+    .y = monitor_crtc_mode->y / scale,
+    .width = monitor_crtc_mode->crtc_mode->width / scale,
+    .height = monitor_crtc_mode->crtc_mode->height / scale
+  };
+
+  if (priv->has_hw_cursor &&
+      meta_rectangle_overlap (&scaled_crtc_rect,
+                              &data->in_local_cursor_rect))
+    {
+      int crtc_cursor_x, crtc_cursor_y;
+
+      set_crtc_cursor (data->in_cursor_renderer_native,
+                       monitor_crtc_mode->output->crtc,
+                       data->in_cursor_sprite);
+
+      crtc_cursor_x = (data->in_local_cursor_rect.x - scaled_crtc_rect.x) * scale;
+      crtc_cursor_y = (data->in_local_cursor_rect.y - scaled_crtc_rect.y) * scale;
+      drmModeMoveCursor (priv->drm_fd,
+                         monitor_crtc_mode->output->crtc->crtc_id,
+                         crtc_cursor_x,
+                         crtc_cursor_y);
+
+      data->out_painted = data->out_painted || TRUE;
+    }
+  else
+    {
+      set_crtc_cursor (data->in_cursor_renderer_native,
+                       monitor_crtc_mode->output->crtc, NULL);
+    }
+
+  return TRUE;
+}
+
 static void
 update_hw_cursor (MetaCursorRendererNative *native,
                   MetaCursorSprite         *cursor_sprite)
 {
   MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
   MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
-  MetaMonitorManager *monitors;
-  MetaCrtc *crtcs;
-  unsigned int i, n_crtcs;
+  MetaBackend *backend = meta_get_backend ();
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  GList *logical_monitors;
+  GList *l;
   MetaRectangle rect;
   gboolean painted = FALSE;
 
-  monitors = meta_monitor_manager_get ();
-  meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
-
   if (cursor_sprite)
     rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
   else
     rect = (MetaRectangle) { 0 };
 
-  for (i = 0; i < n_crtcs; i++)
+  logical_monitors =
+    meta_monitor_manager_get_logical_monitors (monitor_manager);
+  for (l = logical_monitors; l; l = l->next)
     {
-      gboolean crtc_should_use_cursor;
-      MetaCursorSprite *crtc_cursor;
-      MetaRectangle *crtc_rect;
-
-      crtc_rect = &crtcs[i].rect;
-
-      crtc_should_use_cursor = (priv->has_hw_cursor &&
-                                meta_rectangle_overlap (&rect, crtc_rect));
-      if (crtc_should_use_cursor)
-        crtc_cursor = cursor_sprite;
-      else
-        crtc_cursor = NULL;
-
-      set_crtc_cursor (native, &crtcs[i], crtc_cursor);
-
-      if (crtc_cursor)
+      MetaLogicalMonitor *logical_monitor = l->data;
+      UpdateCrtcCursorData data;
+      GList *monitors;
+      GList *k;
+
+      data = (UpdateCrtcCursorData) {
+        .in_cursor_renderer_native = native,
+        .in_logical_monitor = logical_monitor,
+        .in_local_cursor_rect = (MetaRectangle) {
+          .x = rect.x - logical_monitor->rect.x,
+          .y = rect.y - logical_monitor->rect.y,
+          .width = rect.width,
+          .height = rect.height
+        },
+        .in_cursor_sprite = cursor_sprite
+      };
+
+      monitors = meta_logical_monitor_get_monitors (logical_monitor);
+      for (k = monitors; k; k = k->next)
         {
-          drmModeMoveCursor (priv->drm_fd, crtcs[i].crtc_id,
-                             rect.x - crtc_rect->x,
-                             rect.y - crtc_rect->y);
-          painted = TRUE;
+          MetaMonitor *monitor = k->data;
+          MetaMonitorMode *monitor_mode;
+
+          monitor_mode = meta_monitor_get_current_mode (monitor);
+          meta_monitor_mode_foreach_crtc (monitor, monitor_mode,
+                                          update_monitor_crtc_cursor,
+                                          &data,
+                                          NULL);
         }
+
+      painted = painted || data.out_painted;
     }
 
   priv->hw_state_invalidated = FALSE;
@@ -316,6 +393,55 @@ cursor_over_transformed_crtc (MetaCursorRenderer *renderer,
   return FALSE;
 }
 
+static float
+calculate_cursor_crtc_sprite_scale (MetaCursorSprite   *cursor_sprite,
+                                    MetaLogicalMonitor *logical_monitor)
+{
+  return (meta_logical_monitor_get_scale (logical_monitor) *
+          meta_cursor_sprite_get_texture_scale (cursor_sprite));
+}
+
+static gboolean
+can_draw_cursor_unscaled (MetaCursorRenderer *renderer,
+                          MetaCursorSprite   *cursor_sprite)
+{
+  MetaBackend *backend;
+  MetaMonitorManager *monitor_manager;
+  MetaRectangle cursor_rect;
+  GList *logical_monitors;
+  GList *l;
+  gboolean has_visible_crtc_sprite = FALSE;
+
+  if (!meta_is_stage_views_scaled ())
+   return meta_cursor_sprite_get_texture_scale (cursor_sprite) == 1.0;
+
+  backend = meta_get_backend ();
+  monitor_manager = meta_backend_get_monitor_manager (backend);
+  logical_monitors =
+    meta_monitor_manager_get_logical_monitors (monitor_manager);
+
+  if (!logical_monitors)
+    return FALSE;
+
+  cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
+
+  for (l = logical_monitors; l; l = l->next)
+    {
+      MetaLogicalMonitor *logical_monitor = l->data;
+
+      if (!meta_rectangle_overlap (&cursor_rect, &logical_monitor->rect))
+        continue;
+
+      if (calculate_cursor_crtc_sprite_scale (cursor_sprite,
+                                              logical_monitor) != 1.0)
+        return FALSE;
+
+      has_visible_crtc_sprite = TRUE;
+    }
+
+  return has_visible_crtc_sprite;
+}
+
 static gboolean
 should_have_hw_cursor (MetaCursorRenderer *renderer,
                        MetaCursorSprite   *cursor_sprite)
@@ -337,7 +463,7 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
   if (!texture)
     return FALSE;
 
-  if (meta_cursor_sprite_get_texture_scale (cursor_sprite) != 1)
+  if (!can_draw_cursor_unscaled (renderer, cursor_sprite))
     return FALSE;
 
   if (!has_valid_cursor_sprite_gbm_bo (cursor_sprite))
diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c
index a000a7e..78930b8 100644
--- a/src/backends/native/meta-monitor-manager-kms.c
+++ b/src/backends/native/meta-monitor-manager-kms.c
@@ -1937,6 +1937,11 @@ meta_monitor_manager_kms_get_capabilities (MetaMonitorManager *manager)
   MetaMonitorManagerCapability capabilities =
     META_MONITOR_MANAGER_CAPABILITY_NONE;
 
+  if (meta_backend_is_experimental_feature_enabled (
+        backend,
+        META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
+    capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE;
+
   switch (meta_renderer_native_get_mode (renderer_native))
     {
     case META_RENDERER_NATIVE_MODE_GBM:
@@ -1967,6 +1972,20 @@ meta_monitor_manager_kms_get_max_screen_size (MetaMonitorManager *manager,
   return TRUE;
 }
 
+static MetaLogicalMonitorLayoutMode
+meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager)
+{
+  if (!meta_is_stage_views_enabled ())
+    return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+
+  if (meta_backend_is_experimental_feature_enabled (
+        meta_get_backend (),
+        META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
+    return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
+  else
+    return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+}
+
 static void
 meta_monitor_manager_kms_dispose (GObject *object)
 {
@@ -2011,4 +2030,5 @@ meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
   manager_class->get_supported_scales = meta_monitor_manager_kms_get_supported_scales;
   manager_class->get_capabilities = meta_monitor_manager_kms_get_capabilities;
   manager_class->get_max_screen_size = meta_monitor_manager_kms_get_max_screen_size;
+  manager_class->get_default_layout_mode = meta_monitor_manager_kms_get_default_layout_mode;
 }
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index 9dae6dc..ae3381b 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -1707,16 +1707,26 @@ meta_renderer_native_create_view (MetaRenderer       *renderer,
   MetaMonitorTransform view_transform;
   CoglOnscreen *onscreen = NULL;
   CoglOffscreen *offscreen = NULL;
+  int scale;
+  int width, height;
   MetaRendererView *view;
   GError *error = NULL;
 
   view_transform = calculate_view_transform (monitor_manager, logical_monitor);
 
+  if (meta_is_stage_views_scaled ())
+    scale = logical_monitor->scale;
+  else
+    scale = 1;
+
+  width = logical_monitor->rect.width * scale;
+  height = logical_monitor->rect.height * scale;
+
   onscreen = meta_renderer_native_create_onscreen (META_RENDERER_NATIVE (renderer),
                                                    cogl_context,
                                                    view_transform,
-                                                   logical_monitor->rect.width,
-                                                   logical_monitor->rect.height);
+                                                   width,
+                                                   height);
   if (!onscreen)
     meta_fatal ("Failed to allocate onscreen framebuffer\n");
 
@@ -1725,14 +1735,15 @@ meta_renderer_native_create_view (MetaRenderer       *renderer,
       offscreen = meta_renderer_native_create_offscreen (META_RENDERER_NATIVE (renderer),
                                                          cogl_context,
                                                          view_transform,
-                                                         logical_monitor->rect.width,
-                                                         logical_monitor->rect.height);
+                                                         width,
+                                                         height);
       if (!offscreen)
         meta_fatal ("Failed to allocate back buffer texture\n");
     }
 
   view = g_object_new (META_TYPE_RENDERER_VIEW,
                        "layout", &logical_monitor->rect,
+                       "scale", scale,
                        "framebuffer", onscreen,
                        "offscreen", offscreen,
                        "logical-monitor", logical_monitor,
diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
index 4083e08..fd044c8 100644
--- a/src/backends/x11/meta-monitor-manager-xrandr.c
+++ b/src/backends/x11/meta-monitor-manager-xrandr.c
@@ -1623,6 +1623,16 @@ meta_monitor_manager_xrandr_get_max_screen_size (MetaMonitorManager *manager,
   return TRUE;
 }
 
+static MetaLogicalMonitorLayoutMode
+meta_monitor_manager_xrandr_get_default_layout_mode (MetaMonitorManager *manager)
+{
+  /*
+   * Under X11, we still use the 'logical' layout mode, but it is
+   * eqivalent to 'physical' as the scale is always 1.
+   */
+  return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
+}
+
 static void
 meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
 {
@@ -1703,6 +1713,7 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
   manager_class->get_supported_scales = meta_monitor_manager_xrandr_get_supported_scales;
   manager_class->get_capabilities = meta_monitor_manager_xrandr_get_capabilities;
   manager_class->get_max_screen_size = meta_monitor_manager_xrandr_get_max_screen_size;
+  manager_class->get_default_layout_mode = meta_monitor_manager_xrandr_get_default_layout_mode;
 
   quark_meta_monitor_xrandr_data =
     g_quark_from_static_string ("-meta-monitor-xrandr-data");
diff --git a/src/backends/x11/meta-renderer-x11.c b/src/backends/x11/meta-renderer-x11.c
index da06133..5eb81dd 100644
--- a/src/backends/x11/meta-renderer-x11.c
+++ b/src/backends/x11/meta-renderer-x11.c
@@ -122,6 +122,7 @@ meta_renderer_x11_create_view (MetaRenderer       *renderer,
   ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
   CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
   MetaMonitorTransform view_transform;
+  int view_scale;
   int width, height;
   CoglTexture2D *texture_2d;
   CoglOffscreen *fake_onscreen;
@@ -130,11 +131,16 @@ meta_renderer_x11_create_view (MetaRenderer       *renderer,
 
   g_assert (meta_is_wayland_compositor ());
 
-  width = logical_monitor->rect.width;
-  height = logical_monitor->rect.height;
-
   view_transform = calculate_view_transform (monitor_manager, logical_monitor);
 
+  if (meta_is_stage_views_scaled ())
+    view_scale = logical_monitor->scale;
+  else
+    view_scale = 1;
+
+  width = logical_monitor->rect.width * view_scale;
+  height = logical_monitor->rect.height * view_scale;
+
   texture_2d = cogl_texture_2d_new_with_size (cogl_context, width, height);
   fake_onscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture_2d));
 
@@ -158,6 +164,7 @@ meta_renderer_x11_create_view (MetaRenderer       *renderer,
                        "framebuffer", COGL_FRAMEBUFFER (fake_onscreen),
                        "offscreen", COGL_FRAMEBUFFER (offscreen),
                        "transform", view_transform,
+                       "scale", view_scale,
                        NULL);
 }
 
diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
index 8fc4b9e..0dfc427 100644
--- a/src/compositor/meta-surface-actor-wayland.c
+++ b/src/compositor/meta-surface-actor-wayland.c
@@ -35,6 +35,7 @@
 #include "wayland/meta-wayland-private.h"
 #include "wayland/meta-window-wayland.h"
 
+#include "backends/meta-backend-private.h"
 #include "compositor/region-utils.h"
 
 enum {
@@ -104,9 +105,12 @@ meta_surface_actor_wayland_get_scale (MetaSurfaceActorWayland *self)
 
    window = meta_wayland_surface_get_toplevel_window (surface);
 
-   /* XXX: We do not handle x11 clients yet */
-   if (window && window->client_type != META_WINDOW_CLIENT_TYPE_X11)
-     geometry_scale = meta_window_wayland_get_geometry_scale (window);
+   if (!meta_is_stage_views_scaled ())
+     {
+       /* XXX: We do not handle x11 clients yet */
+       if (window && window->client_type != META_WINDOW_CLIENT_TYPE_X11)
+         geometry_scale = meta_window_wayland_get_geometry_scale (window);
+     }
 
    return (double) geometry_scale / (double) surface->scale;
 }
diff --git a/src/core/screen.c b/src/core/screen.c
index dfc499c..d6b5eac 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -1279,6 +1279,37 @@ update_num_workspaces (MetaScreen *screen,
   g_object_notify (G_OBJECT (screen), "n-workspaces");
 }
 
+static int
+find_highest_logical_monitor_scale (MetaBackend      *backend,
+                                    MetaCursorSprite *cursor_sprite)
+{
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaCursorRenderer *cursor_renderer =
+    meta_backend_get_cursor_renderer (backend);
+  MetaRectangle cursor_rect;
+  GList *logical_monitors;
+  GList *l;
+  int highest_scale = 0.0;
+
+  cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
+                                                     cursor_sprite);
+
+  logical_monitors =
+    meta_monitor_manager_get_logical_monitors (monitor_manager);
+  for (l = logical_monitors; l; l = l->next)
+    {
+      MetaLogicalMonitor *logical_monitor = l->data;
+
+      if (!meta_rectangle_overlap (&cursor_rect, &logical_monitor->rect))
+        continue;
+
+      highest_scale = MAX (highest_scale, logical_monitor->scale);
+    }
+
+  return highest_scale;
+}
+
 static void
 root_cursor_prepare_at (MetaCursorSprite *cursor_sprite,
                         int               x,
@@ -1286,16 +1317,35 @@ root_cursor_prepare_at (MetaCursorSprite *cursor_sprite,
                         MetaScreen       *screen)
 {
   MetaBackend *backend = meta_get_backend ();
-  MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
-  MetaLogicalMonitor *logical_monitor;
 
-  logical_monitor =
-    meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
+  if (meta_is_stage_views_scaled ())
+    {
+      int scale;
 
-  /* Reload the cursor texture if the scale has changed. */
-  if (logical_monitor)
-    meta_cursor_sprite_set_theme_scale (cursor_sprite, logical_monitor->scale);
+      scale = find_highest_logical_monitor_scale (backend, cursor_sprite);
+      if (scale != 0.0)
+        {
+          meta_cursor_sprite_set_theme_scale (cursor_sprite, scale);
+          meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0 / scale);
+        }
+    }
+  else
+    {
+      MetaMonitorManager *monitor_manager =
+        meta_backend_get_monitor_manager (backend);
+      MetaLogicalMonitor *logical_monitor;
+
+      logical_monitor =
+        meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
+
+      /* Reload the cursor texture if the scale has changed. */
+      if (logical_monitor)
+        {
+          meta_cursor_sprite_set_theme_scale (cursor_sprite,
+                                              logical_monitor->scale);
+          meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0);
+        }
+    }
 }
 
 static void
@@ -2206,6 +2256,9 @@ static void
 on_monitors_changed (MetaMonitorManager *manager,
                      MetaScreen         *screen)
 {
+  MetaBackend *backend;
+  MetaCursorRenderer *cursor_renderer;
+
   meta_monitor_manager_get_screen_size (manager,
                                         &screen->rect.width,
                                         &screen->rect.height);
@@ -2237,6 +2290,10 @@ on_monitors_changed (MetaMonitorManager *manager,
 
   meta_screen_queue_check_fullscreen (screen);
 
+  backend = meta_get_backend ();
+  cursor_renderer = meta_backend_get_cursor_renderer (backend);
+  meta_cursor_renderer_force_update (cursor_renderer);
+
   g_signal_emit (screen, screen_signals[MONITORS_CHANGED], 0);
 }
 
diff --git a/src/org.gnome.Mutter.DisplayConfig.xml b/src/org.gnome.Mutter.DisplayConfig.xml
index 2c623c6..bb48768 100644
--- a/src/org.gnome.Mutter.DisplayConfig.xml
+++ b/src/org.gnome.Mutter.DisplayConfig.xml
@@ -344,10 +344,34 @@
        scale factors of logical monitors supported by the display server.
 
 
+       @layout_mode current layout mode represents the way logical monitors
+       are layed out on the screen. Possible modes include:
+
+         1 : physical
+         2 : logical
+
+       With physical layout mode, each logical monitor has the same dimensions
+       an the monitor modes of the associated monitors assigned to it, no
+       matter what scale is in use.
+
+       With logical mode, the dimension of a logical monitor is the dimension
+       of the monitor mode, divided by the logical monitor scale.
+
+
        Possible @properties are:
 
        * "supports-mirroring" (b): FALSE if mirroring not supported; TRUE or not
                                    present if mirroring is supported.
+       * "layout-mode" (u): Represents in what way logical monitors are laid
+                            out on the screen. The layout mode can be either
+                            of the ones listed below. Absence of this property
+                            means the layout mode cannot be changed, and that
+                            "logical" mode is assumed to be used.
+           * 1 : logical  - the dimension of a logical monitor is derived from
+                            the monitor modes associated with it, then scaled
+                            using the logical monitor scale.
+           * 2 : physical - the dimension of a logical monitor is derived from
+                            the monitor modes associated with it.
     -->
     <method name="GetCurrentState">
       <arg name="serial" direction="out" type="u" />
@@ -386,6 +410,13 @@
                - "enable_underscanning" (b): enable monitor underscanning;
                                              may only be set when underscanning
                                              is supported (see GetCurrentState).
+
+       @properties may effect the global monitor configuration state. Possible
+       properties are:
+
+       * "layout-mode" (u): layout mode the passed configuration is in; may
+                            only be set when changing the layout mode is
+                            supported (see GetCurrentState).
     -->
     <method name="ApplyMonitorsConfig">
       <arg name="serial" direction="in" type="u" />
diff --git a/src/tests/meta-monitor-manager-test.c b/src/tests/meta-monitor-manager-test.c
index 6925365..cc88dfe 100644
--- a/src/tests/meta-monitor-manager-test.c
+++ b/src/tests/meta-monitor-manager-test.c
@@ -380,10 +380,28 @@ meta_monitor_manager_test_get_supported_scales (MetaMonitorManager *manager,
   *n_scales = G_N_ELEMENTS (supported_scales_test);
 }
 
+static gboolean
+is_monitor_framebuffer_scaled (void)
+{
+  MetaBackend *backend = meta_get_backend ();
+
+  return meta_backend_is_experimental_feature_enabled (
+    backend,
+    META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
+}
+
 static MetaMonitorManagerCapability
 meta_monitor_manager_test_get_capabilities (MetaMonitorManager *manager)
 {
-  return META_MONITOR_MANAGER_CAPABILITY_MIRRORING;
+  MetaMonitorManagerCapability capabilities =
+    META_MONITOR_MANAGER_CAPABILITY_NONE;
+
+  capabilities |= META_MONITOR_MANAGER_CAPABILITY_MIRRORING;
+
+  if (is_monitor_framebuffer_scaled ())
+    capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE;
+
+  return capabilities;
 }
 
 static gboolean
@@ -400,6 +418,18 @@ meta_monitor_manager_test_get_max_screen_size (MetaMonitorManager *manager,
   return TRUE;
 }
 
+static MetaLogicalMonitorLayoutMode
+meta_monitor_manager_test_get_default_layout_mode (MetaMonitorManager *manager)
+{
+  if (!meta_is_stage_views_enabled ())
+    return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+
+  if (is_monitor_framebuffer_scaled ())
+    return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
+  else
+    return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+}
+
 static void
 meta_monitor_manager_test_dispose (GObject *object)
 {
@@ -436,4 +466,5 @@ meta_monitor_manager_test_class_init (MetaMonitorManagerTestClass *klass)
   manager_class->get_supported_scales = meta_monitor_manager_test_get_supported_scales;
   manager_class->get_capabilities = meta_monitor_manager_test_get_capabilities;
   manager_class->get_max_screen_size = meta_monitor_manager_test_get_max_screen_size;
+  manager_class->get_default_layout_mode = meta_monitor_manager_test_get_default_layout_mode;
 }
diff --git a/src/tests/monitor-store-unit-tests.c b/src/tests/monitor-store-unit-tests.c
index 37bd221..60aa872 100644
--- a/src/tests/monitor-store-unit-tests.c
+++ b/src/tests/monitor-store-unit-tests.c
@@ -472,8 +472,8 @@ meta_test_monitor_store_scale (void)
             .layout = {
               .x = 0,
               .y = 0,
-              .width = 1920,
-              .height = 1080
+              .width = 960,
+              .height = 540
             },
             .scale = 2,
             .is_primary = TRUE,
diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c
index 1eb3841..3abcc76 100644
--- a/src/tests/monitor-unit-tests.c
+++ b/src/tests/monitor-unit-tests.c
@@ -1354,13 +1354,13 @@ meta_test_monitor_hidpi_linear_config (void)
         {
           .monitors = { 0 },
           .n_monitors = 1,
-          .layout = { .x = 0, .y = 0, .width = 1280, .height = 720 },
+          .layout = { .x = 0, .y = 0, .width = 640, .height = 360 },
           .scale = 2
         },
         {
           .monitors = { 1 },
           .n_monitors = 1,
-          .layout = { .x = 1280, .y = 0, .width = 1024, .height = 768 },
+          .layout = { .x = 640, .y = 0, .width = 1024, .height = 768 },
           .scale = 1
         }
       },
@@ -1376,12 +1376,18 @@ meta_test_monitor_hidpi_linear_config (void)
         }
       },
       .n_crtcs = 2,
-      .screen_width = 1280 + 1024,
+      .screen_width = 640 + 1024,
       .screen_height = 768
     }
   };
   MetaMonitorTestSetup *test_setup;
 
+  if (!is_using_monitor_config_manager ())
+    {
+      g_test_skip ("Not using MetaMonitorConfigManager");
+      return;
+    }
+
   test_setup = create_monitor_test_setup (&test_case,
                                           MONITOR_TEST_FLAG_NO_STORED);
   emulate_hotplug (test_setup);
@@ -2689,7 +2695,7 @@ meta_test_monitor_custom_scale_config (void)
         {
           .monitors = { 0 },
           .n_monitors = 1,
-          .layout = { .x = 0, .y = 0, .width = 1920, .height = 1080 },
+          .layout = { .x = 0, .y = 0, .width = 960, .height = 540 },
           .scale = 2
         }
       },
@@ -2703,8 +2709,8 @@ meta_test_monitor_custom_scale_config (void)
       },
       .n_crtcs = 1,
       .n_tiled_monitors = 0,
-      .screen_width = 1920,
-      .screen_height = 1080
+      .screen_width = 960,
+      .screen_height = 540
     }
   };
   MetaMonitorTestSetup *test_setup;
@@ -2824,7 +2830,7 @@ meta_test_monitor_custom_tiled_config (void)
         {
           .monitors = { 0 },
           .n_monitors = 1,
-          .layout = { .x = 0, .y = 0, .width = 800, .height = 600 },
+          .layout = { .x = 0, .y = 0, .width = 400, .height = 300 },
           .scale = 2
         }
       },
@@ -2841,8 +2847,8 @@ meta_test_monitor_custom_tiled_config (void)
       },
       .n_crtcs = 2,
       .n_tiled_monitors = 1,
-      .screen_width = 800,
-      .screen_height = 600
+      .screen_width = 400,
+      .screen_height = 300
     }
   };
   MetaMonitorTestSetup *test_setup;
diff --git a/src/tests/unit-tests.c b/src/tests/unit-tests.c
index 7e5a1e8..efd56f1 100644
--- a/src/tests/unit-tests.c
+++ b/src/tests/unit-tests.c
@@ -214,8 +214,15 @@ meta_test_adjecent_to (void)
 static gboolean
 run_tests (gpointer data)
 {
+  MetaBackend *backend = meta_get_backend ();
   gboolean ret;
 
+  meta_backend_override_experimental_features (backend);
+
+  meta_backend_enable_experimental_feature (
+    backend,
+    META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
+
   ret = g_test_run ();
 
   meta_quit (ret != 0);
diff --git a/src/wayland/meta-wayland-surface-role-cursor.c b/src/wayland/meta-wayland-surface-role-cursor.c
index 6b6c0a0..18b4fe9 100644
--- a/src/wayland/meta-wayland-surface-role-cursor.c
+++ b/src/wayland/meta-wayland-surface-role-cursor.c
@@ -112,7 +112,11 @@ cursor_sprite_prepare_at (MetaCursorSprite             *cursor_sprite,
         {
           float texture_scale;
 
-          texture_scale = (float) logical_monitor->scale / surface->scale;
+          if (meta_is_stage_views_scaled ())
+            texture_scale = 1.0 / surface->scale;
+          else
+            texture_scale = (float) logical_monitor->scale / surface->scale;
+
           meta_cursor_sprite_set_texture_scale (cursor_sprite, texture_scale);
         }
     }
diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
index 9a21388..a1b239b 100644
--- a/src/wayland/meta-window-wayland.c
+++ b/src/wayland/meta-window-wayland.c
@@ -38,11 +38,14 @@
 #include "backends/meta-backend-private.h"
 #include "backends/meta-logical-monitor.h"
 #include "compositor/meta-surface-actor-wayland.h"
+#include "backends/meta-backend-private.h"
 
 struct _MetaWindowWayland
 {
   MetaWindow parent;
 
+  int geometry_scale;
+
   MetaWaylandSerial pending_configure_serial;
   gboolean has_pending_move;
   int pending_move_x;
@@ -61,11 +64,24 @@ struct _MetaWindowWaylandClass
 
 G_DEFINE_TYPE (MetaWindowWayland, meta_window_wayland, META_TYPE_WINDOW)
 
+static int
+get_window_geometry_scale_for_logical_monitor (MetaLogicalMonitor *logical_monitor)
+{
+  if (meta_is_stage_views_scaled ())
+    return 1;
+  else
+    return logical_monitor->scale;
+}
+
 static void
 meta_window_wayland_manage (MetaWindow *window)
 {
+  MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);
   MetaDisplay *display = window->display;
 
+  wl_window->geometry_scale =
+    get_window_geometry_scale_for_logical_monitor (window->monitor);
+
   meta_display_register_wayland_window (display, window);
 
   {
@@ -375,6 +391,12 @@ meta_window_wayland_update_main_monitor (MetaWindow *window)
       return;
     }
 
+  if (meta_is_stage_views_scaled ())
+    {
+      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. */
@@ -393,16 +415,24 @@ static void
 meta_window_wayland_main_monitor_changed (MetaWindow               *window,
                                           const MetaLogicalMonitor *old)
 {
+  MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);
+  int old_geometry_scale = wl_window->geometry_scale;
+  int geometry_scale;
   float scale_factor;
   MetaWaylandSurface *surface;
 
+  if (!window->monitor)
+    return;
+
+  geometry_scale = meta_window_wayland_get_geometry_scale (window);
+
   /* 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)
+      old_geometry_scale == geometry_scale)
     return;
 
   /* MetaWindow keeps its rectangles in the physical pixel coordinate space.
@@ -410,7 +440,7 @@ meta_window_wayland_main_monitor_changed (MetaWindow               *window,
    * 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;
+  scale_factor = (float) geometry_scale / old_geometry_scale;
 
   /* Window size. */
   scale_rect_size (&window->rect, scale_factor);
@@ -419,7 +449,6 @@ meta_window_wayland_main_monitor_changed (MetaWindow               *window,
   scale_size (&window->size_hints.min_width, &window->size_hints.min_height, scale_factor);
   scale_size (&window->size_hints.max_width, &window->size_hints.max_height, scale_factor);
 
-
   /* Window geometry offset (XXX: Need a better place, see
    * meta_window_wayland_move_resize). */
   window->custom_frame_extents.left =
@@ -449,6 +478,8 @@ meta_window_wayland_main_monitor_changed (MetaWindow               *window,
       meta_surface_actor_wayland_sync_state_recursive (actor);
     }
 
+  wl_window->geometry_scale = geometry_scale;
+
   meta_window_emit_size_changed (window);
 }
 
@@ -477,6 +508,8 @@ meta_window_wayland_init (MetaWindowWayland *wl_window)
 {
   MetaWindow *window = META_WINDOW (wl_window);
 
+  wl_window->geometry_scale = 1;
+
   g_signal_connect (window, "notify::appears-focused",
                     G_CALLBACK (appears_focused_changed), NULL);
 }
@@ -571,7 +604,7 @@ should_do_pending_move (MetaWindowWayland *wl_window,
 int
 meta_window_wayland_get_geometry_scale (MetaWindow *window)
 {
-  return window->monitor->scale;
+  return get_window_geometry_scale_for_logical_monitor (window->monitor);
 }
 
 /**


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]