518fb9fb5e
The monitor manager instance was created and setup in one step; at construction. This is problematic if, in the future, the monitor manager creation can fail, as the monitor manager is created quite late. To make it possible to in the future fail creating a monitor manager, create the instance very early when initiating the backend, then on post init backend setup, "setup" the monitor manager state, i.e. read the current state and setup the stage. https://bugzilla.gnome.org/show_bug.cgi?id=785381
2901 lines
93 KiB
C
2901 lines
93 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
/*
|
|
* 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.
|
|
*
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "meta-monitor-manager-private.h"
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <clutter/clutter.h>
|
|
|
|
#include <meta/main.h>
|
|
#include "util-private.h"
|
|
#include <meta/errors.h>
|
|
#include "edid.h"
|
|
#include "backends/meta-crtc.h"
|
|
#include "backends/meta-logical-monitor.h"
|
|
#include "backends/meta-monitor.h"
|
|
#include "backends/meta-monitor-config-manager.h"
|
|
#include "backends/meta-orientation-manager.h"
|
|
#include "backends/meta-output.h"
|
|
#include "backends/x11/meta-monitor-manager-xrandr.h"
|
|
#include "meta-backend-private.h"
|
|
|
|
#define DEFAULT_DISPLAY_CONFIGURATION_TIMEOUT 20
|
|
|
|
enum {
|
|
CONFIRM_DISPLAY_CHANGE,
|
|
SIGNALS_LAST
|
|
};
|
|
|
|
/* 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 */
|
|
};
|
|
|
|
static int signals[SIGNALS_LAST];
|
|
|
|
static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface);
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYPE_DISPLAY_CONFIG_SKELETON,
|
|
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_DISPLAY_CONFIG, meta_monitor_manager_display_config_init));
|
|
|
|
static void initialize_dbus_interface (MetaMonitorManager *manager);
|
|
|
|
static gboolean
|
|
meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config);
|
|
|
|
static void
|
|
meta_monitor_manager_init (MetaMonitorManager *manager)
|
|
{
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static gboolean
|
|
is_main_tiled_monitor_output (MetaOutput *output)
|
|
{
|
|
return output->tile_info.loc_h_tile == 0 && output->tile_info.loc_v_tile == 0;
|
|
}
|
|
|
|
static MetaLogicalMonitor *
|
|
logical_monitor_from_layout (MetaMonitorManager *manager,
|
|
GList *logical_monitors,
|
|
MetaRectangle *layout)
|
|
{
|
|
GList *l;
|
|
|
|
for (l = logical_monitors; l; l = l->next)
|
|
{
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
|
|
|
if (meta_rectangle_equal (layout, &logical_monitor->rect))
|
|
return logical_monitor;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_rebuild_logical_monitors (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config)
|
|
{
|
|
GList *logical_monitor_configs;
|
|
GList *logical_monitors = NULL;
|
|
GList *l;
|
|
int monitor_number = 0;
|
|
MetaLogicalMonitor *primary_logical_monitor = NULL;
|
|
|
|
logical_monitor_configs = config ? config->logical_monitor_configs : NULL;
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
|
{
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
MetaLogicalMonitor *logical_monitor;
|
|
|
|
logical_monitor = meta_logical_monitor_new (manager,
|
|
logical_monitor_config,
|
|
monitor_number);
|
|
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);
|
|
}
|
|
|
|
static float
|
|
derive_configured_global_scale (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config)
|
|
{
|
|
MetaLogicalMonitorConfig *logical_monitor_config;
|
|
|
|
logical_monitor_config = config->logical_monitor_configs->data;
|
|
|
|
return logical_monitor_config->scale;
|
|
}
|
|
|
|
static float
|
|
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,
|
|
monitor,
|
|
monitor_mode);
|
|
}
|
|
|
|
static float
|
|
derive_calculated_global_scale (MetaMonitorManager *manager)
|
|
{
|
|
MetaMonitor *primary_monitor;
|
|
|
|
primary_monitor = meta_monitor_manager_get_primary_monitor (manager);
|
|
if (!primary_monitor)
|
|
return 1.0;
|
|
|
|
return calculate_monitor_scale (manager, primary_monitor);
|
|
}
|
|
|
|
static float
|
|
derive_scale_from_config (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config,
|
|
MetaRectangle *layout)
|
|
{
|
|
GList *l;
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
{
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
if (meta_rectangle_equal (layout, &logical_monitor_config->layout))
|
|
return logical_monitor_config->scale;
|
|
}
|
|
|
|
g_warning ("Missing logical monitor, using scale 1");
|
|
return 1.0;
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_rebuild_logical_monitors_derived (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config)
|
|
{
|
|
GList *logical_monitors = NULL;
|
|
GList *l;
|
|
int monitor_number;
|
|
MetaLogicalMonitor *primary_logical_monitor = NULL;
|
|
gboolean use_global_scale;
|
|
float global_scale = 0.0;
|
|
MetaMonitorManagerCapability capabilities;
|
|
|
|
monitor_number = 0;
|
|
|
|
capabilities = meta_monitor_manager_get_capabilities (manager);
|
|
use_global_scale =
|
|
!!(capabilities & META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
|
|
|
|
if (use_global_scale)
|
|
{
|
|
if (config)
|
|
global_scale = derive_configured_global_scale (manager, config);
|
|
else
|
|
global_scale = derive_calculated_global_scale (manager);
|
|
}
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
{
|
|
MetaMonitor *monitor = l->data;
|
|
MetaLogicalMonitor *logical_monitor;
|
|
MetaRectangle layout;
|
|
|
|
if (!meta_monitor_is_active (monitor))
|
|
continue;
|
|
|
|
meta_monitor_derive_layout (monitor, &layout);
|
|
logical_monitor = logical_monitor_from_layout (manager, logical_monitors,
|
|
&layout);
|
|
if (logical_monitor)
|
|
{
|
|
meta_logical_monitor_add_monitor (logical_monitor, monitor);
|
|
}
|
|
else
|
|
{
|
|
float scale;
|
|
|
|
if (use_global_scale)
|
|
scale = global_scale;
|
|
else if (config)
|
|
scale = derive_scale_from_config (manager, config, &layout);
|
|
else
|
|
scale = calculate_monitor_scale (manager, monitor);
|
|
|
|
g_assert (scale > 0);
|
|
|
|
logical_monitor = meta_logical_monitor_new_derived (manager,
|
|
monitor,
|
|
&layout,
|
|
scale,
|
|
monitor_number);
|
|
logical_monitors = g_list_append (logical_monitors, logical_monitor);
|
|
monitor_number++;
|
|
}
|
|
|
|
if (meta_monitor_is_primary (monitor))
|
|
primary_logical_monitor = logical_monitor;
|
|
}
|
|
|
|
manager->logical_monitors = logical_monitors;
|
|
|
|
/*
|
|
* If no monitor was marked as primary, fall back on marking the first
|
|
* logical monitor the primary one.
|
|
*/
|
|
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);
|
|
}
|
|
|
|
static void
|
|
power_save_mode_changed (MetaMonitorManager *manager,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
MetaMonitorManagerClass *klass;
|
|
int mode = meta_dbus_display_config_get_power_save_mode (META_DBUS_DISPLAY_CONFIG (manager));
|
|
|
|
if (mode == META_POWER_SAVE_UNSUPPORTED)
|
|
return;
|
|
|
|
/* If DPMS is unsupported, force the property back. */
|
|
if (manager->power_save_mode == META_POWER_SAVE_UNSUPPORTED)
|
|
{
|
|
meta_dbus_display_config_set_power_save_mode (META_DBUS_DISPLAY_CONFIG (manager), META_POWER_SAVE_UNSUPPORTED);
|
|
return;
|
|
}
|
|
|
|
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
if (klass->set_power_save_mode)
|
|
klass->set_power_save_mode (manager, mode);
|
|
|
|
manager->power_save_mode = mode;
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_lid_is_closed_changed (MetaMonitorManager *manager)
|
|
{
|
|
meta_monitor_manager_ensure_configured (manager);
|
|
}
|
|
|
|
static void
|
|
lid_is_closed_changed (UpClient *client,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
meta_monitor_manager_lid_is_closed_changed (manager);
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_real_is_lid_closed (MetaMonitorManager *manager)
|
|
{
|
|
if (!manager->up_client)
|
|
return FALSE;
|
|
|
|
return up_client_get_lid_is_closed (manager->up_client);
|
|
}
|
|
|
|
gboolean
|
|
meta_monitor_manager_is_lid_closed (MetaMonitorManager *manager)
|
|
{
|
|
return META_MONITOR_MANAGER_GET_CLASS (manager)->is_lid_closed (manager);
|
|
}
|
|
|
|
gboolean
|
|
meta_monitor_manager_is_headless (MetaMonitorManager *manager)
|
|
{
|
|
return !manager->logical_monitors;
|
|
}
|
|
|
|
float
|
|
meta_monitor_manager_calculate_monitor_mode_scale (MetaMonitorManager *manager,
|
|
MetaMonitor *monitor,
|
|
MetaMonitorMode *monitor_mode)
|
|
{
|
|
MetaMonitorManagerClass *manager_class =
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
return manager_class->calculate_monitor_mode_scale (manager,
|
|
monitor,
|
|
monitor_mode);
|
|
}
|
|
|
|
float *
|
|
meta_monitor_manager_calculate_supported_scales (MetaMonitorManager *manager,
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
MetaMonitor *monitor,
|
|
MetaMonitorMode *monitor_mode,
|
|
int *n_supported_scales)
|
|
{
|
|
MetaMonitorManagerClass *manager_class =
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
return manager_class->calculate_supported_scales (manager,
|
|
layout_mode,
|
|
monitor,
|
|
monitor_mode,
|
|
n_supported_scales);
|
|
}
|
|
|
|
MetaMonitorManagerCapability
|
|
meta_monitor_manager_get_capabilities (MetaMonitorManager *manager)
|
|
{
|
|
MetaMonitorManagerClass *manager_class =
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
return manager_class->get_capabilities (manager);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager)
|
|
{
|
|
META_MONITOR_MANAGER_GET_CLASS (manager)->ensure_initial_config (manager);
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_apply_monitors_config (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config,
|
|
MetaMonitorsConfigMethod method,
|
|
GError **error)
|
|
{
|
|
MetaMonitorManagerClass *manager_class =
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
g_assert (!config ||
|
|
!(config->flags & META_MONITORS_CONFIG_FLAG_MIGRATED));
|
|
|
|
if (!manager_class->apply_monitors_config (manager, config, method, error))
|
|
return FALSE;
|
|
|
|
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;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
|
|
{
|
|
GList *l;
|
|
|
|
for (l = manager->outputs; l; l = l->next)
|
|
{
|
|
MetaOutput *output = l->data;
|
|
|
|
if (output->hotplug_mode_update)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
should_use_stored_config (MetaMonitorManager *manager)
|
|
{
|
|
return (manager->in_init ||
|
|
!meta_monitor_manager_has_hotplug_mode_update (manager));
|
|
}
|
|
|
|
MetaMonitorsConfig *
|
|
meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
|
|
{
|
|
MetaMonitorsConfig *config = NULL;
|
|
GError *error = NULL;
|
|
gboolean use_stored_config;
|
|
MetaMonitorsConfigMethod method;
|
|
MetaMonitorsConfigMethod fallback_method =
|
|
META_MONITORS_CONFIG_METHOD_TEMPORARY;
|
|
|
|
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)
|
|
{
|
|
config = meta_monitor_config_manager_get_stored (manager->config_manager);
|
|
if (config)
|
|
{
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
config,
|
|
method,
|
|
&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;
|
|
}
|
|
}
|
|
}
|
|
|
|
config = meta_monitor_config_manager_create_suggested (manager->config_manager);
|
|
if (config)
|
|
{
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
config,
|
|
method,
|
|
&error))
|
|
{
|
|
g_clear_object (&config);
|
|
g_warning ("Failed to use suggested monitor configuration: %s",
|
|
error->message);
|
|
g_clear_error (&error);
|
|
}
|
|
else
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
config = meta_monitor_config_manager_get_previous (manager->config_manager);
|
|
if (config)
|
|
{
|
|
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);
|
|
}
|
|
|
|
config = meta_monitor_config_manager_create_linear (manager->config_manager);
|
|
if (config)
|
|
{
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
config,
|
|
method,
|
|
&error))
|
|
{
|
|
g_clear_object (&config);
|
|
g_warning ("Failed to use linear monitor configuration: %s",
|
|
error->message);
|
|
g_clear_error (&error);
|
|
}
|
|
else
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
config = meta_monitor_config_manager_create_fallback (manager->config_manager);
|
|
if (config)
|
|
{
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
config,
|
|
fallback_method,
|
|
&error))
|
|
{
|
|
g_clear_object (&config);
|
|
g_warning ("Failed to use fallback monitor configuration: %s",
|
|
error->message);
|
|
g_clear_error (&error);
|
|
}
|
|
else
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (!config)
|
|
{
|
|
meta_monitor_manager_apply_monitors_config (manager,
|
|
NULL,
|
|
fallback_method,
|
|
&error);
|
|
return NULL;
|
|
}
|
|
|
|
g_object_unref (config);
|
|
|
|
return config;
|
|
}
|
|
|
|
static void
|
|
orientation_changed (MetaOrientationManager *orientation_manager,
|
|
MetaMonitorManager *manager)
|
|
{
|
|
MetaMonitorTransform transform;
|
|
GError *error = NULL;
|
|
MetaMonitorsConfig *config;
|
|
|
|
switch (meta_orientation_manager_get_orientation (orientation_manager))
|
|
{
|
|
case META_ORIENTATION_NORMAL:
|
|
transform = META_MONITOR_TRANSFORM_NORMAL;
|
|
break;
|
|
case META_ORIENTATION_BOTTOM_UP:
|
|
transform = META_MONITOR_TRANSFORM_180;
|
|
break;
|
|
case META_ORIENTATION_LEFT_UP:
|
|
transform = META_MONITOR_TRANSFORM_90;
|
|
break;
|
|
case META_ORIENTATION_RIGHT_UP:
|
|
transform = META_MONITOR_TRANSFORM_270;
|
|
break;
|
|
|
|
case META_ORIENTATION_UNDEFINED:
|
|
default:
|
|
return;
|
|
}
|
|
|
|
config =
|
|
meta_monitor_config_manager_create_for_orientation (manager->config_manager,
|
|
transform);
|
|
if (!config)
|
|
return;
|
|
|
|
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);
|
|
}
|
|
g_object_unref (config);
|
|
}
|
|
|
|
static void
|
|
experimental_features_changed (MetaSettings *settings,
|
|
MetaExperimentalFeature old_experimental_features,
|
|
MetaMonitorManager *manager)
|
|
{
|
|
gboolean was_stage_views_scaled;
|
|
gboolean is_stage_views_scaled;
|
|
gboolean should_reconfigure = FALSE;
|
|
|
|
was_stage_views_scaled =
|
|
!!(old_experimental_features &
|
|
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
|
|
is_stage_views_scaled =
|
|
meta_settings_is_experimental_feature_enabled (
|
|
settings,
|
|
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
|
|
|
|
if (is_stage_views_scaled != was_stage_views_scaled)
|
|
should_reconfigure = TRUE;
|
|
|
|
if (should_reconfigure)
|
|
meta_monitor_manager_on_hotplug (manager);
|
|
|
|
meta_settings_update_ui_scaling_factor (settings);
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_setup (MetaMonitorManager *manager)
|
|
{
|
|
manager->in_init = TRUE;
|
|
|
|
manager->config_manager = meta_monitor_config_manager_new (manager);
|
|
|
|
meta_monitor_manager_read_current_state (manager);
|
|
|
|
meta_monitor_manager_ensure_initial_config (manager);
|
|
|
|
manager->in_init = FALSE;
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_constructed (GObject *object)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
|
MetaMonitorManagerClass *manager_class =
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
MetaBackend *backend = meta_get_backend ();
|
|
MetaSettings *settings = meta_backend_get_settings (backend);
|
|
|
|
manager->experimental_features_changed_handler_id =
|
|
g_signal_connect (settings,
|
|
"experimental-features-changed",
|
|
G_CALLBACK (experimental_features_changed),
|
|
manager);
|
|
|
|
if (manager_class->is_lid_closed == meta_monitor_manager_real_is_lid_closed)
|
|
{
|
|
manager->up_client = up_client_new ();
|
|
g_signal_connect_object (manager->up_client, "notify::lid-is-closed",
|
|
G_CALLBACK (lid_is_closed_changed), manager, 0);
|
|
}
|
|
|
|
g_signal_connect_object (manager, "notify::power-save-mode",
|
|
G_CALLBACK (power_save_mode_changed), manager, 0);
|
|
|
|
g_signal_connect_object (meta_backend_get_orientation_manager (backend),
|
|
"orientation-changed",
|
|
G_CALLBACK (orientation_changed),
|
|
manager, 0);
|
|
|
|
manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
|
|
|
initialize_dbus_interface (manager);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_finalize (GObject *object)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
|
|
|
g_list_free_full (manager->outputs, g_object_unref);
|
|
g_list_free_full (manager->modes, g_object_unref);
|
|
g_list_free_full (manager->crtcs, g_object_unref);
|
|
g_list_free_full (manager->logical_monitors, g_object_unref);
|
|
|
|
g_signal_handler_disconnect (meta_get_backend (),
|
|
manager->experimental_features_changed_handler_id);
|
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_dispose (GObject *object)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
|
|
|
if (manager->dbus_name_id != 0)
|
|
{
|
|
g_bus_unown_name (manager->dbus_name_id);
|
|
manager->dbus_name_id = 0;
|
|
}
|
|
|
|
g_clear_object (&manager->config_manager);
|
|
g_clear_object (&manager->up_client);
|
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
|
|
}
|
|
|
|
static GBytes *
|
|
meta_monitor_manager_real_read_edid (MetaMonitorManager *manager,
|
|
MetaOutput *output)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static char *
|
|
meta_monitor_manager_real_get_edid_file (MetaMonitorManager *manager,
|
|
MetaOutput *output)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->constructed = meta_monitor_manager_constructed;
|
|
object_class->dispose = meta_monitor_manager_dispose;
|
|
object_class->finalize = meta_monitor_manager_finalize;
|
|
|
|
klass->get_edid_file = meta_monitor_manager_real_get_edid_file;
|
|
klass->read_edid = meta_monitor_manager_real_read_edid;
|
|
klass->is_lid_closed = meta_monitor_manager_real_is_lid_closed;
|
|
|
|
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);
|
|
}
|
|
|
|
static const double known_diagonals[] = {
|
|
12.1,
|
|
13.3,
|
|
15.6
|
|
};
|
|
|
|
static char *
|
|
diagonal_to_str (double d)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (known_diagonals); i++)
|
|
{
|
|
double delta;
|
|
|
|
delta = fabs(known_diagonals[i] - d);
|
|
if (delta < 0.1)
|
|
return g_strdup_printf ("%0.1lf\"", known_diagonals[i]);
|
|
}
|
|
|
|
return g_strdup_printf ("%d\"", (int) (d + 0.5));
|
|
}
|
|
|
|
static char *
|
|
make_display_name (MetaMonitorManager *manager,
|
|
MetaOutput *output)
|
|
{
|
|
g_autofree char *inches = NULL;
|
|
g_autofree char *vendor_name = NULL;
|
|
|
|
if (meta_output_is_laptop (output))
|
|
return g_strdup (_("Built-in display"));
|
|
|
|
if (output->width_mm > 0 && output->height_mm > 0)
|
|
{
|
|
double d = sqrt (output->width_mm * output->width_mm +
|
|
output->height_mm * output->height_mm);
|
|
inches = diagonal_to_str (d / 25.4);
|
|
}
|
|
|
|
if (g_strcmp0 (output->vendor, "unknown") != 0)
|
|
{
|
|
if (!manager->pnp_ids)
|
|
manager->pnp_ids = gnome_pnp_ids_new ();
|
|
|
|
vendor_name = gnome_pnp_ids_get_pnp_id (manager->pnp_ids,
|
|
output->vendor);
|
|
|
|
if (!vendor_name)
|
|
vendor_name = g_strdup (output->vendor);
|
|
}
|
|
else
|
|
{
|
|
if (inches != NULL)
|
|
vendor_name = g_strdup (_("Unknown"));
|
|
else
|
|
vendor_name = g_strdup (_("Unknown Display"));
|
|
}
|
|
|
|
if (inches != NULL)
|
|
{
|
|
/* TRANSLATORS: this is a monitor vendor name, followed by a
|
|
* size in inches, like 'Dell 15"'
|
|
*/
|
|
return g_strdup_printf (_("%s %s"), vendor_name, inches);
|
|
}
|
|
else
|
|
{
|
|
return g_strdup (vendor_name);
|
|
}
|
|
}
|
|
|
|
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";
|
|
default: g_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
|
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_GET_CLASS (skeleton);
|
|
GVariantBuilder crtc_builder, output_builder, mode_builder;
|
|
GList *l;
|
|
unsigned int i, j;
|
|
int max_screen_width;
|
|
int max_screen_height;
|
|
|
|
g_variant_builder_init (&crtc_builder, G_VARIANT_TYPE ("a(uxiiiiiuaua{sv})"));
|
|
g_variant_builder_init (&output_builder, G_VARIANT_TYPE ("a(uxiausauaua{sv})"));
|
|
g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uxuudu)"));
|
|
|
|
for (l = manager->crtcs, i = 0; l; l = l->next, i++)
|
|
{
|
|
MetaCrtc *crtc = l->data;
|
|
GVariantBuilder transforms;
|
|
int current_mode_index;
|
|
|
|
g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au"));
|
|
for (j = 0; j <= META_MONITOR_TRANSFORM_FLIPPED_270; j++)
|
|
if (crtc->all_transforms & (1 << j))
|
|
g_variant_builder_add (&transforms, "u", j);
|
|
|
|
if (crtc->current_mode)
|
|
current_mode_index = g_list_index (manager->modes, crtc->current_mode);
|
|
else
|
|
current_mode_index = -1;
|
|
g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})",
|
|
i, /* ID */
|
|
(gint64)crtc->crtc_id,
|
|
(int)crtc->rect.x,
|
|
(int)crtc->rect.y,
|
|
(int)crtc->rect.width,
|
|
(int)crtc->rect.height,
|
|
current_mode_index,
|
|
(guint32)crtc->transform,
|
|
&transforms,
|
|
NULL /* properties */);
|
|
}
|
|
|
|
for (l = manager->outputs; l; l = l->next)
|
|
{
|
|
MetaOutput *output = l->data;
|
|
GVariantBuilder crtcs, modes, clones, properties;
|
|
GBytes *edid;
|
|
char *edid_file;
|
|
int crtc_index;
|
|
|
|
g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au"));
|
|
for (j = 0; j < output->n_possible_crtcs; j++)
|
|
{
|
|
MetaCrtc *possible_crtc = output->possible_crtcs[j];
|
|
unsigned possible_crtc_index;
|
|
|
|
possible_crtc_index = g_list_index (manager->crtcs, possible_crtc);
|
|
g_variant_builder_add (&crtcs, "u", possible_crtc_index);
|
|
}
|
|
|
|
g_variant_builder_init (&modes, G_VARIANT_TYPE ("au"));
|
|
for (j = 0; j < output->n_modes; j++)
|
|
{
|
|
unsigned mode_index;
|
|
|
|
mode_index = g_list_index (manager->modes, output->modes[j]);
|
|
g_variant_builder_add (&modes, "u", mode_index);
|
|
}
|
|
|
|
g_variant_builder_init (&clones, G_VARIANT_TYPE ("au"));
|
|
for (j = 0; j < output->n_possible_clones; j++)
|
|
{
|
|
unsigned int possible_clone_index;
|
|
|
|
possible_clone_index = g_list_index (manager->outputs,
|
|
output->possible_clones[j]);
|
|
g_variant_builder_add (&clones, "u", possible_clone_index);
|
|
}
|
|
|
|
g_variant_builder_init (&properties, G_VARIANT_TYPE ("a{sv}"));
|
|
g_variant_builder_add (&properties, "{sv}", "vendor",
|
|
g_variant_new_string (output->vendor));
|
|
g_variant_builder_add (&properties, "{sv}", "product",
|
|
g_variant_new_string (output->product));
|
|
g_variant_builder_add (&properties, "{sv}", "serial",
|
|
g_variant_new_string (output->serial));
|
|
g_variant_builder_add (&properties, "{sv}", "width-mm",
|
|
g_variant_new_int32 (output->width_mm));
|
|
g_variant_builder_add (&properties, "{sv}", "height-mm",
|
|
g_variant_new_int32 (output->height_mm));
|
|
g_variant_builder_add (&properties, "{sv}", "display-name",
|
|
g_variant_new_take_string (make_display_name (manager, output)));
|
|
g_variant_builder_add (&properties, "{sv}", "backlight",
|
|
g_variant_new_int32 (output->backlight));
|
|
g_variant_builder_add (&properties, "{sv}", "min-backlight-step",
|
|
g_variant_new_int32 ((output->backlight_max - output->backlight_min) ?
|
|
100 / (output->backlight_max - output->backlight_min) : -1));
|
|
g_variant_builder_add (&properties, "{sv}", "primary",
|
|
g_variant_new_boolean (output->is_primary));
|
|
g_variant_builder_add (&properties, "{sv}", "presentation",
|
|
g_variant_new_boolean (output->is_presentation));
|
|
g_variant_builder_add (&properties, "{sv}", "connector-type",
|
|
g_variant_new_string (get_connector_type_name (output->connector_type)));
|
|
g_variant_builder_add (&properties, "{sv}", "underscanning",
|
|
g_variant_new_boolean (output->is_underscanning));
|
|
g_variant_builder_add (&properties, "{sv}", "supports-underscanning",
|
|
g_variant_new_boolean (output->supports_underscanning));
|
|
|
|
edid_file = manager_class->get_edid_file (manager, output);
|
|
if (edid_file)
|
|
{
|
|
g_variant_builder_add (&properties, "{sv}", "edid-file",
|
|
g_variant_new_take_string (edid_file));
|
|
}
|
|
else
|
|
{
|
|
edid = manager_class->read_edid (manager, output);
|
|
|
|
if (edid)
|
|
{
|
|
g_variant_builder_add (&properties, "{sv}", "edid",
|
|
g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"),
|
|
edid, TRUE));
|
|
g_bytes_unref (edid);
|
|
}
|
|
}
|
|
|
|
if (output->tile_info.group_id)
|
|
{
|
|
g_variant_builder_add (&properties, "{sv}", "tile",
|
|
g_variant_new ("(uuuuuuuu)",
|
|
output->tile_info.group_id,
|
|
output->tile_info.flags,
|
|
output->tile_info.max_h_tiles,
|
|
output->tile_info.max_v_tiles,
|
|
output->tile_info.loc_h_tile,
|
|
output->tile_info.loc_v_tile,
|
|
output->tile_info.tile_w,
|
|
output->tile_info.tile_h));
|
|
}
|
|
|
|
crtc_index = output->crtc ? g_list_index (manager->crtcs, output->crtc)
|
|
: -1;
|
|
g_variant_builder_add (&output_builder, "(uxiausauaua{sv})",
|
|
i, /* ID */
|
|
(gint64)output->winsys_id,
|
|
crtc_index,
|
|
&crtcs,
|
|
output->name,
|
|
&modes,
|
|
&clones,
|
|
&properties);
|
|
}
|
|
|
|
for (l = manager->modes, i = 0; l; l = l->next, i++)
|
|
{
|
|
MetaCrtcMode *mode = l->data;
|
|
|
|
g_variant_builder_add (&mode_builder, "(uxuudu)",
|
|
i, /* ID */
|
|
(gint64)mode->mode_id,
|
|
(guint32)mode->width,
|
|
(guint32)mode->height,
|
|
(double)mode->refresh_rate,
|
|
(guint32)mode->flags);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
meta_dbus_display_config_complete_get_resources (skeleton,
|
|
invocation,
|
|
manager->serial,
|
|
g_variant_builder_end (&crtc_builder),
|
|
g_variant_builder_end (&output_builder),
|
|
g_variant_builder_end (&mode_builder),
|
|
max_screen_width,
|
|
max_screen_height);
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
restore_previous_config (MetaMonitorManager *manager)
|
|
{
|
|
MetaMonitorsConfig *previous_config;
|
|
GError *error = NULL;
|
|
|
|
previous_config =
|
|
meta_monitor_config_manager_pop_previous (manager->config_manager);
|
|
|
|
if (previous_config)
|
|
{
|
|
MetaMonitorsConfigMethod method;
|
|
|
|
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);
|
|
}
|
|
|
|
gint
|
|
meta_monitor_manager_get_display_configuration_timeout (void)
|
|
{
|
|
return DEFAULT_DISPLAY_CONFIGURATION_TIMEOUT;
|
|
}
|
|
|
|
static gboolean
|
|
save_config_timeout (gpointer user_data)
|
|
{
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
restore_previous_config (manager);
|
|
manager->persistent_timeout_id = 0;
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
cancel_persistent_confirmation (MetaMonitorManager *manager)
|
|
{
|
|
g_source_remove (manager->persistent_timeout_id);
|
|
manager->persistent_timeout_id = 0;
|
|
}
|
|
|
|
static void
|
|
request_persistent_confirmation (MetaMonitorManager *manager)
|
|
{
|
|
manager->persistent_timeout_id = g_timeout_add_seconds (meta_monitor_manager_get_display_configuration_timeout (),
|
|
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);
|
|
}
|
|
|
|
#define META_DISPLAY_CONFIG_MODE_FLAGS_PREFERRED (1 << 0)
|
|
#define META_DISPLAY_CONFIG_MODE_FLAGS_CURRENT (1 << 1)
|
|
|
|
#define MODE_FORMAT "(siiddada{sv})"
|
|
#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
|
|
#define LOGICAL_MONITOR_FORMAT "(iidub" LOGICAL_MONITOR_MONITORS_FORMAT "a{sv})"
|
|
#define LOGICAL_MONITORS_FORMAT "a" LOGICAL_MONITOR_FORMAT
|
|
|
|
static gboolean
|
|
meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
|
GVariantBuilder monitors_builder;
|
|
GVariantBuilder logical_monitors_builder;
|
|
GVariantBuilder properties_builder;
|
|
GList *l;
|
|
int i;
|
|
MetaMonitorManagerCapability capabilities;
|
|
int max_screen_width, max_screen_height;
|
|
|
|
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;
|
|
GVariantBuilder modes_builder;
|
|
GVariantBuilder monitor_properties_builder;
|
|
GList *k;
|
|
gboolean is_builtin;
|
|
MetaOutput *main_output;
|
|
char *display_name;
|
|
|
|
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;
|
|
GVariantBuilder supported_scales_builder;
|
|
const char *mode_id;
|
|
int mode_width, mode_height;
|
|
float refresh_rate;
|
|
float preferred_scale;
|
|
float *supported_scales;
|
|
int n_supported_scales;
|
|
GVariantBuilder mode_properties_builder;
|
|
MetaCrtcModeFlag mode_flags;
|
|
|
|
mode_id = meta_monitor_mode_get_id (monitor_mode);
|
|
meta_monitor_mode_get_resolution (monitor_mode,
|
|
&mode_width, &mode_height);
|
|
refresh_rate = meta_monitor_mode_get_refresh_rate (monitor_mode);
|
|
|
|
preferred_scale =
|
|
meta_monitor_manager_calculate_monitor_mode_scale (manager,
|
|
monitor,
|
|
monitor_mode);
|
|
|
|
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);
|
|
|
|
mode_flags = meta_monitor_mode_get_flags (monitor_mode);
|
|
|
|
g_variant_builder_init (&mode_properties_builder,
|
|
G_VARIANT_TYPE ("a{sv}"));
|
|
if (monitor_mode == current_mode)
|
|
g_variant_builder_add (&mode_properties_builder, "{sv}",
|
|
"is-current",
|
|
g_variant_new_boolean (TRUE));
|
|
if (monitor_mode == preferred_mode)
|
|
g_variant_builder_add (&mode_properties_builder, "{sv}",
|
|
"is-preferred",
|
|
g_variant_new_boolean (TRUE));
|
|
if (mode_flags & META_CRTC_MODE_FLAG_INTERLACE)
|
|
g_variant_builder_add (&mode_properties_builder, "{sv}",
|
|
"is-interlaced",
|
|
g_variant_new_boolean (TRUE));
|
|
|
|
g_variant_builder_add (&modes_builder, MODE_FORMAT,
|
|
mode_id,
|
|
mode_width,
|
|
mode_height,
|
|
refresh_rate,
|
|
(double) preferred_scale,
|
|
&supported_scales_builder,
|
|
&mode_properties_builder);
|
|
}
|
|
|
|
g_variant_builder_init (&monitor_properties_builder,
|
|
G_VARIANT_TYPE ("a{sv}"));
|
|
if (meta_monitor_supports_underscanning (monitor))
|
|
{
|
|
gboolean is_underscanning = meta_monitor_is_underscanning (monitor);
|
|
|
|
g_variant_builder_add (&monitor_properties_builder, "{sv}",
|
|
"is-underscanning",
|
|
g_variant_new_boolean (is_underscanning));
|
|
}
|
|
|
|
is_builtin = meta_monitor_is_laptop_panel (monitor);
|
|
g_variant_builder_add (&monitor_properties_builder, "{sv}",
|
|
"is-builtin",
|
|
g_variant_new_boolean (is_builtin));
|
|
|
|
main_output = meta_monitor_get_main_output (monitor);
|
|
display_name = make_display_name (manager, main_output);
|
|
g_variant_builder_add (&monitor_properties_builder, "{sv}",
|
|
"display-name",
|
|
g_variant_new_take_string (display_name));
|
|
|
|
g_variant_builder_add (&monitors_builder, MONITOR_FORMAT,
|
|
monitor_spec->connector,
|
|
monitor_spec->vendor,
|
|
monitor_spec->product,
|
|
monitor_spec->serial,
|
|
&modes_builder,
|
|
&monitor_properties_builder);
|
|
}
|
|
|
|
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,
|
|
(double) logical_monitor->scale,
|
|
logical_monitor->transform,
|
|
logical_monitor->is_primary,
|
|
&logical_monitor_monitors_builder,
|
|
NULL);
|
|
}
|
|
|
|
g_variant_builder_init (&properties_builder, G_VARIANT_TYPE ("a{sv}"));
|
|
capabilities = meta_monitor_manager_get_capabilities (manager);
|
|
if ((capabilities & META_MONITOR_MANAGER_CAPABILITY_MIRRORING) == 0)
|
|
{
|
|
g_variant_builder_add (&properties_builder, "{sv}",
|
|
"supports-mirroring",
|
|
g_variant_new_boolean (FALSE));
|
|
}
|
|
|
|
g_variant_builder_add (&properties_builder, "{sv}",
|
|
"layout-mode",
|
|
g_variant_new_uint32 (manager->layout_mode));
|
|
if (capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
|
|
{
|
|
g_variant_builder_add (&properties_builder, "{sv}",
|
|
"supports-changing-layout-mode",
|
|
g_variant_new_boolean (TRUE));
|
|
}
|
|
|
|
if (capabilities & META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED)
|
|
{
|
|
g_variant_builder_add (&properties_builder, "{sv}",
|
|
"global-scale-required",
|
|
g_variant_new_boolean (TRUE));
|
|
}
|
|
|
|
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}",
|
|
"max-screen-size",
|
|
g_variant_builder_end (&max_screen_size_builder));
|
|
}
|
|
|
|
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),
|
|
g_variant_builder_end (&properties_builder));
|
|
|
|
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
|
|
|
|
gboolean
|
|
meta_monitor_manager_is_scale_supported (MetaMonitorManager *manager,
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
MetaMonitor *monitor,
|
|
MetaMonitorMode *monitor_mode,
|
|
float scale)
|
|
{
|
|
g_autofree float *supported_scales = NULL;
|
|
int n_supported_scales;
|
|
int i;
|
|
|
|
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++)
|
|
{
|
|
if (supported_scales[i] == scale)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (!meta_monitor_manager_is_scale_supported (manager,
|
|
config->layout_mode,
|
|
monitor,
|
|
monitor_mode,
|
|
scale))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Scale not supported by backend");
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config)
|
|
{
|
|
GList *l;
|
|
unsigned int configured_monitor_count = 0;
|
|
unsigned int expected_monitor_count = 0;
|
|
|
|
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)
|
|
configured_monitor_count++;
|
|
}
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
{
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
if (meta_monitor_is_laptop_panel (monitor))
|
|
{
|
|
if (!meta_monitor_manager_is_lid_closed (manager))
|
|
expected_monitor_count++;
|
|
}
|
|
else
|
|
{
|
|
expected_monitor_count++;
|
|
}
|
|
}
|
|
|
|
if (configured_monitor_count != expected_monitor_count)
|
|
return FALSE;
|
|
|
|
return meta_monitor_manager_is_config_applicable (manager, config, NULL);
|
|
}
|
|
|
|
static MetaMonitor *
|
|
find_monitor_from_connector (MetaMonitorManager *manager,
|
|
char *connector)
|
|
{
|
|
GList *monitors;
|
|
GList *l;
|
|
|
|
if (!connector)
|
|
return NULL;
|
|
|
|
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))
|
|
return monitor;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#define MONITOR_CONFIG_FORMAT "(ssa{sv})"
|
|
#define MONITOR_CONFIGS_FORMAT "a" MONITOR_CONFIG_FORMAT
|
|
|
|
#define LOGICAL_MONITOR_CONFIG_FORMAT "(iidub" MONITOR_CONFIGS_FORMAT ")"
|
|
|
|
static MetaMonitorConfig *
|
|
create_monitor_config_from_variant (MetaMonitorManager *manager,
|
|
GVariant *monitor_config_variant,
|
|
GError **error)
|
|
{
|
|
|
|
MetaMonitorConfig *monitor_config = NULL;
|
|
g_autofree char *connector = NULL;
|
|
g_autofree char *mode_id = NULL;
|
|
MetaMonitorMode *monitor_mode;
|
|
MetaMonitor *monitor;
|
|
MetaMonitorSpec *monitor_spec;
|
|
MetaMonitorModeSpec *monitor_mode_spec;
|
|
g_autoptr (GVariant) properties_variant = NULL;
|
|
gboolean enable_underscanning = FALSE;
|
|
|
|
g_variant_get (monitor_config_variant, "(ss@a{sv})",
|
|
&connector,
|
|
&mode_id,
|
|
&properties_variant);
|
|
|
|
monitor = find_monitor_from_connector (manager, connector);
|
|
if (!monitor)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Invalid connector '%s' specified", connector);
|
|
return NULL;
|
|
}
|
|
|
|
monitor_mode = meta_monitor_get_mode_from_id (monitor, mode_id);
|
|
if (!monitor_mode)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Invalid mode '%s' specified", mode_id);
|
|
return NULL;
|
|
}
|
|
|
|
g_variant_lookup (properties_variant, "underscanning", "b", &enable_underscanning);
|
|
|
|
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);
|
|
|
|
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
|
|
find_monitor_mode_scale (MetaMonitorManager *manager,
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
MetaMonitorConfig *monitor_config,
|
|
float scale,
|
|
float *out_scale,
|
|
GError **error)
|
|
{
|
|
MetaMonitorSpec *monitor_spec;
|
|
MetaMonitor *monitor;
|
|
MetaMonitorModeSpec *monitor_mode_spec;
|
|
MetaMonitorMode *monitor_mode;
|
|
g_autofree float *supported_scales = NULL;
|
|
int n_supported_scales;
|
|
int i;
|
|
|
|
monitor_spec = monitor_config->monitor_spec;
|
|
monitor = meta_monitor_manager_get_monitor_from_spec (manager,
|
|
monitor_spec);
|
|
if (!monitor)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Monitor not found");
|
|
return FALSE;
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
switch (layout_mode)
|
|
{
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
|
|
width = roundf (width / scale);
|
|
height = roundf (height / scale);
|
|
break;
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
|
|
break;
|
|
}
|
|
|
|
*out_width = width;
|
|
*out_height = height;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static MetaLogicalMonitorConfig *
|
|
create_logical_monitor_config_from_variant (MetaMonitorManager *manager,
|
|
GVariant *logical_monitor_config_variant,
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
GError **error)
|
|
{
|
|
MetaLogicalMonitorConfig *logical_monitor_config;
|
|
int x, y, width, height;
|
|
double scale_d;
|
|
float scale;
|
|
MetaMonitorTransform transform;
|
|
gboolean is_primary;
|
|
GVariantIter *monitor_configs_iter;
|
|
GList *monitor_configs = NULL;
|
|
MetaMonitorConfig *monitor_config;
|
|
|
|
g_variant_get (logical_monitor_config_variant, LOGICAL_MONITOR_CONFIG_FORMAT,
|
|
&x,
|
|
&y,
|
|
&scale_d,
|
|
&transform,
|
|
&is_primary,
|
|
&monitor_configs_iter);
|
|
scale = (float) scale_d;
|
|
|
|
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);
|
|
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);
|
|
|
|
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,
|
|
scale, transform, layout_mode, error))
|
|
goto err;
|
|
|
|
logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
|
|
*logical_monitor_config = (MetaLogicalMonitorConfig) {
|
|
.layout = {
|
|
.x = x,
|
|
.y = y,
|
|
.width = width,
|
|
.height = height
|
|
},
|
|
.transform = transform,
|
|
.scale = scale,
|
|
.is_primary = is_primary,
|
|
.monitor_configs = monitor_configs
|
|
};
|
|
|
|
if (!meta_verify_logical_monitor_config (logical_monitor_config,
|
|
layout_mode,
|
|
manager,
|
|
error))
|
|
{
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skeleton,
|
|
GDBusMethodInvocation *invocation,
|
|
guint serial,
|
|
guint method,
|
|
GVariant *logical_monitor_configs_variant,
|
|
GVariant *properties_variant)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
|
MetaMonitorManagerCapability capabilities;
|
|
GVariant *layout_mode_variant = NULL;
|
|
MetaLogicalMonitorLayoutMode layout_mode;
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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,
|
|
layout_mode,
|
|
&error);
|
|
if (!logical_monitor_config)
|
|
{
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
"%s", error->message);
|
|
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);
|
|
}
|
|
|
|
config = meta_monitors_config_new (manager,
|
|
logical_monitor_configs,
|
|
layout_mode,
|
|
META_MONITORS_CONFIG_FLAG_NONE);
|
|
if (!meta_verify_monitors_config (config, manager, &error))
|
|
{
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
"%s", error->message);
|
|
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,
|
|
"%s", error->message);
|
|
g_error_free (error);
|
|
g_object_unref (config);
|
|
return TRUE;
|
|
}
|
|
|
|
if (manager->persistent_timeout_id &&
|
|
method != META_MONITORS_CONFIG_METHOD_VERIFY)
|
|
cancel_persistent_confirmation (manager);
|
|
|
|
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,
|
|
"%s", error->message);
|
|
g_error_free (error);
|
|
g_object_unref (config);
|
|
return TRUE;
|
|
}
|
|
|
|
if (method == META_MONITORS_CONFIG_METHOD_PERSISTENT)
|
|
request_persistent_confirmation (manager);
|
|
|
|
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
|
|
|
|
static void
|
|
confirm_configuration (MetaMonitorManager *manager,
|
|
gboolean confirmed)
|
|
{
|
|
if (confirmed)
|
|
meta_monitor_config_manager_save_current (manager->config_manager);
|
|
else
|
|
restore_previous_config (manager);
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager,
|
|
gboolean ok)
|
|
{
|
|
if (!manager->persistent_timeout_id)
|
|
{
|
|
/* too late */
|
|
return;
|
|
}
|
|
|
|
cancel_persistent_confirmation (manager);
|
|
confirm_configuration (manager, ok);
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
|
|
GDBusMethodInvocation *invocation,
|
|
guint serial,
|
|
guint output_index,
|
|
gint value)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
|
MetaOutput *output;
|
|
|
|
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;
|
|
}
|
|
|
|
if (output_index >= g_list_length (manager->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 (manager->outputs, output_index);
|
|
|
|
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;
|
|
}
|
|
|
|
if (output->backlight == -1 ||
|
|
(output->backlight_min == 0 && output->backlight_max == 0))
|
|
{
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
"Output does not support changing backlight");
|
|
return TRUE;
|
|
}
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager)->change_backlight (manager, output, value);
|
|
|
|
meta_dbus_display_config_complete_change_backlight (skeleton, invocation, output->backlight);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_handle_get_crtc_gamma (MetaDBusDisplayConfig *skeleton,
|
|
GDBusMethodInvocation *invocation,
|
|
guint serial,
|
|
guint crtc_id)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
|
MetaMonitorManagerClass *klass;
|
|
MetaCrtc *crtc;
|
|
gsize size;
|
|
unsigned short *red;
|
|
unsigned short *green;
|
|
unsigned short *blue;
|
|
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;
|
|
}
|
|
|
|
if (crtc_id >= g_list_length (manager->crtcs))
|
|
{
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
"Invalid crtc id");
|
|
return TRUE;
|
|
}
|
|
|
|
crtc = g_list_nth_data (manager->crtcs, crtc_id);
|
|
|
|
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
if (klass->get_crtc_gamma)
|
|
klass->get_crtc_gamma (manager, crtc, &size, &red, &green, &blue);
|
|
else
|
|
{
|
|
size = 0;
|
|
red = green = blue = NULL;
|
|
}
|
|
|
|
red_bytes = g_bytes_new_take (red, size * sizeof (unsigned short));
|
|
green_bytes = g_bytes_new_take (green, size * sizeof (unsigned short));
|
|
blue_bytes = g_bytes_new_take (blue, size * sizeof (unsigned short));
|
|
|
|
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,
|
|
GVariant *blue_v)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
|
MetaMonitorManagerClass *klass;
|
|
MetaCrtc *crtc;
|
|
gsize size, dummy;
|
|
unsigned short *red;
|
|
unsigned short *green;
|
|
unsigned short *blue;
|
|
GBytes *red_bytes, *green_bytes, *blue_bytes;
|
|
|
|
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;
|
|
}
|
|
|
|
if (crtc_id >= g_list_length (manager->crtcs))
|
|
{
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
"Invalid crtc id");
|
|
return TRUE;
|
|
}
|
|
|
|
crtc = g_list_nth_data (manager->crtcs, crtc_id);
|
|
|
|
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);
|
|
|
|
size = g_bytes_get_size (red_bytes) / sizeof (unsigned short);
|
|
red = (unsigned short*) g_bytes_get_data (red_bytes, &dummy);
|
|
green = (unsigned short*) g_bytes_get_data (green_bytes, &dummy);
|
|
blue = (unsigned short*) g_bytes_get_data (blue_bytes, &dummy);
|
|
|
|
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
if (klass->set_crtc_gamma)
|
|
klass->set_crtc_gamma (manager, crtc, size, red, green, blue);
|
|
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;
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface)
|
|
{
|
|
iface->handle_get_resources = meta_monitor_manager_handle_get_resources;
|
|
iface->handle_change_backlight = meta_monitor_manager_handle_change_backlight;
|
|
iface->handle_get_crtc_gamma = meta_monitor_manager_handle_get_crtc_gamma;
|
|
iface->handle_set_crtc_gamma = meta_monitor_manager_handle_set_crtc_gamma;
|
|
iface->handle_get_current_state = meta_monitor_manager_handle_get_current_state;
|
|
iface->handle_apply_monitors_config = meta_monitor_manager_handle_apply_monitors_config;
|
|
}
|
|
|
|
static void
|
|
on_bus_acquired (GDBusConnection *connection,
|
|
const char *name,
|
|
gpointer user_data)
|
|
{
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager),
|
|
connection,
|
|
"/org/gnome/Mutter/DisplayConfig",
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
on_name_acquired (GDBusConnection *connection,
|
|
const char *name,
|
|
gpointer user_data)
|
|
{
|
|
meta_topic (META_DEBUG_DBUS, "Acquired name %s\n", name);
|
|
}
|
|
|
|
static void
|
|
on_name_lost (GDBusConnection *connection,
|
|
const char *name,
|
|
gpointer user_data)
|
|
{
|
|
meta_topic (META_DEBUG_DBUS, "Lost or failed to acquire name %s\n", name);
|
|
}
|
|
|
|
static void
|
|
initialize_dbus_interface (MetaMonitorManager *manager)
|
|
{
|
|
manager->dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
|
"org.gnome.Mutter.DisplayConfig",
|
|
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
|
|
(meta_get_replace_current_wm () ?
|
|
G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
|
|
on_bus_acquired,
|
|
on_name_acquired,
|
|
on_name_lost,
|
|
g_object_ref (manager),
|
|
g_object_unref);
|
|
}
|
|
|
|
/**
|
|
* meta_monitor_manager_get:
|
|
*
|
|
* Accessor for the singleton MetaMonitorManager.
|
|
*
|
|
* Returns: (transfer none): The only #MetaMonitorManager there is.
|
|
*/
|
|
MetaMonitorManager *
|
|
meta_monitor_manager_get (void)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
|
|
return meta_backend_get_monitor_manager (backend);
|
|
}
|
|
|
|
int
|
|
meta_monitor_manager_get_num_logical_monitors (MetaMonitorManager *manager)
|
|
{
|
|
return g_list_length (manager->logical_monitors);
|
|
}
|
|
|
|
GList *
|
|
meta_monitor_manager_get_logical_monitors (MetaMonitorManager *manager)
|
|
{
|
|
return manager->logical_monitors;
|
|
}
|
|
|
|
MetaLogicalMonitor *
|
|
meta_monitor_manager_get_logical_monitor_from_number (MetaMonitorManager *manager,
|
|
int number)
|
|
{
|
|
g_assert ((unsigned int) number < g_list_length (manager->logical_monitors));
|
|
|
|
return g_list_nth (manager->logical_monitors, number)->data;
|
|
}
|
|
|
|
MetaLogicalMonitor *
|
|
meta_monitor_manager_get_primary_logical_monitor (MetaMonitorManager *manager)
|
|
{
|
|
return manager->primary_logical_monitor;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
MetaMonitor *
|
|
meta_monitor_manager_get_primary_monitor (MetaMonitorManager *manager)
|
|
{
|
|
return find_monitor (manager, meta_monitor_is_primary);
|
|
}
|
|
|
|
MetaMonitor *
|
|
meta_monitor_manager_get_laptop_panel (MetaMonitorManager *manager)
|
|
{
|
|
return find_monitor (manager, meta_monitor_is_laptop_panel);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
MetaLogicalMonitor *
|
|
meta_monitor_manager_get_logical_monitor_at (MetaMonitorManager *manager,
|
|
float x,
|
|
float y)
|
|
{
|
|
GList *l;
|
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
|
{
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
|
|
|
if (POINT_IN_RECT (x, y, logical_monitor->rect))
|
|
return logical_monitor;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
MetaLogicalMonitor *
|
|
meta_monitor_manager_get_logical_monitor_from_rect (MetaMonitorManager *manager,
|
|
MetaRectangle *rect)
|
|
{
|
|
MetaLogicalMonitor *best_logical_monitor;
|
|
int best_logical_monitor_area;
|
|
GList *l;
|
|
|
|
best_logical_monitor = NULL;
|
|
best_logical_monitor_area = 0;
|
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
|
{
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
|
MetaRectangle intersection;
|
|
int intersection_area;
|
|
|
|
if (!meta_rectangle_intersect (&logical_monitor->rect,
|
|
rect,
|
|
&intersection))
|
|
continue;
|
|
|
|
intersection_area = meta_rectangle_area (&intersection);
|
|
|
|
if (intersection_area > best_logical_monitor_area)
|
|
{
|
|
best_logical_monitor = logical_monitor;
|
|
best_logical_monitor_area = intersection_area;
|
|
}
|
|
}
|
|
|
|
if (!best_logical_monitor && (rect->width == 0 || rect->height == 0))
|
|
best_logical_monitor =
|
|
meta_monitor_manager_get_logical_monitor_at (manager, rect->x, rect->y);
|
|
|
|
if (!best_logical_monitor)
|
|
best_logical_monitor = manager->primary_logical_monitor;
|
|
|
|
return best_logical_monitor;
|
|
}
|
|
|
|
MetaLogicalMonitor *
|
|
meta_monitor_manager_get_logical_monitor_neighbor (MetaMonitorManager *manager,
|
|
MetaLogicalMonitor *logical_monitor,
|
|
MetaScreenDirection direction)
|
|
{
|
|
GList *l;
|
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
|
{
|
|
MetaLogicalMonitor *other = l->data;
|
|
|
|
if (meta_logical_monitor_has_neighbor (logical_monitor, other, direction))
|
|
return other;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
GList *
|
|
meta_monitor_manager_get_monitors (MetaMonitorManager *manager)
|
|
{
|
|
return manager->monitors;
|
|
}
|
|
|
|
GList *
|
|
meta_monitor_manager_get_outputs (MetaMonitorManager *manager)
|
|
{
|
|
return manager->outputs;
|
|
}
|
|
|
|
GList *
|
|
meta_monitor_manager_get_crtcs (MetaMonitorManager *manager)
|
|
{
|
|
return manager->crtcs;
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
|
|
int *width,
|
|
int *height)
|
|
{
|
|
*width = manager->screen_width;
|
|
*height = manager->screen_height;
|
|
}
|
|
|
|
static void
|
|
rebuild_monitors (MetaMonitorManager *manager)
|
|
{
|
|
GList *l;
|
|
|
|
if (manager->monitors)
|
|
{
|
|
g_list_free_full (manager->monitors, g_object_unref);
|
|
manager->monitors = NULL;
|
|
}
|
|
|
|
for (l = manager->outputs; l; l = l->next)
|
|
{
|
|
MetaOutput *output = l->data;
|
|
|
|
if (output->tile_info.group_id)
|
|
{
|
|
if (is_main_tiled_monitor_output (output))
|
|
{
|
|
MetaMonitorTiled *monitor_tiled;
|
|
|
|
monitor_tiled = meta_monitor_tiled_new (manager, output);
|
|
manager->monitors = g_list_append (manager->monitors,
|
|
monitor_tiled);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MetaMonitorNormal *monitor_normal;
|
|
|
|
monitor_normal = meta_monitor_normal_new (manager, output);
|
|
manager->monitors = g_list_append (manager->monitors,
|
|
monitor_normal);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
gboolean
|
|
meta_monitor_manager_is_transform_handled (MetaMonitorManager *manager,
|
|
MetaCrtc *crtc,
|
|
MetaMonitorTransform transform)
|
|
{
|
|
MetaMonitorManagerClass *manager_class =
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
return manager_class->is_transform_handled (manager, crtc, transform);
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
|
|
{
|
|
GList *old_outputs;
|
|
GList *old_crtcs;
|
|
GList *old_modes;
|
|
|
|
/* Some implementations of read_current use the existing information
|
|
* we have available, so don't free the old configuration until after
|
|
* read_current finishes. */
|
|
old_outputs = manager->outputs;
|
|
old_crtcs = manager->crtcs;
|
|
old_modes = manager->modes;
|
|
|
|
manager->serial++;
|
|
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
|
|
|
|
rebuild_monitors (manager);
|
|
|
|
g_list_free_full (old_outputs, g_object_unref);
|
|
g_list_free_full (old_modes, g_object_unref);
|
|
g_list_free_full (old_crtcs, g_object_unref);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_notify_monitors_changed (MetaMonitorManager *manager)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
|
|
manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
|
|
|
meta_backend_monitors_changed (backend);
|
|
g_signal_emit_by_name (manager, "monitors-changed");
|
|
}
|
|
|
|
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)
|
|
{
|
|
GList *logical_monitor_configs;
|
|
GList *l;
|
|
|
|
g_list_foreach (manager->monitors,
|
|
(GFunc) meta_monitor_set_current_mode,
|
|
NULL);
|
|
|
|
logical_monitor_configs = config ? config->logical_monitor_configs : NULL;
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
|
{
|
|
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)
|
|
{
|
|
if (config)
|
|
manager->layout_mode = config->layout_mode;
|
|
else
|
|
manager->layout_mode =
|
|
meta_monitor_manager_get_default_layout_mode (manager);
|
|
|
|
meta_monitor_manager_rebuild_logical_monitors (manager, config);
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_rebuild (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config)
|
|
{
|
|
GList *old_logical_monitors;
|
|
|
|
meta_monitor_manager_update_monitor_modes (manager, config);
|
|
|
|
if (manager->in_init)
|
|
return;
|
|
|
|
old_logical_monitors = manager->logical_monitors;
|
|
|
|
meta_monitor_manager_update_logical_state (manager, config);
|
|
|
|
meta_monitor_manager_notify_monitors_changed (manager);
|
|
|
|
g_list_free_full (old_logical_monitors, g_object_unref);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config)
|
|
{
|
|
manager->layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
|
|
|
|
meta_monitor_manager_rebuild_logical_monitors_derived (manager, config);
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config)
|
|
{
|
|
GList *old_logical_monitors;
|
|
|
|
meta_monitor_manager_update_monitor_modes_derived (manager);
|
|
|
|
if (manager->in_init)
|
|
return;
|
|
|
|
old_logical_monitors = manager->logical_monitors;
|
|
|
|
meta_monitor_manager_update_logical_state_derived (manager, config);
|
|
|
|
meta_monitor_manager_notify_monitors_changed (manager);
|
|
|
|
g_list_free_full (old_logical_monitors, g_object_unref);
|
|
}
|
|
|
|
void
|
|
meta_output_parse_edid (MetaOutput *output,
|
|
GBytes *edid)
|
|
{
|
|
MonitorInfo *parsed_edid;
|
|
gsize len;
|
|
|
|
if (!edid)
|
|
goto out;
|
|
|
|
parsed_edid = decode_edid (g_bytes_get_data (edid, &len));
|
|
|
|
if (parsed_edid)
|
|
{
|
|
output->vendor = g_strndup (parsed_edid->manufacturer_code, 4);
|
|
if (!g_utf8_validate (output->vendor, -1, NULL))
|
|
g_clear_pointer (&output->vendor, g_free);
|
|
|
|
output->product = g_strndup (parsed_edid->dsc_product_name, 14);
|
|
if (!g_utf8_validate (output->product, -1, NULL) ||
|
|
output->product[0] == '\0')
|
|
{
|
|
g_clear_pointer (&output->product, g_free);
|
|
output->product = g_strdup_printf ("0x%04x", (unsigned) parsed_edid->product_code);
|
|
}
|
|
|
|
output->serial = g_strndup (parsed_edid->dsc_serial_number, 14);
|
|
if (!g_utf8_validate (output->serial, -1, NULL) ||
|
|
output->serial[0] == '\0')
|
|
{
|
|
g_clear_pointer (&output->serial, g_free);
|
|
output->serial = g_strdup_printf ("0x%08x", parsed_edid->serial_number);
|
|
}
|
|
|
|
g_free (parsed_edid);
|
|
}
|
|
|
|
out:
|
|
if (!output->vendor)
|
|
output->vendor = g_strdup ("unknown");
|
|
if (!output->product)
|
|
output->product = g_strdup ("unknown");
|
|
if (!output->serial)
|
|
output->serial = g_strdup ("unknown");
|
|
}
|
|
|
|
gboolean
|
|
meta_output_is_laptop (MetaOutput *output)
|
|
{
|
|
/* FIXME: extend with better heuristics */
|
|
switch (output->connector_type)
|
|
{
|
|
case META_CONNECTOR_TYPE_eDP:
|
|
case META_CONNECTOR_TYPE_LVDS:
|
|
case META_CONNECTOR_TYPE_DSI:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_on_hotplug (MetaMonitorManager *manager)
|
|
{
|
|
meta_monitor_manager_ensure_configured (manager);
|
|
}
|
|
|
|
static gboolean
|
|
calculate_viewport_matrix (MetaMonitorManager *manager,
|
|
MetaLogicalMonitor *logical_monitor,
|
|
gfloat viewport[6])
|
|
{
|
|
gfloat x, y, width, height;
|
|
|
|
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;
|
|
|
|
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,
|
|
MetaLogicalMonitor *logical_monitor,
|
|
gfloat matrix[6])
|
|
{
|
|
MetaMonitorTransform transform;
|
|
gfloat viewport[9];
|
|
|
|
if (!calculate_viewport_matrix (manager, logical_monitor, viewport))
|
|
return FALSE;
|
|
|
|
transform = logical_monitor->transform;
|
|
multiply_matrix (viewport, transform_matrices[transform],
|
|
matrix);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* meta_monitor_manager_get_monitor_for_output:
|
|
* @manager: A #MetaMonitorManager
|
|
* @id: A valid #MetaOutput id
|
|
*
|
|
* Returns: The monitor index or -1 if @id isn't valid or the output
|
|
* isn't associated with a logical monitor.
|
|
*/
|
|
gint
|
|
meta_monitor_manager_get_monitor_for_output (MetaMonitorManager *manager,
|
|
guint id)
|
|
{
|
|
MetaOutput *output;
|
|
GList *l;
|
|
|
|
g_return_val_if_fail (META_IS_MONITOR_MANAGER (manager), -1);
|
|
g_return_val_if_fail (id < g_list_length (manager->outputs), -1);
|
|
|
|
output = g_list_nth_data (manager->outputs, id);
|
|
if (!output || !output->crtc)
|
|
return -1;
|
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
|
{
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
|
|
|
if (meta_rectangle_contains_rect (&logical_monitor->rect,
|
|
&output->crtc->rect))
|
|
return logical_monitor->number;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
|
|
if (meta_monitor_is_active (monitor) &&
|
|
g_str_equal (connector, meta_monitor_get_connector (monitor)))
|
|
{
|
|
MetaOutput *main_output = meta_monitor_get_main_output (monitor);
|
|
|
|
return main_output->crtc->logical_monitor->number;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
gboolean
|
|
meta_monitor_manager_get_is_builtin_display_on (MetaMonitorManager *manager)
|
|
{
|
|
MetaMonitor *laptop_panel;
|
|
|
|
g_return_val_if_fail (META_IS_MONITOR_MANAGER (manager), FALSE);
|
|
|
|
laptop_panel = meta_monitor_manager_get_laptop_panel (manager);
|
|
if (!laptop_panel)
|
|
return FALSE;
|
|
|
|
return meta_monitor_is_active (laptop_panel);
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_rotate_monitor (MetaMonitorManager *manager)
|
|
{
|
|
GError *error = NULL;
|
|
MetaMonitorsConfig *config =
|
|
meta_monitor_config_manager_create_for_rotate_monitor (manager->config_manager);
|
|
|
|
if (!config)
|
|
return;
|
|
|
|
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);
|
|
}
|
|
g_object_unref (config);
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_switch_config (MetaMonitorManager *manager,
|
|
MetaMonitorSwitchConfigType config_type)
|
|
{
|
|
GError *error = NULL;
|
|
MetaMonitorsConfig *config;
|
|
|
|
g_return_if_fail (config_type != META_MONITOR_SWITCH_CONFIG_UNKNOWN);
|
|
|
|
config =
|
|
meta_monitor_config_manager_create_for_switch_config (manager->config_manager,
|
|
config_type);
|
|
if (!config)
|
|
return;
|
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager,
|
|
config,
|
|
META_MONITORS_CONFIG_METHOD_TEMPORARY,
|
|
&error))
|
|
{
|
|
g_warning ("Failed to use switch monitor configuration: %s",
|
|
error->message);
|
|
g_error_free (error);
|
|
}
|
|
else
|
|
{
|
|
manager->current_switch_config = config_type;
|
|
}
|
|
g_object_unref (config);
|
|
}
|
|
|
|
gboolean
|
|
meta_monitor_manager_can_switch_config (MetaMonitorManager *manager)
|
|
{
|
|
return (!meta_monitor_manager_is_lid_closed (manager) &&
|
|
g_list_length (manager->monitors) > 1);
|
|
}
|
|
|
|
MetaMonitorSwitchConfigType
|
|
meta_monitor_manager_get_switch_config (MetaMonitorManager *manager)
|
|
{
|
|
return manager->current_switch_config;
|
|
}
|
|
|
|
MetaMonitorConfigManager *
|
|
meta_monitor_manager_get_config_manager (MetaMonitorManager *manager)
|
|
{
|
|
return manager->config_manager;
|
|
}
|