From d9a0f2a88d2abc2d0862da1691161baddbab5ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 13 Dec 2016 10:53:38 +0800 Subject: [PATCH] monitor-manager: Generate a monitor abstraction from outputs and crtcs Generate a set of "monitors" abstracting the physical concepts. Each monitor is built up of one or more outputs; multiple outputs being tiled monitors. Logical monitors will later be built from these. https://bugzilla.gnome.org/show_bug.cgi?id=777732 --- src/Makefile.am | 3 + src/backends/meta-monitor-manager-private.h | 7 + src/backends/meta-monitor-manager.c | 46 ++++ src/backends/meta-monitor.c | 268 ++++++++++++++++++++ src/backends/meta-monitor.h | 69 +++++ 5 files changed, 393 insertions(+) create mode 100644 src/backends/meta-monitor.c create mode 100644 src/backends/meta-monitor.h diff --git a/src/Makefile.am b/src/Makefile.am index b2509ad0e..d5af5b2a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -105,6 +105,9 @@ libmutter_la_SOURCES = \ backends/meta-logical-monitor.h \ backends/meta-monitor-config.c \ backends/meta-monitor-config.h \ + backends/meta-monitor.c \ + backends/meta-monitor.h \ + backends/meta-monitor-private.h \ backends/meta-monitor-manager.c \ meta/meta-monitor-manager.h \ backends/meta-monitor-manager-private.h \ diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index 53f1e4e48..e27107b54 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -50,6 +50,9 @@ typedef struct _MetaMonitorConfigClass MetaMonitorConfigClass; typedef struct _MetaMonitorConfig MetaMonitorConfig; +typedef struct _MetaMonitor MetaMonitor; +typedef struct _MetaMonitorNormal MetaMonitorNormal; +typedef struct _MetaMonitorTiled MetaMonitorTiled; typedef struct _MetaLogicalMonitor MetaLogicalMonitor; typedef struct _MetaCrtc MetaCrtc; @@ -266,6 +269,8 @@ struct _MetaMonitorManager MetaCrtc *crtcs; unsigned int n_crtcs; + GList *monitors; + GList *logical_monitors; MetaLogicalMonitor *primary_logical_monitor; @@ -344,6 +349,8 @@ MetaLogicalMonitor *meta_monitor_manager_get_logical_monitor_neighbor (MetaMonit MetaLogicalMonitor *logical_monitor, MetaScreenDirection direction); +GList * meta_monitor_manager_get_monitors (MetaMonitorManager *manager); + MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager, unsigned int *n_outputs); diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 588c08436..14dd50319 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -38,6 +38,7 @@ #include "edid.h" #include "meta-monitor-config.h" #include "backends/meta-logical-monitor.h" +#include "backends/meta-monitor.h" #include "backends/x11/meta-monitor-manager-xrandr.h" #include "meta-backend-private.h" @@ -1446,6 +1447,12 @@ meta_monitor_manager_get_logical_monitor_neighbor (MetaMonitorManager *manager, return NULL; } +GList * +meta_monitor_manager_get_monitors (MetaMonitorManager *manager) +{ + return manager->monitors; +} + MetaOutput * meta_monitor_manager_get_outputs (MetaMonitorManager *manager, unsigned int *n_outputs) @@ -1498,6 +1505,43 @@ meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager, *height = manager->max_screen_height; } +static void +rebuild_monitors (MetaMonitorManager *manager) +{ + unsigned int i; + + if (manager->monitors) + { + g_list_free_full (manager->monitors, g_object_unref); + manager->monitors = NULL; + } + + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *output = &manager->outputs[i]; + + if (output->tile_info.group_id) + { + if (is_main_tiled_monitor_output (output)) + { + MetaMonitorTiled *monitor_tiled; + + monitor_tiled = meta_monitor_tiled_new (manager, output); + manager->monitors = g_list_append (manager->monitors, + monitor_tiled); + } + } + else + { + MetaMonitorNormal *monitor_normal; + + monitor_normal = meta_monitor_normal_new (output); + manager->monitors = g_list_append (manager->monitors, + monitor_normal); + } + } +} + void meta_monitor_manager_read_current_config (MetaMonitorManager *manager) { @@ -1519,6 +1563,8 @@ meta_monitor_manager_read_current_config (MetaMonitorManager *manager) manager->serial++; META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager); + rebuild_monitors (manager); + meta_monitor_manager_free_output_array (old_outputs, n_old_outputs); meta_monitor_manager_free_mode_array (old_modes, n_old_modes); meta_monitor_manager_free_crtc_array (old_crtcs, n_old_crtcs); diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c new file mode 100644 index 000000000..d52868697 --- /dev/null +++ b/src/backends/meta-monitor.c @@ -0,0 +1,268 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2016 Red Hat + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/meta-monitor.h" + +#include "backends/meta-monitor-manager-private.h" + +typedef struct _MetaMonitorPrivate +{ + GList *outputs; + + /* + * The primary or first output for this monitor, 0 if we can't figure out. + * It can be matched to a winsys_id of a MetaOutput. + * + * This is used as an opaque token on reconfiguration when switching from + * clone to extened, to decide on what output the windows should go next + * (it's an attempt to keep windows on the same monitor, and preferably on + * the primary one). + */ + long winsys_id; +} MetaMonitorPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaMonitor, meta_monitor, G_TYPE_OBJECT) + +struct _MetaMonitorNormal +{ + MetaMonitor parent; +}; + +G_DEFINE_TYPE (MetaMonitorNormal, meta_monitor_normal, META_TYPE_MONITOR) + +struct _MetaMonitorTiled +{ + MetaMonitor parent; + + uint32_t tile_group_id; + + MetaOutput *main_output; +}; + +G_DEFINE_TYPE (MetaMonitorTiled, meta_monitor_tiled, META_TYPE_MONITOR) + +GList * +meta_monitor_get_outputs (MetaMonitor *monitor) +{ + MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor); + + return priv->outputs; +} + +static MetaOutput * +meta_monitor_get_main_output (MetaMonitor *monitor) +{ + return META_MONITOR_GET_CLASS (monitor)->get_main_output (monitor); +} + +gboolean +meta_monitor_is_active (MetaMonitor *monitor) +{ + MetaOutput *output; + + output = meta_monitor_get_main_output (monitor); + + return output->crtc && output->crtc->current_mode; +} + +void +meta_monitor_get_dimensions (MetaMonitor *monitor, + int *width, + int *height) +{ + META_MONITOR_GET_CLASS (monitor)->get_dimensions (monitor, width, height); +} + +void +meta_monitor_get_physical_dimensions (MetaMonitor *monitor, + int *width_mm, + int *height_mm) +{ + MetaOutput *output; + + output = meta_monitor_get_main_output (monitor); + *width_mm = output->width_mm; + *height_mm = output->height_mm; +} + +static void +meta_monitor_finalize (GObject *object) +{ + MetaMonitor *monitor = META_MONITOR (object); + MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor); + + g_clear_pointer (&priv->outputs, g_list_free); +} + +static void +meta_monitor_init (MetaMonitor *monitor) +{ +} + +static void +meta_monitor_class_init (MetaMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_monitor_finalize; +} + +MetaMonitorNormal * +meta_monitor_normal_new (MetaOutput *output) +{ + MetaMonitorNormal *monitor_normal; + MetaMonitorPrivate *monitor_priv; + + monitor_normal = g_object_new (META_TYPE_MONITOR_NORMAL, NULL); + monitor_priv = + meta_monitor_get_instance_private (META_MONITOR (monitor_normal)); + + monitor_priv->outputs = g_list_append (NULL, output); + monitor_priv->winsys_id = output->winsys_id; + + return monitor_normal; +} + +static MetaOutput * +meta_monitor_normal_get_main_output (MetaMonitor *monitor) +{ + MetaMonitorPrivate *monitor_priv = + meta_monitor_get_instance_private (monitor); + + return monitor_priv->outputs->data; +} + +static void +meta_monitor_normal_get_dimensions (MetaMonitor *monitor, + int *width, + int *height) +{ + MetaOutput *output; + + output = meta_monitor_get_main_output (monitor); + *width = output->crtc->rect.width; + *height = output->crtc->rect.height; +} + +static void +meta_monitor_normal_init (MetaMonitorNormal *monitor) +{ +} + +static void +meta_monitor_normal_class_init (MetaMonitorNormalClass *klass) +{ + MetaMonitorClass *monitor_class = META_MONITOR_CLASS (klass); + + monitor_class->get_main_output = meta_monitor_normal_get_main_output; + monitor_class->get_dimensions = meta_monitor_normal_get_dimensions; +} + +static void +add_tiled_monitor_outputs (MetaMonitorManager *monitor_manager, + MetaMonitorTiled *monitor_tiled) +{ + MetaMonitorPrivate *monitor_priv = + meta_monitor_get_instance_private (META_MONITOR (monitor_tiled)); + unsigned int i; + + for (i = 0; i < monitor_manager->n_outputs; i++) + { + MetaOutput *output = &monitor_manager->outputs[i]; + + if (output->tile_info.group_id != monitor_tiled->tile_group_id) + continue; + + monitor_priv->outputs = g_list_append (monitor_priv->outputs, output); + } +} + +MetaMonitorTiled * +meta_monitor_tiled_new (MetaMonitorManager *monitor_manager, + MetaOutput *output) +{ + MetaMonitorTiled *monitor_tiled; + MetaMonitorPrivate *monitor_priv; + + monitor_tiled = g_object_new (META_TYPE_MONITOR_TILED, NULL); + monitor_priv = + meta_monitor_get_instance_private (META_MONITOR (monitor_tiled)); + + monitor_tiled->tile_group_id = output->tile_info.group_id; + monitor_priv->winsys_id = output->winsys_id; + + add_tiled_monitor_outputs (monitor_manager, monitor_tiled); + monitor_tiled->main_output = output; + + return monitor_tiled; +} + +static MetaOutput * +meta_monitor_tiled_get_main_output (MetaMonitor *monitor) +{ + MetaMonitorTiled *monitor_tiled = META_MONITOR_TILED (monitor); + + return monitor_tiled->main_output; +} + +static void +meta_monitor_tiled_get_dimensions (MetaMonitor *monitor, + int *out_width, + int *out_height) +{ + MetaMonitorPrivate *monitor_priv = + meta_monitor_get_instance_private (monitor); + GList *l; + int width; + int height; + + width = 0; + height = 0; + for (l = monitor_priv->outputs; l; l = l->next) + { + MetaOutput *output = l->data; + + if (output->tile_info.loc_v_tile == 0) + width += output->tile_info.tile_w; + + if (output->tile_info.loc_h_tile == 0) + height += output->tile_info.tile_h; + } + + *out_width = width; + *out_height = height; +} + +static void +meta_monitor_tiled_init (MetaMonitorTiled *monitor) +{ +} + +static void +meta_monitor_tiled_class_init (MetaMonitorTiledClass *klass) +{ + MetaMonitorClass *monitor_class = META_MONITOR_CLASS (klass); + + monitor_class->get_main_output = meta_monitor_tiled_get_main_output; + monitor_class->get_dimensions = meta_monitor_tiled_get_dimensions; +} diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h new file mode 100644 index 000000000..b469e18c3 --- /dev/null +++ b/src/backends/meta-monitor.h @@ -0,0 +1,69 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2016 Red Hat + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_MONITOR_H +#define META_MONITOR_H + +#include + +#include "backends/meta-monitor-manager-private.h" + +#define META_TYPE_MONITOR (meta_monitor_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaMonitor, meta_monitor, META, MONITOR, GObject) + +struct _MetaMonitorClass +{ + GObjectClass parent_class; + + MetaOutput * (* get_main_output) (MetaMonitor *monitor); + void (* get_dimensions) (MetaMonitor *monitor, + int *width, + int *height); +}; + +#define META_TYPE_MONITOR_NORMAL (meta_monitor_normal_get_type ()) +G_DECLARE_FINAL_TYPE (MetaMonitorNormal, meta_monitor_normal, + META, MONITOR_NORMAL, + MetaMonitor) + +#define META_TYPE_MONITOR_TILED (meta_monitor_tiled_get_type ()) +G_DECLARE_FINAL_TYPE (MetaMonitorTiled, meta_monitor_tiled, + META, MONITOR_TILED, + MetaMonitor) + +MetaMonitorTiled * meta_monitor_tiled_new (MetaMonitorManager *monitor_manager, + MetaOutput *main_output); + +MetaMonitorNormal * meta_monitor_normal_new (MetaOutput *output); + +gboolean meta_monitor_is_active (MetaMonitor *monitor); + +GList * meta_monitor_get_outputs (MetaMonitor *monitor); + +void meta_monitor_get_dimensions (MetaMonitor *monitor, + int *width, + int *height); + +void meta_monitor_get_physical_dimensions (MetaMonitor *monitor, + int *width_mm, + int *height_mm); + +#endif /* META_MONITOR_H */