f7d48e
From f1c80e0962c36b3e7e3d304ec7abec0c69f5523b Mon Sep 17 00:00:00 2001
f7d48e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
f7d48e
Date: Fri, 14 Jan 2022 22:11:17 +0100
f7d48e
Subject: [PATCH 1/9] test/utils: Add helper to set custom monitors config
f7d48e
f7d48e
Make the existing implementation a wrapper to avoid changing monitor
f7d48e
config tests.
f7d48e
f7d48e
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2237>
f7d48e
f7d48e
Cherry-picked from 57d1d82ead6392a104a9e9d6c7f1f4f14ad54e48
f7d48e
---
f7d48e
 src/tests/monitor-test-utils.c | 18 +-----------------
f7d48e
 src/tests/test-utils.c         | 23 +++++++++++++++++++++++
f7d48e
 src/tests/test-utils.h         |  3 +++
f7d48e
 3 files changed, 27 insertions(+), 17 deletions(-)
f7d48e
f7d48e
diff --git a/src/tests/monitor-test-utils.c b/src/tests/monitor-test-utils.c
f7d48e
index 705201810abc..98958a5042ee 100644
f7d48e
--- a/src/tests/monitor-test-utils.c
f7d48e
+++ b/src/tests/monitor-test-utils.c
f7d48e
@@ -39,23 +39,7 @@ test_get_gpu (void)
f7d48e
 void
f7d48e
 set_custom_monitor_config (const char *filename)
f7d48e
 {
f7d48e
-  MetaBackend *backend = meta_get_backend ();
f7d48e
-  MetaMonitorManager *monitor_manager =
f7d48e
-    meta_backend_get_monitor_manager (backend);
f7d48e
-  MetaMonitorConfigManager *config_manager = monitor_manager->config_manager;
f7d48e
-  MetaMonitorConfigStore *config_store;
f7d48e
-  GError *error = NULL;
f7d48e
-  const char *path;
f7d48e
-
f7d48e
-  g_assert_nonnull (config_manager);
f7d48e
-
f7d48e
-  config_store = meta_monitor_config_manager_get_store (config_manager);
f7d48e
-
f7d48e
-  path = g_test_get_filename (G_TEST_DIST, "tests", "monitor-configs",
f7d48e
-                              filename, NULL);
f7d48e
-  if (!meta_monitor_config_store_set_custom (config_store, path, NULL,
f7d48e
-                                             &error))
f7d48e
-    g_error ("Failed to set custom config: %s", error->message);
f7d48e
+  meta_set_custom_monitor_config (meta_get_backend (), filename);
f7d48e
 }
f7d48e
 
f7d48e
 char *
f7d48e
diff --git a/src/tests/test-utils.c b/src/tests/test-utils.c
f7d48e
index ca332a0b918e..bf326ef27105 100644
f7d48e
--- a/src/tests/test-utils.c
f7d48e
+++ b/src/tests/test-utils.c
f7d48e
@@ -24,6 +24,7 @@
f7d48e
 #include <gio/gio.h>
f7d48e
 #include <string.h>
f7d48e
 
f7d48e
+#include "backends/meta-monitor-config-store.h"
f7d48e
 #include "core/display-private.h"
f7d48e
 #include "core/window-private.h"
f7d48e
 #include "wayland/meta-wayland.h"
f7d48e
@@ -575,3 +576,25 @@ test_wait_for_x11_display (void)
f7d48e
 
f7d48e
   g_assert_nonnull (display->x11_display);
f7d48e
 }
f7d48e
+
f7d48e
+void
f7d48e
+meta_set_custom_monitor_config (MetaBackend *backend,
f7d48e
+                                const char  *filename)
f7d48e
+{
f7d48e
+  MetaMonitorManager *monitor_manager =
f7d48e
+    meta_backend_get_monitor_manager (backend);
f7d48e
+  MetaMonitorConfigManager *config_manager = monitor_manager->config_manager;
f7d48e
+  MetaMonitorConfigStore *config_store;
f7d48e
+  GError *error = NULL;
f7d48e
+  const char *path;
f7d48e
+
f7d48e
+  g_assert_nonnull (config_manager);
f7d48e
+
f7d48e
+  config_store = meta_monitor_config_manager_get_store (config_manager);
f7d48e
+
f7d48e
+  path = g_test_get_filename (G_TEST_DIST, "tests", "monitor-configs",
f7d48e
+                              filename, NULL);
f7d48e
+  if (!meta_monitor_config_store_set_custom (config_store, path, NULL,
f7d48e
+                                             &error))
f7d48e
+    g_error ("Failed to set custom config: %s", error->message);
f7d48e
+}
f7d48e
diff --git a/src/tests/test-utils.h b/src/tests/test-utils.h
f7d48e
index 1710b98e0e80..c8a0d16aebec 100644
f7d48e
--- a/src/tests/test-utils.h
f7d48e
+++ b/src/tests/test-utils.h
f7d48e
@@ -86,4 +86,7 @@ const char * test_get_plugin_name (void);
f7d48e
 
f7d48e
 void test_wait_for_x11_display (void);
f7d48e
 
f7d48e
+void meta_set_custom_monitor_config (MetaBackend *backend,
f7d48e
+                                     const char  *filename);
f7d48e
+
f7d48e
 #endif /* TEST_UTILS_H */
f7d48e
-- 
f7d48e
2.33.1
f7d48e
f7d48e
f7d48e
From 9fdf146e7bf04b71dafd67388345b694e8bfac77 Mon Sep 17 00:00:00 2001
f7d48e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
f7d48e
Date: Fri, 14 Jan 2022 22:12:36 +0100
f7d48e
Subject: [PATCH 2/9] tests/utils: Add meta_wait_for_paint() helper
f7d48e
f7d48e
This function queues a full stage redraw, then waits for every view to
f7d48e
receive the "presented" signal before returning.
f7d48e
f7d48e
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2237>
f7d48e
(cherry picked from commit d84f7971e476a1e2d727310d9a33ac4080137f58)
f7d48e
---
f7d48e
 src/tests/test-utils.c | 27 +++++++++++++++++++++++++++
f7d48e
 src/tests/test-utils.h |  2 ++
f7d48e
 2 files changed, 29 insertions(+)
f7d48e
f7d48e
diff --git a/src/tests/test-utils.c b/src/tests/test-utils.c
f7d48e
index bf326ef27105..bee6aa102c0e 100644
f7d48e
--- a/src/tests/test-utils.c
f7d48e
+++ b/src/tests/test-utils.c
f7d48e
@@ -598,3 +598,30 @@ meta_set_custom_monitor_config (MetaBackend *backend,
f7d48e
                                              &error))
f7d48e
     g_error ("Failed to set custom config: %s", error->message);
f7d48e
 }
f7d48e
+
f7d48e
+static void
f7d48e
+on_view_presented (ClutterStage      *stage,
f7d48e
+                   ClutterStageView  *view,
f7d48e
+                   ClutterFrameInfo  *frame_info,
f7d48e
+                   GList            **presented_views)
f7d48e
+{
f7d48e
+  *presented_views = g_list_remove (*presented_views, view);
f7d48e
+}
f7d48e
+
f7d48e
+void
f7d48e
+meta_wait_for_paint (MetaBackend *backend)
f7d48e
+{
f7d48e
+  ClutterActor *stage = meta_backend_get_stage (backend);
f7d48e
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
f7d48e
+  GList *views;
f7d48e
+  gulong handler_id;
f7d48e
+
f7d48e
+  clutter_actor_queue_redraw (stage);
f7d48e
+
f7d48e
+  views = g_list_copy (meta_renderer_get_views (renderer));
f7d48e
+  handler_id = g_signal_connect (stage, "presented",
f7d48e
+                                 G_CALLBACK (on_view_presented), &views);
f7d48e
+  while (views)
f7d48e
+    g_main_context_iteration (NULL, TRUE);
f7d48e
+  g_signal_handler_disconnect (stage, handler_id);
f7d48e
+}
f7d48e
diff --git a/src/tests/test-utils.h b/src/tests/test-utils.h
f7d48e
index c8a0d16aebec..4b6aa34e8998 100644
f7d48e
--- a/src/tests/test-utils.h
f7d48e
+++ b/src/tests/test-utils.h
f7d48e
@@ -89,4 +89,6 @@ void test_wait_for_x11_display (void);
f7d48e
 void meta_set_custom_monitor_config (MetaBackend *backend,
f7d48e
                                      const char  *filename);
f7d48e
 
f7d48e
+void meta_wait_for_paint (MetaBackend *backend);
f7d48e
+
f7d48e
 #endif /* TEST_UTILS_H */
f7d48e
-- 
f7d48e
2.33.1
f7d48e
f7d48e
f7d48e
From 570c234f6e4cab567cd329d45347565100d5494d Mon Sep 17 00:00:00 2001
f7d48e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
f7d48e
Date: Thu, 30 Sep 2021 08:59:03 +0200
f7d48e
Subject: [PATCH 3/9] monitor-config-store: Make parsing a bit more forgiving
f7d48e
f7d48e
Allow unknown XML elements inside <monitors>. This makes extending in
f7d48e
the future easier.
f7d48e
f7d48e
(cherry picked from commit 3cd666c657fa716f06dee69df59356b53b6c5d72)
f7d48e
---
f7d48e
 src/backends/meta-monitor-config-store.c      | 54 +++++++++++++++---
f7d48e
 .../monitor-configs/unknown-elements.xml      | 31 ++++++++++
f7d48e
 src/tests/monitor-store-unit-tests.c          | 56 +++++++++++++++++++
f7d48e
 3 files changed, 133 insertions(+), 8 deletions(-)
f7d48e
 create mode 100644 src/tests/monitor-configs/unknown-elements.xml
f7d48e
f7d48e
diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
f7d48e
index 4dd357a15164..3c69157eae40 100644
f7d48e
--- a/src/backends/meta-monitor-config-store.c
f7d48e
+++ b/src/backends/meta-monitor-config-store.c
f7d48e
@@ -136,6 +136,7 @@ G_DEFINE_QUARK (meta-monitor-config-store-error-quark,
f7d48e
 typedef enum
f7d48e
 {
f7d48e
   STATE_INITIAL,
f7d48e
+  STATE_UNKNOWN,
f7d48e
   STATE_MONITORS,
f7d48e
   STATE_CONFIGURATION,
f7d48e
   STATE_MIGRATED,
f7d48e
@@ -180,12 +181,28 @@ typedef struct
f7d48e
   MetaLogicalMonitorConfig *current_logical_monitor_config;
f7d48e
   GList *current_disabled_monitor_specs;
f7d48e
 
f7d48e
+  ParserState unknown_state_root;
f7d48e
+  int unknown_level;
f7d48e
+
f7d48e
   MetaMonitorsConfigFlag extra_config_flags;
f7d48e
 } ConfigParser;
f7d48e
 
f7d48e
 G_DEFINE_TYPE (MetaMonitorConfigStore, meta_monitor_config_store,
f7d48e
                G_TYPE_OBJECT)
f7d48e
 
f7d48e
+static void
f7d48e
+enter_unknown_element (ConfigParser *parser,
f7d48e
+                       const char   *element_name,
f7d48e
+                       const char   *root_element_name,
f7d48e
+                       ParserState   root_state)
f7d48e
+{
f7d48e
+  parser->state = STATE_UNKNOWN;
f7d48e
+  parser->unknown_level = 1;
f7d48e
+  parser->unknown_state_root = root_state;
f7d48e
+  g_warning ("Unknown element <%s> under <%s>, ignoring",
f7d48e
+             element_name, root_element_name);
f7d48e
+}
f7d48e
+
f7d48e
 static void
f7d48e
 handle_start_element (GMarkupParseContext  *context,
f7d48e
                       const char           *element_name,
f7d48e
@@ -242,8 +259,8 @@ handle_start_element (GMarkupParseContext  *context,
f7d48e
       {
f7d48e
         if (!g_str_equal (element_name, "configuration"))
f7d48e
           {
f7d48e
-            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
f7d48e
-                         "Invalid toplevel element '%s'", element_name);
f7d48e
+            enter_unknown_element (parser, element_name,
f7d48e
+                                   "monitors", STATE_MONITORS);
f7d48e
             return;
f7d48e
           }
f7d48e
 
f7d48e
@@ -253,6 +270,13 @@ handle_start_element (GMarkupParseContext  *context,
f7d48e
         return;
f7d48e
       }
f7d48e
 
f7d48e
+    case STATE_UNKNOWN:
f7d48e
+      {
f7d48e
+        parser->unknown_level++;
f7d48e
+
f7d48e
+        return;
f7d48e
+      }
f7d48e
+
f7d48e
     case STATE_CONFIGURATION:
f7d48e
       {
f7d48e
         if (g_str_equal (element_name, "logicalmonitor"))
f7d48e
@@ -274,9 +298,8 @@ handle_start_element (GMarkupParseContext  *context,
f7d48e
           }
f7d48e
         else
f7d48e
           {
f7d48e
-            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
f7d48e
-                         "Invalid configuration element '%s'", element_name);
f7d48e
-            return;
f7d48e
+            enter_unknown_element (parser, element_name,
f7d48e
+                                   "configuration", STATE_CONFIGURATION);
f7d48e
           }
f7d48e
 
f7d48e
         return;
f7d48e
@@ -323,9 +346,8 @@ handle_start_element (GMarkupParseContext  *context,
f7d48e
           }
f7d48e
         else
f7d48e
           {
f7d48e
-            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
f7d48e
-                         "Invalid monitor logicalmonitor element '%s'", element_name);
f7d48e
-            return;
f7d48e
+            enter_unknown_element (parser, element_name,
f7d48e
+                                   "logicalmonitor", STATE_LOGICAL_MONITOR);
f7d48e
           }
f7d48e
 
f7d48e
         return;
f7d48e
@@ -793,6 +815,18 @@ handle_end_element (GMarkupParseContext  *context,
f7d48e
         return;
f7d48e
       }
f7d48e
 
f7d48e
+    case STATE_UNKNOWN:
f7d48e
+      {
f7d48e
+        parser->unknown_level--;
f7d48e
+        if (parser->unknown_level == 0)
f7d48e
+          {
f7d48e
+            g_assert (parser->unknown_state_root >= 0);
f7d48e
+            parser->state = parser->unknown_state_root;
f7d48e
+            parser->unknown_state_root = -1;
f7d48e
+          }
f7d48e
+        return;
f7d48e
+      }
f7d48e
+
f7d48e
     case STATE_MONITORS:
f7d48e
       {
f7d48e
         g_assert (g_str_equal (element_name, "monitors"));
f7d48e
@@ -912,6 +946,9 @@ handle_text (GMarkupParseContext *context,
f7d48e
 
f7d48e
   switch (parser->state)
f7d48e
     {
f7d48e
+    case STATE_UNKNOWN:
f7d48e
+      return;
f7d48e
+
f7d48e
     case STATE_INITIAL:
f7d48e
     case STATE_MONITORS:
f7d48e
     case STATE_CONFIGURATION:
f7d48e
@@ -1099,6 +1136,7 @@ read_config_file (MetaMonitorConfigStore  *config_store,
f7d48e
     .state = STATE_INITIAL,
f7d48e
     .config_store = config_store,
f7d48e
     .extra_config_flags = extra_config_flags,
f7d48e
+    .unknown_state_root = -1,
f7d48e
   };
f7d48e
 
f7d48e
   parse_context = g_markup_parse_context_new (&config_parser,
f7d48e
diff --git a/src/tests/monitor-configs/unknown-elements.xml b/src/tests/monitor-configs/unknown-elements.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..f81be95dd9df
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/unknown-elements.xml
f7d48e
@@ -0,0 +1,31 @@
f7d48e
+<monitors version="2">
f7d48e
+  <unknownundermonitors>
f7d48e
+    <anotherlevel>text</anotherlevel>
f7d48e
+  </unknownundermonitors>
f7d48e
+  <configuration>
f7d48e
+    <unknownunderconfiguration>
f7d48e
+      <anotherlevel>text</anotherlevel>
f7d48e
+    </unknownunderconfiguration>
f7d48e
+    <logicalmonitor>
f7d48e
+      <unknownunderlogicalmonitor>
f7d48e
+	<anotherlevel>text</anotherlevel>
f7d48e
+      </unknownunderlogicalmonitor>
f7d48e
+      <x>0</x>
f7d48e
+      <y>0</y>
f7d48e
+      <primary>yes</primary>
f7d48e
+      <monitor>
f7d48e
+	<monitorspec>
f7d48e
+	  <connector>DP-1</connector>
f7d48e
+	  <vendor>MetaProduct's Inc.</vendor>
f7d48e
+	  <product>MetaMonitor</product>
f7d48e
+	  <serial>0x123456</serial>
f7d48e
+	</monitorspec>
f7d48e
+	<mode>
f7d48e
+	  <width>1920</width>
f7d48e
+	  <height>1080</height>
f7d48e
+	  <rate>60.000495910644531</rate>
f7d48e
+	</mode>
f7d48e
+      </monitor>
f7d48e
+    </logicalmonitor>
f7d48e
+  </configuration>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-store-unit-tests.c b/src/tests/monitor-store-unit-tests.c
f7d48e
index b9d5622b7ae3..64618174f4b3 100644
f7d48e
--- a/src/tests/monitor-store-unit-tests.c
f7d48e
+++ b/src/tests/monitor-store-unit-tests.c
f7d48e
@@ -836,6 +836,60 @@ meta_test_monitor_store_interlaced (void)
f7d48e
   check_monitor_store_configurations (&expect);
f7d48e
 }
f7d48e
 
f7d48e
+static void
f7d48e
+meta_test_monitor_store_unknown_elements (void)
f7d48e
+{
f7d48e
+  MonitorStoreTestExpect expect = {
f7d48e
+    .configurations = {
f7d48e
+      {
f7d48e
+        .logical_monitors = {
f7d48e
+          {
f7d48e
+            .layout = {
f7d48e
+              .x = 0,
f7d48e
+              .y = 0,
f7d48e
+              .width = 1920,
f7d48e
+              .height = 1080
f7d48e
+            },
f7d48e
+            .scale = 1,
f7d48e
+            .is_primary = TRUE,
f7d48e
+            .is_presentation = FALSE,
f7d48e
+            .monitors = {
f7d48e
+              {
f7d48e
+                .connector = "DP-1",
f7d48e
+                .vendor = "MetaProduct's Inc.",
f7d48e
+                .product = "MetaMonitor",
f7d48e
+                .serial = "0x123456",
f7d48e
+                .mode = {
f7d48e
+                  .width = 1920,
f7d48e
+                  .height = 1080,
f7d48e
+                  .refresh_rate = 60.000495910644531
f7d48e
+                }
f7d48e
+              }
f7d48e
+            },
f7d48e
+            .n_monitors = 1,
f7d48e
+          }
f7d48e
+        },
f7d48e
+        .n_logical_monitors = 1
f7d48e
+      }
f7d48e
+    },
f7d48e
+    .n_configurations = 1
f7d48e
+  };
f7d48e
+
f7d48e
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
f7d48e
+                         "Unknown element <unknownundermonitors> "
f7d48e
+                         "under <monitors>, ignoring");
f7d48e
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
f7d48e
+                         "Unknown element <unknownunderconfiguration> "
f7d48e
+                         "under <configuration>, ignoring");
f7d48e
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
f7d48e
+                         "Unknown element <unknownunderlogicalmonitor> "
f7d48e
+                         "under <logicalmonitor>, ignoring");
f7d48e
+  set_custom_monitor_config ("unknown-elements.xml");
f7d48e
+  g_test_assert_expected_messages ();
f7d48e
+
f7d48e
+  check_monitor_store_configurations (&expect);
f7d48e
+}
f7d48e
+
f7d48e
 void
f7d48e
 init_monitor_store_tests (void)
f7d48e
 {
f7d48e
@@ -861,4 +915,6 @@ init_monitor_store_tests (void)
f7d48e
                    meta_test_monitor_store_second_rotated);
f7d48e
   g_test_add_func ("/backends/monitor-store/interlaced",
f7d48e
                    meta_test_monitor_store_interlaced);
f7d48e
+  g_test_add_func ("/backends/monitor-store/unknown-elements",
f7d48e
+                   meta_test_monitor_store_unknown_elements);
f7d48e
 }
f7d48e
-- 
f7d48e
2.33.1
f7d48e
f7d48e
f7d48e
From 48a259017f0f59abb80fa6fe7c9d6b864f129267 Mon Sep 17 00:00:00 2001
f7d48e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
f7d48e
Date: Fri, 24 Sep 2021 16:29:47 +0200
f7d48e
Subject: [PATCH 4/9] monitor-config-store: Fix incorrect string comparison
f7d48e
 with empty string
f7d48e
f7d48e
strncmp() always return 0 if the passed length is 0. What this means is
f7d48e
that whatever the first string check happens to be, if the parsed XML
f7d48e
cdata was empty (e.g. if we got <element></element>), the first
f7d48e
condition would evaluate to true, which is rather unexpected.
f7d48e
f7d48e
Fix this by making sure the string length is correct first. Also move it
f7d48e
into a helper so we don't need to repeat the same strlen() check every
f7d48e
time.
f7d48e
f7d48e
(cherry picked from commit f798e49502313dd3e7dd67143513a7a6a91b49f8)
f7d48e
---
f7d48e
 src/backends/meta-monitor-config-store.c | 25 +++++++++++++++++-------
f7d48e
 1 file changed, 18 insertions(+), 7 deletions(-)
f7d48e
f7d48e
diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
f7d48e
index 3c69157eae40..d2572fa06ab0 100644
f7d48e
--- a/src/backends/meta-monitor-config-store.c
f7d48e
+++ b/src/backends/meta-monitor-config-store.c
f7d48e
@@ -190,6 +190,17 @@ typedef struct
f7d48e
 G_DEFINE_TYPE (MetaMonitorConfigStore, meta_monitor_config_store,
f7d48e
                G_TYPE_OBJECT)
f7d48e
 
f7d48e
+static gboolean
f7d48e
+text_equals (const char *text,
f7d48e
+             int         len,
f7d48e
+             const char *expect)
f7d48e
+{
f7d48e
+  if (strlen (expect) != len)
f7d48e
+    return FALSE;
f7d48e
+
f7d48e
+  return strncmp (text, expect, len) == 0;
f7d48e
+}
f7d48e
+
f7d48e
 static void
f7d48e
 enter_unknown_element (ConfigParser *parser,
f7d48e
                        const char   *element_name,
f7d48e
@@ -904,12 +915,12 @@ read_bool (const char  *text,
f7d48e
            gboolean    *out_value,
f7d48e
            GError     **error)
f7d48e
 {
f7d48e
-  if (strncmp (text, "no", text_len) == 0)
f7d48e
+  if (text_equals (text, text_len, "no"))
f7d48e
     {
f7d48e
       *out_value = FALSE;
f7d48e
       return TRUE;
f7d48e
     }
f7d48e
-  else if (strncmp (text, "yes", text_len) == 0)
f7d48e
+  else if (text_equals (text, text_len, "yes"))
f7d48e
     {
f7d48e
       *out_value = TRUE;
f7d48e
       return TRUE;
f7d48e
@@ -1039,13 +1050,13 @@ handle_text (GMarkupParseContext *context,
f7d48e
 
f7d48e
     case STATE_TRANSFORM_ROTATION:
f7d48e
       {
f7d48e
-        if (strncmp (text, "normal", text_len) == 0)
f7d48e
+        if (text_equals (text, text_len, "normal"))
f7d48e
           parser->current_transform = META_MONITOR_TRANSFORM_NORMAL;
f7d48e
-        else if (strncmp (text, "left", text_len) == 0)
f7d48e
+        else if (text_equals (text, text_len, "left"))
f7d48e
           parser->current_transform = META_MONITOR_TRANSFORM_90;
f7d48e
-        else if (strncmp (text, "upside_down", text_len) == 0)
f7d48e
+        else if (text_equals (text, text_len, "upside_down"))
f7d48e
           parser->current_transform = META_MONITOR_TRANSFORM_180;
f7d48e
-        else if (strncmp (text, "right", text_len) == 0)
f7d48e
+        else if (text_equals (text, text_len, "right"))
f7d48e
           parser->current_transform = META_MONITOR_TRANSFORM_270;
f7d48e
         else
f7d48e
           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
f7d48e
@@ -1088,7 +1099,7 @@ handle_text (GMarkupParseContext *context,
f7d48e
 
f7d48e
     case STATE_MONITOR_MODE_FLAG:
f7d48e
       {
f7d48e
-        if (strncmp (text, "interlace", text_len) == 0)
f7d48e
+        if (text_equals (text, text_len, "interlace"))
f7d48e
           {
f7d48e
             parser->current_monitor_mode_spec->flags |=
f7d48e
               META_CRTC_MODE_FLAG_INTERLACE;
f7d48e
-- 
f7d48e
2.33.1
f7d48e
f7d48e
f7d48e
From a67835d2a9f41194d29089e8b4deb0d2af05203a Mon Sep 17 00:00:00 2001
f7d48e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
f7d48e
Date: Mon, 17 Jan 2022 11:45:53 +0100
f7d48e
Subject: [PATCH 5/9] monitor-config-store: Add way to define config store
f7d48e
 loading policy
f7d48e
f7d48e
This adds a way to define a way, at the system level, to define a policy
f7d48e
of how monitor configuration files are loaded.
f7d48e
f7d48e
The intended use case is to e.g. either prefer system level monitor
f7d48e
configurations before user levels, or only allow system level
f7d48e
configurations.
f7d48e
f7d48e
Examples:
f7d48e
f7d48e
Prefer system over user level configurations:
f7d48e
f7d48e
    <monitors version="2">
f7d48e
      <policy>
f7d48e
        <stores>
f7d48e
          <store>system</store>
f7d48e
          <store>user</store>
f7d48e
        </stores>
f7d48e
      </policy>
f7d48e
      <configuration>
f7d48e
        ...
f7d48e
      </configuration>
f7d48e
    </monitors>
f7d48e
f7d48e
Only allow system level configurations:
f7d48e
f7d48e
    <monitors version="2">
f7d48e
      <policy>
f7d48e
        <stores>
f7d48e
          <store>system</store>
f7d48e
        </stores>
f7d48e
      </policy>
f7d48e
      <configuration>
f7d48e
        ...
f7d48e
      </configuration>
f7d48e
    </monitors>
f7d48e
f7d48e
(cherry picked from commit b747884c1eaf309bb2d9395a655c85c968bd1829)
f7d48e
---
f7d48e
 src/backends/meta-backend-types.h             |   2 +
f7d48e
 src/backends/meta-monitor-config-manager.h    |   4 +-
f7d48e
 src/backends/meta-monitor-config-store.c      | 421 ++++++++++++++----
f7d48e
 src/backends/meta-monitor-config-store.h      |  21 +-
f7d48e
 .../monitor-config-migration-unit-tests.c     |   1 +
f7d48e
 src/tests/monitor-configs/policy.xml          |  27 ++
f7d48e
 src/tests/monitor-store-unit-tests.c          |  33 ++
f7d48e
 src/tests/monitor-test-utils.c                |  16 +-
f7d48e
 src/tests/monitor-test-utils.h                |   2 +
f7d48e
 src/tests/monitor-unit-tests.c                |   3 +
f7d48e
 src/tests/test-utils.c                        |   8 +-
f7d48e
 src/tests/test-utils.h                        |   6 +-
f7d48e
 12 files changed, 450 insertions(+), 94 deletions(-)
f7d48e
 create mode 100644 src/tests/monitor-configs/policy.xml
f7d48e
f7d48e
diff --git a/src/backends/meta-backend-types.h b/src/backends/meta-backend-types.h
f7d48e
index eae62c02f244..5133ccb6131d 100644
f7d48e
--- a/src/backends/meta-backend-types.h
f7d48e
+++ b/src/backends/meta-backend-types.h
f7d48e
@@ -29,6 +29,8 @@ typedef struct _MetaMonitorConfigManager MetaMonitorConfigManager;
f7d48e
 typedef struct _MetaMonitorConfigStore MetaMonitorConfigStore;
f7d48e
 typedef struct _MetaMonitorsConfig MetaMonitorsConfig;
f7d48e
 
f7d48e
+typedef enum _MetaMonitorsConfigFlag MetaMonitorsConfigFlag;
f7d48e
+
f7d48e
 typedef struct _MetaMonitor MetaMonitor;
f7d48e
 typedef struct _MetaMonitorNormal MetaMonitorNormal;
f7d48e
 typedef struct _MetaMonitorTiled MetaMonitorTiled;
f7d48e
diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
f7d48e
index 641ed1bc1afb..a35b3e2e1f95 100644
f7d48e
--- a/src/backends/meta-monitor-config-manager.h
f7d48e
+++ b/src/backends/meta-monitor-config-manager.h
f7d48e
@@ -51,12 +51,12 @@ typedef struct _MetaMonitorsConfigKey
f7d48e
   GList *monitor_specs;
f7d48e
 } MetaMonitorsConfigKey;
f7d48e
 
f7d48e
-typedef enum _MetaMonitorsConfigFlag
f7d48e
+enum _MetaMonitorsConfigFlag
f7d48e
 {
f7d48e
   META_MONITORS_CONFIG_FLAG_NONE = 0,
f7d48e
   META_MONITORS_CONFIG_FLAG_MIGRATED = (1 << 0),
f7d48e
   META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG = (1 << 1),
f7d48e
-} MetaMonitorsConfigFlag;
f7d48e
+};
f7d48e
 
f7d48e
 struct _MetaMonitorsConfig
f7d48e
 {
f7d48e
diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
f7d48e
index d2572fa06ab0..93a494c79b80 100644
f7d48e
--- a/src/backends/meta-monitor-config-store.c
f7d48e
+++ b/src/backends/meta-monitor-config-store.c
f7d48e
@@ -120,6 +120,9 @@ struct _MetaMonitorConfigStore
f7d48e
   GFile *user_file;
f7d48e
   GFile *custom_read_file;
f7d48e
   GFile *custom_write_file;
f7d48e
+
f7d48e
+  gboolean has_stores_policy;
f7d48e
+  GList *stores_policy;
f7d48e
 };
f7d48e
 
f7d48e
 #define META_MONITOR_CONFIG_STORE_ERROR (meta_monitor_config_store_error_quark ())
f7d48e
@@ -162,12 +165,18 @@ typedef enum
f7d48e
   STATE_MONITOR_MODE_FLAG,
f7d48e
   STATE_MONITOR_UNDERSCANNING,
f7d48e
   STATE_DISABLED,
f7d48e
+  STATE_POLICY,
f7d48e
+  STATE_STORES,
f7d48e
+  STATE_STORE,
f7d48e
 } ParserState;
f7d48e
 
f7d48e
 typedef struct
f7d48e
 {
f7d48e
   ParserState state;
f7d48e
   MetaMonitorConfigStore *config_store;
f7d48e
+  GFile *file;
f7d48e
+
f7d48e
+  GHashTable *pending_configs;
f7d48e
 
f7d48e
   ParserState monitor_spec_parent_state;
f7d48e
 
f7d48e
@@ -180,6 +189,10 @@ typedef struct
f7d48e
   MetaMonitorConfig *current_monitor_config;
f7d48e
   MetaLogicalMonitorConfig *current_logical_monitor_config;
f7d48e
   GList *current_disabled_monitor_specs;
f7d48e
+  gboolean seen_policy;
f7d48e
+  gboolean seen_stores;
f7d48e
+  MetaConfigStore pending_store;
f7d48e
+  GList *stores;
f7d48e
 
f7d48e
   ParserState unknown_state_root;
f7d48e
   int unknown_level;
f7d48e
@@ -268,16 +281,31 @@ handle_start_element (GMarkupParseContext  *context,
f7d48e
 
f7d48e
     case STATE_MONITORS:
f7d48e
       {
f7d48e
-        if (!g_str_equal (element_name, "configuration"))
f7d48e
+        if (g_str_equal (element_name, "configuration"))
f7d48e
+          {
f7d48e
+            parser->state = STATE_CONFIGURATION;
f7d48e
+            parser->current_was_migrated = FALSE;
f7d48e
+          }
f7d48e
+        else if (g_str_equal (element_name, "policy"))
f7d48e
+          {
f7d48e
+            if (parser->seen_policy)
f7d48e
+              {
f7d48e
+                g_set_error (error,
f7d48e
+                             G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
f7d48e
+                             "Multiple policy definitions");
f7d48e
+                return;
f7d48e
+              }
f7d48e
+
f7d48e
+            parser->seen_policy = TRUE;
f7d48e
+            parser->state = STATE_POLICY;
f7d48e
+          }
f7d48e
+        else
f7d48e
           {
f7d48e
             enter_unknown_element (parser, element_name,
f7d48e
                                    "monitors", STATE_MONITORS);
f7d48e
             return;
f7d48e
           }
f7d48e
 
f7d48e
-        parser->state = STATE_CONFIGURATION;
f7d48e
-        parser->current_was_migrated = FALSE;
f7d48e
-
f7d48e
         return;
f7d48e
       }
f7d48e
 
f7d48e
@@ -523,6 +551,59 @@ handle_start_element (GMarkupParseContext  *context,
f7d48e
 
f7d48e
         return;
f7d48e
       }
f7d48e
+
f7d48e
+    case STATE_POLICY:
f7d48e
+      {
f7d48e
+        if (!(parser->extra_config_flags &
f7d48e
+              META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG))
f7d48e
+          {
f7d48e
+            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
f7d48e
+                         "Policy can only be defined in system level configurations");
f7d48e
+            return;
f7d48e
+          }
f7d48e
+
f7d48e
+        if (g_str_equal (element_name, "stores"))
f7d48e
+          {
f7d48e
+            if (parser->seen_stores)
f7d48e
+              {
f7d48e
+                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
f7d48e
+                             "Multiple stores elements under policy");
f7d48e
+                return;
f7d48e
+              }
f7d48e
+
f7d48e
+            parser->seen_stores = TRUE;
f7d48e
+            parser->state = STATE_STORES;
f7d48e
+          }
f7d48e
+        else
f7d48e
+          {
f7d48e
+            enter_unknown_element (parser, element_name,
f7d48e
+                                   "policy", STATE_POLICY);
f7d48e
+          }
f7d48e
+
f7d48e
+        return;
f7d48e
+      }
f7d48e
+
f7d48e
+    case STATE_STORES:
f7d48e
+      {
f7d48e
+        if (g_str_equal (element_name, "store"))
f7d48e
+          {
f7d48e
+            parser->state = STATE_STORE;
f7d48e
+          }
f7d48e
+        else
f7d48e
+          {
f7d48e
+            enter_unknown_element (parser, element_name,
f7d48e
+                                   "stores", STATE_STORES);
f7d48e
+          }
f7d48e
+
f7d48e
+        return;
f7d48e
+      }
f7d48e
+
f7d48e
+    case STATE_STORE:
f7d48e
+      {
f7d48e
+        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
f7d48e
+                     "Invalid store sub element '%s'", element_name);
f7d48e
+        return;
f7d48e
+      }
f7d48e
     }
f7d48e
 }
f7d48e
 
f7d48e
@@ -819,13 +900,65 @@ handle_end_element (GMarkupParseContext  *context,
f7d48e
             return;
f7d48e
           }
f7d48e
 
f7d48e
-        g_hash_table_replace (parser->config_store->configs,
f7d48e
+        g_hash_table_replace (parser->pending_configs,
f7d48e
                               config->key, config);
f7d48e
 
f7d48e
         parser->state = STATE_MONITORS;
f7d48e
         return;
f7d48e
       }
f7d48e
 
f7d48e
+    case STATE_STORE:
f7d48e
+        g_assert (g_str_equal (element_name, "store"));
f7d48e
+
f7d48e
+        if (parser->pending_store == -1)
f7d48e
+          {
f7d48e
+            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
f7d48e
+                         "Got an empty store");
f7d48e
+            return;
f7d48e
+          }
f7d48e
+
f7d48e
+        if (g_list_find (parser->stores,
f7d48e
+                         GINT_TO_POINTER (parser->pending_store)))
f7d48e
+          {
f7d48e
+            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
f7d48e
+                         "Multiple identical stores in policy");
f7d48e
+            return;
f7d48e
+          }
f7d48e
+
f7d48e
+        parser->stores =
f7d48e
+          g_list_append (parser->stores,
f7d48e
+                         GINT_TO_POINTER (parser->pending_store));
f7d48e
+        parser->pending_store = -1;
f7d48e
+
f7d48e
+        parser->state = STATE_STORES;
f7d48e
+        return;
f7d48e
+
f7d48e
+    case STATE_STORES:
f7d48e
+        g_assert (g_str_equal (element_name, "stores"));
f7d48e
+
f7d48e
+        if (parser->config_store->has_stores_policy)
f7d48e
+          {
f7d48e
+            g_warning ("Ignoring stores policy from '%s', "
f7d48e
+                       "it has already been configured",
f7d48e
+                       g_file_peek_path (parser->file));
f7d48e
+            g_clear_pointer (&parser->stores, g_list_free);
f7d48e
+          }
f7d48e
+        else
f7d48e
+          {
f7d48e
+            parser->config_store->stores_policy =
f7d48e
+              g_steal_pointer (&parser->stores);
f7d48e
+            parser->config_store->has_stores_policy = TRUE;
f7d48e
+          }
f7d48e
+
f7d48e
+        parser->state = STATE_POLICY;
f7d48e
+        return;
f7d48e
+
f7d48e
+    case STATE_POLICY:
f7d48e
+        g_assert (g_str_equal (element_name, "policy"));
f7d48e
+
f7d48e
+        parser->state = STATE_MONITORS;
f7d48e
+        return;
f7d48e
+
f7d48e
     case STATE_UNKNOWN:
f7d48e
       {
f7d48e
         parser->unknown_level--;
f7d48e
@@ -970,6 +1103,8 @@ handle_text (GMarkupParseContext *context,
f7d48e
     case STATE_MONITOR_MODE:
f7d48e
     case STATE_TRANSFORM:
f7d48e
     case STATE_DISABLED:
f7d48e
+    case STATE_POLICY:
f7d48e
+    case STATE_STORES:
f7d48e
       {
f7d48e
         if (!is_all_whitespace (text, text_len))
f7d48e
           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
f7d48e
@@ -1120,6 +1255,36 @@ handle_text (GMarkupParseContext *context,
f7d48e
                    error);
f7d48e
         return;
f7d48e
       }
f7d48e
+
f7d48e
+    case STATE_STORE:
f7d48e
+      {
f7d48e
+        MetaConfigStore store;
f7d48e
+
f7d48e
+        if (parser->pending_store != -1)
f7d48e
+          {
f7d48e
+            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
f7d48e
+                         "Multiple store strings");
f7d48e
+            return;
f7d48e
+          }
f7d48e
+
f7d48e
+        if (text_equals (text, text_len, "system"))
f7d48e
+          {
f7d48e
+            store = META_CONFIG_STORE_SYSTEM;
f7d48e
+          }
f7d48e
+        else if (text_equals (text, text_len, "user"))
f7d48e
+          {
f7d48e
+            store = META_CONFIG_STORE_USER;
f7d48e
+          }
f7d48e
+        else
f7d48e
+          {
f7d48e
+            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
f7d48e
+                         "Invalid store %.*s", (int) text_len, text);
f7d48e
+            return;
f7d48e
+          }
f7d48e
+
f7d48e
+        parser->pending_store = store;
f7d48e
+        return;
f7d48e
+      }
f7d48e
     }
f7d48e
 }
f7d48e
 
f7d48e
@@ -1133,6 +1298,7 @@ static gboolean
f7d48e
 read_config_file (MetaMonitorConfigStore  *config_store,
f7d48e
                   GFile                   *file,
f7d48e
                   MetaMonitorsConfigFlag   extra_config_flags,
f7d48e
+                  GHashTable             **out_configs,
f7d48e
                   GError                 **error)
f7d48e
 {
f7d48e
   char *buffer;
f7d48e
@@ -1145,9 +1311,15 @@ read_config_file (MetaMonitorConfigStore  *config_store,
f7d48e
 
f7d48e
   parser = (ConfigParser) {
f7d48e
     .state = STATE_INITIAL,
f7d48e
+    .file = file,
f7d48e
     .config_store = config_store,
f7d48e
+    .pending_configs = g_hash_table_new_full (meta_monitors_config_key_hash,
f7d48e
+                                              meta_monitors_config_key_equal,
f7d48e
+                                              NULL,
f7d48e
+                                              g_object_unref),
f7d48e
     .extra_config_flags = extra_config_flags,
f7d48e
     .unknown_state_root = -1,
f7d48e
+    .pending_store = -1,
f7d48e
   };
f7d48e
 
f7d48e
   parse_context = g_markup_parse_context_new (&config_parser,
f7d48e
@@ -1165,9 +1337,13 @@ read_config_file (MetaMonitorConfigStore  *config_store,
f7d48e
                       meta_monitor_config_free);
f7d48e
       g_clear_pointer (&parser.current_logical_monitor_config,
f7d48e
                        meta_logical_monitor_config_free);
f7d48e
+      g_list_free (parser.stores);
f7d48e
+      g_hash_table_unref (parser.pending_configs);
f7d48e
       return FALSE;
f7d48e
     }
f7d48e
 
f7d48e
+  *out_configs = g_steal_pointer (&parser.pending_configs);
f7d48e
+
f7d48e
   g_markup_parse_context_free (parse_context);
f7d48e
   g_free (buffer);
f7d48e
 
f7d48e
@@ -1526,23 +1702,34 @@ meta_monitor_config_store_remove (MetaMonitorConfigStore *config_store,
f7d48e
 }
f7d48e
 
f7d48e
 gboolean
f7d48e
-meta_monitor_config_store_set_custom (MetaMonitorConfigStore *config_store,
f7d48e
-                                      const char             *read_path,
f7d48e
-                                      const char             *write_path,
f7d48e
-                                      GError                **error)
f7d48e
+meta_monitor_config_store_set_custom (MetaMonitorConfigStore  *config_store,
f7d48e
+                                      const char              *read_path,
f7d48e
+                                      const char              *write_path,
f7d48e
+                                      MetaMonitorsConfigFlag   config_flags,
f7d48e
+                                      GError                 **error)
f7d48e
 {
f7d48e
+  GHashTable *new_configs = NULL;
f7d48e
+
f7d48e
   g_clear_object (&config_store->custom_read_file);
f7d48e
   g_clear_object (&config_store->custom_write_file);
f7d48e
-  g_hash_table_remove_all (config_store->configs);
f7d48e
 
f7d48e
   config_store->custom_read_file = g_file_new_for_path (read_path);
f7d48e
   if (write_path)
f7d48e
     config_store->custom_write_file = g_file_new_for_path (write_path);
f7d48e
 
f7d48e
-  return read_config_file (config_store,
f7d48e
-                           config_store->custom_read_file,
f7d48e
-                           META_MONITORS_CONFIG_FLAG_NONE,
f7d48e
-                           error);
f7d48e
+  g_clear_pointer (&config_store->stores_policy, g_list_free);
f7d48e
+  config_store->has_stores_policy = FALSE;
f7d48e
+
f7d48e
+  if (!read_config_file (config_store,
f7d48e
+                         config_store->custom_read_file,
f7d48e
+                         config_flags,
f7d48e
+                         &new_configs,
f7d48e
+                         error))
f7d48e
+    return FALSE;
f7d48e
+
f7d48e
+  g_clear_pointer (&config_store->configs, g_hash_table_unref);
f7d48e
+  config_store->configs = g_steal_pointer (&new_configs);
f7d48e
+  return TRUE;
f7d48e
 }
f7d48e
 
f7d48e
 int
f7d48e
@@ -1551,6 +1738,12 @@ meta_monitor_config_store_get_config_count (MetaMonitorConfigStore *config_store
f7d48e
   return (int) g_hash_table_size (config_store->configs);
f7d48e
 }
f7d48e
 
f7d48e
+GList *
f7d48e
+meta_monitor_config_store_get_stores_policy (MetaMonitorConfigStore *config_store)
f7d48e
+{
f7d48e
+  return config_store->stores_policy;
f7d48e
+}
f7d48e
+
f7d48e
 MetaMonitorManager *
f7d48e
 meta_monitor_config_store_get_monitor_manager (MetaMonitorConfigStore *config_store)
f7d48e
 {
f7d48e
@@ -1569,75 +1762,8 @@ static void
f7d48e
 meta_monitor_config_store_constructed (GObject *object)
f7d48e
 {
f7d48e
   MetaMonitorConfigStore *config_store = META_MONITOR_CONFIG_STORE (object);
f7d48e
-  const char * const *system_dirs;
f7d48e
-  char *user_file_path;
f7d48e
-  GError *error = NULL;
f7d48e
-
f7d48e
-  for (system_dirs = g_get_system_config_dirs ();
f7d48e
-       system_dirs && *system_dirs;
f7d48e
-       system_dirs++)
f7d48e
-    {
f7d48e
-      g_autofree char *system_file_path = NULL;
f7d48e
-
f7d48e
-      system_file_path = g_build_filename (*system_dirs, "monitors.xml", NULL);
f7d48e
-      if (g_file_test (system_file_path, G_FILE_TEST_EXISTS))
f7d48e
-        {
f7d48e
-          g_autoptr (GFile) system_file = NULL;
f7d48e
-
f7d48e
-          system_file = g_file_new_for_path (system_file_path);
f7d48e
-          if (!read_config_file (config_store,
f7d48e
-                                 system_file,
f7d48e
-                                 META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG,
f7d48e
-                                 &error))
f7d48e
-            {
f7d48e
-              if (g_error_matches (error,
f7d48e
-                                   META_MONITOR_CONFIG_STORE_ERROR,
f7d48e
-                                   META_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION))
f7d48e
-                g_warning ("System monitor configuration file (%s) is "
f7d48e
-                           "incompatible; ask your administrator to migrate "
f7d48e
-                           "the system monitor configuration.",
f7d48e
-                           system_file_path);
f7d48e
-              else
f7d48e
-                g_warning ("Failed to read monitors config file '%s': %s",
f7d48e
-                           system_file_path, error->message);
f7d48e
-              g_clear_error (&error);
f7d48e
-            }
f7d48e
-        }
f7d48e
-    }
f7d48e
 
f7d48e
-  user_file_path = g_build_filename (g_get_user_config_dir (),
f7d48e
-                                     "monitors.xml",
f7d48e
-                                     NULL);
f7d48e
-  config_store->user_file = g_file_new_for_path (user_file_path);
f7d48e
-
f7d48e
-  if (g_file_test (user_file_path, G_FILE_TEST_EXISTS))
f7d48e
-    {
f7d48e
-      if (!read_config_file (config_store,
f7d48e
-                             config_store->user_file,
f7d48e
-                             META_MONITORS_CONFIG_FLAG_NONE,
f7d48e
-                             &error))
f7d48e
-        {
f7d48e
-          if (error->domain == META_MONITOR_CONFIG_STORE_ERROR &&
f7d48e
-              error->code == META_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION)
f7d48e
-            {
f7d48e
-              g_clear_error (&error);
f7d48e
-              if (!meta_migrate_old_user_monitors_config (config_store, &error))
f7d48e
-                {
f7d48e
-                  g_warning ("Failed to migrate old monitors config file: %s",
f7d48e
-                             error->message);
f7d48e
-                  g_error_free (error);
f7d48e
-                }
f7d48e
-            }
f7d48e
-          else
f7d48e
-            {
f7d48e
-              g_warning ("Failed to read monitors config file '%s': %s",
f7d48e
-                         user_file_path, error->message);
f7d48e
-              g_error_free (error);
f7d48e
-            }
f7d48e
-        }
f7d48e
-    }
f7d48e
-
f7d48e
-  g_free (user_file_path);
f7d48e
+  meta_monitor_config_store_reset (config_store);
f7d48e
 
f7d48e
   G_OBJECT_CLASS (meta_monitor_config_store_parent_class)->constructed (object);
f7d48e
 }
f7d48e
@@ -1660,6 +1786,7 @@ meta_monitor_config_store_dispose (GObject *object)
f7d48e
   g_clear_object (&config_store->user_file);
f7d48e
   g_clear_object (&config_store->custom_read_file);
f7d48e
   g_clear_object (&config_store->custom_write_file);
f7d48e
+  g_clear_pointer (&config_store->stores_policy, g_list_free);
f7d48e
 
f7d48e
   G_OBJECT_CLASS (meta_monitor_config_store_parent_class)->dispose (object);
f7d48e
 }
f7d48e
@@ -1730,3 +1857,133 @@ meta_monitor_config_store_class_init (MetaMonitorConfigStoreClass *klass)
f7d48e
 
f7d48e
   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
f7d48e
 }
f7d48e
+
f7d48e
+static void
f7d48e
+replace_configs (MetaMonitorConfigStore *config_store,
f7d48e
+                 GHashTable             *configs)
f7d48e
+{
f7d48e
+  GHashTableIter iter;
f7d48e
+  MetaMonitorsConfigKey *key;
f7d48e
+  MetaMonitorsConfig *config;
f7d48e
+
f7d48e
+  g_hash_table_iter_init (&iter, configs);
f7d48e
+  while (g_hash_table_iter_next (&iter,
f7d48e
+                                 (gpointer *) &key,
f7d48e
+                                 (gpointer *) &config))
f7d48e
+    {
f7d48e
+      g_hash_table_iter_steal (&iter);
f7d48e
+      g_hash_table_replace (config_store->configs, key, config);
f7d48e
+    }
f7d48e
+}
f7d48e
+
f7d48e
+void
f7d48e
+meta_monitor_config_store_reset (MetaMonitorConfigStore *config_store)
f7d48e
+{
f7d48e
+  g_autoptr (GHashTable) system_configs = NULL;
f7d48e
+  g_autoptr (GHashTable) user_configs = NULL;
f7d48e
+  const char * const *system_dirs;
f7d48e
+  char *user_file_path;
f7d48e
+  GError *error = NULL;
f7d48e
+
f7d48e
+  g_clear_object (&config_store->user_file);
f7d48e
+  g_clear_object (&config_store->custom_read_file);
f7d48e
+  g_clear_object (&config_store->custom_write_file);
f7d48e
+  g_hash_table_remove_all (config_store->configs);
f7d48e
+
f7d48e
+  for (system_dirs = g_get_system_config_dirs ();
f7d48e
+       system_dirs && *system_dirs;
f7d48e
+       system_dirs++)
f7d48e
+    {
f7d48e
+      g_autofree char *system_file_path = NULL;
f7d48e
+
f7d48e
+      system_file_path = g_build_filename (*system_dirs, "monitors.xml", NULL);
f7d48e
+      if (g_file_test (system_file_path, G_FILE_TEST_EXISTS))
f7d48e
+        {
f7d48e
+          g_autoptr (GFile) system_file = NULL;
f7d48e
+
f7d48e
+          system_file = g_file_new_for_path (system_file_path);
f7d48e
+          if (!read_config_file (config_store,
f7d48e
+                                 system_file,
f7d48e
+                                 META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG,
f7d48e
+                                 &system_configs,
f7d48e
+                                 &error))
f7d48e
+            {
f7d48e
+              if (g_error_matches (error,
f7d48e
+                                   META_MONITOR_CONFIG_STORE_ERROR,
f7d48e
+                                   META_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION))
f7d48e
+                g_warning ("System monitor configuration file (%s) is "
f7d48e
+                           "incompatible; ask your administrator to migrate "
f7d48e
+                           "the system monitor configuration.",
f7d48e
+                           system_file_path);
f7d48e
+              else
f7d48e
+                g_warning ("Failed to read monitors config file '%s': %s",
f7d48e
+                           system_file_path, error->message);
f7d48e
+              g_clear_error (&error);
f7d48e
+            }
f7d48e
+        }
f7d48e
+    }
f7d48e
+
f7d48e
+  user_file_path = g_build_filename (g_get_user_config_dir (),
f7d48e
+                                     "monitors.xml",
f7d48e
+                                     NULL);
f7d48e
+  config_store->user_file = g_file_new_for_path (user_file_path);
f7d48e
+
f7d48e
+  if (g_file_test (user_file_path, G_FILE_TEST_EXISTS))
f7d48e
+    {
f7d48e
+      if (!read_config_file (config_store,
f7d48e
+                             config_store->user_file,
f7d48e
+                             META_MONITORS_CONFIG_FLAG_NONE,
f7d48e
+                             &user_configs,
f7d48e
+                             &error))
f7d48e
+        {
f7d48e
+          if (error->domain == META_MONITOR_CONFIG_STORE_ERROR &&
f7d48e
+              error->code == META_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION)
f7d48e
+            {
f7d48e
+              g_clear_error (&error);
f7d48e
+              if (!meta_migrate_old_user_monitors_config (config_store, &error))
f7d48e
+                {
f7d48e
+                  g_warning ("Failed to migrate old monitors config file: %s",
f7d48e
+                             error->message);
f7d48e
+                  g_error_free (error);
f7d48e
+                }
f7d48e
+            }
f7d48e
+          else
f7d48e
+            {
f7d48e
+              g_warning ("Failed to read monitors config file '%s': %s",
f7d48e
+                         user_file_path, error->message);
f7d48e
+              g_error_free (error);
f7d48e
+            }
f7d48e
+        }
f7d48e
+    }
f7d48e
+
f7d48e
+  if (config_store->has_stores_policy)
f7d48e
+    {
f7d48e
+      GList *l;
f7d48e
+
f7d48e
+      for (l = g_list_last (config_store->stores_policy); l; l = l->prev)
f7d48e
+        {
f7d48e
+          MetaConfigStore store = GPOINTER_TO_INT (l->data);
f7d48e
+
f7d48e
+          switch (store)
f7d48e
+            {
f7d48e
+            case META_CONFIG_STORE_SYSTEM:
f7d48e
+              if (system_configs)
f7d48e
+                replace_configs (config_store, system_configs);
f7d48e
+              break;
f7d48e
+            case META_CONFIG_STORE_USER:
f7d48e
+              if (user_configs)
f7d48e
+                replace_configs (config_store, user_configs);
f7d48e
+            }
f7d48e
+        }
f7d48e
+    }
f7d48e
+  else
f7d48e
+    {
f7d48e
+      if (system_configs)
f7d48e
+        replace_configs (config_store, system_configs);
f7d48e
+      if (user_configs)
f7d48e
+        replace_configs (config_store, user_configs);
f7d48e
+    }
f7d48e
+
f7d48e
+
f7d48e
+  g_free (user_file_path);
f7d48e
+}
f7d48e
diff --git a/src/backends/meta-monitor-config-store.h b/src/backends/meta-monitor-config-store.h
f7d48e
index 92c24ecaa8b6..cb6759dca00f 100644
f7d48e
--- a/src/backends/meta-monitor-config-store.h
f7d48e
+++ b/src/backends/meta-monitor-config-store.h
f7d48e
@@ -26,6 +26,12 @@
f7d48e
 
f7d48e
 #include "backends/meta-monitor-config-manager.h"
f7d48e
 
f7d48e
+typedef enum _MetaConfigStore
f7d48e
+{
f7d48e
+  META_CONFIG_STORE_SYSTEM,
f7d48e
+  META_CONFIG_STORE_USER,
f7d48e
+} MetaConfigStore;
f7d48e
+
f7d48e
 #define META_TYPE_MONITOR_CONFIG_STORE (meta_monitor_config_store_get_type ())
f7d48e
 G_DECLARE_FINAL_TYPE (MetaMonitorConfigStore, meta_monitor_config_store,
f7d48e
                       META, MONITOR_CONFIG_STORE, GObject)
f7d48e
@@ -46,10 +52,14 @@ void meta_monitor_config_store_remove (MetaMonitorConfigStore *config_store,
f7d48e
                                        MetaMonitorsConfig     *config);
f7d48e
 
f7d48e
 META_EXPORT_TEST
f7d48e
-gboolean meta_monitor_config_store_set_custom (MetaMonitorConfigStore *config_store,
f7d48e
-                                               const char             *read_path,
f7d48e
-                                               const char             *write_path,
f7d48e
-                                               GError                **error);
f7d48e
+gboolean meta_monitor_config_store_set_custom (MetaMonitorConfigStore  *config_store,
f7d48e
+                                               const char              *read_path,
f7d48e
+                                               const char              *write_path,
f7d48e
+                                               MetaMonitorsConfigFlag   flags,
f7d48e
+                                               GError                 **error);
f7d48e
+
f7d48e
+META_EXPORT_TEST
f7d48e
+GList * meta_monitor_config_store_get_stores_policy (MetaMonitorConfigStore *config_store);
f7d48e
 
f7d48e
 META_EXPORT_TEST
f7d48e
 int meta_monitor_config_store_get_config_count (MetaMonitorConfigStore *config_store);
f7d48e
@@ -57,4 +67,7 @@ int meta_monitor_config_store_get_config_count (MetaMonitorConfigStore *config_s
f7d48e
 META_EXPORT_TEST
f7d48e
 MetaMonitorManager * meta_monitor_config_store_get_monitor_manager (MetaMonitorConfigStore *config_store);
f7d48e
 
f7d48e
+META_EXPORT_TEST
f7d48e
+void meta_monitor_config_store_reset (MetaMonitorConfigStore *config_store);
f7d48e
+
f7d48e
 #endif /* META_MONITOR_CONFIG_STORE_H */
f7d48e
diff --git a/src/tests/monitor-config-migration-unit-tests.c b/src/tests/monitor-config-migration-unit-tests.c
f7d48e
index bb2ac62ccdbc..df22ee3a8d39 100644
f7d48e
--- a/src/tests/monitor-config-migration-unit-tests.c
f7d48e
+++ b/src/tests/monitor-config-migration-unit-tests.c
f7d48e
@@ -55,6 +55,7 @@ test_migration (const char *old_config,
f7d48e
                                     NULL);
f7d48e
   if (!meta_monitor_config_store_set_custom (config_store, "/dev/null",
f7d48e
                                              migrated_path,
f7d48e
+                                             META_MONITORS_CONFIG_FLAG_NONE,
f7d48e
                                              &error))
f7d48e
     g_error ("Failed to set custom config store: %s", error->message);
f7d48e
 
f7d48e
diff --git a/src/tests/monitor-configs/policy.xml b/src/tests/monitor-configs/policy.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..760046513e6e
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/policy.xml
f7d48e
@@ -0,0 +1,27 @@
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <stores>
f7d48e
+      <store>system</store>
f7d48e
+    </stores>
f7d48e
+  </policy>
f7d48e
+  <configuration>
f7d48e
+    <logicalmonitor>
f7d48e
+      <x>0</x>
f7d48e
+      <y>0</y>
f7d48e
+      <primary>yes</primary>
f7d48e
+      <monitor>
f7d48e
+	<monitorspec>
f7d48e
+	  <connector>DP-1</connector>
f7d48e
+	  <vendor>MetaProduct's Inc.</vendor>
f7d48e
+	  <product>MetaMonitor</product>
f7d48e
+	  <serial>0x123456</serial>
f7d48e
+	</monitorspec>
f7d48e
+	<mode>
f7d48e
+	  <width>1920</width>
f7d48e
+	  <height>1080</height>
f7d48e
+	  <rate>60</rate>
f7d48e
+	</mode>
f7d48e
+      </monitor>
f7d48e
+    </logicalmonitor>
f7d48e
+  </configuration>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-store-unit-tests.c b/src/tests/monitor-store-unit-tests.c
f7d48e
index 64618174f4b3..f7efa894b479 100644
f7d48e
--- a/src/tests/monitor-store-unit-tests.c
f7d48e
+++ b/src/tests/monitor-store-unit-tests.c
f7d48e
@@ -890,6 +890,35 @@ meta_test_monitor_store_unknown_elements (void)
f7d48e
   check_monitor_store_configurations (&expect);
f7d48e
 }
f7d48e
 
f7d48e
+static void
f7d48e
+meta_test_monitor_store_policy_not_allowed (void)
f7d48e
+{
f7d48e
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
f7d48e
+                         "*Policy can only be defined in system level "
f7d48e
+                         "configurations*");
f7d48e
+  set_custom_monitor_config ("policy.xml");
f7d48e
+  g_test_assert_expected_messages ();
f7d48e
+}
f7d48e
+
f7d48e
+static void
f7d48e
+meta_test_monitor_store_policy (void)
f7d48e
+{
f7d48e
+  MetaBackend *backend = meta_get_backend ();
f7d48e
+  MetaMonitorManager *monitor_manager =
f7d48e
+    meta_backend_get_monitor_manager (backend);
f7d48e
+  MetaMonitorConfigManager *config_manager = monitor_manager->config_manager;
f7d48e
+  MetaMonitorConfigStore *config_store =
f7d48e
+    meta_monitor_config_manager_get_store (config_manager);
f7d48e
+  GList *stores_policy;
f7d48e
+
f7d48e
+  set_custom_monitor_system_config ("policy.xml");
f7d48e
+  stores_policy = meta_monitor_config_store_get_stores_policy (config_store);
f7d48e
+  g_assert_cmpuint (g_list_length (stores_policy), ==, 1);
f7d48e
+  g_assert_cmpint (GPOINTER_TO_INT (stores_policy->data),
f7d48e
+                   ==,
f7d48e
+                   META_CONFIG_STORE_SYSTEM);
f7d48e
+}
f7d48e
+
f7d48e
 void
f7d48e
 init_monitor_store_tests (void)
f7d48e
 {
f7d48e
@@ -917,4 +946,8 @@ init_monitor_store_tests (void)
f7d48e
                    meta_test_monitor_store_interlaced);
f7d48e
   g_test_add_func ("/backends/monitor-store/unknown-elements",
f7d48e
                    meta_test_monitor_store_unknown_elements);
f7d48e
+  g_test_add_func ("/backends/monitor-store/policy-not-allowed",
f7d48e
+                   meta_test_monitor_store_policy_not_allowed);
f7d48e
+  g_test_add_func ("/backends/monitor-store/policy",
f7d48e
+                   meta_test_monitor_store_policy);
f7d48e
 }
f7d48e
diff --git a/src/tests/monitor-test-utils.c b/src/tests/monitor-test-utils.c
f7d48e
index 98958a5042ee..38401e54c847 100644
f7d48e
--- a/src/tests/monitor-test-utils.c
f7d48e
+++ b/src/tests/monitor-test-utils.c
f7d48e
@@ -36,10 +36,24 @@ test_get_gpu (void)
f7d48e
   return META_GPU (meta_backend_get_gpus (meta_get_backend ())->data);
f7d48e
 }
f7d48e
 
f7d48e
+static void
f7d48e
+set_custom_monitor_config_common (const char             *filename,
f7d48e
+                                  MetaMonitorsConfigFlag  configs_flags)
f7d48e
+{
f7d48e
+  meta_set_custom_monitor_config (meta_get_backend (), filename, configs_flags);
f7d48e
+}
f7d48e
+
f7d48e
 void
f7d48e
 set_custom_monitor_config (const char *filename)
f7d48e
 {
f7d48e
-  meta_set_custom_monitor_config (meta_get_backend (), filename);
f7d48e
+  set_custom_monitor_config_common (filename, META_MONITORS_CONFIG_FLAG_NONE);
f7d48e
+}
f7d48e
+
f7d48e
+void
f7d48e
+set_custom_monitor_system_config (const char *filename)
f7d48e
+{
f7d48e
+  set_custom_monitor_config_common (filename,
f7d48e
+                                    META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG);
f7d48e
 }
f7d48e
 
f7d48e
 char *
f7d48e
diff --git a/src/tests/monitor-test-utils.h b/src/tests/monitor-test-utils.h
f7d48e
index 3ebf1ff796ac..e5d16c438c2f 100644
f7d48e
--- a/src/tests/monitor-test-utils.h
f7d48e
+++ b/src/tests/monitor-test-utils.h
f7d48e
@@ -196,6 +196,8 @@ MetaGpu * test_get_gpu (void);
f7d48e
 
f7d48e
 void set_custom_monitor_config (const char *filename);
f7d48e
 
f7d48e
+void set_custom_monitor_system_config (const char *filename);
f7d48e
+
f7d48e
 char * read_file (const char *file_path);
f7d48e
 
f7d48e
 void check_monitor_configuration (MonitorTestCaseExpect *expect);
f7d48e
diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c
f7d48e
index f05bdb2773a8..ce332b7d4dcd 100644
f7d48e
--- a/src/tests/monitor-unit-tests.c
f7d48e
+++ b/src/tests/monitor-unit-tests.c
f7d48e
@@ -5277,6 +5277,7 @@ meta_test_monitor_migrated_rotated (void)
f7d48e
   if (!meta_monitor_config_store_set_custom (config_store,
f7d48e
                                              "/dev/null",
f7d48e
                                              migrated_path,
f7d48e
+                                             META_MONITORS_CONFIG_FLAG_NONE,
f7d48e
                                              &error))
f7d48e
     g_error ("Failed to set custom config store files: %s", error->message);
f7d48e
 
f7d48e
@@ -5418,6 +5419,7 @@ meta_test_monitor_migrated_wiggle_discard (void)
f7d48e
   if (!meta_monitor_config_store_set_custom (config_store,
f7d48e
                                              "/dev/null",
f7d48e
                                              migrated_path,
f7d48e
+                                             META_MONITORS_CONFIG_FLAG_NONE,
f7d48e
                                              &error))
f7d48e
     g_error ("Failed to set custom config store files: %s", error->message);
f7d48e
 
f7d48e
@@ -5684,6 +5686,7 @@ meta_test_monitor_migrated_wiggle (void)
f7d48e
   if (!meta_monitor_config_store_set_custom (config_store,
f7d48e
                                              "/dev/null",
f7d48e
                                              migrated_path,
f7d48e
+                                             META_MONITORS_CONFIG_FLAG_NONE,
f7d48e
                                              &error))
f7d48e
     g_error ("Failed to set custom config store files: %s", error->message);
f7d48e
 
f7d48e
diff --git a/src/tests/test-utils.c b/src/tests/test-utils.c
f7d48e
index bee6aa102c0e..49cef3b4c37f 100644
f7d48e
--- a/src/tests/test-utils.c
f7d48e
+++ b/src/tests/test-utils.c
f7d48e
@@ -578,8 +578,9 @@ test_wait_for_x11_display (void)
f7d48e
 }
f7d48e
 
f7d48e
 void
f7d48e
-meta_set_custom_monitor_config (MetaBackend *backend,
f7d48e
-                                const char  *filename)
f7d48e
+meta_set_custom_monitor_config (MetaBackend            *backend,
f7d48e
+                                const char             *filename,
f7d48e
+                                MetaMonitorsConfigFlag  configs_flags)
f7d48e
 {
f7d48e
   MetaMonitorManager *monitor_manager =
f7d48e
     meta_backend_get_monitor_manager (backend);
f7d48e
@@ -595,8 +596,9 @@ meta_set_custom_monitor_config (MetaBackend *backend,
f7d48e
   path = g_test_get_filename (G_TEST_DIST, "tests", "monitor-configs",
f7d48e
                               filename, NULL);
f7d48e
   if (!meta_monitor_config_store_set_custom (config_store, path, NULL,
f7d48e
+                                             configs_flags,
f7d48e
                                              &error))
f7d48e
-    g_error ("Failed to set custom config: %s", error->message);
f7d48e
+    g_warning ("Failed to set custom config: %s", error->message);
f7d48e
 }
f7d48e
 
f7d48e
 static void
f7d48e
diff --git a/src/tests/test-utils.h b/src/tests/test-utils.h
f7d48e
index 4b6aa34e8998..3b20e27f66e1 100644
f7d48e
--- a/src/tests/test-utils.h
f7d48e
+++ b/src/tests/test-utils.h
f7d48e
@@ -24,6 +24,7 @@
f7d48e
 #include <X11/Xlib.h>
f7d48e
 #include <X11/extensions/sync.h>
f7d48e
 
f7d48e
+#include "backends/meta-backend-types.h"
f7d48e
 #include "meta/window.h"
f7d48e
 
f7d48e
 #define TEST_RUNNER_ERROR test_runner_error_quark ()
f7d48e
@@ -86,8 +87,9 @@ const char * test_get_plugin_name (void);
f7d48e
 
f7d48e
 void test_wait_for_x11_display (void);
f7d48e
 
f7d48e
-void meta_set_custom_monitor_config (MetaBackend *backend,
f7d48e
-                                     const char  *filename);
f7d48e
+void meta_set_custom_monitor_config (MetaBackend            *backend,
f7d48e
+                                     const char             *filename,
f7d48e
+                                     MetaMonitorsConfigFlag  configs_flags);
f7d48e
 
f7d48e
 void meta_wait_for_paint (MetaBackend *backend);
f7d48e
 
f7d48e
-- 
f7d48e
2.33.1
f7d48e
f7d48e
f7d48e
From f79a90d0e366eee7669013448becf7dfcb96a6cb Mon Sep 17 00:00:00 2001
f7d48e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
f7d48e
Date: Fri, 24 Sep 2021 19:07:32 +0200
f7d48e
Subject: [PATCH 6/9] tests: Add more monitor config policy parsing tests
f7d48e
f7d48e
(cherry picked from commit 48a3ff845fabf0f23568d3c798e047e9b303bffd)
f7d48e
---
f7d48e
 .../monitor-configs/policy-duplicate.xml      |  8 ++++
f7d48e
 src/tests/monitor-configs/policy-empty.xml    |  7 +++
f7d48e
 src/tests/monitor-configs/policy-invalid.xml  |  8 ++++
f7d48e
 src/tests/monitor-configs/policy-multiple.xml | 12 +++++
f7d48e
 src/tests/monitor-store-unit-tests.c          | 44 +++++++++++++++++++
f7d48e
 5 files changed, 79 insertions(+)
f7d48e
 create mode 100644 src/tests/monitor-configs/policy-duplicate.xml
f7d48e
 create mode 100644 src/tests/monitor-configs/policy-empty.xml
f7d48e
 create mode 100644 src/tests/monitor-configs/policy-invalid.xml
f7d48e
 create mode 100644 src/tests/monitor-configs/policy-multiple.xml
f7d48e
f7d48e
diff --git a/src/tests/monitor-configs/policy-duplicate.xml b/src/tests/monitor-configs/policy-duplicate.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..d93cc81a4906
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/policy-duplicate.xml
f7d48e
@@ -0,0 +1,8 @@
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <stores>
f7d48e
+      <store>user</store>
f7d48e
+      <store>user</store>
f7d48e
+    </stores>
f7d48e
+  </policy>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-configs/policy-empty.xml b/src/tests/monitor-configs/policy-empty.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..f56026b66846
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/policy-empty.xml
f7d48e
@@ -0,0 +1,7 @@
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <stores>
f7d48e
+      <store></store>
f7d48e
+    </stores>
f7d48e
+  </policy>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-configs/policy-invalid.xml b/src/tests/monitor-configs/policy-invalid.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..fc4552fbefc7
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/policy-invalid.xml
f7d48e
@@ -0,0 +1,8 @@
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <stores>
f7d48e
+      <store>user</store>
f7d48e
+      <store>not-a-store</store>
f7d48e
+    </stores>
f7d48e
+  </policy>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-configs/policy-multiple.xml b/src/tests/monitor-configs/policy-multiple.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..ffeb79aafe8a
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/policy-multiple.xml
f7d48e
@@ -0,0 +1,12 @@
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <stores>
f7d48e
+      <store>user</store>
f7d48e
+      <store>system</store>
f7d48e
+    </stores>
f7d48e
+    <stores>
f7d48e
+      <store>system</store>
f7d48e
+      <store>user</store>
f7d48e
+    </stores>
f7d48e
+  </policy>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-store-unit-tests.c b/src/tests/monitor-store-unit-tests.c
f7d48e
index f7efa894b479..37b0675d0bf9 100644
f7d48e
--- a/src/tests/monitor-store-unit-tests.c
f7d48e
+++ b/src/tests/monitor-store-unit-tests.c
f7d48e
@@ -919,6 +919,42 @@ meta_test_monitor_store_policy (void)
f7d48e
                    META_CONFIG_STORE_SYSTEM);
f7d48e
 }
f7d48e
 
f7d48e
+static void
f7d48e
+meta_test_monitor_store_policy_empty (void)
f7d48e
+{
f7d48e
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
f7d48e
+                         "*Invalid store*");
f7d48e
+  set_custom_monitor_system_config ("policy-empty.xml");
f7d48e
+  g_test_assert_expected_messages ();
f7d48e
+}
f7d48e
+
f7d48e
+static void
f7d48e
+meta_test_monitor_store_policy_duplicate (void)
f7d48e
+{
f7d48e
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
f7d48e
+                         "*Multiple identical stores*");
f7d48e
+  set_custom_monitor_system_config ("policy-duplicate.xml");
f7d48e
+  g_test_assert_expected_messages ();
f7d48e
+}
f7d48e
+
f7d48e
+static void
f7d48e
+meta_test_monitor_store_policy_invalid (void)
f7d48e
+{
f7d48e
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
f7d48e
+                         "*Invalid store*");
f7d48e
+  set_custom_monitor_system_config ("policy-invalid.xml");
f7d48e
+  g_test_assert_expected_messages ();
f7d48e
+}
f7d48e
+
f7d48e
+static void
f7d48e
+meta_test_monitor_store_policy_multiple (void)
f7d48e
+{
f7d48e
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
f7d48e
+                         "*Multiple stores elements under policy*");
f7d48e
+  set_custom_monitor_system_config ("policy-multiple.xml");
f7d48e
+  g_test_assert_expected_messages ();
f7d48e
+}
f7d48e
+
f7d48e
 void
f7d48e
 init_monitor_store_tests (void)
f7d48e
 {
f7d48e
@@ -950,4 +986,12 @@ init_monitor_store_tests (void)
f7d48e
                    meta_test_monitor_store_policy_not_allowed);
f7d48e
   g_test_add_func ("/backends/monitor-store/policy",
f7d48e
                    meta_test_monitor_store_policy);
f7d48e
+  g_test_add_func ("/backends/monitor-store/policy-empty",
f7d48e
+                   meta_test_monitor_store_policy_empty);
f7d48e
+  g_test_add_func ("/backends/monitor-store/policy-duplicate",
f7d48e
+                   meta_test_monitor_store_policy_duplicate);
f7d48e
+  g_test_add_func ("/backends/monitor-store/policy-invalid",
f7d48e
+                   meta_test_monitor_store_policy_invalid);
f7d48e
+  g_test_add_func ("/backends/monitor-store/policy-multiple",
f7d48e
+                   meta_test_monitor_store_policy_multiple);
f7d48e
 }
f7d48e
-- 
f7d48e
2.33.1
f7d48e
f7d48e
f7d48e
From b884aa26afbfc6a90d9777fd077e885373200e45 Mon Sep 17 00:00:00 2001
f7d48e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
f7d48e
Date: Thu, 30 Sep 2021 17:32:31 +0200
f7d48e
Subject: [PATCH 7/9] monitor-config-store: Add test for monitor configuration
f7d48e
 policy
f7d48e
f7d48e
The test aims to verify that setting the following policy
f7d48e
f7d48e
    <policy>
f7d48e
      <stores>
f7d48e
        <store>system</store>
f7d48e
      </stores>
f7d48e
    </policy>
f7d48e
f7d48e
only applies monitor configurations from the system level.
f7d48e
f7d48e
(cherry picked from commit 9969a8aa25623dbff51e120d85ab202026571bb1)
f7d48e
---
f7d48e
 src/tests/monitor-configs/system/monitors.xml |  27 ++++
f7d48e
 src/tests/monitor-configs/user/monitors.xml   |  22 +++
f7d48e
 src/tests/monitor-store-unit-tests.c          |  17 +++
f7d48e
 src/tests/monitor-unit-tests.c                | 132 ++++++++++++++++++
f7d48e
 4 files changed, 198 insertions(+)
f7d48e
 create mode 100644 src/tests/monitor-configs/system/monitors.xml
f7d48e
 create mode 100644 src/tests/monitor-configs/user/monitors.xml
f7d48e
f7d48e
diff --git a/src/tests/monitor-configs/system/monitors.xml b/src/tests/monitor-configs/system/monitors.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..4d2eafec1327
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/system/monitors.xml
f7d48e
@@ -0,0 +1,27 @@
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <stores>
f7d48e
+      <store>system</store>
f7d48e
+    </stores>
f7d48e
+  </policy>
f7d48e
+  <configuration>
f7d48e
+    <logicalmonitor>
f7d48e
+      <x>0</x>
f7d48e
+      <y>0</y>
f7d48e
+      <primary>yes</primary>
f7d48e
+      <monitor>
f7d48e
+	<monitorspec>
f7d48e
+	  <connector>DP-1</connector>
f7d48e
+	  <vendor>MetaProduct's Inc.</vendor>
f7d48e
+	  <product>MetaMonitor</product>
f7d48e
+	  <serial>0x123456</serial>
f7d48e
+	</monitorspec>
f7d48e
+	<mode>
f7d48e
+	  <width>640</width>
f7d48e
+	  <height>480</height>
f7d48e
+	  <rate>60</rate>
f7d48e
+	</mode>
f7d48e
+      </monitor>
f7d48e
+    </logicalmonitor>
f7d48e
+  </configuration>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-configs/user/monitors.xml b/src/tests/monitor-configs/user/monitors.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..f125972e01e7
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/user/monitors.xml
f7d48e
@@ -0,0 +1,22 @@
f7d48e
+<monitors version="2">
f7d48e
+  <configuration>
f7d48e
+    <logicalmonitor>
f7d48e
+      <x>0</x>
f7d48e
+      <y>0</y>
f7d48e
+      <primary>yes</primary>
f7d48e
+      <monitor>
f7d48e
+	<monitorspec>
f7d48e
+	  <connector>DP-1</connector>
f7d48e
+	  <vendor>MetaProduct's Inc.</vendor>
f7d48e
+	  <product>MetaMonitor</product>
f7d48e
+	  <serial>0x123456</serial>
f7d48e
+	</monitorspec>
f7d48e
+	<mode>
f7d48e
+	  <width>800</width>
f7d48e
+	  <height>600</height>
f7d48e
+	  <rate>60</rate>
f7d48e
+	</mode>
f7d48e
+      </monitor>
f7d48e
+    </logicalmonitor>
f7d48e
+  </configuration>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-store-unit-tests.c b/src/tests/monitor-store-unit-tests.c
f7d48e
index 37b0675d0bf9..3ea3d94dbe35 100644
f7d48e
--- a/src/tests/monitor-store-unit-tests.c
f7d48e
+++ b/src/tests/monitor-store-unit-tests.c
f7d48e
@@ -958,6 +958,23 @@ meta_test_monitor_store_policy_multiple (void)
f7d48e
 void
f7d48e
 init_monitor_store_tests (void)
f7d48e
 {
f7d48e
+  char *path;
f7d48e
+
f7d48e
+  path = g_test_build_filename (G_TEST_DIST,
f7d48e
+                                "tests",
f7d48e
+                                "monitor-configs",
f7d48e
+                                "system",
f7d48e
+                                NULL);
f7d48e
+  g_setenv ("XDG_CONFIG_DIRS", path, TRUE);
f7d48e
+  g_free (path);
f7d48e
+  path = g_test_build_filename (G_TEST_DIST,
f7d48e
+                                "tests",
f7d48e
+                                "monitor-configs",
f7d48e
+                                "user",
f7d48e
+                                NULL);
f7d48e
+  g_setenv ("XDG_CONFIG_HOME", path, TRUE);
f7d48e
+  g_free (path);
f7d48e
+
f7d48e
   g_test_add_func ("/backends/monitor-store/single",
f7d48e
                    meta_test_monitor_store_single);
f7d48e
   g_test_add_func ("/backends/monitor-store/vertical",
f7d48e
diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c
f7d48e
index ce332b7d4dcd..91d88d0325d9 100644
f7d48e
--- a/src/tests/monitor-unit-tests.c
f7d48e
+++ b/src/tests/monitor-unit-tests.c
f7d48e
@@ -5722,6 +5722,135 @@ meta_test_monitor_migrated_wiggle (void)
f7d48e
     g_error ("Failed to remove test data output file: %s", error->message);
f7d48e
 }
f7d48e
 
f7d48e
+static void
f7d48e
+meta_test_monitor_policy_system_only (void)
f7d48e
+{
f7d48e
+  MetaMonitorTestSetup *test_setup;
f7d48e
+  MonitorTestCase test_case = {
f7d48e
+    .setup = {
f7d48e
+      .modes = {
f7d48e
+        {
f7d48e
+          .width = 1024,
f7d48e
+          .height = 768,
f7d48e
+          .refresh_rate = 60.0
f7d48e
+        },
f7d48e
+        {
f7d48e
+          .width = 800,
f7d48e
+          .height = 600,
f7d48e
+          .refresh_rate = 60.0
f7d48e
+        },
f7d48e
+        {
f7d48e
+          .width = 640,
f7d48e
+          .height = 480,
f7d48e
+          .refresh_rate = 60.0
f7d48e
+        }
f7d48e
+      },
f7d48e
+      .n_modes = 3,
f7d48e
+      .outputs = {
f7d48e
+         {
f7d48e
+          .crtc = 0,
f7d48e
+          .modes = { 0, 1, 2 },
f7d48e
+          .n_modes = 3,
f7d48e
+          .preferred_mode = 0,
f7d48e
+          .possible_crtcs = { 0 },
f7d48e
+          .n_possible_crtcs = 1,
f7d48e
+          .width_mm = 222,
f7d48e
+          .height_mm = 125
f7d48e
+        },
f7d48e
+      },
f7d48e
+      .n_outputs = 1,
f7d48e
+      .crtcs = {
f7d48e
+        {
f7d48e
+          .current_mode = 0
f7d48e
+        }
f7d48e
+      },
f7d48e
+      .n_crtcs = 1
f7d48e
+    },
f7d48e
+
f7d48e
+    .expect = {
f7d48e
+      .monitors = {
f7d48e
+        {
f7d48e
+          .outputs = { 0 },
f7d48e
+          .n_outputs = 1,
f7d48e
+          .modes = {
f7d48e
+            {
f7d48e
+              .width = 1024,
f7d48e
+              .height = 768,
f7d48e
+              .refresh_rate = 60.0,
f7d48e
+              .crtc_modes = {
f7d48e
+                {
f7d48e
+                  .output = 0,
f7d48e
+                  .crtc_mode = 0
f7d48e
+                }
f7d48e
+              }
f7d48e
+            },
f7d48e
+            {
f7d48e
+              .width = 800,
f7d48e
+              .height = 600,
f7d48e
+              .refresh_rate = 60.0,
f7d48e
+              .crtc_modes = {
f7d48e
+                {
f7d48e
+                  .output = 0,
f7d48e
+                  .crtc_mode = 1
f7d48e
+                }
f7d48e
+              }
f7d48e
+            },
f7d48e
+            {
f7d48e
+              .width = 640,
f7d48e
+              .height = 480,
f7d48e
+              .refresh_rate = 60.0,
f7d48e
+              .crtc_modes = {
f7d48e
+                {
f7d48e
+                  .output = 0,
f7d48e
+                  .crtc_mode = 2
f7d48e
+                }
f7d48e
+              }
f7d48e
+            }
f7d48e
+          },
f7d48e
+          .n_modes = 3,
f7d48e
+          .current_mode = 2,
f7d48e
+          .width_mm = 222,
f7d48e
+          .height_mm = 125
f7d48e
+        },
f7d48e
+      },
f7d48e
+      .n_monitors = 1,
f7d48e
+      .logical_monitors = {
f7d48e
+        {
f7d48e
+          .monitors = { 0 },
f7d48e
+          .n_monitors = 1,
f7d48e
+          .layout = { .x = 0, .y = 0, .width = 640, .height = 480 },
f7d48e
+          .scale = 1
f7d48e
+        },
f7d48e
+      },
f7d48e
+      .n_logical_monitors = 1,
f7d48e
+      .primary_logical_monitor = 0,
f7d48e
+      .n_outputs = 1,
f7d48e
+      .crtcs = {
f7d48e
+        {
f7d48e
+          .current_mode = 2,
f7d48e
+          .x = 0,
f7d48e
+        }
f7d48e
+      },
f7d48e
+      .n_crtcs = 1,
f7d48e
+      .screen_width = 640,
f7d48e
+      .screen_height = 480,
f7d48e
+    }
f7d48e
+  };
f7d48e
+  MetaBackend *backend = meta_get_backend ();
f7d48e
+  MetaMonitorManager *monitor_manager =
f7d48e
+    meta_backend_get_monitor_manager (backend);
f7d48e
+  MetaMonitorConfigManager *config_manager = monitor_manager->config_manager;
f7d48e
+  MetaMonitorConfigStore *config_store =
f7d48e
+    meta_monitor_config_manager_get_store (config_manager);
f7d48e
+
f7d48e
+  test_setup = create_monitor_test_setup (&test_case.setup,
f7d48e
+                                          MONITOR_TEST_FLAG_NONE);
f7d48e
+
f7d48e
+  meta_monitor_config_store_reset (config_store);
f7d48e
+  emulate_hotplug (test_setup);
f7d48e
+  check_monitor_configuration (&test_case.expect);
f7d48e
+}
f7d48e
+
f7d48e
 static void
f7d48e
 test_case_setup (void       **fixture,
f7d48e
                  const void   *data)
f7d48e
@@ -5848,6 +5977,9 @@ init_monitor_tests (void)
f7d48e
 
f7d48e
   add_monitor_test ("/backends/monitor/wm/tiling",
f7d48e
                     meta_test_monitor_wm_tiling);
f7d48e
+
f7d48e
+  add_monitor_test ("/backends/monitor/policy/system-only",
f7d48e
+                    meta_test_monitor_policy_system_only);
f7d48e
 }
f7d48e
 
f7d48e
 void
f7d48e
-- 
f7d48e
2.33.1
f7d48e
f7d48e
f7d48e
From cc88250c8a4e201c643ec7ada344323104549eb2 Mon Sep 17 00:00:00 2001
f7d48e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
f7d48e
Date: Thu, 30 Sep 2021 21:06:38 +0200
f7d48e
Subject: [PATCH 8/9] monitor-config-store: Allow changing D-Bus configuration
f7d48e
 policy
f7d48e
f7d48e
Adding a <dbus/> element containing a boolean (yes/no) determines
f7d48e
whether org.gnome.Mutter.DisplayConfig ApplyMonitorsConfig will be
f7d48e
callable. The state is also introspectable via the
f7d48e
ApplyMonitorsConfigAllowed property on the same interface.
f7d48e
f7d48e
For example
f7d48e
f7d48e
    <monitors version="2">
f7d48e
      <policy>
f7d48e
        <dbus>no</dbus>
f7d48e
      </policy>
f7d48e
    </monitors>
f7d48e
f7d48e
(cherry picked from commit f2c7ae821b7af7e732e588e7548238dd814e5f84)
f7d48e
---
f7d48e
 src/backends/meta-monitor-config-store.c      | 68 +++++++++++++++++++
f7d48e
 src/backends/meta-monitor-config-store.h      |  8 +++
f7d48e
 src/backends/meta-monitor-manager.c           | 24 +++++++
f7d48e
 src/org.gnome.Mutter.DisplayConfig.xml        |  7 ++
f7d48e
 .../monitor-configs/policy-dbus-invalid.xml   |  6 ++
f7d48e
 src/tests/monitor-configs/policy-dbus.xml     |  5 ++
f7d48e
 src/tests/monitor-store-unit-tests.c          | 49 +++++++++++++
f7d48e
 7 files changed, 167 insertions(+)
f7d48e
 create mode 100644 src/tests/monitor-configs/policy-dbus-invalid.xml
f7d48e
 create mode 100644 src/tests/monitor-configs/policy-dbus.xml
f7d48e
f7d48e
diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
f7d48e
index 93a494c79b80..5d48ec2ea5cf 100644
f7d48e
--- a/src/backends/meta-monitor-config-store.c
f7d48e
+++ b/src/backends/meta-monitor-config-store.c
f7d48e
@@ -123,6 +123,9 @@ struct _MetaMonitorConfigStore
f7d48e
 
f7d48e
   gboolean has_stores_policy;
f7d48e
   GList *stores_policy;
f7d48e
+
f7d48e
+  gboolean has_dbus_policy;
f7d48e
+  MetaMonitorConfigPolicy policy;
f7d48e
 };
f7d48e
 
f7d48e
 #define META_MONITOR_CONFIG_STORE_ERROR (meta_monitor_config_store_error_quark ())
f7d48e
@@ -168,6 +171,7 @@ typedef enum
f7d48e
   STATE_POLICY,
f7d48e
   STATE_STORES,
f7d48e
   STATE_STORE,
f7d48e
+  STATE_DBUS,
f7d48e
 } ParserState;
f7d48e
 
f7d48e
 typedef struct
f7d48e
@@ -191,9 +195,13 @@ typedef struct
f7d48e
   GList *current_disabled_monitor_specs;
f7d48e
   gboolean seen_policy;
f7d48e
   gboolean seen_stores;
f7d48e
+  gboolean seen_dbus;
f7d48e
   MetaConfigStore pending_store;
f7d48e
   GList *stores;
f7d48e
 
f7d48e
+  gboolean enable_dbus_set;
f7d48e
+  gboolean enable_dbus;
f7d48e
+
f7d48e
   ParserState unknown_state_root;
f7d48e
   int unknown_level;
f7d48e
 
f7d48e
@@ -574,6 +582,19 @@ handle_start_element (GMarkupParseContext  *context,
f7d48e
             parser->seen_stores = TRUE;
f7d48e
             parser->state = STATE_STORES;
f7d48e
           }
f7d48e
+        else if (g_str_equal (element_name, "dbus"))
f7d48e
+          {
f7d48e
+            if (parser->seen_dbus)
f7d48e
+              {
f7d48e
+                g_set_error (error,
f7d48e
+                             G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
f7d48e
+                             "Multiple dbus elements under policy");
f7d48e
+                return;
f7d48e
+              }
f7d48e
+
f7d48e
+            parser->seen_dbus = TRUE;
f7d48e
+            parser->state = STATE_DBUS;
f7d48e
+          }
f7d48e
         else
f7d48e
           {
f7d48e
             enter_unknown_element (parser, element_name,
f7d48e
@@ -604,6 +625,13 @@ handle_start_element (GMarkupParseContext  *context,
f7d48e
                      "Invalid store sub element '%s'", element_name);
f7d48e
         return;
f7d48e
       }
f7d48e
+
f7d48e
+    case STATE_DBUS:
f7d48e
+      {
f7d48e
+        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
f7d48e
+                     "Invalid dbus sub element '%s'", element_name);
f7d48e
+        return;
f7d48e
+      }
f7d48e
     }
f7d48e
 }
f7d48e
 
f7d48e
@@ -953,6 +981,23 @@ handle_end_element (GMarkupParseContext  *context,
f7d48e
         parser->state = STATE_POLICY;
f7d48e
         return;
f7d48e
 
f7d48e
+    case STATE_DBUS:
f7d48e
+        if (!parser->config_store->has_dbus_policy)
f7d48e
+          {
f7d48e
+            parser->config_store->has_dbus_policy = TRUE;
f7d48e
+            parser->config_store->policy.enable_dbus = parser->enable_dbus;
f7d48e
+            parser->enable_dbus_set = FALSE;
f7d48e
+          }
f7d48e
+        else
f7d48e
+          {
f7d48e
+            g_warning ("Policy for monitor configuration via D-Bus "
f7d48e
+                       "has already been set, ignoring policy from '%s'",
f7d48e
+                       g_file_get_path (parser->file));
f7d48e
+          }
f7d48e
+        parser->state = STATE_POLICY;
f7d48e
+
f7d48e
+        return;
f7d48e
+
f7d48e
     case STATE_POLICY:
f7d48e
         g_assert (g_str_equal (element_name, "policy"));
f7d48e
 
f7d48e
@@ -1285,6 +1330,15 @@ handle_text (GMarkupParseContext *context,
f7d48e
         parser->pending_store = store;
f7d48e
         return;
f7d48e
       }
f7d48e
+
f7d48e
+    case STATE_DBUS:
f7d48e
+      {
f7d48e
+        parser->enable_dbus_set = TRUE;
f7d48e
+        read_bool (text, text_len,
f7d48e
+                   &parser->enable_dbus,
f7d48e
+                   error);
f7d48e
+        return;
f7d48e
+      }
f7d48e
     }
f7d48e
 }
f7d48e
 
f7d48e
@@ -1643,6 +1697,11 @@ meta_monitor_config_store_save (MetaMonitorConfigStore *config_store)
f7d48e
       return;
f7d48e
     }
f7d48e
 
f7d48e
+  if (config_store->has_stores_policy &&
f7d48e
+      !g_list_find (config_store->stores_policy,
f7d48e
+                    GINT_TO_POINTER (META_CONFIG_STORE_USER)))
f7d48e
+    return;
f7d48e
+
f7d48e
   config_store->save_cancellable = g_cancellable_new ();
f7d48e
 
f7d48e
   buffer = generate_config_xml (config_store);
f7d48e
@@ -1719,6 +1778,8 @@ meta_monitor_config_store_set_custom (MetaMonitorConfigStore  *config_store,
f7d48e
 
f7d48e
   g_clear_pointer (&config_store->stores_policy, g_list_free);
f7d48e
   config_store->has_stores_policy = FALSE;
f7d48e
+  config_store->policy.enable_dbus = TRUE;
f7d48e
+  config_store->has_dbus_policy = FALSE;
f7d48e
 
f7d48e
   if (!read_config_file (config_store,
f7d48e
                          config_store->custom_read_file,
f7d48e
@@ -1834,6 +1895,7 @@ meta_monitor_config_store_init (MetaMonitorConfigStore *config_store)
f7d48e
                                                  meta_monitors_config_key_equal,
f7d48e
                                                  NULL,
f7d48e
                                                  g_object_unref);
f7d48e
+  config_store->policy.enable_dbus = TRUE;
f7d48e
 }
f7d48e
 
f7d48e
 static void
f7d48e
@@ -1987,3 +2049,9 @@ meta_monitor_config_store_reset (MetaMonitorConfigStore *config_store)
f7d48e
 
f7d48e
   g_free (user_file_path);
f7d48e
 }
f7d48e
+
f7d48e
+const MetaMonitorConfigPolicy *
f7d48e
+meta_monitor_config_store_get_policy (MetaMonitorConfigStore *config_store)
f7d48e
+{
f7d48e
+  return &config_store->policy;
f7d48e
+}
f7d48e
diff --git a/src/backends/meta-monitor-config-store.h b/src/backends/meta-monitor-config-store.h
f7d48e
index cb6759dca00f..a255e370baaf 100644
f7d48e
--- a/src/backends/meta-monitor-config-store.h
f7d48e
+++ b/src/backends/meta-monitor-config-store.h
f7d48e
@@ -32,6 +32,11 @@ typedef enum _MetaConfigStore
f7d48e
   META_CONFIG_STORE_USER,
f7d48e
 } MetaConfigStore;
f7d48e
 
f7d48e
+typedef struct _MetaMonitorConfigPolicy
f7d48e
+{
f7d48e
+  gboolean enable_dbus;
f7d48e
+} MetaMonitorConfigPolicy;
f7d48e
+
f7d48e
 #define META_TYPE_MONITOR_CONFIG_STORE (meta_monitor_config_store_get_type ())
f7d48e
 G_DECLARE_FINAL_TYPE (MetaMonitorConfigStore, meta_monitor_config_store,
f7d48e
                       META, MONITOR_CONFIG_STORE, GObject)
f7d48e
@@ -70,4 +75,7 @@ MetaMonitorManager * meta_monitor_config_store_get_monitor_manager (MetaMonitorC
f7d48e
 META_EXPORT_TEST
f7d48e
 void meta_monitor_config_store_reset (MetaMonitorConfigStore *config_store);
f7d48e
 
f7d48e
+META_EXPORT_TEST
f7d48e
+const MetaMonitorConfigPolicy * meta_monitor_config_store_get_policy (MetaMonitorConfigStore *config_store);
f7d48e
+
f7d48e
 #endif /* META_MONITOR_CONFIG_STORE_H */
f7d48e
diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
f7d48e
index 9e57db94cddd..75146950c38a 100644
f7d48e
--- a/src/backends/meta-monitor-manager.c
f7d48e
+++ b/src/backends/meta-monitor-manager.c
f7d48e
@@ -51,6 +51,7 @@
f7d48e
 #include "backends/meta-logical-monitor.h"
f7d48e
 #include "backends/meta-monitor.h"
f7d48e
 #include "backends/meta-monitor-config-manager.h"
f7d48e
+#include "backends/meta-monitor-config-store.h"
f7d48e
 #include "backends/meta-orientation-manager.h"
f7d48e
 #include "backends/meta-output.h"
f7d48e
 #include "backends/meta-virtual-monitor.h"
f7d48e
@@ -954,9 +955,18 @@ update_panel_orientation_managed (MetaMonitorManager *manager)
f7d48e
 void
f7d48e
 meta_monitor_manager_setup (MetaMonitorManager *manager)
f7d48e
 {
f7d48e
+  MetaMonitorConfigStore *config_store;
f7d48e
+  const MetaMonitorConfigPolicy *policy;
f7d48e
+
f7d48e
   manager->in_init = TRUE;
f7d48e
 
f7d48e
   manager->config_manager = meta_monitor_config_manager_new (manager);
f7d48e
+  config_store =
f7d48e
+    meta_monitor_config_manager_get_store (manager->config_manager);
f7d48e
+  policy = meta_monitor_config_store_get_policy (config_store);
f7d48e
+  meta_dbus_display_config_set_apply_monitors_config_allowed (manager->display_config,
f7d48e
+                                                              policy->enable_dbus);
f7d48e
+
f7d48e
 
f7d48e
   meta_monitor_manager_read_current_state (manager);
f7d48e
 
f7d48e
@@ -2192,6 +2202,8 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
f7d48e
                                                    GVariant              *properties_variant,
f7d48e
                                                    MetaMonitorManager    *manager)
f7d48e
 {
f7d48e
+  MetaMonitorConfigStore *config_store;
f7d48e
+  const MetaMonitorConfigPolicy *policy;
f7d48e
   MetaMonitorManagerCapability capabilities;
f7d48e
   GVariant *layout_mode_variant = NULL;
f7d48e
   MetaLogicalMonitorLayoutMode layout_mode;
f7d48e
@@ -2208,6 +2220,18 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
f7d48e
       return TRUE;
f7d48e
     }
f7d48e
 
f7d48e
+  config_store =
f7d48e
+    meta_monitor_config_manager_get_store (manager->config_manager);
f7d48e
+  policy = meta_monitor_config_store_get_policy (config_store);
f7d48e
+
f7d48e
+  if (!policy->enable_dbus)
f7d48e
+    {
f7d48e
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
f7d48e
+                                             G_DBUS_ERROR_ACCESS_DENIED,
f7d48e
+                                             "Monitor configuration via D-Bus is disabled");
f7d48e
+      return TRUE;
f7d48e
+    }
f7d48e
+
f7d48e
   capabilities = meta_monitor_manager_get_capabilities (manager);
f7d48e
 
f7d48e
   if (properties_variant)
f7d48e
diff --git a/src/org.gnome.Mutter.DisplayConfig.xml b/src/org.gnome.Mutter.DisplayConfig.xml
f7d48e
index 7522652dc05a..c6859c2c09c9 100644
f7d48e
--- a/src/org.gnome.Mutter.DisplayConfig.xml
f7d48e
+++ b/src/org.gnome.Mutter.DisplayConfig.xml
f7d48e
@@ -290,6 +290,13 @@
f7d48e
     -->
f7d48e
     <property name="PanelOrientationManaged" type="b" access="read" />
f7d48e
 
f7d48e
+    
f7d48e
+        ApplyMonitorsConfigAllowed:
f7d48e
+
f7d48e
+        Whether calling the ApplyMonitorsConfig method is allowed.
f7d48e
+    -->
f7d48e
+    <property name="ApplyMonitorsConfigAllowed" type="b" access="read" />
f7d48e
+
f7d48e
     
f7d48e
         MonitorsChanged:
f7d48e
 
f7d48e
diff --git a/src/tests/monitor-configs/policy-dbus-invalid.xml b/src/tests/monitor-configs/policy-dbus-invalid.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..67fa6045ff26
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/policy-dbus-invalid.xml
f7d48e
@@ -0,0 +1,6 @@
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <dbus>no</dbus>
f7d48e
+    <dbus>yes</dbus>
f7d48e
+  </policy>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-configs/policy-dbus.xml b/src/tests/monitor-configs/policy-dbus.xml
f7d48e
new file mode 100644
f7d48e
index 000000000000..c407e1f02194
f7d48e
--- /dev/null
f7d48e
+++ b/src/tests/monitor-configs/policy-dbus.xml
f7d48e
@@ -0,0 +1,5 @@
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <dbus>no</dbus>
f7d48e
+  </policy>
f7d48e
+</monitors>
f7d48e
diff --git a/src/tests/monitor-store-unit-tests.c b/src/tests/monitor-store-unit-tests.c
f7d48e
index 3ea3d94dbe35..073e09f696f3 100644
f7d48e
--- a/src/tests/monitor-store-unit-tests.c
f7d48e
+++ b/src/tests/monitor-store-unit-tests.c
f7d48e
@@ -955,6 +955,51 @@ meta_test_monitor_store_policy_multiple (void)
f7d48e
   g_test_assert_expected_messages ();
f7d48e
 }
f7d48e
 
f7d48e
+static void
f7d48e
+meta_test_monitor_store_policy_dbus (void)
f7d48e
+{
f7d48e
+  MetaBackend *backend = meta_get_backend ();
f7d48e
+  MetaMonitorManager *monitor_manager =
f7d48e
+    meta_backend_get_monitor_manager (backend);
f7d48e
+  MetaMonitorConfigManager *config_manager =
f7d48e
+    meta_monitor_manager_get_config_manager (monitor_manager);
f7d48e
+  MetaMonitorConfigStore *config_store =
f7d48e
+    meta_monitor_config_manager_get_store (config_manager);
f7d48e
+  const MetaMonitorConfigPolicy *policy;
f7d48e
+
f7d48e
+  policy = meta_monitor_config_store_get_policy (config_store);
f7d48e
+  g_assert_nonnull (policy);
f7d48e
+  g_assert_cmpint (policy->enable_dbus, ==, TRUE);
f7d48e
+
f7d48e
+  set_custom_monitor_system_config ("policy-dbus.xml");
f7d48e
+
f7d48e
+  policy = meta_monitor_config_store_get_policy (config_store);
f7d48e
+  g_assert_nonnull (policy);
f7d48e
+  g_assert_cmpint (policy->enable_dbus, ==, FALSE);
f7d48e
+}
f7d48e
+
f7d48e
+static void
f7d48e
+meta_test_monitor_store_policy_dbus_invalid (void)
f7d48e
+{
f7d48e
+  MetaBackend *backend = meta_get_backend ();
f7d48e
+  MetaMonitorManager *monitor_manager =
f7d48e
+    meta_backend_get_monitor_manager (backend);
f7d48e
+  MetaMonitorConfigManager *config_manager =
f7d48e
+    meta_monitor_manager_get_config_manager (monitor_manager);
f7d48e
+  MetaMonitorConfigStore *config_store =
f7d48e
+    meta_monitor_config_manager_get_store (config_manager);
f7d48e
+  const MetaMonitorConfigPolicy *policy;
f7d48e
+
f7d48e
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
f7d48e
+                         "*Multiple dbus elements under policy*");
f7d48e
+  set_custom_monitor_system_config ("policy-dbus-invalid.xml");
f7d48e
+  g_test_assert_expected_messages ();
f7d48e
+
f7d48e
+  policy = meta_monitor_config_store_get_policy (config_store);
f7d48e
+  g_assert_nonnull (policy);
f7d48e
+  g_assert_cmpint (policy->enable_dbus, ==, FALSE);
f7d48e
+}
f7d48e
+
f7d48e
 void
f7d48e
 init_monitor_store_tests (void)
f7d48e
 {
f7d48e
@@ -1011,4 +1056,8 @@ init_monitor_store_tests (void)
f7d48e
                    meta_test_monitor_store_policy_invalid);
f7d48e
   g_test_add_func ("/backends/monitor-store/policy-multiple",
f7d48e
                    meta_test_monitor_store_policy_multiple);
f7d48e
+  g_test_add_func ("/backends/monitor-store/dbus",
f7d48e
+                   meta_test_monitor_store_policy_dbus);
f7d48e
+  g_test_add_func ("/backends/monitor-store/dbus-invalid",
f7d48e
+                   meta_test_monitor_store_policy_dbus_invalid);
f7d48e
 }
f7d48e
-- 
f7d48e
2.33.1
f7d48e
f7d48e
f7d48e
From c10026a0f21f3b2260771a6c2e2218d0a3eb4d2f Mon Sep 17 00:00:00 2001
f7d48e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
f7d48e
Date: Fri, 1 Oct 2021 09:52:15 +0200
f7d48e
Subject: [PATCH 9/9] doc: Add monitor configuration documentation
f7d48e
f7d48e
This describes how the `monitors.xml` file work, and how to override the
f7d48e
newly introduced configurable policy.
f7d48e
f7d48e
(cherry picked from commit 3bbb53db3da07c0e944903ee8dede722cd082d34)
f7d48e
---
f7d48e
 doc/monitor-configuration.md | 105 +++++++++++++++++++++++++++++++++++
f7d48e
 1 file changed, 105 insertions(+)
f7d48e
 create mode 100644 doc/monitor-configuration.md
f7d48e
f7d48e
diff --git a/doc/monitor-configuration.md b/doc/monitor-configuration.md
f7d48e
new file mode 100644
f7d48e
index 000000000000..46c1078379cb
f7d48e
--- /dev/null
f7d48e
+++ b/doc/monitor-configuration.md
f7d48e
@@ -0,0 +1,105 @@
f7d48e
+Monitor configuration
f7d48e
+=====================
f7d48e
+
f7d48e
+File locations
f7d48e
+--------------
f7d48e
+
f7d48e
+Monitor configurations are stored as XML files called `monitors.xml` on the file
f7d48e
+system. There are two types of locations for the XML file: the system level and
f7d48e
+the user level.
f7d48e
+
f7d48e
+The directories for system level configuration is defined in accordance to the
f7d48e
+$XDG_CONFIG_DIRS environment variable defined in the XDG Base Directory
f7d48e
+Specification. The default is `/etc/xdg/monitors.xml`.
f7d48e
+
f7d48e
+The directory for the user level configuration is defined in accordance to the
f7d48e
+$XDG_CONFIG_HOME environment variable defined in the XDG Base Directory
f7d48e
+Specification. The default is `~/.config/monitors.xml`
f7d48e
+
f7d48e
+File contents
f7d48e
+-------------
f7d48e
+
f7d48e
+A configuration file consists of an XML document with the root element
f7d48e
+`<monitors version="2">`. In this document multiple configurations are stored as
f7d48e
+individual `<configuration/>` elements containing all the details of the monitor
f7d48e
+setup. The `version` attribute must be set to `"2"`.
f7d48e
+
f7d48e
+Each configuration corresponds to a specific hardware setup, where a given set
f7d48e
+of monitors are connected to the computer. There can only be one configuration
f7d48e
+per hardware setup.
f7d48e
+
f7d48e
+Writing configuration
f7d48e
+---------------------
f7d48e
+
f7d48e
+Monitor configurations are managed by Mutter via the Display panel in Settings,
f7d48e
+which uses a D-Bus API to communicate with Mutter. Each time a new configuration
f7d48e
+is applied and accepted, the user level configuration file is replaced with
f7d48e
+updated content.
f7d48e
+
f7d48e
+Previously defined monitor configurations for hardware state other than the
f7d48e
+current are left intact.
f7d48e
+
f7d48e
+Configuration policy
f7d48e
+--------------------
f7d48e
+
f7d48e
+The monitor configuration policy determines how Mutter configures monitors. This
f7d48e
+can mean for example in what order configuration files should be preferred, or
f7d48e
+whether configuration via Settings (i.e. D-Bus) should be allowed.
f7d48e
+
f7d48e
+The default policy is to prioritize configurations defined in the user level
f7d48e
+configuration file, and to allow configuring via D-Bus.
f7d48e
+
f7d48e
+Changing the policy is possible by manually adding a `<policy/>` element inside
f7d48e
+the `<monitors version="2"/>` element in the `monitors.xml` file. Note that
f7d48e
+there may only be one `<policy/>` element in each configuration file.
f7d48e
+
f7d48e
+### Changing configuration file priority policy
f7d48e
+
f7d48e
+To change the order of configuration file priority, or to disable configuration
f7d48e
+files completely, add a `<stores/>` element inside the `<policy/>` element
f7d48e
+described above.
f7d48e
+
f7d48e
+In this element, the file policy is defined by a `<stores/>` element, which
f7d48e
+lists stores with the order according to prioritization. Each store is specified
f7d48e
+using a `<store/>` element with either `system` or `user` as the content.
f7d48e
+
f7d48e
+#### Example of only reading monitor configuration from the system level file:
f7d48e
+
f7d48e
+```xml
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <stores>
f7d48e
+      <store>system</store>
f7d48e
+    </stores>
f7d48e
+  </policy>
f7d48e
+</monitors>
f7d48e
+```
f7d48e
+
f7d48e
+#### Example of reversing the priority of monitor configuration:
f7d48e
+
f7d48e
+```xml
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <stores>
f7d48e
+      <store>user</store>
f7d48e
+      <store>system</store>
f7d48e
+    </stores>
f7d48e
+  </policy>
f7d48e
+</monitors>
f7d48e
+```
f7d48e
+
f7d48e
+### Changing D-Bus configuration policy
f7d48e
+
f7d48e
+D-Bus configureability can be configured using a `<dbus/>` element in the
f7d48e
+`<policy/>` element. It's content should either be `yes` or `no` depending on
f7d48e
+whether monitor configuration via D-Bus should be enabled or disable.
f7d48e
+
f7d48e
+#### Example of how to disable monitor configuration via D-Bus:
f7d48e
+
f7d48e
+```xml
f7d48e
+<monitors version="2">
f7d48e
+  <policy>
f7d48e
+    <dbus>no</dbus>
f7d48e
+  </policy>
f7d48e
+</monitors>
f7d48e
+```
f7d48e
-- 
f7d48e
2.33.1
f7d48e