[gnome-flashback] backends: add GfMonitorsConfig
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] backends: add GfMonitorsConfig
- Date: Thu, 21 Sep 2017 00:08:24 +0000 (UTC)
commit b68ab446d64973f01bbd55ac340cdf552cc482fc
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Wed Sep 20 18:31:08 2017 +0300
backends: add GfMonitorsConfig
backends/Makefile.am | 4 +
backends/gf-monitor-manager-private.h | 18 +-
backends/gf-monitor-manager.c | 10 +
backends/gf-monitors-config-private.h | 73 ++++++++
backends/gf-monitors-config.c | 294 +++++++++++++++++++++++++++++++++
backends/gf-rectangle-private.h | 37 ++++
backends/gf-rectangle.c | 77 +++++++++
7 files changed, 505 insertions(+), 8 deletions(-)
---
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 1eeb37b..1c3bea5 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -59,10 +59,14 @@ libbackends_la_SOURCES = \
gf-monitor-tiled-private.h \
gf-monitor-tiled.c \
gf-monitor.c \
+ gf-monitors-config-private.h \
+ gf-monitors-config.c \
gf-orientation-manager-private.h \
gf-orientation-manager.c \
gf-output-private.h \
gf-output.c \
+ gf-rectangle-private.h \
+ gf-rectangle.c \
gf-rectangle.h \
gf-settings-private.h \
gf-settings.c \
diff --git a/backends/gf-monitor-manager-private.h b/backends/gf-monitor-manager-private.h
index d56db1d..7228286 100644
--- a/backends/gf-monitor-manager-private.h
+++ b/backends/gf-monitor-manager-private.h
@@ -155,18 +155,20 @@ 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_monitor_from_spec (GfMonitorManager *manager,
+ GfMonitorSpec *monitor_spec);
-void gf_monitor_manager_tiled_monitor_added (GfMonitorManager *manager,
- GfMonitor *monitor);
+void gf_monitor_manager_tiled_monitor_added (GfMonitorManager *manager,
+ GfMonitor *monitor);
-void gf_monitor_manager_tiled_monitor_removed (GfMonitorManager *manager,
- GfMonitor *monitor);
+void gf_monitor_manager_tiled_monitor_removed (GfMonitorManager *manager,
+ GfMonitor *monitor);
+
+GfMonitorManagerCapability gf_monitor_manager_get_capabilities (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 902a982..ba7b808 100644
--- a/backends/gf-monitor-manager.c
+++ b/backends/gf-monitor-manager.c
@@ -370,3 +370,13 @@ gf_monitor_manager_tiled_monitor_removed (GfMonitorManager *manager,
if (manager_class->tiled_monitor_removed)
manager_class->tiled_monitor_removed (manager, monitor);
}
+
+GfMonitorManagerCapability
+gf_monitor_manager_get_capabilities (GfMonitorManager *manager)
+{
+ GfMonitorManagerClass *manager_class;
+
+ manager_class = GF_MONITOR_MANAGER_GET_CLASS (manager);
+
+ return manager_class->get_capabilities (manager);
+}
diff --git a/backends/gf-monitors-config-private.h b/backends/gf-monitors-config-private.h
new file mode 100644
index 0000000..065378d
--- /dev/null
+++ b/backends/gf-monitors-config-private.h
@@ -0,0 +1,73 @@
+/*
+ * 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.h
+ */
+
+#ifndef GF_MONITORS_CONFIG_PRIVATE_H
+#define GF_MONITORS_CONFIG_PRIVATE_H
+
+#include "gf-monitor-manager-private.h"
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+ GList *monitor_specs;
+} GfMonitorsConfigKey;
+
+typedef enum
+{
+ GF_MONITORS_CONFIG_FLAG_NONE = 0,
+ GF_MONITORS_CONFIG_FLAG_MIGRATED = (1 << 0),
+} GfMonitorsConfigFlag;
+
+struct _GfMonitorsConfig
+{
+ GObject parent;
+
+ GfMonitorsConfigKey *key;
+ GList *logical_monitor_configs;
+
+ GfMonitorsConfigFlag flags;
+
+ GfLogicalMonitorLayoutMode layout_mode;
+};
+
+#define GF_TYPE_MONITORS_CONFIG (gf_monitors_config_get_type ())
+G_DECLARE_FINAL_TYPE (GfMonitorsConfig, gf_monitors_config,
+ GF, MONITORS_CONFIG, GObject)
+
+GfMonitorsConfig *gf_monitors_config_new (GList *logical_monitor_configs,
+ GfLogicalMonitorLayoutMode layout_mode,
+ GfMonitorsConfigFlag flags);
+
+guint gf_monitors_config_key_hash (gconstpointer data);
+
+gboolean gf_monitors_config_key_equal (gconstpointer data_a,
+ gconstpointer data_b);
+
+void gf_monitors_config_key_free (GfMonitorsConfigKey *config_key);
+
+gboolean gf_verify_monitors_config (GfMonitorsConfig *config,
+ GfMonitorManager *monitor_manager,
+ GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/backends/gf-monitors-config.c b/backends/gf-monitors-config.c
new file mode 100644
index 0000000..b88393f
--- /dev/null
+++ b/backends/gf-monitors-config.c
@@ -0,0 +1,294 @@
+/*
+ * 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 "gf-logical-monitor-config-private.h"
+#include "gf-monitor-config-private.h"
+#include "gf-monitor-spec-private.h"
+#include "gf-monitors-config-private.h"
+#include "gf-rectangle-private.h"
+
+G_DEFINE_TYPE (GfMonitorsConfig, gf_monitors_config, G_TYPE_OBJECT)
+
+static gboolean
+has_adjecent_neighbour (GfMonitorsConfig *config,
+ GfLogicalMonitorConfig *logical_monitor_config)
+{
+ GList *l;
+
+ if (!config->logical_monitor_configs->next)
+ {
+ g_assert (config->logical_monitor_configs->data == logical_monitor_config);
+ return TRUE;
+ }
+
+ for (l = config->logical_monitor_configs; l; l = l->next)
+ {
+ GfLogicalMonitorConfig *other_logical_monitor_config = l->data;
+
+ if (logical_monitor_config == other_logical_monitor_config)
+ continue;
+
+ if (gf_rectangle_is_adjecent_to (&logical_monitor_config->layout,
+ &other_logical_monitor_config->layout))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GfMonitorsConfigKey *
+gf_monitors_config_key_new (GList *logical_monitor_configs)
+{
+ GfMonitorsConfigKey *config_key;
+ GList *monitor_specs;
+ GList *l;
+
+ monitor_specs = NULL;
+ for (l = logical_monitor_configs; l; l = l->next)
+ {
+ GfLogicalMonitorConfig *logical_monitor_config = l->data;
+ GList *k;
+
+ for (k = logical_monitor_config->monitor_configs; k; k = k->next)
+ {
+ GfMonitorConfig *monitor_config = k->data;
+ GfMonitorSpec *monitor_spec;
+
+ monitor_spec = gf_monitor_spec_clone (monitor_config->monitor_spec);
+ monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
+ }
+ }
+
+ 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_monitors_config_finalize (GObject *object)
+{
+ GfMonitorsConfig *config;
+
+ config = GF_MONITORS_CONFIG (object);
+
+ gf_monitors_config_key_free (config->key);
+ g_list_free_full (config->logical_monitor_configs,
+ (GDestroyNotify) gf_logical_monitor_config_free);
+
+ G_OBJECT_CLASS (gf_monitors_config_parent_class)->finalize (object);
+}
+
+static void
+gf_monitors_config_class_init (GfMonitorsConfigClass *config_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (config_class);
+
+ object_class->finalize = gf_monitors_config_finalize;
+}
+
+static void
+gf_monitors_config_init (GfMonitorsConfig *config)
+{
+}
+
+GfMonitorsConfig *
+gf_monitors_config_new (GList *logical_monitor_configs,
+ GfLogicalMonitorLayoutMode layout_mode,
+ GfMonitorsConfigFlag flags)
+{
+ GfMonitorsConfig *config;
+
+ config = g_object_new (GF_TYPE_MONITORS_CONFIG, NULL);
+ config->logical_monitor_configs = logical_monitor_configs;
+ config->key = gf_monitors_config_key_new (logical_monitor_configs);
+ config->layout_mode = layout_mode;
+ config->flags = flags;
+
+ return config;
+}
+
+guint
+gf_monitors_config_key_hash (gconstpointer data)
+{
+ const GfMonitorsConfigKey *config_key;
+ glong hash;
+ GList *l;
+
+ config_key = data;
+ hash = 0;
+
+ for (l = config_key->monitor_specs; l; l = l->next)
+ {
+ GfMonitorSpec *monitor_spec = l->data;
+
+ hash ^= (g_str_hash (monitor_spec->connector) ^
+ g_str_hash (monitor_spec->vendor) ^
+ g_str_hash (monitor_spec->product) ^
+ g_str_hash (monitor_spec->serial));
+ }
+
+ return hash;
+}
+
+gboolean
+gf_monitors_config_key_equal (gconstpointer data_a,
+ gconstpointer data_b)
+{
+ const GfMonitorsConfigKey *config_key_a;
+ const GfMonitorsConfigKey *config_key_b;
+ GList *l_a, *l_b;
+
+ config_key_a = data_a;
+ config_key_b = data_b;
+
+ for (l_a = config_key_a->monitor_specs, l_b = config_key_b->monitor_specs;
+ l_a && l_b;
+ l_a = l_a->next, l_b = l_b->next)
+ {
+ GfMonitorSpec *monitor_spec_a = l_a->data;
+ GfMonitorSpec *monitor_spec_b = l_b->data;
+
+ if (!gf_monitor_spec_equals (monitor_spec_a, monitor_spec_b))
+ return FALSE;
+ }
+
+ if (l_a || l_b)
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+gf_monitors_config_key_free (GfMonitorsConfigKey *config_key)
+{
+ g_list_free_full (config_key->monitor_specs, (GDestroyNotify) gf_monitor_spec_free);
+ g_free (config_key);
+}
+
+gboolean
+gf_verify_monitors_config (GfMonitorsConfig *config,
+ GfMonitorManager *monitor_manager,
+ GError **error)
+{
+ gint min_x, min_y;
+ gboolean has_primary;
+ GList *region;
+ GList *l;
+ gboolean global_scale_required;
+
+ if (!config->logical_monitor_configs)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Monitors config incomplete");
+
+ return FALSE;
+ }
+
+ global_scale_required = !!(gf_monitor_manager_get_capabilities (monitor_manager) &
+ GF_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
+
+ min_x = INT_MAX;
+ min_y = INT_MAX;
+ region = NULL;
+ has_primary = FALSE;
+ for (l = config->logical_monitor_configs; l; l = l->next)
+ {
+ GfLogicalMonitorConfig *logical_monitor_config = l->data;
+
+ if (global_scale_required)
+ {
+ GfLogicalMonitorConfig *prev_logical_monitor_config;
+
+ prev_logical_monitor_config = l->prev ? l->prev->data : NULL;
+
+ if (prev_logical_monitor_config &&
+ (prev_logical_monitor_config->scale !=
+ logical_monitor_config->scale))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Logical monitor scales must be identical");
+
+ return FALSE;
+ }
+ }
+
+ if (gf_rectangle_overlaps_with_region (region, &logical_monitor_config->layout))
+ {
+ g_list_free (region);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Logical monitors overlap");
+
+ return FALSE;
+ }
+
+ if (has_primary && logical_monitor_config->is_primary)
+ {
+ g_list_free (region);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Config contains multiple primary logical monitors");
+
+ return FALSE;
+ }
+ else if (logical_monitor_config->is_primary)
+ {
+ has_primary = TRUE;
+ }
+
+ if (!has_adjecent_neighbour (config, logical_monitor_config))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Logical monitors not adjecent");
+
+ return FALSE;
+ }
+
+ min_x = MIN (logical_monitor_config->layout.x, min_x);
+ min_y = MIN (logical_monitor_config->layout.y, min_y);
+
+ region = g_list_prepend (region, &logical_monitor_config->layout);
+ }
+
+ g_list_free (region);
+
+ if (min_x != 0 || min_y != 0)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Logical monitors positions are offset");
+
+ return FALSE;
+ }
+
+ if (!has_primary)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Config is missing primary logical");
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/backends/gf-rectangle-private.h b/backends/gf-rectangle-private.h
new file mode 100644
index 0000000..490261a
--- /dev/null
+++ b/backends/gf-rectangle-private.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2005, 2006 Elijah Newren
+ * 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/core/boxes-private.h
+ */
+
+#ifndef GF_RECTANGLE_PRIVATE_H
+#define GF_RECTANGLE_PRIVATE_H
+
+#include "gf-rectangle.h"
+
+G_BEGIN_DECLS
+
+gboolean gf_rectangle_overlaps_with_region (const GList *spanning_rects,
+ const GfRectangle *rect);
+
+gboolean gf_rectangle_is_adjecent_to (const GfRectangle *rect,
+ const GfRectangle *other);
+
+G_END_DECLS
+
+#endif
diff --git a/backends/gf-rectangle.c b/backends/gf-rectangle.c
new file mode 100644
index 0000000..bddd481
--- /dev/null
+++ b/backends/gf-rectangle.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2005, 2006 Elijah Newren
+ * 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/core/boxes.c
+ */
+
+#include "config.h"
+#include "gf-rectangle-private.h"
+
+static gboolean
+gf_rectangle_overlap (const GfRectangle *rect1,
+ const GfRectangle *rect2)
+{
+ g_return_val_if_fail (rect1 != NULL, FALSE);
+ g_return_val_if_fail (rect2 != NULL, FALSE);
+
+ return !((rect1->x + rect1->width <= rect2->x) ||
+ (rect2->x + rect2->width <= rect1->x) ||
+ (rect1->y + rect1->height <= rect2->y) ||
+ (rect2->y + rect2->height <= rect1->y));
+}
+
+gboolean
+gf_rectangle_overlaps_with_region (const GList *spanning_rects,
+ const GfRectangle *rect)
+{
+ const GList *temp;
+ gboolean overlaps;
+
+ temp = spanning_rects;
+ overlaps = FALSE;
+ while (!overlaps && temp != NULL)
+ {
+ overlaps = overlaps || gf_rectangle_overlap (temp->data, rect);
+ temp = temp->next;
+ }
+
+ return overlaps;
+}
+
+gboolean
+gf_rectangle_is_adjecent_to (const GfRectangle *rect,
+ const GfRectangle *other)
+{
+ gint rect_x1 = rect->x;
+ gint rect_y1 = rect->y;
+ gint rect_x2 = rect->x + rect->width;
+ gint rect_y2 = rect->y + rect->height;
+ gint other_x1 = other->x;
+ gint other_y1 = other->y;
+ gint other_x2 = other->x + other->width;
+ gint other_y2 = other->y + other->height;
+
+ if ((rect_x1 == other_x2 || rect_x2 == other_x1) &&
+ !(rect_y2 <= other_y1 || rect_y1 >= other_y2))
+ return TRUE;
+ else if ((rect_y1 == other_y2 || rect_y2 == other_y1) &&
+ !(rect_x2 <= other_x1 || rect_x1 >= other_x2))
+ return TRUE;
+ else
+ return FALSE;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]