2013-07-18 07:09:16 -04:00
|
|
|
/* -*- 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
* 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
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>
|
|
|
|
|
|
|
|
#ifdef HAVE_RANDR
|
2013-07-25 05:16:51 -04:00
|
|
|
#include <X11/Xatom.h>
|
2013-07-18 07:09:16 -04:00
|
|
|
#include <X11/extensions/Xrandr.h>
|
2013-07-24 04:39:06 -04:00
|
|
|
#include <X11/extensions/dpms.h>
|
2013-07-18 07:09:16 -04:00
|
|
|
#endif
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
#include <meta/main.h>
|
|
|
|
#include <meta/util.h>
|
2013-07-22 07:31:10 -04:00
|
|
|
#include <meta/errors.h>
|
2013-07-18 07:09:16 -04:00
|
|
|
#include "monitor-private.h"
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
#include "meta-dbus-xrandr.h"
|
|
|
|
|
2013-07-24 04:01:57 -04:00
|
|
|
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
2013-07-22 07:31:10 -04:00
|
|
|
|
|
|
|
typedef enum {
|
2013-07-22 12:57:12 -04:00
|
|
|
META_BACKEND_UNSPECIFIED,
|
2013-07-22 07:31:10 -04:00
|
|
|
META_BACKEND_DUMMY,
|
2013-07-22 12:57:12 -04:00
|
|
|
META_BACKEND_XRANDR
|
|
|
|
} MetaMonitorBackend;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
struct _MetaMonitorManager
|
|
|
|
{
|
2013-07-23 13:32:17 -04:00
|
|
|
MetaDBusDisplayConfigSkeleton parent_instance;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-22 12:57:12 -04:00
|
|
|
MetaMonitorBackend backend;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
/* XXX: this structure is very badly
|
|
|
|
packed, but I like the logical organization
|
|
|
|
of fields */
|
|
|
|
|
2013-07-25 04:57:59 -04:00
|
|
|
gboolean in_init;
|
2013-07-19 08:39:28 -04:00
|
|
|
unsigned int serial;
|
|
|
|
|
2013-07-24 04:39:06 -04:00
|
|
|
MetaPowerSave power_save_mode;
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
int max_screen_width;
|
|
|
|
int max_screen_height;
|
2013-07-22 12:57:12 -04:00
|
|
|
int screen_width;
|
|
|
|
int screen_height;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
/* Outputs refer to physical screens,
|
|
|
|
CRTCs refer to stuff that can drive outputs
|
|
|
|
(like encoders, but less tied to the HW),
|
|
|
|
while monitor_infos refer to logical ones.
|
|
|
|
|
|
|
|
See also the comment in monitor-private.h
|
2013-07-18 07:09:16 -04:00
|
|
|
*/
|
|
|
|
MetaOutput *outputs;
|
2013-07-19 08:39:28 -04:00
|
|
|
unsigned int n_outputs;
|
|
|
|
|
|
|
|
MetaMonitorMode *modes;
|
|
|
|
unsigned int n_modes;
|
|
|
|
|
|
|
|
MetaCRTC *crtcs;
|
|
|
|
unsigned int n_crtcs;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
|
|
|
MetaMonitorInfo *monitor_infos;
|
2013-07-19 08:39:28 -04:00
|
|
|
unsigned int n_monitor_infos;
|
|
|
|
int primary_monitor_index;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
|
|
|
#ifdef HAVE_RANDR
|
|
|
|
Display *xdisplay;
|
2013-07-22 07:31:10 -04:00
|
|
|
XRRScreenResources *resources;
|
|
|
|
int time;
|
2013-07-22 12:57:12 -04:00
|
|
|
int rr_event_base;
|
|
|
|
int rr_error_base;
|
2013-07-18 07:09:16 -04:00
|
|
|
#endif
|
2013-07-19 08:39:28 -04:00
|
|
|
|
|
|
|
int dbus_name_id;
|
2013-07-24 09:35:47 -04:00
|
|
|
|
|
|
|
int persistent_timeout_id;
|
|
|
|
MetaMonitorConfig *config;
|
2013-07-18 07:09:16 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _MetaMonitorManagerClass
|
|
|
|
{
|
2013-07-23 13:32:17 -04:00
|
|
|
MetaDBusDisplayConfigSkeletonClass parent_class;
|
2013-07-18 07:09:16 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
MONITORS_CHANGED,
|
2013-07-29 04:12:24 -04:00
|
|
|
CONFIRM_DISPLAY_CHANGE,
|
2013-07-18 07:09:16 -04:00
|
|
|
SIGNALS_LAST
|
|
|
|
};
|
|
|
|
|
2013-07-24 04:39:06 -04:00
|
|
|
enum {
|
|
|
|
PROP_0,
|
|
|
|
PROP_POWER_SAVE_MODE,
|
|
|
|
PROP_LAST
|
|
|
|
};
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
G_DEFINE_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-24 09:35:47 -04:00
|
|
|
static void free_output_array (MetaOutput *old_outputs,
|
|
|
|
int n_old_outputs);
|
2013-07-23 04:07:52 -04:00
|
|
|
static void invalidate_logical_config (MetaMonitorManager *manager);
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
static void
|
|
|
|
make_dummy_monitor_config (MetaMonitorManager *manager)
|
|
|
|
{
|
2013-07-23 04:07:52 -04:00
|
|
|
/* The dummy monitor config has:
|
|
|
|
- one enabled output, LVDS, primary, at 0x0 and 1024x768
|
|
|
|
- one free CRTC
|
|
|
|
- two disabled outputs
|
|
|
|
- three modes, 1024x768, 800x600 and 640x480
|
|
|
|
- no clones are possible (use different CRTCs)
|
|
|
|
|
|
|
|
Low-level IDs should be assigned sequentially, to
|
|
|
|
mimick what XRandR and KMS do
|
|
|
|
*/
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
manager->backend = META_BACKEND_DUMMY;
|
|
|
|
|
2013-07-22 12:57:12 -04:00
|
|
|
manager->max_screen_width = 65535;
|
|
|
|
manager->max_screen_height = 65535;
|
|
|
|
manager->screen_width = 1024;
|
|
|
|
manager->screen_height = 768;
|
|
|
|
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->modes = g_new0 (MetaMonitorMode, 6);
|
|
|
|
manager->n_modes = 6;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->modes[0].mode_id = 1;
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->modes[0].width = 1024;
|
|
|
|
manager->modes[0].height = 768;
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->modes[0].refresh_rate = 60.0;
|
|
|
|
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->modes[1].mode_id = 2;
|
|
|
|
manager->modes[1].width = 800;
|
|
|
|
manager->modes[1].height = 600;
|
|
|
|
manager->modes[1].refresh_rate = 60.0;
|
|
|
|
|
|
|
|
manager->modes[2].mode_id = 3;
|
|
|
|
manager->modes[2].width = 640;
|
|
|
|
manager->modes[2].height = 480;
|
|
|
|
manager->modes[2].refresh_rate = 60.0;
|
2013-07-19 08:39:28 -04:00
|
|
|
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->modes[3].mode_id = 4;
|
|
|
|
manager->modes[3].width = 1920;
|
|
|
|
manager->modes[3].height = 1080;
|
|
|
|
manager->modes[3].refresh_rate = 60.0;
|
|
|
|
|
|
|
|
manager->modes[4].mode_id = 5;
|
|
|
|
manager->modes[4].width = 1920;
|
|
|
|
manager->modes[4].height = 1080;
|
|
|
|
manager->modes[4].refresh_rate = 55.0;
|
|
|
|
|
|
|
|
manager->modes[5].mode_id = 6;
|
|
|
|
manager->modes[5].width = 1600;
|
|
|
|
manager->modes[5].height = 900;
|
|
|
|
manager->modes[5].refresh_rate = 60.0;
|
|
|
|
|
|
|
|
manager->crtcs = g_new0 (MetaCRTC, 3);
|
|
|
|
manager->n_crtcs = 3;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
|
|
|
manager->crtcs[0].crtc_id = 4;
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->crtcs[0].rect.x = 0;
|
|
|
|
manager->crtcs[0].rect.y = 0;
|
|
|
|
manager->crtcs[0].rect.width = manager->modes[0].width;
|
|
|
|
manager->crtcs[0].rect.height = manager->modes[0].height;
|
|
|
|
manager->crtcs[0].current_mode = &manager->modes[0];
|
2013-07-24 04:01:57 -04:00
|
|
|
manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
|
|
|
manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS;
|
2013-07-22 07:31:10 -04:00
|
|
|
manager->crtcs[0].is_dirty = FALSE;
|
|
|
|
manager->crtcs[0].logical_monitor = NULL;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->crtcs[1].crtc_id = 5;
|
|
|
|
manager->crtcs[1].rect.x = 0;
|
|
|
|
manager->crtcs[1].rect.y = 0;
|
|
|
|
manager->crtcs[1].rect.width = 0;
|
|
|
|
manager->crtcs[1].rect.height = 0;
|
|
|
|
manager->crtcs[1].current_mode = NULL;
|
2013-07-24 04:01:57 -04:00
|
|
|
manager->crtcs[1].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
|
|
|
manager->crtcs[1].all_transforms = ALL_WL_TRANSFORMS;
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->crtcs[1].is_dirty = FALSE;
|
|
|
|
manager->crtcs[1].logical_monitor = NULL;
|
|
|
|
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->crtcs[2].crtc_id = 5;
|
|
|
|
manager->crtcs[2].rect.x = 0;
|
|
|
|
manager->crtcs[2].rect.y = 0;
|
|
|
|
manager->crtcs[2].rect.width = 0;
|
|
|
|
manager->crtcs[2].rect.height = 0;
|
|
|
|
manager->crtcs[2].current_mode = NULL;
|
|
|
|
manager->crtcs[2].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
|
|
|
manager->crtcs[2].all_transforms = ALL_WL_TRANSFORMS;
|
|
|
|
manager->crtcs[2].is_dirty = FALSE;
|
|
|
|
manager->crtcs[2].logical_monitor = NULL;
|
|
|
|
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs = g_new0 (MetaOutput, 3);
|
|
|
|
manager->n_outputs = 3;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->outputs[0].crtc = NULL;
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[0].output_id = 6;
|
2013-07-24 09:35:47 -04:00
|
|
|
manager->outputs[0].name = g_strdup ("HDMI");
|
|
|
|
manager->outputs[0].vendor = g_strdup ("MetaProducts Inc.");
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->outputs[0].product = g_strdup ("unknown");
|
2013-07-24 09:35:47 -04:00
|
|
|
manager->outputs[0].serial = g_strdup ("0xC0F01A");
|
|
|
|
manager->outputs[0].width_mm = 510;
|
|
|
|
manager->outputs[0].height_mm = 287;
|
2013-07-18 07:09:16 -04:00
|
|
|
manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->outputs[0].preferred_mode = &manager->modes[3];
|
|
|
|
manager->outputs[0].n_modes = 5;
|
|
|
|
manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 5);
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->outputs[0].modes[0] = &manager->modes[0];
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[0].modes[1] = &manager->modes[1];
|
|
|
|
manager->outputs[0].modes[2] = &manager->modes[2];
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->outputs[0].modes[3] = &manager->modes[3];
|
|
|
|
manager->outputs[0].modes[4] = &manager->modes[4];
|
|
|
|
manager->outputs[0].n_possible_crtcs = 3;
|
|
|
|
manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 3);
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->outputs[0].possible_crtcs[0] = &manager->crtcs[0];
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[0].possible_crtcs[1] = &manager->crtcs[1];
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->outputs[0].possible_crtcs[2] = &manager->crtcs[2];
|
2013-07-19 12:47:01 -04:00
|
|
|
manager->outputs[0].n_possible_clones = 0;
|
|
|
|
manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0);
|
2013-07-25 09:06:09 -04:00
|
|
|
manager->outputs[0].backlight = -1;
|
|
|
|
manager->outputs[0].backlight_min = 0;
|
|
|
|
manager->outputs[0].backlight_max = 0;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-24 09:35:47 -04:00
|
|
|
manager->outputs[1].crtc = &manager->crtcs[0];
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[1].output_id = 7;
|
2013-07-24 09:35:47 -04:00
|
|
|
manager->outputs[1].name = g_strdup ("LVDS");
|
|
|
|
manager->outputs[1].vendor = g_strdup ("MetaProducts Inc.");
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[1].product = g_strdup ("unknown");
|
2013-07-24 09:35:47 -04:00
|
|
|
manager->outputs[1].serial = g_strdup ("0xC0FFEE");
|
|
|
|
manager->outputs[1].width_mm = 222;
|
|
|
|
manager->outputs[1].height_mm = 125;
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[1].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->outputs[1].preferred_mode = &manager->modes[5];
|
|
|
|
manager->outputs[1].n_modes = 4;
|
|
|
|
manager->outputs[1].modes = g_new0 (MetaMonitorMode *, 4);
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[1].modes[0] = &manager->modes[0];
|
|
|
|
manager->outputs[1].modes[1] = &manager->modes[1];
|
|
|
|
manager->outputs[1].modes[2] = &manager->modes[2];
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->outputs[1].modes[3] = &manager->modes[5];
|
|
|
|
manager->outputs[1].n_possible_crtcs = 3;
|
|
|
|
manager->outputs[1].possible_crtcs = g_new0 (MetaCRTC *, 3);
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[1].possible_crtcs[0] = &manager->crtcs[0];
|
|
|
|
manager->outputs[1].possible_crtcs[1] = &manager->crtcs[1];
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->outputs[1].possible_crtcs[2] = &manager->crtcs[2];
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[1].n_possible_clones = 0;
|
|
|
|
manager->outputs[1].possible_clones = g_new0 (MetaOutput *, 0);
|
2013-07-25 09:06:09 -04:00
|
|
|
manager->outputs[1].backlight = -1;
|
|
|
|
manager->outputs[1].backlight_min = 0;
|
|
|
|
manager->outputs[1].backlight_max = 0;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
|
|
|
manager->outputs[2].crtc = NULL;
|
|
|
|
manager->outputs[2].output_id = 8;
|
|
|
|
manager->outputs[2].name = g_strdup ("VGA");
|
2013-07-24 09:35:47 -04:00
|
|
|
manager->outputs[2].vendor = g_strdup ("MetaProducts Inc.");
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[2].product = g_strdup ("unknown");
|
2013-07-24 09:35:47 -04:00
|
|
|
manager->outputs[2].serial = g_strdup ("0xC4FE");
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[2].width_mm = 309;
|
|
|
|
manager->outputs[2].height_mm = 174;
|
|
|
|
manager->outputs[2].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
|
|
|
manager->outputs[2].preferred_mode = &manager->modes[0];
|
|
|
|
manager->outputs[2].n_modes = 3;
|
|
|
|
manager->outputs[2].modes = g_new0 (MetaMonitorMode *, 3);
|
|
|
|
manager->outputs[2].modes[0] = &manager->modes[0];
|
|
|
|
manager->outputs[2].modes[1] = &manager->modes[1];
|
|
|
|
manager->outputs[2].modes[2] = &manager->modes[2];
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->outputs[2].n_possible_crtcs = 3;
|
|
|
|
manager->outputs[2].possible_crtcs = g_new0 (MetaCRTC *, 3);
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[2].possible_crtcs[0] = &manager->crtcs[0];
|
|
|
|
manager->outputs[2].possible_crtcs[1] = &manager->crtcs[1];
|
2013-07-25 05:54:22 -04:00
|
|
|
manager->outputs[2].possible_crtcs[2] = &manager->crtcs[2];
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[2].n_possible_clones = 0;
|
|
|
|
manager->outputs[2].possible_clones = g_new0 (MetaOutput *, 0);
|
2013-07-25 09:06:09 -04:00
|
|
|
manager->outputs[2].backlight = -1;
|
|
|
|
manager->outputs[2].backlight_min = 0;
|
|
|
|
manager->outputs[2].backlight_max = 0;
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_RANDR
|
2013-07-24 04:01:57 -04:00
|
|
|
static enum wl_output_transform
|
|
|
|
wl_transform_from_xrandr (Rotation rotation)
|
|
|
|
{
|
|
|
|
static const enum wl_output_transform y_reflected_map[4] = {
|
|
|
|
WL_OUTPUT_TRANSFORM_FLIPPED_180,
|
|
|
|
WL_OUTPUT_TRANSFORM_FLIPPED_90,
|
|
|
|
WL_OUTPUT_TRANSFORM_FLIPPED,
|
|
|
|
WL_OUTPUT_TRANSFORM_FLIPPED_270
|
|
|
|
};
|
|
|
|
enum wl_output_transform ret;
|
|
|
|
|
|
|
|
switch (rotation & 0x7F)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case RR_Rotate_0:
|
|
|
|
ret = WL_OUTPUT_TRANSFORM_NORMAL;
|
|
|
|
break;
|
|
|
|
case RR_Rotate_90:
|
|
|
|
ret = WL_OUTPUT_TRANSFORM_90;
|
|
|
|
break;
|
|
|
|
case RR_Rotate_180:
|
|
|
|
ret = WL_OUTPUT_TRANSFORM_180;
|
|
|
|
break;
|
|
|
|
case RR_Rotate_270:
|
|
|
|
ret = WL_OUTPUT_TRANSFORM_270;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rotation & RR_Reflect_X)
|
|
|
|
return ret + 4;
|
|
|
|
else if (rotation & RR_Reflect_Y)
|
|
|
|
return y_reflected_map[ret];
|
|
|
|
else
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ALL_ROTATIONS (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270)
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
wl_transform_from_xrandr_all (Rotation rotation)
|
|
|
|
{
|
|
|
|
unsigned ret;
|
|
|
|
|
|
|
|
/* Handle the common cases first (none or all) */
|
|
|
|
if (rotation == 0 || rotation == RR_Rotate_0)
|
|
|
|
return (1 << WL_OUTPUT_TRANSFORM_NORMAL);
|
|
|
|
|
|
|
|
/* All rotations and one reflection -> all of them by composition */
|
|
|
|
if ((rotation & ALL_ROTATIONS) &&
|
|
|
|
((rotation & RR_Reflect_X) || (rotation & RR_Reflect_Y)))
|
|
|
|
return ALL_WL_TRANSFORMS;
|
|
|
|
|
|
|
|
ret = 1 << WL_OUTPUT_TRANSFORM_NORMAL;
|
|
|
|
if (rotation & RR_Rotate_90)
|
|
|
|
ret |= 1 << WL_OUTPUT_TRANSFORM_90;
|
|
|
|
if (rotation & RR_Rotate_180)
|
|
|
|
ret |= 1 << WL_OUTPUT_TRANSFORM_180;
|
|
|
|
if (rotation & RR_Rotate_270)
|
|
|
|
ret |= 1 << WL_OUTPUT_TRANSFORM_270;
|
|
|
|
if (rotation & (RR_Rotate_0 | RR_Reflect_X))
|
|
|
|
ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED;
|
|
|
|
if (rotation & (RR_Rotate_90 | RR_Reflect_X))
|
|
|
|
ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_90;
|
|
|
|
if (rotation & (RR_Rotate_180 | RR_Reflect_X))
|
|
|
|
ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_180;
|
|
|
|
if (rotation & (RR_Rotate_270 | RR_Reflect_X))
|
|
|
|
ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_270;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-25 05:16:51 -04:00
|
|
|
static gboolean
|
|
|
|
output_get_presentation_xrandr (MetaMonitorManager *manager,
|
|
|
|
MetaOutput *output)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_get_display ();
|
|
|
|
gboolean value;
|
|
|
|
Atom actual_type;
|
|
|
|
int actual_format;
|
|
|
|
unsigned long nitems, bytes_after;
|
|
|
|
unsigned char *buffer;
|
|
|
|
|
|
|
|
XRRGetOutputProperty (manager->xdisplay,
|
|
|
|
(XID)output->output_id,
|
|
|
|
display->atom__MUTTER_PRESENTATION_OUTPUT,
|
|
|
|
0, G_MAXLONG, False, False, XA_CARDINAL,
|
|
|
|
&actual_type, &actual_format,
|
|
|
|
&nitems, &bytes_after, &buffer);
|
|
|
|
|
|
|
|
if (actual_type != XA_CARDINAL || actual_format != 32 ||
|
|
|
|
nitems < 1)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
value = ((int*)buffer)[0];
|
|
|
|
|
|
|
|
XFree (buffer);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2013-07-25 09:06:09 -04:00
|
|
|
static int
|
|
|
|
normalize_backlight (MetaOutput *output,
|
|
|
|
int hw_value)
|
|
|
|
{
|
|
|
|
return round ((double)(hw_value - output->backlight_min) /
|
|
|
|
(output->backlight_max - output->backlight_min) * 100.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
output_get_backlight_xrandr (MetaMonitorManager *manager,
|
|
|
|
MetaOutput *output)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_get_display ();
|
|
|
|
gboolean value;
|
|
|
|
Atom actual_type;
|
|
|
|
int actual_format;
|
|
|
|
unsigned long nitems, bytes_after;
|
|
|
|
unsigned char *buffer;
|
|
|
|
|
|
|
|
XRRGetOutputProperty (manager->xdisplay,
|
|
|
|
(XID)output->output_id,
|
|
|
|
display->atom_BACKLIGHT,
|
|
|
|
0, G_MAXLONG, False, False, XA_INTEGER,
|
|
|
|
&actual_type, &actual_format,
|
|
|
|
&nitems, &bytes_after, &buffer);
|
|
|
|
|
|
|
|
if (actual_type != XA_INTEGER || actual_format != 32 ||
|
|
|
|
nitems < 1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
value = ((int*)buffer)[0];
|
|
|
|
|
|
|
|
XFree (buffer);
|
|
|
|
return normalize_backlight (output, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
output_get_backlight_limits_xrandr (MetaMonitorManager *manager,
|
|
|
|
MetaOutput *output)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_get_display ();
|
|
|
|
XRRPropertyInfo *info;
|
|
|
|
|
|
|
|
meta_error_trap_push (display);
|
|
|
|
info = XRRQueryOutputProperty (manager->xdisplay,
|
|
|
|
(XID)output->output_id,
|
|
|
|
display->atom_BACKLIGHT);
|
|
|
|
meta_error_trap_pop (display);
|
|
|
|
|
|
|
|
if (info == NULL)
|
|
|
|
{
|
|
|
|
meta_warning ("could not get output property for %s\n", output->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!info->range || info->num_values != 2)
|
|
|
|
{
|
|
|
|
meta_verbose ("backlight %s was not range\n", output->name);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
output->backlight_min = info->values[0];
|
|
|
|
output->backlight_max = info->values[1];
|
|
|
|
|
|
|
|
out:
|
|
|
|
XFree (info);
|
|
|
|
}
|
|
|
|
|
2013-07-24 09:35:47 -04:00
|
|
|
static int
|
|
|
|
compare_outputs (const void *one,
|
|
|
|
const void *two)
|
|
|
|
{
|
|
|
|
const MetaOutput *o_one = one, *o_two = two;
|
|
|
|
|
|
|
|
return strcmp (o_one->name, o_two->name);
|
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
static void
|
|
|
|
read_monitor_infos_from_xrandr (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
XRRScreenResources *resources;
|
2013-07-19 08:39:28 -04:00
|
|
|
RROutput primary_output;
|
|
|
|
unsigned int i, j, k;
|
|
|
|
unsigned int n_actual_outputs;
|
2013-07-22 07:31:10 -04:00
|
|
|
int min_width, min_height;
|
2013-07-22 12:57:12 -04:00
|
|
|
Screen *screen;
|
2013-07-24 04:39:06 -04:00
|
|
|
BOOL dpms_capable, dpms_enabled;
|
|
|
|
CARD16 dpms_state;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
|
|
|
if (manager->resources)
|
|
|
|
XRRFreeScreenResources (manager->resources);
|
|
|
|
manager->resources = NULL;
|
|
|
|
|
2013-07-24 04:39:06 -04:00
|
|
|
meta_error_trap_push (meta_get_display ());
|
|
|
|
dpms_capable = DPMSCapable (manager->xdisplay);
|
|
|
|
meta_error_trap_pop (meta_get_display ());
|
|
|
|
|
|
|
|
if (dpms_capable &&
|
|
|
|
DPMSInfo (manager->xdisplay, &dpms_state, &dpms_enabled) &&
|
|
|
|
dpms_enabled)
|
|
|
|
{
|
|
|
|
switch (dpms_state)
|
|
|
|
{
|
|
|
|
case DPMSModeOn:
|
|
|
|
manager->power_save_mode = META_POWER_SAVE_ON;
|
|
|
|
case DPMSModeStandby:
|
|
|
|
manager->power_save_mode = META_POWER_SAVE_STANDBY;
|
|
|
|
case DPMSModeSuspend:
|
|
|
|
manager->power_save_mode = META_POWER_SAVE_SUSPEND;
|
|
|
|
case DPMSModeOff:
|
|
|
|
manager->power_save_mode = META_POWER_SAVE_OFF;
|
|
|
|
default:
|
|
|
|
manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
XRRGetScreenSizeRange (manager->xdisplay, DefaultRootWindow (manager->xdisplay),
|
|
|
|
&min_width,
|
|
|
|
&min_height,
|
|
|
|
&manager->max_screen_width,
|
|
|
|
&manager->max_screen_height);
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-22 12:57:12 -04:00
|
|
|
screen = ScreenOfDisplay (manager->xdisplay,
|
|
|
|
DefaultScreen (manager->xdisplay));
|
|
|
|
/* This is updated because we called RRUpdateConfiguration below */
|
|
|
|
manager->screen_width = WidthOfScreen (screen);
|
|
|
|
manager->screen_height = HeightOfScreen (screen);
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
resources = XRRGetScreenResourcesCurrent (manager->xdisplay,
|
|
|
|
DefaultRootWindow (manager->xdisplay));
|
|
|
|
if (!resources)
|
|
|
|
return make_dummy_monitor_config (manager);
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
manager->resources = resources;
|
|
|
|
manager->time = resources->configTimestamp;
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->n_outputs = resources->noutput;
|
|
|
|
manager->n_crtcs = resources->ncrtc;
|
|
|
|
manager->n_modes = resources->nmode;
|
|
|
|
manager->outputs = g_new0 (MetaOutput, manager->n_outputs);
|
|
|
|
manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
|
|
|
|
manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
for (i = 0; i < (unsigned)resources->nmode; i++)
|
|
|
|
{
|
|
|
|
XRRModeInfo *xmode = &resources->modes[i];
|
|
|
|
MetaMonitorMode *mode;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
mode = &manager->modes[i];
|
|
|
|
|
|
|
|
mode->mode_id = xmode->id;
|
|
|
|
mode->width = xmode->width;
|
|
|
|
mode->height = xmode->height;
|
|
|
|
mode->refresh_rate = (xmode->dotClock /
|
|
|
|
((float)xmode->hTotal * xmode->vTotal));
|
|
|
|
}
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
for (i = 0; i < (unsigned)resources->ncrtc; i++)
|
2013-07-18 07:09:16 -04:00
|
|
|
{
|
|
|
|
XRRCrtcInfo *crtc;
|
2013-07-19 08:39:28 -04:00
|
|
|
MetaCRTC *meta_crtc;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
|
|
|
crtc = XRRGetCrtcInfo (manager->xdisplay, resources, resources->crtcs[i]);
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
meta_crtc = &manager->crtcs[i];
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
meta_crtc->crtc_id = resources->crtcs[i];
|
|
|
|
meta_crtc->rect.x = crtc->x;
|
|
|
|
meta_crtc->rect.y = crtc->y;
|
|
|
|
meta_crtc->rect.width = crtc->width;
|
|
|
|
meta_crtc->rect.height = crtc->height;
|
2013-07-22 07:31:10 -04:00
|
|
|
meta_crtc->is_dirty = FALSE;
|
2013-07-24 04:01:57 -04:00
|
|
|
meta_crtc->transform = wl_transform_from_xrandr (crtc->rotation);
|
|
|
|
meta_crtc->all_transforms = wl_transform_from_xrandr_all (crtc->rotations);
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
for (j = 0; j < (unsigned)resources->nmode; j++)
|
2013-07-18 07:09:16 -04:00
|
|
|
{
|
|
|
|
if (resources->modes[j].id == crtc->mode)
|
2013-07-19 08:39:28 -04:00
|
|
|
{
|
|
|
|
meta_crtc->current_mode = &manager->modes[j];
|
|
|
|
break;
|
|
|
|
}
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
XRRFreeCrtcInfo (crtc);
|
|
|
|
}
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
primary_output = XRRGetOutputPrimary (manager->xdisplay,
|
|
|
|
DefaultRootWindow (manager->xdisplay));
|
|
|
|
|
|
|
|
n_actual_outputs = 0;
|
|
|
|
for (i = 0; i < (unsigned)resources->noutput; i++)
|
|
|
|
{
|
|
|
|
XRROutputInfo *output;
|
|
|
|
MetaOutput *meta_output;
|
|
|
|
|
|
|
|
output = XRRGetOutputInfo (manager->xdisplay, resources, resources->outputs[i]);
|
|
|
|
|
|
|
|
meta_output = &manager->outputs[n_actual_outputs];
|
|
|
|
|
|
|
|
if (output->connection != RR_Disconnected)
|
|
|
|
{
|
|
|
|
meta_output->output_id = resources->outputs[i];
|
|
|
|
meta_output->name = g_strdup (output->name);
|
|
|
|
/* FIXME: to fill useful values for these we need an EDID parser */
|
|
|
|
meta_output->vendor = g_strdup ("unknown");
|
|
|
|
meta_output->product = g_strdup ("unknown");
|
|
|
|
meta_output->serial = g_strdup ("");
|
|
|
|
meta_output->width_mm = output->mm_width;
|
|
|
|
meta_output->height_mm = output->mm_height;
|
|
|
|
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
|
|
|
|
|
|
|
meta_output->n_modes = output->nmode;
|
|
|
|
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
|
|
|
|
for (j = 0; j < meta_output->n_modes; j++)
|
|
|
|
{
|
|
|
|
for (k = 0; k < manager->n_modes; k++)
|
|
|
|
{
|
|
|
|
if (output->modes[j] == (XID)manager->modes[k].mode_id)
|
|
|
|
{
|
|
|
|
meta_output->modes[j] = &manager->modes[k];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
meta_output->preferred_mode = meta_output->modes[0];
|
|
|
|
|
2013-07-25 04:57:59 -04:00
|
|
|
if (meta_output->preferred_mode == NULL)
|
|
|
|
meta_output->preferred_mode = meta_output->modes[0];
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
meta_output->n_possible_crtcs = output->ncrtc;
|
|
|
|
meta_output->possible_crtcs = g_new0 (MetaCRTC *, meta_output->n_possible_crtcs);
|
|
|
|
for (j = 0; j < (unsigned)output->ncrtc; j++)
|
|
|
|
{
|
|
|
|
for (k = 0; k < manager->n_crtcs; k++)
|
|
|
|
{
|
|
|
|
if ((XID)manager->crtcs[k].crtc_id == output->crtcs[j])
|
|
|
|
{
|
|
|
|
meta_output->possible_crtcs[j] = &manager->crtcs[k];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_output->crtc = NULL;
|
|
|
|
for (j = 0; j < manager->n_crtcs; j++)
|
|
|
|
{
|
|
|
|
if ((XID)manager->crtcs[j].crtc_id == output->crtc)
|
|
|
|
{
|
|
|
|
meta_output->crtc = &manager->crtcs[j];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-19 12:47:01 -04:00
|
|
|
meta_output->n_possible_clones = output->nclone;
|
|
|
|
meta_output->possible_clones = g_new0 (MetaOutput *, meta_output->n_possible_clones);
|
|
|
|
/* We can build the list of clones now, because we don't have the list of outputs
|
|
|
|
yet, so temporarily set the pointers to the bare XIDs, and then we'll fix them
|
|
|
|
in a second pass
|
|
|
|
*/
|
|
|
|
for (j = 0; j < (unsigned)output->nclone; j++)
|
|
|
|
{
|
|
|
|
meta_output->possible_clones = GINT_TO_POINTER (output->clones[j]);
|
|
|
|
}
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
meta_output->is_primary = ((XID)meta_output->output_id == primary_output);
|
2013-07-25 05:16:51 -04:00
|
|
|
meta_output->is_presentation = output_get_presentation_xrandr (manager, meta_output);
|
2013-07-25 09:06:09 -04:00
|
|
|
output_get_backlight_limits_xrandr (manager, meta_output);
|
|
|
|
|
|
|
|
if (!(meta_output->backlight_min == 0 && meta_output->backlight_max == 0))
|
|
|
|
meta_output->backlight = output_get_backlight_xrandr (manager, meta_output);
|
|
|
|
else
|
|
|
|
meta_output->backlight = -1;
|
2013-07-19 08:39:28 -04:00
|
|
|
|
|
|
|
n_actual_outputs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
XRRFreeOutputInfo (output);
|
|
|
|
}
|
|
|
|
|
|
|
|
manager->n_outputs = n_actual_outputs;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-24 09:35:47 -04:00
|
|
|
/* Sort the outputs for easier handling in MetaMonitorConfig */
|
|
|
|
qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
|
|
|
|
|
2013-07-19 12:47:01 -04:00
|
|
|
/* Now fix the clones */
|
|
|
|
for (i = 0; i < manager->n_outputs; i++)
|
|
|
|
{
|
|
|
|
MetaOutput *meta_output;
|
|
|
|
|
|
|
|
meta_output = &manager->outputs[i];
|
|
|
|
|
|
|
|
for (j = 0; j < meta_output->n_possible_clones; j++)
|
|
|
|
{
|
|
|
|
RROutput clone = GPOINTER_TO_INT (meta_output->possible_clones[j]);
|
|
|
|
|
|
|
|
for (k = 0; k < manager->n_outputs; k++)
|
|
|
|
{
|
|
|
|
if (clone == (XID)manager->outputs[k].output_id)
|
|
|
|
{
|
|
|
|
meta_output->possible_clones[j] = &manager->outputs[k];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* meta_has_dummy_output:
|
|
|
|
*
|
|
|
|
* Returns TRUE if the only available monitor is the dummy one
|
|
|
|
* backing the ClutterStage window.
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
has_dummy_output (void)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitor_manager_init (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-07-22 12:57:12 -04:00
|
|
|
static MetaMonitorBackend
|
2013-07-19 08:39:28 -04:00
|
|
|
make_debug_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
const char *env;
|
|
|
|
|
|
|
|
env = g_getenv ("META_DEBUG_MULTIMONITOR");
|
|
|
|
|
|
|
|
if (env == NULL)
|
2013-07-22 12:57:12 -04:00
|
|
|
return META_BACKEND_UNSPECIFIED;
|
2013-07-19 08:39:28 -04:00
|
|
|
|
|
|
|
#ifdef HAVE_RANDR
|
|
|
|
if (strcmp (env, "xrandr") == 0)
|
2013-07-22 12:57:12 -04:00
|
|
|
return META_BACKEND_XRANDR;
|
2013-07-19 08:39:28 -04:00
|
|
|
else
|
|
|
|
#endif
|
2013-07-22 12:57:12 -04:00
|
|
|
return META_BACKEND_DUMMY;
|
2013-07-19 08:39:28 -04:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
static void
|
|
|
|
read_current_config (MetaMonitorManager *manager)
|
|
|
|
{
|
2013-07-24 09:35:47 -04:00
|
|
|
manager->serial++;
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
#ifdef HAVE_RANDR
|
2013-07-22 12:57:12 -04:00
|
|
|
if (manager->backend == META_BACKEND_XRANDR)
|
|
|
|
return read_monitor_infos_from_xrandr (manager);
|
2013-07-18 07:09:16 -04:00
|
|
|
#endif
|
2013-07-22 12:57:12 -04:00
|
|
|
|
|
|
|
return make_dummy_monitor_config (manager);
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
/*
|
|
|
|
* make_logical_config:
|
|
|
|
*
|
|
|
|
* Turn outputs and CRTCs into logical MetaMonitorInfo,
|
|
|
|
* that will be used by the core and API layer (MetaScreen
|
|
|
|
* and friends)
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
make_logical_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
GArray *monitor_infos;
|
|
|
|
unsigned int i, j;
|
|
|
|
|
|
|
|
monitor_infos = g_array_sized_new (FALSE, TRUE, sizeof (MetaMonitorInfo),
|
|
|
|
manager->n_outputs);
|
|
|
|
|
|
|
|
/* Walk the list of MetaCRTCs, and build a MetaMonitorInfo
|
|
|
|
for each of them, unless they reference a rectangle that
|
|
|
|
is already there.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < manager->n_crtcs; i++)
|
|
|
|
{
|
|
|
|
MetaCRTC *crtc = &manager->crtcs[i];
|
|
|
|
|
|
|
|
/* Ignore CRTCs not in use */
|
|
|
|
if (crtc->current_mode == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; j < monitor_infos->len; j++)
|
|
|
|
{
|
|
|
|
MetaMonitorInfo *info = &g_array_index (monitor_infos, MetaMonitorInfo, i);
|
|
|
|
if (meta_rectangle_equal (&crtc->rect,
|
|
|
|
&info->rect))
|
|
|
|
{
|
|
|
|
crtc->logical_monitor = info;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (crtc->logical_monitor == NULL)
|
|
|
|
{
|
|
|
|
MetaMonitorInfo info;
|
|
|
|
|
|
|
|
info.number = monitor_infos->len;
|
|
|
|
info.rect = crtc->rect;
|
|
|
|
info.is_primary = FALSE;
|
|
|
|
/* This starts true because we want
|
|
|
|
is_presentation only if all outputs are
|
|
|
|
marked as such (while for primary it's enough
|
|
|
|
that any is marked)
|
|
|
|
*/
|
|
|
|
info.is_presentation = TRUE;
|
|
|
|
info.in_fullscreen = -1;
|
|
|
|
info.output_id = 0;
|
|
|
|
|
|
|
|
g_array_append_val (monitor_infos, info);
|
|
|
|
|
|
|
|
crtc->logical_monitor = &g_array_index (monitor_infos, MetaMonitorInfo,
|
|
|
|
info.number);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now walk the list of outputs applying extended properties (primary
|
|
|
|
and presentation)
|
|
|
|
*/
|
|
|
|
for (i = 0; i < manager->n_outputs; i++)
|
|
|
|
{
|
|
|
|
MetaOutput *output;
|
|
|
|
MetaMonitorInfo *info;
|
|
|
|
|
|
|
|
output = &manager->outputs[i];
|
|
|
|
|
|
|
|
/* Ignore outputs that are not active */
|
|
|
|
if (output->crtc == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* We must have a logical monitor on every CRTC at this point */
|
|
|
|
g_assert (output->crtc->logical_monitor != NULL);
|
|
|
|
|
|
|
|
info = output->crtc->logical_monitor;
|
|
|
|
|
|
|
|
info->is_primary = info->is_primary || output->is_primary;
|
|
|
|
info->is_presentation = info->is_presentation && output->is_presentation;
|
|
|
|
|
|
|
|
if (output->is_primary || info->output_id == 0)
|
|
|
|
info->output_id = output->output_id;
|
|
|
|
|
|
|
|
if (info->is_primary)
|
|
|
|
manager->primary_monitor_index = info->number;
|
|
|
|
}
|
|
|
|
|
|
|
|
manager->n_monitor_infos = monitor_infos->len;
|
|
|
|
manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
|
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
static MetaMonitorManager *
|
|
|
|
meta_monitor_manager_new (Display *display)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager;
|
|
|
|
|
|
|
|
manager = g_object_new (META_TYPE_MONITOR_MANAGER, NULL);
|
|
|
|
|
2013-07-25 04:57:59 -04:00
|
|
|
manager->in_init = TRUE;
|
2013-07-18 07:09:16 -04:00
|
|
|
manager->xdisplay = display;
|
|
|
|
|
2013-07-22 12:57:12 -04:00
|
|
|
manager->backend = make_debug_config (manager);
|
|
|
|
|
|
|
|
if (manager->backend == META_BACKEND_UNSPECIFIED)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_XRANDR
|
|
|
|
if (display)
|
|
|
|
manager->backend = META_BACKEND_XRANDR;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (has_dummy_output ())
|
|
|
|
manager->backend = META_BACKEND_DUMMY;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_XRANDR
|
|
|
|
if (manager->backend == META_BACKEND_XRANDR)
|
|
|
|
{
|
|
|
|
if (!XRRQueryExtension (display,
|
|
|
|
&manager->rr_event_base,
|
|
|
|
&manager->rr_error_base))
|
|
|
|
{
|
|
|
|
manager->backend = META_BACKEND_DUMMY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* We only use ScreenChangeNotify, but GDK uses the others,
|
|
|
|
and we don't want to step on its toes */
|
|
|
|
XRRSelectInput (display, DefaultRootWindow (display),
|
|
|
|
RRScreenChangeNotifyMask
|
|
|
|
| RRCrtcChangeNotifyMask
|
|
|
|
| RROutputPropertyNotifyMask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2013-07-24 09:35:47 -04:00
|
|
|
manager->config = meta_monitor_config_new ();
|
2013-07-22 12:57:12 -04:00
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
read_current_config (manager);
|
2013-07-24 09:35:47 -04:00
|
|
|
|
|
|
|
if (!meta_monitor_config_apply_stored (manager->config, manager))
|
|
|
|
meta_monitor_config_make_default (manager->config, manager);
|
|
|
|
|
|
|
|
/* Under XRandR, we don't rebuild our data structures until we see
|
|
|
|
the RRScreenNotify event, but at least at startup we want to have
|
|
|
|
the right configuration immediately.
|
|
|
|
|
|
|
|
The other backends keep the data structures always updated,
|
|
|
|
so this is not needed.
|
|
|
|
*/
|
|
|
|
if (manager->backend == META_BACKEND_XRANDR)
|
|
|
|
{
|
|
|
|
MetaOutput *old_outputs;
|
|
|
|
MetaCRTC *old_crtcs;
|
|
|
|
MetaMonitorMode *old_modes;
|
|
|
|
int n_old_outputs;
|
|
|
|
|
|
|
|
old_outputs = manager->outputs;
|
|
|
|
n_old_outputs = manager->n_outputs;
|
|
|
|
old_modes = manager->modes;
|
|
|
|
old_crtcs = manager->crtcs;
|
|
|
|
|
|
|
|
read_current_config (manager);
|
|
|
|
|
|
|
|
free_output_array (old_outputs, n_old_outputs);
|
|
|
|
g_free (old_modes);
|
|
|
|
g_free (old_crtcs);
|
|
|
|
}
|
2013-07-25 04:57:59 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
make_logical_config (manager);
|
2013-07-25 04:57:59 -04:00
|
|
|
|
|
|
|
manager->in_init = FALSE;
|
2013-07-18 07:09:16 -04:00
|
|
|
return manager;
|
|
|
|
}
|
|
|
|
|
2013-07-24 04:39:06 -04:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_set_power_save_mode (MetaMonitorManager *manager,
|
|
|
|
MetaPowerSave mode)
|
|
|
|
{
|
|
|
|
if (mode == manager->power_save_mode)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (manager->power_save_mode == META_POWER_SAVE_UNKNOWN ||
|
|
|
|
mode == META_POWER_SAVE_UNKNOWN)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef HAVE_RANDR
|
|
|
|
if (manager->backend == META_BACKEND_XRANDR)
|
|
|
|
{
|
|
|
|
CARD16 state;
|
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
case META_POWER_SAVE_ON:
|
|
|
|
state = DPMSModeOn;
|
|
|
|
break;
|
|
|
|
case META_POWER_SAVE_STANDBY:
|
|
|
|
state = DPMSModeStandby;
|
|
|
|
break;
|
|
|
|
case META_POWER_SAVE_SUSPEND:
|
|
|
|
state = DPMSModeSuspend;
|
|
|
|
break;
|
|
|
|
case META_POWER_SAVE_OFF:
|
|
|
|
state = DPMSModeOff;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_error_trap_push (meta_get_display ());
|
|
|
|
DPMSForceLevel (manager->xdisplay, state);
|
|
|
|
DPMSSetTimeouts (manager->xdisplay, 0, 0, 0);
|
|
|
|
meta_error_trap_pop (meta_get_display ());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
manager->power_save_mode = mode;
|
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
static void
|
|
|
|
free_output_array (MetaOutput *old_outputs,
|
|
|
|
int n_old_outputs)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < n_old_outputs; i++)
|
2013-07-19 08:39:28 -04:00
|
|
|
{
|
|
|
|
g_free (old_outputs[i].name);
|
|
|
|
g_free (old_outputs[i].vendor);
|
|
|
|
g_free (old_outputs[i].product);
|
|
|
|
g_free (old_outputs[i].serial);
|
|
|
|
g_free (old_outputs[i].modes);
|
|
|
|
g_free (old_outputs[i].possible_crtcs);
|
2013-07-19 12:47:01 -04:00
|
|
|
g_free (old_outputs[i].possible_clones);
|
2013-07-19 08:39:28 -04:00
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
g_free (old_outputs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitor_manager_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
|
|
|
|
|
|
|
free_output_array (manager->outputs, manager->n_outputs);
|
|
|
|
g_free (manager->monitor_infos);
|
2013-07-19 08:39:28 -04:00
|
|
|
g_free (manager->modes);
|
|
|
|
g_free (manager->crtcs);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
2013-07-24 04:39:06 -04:00
|
|
|
static void
|
|
|
|
meta_monitor_manager_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *self = META_MONITOR_MANAGER (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_POWER_SAVE_MODE:
|
|
|
|
meta_monitor_manager_set_power_save_mode (self, g_value_get_int (value));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_monitor_manager_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *self = META_MONITOR_MANAGER (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_POWER_SAVE_MODE:
|
|
|
|
g_value_set_int (value, self->power_save_mode);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-24 04:39:06 -04:00
|
|
|
object_class->get_property = meta_monitor_manager_get_property;
|
|
|
|
object_class->set_property = meta_monitor_manager_set_property;
|
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;
|
|
|
|
|
|
|
|
signals[MONITORS_CHANGED] =
|
|
|
|
g_signal_new ("monitors-changed",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
2013-07-24 04:39:06 -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);
|
|
|
|
|
2013-07-24 04:39:06 -04:00
|
|
|
g_object_class_override_property (object_class, PROP_POWER_SAVE_MODE, "power-save-mode");
|
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 *
|
|
|
|
make_display_name (MetaOutput *output)
|
|
|
|
{
|
|
|
|
if (output->width_mm != -1 && output->height_mm != -1)
|
|
|
|
{
|
|
|
|
double d = sqrt (output->width_mm * output->width_mm +
|
|
|
|
output->height_mm * output->height_mm);
|
|
|
|
char *inches = diagonal_to_str (d / 25.4);
|
|
|
|
char *ret;
|
|
|
|
|
|
|
|
ret = g_strdup_printf ("%s %s", output->vendor, inches);
|
|
|
|
|
|
|
|
g_free (inches);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return g_strdup (output->vendor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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-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})"));
|
2013-07-19 08:39:28 -04:00
|
|
|
g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uxuud)"));
|
|
|
|
|
|
|
|
for (i = 0; i < manager->n_crtcs; i++)
|
|
|
|
{
|
|
|
|
MetaCRTC *crtc = &manager->crtcs[i];
|
|
|
|
GVariantBuilder transforms;
|
|
|
|
|
|
|
|
g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au"));
|
2013-07-24 04:01:57 -04:00
|
|
|
for (j = 0; j <= WL_OUTPUT_TRANSFORM_FLIPPED_270; j++)
|
|
|
|
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 */
|
|
|
|
crtc->crtc_id,
|
|
|
|
(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-07-24 04:01:57 -04:00
|
|
|
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-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));
|
|
|
|
g_variant_builder_add (&properties, "{sv}", "display-name",
|
|
|
|
g_variant_new_take_string (make_display_name (output)));
|
2013-07-25 09:06:09 -04:00
|
|
|
g_variant_builder_add (&properties, "{sv}", "backlight",
|
|
|
|
g_variant_new_int32 (output->backlight));
|
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));
|
|
|
|
|
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 */
|
|
|
|
output->output_id,
|
|
|
|
(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++)
|
|
|
|
{
|
|
|
|
MetaMonitorMode *mode = &manager->modes[i];
|
|
|
|
|
|
|
|
g_variant_builder_add (&mode_builder, "(uxuud)",
|
|
|
|
i, /* ID */
|
|
|
|
mode->mode_id,
|
|
|
|
mode->width,
|
|
|
|
mode->height,
|
|
|
|
(double)mode->refresh_rate);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
output_can_config (MetaOutput *output,
|
|
|
|
MetaCRTC *crtc,
|
|
|
|
MetaMonitorMode *mode)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_RANDR
|
|
|
|
static Rotation
|
|
|
|
wl_transform_to_xrandr (enum wl_output_transform transform)
|
|
|
|
{
|
|
|
|
switch (transform)
|
|
|
|
{
|
|
|
|
case WL_OUTPUT_TRANSFORM_NORMAL:
|
|
|
|
return RR_Rotate_0;
|
|
|
|
case WL_OUTPUT_TRANSFORM_90:
|
|
|
|
return RR_Rotate_90;
|
|
|
|
case WL_OUTPUT_TRANSFORM_180:
|
|
|
|
return RR_Rotate_180;
|
|
|
|
case WL_OUTPUT_TRANSFORM_270:
|
|
|
|
return RR_Rotate_270;
|
|
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
|
|
|
return RR_Reflect_X | RR_Rotate_0;
|
|
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
|
|
|
return RR_Reflect_X | RR_Rotate_90;
|
|
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
|
|
|
return RR_Reflect_X | RR_Rotate_180;
|
|
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
|
|
|
return RR_Reflect_X | RR_Rotate_270;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
2013-07-25 05:16:51 -04:00
|
|
|
|
|
|
|
static void
|
|
|
|
output_set_presentation_xrandr (MetaMonitorManager *manager,
|
|
|
|
MetaOutput *output,
|
|
|
|
gboolean presentation)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_get_display ();
|
|
|
|
int value = presentation;
|
|
|
|
|
|
|
|
XRRChangeOutputProperty (manager->xdisplay,
|
|
|
|
(XID)output->output_id,
|
|
|
|
display->atom__MUTTER_PRESENTATION_OUTPUT,
|
|
|
|
XA_CARDINAL, 32, PropModeReplace,
|
|
|
|
(unsigned char*) &value, 1);
|
|
|
|
}
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
static void
|
|
|
|
apply_config_xrandr (MetaMonitorManager *manager,
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaCRTCInfo **crtcs,
|
|
|
|
unsigned int n_crtcs,
|
|
|
|
MetaOutputInfo **outputs,
|
|
|
|
unsigned int n_outputs)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
for (i = 0; i < n_crtcs; i++)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaCRTCInfo *crtc_info = crtcs[i];
|
|
|
|
MetaCRTC *crtc = crtc_info->crtc;
|
2013-07-22 07:31:10 -04:00
|
|
|
crtc->is_dirty = TRUE;
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
if (crtc_info->mode == NULL)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
|
|
|
XRRSetCrtcConfig (manager->xdisplay,
|
|
|
|
manager->resources,
|
|
|
|
(XID)crtc->crtc_id,
|
|
|
|
manager->time,
|
|
|
|
0, 0,
|
|
|
|
None,
|
|
|
|
RR_Rotate_0,
|
|
|
|
NULL, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
XID *outputs;
|
2013-07-24 12:01:31 -04:00
|
|
|
int j, n_outputs;
|
2013-07-22 07:31:10 -04:00
|
|
|
Status ok;
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
mode = crtc_info->mode;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
n_outputs = crtc_info->outputs->len;
|
2013-07-22 07:31:10 -04:00
|
|
|
outputs = g_new (XID, n_outputs);
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
for (j = 0; j < n_outputs; j++)
|
|
|
|
outputs[i] = ((MetaOutput**)crtc_info->outputs->pdata)[i]->output_id;
|
2013-07-22 07:31:10 -04:00
|
|
|
|
|
|
|
meta_error_trap_push (meta_get_display ());
|
|
|
|
ok = XRRSetCrtcConfig (manager->xdisplay,
|
|
|
|
manager->resources,
|
|
|
|
(XID)crtc->crtc_id,
|
|
|
|
manager->time,
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc_info->x, crtc_info->y,
|
2013-07-22 07:31:10 -04:00
|
|
|
(XID)mode->mode_id,
|
2013-07-24 12:01:31 -04:00
|
|
|
wl_transform_to_xrandr (crtc_info->transform),
|
2013-07-22 07:31:10 -04:00
|
|
|
outputs, n_outputs);
|
|
|
|
meta_error_trap_pop (meta_get_display ());
|
|
|
|
|
|
|
|
if (ok != Success)
|
|
|
|
meta_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transfrom %u failed\n",
|
|
|
|
(unsigned)(crtc->crtc_id), (unsigned)(mode->mode_id),
|
2013-07-24 12:01:31 -04:00
|
|
|
mode->width, mode->height, (float)mode->refresh_rate,
|
|
|
|
crtc_info->x, crtc_info->y, crtc_info->transform);
|
2013-07-22 07:31:10 -04:00
|
|
|
|
|
|
|
g_free (outputs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
for (i = 0; i < n_outputs; i++)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaOutputInfo *output_info = outputs[i];
|
2013-07-22 07:31:10 -04:00
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
if (output_info->is_primary)
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
|
|
|
XRRSetOutputPrimary (manager->xdisplay,
|
|
|
|
DefaultRootWindow (manager->xdisplay),
|
2013-07-24 12:01:31 -04:00
|
|
|
(XID)output_info->output->output_id);
|
2013-07-22 07:31:10 -04:00
|
|
|
}
|
2013-07-25 05:16:51 -04:00
|
|
|
|
|
|
|
output_set_presentation_xrandr (manager,
|
|
|
|
output_info->output,
|
|
|
|
output_info->is_presentation);
|
2013-07-22 07:31:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Disable CRTCs not mentioned in the list */
|
|
|
|
for (i = 0; i < manager->n_crtcs; i++)
|
|
|
|
{
|
|
|
|
MetaCRTC *crtc = &manager->crtcs[i];
|
|
|
|
|
|
|
|
if (crtc->is_dirty)
|
2013-07-23 04:07:52 -04:00
|
|
|
{
|
|
|
|
crtc->is_dirty = FALSE;
|
|
|
|
continue;
|
|
|
|
}
|
2013-07-22 07:31:10 -04:00
|
|
|
if (crtc->current_mode == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
XRRSetCrtcConfig (manager->xdisplay,
|
|
|
|
manager->resources,
|
|
|
|
(XID)crtc->crtc_id,
|
|
|
|
manager->time,
|
|
|
|
0, 0,
|
|
|
|
None,
|
|
|
|
RR_Rotate_0,
|
|
|
|
NULL, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-07-23 04:07:52 -04:00
|
|
|
static void
|
|
|
|
apply_config_dummy (MetaMonitorManager *manager,
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaCRTCInfo **crtcs,
|
|
|
|
unsigned int n_crtcs,
|
|
|
|
MetaOutputInfo **outputs,
|
|
|
|
unsigned int n_outputs)
|
2013-07-23 04:07:52 -04:00
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
int screen_width = 0, screen_height = 0;
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
for (i = 0; i < n_crtcs; i++)
|
2013-07-23 04:07:52 -04:00
|
|
|
{
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaCRTCInfo *crtc_info = crtcs[i];
|
|
|
|
MetaCRTC *crtc = crtc_info->crtc;
|
2013-07-23 04:07:52 -04:00
|
|
|
crtc->is_dirty = TRUE;
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
if (crtc_info->mode == NULL)
|
2013-07-23 04:07:52 -04:00
|
|
|
{
|
|
|
|
crtc->rect.x = 0;
|
|
|
|
crtc->rect.y = 0;
|
|
|
|
crtc->rect.width = 0;
|
|
|
|
crtc->rect.height = 0;
|
|
|
|
crtc->current_mode = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
MetaOutput *output;
|
|
|
|
int i, n_outputs;
|
2013-07-24 04:01:57 -04:00
|
|
|
int width, height;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
mode = crtc_info->mode;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
if (meta_monitor_transform_is_rotated (crtc_info->transform))
|
2013-07-24 04:01:57 -04:00
|
|
|
{
|
|
|
|
width = mode->height;
|
|
|
|
height = mode->width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
width = mode->width;
|
|
|
|
height = mode->height;
|
|
|
|
}
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc->rect.x = crtc_info->x;
|
|
|
|
crtc->rect.y = crtc_info->y;
|
2013-07-24 04:01:57 -04:00
|
|
|
crtc->rect.width = width;
|
|
|
|
crtc->rect.height = height;
|
2013-07-23 04:07:52 -04:00
|
|
|
crtc->current_mode = mode;
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc->transform = crtc_info->transform;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
screen_width = MAX (screen_width, crtc_info->x + width);
|
|
|
|
screen_height = MAX (screen_height, crtc_info->y + height);
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
n_outputs = crtc_info->outputs->len;
|
2013-07-23 04:07:52 -04:00
|
|
|
for (i = 0; i < n_outputs; i++)
|
|
|
|
{
|
2013-07-24 12:01:31 -04:00
|
|
|
output = ((MetaOutput**)crtc_info->outputs->pdata)[i];
|
2013-07-23 04:07:52 -04:00
|
|
|
|
|
|
|
output->is_dirty = TRUE;
|
|
|
|
output->crtc = crtc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
for (i = 0; i < n_outputs; i++)
|
2013-07-23 04:07:52 -04:00
|
|
|
{
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaOutputInfo *output_info = outputs[i];
|
|
|
|
MetaOutput *output = output_info->output;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
output->is_primary = output_info->is_primary;
|
|
|
|
output->is_presentation = output_info->is_presentation;
|
2013-07-23 04:07:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Disable CRTCs not mentioned in the list */
|
|
|
|
for (i = 0; i < manager->n_crtcs; i++)
|
|
|
|
{
|
|
|
|
MetaCRTC *crtc = &manager->crtcs[i];
|
|
|
|
|
|
|
|
crtc->logical_monitor = NULL;
|
|
|
|
|
|
|
|
if (crtc->is_dirty)
|
|
|
|
{
|
|
|
|
crtc->is_dirty = FALSE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
crtc->rect.x = 0;
|
|
|
|
crtc->rect.y = 0;
|
|
|
|
crtc->rect.width = 0;
|
|
|
|
crtc->rect.height = 0;
|
|
|
|
crtc->current_mode = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Disable outputs not mentioned in the list */
|
|
|
|
for (i = 0; i < manager->n_outputs; i++)
|
|
|
|
{
|
|
|
|
MetaOutput *output = &manager->outputs[i];
|
|
|
|
|
|
|
|
if (output->is_dirty)
|
|
|
|
{
|
|
|
|
output->is_dirty = FALSE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
output->crtc = NULL;
|
|
|
|
output->is_primary = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
manager->screen_width = screen_width;
|
|
|
|
manager->screen_height = screen_height;
|
|
|
|
|
|
|
|
invalidate_logical_config (manager);
|
|
|
|
}
|
|
|
|
|
2013-07-24 09:35:47 -04:00
|
|
|
void
|
|
|
|
meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaCRTCInfo **crtcs,
|
|
|
|
unsigned int n_crtcs,
|
|
|
|
MetaOutputInfo **outputs,
|
|
|
|
unsigned int n_outputs)
|
2013-07-24 09:35:47 -04:00
|
|
|
{
|
2013-07-25 09:06:09 -04:00
|
|
|
if (manager->backend == META_BACKEND_XRANDR)
|
|
|
|
apply_config_xrandr (manager, crtcs, n_crtcs, outputs, n_outputs);
|
2013-07-24 09:35:47 -04:00
|
|
|
else
|
2013-07-24 12:01:31 -04:00
|
|
|
apply_config_dummy (manager, crtcs, n_crtcs, outputs, n_outputs);
|
2013-07-24 09:35:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
save_config_timeout (gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
|
2013-07-29 04:12:24 -04:00
|
|
|
meta_monitor_config_restore_previous (manager->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
|
2013-07-23 13:32:17 -04:00
|
|
|
meta_monitor_manager_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;
|
|
|
|
guint output_id;
|
2013-07-24 12:01:31 -04:00
|
|
|
GPtrArray *crtc_infos, *output_infos;
|
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))
|
|
|
|
{
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaCRTCInfo *crtc_info;
|
2013-07-22 07:31:10 -04:00
|
|
|
MetaOutput *first_output;
|
|
|
|
MetaCRTC *crtc;
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
guint output_id;
|
|
|
|
|
2013-07-24 12:01:31 -04:00
|
|
|
crtc_info = g_slice_new (MetaCRTCInfo);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if (transform < WL_OUTPUT_TRANSFORM_NORMAL ||
|
2013-07-24 04:01:57 -04:00
|
|
|
transform > WL_OUTPUT_TRANSFORM_FLIPPED_270 ||
|
|
|
|
((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;
|
|
|
|
while (g_variant_iter_loop (nested_outputs, "u", &output_id))
|
|
|
|
{
|
|
|
|
MetaOutput *output;
|
|
|
|
|
|
|
|
if (output_id >= manager->n_outputs)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid output id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
output = &manager->outputs[output_id];
|
|
|
|
|
|
|
|
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);
|
2013-07-24 12:01:31 -04:00
|
|
|
while (g_variant_iter_loop (&output_iter, "(u@a{sv})", &output_id, &properties))
|
2013-07-22 07:31:10 -04:00
|
|
|
{
|
2013-07-24 12:01:31 -04:00
|
|
|
MetaOutputInfo *output_info;
|
|
|
|
gboolean primary, presentation;
|
|
|
|
|
2013-07-22 07:31:10 -04:00
|
|
|
if (output_id >= manager->n_outputs)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
output_info->output = &manager->outputs[output_id];
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
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.
|
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,
|
|
|
|
(MetaCRTCInfo**)crtc_infos->pdata,
|
|
|
|
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
|
|
|
*/
|
|
|
|
meta_monitor_config_update_current (manager->config, manager);
|
|
|
|
if (persistent)
|
2013-07-29 04:12:24 -04:00
|
|
|
{
|
|
|
|
manager->persistent_timeout_id = g_timeout_add_seconds (20, save_config_timeout, manager);
|
|
|
|
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
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
meta_monitor_config_make_persistent (manager->config);
|
|
|
|
else
|
|
|
|
meta_monitor_config_restore_previous (manager->config, manager);
|
|
|
|
}
|
|
|
|
|
2013-07-25 09:06:09 -04:00
|
|
|
#ifdef HAVE_RANDR
|
|
|
|
static void
|
|
|
|
handle_change_backlight_xrandr (MetaMonitorManager *manager,
|
|
|
|
MetaOutput *output,
|
|
|
|
gint value)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_get_display ();
|
|
|
|
int hw_value;
|
|
|
|
|
|
|
|
hw_value = round ((double)value / 100.0 * output->backlight_max + output->backlight_min);
|
|
|
|
|
|
|
|
meta_error_trap_push (display);
|
|
|
|
XRRChangeOutputProperty (manager->xdisplay,
|
|
|
|
(XID)output->output_id,
|
|
|
|
display->atom_BACKLIGHT,
|
|
|
|
XA_INTEGER, 32, PropModeReplace,
|
|
|
|
(unsigned char *) &hw_value, 1);
|
|
|
|
meta_error_trap_pop (display);
|
|
|
|
|
|
|
|
/* We're not selecting for property notifies, so update the value immediately */
|
|
|
|
output->backlight = normalize_backlight (output, hw_value);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void
|
|
|
|
handle_change_backlight_dummy (MetaMonitorManager *manager,
|
|
|
|
MetaOutput *output,
|
|
|
|
gint value)
|
|
|
|
{
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
|
|
|
guint output_id,
|
|
|
|
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_id >= manager->n_outputs)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid output id");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
output = &manager->outputs[output_id];
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (manager->backend == META_BACKEND_XRANDR)
|
|
|
|
handle_change_backlight_xrandr (manager, output, value);
|
|
|
|
else
|
|
|
|
handle_change_backlight_dummy (manager, output, value);
|
|
|
|
|
|
|
|
meta_dbus_display_config_complete_change_backlight (skeleton, invocation);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-26 09:57:34 -04:00
|
|
|
#ifdef HAVE_RANDR
|
|
|
|
static void
|
|
|
|
handle_get_crtc_gamma_xrandr (MetaMonitorManager *manager,
|
|
|
|
MetaCRTC *crtc,
|
|
|
|
gsize *size,
|
|
|
|
unsigned short **red,
|
|
|
|
unsigned short **green,
|
|
|
|
unsigned short **blue)
|
|
|
|
{
|
|
|
|
XRRCrtcGamma *gamma;
|
|
|
|
|
|
|
|
gamma = XRRGetCrtcGamma (manager->xdisplay, (XID)crtc->crtc_id);
|
|
|
|
|
|
|
|
*size = gamma->size;
|
|
|
|
*red = g_memdup (gamma->red, sizeof (unsigned short) * gamma->size);
|
|
|
|
*green = g_memdup (gamma->green, sizeof (unsigned short) * gamma->size);
|
|
|
|
*blue = g_memdup (gamma->blue, sizeof (unsigned short) * gamma->size);
|
|
|
|
|
|
|
|
XRRFreeGamma (gamma);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void
|
|
|
|
handle_get_crtc_gamma_dummy (MetaMonitorManager *manager,
|
|
|
|
MetaCRTC *crtc,
|
|
|
|
gsize *size,
|
|
|
|
unsigned short **red,
|
|
|
|
unsigned short **green,
|
|
|
|
unsigned short **blue)
|
|
|
|
{
|
|
|
|
*size = 0;
|
|
|
|
*red = g_new0 (unsigned short, 0);
|
|
|
|
*green = g_new0 (unsigned short, 0);
|
|
|
|
*blue = g_new0 (unsigned short, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_monitor_manager_handle_get_crtc_gamma (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
|
|
|
guint crtc_id)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
|
|
|
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 >= 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];
|
|
|
|
|
|
|
|
if (manager->backend == META_BACKEND_XRANDR)
|
|
|
|
handle_get_crtc_gamma_xrandr (manager, crtc, &size, &red, &green, &blue);
|
|
|
|
else
|
|
|
|
handle_get_crtc_gamma_dummy (manager, crtc, &size, &red, &green, &blue);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_RANDR
|
|
|
|
static void
|
|
|
|
handle_set_crtc_gamma_xrandr (MetaMonitorManager *manager,
|
|
|
|
MetaCRTC *crtc,
|
|
|
|
gsize size,
|
|
|
|
unsigned short *red,
|
|
|
|
unsigned short *green,
|
|
|
|
unsigned short *blue)
|
|
|
|
{
|
|
|
|
XRRCrtcGamma gamma;
|
|
|
|
|
|
|
|
gamma.size = size;
|
|
|
|
gamma.red = red;
|
|
|
|
gamma.green = green;
|
|
|
|
gamma.blue = blue;
|
|
|
|
|
|
|
|
XRRSetCrtcGamma (manager->xdisplay, (XID)crtc->crtc_id, &gamma);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void
|
|
|
|
handle_set_crtc_gamma_dummy (MetaMonitorManager *manager,
|
|
|
|
MetaCRTC *crtc,
|
|
|
|
gsize size,
|
|
|
|
unsigned short *red,
|
|
|
|
unsigned short *green,
|
|
|
|
unsigned short *blue)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
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 >= 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);
|
|
|
|
|
|
|
|
if (manager->backend == META_BACKEND_XRANDR)
|
|
|
|
handle_set_crtc_gamma_xrandr (manager, crtc, size, red, green, blue);
|
|
|
|
else
|
|
|
|
handle_set_crtc_gamma_dummy (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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
iface->handle_apply_configuration = meta_monitor_manager_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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaMonitorManager *global_monitor_manager;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_monitor_manager_initialize (Display *display)
|
|
|
|
{
|
2013-07-19 08:39:28 -04:00
|
|
|
global_monitor_manager = meta_monitor_manager_new (display);
|
|
|
|
|
|
|
|
initialize_dbus_interface (global_monitor_manager);
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorManager *
|
|
|
|
meta_monitor_manager_get (void)
|
|
|
|
{
|
2013-07-19 08:39:28 -04:00
|
|
|
g_assert (global_monitor_manager != NULL);
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
return global_monitor_manager;
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
MetaMonitorInfo *
|
|
|
|
meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
|
2013-07-24 09:35:47 -04:00
|
|
|
unsigned int *n_infos)
|
2013-07-18 07:09:16 -04:00
|
|
|
{
|
|
|
|
*n_infos = manager->n_monitor_infos;
|
|
|
|
return manager->monitor_infos;
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
MetaMonitorMode **modes,
|
|
|
|
unsigned int *n_modes,
|
|
|
|
MetaCRTC **crtcs,
|
|
|
|
unsigned int *n_crtcs,
|
|
|
|
MetaOutput **outputs,
|
|
|
|
unsigned int *n_outputs)
|
|
|
|
{
|
|
|
|
*modes = manager->modes;
|
|
|
|
*n_modes = manager->n_modes;
|
|
|
|
*crtcs = manager->crtcs;
|
|
|
|
*n_crtcs = manager->n_crtcs;
|
|
|
|
*outputs = manager->outputs;
|
|
|
|
*n_outputs = manager->n_outputs;
|
|
|
|
}
|
|
|
|
|
2013-07-18 07:09:16 -04:00
|
|
|
int
|
|
|
|
meta_monitor_manager_get_primary_index (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
return manager->primary_monitor_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-07-23 04:07:52 -04:00
|
|
|
static void
|
|
|
|
invalidate_logical_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorInfo *old_monitor_infos;
|
|
|
|
|
|
|
|
old_monitor_infos = manager->monitor_infos;
|
|
|
|
|
2013-07-25 04:57:59 -04:00
|
|
|
if (manager->in_init)
|
|
|
|
return;
|
|
|
|
|
2013-07-23 04:07:52 -04:00
|
|
|
make_logical_config (manager);
|
|
|
|
|
|
|
|
g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
|
|
|
|
|
|
|
|
g_free (old_monitor_infos);
|
|
|
|
}
|
|
|
|
|
2013-07-22 12:57:12 -04:00
|
|
|
gboolean
|
|
|
|
meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
|
|
|
|
XEvent *event)
|
2013-07-18 07:09:16 -04:00
|
|
|
{
|
|
|
|
MetaOutput *old_outputs;
|
2013-07-19 08:39:28 -04:00
|
|
|
MetaCRTC *old_crtcs;
|
|
|
|
MetaMonitorMode *old_modes;
|
2013-07-18 07:09:16 -04:00
|
|
|
int n_old_outputs;
|
|
|
|
|
2013-07-22 12:57:12 -04:00
|
|
|
if (manager->backend != META_BACKEND_XRANDR)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
#ifdef HAVE_RANDR
|
|
|
|
if ((event->type - manager->rr_event_base) != RRScreenChangeNotify)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
XRRUpdateConfiguration (event);
|
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
/* Save the old structures, so they stay valid during the update */
|
2013-07-18 07:09:16 -04:00
|
|
|
old_outputs = manager->outputs;
|
|
|
|
n_old_outputs = manager->n_outputs;
|
2013-07-19 08:39:28 -04:00
|
|
|
old_modes = manager->modes;
|
|
|
|
old_crtcs = manager->crtcs;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
|
|
|
read_current_config (manager);
|
2013-07-24 09:35:47 -04:00
|
|
|
|
|
|
|
/* Check if the current intended configuration has the same outputs
|
|
|
|
as the new real one. If so, this was a result of an ApplyConfiguration
|
|
|
|
call (or a change from ourselves), and we can go straight to rebuild
|
|
|
|
the logical config and tell the outside world.
|
|
|
|
|
|
|
|
Otherwise, this event was caused by hotplug, so give a chance to
|
|
|
|
MetaMonitorConfig.
|
|
|
|
*/
|
|
|
|
if (meta_monitor_config_match_current (manager->config, manager))
|
|
|
|
{
|
|
|
|
invalidate_logical_config (manager);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!meta_monitor_config_apply_stored (manager->config, manager))
|
|
|
|
meta_monitor_config_make_default (manager->config, manager);
|
|
|
|
}
|
2013-07-18 07:09:16 -04:00
|
|
|
|
|
|
|
free_output_array (old_outputs, n_old_outputs);
|
2013-07-19 08:39:28 -04:00
|
|
|
g_free (old_modes);
|
|
|
|
g_free (old_crtcs);
|
2013-07-22 12:57:12 -04:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
#else
|
|
|
|
return FALSE;
|
|
|
|
#endif
|
2013-07-18 07:09:16 -04:00
|
|
|
}
|
|
|
|
|