[mutter] monitor-manager/xrandr: Allow configuring scales on X11 too



commit 1bb0e18042df00024a58fd32bf62172e39d54f98
Author: Jonas Ådahl <jadahl gmail com>
Date:   Fri Apr 21 18:01:15 2017 +0800

    monitor-manager/xrandr: Allow configuring scales on X11 too
    
    This commit makes it possible to configure logical monitor scale also
    when running on top of an X11 server using Xrandr. An extra property
    'requires-globla-scale' is added to the D-Bus API is added to instruct
    a configuration application to only allow setting a global logical
    monitor scale.
    
    This is needed to let gsd-xsettings use the configured state to set a
    XSettings state that respects the explicit monitor configuration.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=777732

 src/backends/meta-logical-monitor.c            |    8 +-
 src/backends/meta-logical-monitor.h            |    1 +
 src/backends/meta-monitor-config-manager.c     |   68 ++++++--
 src/backends/meta-monitor-config-manager.h     |    1 +
 src/backends/meta-monitor-config-store.c       |    3 +-
 src/backends/meta-monitor-manager-dummy.c      |   16 ++-
 src/backends/meta-monitor-manager-private.h    |   18 ++-
 src/backends/meta-monitor-manager.c            |  114 ++++++++++++-
 src/backends/native/meta-monitor-manager-kms.c |   16 ++-
 src/backends/x11/meta-monitor-manager-xrandr.c |  218 +++++++++++++++++++++---
 src/org.gnome.Mutter.DisplayConfig.xml         |    4 +
 src/tests/meta-monitor-manager-test.c          |   38 ++++-
 12 files changed, 436 insertions(+), 69 deletions(-)
---
diff --git a/src/backends/meta-logical-monitor.c b/src/backends/meta-logical-monitor.c
index 4123165..fab6698 100644
--- a/src/backends/meta-logical-monitor.c
+++ b/src/backends/meta-logical-monitor.c
@@ -107,21 +107,15 @@ MetaLogicalMonitor *
 meta_logical_monitor_new_derived (MetaMonitorManager *monitor_manager,
                                   MetaMonitor        *monitor,
                                   MetaRectangle      *layout,
+                                  int                 scale,
                                   int                 monitor_number)
 {
   MetaLogicalMonitor *logical_monitor;
   MetaOutput *main_output;
-  MetaMonitorMode *monitor_mode;
-  int scale;
   MetaMonitorTransform transform;
 
   logical_monitor = g_object_new (META_TYPE_LOGICAL_MONITOR, NULL);
 
-  monitor_mode = meta_monitor_get_current_mode (monitor);
-  scale = meta_monitor_manager_calculate_monitor_mode_scale (monitor_manager,
-                                                             monitor,
-                                                             monitor_mode);
-
   transform = derive_monitor_transform (monitor);
 
   main_output = meta_monitor_get_main_output (monitor);
diff --git a/src/backends/meta-logical-monitor.h b/src/backends/meta-logical-monitor.h
index c1bd5be..ce0c7e7 100644
--- a/src/backends/meta-logical-monitor.h
+++ b/src/backends/meta-logical-monitor.h
@@ -68,6 +68,7 @@ MetaLogicalMonitor * meta_logical_monitor_new (MetaMonitorManager       *monitor
 MetaLogicalMonitor * meta_logical_monitor_new_derived (MetaMonitorManager *monitor_manager,
                                                        MetaMonitor        *monitor,
                                                        MetaRectangle      *layout,
+                                                       int                 scale,
                                                        int                 monitor_number);
 
 void meta_logical_monitor_add_monitor (MetaLogicalMonitor *logical_monitor,
diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
index 5f80feb..bad55c7 100644
--- a/src/backends/meta-monitor-config-manager.c
+++ b/src/backends/meta-monitor-config-manager.c
@@ -483,6 +483,7 @@ create_preferred_logical_monitor_config (MetaMonitorManager          *monitor_ma
                                          MetaMonitor                 *monitor,
                                          int                          x,
                                          int                          y,
+                                         MetaLogicalMonitorConfig    *primary_logical_monitor_config,
                                          MetaLogicalMonitorLayoutMode layout_mode)
 {
   MetaMonitorMode *mode;
@@ -493,9 +494,15 @@ create_preferred_logical_monitor_config (MetaMonitorManager          *monitor_ma
 
   mode = meta_monitor_get_preferred_mode (monitor);
   meta_monitor_mode_get_resolution (mode, &width, &height);
-  scale = meta_monitor_manager_calculate_monitor_mode_scale (monitor_manager,
-                                                             monitor,
-                                                             mode);
+
+  if ((meta_monitor_manager_get_capabilities (monitor_manager) &
+       META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED) &&
+      primary_logical_monitor_config)
+    scale = primary_logical_monitor_config->scale;
+  else
+    scale = meta_monitor_manager_calculate_monitor_mode_scale (monitor_manager,
+                                                               monitor,
+                                                               mode);
 
   switch (layout_mode)
     {
@@ -546,6 +553,7 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana
     create_preferred_logical_monitor_config (monitor_manager,
                                              primary_monitor,
                                              0, 0,
+                                             NULL,
                                              layout_mode);
   primary_logical_monitor_config->is_primary = TRUE;
   logical_monitor_configs = g_list_append (NULL,
@@ -569,6 +577,7 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana
         create_preferred_logical_monitor_config (monitor_manager,
                                                  monitor,
                                                  x, 0,
+                                                 primary_logical_monitor_config,
                                                  layout_mode);
       logical_monitor_configs = g_list_append (logical_monitor_configs,
                                                logical_monitor_config);
@@ -598,6 +607,7 @@ meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_ma
     create_preferred_logical_monitor_config (monitor_manager,
                                              primary_monitor,
                                              0, 0,
+                                             NULL,
                                              layout_mode);
   primary_logical_monitor_config->is_primary = TRUE;
   logical_monitor_configs = g_list_append (NULL,
@@ -615,6 +625,7 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
   MetaLogicalMonitorLayoutMode layout_mode;
   GList *logical_monitor_configs;
   GList *region;
+  int x, y;
   GList *monitors;
   GList *l;
 
@@ -622,16 +633,30 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
   if (!primary_monitor)
     return NULL;
 
+  if (!meta_monitor_get_suggested_position (primary_monitor, &x, &y))
+    return NULL;
+
   layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
 
-  logical_monitor_configs = NULL;
-  region = NULL;
+  primary_logical_monitor_config =
+    create_preferred_logical_monitor_config (monitor_manager,
+                                             primary_monitor,
+                                             x, y,
+                                             NULL,
+                                             layout_mode);
+  primary_logical_monitor_config->is_primary = TRUE;
+  logical_monitor_configs = g_list_append (NULL,
+                                           primary_logical_monitor_config);
+  region = g_list_prepend (NULL, &primary_logical_monitor_config->layout);
+
   monitors = meta_monitor_manager_get_monitors (monitor_manager);
   for (l = monitors; l; l = l->next)
     {
       MetaMonitor *monitor = l->data;
       MetaLogicalMonitorConfig *logical_monitor_config;
-      int x, y;
+
+      if (monitor == primary_monitor)
+        continue;
 
       if (!meta_monitor_get_suggested_position (monitor, &x, &y))
         continue;
@@ -640,6 +665,7 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
         create_preferred_logical_monitor_config (monitor_manager,
                                                  monitor,
                                                  x, y,
+                                                 primary_logical_monitor_config,
                                                  layout_mode);
       logical_monitor_configs = g_list_append (logical_monitor_configs,
                                                logical_monitor_config);
@@ -655,9 +681,6 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
         }
 
       region = g_list_prepend (region, &logical_monitor_config->layout);
-
-      if (monitor == primary_monitor)
-        primary_logical_monitor_config = logical_monitor_config;
     }
 
   g_list_free (region);
@@ -665,12 +688,6 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
   if (!logical_monitor_configs)
     return NULL;
 
-  if (!primary_logical_monitor_config)
-    primary_logical_monitor_config =
-      g_list_first (logical_monitor_configs)->data;
-
-  primary_logical_monitor_config->is_primary = TRUE;
-
   return meta_monitors_config_new (logical_monitor_configs, layout_mode);
 }
 
@@ -1024,12 +1041,14 @@ has_adjecent_neighbour (MetaMonitorsConfig       *config,
 
 gboolean
 meta_verify_monitors_config (MetaMonitorsConfig *config,
+                             MetaMonitorManager *monitor_manager,
                              GError            **error)
 {
   int min_x, min_y;
   gboolean has_primary;
   GList *region;
   GList *l;
+  gboolean global_scale_required;
 
   if (!config->logical_monitor_configs)
     {
@@ -1038,6 +1057,10 @@ meta_verify_monitors_config (MetaMonitorsConfig *config,
       return FALSE;
     }
 
+  global_scale_required =
+    !!(meta_monitor_manager_get_capabilities (monitor_manager) &
+       META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
+
   min_x = INT_MAX;
   min_y = INT_MAX;
   region = NULL;
@@ -1046,6 +1069,21 @@ meta_verify_monitors_config (MetaMonitorsConfig *config,
     {
       MetaLogicalMonitorConfig *logical_monitor_config = l->data;
 
+      if (global_scale_required)
+        {
+          MetaLogicalMonitorConfig *prev_logical_monitor_config =
+            l->prev ? l->prev->data : NULL;
+
+          if (prev_logical_monitor_config &&
+              (prev_logical_monitor_config->scale !=
+               logical_monitor_config->scale))
+            {
+              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                           "Logical monitor scales must be identical");
+              return FALSE;
+            }
+        }
+
       if (meta_rectangle_overlaps_with_region (region,
                                                &logical_monitor_config->layout))
         {
diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
index 60b4446..7c3dbcd 100644
--- a/src/backends/meta-monitor-config-manager.h
+++ b/src/backends/meta-monitor-config-manager.h
@@ -120,6 +120,7 @@ gboolean meta_verify_logical_monitor_config (MetaLogicalMonitorConfig    *logica
                                              GError                     **error);
 
 gboolean meta_verify_monitors_config (MetaMonitorsConfig *config,
+                                      MetaMonitorManager *monitor_manager,
                                       GError            **error);
 
 #endif /* META_MONITOR_CONFIG_MANAGER_H */
diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
index aa7f08a..8fc4f61 100644
--- a/src/backends/meta-monitor-config-store.c
+++ b/src/backends/meta-monitor-config-store.c
@@ -640,7 +640,8 @@ handle_end_element (GMarkupParseContext  *context,
 
         parser->current_logical_monitor_configs = NULL;
 
-        if (!meta_verify_monitors_config (config, error))
+        if (!meta_verify_monitors_config (config, store->monitor_manager,
+                                          error))
           {
             g_object_unref (config);
             return;
diff --git a/src/backends/meta-monitor-manager-dummy.c b/src/backends/meta-monitor-manager-dummy.c
index 21608a1..3d181d5 100644
--- a/src/backends/meta-monitor-manager-dummy.c
+++ b/src/backends/meta-monitor-manager-dummy.c
@@ -357,9 +357,16 @@ meta_monitor_manager_dummy_ensure_initial_config (MetaMonitorManager *manager)
   config = meta_monitor_manager_ensure_configured (manager);
 
   if (meta_is_monitor_config_manager_enabled ())
-    meta_monitor_manager_update_logical_state (manager, config);
+    {
+      meta_monitor_manager_update_logical_state (manager, config);
+    }
   else
-    meta_monitor_manager_update_logical_state_derived (manager);
+    {
+      MetaMonitorManagerDeriveFlag flags =
+        META_MONITOR_MANAGER_DERIVE_FLAG_NONE;
+
+      meta_monitor_manager_update_logical_state_derived (manager, flags);
+    }
 }
 
 static void
@@ -565,11 +572,14 @@ meta_monitor_manager_dummy_apply_config (MetaMonitorManager *manager,
                                          MetaOutputInfo    **outputs,
                                          unsigned int        n_outputs)
 {
+  MetaMonitorManagerDeriveFlag flags =
+    META_MONITOR_MANAGER_DERIVE_FLAG_NONE;
+
   apply_crtc_assignments (manager, crtcs, n_crtcs, outputs, n_outputs);
 
   legacy_calculate_screen_size (manager);
 
-  meta_monitor_manager_rebuild_derived (manager);
+  meta_monitor_manager_rebuild_derived (manager, flags);
 }
 
 static gboolean
diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h
index 1f12e67..d8bc6f8 100644
--- a/src/backends/meta-monitor-manager-private.h
+++ b/src/backends/meta-monitor-manager-private.h
@@ -72,7 +72,8 @@ typedef enum _MetaMonitorManagerCapability
 {
   META_MONITOR_MANAGER_CAPABILITY_NONE = 0,
   META_MONITOR_MANAGER_CAPABILITY_MIRRORING = (1 << 0),
-  META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE = (1 << 1)
+  META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE = (1 << 1),
+  META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED = (1 << 2)
 } MetaMonitorManagerCapability;
 
 /* Equivalent to the 'method' enum in org.gnome.Mutter.DisplayConfig */
@@ -90,6 +91,12 @@ typedef enum _MetaLogicalMonitorLayoutMode
   META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL = 2
 } MetaLogicalMonitorLayoutMode;
 
+typedef enum _MetaMonitorManagerDeriveFlag
+{
+  META_MONITOR_MANAGER_DERIVE_FLAG_NONE = 0,
+  META_MONITOR_MANAGER_DERIVE_FLAG_CONFIGURED_SCALE = (1 << 0)
+} MetaMonitorManagerDeriveFlag;
+
 typedef enum
 {
   META_MONITOR_TRANSFORM_NORMAL,
@@ -404,7 +411,8 @@ gboolean            meta_is_monitor_config_manager_enabled (void);
 
 void                meta_monitor_manager_rebuild (MetaMonitorManager *manager,
                                                   MetaMonitorsConfig *config);
-void                meta_monitor_manager_rebuild_derived   (MetaMonitorManager *manager);
+void                meta_monitor_manager_rebuild_derived (MetaMonitorManager          *manager,
+                                                          MetaMonitorManagerDeriveFlag flags);
 
 int                 meta_monitor_manager_get_num_logical_monitors (MetaMonitorManager *manager);
 
@@ -487,7 +495,8 @@ MetaMonitorsConfig * meta_monitor_manager_ensure_configured (MetaMonitorManager
 
 void               meta_monitor_manager_update_logical_state (MetaMonitorManager *manager,
                                                               MetaMonitorsConfig *config);
-void               meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager);
+void               meta_monitor_manager_update_logical_state_derived (MetaMonitorManager          *manager,
+                                                                      MetaMonitorManagerDeriveFlag flags);
 
 gboolean           meta_monitor_manager_is_lid_closed (MetaMonitorManager *manager);
 
@@ -499,6 +508,9 @@ int                meta_monitor_manager_calculate_monitor_mode_scale (MetaMonito
                                                                       MetaMonitor        *monitor,
                                                                       MetaMonitorMode    *monitor_mode);
 
+MetaMonitorManagerCapability
+                   meta_monitor_manager_get_capabilities (MetaMonitorManager *manager);
+
 gboolean           meta_monitor_manager_get_max_screen_size (MetaMonitorManager *manager,
                                                              int                *max_width,
                                                              int                *max_height);
diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
index ba071ca..fa2840c 100644
--- a/src/backends/meta-monitor-manager.c
+++ b/src/backends/meta-monitor-manager.c
@@ -184,16 +184,95 @@ derive_monitor_layout (MetaMonitor   *monitor,
   meta_monitor_derive_dimensions (monitor, &layout->width, &layout->height);
 }
 
+static int
+derive_configured_global_scale (MetaMonitorManager *manager)
+{
+  MetaMonitorsConfig *config;
+  MetaLogicalMonitorConfig *logical_monitor_config;
+
+  config = meta_monitor_config_manager_get_current (manager->config_manager);
+  if (!config)
+    return 1;
+
+  logical_monitor_config = config->logical_monitor_configs->data;
+
+  return logical_monitor_config->scale;
+}
+
+static int
+calculate_monitor_scale (MetaMonitorManager *manager,
+                         MetaMonitor        *monitor)
+{
+  MetaMonitorMode *monitor_mode;
+
+  monitor_mode = meta_monitor_get_current_mode (monitor);
+  return meta_monitor_manager_calculate_monitor_mode_scale (manager,
+                                                            monitor,
+                                                            monitor_mode);
+}
+
+static int
+derive_calculated_global_scale (MetaMonitorManager *manager)
+{
+  MetaMonitor *primary_monitor;
+
+  primary_monitor = meta_monitor_manager_get_primary_monitor (manager);
+  if (!primary_monitor)
+    return 1;
+
+  return calculate_monitor_scale (manager, primary_monitor);
+}
+
+static int
+derive_scale_from_config (MetaMonitorManager *manager,
+                          MetaRectangle      *layout)
+{
+  MetaMonitorsConfig *config;
+  GList *l;
+
+  config = meta_monitor_config_manager_get_current (manager->config_manager);
+  for (l = config->logical_monitor_configs; l; l = l->next)
+    {
+      MetaLogicalMonitorConfig *logical_monitor_config = l->data;
+
+      if (meta_rectangle_equal (layout, &logical_monitor_config->layout))
+        return logical_monitor_config->scale;
+    }
+
+  g_warning ("Missing logical monitor, using scale 1");
+  return 1;
+}
+
 static void
-meta_monitor_manager_rebuild_logical_monitors_derived (MetaMonitorManager *manager)
+meta_monitor_manager_rebuild_logical_monitors_derived (MetaMonitorManager          *manager,
+                                                       MetaMonitorManagerDeriveFlag flags)
 {
   GList *logical_monitors = NULL;
   GList *l;
   int monitor_number;
   MetaLogicalMonitor *primary_logical_monitor = NULL;
+  gboolean use_configured_scale;
+  gboolean use_global_scale;
+  int global_scale = 0;
+  MetaMonitorManagerCapability capabilities;
 
   monitor_number = 0;
 
+  capabilities = meta_monitor_manager_get_capabilities (manager);
+  use_global_scale =
+    !!(capabilities & META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
+
+  use_configured_scale =
+    !!(flags & META_MONITOR_MANAGER_DERIVE_FLAG_CONFIGURED_SCALE);
+
+  if (use_global_scale)
+    {
+      if (use_configured_scale)
+        global_scale = derive_configured_global_scale (manager);
+      else
+        global_scale = derive_calculated_global_scale (manager);
+    }
+
   for (l = manager->monitors; l; l = l->next)
     {
       MetaMonitor *monitor = l->data;
@@ -212,9 +291,21 @@ meta_monitor_manager_rebuild_logical_monitors_derived (MetaMonitorManager *manag
         }
       else
         {
+          int scale;
+
+          if (use_global_scale)
+            scale = global_scale;
+          else if (use_configured_scale)
+            scale = derive_scale_from_config (manager, &layout);
+          else
+            scale = calculate_monitor_scale (manager, monitor);
+
+          g_assert (scale > 0);
+
           logical_monitor = meta_logical_monitor_new_derived (manager,
                                                               monitor,
                                                               &layout,
+                                                              scale,
                                                               monitor_number);
           logical_monitors = g_list_append (logical_monitors, logical_monitor);
           monitor_number++;
@@ -323,7 +414,7 @@ meta_monitor_manager_get_supported_scales (MetaMonitorManager *manager,
   manager_class->get_supported_scales (manager, scales, n_scales);
 }
 
-static MetaMonitorManagerCapability
+MetaMonitorManagerCapability
 meta_monitor_manager_get_capabilities (MetaMonitorManager *manager)
 {
   MetaMonitorManagerClass *manager_class =
@@ -1563,6 +1654,13 @@ meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton,
                              g_variant_new_boolean (TRUE));
     }
 
+  if (capabilities & META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED)
+    {
+      g_variant_builder_add (&properties_builder, "{sv}",
+                             "global-scale-required",
+                             g_variant_new_boolean (TRUE));
+    }
+
   if (meta_monitor_manager_get_max_screen_size (manager,
                                                 &max_screen_width,
                                                 &max_screen_height))
@@ -1997,7 +2095,7 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
     }
 
   config = meta_monitors_config_new (logical_monitor_configs, layout_mode);
-  if (!meta_verify_monitors_config (config, &error))
+  if (!meta_verify_monitors_config (config, manager, &error))
     {
       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                              G_DBUS_ERROR_INVALID_ARGS,
@@ -2729,15 +2827,17 @@ meta_monitor_manager_update_monitor_modes_derived (MetaMonitorManager *manager)
 }
 
 void
-meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager)
+meta_monitor_manager_update_logical_state_derived (MetaMonitorManager          *manager,
+                                                   MetaMonitorManagerDeriveFlag flags)
 {
   manager->layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
 
-  meta_monitor_manager_rebuild_logical_monitors_derived (manager);
+  meta_monitor_manager_rebuild_logical_monitors_derived (manager, flags);
 }
 
 void
-meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
+meta_monitor_manager_rebuild_derived (MetaMonitorManager          *manager,
+                                      MetaMonitorManagerDeriveFlag flags)
 {
   GList *old_logical_monitors;
 
@@ -2748,7 +2848,7 @@ meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
 
   old_logical_monitors = manager->logical_monitors;
 
-  meta_monitor_manager_update_logical_state_derived (manager);
+  meta_monitor_manager_update_logical_state_derived (manager, flags);
 
   meta_monitor_manager_notify_monitors_changed (manager);
 
diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c
index 6000a77..1856d10 100644
--- a/src/backends/native/meta-monitor-manager-kms.c
+++ b/src/backends/native/meta-monitor-manager-kms.c
@@ -1259,9 +1259,16 @@ meta_monitor_manager_kms_ensure_initial_config (MetaMonitorManager *manager)
   config = meta_monitor_manager_ensure_configured (manager);
 
   if (meta_is_monitor_config_manager_enabled ())
-    meta_monitor_manager_update_logical_state (manager, config);
+    {
+      meta_monitor_manager_update_logical_state (manager, config);
+    }
   else
-    meta_monitor_manager_update_logical_state_derived (manager);
+    {
+      MetaMonitorManagerDeriveFlag flags =
+        META_MONITOR_MANAGER_DERIVE_FLAG_NONE;
+
+      meta_monitor_manager_update_logical_state_derived (manager, flags);
+    }
 }
 
 static void
@@ -1492,10 +1499,13 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
                                               MetaOutputInfo    **outputs,
                                               unsigned int        n_outputs)
 {
+  MetaMonitorManagerDeriveFlag flags =
+    META_MONITOR_MANAGER_DERIVE_FLAG_NONE;
+
   apply_crtc_assignments (manager, crtcs, n_crtcs, outputs, n_outputs);
 
   legacy_calculate_screen_size (manager);
-  meta_monitor_manager_rebuild_derived (manager);
+  meta_monitor_manager_rebuild_derived (manager, flags);
 }
 
 static void
diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
index 689a97e..4c41041 100644
--- a/src/backends/x11/meta-monitor-manager-xrandr.c
+++ b/src/backends/x11/meta-monitor-manager-xrandr.c
@@ -55,7 +55,7 @@
 #define DPI_FALLBACK 96.0
 
 static float supported_scales_xrandr[] = {
-  1.0
+  1.0, 2.0
 };
 
 struct _MetaMonitorManagerXrandr
@@ -68,6 +68,8 @@ struct _MetaMonitorManagerXrandr
   int rr_error_base;
   gboolean has_randr15;
 
+  xcb_timestamp_t last_xrandr_set_timestamp;
+
 #ifdef HAVE_XRANDR15
   GHashTable *tiled_monitor_atoms;
 #endif /* HAVE_XRANDR15 */
@@ -1071,6 +1073,7 @@ output_set_underscanning_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
 
 static gboolean
 xrandr_set_crtc_config (MetaMonitorManagerXrandr *manager_xrandr,
+                        gboolean                  save_timestamp,
                         xcb_randr_crtc_t          crtc,
                         xcb_timestamp_t           timestamp,
                         int                       x,
@@ -1107,13 +1110,141 @@ xrandr_set_crtc_config (MetaMonitorManagerXrandr *manager_xrandr,
       return FALSE;
     }
 
+  if (save_timestamp)
+    manager_xrandr->last_xrandr_set_timestamp = reply->timestamp;
+
   free (reply);
 
   return TRUE;
 }
 
+static gboolean
+is_crtc_assignment_changed (MetaCrtc      *crtc,
+                            MetaCrtcInfo **crtc_infos,
+                            unsigned int   n_crtc_infos)
+{
+  unsigned int i;
+
+  for (i = 0; i < n_crtc_infos; i++)
+    {
+      MetaCrtcInfo *crtc_info = crtc_infos[i];
+      unsigned int j;
+
+      if (crtc_info->crtc != crtc)
+        continue;
+
+      if (crtc->current_mode != crtc_info->mode)
+        return TRUE;
+
+      if (crtc->rect.x != crtc_info->x)
+        return TRUE;
+
+      if (crtc->rect.y != crtc_info->y)
+        return TRUE;
+
+      if (crtc->transform != crtc_info->transform)
+        return TRUE;
+
+      for (j = 0; j < crtc_info->outputs->len; j++)
+        {
+          MetaOutput *output = ((MetaOutput**) crtc_info->outputs->pdata)[j];
+
+          if (output->crtc != crtc)
+            return TRUE;
+        }
+
+      return FALSE;
+    }
+
+  return crtc->current_mode != NULL;
+}
+
+static gboolean
+is_output_assignment_changed (MetaOutput      *output,
+                              MetaCrtcInfo   **crtc_infos,
+                              unsigned int     n_crtc_infos,
+                              MetaOutputInfo **output_infos,
+                              unsigned int     n_output_infos)
+{
+  gboolean output_is_found = FALSE;
+  unsigned int i;
+
+  for (i = 0; i < n_output_infos; i++)
+    {
+      MetaOutputInfo *output_info = output_infos[i];
+
+      if (output_info->output != output)
+        continue;
+
+      if (output->is_primary != output_info->is_primary)
+        return TRUE;
+
+      if (output->is_presentation != output_info->is_presentation)
+        return TRUE;
+
+      if (output->is_underscanning != output_info->is_underscanning)
+        return TRUE;
+
+      output_is_found = TRUE;
+    }
+
+  if (!output_is_found)
+    return output->crtc != NULL;
+
+  for (i = 0; i < n_crtc_infos; i++)
+    {
+      MetaCrtcInfo *crtc_info = crtc_infos[i];
+      unsigned int j;
+
+      for (j = 0; j < crtc_info->outputs->len; j++)
+        {
+          MetaOutput *crtc_info_output =
+            ((MetaOutput**) crtc_info->outputs->pdata)[j];
+
+          if (crtc_info_output == output &&
+              crtc_info->crtc == output->crtc)
+            return FALSE;
+        }
+    }
+
+  return TRUE;
+}
+
+static gboolean
+is_assignments_changed (MetaMonitorManager *manager,
+                        MetaCrtcInfo      **crtc_infos,
+                        unsigned int        n_crtc_infos,
+                        MetaOutputInfo    **output_infos,
+                        unsigned int        n_output_infos)
+{
+  unsigned int i;
+
+  for (i = 0; i < manager->n_crtcs; i++)
+    {
+      MetaCrtc *crtc = &manager->crtcs[i];
+
+      if (is_crtc_assignment_changed (crtc, crtc_infos, n_crtc_infos))
+        return TRUE;
+    }
+
+  for (i = 0; i < manager->n_outputs; i++)
+    {
+      MetaOutput *output = &manager->outputs[i];
+
+      if (is_output_assignment_changed (output,
+                                        crtc_infos,
+                                        n_crtc_infos,
+                                        output_infos,
+                                        n_output_infos))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
 static void
 apply_crtc_assignments (MetaMonitorManager *manager,
+                        gboolean            save_timestamp,
                         MetaCrtcInfo      **crtcs,
                         unsigned int        n_crtcs,
                         MetaOutputInfo    **outputs,
@@ -1163,6 +1294,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
           crtc->rect.y + crtc->rect.height > height)
         {
           xrandr_set_crtc_config (manager_xrandr,
+                                  save_timestamp,
                                   (xcb_randr_crtc_t) crtc->crtc_id,
                                   XCB_CURRENT_TIME,
                                   0, 0, XCB_NONE,
@@ -1191,6 +1323,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
         continue;
 
       xrandr_set_crtc_config (manager_xrandr,
+                              save_timestamp,
                               (xcb_randr_crtc_t) crtc->crtc_id,
                               XCB_CURRENT_TIME,
                               0, 0, XCB_NONE,
@@ -1247,6 +1380,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 
           rotation = meta_monitor_transform_to_xrandr (crtc_info->transform);
           if (!xrandr_set_crtc_config (manager_xrandr,
+                                       save_timestamp,
                                        (xcb_randr_crtc_t) crtc->crtc_id,
                                        XCB_CURRENT_TIME,
                                        crtc_info->x, crtc_info->y,
@@ -1329,6 +1463,9 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 static void
 meta_monitor_manager_xrandr_ensure_initial_config (MetaMonitorManager *manager)
 {
+  MetaMonitorManagerDeriveFlag flags =
+    META_MONITOR_MANAGER_DERIVE_FLAG_NONE;
+
   meta_monitor_manager_ensure_configured (manager);
 
   /*
@@ -1338,7 +1475,10 @@ meta_monitor_manager_xrandr_ensure_initial_config (MetaMonitorManager *manager)
    */
   meta_monitor_manager_read_current_state (manager);
 
-  meta_monitor_manager_update_logical_state_derived (manager);
+  if (meta_is_monitor_config_manager_enabled ())
+    flags |= META_MONITOR_MANAGER_DERIVE_FLAG_CONFIGURED_SCALE;
+
+  meta_monitor_manager_update_logical_state_derived (manager, flags);
 }
 
 static gboolean
@@ -1352,7 +1492,10 @@ meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager      *mana
 
   if (!config)
     {
-      meta_monitor_manager_rebuild_derived (manager);
+      MetaMonitorManagerDeriveFlag flags =
+        META_MONITOR_MANAGER_DERIVE_FLAG_NONE;
+
+      meta_monitor_manager_rebuild_derived (manager, flags);
       return TRUE;
     }
 
@@ -1363,11 +1506,35 @@ meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager      *mana
 
   if (method != META_MONITORS_CONFIG_METHOD_VERIFY)
     {
-      apply_crtc_assignments (manager,
-                              (MetaCrtcInfo **) crtc_infos->pdata,
-                              crtc_infos->len,
-                              (MetaOutputInfo **) output_infos->pdata,
-                              output_infos->len);
+      /*
+       * If the assignment has not changed, we won't get any notification about
+       * any new configuration from the X server; but we still need to update
+       * our own configuration, as something not applicable in Xrandr might
+       * have changed locally, such as the logical monitors scale. This means we
+       * must check that our new assignment actually changes anything, otherwise
+       * just update the logical state.
+       */
+      if (is_assignments_changed (manager,
+                                  (MetaCrtcInfo **) crtc_infos->pdata,
+                                  crtc_infos->len,
+                                  (MetaOutputInfo **) output_infos->pdata,
+                                  output_infos->len))
+        {
+          apply_crtc_assignments (manager,
+                                  TRUE,
+                                  (MetaCrtcInfo **) crtc_infos->pdata,
+                                  crtc_infos->len,
+                                  (MetaOutputInfo **) output_infos->pdata,
+                                  output_infos->len);
+        }
+      else
+        {
+          MetaMonitorManagerDeriveFlag flags;
+
+          flags = (META_MONITOR_MANAGER_DERIVE_FLAG_NONE |
+                   META_MONITOR_MANAGER_DERIVE_FLAG_CONFIGURED_SCALE);
+          meta_monitor_manager_rebuild_derived (manager, flags);
+        }
     }
 
   g_ptr_array_free (crtc_infos, TRUE);
@@ -1383,7 +1550,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
                                                 MetaOutputInfo    **outputs,
                                                 unsigned int        n_outputs)
 {
-  apply_crtc_assignments (manager, crtcs, n_crtcs, outputs, n_outputs);
+  apply_crtc_assignments (manager, FALSE, crtcs, n_crtcs, outputs, n_outputs);
 }
 
 static void
@@ -1629,8 +1796,7 @@ meta_monitor_manager_xrandr_calculate_monitor_mode_scale (MetaMonitorManager *ma
                                                           MetaMonitor        *monitor,
                                                           MetaMonitorMode    *monitor_mode)
 {
-  /* X11 does not support anything other than scale 1. */
-  return 1;
+  return meta_monitor_calculate_mode_scale (monitor, monitor_mode);
 }
 
 static void
@@ -1645,7 +1811,8 @@ meta_monitor_manager_xrandr_get_supported_scales (MetaMonitorManager *manager,
 static MetaMonitorManagerCapability
 meta_monitor_manager_xrandr_get_capabilities (MetaMonitorManager *manager)
 {
-  return META_MONITOR_MANAGER_CAPABILITY_MIRRORING;
+  return (META_MONITOR_MANAGER_CAPABILITY_MIRRORING |
+          META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
 }
 
 static gboolean
@@ -1665,11 +1832,7 @@ meta_monitor_manager_xrandr_get_max_screen_size (MetaMonitorManager *manager,
 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;
+  return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
 }
 
 static void
@@ -1763,7 +1926,8 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
                                           XEvent                   *event)
 {
   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
-  gboolean hotplug;
+  gboolean is_hotplug;
+  gboolean is_our_configuration;
 
   if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
     return FALSE;
@@ -1772,16 +1936,24 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
 
   meta_monitor_manager_read_current_state (manager);
 
-  hotplug = manager_xrandr->resources->timestamp < manager_xrandr->resources->configTimestamp;
-  if (hotplug)
+
+  is_hotplug = (manager_xrandr->resources->timestamp <
+                manager_xrandr->resources->configTimestamp);
+  is_our_configuration = (manager_xrandr->resources->timestamp ==
+                          manager_xrandr->last_xrandr_set_timestamp);
+  if (is_hotplug)
     {
-      /* This is a hotplug event, so go ahead and build a new configuration. */
       meta_monitor_manager_on_hotplug (manager);
     }
   else
     {
-      /* Something else changed -- tell the world about it. */
-      meta_monitor_manager_rebuild_derived (manager);
+      MetaMonitorManagerDeriveFlag flags =
+        META_MONITOR_MANAGER_DERIVE_FLAG_NONE;
+
+      if (is_our_configuration)
+        flags |= META_MONITOR_MANAGER_DERIVE_FLAG_CONFIGURED_SCALE;
+
+      meta_monitor_manager_rebuild_derived (manager, flags);
     }
 
   return TRUE;
diff --git a/src/org.gnome.Mutter.DisplayConfig.xml b/src/org.gnome.Mutter.DisplayConfig.xml
index 30d2ead..fb1c6c4 100644
--- a/src/org.gnome.Mutter.DisplayConfig.xml
+++ b/src/org.gnome.Mutter.DisplayConfig.xml
@@ -401,6 +401,10 @@
        * "supports-changing-layout-mode" (b): True if the layout mode can be
                                               changed. Absence of this means the
                                               layout mode cannot be changed.
+       * "global-scale-required" (b): True if all the logical monitors must
+                                      always use the same scale. Absence of
+                                      this means logical monitor scales can
+                                      differ.
     -->
     <method name="GetCurrentState">
       <arg name="serial" direction="out" type="u" />
diff --git a/src/tests/meta-monitor-manager-test.c b/src/tests/meta-monitor-manager-test.c
index ed582f9..ca61514 100644
--- a/src/tests/meta-monitor-manager-test.c
+++ b/src/tests/meta-monitor-manager-test.c
@@ -123,9 +123,16 @@ meta_monitor_manager_test_ensure_initial_config (MetaMonitorManager *manager)
   config = meta_monitor_manager_ensure_configured (manager);
 
   if (meta_is_monitor_config_manager_enabled ())
-    meta_monitor_manager_update_logical_state (manager, config);
+    {
+      meta_monitor_manager_update_logical_state (manager, config);
+    }
   else
-    meta_monitor_manager_update_logical_state_derived (manager);
+    {
+      MetaMonitorManagerDeriveFlag flags =
+        META_MONITOR_MANAGER_DERIVE_FLAG_NONE;
+
+      meta_monitor_manager_update_logical_state_derived (manager, flags);
+    }
 }
 
 static void
@@ -279,9 +286,16 @@ meta_monitor_manager_test_apply_monitors_config (MetaMonitorManager      *manage
       manager->screen_height = 1;
 
       if (meta_is_stage_views_enabled ())
-        meta_monitor_manager_rebuild (manager, NULL);
+        {
+          meta_monitor_manager_rebuild (manager, NULL);
+        }
       else
-        meta_monitor_manager_rebuild_derived (manager);
+        {
+          MetaMonitorManagerDeriveFlag flags =
+            META_MONITOR_MANAGER_DERIVE_FLAG_CONFIGURED_SCALE;
+
+          meta_monitor_manager_rebuild_derived (manager, flags);
+        }
 
       return TRUE;
     }
@@ -311,9 +325,16 @@ meta_monitor_manager_test_apply_monitors_config (MetaMonitorManager      *manage
   update_screen_size (manager, config);
 
   if (meta_is_stage_views_enabled ())
-    meta_monitor_manager_rebuild (manager, config);
+    {
+      meta_monitor_manager_rebuild (manager, config);
+    }
   else
-    meta_monitor_manager_rebuild_derived (manager);
+    {
+      MetaMonitorManagerDeriveFlag flags =
+        META_MONITOR_MANAGER_DERIVE_FLAG_CONFIGURED_SCALE;
+
+      meta_monitor_manager_rebuild_derived (manager, flags);
+    }
 
   return TRUE;
 }
@@ -343,9 +364,12 @@ meta_monitor_manager_test_apply_configuration (MetaMonitorManager *manager,
                                                MetaOutputInfo    **outputs,
                                                unsigned int        n_outputs)
 {
+  MetaMonitorManagerDeriveFlag flags =
+    META_MONITOR_MANAGER_DERIVE_FLAG_NONE;
+
   apply_crtc_assignments (manager, crtcs, n_crtcs, outputs, n_outputs);
   legacy_calculate_screen_size (manager);
-  meta_monitor_manager_rebuild_derived (manager);
+  meta_monitor_manager_rebuild_derived (manager, flags);
 }
 
 static void



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