[gnome-flashback] backends: add GfMonitorConfigManager
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] backends: add GfMonitorConfigManager
- Date: Thu, 21 Sep 2017 00:08:44 +0000 (UTC)
commit b2474c735e9f0155d95c0c2df9802ce89c0b449f
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Wed Sep 20 22:21:48 2017 +0300
backends: add GfMonitorConfigManager
backends/Makefile.am | 1 +
backends/gf-monitor-config-manager-private.h | 46 +-
backends/gf-monitor-config-manager.c | 1036 ++++++++++++++++++++++++
backends/gf-monitor-config-migration-private.h | 4 +
backends/gf-monitor-config-migration.c | 9 +
backends/gf-monitor-manager-private.h | 36 +-
backends/gf-monitor-manager.c | 90 ++
backends/gf-monitor-manager.h | 13 +
8 files changed, 1224 insertions(+), 11 deletions(-)
---
diff --git a/backends/Makefile.am b/backends/Makefile.am
index befc14d..3714a4c 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -39,6 +39,7 @@ libbackends_la_SOURCES = \
gf-logical-monitor-private.h \
gf-logical-monitor.c \
gf-monitor-config-manager-private.h \
+ gf-monitor-config-manager.c \
gf-monitor-config-migration-private.h \
gf-monitor-config-migration.c \
gf-monitor-config-private.h \
diff --git a/backends/gf-monitor-config-manager-private.h b/backends/gf-monitor-config-manager-private.h
index 8d2d6bc..48e434a 100644
--- a/backends/gf-monitor-config-manager-private.h
+++ b/backends/gf-monitor-config-manager-private.h
@@ -22,11 +22,55 @@
#ifndef GF_MONITOR_CONFIG_MANAGER_PRIVATE_H
#define GF_MONITOR_CONFIG_MANAGER_PRIVATE_H
+#include "gf-logical-monitor-config-private.h"
+#include "gf-monitor-config-private.h"
#include "gf-monitor-manager-private.h"
-#include "gf-monitor-private.h"
G_BEGIN_DECLS
+#define GF_TYPE_MONITOR_CONFIG_MANAGER (gf_monitor_config_manager_get_type ())
+G_DECLARE_FINAL_TYPE (GfMonitorConfigManager, gf_monitor_config_manager,
+ GF, MONITOR_CONFIG_MANAGER, GObject)
+
+GfMonitorConfigManager *gf_monitor_config_manager_new (GfMonitorManager
*monitor_manager);
+
+GfMonitorConfigStore *gf_monitor_config_manager_get_store (GfMonitorConfigManager
*config_manager);
+
+gboolean gf_monitor_config_manager_assign (GfMonitorManager
*manager,
+ GfMonitorsConfig
*config,
+ GPtrArray
**crtc_infos,
+ GPtrArray
**output_infos,
+ GError
**error);
+
+GfMonitorsConfig *gf_monitor_config_manager_get_stored (GfMonitorConfigManager
*config_manager);
+
+GfMonitorsConfig *gf_monitor_config_manager_create_linear (GfMonitorConfigManager
*config_manager);
+
+GfMonitorsConfig *gf_monitor_config_manager_create_fallback (GfMonitorConfigManager
*config_manager);
+
+GfMonitorsConfig *gf_monitor_config_manager_create_suggested (GfMonitorConfigManager
*config_manager);
+
+GfMonitorsConfig *gf_monitor_config_manager_create_for_orientation (GfMonitorConfigManager
*config_manager,
+ GfMonitorTransform
transform);
+
+GfMonitorsConfig *gf_monitor_config_manager_create_for_rotate_monitor (GfMonitorConfigManager
*config_manager);
+
+GfMonitorsConfig *gf_monitor_config_manager_create_for_switch_config (GfMonitorConfigManager
*config_manager,
+ GfMonitorSwitchConfigType
config_type);
+
+void gf_monitor_config_manager_set_current (GfMonitorConfigManager
*config_manager,
+ GfMonitorsConfig
*config);
+
+GfMonitorsConfig *gf_monitor_config_manager_get_current (GfMonitorConfigManager
*config_manager);
+
+GfMonitorsConfig *gf_monitor_config_manager_pop_previous (GfMonitorConfigManager
*config_manager);
+
+GfMonitorsConfig *gf_monitor_config_manager_get_previous (GfMonitorConfigManager
*config_manager);
+
+void gf_monitor_config_manager_clear_history (GfMonitorConfigManager
*config_manager);
+
+void gf_monitor_config_manager_save_current (GfMonitorConfigManager
*config_manager);
+
G_END_DECLS
#endif
diff --git a/backends/gf-monitor-config-manager.c b/backends/gf-monitor-config-manager.c
new file mode 100644
index 0000000..67cb37e
--- /dev/null
+++ b/backends/gf-monitor-config-manager.c
@@ -0,0 +1,1036 @@
+/*
+ * Copyright (C) 2016 Red Hat
+ * Copyright (C) 2017 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Adapted from mutter:
+ * - src/backends/meta-monitor-config-manager.c
+ */
+
+#include "config.h"
+
+#include <math.h>
+
+#include "gf-crtc-private.h"
+#include "gf-monitor-config-store-private.h"
+#include "gf-monitor-config-manager-private.h"
+#include "gf-monitor-config-migration-private.h"
+#include "gf-monitor-spec-private.h"
+#include "gf-output-private.h"
+#include "gf-rectangle-private.h"
+
+#define CONFIG_HISTORY_MAX_SIZE 3
+
+typedef struct
+{
+ GfMonitorManager *monitor_manager;
+ GfLogicalMonitorConfig *logical_monitor_config;
+ GfMonitorConfig *monitor_config;
+ GPtrArray *crtc_infos;
+ GPtrArray *output_infos;
+} MonitorAssignmentData;
+
+typedef enum
+{
+ MONITOR_MATCH_ALL = 0,
+ MONITOR_MATCH_EXTERNAL = (1 << 0)
+} MonitorMatchRule;
+
+struct _GfMonitorConfigManager
+{
+ GObject parent;
+
+ GfMonitorManager *monitor_manager;
+
+ GfMonitorConfigStore *config_store;
+
+ GfMonitorsConfig *current_config;
+ GQueue config_history;
+};
+
+G_DEFINE_TYPE (GfMonitorConfigManager, gf_monitor_config_manager, G_TYPE_OBJECT)
+
+static GfMonitor *
+find_monitor_with_highest_preferred_resolution (GfMonitorManager *monitor_manager,
+ MonitorMatchRule match_rule)
+{
+ GList *monitors;
+ GList *l;
+ int largest_area = 0;
+ GfMonitor *largest_monitor = NULL;
+
+ monitors = gf_monitor_manager_get_monitors (monitor_manager);
+ for (l = monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+ GfMonitorMode *mode;
+ int width, height;
+ int area;
+
+ if (match_rule & MONITOR_MATCH_EXTERNAL)
+ {
+ if (gf_monitor_is_laptop_panel (monitor))
+ continue;
+ }
+
+ mode = gf_monitor_get_preferred_mode (monitor);
+ gf_monitor_mode_get_resolution (mode, &width, &height);
+ area = width * height;
+
+ if (area > largest_area)
+ {
+ largest_area = area;
+ largest_monitor = monitor;
+ }
+ }
+
+ return largest_monitor;
+}
+
+/*
+ * Try to find the primary monitor. The priority of classification is:
+ *
+ * 1. Find the primary monitor as reported by the underlying system,
+ * 2. Find the laptop panel
+ * 3. Find the external monitor with highest resolution
+ *
+ * If the laptop lid is closed, exclude the laptop panel from possible
+ * alternatives, except if no other alternatives exist.
+ */
+static GfMonitor *
+find_primary_monitor (GfMonitorManager *monitor_manager)
+{
+ GfMonitor *monitor;
+
+ if (gf_monitor_manager_is_lid_closed (monitor_manager))
+ {
+ monitor = gf_monitor_manager_get_primary_monitor (monitor_manager);
+ if (monitor && !gf_monitor_is_laptop_panel (monitor))
+ return monitor;
+
+ monitor = find_monitor_with_highest_preferred_resolution (monitor_manager,
+ MONITOR_MATCH_EXTERNAL);
+
+ if (monitor)
+ return monitor;
+
+ return find_monitor_with_highest_preferred_resolution (monitor_manager,
+ MONITOR_MATCH_ALL);
+ }
+ else
+ {
+ monitor = gf_monitor_manager_get_primary_monitor (monitor_manager);
+ if (monitor)
+ return monitor;
+
+ monitor = gf_monitor_manager_get_laptop_panel (monitor_manager);
+ if (monitor)
+ return monitor;
+
+ return find_monitor_with_highest_preferred_resolution (monitor_manager,
+ MONITOR_MATCH_ALL);
+ }
+}
+
+static GfLogicalMonitorConfig *
+create_preferred_logical_monitor_config (GfMonitorManager *monitor_manager,
+ GfMonitor *monitor,
+ int x,
+ int y,
+ GfLogicalMonitorConfig *primary_logical_monitor_config,
+ GfLogicalMonitorLayoutMode layout_mode)
+{
+ GfMonitorMode *mode;
+ int width, height;
+ float scale;
+ GfMonitorConfig *monitor_config;
+ GfLogicalMonitorConfig *logical_monitor_config;
+
+ mode = gf_monitor_get_preferred_mode (monitor);
+ gf_monitor_mode_get_resolution (mode, &width, &height);
+
+ if ((gf_monitor_manager_get_capabilities (monitor_manager) &
+ GF_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED) &&
+ primary_logical_monitor_config)
+ scale = primary_logical_monitor_config->scale;
+ else
+ scale = gf_monitor_manager_calculate_monitor_mode_scale (monitor_manager,
+ monitor, mode);
+
+ switch (layout_mode)
+ {
+ case GF_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
+ width /= scale;
+ height /= scale;
+ break;
+
+ case GF_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
+ default:
+ break;
+ }
+
+ monitor_config = gf_monitor_config_new (monitor, mode);
+
+ logical_monitor_config = g_new0 (GfLogicalMonitorConfig, 1);
+ *logical_monitor_config = (GfLogicalMonitorConfig) {
+ .layout = (GfRectangle) {
+ .x = x,
+ .y = y,
+ .width = width,
+ .height = height
+ },
+ .scale = scale,
+ .monitor_configs = g_list_append (NULL, monitor_config)
+ };
+
+ return logical_monitor_config;
+}
+
+static GfMonitorsConfig *
+create_for_switch_config_all_mirror (GfMonitorConfigManager *config_manager)
+{
+ GfMonitorManager *monitor_manager = config_manager->monitor_manager;
+ GfLogicalMonitorLayoutMode layout_mode;
+ GfLogicalMonitorConfig *logical_monitor_config = NULL;
+ GList *monitor_configs = NULL;
+ gint common_mode_w = 0, common_mode_h = 0;
+ float best_scale = 1.0;
+ GfMonitor *monitor;
+ GList *modes;
+ GList *monitors;
+ GList *l;
+
+ monitors = gf_monitor_manager_get_monitors (monitor_manager);
+ monitor = monitors->data;
+ modes = gf_monitor_get_modes (monitor);
+ for (l = modes; l; l = l->next)
+ {
+ GfMonitorMode *mode = l->data;
+ gboolean common_mode_size = TRUE;
+ gint mode_w, mode_h;
+ GList *ll;
+
+ gf_monitor_mode_get_resolution (mode, &mode_w, &mode_h);
+
+ for (ll = monitors->next; ll; ll = ll->next)
+ {
+ GfMonitor *monitor_b = ll->data;
+ gboolean have_same_mode_size = FALSE;
+ GList *mm;
+
+ for (mm = gf_monitor_get_modes (monitor_b); mm; mm = mm->next)
+ {
+ GfMonitorMode *mode_b = mm->data;
+ gint mode_b_w, mode_b_h;
+
+ gf_monitor_mode_get_resolution (mode_b, &mode_b_w, &mode_b_h);
+
+ if (mode_w == mode_b_w && mode_h == mode_b_h)
+ {
+ have_same_mode_size = TRUE;
+ break;
+ }
+ }
+
+ if (!have_same_mode_size)
+ {
+ common_mode_size = FALSE;
+ break;
+ }
+ }
+
+ if (common_mode_size &&
+ common_mode_w * common_mode_h < mode_w * mode_h)
+ {
+ common_mode_w = mode_w;
+ common_mode_h = mode_h;
+ }
+ }
+
+ if (common_mode_w == 0 || common_mode_h == 0)
+ return NULL;
+
+ for (l = monitors; l; l = l->next)
+ {
+ GfMonitor *l_monitor = l->data;
+ GfMonitorMode *mode = NULL;
+ GList *ll;
+ float scale;
+
+ for (ll = gf_monitor_get_modes (l_monitor); ll; ll = ll->next)
+ {
+ gint mode_w, mode_h;
+
+ mode = ll->data;
+ gf_monitor_mode_get_resolution (mode, &mode_w, &mode_h);
+
+ if (mode_w == common_mode_w && mode_h == common_mode_h)
+ break;
+ }
+
+ if (!mode)
+ continue;
+
+ scale = gf_monitor_manager_calculate_monitor_mode_scale (monitor_manager, l_monitor, mode);
+ best_scale = MAX (best_scale, scale);
+ monitor_configs = g_list_prepend (monitor_configs, gf_monitor_config_new (l_monitor, mode));
+ }
+
+ logical_monitor_config = g_new0 (GfLogicalMonitorConfig, 1);
+ *logical_monitor_config = (GfLogicalMonitorConfig) {
+ .layout = (GfRectangle) {
+ .x = 0,
+ .y = 0,
+ .width = common_mode_w,
+ .height = common_mode_h
+ },
+ .scale = best_scale,
+ .monitor_configs = monitor_configs
+ };
+
+ layout_mode = gf_monitor_manager_get_default_layout_mode (monitor_manager);
+ return gf_monitors_config_new (g_list_append (NULL, logical_monitor_config),
+ layout_mode, GF_MONITORS_CONFIG_FLAG_NONE);
+}
+
+static GfMonitorsConfig *
+create_for_switch_config_external (GfMonitorConfigManager *config_manager)
+{
+ GfMonitorManager *monitor_manager = config_manager->monitor_manager;
+ GList *logical_monitor_configs = NULL;
+ int x = 0;
+ GfLogicalMonitorLayoutMode layout_mode;
+ GList *monitors;
+ GList *l;
+
+ layout_mode = gf_monitor_manager_get_default_layout_mode (monitor_manager);
+
+ monitors = gf_monitor_manager_get_monitors (monitor_manager);
+ for (l = monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+ GfLogicalMonitorConfig *logical_monitor_config;
+
+ if (gf_monitor_is_laptop_panel (monitor))
+ continue;
+
+ logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager,
+ monitor, x, 0, NULL,
+ layout_mode);
+
+ logical_monitor_configs = g_list_append (logical_monitor_configs,
+ logical_monitor_config);
+
+ if (x == 0)
+ logical_monitor_config->is_primary = TRUE;
+
+ x += logical_monitor_config->layout.width;
+ }
+
+ return gf_monitors_config_new (logical_monitor_configs, layout_mode,
+ GF_MONITORS_CONFIG_FLAG_NONE);
+}
+
+static GfMonitorsConfig *
+create_for_switch_config_builtin (GfMonitorConfigManager *config_manager)
+{
+ GfMonitorManager *monitor_manager = config_manager->monitor_manager;
+ GfLogicalMonitorLayoutMode layout_mode;
+ GList *logical_monitor_configs;
+ GfLogicalMonitorConfig *primary_logical_monitor_config;
+ GfMonitor *monitor;
+
+ monitor = gf_monitor_manager_get_laptop_panel (monitor_manager);
+ if (!monitor)
+ return NULL;
+
+ layout_mode = gf_monitor_manager_get_default_layout_mode (monitor_manager);
+
+ primary_logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager,
+ monitor, 0, 0, NULL,
+ layout_mode);
+
+ primary_logical_monitor_config->is_primary = TRUE;
+ logical_monitor_configs = g_list_append (NULL, primary_logical_monitor_config);
+
+ return gf_monitors_config_new (logical_monitor_configs, layout_mode,
+ GF_MONITORS_CONFIG_FLAG_NONE);
+}
+
+static GfMonitorsConfig *
+create_for_builtin_display_rotation (GfMonitorConfigManager *config_manager,
+ gboolean rotate,
+ GfMonitorTransform transform)
+{
+ GfLogicalMonitorConfig *logical_monitor_config;
+ GfLogicalMonitorConfig *current_logical_monitor_config;
+ GfMonitorConfig *monitor_config;
+ GfMonitorConfig *current_monitor_config;
+
+ if (!gf_monitor_manager_get_is_builtin_display_on (config_manager->monitor_manager))
+ return NULL;
+
+ if (!config_manager->current_config)
+ return NULL;
+
+ if (g_list_length (config_manager->current_config->logical_monitor_configs) != 1)
+ return NULL;
+
+ current_logical_monitor_config = config_manager->current_config->logical_monitor_configs->data;
+
+ if (rotate)
+ transform = (current_logical_monitor_config->transform + 1) % GF_MONITOR_TRANSFORM_FLIPPED;
+
+ if (current_logical_monitor_config->transform == transform)
+ return NULL;
+
+ if (g_list_length (current_logical_monitor_config->monitor_configs) != 1)
+ return NULL;
+
+ current_monitor_config = current_logical_monitor_config->monitor_configs->data;
+
+ monitor_config = g_new0 (GfMonitorConfig, 1);
+ *monitor_config = (GfMonitorConfig) {
+ .monitor_spec = gf_monitor_spec_clone (current_monitor_config->monitor_spec),
+ .mode_spec = g_memdup (current_monitor_config->mode_spec, sizeof (GfMonitorModeSpec)),
+ .enable_underscanning = current_monitor_config->enable_underscanning
+ };
+
+ logical_monitor_config = g_memdup (current_logical_monitor_config, sizeof (GfLogicalMonitorConfig));
+ logical_monitor_config->monitor_configs = g_list_append (NULL, monitor_config);
+ logical_monitor_config->transform = transform;
+
+ return gf_monitors_config_new (g_list_append (NULL, logical_monitor_config),
+ config_manager->current_config->layout_mode,
+ GF_MONITORS_CONFIG_FLAG_NONE);
+}
+
+static gboolean
+is_crtc_assigned (GfCrtc *crtc,
+ GPtrArray *crtc_infos)
+{
+ unsigned int i;
+
+ for (i = 0; i < crtc_infos->len; i++)
+ {
+ GfCrtcInfo *assigned_crtc_info = g_ptr_array_index (crtc_infos, i);
+
+ if (assigned_crtc_info->crtc == crtc)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GfCrtc *
+find_unassigned_crtc (GfOutput *output,
+ GPtrArray *crtc_infos)
+{
+ unsigned int i;
+
+ for (i = 0; i < output->n_possible_crtcs; i++)
+ {
+ GfCrtc *crtc = output->possible_crtcs[i];
+
+ if (is_crtc_assigned (crtc, crtc_infos))
+ continue;
+
+ return crtc;
+ }
+
+ return NULL;
+}
+
+static gboolean
+assign_monitor_crtc (GfMonitor *monitor,
+ GfMonitorMode *mode,
+ GfMonitorCrtcMode *monitor_crtc_mode,
+ gpointer user_data,
+ GError **error)
+{
+ MonitorAssignmentData *data = user_data;
+ GfOutput *output;
+ GfCrtc *crtc;
+ GfMonitorTransform transform;
+ GfMonitorTransform crtc_transform;
+ int crtc_x, crtc_y;
+ GfCrtcInfo *crtc_info;
+ GfOutputInfo *output_info;
+ GfMonitorConfig *first_monitor_config;
+ gboolean assign_output_as_primary;
+ gboolean assign_output_as_presentation;
+
+ output = monitor_crtc_mode->output;
+
+ crtc = find_unassigned_crtc (output, data->crtc_infos);
+ if (!crtc)
+ {
+ GfMonitorSpec *monitor_spec = gf_monitor_get_spec (monitor);
+
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "No available CRTC for monitor '%s %s' not found",
+ monitor_spec->vendor, monitor_spec->product);
+
+ return FALSE;
+ }
+
+ transform = data->logical_monitor_config->transform;
+ if (gf_monitor_manager_is_transform_handled (data->monitor_manager,
+ crtc, transform))
+ crtc_transform = transform;
+ else
+ crtc_transform = GF_MONITOR_TRANSFORM_NORMAL;
+
+ gf_monitor_calculate_crtc_pos (monitor, mode, output, crtc_transform,
+ &crtc_x, &crtc_y);
+
+ crtc_info = g_slice_new0 (GfCrtcInfo);
+ *crtc_info = (GfCrtcInfo) {
+ .crtc = crtc,
+ .mode = monitor_crtc_mode->crtc_mode,
+ .x = crtc_x,
+ .y = crtc_y,
+ .transform = crtc_transform,
+ .outputs = g_ptr_array_new ()
+ };
+ g_ptr_array_add (crtc_info->outputs, output);
+
+ /*
+ * Currently, GfCrtcInfo are deliberately offset incorrectly to carry over
+ * logical monitor location inside the GfCrtc struct, when in fact this
+ * depends on the framebuffer configuration. This will eventually be negated
+ * when setting the actual KMS mode.
+ *
+ * TODO: Remove this hack when we don't need to rely on GfCrtc to pass
+ * logical monitor state.
+ */
+ crtc_info->x += data->logical_monitor_config->layout.x;
+ crtc_info->y += data->logical_monitor_config->layout.y;
+
+ /*
+ * Only one output can be marked as primary (due to Xrandr limitation),
+ * so only mark the main output of the first monitor in the logical monitor
+ * as such.
+ */
+ first_monitor_config = data->logical_monitor_config->monitor_configs->data;
+ if (data->logical_monitor_config->is_primary &&
+ data->monitor_config == first_monitor_config &&
+ gf_monitor_get_main_output (monitor) == output)
+ assign_output_as_primary = TRUE;
+ else
+ assign_output_as_primary = FALSE;
+
+ if (data->logical_monitor_config->is_presentation)
+ assign_output_as_presentation = TRUE;
+ else
+ assign_output_as_presentation = FALSE;
+
+ output_info = g_slice_new0 (GfOutputInfo);
+ *output_info = (GfOutputInfo) {
+ .output = output,
+ .is_primary = assign_output_as_primary,
+ .is_presentation = assign_output_as_presentation,
+ .is_underscanning = data->monitor_config->enable_underscanning
+ };
+
+ g_ptr_array_add (data->crtc_infos, crtc_info);
+ g_ptr_array_add (data->output_infos, output_info);
+
+ return TRUE;
+}
+
+static gboolean
+assign_monitor_crtcs (GfMonitorManager *manager,
+ GfLogicalMonitorConfig *logical_monitor_config,
+ GfMonitorConfig *monitor_config,
+ GPtrArray *crtc_infos,
+ GPtrArray *output_infos,
+ GError **error)
+{
+ GfMonitorSpec *monitor_spec = monitor_config->monitor_spec;
+ GfMonitorModeSpec *monitor_mode_spec = monitor_config->mode_spec;
+ GfMonitor *monitor;
+ GfMonitorMode *monitor_mode;
+ MonitorAssignmentData data;
+
+ monitor = gf_monitor_manager_get_monitor_from_spec (manager, monitor_spec);
+ if (!monitor)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Configured monitor '%s %s' not found",
+ monitor_spec->vendor, monitor_spec->product);
+
+ return FALSE;
+ }
+
+ monitor_mode = gf_monitor_get_mode_from_spec (monitor, monitor_mode_spec);
+ if (!monitor_mode)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Invalid mode %dx%d (%f) for monitor '%s %s'",
+ monitor_mode_spec->width, monitor_mode_spec->height,
+ monitor_mode_spec->refresh_rate,
+ monitor_spec->vendor, monitor_spec->product);
+
+ return FALSE;
+ }
+
+ data = (MonitorAssignmentData) {
+ .monitor_manager = manager,
+ .logical_monitor_config = logical_monitor_config,
+ .monitor_config = monitor_config,
+ .crtc_infos = crtc_infos,
+ .output_infos = output_infos
+ };
+
+ if (!gf_monitor_mode_foreach_crtc (monitor, monitor_mode,
+ assign_monitor_crtc,
+ &data, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+assign_logical_monitor_crtcs (GfMonitorManager *manager,
+ GfLogicalMonitorConfig *logical_monitor_config,
+ GPtrArray *crtc_infos,
+ GPtrArray *output_infos,
+ GError **error)
+{
+ GList *l;
+
+ for (l = logical_monitor_config->monitor_configs; l; l = l->next)
+ {
+ GfMonitorConfig *monitor_config = l->data;
+
+ if (!assign_monitor_crtcs (manager,
+ logical_monitor_config,
+ monitor_config,
+ crtc_infos, output_infos,
+ error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GfMonitorsConfigKey *
+create_key_for_current_state (GfMonitorManager *monitor_manager)
+{
+ GfMonitorsConfigKey *config_key;
+ GList *l;
+ GList *monitor_specs;
+
+ monitor_specs = NULL;
+ for (l = monitor_manager->monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+ GfMonitorSpec *monitor_spec;
+
+ if (gf_monitor_is_laptop_panel (monitor) &&
+ gf_monitor_manager_is_lid_closed (monitor_manager))
+ continue;
+
+ monitor_spec = gf_monitor_spec_clone (gf_monitor_get_spec (monitor));
+ monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
+ }
+
+ if (!monitor_specs)
+ return NULL;
+
+ monitor_specs = g_list_sort (monitor_specs, (GCompareFunc) gf_monitor_spec_compare);
+
+ config_key = g_new0 (GfMonitorsConfigKey, 1);
+ config_key->monitor_specs = monitor_specs;
+
+ return config_key;
+}
+
+static void
+gf_crtc_info_free (GfCrtcInfo *info)
+{
+ g_ptr_array_free (info->outputs, TRUE);
+ g_slice_free (GfCrtcInfo, info);
+}
+
+static void
+gf_output_info_free (GfOutputInfo *info)
+{
+ g_slice_free (GfOutputInfo, info);
+}
+
+static void
+gf_monitor_config_manager_dispose (GObject *object)
+{
+ GfMonitorConfigManager *config_manager;
+
+ config_manager = GF_MONITOR_CONFIG_MANAGER (object);
+
+ g_clear_object (&config_manager->current_config);
+ gf_monitor_config_manager_clear_history (config_manager);
+
+ G_OBJECT_CLASS (gf_monitor_config_manager_parent_class)->dispose (object);
+}
+
+static void
+gf_monitor_config_manager_class_init (GfMonitorConfigManagerClass *config_manager_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (config_manager_class);
+
+ object_class->dispose = gf_monitor_config_manager_dispose;
+}
+
+static void
+gf_monitor_config_manager_init (GfMonitorConfigManager *config_manager)
+{
+ g_queue_init (&config_manager->config_history);
+}
+
+GfMonitorConfigManager *
+gf_monitor_config_manager_new (GfMonitorManager *monitor_manager)
+{
+ GfMonitorConfigManager *config_manager;
+
+ config_manager = g_object_new (GF_TYPE_MONITOR_CONFIG_MANAGER, NULL);
+ config_manager->monitor_manager = monitor_manager;
+ config_manager->config_store = gf_monitor_config_store_new (monitor_manager);
+
+ return config_manager;
+}
+
+GfMonitorConfigStore *
+gf_monitor_config_manager_get_store (GfMonitorConfigManager *config_manager)
+{
+ return config_manager->config_store;
+}
+
+gboolean
+gf_monitor_config_manager_assign (GfMonitorManager *manager,
+ GfMonitorsConfig *config,
+ GPtrArray **out_crtc_infos,
+ GPtrArray **out_output_infos,
+ GError **error)
+{
+ GPtrArray *crtc_infos;
+ GPtrArray *output_infos;
+ GList *l;
+
+ crtc_infos = g_ptr_array_new_with_free_func ((GDestroyNotify) gf_crtc_info_free);
+ output_infos = g_ptr_array_new_with_free_func ((GDestroyNotify) gf_output_info_free);
+
+ for (l = config->logical_monitor_configs; l; l = l->next)
+ {
+ GfLogicalMonitorConfig *logical_monitor_config = l->data;
+
+ if (!assign_logical_monitor_crtcs (manager, logical_monitor_config,
+ crtc_infos, output_infos,
+ error))
+ {
+ g_ptr_array_free (crtc_infos, TRUE);
+ g_ptr_array_free (output_infos, TRUE);
+ return FALSE;
+ }
+ }
+
+ *out_crtc_infos = crtc_infos;
+ *out_output_infos = output_infos;
+
+ return TRUE;
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_get_stored (GfMonitorConfigManager *config_manager)
+{
+ GfMonitorManager *monitor_manager = config_manager->monitor_manager;
+ GfMonitorsConfigKey *config_key;
+ GfMonitorsConfig *config;
+ GError *error = NULL;
+
+ config_key = create_key_for_current_state (monitor_manager);
+ if (!config_key)
+ return NULL;
+
+ config = gf_monitor_config_store_lookup (config_manager->config_store, config_key);
+ gf_monitors_config_key_free (config_key);
+
+ if (!config)
+ return NULL;
+
+ if (config->flags & GF_MONITORS_CONFIG_FLAG_MIGRATED)
+ {
+ if (!gf_finish_monitors_config_migration (monitor_manager, config, &error))
+ {
+ g_warning ("Failed to finish monitors config migration: %s", error->message);
+ g_error_free (error);
+
+ gf_monitor_config_store_remove (config_manager->config_store, config);
+ return NULL;
+ }
+ }
+
+ return config;
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_create_linear (GfMonitorConfigManager *config_manager)
+{
+ GfMonitorManager *monitor_manager = config_manager->monitor_manager;
+ GList *logical_monitor_configs;
+ GfMonitor *primary_monitor;
+ GfLogicalMonitorLayoutMode layout_mode;
+ GfLogicalMonitorConfig *primary_logical_monitor_config;
+ int x;
+ GList *monitors;
+ GList *l;
+
+ primary_monitor = find_primary_monitor (monitor_manager);
+ if (!primary_monitor)
+ return NULL;
+
+ layout_mode = gf_monitor_manager_get_default_layout_mode (monitor_manager);
+
+ primary_logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager,
+ primary_monitor,
+ 0, 0, NULL,
+ layout_mode);
+
+ primary_logical_monitor_config->is_primary = TRUE;
+ logical_monitor_configs = g_list_append (NULL, primary_logical_monitor_config);
+
+ x = primary_logical_monitor_config->layout.width;
+ monitors = gf_monitor_manager_get_monitors (monitor_manager);
+ for (l = monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+ GfLogicalMonitorConfig *logical_monitor_config;
+
+ if (monitor == primary_monitor)
+ continue;
+
+ if (gf_monitor_is_laptop_panel (monitor) &&
+ gf_monitor_manager_is_lid_closed (monitor_manager))
+ continue;
+
+ logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager,
+ monitor, x, 0,
+ primary_logical_monitor_config,
+ layout_mode);
+
+ logical_monitor_configs = g_list_append (logical_monitor_configs,
+ logical_monitor_config);
+
+ x += logical_monitor_config->layout.width;
+ }
+
+ return gf_monitors_config_new (logical_monitor_configs, layout_mode,
+ GF_MONITORS_CONFIG_FLAG_NONE);
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_create_fallback (GfMonitorConfigManager *config_manager)
+{
+ GfMonitorManager *monitor_manager = config_manager->monitor_manager;
+ GfMonitor *primary_monitor;
+ GList *logical_monitor_configs;
+ GfLogicalMonitorLayoutMode layout_mode;
+ GfLogicalMonitorConfig *primary_logical_monitor_config;
+
+ primary_monitor = find_primary_monitor (monitor_manager);
+ if (!primary_monitor)
+ return NULL;
+
+ layout_mode = gf_monitor_manager_get_default_layout_mode (monitor_manager);
+
+ primary_logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager,
+ primary_monitor,
+ 0, 0, NULL,
+ layout_mode);
+
+ primary_logical_monitor_config->is_primary = TRUE;
+ logical_monitor_configs = g_list_append (NULL, primary_logical_monitor_config);
+
+ return gf_monitors_config_new (logical_monitor_configs, layout_mode,
+ GF_MONITORS_CONFIG_FLAG_NONE);
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_create_suggested (GfMonitorConfigManager *config_manager)
+{
+ GfMonitorManager *monitor_manager = config_manager->monitor_manager;
+ GfLogicalMonitorConfig *primary_logical_monitor_config = NULL;
+ GfMonitor *primary_monitor;
+ GfLogicalMonitorLayoutMode layout_mode;
+ GList *logical_monitor_configs;
+ GList *region;
+ int x, y;
+ GList *monitors;
+ GList *l;
+
+ primary_monitor = find_primary_monitor (monitor_manager);
+ if (!primary_monitor)
+ return NULL;
+
+ if (!gf_monitor_get_suggested_position (primary_monitor, &x, &y))
+ return NULL;
+
+ layout_mode = gf_monitor_manager_get_default_layout_mode (monitor_manager);
+
+ primary_logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager,
+ primary_monitor,
+ x, y, NULL,
+ layout_mode);
+
+ primary_logical_monitor_config->is_primary = TRUE;
+ logical_monitor_configs = g_list_append (NULL, primary_logical_monitor_config);
+ region = g_list_prepend (NULL, &primary_logical_monitor_config->layout);
+
+ monitors = gf_monitor_manager_get_monitors (monitor_manager);
+ for (l = monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+ GfLogicalMonitorConfig *logical_monitor_config;
+
+ if (monitor == primary_monitor)
+ continue;
+
+ if (!gf_monitor_get_suggested_position (monitor, &x, &y))
+ continue;
+
+ logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager,
+ monitor, x, y,
+ primary_logical_monitor_config,
+ layout_mode);
+
+ logical_monitor_configs = g_list_append (logical_monitor_configs, logical_monitor_config);
+
+ if (gf_rectangle_overlaps_with_region (region, &logical_monitor_config->layout))
+ {
+ g_warning ("Suggested monitor config has overlapping region, rejecting");
+ g_list_free (region);
+ g_list_free_full (logical_monitor_configs,
+ (GDestroyNotify) gf_logical_monitor_config_free);
+
+ return NULL;
+ }
+
+ region = g_list_prepend (region, &logical_monitor_config->layout);
+ }
+
+ g_list_free (region);
+
+ if (!logical_monitor_configs)
+ return NULL;
+
+ return gf_monitors_config_new (logical_monitor_configs, layout_mode,
+ GF_MONITORS_CONFIG_FLAG_NONE);
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_create_for_orientation (GfMonitorConfigManager *config_manager,
+ GfMonitorTransform transform)
+{
+ return create_for_builtin_display_rotation (config_manager, FALSE, transform);
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_create_for_rotate_monitor (GfMonitorConfigManager *config_manager)
+{
+ return create_for_builtin_display_rotation (config_manager, TRUE, GF_MONITOR_TRANSFORM_NORMAL);
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_create_for_switch_config (GfMonitorConfigManager *config_manager,
+ GfMonitorSwitchConfigType config_type)
+{
+ GfMonitorManager *monitor_manager = config_manager->monitor_manager;
+
+ if (!gf_monitor_manager_can_switch_config (monitor_manager))
+ return NULL;
+
+ switch (config_type)
+ {
+ case GF_MONITOR_SWITCH_CONFIG_ALL_MIRROR:
+ return create_for_switch_config_all_mirror (config_manager);
+
+ case GF_MONITOR_SWITCH_CONFIG_ALL_LINEAR:
+ return gf_monitor_config_manager_create_linear (config_manager);
+
+ case GF_MONITOR_SWITCH_CONFIG_EXTERNAL:
+ return create_for_switch_config_external (config_manager);
+
+ case GF_MONITOR_SWITCH_CONFIG_BUILTIN:
+ return create_for_switch_config_builtin (config_manager);
+
+ case GF_MONITOR_SWITCH_CONFIG_UNKNOWN:
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+
+ return NULL;
+}
+
+void
+gf_monitor_config_manager_set_current (GfMonitorConfigManager *config_manager,
+ GfMonitorsConfig *config)
+{
+ if (config_manager->current_config)
+ {
+ g_queue_push_head (&config_manager->config_history,
+ g_object_ref (config_manager->current_config));
+ if (g_queue_get_length (&config_manager->config_history) >
+ CONFIG_HISTORY_MAX_SIZE)
+ g_object_unref (g_queue_pop_tail (&config_manager->config_history));
+ }
+
+ g_set_object (&config_manager->current_config, config);
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_get_current (GfMonitorConfigManager *config_manager)
+{
+ return config_manager->current_config;
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_pop_previous (GfMonitorConfigManager *config_manager)
+{
+ return g_queue_pop_head (&config_manager->config_history);
+}
+
+GfMonitorsConfig *
+gf_monitor_config_manager_get_previous (GfMonitorConfigManager *config_manager)
+{
+ return g_queue_peek_head (&config_manager->config_history);
+}
+
+void
+gf_monitor_config_manager_clear_history (GfMonitorConfigManager *config_manager)
+{
+ g_queue_foreach (&config_manager->config_history, (GFunc) g_object_unref, NULL);
+ g_queue_clear (&config_manager->config_history);
+}
+
+void
+gf_monitor_config_manager_save_current (GfMonitorConfigManager *config_manager)
+{
+ g_return_if_fail (config_manager->current_config);
+
+ gf_monitor_config_store_add (config_manager->config_store,
+ config_manager->current_config);
+}
diff --git a/backends/gf-monitor-config-migration-private.h b/backends/gf-monitor-config-migration-private.h
index 309361d..c86602a 100644
--- a/backends/gf-monitor-config-migration-private.h
+++ b/backends/gf-monitor-config-migration-private.h
@@ -33,6 +33,10 @@ gboolean gf_migrate_old_monitors_config (GfMonitorConfigStore *config_stor
gboolean gf_migrate_old_user_monitors_config (GfMonitorConfigStore *config_store,
GError **error);
+gboolean gf_finish_monitors_config_migration (GfMonitorManager *monitor_manager,
+ GfMonitorsConfig *config,
+ GError **error);
+
G_END_DECLS
#endif
diff --git a/backends/gf-monitor-config-migration.c b/backends/gf-monitor-config-migration.c
index f3970f6..3c4902c 100644
--- a/backends/gf-monitor-config-migration.c
+++ b/backends/gf-monitor-config-migration.c
@@ -58,3 +58,12 @@ gf_migrate_old_user_monitors_config (GfMonitorConfigStore *config_store,
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Not implemented");
return FALSE;
}
+
+gboolean
+gf_finish_monitors_config_migration (GfMonitorManager *monitor_manager,
+ GfMonitorsConfig *config,
+ GError **error)
+{
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Not implemented");
+ return FALSE;
+}
diff --git a/backends/gf-monitor-manager-private.h b/backends/gf-monitor-manager-private.h
index ad45e52..4941c93 100644
--- a/backends/gf-monitor-manager-private.h
+++ b/backends/gf-monitor-manager-private.h
@@ -155,22 +155,38 @@ typedef struct
GfLogicalMonitorLayoutMode (* get_default_layout_mode) (GfMonitorManager *manager);
} GfMonitorManagerClass;
-GType gf_monitor_manager_get_type (void);
+GType gf_monitor_manager_get_type (void);
-GfBackend *gf_monitor_manager_get_backend (GfMonitorManager *manager);
+GfBackend *gf_monitor_manager_get_backend (GfMonitorManager *manager);
-GfMonitor *gf_monitor_manager_get_monitor_from_spec (GfMonitorManager *manager,
- GfMonitorSpec *monitor_spec);
+GfMonitor *gf_monitor_manager_get_primary_monitor (GfMonitorManager *manager);
-void gf_monitor_manager_tiled_monitor_added (GfMonitorManager *manager,
- GfMonitor *monitor);
+GfMonitor *gf_monitor_manager_get_laptop_panel (GfMonitorManager *manager);
-void gf_monitor_manager_tiled_monitor_removed (GfMonitorManager *manager,
- GfMonitor *monitor);
+GfMonitor *gf_monitor_manager_get_monitor_from_spec (GfMonitorManager *manager,
+ GfMonitorSpec
*monitor_spec);
-GfMonitorManagerCapability gf_monitor_manager_get_capabilities (GfMonitorManager *manager);
+GList *gf_monitor_manager_get_monitors (GfMonitorManager *manager);
-GfLogicalMonitorLayoutMode gf_monitor_manager_get_default_layout_mode (GfMonitorManager *manager);
+void gf_monitor_manager_tiled_monitor_added (GfMonitorManager *manager,
+ GfMonitor *monitor);
+
+void gf_monitor_manager_tiled_monitor_removed (GfMonitorManager *manager,
+ GfMonitor *monitor);
+
+gboolean gf_monitor_manager_is_transform_handled (GfMonitorManager *manager,
+ GfCrtc *crtc,
+ GfMonitorTransform transform);
+
+gboolean gf_monitor_manager_is_lid_closed (GfMonitorManager *manager);
+
+gfloat gf_monitor_manager_calculate_monitor_mode_scale (GfMonitorManager *manager,
+ GfMonitor *monitor,
+ GfMonitorMode
*monitor_mode);
+
+GfMonitorManagerCapability gf_monitor_manager_get_capabilities (GfMonitorManager *manager);
+
+GfLogicalMonitorLayoutMode gf_monitor_manager_get_default_layout_mode (GfMonitorManager *manager);
static inline gboolean
gf_monitor_transform_is_rotated (GfMonitorTransform transform)
diff --git a/backends/gf-monitor-manager.c b/backends/gf-monitor-manager.c
index 6595ee8..5d2dea4 100644
--- a/backends/gf-monitor-manager.c
+++ b/backends/gf-monitor-manager.c
@@ -37,6 +37,8 @@ typedef struct
guint bus_name_id;
} GfMonitorManagerPrivate;
+typedef gboolean (* MonitorMatchFunc) (GfMonitor *monitor);
+
enum
{
PROP_0,
@@ -63,6 +65,25 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GfMonitorManager, gf_monitor_manager, GF_DBUS_
G_ADD_PRIVATE (GfMonitorManager)
G_IMPLEMENT_INTERFACE (GF_DBUS_TYPE_DISPLAY_CONFIG,
gf_monitor_manager_display_config_init))
+static GfMonitor *
+find_monitor (GfMonitorManager *monitor_manager,
+ MonitorMatchFunc match_func)
+{
+ GList *monitors;
+ GList *l;
+
+ monitors = gf_monitor_manager_get_monitors (monitor_manager);
+ for (l = monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+
+ if (match_func (monitor))
+ return monitor;
+ }
+
+ return NULL;
+}
+
static gboolean
gf_monitor_manager_handle_get_resources (GfDBusDisplayConfig *skeleton,
GDBusMethodInvocation *invocation)
@@ -331,6 +352,18 @@ gf_monitor_manager_get_backend (GfMonitorManager *manager)
}
GfMonitor *
+gf_monitor_manager_get_primary_monitor (GfMonitorManager *manager)
+{
+ return find_monitor (manager, gf_monitor_is_primary);
+}
+
+GfMonitor *
+gf_monitor_manager_get_laptop_panel (GfMonitorManager *manager)
+{
+ return find_monitor (manager, gf_monitor_is_laptop_panel);
+}
+
+GfMonitor *
gf_monitor_manager_get_monitor_from_spec (GfMonitorManager *manager,
GfMonitorSpec *monitor_spec)
{
@@ -347,6 +380,12 @@ gf_monitor_manager_get_monitor_from_spec (GfMonitorManager *manager,
return NULL;
}
+GList *
+gf_monitor_manager_get_monitors (GfMonitorManager *manager)
+{
+ return manager->monitors;
+}
+
void
gf_monitor_manager_tiled_monitor_added (GfMonitorManager *manager,
GfMonitor *monitor)
@@ -371,6 +410,36 @@ gf_monitor_manager_tiled_monitor_removed (GfMonitorManager *manager,
manager_class->tiled_monitor_removed (manager, monitor);
}
+gboolean
+gf_monitor_manager_is_transform_handled (GfMonitorManager *manager,
+ GfCrtc *crtc,
+ GfMonitorTransform transform)
+{
+ GfMonitorManagerClass *manager_class;
+
+ manager_class = GF_MONITOR_MANAGER_GET_CLASS (manager);
+
+ return manager_class->is_transform_handled (manager, crtc, transform);
+}
+
+gboolean
+gf_monitor_manager_is_lid_closed (GfMonitorManager *manager)
+{
+ return GF_MONITOR_MANAGER_GET_CLASS (manager)->is_lid_closed (manager);
+}
+
+gfloat
+gf_monitor_manager_calculate_monitor_mode_scale (GfMonitorManager *manager,
+ GfMonitor *monitor,
+ GfMonitorMode *monitor_mode)
+{
+ GfMonitorManagerClass *manager_class;
+
+ manager_class = GF_MONITOR_MANAGER_GET_CLASS (manager);
+
+ return manager_class->calculate_monitor_mode_scale (manager, monitor, monitor_mode);
+}
+
GfMonitorManagerCapability
gf_monitor_manager_get_capabilities (GfMonitorManager *manager)
{
@@ -390,3 +459,24 @@ gf_monitor_manager_get_default_layout_mode (GfMonitorManager *manager)
return manager_class->get_default_layout_mode (manager);
}
+
+gboolean
+gf_monitor_manager_get_is_builtin_display_on (GfMonitorManager *manager)
+{
+ GfMonitor *laptop_panel;
+
+ g_return_val_if_fail (GF_IS_MONITOR_MANAGER (manager), FALSE);
+
+ laptop_panel = gf_monitor_manager_get_laptop_panel (manager);
+ if (!laptop_panel)
+ return FALSE;
+
+ return gf_monitor_is_active (laptop_panel);
+}
+
+gboolean
+gf_monitor_manager_can_switch_config (GfMonitorManager *manager)
+{
+ return (!gf_monitor_manager_is_lid_closed (manager) &&
+ g_list_length (manager->monitors) > 1);
+}
diff --git a/backends/gf-monitor-manager.h b/backends/gf-monitor-manager.h
index 9c7ac64..a83eae8 100644
--- a/backends/gf-monitor-manager.h
+++ b/backends/gf-monitor-manager.h
@@ -26,8 +26,21 @@
G_BEGIN_DECLS
+typedef enum
+{
+ GF_MONITOR_SWITCH_CONFIG_ALL_MIRROR,
+ GF_MONITOR_SWITCH_CONFIG_ALL_LINEAR,
+ GF_MONITOR_SWITCH_CONFIG_EXTERNAL,
+ GF_MONITOR_SWITCH_CONFIG_BUILTIN,
+ GF_MONITOR_SWITCH_CONFIG_UNKNOWN,
+} GfMonitorSwitchConfigType;
+
typedef struct _GfMonitorManager GfMonitorManager;
+gboolean gf_monitor_manager_get_is_builtin_display_on (GfMonitorManager *manager);
+
+gboolean gf_monitor_manager_can_switch_config (GfMonitorManager *manager);
+
G_END_DECLS
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]