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-18 07:09:16 -04:00
|
|
|
#include <clutter/clutter.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_RANDR
|
|
|
|
#include <X11/extensions/Xrandr.h>
|
|
|
|
#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
|
|
|
|
{
|
|
|
|
GObject parent_instance;
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
unsigned int serial;
|
|
|
|
|
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;
|
|
|
|
MetaDBusDisplayConfig *skeleton;
|
2013-07-18 07:09:16 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _MetaMonitorManagerClass
|
|
|
|
{
|
|
|
|
GObjectClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
MONITORS_CHANGED,
|
|
|
|
SIGNALS_LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
static int signals[SIGNALS_LAST];
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (MetaMonitorManager, meta_monitor_manager, G_TYPE_OBJECT);
|
|
|
|
|
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-23 04:07:52 -04:00
|
|
|
manager->modes = g_new0 (MetaMonitorMode, 3);
|
|
|
|
manager->n_modes = 3;
|
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-23 04:07:52 -04:00
|
|
|
manager->crtcs = g_new0 (MetaCRTC, 2);
|
|
|
|
manager->n_crtcs = 2;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
manager->outputs = g_new0 (MetaOutput, 3);
|
|
|
|
manager->n_outputs = 3;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->outputs[0].crtc = &manager->crtcs[0];
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[0].output_id = 6;
|
2013-07-18 07:09:16 -04:00
|
|
|
manager->outputs[0].name = g_strdup ("LVDS");
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->outputs[0].vendor = g_strdup ("unknown");
|
|
|
|
manager->outputs[0].product = g_strdup ("unknown");
|
|
|
|
manager->outputs[0].serial = g_strdup ("");
|
2013-07-18 07:09:16 -04:00
|
|
|
manager->outputs[0].width_mm = 222;
|
|
|
|
manager->outputs[0].height_mm = 125;
|
|
|
|
manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
2013-07-19 08:39:28 -04:00
|
|
|
manager->outputs[0].preferred_mode = &manager->modes[0];
|
2013-07-23 04:07:52 -04:00
|
|
|
manager->outputs[0].n_modes = 3;
|
|
|
|
manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 3);
|
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];
|
|
|
|
manager->outputs[0].n_possible_crtcs = 2;
|
|
|
|
manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 2);
|
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-19 12:47:01 -04:00
|
|
|
manager->outputs[0].n_possible_clones = 0;
|
|
|
|
manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0);
|
2013-07-23 04:07:52 -04:00
|
|
|
|
|
|
|
manager->outputs[1].crtc = NULL;
|
|
|
|
manager->outputs[1].output_id = 7;
|
|
|
|
manager->outputs[1].name = g_strdup ("HDMI");
|
|
|
|
manager->outputs[1].vendor = g_strdup ("unknown");
|
|
|
|
manager->outputs[1].product = g_strdup ("unknown");
|
|
|
|
manager->outputs[1].serial = g_strdup ("");
|
|
|
|
manager->outputs[1].width_mm = 510;
|
|
|
|
manager->outputs[1].height_mm = 287;
|
|
|
|
manager->outputs[1].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
|
|
|
manager->outputs[1].preferred_mode = &manager->modes[0];
|
|
|
|
manager->outputs[1].n_modes = 3;
|
|
|
|
manager->outputs[1].modes = g_new0 (MetaMonitorMode *, 3);
|
|
|
|
manager->outputs[1].modes[0] = &manager->modes[0];
|
|
|
|
manager->outputs[1].modes[1] = &manager->modes[1];
|
|
|
|
manager->outputs[1].modes[2] = &manager->modes[2];
|
|
|
|
manager->outputs[1].n_possible_crtcs = 2;
|
|
|
|
manager->outputs[1].possible_crtcs = g_new0 (MetaCRTC *, 2);
|
|
|
|
manager->outputs[1].possible_crtcs[0] = &manager->crtcs[0];
|
|
|
|
manager->outputs[1].possible_crtcs[1] = &manager->crtcs[1];
|
|
|
|
manager->outputs[1].n_possible_clones = 0;
|
|
|
|
manager->outputs[1].possible_clones = g_new0 (MetaOutput *, 0);
|
|
|
|
|
|
|
|
manager->outputs[2].crtc = NULL;
|
|
|
|
manager->outputs[2].output_id = 8;
|
|
|
|
manager->outputs[2].name = g_strdup ("VGA");
|
|
|
|
manager->outputs[2].vendor = g_strdup ("unknown");
|
|
|
|
manager->outputs[2].product = g_strdup ("unknown");
|
|
|
|
manager->outputs[2].serial = g_strdup ("");
|
|
|
|
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];
|
|
|
|
manager->outputs[2].n_possible_crtcs = 2;
|
|
|
|
manager->outputs[2].possible_crtcs = g_new0 (MetaCRTC *, 2);
|
|
|
|
manager->outputs[2].possible_crtcs[0] = &manager->crtcs[0];
|
|
|
|
manager->outputs[2].possible_crtcs[1] = &manager->crtcs[1];
|
|
|
|
manager->outputs[2].n_possible_clones = 0;
|
|
|
|
manager->outputs[2].possible_clones = g_new0 (MetaOutput *, 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
|
|
|
|
|
|
|
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-22 07:31:10 -04:00
|
|
|
|
|
|
|
if (manager->resources)
|
|
|
|
XRRFreeScreenResources (manager->resources);
|
|
|
|
manager->resources = NULL;
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
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);
|
|
|
|
meta_output->is_presentation = FALSE;
|
|
|
|
|
|
|
|
n_actual_outputs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
XRRFreeOutputInfo (output);
|
|
|
|
}
|
|
|
|
|
|
|
|
manager->n_outputs = n_actual_outputs;
|
2013-07-18 07:09:16 -04:00
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
#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);
|
|
|
|
|
|
|
|
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-18 07:09:16 -04:00
|
|
|
read_current_config (manager);
|
2013-07-19 08:39:28 -04:00
|
|
|
make_logical_config (manager);
|
2013-07-18 07:09:16 -04:00
|
|
|
return manager;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_clear_object (&manager->skeleton);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
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-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-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
|
|
|
|
handle_get_resources (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
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)));
|
|
|
|
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 ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
apply_config_xrandr (MetaMonitorManager *manager,
|
|
|
|
GVariantIter *crtcs,
|
|
|
|
GVariantIter *outputs)
|
|
|
|
{
|
|
|
|
GVariant *nested_outputs, *properties;
|
|
|
|
guint crtc_id, output_id, transform;
|
|
|
|
int new_mode, x, y;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
while (g_variant_iter_loop (crtcs, "(uiiiu@aua{sv})",
|
|
|
|
&crtc_id, &new_mode, &x, &y,
|
|
|
|
&transform, &nested_outputs, NULL))
|
|
|
|
{
|
|
|
|
MetaCRTC *crtc = &manager->crtcs[crtc_id];
|
|
|
|
crtc->is_dirty = TRUE;
|
|
|
|
|
|
|
|
if (new_mode == -1)
|
|
|
|
{
|
|
|
|
XRRSetCrtcConfig (manager->xdisplay,
|
|
|
|
manager->resources,
|
|
|
|
(XID)crtc->crtc_id,
|
|
|
|
manager->time,
|
|
|
|
0, 0,
|
|
|
|
None,
|
|
|
|
RR_Rotate_0,
|
|
|
|
NULL, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
XID *outputs;
|
|
|
|
int i, n_outputs;
|
|
|
|
guint output_id;
|
|
|
|
Status ok;
|
|
|
|
|
|
|
|
mode = &manager->modes[new_mode];
|
|
|
|
|
|
|
|
n_outputs = g_variant_n_children (nested_outputs);
|
|
|
|
outputs = g_new (XID, n_outputs);
|
|
|
|
|
|
|
|
for (i = 0; i < n_outputs; i++)
|
|
|
|
{
|
|
|
|
g_variant_get_child (nested_outputs, i, "u", &output_id);
|
|
|
|
|
|
|
|
outputs[i] = manager->outputs[output_id].output_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_error_trap_push (meta_get_display ());
|
|
|
|
ok = XRRSetCrtcConfig (manager->xdisplay,
|
|
|
|
manager->resources,
|
|
|
|
(XID)crtc->crtc_id,
|
|
|
|
manager->time,
|
|
|
|
x, y,
|
|
|
|
(XID)mode->mode_id,
|
|
|
|
wl_transform_to_xrandr (transform),
|
|
|
|
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),
|
|
|
|
mode->width, mode->height, (float)mode->refresh_rate, x, y, transform);
|
|
|
|
|
|
|
|
g_free (outputs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (g_variant_iter_loop (outputs, "(u@a{sv})",
|
|
|
|
&output_id, &properties))
|
|
|
|
{
|
|
|
|
gboolean primary;
|
|
|
|
|
|
|
|
if (g_variant_lookup (properties, "primary", "b", &primary) && primary)
|
|
|
|
{
|
|
|
|
MetaOutput *output = &manager->outputs[output_id];
|
|
|
|
|
|
|
|
XRRSetOutputPrimary (manager->xdisplay,
|
|
|
|
DefaultRootWindow (manager->xdisplay),
|
|
|
|
(XID)output->output_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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,
|
|
|
|
GVariantIter *crtcs,
|
|
|
|
GVariantIter *outputs)
|
|
|
|
{
|
|
|
|
GVariant *nested_outputs, *properties;
|
|
|
|
guint crtc_id, output_id, transform;
|
|
|
|
int new_mode, x, y;
|
|
|
|
unsigned i;
|
|
|
|
int screen_width = 0, screen_height = 0;
|
|
|
|
|
|
|
|
while (g_variant_iter_loop (crtcs, "(uiiiu@aua{sv})",
|
|
|
|
&crtc_id, &new_mode, &x, &y,
|
|
|
|
&transform, &nested_outputs, NULL))
|
|
|
|
{
|
|
|
|
MetaCRTC *crtc = &manager->crtcs[crtc_id];
|
|
|
|
crtc->is_dirty = TRUE;
|
|
|
|
|
|
|
|
if (new_mode == -1)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
guint output_id;
|
2013-07-24 04:01:57 -04:00
|
|
|
int width, height;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
|
|
|
mode = &manager->modes[new_mode];
|
|
|
|
|
2013-07-24 04:01:57 -04:00
|
|
|
if (meta_monitor_transform_is_rotated (transform))
|
|
|
|
{
|
|
|
|
width = mode->height;
|
|
|
|
height = mode->width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
width = mode->width;
|
|
|
|
height = mode->height;
|
|
|
|
}
|
|
|
|
|
2013-07-23 04:07:52 -04:00
|
|
|
crtc->rect.x = x;
|
|
|
|
crtc->rect.y = 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 04:01:57 -04:00
|
|
|
crtc->transform = transform;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-24 04:01:57 -04:00
|
|
|
screen_width = MAX (screen_width, x + width);
|
|
|
|
screen_height = MAX (screen_height, y + height);
|
2013-07-23 04:07:52 -04:00
|
|
|
|
|
|
|
n_outputs = g_variant_n_children (nested_outputs);
|
|
|
|
for (i = 0; i < n_outputs; i++)
|
|
|
|
{
|
|
|
|
g_variant_get_child (nested_outputs, i, "u", &output_id);
|
|
|
|
|
|
|
|
output = &manager->outputs[output_id];
|
|
|
|
|
|
|
|
output->is_dirty = TRUE;
|
|
|
|
output->crtc = crtc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (g_variant_iter_loop (outputs, "(u@a{sv})",
|
|
|
|
&output_id, &properties))
|
|
|
|
{
|
|
|
|
MetaOutput *output = &manager->outputs[output_id];
|
|
|
|
gboolean primary, presentation;
|
|
|
|
|
|
|
|
if (g_variant_lookup (properties, "primary", "b", &primary))
|
|
|
|
output->is_primary = primary;
|
|
|
|
|
|
|
|
if (g_variant_lookup (properties, "presentation", "b", &presentation))
|
|
|
|
output->is_presentation = presentation;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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-22 07:31:10 -04:00
|
|
|
static gboolean
|
|
|
|
handle_apply_configuration (MetaDBusDisplayConfig *skeleton,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
guint serial,
|
|
|
|
gboolean persistent,
|
|
|
|
GVariant *crtcs,
|
|
|
|
GVariant *outputs,
|
|
|
|
MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
GVariantIter crtc_iter, output_iter, *nested_outputs;
|
|
|
|
guint crtc_id;
|
|
|
|
int new_mode, x, y;
|
|
|
|
guint transform;
|
|
|
|
guint output_id;
|
|
|
|
|
|
|
|
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 (persistent)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_NOT_SUPPORTED,
|
|
|
|
"Persistent configuration is not yet implemented");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Validate all arguments */
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
MetaOutput *first_output;
|
|
|
|
MetaCRTC *crtc;
|
|
|
|
MetaMonitorMode *mode;
|
|
|
|
guint output_id;
|
|
|
|
|
|
|
|
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 (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 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-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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_variant_iter_init (&output_iter, outputs);
|
|
|
|
while (g_variant_iter_loop (&output_iter, "(ua{sv})", &output_id, NULL))
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_variant_iter_init (&crtc_iter, crtcs);
|
|
|
|
g_variant_iter_init (&output_iter, outputs);
|
2013-07-23 04:07:52 -04:00
|
|
|
|
|
|
|
if (manager->backend == META_BACKEND_XRANDR)
|
|
|
|
apply_config_xrandr (manager, &crtc_iter, &output_iter);
|
|
|
|
else
|
|
|
|
apply_config_dummy (manager, &crtc_iter, &output_iter);
|
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
|
|
|
|
|
|
|
static void
|
|
|
|
on_bus_acquired (GDBusConnection *connection,
|
|
|
|
const char *name,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *manager = user_data;
|
|
|
|
|
|
|
|
manager->skeleton = META_DBUS_DISPLAY_CONFIG (meta_dbus_display_config_skeleton_new ());
|
|
|
|
|
|
|
|
g_signal_connect_object (manager->skeleton, "handle-get-resources",
|
|
|
|
G_CALLBACK (handle_get_resources), manager, 0);
|
2013-07-22 07:31:10 -04:00
|
|
|
g_signal_connect_object (manager->skeleton, "handle-apply-configuration",
|
|
|
|
G_CALLBACK (handle_apply_configuration), manager, 0);
|
2013-07-19 08:39:28 -04:00
|
|
|
|
|
|
|
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager->skeleton),
|
|
|
|
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,
|
|
|
|
int *n_infos)
|
|
|
|
{
|
|
|
|
*n_infos = manager->n_monitor_infos;
|
|
|
|
return manager->monitor_infos;
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaOutput *
|
|
|
|
meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
|
|
|
|
int *n_outputs)
|
|
|
|
{
|
|
|
|
*n_outputs = manager->n_outputs;
|
|
|
|
return manager->outputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-23 04:07:52 -04:00
|
|
|
static void
|
|
|
|
invalidate_logical_config (MetaMonitorManager *manager)
|
|
|
|
{
|
|
|
|
MetaMonitorInfo *old_monitor_infos;
|
|
|
|
|
|
|
|
old_monitor_infos = manager->monitor_infos;
|
|
|
|
|
|
|
|
manager->serial++;
|
|
|
|
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;
|
2013-07-23 04:07:52 -04:00
|
|
|
|
2013-07-19 08:39:28 -04:00
|
|
|
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-23 04:07:52 -04:00
|
|
|
invalidate_logical_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
|
|
|
}
|
|
|
|
|