2017-01-09 01:31:18 -05:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2016 Red Hat
|
2018-11-06 09:03:50 -05:00
|
|
|
* Copyright (c) 2018 DisplayLink (UK) Ltd.
|
2017-01-09 01:31:18 -05: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.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
* 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "backends/meta-monitor-config-manager.h"
|
|
|
|
|
2018-04-16 14:07:45 -04:00
|
|
|
#include "backends/meta-backend-private.h"
|
2017-08-10 03:12:41 -04:00
|
|
|
#include "backends/meta-monitor-config-migration.h"
|
2017-01-12 03:13:48 -05:00
|
|
|
#include "backends/meta-monitor-config-store.h"
|
2017-01-09 01:31:18 -05:00
|
|
|
#include "backends/meta-monitor-manager-private.h"
|
2017-03-24 05:35:51 -04:00
|
|
|
#include "backends/meta-output.h"
|
2017-01-09 02:38:17 -05:00
|
|
|
#include "core/boxes-private.h"
|
2019-04-02 18:51:34 -04:00
|
|
|
#include "meta/meta-monitor-manager.h"
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2017-08-11 03:16:15 -04:00
|
|
|
#define CONFIG_HISTORY_MAX_SIZE 3
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
struct _MetaMonitorConfigManager
|
|
|
|
{
|
|
|
|
GObject parent;
|
|
|
|
|
|
|
|
MetaMonitorManager *monitor_manager;
|
|
|
|
|
2017-01-12 03:13:48 -05:00
|
|
|
MetaMonitorConfigStore *config_store;
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaMonitorsConfig *current_config;
|
2017-08-11 03:16:15 -04:00
|
|
|
GQueue config_history;
|
2017-01-09 01:31:18 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (MetaMonitorConfigManager, meta_monitor_config_manager,
|
|
|
|
G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (MetaMonitorsConfig, meta_monitors_config,
|
|
|
|
G_TYPE_OBJECT)
|
|
|
|
|
2017-03-24 03:36:12 -04:00
|
|
|
static void
|
2020-02-25 14:30:46 -05:00
|
|
|
meta_crtc_assignment_free (MetaCrtcAssignment *assignment);
|
2017-03-24 03:36:12 -04:00
|
|
|
|
|
|
|
static void
|
2020-02-25 14:30:46 -05:00
|
|
|
meta_output_assignment_free (MetaOutputAssignment *assignment);
|
2017-03-24 03:36:12 -04:00
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaMonitorConfigManager *
|
|
|
|
meta_monitor_config_manager_new (MetaMonitorManager *monitor_manager)
|
|
|
|
{
|
|
|
|
MetaMonitorConfigManager *config_manager;
|
|
|
|
|
|
|
|
config_manager = g_object_new (META_TYPE_MONITOR_CONFIG_MANAGER, NULL);
|
|
|
|
config_manager->monitor_manager = monitor_manager;
|
2017-02-24 05:10:52 -05:00
|
|
|
config_manager->config_store =
|
|
|
|
meta_monitor_config_store_new (monitor_manager);
|
2017-01-09 01:31:18 -05:00
|
|
|
|
|
|
|
return config_manager;
|
|
|
|
}
|
|
|
|
|
2017-01-12 03:13:48 -05:00
|
|
|
MetaMonitorConfigStore *
|
|
|
|
meta_monitor_config_manager_get_store (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
|
|
|
return config_manager->config_store;
|
|
|
|
}
|
|
|
|
|
2018-11-12 13:46:06 -05:00
|
|
|
static gboolean
|
|
|
|
is_crtc_reserved (MetaCrtc *crtc,
|
|
|
|
GArray *reserved_crtcs)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < reserved_crtcs->len; i++)
|
|
|
|
{
|
2020-02-25 05:34:43 -05:00
|
|
|
uint64_t id;
|
|
|
|
|
|
|
|
id = g_array_index (reserved_crtcs, uint64_t, i);
|
|
|
|
if (id == meta_crtc_get_id (crtc))
|
2018-11-12 13:46:06 -05:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
static gboolean
|
|
|
|
is_crtc_assigned (MetaCrtc *crtc,
|
2020-02-25 14:30:46 -05:00
|
|
|
GPtrArray *crtc_assignments)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2020-02-25 14:30:46 -05:00
|
|
|
for (i = 0; i < crtc_assignments->len; i++)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
2020-02-25 14:30:46 -05:00
|
|
|
MetaCrtcAssignment *assigned_crtc_assignment =
|
|
|
|
g_ptr_array_index (crtc_assignments, i);
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2020-02-25 14:30:46 -05:00
|
|
|
if (assigned_crtc_assignment->crtc == crtc)
|
2017-01-09 01:31:18 -05:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaCrtc *
|
|
|
|
find_unassigned_crtc (MetaOutput *output,
|
2020-02-25 14:30:46 -05:00
|
|
|
GPtrArray *crtc_assignments,
|
2018-11-12 13:46:06 -05:00
|
|
|
GArray *reserved_crtcs)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
2018-11-06 09:03:50 -05:00
|
|
|
MetaCrtc *crtc;
|
2020-02-26 03:45:07 -05:00
|
|
|
const MetaOutputInfo *output_info;
|
2017-01-09 01:31:18 -05:00
|
|
|
unsigned int i;
|
|
|
|
|
2018-11-06 09:03:50 -05:00
|
|
|
crtc = meta_output_get_assigned_crtc (output);
|
2020-02-25 14:30:46 -05:00
|
|
|
if (crtc && !is_crtc_assigned (crtc, crtc_assignments))
|
2018-11-06 09:03:50 -05:00
|
|
|
return crtc;
|
|
|
|
|
2020-02-26 03:45:07 -05:00
|
|
|
output_info = meta_output_get_info (output);
|
|
|
|
|
2018-11-12 13:46:06 -05:00
|
|
|
/* then try to assign a CRTC that wasn't used */
|
2020-02-26 03:45:07 -05:00
|
|
|
for (i = 0; i < output_info->n_possible_crtcs; i++)
|
2018-11-12 13:46:06 -05:00
|
|
|
{
|
2020-02-26 03:45:07 -05:00
|
|
|
crtc = output_info->possible_crtcs[i];
|
2018-11-12 13:46:06 -05:00
|
|
|
|
2020-02-25 14:30:46 -05:00
|
|
|
if (is_crtc_assigned (crtc, crtc_assignments))
|
2018-11-12 13:46:06 -05:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (is_crtc_reserved (crtc, reserved_crtcs))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return crtc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* finally just give a CRTC that we haven't assigned */
|
2020-02-26 03:45:07 -05:00
|
|
|
for (i = 0; i < output_info->n_possible_crtcs; i++)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
2020-02-26 03:45:07 -05:00
|
|
|
crtc = output_info->possible_crtcs[i];
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2020-02-25 14:30:46 -05:00
|
|
|
if (is_crtc_assigned (crtc, crtc_assignments))
|
2017-01-09 01:31:18 -05:00
|
|
|
continue;
|
|
|
|
|
|
|
|
return crtc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
2017-03-21 02:17:18 -04:00
|
|
|
MetaMonitorManager *monitor_manager;
|
2020-03-11 04:53:17 -04:00
|
|
|
MetaMonitorsConfig *config;
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config;
|
|
|
|
MetaMonitorConfig *monitor_config;
|
2020-02-25 14:30:46 -05:00
|
|
|
GPtrArray *crtc_assignments;
|
|
|
|
GPtrArray *output_assignments;
|
2018-11-12 13:46:06 -05:00
|
|
|
GArray *reserved_crtcs;
|
2017-01-09 01:31:18 -05:00
|
|
|
} MonitorAssignmentData;
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
assign_monitor_crtc (MetaMonitor *monitor,
|
|
|
|
MetaMonitorMode *mode,
|
|
|
|
MetaMonitorCrtcMode *monitor_crtc_mode,
|
|
|
|
gpointer user_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MonitorAssignmentData *data = user_data;
|
|
|
|
MetaOutput *output;
|
|
|
|
MetaCrtc *crtc;
|
2017-03-21 02:17:18 -04:00
|
|
|
MetaMonitorTransform transform;
|
|
|
|
MetaMonitorTransform crtc_transform;
|
2020-04-14 04:23:43 -04:00
|
|
|
MetaMonitorTransform crtc_hw_transform;
|
2017-03-17 05:21:10 -04:00
|
|
|
int crtc_x, crtc_y;
|
2020-01-14 16:34:44 -05:00
|
|
|
float x_offset, y_offset;
|
2020-03-11 04:53:17 -04:00
|
|
|
float scale = 0.0;
|
2020-01-14 16:34:44 -05:00
|
|
|
float width, height;
|
|
|
|
MetaCrtcMode *crtc_mode;
|
2020-02-26 18:08:58 -05:00
|
|
|
const MetaCrtcModeInfo *crtc_mode_info;
|
2020-01-14 16:34:44 -05:00
|
|
|
graphene_rect_t crtc_layout;
|
2020-02-25 14:30:46 -05:00
|
|
|
MetaCrtcAssignment *crtc_assignment;
|
|
|
|
MetaOutputAssignment *output_assignment;
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaMonitorConfig *first_monitor_config;
|
|
|
|
gboolean assign_output_as_primary;
|
|
|
|
gboolean assign_output_as_presentation;
|
|
|
|
|
|
|
|
output = monitor_crtc_mode->output;
|
|
|
|
|
2020-02-25 14:30:46 -05:00
|
|
|
crtc = find_unassigned_crtc (output,
|
|
|
|
data->crtc_assignments,
|
|
|
|
data->reserved_crtcs);
|
2018-11-12 13:46:06 -05:00
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
if (!crtc)
|
|
|
|
{
|
|
|
|
MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor);
|
|
|
|
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"No available CRTC for monitor '%s %s' not found",
|
|
|
|
monitor_spec->vendor, monitor_spec->product);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-03-21 02:17:18 -04:00
|
|
|
transform = data->logical_monitor_config->transform;
|
2017-10-24 06:43:58 -04:00
|
|
|
crtc_transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
|
2020-04-14 04:23:43 -04:00
|
|
|
if (meta_monitor_manager_is_transform_handled (data->monitor_manager,
|
|
|
|
crtc,
|
|
|
|
crtc_transform))
|
|
|
|
crtc_hw_transform = crtc_transform;
|
|
|
|
else
|
|
|
|
crtc_hw_transform = META_MONITOR_TRANSFORM_NORMAL;
|
2017-03-21 02:17:18 -04:00
|
|
|
|
|
|
|
meta_monitor_calculate_crtc_pos (monitor, mode, output, crtc_transform,
|
2017-03-17 05:21:10 -04:00
|
|
|
&crtc_x, &crtc_y);
|
|
|
|
|
2020-01-14 16:34:44 -05:00
|
|
|
x_offset = data->logical_monitor_config->layout.x;
|
|
|
|
y_offset = data->logical_monitor_config->layout.y;
|
2020-03-11 04:53:17 -04:00
|
|
|
|
|
|
|
switch (data->config->layout_mode)
|
|
|
|
{
|
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
|
|
|
|
scale = data->logical_monitor_config->scale;
|
|
|
|
break;
|
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
|
|
|
|
scale = 1.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-01-14 16:34:44 -05:00
|
|
|
crtc_mode = monitor_crtc_mode->crtc_mode;
|
2020-02-26 18:08:58 -05:00
|
|
|
crtc_mode_info = meta_crtc_mode_get_info (monitor_crtc_mode->crtc_mode);
|
2020-01-14 16:34:44 -05:00
|
|
|
|
|
|
|
if (meta_monitor_transform_is_rotated (crtc_transform))
|
|
|
|
{
|
2020-02-26 18:08:58 -05:00
|
|
|
width = crtc_mode_info->height / scale;
|
|
|
|
height = crtc_mode_info->width / scale;
|
2020-01-14 16:34:44 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-02-26 18:08:58 -05:00
|
|
|
width = crtc_mode_info->width / scale;
|
|
|
|
height = crtc_mode_info->height / scale;
|
2020-01-14 16:34:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
crtc_layout = GRAPHENE_RECT_INIT (x_offset + (crtc_x / scale),
|
|
|
|
y_offset + (crtc_y / scale),
|
|
|
|
width,
|
|
|
|
height);
|
|
|
|
|
2020-10-19 13:57:57 -04:00
|
|
|
crtc_assignment = g_new0 (MetaCrtcAssignment, 1);
|
2020-02-25 14:30:46 -05:00
|
|
|
*crtc_assignment = (MetaCrtcAssignment) {
|
2017-01-09 01:31:18 -05:00
|
|
|
.crtc = crtc,
|
2020-01-14 16:34:44 -05:00
|
|
|
.mode = crtc_mode,
|
|
|
|
.layout = crtc_layout,
|
2020-04-14 04:23:43 -04:00
|
|
|
.transform = crtc_hw_transform,
|
2017-01-09 01:31:18 -05:00
|
|
|
.outputs = g_ptr_array_new ()
|
|
|
|
};
|
2020-02-25 14:30:46 -05:00
|
|
|
g_ptr_array_add (crtc_assignment->outputs, output);
|
2017-01-09 01:31:18 -05:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Only one output can be marked as primary (due to Xrandr limitation),
|
|
|
|
* so only mark the main output of the first monitor in the logical monitor
|
|
|
|
* as such.
|
|
|
|
*/
|
|
|
|
first_monitor_config = data->logical_monitor_config->monitor_configs->data;
|
2017-03-21 04:36:24 -04:00
|
|
|
if (data->logical_monitor_config->is_primary &&
|
|
|
|
data->monitor_config == first_monitor_config &&
|
2017-01-09 01:31:18 -05:00
|
|
|
meta_monitor_get_main_output (monitor) == output)
|
|
|
|
assign_output_as_primary = TRUE;
|
|
|
|
else
|
|
|
|
assign_output_as_primary = FALSE;
|
|
|
|
|
|
|
|
if (data->logical_monitor_config->is_presentation)
|
|
|
|
assign_output_as_presentation = TRUE;
|
|
|
|
else
|
|
|
|
assign_output_as_presentation = FALSE;
|
|
|
|
|
2020-10-19 13:57:57 -04:00
|
|
|
output_assignment = g_new0 (MetaOutputAssignment, 1);
|
2020-02-25 14:30:46 -05:00
|
|
|
*output_assignment = (MetaOutputAssignment) {
|
2017-01-09 01:31:18 -05:00
|
|
|
.output = output,
|
|
|
|
.is_primary = assign_output_as_primary,
|
|
|
|
.is_presentation = assign_output_as_presentation,
|
2017-02-14 05:19:09 -05:00
|
|
|
.is_underscanning = data->monitor_config->enable_underscanning
|
2017-01-09 01:31:18 -05:00
|
|
|
};
|
|
|
|
|
2020-02-25 14:30:46 -05:00
|
|
|
g_ptr_array_add (data->crtc_assignments, crtc_assignment);
|
|
|
|
g_ptr_array_add (data->output_assignments, output_assignment);
|
2017-01-09 01:31:18 -05:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
assign_monitor_crtcs (MetaMonitorManager *manager,
|
2020-03-11 04:53:17 -04:00
|
|
|
MetaMonitorsConfig *config,
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config,
|
|
|
|
MetaMonitorConfig *monitor_config,
|
2020-02-25 14:30:46 -05:00
|
|
|
GPtrArray *crtc_assignments,
|
|
|
|
GPtrArray *output_assignments,
|
2018-11-12 13:46:06 -05:00
|
|
|
GArray *reserved_crtcs,
|
2017-01-09 01:31:18 -05:00
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaMonitorSpec *monitor_spec = monitor_config->monitor_spec;
|
|
|
|
MetaMonitorModeSpec *monitor_mode_spec = monitor_config->mode_spec;
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
MetaMonitorMode *monitor_mode;
|
|
|
|
MonitorAssignmentData data;
|
|
|
|
|
|
|
|
monitor = meta_monitor_manager_get_monitor_from_spec (manager, monitor_spec);
|
|
|
|
if (!monitor)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Configured monitor '%s %s' not found",
|
|
|
|
monitor_spec->vendor, monitor_spec->product);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_mode = meta_monitor_get_mode_from_spec (monitor, monitor_mode_spec);
|
|
|
|
if (!monitor_mode)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Invalid mode %dx%d (%f) for monitor '%s %s'",
|
|
|
|
monitor_mode_spec->width, monitor_mode_spec->height,
|
|
|
|
monitor_mode_spec->refresh_rate,
|
|
|
|
monitor_spec->vendor, monitor_spec->product);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
data = (MonitorAssignmentData) {
|
2017-03-21 02:17:18 -04:00
|
|
|
.monitor_manager = manager,
|
2020-03-11 04:53:17 -04:00
|
|
|
.config = config,
|
2017-01-09 01:31:18 -05:00
|
|
|
.logical_monitor_config = logical_monitor_config,
|
|
|
|
.monitor_config = monitor_config,
|
2020-02-25 14:30:46 -05:00
|
|
|
.crtc_assignments = crtc_assignments,
|
|
|
|
.output_assignments = output_assignments,
|
2018-11-12 13:46:06 -05:00
|
|
|
.reserved_crtcs = reserved_crtcs
|
2017-01-09 01:31:18 -05:00
|
|
|
};
|
|
|
|
if (!meta_monitor_mode_foreach_crtc (monitor, monitor_mode,
|
|
|
|
assign_monitor_crtc,
|
|
|
|
&data,
|
|
|
|
error))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
assign_logical_monitor_crtcs (MetaMonitorManager *manager,
|
2020-03-11 04:53:17 -04:00
|
|
|
MetaMonitorsConfig *config,
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config,
|
2020-02-25 14:30:46 -05:00
|
|
|
GPtrArray *crtc_assignments,
|
|
|
|
GPtrArray *output_assignments,
|
2018-11-12 13:46:06 -05:00
|
|
|
GArray *reserved_crtcs,
|
2017-01-09 01:31:18 -05:00
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = logical_monitor_config->monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitorConfig *monitor_config = l->data;
|
|
|
|
|
|
|
|
if (!assign_monitor_crtcs (manager,
|
2020-03-11 04:53:17 -04:00
|
|
|
config,
|
2017-01-09 01:31:18 -05:00
|
|
|
logical_monitor_config,
|
|
|
|
monitor_config,
|
2020-02-25 14:30:46 -05:00
|
|
|
crtc_assignments, output_assignments,
|
2018-11-12 13:46:06 -05:00
|
|
|
reserved_crtcs, error))
|
2017-01-09 01:31:18 -05:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_monitor_config_manager_assign (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config,
|
2020-02-25 14:30:46 -05:00
|
|
|
GPtrArray **out_crtc_assignments,
|
|
|
|
GPtrArray **out_output_assignments,
|
2017-01-09 01:31:18 -05:00
|
|
|
GError **error)
|
|
|
|
{
|
2020-02-25 14:30:46 -05:00
|
|
|
GPtrArray *crtc_assignments;
|
|
|
|
GPtrArray *output_assignments;
|
2018-11-12 13:46:06 -05:00
|
|
|
GArray *reserved_crtcs;
|
2017-01-09 01:31:18 -05:00
|
|
|
GList *l;
|
|
|
|
|
2020-02-25 14:30:46 -05:00
|
|
|
crtc_assignments =
|
|
|
|
g_ptr_array_new_with_free_func ((GDestroyNotify) meta_crtc_assignment_free);
|
|
|
|
output_assignments =
|
|
|
|
g_ptr_array_new_with_free_func ((GDestroyNotify) meta_output_assignment_free);
|
2020-02-25 05:34:43 -05:00
|
|
|
reserved_crtcs = g_array_new (FALSE, FALSE, sizeof (uint64_t));
|
2018-11-12 13:46:06 -05:00
|
|
|
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
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;
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
GList *o;
|
|
|
|
|
|
|
|
monitor = meta_monitor_manager_get_monitor_from_spec (manager, monitor_spec);
|
|
|
|
|
|
|
|
for (o = meta_monitor_get_outputs (monitor); o; o = o->next)
|
|
|
|
{
|
|
|
|
MetaOutput *output = o->data;
|
|
|
|
MetaCrtc *crtc;
|
|
|
|
|
|
|
|
crtc = meta_output_get_assigned_crtc (output);
|
|
|
|
if (crtc)
|
2020-02-25 05:34:43 -05:00
|
|
|
{
|
|
|
|
uint64_t crtc_id = meta_crtc_get_id (crtc);
|
|
|
|
|
|
|
|
g_array_append_val (reserved_crtcs, crtc_id);
|
|
|
|
}
|
2018-11-12 13:46:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-09 01:31:18 -05:00
|
|
|
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
|
2020-03-11 04:53:17 -04:00
|
|
|
if (!assign_logical_monitor_crtcs (manager,
|
|
|
|
config, logical_monitor_config,
|
2020-02-25 14:30:46 -05:00
|
|
|
crtc_assignments, output_assignments,
|
2018-11-12 13:46:06 -05:00
|
|
|
reserved_crtcs, error))
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
2020-02-25 14:30:46 -05:00
|
|
|
g_ptr_array_free (crtc_assignments, TRUE);
|
|
|
|
g_ptr_array_free (output_assignments, TRUE);
|
2018-11-12 13:46:06 -05:00
|
|
|
g_array_free (reserved_crtcs, TRUE);
|
2017-01-09 01:31:18 -05:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 13:46:06 -05:00
|
|
|
g_array_free (reserved_crtcs, TRUE);
|
|
|
|
|
2020-02-25 14:30:46 -05:00
|
|
|
*out_crtc_assignments = crtc_assignments;
|
|
|
|
*out_output_assignments = output_assignments;
|
2017-01-09 01:31:18 -05:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-04-16 14:07:45 -04:00
|
|
|
static gboolean
|
|
|
|
is_lid_closed (MetaMonitorManager *monitor_manager)
|
|
|
|
{
|
|
|
|
MetaBackend *backend;
|
|
|
|
|
|
|
|
backend = meta_monitor_manager_get_backend (monitor_manager);
|
|
|
|
return meta_backend_is_lid_closed (backend);
|
|
|
|
}
|
|
|
|
|
2017-11-03 04:03:23 -04:00
|
|
|
MetaMonitorsConfigKey *
|
|
|
|
meta_create_monitors_config_key_for_current_state (MetaMonitorManager *monitor_manager)
|
2017-01-12 22:01:27 -05:00
|
|
|
{
|
|
|
|
MetaMonitorsConfigKey *config_key;
|
2020-04-15 18:28:05 -04:00
|
|
|
MetaMonitorSpec *laptop_monitor_spec;
|
2017-01-12 22:01:27 -05:00
|
|
|
GList *l;
|
|
|
|
GList *monitor_specs;
|
|
|
|
|
2020-04-15 18:28:05 -04:00
|
|
|
laptop_monitor_spec = NULL;
|
2017-01-12 22:01:27 -05:00
|
|
|
monitor_specs = NULL;
|
|
|
|
for (l = monitor_manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaMonitorSpec *monitor_spec;
|
|
|
|
|
2020-04-15 18:28:05 -04:00
|
|
|
if (meta_monitor_is_laptop_panel (monitor))
|
|
|
|
{
|
|
|
|
laptop_monitor_spec = meta_monitor_get_spec (monitor);
|
|
|
|
|
|
|
|
if (is_lid_closed (monitor_manager))
|
|
|
|
continue;
|
|
|
|
}
|
2017-01-12 22:01:27 -05:00
|
|
|
|
|
|
|
monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor));
|
|
|
|
monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
|
|
|
|
}
|
|
|
|
|
2020-04-15 18:28:05 -04:00
|
|
|
if (!monitor_specs && laptop_monitor_spec)
|
|
|
|
{
|
|
|
|
monitor_specs =
|
|
|
|
g_list_prepend (NULL, meta_monitor_spec_clone (laptop_monitor_spec));
|
|
|
|
}
|
|
|
|
|
2017-01-12 22:01:27 -05:00
|
|
|
if (!monitor_specs)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
monitor_specs = g_list_sort (monitor_specs,
|
|
|
|
(GCompareFunc) meta_monitor_spec_compare);
|
|
|
|
|
|
|
|
config_key = g_new0 (MetaMonitorsConfigKey, 1);
|
|
|
|
*config_key = (MetaMonitorsConfigKey) {
|
|
|
|
.monitor_specs = monitor_specs
|
|
|
|
};
|
|
|
|
|
|
|
|
return config_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_get_stored (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
2017-08-10 03:12:41 -04:00
|
|
|
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
|
2017-01-12 22:01:27 -05:00
|
|
|
MetaMonitorsConfigKey *config_key;
|
|
|
|
MetaMonitorsConfig *config;
|
2017-08-10 03:12:41 -04:00
|
|
|
GError *error = NULL;
|
2017-01-12 22:01:27 -05:00
|
|
|
|
2017-11-03 04:03:23 -04:00
|
|
|
config_key =
|
|
|
|
meta_create_monitors_config_key_for_current_state (monitor_manager);
|
2017-01-12 22:01:27 -05:00
|
|
|
if (!config_key)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
config = meta_monitor_config_store_lookup (config_manager->config_store,
|
|
|
|
config_key);
|
|
|
|
meta_monitors_config_key_free (config_key);
|
|
|
|
|
2017-08-10 03:12:41 -04:00
|
|
|
if (!config)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (config->flags & META_MONITORS_CONFIG_FLAG_MIGRATED)
|
|
|
|
{
|
|
|
|
if (!meta_finish_monitors_config_migration (monitor_manager, config,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to finish monitors config migration: %s",
|
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
meta_monitor_config_store_remove (config_manager->config_store, config);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-12 22:01:27 -05:00
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
2017-01-10 00:17:16 -05:00
|
|
|
typedef enum _MonitorMatchRule
|
|
|
|
{
|
|
|
|
MONITOR_MATCH_ALL = 0,
|
2019-03-27 01:22:15 -04:00
|
|
|
MONITOR_MATCH_EXTERNAL = (1 << 0),
|
|
|
|
MONITOR_MATCH_BUILTIN = (1 << 1),
|
|
|
|
MONITOR_MATCH_VISIBLE = (1 << 2),
|
|
|
|
MONITOR_MATCH_WITH_SUGGESTED_POSITION = (1 << 3),
|
2019-04-02 18:51:34 -04:00
|
|
|
MONITOR_MATCH_PRIMARY = (1 << 4),
|
|
|
|
MONITOR_MATCH_ALLOW_FALLBACK = (1 << 5),
|
2017-01-10 00:17:16 -05:00
|
|
|
} MonitorMatchRule;
|
|
|
|
|
2019-03-27 01:22:15 -04:00
|
|
|
static gboolean
|
|
|
|
monitor_matches_rule (MetaMonitor *monitor,
|
|
|
|
MetaMonitorManager *monitor_manager,
|
|
|
|
MonitorMatchRule match_rule)
|
|
|
|
{
|
|
|
|
if (!monitor)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (match_rule & MONITOR_MATCH_BUILTIN)
|
|
|
|
{
|
|
|
|
if (!meta_monitor_is_laptop_panel (monitor))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if (match_rule & MONITOR_MATCH_EXTERNAL)
|
|
|
|
{
|
|
|
|
if (meta_monitor_is_laptop_panel (monitor))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match_rule & MONITOR_MATCH_VISIBLE)
|
|
|
|
{
|
|
|
|
if (meta_monitor_is_laptop_panel (monitor) &&
|
|
|
|
is_lid_closed (monitor_manager))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match_rule & MONITOR_MATCH_WITH_SUGGESTED_POSITION)
|
|
|
|
{
|
|
|
|
if (!meta_monitor_get_suggested_position (monitor, NULL, NULL))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GList *
|
|
|
|
find_monitors (MetaMonitorManager *monitor_manager,
|
2019-04-03 10:25:10 -04:00
|
|
|
MonitorMatchRule match_rule,
|
|
|
|
MetaMonitor *not_this_one)
|
2019-03-27 01:22:15 -04:00
|
|
|
{
|
|
|
|
GList *result = NULL;
|
|
|
|
GList *monitors, *l;
|
|
|
|
|
|
|
|
monitors = meta_monitor_manager_get_monitors (monitor_manager);
|
|
|
|
for (l = g_list_last (monitors); l; l = l->prev)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
2019-04-03 10:25:10 -04:00
|
|
|
if (not_this_one && monitor == not_this_one)
|
|
|
|
continue;
|
|
|
|
|
2019-03-27 01:22:15 -04:00
|
|
|
if (monitor_matches_rule (monitor, monitor_manager, match_rule))
|
|
|
|
result = g_list_prepend (result, monitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
static MetaMonitor *
|
2017-01-10 00:17:16 -05:00
|
|
|
find_monitor_with_highest_preferred_resolution (MetaMonitorManager *monitor_manager,
|
|
|
|
MonitorMatchRule match_rule)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
2019-03-27 01:22:15 -04:00
|
|
|
g_autoptr (GList) monitors = NULL;
|
2017-01-09 01:31:18 -05:00
|
|
|
GList *l;
|
|
|
|
int largest_area = 0;
|
|
|
|
MetaMonitor *largest_monitor = NULL;
|
|
|
|
|
2019-04-03 10:25:10 -04:00
|
|
|
monitors = find_monitors (monitor_manager, match_rule, NULL);
|
2017-01-09 01:31:18 -05:00
|
|
|
for (l = monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
int width, height;
|
|
|
|
int area;
|
|
|
|
|
|
|
|
mode = meta_monitor_get_preferred_mode (monitor);
|
|
|
|
meta_monitor_mode_get_resolution (mode, &width, &height);
|
|
|
|
area = width * height;
|
|
|
|
|
|
|
|
if (area > largest_area)
|
|
|
|
{
|
|
|
|
largest_area = area;
|
|
|
|
largest_monitor = monitor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return largest_monitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-01-10 00:17:16 -05:00
|
|
|
* Try to find the primary monitor. The priority of classification is:
|
|
|
|
*
|
|
|
|
* 1. Find the primary monitor as reported by the underlying system,
|
|
|
|
* 2. Find the laptop panel
|
|
|
|
* 3. Find the external monitor with highest resolution
|
|
|
|
*
|
|
|
|
* If the laptop lid is closed, exclude the laptop panel from possible
|
|
|
|
* alternatives, except if no other alternatives exist.
|
2017-01-09 01:31:18 -05:00
|
|
|
*/
|
|
|
|
static MetaMonitor *
|
2019-03-27 01:22:15 -04:00
|
|
|
find_primary_monitor (MetaMonitorManager *monitor_manager,
|
|
|
|
MonitorMatchRule match_rule)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
|
2019-03-27 01:22:15 -04:00
|
|
|
monitor = meta_monitor_manager_get_primary_monitor (monitor_manager);
|
|
|
|
if (monitor_matches_rule (monitor, monitor_manager, match_rule))
|
|
|
|
return monitor;
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2019-03-27 01:22:15 -04:00
|
|
|
monitor = meta_monitor_manager_get_laptop_panel (monitor_manager);
|
|
|
|
if (monitor_matches_rule (monitor, monitor_manager, match_rule))
|
|
|
|
return monitor;
|
|
|
|
|
|
|
|
monitor = find_monitor_with_highest_preferred_resolution (monitor_manager,
|
|
|
|
match_rule);
|
|
|
|
if (monitor)
|
|
|
|
return monitor;
|
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
if (match_rule & MONITOR_MATCH_ALLOW_FALLBACK)
|
|
|
|
return find_monitor_with_highest_preferred_resolution (monitor_manager,
|
|
|
|
MONITOR_MATCH_ALL);
|
|
|
|
|
|
|
|
return NULL;
|
2017-01-09 01:31:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static MetaMonitorConfig *
|
|
|
|
create_monitor_config (MetaMonitor *monitor,
|
|
|
|
MetaMonitorMode *mode)
|
|
|
|
{
|
|
|
|
MetaMonitorSpec *monitor_spec;
|
|
|
|
MetaMonitorModeSpec *mode_spec;
|
|
|
|
MetaMonitorConfig *monitor_config;
|
|
|
|
|
|
|
|
monitor_spec = meta_monitor_get_spec (monitor);
|
|
|
|
mode_spec = meta_monitor_mode_get_spec (mode);
|
|
|
|
|
|
|
|
monitor_config = g_new0 (MetaMonitorConfig, 1);
|
|
|
|
*monitor_config = (MetaMonitorConfig) {
|
|
|
|
.monitor_spec = meta_monitor_spec_clone (monitor_spec),
|
2021-02-04 12:45:59 -05:00
|
|
|
.mode_spec = g_memdup2 (mode_spec, sizeof (MetaMonitorModeSpec)),
|
2017-02-14 05:19:09 -05:00
|
|
|
.enable_underscanning = meta_monitor_is_underscanning (monitor)
|
2017-01-09 01:31:18 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
return monitor_config;
|
|
|
|
}
|
|
|
|
|
2019-12-04 10:34:38 -05:00
|
|
|
static MetaMonitorTransform
|
|
|
|
get_monitor_transform (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaMonitor *monitor)
|
|
|
|
{
|
|
|
|
MetaOrientationManager *orientation_manager;
|
2020-05-04 14:09:28 -04:00
|
|
|
MetaOrientation orientation;
|
2019-12-04 10:34:38 -05:00
|
|
|
MetaBackend *backend;
|
|
|
|
|
2021-07-22 21:58:51 -04:00
|
|
|
if (!meta_monitor_is_laptop_panel (monitor) ||
|
|
|
|
!meta_monitor_manager_get_panel_orientation_managed (monitor_manager))
|
2019-12-04 10:34:38 -05:00
|
|
|
return META_MONITOR_TRANSFORM_NORMAL;
|
|
|
|
|
|
|
|
backend = meta_monitor_manager_get_backend (monitor_manager);
|
|
|
|
orientation_manager = meta_backend_get_orientation_manager (backend);
|
2020-05-04 14:09:28 -04:00
|
|
|
orientation = meta_orientation_manager_get_orientation (orientation_manager);
|
2019-12-04 10:34:38 -05:00
|
|
|
|
2020-05-04 14:09:28 -04:00
|
|
|
return meta_monitor_transform_from_orientation (orientation);
|
2019-12-04 10:34:38 -05:00
|
|
|
}
|
|
|
|
|
2022-06-23 06:41:22 -04:00
|
|
|
static void
|
|
|
|
scale_logical_monitor_width (MetaLogicalMonitorLayoutMode layout_mode,
|
|
|
|
float scale,
|
|
|
|
int mode_width,
|
|
|
|
int mode_height,
|
|
|
|
int *width,
|
|
|
|
int *height)
|
|
|
|
{
|
|
|
|
switch (layout_mode)
|
|
|
|
{
|
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
|
|
|
|
*width = (int) roundf (mode_width / scale);
|
|
|
|
*height = (int) roundf (mode_height / scale);
|
|
|
|
return;
|
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
|
|
|
|
*width = mode_width;
|
|
|
|
*height = mode_height;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
static MetaLogicalMonitorConfig *
|
2017-02-24 05:10:52 -05:00
|
|
|
create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaMonitor *monitor,
|
|
|
|
int x,
|
|
|
|
int y,
|
2019-04-03 10:11:21 -04:00
|
|
|
float scale,
|
2017-02-24 05:10:52 -05:00
|
|
|
MetaLogicalMonitorLayoutMode layout_mode)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
int width, height;
|
2019-12-04 10:34:38 -05:00
|
|
|
MetaMonitorTransform transform;
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaMonitorConfig *monitor_config;
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config;
|
|
|
|
|
|
|
|
mode = meta_monitor_get_preferred_mode (monitor);
|
|
|
|
meta_monitor_mode_get_resolution (mode, &width, &height);
|
2022-06-23 06:41:22 -04:00
|
|
|
scale_logical_monitor_width (layout_mode, scale,
|
|
|
|
width, height, &width, &height);
|
2017-02-24 05:10:52 -05:00
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
monitor_config = create_monitor_config (monitor, mode);
|
|
|
|
|
2019-12-04 10:34:38 -05:00
|
|
|
transform = get_monitor_transform (monitor_manager, monitor);
|
|
|
|
if (meta_monitor_transform_is_rotated (transform))
|
|
|
|
{
|
|
|
|
int temp = width;
|
|
|
|
width = height;
|
|
|
|
height = temp;
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
|
|
|
|
*logical_monitor_config = (MetaLogicalMonitorConfig) {
|
|
|
|
.layout = (MetaRectangle) {
|
|
|
|
.x = x,
|
|
|
|
.y = y,
|
|
|
|
.width = width,
|
|
|
|
.height = height
|
|
|
|
},
|
2019-12-04 10:34:38 -05:00
|
|
|
.transform = transform,
|
2017-01-19 04:23:48 -05:00
|
|
|
.scale = scale,
|
2017-01-09 01:31:18 -05:00
|
|
|
.monitor_configs = g_list_append (NULL, monitor_config)
|
|
|
|
};
|
|
|
|
|
|
|
|
return logical_monitor_config;
|
|
|
|
}
|
|
|
|
|
2019-04-03 10:11:21 -04:00
|
|
|
static float
|
|
|
|
compute_scale_for_monitor (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaMonitor *monitor,
|
|
|
|
MetaMonitor *primary_monitor)
|
|
|
|
{
|
|
|
|
MetaMonitor *target_monitor = monitor;
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode;
|
|
|
|
MetaMonitorMode *monitor_mode;
|
|
|
|
|
|
|
|
if ((meta_monitor_manager_get_capabilities (monitor_manager) &
|
|
|
|
META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED) &&
|
|
|
|
primary_monitor)
|
|
|
|
target_monitor = primary_monitor;
|
|
|
|
|
|
|
|
layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
|
|
|
|
monitor_mode = meta_monitor_get_preferred_mode (target_monitor);
|
|
|
|
|
|
|
|
return meta_monitor_manager_calculate_monitor_mode_scale (monitor_manager,
|
|
|
|
layout_mode,
|
|
|
|
target_monitor,
|
|
|
|
monitor_mode);
|
|
|
|
}
|
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
typedef enum _MonitorPositioningMode
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
2019-04-02 18:51:34 -04:00
|
|
|
MONITOR_POSITIONING_LINEAR,
|
|
|
|
MONITOR_POSITIONING_SUGGESTED,
|
|
|
|
} MonitorPositioningMode;
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
static gboolean
|
|
|
|
verify_suggested_monitors_config (GList *logical_monitor_configs)
|
|
|
|
{
|
|
|
|
g_autoptr (GList) region = NULL;
|
|
|
|
GList *l;
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
2019-04-02 18:51:34 -04:00
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
MetaRectangle *rect = &logical_monitor_config->layout;
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
if (meta_rectangle_overlaps_with_region (region, rect))
|
|
|
|
{
|
|
|
|
g_warning ("Suggested monitor config has overlapping region, "
|
|
|
|
"rejecting");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
region = g_list_prepend (region, rect);
|
2017-01-09 01:31:18 -05:00
|
|
|
}
|
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
for (l = region; region->next && l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaRectangle *rect = l->data;
|
2017-02-24 05:10:52 -05:00
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
if (!meta_rectangle_is_adjacent_to_any_in_region (region, rect))
|
|
|
|
{
|
|
|
|
g_warning ("Suggested monitor config has monitors with no "
|
|
|
|
"neighbors, rejecting");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
return TRUE;
|
2017-01-09 01:31:18 -05:00
|
|
|
}
|
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
static MetaMonitorsConfig *
|
|
|
|
create_monitors_config (MetaMonitorConfigManager *config_manager,
|
|
|
|
MonitorMatchRule match_rule,
|
|
|
|
MonitorPositioningMode positioning,
|
|
|
|
MetaMonitorsConfigFlag config_flags)
|
2017-01-09 02:38:17 -05:00
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
|
2019-03-27 01:22:15 -04:00
|
|
|
g_autoptr (GList) monitors = NULL;
|
2019-04-02 18:51:34 -04:00
|
|
|
g_autolist (MetaLogicalMonitorConfig) logical_monitor_configs = NULL;
|
2017-01-09 02:38:17 -05:00
|
|
|
MetaMonitor *primary_monitor;
|
2017-02-24 05:10:52 -05:00
|
|
|
MetaLogicalMonitorLayoutMode layout_mode;
|
2019-04-03 10:11:21 -04:00
|
|
|
float scale;
|
2017-01-09 02:38:17 -05:00
|
|
|
GList *l;
|
2019-03-27 01:22:15 -04:00
|
|
|
int x, y;
|
2017-01-09 02:38:17 -05:00
|
|
|
|
2019-03-27 01:22:15 -04:00
|
|
|
primary_monitor = find_primary_monitor (monitor_manager,
|
2019-04-02 18:51:34 -04:00
|
|
|
match_rule | MONITOR_MATCH_VISIBLE);
|
2017-01-09 02:38:17 -05:00
|
|
|
if (!primary_monitor)
|
|
|
|
return NULL;
|
|
|
|
|
2019-04-03 10:25:10 -04:00
|
|
|
x = y = 0;
|
2017-02-24 05:10:52 -05:00
|
|
|
layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
|
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
if (!(match_rule & MONITOR_MATCH_PRIMARY))
|
2019-04-03 10:25:10 -04:00
|
|
|
monitors = find_monitors (monitor_manager, match_rule, primary_monitor);
|
|
|
|
|
|
|
|
/* The primary monitor needs to be at the head of the list for the
|
|
|
|
* linear positioning to be correct.
|
|
|
|
*/
|
|
|
|
monitors = g_list_prepend (monitors, primary_monitor);
|
2019-04-02 18:51:34 -04:00
|
|
|
|
2017-01-09 02:38:17 -05:00
|
|
|
for (l = monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config;
|
2019-04-03 10:25:10 -04:00
|
|
|
gboolean has_suggested_position;
|
2017-01-09 02:38:17 -05:00
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
switch (positioning)
|
|
|
|
{
|
|
|
|
case MONITOR_POSITIONING_LINEAR:
|
|
|
|
break;
|
|
|
|
case MONITOR_POSITIONING_SUGGESTED:
|
|
|
|
has_suggested_position =
|
|
|
|
meta_monitor_get_suggested_position (monitor, &x, &y);
|
|
|
|
g_assert (has_suggested_position);
|
|
|
|
break;
|
|
|
|
}
|
2017-01-09 02:38:17 -05:00
|
|
|
|
2019-04-03 10:11:21 -04:00
|
|
|
scale = compute_scale_for_monitor (monitor_manager, monitor,
|
|
|
|
primary_monitor);
|
2017-01-09 02:38:17 -05:00
|
|
|
logical_monitor_config =
|
2017-01-20 02:07:12 -05:00
|
|
|
create_preferred_logical_monitor_config (monitor_manager,
|
|
|
|
monitor,
|
2019-04-03 10:11:21 -04:00
|
|
|
x, y, scale,
|
2017-02-24 05:10:52 -05:00
|
|
|
layout_mode);
|
2019-04-03 10:25:10 -04:00
|
|
|
logical_monitor_config->is_primary = (monitor == primary_monitor);
|
2017-01-09 02:38:17 -05:00
|
|
|
logical_monitor_configs = g_list_append (logical_monitor_configs,
|
|
|
|
logical_monitor_config);
|
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
x += logical_monitor_config->layout.width;
|
2017-01-09 02:38:17 -05:00
|
|
|
}
|
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
if (positioning == MONITOR_POSITIONING_SUGGESTED)
|
2019-03-15 19:22:31 -04:00
|
|
|
{
|
2019-04-02 18:51:34 -04:00
|
|
|
if (!verify_suggested_monitors_config (logical_monitor_configs))
|
|
|
|
return NULL;
|
2019-03-15 19:22:31 -04:00
|
|
|
}
|
|
|
|
|
2017-09-28 11:34:33 -04:00
|
|
|
return meta_monitors_config_new (monitor_manager,
|
2019-04-02 18:51:34 -04:00
|
|
|
g_steal_pointer (&logical_monitor_configs),
|
2017-09-28 11:34:33 -04:00
|
|
|
layout_mode,
|
2019-04-02 18:51:34 -04:00
|
|
|
config_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
|
|
|
return create_monitors_config (config_manager,
|
|
|
|
MONITOR_MATCH_VISIBLE |
|
|
|
|
MONITOR_MATCH_ALLOW_FALLBACK,
|
|
|
|
MONITOR_POSITIONING_LINEAR,
|
|
|
|
META_MONITORS_CONFIG_FLAG_NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
|
|
|
return create_monitors_config (config_manager,
|
|
|
|
MONITOR_MATCH_PRIMARY |
|
|
|
|
MONITOR_MATCH_ALLOW_FALLBACK,
|
|
|
|
MONITOR_POSITIONING_LINEAR,
|
|
|
|
META_MONITORS_CONFIG_FLAG_NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
|
|
|
return create_monitors_config (config_manager,
|
|
|
|
MONITOR_MATCH_WITH_SUGGESTED_POSITION,
|
|
|
|
MONITOR_POSITIONING_SUGGESTED,
|
|
|
|
META_MONITORS_CONFIG_FLAG_NONE);
|
2017-01-09 02:38:17 -05:00
|
|
|
}
|
|
|
|
|
2019-12-11 04:46:31 -05:00
|
|
|
static GList *
|
|
|
|
clone_monitor_config_list (GList *monitor_configs_in)
|
|
|
|
{
|
|
|
|
MetaMonitorConfig *monitor_config_in;
|
|
|
|
MetaMonitorConfig *monitor_config_out;
|
|
|
|
GList *monitor_configs_out = NULL;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = monitor_configs_in; l; l = l->next)
|
|
|
|
{
|
|
|
|
monitor_config_in = l->data;
|
|
|
|
monitor_config_out = g_new0 (MetaMonitorConfig, 1);
|
|
|
|
*monitor_config_out = (MetaMonitorConfig) {
|
|
|
|
.monitor_spec = meta_monitor_spec_clone (monitor_config_in->monitor_spec),
|
2021-02-04 12:45:59 -05:00
|
|
|
.mode_spec = g_memdup2 (monitor_config_in->mode_spec,
|
|
|
|
sizeof (MetaMonitorModeSpec)),
|
2019-12-11 04:46:31 -05:00
|
|
|
.enable_underscanning = monitor_config_in->enable_underscanning
|
|
|
|
};
|
|
|
|
monitor_configs_out =
|
|
|
|
g_list_append (monitor_configs_out, monitor_config_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
return monitor_configs_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GList *
|
|
|
|
clone_logical_monitor_config_list (GList *logical_monitor_configs_in)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config_in;
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config_out;
|
|
|
|
GList *logical_monitor_configs_out = NULL;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = logical_monitor_configs_in; l; l = l->next)
|
|
|
|
{
|
|
|
|
logical_monitor_config_in = l->data;
|
|
|
|
|
|
|
|
logical_monitor_config_out =
|
2021-02-04 12:45:59 -05:00
|
|
|
g_memdup2 (logical_monitor_config_in,
|
|
|
|
sizeof (MetaLogicalMonitorConfig));
|
2019-12-11 04:46:31 -05:00
|
|
|
logical_monitor_config_out->monitor_configs =
|
|
|
|
clone_monitor_config_list (logical_monitor_config_in->monitor_configs);
|
|
|
|
|
|
|
|
logical_monitor_configs_out =
|
|
|
|
g_list_append (logical_monitor_configs_out, logical_monitor_config_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
return logical_monitor_configs_out;
|
|
|
|
}
|
|
|
|
|
2019-12-11 05:34:34 -05:00
|
|
|
static MetaLogicalMonitorConfig *
|
2021-07-30 10:12:08 -04:00
|
|
|
find_logical_config_for_builtin_monitor (MetaMonitorConfigManager *config_manager,
|
|
|
|
GList *logical_monitor_configs)
|
2019-12-11 05:34:34 -05:00
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config;
|
|
|
|
MetaMonitorConfig *monitor_config;
|
|
|
|
MetaMonitor *panel;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
panel = meta_monitor_manager_get_laptop_panel (config_manager->monitor_manager);
|
2021-07-30 08:12:40 -04:00
|
|
|
if (panel)
|
2019-12-11 05:34:34 -05:00
|
|
|
{
|
|
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
logical_monitor_config = l->data;
|
|
|
|
/*
|
|
|
|
* We only want to return the config for the panel if it is
|
|
|
|
* configured on its own, so we skip configs which contain clones.
|
|
|
|
*/
|
|
|
|
if (g_list_length (logical_monitor_config->monitor_configs) != 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
monitor_config = logical_monitor_config->monitor_configs->data;
|
|
|
|
if (meta_monitor_spec_equals (meta_monitor_get_spec (panel),
|
|
|
|
monitor_config->monitor_spec))
|
2021-07-30 08:12:40 -04:00
|
|
|
{
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
|
|
|
|
mode = meta_monitor_get_mode_from_spec (panel,
|
|
|
|
monitor_config->mode_spec);
|
|
|
|
if (mode)
|
|
|
|
return logical_monitor_config;
|
|
|
|
}
|
2019-12-11 05:34:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-04-28 11:56:18 -04:00
|
|
|
static MetaMonitorsConfig *
|
|
|
|
create_for_builtin_display_rotation (MetaMonitorConfigManager *config_manager,
|
2020-05-01 09:24:34 -04:00
|
|
|
MetaMonitorsConfig *base_config,
|
2017-04-28 11:56:18 -04:00
|
|
|
gboolean rotate,
|
|
|
|
MetaMonitorTransform transform)
|
|
|
|
{
|
2017-09-28 11:34:33 -04:00
|
|
|
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
|
2017-04-28 11:56:18 -04:00
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config;
|
|
|
|
MetaLogicalMonitorConfig *current_logical_monitor_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 09:53:55 -04:00
|
|
|
MetaMonitorsConfig *config;
|
2019-12-11 05:34:34 -05:00
|
|
|
GList *logical_monitor_configs, *current_configs;
|
2017-09-28 11:34:33 -04:00
|
|
|
MetaLogicalMonitorLayoutMode layout_mode;
|
2017-04-28 11:56:18 -04:00
|
|
|
|
2020-05-01 09:24:34 -04:00
|
|
|
g_return_val_if_fail (base_config, NULL);
|
2017-04-28 11:56:18 -04:00
|
|
|
|
2020-05-01 09:24:34 -04:00
|
|
|
current_configs = base_config->logical_monitor_configs;
|
2019-12-11 05:34:34 -05:00
|
|
|
current_logical_monitor_config =
|
2021-07-30 10:12:08 -04:00
|
|
|
find_logical_config_for_builtin_monitor (config_manager, current_configs);
|
2019-12-11 05:34:34 -05:00
|
|
|
if (!current_logical_monitor_config)
|
2017-04-28 11:56:18 -04:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (rotate)
|
|
|
|
transform = (current_logical_monitor_config->transform + 1) % META_MONITOR_TRANSFORM_FLIPPED;
|
2017-10-23 05:50:18 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The transform coming from the accelerometer should be applied to
|
|
|
|
* the crtc as is, without taking panel-orientation into account, this
|
|
|
|
* is done so that non panel-orientation aware desktop environments do the
|
|
|
|
* right thing. Mutter corrects for panel-orientation when applying the
|
|
|
|
* transform from a logical-monitor-config, so we must convert here.
|
|
|
|
*/
|
|
|
|
MetaMonitor *panel =
|
|
|
|
meta_monitor_manager_get_laptop_panel (config_manager->monitor_manager);
|
|
|
|
|
|
|
|
transform = meta_monitor_crtc_to_logical_transform (panel, transform);
|
|
|
|
}
|
2017-04-28 11:56:18 -04:00
|
|
|
|
|
|
|
if (current_logical_monitor_config->transform == transform)
|
|
|
|
return NULL;
|
|
|
|
|
2019-12-11 04:46:31 -05:00
|
|
|
logical_monitor_configs =
|
2020-05-01 09:24:34 -04:00
|
|
|
clone_logical_monitor_config_list (base_config->logical_monitor_configs);
|
2019-12-11 05:34:34 -05:00
|
|
|
logical_monitor_config =
|
2021-07-30 10:12:08 -04:00
|
|
|
find_logical_config_for_builtin_monitor (config_manager,
|
|
|
|
logical_monitor_configs);
|
2017-04-28 11:56:18 -04:00
|
|
|
logical_monitor_config->transform = transform;
|
|
|
|
|
2017-09-17 06:07:12 -04:00
|
|
|
if (meta_monitor_transform_is_rotated (current_logical_monitor_config->transform) !=
|
|
|
|
meta_monitor_transform_is_rotated (logical_monitor_config->transform))
|
|
|
|
{
|
|
|
|
int temp = logical_monitor_config->layout.width;
|
|
|
|
logical_monitor_config->layout.width = logical_monitor_config->layout.height;
|
|
|
|
logical_monitor_config->layout.height = temp;
|
|
|
|
}
|
|
|
|
|
2020-05-01 09:24:34 -04:00
|
|
|
layout_mode = base_config->layout_mode;
|
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 09:53:55 -04:00
|
|
|
config = meta_monitors_config_new (monitor_manager,
|
|
|
|
logical_monitor_configs,
|
|
|
|
layout_mode,
|
|
|
|
META_MONITORS_CONFIG_FLAG_NONE);
|
|
|
|
meta_monitors_config_set_parent_config (config, base_config);
|
|
|
|
|
|
|
|
return config;
|
2017-04-28 11:56:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_create_for_orientation (MetaMonitorConfigManager *config_manager,
|
2020-05-01 09:24:34 -04:00
|
|
|
MetaMonitorsConfig *base_config,
|
2017-04-28 11:56:18 -04:00
|
|
|
MetaMonitorTransform transform)
|
|
|
|
{
|
2020-05-01 09:24:34 -04:00
|
|
|
return create_for_builtin_display_rotation (config_manager, base_config,
|
|
|
|
FALSE, transform);
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_create_for_builtin_orientation (MetaMonitorConfigManager *config_manager,
|
|
|
|
MetaMonitorsConfig *base_config)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
|
|
|
|
MetaMonitorTransform current_transform;
|
|
|
|
MetaMonitor *laptop_panel;
|
|
|
|
|
|
|
|
g_return_val_if_fail (
|
|
|
|
meta_monitor_manager_get_panel_orientation_managed (monitor_manager), NULL);
|
|
|
|
|
|
|
|
laptop_panel = meta_monitor_manager_get_laptop_panel (monitor_manager);
|
|
|
|
current_transform = get_monitor_transform (monitor_manager, laptop_panel);
|
|
|
|
|
|
|
|
return create_for_builtin_display_rotation (config_manager, base_config,
|
|
|
|
FALSE, current_transform);
|
2017-04-28 11:56:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_create_for_rotate_monitor (MetaMonitorConfigManager *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 09:53:55 -04:00
|
|
|
if (!config_manager->current_config)
|
|
|
|
return NULL;
|
|
|
|
|
2020-05-01 09:24:34 -04:00
|
|
|
return create_for_builtin_display_rotation (config_manager,
|
|
|
|
config_manager->current_config,
|
|
|
|
TRUE,
|
|
|
|
META_MONITOR_TRANSFORM_NORMAL);
|
2017-04-28 11:56:18 -04:00
|
|
|
}
|
|
|
|
|
2019-04-02 18:51:34 -04:00
|
|
|
static MetaMonitorsConfig *
|
|
|
|
create_monitors_switch_config (MetaMonitorConfigManager *config_manager,
|
|
|
|
MonitorMatchRule match_rule,
|
|
|
|
MonitorPositioningMode positioning,
|
|
|
|
MetaMonitorsConfigFlag config_flags,
|
|
|
|
MetaMonitorSwitchConfigType switch_config)
|
|
|
|
{
|
|
|
|
MetaMonitorsConfig *monitors_config;
|
|
|
|
|
|
|
|
monitors_config = create_monitors_config (config_manager, match_rule,
|
|
|
|
positioning, config_flags);
|
|
|
|
|
|
|
|
if (!monitors_config)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
meta_monitors_config_set_switch_config (monitors_config, switch_config);
|
|
|
|
return monitors_config;
|
|
|
|
}
|
|
|
|
|
2017-06-07 12:38:10 -04:00
|
|
|
static MetaMonitorsConfig *
|
|
|
|
create_for_switch_config_all_mirror (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
|
2022-06-23 06:48:57 -04:00
|
|
|
MetaMonitor *primary_monitor;
|
2017-08-10 03:12:41 -04:00
|
|
|
MetaLogicalMonitorLayoutMode layout_mode;
|
2017-06-07 12:38:10 -04:00
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = NULL;
|
2017-09-28 11:34:33 -04:00
|
|
|
GList *logical_monitor_configs;
|
2017-06-07 12:38:10 -04:00
|
|
|
GList *monitor_configs = NULL;
|
|
|
|
gint common_mode_w = 0, common_mode_h = 0;
|
|
|
|
float best_scale = 1.0;
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
GList *modes;
|
|
|
|
GList *monitors;
|
|
|
|
GList *l;
|
2020-08-05 23:52:32 -04:00
|
|
|
MetaMonitorsConfig *monitors_config;
|
2022-06-23 06:42:55 -04:00
|
|
|
int width, height;
|
2017-06-07 12:38:10 -04:00
|
|
|
|
2022-06-23 06:48:57 -04:00
|
|
|
primary_monitor = find_primary_monitor (monitor_manager,
|
|
|
|
MONITOR_MATCH_ALLOW_FALLBACK);
|
|
|
|
if (!primary_monitor)
|
|
|
|
return NULL;
|
|
|
|
|
2017-06-10 10:10:57 -04:00
|
|
|
layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
|
2017-06-07 12:38:10 -04:00
|
|
|
monitors = meta_monitor_manager_get_monitors (monitor_manager);
|
|
|
|
monitor = monitors->data;
|
|
|
|
modes = meta_monitor_get_modes (monitor);
|
|
|
|
for (l = modes; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitorMode *mode = l->data;
|
|
|
|
gboolean common_mode_size = TRUE;
|
|
|
|
gint mode_w, mode_h;
|
|
|
|
GList *ll;
|
|
|
|
|
|
|
|
meta_monitor_mode_get_resolution (mode, &mode_w, &mode_h);
|
|
|
|
|
|
|
|
for (ll = monitors->next; ll; ll = ll->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor_b = ll->data;
|
|
|
|
gboolean have_same_mode_size = FALSE;
|
|
|
|
GList *mm;
|
|
|
|
|
|
|
|
for (mm = meta_monitor_get_modes (monitor_b); mm; mm = mm->next)
|
|
|
|
{
|
|
|
|
MetaMonitorMode *mode_b = mm->data;
|
|
|
|
gint mode_b_w, mode_b_h;
|
|
|
|
|
|
|
|
meta_monitor_mode_get_resolution (mode_b, &mode_b_w, &mode_b_h);
|
|
|
|
|
|
|
|
if (mode_w == mode_b_w &&
|
|
|
|
mode_h == mode_b_h)
|
|
|
|
{
|
|
|
|
have_same_mode_size = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!have_same_mode_size)
|
|
|
|
{
|
|
|
|
common_mode_size = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (common_mode_size &&
|
|
|
|
common_mode_w * common_mode_h < mode_w * mode_h)
|
|
|
|
{
|
|
|
|
common_mode_w = mode_w;
|
|
|
|
common_mode_h = mode_h;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (common_mode_w == 0 || common_mode_h == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (l = monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaMonitorMode *mode = NULL;
|
|
|
|
GList *ll;
|
|
|
|
float scale;
|
|
|
|
|
|
|
|
for (ll = meta_monitor_get_modes (monitor); ll; ll = ll->next)
|
|
|
|
{
|
|
|
|
gint mode_w, mode_h;
|
|
|
|
|
|
|
|
mode = ll->data;
|
|
|
|
meta_monitor_mode_get_resolution (mode, &mode_w, &mode_h);
|
|
|
|
|
|
|
|
if (mode_w == common_mode_w && mode_h == common_mode_h)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mode)
|
|
|
|
continue;
|
|
|
|
|
2022-07-26 18:25:22 -04:00
|
|
|
scale = compute_scale_for_monitor (monitor_manager, monitor,
|
2022-06-23 06:48:57 -04:00
|
|
|
primary_monitor);
|
2017-06-07 12:38:10 -04:00
|
|
|
best_scale = MAX (best_scale, scale);
|
|
|
|
monitor_configs = g_list_prepend (monitor_configs, create_monitor_config (monitor, mode));
|
|
|
|
}
|
|
|
|
|
2022-06-23 06:42:55 -04:00
|
|
|
scale_logical_monitor_width (layout_mode, best_scale,
|
|
|
|
common_mode_w, common_mode_h,
|
|
|
|
&width, &height);
|
|
|
|
|
2017-06-07 12:38:10 -04:00
|
|
|
logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
|
|
|
|
*logical_monitor_config = (MetaLogicalMonitorConfig) {
|
|
|
|
.layout = (MetaRectangle) {
|
|
|
|
.x = 0,
|
|
|
|
.y = 0,
|
2022-06-23 06:42:55 -04:00
|
|
|
.width = width,
|
|
|
|
.height = height
|
2017-06-07 12:38:10 -04:00
|
|
|
},
|
|
|
|
.scale = best_scale,
|
2022-06-23 06:44:21 -04:00
|
|
|
.monitor_configs = monitor_configs,
|
|
|
|
.is_primary = TRUE,
|
2017-06-07 12:38:10 -04:00
|
|
|
};
|
|
|
|
|
2017-09-28 11:34:33 -04:00
|
|
|
logical_monitor_configs = g_list_append (NULL, logical_monitor_config);
|
2020-08-05 23:52:32 -04:00
|
|
|
monitors_config = meta_monitors_config_new (monitor_manager,
|
|
|
|
logical_monitor_configs,
|
|
|
|
layout_mode,
|
|
|
|
META_MONITORS_CONFIG_FLAG_NONE);
|
|
|
|
|
|
|
|
if (monitors_config)
|
|
|
|
meta_monitors_config_set_switch_config (monitors_config, META_MONITOR_SWITCH_CONFIG_ALL_MIRROR);
|
|
|
|
|
|
|
|
return monitors_config;
|
2017-06-07 12:38:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static MetaMonitorsConfig *
|
|
|
|
create_for_switch_config_external (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
2019-04-02 18:51:34 -04:00
|
|
|
return create_monitors_switch_config (config_manager,
|
|
|
|
MONITOR_MATCH_EXTERNAL,
|
|
|
|
MONITOR_POSITIONING_LINEAR,
|
|
|
|
META_MONITORS_CONFIG_FLAG_NONE,
|
|
|
|
META_MONITOR_SWITCH_CONFIG_EXTERNAL);
|
2017-06-07 12:38:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static MetaMonitorsConfig *
|
|
|
|
create_for_switch_config_builtin (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
2019-04-02 18:51:34 -04:00
|
|
|
return create_monitors_switch_config (config_manager,
|
|
|
|
MONITOR_MATCH_BUILTIN,
|
|
|
|
MONITOR_POSITIONING_LINEAR,
|
|
|
|
META_MONITORS_CONFIG_FLAG_NONE,
|
|
|
|
META_MONITOR_SWITCH_CONFIG_BUILTIN);
|
2017-06-07 12:38:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_create_for_switch_config (MetaMonitorConfigManager *config_manager,
|
|
|
|
MetaMonitorSwitchConfigType config_type)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
|
2018-08-29 20:34:53 -04:00
|
|
|
MetaMonitorsConfig *config;
|
2017-06-07 12:38:10 -04:00
|
|
|
|
|
|
|
if (!meta_monitor_manager_can_switch_config (monitor_manager))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
switch (config_type)
|
|
|
|
{
|
|
|
|
case META_MONITOR_SWITCH_CONFIG_ALL_MIRROR:
|
2018-08-29 20:34:53 -04:00
|
|
|
config = create_for_switch_config_all_mirror (config_manager);
|
|
|
|
break;
|
2017-06-07 12:38:10 -04:00
|
|
|
case META_MONITOR_SWITCH_CONFIG_ALL_LINEAR:
|
2018-08-29 20:34:53 -04:00
|
|
|
config = meta_monitor_config_manager_create_linear (config_manager);
|
|
|
|
break;
|
2017-06-07 12:38:10 -04:00
|
|
|
case META_MONITOR_SWITCH_CONFIG_EXTERNAL:
|
2018-08-29 20:34:53 -04:00
|
|
|
config = create_for_switch_config_external (config_manager);
|
|
|
|
break;
|
2017-06-07 12:38:10 -04:00
|
|
|
case META_MONITOR_SWITCH_CONFIG_BUILTIN:
|
2018-08-29 20:34:53 -04:00
|
|
|
config = create_for_switch_config_builtin (config_manager);
|
|
|
|
break;
|
2017-06-07 12:38:10 -04:00
|
|
|
case META_MONITOR_SWITCH_CONFIG_UNKNOWN:
|
2018-08-29 20:34:53 -04:00
|
|
|
default:
|
2017-06-07 12:38:10 -04:00
|
|
|
g_warn_if_reached ();
|
2018-08-29 20:34:53 -04:00
|
|
|
return NULL;
|
2017-06-07 12:38:10 -04:00
|
|
|
}
|
2018-08-29 20:34:53 -04:00
|
|
|
|
|
|
|
return config;
|
2017-06-07 12:38:10 -04:00
|
|
|
}
|
|
|
|
|
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 09:53:55 -04:00
|
|
|
static MetaMonitorsConfig *
|
|
|
|
get_root_config (MetaMonitorsConfig *config)
|
|
|
|
{
|
|
|
|
if (!config->parent_config)
|
|
|
|
return config;
|
|
|
|
|
|
|
|
return get_root_config (config->parent_config);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
has_same_root_config (MetaMonitorsConfig *config_a,
|
|
|
|
MetaMonitorsConfig *config_b)
|
|
|
|
{
|
|
|
|
return get_root_config (config_a) == get_root_config (config_b);
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
void
|
|
|
|
meta_monitor_config_manager_set_current (MetaMonitorConfigManager *config_manager,
|
|
|
|
MetaMonitorsConfig *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 09:53:55 -04:00
|
|
|
MetaMonitorsConfig *current_config = config_manager->current_config;
|
|
|
|
gboolean overrides_current = FALSE;
|
|
|
|
|
|
|
|
if (config && current_config &&
|
|
|
|
has_same_root_config (config, current_config))
|
|
|
|
{
|
|
|
|
overrides_current = meta_monitors_config_key_equal (config->key,
|
|
|
|
current_config->key);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (current_config && !overrides_current)
|
2017-08-11 03:16:15 -04:00
|
|
|
{
|
|
|
|
g_queue_push_head (&config_manager->config_history,
|
|
|
|
g_object_ref (config_manager->current_config));
|
|
|
|
if (g_queue_get_length (&config_manager->config_history) >
|
|
|
|
CONFIG_HISTORY_MAX_SIZE)
|
|
|
|
g_object_unref (g_queue_pop_tail (&config_manager->config_history));
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
g_set_object (&config_manager->current_config, config);
|
|
|
|
}
|
|
|
|
|
2017-03-23 05:20:07 -04:00
|
|
|
void
|
|
|
|
meta_monitor_config_manager_save_current (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
|
|
|
g_return_if_fail (config_manager->current_config);
|
|
|
|
|
|
|
|
meta_monitor_config_store_add (config_manager->config_store,
|
|
|
|
config_manager->current_config);
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_get_current (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
|
|
|
return config_manager->current_config;
|
|
|
|
}
|
|
|
|
|
2017-08-11 03:16:15 -04:00
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_pop_previous (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
|
|
|
return g_queue_pop_head (&config_manager->config_history);
|
|
|
|
}
|
|
|
|
|
2017-03-23 05:20:07 -04:00
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitor_config_manager_get_previous (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
2017-08-11 03:16:15 -04:00
|
|
|
return g_queue_peek_head (&config_manager->config_history);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_config_manager_clear_history (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
|
|
|
g_queue_foreach (&config_manager->config_history, (GFunc) g_object_unref, NULL);
|
|
|
|
g_queue_clear (&config_manager->config_history);
|
2017-03-23 05:20:07 -04:00
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
static void
|
|
|
|
meta_monitor_config_manager_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
MetaMonitorConfigManager *config_manager =
|
|
|
|
META_MONITOR_CONFIG_MANAGER (object);
|
|
|
|
|
|
|
|
g_clear_object (&config_manager->current_config);
|
2017-08-11 03:16:15 -04:00
|
|
|
meta_monitor_config_manager_clear_history (config_manager);
|
2017-01-09 01:31:18 -05:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_monitor_config_manager_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitor_config_manager_init (MetaMonitorConfigManager *config_manager)
|
|
|
|
{
|
2017-08-11 03:16:15 -04:00
|
|
|
g_queue_init (&config_manager->config_history);
|
2017-01-09 01:31:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitor_config_manager_class_init (MetaMonitorConfigManagerClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->dispose = meta_monitor_config_manager_dispose;
|
|
|
|
}
|
|
|
|
|
2017-01-12 03:13:48 -05:00
|
|
|
void
|
2017-01-09 01:31:18 -05:00
|
|
|
meta_monitor_config_free (MetaMonitorConfig *monitor_config)
|
|
|
|
{
|
2021-01-27 14:00:04 -05:00
|
|
|
if (monitor_config->monitor_spec)
|
|
|
|
meta_monitor_spec_free (monitor_config->monitor_spec);
|
2017-01-09 01:31:18 -05:00
|
|
|
g_free (monitor_config->mode_spec);
|
|
|
|
g_free (monitor_config);
|
|
|
|
}
|
|
|
|
|
2017-01-12 03:13:48 -05:00
|
|
|
void
|
2017-01-09 01:31:18 -05:00
|
|
|
meta_logical_monitor_config_free (MetaLogicalMonitorConfig *logical_monitor_config)
|
|
|
|
{
|
|
|
|
g_list_free_full (logical_monitor_config->monitor_configs,
|
|
|
|
(GDestroyNotify) meta_monitor_config_free);
|
|
|
|
g_free (logical_monitor_config);
|
|
|
|
}
|
|
|
|
|
2017-01-12 03:13:48 -05:00
|
|
|
static MetaMonitorsConfigKey *
|
2017-09-28 11:34:33 -04:00
|
|
|
meta_monitors_config_key_new (GList *logical_monitor_configs,
|
|
|
|
GList *disabled_monitor_specs)
|
2017-01-12 03:13:48 -05:00
|
|
|
{
|
|
|
|
MetaMonitorsConfigKey *config_key;
|
|
|
|
GList *monitor_specs;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
monitor_specs = NULL;
|
|
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
GList *k;
|
|
|
|
|
|
|
|
for (k = logical_monitor_config->monitor_configs; k; k = k->next)
|
|
|
|
{
|
|
|
|
MetaMonitorConfig *monitor_config = k->data;
|
|
|
|
MetaMonitorSpec *monitor_spec;
|
|
|
|
|
|
|
|
monitor_spec = meta_monitor_spec_clone (monitor_config->monitor_spec);
|
|
|
|
monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-28 11:34:33 -04:00
|
|
|
for (l = disabled_monitor_specs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitorSpec *monitor_spec = l->data;
|
|
|
|
|
|
|
|
monitor_spec = meta_monitor_spec_clone (monitor_spec);
|
|
|
|
monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
|
|
|
|
}
|
|
|
|
|
2017-01-12 03:13:48 -05:00
|
|
|
monitor_specs = g_list_sort (monitor_specs,
|
|
|
|
(GCompareFunc) meta_monitor_spec_compare);
|
|
|
|
|
|
|
|
config_key = g_new0 (MetaMonitorsConfigKey, 1);
|
|
|
|
*config_key = (MetaMonitorsConfigKey) {
|
|
|
|
.monitor_specs = monitor_specs
|
|
|
|
};
|
|
|
|
|
|
|
|
return config_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitors_config_key_free (MetaMonitorsConfigKey *config_key)
|
|
|
|
{
|
|
|
|
g_list_free_full (config_key->monitor_specs,
|
|
|
|
(GDestroyNotify) meta_monitor_spec_free);
|
|
|
|
g_free (config_key);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
meta_monitors_config_key_hash (gconstpointer data)
|
|
|
|
{
|
|
|
|
const MetaMonitorsConfigKey *config_key = data;
|
|
|
|
GList *l;
|
|
|
|
unsigned long hash;
|
|
|
|
|
|
|
|
hash = 0;
|
|
|
|
for (l = config_key->monitor_specs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitorSpec *monitor_spec = l->data;
|
|
|
|
|
|
|
|
hash ^= (g_str_hash (monitor_spec->connector) ^
|
|
|
|
g_str_hash (monitor_spec->vendor) ^
|
|
|
|
g_str_hash (monitor_spec->product) ^
|
|
|
|
g_str_hash (monitor_spec->serial));
|
|
|
|
}
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_monitors_config_key_equal (gconstpointer data_a,
|
|
|
|
gconstpointer data_b)
|
|
|
|
{
|
|
|
|
const MetaMonitorsConfigKey *config_key_a = data_a;
|
|
|
|
const MetaMonitorsConfigKey *config_key_b = data_b;
|
|
|
|
GList *l_a, *l_b;
|
|
|
|
|
|
|
|
for (l_a = config_key_a->monitor_specs, l_b = config_key_b->monitor_specs;
|
|
|
|
l_a && l_b;
|
|
|
|
l_a = l_a->next, l_b = l_b->next)
|
|
|
|
{
|
|
|
|
MetaMonitorSpec *monitor_spec_a = l_a->data;
|
|
|
|
MetaMonitorSpec *monitor_spec_b = l_b->data;
|
|
|
|
|
|
|
|
if (!meta_monitor_spec_equals (monitor_spec_a, monitor_spec_b))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-04-13 01:02:18 -04:00
|
|
|
if (l_a || l_b)
|
2017-01-12 03:13:48 -05:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-08-29 20:34:53 -04:00
|
|
|
MetaMonitorSwitchConfigType
|
|
|
|
meta_monitors_config_get_switch_config (MetaMonitorsConfig *config)
|
|
|
|
{
|
|
|
|
return config->switch_config;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitors_config_set_switch_config (MetaMonitorsConfig *config,
|
|
|
|
MetaMonitorSwitchConfigType switch_config)
|
|
|
|
{
|
|
|
|
config->switch_config = switch_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 09:53:55 -04:00
|
|
|
void
|
|
|
|
meta_monitors_config_set_parent_config (MetaMonitorsConfig *config,
|
|
|
|
MetaMonitorsConfig *parent_config)
|
|
|
|
{
|
|
|
|
g_assert (config != parent_config);
|
|
|
|
g_assert (!parent_config || parent_config->parent_config != config);
|
|
|
|
|
|
|
|
g_set_object (&config->parent_config, parent_config);
|
|
|
|
}
|
|
|
|
|
2017-01-10 23:13:39 -05:00
|
|
|
MetaMonitorsConfig *
|
2017-09-28 11:34:33 -04:00
|
|
|
meta_monitors_config_new_full (GList *logical_monitor_configs,
|
|
|
|
GList *disabled_monitor_specs,
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
|
|
MetaMonitorsConfigFlag flags)
|
2017-01-10 23:13:39 -05:00
|
|
|
{
|
|
|
|
MetaMonitorsConfig *config;
|
|
|
|
|
|
|
|
config = g_object_new (META_TYPE_MONITORS_CONFIG, NULL);
|
|
|
|
config->logical_monitor_configs = logical_monitor_configs;
|
2017-09-28 11:34:33 -04:00
|
|
|
config->disabled_monitor_specs = disabled_monitor_specs;
|
|
|
|
config->key = meta_monitors_config_key_new (logical_monitor_configs,
|
|
|
|
disabled_monitor_specs);
|
2017-02-24 05:10:52 -05:00
|
|
|
config->layout_mode = layout_mode;
|
2017-08-10 03:12:41 -04:00
|
|
|
config->flags = flags;
|
2018-08-29 20:34:53 -04:00
|
|
|
config->switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
2017-01-10 23:13:39 -05:00
|
|
|
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
2017-09-28 11:34:33 -04:00
|
|
|
MetaMonitorsConfig *
|
|
|
|
meta_monitors_config_new (MetaMonitorManager *monitor_manager,
|
|
|
|
GList *logical_monitor_configs,
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
|
|
MetaMonitorsConfigFlag flags)
|
|
|
|
{
|
|
|
|
GList *disabled_monitor_specs = NULL;
|
|
|
|
GList *monitors;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
monitors = meta_monitor_manager_get_monitors (monitor_manager);
|
|
|
|
for (l = monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaMonitorSpec *monitor_spec;
|
|
|
|
|
2019-04-03 10:29:54 -04:00
|
|
|
if (!monitor_matches_rule (monitor, monitor_manager,
|
|
|
|
MONITOR_MATCH_VISIBLE))
|
2017-11-03 03:58:02 -04:00
|
|
|
continue;
|
|
|
|
|
2017-09-28 11:34:33 -04:00
|
|
|
monitor_spec = meta_monitor_get_spec (monitor);
|
|
|
|
if (meta_logical_monitor_configs_have_monitor (logical_monitor_configs,
|
|
|
|
monitor_spec))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
disabled_monitor_specs =
|
|
|
|
g_list_prepend (disabled_monitor_specs,
|
|
|
|
meta_monitor_spec_clone (monitor_spec));
|
|
|
|
}
|
|
|
|
|
|
|
|
return meta_monitors_config_new_full (logical_monitor_configs,
|
|
|
|
disabled_monitor_specs,
|
|
|
|
layout_mode,
|
|
|
|
flags);
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
static void
|
|
|
|
meta_monitors_config_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaMonitorsConfig *config = META_MONITORS_CONFIG (object);
|
|
|
|
|
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 09:53:55 -04:00
|
|
|
g_clear_object (&config->parent_config);
|
2017-01-12 03:13:48 -05:00
|
|
|
meta_monitors_config_key_free (config->key);
|
2017-01-09 01:31:18 -05:00
|
|
|
g_list_free_full (config->logical_monitor_configs,
|
|
|
|
(GDestroyNotify) meta_logical_monitor_config_free);
|
2017-09-28 11:34:33 -04:00
|
|
|
g_list_free_full (config->disabled_monitor_specs,
|
|
|
|
(GDestroyNotify) meta_monitor_spec_free);
|
2017-09-10 23:12:03 -04:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_monitors_config_parent_class)->finalize (object);
|
2017-01-09 01:31:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitors_config_init (MetaMonitorsConfig *config)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitors_config_class_init (MetaMonitorsConfigClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->finalize = meta_monitors_config_finalize;
|
|
|
|
}
|
2017-02-07 21:31:32 -05:00
|
|
|
|
2017-03-24 03:36:12 -04:00
|
|
|
static void
|
2020-02-25 14:30:46 -05:00
|
|
|
meta_crtc_assignment_free (MetaCrtcAssignment *assignment)
|
2017-03-24 03:36:12 -04:00
|
|
|
{
|
2020-02-25 14:30:46 -05:00
|
|
|
g_ptr_array_free (assignment->outputs, TRUE);
|
2020-10-19 13:57:57 -04:00
|
|
|
g_free (assignment);
|
2017-03-24 03:36:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-25 14:30:46 -05:00
|
|
|
meta_output_assignment_free (MetaOutputAssignment *assignment)
|
2017-03-24 03:36:12 -04:00
|
|
|
{
|
2020-10-19 13:57:57 -04:00
|
|
|
g_free (assignment);
|
2017-03-24 03:36:12 -04:00
|
|
|
}
|
|
|
|
|
2017-02-07 21:31:32 -05:00
|
|
|
gboolean
|
|
|
|
meta_verify_monitor_mode_spec (MetaMonitorModeSpec *monitor_mode_spec,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
if (monitor_mode_spec->width > 0 &&
|
|
|
|
monitor_mode_spec->height > 0 &&
|
|
|
|
monitor_mode_spec->refresh_rate > 0.0f)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Monitor mode invalid");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_verify_monitor_spec (MetaMonitorSpec *monitor_spec,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
if (monitor_spec->connector &&
|
|
|
|
monitor_spec->vendor &&
|
|
|
|
monitor_spec->product &&
|
|
|
|
monitor_spec->serial)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Monitor spec incomplete");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_verify_monitor_config (MetaMonitorConfig *monitor_config,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
if (monitor_config->monitor_spec && monitor_config->mode_spec)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Monitor config incomplete");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2017-02-24 05:10:52 -05:00
|
|
|
meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config,
|
|
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
2017-05-25 05:20:59 -04:00
|
|
|
MetaMonitorManager *monitor_manager,
|
2017-02-24 05:10:52 -05:00
|
|
|
GError **error)
|
2017-02-07 21:31:32 -05:00
|
|
|
{
|
2017-02-14 06:43:10 -05:00
|
|
|
GList *l;
|
2017-02-24 05:10:52 -05:00
|
|
|
int expected_mode_width = 0;
|
|
|
|
int expected_mode_height = 0;
|
2017-02-14 06:43:10 -05:00
|
|
|
|
2017-02-07 21:31:32 -05:00
|
|
|
if (logical_monitor_config->layout.x < 0 ||
|
|
|
|
logical_monitor_config->layout.y < 0)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Invalid logical monitor position (%d, %d)",
|
|
|
|
logical_monitor_config->layout.x,
|
|
|
|
logical_monitor_config->layout.y);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!logical_monitor_config->monitor_configs)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Logical monitor is empty");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-03-21 02:17:18 -04:00
|
|
|
if (meta_monitor_transform_is_rotated (logical_monitor_config->transform))
|
|
|
|
{
|
|
|
|
expected_mode_width = logical_monitor_config->layout.height;
|
|
|
|
expected_mode_height = logical_monitor_config->layout.width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
expected_mode_width = logical_monitor_config->layout.width;
|
|
|
|
expected_mode_height = logical_monitor_config->layout.height;
|
|
|
|
}
|
|
|
|
|
2017-02-24 05:10:52 -05:00
|
|
|
switch (layout_mode)
|
|
|
|
{
|
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
|
2017-06-09 03:51:14 -04:00
|
|
|
expected_mode_width = roundf (expected_mode_width *
|
|
|
|
logical_monitor_config->scale);
|
|
|
|
expected_mode_height = roundf (expected_mode_height *
|
|
|
|
logical_monitor_config->scale);
|
2017-02-24 05:10:52 -05:00
|
|
|
break;
|
|
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-02-14 06:43:10 -05:00
|
|
|
for (l = logical_monitor_config->monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitorConfig *monitor_config = l->data;
|
|
|
|
|
2017-02-24 05:10:52 -05:00
|
|
|
if (monitor_config->mode_spec->width != expected_mode_width ||
|
|
|
|
monitor_config->mode_spec->height != expected_mode_height)
|
2017-02-14 06:43:10 -05:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Monitor modes in logical monitor conflict");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 21:31:32 -05:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-02-07 21:32:33 -05:00
|
|
|
static gboolean
|
2019-03-15 11:39:08 -04:00
|
|
|
has_adjacent_neighbour (MetaMonitorsConfig *config,
|
2017-02-07 21:32:33 -05:00
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
if (!config->logical_monitor_configs->next)
|
|
|
|
{
|
|
|
|
g_assert (config->logical_monitor_configs->data ==
|
|
|
|
logical_monitor_config);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *other_logical_monitor_config = l->data;
|
|
|
|
|
|
|
|
if (logical_monitor_config == other_logical_monitor_config)
|
|
|
|
continue;
|
|
|
|
|
2019-03-15 11:39:08 -04:00
|
|
|
if (meta_rectangle_is_adjacent_to (&logical_monitor_config->layout,
|
2017-02-07 21:32:33 -05:00
|
|
|
&other_logical_monitor_config->layout))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-09-28 11:34:33 -04:00
|
|
|
gboolean
|
|
|
|
meta_logical_monitor_configs_have_monitor (GList *logical_monitor_configs,
|
|
|
|
MetaMonitorSpec *monitor_spec)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
GList *k;
|
|
|
|
|
|
|
|
for (k = logical_monitor_config->monitor_configs; k; k = k->next)
|
|
|
|
{
|
|
|
|
MetaMonitorConfig *monitor_config = k->data;
|
|
|
|
|
|
|
|
if (meta_monitor_spec_equals (monitor_spec,
|
|
|
|
monitor_config->monitor_spec))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_monitors_config_is_monitor_enabled (MetaMonitorsConfig *config,
|
|
|
|
MetaMonitorSpec *monitor_spec)
|
|
|
|
{
|
|
|
|
return meta_logical_monitor_configs_have_monitor (config->logical_monitor_configs,
|
|
|
|
monitor_spec);
|
|
|
|
}
|
|
|
|
|
2017-02-07 21:31:32 -05:00
|
|
|
gboolean
|
|
|
|
meta_verify_monitors_config (MetaMonitorsConfig *config,
|
2017-04-21 06:01:15 -04:00
|
|
|
MetaMonitorManager *monitor_manager,
|
2017-02-07 21:31:32 -05:00
|
|
|
GError **error)
|
|
|
|
{
|
2017-02-07 21:33:24 -05:00
|
|
|
int min_x, min_y;
|
2017-02-07 21:31:32 -05:00
|
|
|
gboolean has_primary;
|
|
|
|
GList *region;
|
|
|
|
GList *l;
|
2017-04-21 06:01:15 -04:00
|
|
|
gboolean global_scale_required;
|
2017-02-07 21:31:32 -05:00
|
|
|
|
|
|
|
if (!config->logical_monitor_configs)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Monitors config incomplete");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-04-21 06:01:15 -04:00
|
|
|
global_scale_required =
|
|
|
|
!!(meta_monitor_manager_get_capabilities (monitor_manager) &
|
|
|
|
META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
|
|
|
|
|
2017-02-07 21:33:24 -05:00
|
|
|
min_x = INT_MAX;
|
|
|
|
min_y = INT_MAX;
|
2017-02-07 21:31:32 -05:00
|
|
|
region = NULL;
|
|
|
|
has_primary = FALSE;
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
|
2017-04-21 06:01:15 -04:00
|
|
|
if (global_scale_required)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *prev_logical_monitor_config =
|
|
|
|
l->prev ? l->prev->data : NULL;
|
|
|
|
|
|
|
|
if (prev_logical_monitor_config &&
|
|
|
|
(prev_logical_monitor_config->scale !=
|
|
|
|
logical_monitor_config->scale))
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Logical monitor scales must be identical");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 21:31:32 -05:00
|
|
|
if (meta_rectangle_overlaps_with_region (region,
|
|
|
|
&logical_monitor_config->layout))
|
|
|
|
{
|
|
|
|
g_list_free (region);
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Logical monitors overlap");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (has_primary && logical_monitor_config->is_primary)
|
|
|
|
{
|
|
|
|
g_list_free (region);
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Config contains multiple primary logical monitors");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if (logical_monitor_config->is_primary)
|
|
|
|
{
|
|
|
|
has_primary = TRUE;
|
|
|
|
}
|
|
|
|
|
2019-03-15 11:39:08 -04:00
|
|
|
if (!has_adjacent_neighbour (config, logical_monitor_config))
|
2017-02-07 21:32:33 -05:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
2019-03-15 11:39:08 -04:00
|
|
|
"Logical monitors not adjacent");
|
2017-02-07 21:32:33 -05:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-02-07 21:33:24 -05:00
|
|
|
min_x = MIN (logical_monitor_config->layout.x, min_x);
|
|
|
|
min_y = MIN (logical_monitor_config->layout.y, min_y);
|
|
|
|
|
2017-02-07 21:31:32 -05:00
|
|
|
region = g_list_prepend (region, &logical_monitor_config->layout);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free (region);
|
|
|
|
|
2017-09-28 11:34:33 -04:00
|
|
|
for (l = config->disabled_monitor_specs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitorSpec *monitor_spec = l->data;
|
|
|
|
|
|
|
|
if (meta_monitors_config_is_monitor_enabled (config, monitor_spec))
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Assigned monitor explicitly disabled");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 21:33:24 -05:00
|
|
|
if (min_x != 0 || min_y != 0)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Logical monitors positions are offset");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-02-07 21:31:32 -05:00
|
|
|
if (!has_primary)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Config is missing primary logical");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|