From 740436ab4d166feed10fbb913353d9cf1d8eea5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 23 Mar 2017 17:34:07 +0800 Subject: [PATCH] monitor-config-store: Add support for saving configuration When told to, MetaMonitorConfigStore will save the current configuration state by replacing the monitors-experimental.xml file (while backing a backup). https://bugzilla.gnome.org/show_bug.cgi?id=777732 --- src/backends/meta-monitor-config-store.c | 229 ++++++++++++++++++++++- 1 file changed, 224 insertions(+), 5 deletions(-) diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c index b67e61316..7c4c624a5 100644 --- a/src/backends/meta-monitor-config-store.c +++ b/src/backends/meta-monitor-config-store.c @@ -28,6 +28,11 @@ #include "backends/meta-monitor-config-manager.h" +#define MONITORS_CONFIG_XML_FORMAT_VERSION 2 + +#define QUOTE1(a) #a +#define QUOTE(a) QUOTE1(a) + /* * Example configuration: * @@ -100,7 +105,10 @@ struct _MetaMonitorConfigStore GHashTable *configs; + GCancellable *save_cancellable; + GFile *user_file; + GFile *custom_file; }; typedef enum @@ -181,7 +189,7 @@ handle_start_element (GMarkupParseContext *context, /* TODO: Handle converting version 1 configuration files. */ - if (!g_str_equal (version, "2")) + if (!g_str_equal (version, QUOTE (MONITORS_CONFIG_XML_FORMAT_VERSION))) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Invalid or unsupported version '%s'", version); @@ -965,12 +973,223 @@ meta_monitor_config_store_lookup (MetaMonitorConfigStore *config_store, key)); } +static void +append_monitors (GString *buffer, + GList *monitor_configs) +{ + GList *l; + + for (l = monitor_configs; l; l = l->next) + { + MetaMonitorConfig *monitor_config = l->data; + char rate_str[G_ASCII_DTOSTR_BUF_SIZE]; + + g_ascii_dtostr (rate_str, sizeof (rate_str), + monitor_config->mode_spec->refresh_rate); + + g_string_append (buffer, " \n"); + g_string_append (buffer, " \n"); + g_string_append_printf (buffer, " %s\n", + monitor_config->monitor_spec->connector); + g_string_append_printf (buffer, " %s\n", + monitor_config->monitor_spec->vendor); + g_string_append_printf (buffer, " %s\n", + monitor_config->monitor_spec->product); + g_string_append_printf (buffer, " %s\n", + monitor_config->monitor_spec->serial); + g_string_append (buffer, " \n"); + g_string_append (buffer, " \n"); + g_string_append_printf (buffer, " %d\n", + monitor_config->mode_spec->width); + g_string_append_printf (buffer, " %d\n", + monitor_config->mode_spec->height); + g_string_append_printf (buffer, " %s\n", + rate_str); + g_string_append (buffer, " \n"); + if (monitor_config->enable_underscanning) + g_string_append (buffer, " yes\n"); + g_string_append (buffer, " \n"); + } +} + +static const char * +bool_to_string (gboolean value) +{ + return value ? "yes" : "no"; +} + +static void +append_transform (GString *buffer, + MetaMonitorTransform transform) +{ + const char *rotation = NULL; + gboolean flipped = FALSE; + + switch (transform) + { + case META_MONITOR_TRANSFORM_NORMAL: + return; + case META_MONITOR_TRANSFORM_90: + rotation = "left"; + break; + case META_MONITOR_TRANSFORM_180: + rotation = "upside_down"; + break; + case META_MONITOR_TRANSFORM_270: + rotation = "right"; + break; + case META_MONITOR_TRANSFORM_FLIPPED: + rotation = "normal"; + flipped = TRUE; + break; + case META_MONITOR_TRANSFORM_FLIPPED_90: + rotation = "left"; + flipped = TRUE; + break; + case META_MONITOR_TRANSFORM_FLIPPED_180: + rotation = "upside_down"; + flipped = TRUE; + break; + case META_MONITOR_TRANSFORM_FLIPPED_270: + rotation = "right"; + flipped = TRUE; + break; + } + + g_string_append (buffer, " \n"); + g_string_append_printf (buffer, " %s\n", + rotation); + g_string_append_printf (buffer, " %s\n", + bool_to_string (flipped)); + g_string_append (buffer, " \n"); +} + +static void +append_logical_monitor_xml (GString *buffer, + MetaLogicalMonitorConfig *logical_monitor_config) +{ + g_string_append (buffer, " \n"); + g_string_append_printf (buffer, " %d\n", + logical_monitor_config->layout.x); + g_string_append_printf (buffer, " %d\n", + logical_monitor_config->layout.y); + g_string_append_printf (buffer, " %d\n", + logical_monitor_config->scale); + if (logical_monitor_config->is_primary) + g_string_append (buffer, " yes\n"); + if (logical_monitor_config->is_presentation) + g_string_append (buffer, " yes\n"); + append_transform (buffer, logical_monitor_config->transform); + append_monitors (buffer, logical_monitor_config->monitor_configs); + g_string_append (buffer, " \n"); +} + +static GString * +generate_config_xml (MetaMonitorConfigStore *config_store) +{ + GString *buffer; + GHashTableIter iter; + MetaMonitorsConfig *config; + + buffer = g_string_new (""); + g_string_append_printf (buffer, "\n", + MONITORS_CONFIG_XML_FORMAT_VERSION); + + g_hash_table_iter_init (&iter, config_store->configs); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &config)) + { + GList *l; + + g_string_append (buffer, " \n"); + + for (l = config->logical_monitor_configs; l; l = l->next) + { + MetaLogicalMonitorConfig *logical_monitor_config = l->data; + + append_logical_monitor_xml (buffer, logical_monitor_config); + } + + g_string_append (buffer, " \n"); + } + + g_string_append (buffer, "\n"); + + return buffer; +} + +typedef struct _SaveData +{ + MetaMonitorConfigStore *config_store; + GString *buffer; +} SaveData; + +static void +saved_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + SaveData *data = user_data; + GError *error = NULL; + + if (!g_file_replace_contents_finish (G_FILE (object), result, NULL, &error)) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Saving monitor configuration failed: %s\n", error->message); + else + g_clear_object (&data->config_store->save_cancellable); + + g_error_free (error); + } + else + { + g_clear_object (&data->config_store->save_cancellable); + } + + g_clear_object (&data->config_store); + g_string_free (data->buffer, TRUE); + g_free (data); +} + +static void +meta_monitor_config_store_save (MetaMonitorConfigStore *config_store) +{ + GString *buffer; + SaveData *data; + + if (config_store->save_cancellable) + { + g_cancellable_cancel (config_store->save_cancellable); + g_clear_object (&config_store->save_cancellable); + } + + config_store->save_cancellable = g_cancellable_new (); + + buffer = generate_config_xml (config_store); + + data = g_new0 (SaveData, 1); + *data = (SaveData) { + .config_store = g_object_ref (config_store), + .buffer = buffer + }; + + g_file_replace_contents_async (config_store->user_file, + buffer->str, buffer->len, + NULL, + TRUE, + G_FILE_CREATE_REPLACE_DESTINATION, + config_store->save_cancellable, + saved_cb, data); +} + void meta_monitor_config_store_add (MetaMonitorConfigStore *config_store, MetaMonitorsConfig *config) { g_hash_table_insert (config_store->configs, config->key, g_object_ref (config)); + + if (!config_store->custom_file) + meta_monitor_config_store_save (config_store); } gboolean @@ -978,13 +1197,12 @@ meta_monitor_config_store_set_custom (MetaMonitorConfigStore *config_store, const char *path, GError **error) { - g_autoptr (GFile) custom_file = NULL; - + g_clear_object (&config_store->custom_file); g_hash_table_remove_all (config_store->configs); - custom_file = g_file_new_for_path (path); + config_store->custom_file = g_file_new_for_path (path); - return read_config_file (config_store, custom_file, error); + return read_config_file (config_store, config_store->custom_file, error); } int @@ -1034,6 +1252,7 @@ meta_monitor_config_store_dispose (GObject *object) g_clear_pointer (&config_store->configs, g_hash_table_destroy); g_clear_object (&config_store->user_file); + g_clear_object (&config_store->custom_file); G_OBJECT_CLASS (meta_monitor_config_store_parent_class)->dispose (object); }