2013-07-18 11:09:16 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
2014-05-02 13:34:02 +00:00
|
|
|
/*
|
2013-07-18 11:09:16 +00:00
|
|
|
* Copyright (C) 2001, 2002 Havoc Pennington
|
|
|
|
* Copyright (C) 2002, 2003 Red Hat Inc.
|
|
|
|
* Some ICCCM manager selection code derived from fvwm2,
|
|
|
|
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
|
|
|
|
* Copyright (C) 2003 Rob Adams
|
|
|
|
* Copyright (C) 2004-2006 Elijah Newren
|
|
|
|
* Copyright (C) 2013 Red Hat Inc.
|
2020-02-05 00:41:34 +00:00
|
|
|
* Copyright (C) 2020 NVIDIA CORPORATION
|
2014-05-02 13:34:02 +00:00
|
|
|
*
|
2013-07-18 11:09:16 +00:00
|
|
|
* 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.
|
2014-05-02 13:34:02 +00:00
|
|
|
*
|
2013-07-18 11:09:16 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
2014-01-12 01:42:06 +00:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2013-07-18 11:09:16 +00:00
|
|
|
*/
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
2023-03-28 14:35:11 +00:00
|
|
|
* MetaMonitorManager:
|
2023-05-23 18:25:54 +00:00
|
|
|
*
|
2023-03-28 14:35:11 +00:00
|
|
|
* A manager for multiple monitors
|
2018-10-19 07:15:54 +00:00
|
|
|
*
|
|
|
|
* #MetaMonitorManager is an abstract class which contains methods to handle
|
|
|
|
* multiple monitors (both #MetaMonitor and #MetaLogicalMonitor) and GPU's
|
|
|
|
* (#MetaGpu). Its functions include reading and/or changing the current
|
|
|
|
* configuration and available capabiliies.
|
|
|
|
*
|
|
|
|
* The #MetaMonitorManager also provides the "org.gnome.Mutter.DisplayConfig"
|
|
|
|
* DBus service, so apps like GNOME Settings can use this functionality.
|
|
|
|
*/
|
|
|
|
|
2013-07-18 11:09:16 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "backends/meta-monitor-manager-private.h"
|
2014-04-01 02:04:10 +00:00
|
|
|
|
2013-07-19 12:39:28 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
2013-07-24 13:35:47 +00:00
|
|
|
#include <stdlib.h>
|
2013-07-18 11:09:16 +00:00
|
|
|
|
2018-04-16 18:07:45 +00:00
|
|
|
#include "backends/meta-backend-private.h"
|
2017-03-28 04:35:19 +00:00
|
|
|
#include "backends/meta-crtc.h"
|
2016-12-13 02:37:11 +00:00
|
|
|
#include "backends/meta-logical-monitor.h"
|
2016-12-13 02:53:38 +00:00
|
|
|
#include "backends/meta-monitor.h"
|
2017-01-09 06:31:18 +00:00
|
|
|
#include "backends/meta-monitor-config-manager.h"
|
2021-09-30 19:06:38 +00:00
|
|
|
#include "backends/meta-monitor-config-store.h"
|
2017-04-28 15:53:07 +00:00
|
|
|
#include "backends/meta-orientation-manager.h"
|
2017-03-24 09:35:51 +00:00
|
|
|
#include "backends/meta-output.h"
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
#include "backends/meta-virtual-monitor.h"
|
2014-04-01 03:25:37 +00:00
|
|
|
#include "backends/x11/meta-monitor-manager-xrandr.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "clutter/clutter.h"
|
|
|
|
#include "core/util-private.h"
|
|
|
|
#include "meta/main.h"
|
2023-09-01 20:20:16 +00:00
|
|
|
#include "meta/meta-enum-types.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "meta/meta-x11-errors.h"
|
2013-07-18 11:09:16 +00:00
|
|
|
|
2021-04-12 09:46:30 +00:00
|
|
|
#include "meta-dbus-display-config.h"
|
|
|
|
|
2014-08-21 00:07:13 +00:00
|
|
|
#define DEFAULT_DISPLAY_CONFIGURATION_TIMEOUT 20
|
|
|
|
|
2017-07-10 09:39:07 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
|
|
|
|
PROP_BACKEND,
|
2020-06-11 16:15:22 +00:00
|
|
|
PROP_PANEL_ORIENTATION_MANAGED,
|
2021-12-02 20:43:08 +00:00
|
|
|
PROP_HAS_BUILTIN_PANEL,
|
2022-08-15 12:09:29 +00:00
|
|
|
PROP_NIGHT_LIGHT_SUPPORTED,
|
2023-03-02 00:35:10 +00:00
|
|
|
PROP_EXPERIMENTAL_HDR,
|
2017-07-10 09:39:07 +00:00
|
|
|
|
|
|
|
PROP_LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
static GParamSpec *obj_props[PROP_LAST];
|
|
|
|
|
2018-12-19 08:04:25 +00:00
|
|
|
enum
|
|
|
|
{
|
2019-01-23 01:49:26 +00:00
|
|
|
MONITORS_CHANGED,
|
2017-10-13 00:14:40 +00:00
|
|
|
MONITORS_CHANGED_INTERNAL,
|
2019-01-23 01:49:26 +00:00
|
|
|
POWER_SAVE_MODE_CHANGED,
|
2013-07-29 08:12:24 +00:00
|
|
|
CONFIRM_DISPLAY_CHANGE,
|
2021-08-02 16:22:46 +00:00
|
|
|
MONITOR_PRIVACY_SCREEN_CHANGED,
|
2013-07-18 11:09:16 +00:00
|
|
|
SIGNALS_LAST
|
|
|
|
};
|
|
|
|
|
2014-12-11 17:14:00 +00:00
|
|
|
/* Array index matches MetaMonitorTransform */
|
|
|
|
static gfloat transform_matrices[][6] = {
|
|
|
|
{ 1, 0, 0, 0, 1, 0 }, /* normal */
|
|
|
|
{ 0, -1, 1, 1, 0, 0 }, /* 90° */
|
|
|
|
{ -1, 0, 1, 0, -1, 1 }, /* 180° */
|
|
|
|
{ 0, 1, 0, -1, 0, 1 }, /* 270° */
|
|
|
|
{ -1, 0, 1, 0, 1, 0 }, /* normal flipped */
|
|
|
|
{ 0, 1, 0, 1, 0, 0 }, /* 90° flipped */
|
|
|
|
{ 1, 0, 0, 0, -1, 1 }, /* 180° flipped */
|
|
|
|
{ 0, -1, 1, -1, 0, 1 }, /* 270° flipped */
|
|
|
|
};
|
|
|
|
|
2013-07-18 11:09:16 +00:00
|
|
|
static int signals[SIGNALS_LAST];
|
|
|
|
|
2019-01-11 13:45:44 +00:00
|
|
|
typedef struct _MetaMonitorManagerPrivate
|
|
|
|
{
|
|
|
|
MetaPowerSave power_save_mode;
|
2023-10-01 06:33:03 +00:00
|
|
|
gboolean initial_orient_change_done;
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
|
|
|
|
GList *virtual_monitors;
|
|
|
|
|
|
|
|
gboolean shutting_down;
|
2021-12-02 20:43:08 +00:00
|
|
|
|
|
|
|
gboolean has_builtin_panel;
|
2022-08-15 12:09:29 +00:00
|
|
|
gboolean night_light_supported;
|
2023-10-24 08:20:49 +00:00
|
|
|
char *experimental_hdr;
|
2023-03-14 16:28:24 +00:00
|
|
|
|
2023-09-29 12:31:41 +00:00
|
|
|
guint reload_monitor_manager_id;
|
2023-03-14 16:28:24 +00:00
|
|
|
guint switch_config_handle_id;
|
2019-01-11 13:45:44 +00:00
|
|
|
} MetaMonitorManagerPrivate;
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaMonitorManager, meta_monitor_manager,
|
|
|
|
G_TYPE_OBJECT)
|
2013-07-18 11:09:16 +00:00
|
|
|
|
2013-07-29 11:00:15 +00:00
|
|
|
static void initialize_dbus_interface (MetaMonitorManager *manager);
|
2019-01-23 01:49:26 +00:00
|
|
|
static void monitor_manager_setup_dbus_config_handlers (MetaMonitorManager *manager);
|
2013-07-23 08:07:52 +00:00
|
|
|
|
2017-08-11 07:21:36 +00:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config);
|
|
|
|
|
2019-01-11 13:45:44 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_real_read_current_state (MetaMonitorManager *manager);
|
|
|
|
|
2018-11-30 04:04:17 +00:00
|
|
|
static gboolean
|
|
|
|
is_global_scale_matching_in_config (MetaMonitorsConfig *config,
|
|
|
|
float scale);
|
|
|
|
|
2017-07-10 09:39:07 +00:00
|
|
|
MetaBackend *
|
|
|
|
meta_monitor_manager_get_backend (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return manager->backend;
|
|
|
|
}
|
|
|
|
|
2013-07-18 11:09:16 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_init (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-12-13 03:03:22 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_set_primary_logical_monitor (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitor *logical_monitor)
|
|
|
|
{
|
|
|
|
manager->primary_logical_monitor = logical_monitor;
|
|
|
|
if (logical_monitor)
|
|
|
|
meta_logical_monitor_make_primary (logical_monitor);
|
|
|
|
}
|
|
|
|
|
2016-12-02 07:48:53 +00:00
|
|
|
static gboolean
|
|
|
|
is_main_tiled_monitor_output (MetaOutput *output)
|
|
|
|
{
|
2020-02-26 08:45:07 +00:00
|
|
|
const MetaOutputInfo *output_info = meta_output_get_info (output);
|
|
|
|
|
|
|
|
return (output_info->tile_info.loc_h_tile == 0 &&
|
|
|
|
output_info->tile_info.loc_v_tile == 0);
|
2016-12-02 07:48:53 +00:00
|
|
|
}
|
|
|
|
|
2016-12-13 03:03:22 +00:00
|
|
|
static MetaLogicalMonitor *
|
|
|
|
logical_monitor_from_layout (MetaMonitorManager *manager,
|
|
|
|
GList *logical_monitors,
|
2023-07-19 23:46:15 +00:00
|
|
|
MtkRectangle *layout)
|
2015-03-31 01:08:34 +00:00
|
|
|
{
|
2016-12-13 03:03:22 +00:00
|
|
|
GList *l;
|
2015-03-31 01:08:34 +00:00
|
|
|
|
2016-12-13 03:03:22 +00:00
|
|
|
for (l = logical_monitors; l; l = l->next)
|
2015-03-31 01:08:34 +00:00
|
|
|
{
|
2016-12-13 03:03:22 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
2015-03-31 01:08:34 +00:00
|
|
|
|
2023-07-19 15:14:13 +00:00
|
|
|
if (mtk_rectangle_equal (layout, &logical_monitor->rect))
|
2016-12-13 03:03:22 +00:00
|
|
|
return logical_monitor;
|
2015-03-31 01:08:34 +00:00
|
|
|
}
|
|
|
|
|
2016-12-13 03:03:22 +00:00
|
|
|
return NULL;
|
2016-12-02 07:48:53 +00:00
|
|
|
}
|
|
|
|
|
2017-01-09 06:31:18 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_rebuild_logical_monitors (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
|
|
|
{
|
2017-01-12 05:47:54 +00:00
|
|
|
GList *logical_monitor_configs;
|
2017-01-09 06:31:18 +00:00
|
|
|
GList *logical_monitors = NULL;
|
|
|
|
GList *l;
|
|
|
|
int monitor_number = 0;
|
|
|
|
MetaLogicalMonitor *primary_logical_monitor = NULL;
|
|
|
|
|
2017-01-12 05:47:54 +00:00
|
|
|
logical_monitor_configs = config ? config->logical_monitor_configs : NULL;
|
|
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
2017-01-09 06:31:18 +00:00
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
MetaLogicalMonitor *logical_monitor;
|
|
|
|
|
2017-03-07 04:34:38 +00:00
|
|
|
logical_monitor = meta_logical_monitor_new (manager,
|
|
|
|
logical_monitor_config,
|
|
|
|
monitor_number);
|
2017-01-09 06:31:18 +00:00
|
|
|
monitor_number++;
|
|
|
|
|
|
|
|
if (logical_monitor_config->is_primary)
|
|
|
|
primary_logical_monitor = logical_monitor;
|
|
|
|
|
|
|
|
logical_monitors = g_list_append (logical_monitors, logical_monitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If no monitor was marked as primary, fall back on marking the first
|
|
|
|
* logical monitor the primary one.
|
|
|
|
*/
|
|
|
|
if (!primary_logical_monitor && logical_monitors)
|
|
|
|
primary_logical_monitor = g_list_first (logical_monitors)->data;
|
|
|
|
|
|
|
|
manager->logical_monitors = logical_monitors;
|
|
|
|
meta_monitor_manager_set_primary_logical_monitor (manager,
|
|
|
|
primary_logical_monitor);
|
|
|
|
}
|
|
|
|
|
2017-05-25 08:12:51 +00:00
|
|
|
static float
|
2017-09-11 06:10:26 +00:00
|
|
|
derive_configured_global_scale (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
2017-04-21 10:01:15 +00:00
|
|
|
{
|
2018-11-30 04:29:08 +00:00
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *monitor_config = l->data;
|
2017-04-21 10:01:15 +00:00
|
|
|
|
2018-11-30 04:29:08 +00:00
|
|
|
if (is_global_scale_matching_in_config (config, monitor_config->scale))
|
|
|
|
return monitor_config->scale;
|
|
|
|
}
|
2017-04-21 10:01:15 +00:00
|
|
|
|
2018-11-30 04:29:08 +00:00
|
|
|
return 1.0;
|
2017-04-21 10:01:15 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 08:12:51 +00:00
|
|
|
static float
|
2017-04-21 10:01:15 +00:00
|
|
|
calculate_monitor_scale (MetaMonitorManager *manager,
|
|
|
|
MetaMonitor *monitor)
|
|
|
|
{
|
|
|
|
MetaMonitorMode *monitor_mode;
|
|
|
|
|
|
|
|
monitor_mode = meta_monitor_get_current_mode (monitor);
|
|
|
|
return meta_monitor_manager_calculate_monitor_mode_scale (manager,
|
2017-06-10 14:10:57 +00:00
|
|
|
manager->layout_mode,
|
2017-04-21 10:01:15 +00:00
|
|
|
monitor,
|
|
|
|
monitor_mode);
|
|
|
|
}
|
|
|
|
|
2018-11-30 04:51:55 +00:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_is_scale_supported_by_other_monitors (MetaMonitorManager *manager,
|
|
|
|
MetaMonitor *not_this_one,
|
|
|
|
float scale)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
|
|
|
|
if (monitor == not_this_one || !meta_monitor_is_active (monitor))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
mode = meta_monitor_get_current_mode (monitor);
|
|
|
|
if (!meta_monitor_manager_is_scale_supported (manager,
|
|
|
|
manager->layout_mode,
|
|
|
|
monitor, mode, scale))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-05-25 08:12:51 +00:00
|
|
|
static float
|
2017-04-21 10:01:15 +00:00
|
|
|
derive_calculated_global_scale (MetaMonitorManager *manager)
|
|
|
|
{
|
2018-04-25 08:43:11 +00:00
|
|
|
MetaMonitor *monitor = NULL;
|
2018-11-30 04:51:55 +00:00
|
|
|
float scale;
|
|
|
|
GList *l;
|
2018-04-25 08:43:11 +00:00
|
|
|
|
2018-11-30 04:51:55 +00:00
|
|
|
scale = 1.0;
|
2018-04-25 08:43:11 +00:00
|
|
|
monitor = meta_monitor_manager_get_primary_monitor (manager);
|
2017-04-21 10:01:15 +00:00
|
|
|
|
2018-11-30 04:51:55 +00:00
|
|
|
if (monitor && meta_monitor_is_active (monitor))
|
|
|
|
{
|
|
|
|
scale = calculate_monitor_scale (manager, monitor);
|
|
|
|
if (meta_monitor_manager_is_scale_supported_by_other_monitors (manager,
|
|
|
|
monitor,
|
|
|
|
scale))
|
|
|
|
return scale;
|
|
|
|
}
|
2018-04-25 08:43:11 +00:00
|
|
|
|
2018-11-30 04:51:55 +00:00
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *other_monitor = l->data;
|
|
|
|
float monitor_scale;
|
2017-04-21 10:01:15 +00:00
|
|
|
|
2018-11-30 04:51:55 +00:00
|
|
|
if (other_monitor == monitor || !meta_monitor_is_active (other_monitor))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
monitor_scale = calculate_monitor_scale (manager, other_monitor);
|
|
|
|
if (meta_monitor_manager_is_scale_supported_by_other_monitors (manager,
|
|
|
|
other_monitor,
|
|
|
|
monitor_scale))
|
|
|
|
scale = MAX (scale, monitor_scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
return scale;
|
2017-04-21 10:01:15 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 08:12:51 +00:00
|
|
|
static float
|
2017-04-21 10:01:15 +00:00
|
|
|
derive_scale_from_config (MetaMonitorManager *manager,
|
2017-09-11 06:10:26 +00:00
|
|
|
MetaMonitorsConfig *config,
|
2023-07-19 23:46:15 +00:00
|
|
|
MtkRectangle *layout)
|
2017-04-21 10:01:15 +00:00
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
|
2023-07-19 15:14:13 +00:00
|
|
|
if (mtk_rectangle_equal (layout, &logical_monitor_config->layout))
|
2017-04-21 10:01:15 +00:00
|
|
|
return logical_monitor_config->scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_warning ("Missing logical monitor, using scale 1");
|
2017-05-25 08:12:51 +00:00
|
|
|
return 1.0;
|
2017-04-21 10:01:15 +00:00
|
|
|
}
|
|
|
|
|
2013-07-19 12:39:28 +00:00
|
|
|
static void
|
2017-09-11 06:10:26 +00:00
|
|
|
meta_monitor_manager_rebuild_logical_monitors_derived (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
2013-07-19 12:39:28 +00:00
|
|
|
{
|
2016-12-02 08:00:03 +00:00
|
|
|
GList *logical_monitors = NULL;
|
2016-12-13 03:03:22 +00:00
|
|
|
GList *l;
|
2016-12-02 08:00:03 +00:00
|
|
|
int monitor_number;
|
2016-12-13 03:03:22 +00:00
|
|
|
MetaLogicalMonitor *primary_logical_monitor = NULL;
|
2017-04-21 10:01:15 +00:00
|
|
|
gboolean use_global_scale;
|
2017-05-25 08:12:51 +00:00
|
|
|
float global_scale = 0.0;
|
2017-04-21 10:01:15 +00:00
|
|
|
MetaMonitorManagerCapability capabilities;
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2016-12-02 08:00:03 +00:00
|
|
|
monitor_number = 0;
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2017-04-21 10:01:15 +00:00
|
|
|
capabilities = meta_monitor_manager_get_capabilities (manager);
|
|
|
|
use_global_scale =
|
|
|
|
!!(capabilities & META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
|
|
|
|
|
|
|
|
if (use_global_scale)
|
|
|
|
{
|
2017-09-11 06:10:26 +00:00
|
|
|
if (config)
|
|
|
|
global_scale = derive_configured_global_scale (manager, config);
|
2017-04-21 10:01:15 +00:00
|
|
|
else
|
|
|
|
global_scale = derive_calculated_global_scale (manager);
|
|
|
|
}
|
|
|
|
|
2016-12-13 03:03:22 +00:00
|
|
|
for (l = manager->monitors; l; l = l->next)
|
2013-07-19 12:39:28 +00:00
|
|
|
{
|
2016-12-13 03:03:22 +00:00
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaLogicalMonitor *logical_monitor;
|
2023-07-19 23:46:15 +00:00
|
|
|
MtkRectangle layout;
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2016-12-13 03:03:22 +00:00
|
|
|
if (!meta_monitor_is_active (monitor))
|
2013-07-19 12:39:28 +00:00
|
|
|
continue;
|
|
|
|
|
2017-07-12 07:42:20 +00:00
|
|
|
meta_monitor_derive_layout (monitor, &layout);
|
2016-12-13 03:03:22 +00:00
|
|
|
logical_monitor = logical_monitor_from_layout (manager, logical_monitors,
|
|
|
|
&layout);
|
|
|
|
if (logical_monitor)
|
2013-07-19 12:39:28 +00:00
|
|
|
{
|
2016-12-13 03:03:22 +00:00
|
|
|
meta_logical_monitor_add_monitor (logical_monitor, monitor);
|
2013-07-19 12:39:28 +00:00
|
|
|
}
|
2016-12-13 03:03:22 +00:00
|
|
|
else
|
2013-07-19 12:39:28 +00:00
|
|
|
{
|
2017-05-25 08:12:51 +00:00
|
|
|
float scale;
|
2017-04-21 10:01:15 +00:00
|
|
|
|
|
|
|
if (use_global_scale)
|
|
|
|
scale = global_scale;
|
2017-09-11 06:10:26 +00:00
|
|
|
else if (config)
|
|
|
|
scale = derive_scale_from_config (manager, config, &layout);
|
2017-04-21 10:01:15 +00:00
|
|
|
else
|
|
|
|
scale = calculate_monitor_scale (manager, monitor);
|
|
|
|
|
|
|
|
g_assert (scale > 0);
|
|
|
|
|
2017-03-07 04:34:38 +00:00
|
|
|
logical_monitor = meta_logical_monitor_new_derived (manager,
|
|
|
|
monitor,
|
|
|
|
&layout,
|
2017-04-21 10:01:15 +00:00
|
|
|
scale,
|
2017-03-07 04:34:38 +00:00
|
|
|
monitor_number);
|
2016-12-02 08:00:03 +00:00
|
|
|
logical_monitors = g_list_append (logical_monitors, logical_monitor);
|
|
|
|
monitor_number++;
|
2013-07-19 12:39:28 +00:00
|
|
|
}
|
|
|
|
|
2016-12-13 03:03:22 +00:00
|
|
|
if (meta_monitor_is_primary (monitor))
|
|
|
|
primary_logical_monitor = logical_monitor;
|
2013-07-19 12:39:28 +00:00
|
|
|
}
|
|
|
|
|
2016-12-02 08:00:03 +00:00
|
|
|
manager->logical_monitors = logical_monitors;
|
2015-03-31 01:11:12 +00:00
|
|
|
|
2016-11-28 12:43:27 +00:00
|
|
|
/*
|
|
|
|
* If no monitor was marked as primary, fall back on marking the first
|
|
|
|
* logical monitor the primary one.
|
|
|
|
*/
|
2016-12-13 03:03:22 +00:00
|
|
|
if (!primary_logical_monitor && manager->logical_monitors)
|
|
|
|
primary_logical_monitor = g_list_first (manager->logical_monitors)->data;
|
|
|
|
|
|
|
|
meta_monitor_manager_set_primary_logical_monitor (manager,
|
|
|
|
primary_logical_monitor);
|
2013-07-19 12:39:28 +00:00
|
|
|
}
|
|
|
|
|
2019-01-11 13:45:44 +00:00
|
|
|
void
|
2023-09-01 20:20:16 +00:00
|
|
|
meta_monitor_manager_power_save_mode_changed (MetaMonitorManager *manager,
|
|
|
|
MetaPowerSave mode,
|
|
|
|
MetaPowerSaveChangeReason reason)
|
2019-01-11 13:45:44 +00:00
|
|
|
{
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
|
2019-07-06 23:23:57 +00:00
|
|
|
if (priv->power_save_mode == mode)
|
|
|
|
return;
|
|
|
|
|
2019-01-11 13:45:44 +00:00
|
|
|
priv->power_save_mode = mode;
|
2023-09-01 20:20:16 +00:00
|
|
|
g_signal_emit (manager, signals[POWER_SAVE_MODE_CHANGED], 0, reason);
|
2019-01-11 13:45:44 +00:00
|
|
|
}
|
|
|
|
|
2014-09-26 01:39:14 +00:00
|
|
|
static void
|
|
|
|
power_save_mode_changed (MetaMonitorManager *manager,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2019-01-11 13:45:44 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
2014-09-26 01:39:14 +00:00
|
|
|
MetaMonitorManagerClass *klass;
|
2019-01-23 01:49:26 +00:00
|
|
|
int mode = meta_dbus_display_config_get_power_save_mode (manager->display_config);
|
2023-09-01 20:20:16 +00:00
|
|
|
MetaPowerSaveChangeReason reason;
|
2014-09-26 01:39:14 +00:00
|
|
|
|
|
|
|
if (mode == META_POWER_SAVE_UNSUPPORTED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* If DPMS is unsupported, force the property back. */
|
2019-01-11 13:45:44 +00:00
|
|
|
if (priv->power_save_mode == META_POWER_SAVE_UNSUPPORTED)
|
2014-09-26 01:39:14 +00:00
|
|
|
{
|
2019-01-23 01:49:26 +00:00
|
|
|
meta_dbus_display_config_set_power_save_mode (manager->display_config, META_POWER_SAVE_UNSUPPORTED);
|
2014-09-26 01:39:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
if (klass->set_power_save_mode)
|
|
|
|
klass->set_power_save_mode (manager, mode);
|
|
|
|
|
2023-09-01 20:20:16 +00:00
|
|
|
reason = META_POWER_SAVE_CHANGE_REASON_MODE_CHANGE;
|
|
|
|
meta_monitor_manager_power_save_mode_changed (manager, mode, reason);
|
2014-09-26 01:39:14 +00:00
|
|
|
}
|
|
|
|
|
2017-01-10 02:38:06 +00:00
|
|
|
void
|
|
|
|
meta_monitor_manager_lid_is_closed_changed (MetaMonitorManager *manager)
|
|
|
|
{
|
2017-03-24 07:36:12 +00:00
|
|
|
meta_monitor_manager_ensure_configured (manager);
|
2017-01-10 02:38:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-04-16 18:07:45 +00:00
|
|
|
lid_is_closed_changed (MetaBackend *backend,
|
|
|
|
gboolean lid_is_closed,
|
|
|
|
gpointer user_data)
|
2017-01-10 02:38:06 +00:00
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
meta_monitor_manager_lid_is_closed_changed (manager);
|
|
|
|
}
|
|
|
|
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
static void
|
|
|
|
prepare_shutdown (MetaBackend *backend,
|
|
|
|
MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
|
|
|
|
priv->shutting_down = TRUE;
|
2023-09-29 12:31:41 +00:00
|
|
|
|
|
|
|
g_clear_handle_id (&priv->reload_monitor_manager_id, g_source_remove);
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
}
|
|
|
|
|
2023-03-02 00:35:10 +00:00
|
|
|
static void
|
|
|
|
ensure_hdr_settings (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
MetaOutputColorspace color_space;
|
|
|
|
MetaOutputHdrMetadata hdr_metadata;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
if (g_strcmp0 (priv->experimental_hdr, "on") == 0)
|
|
|
|
{
|
|
|
|
color_space = META_OUTPUT_COLORSPACE_BT2020;
|
|
|
|
hdr_metadata = (MetaOutputHdrMetadata) {
|
|
|
|
.active = TRUE,
|
|
|
|
.eotf = META_OUTPUT_HDR_METADATA_EOTF_PQ,
|
|
|
|
};
|
2023-09-06 15:30:00 +00:00
|
|
|
|
|
|
|
meta_topic (META_DEBUG_COLOR,
|
|
|
|
"MonitorManager: Trying to enabling HDR mode "
|
|
|
|
"(Colorimetry: bt.2020, TF: PQ, HDR Metadata: Minimal):");
|
2023-03-02 00:35:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
color_space = META_OUTPUT_COLORSPACE_DEFAULT;
|
|
|
|
hdr_metadata = (MetaOutputHdrMetadata) {
|
|
|
|
.active = FALSE,
|
|
|
|
};
|
2023-09-06 15:30:00 +00:00
|
|
|
|
|
|
|
meta_topic (META_DEBUG_COLOR,
|
|
|
|
"MonitorManager: Trying to enable default mode "
|
|
|
|
"(Colorimetry: default, TF: default, HDR Metadata: None):");
|
2023-03-02 00:35:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
|
|
if (!meta_monitor_set_color_space (monitor, color_space, &error))
|
|
|
|
{
|
|
|
|
meta_monitor_set_color_space (monitor,
|
2023-03-15 12:28:52 +00:00
|
|
|
META_OUTPUT_COLORSPACE_DEFAULT,
|
2023-03-02 00:35:10 +00:00
|
|
|
NULL);
|
2023-09-06 15:30:00 +00:00
|
|
|
meta_monitor_set_hdr_metadata (monitor, &(MetaOutputHdrMetadata) {
|
|
|
|
.active = FALSE,
|
|
|
|
}, NULL);
|
|
|
|
|
|
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
|
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_COLOR,
|
|
|
|
"MonitorManager: Colorimetry not supported "
|
|
|
|
"on monitor %s",
|
|
|
|
meta_monitor_get_display_name (monitor));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Failed to set color space on monitor %s: %s",
|
|
|
|
meta_monitor_get_display_name (monitor), error->message);
|
|
|
|
}
|
2023-03-02 00:35:10 +00:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!meta_monitor_set_hdr_metadata (monitor, &hdr_metadata, &error))
|
|
|
|
{
|
|
|
|
meta_monitor_set_color_space (monitor,
|
2023-03-15 12:28:52 +00:00
|
|
|
META_OUTPUT_COLORSPACE_DEFAULT,
|
2023-03-02 00:35:10 +00:00
|
|
|
NULL);
|
|
|
|
meta_monitor_set_hdr_metadata (monitor, &(MetaOutputHdrMetadata) {
|
|
|
|
.active = FALSE,
|
|
|
|
}, NULL);
|
|
|
|
|
2023-09-06 15:30:00 +00:00
|
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
|
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_COLOR,
|
|
|
|
"MonitorManager: HDR Metadata not supported "
|
|
|
|
"on monitor %s",
|
|
|
|
meta_monitor_get_display_name (monitor));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Failed to set HDR metadata on monitor %s: %s",
|
|
|
|
meta_monitor_get_display_name (monitor),
|
|
|
|
error->message);
|
|
|
|
}
|
|
|
|
|
2023-03-02 00:35:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
2023-09-06 15:30:00 +00:00
|
|
|
|
|
|
|
meta_topic (META_DEBUG_COLOR,
|
|
|
|
"MonitorManager: successfully set on monitor %s",
|
|
|
|
meta_monitor_get_display_name (monitor));
|
2023-03-02 00:35:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_is_headless:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
*
|
|
|
|
* Returns whether the monitor manager is headless, i.e. without
|
2023-03-28 14:35:11 +00:00
|
|
|
* any `MetaLogicalMonitor`s attached to it.
|
2018-10-19 07:15:54 +00:00
|
|
|
*
|
|
|
|
* Returns: %TRUE if no monitors are attached, %FALSE otherwise.
|
|
|
|
*/
|
2017-01-12 05:47:54 +00:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_is_headless (MetaMonitorManager *manager)
|
|
|
|
{
|
2017-04-12 06:09:58 +00:00
|
|
|
return !manager->logical_monitors;
|
2017-01-12 05:47:54 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 08:12:51 +00:00
|
|
|
float
|
2017-06-10 14:10:57 +00:00
|
|
|
meta_monitor_manager_calculate_monitor_mode_scale (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
|
|
MetaMonitor *monitor,
|
|
|
|
MetaMonitorMode *monitor_mode)
|
2017-01-20 07:07:12 +00:00
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
return manager_class->calculate_monitor_mode_scale (manager,
|
2017-06-10 14:10:57 +00:00
|
|
|
layout_mode,
|
2017-01-20 07:07:12 +00:00
|
|
|
monitor,
|
|
|
|
monitor_mode);
|
|
|
|
}
|
|
|
|
|
2017-06-05 07:59:47 +00:00
|
|
|
float *
|
2019-03-08 18:03:57 +00:00
|
|
|
meta_monitor_manager_calculate_supported_scales (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
|
|
MetaMonitor *monitor,
|
|
|
|
MetaMonitorMode *monitor_mode,
|
|
|
|
int *n_supported_scales)
|
2017-01-26 09:15:52 +00:00
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
2017-06-05 07:59:47 +00:00
|
|
|
return manager_class->calculate_supported_scales (manager,
|
|
|
|
layout_mode,
|
|
|
|
monitor,
|
|
|
|
monitor_mode,
|
|
|
|
n_supported_scales);
|
2017-01-26 09:15:52 +00:00
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_capabilities:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
*
|
|
|
|
* Queries the capabilities of the monitor manager.
|
|
|
|
*
|
|
|
|
* Returns: #MetaMonitorManagerCapability flags representing the capabilities.
|
|
|
|
*/
|
2017-04-21 10:01:15 +00:00
|
|
|
MetaMonitorManagerCapability
|
2017-02-07 08:03:43 +00:00
|
|
|
meta_monitor_manager_get_capabilities (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
return manager_class->get_capabilities (manager);
|
|
|
|
}
|
|
|
|
|
2017-02-15 08:06:46 +00:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_get_max_screen_size (MetaMonitorManager *manager,
|
|
|
|
int *max_width,
|
|
|
|
int *max_height)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
return manager_class->get_max_screen_size (manager, max_width, max_height);
|
|
|
|
}
|
|
|
|
|
2017-02-24 10:10:52 +00:00
|
|
|
|
|
|
|
MetaLogicalMonitorLayoutMode
|
|
|
|
meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
return manager_class->get_default_layout_mode (manager);
|
|
|
|
}
|
|
|
|
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
static void
|
|
|
|
on_virtual_monitor_destroyed (MetaVirtualMonitor *virtual_monitor,
|
|
|
|
MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
MetaOutput *output;
|
|
|
|
|
|
|
|
output = meta_virtual_monitor_get_output (virtual_monitor);
|
|
|
|
g_message ("Removed virtual monitor %s", meta_output_get_name (output));
|
|
|
|
priv->virtual_monitors = g_list_remove (priv->virtual_monitors,
|
|
|
|
virtual_monitor);
|
|
|
|
|
2023-09-29 12:31:41 +00:00
|
|
|
if (!priv->shutting_down && !priv->reload_monitor_manager_id)
|
|
|
|
{
|
|
|
|
priv->reload_monitor_manager_id =
|
|
|
|
g_idle_add_once ((GSourceOnceFunc) meta_monitor_manager_reload,
|
|
|
|
manager);
|
|
|
|
}
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MetaVirtualMonitor *
|
|
|
|
meta_monitor_manager_create_virtual_monitor (MetaMonitorManager *manager,
|
|
|
|
const MetaVirtualMonitorInfo *info,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
MetaVirtualMonitor *virtual_monitor;
|
|
|
|
MetaOutput *output;
|
|
|
|
|
|
|
|
if (!manager_class->create_virtual_monitor)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
|
|
"Backend doesn't support creating virtual monitors");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual_monitor = manager_class->create_virtual_monitor (manager, info,
|
|
|
|
error);
|
|
|
|
if (!virtual_monitor)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
g_signal_connect (virtual_monitor, "destroy",
|
|
|
|
G_CALLBACK (on_virtual_monitor_destroyed),
|
|
|
|
manager);
|
|
|
|
|
|
|
|
priv->virtual_monitors = g_list_append (priv->virtual_monitors,
|
|
|
|
virtual_monitor);
|
|
|
|
|
|
|
|
output = meta_virtual_monitor_get_output (virtual_monitor);
|
|
|
|
g_message ("Added virtual monitor %s", meta_output_get_name (output));
|
|
|
|
|
|
|
|
return virtual_monitor;
|
|
|
|
}
|
|
|
|
|
2017-01-06 05:27:21 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager)->ensure_initial_config (manager);
|
|
|
|
}
|
|
|
|
|
2023-10-09 08:16:03 +00:00
|
|
|
gboolean
|
2017-02-14 11:54:04 +00:00
|
|
|
meta_monitor_manager_apply_monitors_config (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config,
|
|
|
|
MetaMonitorsConfigMethod method,
|
|
|
|
GError **error)
|
2017-01-09 06:31:18 +00:00
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
2017-08-10 07:12:41 +00:00
|
|
|
g_assert (!config ||
|
|
|
|
!(config->flags & META_MONITORS_CONFIG_FLAG_MIGRATED));
|
|
|
|
|
2017-02-24 09:09:19 +00:00
|
|
|
if (!manager_class->apply_monitors_config (manager, config, method, error))
|
|
|
|
return FALSE;
|
|
|
|
|
2017-06-14 10:40:53 +00:00
|
|
|
switch (method)
|
|
|
|
{
|
|
|
|
case META_MONITORS_CONFIG_METHOD_TEMPORARY:
|
|
|
|
case META_MONITORS_CONFIG_METHOD_PERSISTENT:
|
|
|
|
meta_monitor_config_manager_set_current (manager->config_manager, config);
|
|
|
|
break;
|
|
|
|
case META_MONITORS_CONFIG_METHOD_VERIFY:
|
|
|
|
break;
|
|
|
|
}
|
2017-02-24 09:09:19 +00:00
|
|
|
|
|
|
|
return TRUE;
|
2017-01-09 06:31:18 +00:00
|
|
|
}
|
|
|
|
|
2016-12-19 07:56:50 +00:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
|
|
|
|
{
|
2019-01-11 14:35:42 +00:00
|
|
|
GList *gpus;
|
2017-03-24 09:35:51 +00:00
|
|
|
GList *l;
|
2016-12-19 07:56:50 +00:00
|
|
|
|
2019-01-11 14:35:42 +00:00
|
|
|
gpus = meta_backend_get_gpus (manager->backend);
|
|
|
|
for (l = gpus; l; l = l->next)
|
2016-12-19 07:56:50 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaGpu *gpu = l->data;
|
2016-12-19 07:56:50 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
if (meta_gpu_has_hotplug_mode_update (gpu))
|
2016-12-19 07:56:50 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-01-13 03:01:27 +00:00
|
|
|
static gboolean
|
|
|
|
should_use_stored_config (MetaMonitorManager *manager)
|
|
|
|
{
|
2017-05-25 05:15:06 +00:00
|
|
|
return (manager->in_init ||
|
|
|
|
!meta_monitor_manager_has_hotplug_mode_update (manager));
|
2017-01-13 03:01:27 +00:00
|
|
|
}
|
|
|
|
|
2017-01-09 06:31:18 +00:00
|
|
|
MetaMonitorsConfig *
|
2017-01-06 05:27:21 +00:00
|
|
|
meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
|
|
|
|
{
|
2017-01-09 06:31:18 +00:00
|
|
|
MetaMonitorsConfig *config = NULL;
|
|
|
|
GError *error = NULL;
|
2017-02-14 11:54:04 +00:00
|
|
|
gboolean use_stored_config;
|
|
|
|
MetaMonitorsConfigMethod method;
|
|
|
|
MetaMonitorsConfigMethod fallback_method =
|
|
|
|
META_MONITORS_CONFIG_METHOD_TEMPORARY;
|
2017-01-09 06:31:18 +00:00
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
use_stored_config = should_use_stored_config (manager);
|
|
|
|
if (use_stored_config)
|
|
|
|
method = META_MONITORS_CONFIG_METHOD_PERSISTENT;
|
|
|
|
else
|
|
|
|
method = META_MONITORS_CONFIG_METHOD_TEMPORARY;
|
|
|
|
|
|
|
|
if (use_stored_config)
|
2017-01-13 03:01:27 +00:00
|
|
|
{
|
|
|
|
config = meta_monitor_config_manager_get_stored (manager->config_manager);
|
|
|
|
if (config)
|
|
|
|
{
|
2020-05-01 13:24:34 +00:00
|
|
|
g_autoptr (MetaMonitorsConfig) oriented_config = NULL;
|
|
|
|
|
|
|
|
if (manager->panel_orientation_managed)
|
|
|
|
{
|
|
|
|
oriented_config = meta_monitor_config_manager_create_for_builtin_orientation (
|
|
|
|
manager->config_manager, config);
|
|
|
|
|
|
|
|
if (oriented_config)
|
|
|
|
config = oriented_config;
|
|
|
|
}
|
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
config,
|
|
|
|
method,
|
2017-01-13 03:01:27 +00:00
|
|
|
&error))
|
|
|
|
{
|
|
|
|
config = NULL;
|
|
|
|
g_warning ("Failed to use stored monitor configuration: %s",
|
|
|
|
error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_object_ref (config);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-01 13:24:34 +00:00
|
|
|
if (manager->panel_orientation_managed)
|
|
|
|
{
|
|
|
|
MetaMonitorsConfig *current_config =
|
|
|
|
meta_monitor_config_manager_get_current (manager->config_manager);
|
|
|
|
|
|
|
|
if (current_config)
|
|
|
|
{
|
|
|
|
config = meta_monitor_config_manager_create_for_builtin_orientation (
|
|
|
|
manager->config_manager, current_config);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
{
|
|
|
|
if (meta_monitor_manager_is_config_complete (manager, config))
|
|
|
|
{
|
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
config,
|
|
|
|
method,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_clear_object (&config);
|
|
|
|
g_warning ("Failed to use current monitor configuration: %s",
|
|
|
|
error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-09 07:38:17 +00:00
|
|
|
config = meta_monitor_config_manager_create_suggested (manager->config_manager);
|
|
|
|
if (config)
|
|
|
|
{
|
2017-02-14 11:54:04 +00:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
config,
|
|
|
|
method,
|
|
|
|
&error))
|
2017-01-09 07:38:17 +00:00
|
|
|
{
|
|
|
|
g_clear_object (&config);
|
|
|
|
g_warning ("Failed to use suggested monitor configuration: %s",
|
|
|
|
error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-11 07:21:36 +00:00
|
|
|
config = meta_monitor_config_manager_get_previous (manager->config_manager);
|
|
|
|
if (config)
|
|
|
|
{
|
monitor-manager: Add config relationships and use it for orientation events
When we get an orientation event we don't care about keeping track of the
configuration changes, but actually we can consider the new configuration
just a variant of the previous one, adapted to floating device hardware
events, so we only want to apply it if possible, but we don't want to keep
a record of it for reverting capabilities.
Doing that would in fact, break the ability of reverting back to an actual
temporary or persistent configuration.
For example when device orientation events happen while we're waiting for
an user resolution change confirmation, we would save our new rotated
configuration in the history, making then impossible to revert back to
the original persistent one.
So in such case, don't keep track of those configurations in the history,
but only keep track of the last one as current, checking whether the
new current is child or sibling of the previously one.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1221
Related to: https://gitlab.gnome.org/GNOME/mutter/-/issues/646
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1233>
2020-05-01 13:53:55 +00:00
|
|
|
g_autoptr (MetaMonitorsConfig) oriented_config = NULL;
|
|
|
|
|
|
|
|
if (manager->panel_orientation_managed)
|
|
|
|
{
|
|
|
|
oriented_config =
|
|
|
|
meta_monitor_config_manager_create_for_builtin_orientation (
|
|
|
|
manager->config_manager, config);
|
|
|
|
|
|
|
|
if (oriented_config)
|
|
|
|
config = oriented_config;
|
|
|
|
}
|
|
|
|
|
2017-08-11 07:21:36 +00:00
|
|
|
config = g_object_ref (config);
|
|
|
|
|
|
|
|
if (meta_monitor_manager_is_config_complete (manager, config))
|
|
|
|
{
|
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
config,
|
|
|
|
method,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to use suggested monitor configuration: %s",
|
|
|
|
error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_clear_object (&config);
|
|
|
|
}
|
|
|
|
|
2018-10-11 13:16:26 +00:00
|
|
|
config = meta_monitor_config_manager_create_linear (manager->config_manager);
|
2017-01-12 05:47:54 +00:00
|
|
|
if (config)
|
2017-01-09 06:31:18 +00:00
|
|
|
{
|
2017-02-14 11:54:04 +00:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
config,
|
|
|
|
method,
|
|
|
|
&error))
|
2017-01-12 05:47:54 +00:00
|
|
|
{
|
|
|
|
g_clear_object (&config);
|
2018-04-24 13:25:56 +00:00
|
|
|
g_warning ("Failed to use linear monitor configuration: %s",
|
|
|
|
error->message);
|
2017-01-12 05:47:54 +00:00
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
2017-01-09 06:31:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
config = meta_monitor_config_manager_create_fallback (manager->config_manager);
|
2017-01-12 05:47:54 +00:00
|
|
|
if (config)
|
2017-01-09 06:31:18 +00:00
|
|
|
{
|
2017-02-14 11:54:04 +00:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
config,
|
|
|
|
fallback_method,
|
|
|
|
&error))
|
2017-01-12 05:47:54 +00:00
|
|
|
{
|
|
|
|
g_clear_object (&config);
|
2018-04-24 13:25:56 +00:00
|
|
|
g_warning ("Failed to use fallback monitor configuration: %s",
|
|
|
|
error->message);
|
2017-01-12 05:47:54 +00:00
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
2017-01-09 06:31:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (!config)
|
2017-01-12 05:47:54 +00:00
|
|
|
{
|
2017-02-14 11:54:04 +00:00
|
|
|
meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
NULL,
|
|
|
|
fallback_method,
|
|
|
|
&error);
|
2017-01-12 05:47:54 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2017-01-09 06:31:18 +00:00
|
|
|
|
|
|
|
g_object_unref (config);
|
|
|
|
|
|
|
|
return config;
|
2017-01-06 05:27:21 +00:00
|
|
|
}
|
|
|
|
|
2017-04-28 15:53:07 +00:00
|
|
|
static void
|
2020-10-15 10:21:05 +00:00
|
|
|
handle_orientation_change (MetaOrientationManager *orientation_manager,
|
|
|
|
MetaMonitorManager *manager)
|
2017-04-28 15:53:07 +00:00
|
|
|
{
|
2020-05-04 18:09:28 +00:00
|
|
|
MetaOrientation orientation;
|
2017-04-28 15:53:07 +00:00
|
|
|
MetaMonitorTransform transform;
|
2021-11-15 16:20:27 +00:00
|
|
|
MetaMonitorTransform panel_transform;
|
2017-03-24 07:36:12 +00:00
|
|
|
GError *error = NULL;
|
|
|
|
MetaMonitorsConfig *config;
|
2020-05-01 13:34:25 +00:00
|
|
|
MetaMonitor *laptop_panel;
|
|
|
|
MetaLogicalMonitor *laptop_logical_monitor;
|
2020-05-01 13:24:34 +00:00
|
|
|
MetaMonitorsConfig *current_config;
|
2020-05-01 13:34:25 +00:00
|
|
|
|
|
|
|
laptop_panel = meta_monitor_manager_get_laptop_panel (manager);
|
|
|
|
g_return_if_fail (laptop_panel);
|
|
|
|
|
|
|
|
if (!meta_monitor_is_active (laptop_panel))
|
|
|
|
return;
|
2017-04-28 15:53:07 +00:00
|
|
|
|
2020-05-04 18:09:28 +00:00
|
|
|
orientation = meta_orientation_manager_get_orientation (orientation_manager);
|
|
|
|
transform = meta_monitor_transform_from_orientation (orientation);
|
2017-04-28 15:53:07 +00:00
|
|
|
|
2020-05-01 13:34:25 +00:00
|
|
|
laptop_logical_monitor = meta_monitor_get_logical_monitor (laptop_panel);
|
2021-11-15 16:20:27 +00:00
|
|
|
panel_transform =
|
|
|
|
meta_monitor_crtc_to_logical_transform (laptop_panel, transform);
|
|
|
|
if (meta_logical_monitor_get_transform (laptop_logical_monitor) ==
|
|
|
|
panel_transform)
|
2020-05-01 13:34:25 +00:00
|
|
|
return;
|
|
|
|
|
2020-05-01 13:24:34 +00:00
|
|
|
current_config =
|
|
|
|
meta_monitor_config_manager_get_current (manager->config_manager);
|
monitor-manager: Add config relationships and use it for orientation events
When we get an orientation event we don't care about keeping track of the
configuration changes, but actually we can consider the new configuration
just a variant of the previous one, adapted to floating device hardware
events, so we only want to apply it if possible, but we don't want to keep
a record of it for reverting capabilities.
Doing that would in fact, break the ability of reverting back to an actual
temporary or persistent configuration.
For example when device orientation events happen while we're waiting for
an user resolution change confirmation, we would save our new rotated
configuration in the history, making then impossible to revert back to
the original persistent one.
So in such case, don't keep track of those configurations in the history,
but only keep track of the last one as current, checking whether the
new current is child or sibling of the previously one.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1221
Related to: https://gitlab.gnome.org/GNOME/mutter/-/issues/646
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1233>
2020-05-01 13:53:55 +00:00
|
|
|
if (!current_config)
|
|
|
|
return;
|
|
|
|
|
2017-03-24 07:36:12 +00:00
|
|
|
config =
|
|
|
|
meta_monitor_config_manager_create_for_orientation (manager->config_manager,
|
2020-05-01 13:24:34 +00:00
|
|
|
current_config,
|
2017-03-24 07:36:12 +00:00
|
|
|
transform);
|
|
|
|
if (!config)
|
|
|
|
return;
|
2017-04-28 15:53:07 +00:00
|
|
|
|
2017-03-24 07:36:12 +00:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
config,
|
|
|
|
META_MONITORS_CONFIG_METHOD_TEMPORARY,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to use orientation monitor configuration: %s",
|
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
2017-04-28 15:53:07 +00:00
|
|
|
}
|
2017-03-24 07:36:12 +00:00
|
|
|
g_object_unref (config);
|
2017-04-28 15:53:07 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 14:09:04 +00:00
|
|
|
/*
|
|
|
|
* Special case for tablets with a native portrait mode and a keyboard dock,
|
|
|
|
* where the device gets docked in landscape mode. For this combo to work
|
|
|
|
* properly with mutter starting while the tablet is docked, we need to take
|
|
|
|
* the accelerometer reported orientation into account (at mutter startup)
|
|
|
|
* even if there is a tablet-mode-switch which indicates that the device is
|
|
|
|
* NOT in tablet-mode (because it is docked).
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
handle_initial_orientation_change (MetaOrientationManager *orientation_manager,
|
|
|
|
MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
ClutterBackend *clutter_backend;
|
|
|
|
ClutterSeat *seat;
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
int width, height;
|
|
|
|
|
|
|
|
clutter_backend = meta_backend_get_clutter_backend (manager->backend);
|
|
|
|
seat = clutter_backend_get_default_seat (clutter_backend);
|
|
|
|
|
2021-07-27 00:42:38 +00:00
|
|
|
/*
|
2020-10-15 14:09:04 +00:00
|
|
|
* This is a workaround to ignore the tablet mode switch on the initial config
|
|
|
|
* of devices with a native portrait mode panel. The touchscreen and
|
|
|
|
* accelerometer requirements for applying the orientation must still be met.
|
|
|
|
*/
|
|
|
|
if (!clutter_seat_has_touchscreen (seat) ||
|
|
|
|
!meta_orientation_manager_has_accelerometer (orientation_manager))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Check for a portrait mode panel */
|
|
|
|
monitor = meta_monitor_manager_get_laptop_panel (manager);
|
|
|
|
if (!monitor)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
mode = meta_monitor_get_preferred_mode (monitor);
|
|
|
|
meta_monitor_mode_get_resolution (mode, &width, &height);
|
|
|
|
if (width > height)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
handle_orientation_change (orientation_manager, manager);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-10-15 10:21:05 +00:00
|
|
|
static void
|
|
|
|
orientation_changed (MetaOrientationManager *orientation_manager,
|
2021-07-27 00:42:38 +00:00
|
|
|
MetaMonitorManager *manager)
|
2020-10-15 10:21:05 +00:00
|
|
|
{
|
2020-10-15 14:09:04 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
|
|
|
|
if (!priv->initial_orient_change_done)
|
|
|
|
{
|
|
|
|
priv->initial_orient_change_done = TRUE;
|
|
|
|
if (handle_initial_orientation_change (orientation_manager, manager))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-15 10:21:05 +00:00
|
|
|
if (!manager->panel_orientation_managed)
|
|
|
|
return;
|
|
|
|
|
|
|
|
handle_orientation_change (orientation_manager, manager);
|
|
|
|
}
|
|
|
|
|
2017-03-04 07:30:56 +00:00
|
|
|
static void
|
2017-04-21 08:40:51 +00:00
|
|
|
experimental_features_changed (MetaSettings *settings,
|
2017-04-07 13:05:26 +00:00
|
|
|
MetaExperimentalFeature old_experimental_features,
|
|
|
|
MetaMonitorManager *manager)
|
2017-03-04 07:30:56 +00:00
|
|
|
{
|
2017-04-07 13:05:26 +00:00
|
|
|
gboolean was_stage_views_scaled;
|
|
|
|
gboolean is_stage_views_scaled;
|
|
|
|
gboolean should_reconfigure = FALSE;
|
2017-03-04 07:30:56 +00:00
|
|
|
|
2017-04-07 13:05:26 +00:00
|
|
|
was_stage_views_scaled =
|
|
|
|
!!(old_experimental_features &
|
|
|
|
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
|
|
|
|
is_stage_views_scaled =
|
2017-04-21 08:40:51 +00:00
|
|
|
meta_settings_is_experimental_feature_enabled (
|
|
|
|
settings,
|
2017-04-07 13:05:26 +00:00
|
|
|
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
|
|
|
|
|
2017-03-24 07:36:12 +00:00
|
|
|
if (is_stage_views_scaled != was_stage_views_scaled)
|
2017-04-07 13:05:26 +00:00
|
|
|
should_reconfigure = TRUE;
|
|
|
|
|
|
|
|
if (should_reconfigure)
|
2021-01-25 20:10:53 +00:00
|
|
|
meta_monitor_manager_reconfigure (manager);
|
2017-04-07 13:05:26 +00:00
|
|
|
|
2017-04-21 08:40:51 +00:00
|
|
|
meta_settings_update_ui_scaling_factor (settings);
|
2017-03-04 07:30:56 +00:00
|
|
|
}
|
|
|
|
|
2021-03-22 00:15:40 +00:00
|
|
|
static gboolean
|
2022-03-17 09:33:23 +00:00
|
|
|
ensure_privacy_screen_settings (MetaMonitorManager *manager)
|
2021-03-22 00:15:40 +00:00
|
|
|
{
|
2022-03-17 09:33:23 +00:00
|
|
|
MetaSettings *settings = meta_backend_get_settings (manager->backend);
|
|
|
|
gboolean privacy_screen_enabled;
|
2021-03-22 00:15:40 +00:00
|
|
|
GList *l;
|
|
|
|
|
2022-03-17 09:33:23 +00:00
|
|
|
privacy_screen_enabled = meta_settings_is_privacy_screen_enabled (settings);
|
2021-03-22 00:15:40 +00:00
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
2022-03-17 09:33:23 +00:00
|
|
|
g_autoptr (GError) error = NULL;
|
2021-03-22 00:15:40 +00:00
|
|
|
|
2022-03-17 09:33:23 +00:00
|
|
|
if (!meta_monitor_set_privacy_screen_enabled (monitor,
|
|
|
|
privacy_screen_enabled,
|
|
|
|
&error))
|
2021-03-22 00:15:40 +00:00
|
|
|
{
|
|
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
g_warning ("Failed to set privacy screen setting on monitor %s: %s",
|
|
|
|
meta_monitor_get_display_name (monitor), error->message);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaPrivacyScreenState
|
|
|
|
get_global_privacy_screen_state (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaPrivacyScreenState global_state = META_PRIVACY_SCREEN_UNAVAILABLE;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaPrivacyScreenState monitor_state;
|
|
|
|
|
|
|
|
if (!meta_monitor_is_active (monitor))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
monitor_state = meta_monitor_get_privacy_screen_state (monitor);
|
|
|
|
if (monitor_state == META_PRIVACY_SCREEN_UNAVAILABLE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (monitor_state & META_PRIVACY_SCREEN_DISABLED)
|
|
|
|
return META_PRIVACY_SCREEN_DISABLED;
|
|
|
|
|
|
|
|
if (monitor_state & META_PRIVACY_SCREEN_ENABLED)
|
|
|
|
global_state = META_PRIVACY_SCREEN_ENABLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return global_state;
|
|
|
|
}
|
|
|
|
|
2022-04-12 23:42:14 +00:00
|
|
|
static gboolean
|
|
|
|
privacy_screen_needs_update (MetaMonitorManager *manager)
|
2021-03-22 00:15:40 +00:00
|
|
|
{
|
|
|
|
MetaSettings *settings = meta_backend_get_settings (manager->backend);
|
|
|
|
MetaPrivacyScreenState privacy_screen_state =
|
|
|
|
get_global_privacy_screen_state (manager);
|
|
|
|
|
|
|
|
if (privacy_screen_state == META_PRIVACY_SCREEN_UNAVAILABLE)
|
2022-04-12 23:42:14 +00:00
|
|
|
return FALSE;
|
2021-03-22 00:15:40 +00:00
|
|
|
|
2022-04-12 23:42:14 +00:00
|
|
|
return (!!(privacy_screen_state & META_PRIVACY_SCREEN_ENABLED) !=
|
|
|
|
meta_settings_is_privacy_screen_enabled (settings));
|
|
|
|
}
|
2021-03-22 00:15:40 +00:00
|
|
|
|
2022-04-12 23:42:14 +00:00
|
|
|
static void
|
|
|
|
apply_privacy_screen_settings (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
if (privacy_screen_needs_update (manager) &&
|
2022-03-17 09:33:23 +00:00
|
|
|
ensure_privacy_screen_settings (manager))
|
2021-08-02 16:22:46 +00:00
|
|
|
{
|
|
|
|
manager->privacy_screen_change_state =
|
|
|
|
META_PRIVACY_SCREEN_CHANGE_STATE_PENDING_SETTING;
|
|
|
|
}
|
2021-03-22 00:15:40 +00:00
|
|
|
}
|
|
|
|
|
2020-06-11 16:15:22 +00:00
|
|
|
static void
|
|
|
|
update_panel_orientation_managed (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaOrientationManager *orientation_manager;
|
2020-06-11 16:18:37 +00:00
|
|
|
ClutterBackend *clutter_backend;
|
|
|
|
ClutterSeat *seat;
|
2020-06-11 16:15:22 +00:00
|
|
|
gboolean panel_orientation_managed;
|
|
|
|
|
2020-06-11 16:18:37 +00:00
|
|
|
clutter_backend = meta_backend_get_clutter_backend (manager->backend);
|
|
|
|
seat = clutter_backend_get_default_seat (clutter_backend);
|
|
|
|
|
2020-06-11 16:15:22 +00:00
|
|
|
orientation_manager = meta_backend_get_orientation_manager (manager->backend);
|
|
|
|
|
|
|
|
panel_orientation_managed =
|
2020-06-11 16:18:37 +00:00
|
|
|
(clutter_seat_get_touch_mode (seat) &&
|
2021-07-30 11:47:42 +00:00
|
|
|
meta_orientation_manager_has_accelerometer (orientation_manager) &&
|
|
|
|
meta_monitor_manager_get_laptop_panel (manager));
|
2020-06-11 16:15:22 +00:00
|
|
|
|
|
|
|
if (manager->panel_orientation_managed == panel_orientation_managed)
|
|
|
|
return;
|
|
|
|
|
|
|
|
manager->panel_orientation_managed = panel_orientation_managed;
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (manager),
|
|
|
|
obj_props[PROP_PANEL_ORIENTATION_MANAGED]);
|
|
|
|
|
|
|
|
meta_dbus_display_config_set_panel_orientation_managed (manager->display_config,
|
|
|
|
manager->panel_orientation_managed);
|
2020-10-15 10:22:53 +00:00
|
|
|
|
|
|
|
/* The orientation may have changed while it was unmanaged */
|
|
|
|
if (panel_orientation_managed)
|
|
|
|
handle_orientation_change (orientation_manager, manager);
|
2020-06-11 16:15:22 +00:00
|
|
|
}
|
|
|
|
|
2021-12-02 20:43:08 +00:00
|
|
|
static void
|
|
|
|
update_has_builtin_panel (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
GList *l;
|
|
|
|
gboolean has_builtin_panel = FALSE;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = META_MONITOR (l->data);
|
|
|
|
|
|
|
|
if (meta_monitor_is_laptop_panel (monitor))
|
|
|
|
{
|
|
|
|
has_builtin_panel = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->has_builtin_panel == has_builtin_panel)
|
|
|
|
return;
|
|
|
|
|
|
|
|
priv->has_builtin_panel = has_builtin_panel;
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (manager),
|
|
|
|
obj_props[PROP_HAS_BUILTIN_PANEL]);
|
|
|
|
}
|
|
|
|
|
2022-08-15 12:09:29 +00:00
|
|
|
static void
|
|
|
|
update_night_light_supported (MetaMonitorManager *manager)
|
2022-02-24 11:32:27 +00:00
|
|
|
{
|
2022-08-15 12:09:29 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
2022-02-24 11:32:27 +00:00
|
|
|
GList *l;
|
|
|
|
|
2022-08-15 12:09:29 +00:00
|
|
|
gboolean night_light_supported = FALSE;
|
|
|
|
|
2022-02-24 11:32:27 +00:00
|
|
|
for (l = meta_backend_get_gpus (manager->backend); l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaGpu *gpu = l->data;
|
|
|
|
GList *l_crtc;
|
|
|
|
|
|
|
|
for (l_crtc = meta_gpu_get_crtcs (gpu); l_crtc; l_crtc = l_crtc->next)
|
|
|
|
{
|
|
|
|
MetaCrtc *crtc = l_crtc->data;
|
|
|
|
|
2021-12-03 16:34:34 +00:00
|
|
|
if (meta_crtc_get_gamma_lut_size (crtc) > 0)
|
2022-08-15 12:09:29 +00:00
|
|
|
{
|
|
|
|
night_light_supported = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
2022-02-24 11:32:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-15 12:09:29 +00:00
|
|
|
if (priv->night_light_supported == night_light_supported)
|
|
|
|
return;
|
|
|
|
|
|
|
|
priv->night_light_supported = night_light_supported;
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (manager),
|
|
|
|
obj_props[PROP_NIGHT_LIGHT_SUPPORTED]);
|
2022-09-13 18:03:42 +00:00
|
|
|
meta_dbus_display_config_set_night_light_supported (manager->display_config,
|
|
|
|
night_light_supported);
|
2022-02-24 11:32:27 +00:00
|
|
|
}
|
|
|
|
|
2017-07-05 10:06:06 +00:00
|
|
|
void
|
|
|
|
meta_monitor_manager_setup (MetaMonitorManager *manager)
|
|
|
|
{
|
2021-09-30 19:06:38 +00:00
|
|
|
MetaMonitorConfigStore *config_store;
|
|
|
|
const MetaMonitorConfigPolicy *policy;
|
2022-08-15 12:09:29 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
2021-09-30 19:06:38 +00:00
|
|
|
|
2017-07-05 10:06:06 +00:00
|
|
|
manager->in_init = TRUE;
|
|
|
|
|
|
|
|
manager->config_manager = meta_monitor_config_manager_new (manager);
|
2021-09-30 19:06:38 +00:00
|
|
|
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);
|
|
|
|
|
2022-02-24 11:32:27 +00:00
|
|
|
meta_dbus_display_config_set_night_light_supported (manager->display_config,
|
2022-08-15 12:09:29 +00:00
|
|
|
priv->night_light_supported);
|
2017-07-05 10:06:06 +00:00
|
|
|
|
|
|
|
meta_monitor_manager_read_current_state (manager);
|
|
|
|
|
|
|
|
meta_monitor_manager_ensure_initial_config (manager);
|
|
|
|
|
2022-04-12 23:42:14 +00:00
|
|
|
if (privacy_screen_needs_update (manager))
|
|
|
|
manager->privacy_screen_change_state = META_PRIVACY_SCREEN_CHANGE_STATE_INIT;
|
2021-03-22 00:15:40 +00:00
|
|
|
|
2023-10-24 08:21:09 +00:00
|
|
|
ensure_hdr_settings (manager);
|
|
|
|
|
2017-07-05 10:06:06 +00:00
|
|
|
manager->in_init = FALSE;
|
|
|
|
}
|
|
|
|
|
2023-11-09 05:10:37 +00:00
|
|
|
static void
|
|
|
|
on_started (MetaContext *context,
|
|
|
|
MetaMonitorManager *monitor_manager)
|
|
|
|
{
|
|
|
|
g_signal_connect (monitor_manager, "notify::experimental-hdr",
|
|
|
|
G_CALLBACK (meta_monitor_manager_reconfigure),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2013-07-29 11:00:15 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_constructed (GObject *object)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
2023-10-24 08:21:09 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
2017-07-10 09:39:07 +00:00
|
|
|
MetaBackend *backend = manager->backend;
|
2023-11-09 05:10:37 +00:00
|
|
|
MetaContext *context = meta_backend_get_context (backend);
|
2017-04-21 08:40:51 +00:00
|
|
|
MetaSettings *settings = meta_backend_get_settings (backend);
|
2017-01-10 02:38:06 +00:00
|
|
|
|
2019-01-23 01:49:26 +00:00
|
|
|
manager->display_config = meta_dbus_display_config_skeleton_new ();
|
|
|
|
|
2023-10-24 08:21:09 +00:00
|
|
|
if (g_strcmp0 (getenv ("MUTTER_DEBUG_ENABLE_HDR"), "1") == 0)
|
|
|
|
priv->experimental_hdr = g_strdup ("on");
|
|
|
|
|
2021-03-19 14:39:35 +00:00
|
|
|
g_signal_connect_object (settings,
|
|
|
|
"experimental-features-changed",
|
|
|
|
G_CALLBACK (experimental_features_changed),
|
|
|
|
manager, 0);
|
2017-03-04 07:30:56 +00:00
|
|
|
|
2021-03-22 00:15:40 +00:00
|
|
|
g_signal_connect_object (settings,
|
|
|
|
"privacy-screen-changed",
|
|
|
|
G_CALLBACK (apply_privacy_screen_settings),
|
|
|
|
manager, G_CONNECT_SWAPPED);
|
|
|
|
|
2019-01-23 01:49:26 +00:00
|
|
|
monitor_manager_setup_dbus_config_handlers (manager);
|
|
|
|
|
|
|
|
g_signal_connect_object (manager->display_config, "notify::power-save-mode",
|
|
|
|
G_CALLBACK (power_save_mode_changed), manager,
|
|
|
|
G_CONNECT_SWAPPED);
|
2014-09-26 01:39:14 +00:00
|
|
|
|
2017-04-28 15:53:07 +00:00
|
|
|
g_signal_connect_object (meta_backend_get_orientation_manager (backend),
|
|
|
|
"orientation-changed",
|
|
|
|
G_CALLBACK (orientation_changed),
|
|
|
|
manager, 0);
|
|
|
|
|
2020-06-11 16:15:22 +00:00
|
|
|
g_signal_connect_object (meta_backend_get_orientation_manager (backend),
|
|
|
|
"notify::has-accelerometer",
|
|
|
|
G_CALLBACK (update_panel_orientation_managed), manager,
|
|
|
|
G_CONNECT_SWAPPED);
|
|
|
|
|
2018-04-16 18:07:45 +00:00
|
|
|
g_signal_connect_object (backend,
|
|
|
|
"lid-is-closed-changed",
|
|
|
|
G_CALLBACK (lid_is_closed_changed),
|
|
|
|
manager, 0);
|
|
|
|
|
2023-11-09 05:10:37 +00:00
|
|
|
g_signal_connect (context, "started", G_CALLBACK (on_started), manager);
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
g_signal_connect (backend, "prepare-shutdown",
|
|
|
|
G_CALLBACK (prepare_shutdown),
|
|
|
|
manager);
|
|
|
|
|
2017-06-07 16:38:10 +00:00
|
|
|
manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
2013-07-25 08:57:59 +00:00
|
|
|
|
2013-07-29 11:00:15 +00:00
|
|
|
initialize_dbus_interface (manager);
|
2013-07-18 11:09:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitor_manager_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
2013-07-18 11:09:16 +00:00
|
|
|
|
2023-10-24 08:20:49 +00:00
|
|
|
g_clear_pointer (&priv->experimental_hdr, g_free);
|
2016-12-02 08:08:59 +00:00
|
|
|
g_list_free_full (manager->logical_monitors, g_object_unref);
|
2013-07-18 11:09:16 +00:00
|
|
|
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
g_warn_if_fail (!priv->virtual_monitors);
|
|
|
|
|
2013-07-18 11:09:16 +00:00
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2013-07-19 12:39:28 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
2023-03-14 16:28:24 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2023-03-06 22:49:39 +00:00
|
|
|
g_clear_handle_id (&manager->dbus_name_id, g_bus_unown_name);
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2019-01-23 01:49:26 +00:00
|
|
|
g_clear_object (&manager->display_config);
|
2017-01-09 06:31:18 +00:00
|
|
|
g_clear_object (&manager->config_manager);
|
|
|
|
|
2020-05-01 14:39:47 +00:00
|
|
|
g_clear_handle_id (&manager->persistent_timeout_id, g_source_remove);
|
2023-03-06 23:06:30 +00:00
|
|
|
g_clear_handle_id (&manager->restore_config_id, g_source_remove);
|
2023-03-14 16:28:24 +00:00
|
|
|
g_clear_handle_id (&priv->switch_config_handle_id, g_source_remove);
|
2023-09-29 12:31:41 +00:00
|
|
|
g_clear_handle_id (&priv->reload_monitor_manager_id, g_source_remove);
|
2020-05-01 14:39:47 +00:00
|
|
|
|
2013-07-19 12:39:28 +00:00
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
2014-04-01 14:24:10 +00:00
|
|
|
static GBytes *
|
|
|
|
meta_monitor_manager_real_read_edid (MetaMonitorManager *manager,
|
|
|
|
MetaOutput *output)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-07-10 09:39:07 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
2023-03-02 00:35:10 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
2017-07-10 09:39:07 +00:00
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_BACKEND:
|
|
|
|
manager->backend = g_value_get_object (value);
|
|
|
|
break;
|
2023-03-02 00:35:10 +00:00
|
|
|
case PROP_EXPERIMENTAL_HDR:
|
2023-10-24 08:20:49 +00:00
|
|
|
g_clear_pointer (&priv->experimental_hdr, g_free);
|
2023-03-02 00:35:10 +00:00
|
|
|
priv->experimental_hdr = g_value_dup_string (value);
|
|
|
|
break;
|
2020-06-11 16:15:22 +00:00
|
|
|
case PROP_PANEL_ORIENTATION_MANAGED:
|
2021-12-02 20:43:08 +00:00
|
|
|
case PROP_HAS_BUILTIN_PANEL:
|
2022-08-15 12:09:29 +00:00
|
|
|
case PROP_NIGHT_LIGHT_SUPPORTED:
|
2017-07-10 09:39:07 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitor_manager_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
2021-12-02 20:43:08 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
2017-07-10 09:39:07 +00:00
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_BACKEND:
|
|
|
|
g_value_set_object (value, manager->backend);
|
|
|
|
break;
|
2020-06-11 16:15:22 +00:00
|
|
|
case PROP_PANEL_ORIENTATION_MANAGED:
|
|
|
|
g_value_set_boolean (value, manager->panel_orientation_managed);
|
|
|
|
break;
|
2021-12-02 20:43:08 +00:00
|
|
|
case PROP_HAS_BUILTIN_PANEL:
|
|
|
|
g_value_set_boolean (value, priv->has_builtin_panel);
|
|
|
|
break;
|
2022-08-15 12:09:29 +00:00
|
|
|
case PROP_NIGHT_LIGHT_SUPPORTED:
|
|
|
|
g_value_set_boolean (value, priv->night_light_supported);
|
|
|
|
break;
|
2023-03-02 00:35:10 +00:00
|
|
|
case PROP_EXPERIMENTAL_HDR:
|
|
|
|
g_value_set_string (value, priv->experimental_hdr);
|
|
|
|
break;
|
2017-07-10 09:39:07 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-18 11:09:16 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
2013-07-29 11:00:15 +00:00
|
|
|
object_class->constructed = meta_monitor_manager_constructed;
|
2013-07-19 12:39:28 +00:00
|
|
|
object_class->dispose = meta_monitor_manager_dispose;
|
2013-07-18 11:09:16 +00:00
|
|
|
object_class->finalize = meta_monitor_manager_finalize;
|
2017-07-10 09:39:07 +00:00
|
|
|
object_class->get_property = meta_monitor_manager_get_property;
|
|
|
|
object_class->set_property = meta_monitor_manager_set_property;
|
2013-07-18 11:09:16 +00:00
|
|
|
|
2014-04-01 14:24:10 +00:00
|
|
|
klass->read_edid = meta_monitor_manager_real_read_edid;
|
2019-01-11 13:45:44 +00:00
|
|
|
klass->read_current_state = meta_monitor_manager_real_read_current_state;
|
2014-04-01 14:24:10 +00:00
|
|
|
|
2019-01-23 01:49:26 +00:00
|
|
|
signals[MONITORS_CHANGED] =
|
|
|
|
g_signal_new ("monitors-changed",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2017-10-13 00:14:40 +00:00
|
|
|
signals[MONITORS_CHANGED_INTERNAL] =
|
|
|
|
g_signal_new ("monitors-changed-internal",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2019-01-23 01:49:26 +00:00
|
|
|
signals[POWER_SAVE_MODE_CHANGED] =
|
|
|
|
g_signal_new ("power-save-mode-changed",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
2023-09-01 20:20:16 +00:00
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
META_TYPE_POWER_SAVE_CHANGE_REASON);
|
2019-01-23 01:49:26 +00:00
|
|
|
|
2013-07-29 08:12:24 +00:00
|
|
|
signals[CONFIRM_DISPLAY_CHANGE] =
|
|
|
|
g_signal_new ("confirm-display-change",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
2017-07-10 09:39:07 +00:00
|
|
|
|
2022-02-14 08:43:31 +00:00
|
|
|
/**
|
|
|
|
* MetaMonitorManager::monitor-privacy-screen-changed: (skip)
|
|
|
|
* @monitor_manager: The #MetaMonitorManager
|
|
|
|
* @logical_monitor: The #MetaLogicalMonitor where the privacy screen state
|
|
|
|
* changed
|
|
|
|
* @enabled: %TRUE if the privacy screen was enabled, otherwise %FALSE
|
|
|
|
*/
|
2021-08-02 16:22:46 +00:00
|
|
|
signals[MONITOR_PRIVACY_SCREEN_CHANGED] =
|
|
|
|
g_signal_new ("monitor-privacy-screen-changed",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 2, META_TYPE_LOGICAL_MONITOR, G_TYPE_BOOLEAN);
|
|
|
|
|
2017-07-10 09:39:07 +00:00
|
|
|
obj_props[PROP_BACKEND] =
|
2023-06-28 12:02:43 +00:00
|
|
|
g_param_spec_object ("backend", NULL, NULL,
|
2017-07-10 09:39:07 +00:00
|
|
|
META_TYPE_BACKEND,
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
2020-06-11 16:15:22 +00:00
|
|
|
|
|
|
|
obj_props[PROP_PANEL_ORIENTATION_MANAGED] =
|
2023-06-28 12:02:43 +00:00
|
|
|
g_param_spec_boolean ("panel-orientation-managed", NULL, NULL,
|
2020-06-11 16:15:22 +00:00
|
|
|
FALSE,
|
|
|
|
G_PARAM_READABLE |
|
|
|
|
G_PARAM_EXPLICIT_NOTIFY |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
2021-12-02 20:43:08 +00:00
|
|
|
|
|
|
|
obj_props[PROP_HAS_BUILTIN_PANEL] =
|
2023-06-28 12:02:43 +00:00
|
|
|
g_param_spec_boolean ("has-builtin-panel", NULL, NULL,
|
2021-12-02 20:43:08 +00:00
|
|
|
FALSE,
|
|
|
|
G_PARAM_READABLE |
|
|
|
|
G_PARAM_EXPLICIT_NOTIFY |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
|
2022-08-15 12:09:29 +00:00
|
|
|
obj_props[PROP_NIGHT_LIGHT_SUPPORTED] =
|
2023-06-28 12:02:43 +00:00
|
|
|
g_param_spec_boolean ("night-light-supported", NULL, NULL,
|
2022-08-15 12:09:29 +00:00
|
|
|
FALSE,
|
|
|
|
G_PARAM_READABLE |
|
|
|
|
G_PARAM_EXPLICIT_NOTIFY |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
|
2023-03-02 00:35:10 +00:00
|
|
|
obj_props[PROP_EXPERIMENTAL_HDR] =
|
2023-06-28 12:02:43 +00:00
|
|
|
g_param_spec_string ("experimental-hdr", NULL, NULL,
|
2023-03-02 00:35:10 +00:00
|
|
|
NULL,
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
|
2017-07-10 09:39:07 +00:00
|
|
|
g_object_class_install_properties (object_class, PROP_LAST, obj_props);
|
2013-07-18 11:09:16 +00:00
|
|
|
}
|
|
|
|
|
2018-09-24 07:48:37 +00:00
|
|
|
gboolean
|
|
|
|
meta_monitor_has_aspect_as_size (MetaMonitor *monitor)
|
|
|
|
{
|
|
|
|
int width_mm;
|
|
|
|
int height_mm;
|
|
|
|
|
|
|
|
meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm);
|
|
|
|
|
2018-09-24 07:50:27 +00:00
|
|
|
return (width_mm == 1600 && height_mm == 900) ||
|
|
|
|
(width_mm == 1600 && height_mm == 1000) ||
|
|
|
|
(width_mm == 160 && height_mm == 90) ||
|
2018-09-24 07:48:37 +00:00
|
|
|
(width_mm == 160 && height_mm == 100) ||
|
|
|
|
(width_mm == 16 && height_mm == 9) ||
|
|
|
|
(width_mm == 16 && height_mm == 10);
|
|
|
|
}
|
|
|
|
|
2014-12-30 00:18:24 +00:00
|
|
|
static const char *
|
|
|
|
get_connector_type_name (MetaConnectorType connector_type)
|
|
|
|
{
|
|
|
|
switch (connector_type)
|
|
|
|
{
|
|
|
|
case META_CONNECTOR_TYPE_Unknown: return "Unknown";
|
|
|
|
case META_CONNECTOR_TYPE_VGA: return "VGA";
|
|
|
|
case META_CONNECTOR_TYPE_DVII: return "DVII";
|
|
|
|
case META_CONNECTOR_TYPE_DVID: return "DVID";
|
|
|
|
case META_CONNECTOR_TYPE_DVIA: return "DVIA";
|
|
|
|
case META_CONNECTOR_TYPE_Composite: return "Composite";
|
|
|
|
case META_CONNECTOR_TYPE_SVIDEO: return "SVIDEO";
|
|
|
|
case META_CONNECTOR_TYPE_LVDS: return "LVDS";
|
|
|
|
case META_CONNECTOR_TYPE_Component: return "Component";
|
|
|
|
case META_CONNECTOR_TYPE_9PinDIN: return "9PinDIN";
|
|
|
|
case META_CONNECTOR_TYPE_DisplayPort: return "DisplayPort";
|
|
|
|
case META_CONNECTOR_TYPE_HDMIA: return "HDMIA";
|
|
|
|
case META_CONNECTOR_TYPE_HDMIB: return "HDMIB";
|
|
|
|
case META_CONNECTOR_TYPE_TV: return "TV";
|
|
|
|
case META_CONNECTOR_TYPE_eDP: return "eDP";
|
|
|
|
case META_CONNECTOR_TYPE_VIRTUAL: return "VIRTUAL";
|
|
|
|
case META_CONNECTOR_TYPE_DSI: return "DSI";
|
2022-08-16 22:41:42 +00:00
|
|
|
case META_CONNECTOR_TYPE_DPI: return "DPI";
|
|
|
|
case META_CONNECTOR_TYPE_WRITEBACK: return "WRITEBACK";
|
|
|
|
case META_CONNECTOR_TYPE_SPI: return "SPI";
|
|
|
|
case META_CONNECTOR_TYPE_USB: return "USB";
|
2014-12-30 00:18:24 +00:00
|
|
|
default: g_assert_not_reached ();
|
|
|
|
}
|
2019-01-24 23:47:44 +00:00
|
|
|
return NULL;
|
2014-12-30 00:18:24 +00:00
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
static GList *
|
|
|
|
combine_gpu_lists (MetaMonitorManager *manager,
|
|
|
|
GList * (*list_getter) (MetaGpu *gpu))
|
|
|
|
{
|
2019-01-11 14:35:42 +00:00
|
|
|
GList *gpus;
|
2017-07-10 10:19:32 +00:00
|
|
|
GList *list = NULL;
|
|
|
|
GList *l;
|
|
|
|
|
2019-01-11 14:35:42 +00:00
|
|
|
gpus = meta_backend_get_gpus (manager->backend);
|
|
|
|
for (l = gpus; l; l = l->next)
|
2017-07-10 10:19:32 +00:00
|
|
|
{
|
|
|
|
MetaGpu *gpu = l->data;
|
|
|
|
|
|
|
|
list = g_list_concat (list, g_list_copy (list_getter (gpu)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2021-08-02 16:22:46 +00:00
|
|
|
static void
|
|
|
|
emit_privacy_screen_change (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaPrivacyScreenState privacy_screen_state;
|
|
|
|
gboolean enabled;
|
|
|
|
|
|
|
|
if (!meta_monitor_is_active (monitor))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
privacy_screen_state = meta_monitor_get_privacy_screen_state (monitor);
|
|
|
|
if (privacy_screen_state == META_PRIVACY_SCREEN_UNAVAILABLE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
enabled = !!(privacy_screen_state & META_PRIVACY_SCREEN_ENABLED);
|
|
|
|
|
|
|
|
g_signal_emit (manager, signals[MONITOR_PRIVACY_SCREEN_CHANGED], 0,
|
|
|
|
meta_monitor_get_logical_monitor (monitor), enabled);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_maybe_emit_privacy_screen_change (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaPrivacyScreenChangeState reason = manager->privacy_screen_change_state;
|
|
|
|
|
2022-04-12 23:42:14 +00:00
|
|
|
if (reason == META_PRIVACY_SCREEN_CHANGE_STATE_NONE ||
|
|
|
|
reason == META_PRIVACY_SCREEN_CHANGE_STATE_INIT)
|
2021-08-02 16:22:46 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (reason == META_PRIVACY_SCREEN_CHANGE_STATE_PENDING_HOTKEY)
|
|
|
|
emit_privacy_screen_change (manager);
|
|
|
|
|
|
|
|
if (reason != META_PRIVACY_SCREEN_CHANGE_STATE_PENDING_SETTING)
|
|
|
|
{
|
|
|
|
MetaSettings *settings = meta_backend_get_settings (manager->backend);
|
|
|
|
|
|
|
|
meta_settings_set_privacy_screen_enabled (settings,
|
|
|
|
get_global_privacy_screen_state (manager) ==
|
|
|
|
META_PRIVACY_SCREEN_ENABLED);
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_dbus_display_config_emit_monitors_changed (manager->display_config);
|
|
|
|
manager->privacy_screen_change_state = META_PRIVACY_SCREEN_CHANGE_STATE_NONE;
|
|
|
|
}
|
|
|
|
|
2013-07-19 12:39:28 +00:00
|
|
|
static gboolean
|
2013-07-23 17:32:17 +00:00
|
|
|
meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
|
2019-01-23 01:49:26 +00:00
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
MetaMonitorManager *manager)
|
2013-07-19 12:39:28 +00:00
|
|
|
{
|
2019-01-23 01:49:26 +00:00
|
|
|
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_GET_CLASS (manager);
|
2017-07-10 10:19:32 +00:00
|
|
|
GList *combined_modes;
|
|
|
|
GList *combined_outputs;
|
|
|
|
GList *combined_crtcs;
|
2013-07-19 12:39:28 +00:00
|
|
|
GVariantBuilder crtc_builder, output_builder, mode_builder;
|
2017-03-24 09:35:51 +00:00
|
|
|
GList *l;
|
2013-07-19 12:39:28 +00:00
|
|
|
unsigned int i, j;
|
2017-02-15 08:06:46 +00:00
|
|
|
int max_screen_width;
|
|
|
|
int max_screen_height;
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
combined_modes = combine_gpu_lists (manager, meta_gpu_get_modes);
|
|
|
|
combined_outputs = combine_gpu_lists (manager, meta_gpu_get_outputs);
|
|
|
|
combined_crtcs = combine_gpu_lists (manager, meta_gpu_get_crtcs);
|
|
|
|
|
2013-07-19 12:39:28 +00:00
|
|
|
g_variant_builder_init (&crtc_builder, G_VARIANT_TYPE ("a(uxiiiiiuaua{sv})"));
|
2013-07-19 16:47:01 +00:00
|
|
|
g_variant_builder_init (&output_builder, G_VARIANT_TYPE ("a(uxiausauaua{sv})"));
|
2015-04-21 15:49:55 +00:00
|
|
|
g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uxuudu)"));
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
for (l = combined_crtcs, i = 0; l; l = l->next, i++)
|
2013-07-19 12:39:28 +00:00
|
|
|
{
|
2017-03-28 04:35:19 +00:00
|
|
|
MetaCrtc *crtc = l->data;
|
2013-07-19 12:39:28 +00:00
|
|
|
GVariantBuilder transforms;
|
2020-02-26 09:37:53 +00:00
|
|
|
const MetaCrtcConfig *crtc_config;
|
2013-07-19 12:39:28 +00:00
|
|
|
|
|
|
|
g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au"));
|
2014-07-10 21:39:47 +00:00
|
|
|
for (j = 0; j <= META_MONITOR_TRANSFORM_FLIPPED_270; j++)
|
2020-02-26 09:14:52 +00:00
|
|
|
{
|
|
|
|
if (meta_crtc_get_all_transforms (crtc) & (1 << j))
|
|
|
|
g_variant_builder_add (&transforms, "u", j);
|
|
|
|
}
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2020-02-26 09:37:53 +00:00
|
|
|
crtc_config = meta_crtc_get_config (crtc);
|
2020-01-14 21:34:44 +00:00
|
|
|
if (crtc_config)
|
|
|
|
{
|
|
|
|
int current_mode_index;
|
|
|
|
|
|
|
|
current_mode_index = g_list_index (combined_modes, crtc_config->mode);
|
|
|
|
g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})",
|
|
|
|
i, /* ID */
|
2020-02-25 10:34:43 +00:00
|
|
|
(int64_t) meta_crtc_get_id (crtc),
|
2020-01-14 21:34:44 +00:00
|
|
|
(int) roundf (crtc_config->layout.origin.x),
|
|
|
|
(int) roundf (crtc_config->layout.origin.y),
|
|
|
|
(int) roundf (crtc_config->layout.size.width),
|
|
|
|
(int) roundf (crtc_config->layout.size.height),
|
|
|
|
current_mode_index,
|
|
|
|
(uint32_t) crtc_config->transform,
|
|
|
|
&transforms,
|
|
|
|
NULL /* properties */);
|
|
|
|
}
|
2017-03-28 08:52:15 +00:00
|
|
|
else
|
2020-01-14 21:34:44 +00:00
|
|
|
{
|
|
|
|
g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})",
|
|
|
|
i, /* ID */
|
2020-02-25 10:34:43 +00:00
|
|
|
(int64_t) meta_crtc_get_id (crtc),
|
2020-01-14 21:34:44 +00:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
-1,
|
|
|
|
(uint32_t) META_MONITOR_TRANSFORM_NORMAL,
|
|
|
|
&transforms,
|
|
|
|
NULL /* properties */);
|
|
|
|
}
|
2013-07-19 12:39:28 +00:00
|
|
|
}
|
|
|
|
|
2018-04-07 19:40:30 +00:00
|
|
|
for (l = combined_outputs, i = 0; l; l = l->next, i++)
|
2013-07-19 12:39:28 +00:00
|
|
|
{
|
2017-03-24 09:35:51 +00:00
|
|
|
MetaOutput *output = l->data;
|
2020-02-26 08:45:07 +00:00
|
|
|
const MetaOutputInfo *output_info = meta_output_get_info (output);
|
2013-07-19 16:47:01 +00:00
|
|
|
GVariantBuilder crtcs, modes, clones, properties;
|
2013-08-08 11:32:05 +00:00
|
|
|
GBytes *edid;
|
2017-11-03 10:25:30 +00:00
|
|
|
MetaCrtc *crtc;
|
2017-03-28 04:35:19 +00:00
|
|
|
int crtc_index;
|
2020-02-26 08:45:07 +00:00
|
|
|
int backlight;
|
|
|
|
int min_backlight_step;
|
|
|
|
gboolean is_primary;
|
|
|
|
gboolean is_presentation;
|
|
|
|
const char * connector_type_name;
|
|
|
|
gboolean is_underscanning;
|
|
|
|
gboolean supports_underscanning;
|
2020-02-05 00:41:34 +00:00
|
|
|
gboolean supports_color_transform;
|
2021-10-28 13:25:58 +00:00
|
|
|
const char *vendor;
|
|
|
|
const char *product;
|
|
|
|
const char *serial;
|
2013-07-19 12:39:28 +00:00
|
|
|
|
|
|
|
g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au"));
|
2020-02-26 08:45:07 +00:00
|
|
|
for (j = 0; j < output_info->n_possible_crtcs; j++)
|
2017-03-28 04:35:19 +00:00
|
|
|
{
|
2020-02-26 08:45:07 +00:00
|
|
|
MetaCrtc *possible_crtc = output_info->possible_crtcs[j];
|
2017-03-28 04:35:19 +00:00
|
|
|
unsigned possible_crtc_index;
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
possible_crtc_index = g_list_index (combined_crtcs, possible_crtc);
|
2017-03-28 04:35:19 +00:00
|
|
|
g_variant_builder_add (&crtcs, "u", possible_crtc_index);
|
|
|
|
}
|
2013-07-19 12:39:28 +00:00
|
|
|
|
|
|
|
g_variant_builder_init (&modes, G_VARIANT_TYPE ("au"));
|
2020-02-26 08:45:07 +00:00
|
|
|
for (j = 0; j < output_info->n_modes; j++)
|
2017-03-28 08:52:15 +00:00
|
|
|
{
|
|
|
|
unsigned mode_index;
|
|
|
|
|
2020-02-26 08:45:07 +00:00
|
|
|
mode_index = g_list_index (combined_modes, output_info->modes[j]);
|
2017-03-28 08:52:15 +00:00
|
|
|
g_variant_builder_add (&modes, "u", mode_index);
|
|
|
|
}
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2013-07-19 16:47:01 +00:00
|
|
|
g_variant_builder_init (&clones, G_VARIANT_TYPE ("au"));
|
2020-02-26 08:45:07 +00:00
|
|
|
for (j = 0; j < output_info->n_possible_clones; j++)
|
2017-03-24 09:35:51 +00:00
|
|
|
{
|
|
|
|
unsigned int possible_clone_index;
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
possible_clone_index = g_list_index (combined_outputs,
|
2020-02-26 08:45:07 +00:00
|
|
|
output_info->possible_clones[j]);
|
2017-03-24 09:35:51 +00:00
|
|
|
g_variant_builder_add (&clones, "u", possible_clone_index);
|
|
|
|
}
|
2013-07-19 16:47:01 +00:00
|
|
|
|
2020-02-26 08:45:07 +00:00
|
|
|
backlight = meta_output_get_backlight (output);
|
|
|
|
min_backlight_step =
|
|
|
|
output_info->backlight_max - output_info->backlight_min
|
|
|
|
? 100 / (output_info->backlight_max - output_info->backlight_min)
|
|
|
|
: -1;
|
|
|
|
is_primary = meta_output_is_primary (output);
|
|
|
|
is_presentation = meta_output_is_presentation (output);
|
|
|
|
is_underscanning = meta_output_is_underscanning (output);
|
|
|
|
connector_type_name = get_connector_type_name (output_info->connector_type);
|
|
|
|
supports_underscanning = output_info->supports_underscanning;
|
2020-02-05 00:41:34 +00:00
|
|
|
supports_color_transform = output_info->supports_color_transform;
|
2021-10-28 13:25:58 +00:00
|
|
|
vendor = output_info->vendor;
|
2023-01-31 14:53:41 +00:00
|
|
|
product = output_info->product;
|
2021-10-28 13:25:58 +00:00
|
|
|
serial = output_info->serial;
|
2020-02-26 08:45:07 +00:00
|
|
|
|
2013-07-19 12:39:28 +00:00
|
|
|
g_variant_builder_init (&properties, G_VARIANT_TYPE ("a{sv}"));
|
|
|
|
g_variant_builder_add (&properties, "{sv}", "vendor",
|
2021-10-28 13:25:58 +00:00
|
|
|
g_variant_new_string (vendor ? vendor : "unknown"));
|
2013-07-19 12:39:28 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "product",
|
2021-10-28 13:25:58 +00:00
|
|
|
g_variant_new_string (product ? product : "unknown"));
|
2013-07-19 12:39:28 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "serial",
|
2021-10-28 13:25:58 +00:00
|
|
|
g_variant_new_string (serial ? serial : "unknown"));
|
2013-08-19 15:37:24 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "width-mm",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_int32 (output_info->width_mm));
|
2013-08-19 15:37:24 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "height-mm",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_int32 (output_info->height_mm));
|
2013-07-19 12:39:28 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "display-name",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_string (output_info->name));
|
2013-07-25 13:06:09 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "backlight",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_int32 (backlight));
|
2013-10-17 15:05:59 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "min-backlight-step",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_int32 (min_backlight_step));
|
2013-07-19 12:39:28 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "primary",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_boolean (is_primary));
|
2013-07-19 12:39:28 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "presentation",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_boolean (is_presentation));
|
2014-12-30 00:18:24 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "connector-type",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_string (connector_type_name));
|
2014-04-16 08:20:55 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "underscanning",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_boolean (is_underscanning));
|
2015-07-02 00:42:46 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "supports-underscanning",
|
2020-02-26 08:45:07 +00:00
|
|
|
g_variant_new_boolean (supports_underscanning));
|
2020-02-05 00:41:34 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "supports-color-transform",
|
|
|
|
g_variant_new_boolean (supports_color_transform));
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2018-11-26 13:19:55 +00:00
|
|
|
edid = manager_class->read_edid (manager, output);
|
|
|
|
if (edid)
|
2013-08-08 11:32:05 +00:00
|
|
|
{
|
2018-11-26 13:19:55 +00:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "edid",
|
|
|
|
g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"),
|
|
|
|
edid, TRUE));
|
|
|
|
g_bytes_unref (edid);
|
2013-08-08 11:32:05 +00:00
|
|
|
}
|
|
|
|
|
2020-02-26 08:45:07 +00:00
|
|
|
if (output_info->tile_info.group_id)
|
2015-03-31 00:44:16 +00:00
|
|
|
{
|
2020-02-26 08:45:07 +00:00
|
|
|
GVariant *tile_variant;
|
|
|
|
|
|
|
|
tile_variant = g_variant_new ("(uuuuuuuu)",
|
|
|
|
output_info->tile_info.group_id,
|
|
|
|
output_info->tile_info.flags,
|
|
|
|
output_info->tile_info.max_h_tiles,
|
|
|
|
output_info->tile_info.max_v_tiles,
|
|
|
|
output_info->tile_info.loc_h_tile,
|
|
|
|
output_info->tile_info.loc_v_tile,
|
|
|
|
output_info->tile_info.tile_w,
|
|
|
|
output_info->tile_info.tile_h);
|
|
|
|
g_variant_builder_add (&properties, "{sv}", "tile", tile_variant);
|
2015-03-31 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 10:25:30 +00:00
|
|
|
crtc = meta_output_get_assigned_crtc (output);
|
|
|
|
crtc_index = crtc ? g_list_index (combined_crtcs, crtc) : -1;
|
2013-07-19 16:47:01 +00:00
|
|
|
g_variant_builder_add (&output_builder, "(uxiausauaua{sv})",
|
2013-07-19 12:39:28 +00:00
|
|
|
i, /* ID */
|
2020-02-25 15:13:52 +00:00
|
|
|
meta_output_get_id (output),
|
2017-03-28 04:35:19 +00:00
|
|
|
crtc_index,
|
2013-07-19 12:39:28 +00:00
|
|
|
&crtcs,
|
2020-02-26 08:45:07 +00:00
|
|
|
meta_output_get_name (output),
|
2013-07-19 12:39:28 +00:00
|
|
|
&modes,
|
2013-07-19 16:47:01 +00:00
|
|
|
&clones,
|
2013-07-19 12:39:28 +00:00
|
|
|
&properties);
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
for (l = combined_modes, i = 0; l; l = l->next, i++)
|
2013-07-19 12:39:28 +00:00
|
|
|
{
|
2017-03-28 08:52:15 +00:00
|
|
|
MetaCrtcMode *mode = l->data;
|
2020-02-26 23:08:58 +00:00
|
|
|
const MetaCrtcModeInfo *crtc_mode_info =
|
2020-07-28 08:11:07 +00:00
|
|
|
meta_crtc_mode_get_info (mode);
|
2013-07-19 12:39:28 +00:00
|
|
|
|
2015-04-21 15:49:55 +00:00
|
|
|
g_variant_builder_add (&mode_builder, "(uxuudu)",
|
2013-07-19 12:39:28 +00:00
|
|
|
i, /* ID */
|
2020-02-26 23:08:58 +00:00
|
|
|
(int64_t) meta_crtc_mode_get_id (mode),
|
|
|
|
(uint32_t) crtc_mode_info->width,
|
|
|
|
(uint32_t) crtc_mode_info->height,
|
|
|
|
(double) crtc_mode_info->refresh_rate,
|
|
|
|
(uint32_t) crtc_mode_info->flags);
|
2013-07-19 12:39:28 +00:00
|
|
|
}
|
|
|
|
|
2017-02-15 08:06:46 +00:00
|
|
|
if (!meta_monitor_manager_get_max_screen_size (manager,
|
|
|
|
&max_screen_width,
|
|
|
|
&max_screen_height))
|
|
|
|
{
|
|
|
|
/* No max screen size, just send something large */
|
|
|
|
max_screen_width = 65535;
|
|
|
|
max_screen_height = 65535;
|
|
|
|
}
|
|
|
|
|
2013-07-19 12:39:28 +00:00
|
|
|
meta_dbus_display_config_complete_get_resources (skeleton,
|
|
|
|
invocation,
|
|
|
|
manager->serial,
|
|
|
|
g_variant_builder_end (&crtc_builder),
|
|
|
|
g_variant_builder_end (&output_builder),
|
2013-07-22 11:31:10 +00:00
|
|
|
g_variant_builder_end (&mode_builder),
|
2017-02-15 08:06:46 +00:00
|
|
|
max_screen_width,
|
|
|
|
max_screen_height);
|
2017-07-10 10:19:32 +00:00
|
|
|
|
|
|
|
g_list_free (combined_modes);
|
|
|
|
g_list_free (combined_outputs);
|
|
|
|
g_list_free (combined_crtcs);
|
|
|
|
|
2013-07-22 11:31:10 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-03-23 09:20:07 +00:00
|
|
|
static void
|
|
|
|
restore_previous_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorsConfig *previous_config;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
previous_config =
|
2017-08-11 07:16:15 +00:00
|
|
|
meta_monitor_config_manager_pop_previous (manager->config_manager);
|
2017-03-23 09:20:07 +00:00
|
|
|
|
|
|
|
if (previous_config)
|
|
|
|
{
|
|
|
|
MetaMonitorsConfigMethod method;
|
|
|
|
|
2020-05-01 13:24:34 +00:00
|
|
|
if (manager->panel_orientation_managed)
|
|
|
|
{
|
|
|
|
g_autoptr (MetaMonitorsConfig) oriented_config = NULL;
|
|
|
|
|
|
|
|
oriented_config =
|
|
|
|
meta_monitor_config_manager_create_for_builtin_orientation (
|
|
|
|
manager->config_manager, previous_config);
|
|
|
|
|
|
|
|
if (oriented_config)
|
|
|
|
g_set_object (&previous_config, oriented_config);
|
|
|
|
}
|
|
|
|
|
2017-03-23 09:20:07 +00:00
|
|
|
method = META_MONITORS_CONFIG_METHOD_TEMPORARY;
|
|
|
|
if (meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
previous_config,
|
|
|
|
method,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_object_unref (previous_config);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_object_unref (previous_config);
|
|
|
|
g_warning ("Failed to restore previous configuration: %s",
|
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_monitor_manager_ensure_configured (manager);
|
|
|
|
}
|
|
|
|
|
2022-09-07 14:21:25 +00:00
|
|
|
int
|
|
|
|
meta_monitor_manager_get_display_configuration_timeout (MetaMonitorManager *manager)
|
2014-08-21 00:07:13 +00:00
|
|
|
{
|
|
|
|
return DEFAULT_DISPLAY_CONFIGURATION_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
2013-07-24 13:35:47 +00:00
|
|
|
static gboolean
|
|
|
|
save_config_timeout (gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
|
2017-03-24 07:36:12 +00:00
|
|
|
restore_previous_config (manager);
|
2013-07-29 08:12:24 +00:00
|
|
|
manager->persistent_timeout_id = 0;
|
2017-03-24 07:36:12 +00:00
|
|
|
|
2013-07-24 13:35:47 +00:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
2017-03-23 09:20:07 +00:00
|
|
|
static void
|
2017-03-24 07:36:12 +00:00
|
|
|
request_persistent_confirmation (MetaMonitorManager *manager)
|
2017-03-23 09:20:07 +00:00
|
|
|
{
|
2022-09-07 14:21:25 +00:00
|
|
|
int timeout_s;
|
|
|
|
|
|
|
|
timeout_s = meta_monitor_manager_get_display_configuration_timeout (manager);
|
|
|
|
manager->persistent_timeout_id = g_timeout_add_seconds (timeout_s,
|
2017-03-23 09:20:07 +00:00
|
|
|
save_config_timeout,
|
|
|
|
manager);
|
|
|
|
g_source_set_name_by_id (manager->persistent_timeout_id,
|
|
|
|
"[mutter] save_config_timeout");
|
|
|
|
|
|
|
|
g_signal_emit (manager, signals[CONFIRM_DISPLAY_CHANGE], 0);
|
|
|
|
}
|
|
|
|
|
2017-01-20 08:55:43 +00:00
|
|
|
#define META_DISPLAY_CONFIG_MODE_FLAGS_PREFERRED (1 << 0)
|
|
|
|
#define META_DISPLAY_CONFIG_MODE_FLAGS_CURRENT (1 << 1)
|
|
|
|
|
2017-06-14 04:17:31 +00:00
|
|
|
#define MODE_FORMAT "(siiddada{sv})"
|
2017-01-20 08:55:43 +00:00
|
|
|
#define MODES_FORMAT "a" MODE_FORMAT
|
|
|
|
#define MONITOR_SPEC_FORMAT "(ssss)"
|
|
|
|
#define MONITOR_FORMAT "(" MONITOR_SPEC_FORMAT MODES_FORMAT "a{sv})"
|
|
|
|
#define MONITORS_FORMAT "a" MONITOR_FORMAT
|
|
|
|
|
|
|
|
#define LOGICAL_MONITOR_MONITORS_FORMAT "a" MONITOR_SPEC_FORMAT
|
2017-03-21 06:29:32 +00:00
|
|
|
#define LOGICAL_MONITOR_FORMAT "(iidub" LOGICAL_MONITOR_MONITORS_FORMAT "a{sv})"
|
2017-01-20 08:55:43 +00:00
|
|
|
#define LOGICAL_MONITORS_FORMAT "a" LOGICAL_MONITOR_FORMAT
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton,
|
2019-01-23 01:49:26 +00:00
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
MetaMonitorManager *manager)
|
2017-01-20 08:55:43 +00:00
|
|
|
{
|
2017-10-11 09:59:04 +00:00
|
|
|
MetaSettings *settings = meta_backend_get_settings (manager->backend);
|
2017-01-20 08:55:43 +00:00
|
|
|
GVariantBuilder monitors_builder;
|
|
|
|
GVariantBuilder logical_monitors_builder;
|
2017-02-07 08:03:43 +00:00
|
|
|
GVariantBuilder properties_builder;
|
2017-01-20 08:55:43 +00:00
|
|
|
GList *l;
|
2017-01-26 09:15:52 +00:00
|
|
|
int i;
|
2017-02-07 08:03:43 +00:00
|
|
|
MetaMonitorManagerCapability capabilities;
|
2017-10-11 09:59:04 +00:00
|
|
|
int ui_scaling_factor;
|
2017-02-15 08:06:46 +00:00
|
|
|
int max_screen_width, max_screen_height;
|
2017-01-20 08:55:43 +00:00
|
|
|
|
|
|
|
g_variant_builder_init (&monitors_builder,
|
|
|
|
G_VARIANT_TYPE (MONITORS_FORMAT));
|
|
|
|
g_variant_builder_init (&logical_monitors_builder,
|
|
|
|
G_VARIANT_TYPE (LOGICAL_MONITORS_FORMAT));
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor);
|
|
|
|
MetaMonitorMode *current_mode;
|
|
|
|
MetaMonitorMode *preferred_mode;
|
2021-03-22 00:20:00 +00:00
|
|
|
MetaPrivacyScreenState privacy_screen_state;
|
2017-01-20 08:55:43 +00:00
|
|
|
GVariantBuilder modes_builder;
|
2017-02-07 08:03:43 +00:00
|
|
|
GVariantBuilder monitor_properties_builder;
|
2017-01-20 08:55:43 +00:00
|
|
|
GList *k;
|
2017-03-23 15:33:34 +00:00
|
|
|
gboolean is_builtin;
|
2019-06-26 09:40:00 +00:00
|
|
|
const char *display_name;
|
2017-01-20 08:55:43 +00:00
|
|
|
|
|
|
|
current_mode = meta_monitor_get_current_mode (monitor);
|
|
|
|
preferred_mode = meta_monitor_get_preferred_mode (monitor);
|
|
|
|
|
|
|
|
g_variant_builder_init (&modes_builder, G_VARIANT_TYPE (MODES_FORMAT));
|
|
|
|
for (k = meta_monitor_get_modes (monitor); k; k = k->next)
|
|
|
|
{
|
|
|
|
MetaMonitorMode *monitor_mode = k->data;
|
2017-06-05 07:59:47 +00:00
|
|
|
GVariantBuilder supported_scales_builder;
|
2017-06-14 04:04:09 +00:00
|
|
|
const char *mode_id;
|
|
|
|
int mode_width, mode_height;
|
|
|
|
float refresh_rate;
|
2017-06-05 07:59:47 +00:00
|
|
|
float preferred_scale;
|
|
|
|
float *supported_scales;
|
|
|
|
int n_supported_scales;
|
2017-06-14 04:17:31 +00:00
|
|
|
GVariantBuilder mode_properties_builder;
|
2017-06-14 06:41:13 +00:00
|
|
|
MetaCrtcModeFlag mode_flags;
|
2017-01-20 08:55:43 +00:00
|
|
|
|
2018-07-16 16:09:40 +00:00
|
|
|
if (!meta_monitor_mode_should_be_advertised (monitor_mode))
|
|
|
|
continue;
|
|
|
|
|
2017-06-14 04:04:09 +00:00
|
|
|
mode_id = meta_monitor_mode_get_id (monitor_mode);
|
|
|
|
meta_monitor_mode_get_resolution (monitor_mode,
|
|
|
|
&mode_width, &mode_height);
|
2018-07-16 16:09:40 +00:00
|
|
|
|
2017-06-14 04:04:09 +00:00
|
|
|
refresh_rate = meta_monitor_mode_get_refresh_rate (monitor_mode);
|
|
|
|
|
2017-01-20 08:55:43 +00:00
|
|
|
preferred_scale =
|
|
|
|
meta_monitor_manager_calculate_monitor_mode_scale (manager,
|
2017-06-10 14:10:57 +00:00
|
|
|
manager->layout_mode,
|
2017-01-20 08:55:43 +00:00
|
|
|
monitor,
|
|
|
|
monitor_mode);
|
2017-06-05 07:59:47 +00:00
|
|
|
|
|
|
|
g_variant_builder_init (&supported_scales_builder,
|
|
|
|
G_VARIANT_TYPE ("ad"));
|
|
|
|
supported_scales =
|
|
|
|
meta_monitor_manager_calculate_supported_scales (manager,
|
|
|
|
manager->layout_mode,
|
|
|
|
monitor,
|
|
|
|
monitor_mode,
|
|
|
|
&n_supported_scales);
|
|
|
|
for (i = 0; i < n_supported_scales; i++)
|
|
|
|
g_variant_builder_add (&supported_scales_builder, "d",
|
|
|
|
(double) supported_scales[i]);
|
|
|
|
g_free (supported_scales);
|
|
|
|
|
2017-06-14 06:41:13 +00:00
|
|
|
mode_flags = meta_monitor_mode_get_flags (monitor_mode);
|
|
|
|
|
2017-06-14 04:17:31 +00:00
|
|
|
g_variant_builder_init (&mode_properties_builder,
|
|
|
|
G_VARIANT_TYPE ("a{sv}"));
|
2017-01-20 08:55:43 +00:00
|
|
|
if (monitor_mode == current_mode)
|
2017-06-14 04:17:31 +00:00
|
|
|
g_variant_builder_add (&mode_properties_builder, "{sv}",
|
|
|
|
"is-current",
|
|
|
|
g_variant_new_boolean (TRUE));
|
2017-01-20 08:55:43 +00:00
|
|
|
if (monitor_mode == preferred_mode)
|
2017-06-14 04:17:31 +00:00
|
|
|
g_variant_builder_add (&mode_properties_builder, "{sv}",
|
|
|
|
"is-preferred",
|
|
|
|
g_variant_new_boolean (TRUE));
|
2017-06-14 06:41:13 +00:00
|
|
|
if (mode_flags & META_CRTC_MODE_FLAG_INTERLACE)
|
|
|
|
g_variant_builder_add (&mode_properties_builder, "{sv}",
|
|
|
|
"is-interlaced",
|
|
|
|
g_variant_new_boolean (TRUE));
|
2017-01-20 08:55:43 +00:00
|
|
|
|
|
|
|
g_variant_builder_add (&modes_builder, MODE_FORMAT,
|
2017-06-14 04:04:09 +00:00
|
|
|
mode_id,
|
|
|
|
mode_width,
|
|
|
|
mode_height,
|
|
|
|
refresh_rate,
|
2017-01-26 07:33:12 +00:00
|
|
|
(double) preferred_scale,
|
2017-06-05 07:59:47 +00:00
|
|
|
&supported_scales_builder,
|
2017-06-14 04:17:31 +00:00
|
|
|
&mode_properties_builder);
|
2017-01-20 08:55:43 +00:00
|
|
|
}
|
|
|
|
|
2017-02-07 08:03:43 +00:00
|
|
|
g_variant_builder_init (&monitor_properties_builder,
|
|
|
|
G_VARIANT_TYPE ("a{sv}"));
|
2017-01-23 09:59:43 +00:00
|
|
|
if (meta_monitor_supports_underscanning (monitor))
|
|
|
|
{
|
|
|
|
gboolean is_underscanning = meta_monitor_is_underscanning (monitor);
|
|
|
|
|
2017-02-07 08:03:43 +00:00
|
|
|
g_variant_builder_add (&monitor_properties_builder, "{sv}",
|
2017-04-06 05:09:28 +00:00
|
|
|
"is-underscanning",
|
2017-01-23 09:59:43 +00:00
|
|
|
g_variant_new_boolean (is_underscanning));
|
|
|
|
}
|
|
|
|
|
2017-03-23 15:33:34 +00:00
|
|
|
is_builtin = meta_monitor_is_laptop_panel (monitor);
|
|
|
|
g_variant_builder_add (&monitor_properties_builder, "{sv}",
|
2017-04-06 05:09:28 +00:00
|
|
|
"is-builtin",
|
2017-03-23 15:33:34 +00:00
|
|
|
g_variant_new_boolean (is_builtin));
|
|
|
|
|
2019-06-26 09:40:00 +00:00
|
|
|
display_name = meta_monitor_get_display_name (monitor);
|
2017-04-06 05:13:20 +00:00
|
|
|
g_variant_builder_add (&monitor_properties_builder, "{sv}",
|
|
|
|
"display-name",
|
2019-06-26 09:40:00 +00:00
|
|
|
g_variant_new_string (display_name));
|
2017-04-06 05:13:20 +00:00
|
|
|
|
2021-03-22 00:20:00 +00:00
|
|
|
privacy_screen_state = meta_monitor_get_privacy_screen_state (monitor);
|
|
|
|
if (privacy_screen_state != META_PRIVACY_SCREEN_UNAVAILABLE)
|
|
|
|
{
|
|
|
|
GVariant *state;
|
|
|
|
|
|
|
|
state = g_variant_new ("(bb)",
|
|
|
|
!!(privacy_screen_state & META_PRIVACY_SCREEN_ENABLED),
|
|
|
|
!!(privacy_screen_state & META_PRIVACY_SCREEN_LOCKED));
|
|
|
|
|
|
|
|
g_variant_builder_add (&monitor_properties_builder, "{sv}",
|
|
|
|
"privacy-screen-state", state);
|
|
|
|
}
|
|
|
|
|
2017-01-20 08:55:43 +00:00
|
|
|
g_variant_builder_add (&monitors_builder, MONITOR_FORMAT,
|
|
|
|
monitor_spec->connector,
|
|
|
|
monitor_spec->vendor,
|
|
|
|
monitor_spec->product,
|
|
|
|
monitor_spec->serial,
|
|
|
|
&modes_builder,
|
2017-02-07 08:03:43 +00:00
|
|
|
&monitor_properties_builder);
|
2017-01-20 08:55:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
|
|
|
GVariantBuilder logical_monitor_monitors_builder;
|
|
|
|
GList *k;
|
|
|
|
|
|
|
|
g_variant_builder_init (&logical_monitor_monitors_builder,
|
|
|
|
G_VARIANT_TYPE (LOGICAL_MONITOR_MONITORS_FORMAT));
|
|
|
|
|
|
|
|
for (k = logical_monitor->monitors; k; k = k->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = k->data;
|
|
|
|
MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor);
|
|
|
|
|
|
|
|
g_variant_builder_add (&logical_monitor_monitors_builder,
|
|
|
|
MONITOR_SPEC_FORMAT,
|
|
|
|
monitor_spec->connector,
|
|
|
|
monitor_spec->vendor,
|
|
|
|
monitor_spec->product,
|
|
|
|
monitor_spec->serial);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_variant_builder_add (&logical_monitors_builder,
|
|
|
|
LOGICAL_MONITOR_FORMAT,
|
|
|
|
logical_monitor->rect.x,
|
|
|
|
logical_monitor->rect.y,
|
2017-01-26 07:33:12 +00:00
|
|
|
(double) logical_monitor->scale,
|
2017-03-21 06:29:32 +00:00
|
|
|
logical_monitor->transform,
|
2017-01-20 08:55:43 +00:00
|
|
|
logical_monitor->is_primary,
|
2017-02-14 10:31:05 +00:00
|
|
|
&logical_monitor_monitors_builder,
|
2017-01-20 08:55:43 +00:00
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2017-02-07 08:03:43 +00:00
|
|
|
g_variant_builder_init (&properties_builder, G_VARIANT_TYPE ("a{sv}"));
|
|
|
|
capabilities = meta_monitor_manager_get_capabilities (manager);
|
|
|
|
|
2017-04-06 06:00:06 +00:00
|
|
|
g_variant_builder_add (&properties_builder, "{sv}",
|
|
|
|
"layout-mode",
|
|
|
|
g_variant_new_uint32 (manager->layout_mode));
|
2017-02-24 10:10:52 +00:00
|
|
|
if (capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
|
|
|
|
{
|
|
|
|
g_variant_builder_add (&properties_builder, "{sv}",
|
2017-04-06 06:00:06 +00:00
|
|
|
"supports-changing-layout-mode",
|
|
|
|
g_variant_new_boolean (TRUE));
|
2017-02-24 10:10:52 +00:00
|
|
|
}
|
|
|
|
|
2017-04-21 10:01:15 +00:00
|
|
|
if (capabilities & META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED)
|
|
|
|
{
|
|
|
|
g_variant_builder_add (&properties_builder, "{sv}",
|
|
|
|
"global-scale-required",
|
|
|
|
g_variant_new_boolean (TRUE));
|
|
|
|
}
|
|
|
|
|
2017-10-11 09:59:04 +00:00
|
|
|
ui_scaling_factor = meta_settings_get_ui_scaling_factor (settings);
|
|
|
|
g_variant_builder_add (&properties_builder, "{sv}",
|
|
|
|
"legacy-ui-scaling-factor",
|
|
|
|
g_variant_new_int32 (ui_scaling_factor));
|
|
|
|
|
2017-02-15 08:06:46 +00:00
|
|
|
if (meta_monitor_manager_get_max_screen_size (manager,
|
|
|
|
&max_screen_width,
|
|
|
|
&max_screen_height))
|
|
|
|
{
|
|
|
|
GVariantBuilder max_screen_size_builder;
|
|
|
|
|
|
|
|
g_variant_builder_init (&max_screen_size_builder,
|
|
|
|
G_VARIANT_TYPE ("(ii)"));
|
|
|
|
g_variant_builder_add (&max_screen_size_builder, "i",
|
|
|
|
max_screen_width);
|
|
|
|
g_variant_builder_add (&max_screen_size_builder, "i",
|
|
|
|
max_screen_height);
|
|
|
|
|
|
|
|
g_variant_builder_add (&properties_builder, "{sv}",
|
2017-04-06 05:09:28 +00:00
|
|
|
"max-screen-size",
|
2017-02-15 08:06:46 +00:00
|
|
|
g_variant_builder_end (&max_screen_size_builder));
|
|
|
|
}
|
|
|
|
|
2017-01-20 08:55:43 +00:00
|
|
|
meta_dbus_display_config_complete_get_current_state (
|
|
|
|
skeleton,
|
|
|
|
invocation,
|
|
|
|
manager->serial,
|
|
|
|
g_variant_builder_end (&monitors_builder),
|
|
|
|
g_variant_builder_end (&logical_monitors_builder),
|
2017-02-07 08:03:43 +00:00
|
|
|
g_variant_builder_end (&properties_builder));
|
2017-01-20 08:55:43 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef MODE_FORMAT
|
|
|
|
#undef MODES_FORMAT
|
|
|
|
#undef MONITOR_SPEC_FORMAT
|
|
|
|
#undef MONITOR_FORMAT
|
|
|
|
#undef MONITORS_FORMAT
|
|
|
|
#undef LOGICAL_MONITOR_MONITORS_FORMAT
|
|
|
|
#undef LOGICAL_MONITOR_FORMAT
|
|
|
|
#undef LOGICAL_MONITORS_FORMAT
|
|
|
|
|
2017-05-25 09:20:59 +00:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_is_scale_supported (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
2017-06-05 07:59:47 +00:00
|
|
|
MetaMonitor *monitor,
|
|
|
|
MetaMonitorMode *monitor_mode,
|
2017-05-25 09:20:59 +00:00
|
|
|
float scale)
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
2017-06-05 07:59:47 +00:00
|
|
|
g_autofree float *supported_scales = NULL;
|
2017-02-14 11:54:04 +00:00
|
|
|
int n_supported_scales;
|
|
|
|
int i;
|
|
|
|
|
2017-06-05 07:59:47 +00:00
|
|
|
supported_scales =
|
|
|
|
meta_monitor_manager_calculate_supported_scales (manager,
|
|
|
|
layout_mode,
|
|
|
|
monitor,
|
|
|
|
monitor_mode,
|
|
|
|
&n_supported_scales);
|
2017-02-14 11:54:04 +00:00
|
|
|
for (i = 0; i < n_supported_scales; i++)
|
|
|
|
{
|
|
|
|
if (supported_scales[i] == scale)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-11-30 04:04:17 +00:00
|
|
|
static gboolean
|
|
|
|
is_global_scale_matching_in_config (MetaMonitorsConfig *config,
|
|
|
|
float scale)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
|
|
|
|
if (!G_APPROX_VALUE (logical_monitor_config->scale, scale, FLT_EPSILON))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_is_scale_supported_for_config (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config,
|
|
|
|
MetaMonitor *monitor,
|
|
|
|
MetaMonitorMode *monitor_mode,
|
|
|
|
float scale)
|
|
|
|
{
|
|
|
|
if (meta_monitor_manager_is_scale_supported (manager, config->layout_mode,
|
|
|
|
monitor, monitor_mode, scale))
|
|
|
|
{
|
|
|
|
if (meta_monitor_manager_get_capabilities (manager) &
|
|
|
|
META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED)
|
|
|
|
return is_global_scale_matching_in_config (config, scale);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_is_config_applicable (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
float scale = logical_monitor_config->scale;
|
|
|
|
GList *k;
|
|
|
|
|
|
|
|
for (k = logical_monitor_config->monitor_configs; k; k = k->next)
|
|
|
|
{
|
|
|
|
MetaMonitorConfig *monitor_config = k->data;
|
|
|
|
MetaMonitorSpec *monitor_spec = monitor_config->monitor_spec;
|
|
|
|
MetaMonitorModeSpec *mode_spec = monitor_config->mode_spec;
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
MetaMonitorMode *monitor_mode;
|
|
|
|
|
|
|
|
monitor = meta_monitor_manager_get_monitor_from_spec (manager,
|
|
|
|
monitor_spec);
|
|
|
|
if (!monitor)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Specified monitor not found");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_mode = meta_monitor_get_mode_from_spec (monitor, mode_spec);
|
|
|
|
if (!monitor_mode)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Specified monitor mode not available");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2017-06-05 07:59:47 +00:00
|
|
|
|
2018-11-30 04:04:17 +00:00
|
|
|
if (!meta_monitor_manager_is_scale_supported_for_config (manager,
|
|
|
|
config,
|
|
|
|
monitor,
|
|
|
|
monitor_mode,
|
|
|
|
scale))
|
2017-06-05 07:59:47 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Scale not supported by backend");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-11-14 17:10:55 +00:00
|
|
|
if (meta_monitor_is_laptop_panel (monitor) &&
|
2018-04-16 18:07:45 +00:00
|
|
|
meta_backend_is_lid_closed (manager->backend))
|
2017-11-14 17:10:55 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Refusing to activate a closed laptop panel");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2017-02-14 11:54:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-08-11 07:21:36 +00:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
|
|
|
{
|
2017-11-03 08:03:23 +00:00
|
|
|
MetaMonitorsConfigKey *current_state_key;
|
|
|
|
gboolean is_config_complete;
|
2017-08-11 07:21:36 +00:00
|
|
|
|
2017-11-03 08:03:23 +00:00
|
|
|
current_state_key =
|
|
|
|
meta_create_monitors_config_key_for_current_state (manager);
|
|
|
|
if (!current_state_key)
|
|
|
|
return FALSE;
|
2017-08-11 07:21:36 +00:00
|
|
|
|
2017-11-03 08:03:23 +00:00
|
|
|
is_config_complete = meta_monitors_config_key_equal (current_state_key,
|
|
|
|
config->key);
|
|
|
|
meta_monitors_config_key_free (current_state_key);
|
2017-08-11 07:21:36 +00:00
|
|
|
|
2017-11-03 08:03:23 +00:00
|
|
|
if (!is_config_complete)
|
2017-08-11 07:21:36 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return meta_monitor_manager_is_config_applicable (manager, config, NULL);
|
|
|
|
}
|
|
|
|
|
2017-06-14 04:04:09 +00:00
|
|
|
static MetaMonitor *
|
|
|
|
find_monitor_from_connector (MetaMonitorManager *manager,
|
|
|
|
char *connector)
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
|
|
|
GList *monitors;
|
|
|
|
GList *l;
|
|
|
|
|
2017-06-14 04:04:09 +00:00
|
|
|
if (!connector)
|
|
|
|
return NULL;
|
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
monitors = meta_monitor_manager_get_monitors (manager);
|
|
|
|
for (l = monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor);
|
|
|
|
|
|
|
|
if (g_str_equal (connector, monitor_spec->connector))
|
2017-06-14 04:04:09 +00:00
|
|
|
return monitor;
|
2017-02-14 11:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-06-14 04:04:09 +00:00
|
|
|
#define MONITOR_CONFIG_FORMAT "(ssa{sv})"
|
2017-02-14 11:54:04 +00:00
|
|
|
#define MONITOR_CONFIGS_FORMAT "a" MONITOR_CONFIG_FORMAT
|
|
|
|
|
2017-03-21 06:29:32 +00:00
|
|
|
#define LOGICAL_MONITOR_CONFIG_FORMAT "(iidub" MONITOR_CONFIGS_FORMAT ")"
|
2017-02-14 11:54:04 +00:00
|
|
|
|
|
|
|
static MetaMonitorConfig *
|
|
|
|
create_monitor_config_from_variant (MetaMonitorManager *manager,
|
|
|
|
GVariant *monitor_config_variant,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
|
|
|
|
MetaMonitorConfig *monitor_config = NULL;
|
2017-06-14 04:04:09 +00:00
|
|
|
g_autofree char *connector = NULL;
|
|
|
|
g_autofree char *mode_id = NULL;
|
|
|
|
MetaMonitorMode *monitor_mode;
|
|
|
|
MetaMonitor *monitor;
|
2017-02-14 11:54:04 +00:00
|
|
|
MetaMonitorSpec *monitor_spec;
|
|
|
|
MetaMonitorModeSpec *monitor_mode_spec;
|
2017-06-14 04:04:09 +00:00
|
|
|
g_autoptr (GVariant) properties_variant = NULL;
|
2017-02-14 11:54:04 +00:00
|
|
|
gboolean enable_underscanning = FALSE;
|
2019-07-04 19:52:30 +00:00
|
|
|
gboolean set_underscanning = FALSE;
|
2017-02-14 11:54:04 +00:00
|
|
|
|
2017-06-14 04:04:09 +00:00
|
|
|
g_variant_get (monitor_config_variant, "(ss@a{sv})",
|
2017-02-14 11:54:04 +00:00
|
|
|
&connector,
|
2017-06-14 04:04:09 +00:00
|
|
|
&mode_id,
|
2017-02-14 11:54:04 +00:00
|
|
|
&properties_variant);
|
|
|
|
|
2017-06-14 04:04:09 +00:00
|
|
|
monitor = find_monitor_from_connector (manager, connector);
|
|
|
|
if (!monitor)
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Invalid connector '%s' specified", connector);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-06-14 04:04:09 +00:00
|
|
|
monitor_mode = meta_monitor_get_mode_from_id (monitor, mode_id);
|
|
|
|
if (!monitor_mode)
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
2017-06-14 04:04:09 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Invalid mode '%s' specified", mode_id);
|
2017-02-14 11:54:04 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-07-04 19:52:30 +00:00
|
|
|
set_underscanning =
|
|
|
|
g_variant_lookup (properties_variant, "underscanning", "b",
|
|
|
|
&enable_underscanning);
|
|
|
|
if (set_underscanning)
|
|
|
|
{
|
|
|
|
if (enable_underscanning && !meta_monitor_supports_underscanning (monitor))
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Underscanning requested but unsupported");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2017-02-14 11:54:04 +00:00
|
|
|
|
2017-06-14 04:04:09 +00:00
|
|
|
monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor));
|
|
|
|
|
|
|
|
monitor_mode_spec = g_new0 (MetaMonitorModeSpec, 1);
|
|
|
|
*monitor_mode_spec = *meta_monitor_mode_get_spec (monitor_mode);
|
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
monitor_config = g_new0 (MetaMonitorConfig, 1);
|
|
|
|
*monitor_config = (MetaMonitorConfig) {
|
|
|
|
.monitor_spec = monitor_spec,
|
|
|
|
.mode_spec = monitor_mode_spec,
|
|
|
|
.enable_underscanning = enable_underscanning
|
|
|
|
};
|
|
|
|
|
|
|
|
return monitor_config;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2017-06-07 09:39:58 +00:00
|
|
|
find_monitor_mode_scale (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
|
|
MetaMonitorConfig *monitor_config,
|
|
|
|
float scale,
|
|
|
|
float *out_scale,
|
|
|
|
GError **error)
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
2017-06-07 09:39:58 +00:00
|
|
|
MetaMonitorSpec *monitor_spec;
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
MetaMonitorModeSpec *monitor_mode_spec;
|
|
|
|
MetaMonitorMode *monitor_mode;
|
|
|
|
g_autofree float *supported_scales = NULL;
|
|
|
|
int n_supported_scales;
|
|
|
|
int i;
|
2017-02-14 11:54:04 +00:00
|
|
|
|
2017-06-07 09:39:58 +00:00
|
|
|
monitor_spec = monitor_config->monitor_spec;
|
|
|
|
monitor = meta_monitor_manager_get_monitor_from_spec (manager,
|
|
|
|
monitor_spec);
|
|
|
|
if (!monitor)
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
2017-06-07 09:39:58 +00:00
|
|
|
"Monitor not found");
|
2017-02-14 11:54:04 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-06-07 09:39:58 +00:00
|
|
|
monitor_mode_spec = monitor_config->mode_spec;
|
|
|
|
monitor_mode = meta_monitor_get_mode_from_spec (monitor,
|
|
|
|
monitor_mode_spec);
|
|
|
|
if (!monitor_mode)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Monitor mode not found");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
supported_scales =
|
|
|
|
meta_monitor_manager_calculate_supported_scales (manager, layout_mode,
|
|
|
|
monitor, monitor_mode,
|
|
|
|
&n_supported_scales);
|
|
|
|
|
|
|
|
for (i = 0; i < n_supported_scales; i++)
|
|
|
|
{
|
|
|
|
float supported_scale = supported_scales[i];
|
|
|
|
|
|
|
|
if (fabsf (supported_scale - scale) < FLT_EPSILON)
|
|
|
|
{
|
|
|
|
*out_scale = supported_scale;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Scale %g not valid for resolution %dx%d",
|
|
|
|
scale,
|
|
|
|
monitor_mode_spec->width,
|
|
|
|
monitor_mode_spec->height);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
derive_logical_monitor_size (MetaMonitorConfig *monitor_config,
|
|
|
|
int *out_width,
|
|
|
|
int *out_height,
|
|
|
|
float scale,
|
|
|
|
MetaMonitorTransform transform,
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
int width, height;
|
2017-02-14 11:54:04 +00:00
|
|
|
|
2017-03-21 06:29:32 +00:00
|
|
|
if (meta_monitor_transform_is_rotated (transform))
|
|
|
|
{
|
|
|
|
width = monitor_config->mode_spec->height;
|
|
|
|
height = monitor_config->mode_spec->width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
width = monitor_config->mode_spec->width;
|
|
|
|
height = monitor_config->mode_spec->height;
|
|
|
|
}
|
|
|
|
|
2017-02-24 10:10:52 +00:00
|
|
|
switch (layout_mode)
|
|
|
|
{
|
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
|
2017-06-09 07:51:14 +00:00
|
|
|
width = roundf (width / scale);
|
|
|
|
height = roundf (height / scale);
|
2017-03-21 06:29:32 +00:00
|
|
|
break;
|
2017-02-24 10:10:52 +00:00
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
|
2017-03-21 06:29:32 +00:00
|
|
|
break;
|
2017-02-24 10:10:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-21 06:29:32 +00:00
|
|
|
*out_width = width;
|
|
|
|
*out_height = height;
|
|
|
|
|
|
|
|
return TRUE;
|
2017-02-14 11:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static MetaLogicalMonitorConfig *
|
2017-02-24 10:10:52 +00:00
|
|
|
create_logical_monitor_config_from_variant (MetaMonitorManager *manager,
|
|
|
|
GVariant *logical_monitor_config_variant,
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
|
|
GError **error)
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config;
|
|
|
|
int x, y, width, height;
|
2017-06-07 09:39:58 +00:00
|
|
|
double scale_d;
|
|
|
|
float scale;
|
2017-03-21 06:29:32 +00:00
|
|
|
MetaMonitorTransform transform;
|
2017-02-14 11:54:04 +00:00
|
|
|
gboolean is_primary;
|
|
|
|
GVariantIter *monitor_configs_iter;
|
|
|
|
GList *monitor_configs = NULL;
|
2017-06-07 09:39:58 +00:00
|
|
|
MetaMonitorConfig *monitor_config;
|
2017-02-14 11:54:04 +00:00
|
|
|
|
|
|
|
g_variant_get (logical_monitor_config_variant, LOGICAL_MONITOR_CONFIG_FORMAT,
|
|
|
|
&x,
|
|
|
|
&y,
|
2017-06-07 09:39:58 +00:00
|
|
|
&scale_d,
|
2017-03-21 06:29:32 +00:00
|
|
|
&transform,
|
2017-02-14 11:54:04 +00:00
|
|
|
&is_primary,
|
|
|
|
&monitor_configs_iter);
|
2017-06-07 09:39:58 +00:00
|
|
|
scale = (float) scale_d;
|
2017-02-14 11:54:04 +00:00
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
GVariant *monitor_config_variant =
|
|
|
|
g_variant_iter_next_value (monitor_configs_iter);
|
|
|
|
MetaMonitorConfig *monitor_config;
|
|
|
|
|
|
|
|
if (!monitor_config_variant)
|
|
|
|
break;
|
|
|
|
|
|
|
|
monitor_config =
|
|
|
|
create_monitor_config_from_variant (manager,
|
|
|
|
monitor_config_variant, error);
|
2017-10-27 10:27:00 +00:00
|
|
|
g_variant_unref (monitor_config_variant);
|
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
if (!monitor_config)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (!meta_verify_monitor_config (monitor_config, error))
|
|
|
|
{
|
|
|
|
meta_monitor_config_free (monitor_config);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_configs = g_list_append (monitor_configs, monitor_config);
|
|
|
|
}
|
|
|
|
g_variant_iter_free (monitor_configs_iter);
|
|
|
|
|
2017-06-07 09:39:58 +00:00
|
|
|
if (!monitor_configs)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Empty logical monitor");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_config = monitor_configs->data;
|
|
|
|
if (!find_monitor_mode_scale (manager,
|
|
|
|
layout_mode,
|
|
|
|
monitor_config,
|
|
|
|
scale,
|
|
|
|
&scale,
|
|
|
|
error))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (!derive_logical_monitor_size (monitor_config, &width, &height,
|
2017-03-21 06:29:32 +00:00
|
|
|
scale, transform, layout_mode, error))
|
2017-02-14 11:54:04 +00:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
|
|
|
|
*logical_monitor_config = (MetaLogicalMonitorConfig) {
|
|
|
|
.layout = {
|
|
|
|
.x = x,
|
|
|
|
.y = y,
|
|
|
|
.width = width,
|
|
|
|
.height = height
|
|
|
|
},
|
2017-03-21 06:29:32 +00:00
|
|
|
.transform = transform,
|
2017-05-25 08:12:51 +00:00
|
|
|
.scale = scale,
|
2017-02-14 11:54:04 +00:00
|
|
|
.is_primary = is_primary,
|
|
|
|
.monitor_configs = monitor_configs
|
|
|
|
};
|
|
|
|
|
2017-02-24 10:10:52 +00:00
|
|
|
if (!meta_verify_logical_monitor_config (logical_monitor_config,
|
|
|
|
layout_mode,
|
2017-05-25 09:20:59 +00:00
|
|
|
manager,
|
2017-02-24 10:10:52 +00:00
|
|
|
error))
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
|
|
|
meta_logical_monitor_config_free (logical_monitor_config);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return logical_monitor_config;
|
|
|
|
|
|
|
|
err:
|
|
|
|
g_list_free_full (monitor_configs, (GDestroyNotify) meta_monitor_config_free);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-02-24 10:10:52 +00:00
|
|
|
static gboolean
|
|
|
|
is_valid_layout_mode (MetaLogicalMonitorLayoutMode layout_mode)
|
|
|
|
{
|
|
|
|
switch (layout_mode)
|
|
|
|
{
|
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
|
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
|
|
|
guint method,
|
|
|
|
GVariant *logical_monitor_configs_variant,
|
2019-01-23 01:49:26 +00:00
|
|
|
GVariant *properties_variant,
|
|
|
|
MetaMonitorManager *manager)
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
2021-09-30 19:06:38 +00:00
|
|
|
MetaMonitorConfigStore *config_store;
|
|
|
|
const MetaMonitorConfigPolicy *policy;
|
2017-02-24 10:10:52 +00:00
|
|
|
MetaMonitorManagerCapability capabilities;
|
|
|
|
GVariant *layout_mode_variant = NULL;
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode;
|
2017-02-14 11:54:04 +00:00
|
|
|
GVariantIter logical_monitor_configs_iter;
|
|
|
|
MetaMonitorsConfig *config;
|
|
|
|
GList *logical_monitor_configs = NULL;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (serial != manager->serial)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_ACCESS_DENIED,
|
|
|
|
"The requested configuration is based on stale information");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2021-09-30 19:06:38 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-02-24 10:10:52 +00:00
|
|
|
capabilities = meta_monitor_manager_get_capabilities (manager);
|
|
|
|
|
|
|
|
if (properties_variant)
|
|
|
|
layout_mode_variant = g_variant_lookup_value (properties_variant,
|
|
|
|
"layout-mode",
|
|
|
|
G_VARIANT_TYPE ("u"));
|
|
|
|
|
|
|
|
if (layout_mode_variant &&
|
|
|
|
capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
|
|
|
|
{
|
|
|
|
g_variant_get (layout_mode_variant, "u", &layout_mode);
|
|
|
|
}
|
|
|
|
else if (!layout_mode_variant)
|
|
|
|
{
|
|
|
|
layout_mode =
|
|
|
|
meta_monitor_manager_get_default_layout_mode (manager);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Can't set layout mode");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_valid_layout_mode (layout_mode))
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_ACCESS_DENIED,
|
|
|
|
"Invalid layout mode specified");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
g_variant_iter_init (&logical_monitor_configs_iter,
|
|
|
|
logical_monitor_configs_variant);
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
GVariant *logical_monitor_config_variant =
|
|
|
|
g_variant_iter_next_value (&logical_monitor_configs_iter);
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config;
|
|
|
|
|
|
|
|
if (!logical_monitor_config_variant)
|
|
|
|
break;
|
|
|
|
|
|
|
|
logical_monitor_config =
|
|
|
|
create_logical_monitor_config_from_variant (manager,
|
|
|
|
logical_monitor_config_variant,
|
2017-02-24 10:10:52 +00:00
|
|
|
layout_mode,
|
2017-02-14 11:54:04 +00:00
|
|
|
&error);
|
2017-10-27 10:27:00 +00:00
|
|
|
g_variant_unref (logical_monitor_config_variant);
|
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
if (!logical_monitor_config)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
2017-04-12 14:26:21 +00:00
|
|
|
"%s", error->message);
|
2017-02-14 11:54:04 +00:00
|
|
|
g_error_free (error);
|
|
|
|
g_list_free_full (logical_monitor_configs,
|
|
|
|
(GDestroyNotify) meta_logical_monitor_config_free);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
logical_monitor_configs = g_list_append (logical_monitor_configs,
|
|
|
|
logical_monitor_config);
|
|
|
|
}
|
|
|
|
|
2017-09-28 15:34:33 +00:00
|
|
|
config = meta_monitors_config_new (manager,
|
|
|
|
logical_monitor_configs,
|
|
|
|
layout_mode,
|
2017-08-10 07:12:41 +00:00
|
|
|
META_MONITORS_CONFIG_FLAG_NONE);
|
2017-04-21 10:01:15 +00:00
|
|
|
if (!meta_verify_monitors_config (config, manager, &error))
|
2017-02-14 11:54:04 +00:00
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
2017-04-12 14:26:21 +00:00
|
|
|
"%s", error->message);
|
2017-02-14 11:54:04 +00:00
|
|
|
g_error_free (error);
|
|
|
|
g_object_unref (config);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!meta_monitor_manager_is_config_applicable (manager, config, &error))
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
2017-04-12 14:26:21 +00:00
|
|
|
"%s", error->message);
|
2017-02-14 11:54:04 +00:00
|
|
|
g_error_free (error);
|
|
|
|
g_object_unref (config);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2023-03-06 23:06:30 +00:00
|
|
|
if (method != META_MONITORS_CONFIG_METHOD_VERIFY)
|
|
|
|
{
|
|
|
|
g_clear_handle_id (&manager->restore_config_id, g_source_remove);
|
|
|
|
g_clear_handle_id (&manager->persistent_timeout_id, g_source_remove);
|
|
|
|
}
|
2017-03-23 09:20:07 +00:00
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
config,
|
|
|
|
method,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
2017-04-12 14:26:21 +00:00
|
|
|
"%s", error->message);
|
2017-02-14 11:54:04 +00:00
|
|
|
g_error_free (error);
|
|
|
|
g_object_unref (config);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-03-23 09:20:07 +00:00
|
|
|
if (method == META_MONITORS_CONFIG_METHOD_PERSISTENT)
|
2017-03-24 07:36:12 +00:00
|
|
|
request_persistent_confirmation (manager);
|
2017-03-23 09:20:07 +00:00
|
|
|
|
2017-02-14 11:54:04 +00:00
|
|
|
meta_dbus_display_config_complete_apply_monitors_config (skeleton, invocation);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef MONITOR_MODE_SPEC_FORMAT
|
|
|
|
#undef MONITOR_CONFIG_FORMAT
|
|
|
|
#undef MONITOR_CONFIGS_FORMAT
|
|
|
|
#undef LOGICAL_MONITOR_CONFIG_FORMAT
|
|
|
|
|
2013-07-29 08:12:24 +00:00
|
|
|
void
|
|
|
|
meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager,
|
|
|
|
gboolean ok)
|
|
|
|
{
|
|
|
|
if (!manager->persistent_timeout_id)
|
2023-03-06 23:06:30 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
g_clear_handle_id (&manager->restore_config_id, g_source_remove);
|
|
|
|
g_clear_handle_id (&manager->persistent_timeout_id, g_source_remove);
|
|
|
|
|
|
|
|
if (ok)
|
2013-07-29 08:12:24 +00:00
|
|
|
{
|
2023-03-06 23:06:30 +00:00
|
|
|
meta_monitor_config_manager_save_current (manager->config_manager);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
manager->restore_config_id =
|
|
|
|
g_idle_add_once ((GSourceOnceFunc) restore_previous_config, manager);
|
2013-07-29 08:12:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-25 13:06:09 +00:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
2014-07-01 17:00:36 +00:00
|
|
|
guint output_index,
|
2019-01-23 01:49:26 +00:00
|
|
|
gint value,
|
|
|
|
MetaMonitorManager *manager)
|
2013-07-25 13:06:09 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
GList *combined_outputs;
|
2013-07-25 13:06:09 +00:00
|
|
|
MetaOutput *output;
|
2020-02-26 08:45:07 +00:00
|
|
|
const MetaOutputInfo *output_info;
|
2020-02-25 17:37:21 +00:00
|
|
|
int new_backlight;
|
2013-07-25 13:06:09 +00:00
|
|
|
|
|
|
|
if (serial != manager->serial)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_ACCESS_DENIED,
|
|
|
|
"The requested configuration is based on stale information");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
combined_outputs = combine_gpu_lists (manager, meta_gpu_get_outputs);
|
|
|
|
|
|
|
|
if (output_index >= g_list_length (combined_outputs))
|
2013-07-25 13:06:09 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
g_list_free (combined_outputs);
|
2013-07-25 13:06:09 +00:00
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid output id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2017-07-10 10:19:32 +00:00
|
|
|
output = g_list_nth_data (combined_outputs, output_index);
|
|
|
|
g_list_free (combined_outputs);
|
2013-07-25 13:06:09 +00:00
|
|
|
|
|
|
|
if (value < 0 || value > 100)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid backlight value");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-02-26 08:45:07 +00:00
|
|
|
output_info = meta_output_get_info (output);
|
2020-02-25 17:37:21 +00:00
|
|
|
if (meta_output_get_backlight (output) == -1 ||
|
2020-02-26 08:45:07 +00:00
|
|
|
(output_info->backlight_min == 0 &&
|
|
|
|
output_info->backlight_max == 0))
|
2013-07-25 13:06:09 +00:00
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Output does not support changing backlight");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-29 11:00:15 +00:00
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager)->change_backlight (manager, output, value);
|
2013-07-25 13:06:09 +00:00
|
|
|
|
2020-02-25 17:37:21 +00:00
|
|
|
new_backlight = meta_output_get_backlight (output);
|
|
|
|
meta_dbus_display_config_complete_change_backlight (skeleton,
|
|
|
|
invocation,
|
|
|
|
new_backlight);
|
2013-07-25 13:06:09 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-26 13:57:34 +00:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_get_crtc_gamma (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
2019-01-23 01:49:26 +00:00
|
|
|
guint crtc_id,
|
|
|
|
MetaMonitorManager *manager)
|
2013-07-26 13:57:34 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
GList *combined_crtcs;
|
2016-12-08 04:15:28 +00:00
|
|
|
MetaCrtc *crtc;
|
2021-12-03 16:34:34 +00:00
|
|
|
g_autoptr (MetaGammaLut) gamma_lut = NULL;
|
2013-07-26 13:57:34 +00:00
|
|
|
GBytes *red_bytes, *green_bytes, *blue_bytes;
|
|
|
|
GVariant *red_v, *green_v, *blue_v;
|
|
|
|
|
|
|
|
if (serial != manager->serial)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_ACCESS_DENIED,
|
|
|
|
"The requested configuration is based on stale information");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
combined_crtcs = combine_gpu_lists (manager, meta_gpu_get_crtcs);
|
|
|
|
if (crtc_id >= g_list_length (combined_crtcs))
|
2013-07-26 13:57:34 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
g_list_free (combined_crtcs);
|
2013-07-26 13:57:34 +00:00
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid crtc id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2017-03-28 04:35:19 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
crtc = g_list_nth_data (combined_crtcs, crtc_id);
|
|
|
|
g_list_free (combined_crtcs);
|
2013-07-26 13:57:34 +00:00
|
|
|
|
2021-12-03 16:34:34 +00:00
|
|
|
gamma_lut = meta_crtc_get_gamma_lut (crtc);
|
2013-07-26 13:57:34 +00:00
|
|
|
|
2021-12-03 16:34:34 +00:00
|
|
|
red_bytes = g_bytes_new_take (g_steal_pointer (&gamma_lut->red),
|
|
|
|
gamma_lut->size * sizeof (unsigned short));
|
|
|
|
green_bytes = g_bytes_new_take (g_steal_pointer (&gamma_lut->green),
|
|
|
|
gamma_lut->size * sizeof (unsigned short));
|
|
|
|
blue_bytes = g_bytes_new_take (g_steal_pointer (&gamma_lut->blue),
|
|
|
|
gamma_lut->size * sizeof (unsigned short));
|
2013-07-26 13:57:34 +00:00
|
|
|
|
|
|
|
red_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), red_bytes, TRUE);
|
|
|
|
green_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), green_bytes, TRUE);
|
|
|
|
blue_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), blue_bytes, TRUE);
|
|
|
|
|
|
|
|
meta_dbus_display_config_complete_get_crtc_gamma (skeleton, invocation,
|
|
|
|
red_v, green_v, blue_v);
|
|
|
|
|
|
|
|
g_bytes_unref (red_bytes);
|
|
|
|
g_bytes_unref (green_bytes);
|
|
|
|
g_bytes_unref (blue_bytes);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_set_crtc_gamma (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
|
|
|
guint crtc_id,
|
|
|
|
GVariant *red_v,
|
|
|
|
GVariant *green_v,
|
2019-01-23 01:49:26 +00:00
|
|
|
GVariant *blue_v,
|
|
|
|
MetaMonitorManager *manager)
|
2013-07-26 13:57:34 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
GList *combined_crtcs;
|
2016-12-08 04:15:28 +00:00
|
|
|
MetaCrtc *crtc;
|
2021-12-03 16:34:34 +00:00
|
|
|
size_t dummy;
|
2013-07-26 13:57:34 +00:00
|
|
|
GBytes *red_bytes, *green_bytes, *blue_bytes;
|
2021-12-03 16:34:34 +00:00
|
|
|
MetaGammaLut lut;
|
2013-07-26 13:57:34 +00:00
|
|
|
|
|
|
|
if (serial != manager->serial)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_ACCESS_DENIED,
|
|
|
|
"The requested configuration is based on stale information");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
combined_crtcs = combine_gpu_lists (manager, meta_gpu_get_crtcs);
|
|
|
|
|
|
|
|
if (crtc_id >= g_list_length (combined_crtcs))
|
2013-07-26 13:57:34 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
g_list_free (combined_crtcs);
|
2013-07-26 13:57:34 +00:00
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid crtc id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2017-03-28 04:35:19 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
crtc = g_list_nth_data (combined_crtcs, crtc_id);
|
|
|
|
g_list_free (combined_crtcs);
|
2013-07-26 13:57:34 +00:00
|
|
|
|
|
|
|
red_bytes = g_variant_get_data_as_bytes (red_v);
|
|
|
|
green_bytes = g_variant_get_data_as_bytes (green_v);
|
|
|
|
blue_bytes = g_variant_get_data_as_bytes (blue_v);
|
|
|
|
|
2021-12-03 16:34:34 +00:00
|
|
|
lut.size = g_bytes_get_size (red_bytes) / sizeof (uint16_t);
|
|
|
|
lut.red = (uint16_t *) g_bytes_get_data (red_bytes, &dummy);
|
|
|
|
lut.green = (uint16_t *) g_bytes_get_data (green_bytes, &dummy);
|
|
|
|
lut.blue = (uint16_t *) g_bytes_get_data (blue_bytes, &dummy);
|
2013-07-26 13:57:34 +00:00
|
|
|
|
2021-12-03 16:34:34 +00:00
|
|
|
meta_crtc_set_gamma_lut (crtc, &lut);
|
2013-07-26 13:57:34 +00:00
|
|
|
meta_dbus_display_config_complete_set_crtc_gamma (skeleton, invocation);
|
|
|
|
|
|
|
|
g_bytes_unref (red_bytes);
|
|
|
|
g_bytes_unref (green_bytes);
|
|
|
|
g_bytes_unref (blue_bytes);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-02-05 00:41:34 +00:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_set_output_ctm (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
|
|
|
guint output_id,
|
|
|
|
GVariant *ctm_var,
|
|
|
|
MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *klass;
|
|
|
|
GList *combined_outputs;
|
|
|
|
MetaOutput *output;
|
|
|
|
MetaOutputCtm ctm;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (serial != manager->serial)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_ACCESS_DENIED,
|
|
|
|
"The requested configuration is based on stale information");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
combined_outputs = combine_gpu_lists (manager, meta_gpu_get_outputs);
|
|
|
|
|
|
|
|
if (output_id >= g_list_length (combined_outputs))
|
|
|
|
{
|
|
|
|
g_list_free (combined_outputs);
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid output id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
output = g_list_nth_data (combined_outputs, output_id);
|
|
|
|
g_list_free (combined_outputs);
|
|
|
|
|
|
|
|
if (g_variant_n_children (ctm_var) != 9)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Unexpected color transform matrix variant length");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 9; i++)
|
|
|
|
{
|
|
|
|
GVariant *tmp = g_variant_get_child_value (ctm_var, i);
|
|
|
|
ctm.matrix[i] = g_variant_get_uint64 (tmp);
|
|
|
|
g_variant_unref (tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
if (klass->set_output_ctm)
|
|
|
|
klass->set_output_ctm (output, &ctm);
|
|
|
|
meta_dbus_display_config_complete_set_output_ctm (skeleton, invocation);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-23 17:32:17 +00:00
|
|
|
static void
|
2019-01-23 01:49:26 +00:00
|
|
|
monitor_manager_setup_dbus_config_handlers (MetaMonitorManager *manager)
|
2013-07-23 17:32:17 +00:00
|
|
|
{
|
2019-01-23 01:49:26 +00:00
|
|
|
g_signal_connect_object (manager->display_config, "handle-get-resources",
|
|
|
|
G_CALLBACK (meta_monitor_manager_handle_get_resources),
|
|
|
|
manager, 0);
|
|
|
|
g_signal_connect_object (manager->display_config, "handle-change-backlight",
|
|
|
|
G_CALLBACK (meta_monitor_manager_handle_change_backlight),
|
|
|
|
manager, 0);
|
|
|
|
g_signal_connect_object (manager->display_config, "handle-get-crtc-gamma",
|
|
|
|
G_CALLBACK (meta_monitor_manager_handle_get_crtc_gamma),
|
|
|
|
manager, 0);
|
|
|
|
g_signal_connect_object (manager->display_config, "handle-set-crtc-gamma",
|
|
|
|
G_CALLBACK (meta_monitor_manager_handle_set_crtc_gamma),
|
|
|
|
manager, 0);
|
|
|
|
g_signal_connect_object (manager->display_config, "handle-get-current-state",
|
|
|
|
G_CALLBACK (meta_monitor_manager_handle_get_current_state),
|
|
|
|
manager, 0);
|
|
|
|
g_signal_connect_object (manager->display_config, "handle-apply-monitors-config",
|
|
|
|
G_CALLBACK (meta_monitor_manager_handle_apply_monitors_config),
|
|
|
|
manager, 0);
|
2020-02-05 00:41:34 +00:00
|
|
|
g_signal_connect_object (manager->display_config, "handle-set-output-ctm",
|
|
|
|
G_CALLBACK (meta_monitor_manager_handle_set_output_ctm),
|
|
|
|
manager, 0);
|
2013-07-23 17:32:17 +00:00
|
|
|
}
|
|
|
|
|
2013-07-19 12:39:28 +00:00
|
|
|
static void
|
|
|
|
on_bus_acquired (GDBusConnection *connection,
|
|
|
|
const char *name,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
|
2019-01-23 01:49:26 +00:00
|
|
|
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager->display_config),
|
2013-07-19 12:39:28 +00:00
|
|
|
connection,
|
|
|
|
"/org/gnome/Mutter/DisplayConfig",
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_name_acquired (GDBusConnection *connection,
|
|
|
|
const char *name,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_topic (META_DEBUG_DBUS, "Acquired name %s", name);
|
2013-07-19 12:39:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_name_lost (GDBusConnection *connection,
|
|
|
|
const char *name,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_topic (META_DEBUG_DBUS, "Lost or failed to acquire name %s", name);
|
2013-07-19 12:39:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
initialize_dbus_interface (MetaMonitorManager *manager)
|
|
|
|
{
|
2021-04-19 14:13:47 +00:00
|
|
|
MetaContext *context = meta_backend_get_context (manager->backend);
|
|
|
|
|
|
|
|
manager->dbus_name_id =
|
|
|
|
g_bus_own_name (G_BUS_TYPE_SESSION,
|
|
|
|
"org.gnome.Mutter.DisplayConfig",
|
|
|
|
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
|
|
|
|
(meta_context_is_replacing (context) ?
|
|
|
|
G_BUS_NAME_OWNER_FLAGS_REPLACE :
|
|
|
|
G_BUS_NAME_OWNER_FLAGS_NONE),
|
|
|
|
on_bus_acquired,
|
|
|
|
on_name_acquired,
|
|
|
|
on_name_lost,
|
|
|
|
g_object_ref (manager),
|
|
|
|
g_object_unref);
|
2013-07-19 12:39:28 +00:00
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_num_logical_monitors:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
*
|
2023-03-28 14:35:11 +00:00
|
|
|
* Returns the number of `MetaLogicalMonitor`s (can be 0 in case of a
|
2018-10-19 07:15:54 +00:00
|
|
|
* headless setup).
|
|
|
|
*
|
2023-03-28 14:35:11 +00:00
|
|
|
* Returns: the total number of `MetaLogicalMonitor`s.
|
2018-10-19 07:15:54 +00:00
|
|
|
*/
|
2016-11-28 12:11:24 +00:00
|
|
|
int
|
|
|
|
meta_monitor_manager_get_num_logical_monitors (MetaMonitorManager *manager)
|
|
|
|
{
|
2016-12-02 08:00:03 +00:00
|
|
|
return g_list_length (manager->logical_monitors);
|
2016-11-28 12:11:24 +00:00
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_logical_monitors:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
*
|
2023-03-28 14:35:11 +00:00
|
|
|
* Returns the list of `MetaLogicalMonitor`s that is handled. See also
|
2018-10-19 07:15:54 +00:00
|
|
|
* meta_monitor_manager_get_num_logical_monitors() if you only need the size of
|
|
|
|
* the list.
|
|
|
|
*
|
|
|
|
* Returns: (transfer none) (nullable): the list of logical monitors.
|
|
|
|
*/
|
2016-12-02 08:00:03 +00:00
|
|
|
GList *
|
|
|
|
meta_monitor_manager_get_logical_monitors (MetaMonitorManager *manager)
|
2013-07-18 11:09:16 +00:00
|
|
|
{
|
2016-11-25 06:31:38 +00:00
|
|
|
return manager->logical_monitors;
|
2013-07-18 11:09:16 +00:00
|
|
|
}
|
|
|
|
|
2016-11-29 03:46:41 +00:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_logical_monitor_from_number (MetaMonitorManager *manager,
|
|
|
|
int number)
|
|
|
|
{
|
2017-10-13 05:10:22 +00:00
|
|
|
g_return_val_if_fail ((unsigned int) number < g_list_length (manager->logical_monitors), NULL);
|
2016-11-29 03:46:41 +00:00
|
|
|
|
2016-12-02 08:00:03 +00:00
|
|
|
return g_list_nth (manager->logical_monitors, number)->data;
|
2016-11-29 03:46:41 +00:00
|
|
|
}
|
|
|
|
|
2016-11-28 12:43:27 +00:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_primary_logical_monitor (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return manager->primary_logical_monitor;
|
|
|
|
}
|
|
|
|
|
2016-12-19 06:58:44 +00:00
|
|
|
static MetaMonitor *
|
|
|
|
find_monitor (MetaMonitorManager *monitor_manager,
|
|
|
|
gboolean (*match_func) (MetaMonitor *monitor))
|
|
|
|
{
|
|
|
|
GList *monitors;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
monitors = meta_monitor_manager_get_monitors (monitor_manager);
|
|
|
|
for (l = monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
|
|
|
if (match_func (monitor))
|
|
|
|
return monitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_primary_monitor:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
*
|
|
|
|
* Returns the primary monitor. This can be %NULL (e.g. when running headless).
|
|
|
|
*
|
|
|
|
* Returns: (transfer none) (nullable): The primary #MetaMonitor, or %NULL if
|
|
|
|
* none.
|
|
|
|
*/
|
2016-12-21 04:38:13 +00:00
|
|
|
MetaMonitor *
|
|
|
|
meta_monitor_manager_get_primary_monitor (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return find_monitor (manager, meta_monitor_is_primary);
|
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_laptop_panel:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
*
|
|
|
|
* Returns the #MetaMonitor that represents the built-in laptop panel (if
|
|
|
|
* applicable).
|
|
|
|
*
|
|
|
|
* Returns: (transfer none) (nullable): The laptop panel, or %NULL if none.
|
|
|
|
*/
|
2016-12-19 06:58:44 +00:00
|
|
|
MetaMonitor *
|
|
|
|
meta_monitor_manager_get_laptop_panel (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return find_monitor (manager, meta_monitor_is_laptop_panel);
|
|
|
|
}
|
|
|
|
|
2017-06-21 05:44:06 +00:00
|
|
|
MetaMonitor *
|
|
|
|
meta_monitor_manager_get_monitor_from_connector (MetaMonitorManager *manager,
|
|
|
|
const char *connector)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
|
|
|
if (g_str_equal (meta_monitor_get_connector (monitor),
|
|
|
|
connector))
|
|
|
|
return monitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-12-21 04:41:53 +00:00
|
|
|
MetaMonitor *
|
|
|
|
meta_monitor_manager_get_monitor_from_spec (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorSpec *monitor_spec)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
|
|
|
if (meta_monitor_spec_equals (meta_monitor_get_spec (monitor),
|
|
|
|
monitor_spec))
|
|
|
|
return monitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_logical_monitor_at:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
* @x: The x-coordinate
|
|
|
|
* @y: The y-coordinate
|
|
|
|
*
|
|
|
|
* Finds the #MetaLogicalMonitor at the given @x and @y coordinates in the
|
|
|
|
* total layout.
|
|
|
|
*
|
|
|
|
* Returns: (transfer none) (nullable): The #MetaLogicalMonitor at the given
|
|
|
|
* point, or %NULL if none.
|
|
|
|
*/
|
2016-11-30 02:49:00 +00:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_logical_monitor_at (MetaMonitorManager *manager,
|
2016-12-01 07:37:32 +00:00
|
|
|
float x,
|
|
|
|
float y)
|
2016-11-30 02:49:00 +00:00
|
|
|
{
|
2016-12-02 08:00:03 +00:00
|
|
|
GList *l;
|
2016-11-30 02:49:00 +00:00
|
|
|
|
2016-12-02 08:00:03 +00:00
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
2016-11-30 02:49:00 +00:00
|
|
|
{
|
2016-12-02 08:00:03 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
|
|
|
|
2019-10-02 18:23:41 +00:00
|
|
|
if (META_POINT_IN_RECT (x, y, logical_monitor->rect))
|
2016-12-02 08:00:03 +00:00
|
|
|
return logical_monitor;
|
2016-11-30 02:49:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_logical_monitor_from_rect:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
* @rect: The rectangle
|
|
|
|
*
|
2022-08-22 13:54:32 +00:00
|
|
|
* Finds the #MetaLogicalMonitor which contains the center of the given @rect
|
|
|
|
* or which has the largest area in common with the given @rect in the total
|
|
|
|
* layout if the center is not on a monitor.
|
2018-10-19 07:15:54 +00:00
|
|
|
*
|
|
|
|
* Returns: (transfer none) (nullable): The #MetaLogicalMonitor which
|
|
|
|
* corresponds the most to the given @rect, or %NULL if none.
|
|
|
|
*/
|
2016-12-01 04:52:07 +00:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_logical_monitor_from_rect (MetaMonitorManager *manager,
|
2023-07-19 23:46:15 +00:00
|
|
|
MtkRectangle *rect)
|
2016-12-01 04:52:07 +00:00
|
|
|
{
|
|
|
|
MetaLogicalMonitor *best_logical_monitor;
|
|
|
|
int best_logical_monitor_area;
|
2016-12-02 08:00:03 +00:00
|
|
|
GList *l;
|
2022-08-22 13:54:32 +00:00
|
|
|
int center_x = rect->x + (rect->width / 2);
|
|
|
|
int center_y = rect->y + (rect->height / 2);
|
2016-12-01 04:52:07 +00:00
|
|
|
|
|
|
|
best_logical_monitor = NULL;
|
|
|
|
best_logical_monitor_area = 0;
|
|
|
|
|
2016-12-02 08:00:03 +00:00
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
2016-12-01 04:52:07 +00:00
|
|
|
{
|
2016-12-02 08:00:03 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
2023-07-19 23:46:15 +00:00
|
|
|
MtkRectangle intersection;
|
2016-12-01 04:52:07 +00:00
|
|
|
int intersection_area;
|
|
|
|
|
2022-08-22 13:54:32 +00:00
|
|
|
if (META_POINT_IN_RECT (center_x, center_y, logical_monitor->rect))
|
|
|
|
return logical_monitor;
|
|
|
|
|
2023-07-19 15:40:37 +00:00
|
|
|
if (!mtk_rectangle_intersect (&logical_monitor->rect,
|
|
|
|
rect,
|
|
|
|
&intersection))
|
2016-12-01 04:52:07 +00:00
|
|
|
continue;
|
|
|
|
|
2023-07-19 22:44:52 +00:00
|
|
|
intersection_area = mtk_rectangle_area (&intersection);
|
2016-12-01 04:52:07 +00:00
|
|
|
|
|
|
|
if (intersection_area > best_logical_monitor_area)
|
|
|
|
{
|
|
|
|
best_logical_monitor = logical_monitor;
|
|
|
|
best_logical_monitor_area = intersection_area;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!best_logical_monitor)
|
|
|
|
best_logical_monitor = manager->primary_logical_monitor;
|
|
|
|
|
|
|
|
return best_logical_monitor;
|
|
|
|
}
|
|
|
|
|
2023-03-06 05:43:13 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_highest_scale_from_rect:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
* @rect: The rectangle
|
|
|
|
*
|
|
|
|
* Finds the #MetaLogicalMonitor with the highest scale intersecting @rect.
|
|
|
|
*
|
|
|
|
* Returns: (transfer none) (nullable): the #MetaLogicalMonitor with the
|
|
|
|
* highest scale intersecting with @rect, or %NULL if none.
|
|
|
|
*/
|
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_highest_scale_monitor_from_rect (MetaMonitorManager *manager,
|
2023-07-19 23:46:15 +00:00
|
|
|
MtkRectangle *rect)
|
2023-03-06 05:43:13 +00:00
|
|
|
{
|
|
|
|
MetaLogicalMonitor *best_logical_monitor = NULL;
|
|
|
|
GList *l;
|
|
|
|
float best_scale = 0.0;
|
|
|
|
|
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
2023-07-19 23:46:15 +00:00
|
|
|
MtkRectangle intersection;
|
2023-03-06 05:43:13 +00:00
|
|
|
float scale;
|
|
|
|
|
2023-07-19 15:40:37 +00:00
|
|
|
if (!mtk_rectangle_intersect (&logical_monitor->rect,
|
|
|
|
rect,
|
|
|
|
&intersection))
|
2023-03-06 05:43:13 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
scale = meta_logical_monitor_get_scale (logical_monitor);
|
|
|
|
|
|
|
|
if (scale > best_scale)
|
|
|
|
{
|
|
|
|
best_scale = scale;
|
|
|
|
best_logical_monitor = logical_monitor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return best_logical_monitor;
|
|
|
|
}
|
|
|
|
|
2016-12-01 07:15:52 +00:00
|
|
|
MetaLogicalMonitor *
|
2017-08-26 19:22:34 +00:00
|
|
|
meta_monitor_manager_get_logical_monitor_neighbor (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitor *logical_monitor,
|
|
|
|
MetaDisplayDirection direction)
|
2016-12-01 07:15:52 +00:00
|
|
|
{
|
2016-12-02 08:00:03 +00:00
|
|
|
GList *l;
|
2016-12-01 07:15:52 +00:00
|
|
|
|
2016-12-02 08:00:03 +00:00
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
2016-12-01 07:15:52 +00:00
|
|
|
{
|
2016-12-02 08:00:03 +00:00
|
|
|
MetaLogicalMonitor *other = l->data;
|
2016-12-01 07:15:52 +00:00
|
|
|
|
2017-03-24 14:46:32 +00:00
|
|
|
if (meta_logical_monitor_has_neighbor (logical_monitor, other, direction))
|
|
|
|
return other;
|
2016-12-01 07:15:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_monitors:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
*
|
2023-03-28 14:35:11 +00:00
|
|
|
* Returns the list of [class@Meta.Monitor]s. See also
|
2018-10-19 07:15:54 +00:00
|
|
|
* meta_monitor_manager_get_logical_monitors() for a list of
|
2023-03-28 14:35:11 +00:00
|
|
|
* `MetaLogicalMonitor`s.
|
2018-10-19 07:15:54 +00:00
|
|
|
*
|
2023-03-28 14:35:11 +00:00
|
|
|
* Returns: (transfer none) (nullable): the list of [class@Meta.Monitor]s.
|
2018-10-19 07:15:54 +00:00
|
|
|
*/
|
2016-12-13 02:53:38 +00:00
|
|
|
GList *
|
|
|
|
meta_monitor_manager_get_monitors (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return manager->monitors;
|
|
|
|
}
|
|
|
|
|
2013-07-18 11:09:16 +00:00
|
|
|
void
|
2013-07-22 16:57:12 +00:00
|
|
|
meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
|
|
|
|
int *width,
|
|
|
|
int *height)
|
|
|
|
{
|
|
|
|
*width = manager->screen_width;
|
|
|
|
*height = manager->screen_height;
|
|
|
|
}
|
|
|
|
|
2019-01-11 13:45:44 +00:00
|
|
|
MetaPowerSave
|
|
|
|
meta_monitor_manager_get_power_save_mode (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
|
|
|
|
return priv->power_save_mode;
|
|
|
|
}
|
|
|
|
|
2021-01-27 22:16:05 +00:00
|
|
|
static void
|
|
|
|
destroy_monitor (MetaMonitor *monitor)
|
|
|
|
{
|
|
|
|
g_object_run_dispose (G_OBJECT (monitor));
|
|
|
|
g_object_unref (monitor);
|
|
|
|
}
|
|
|
|
|
2016-12-13 02:53:38 +00:00
|
|
|
static void
|
|
|
|
rebuild_monitors (MetaMonitorManager *manager)
|
|
|
|
{
|
2019-01-11 14:35:42 +00:00
|
|
|
GList *gpus;
|
2017-03-24 09:35:51 +00:00
|
|
|
GList *l;
|
2016-12-13 02:53:38 +00:00
|
|
|
|
|
|
|
if (manager->monitors)
|
|
|
|
{
|
2021-01-27 22:16:05 +00:00
|
|
|
g_list_free_full (manager->monitors, (GDestroyNotify) destroy_monitor);
|
2016-12-13 02:53:38 +00:00
|
|
|
manager->monitors = NULL;
|
|
|
|
}
|
|
|
|
|
2019-01-11 14:35:42 +00:00
|
|
|
gpus = meta_backend_get_gpus (manager->backend);
|
|
|
|
for (l = gpus; l; l = l->next)
|
2016-12-13 02:53:38 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaGpu *gpu = l->data;
|
|
|
|
GList *k;
|
2016-12-13 02:53:38 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
for (k = meta_gpu_get_outputs (gpu); k; k = k->next)
|
2016-12-13 02:53:38 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaOutput *output = k->data;
|
2020-02-26 08:45:07 +00:00
|
|
|
const MetaOutputInfo *output_info = meta_output_get_info (output);
|
2017-07-10 10:19:32 +00:00
|
|
|
|
2020-02-26 08:45:07 +00:00
|
|
|
if (output_info->tile_info.group_id)
|
2017-07-10 10:19:32 +00:00
|
|
|
{
|
|
|
|
if (is_main_tiled_monitor_output (output))
|
|
|
|
{
|
|
|
|
MetaMonitorTiled *monitor_tiled;
|
|
|
|
|
2021-01-26 13:49:25 +00:00
|
|
|
monitor_tiled = meta_monitor_tiled_new (manager, output);
|
2017-07-10 10:19:32 +00:00
|
|
|
manager->monitors = g_list_append (manager->monitors,
|
|
|
|
monitor_tiled);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2016-12-13 02:53:38 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaMonitorNormal *monitor_normal;
|
2016-12-13 02:53:38 +00:00
|
|
|
|
2021-01-26 13:49:25 +00:00
|
|
|
monitor_normal = meta_monitor_normal_new (manager, output);
|
2016-12-13 02:53:38 +00:00
|
|
|
manager->monitors = g_list_append (manager->monitors,
|
2017-07-10 10:19:32 +00:00
|
|
|
monitor_normal);
|
2016-12-13 02:53:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
|
|
|
|
for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaVirtualMonitor *virtual_monitor = l->data;
|
|
|
|
MetaOutput *output = meta_virtual_monitor_get_output (virtual_monitor);
|
|
|
|
MetaMonitorNormal *monitor_normal;
|
|
|
|
|
|
|
|
monitor_normal = meta_monitor_normal_new (manager, output);
|
|
|
|
manager->monitors = g_list_append (manager->monitors,
|
|
|
|
monitor_normal);
|
|
|
|
|
|
|
|
}
|
2021-07-30 11:47:42 +00:00
|
|
|
|
|
|
|
update_panel_orientation_managed (manager);
|
2021-12-02 20:43:08 +00:00
|
|
|
update_has_builtin_panel (manager);
|
2022-08-15 12:09:29 +00:00
|
|
|
update_night_light_supported (manager);
|
2016-12-13 02:53:38 +00:00
|
|
|
}
|
|
|
|
|
2016-12-13 10:58:22 +00:00
|
|
|
void
|
|
|
|
meta_monitor_manager_tiled_monitor_added (MetaMonitorManager *manager,
|
|
|
|
MetaMonitor *monitor)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
if (manager_class->tiled_monitor_added)
|
|
|
|
manager_class->tiled_monitor_added (manager, monitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_tiled_monitor_removed (MetaMonitorManager *manager,
|
|
|
|
MetaMonitor *monitor)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
if (manager_class->tiled_monitor_removed)
|
|
|
|
manager_class->tiled_monitor_removed (manager, monitor);
|
|
|
|
}
|
|
|
|
|
2019-01-11 13:45:44 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_real_read_current_state (MetaMonitorManager *manager)
|
2014-10-12 20:35:55 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
GList *l;
|
2014-10-12 20:35:55 +00:00
|
|
|
|
|
|
|
manager->serial++;
|
|
|
|
|
2019-01-11 14:35:42 +00:00
|
|
|
for (l = meta_backend_get_gpus (manager->backend); l; l = l->next)
|
2017-07-10 10:19:32 +00:00
|
|
|
{
|
|
|
|
MetaGpu *gpu = l->data;
|
|
|
|
GError *error = NULL;
|
2016-12-13 02:53:38 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
if (!meta_gpu_read_current (gpu, &error))
|
|
|
|
{
|
2022-05-27 14:51:42 +00:00
|
|
|
g_warning ("Failed to read current monitor state: %s", error->message);
|
2017-07-10 10:19:32 +00:00
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rebuild_monitors (manager);
|
2014-10-12 20:35:55 +00:00
|
|
|
}
|
|
|
|
|
2019-01-11 13:45:44 +00:00
|
|
|
void
|
|
|
|
meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
manager_class->read_current_state (manager);
|
|
|
|
}
|
|
|
|
|
2017-01-06 05:27:21 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_notify_monitors_changed (MetaMonitorManager *manager)
|
|
|
|
{
|
2017-07-10 09:39:07 +00:00
|
|
|
meta_backend_monitors_changed (manager->backend);
|
|
|
|
|
2017-10-13 00:14:40 +00:00
|
|
|
g_signal_emit (manager, signals[MONITORS_CHANGED_INTERNAL], 0);
|
2019-01-23 01:49:26 +00:00
|
|
|
g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
|
|
|
|
|
|
|
|
meta_dbus_display_config_emit_monitors_changed (manager->display_config);
|
2017-01-06 05:27:21 +00:00
|
|
|
}
|
|
|
|
|
2017-01-09 06:31:18 +00:00
|
|
|
static void
|
|
|
|
set_logical_monitor_modes (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = logical_monitor_config->monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitorConfig *monitor_config = l->data;
|
|
|
|
MetaMonitorSpec *monitor_spec;
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
MetaMonitorModeSpec *monitor_mode_spec;
|
|
|
|
MetaMonitorMode *monitor_mode;
|
|
|
|
|
|
|
|
monitor_spec = monitor_config->monitor_spec;
|
|
|
|
monitor = meta_monitor_manager_get_monitor_from_spec (manager,
|
|
|
|
monitor_spec);
|
|
|
|
monitor_mode_spec = monitor_config->mode_spec;
|
|
|
|
monitor_mode = meta_monitor_get_mode_from_spec (monitor,
|
|
|
|
monitor_mode_spec);
|
|
|
|
|
|
|
|
meta_monitor_set_current_mode (monitor, monitor_mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitor_manager_update_monitor_modes (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
|
|
|
{
|
2017-01-12 05:47:54 +00:00
|
|
|
GList *logical_monitor_configs;
|
2017-01-09 06:31:18 +00:00
|
|
|
GList *l;
|
|
|
|
|
2017-01-20 06:56:34 +00:00
|
|
|
g_list_foreach (manager->monitors,
|
|
|
|
(GFunc) meta_monitor_set_current_mode,
|
|
|
|
NULL);
|
|
|
|
|
2017-01-12 05:47:54 +00:00
|
|
|
logical_monitor_configs = config ? config->logical_monitor_configs : NULL;
|
|
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
2017-01-09 06:31:18 +00:00
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
|
|
|
|
set_logical_monitor_modes (manager, logical_monitor_config);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_update_logical_state (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
|
|
|
{
|
2017-02-24 10:10:52 +00:00
|
|
|
if (config)
|
2018-08-30 00:34:53 +00:00
|
|
|
{
|
|
|
|
manager->layout_mode = config->layout_mode;
|
|
|
|
manager->current_switch_config =
|
|
|
|
meta_monitors_config_get_switch_config (config);
|
|
|
|
}
|
2017-02-24 10:10:52 +00:00
|
|
|
else
|
2018-08-30 00:34:53 +00:00
|
|
|
{
|
|
|
|
manager->layout_mode =
|
|
|
|
meta_monitor_manager_get_default_layout_mode (manager);
|
|
|
|
manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
|
|
|
}
|
2017-02-24 10:10:52 +00:00
|
|
|
|
2017-01-09 06:31:18 +00:00
|
|
|
meta_monitor_manager_rebuild_logical_monitors (manager, config);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_rebuild (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
|
|
|
{
|
|
|
|
GList *old_logical_monitors;
|
|
|
|
|
2017-01-20 06:56:34 +00:00
|
|
|
meta_monitor_manager_update_monitor_modes (manager, config);
|
|
|
|
|
2017-01-09 06:31:18 +00:00
|
|
|
if (manager->in_init)
|
|
|
|
return;
|
|
|
|
|
|
|
|
old_logical_monitors = manager->logical_monitors;
|
|
|
|
|
|
|
|
meta_monitor_manager_update_logical_state (manager, config);
|
|
|
|
|
2022-03-17 09:33:23 +00:00
|
|
|
ensure_privacy_screen_settings (manager);
|
2023-03-02 00:35:10 +00:00
|
|
|
ensure_hdr_settings (manager);
|
|
|
|
|
2023-11-09 05:20:34 +00:00
|
|
|
meta_monitor_manager_notify_monitors_changed (manager);
|
|
|
|
|
2017-01-09 06:31:18 +00:00
|
|
|
g_list_free_full (old_logical_monitors, g_object_unref);
|
|
|
|
}
|
|
|
|
|
2016-12-22 07:22:13 +00:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_update_monitor_modes_derived (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
|
|
|
meta_monitor_derive_current_mode (monitor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-06 05:27:21 +00:00
|
|
|
void
|
2017-09-11 06:10:26 +00:00
|
|
|
meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
2017-01-06 05:27:21 +00:00
|
|
|
{
|
2018-08-30 00:34:53 +00:00
|
|
|
if (config)
|
|
|
|
manager->current_switch_config =
|
|
|
|
meta_monitors_config_get_switch_config (config);
|
|
|
|
else
|
|
|
|
manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
|
|
|
|
2017-02-24 10:10:52 +00:00
|
|
|
manager->layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
|
|
|
|
|
2017-09-11 06:10:26 +00:00
|
|
|
meta_monitor_manager_rebuild_logical_monitors_derived (manager, config);
|
2017-01-06 05:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-02 13:04:05 +00:00
|
|
|
void
|
2017-09-11 06:10:26 +00:00
|
|
|
meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
2013-07-23 08:07:52 +00:00
|
|
|
{
|
2016-12-02 08:00:03 +00:00
|
|
|
GList *old_logical_monitors;
|
2014-10-23 14:31:09 +00:00
|
|
|
|
2017-01-20 06:56:34 +00:00
|
|
|
meta_monitor_manager_update_monitor_modes_derived (manager);
|
|
|
|
|
2013-07-25 08:57:59 +00:00
|
|
|
if (manager->in_init)
|
|
|
|
return;
|
|
|
|
|
2016-12-02 08:00:03 +00:00
|
|
|
old_logical_monitors = manager->logical_monitors;
|
|
|
|
|
2017-09-11 06:10:26 +00:00
|
|
|
meta_monitor_manager_update_logical_state_derived (manager, config);
|
2016-07-06 07:27:45 +00:00
|
|
|
|
2017-01-06 05:27:21 +00:00
|
|
|
meta_monitor_manager_notify_monitors_changed (manager);
|
2014-10-23 14:31:09 +00:00
|
|
|
|
2016-12-02 08:08:59 +00:00
|
|
|
g_list_free_full (old_logical_monitors, g_object_unref);
|
2013-07-23 08:07:52 +00:00
|
|
|
}
|
2014-10-12 22:13:15 +00:00
|
|
|
|
2016-12-19 07:22:07 +00:00
|
|
|
void
|
2021-01-25 20:10:53 +00:00
|
|
|
meta_monitor_manager_reconfigure (MetaMonitorManager *manager)
|
2016-12-19 07:22:07 +00:00
|
|
|
{
|
2017-01-09 06:31:18 +00:00
|
|
|
meta_monitor_manager_ensure_configured (manager);
|
2014-10-12 22:13:15 +00:00
|
|
|
}
|
2014-12-11 17:14:00 +00:00
|
|
|
|
2021-01-25 20:10:53 +00:00
|
|
|
void
|
|
|
|
meta_monitor_manager_reload (MetaMonitorManager *manager)
|
|
|
|
{
|
2023-09-29 12:31:41 +00:00
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
|
|
|
|
g_clear_handle_id (&priv->reload_monitor_manager_id, g_source_remove);
|
|
|
|
|
2021-01-25 20:10:53 +00:00
|
|
|
meta_monitor_manager_read_current_state (manager);
|
|
|
|
meta_monitor_manager_reconfigure (manager);
|
|
|
|
}
|
|
|
|
|
2014-12-11 17:14:00 +00:00
|
|
|
static gboolean
|
|
|
|
calculate_viewport_matrix (MetaMonitorManager *manager,
|
2017-03-07 04:20:14 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor,
|
2014-12-11 17:14:00 +00:00
|
|
|
gfloat viewport[6])
|
|
|
|
{
|
|
|
|
gfloat x, y, width, height;
|
|
|
|
|
2017-03-07 04:20:14 +00:00
|
|
|
x = (float) logical_monitor->rect.x / manager->screen_width;
|
|
|
|
y = (float) logical_monitor->rect.y / manager->screen_height;
|
|
|
|
width = (float) logical_monitor->rect.width / manager->screen_width;
|
|
|
|
height = (float) logical_monitor->rect.height / manager->screen_height;
|
2014-12-11 17:14:00 +00:00
|
|
|
|
|
|
|
viewport[0] = width;
|
|
|
|
viewport[1] = 0.0f;
|
|
|
|
viewport[2] = x;
|
|
|
|
viewport[3] = 0.0f;
|
|
|
|
viewport[4] = height;
|
|
|
|
viewport[5] = y;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
multiply_matrix (float a[6],
|
|
|
|
float b[6],
|
|
|
|
float res[6])
|
|
|
|
{
|
|
|
|
res[0] = a[0] * b[0] + a[1] * b[3];
|
|
|
|
res[1] = a[0] * b[1] + a[1] * b[4];
|
|
|
|
res[2] = a[0] * b[2] + a[1] * b[5] + a[2];
|
|
|
|
res[3] = a[3] * b[0] + a[4] * b[3];
|
|
|
|
res[4] = a[3] * b[1] + a[4] * b[4];
|
|
|
|
res[5] = a[3] * b[2] + a[4] * b[5] + a[5];
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_get_monitor_matrix (MetaMonitorManager *manager,
|
2017-10-06 11:41:49 +00:00
|
|
|
MetaMonitor *monitor,
|
2017-03-07 04:20:14 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor,
|
2014-12-11 17:14:00 +00:00
|
|
|
gfloat matrix[6])
|
|
|
|
{
|
2017-03-07 04:20:14 +00:00
|
|
|
MetaMonitorTransform transform;
|
2014-12-11 17:14:00 +00:00
|
|
|
gfloat viewport[9];
|
|
|
|
|
2017-03-07 04:20:14 +00:00
|
|
|
if (!calculate_viewport_matrix (manager, logical_monitor, viewport))
|
2014-12-11 17:14:00 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2017-10-06 11:41:49 +00:00
|
|
|
/* Get transform corrected for LCD panel-orientation. */
|
2017-03-17 08:33:18 +00:00
|
|
|
transform = logical_monitor->transform;
|
2017-10-06 11:41:49 +00:00
|
|
|
transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
|
2017-03-07 04:20:14 +00:00
|
|
|
multiply_matrix (viewport, transform_matrices[transform],
|
2014-12-11 17:14:00 +00:00
|
|
|
matrix);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2015-01-30 13:54:09 +00:00
|
|
|
|
2017-04-06 05:15:45 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_monitor_for_connector:
|
|
|
|
* @manager: A #MetaMonitorManager
|
|
|
|
* @connector: A valid connector name
|
|
|
|
*
|
|
|
|
* Returns: The monitor index or -1 if @id isn't valid or the connector
|
|
|
|
* isn't associated with a logical monitor.
|
|
|
|
*/
|
|
|
|
gint
|
|
|
|
meta_monitor_manager_get_monitor_for_connector (MetaMonitorManager *manager,
|
|
|
|
const char *connector)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
2017-04-07 15:41:23 +00:00
|
|
|
if (meta_monitor_is_active (monitor) &&
|
|
|
|
g_str_equal (connector, meta_monitor_get_connector (monitor)))
|
2017-11-03 10:25:30 +00:00
|
|
|
return meta_monitor_get_logical_monitor (monitor)->number;
|
2017-04-06 05:15:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-10-19 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_is_builtin_display_on:
|
|
|
|
* @manager: A #MetaMonitorManager object
|
|
|
|
*
|
|
|
|
* Returns whether the built-in display (i.e. a laptop panel) is turned on.
|
|
|
|
*/
|
2016-04-20 18:00:45 +00:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_get_is_builtin_display_on (MetaMonitorManager *manager)
|
|
|
|
{
|
2016-12-19 06:58:44 +00:00
|
|
|
MetaMonitor *laptop_panel;
|
|
|
|
|
2016-04-20 18:00:45 +00:00
|
|
|
g_return_val_if_fail (META_IS_MONITOR_MANAGER (manager), FALSE);
|
|
|
|
|
2016-12-19 06:58:44 +00:00
|
|
|
laptop_panel = meta_monitor_manager_get_laptop_panel (manager);
|
|
|
|
if (!laptop_panel)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return meta_monitor_is_active (laptop_panel);
|
2016-04-20 18:00:45 +00:00
|
|
|
}
|
2017-05-04 12:25:47 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_rotate_monitor (MetaMonitorManager *manager)
|
|
|
|
{
|
2017-03-24 07:36:12 +00:00
|
|
|
GError *error = NULL;
|
|
|
|
MetaMonitorsConfig *config =
|
|
|
|
meta_monitor_config_manager_create_for_rotate_monitor (manager->config_manager);
|
2017-05-04 12:25:47 +00:00
|
|
|
|
2017-03-24 07:36:12 +00:00
|
|
|
if (!config)
|
|
|
|
return;
|
2017-05-04 12:25:47 +00:00
|
|
|
|
2017-03-24 07:36:12 +00:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
|
|
config,
|
|
|
|
META_MONITORS_CONFIG_METHOD_TEMPORARY,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to use rotate monitor configuration: %s",
|
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
2017-05-04 12:25:47 +00:00
|
|
|
}
|
2017-03-24 07:36:12 +00:00
|
|
|
g_object_unref (config);
|
2017-05-04 12:25:47 +00:00
|
|
|
}
|
2017-06-07 16:38:10 +00:00
|
|
|
|
2023-03-14 16:28:24 +00:00
|
|
|
typedef struct
|
2017-06-07 16:38:10 +00:00
|
|
|
{
|
2023-03-14 16:28:24 +00:00
|
|
|
MetaMonitorManager *monitor_manager;
|
|
|
|
MetaMonitorSwitchConfigType config_type;
|
|
|
|
} SwitchConfigData;
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
switch_config_idle_cb (gpointer user_data)
|
|
|
|
{
|
|
|
|
SwitchConfigData *data = user_data;
|
|
|
|
MetaMonitorManager *monitor_manager = data->monitor_manager;
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (monitor_manager);
|
|
|
|
MetaMonitorConfigManager *config_manager = monitor_manager->config_manager;
|
2017-03-24 07:36:12 +00:00
|
|
|
MetaMonitorsConfig *config;
|
2023-03-14 16:28:24 +00:00
|
|
|
g_autoptr (GError) error = NULL;
|
2017-03-24 07:36:12 +00:00
|
|
|
|
2023-03-14 16:28:24 +00:00
|
|
|
priv->switch_config_handle_id = 0;
|
2017-06-07 16:38:10 +00:00
|
|
|
|
2017-03-24 07:36:12 +00:00
|
|
|
config =
|
2023-03-14 16:28:24 +00:00
|
|
|
meta_monitor_config_manager_create_for_switch_config (config_manager,
|
|
|
|
data->config_type);
|
2017-03-24 07:36:12 +00:00
|
|
|
if (!config)
|
2023-03-14 16:28:24 +00:00
|
|
|
return G_SOURCE_REMOVE;
|
2017-03-24 07:36:12 +00:00
|
|
|
|
2023-03-14 16:28:24 +00:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (monitor_manager,
|
2017-03-24 07:36:12 +00:00
|
|
|
config,
|
|
|
|
META_MONITORS_CONFIG_METHOD_TEMPORARY,
|
|
|
|
&error))
|
2017-06-07 16:38:10 +00:00
|
|
|
{
|
2017-03-24 07:36:12 +00:00
|
|
|
g_warning ("Failed to use switch monitor configuration: %s",
|
|
|
|
error->message);
|
2017-06-07 16:38:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-03-14 16:28:24 +00:00
|
|
|
monitor_manager->current_switch_config = data->config_type;
|
2017-06-07 16:38:10 +00:00
|
|
|
}
|
2023-03-14 16:28:24 +00:00
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_switch_config (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorSwitchConfigType config_type)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
SwitchConfigData *data;
|
|
|
|
|
|
|
|
g_return_if_fail (config_type != META_MONITOR_SWITCH_CONFIG_UNKNOWN);
|
|
|
|
|
|
|
|
data = g_new0 (SwitchConfigData, 1);
|
|
|
|
data->monitor_manager = manager;
|
|
|
|
data->config_type = config_type;
|
|
|
|
|
|
|
|
g_clear_handle_id (&priv->switch_config_handle_id, g_source_remove);
|
|
|
|
priv->switch_config_handle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
|
|
|
|
switch_config_idle_cb,
|
|
|
|
data,
|
|
|
|
g_free);
|
2017-06-07 16:38:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_can_switch_config (MetaMonitorManager *manager)
|
|
|
|
{
|
2018-04-16 18:07:45 +00:00
|
|
|
return (!meta_backend_is_lid_closed (manager->backend) &&
|
2017-06-07 16:38:10 +00:00
|
|
|
g_list_length (manager->monitors) > 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorSwitchConfigType
|
|
|
|
meta_monitor_manager_get_switch_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return manager->current_switch_config;
|
|
|
|
}
|
2017-09-11 06:10:26 +00:00
|
|
|
|
|
|
|
MetaMonitorConfigManager *
|
|
|
|
meta_monitor_manager_get_config_manager (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return manager->config_manager;
|
|
|
|
}
|
2019-06-26 10:29:22 +00:00
|
|
|
|
2020-06-11 16:15:22 +00:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_get_panel_orientation_managed (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (META_IS_MONITOR_MANAGER (manager), FALSE);
|
|
|
|
|
|
|
|
return manager->panel_orientation_managed;
|
|
|
|
}
|
2020-06-11 16:18:37 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_post_init (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
ClutterBackend *clutter_backend;
|
|
|
|
ClutterSeat *seat;
|
|
|
|
|
2022-04-12 23:42:14 +00:00
|
|
|
if (manager->privacy_screen_change_state ==
|
|
|
|
META_PRIVACY_SCREEN_CHANGE_STATE_INIT)
|
|
|
|
{
|
|
|
|
manager->privacy_screen_change_state =
|
|
|
|
META_PRIVACY_SCREEN_CHANGE_STATE_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
apply_privacy_screen_settings (manager);
|
|
|
|
|
2020-06-11 16:18:37 +00:00
|
|
|
clutter_backend = meta_backend_get_clutter_backend (manager->backend);
|
|
|
|
seat = clutter_backend_get_default_seat (clutter_backend);
|
|
|
|
|
|
|
|
g_signal_connect_object (seat, "notify::touch-mode",
|
|
|
|
G_CALLBACK (update_panel_orientation_managed), manager,
|
|
|
|
G_CONNECT_SWAPPED);
|
|
|
|
}
|
2020-07-16 11:52:39 +00:00
|
|
|
|
|
|
|
MetaViewportInfo *
|
|
|
|
meta_monitor_manager_get_viewports (MetaMonitorManager *manager)
|
|
|
|
{
|
2022-05-27 18:30:37 +00:00
|
|
|
MetaBackend *backend = meta_monitor_manager_get_backend (manager);
|
2020-07-16 11:52:39 +00:00
|
|
|
MetaViewportInfo *info;
|
|
|
|
GArray *views, *scales;
|
|
|
|
GList *logical_monitors, *l;
|
|
|
|
|
2023-07-19 14:59:04 +00:00
|
|
|
views = g_array_new (FALSE, FALSE, sizeof (MtkRectangle));
|
2020-07-16 11:52:39 +00:00
|
|
|
scales = g_array_new (FALSE, FALSE, sizeof (float));
|
|
|
|
|
|
|
|
logical_monitors = meta_monitor_manager_get_logical_monitors (manager);
|
|
|
|
|
|
|
|
for (l = logical_monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
2023-07-19 14:59:04 +00:00
|
|
|
MtkRectangle rect;
|
2020-07-16 11:52:39 +00:00
|
|
|
float scale;
|
|
|
|
|
|
|
|
rect = logical_monitor->rect;
|
|
|
|
g_array_append_val (views, rect);
|
|
|
|
|
|
|
|
scale = logical_monitor->scale;
|
|
|
|
g_array_append_val (scales, scale);
|
|
|
|
}
|
|
|
|
|
2023-07-19 14:59:04 +00:00
|
|
|
info = meta_viewport_info_new ((MtkRectangle *) views->data,
|
2020-07-16 11:52:39 +00:00
|
|
|
(float *) scales->data,
|
2021-03-26 10:25:38 +00:00
|
|
|
views->len,
|
2022-05-27 18:30:37 +00:00
|
|
|
meta_backend_is_stage_views_scaled (backend));
|
2020-07-16 11:52:39 +00:00
|
|
|
g_array_unref (views);
|
|
|
|
g_array_unref (scales);
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 15:49:28 +00:00
|
|
|
|
|
|
|
GList *
|
|
|
|
meta_monitor_manager_get_virtual_monitors (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerPrivate *priv =
|
|
|
|
meta_monitor_manager_get_instance_private (manager);
|
|
|
|
|
|
|
|
return priv->virtual_monitors;
|
|
|
|
}
|