2013-07-18 07:09:16 -04:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
2014-05-02 09:34:02 -04:00
|
|
|
/*
|
2013-07-18 07:09:16 -04:00
|
|
|
* Copyright (C) 2001, 2002 Havoc Pennington
|
|
|
|
* Copyright (C) 2002, 2003 Red Hat Inc.
|
|
|
|
* Some ICCCM manager selection code derived from fvwm2,
|
|
|
|
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
|
|
|
|
* Copyright (C) 2003 Rob Adams
|
|
|
|
* Copyright (C) 2004-2006 Elijah Newren
|
|
|
|
* Copyright (C) 2013 Red Hat Inc.
|
2014-05-02 09:34:02 -04:00
|
|
|
*
|
2013-07-18 07:09:16 -04:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
2014-05-02 09:34:02 -04:00
|
|
|
*
|
2013-07-18 07:09:16 -04:00
|
|
|
* You should have received a copy of the GNU General Public License
|
2014-01-11 20:42:06 -05:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2013-07-18 07:09:16 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2015-01-30 08:51:18 -05:00
|
|
|
#include "meta-monitor-manager-private.h"
|
2014-03-31 22:04:10 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
2013-07-24 09:35:47 -04:00
|
|
|
#include <stdlib.h>
|
2013-07-18 07:09:16 -04:00
|
|
|
#include <clutter/clutter.h>
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
#include <meta/main.h>
|
2013-09-11 04:18:53 -04:00
|
|
|
#include "util-private.h"
|
2013-07-22 07:31:10 -04:00
|
|
|
#include <meta/errors.h>
|
2015-01-04 15:24:05 -05:00
|
|
|
#include "edid.h"
|
2014-03-31 21:59:16 -04:00
|
|
|
#include "meta-monitor-config.h"
|
2016-12-12 21:37:11 -05:00
|
|
|
#include "backends/meta-logical-monitor.h"
|
2016-12-12 21:53:38 -05:00
|
|
|
#include "backends/meta-monitor.h"
|
2017-01-09 01:31:18 -05:00
|
|
|
#include "backends/meta-monitor-config-manager.h"
|
2014-03-31 23:25:37 -04:00
|
|
|
#include "backends/x11/meta-monitor-manager-xrandr.h"
|
2014-08-05 08:11:59 -04:00
|
|
|
#include "meta-backend-private.h"
|
2013-07-18 07:09:16 -04:00
|
|
|
|
|
|
|
enum {
|
2013-07-29 04:12:24 -04:00
|
|
|
CONFIRM_DISPLAY_CHANGE,
|
2017-01-09 21:38:06 -05:00
|
|
|
LID_IS_CLOSED_CHANGED,
|
2013-07-18 07:09:16 -04:00
|
|
|
SIGNALS_LAST
|
|
|
|
};
|
|
|
|
|
2014-12-11 12:14:00 -05:00
|
|
|
/* Array index matches MetaMonitorTransform */
|
|
|
|
static gfloat transform_matrices[][6] = {
|
|
|
|
{ 1, 0, 0, 0, 1, 0 }, /* normal */
|
|
|
|
{ 0, -1, 1, 1, 0, 0 }, /* 90° */
|
|
|
|
{ -1, 0, 1, 0, -1, 1 }, /* 180° */
|
|
|
|
{ 0, 1, 0, -1, 0, 1 }, /* 270° */
|
|
|
|
{ -1, 0, 1, 0, 1, 0 }, /* normal flipped */
|
|
|
|
{ 0, 1, 0, 1, 0, 0 }, /* 90° flipped */
|
|
|
|
{ 1, 0, 0, 0, -1, 1 }, /* 180° flipped */
|
|
|
|
{ 0, -1, 1, -1, 0, 1 }, /* 270° flipped */
|
|
|
|
};
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
static int signals[SIGNALS_LAST];
|
|
|
|
|
2013-07-23 13:32:17 -04:00
|
|
|
static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface);
|
|
|
|
|
2014-03-31 21:50:09 -04:00
|
|
|
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));
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-29 07:00:15 -04:00
|
|
|
static void initialize_dbus_interface (MetaMonitorManager *manager);
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_init (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-12-12 22:03:22 -05:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_set_primary_logical_monitor (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitor *logical_monitor)
|
|
|
|
{
|
|
|
|
manager->primary_logical_monitor = logical_monitor;
|
|
|
|
if (logical_monitor)
|
|
|
|
meta_logical_monitor_make_primary (logical_monitor);
|
|
|
|
}
|
|
|
|
|
2016-12-02 02:48:53 -05:00
|
|
|
static gboolean
|
|
|
|
is_main_tiled_monitor_output (MetaOutput *output)
|
|
|
|
{
|
|
|
|
return output->tile_info.loc_h_tile == 0 && output->tile_info.loc_v_tile == 0;
|
|
|
|
}
|
|
|
|
|
2016-12-12 22:03:22 -05:00
|
|
|
static MetaLogicalMonitor *
|
|
|
|
logical_monitor_from_layout (MetaMonitorManager *manager,
|
|
|
|
GList *logical_monitors,
|
|
|
|
MetaRectangle *layout)
|
2015-03-30 21:08:34 -04:00
|
|
|
{
|
2016-12-12 22:03:22 -05:00
|
|
|
GList *l;
|
2015-03-30 21:08:34 -04:00
|
|
|
|
2016-12-12 22:03:22 -05:00
|
|
|
for (l = logical_monitors; l; l = l->next)
|
2015-03-30 21:08:34 -04:00
|
|
|
{
|
2016-12-12 22:03:22 -05:00
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
2015-03-30 21:08:34 -04:00
|
|
|
|
2016-12-12 22:03:22 -05:00
|
|
|
if (meta_rectangle_equal (layout, &logical_monitor->rect))
|
|
|
|
return logical_monitor;
|
2015-03-30 21:08:34 -04:00
|
|
|
}
|
|
|
|
|
2016-12-12 22:03:22 -05:00
|
|
|
return NULL;
|
2016-12-02 02:48:53 -05:00
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_rebuild_logical_monitors (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
|
|
|
{
|
2017-01-12 00:47:54 -05:00
|
|
|
GList *logical_monitor_configs;
|
2017-01-09 01:31:18 -05:00
|
|
|
GList *logical_monitors = NULL;
|
|
|
|
GList *l;
|
|
|
|
int monitor_number = 0;
|
|
|
|
MetaLogicalMonitor *primary_logical_monitor = NULL;
|
|
|
|
|
2017-01-12 00:47:54 -05:00
|
|
|
logical_monitor_configs = config ? config->logical_monitor_configs : NULL;
|
|
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
MetaLogicalMonitor *logical_monitor;
|
|
|
|
|
2017-03-06 23:34:38 -05:00
|
|
|
logical_monitor = meta_logical_monitor_new (manager,
|
|
|
|
logical_monitor_config,
|
|
|
|
monitor_number);
|
2017-01-09 01:31:18 -05:00
|
|
|
monitor_number++;
|
|
|
|
|
|
|
|
if (logical_monitor_config->is_primary)
|
|
|
|
primary_logical_monitor = logical_monitor;
|
|
|
|
|
|
|
|
logical_monitors = g_list_append (logical_monitors, logical_monitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If no monitor was marked as primary, fall back on marking the first
|
|
|
|
* logical monitor the primary one.
|
|
|
|
*/
|
|
|
|
if (!primary_logical_monitor && logical_monitors)
|
|
|
|
primary_logical_monitor = g_list_first (logical_monitors)->data;
|
|
|
|
|
|
|
|
manager->logical_monitors = logical_monitors;
|
|
|
|
meta_monitor_manager_set_primary_logical_monitor (manager,
|
|
|
|
primary_logical_monitor);
|
|
|
|
}
|
|
|
|
|
2016-12-02 02:48:53 -05:00
|
|
|
static void
|
2017-03-06 23:34:38 -05:00
|
|
|
derive_monitor_layout (MetaMonitor *monitor,
|
|
|
|
MetaRectangle *layout)
|
2016-12-02 02:48:53 -05:00
|
|
|
{
|
2016-12-12 22:03:22 -05:00
|
|
|
MetaOutput *main_output;
|
2015-03-30 21:08:34 -04:00
|
|
|
|
2016-12-12 22:03:22 -05:00
|
|
|
main_output = meta_monitor_get_main_output (monitor);
|
2017-03-06 23:34:38 -05:00
|
|
|
layout->x = main_output->crtc->rect.x;
|
|
|
|
layout->y = main_output->crtc->rect.y;
|
2015-03-30 21:08:34 -04:00
|
|
|
|
2017-03-06 23:34:38 -05:00
|
|
|
meta_monitor_derive_dimensions (monitor, &layout->width, &layout->height);
|
2016-12-02 02:48:53 -05:00
|
|
|
}
|
2015-03-30 21:08:34 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
static void
|
2017-01-06 00:27:21 -05:00
|
|
|
meta_monitor_manager_rebuild_logical_monitors_derived (MetaMonitorManager *manager)
|
2013-07-19 08:39:28 -04:00
|
|
|
{
|
2016-12-02 03:00:03 -05:00
|
|
|
GList *logical_monitors = NULL;
|
2016-12-12 22:03:22 -05:00
|
|
|
GList *l;
|
2016-12-02 03:00:03 -05:00
|
|
|
int monitor_number;
|
2016-12-12 22:03:22 -05:00
|
|
|
MetaLogicalMonitor *primary_logical_monitor = NULL;
|
2013-07-19 08:39:28 -04:00
|
|
|
|
2016-12-02 03:00:03 -05:00
|
|
|
monitor_number = 0;
|
2013-07-19 08:39:28 -04:00
|
|
|
|
2016-12-12 22:03:22 -05:00
|
|
|
for (l = manager->monitors; l; l = l->next)
|
2013-07-19 08:39:28 -04:00
|
|
|
{
|
2016-12-12 22:03:22 -05:00
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaLogicalMonitor *logical_monitor;
|
|
|
|
MetaRectangle layout;
|
2013-07-19 08:39:28 -04:00
|
|
|
|
2016-12-12 22:03:22 -05:00
|
|
|
if (!meta_monitor_is_active (monitor))
|
2013-07-19 08:39:28 -04:00
|
|
|
continue;
|
|
|
|
|
2017-03-06 23:34:38 -05:00
|
|
|
derive_monitor_layout (monitor, &layout);
|
2016-12-12 22:03:22 -05:00
|
|
|
logical_monitor = logical_monitor_from_layout (manager, logical_monitors,
|
|
|
|
&layout);
|
|
|
|
if (logical_monitor)
|
2013-07-19 08:39:28 -04:00
|
|
|
{
|
2016-12-12 22:03:22 -05:00
|
|
|
meta_logical_monitor_add_monitor (logical_monitor, monitor);
|
2013-07-19 08:39:28 -04:00
|
|
|
}
|
2016-12-12 22:03:22 -05:00
|
|
|
else
|
2013-07-19 08:39:28 -04:00
|
|
|
{
|
2017-03-06 23:34:38 -05:00
|
|
|
logical_monitor = meta_logical_monitor_new_derived (manager,
|
|
|
|
monitor,
|
|
|
|
&layout,
|
|
|
|
monitor_number);
|
2016-12-02 03:00:03 -05:00
|
|
|
logical_monitors = g_list_append (logical_monitors, logical_monitor);
|
|
|
|
monitor_number++;
|
2013-07-19 08:39:28 -04:00
|
|
|
}
|
|
|
|
|
2016-12-12 22:03:22 -05:00
|
|
|
if (meta_monitor_is_primary (monitor))
|
|
|
|
primary_logical_monitor = logical_monitor;
|
2013-07-19 08:39:28 -04:00
|
|
|
}
|
|
|
|
|
2016-12-02 03:00:03 -05:00
|
|
|
manager->logical_monitors = logical_monitors;
|
2015-03-30 21:11:12 -04:00
|
|
|
|
2016-11-28 07:43:27 -05:00
|
|
|
/*
|
|
|
|
* If no monitor was marked as primary, fall back on marking the first
|
|
|
|
* logical monitor the primary one.
|
|
|
|
*/
|
2016-12-12 22:03:22 -05:00
|
|
|
if (!primary_logical_monitor && manager->logical_monitors)
|
|
|
|
primary_logical_monitor = g_list_first (manager->logical_monitors)->data;
|
|
|
|
|
|
|
|
meta_monitor_manager_set_primary_logical_monitor (manager,
|
|
|
|
primary_logical_monitor);
|
2013-07-19 08:39:28 -04:00
|
|
|
}
|
|
|
|
|
2014-09-25 21:39:14 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-01-09 21:38:06 -05:00
|
|
|
void
|
|
|
|
meta_monitor_manager_lid_is_closed_changed (MetaMonitorManager *manager)
|
|
|
|
{
|
2017-01-10 00:17:16 -05:00
|
|
|
if (manager->config_manager)
|
|
|
|
meta_monitor_manager_ensure_configured (manager);
|
|
|
|
|
2017-01-09 21:38:06 -05:00
|
|
|
g_signal_emit (manager, signals[LID_IS_CLOSED_CHANGED], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-01-12 00:47:54 -05:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_is_headless (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return !manager->monitors;
|
|
|
|
}
|
|
|
|
|
2017-01-06 00:27:21 -05:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager)->ensure_initial_config (manager);
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_apply_monitors_config (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
return manager_class->apply_monitors_config (manager, config, error);
|
|
|
|
}
|
|
|
|
|
2016-12-19 02:56:50 -05:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < manager->n_outputs; i++)
|
|
|
|
{
|
|
|
|
MetaOutput *output = &manager->outputs[i];
|
|
|
|
|
|
|
|
if (output->hotplug_mode_update)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-01-12 22:01:27 -05:00
|
|
|
static gboolean
|
|
|
|
should_use_stored_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return !meta_monitor_manager_has_hotplug_mode_update (manager);
|
|
|
|
}
|
|
|
|
|
2016-12-19 02:22:07 -05:00
|
|
|
static void
|
|
|
|
legacy_ensure_configured (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
if (!meta_monitor_config_apply_stored (manager->legacy_config, manager))
|
|
|
|
meta_monitor_config_make_default (manager->legacy_config, manager);
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaMonitorsConfig *
|
2017-01-06 00:27:21 -05:00
|
|
|
meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
|
|
|
|
{
|
2017-01-09 01:31:18 -05:00
|
|
|
MetaMonitorsConfig *config = NULL;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (!manager->config_manager)
|
|
|
|
{
|
|
|
|
legacy_ensure_configured (manager);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-01-12 22:01:27 -05:00
|
|
|
if (should_use_stored_config (manager))
|
|
|
|
{
|
|
|
|
config = meta_monitor_config_manager_get_stored (manager->config_manager);
|
|
|
|
if (config)
|
|
|
|
{
|
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager, config,
|
|
|
|
&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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-09 02:38:17 -05:00
|
|
|
config = meta_monitor_config_manager_create_suggested (manager->config_manager);
|
|
|
|
if (config)
|
|
|
|
{
|
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager, config, &error))
|
|
|
|
{
|
|
|
|
g_clear_object (&config);
|
|
|
|
g_warning ("Failed to use suggested monitor configuration: %s",
|
|
|
|
error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
config = meta_monitor_config_manager_create_linear (manager->config_manager);
|
2017-01-12 00:47:54 -05:00
|
|
|
if (config)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
2017-01-12 00:47:54 -05:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager, config, &error))
|
|
|
|
{
|
|
|
|
g_clear_object (&config);
|
|
|
|
g_warning ("Failed to use linear monitor configuration: %s",
|
|
|
|
error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
2017-01-09 01:31:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
config = meta_monitor_config_manager_create_fallback (manager->config_manager);
|
2017-01-12 00:47:54 -05:00
|
|
|
if (config)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
2017-01-12 00:47:54 -05:00
|
|
|
if (!meta_monitor_manager_apply_monitors_config (manager, config, &error))
|
|
|
|
{
|
|
|
|
g_clear_object (&config);
|
|
|
|
g_warning ("Failed to use fallback monitor configuration: %s",
|
2017-01-09 01:31:18 -05:00
|
|
|
error->message);
|
2017-01-12 00:47:54 -05:00
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
2017-01-09 01:31:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2017-01-12 00:47:54 -05:00
|
|
|
meta_monitor_config_manager_set_current (manager->config_manager, config);
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
if (!config)
|
2017-01-12 00:47:54 -05:00
|
|
|
{
|
|
|
|
meta_monitor_manager_rebuild (manager, NULL);
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-01-09 01:31:18 -05:00
|
|
|
|
|
|
|
g_object_unref (config);
|
|
|
|
|
|
|
|
return config;
|
2017-01-06 00:27:21 -05:00
|
|
|
}
|
|
|
|
|
2013-07-29 07:00:15 -04:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_constructed (GObject *object)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
2017-01-09 21:38:06 -05:00
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (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);
|
|
|
|
}
|
2013-07-29 07:00:15 -04:00
|
|
|
|
2014-09-25 21:39:14 -04:00
|
|
|
g_signal_connect_object (manager, "notify::power-save-mode",
|
|
|
|
G_CALLBACK (power_save_mode_changed), manager, 0);
|
|
|
|
|
2013-07-29 07:00:15 -04:00
|
|
|
manager->in_init = TRUE;
|
2013-07-22 12:57:12 -04:00
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
if (g_strcmp0 (g_getenv ("MUTTER_USE_CONFIG_MANAGER"), "1") == 0)
|
|
|
|
manager->config_manager = meta_monitor_config_manager_new (manager);
|
|
|
|
else
|
2017-01-09 21:38:06 -05:00
|
|
|
manager->legacy_config = meta_monitor_config_new (manager);
|
2013-07-22 12:57:12 -04:00
|
|
|
|
2016-12-19 02:46:31 -05:00
|
|
|
meta_monitor_manager_read_current_state (manager);
|
2013-07-24 09:35:47 -04:00
|
|
|
|
2017-01-06 00:27:21 -05:00
|
|
|
meta_monitor_manager_ensure_initial_config (manager);
|
2013-07-25 04:57:59 -04:00
|
|
|
|
2013-07-29 07:00:15 -04:00
|
|
|
initialize_dbus_interface (manager);
|
2013-07-25 04:57:59 -04:00
|
|
|
|
|
|
|
manager->in_init = FALSE;
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
2015-10-27 10:02:43 -04:00
|
|
|
void
|
|
|
|
meta_monitor_manager_clear_output (MetaOutput *output)
|
|
|
|
{
|
|
|
|
g_free (output->name);
|
|
|
|
g_free (output->vendor);
|
|
|
|
g_free (output->product);
|
|
|
|
g_free (output->serial);
|
|
|
|
g_free (output->modes);
|
|
|
|
g_free (output->possible_crtcs);
|
|
|
|
g_free (output->possible_clones);
|
|
|
|
|
|
|
|
if (output->driver_notify)
|
|
|
|
output->driver_notify (output);
|
|
|
|
|
|
|
|
memset (output, 0, sizeof (*output));
|
|
|
|
}
|
|
|
|
|
2014-10-12 16:35:55 -04:00
|
|
|
static void
|
2013-09-02 09:04:05 -04:00
|
|
|
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
|
|
|
|
int n_old_outputs)
|
2013-07-18 07:09:16 -04:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < n_old_outputs; i++)
|
2015-10-27 10:02:43 -04:00
|
|
|
meta_monitor_manager_clear_output (&old_outputs[i]);
|
2013-07-19 08:39:28 -04:00
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
g_free (old_outputs);
|
|
|
|
}
|
|
|
|
|
2015-10-27 10:02:43 -04:00
|
|
|
void
|
2016-12-09 02:49:54 -05:00
|
|
|
meta_monitor_manager_clear_mode (MetaCrtcMode *mode)
|
2015-10-27 10:02:43 -04:00
|
|
|
{
|
|
|
|
g_free (mode->name);
|
|
|
|
|
|
|
|
if (mode->driver_notify)
|
|
|
|
mode->driver_notify (mode);
|
|
|
|
|
|
|
|
memset (mode, 0, sizeof (*mode));
|
|
|
|
}
|
|
|
|
|
2014-10-12 16:35:55 -04:00
|
|
|
static void
|
2016-12-09 02:49:54 -05:00
|
|
|
meta_monitor_manager_free_mode_array (MetaCrtcMode *old_modes,
|
|
|
|
int n_old_modes)
|
2013-07-30 05:36:18 -04:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < n_old_modes; i++)
|
2015-10-27 10:02:43 -04:00
|
|
|
meta_monitor_manager_clear_mode (&old_modes[i]);
|
2013-07-30 05:36:18 -04:00
|
|
|
|
|
|
|
g_free (old_modes);
|
|
|
|
}
|
|
|
|
|
2015-10-27 10:02:43 -04:00
|
|
|
void
|
2016-12-07 23:15:28 -05:00
|
|
|
meta_monitor_manager_clear_crtc (MetaCrtc *crtc)
|
2015-10-27 10:02:43 -04:00
|
|
|
{
|
|
|
|
if (crtc->driver_notify)
|
|
|
|
crtc->driver_notify (crtc);
|
|
|
|
|
|
|
|
memset (crtc, 0, sizeof (*crtc));
|
|
|
|
}
|
|
|
|
|
2015-04-27 20:42:10 -04:00
|
|
|
static void
|
2016-12-07 23:15:28 -05:00
|
|
|
meta_monitor_manager_free_crtc_array (MetaCrtc *old_crtcs,
|
2015-04-27 20:42:10 -04:00
|
|
|
int n_old_crtcs)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < n_old_crtcs; i++)
|
2015-10-27 10:02:43 -04:00
|
|
|
meta_monitor_manager_clear_crtc (&old_crtcs[i]);
|
2015-04-27 20:42:10 -04:00
|
|
|
|
|
|
|
g_free (old_crtcs);
|
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
|
|
|
|
2013-09-02 09:04:05 -04:00
|
|
|
meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs);
|
2013-07-30 05:36:18 -04:00
|
|
|
meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes);
|
2015-04-27 20:42:10 -04:00
|
|
|
meta_monitor_manager_free_crtc_array (manager->crtcs, manager->n_crtcs);
|
2016-12-02 03:08:59 -05:00
|
|
|
g_list_free_full (manager->logical_monitors, g_object_unref);
|
2013-07-18 07:09:16 -04:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
g_clear_object (&manager->config_manager);
|
2017-01-09 21:38:06 -05:00
|
|
|
g_clear_object (&manager->up_client);
|
2017-01-09 01:31:18 -05:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
2014-04-01 10:24:10 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
2013-07-29 07:00:15 -04:00
|
|
|
object_class->constructed = meta_monitor_manager_constructed;
|
2013-07-19 08:39:28 -04:00
|
|
|
object_class->dispose = meta_monitor_manager_dispose;
|
2013-07-18 07:09:16 -04:00
|
|
|
object_class->finalize = meta_monitor_manager_finalize;
|
|
|
|
|
2014-04-01 10:24:10 -04:00
|
|
|
klass->get_edid_file = meta_monitor_manager_real_get_edid_file;
|
|
|
|
klass->read_edid = meta_monitor_manager_real_read_edid;
|
2017-01-09 21:38:06 -05:00
|
|
|
klass->is_lid_closed = meta_monitor_manager_real_is_lid_closed;
|
2014-04-01 10:24:10 -04:00
|
|
|
|
2013-07-29 04:12:24 -04:00
|
|
|
signals[CONFIRM_DISPLAY_CHANGE] =
|
|
|
|
g_signal_new ("confirm-display-change",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
2017-01-09 21:38:06 -05:00
|
|
|
|
|
|
|
signals[LID_IS_CLOSED_CHANGED] =
|
|
|
|
g_signal_new ("lid-is-closed-changed",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
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 *
|
2013-08-16 11:32:50 -04:00
|
|
|
make_display_name (MetaMonitorManager *manager,
|
|
|
|
MetaOutput *output)
|
2013-07-19 08:39:28 -04:00
|
|
|
{
|
2015-05-29 20:17:34 -04:00
|
|
|
g_autofree char *inches = NULL;
|
|
|
|
g_autofree char *vendor_name = NULL;
|
2014-01-06 21:26:03 -05:00
|
|
|
|
2016-04-21 11:29:44 -04:00
|
|
|
if (meta_output_is_laptop (output))
|
2015-05-29 20:17:34 -04:00
|
|
|
return g_strdup (_("Built-in display"));
|
2013-08-16 11:32:50 -04:00
|
|
|
|
2014-01-06 21:26:03 -05:00
|
|
|
if (output->width_mm > 0 && output->height_mm > 0)
|
2013-07-19 08:39:28 -04:00
|
|
|
{
|
|
|
|
double d = sqrt (output->width_mm * output->width_mm +
|
|
|
|
output->height_mm * output->height_mm);
|
2014-01-06 21:26:03 -05:00
|
|
|
inches = diagonal_to_str (d / 25.4);
|
|
|
|
}
|
2013-08-16 11:32:50 -04:00
|
|
|
|
2014-01-06 21:26:03 -05:00
|
|
|
if (g_strcmp0 (output->vendor, "unknown") != 0)
|
|
|
|
{
|
|
|
|
if (!manager->pnp_ids)
|
|
|
|
manager->pnp_ids = gnome_pnp_ids_new ();
|
2013-08-16 11:32:50 -04:00
|
|
|
|
2014-01-06 21:26:03 -05:00
|
|
|
vendor_name = gnome_pnp_ids_get_pnp_id (manager->pnp_ids,
|
|
|
|
output->vendor);
|
2013-08-16 11:32:50 -04:00
|
|
|
|
2014-01-06 21:26:03 -05:00
|
|
|
if (!vendor_name)
|
|
|
|
vendor_name = g_strdup (output->vendor);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (inches != NULL)
|
|
|
|
vendor_name = g_strdup (_("Unknown"));
|
2013-08-16 11:32:50 -04:00
|
|
|
else
|
2014-01-06 21:26:03 -05:00
|
|
|
vendor_name = g_strdup (_("Unknown Display"));
|
|
|
|
}
|
2013-07-19 08:39:28 -04:00
|
|
|
|
2014-01-06 21:26:03 -05:00
|
|
|
if (inches != NULL)
|
|
|
|
{
|
|
|
|
/* TRANSLATORS: this is a monitor vendor name, followed by a
|
|
|
|
* size in inches, like 'Dell 15"'
|
|
|
|
*/
|
2015-05-29 20:17:34 -04:00
|
|
|
return g_strdup_printf (_("%s %s"), vendor_name, inches);
|
2013-07-19 08:39:28 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-29 20:17:34 -04:00
|
|
|
return g_strdup (vendor_name);
|
2013-07-19 08:39:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-29 19:18:24 -05:00
|
|
|
static const char *
|
|
|
|
get_connector_type_name (MetaConnectorType connector_type)
|
|
|
|
{
|
|
|
|
switch (connector_type)
|
|
|
|
{
|
|
|
|
case META_CONNECTOR_TYPE_Unknown: return "Unknown";
|
|
|
|
case META_CONNECTOR_TYPE_VGA: return "VGA";
|
|
|
|
case META_CONNECTOR_TYPE_DVII: return "DVII";
|
|
|
|
case META_CONNECTOR_TYPE_DVID: return "DVID";
|
|
|
|
case META_CONNECTOR_TYPE_DVIA: return "DVIA";
|
|
|
|
case META_CONNECTOR_TYPE_Composite: return "Composite";
|
|
|
|
case META_CONNECTOR_TYPE_SVIDEO: return "SVIDEO";
|
|
|
|
case META_CONNECTOR_TYPE_LVDS: return "LVDS";
|
|
|
|
case META_CONNECTOR_TYPE_Component: return "Component";
|
|
|
|
case META_CONNECTOR_TYPE_9PinDIN: return "9PinDIN";
|
|
|
|
case META_CONNECTOR_TYPE_DisplayPort: return "DisplayPort";
|
|
|
|
case META_CONNECTOR_TYPE_HDMIA: return "HDMIA";
|
|
|
|
case META_CONNECTOR_TYPE_HDMIB: return "HDMIB";
|
|
|
|
case META_CONNECTOR_TYPE_TV: return "TV";
|
|
|
|
case META_CONNECTOR_TYPE_eDP: return "eDP";
|
|
|
|
case META_CONNECTOR_TYPE_VIRTUAL: return "VIRTUAL";
|
|
|
|
case META_CONNECTOR_TYPE_DSI: return "DSI";
|
|
|
|
default: g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
static gboolean
|
2013-07-23 13:32:17 -04:00
|
|
|
meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation)
|
2013-07-19 08:39:28 -04:00
|
|
|
{
|
2013-07-23 13:32:17 -04:00
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
2013-08-08 07:32:05 -04:00
|
|
|
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_GET_CLASS (skeleton);
|
2013-07-19 08:39:28 -04:00
|
|
|
GVariantBuilder crtc_builder, output_builder, mode_builder;
|
|
|
|
unsigned int i, j;
|
|
|
|
|
|
|
|
g_variant_builder_init (&crtc_builder, G_VARIANT_TYPE ("a(uxiiiiiuaua{sv})"));
|
2013-07-19 12:47:01 -04:00
|
|
|
g_variant_builder_init (&output_builder, G_VARIANT_TYPE ("a(uxiausauaua{sv})"));
|
2015-04-21 11:49:55 -04:00
|
|
|
g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uxuudu)"));
|
2013-07-19 08:39:28 -04:00
|
|
|
|
|
|
|
for (i = 0; i < manager->n_crtcs; i++)
|
|
|
|
{
|
2016-12-07 23:15:28 -05:00
|
|
|
MetaCrtc *crtc = &manager->crtcs[i];
|
2013-07-19 08:39:28 -04:00
|
|
|
GVariantBuilder transforms;
|
|
|
|
|
|
|
|
g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au"));
|
2014-07-10 17:39:47 -04:00
|
|
|
for (j = 0; j <= META_MONITOR_TRANSFORM_FLIPPED_270; j++)
|
2013-07-24 04:01:57 -04:00
|
|
|
if (crtc->all_transforms & (1 << j))
|
|
|
|
g_variant_builder_add (&transforms, "u", j);
|
2013-07-19 08:39:28 -04:00
|
|
|
|
|
|
|
g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})",
|
|
|
|
i, /* ID */
|
2013-09-02 03:29:26 -04:00
|
|
|
(gint64)crtc->crtc_id,
|
2013-07-19 08:39:28 -04:00
|
|
|
(int)crtc->rect.x,
|
|
|
|
(int)crtc->rect.y,
|
|
|
|
(int)crtc->rect.width,
|
|
|
|
(int)crtc->rect.height,
|
|
|
|
(int)(crtc->current_mode ? crtc->current_mode - manager->modes : -1),
|
2013-09-02 03:29:26 -04:00
|
|
|
(guint32)crtc->transform,
|
2013-07-19 08:39:28 -04:00
|
|
|
&transforms,
|
|
|
|
NULL /* properties */);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < manager->n_outputs; i++)
|
|
|
|
{
|
|
|
|
MetaOutput *output = &manager->outputs[i];
|
2013-07-19 12:47:01 -04:00
|
|
|
GVariantBuilder crtcs, modes, clones, properties;
|
2013-08-08 07:32:05 -04:00
|
|
|
GBytes *edid;
|
|
|
|
char *edid_file;
|
2013-07-19 08:39:28 -04:00
|
|
|
|
|
|
|
g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au"));
|
|
|
|
for (j = 0; j < output->n_possible_crtcs; j++)
|
|
|
|
g_variant_builder_add (&crtcs, "u",
|
|
|
|
(unsigned)(output->possible_crtcs[j] - manager->crtcs));
|
|
|
|
|
|
|
|
g_variant_builder_init (&modes, G_VARIANT_TYPE ("au"));
|
|
|
|
for (j = 0; j < output->n_modes; j++)
|
|
|
|
g_variant_builder_add (&modes, "u",
|
|
|
|
(unsigned)(output->modes[j] - manager->modes));
|
|
|
|
|
2013-07-19 12:47:01 -04:00
|
|
|
g_variant_builder_init (&clones, G_VARIANT_TYPE ("au"));
|
|
|
|
for (j = 0; j < output->n_possible_clones; j++)
|
|
|
|
g_variant_builder_add (&clones, "u",
|
|
|
|
(unsigned)(output->possible_clones[j] - manager->outputs));
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
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));
|
2013-08-19 11:37:24 -04:00
|
|
|
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));
|
2013-07-19 08:39:28 -04:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "display-name",
|
2013-08-16 11:32:50 -04:00
|
|
|
g_variant_new_take_string (make_display_name (manager, output)));
|
2013-07-25 09:06:09 -04:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "backlight",
|
|
|
|
g_variant_new_int32 (output->backlight));
|
2013-10-17 11:05:59 -04:00
|
|
|
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));
|
2013-07-19 08:39:28 -04:00
|
|
|
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));
|
2014-12-29 19:18:24 -05:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "connector-type",
|
|
|
|
g_variant_new_string (get_connector_type_name (output->connector_type)));
|
2014-04-16 04:20:55 -04:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "underscanning",
|
|
|
|
g_variant_new_boolean (output->is_underscanning));
|
2015-07-01 20:42:46 -04:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "supports-underscanning",
|
|
|
|
g_variant_new_boolean (output->supports_underscanning));
|
2013-07-19 08:39:28 -04:00
|
|
|
|
2013-08-08 07:32:05 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-30 20:44:16 -04:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2013-07-19 12:47:01 -04:00
|
|
|
g_variant_builder_add (&output_builder, "(uxiausauaua{sv})",
|
2013-07-19 08:39:28 -04:00
|
|
|
i, /* ID */
|
2014-07-01 13:23:05 -04:00
|
|
|
(gint64)output->winsys_id,
|
2013-07-19 08:39:28 -04:00
|
|
|
(int)(output->crtc ? output->crtc - manager->crtcs : -1),
|
|
|
|
&crtcs,
|
|
|
|
output->name,
|
|
|
|
&modes,
|
2013-07-19 12:47:01 -04:00
|
|
|
&clones,
|
2013-07-19 08:39:28 -04:00
|
|
|
&properties);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < manager->n_modes; i++)
|
|
|
|
{
|
2016-12-09 02:49:54 -05:00
|
|
|
MetaCrtcMode *mode = &manager->modes[i];
|
2013-07-19 08:39:28 -04:00
|
|
|
|
2015-04-21 11:49:55 -04:00
|
|
|
g_variant_builder_add (&mode_builder, "(uxuudu)",
|
2013-07-19 08:39:28 -04:00
|
|
|
i, /* ID */
|
2013-09-02 03:29:26 -04:00
|
|
|
(gint64)mode->mode_id,
|
|
|
|
(guint32)mode->width,
|
|
|
|
(guint32)mode->height,
|
2015-04-21 11:49:55 -04:00
|
|
|
(double)mode->refresh_rate,
|
|
|
|
(guint32)mode->flags);
|
2013-07-19 08:39:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
meta_dbus_display_config_complete_get_resources (skeleton,
|
|
|
|
invocation,
|
|
|
|
manager->serial,
|
|
|
|
g_variant_builder_end (&crtc_builder),
|
|
|
|
g_variant_builder_end (&output_builder),
|
2013-07-22 07:31:10 -04:00
|
|
|
g_variant_builder_end (&mode_builder),
|
|
|
|
manager->max_screen_width,
|
|
|
|
manager->max_screen_height);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2016-12-09 02:49:54 -05:00
|
|
|
output_can_config (MetaOutput *output,
|
|
|
|
MetaCrtc *crtc,
|
|
|
|
MetaCrtcMode *mode)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
gboolean ok = FALSE;
|
|
|
|
|
|
|
|
for (i = 0; i < output->n_possible_crtcs && !ok; i++)
|
|
|
|
ok = output->possible_crtcs[i] == crtc;
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (mode == NULL)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
ok = FALSE;
|
|
|
|
for (i = 0; i < output->n_modes && !ok; i++)
|
|
|
|
ok = output->modes[i] == mode;
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
output_can_clone (MetaOutput *output,
|
|
|
|
MetaOutput *clone)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
gboolean ok = FALSE;
|
|
|
|
|
|
|
|
for (i = 0; i < output->n_possible_clones && !ok; i++)
|
|
|
|
ok = output->possible_clones[i] == clone;
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2013-07-24 09:35:47 -04:00
|
|
|
void
|
|
|
|
meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
|
2016-12-07 23:15:28 -05:00
|
|
|
MetaCrtcInfo **crtcs,
|
2013-07-24 12:01:31 -04:00
|
|
|
unsigned int n_crtcs,
|
|
|
|
MetaOutputInfo **outputs,
|
|
|
|
unsigned int n_outputs)
|
2013-07-24 09:35:47 -04:00
|
|
|
{
|
2013-07-29 07:00:15 -04:00
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager)->apply_configuration (manager,
|
|
|
|
crtcs, n_crtcs,
|
|
|
|
outputs, n_outputs);
|
2013-07-24 09:35:47 -04:00
|
|
|
}
|
|
|
|
|
2016-12-19 02:22:07 -05:00
|
|
|
static void
|
|
|
|
legacy_restore_previous_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
meta_monitor_config_restore_previous (manager->legacy_config, manager);
|
|
|
|
}
|
|
|
|
|
2013-07-24 09:35:47 -04:00
|
|
|
static gboolean
|
|
|
|
save_config_timeout (gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
if (manager->config_manager)
|
|
|
|
g_assert (!"missing implementation");
|
|
|
|
else
|
|
|
|
legacy_restore_previous_config (manager);
|
2013-07-24 09:35:47 -04:00
|
|
|
|
2013-07-29 04:12:24 -04:00
|
|
|
manager->persistent_timeout_id = 0;
|
2013-07-24 09:35:47 -04:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
static gboolean
|
2016-12-19 02:22:07 -05:00
|
|
|
meta_monitor_manager_legacy_handle_apply_configuration (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
|
|
|
gboolean persistent,
|
|
|
|
GVariant *crtcs,
|
|
|
|
GVariant *outputs)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
2013-07-23 13:32:17 -04:00
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
2013-07-22 07:31:10 -04:00
|
|
|
GVariantIter crtc_iter, output_iter, *nested_outputs;
|
2013-07-24 12:01:31 -04:00
|
|
|
GVariant *properties;
|
2013-07-22 07:31:10 -04:00
|
|
|
guint crtc_id;
|
|
|
|
int new_mode, x, y;
|
2013-07-26 09:31:17 -04:00
|
|
|
int new_screen_width, new_screen_height;
|
2013-07-22 07:31:10 -04:00
|
|
|
guint transform;
|
2014-07-01 13:00:36 -04:00
|
|
|
guint output_index;
|
2013-07-24 12:01:31 -04:00
|
|
|
GPtrArray *crtc_infos, *output_infos;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
if (manager->config_manager)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_ACCESS_DENIED,
|
|
|
|
"Used old configuration API with new configuration system");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
if (serial != manager->serial)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_ACCESS_DENIED,
|
|
|
|
"The requested configuration is based on stale information");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc_infos = g_ptr_array_new_full (g_variant_n_children (crtcs),
|
|
|
|
(GDestroyNotify) meta_crtc_info_free);
|
|
|
|
output_infos = g_ptr_array_new_full (g_variant_n_children (outputs),
|
|
|
|
(GDestroyNotify) meta_output_info_free);
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
/* Validate all arguments */
|
2013-07-26 09:31:17 -04:00
|
|
|
new_screen_width = 0; new_screen_height = 0;
|
2013-07-22 07:31:10 -04:00
|
|
|
g_variant_iter_init (&crtc_iter, crtcs);
|
|
|
|
while (g_variant_iter_loop (&crtc_iter, "(uiiiuaua{sv})",
|
|
|
|
&crtc_id, &new_mode, &x, &y, &transform,
|
|
|
|
&nested_outputs, NULL))
|
|
|
|
{
|
2016-12-07 23:15:28 -05:00
|
|
|
MetaCrtcInfo *crtc_info;
|
2013-07-22 07:31:10 -04:00
|
|
|
MetaOutput *first_output;
|
2016-12-07 23:15:28 -05:00
|
|
|
MetaCrtc *crtc;
|
2016-12-09 02:49:54 -05:00
|
|
|
MetaCrtcMode *mode;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
2016-12-07 23:15:28 -05:00
|
|
|
crtc_info = g_slice_new (MetaCrtcInfo);
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc_info->outputs = g_ptr_array_new ();
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
if (crtc_id >= manager->n_crtcs)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid CRTC id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
crtc = &manager->crtcs[crtc_id];
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc_info->crtc = crtc;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
|
|
|
if (new_mode != -1 && (new_mode < 0 || (unsigned)new_mode >= manager->n_modes))
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid mode id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
mode = new_mode != -1 ? &manager->modes[new_mode] : NULL;
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc_info->mode = mode;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
2013-07-24 04:01:57 -04:00
|
|
|
if (mode)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
2013-07-24 04:01:57 -04:00
|
|
|
int width, height;
|
|
|
|
|
|
|
|
if (meta_monitor_transform_is_rotated (transform))
|
|
|
|
{
|
|
|
|
width = mode->height;
|
|
|
|
height = mode->width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
width = mode->width;
|
|
|
|
height = mode->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x < 0 ||
|
|
|
|
x + width > manager->max_screen_width ||
|
|
|
|
y < 0 ||
|
|
|
|
y + height > manager->max_screen_height)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid CRTC geometry");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2013-07-26 09:31:17 -04:00
|
|
|
|
|
|
|
new_screen_width = MAX (new_screen_width, x + width);
|
|
|
|
new_screen_height = MAX (new_screen_height, y + height);
|
|
|
|
crtc_info->x = x;
|
|
|
|
crtc_info->y = y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
crtc_info->x = 0;
|
|
|
|
crtc_info->y = 0;
|
2013-07-22 07:31:10 -04:00
|
|
|
}
|
|
|
|
|
2015-09-23 19:32:10 -04:00
|
|
|
if (transform > META_MONITOR_TRANSFORM_FLIPPED_270 ||
|
2013-07-24 04:01:57 -04:00
|
|
|
((crtc->all_transforms & (1 << transform)) == 0))
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid transform");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc_info->transform = transform;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
|
|
|
first_output = NULL;
|
2014-07-01 13:00:36 -04:00
|
|
|
while (g_variant_iter_loop (nested_outputs, "u", &output_index))
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
|
|
|
MetaOutput *output;
|
|
|
|
|
2014-07-01 13:00:36 -04:00
|
|
|
if (output_index >= manager->n_outputs)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid output id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2014-07-01 13:00:36 -04:00
|
|
|
output = &manager->outputs[output_index];
|
2013-07-22 07:31:10 -04:00
|
|
|
|
|
|
|
if (!output_can_config (output, crtc, mode))
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Output cannot be assigned to this CRTC or mode");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2013-07-24 12:01:31 -04:00
|
|
|
g_ptr_array_add (crtc_info->outputs, output);
|
2013-07-22 07:31:10 -04:00
|
|
|
|
|
|
|
if (first_output)
|
|
|
|
{
|
|
|
|
if (!output_can_clone (output, first_output))
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Outputs cannot be cloned");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
first_output = output;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!first_output && mode)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Mode specified without outputs?");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2013-07-25 04:57:59 -04:00
|
|
|
|
|
|
|
g_ptr_array_add (crtc_infos, crtc_info);
|
2013-07-22 07:31:10 -04:00
|
|
|
}
|
|
|
|
|
2013-07-26 09:31:17 -04:00
|
|
|
if (new_screen_width == 0 || new_screen_height == 0)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Refusing to disable all outputs");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
g_variant_iter_init (&output_iter, outputs);
|
2014-07-01 13:00:36 -04:00
|
|
|
while (g_variant_iter_loop (&output_iter, "(u@a{sv})", &output_index, &properties))
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaOutputInfo *output_info;
|
2014-04-16 04:20:55 -04:00
|
|
|
gboolean primary, presentation, underscanning;
|
2013-07-24 12:01:31 -04:00
|
|
|
|
2014-07-01 13:00:36 -04:00
|
|
|
if (output_index >= manager->n_outputs)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid output id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2013-07-24 12:01:31 -04:00
|
|
|
|
|
|
|
output_info = g_slice_new0 (MetaOutputInfo);
|
2014-07-01 13:00:36 -04:00
|
|
|
output_info->output = &manager->outputs[output_index];
|
2013-07-24 12:01:31 -04:00
|
|
|
|
|
|
|
if (g_variant_lookup (properties, "primary", "b", &primary))
|
|
|
|
output_info->is_primary = primary;
|
|
|
|
|
|
|
|
if (g_variant_lookup (properties, "presentation", "b", &presentation))
|
|
|
|
output_info->is_presentation = presentation;
|
2013-07-25 04:57:59 -04:00
|
|
|
|
2014-04-16 04:20:55 -04:00
|
|
|
if (g_variant_lookup (properties, "underscanning", "b", &underscanning))
|
|
|
|
output_info->is_underscanning = underscanning;
|
|
|
|
|
2013-07-25 04:57:59 -04:00
|
|
|
g_ptr_array_add (output_infos, output_info);
|
2013-07-22 07:31:10 -04:00
|
|
|
}
|
|
|
|
|
2013-07-24 09:35:47 -04:00
|
|
|
/* If we were in progress of making a persistent change and we see a
|
|
|
|
new request, it's likely that the old one failed in some way, so
|
2013-07-29 04:12:24 -04:00
|
|
|
don't save it, but also don't queue for restoring it.
|
2014-05-02 09:34:02 -04:00
|
|
|
*/
|
2013-07-24 09:35:47 -04:00
|
|
|
if (manager->persistent_timeout_id && persistent)
|
|
|
|
{
|
|
|
|
g_source_remove (manager->persistent_timeout_id);
|
|
|
|
manager->persistent_timeout_id = 0;
|
|
|
|
}
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
meta_monitor_manager_apply_configuration (manager,
|
2016-12-07 23:15:28 -05:00
|
|
|
(MetaCrtcInfo**)crtc_infos->pdata,
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc_infos->len,
|
|
|
|
(MetaOutputInfo**)output_infos->pdata,
|
|
|
|
output_infos->len);
|
|
|
|
|
|
|
|
g_ptr_array_unref (crtc_infos);
|
|
|
|
g_ptr_array_unref (output_infos);
|
2013-07-24 09:35:47 -04:00
|
|
|
|
|
|
|
/* Update MetaMonitorConfig data structures immediately so that we
|
2013-07-29 04:12:24 -04:00
|
|
|
don't revert the change at the next XRandR event, then ask the plugin
|
|
|
|
manager (through MetaScreen) to confirm the display change with the
|
|
|
|
appropriate UI. Then wait 20 seconds and if not confirmed, revert the
|
|
|
|
configuration.
|
2013-07-24 09:35:47 -04:00
|
|
|
*/
|
2016-12-19 02:22:07 -05:00
|
|
|
meta_monitor_config_update_current (manager->legacy_config, manager);
|
2013-07-24 09:35:47 -04:00
|
|
|
if (persistent)
|
2013-07-29 04:12:24 -04:00
|
|
|
{
|
|
|
|
manager->persistent_timeout_id = g_timeout_add_seconds (20, save_config_timeout, manager);
|
2014-04-10 12:58:58 -04:00
|
|
|
g_source_set_name_by_id (manager->persistent_timeout_id, "[mutter] save_config_timeout");
|
2013-07-29 04:12:24 -04:00
|
|
|
g_signal_emit (manager, signals[CONFIRM_DISPLAY_CHANGE], 0);
|
|
|
|
}
|
2013-07-22 07:31:10 -04:00
|
|
|
|
|
|
|
meta_dbus_display_config_complete_apply_configuration (skeleton, invocation);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2013-07-19 08:39:28 -04:00
|
|
|
|
2016-12-19 02:22:07 -05:00
|
|
|
static void
|
|
|
|
legacy_confirm_configuration (MetaMonitorManager *manager,
|
|
|
|
gboolean confirmed)
|
|
|
|
{
|
|
|
|
if (confirmed)
|
|
|
|
meta_monitor_config_make_persistent (manager->legacy_config);
|
|
|
|
else
|
|
|
|
meta_monitor_config_restore_previous (manager->legacy_config, manager);
|
|
|
|
}
|
|
|
|
|
2013-07-29 04:12:24 -04:00
|
|
|
void
|
|
|
|
meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager,
|
|
|
|
gboolean ok)
|
|
|
|
{
|
|
|
|
if (!manager->persistent_timeout_id)
|
|
|
|
{
|
|
|
|
/* too late */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_source_remove (manager->persistent_timeout_id);
|
|
|
|
manager->persistent_timeout_id = 0;
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
if (manager->config_manager)
|
|
|
|
g_assert (!"not implemented");
|
|
|
|
else
|
|
|
|
legacy_confirm_configuration (manager, ok);
|
2013-07-29 04:12:24 -04:00
|
|
|
}
|
|
|
|
|
2013-07-25 09:06:09 -04:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
2014-07-01 13:00:36 -04:00
|
|
|
guint output_index,
|
2013-07-25 09:06:09 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-07-01 13:00:36 -04:00
|
|
|
if (output_index >= manager->n_outputs)
|
2013-07-25 09:06:09 -04:00
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid output id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2014-07-01 13:00:36 -04:00
|
|
|
output = &manager->outputs[output_index];
|
2013-07-25 09:06:09 -04:00
|
|
|
|
|
|
|
if (value < 0 || value > 100)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid backlight value");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-07-29 07:00:15 -04:00
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager)->change_backlight (manager, output, value);
|
2013-07-25 09:06:09 -04:00
|
|
|
|
2013-08-26 11:27:33 -04:00
|
|
|
meta_dbus_display_config_complete_change_backlight (skeleton, invocation, output->backlight);
|
2013-07-25 09:06:09 -04:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-26 09:57:34 -04:00
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_get_crtc_gamma (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
|
|
|
guint crtc_id)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
2013-07-29 07:00:15 -04:00
|
|
|
MetaMonitorManagerClass *klass;
|
2016-12-07 23:15:28 -05:00
|
|
|
MetaCrtc *crtc;
|
2013-07-26 09:57:34 -04:00
|
|
|
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 >= manager->n_crtcs)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid crtc id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
crtc = &manager->crtcs[crtc_id];
|
|
|
|
|
2013-07-29 07:00:15 -04:00
|
|
|
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
if (klass->get_crtc_gamma)
|
|
|
|
klass->get_crtc_gamma (manager, crtc, &size, &red, &green, &blue);
|
2013-07-26 09:57:34 -04:00
|
|
|
else
|
2013-07-29 07:00:15 -04:00
|
|
|
{
|
|
|
|
size = 0;
|
|
|
|
red = green = blue = NULL;
|
|
|
|
}
|
2013-07-26 09:57:34 -04:00
|
|
|
|
|
|
|
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);
|
2013-07-29 07:00:15 -04:00
|
|
|
MetaMonitorManagerClass *klass;
|
2016-12-07 23:15:28 -05:00
|
|
|
MetaCrtc *crtc;
|
2013-07-26 09:57:34 -04:00
|
|
|
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 >= manager->n_crtcs)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid crtc id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
crtc = &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);
|
|
|
|
|
2013-07-29 07:00:15 -04:00
|
|
|
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
if (klass->set_crtc_gamma)
|
|
|
|
klass->set_crtc_gamma (manager, crtc, size, red, green, blue);
|
2013-07-26 09:57:34 -04:00
|
|
|
|
|
|
|
meta_dbus_display_config_complete_set_crtc_gamma (skeleton, invocation);
|
|
|
|
|
|
|
|
g_bytes_unref (red_bytes);
|
|
|
|
g_bytes_unref (green_bytes);
|
|
|
|
g_bytes_unref (blue_bytes);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-23 13:32:17 -04:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface)
|
|
|
|
{
|
|
|
|
iface->handle_get_resources = meta_monitor_manager_handle_get_resources;
|
2016-12-19 02:22:07 -05:00
|
|
|
iface->handle_apply_configuration = meta_monitor_manager_legacy_handle_apply_configuration;
|
2013-07-25 09:06:09 -04:00
|
|
|
iface->handle_change_backlight = meta_monitor_manager_handle_change_backlight;
|
2013-07-26 09:57:34 -04:00
|
|
|
iface->handle_get_crtc_gamma = meta_monitor_manager_handle_get_crtc_gamma;
|
|
|
|
iface->handle_set_crtc_gamma = meta_monitor_manager_handle_set_crtc_gamma;
|
2013-07-23 13:32:17 -04:00
|
|
|
}
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
static void
|
|
|
|
on_bus_acquired (GDBusConnection *connection,
|
|
|
|
const char *name,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
|
2013-07-23 13:32:17 -04:00
|
|
|
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager),
|
2013-07-19 08:39:28 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-01-30 08:51:18 -05:00
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get:
|
|
|
|
*
|
|
|
|
* Accessor for the singleton MetaMonitorManager.
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): The only #MetaMonitorManager there is.
|
|
|
|
*/
|
2013-07-18 07:09:16 -04:00
|
|
|
MetaMonitorManager *
|
|
|
|
meta_monitor_manager_get (void)
|
|
|
|
{
|
2014-04-21 19:41:11 -04:00
|
|
|
MetaBackend *backend = meta_get_backend ();
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2014-04-21 19:41:11 -04:00
|
|
|
return meta_backend_get_monitor_manager (backend);
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
2016-11-28 07:11:24 -05:00
|
|
|
int
|
|
|
|
meta_monitor_manager_get_num_logical_monitors (MetaMonitorManager *manager)
|
|
|
|
{
|
2016-12-02 03:00:03 -05:00
|
|
|
return g_list_length (manager->logical_monitors);
|
2016-11-28 07:11:24 -05:00
|
|
|
}
|
|
|
|
|
2016-12-02 03:00:03 -05:00
|
|
|
GList *
|
|
|
|
meta_monitor_manager_get_logical_monitors (MetaMonitorManager *manager)
|
2013-07-18 07:09:16 -04:00
|
|
|
{
|
2016-11-25 01:31:38 -05:00
|
|
|
return manager->logical_monitors;
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
2016-11-28 22:46:41 -05:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_logical_monitor_from_number (MetaMonitorManager *manager,
|
|
|
|
int number)
|
|
|
|
{
|
2016-12-02 03:00:03 -05:00
|
|
|
g_assert ((unsigned int) number < g_list_length (manager->logical_monitors));
|
2016-11-28 22:46:41 -05:00
|
|
|
|
2016-12-02 03:00:03 -05:00
|
|
|
return g_list_nth (manager->logical_monitors, number)->data;
|
2016-11-28 22:46:41 -05:00
|
|
|
}
|
|
|
|
|
2016-11-28 07:43:27 -05:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_primary_logical_monitor (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return manager->primary_logical_monitor;
|
|
|
|
}
|
|
|
|
|
2016-12-19 01:58:44 -05:00
|
|
|
static MetaMonitor *
|
|
|
|
find_monitor (MetaMonitorManager *monitor_manager,
|
|
|
|
gboolean (*match_func) (MetaMonitor *monitor))
|
|
|
|
{
|
|
|
|
GList *monitors;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
monitors = meta_monitor_manager_get_monitors (monitor_manager);
|
|
|
|
for (l = monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
|
|
|
if (match_func (monitor))
|
|
|
|
return monitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-12-20 23:38:13 -05:00
|
|
|
MetaMonitor *
|
|
|
|
meta_monitor_manager_get_primary_monitor (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return find_monitor (manager, meta_monitor_is_primary);
|
|
|
|
}
|
|
|
|
|
2016-12-19 01:58:44 -05:00
|
|
|
MetaMonitor *
|
|
|
|
meta_monitor_manager_get_laptop_panel (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return find_monitor (manager, meta_monitor_is_laptop_panel);
|
|
|
|
}
|
|
|
|
|
2016-12-20 23:41:53 -05:00
|
|
|
MetaMonitor *
|
|
|
|
meta_monitor_manager_get_monitor_from_spec (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorSpec *monitor_spec)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
|
|
|
if (meta_monitor_spec_equals (meta_monitor_get_spec (monitor),
|
|
|
|
monitor_spec))
|
|
|
|
return monitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-29 21:49:00 -05:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_logical_monitor_at (MetaMonitorManager *manager,
|
2016-12-01 02:37:32 -05:00
|
|
|
float x,
|
|
|
|
float y)
|
2016-11-29 21:49:00 -05:00
|
|
|
{
|
2016-12-02 03:00:03 -05:00
|
|
|
GList *l;
|
2016-11-29 21:49:00 -05:00
|
|
|
|
2016-12-02 03:00:03 -05:00
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
2016-11-29 21:49:00 -05:00
|
|
|
{
|
2016-12-02 03:00:03 -05:00
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
|
|
|
|
|
|
|
if (POINT_IN_RECT (x, y, logical_monitor->rect))
|
|
|
|
return logical_monitor;
|
2016-11-29 21:49:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-30 23:52:07 -05:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_logical_monitor_from_rect (MetaMonitorManager *manager,
|
|
|
|
MetaRectangle *rect)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitor *best_logical_monitor;
|
|
|
|
int best_logical_monitor_area;
|
2016-12-02 03:00:03 -05:00
|
|
|
GList *l;
|
2016-11-30 23:52:07 -05:00
|
|
|
|
|
|
|
best_logical_monitor = NULL;
|
|
|
|
best_logical_monitor_area = 0;
|
|
|
|
|
2016-12-02 03:00:03 -05:00
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
2016-11-30 23:52:07 -05:00
|
|
|
{
|
2016-12-02 03:00:03 -05:00
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
2016-11-30 23:52:07 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-12-01 02:15:52 -05:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_monitor_manager_get_logical_monitor_neighbor (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitor *logical_monitor,
|
|
|
|
MetaScreenDirection direction)
|
|
|
|
{
|
2016-12-02 03:00:03 -05:00
|
|
|
GList *l;
|
2016-12-01 02:15:52 -05:00
|
|
|
|
2016-12-02 03:00:03 -05:00
|
|
|
for (l = manager->logical_monitors; l; l = l->next)
|
2016-12-01 02:15:52 -05:00
|
|
|
{
|
2016-12-02 03:00:03 -05:00
|
|
|
MetaLogicalMonitor *other = l->data;
|
2016-12-01 02:15:52 -05:00
|
|
|
|
|
|
|
switch (direction)
|
|
|
|
{
|
|
|
|
case META_SCREEN_RIGHT:
|
|
|
|
if (other->rect.x == (logical_monitor->rect.x +
|
|
|
|
logical_monitor->rect.width) &&
|
|
|
|
meta_rectangle_vert_overlap (&other->rect,
|
|
|
|
&logical_monitor->rect))
|
|
|
|
return other;
|
|
|
|
break;
|
|
|
|
case META_SCREEN_LEFT:
|
|
|
|
if (logical_monitor->rect.x == (other->rect.x +
|
|
|
|
other->rect.width) &&
|
|
|
|
meta_rectangle_vert_overlap (&other->rect,
|
|
|
|
&logical_monitor->rect))
|
|
|
|
return other;
|
|
|
|
break;
|
|
|
|
case META_SCREEN_UP:
|
|
|
|
if (logical_monitor->rect.y == (other->rect.y +
|
|
|
|
other->rect.height) &&
|
|
|
|
meta_rectangle_horiz_overlap (&other->rect,
|
|
|
|
&logical_monitor->rect))
|
|
|
|
return other;
|
|
|
|
break;
|
|
|
|
case META_SCREEN_DOWN:
|
|
|
|
if (other->rect.y == (logical_monitor->rect.y +
|
|
|
|
logical_monitor->rect.height) &&
|
|
|
|
meta_rectangle_horiz_overlap (&other->rect,
|
|
|
|
&logical_monitor->rect))
|
|
|
|
return other;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-12-12 21:53:38 -05:00
|
|
|
GList *
|
|
|
|
meta_monitor_manager_get_monitors (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return manager->monitors;
|
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
MetaOutput *
|
|
|
|
meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
|
2013-07-24 09:35:47 -04:00
|
|
|
unsigned int *n_outputs)
|
2013-07-18 07:09:16 -04:00
|
|
|
{
|
|
|
|
*n_outputs = manager->n_outputs;
|
|
|
|
return manager->outputs;
|
|
|
|
}
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
void
|
|
|
|
meta_monitor_manager_get_resources (MetaMonitorManager *manager,
|
2016-12-09 02:49:54 -05:00
|
|
|
MetaCrtcMode **modes,
|
2013-07-24 12:01:31 -04:00
|
|
|
unsigned int *n_modes,
|
2016-12-07 23:15:28 -05:00
|
|
|
MetaCrtc **crtcs,
|
2013-07-24 12:01:31 -04:00
|
|
|
unsigned int *n_crtcs,
|
|
|
|
MetaOutput **outputs,
|
|
|
|
unsigned int *n_outputs)
|
|
|
|
{
|
2013-09-05 10:45:41 -04:00
|
|
|
if (modes)
|
|
|
|
{
|
|
|
|
*modes = manager->modes;
|
|
|
|
*n_modes = manager->n_modes;
|
|
|
|
}
|
|
|
|
if (crtcs)
|
|
|
|
{
|
|
|
|
*crtcs = manager->crtcs;
|
|
|
|
*n_crtcs = manager->n_crtcs;
|
|
|
|
}
|
|
|
|
if (outputs)
|
|
|
|
{
|
|
|
|
*outputs = manager->outputs;
|
|
|
|
*n_outputs = manager->n_outputs;
|
|
|
|
}
|
2013-07-24 12:01:31 -04:00
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
void
|
2013-07-22 12:57:12 -04:00
|
|
|
meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
|
|
|
|
int *width,
|
|
|
|
int *height)
|
|
|
|
{
|
|
|
|
*width = manager->screen_width;
|
|
|
|
*height = manager->screen_height;
|
|
|
|
}
|
|
|
|
|
2013-07-25 04:57:59 -04:00
|
|
|
void
|
|
|
|
meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
|
|
|
|
int *width,
|
|
|
|
int *height)
|
|
|
|
{
|
|
|
|
*width = manager->max_screen_width;
|
|
|
|
*height = manager->max_screen_height;
|
|
|
|
}
|
|
|
|
|
2016-12-12 21:53:38 -05:00
|
|
|
static void
|
|
|
|
rebuild_monitors (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (manager->monitors)
|
|
|
|
{
|
|
|
|
g_list_free_full (manager->monitors, g_object_unref);
|
|
|
|
manager->monitors = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < manager->n_outputs; i++)
|
|
|
|
{
|
|
|
|
MetaOutput *output = &manager->outputs[i];
|
|
|
|
|
|
|
|
if (output->tile_info.group_id)
|
|
|
|
{
|
|
|
|
if (is_main_tiled_monitor_output (output))
|
|
|
|
{
|
|
|
|
MetaMonitorTiled *monitor_tiled;
|
|
|
|
|
|
|
|
monitor_tiled = meta_monitor_tiled_new (manager, output);
|
|
|
|
manager->monitors = g_list_append (manager->monitors,
|
|
|
|
monitor_tiled);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MetaMonitorNormal *monitor_normal;
|
|
|
|
|
|
|
|
monitor_normal = meta_monitor_normal_new (output);
|
|
|
|
manager->monitors = g_list_append (manager->monitors,
|
|
|
|
monitor_normal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 05:58:22 -05:00
|
|
|
void
|
|
|
|
meta_monitor_manager_tiled_monitor_added (MetaMonitorManager *manager,
|
|
|
|
MetaMonitor *monitor)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
if (manager_class->tiled_monitor_added)
|
|
|
|
manager_class->tiled_monitor_added (manager, monitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_tiled_monitor_removed (MetaMonitorManager *manager,
|
|
|
|
MetaMonitor *monitor)
|
|
|
|
{
|
|
|
|
MetaMonitorManagerClass *manager_class =
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager);
|
|
|
|
|
|
|
|
if (manager_class->tiled_monitor_removed)
|
|
|
|
manager_class->tiled_monitor_removed (manager, monitor);
|
|
|
|
}
|
|
|
|
|
2017-03-08 03:05:00 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-10-12 16:35:55 -04:00
|
|
|
void
|
2016-12-19 02:46:31 -05:00
|
|
|
meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
|
2014-10-12 16:35:55 -04:00
|
|
|
{
|
|
|
|
MetaOutput *old_outputs;
|
2016-12-07 23:15:28 -05:00
|
|
|
MetaCrtc *old_crtcs;
|
2016-12-09 02:49:54 -05:00
|
|
|
MetaCrtcMode *old_modes;
|
2015-04-27 20:42:10 -04:00
|
|
|
unsigned int n_old_outputs, n_old_crtcs, n_old_modes;
|
2014-10-12 16:35:55 -04:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
n_old_outputs = manager->n_outputs;
|
2015-04-27 20:42:10 -04:00
|
|
|
old_crtcs = manager->crtcs;
|
|
|
|
n_old_crtcs = manager->n_crtcs;
|
2014-10-12 16:35:55 -04:00
|
|
|
old_modes = manager->modes;
|
|
|
|
n_old_modes = manager->n_modes;
|
|
|
|
|
|
|
|
manager->serial++;
|
|
|
|
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
|
|
|
|
|
2016-12-12 21:53:38 -05:00
|
|
|
rebuild_monitors (manager);
|
|
|
|
|
2014-10-12 16:35:55 -04:00
|
|
|
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
|
|
|
|
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
|
2015-04-27 20:42:10 -04:00
|
|
|
meta_monitor_manager_free_crtc_array (old_crtcs, n_old_crtcs);
|
2014-10-12 16:35:55 -04:00
|
|
|
}
|
|
|
|
|
2017-01-06 00:27:21 -05:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_notify_monitors_changed (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaBackend *backend = meta_get_backend ();
|
|
|
|
|
|
|
|
meta_backend_monitors_changed (backend);
|
|
|
|
g_signal_emit_by_name (manager, "monitors-changed");
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:31:18 -05:00
|
|
|
static void
|
|
|
|
set_logical_monitor_modes (MetaMonitorManager *manager,
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = logical_monitor_config->monitor_configs; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitorConfig *monitor_config = l->data;
|
|
|
|
MetaMonitorSpec *monitor_spec;
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
MetaMonitorModeSpec *monitor_mode_spec;
|
|
|
|
MetaMonitorMode *monitor_mode;
|
|
|
|
|
|
|
|
monitor_spec = monitor_config->monitor_spec;
|
|
|
|
monitor = meta_monitor_manager_get_monitor_from_spec (manager,
|
|
|
|
monitor_spec);
|
|
|
|
monitor_mode_spec = monitor_config->mode_spec;
|
|
|
|
monitor_mode = meta_monitor_get_mode_from_spec (monitor,
|
|
|
|
monitor_mode_spec);
|
|
|
|
|
|
|
|
meta_monitor_set_current_mode (monitor, monitor_mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitor_manager_update_monitor_modes (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
|
|
|
{
|
2017-01-12 00:47:54 -05:00
|
|
|
GList *logical_monitor_configs;
|
2017-01-09 01:31:18 -05:00
|
|
|
GList *l;
|
|
|
|
|
2017-01-12 00:47:54 -05:00
|
|
|
logical_monitor_configs = config ? config->logical_monitor_configs : NULL;
|
|
|
|
for (l = logical_monitor_configs; l; l = l->next)
|
2017-01-09 01:31:18 -05:00
|
|
|
{
|
|
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
|
|
|
|
|
|
set_logical_monitor_modes (manager, logical_monitor_config);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
|
|
|
if (!meta_monitor_get_logical_monitor (monitor))
|
|
|
|
meta_monitor_set_current_mode (monitor, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_update_logical_state (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
|
|
|
{
|
|
|
|
meta_monitor_manager_rebuild_logical_monitors (manager, config);
|
|
|
|
meta_monitor_manager_update_monitor_modes (manager, config);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_rebuild (MetaMonitorManager *manager,
|
|
|
|
MetaMonitorsConfig *config)
|
|
|
|
{
|
|
|
|
GList *old_logical_monitors;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-12-22 02:22:13 -05:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_update_monitor_modes_derived (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = manager->monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
|
|
|
|
meta_monitor_derive_current_mode (monitor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-06 00:27:21 -05:00
|
|
|
void
|
|
|
|
meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
meta_monitor_manager_rebuild_logical_monitors_derived (manager);
|
|
|
|
meta_monitor_manager_update_monitor_modes_derived (manager);
|
|
|
|
}
|
|
|
|
|
2013-09-02 09:04:05 -04:00
|
|
|
void
|
|
|
|
meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
|
2013-07-23 04:07:52 -04:00
|
|
|
{
|
2016-12-02 03:00:03 -05:00
|
|
|
GList *old_logical_monitors;
|
2014-10-23 10:31:09 -04:00
|
|
|
|
2013-07-25 04:57:59 -04:00
|
|
|
if (manager->in_init)
|
|
|
|
return;
|
|
|
|
|
2016-12-02 03:00:03 -05:00
|
|
|
old_logical_monitors = manager->logical_monitors;
|
|
|
|
|
2017-01-06 00:27:21 -05:00
|
|
|
meta_monitor_manager_update_logical_state_derived (manager);
|
2016-07-06 03:27:45 -04:00
|
|
|
|
2017-01-06 00:27:21 -05:00
|
|
|
meta_monitor_manager_notify_monitors_changed (manager);
|
2014-10-23 10:31:09 -04:00
|
|
|
|
2016-12-02 03:08:59 -05:00
|
|
|
g_list_free_full (old_logical_monitors, g_object_unref);
|
2013-07-23 04:07:52 -04:00
|
|
|
}
|
2014-10-12 18:13:15 -04:00
|
|
|
|
2015-01-04 15:24:05 -05:00
|
|
|
void
|
|
|
|
meta_output_parse_edid (MetaOutput *meta_output,
|
|
|
|
GBytes *edid)
|
|
|
|
{
|
|
|
|
MonitorInfo *parsed_edid;
|
|
|
|
gsize len;
|
|
|
|
|
2015-01-23 11:32:21 -05:00
|
|
|
if (!edid)
|
|
|
|
goto out;
|
|
|
|
|
2015-01-04 15:24:05 -05:00
|
|
|
parsed_edid = decode_edid (g_bytes_get_data (edid, &len));
|
|
|
|
|
|
|
|
if (parsed_edid)
|
|
|
|
{
|
|
|
|
meta_output->vendor = g_strndup (parsed_edid->manufacturer_code, 4);
|
2015-07-16 12:41:36 -04:00
|
|
|
if (!g_utf8_validate (meta_output->vendor, -1, NULL))
|
|
|
|
g_clear_pointer (&meta_output->vendor, g_free);
|
|
|
|
|
|
|
|
meta_output->product = g_strndup (parsed_edid->dsc_product_name, 14);
|
|
|
|
if (!g_utf8_validate (meta_output->product, -1, NULL) ||
|
|
|
|
meta_output->product[0] == '\0')
|
|
|
|
{
|
|
|
|
g_clear_pointer (&meta_output->product, g_free);
|
|
|
|
meta_output->product = g_strdup_printf ("0x%04x", (unsigned) parsed_edid->product_code);
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_output->serial = g_strndup (parsed_edid->dsc_serial_number, 14);
|
|
|
|
if (!g_utf8_validate (meta_output->serial, -1, NULL) ||
|
|
|
|
meta_output->serial[0] == '\0')
|
|
|
|
{
|
|
|
|
g_clear_pointer (&meta_output->serial, g_free);
|
|
|
|
meta_output->serial = g_strdup_printf ("0x%08x", parsed_edid->serial_number);
|
|
|
|
}
|
2015-01-04 15:24:05 -05:00
|
|
|
|
|
|
|
g_free (parsed_edid);
|
|
|
|
}
|
|
|
|
|
2015-01-23 11:32:21 -05:00
|
|
|
out:
|
2015-01-04 15:24:05 -05:00
|
|
|
if (!meta_output->vendor)
|
2015-07-16 12:41:36 -04:00
|
|
|
meta_output->vendor = g_strdup ("unknown");
|
|
|
|
if (!meta_output->product)
|
|
|
|
meta_output->product = g_strdup ("unknown");
|
|
|
|
if (!meta_output->serial)
|
|
|
|
meta_output->serial = g_strdup ("unknown");
|
2015-01-04 15:24:05 -05:00
|
|
|
}
|
|
|
|
|
2016-04-21 11:29:44 -04:00
|
|
|
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:
|
2016-04-20 13:10:18 -04:00
|
|
|
case META_CONNECTOR_TYPE_DSI:
|
2016-04-21 11:29:44 -04:00
|
|
|
return TRUE;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-19 02:22:07 -05:00
|
|
|
static void
|
|
|
|
legacy_on_hotplug (MetaMonitorManager *manager)
|
2014-10-12 18:13:15 -04:00
|
|
|
{
|
|
|
|
gboolean applied_config = FALSE;
|
|
|
|
|
|
|
|
/* If the monitor has hotplug_mode_update (which is used by VMs), don't bother
|
|
|
|
* applying our stored configuration, because it's likely the user just resizing
|
|
|
|
* the window.
|
|
|
|
*/
|
|
|
|
if (!meta_monitor_manager_has_hotplug_mode_update (manager))
|
|
|
|
{
|
2016-12-19 02:22:07 -05:00
|
|
|
if (meta_monitor_config_apply_stored (manager->legacy_config, manager))
|
2014-10-12 18:13:15 -04:00
|
|
|
applied_config = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we haven't applied any configuration, apply the default configuration. */
|
|
|
|
if (!applied_config)
|
2016-12-19 02:22:07 -05:00
|
|
|
meta_monitor_config_make_default (manager->legacy_config, manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_on_hotplug (MetaMonitorManager *manager)
|
|
|
|
{
|
2017-01-09 01:31:18 -05:00
|
|
|
if (manager->legacy_config)
|
|
|
|
{
|
|
|
|
legacy_on_hotplug (manager);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_monitor_manager_ensure_configured (manager);
|
2014-10-12 18:13:15 -04:00
|
|
|
}
|
2014-12-11 12:14:00 -05:00
|
|
|
|
|
|
|
static gboolean
|
|
|
|
calculate_viewport_matrix (MetaMonitorManager *manager,
|
2017-03-06 23:20:14 -05:00
|
|
|
MetaLogicalMonitor *logical_monitor,
|
2014-12-11 12:14:00 -05:00
|
|
|
gfloat viewport[6])
|
|
|
|
{
|
|
|
|
gfloat x, y, width, height;
|
|
|
|
|
2017-03-06 23:20:14 -05:00
|
|
|
x = (float) logical_monitor->rect.x / manager->screen_width;
|
|
|
|
y = (float) logical_monitor->rect.y / manager->screen_height;
|
|
|
|
width = (float) logical_monitor->rect.width / manager->screen_width;
|
|
|
|
height = (float) logical_monitor->rect.height / manager->screen_height;
|
2014-12-11 12:14:00 -05:00
|
|
|
|
|
|
|
viewport[0] = width;
|
|
|
|
viewport[1] = 0.0f;
|
|
|
|
viewport[2] = x;
|
|
|
|
viewport[3] = 0.0f;
|
|
|
|
viewport[4] = height;
|
|
|
|
viewport[5] = y;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
multiply_matrix (float a[6],
|
|
|
|
float b[6],
|
|
|
|
float res[6])
|
|
|
|
{
|
|
|
|
res[0] = a[0] * b[0] + a[1] * b[3];
|
|
|
|
res[1] = a[0] * b[1] + a[1] * b[4];
|
|
|
|
res[2] = a[0] * b[2] + a[1] * b[5] + a[2];
|
|
|
|
res[3] = a[3] * b[0] + a[4] * b[3];
|
|
|
|
res[4] = a[3] * b[1] + a[4] * b[4];
|
|
|
|
res[5] = a[3] * b[2] + a[4] * b[5] + a[5];
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_get_monitor_matrix (MetaMonitorManager *manager,
|
2017-03-06 23:20:14 -05:00
|
|
|
MetaLogicalMonitor *logical_monitor,
|
2014-12-11 12:14:00 -05:00
|
|
|
gfloat matrix[6])
|
|
|
|
{
|
2017-03-06 23:20:14 -05:00
|
|
|
MetaMonitor *main_monitor;
|
|
|
|
MetaOutput *main_output;
|
|
|
|
MetaMonitorTransform transform;
|
2014-12-11 12:14:00 -05:00
|
|
|
gfloat viewport[9];
|
|
|
|
|
2017-03-06 23:20:14 -05:00
|
|
|
if (!calculate_viewport_matrix (manager, logical_monitor, viewport))
|
2014-12-11 12:14:00 -05:00
|
|
|
return FALSE;
|
|
|
|
|
2017-03-06 23:20:14 -05:00
|
|
|
main_monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
|
|
|
|
main_output = meta_monitor_get_main_output (main_monitor);
|
|
|
|
transform = main_output->crtc->transform;
|
|
|
|
multiply_matrix (viewport, transform_matrices[transform],
|
2014-12-11 12:14:00 -05:00
|
|
|
matrix);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2015-01-30 08:54:09 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_monitor_manager_get_output_geometry:
|
|
|
|
* @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;
|
2016-12-02 03:00:03 -05:00
|
|
|
GList *l;
|
2015-01-30 08:54:09 -05:00
|
|
|
|
|
|
|
g_return_val_if_fail (META_IS_MONITOR_MANAGER (manager), -1);
|
|
|
|
g_return_val_if_fail (id < manager->n_outputs, -1);
|
|
|
|
|
|
|
|
output = &manager->outputs[id];
|
|
|
|
if (!output || !output->crtc)
|
|
|
|
return -1;
|
|
|
|
|
2016-12-02 03:00:03 -05:00
|
|
|
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;
|
|
|
|
}
|
2015-01-30 08:54:09 -05:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2015-03-27 10:48:49 -04:00
|
|
|
|
2016-04-20 14:00:45 -04:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_get_is_builtin_display_on (MetaMonitorManager *manager)
|
|
|
|
{
|
2016-12-19 01:58:44 -05:00
|
|
|
MetaMonitor *laptop_panel;
|
|
|
|
|
2016-04-20 14:00:45 -04:00
|
|
|
g_return_val_if_fail (META_IS_MONITOR_MANAGER (manager), FALSE);
|
|
|
|
|
2016-12-19 01:58:44 -05:00
|
|
|
laptop_panel = meta_monitor_manager_get_laptop_panel (manager);
|
|
|
|
if (!laptop_panel)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return meta_monitor_is_active (laptop_panel);
|
2016-04-20 14:00:45 -04:00
|
|
|
}
|