You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mutter/SOURCES/monitor-config-policy.patch

2344 lines
78 KiB

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