Merge tag 'xrandr_branch_point' into wayland-kms-base

Conflicts:
	src/Makefile.am
	src/core/display.c
	src/core/screen-private.h
	src/core/screen.c
This commit is contained in:
Giovanni Campagna 2013-08-27 10:07:39 +02:00
commit aa15c09d54
25 changed files with 6128 additions and 307 deletions

View File

@ -79,6 +79,8 @@ MUTTER_PC_MODULES="
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
$CLUTTER_PACKAGE >= 1.14.3
cogl-1.0 >= 1.13.3
upower-glib > 0.9.11
gnome-desktop-3.0
"
GLIB_GSETTINGS

View File

@ -12,6 +12,7 @@ src/core/display.c
src/core/errors.c
src/core/keybindings.c
src/core/main.c
src/core/monitor.c
src/core/mutter.c
src/core/prefs.c
src/core/screen.c
@ -23,12 +24,9 @@ src/core/xprops.c
src/mutter.desktop.in
src/mutter-wm.desktop.in
src/org.gnome.mutter.gschema.xml.in
src/tools/mutter-message.c
src/ui/frames.c
src/ui/menu.c
src/ui/metaaccellabel.c
src/ui/resizepopup.c
src/ui/theme.c
src/ui/theme-parser.c
src/ui/theme-viewer.c

View File

@ -37,6 +37,7 @@ INCLUDES += \
mutter_built_sources = \
$(dbus_idle_built_sources) \
$(dbus_xrandr_built_sources) \
mutter-enum-types.h \
mutter-enum-types.c \
wayland/xserver-protocol.c \
@ -105,6 +106,8 @@ libmutter_wayland_la_SOURCES = \
ui/draw-workspace.h \
core/edge-resistance.c \
core/edge-resistance.h \
core/edid-parse.c \
core/edid.h \
core/errors.c \
meta/errors.h \
core/frame.c \
@ -125,6 +128,11 @@ libmutter_wayland_la_SOURCES = \
core/meta-cursor-tracker-private.h \
core/meta-idle-monitor.c \
core/meta-idle-monitor-private.h \
core/meta-xrandr-shared.h \
core/monitor.c \
core/monitor-config.c \
core/monitor-private.h \
core/monitor-xrandr.c \
core/mutter-Xatomtype.h \
core/place.c \
core/place.h \
@ -353,6 +361,15 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in
cp xgen-tetc mutter-enum-types.c && \
rm -f xgen-tetc
dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h
$(dbus_xrandr_built_sources) : Makefile.am xrandr.xml
$(AM_V_GEN)gdbus-codegen \
--interface-prefix org.gnome.Mutter \
--c-namespace MetaDBus \
--generate-c-code meta-dbus-xrandr \
$(srcdir)/xrandr.xml
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
$(dbus_idle_built_sources) : Makefile.am idle-monitor.xml

View File

@ -85,12 +85,20 @@ meta_plugin_manager_load (const gchar *plugin_name)
g_free (path);
}
static void
on_confirm_display_change (MetaMonitorManager *monitors,
MetaPluginManager *plugin_mgr)
{
meta_plugin_manager_confirm_display_change (plugin_mgr);
}
MetaPluginManager *
meta_plugin_manager_new (MetaScreen *screen)
{
MetaPluginManager *plugin_mgr;
MetaPluginClass *klass;
MetaPlugin *plugin;
MetaMonitorManager *monitors;
plugin_mgr = g_new0 (MetaPluginManager, 1);
plugin_mgr->screen = screen;
@ -101,6 +109,10 @@ meta_plugin_manager_new (MetaScreen *screen)
if (klass->start)
klass->start (plugin);
monitors = meta_monitor_manager_get ();
g_signal_connect (monitors, "confirm-display-change",
G_CALLBACK (on_confirm_display_change), plugin_mgr);
return plugin_mgr;
}
@ -330,3 +342,15 @@ meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr,
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
}
void
meta_plugin_manager_confirm_display_change (MetaPluginManager *plugin_mgr)
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (klass->confirm_display_change)
return klass->confirm_display_change (plugin);
else
return meta_plugin_complete_display_change (plugin, TRUE);
}

View File

@ -73,4 +73,6 @@ gboolean meta_plugin_manager_filter_keybinding (MetaPluginManager *mgr,
gboolean meta_plugin_manager_xevent_filter (MetaPluginManager *mgr,
XEvent *xev);
void meta_plugin_manager_confirm_display_change (MetaPluginManager *mgr);
#endif

View File

@ -41,6 +41,7 @@
#include "compositor-private.h"
#include "meta-window-actor-private.h"
#include "monitor-private.h"
G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT);
@ -332,3 +333,13 @@ meta_plugin_get_screen (MetaPlugin *plugin)
return priv->screen;
}
void
meta_plugin_complete_display_change (MetaPlugin *plugin,
gboolean ok)
{
MetaMonitorManager *manager;
manager = meta_monitor_manager_get ();
meta_monitor_manager_confirm_configuration (manager, ok);
}

View File

@ -24,6 +24,8 @@
#include <meta/meta-plugin.h>
#include <meta/window.h>
#include <meta/util.h>
#include <meta/meta-background-group.h>
#include <meta/meta-background-actor.h>
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
@ -98,6 +100,8 @@ static void kill_window_effects (MetaPlugin *plugin,
MetaWindowActor *actor);
static void kill_switch_workspace (MetaPlugin *plugin);
static void confirm_display_change (MetaPlugin *plugin);
static const MetaPluginInfo * plugin_info (MetaPlugin *plugin);
META_PLUGIN_DECLARE(MetaDefaultPlugin, meta_default_plugin);
@ -113,6 +117,8 @@ struct _MetaDefaultPluginPrivate
ClutterActor *desktop1;
ClutterActor *desktop2;
ClutterActor *background_group;
MetaPluginInfo info;
};
@ -203,6 +209,7 @@ meta_default_plugin_class_init (MetaDefaultPluginClass *klass)
plugin_class->plugin_info = plugin_info;
plugin_class->kill_window_effects = kill_window_effects;
plugin_class->kill_switch_workspace = kill_switch_workspace;
plugin_class->confirm_display_change = confirm_display_change;
g_type_class_add_private (gobject_class, sizeof (MetaDefaultPluginPrivate));
}
@ -299,9 +306,58 @@ show_stage (MetaPlugin *plugin)
return FALSE;
}
static void
on_monitors_changed (MetaScreen *screen,
MetaPlugin *plugin)
{
MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
int i, n;
clutter_actor_destroy_all_children (self->priv->background_group);
n = meta_screen_get_n_monitors (screen);
for (i = 0; i < n; i++)
{
MetaRectangle rect;
ClutterActor *background;
ClutterColor color;
meta_screen_get_monitor_geometry (screen, i, &rect);
background = meta_background_actor_new ();
clutter_actor_set_position (background, rect.x, rect.y);
clutter_actor_set_size (background, rect.width, rect.height);
/* Don't use rand() here, mesa calls srand() internally when
parsing the driconf XML, but it's nice if the colors are
reproducible.
*/
clutter_color_init (&color,
g_random_int () % 255,
g_random_int () % 255,
g_random_int () % 255,
255);
clutter_actor_set_background_color (background, &color);
clutter_actor_add_child (self->priv->background_group, background);
}
}
static void
start (MetaPlugin *plugin)
{
MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
MetaScreen *screen = meta_plugin_get_screen (plugin);
self->priv->background_group = meta_background_group_new ();
clutter_actor_insert_child_below (meta_get_window_group_for_screen (screen),
self->priv->background_group, NULL);
g_signal_connect (screen, "monitors-changed",
G_CALLBACK (on_monitors_changed), plugin);
on_monitors_changed (screen, plugin);
meta_later_add (META_LATER_BEFORE_REDRAW,
(GSourceFunc) show_stage,
plugin,
@ -782,3 +838,33 @@ plugin_info (MetaPlugin *plugin)
return &priv->info;
}
static void
on_dialog_closed (GPid pid,
gint status,
gpointer user_data)
{
MetaPlugin *plugin = user_data;
gboolean ok;
ok = g_spawn_check_exit_status (status, NULL);
meta_plugin_complete_display_change (plugin, ok);
}
static void
confirm_display_change (MetaPlugin *plugin)
{
GPid pid;
pid = meta_show_dialog ("--question",
"Does the display look OK?",
"20",
NULL,
"_Keep This Configuration",
"_Restore Previous Configuration",
"preferences-desktop-display",
0,
NULL, NULL);
g_child_watch_add (pid, on_dialog_closed, plugin);
}

View File

@ -2198,6 +2198,7 @@ meta_display_handle_event (MetaDisplay *display,
gboolean bypass_compositor;
gboolean filter_out_event;
XIEvent *input_event;
MetaMonitorManager *monitor;
MetaScreen *screen;
#ifdef WITH_VERBOSE_MODE
@ -2209,6 +2210,14 @@ meta_display_handle_event (MetaDisplay *display,
sn_display_process_event (display->sn_display, event);
#endif
/* Intercept XRandR events early and don't attempt any
processing for them. We still let them through to Gdk though,
so it can update its own internal state.
*/
monitor = meta_monitor_manager_get ();
if (meta_monitor_manager_handle_xevent (monitor, event))
return FALSE;
bypass_compositor = FALSE;
filter_out_event = FALSE;
display->current_time = event_get_time (display, event);
@ -2910,32 +2919,10 @@ meta_display_handle_event (MetaDisplay *display,
meta_stack_tracker_configure_event (screen->stack_tracker,
&event->xconfigure);
}
if (window && window->override_redirect)
meta_window_configure_notify (window, &event->xconfigure);
else
/* Handle screen resize */
{
MetaScreen *screen;
screen = meta_display_screen_for_root (display,
event->xconfigure.window);
if (screen != NULL)
{
#ifdef HAVE_RANDR
/* do the resize the official way */
XRRUpdateConfiguration (event);
#else
/* poke around in Xlib */
screen->xscreen->width = event->xconfigure.width;
screen->xscreen->height = event->xconfigure.height;
#endif
meta_screen_resize (screen,
event->xconfigure.width,
event->xconfigure.height);
}
}
break;
case ConfigureRequest:
/* This comment and code is found in both twm and fvwm */

539
src/core/edid-parse.c Normal file
View File

@ -0,0 +1,539 @@
/*
* Copyright 2007 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Author: Soren Sandmann <sandmann@redhat.com> */
#include "edid.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <glib.h>
static int
get_bit (int in, int bit)
{
return (in & (1 << bit)) >> bit;
}
static int
get_bits (int in, int begin, int end)
{
int mask = (1 << (end - begin + 1)) - 1;
return (in >> begin) & mask;
}
static int
decode_header (const uchar *edid)
{
if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
return TRUE;
return FALSE;
}
static int
decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
{
int is_model_year;
/* Manufacturer Code */
info->manufacturer_code[0] = get_bits (edid[0x08], 2, 6);
info->manufacturer_code[1] = get_bits (edid[0x08], 0, 1) << 3;
info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7);
info->manufacturer_code[2] = get_bits (edid[0x09], 0, 4);
info->manufacturer_code[3] = '\0';
info->manufacturer_code[0] += 'A' - 1;
info->manufacturer_code[1] += 'A' - 1;
info->manufacturer_code[2] += 'A' - 1;
/* Product Code */
info->product_code = edid[0x0b] << 8 | edid[0x0a];
/* Serial Number */
info->serial_number =
edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
/* Week and Year */
is_model_year = FALSE;
switch (edid[0x10])
{
case 0x00:
info->production_week = -1;
break;
case 0xff:
info->production_week = -1;
is_model_year = TRUE;
break;
default:
info->production_week = edid[0x10];
break;
}
if (is_model_year)
{
info->production_year = -1;
info->model_year = 1990 + edid[0x11];
}
else
{
info->production_year = 1990 + edid[0x11];
info->model_year = -1;
}
return TRUE;
}
static int
decode_edid_version (const uchar *edid, MonitorInfo *info)
{
info->major_version = edid[0x12];
info->minor_version = edid[0x13];
return TRUE;
}
static int
decode_display_parameters (const uchar *edid, MonitorInfo *info)
{
/* Digital vs Analog */
info->is_digital = get_bit (edid[0x14], 7);
if (info->is_digital)
{
int bits;
static const int bit_depth[8] =
{
-1, 6, 8, 10, 12, 14, 16, -1
};
static const Interface interfaces[6] =
{
UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
};
bits = get_bits (edid[0x14], 4, 6);
info->connector.digital.bits_per_primary = bit_depth[bits];
bits = get_bits (edid[0x14], 0, 3);
if (bits <= 5)
info->connector.digital.interface = interfaces[bits];
else
info->connector.digital.interface = UNDEFINED;
}
else
{
int bits = get_bits (edid[0x14], 5, 6);
static const double levels[][3] =
{
{ 0.7, 0.3, 1.0 },
{ 0.714, 0.286, 1.0 },
{ 1.0, 0.4, 1.4 },
{ 0.7, 0.0, 0.7 },
};
info->connector.analog.video_signal_level = levels[bits][0];
info->connector.analog.sync_signal_level = levels[bits][1];
info->connector.analog.total_signal_level = levels[bits][2];
info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
}
/* Screen Size / Aspect Ratio */
if (edid[0x15] == 0 && edid[0x16] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = -1.0;
}
else if (edid[0x16] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x15] + 99);
}
else if (edid[0x15] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x16] + 99);
info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
}
else
{
info->width_mm = 10 * edid[0x15];
info->height_mm = 10 * edid[0x16];
}
/* Gamma */
if (edid[0x17] == 0xFF)
info->gamma = -1.0;
else
info->gamma = (edid[0x17] + 100.0) / 100.0;
/* Features */
info->standby = get_bit (edid[0x18], 7);
info->suspend = get_bit (edid[0x18], 6);
info->active_off = get_bit (edid[0x18], 5);
if (info->is_digital)
{
info->connector.digital.rgb444 = TRUE;
if (get_bit (edid[0x18], 3))
info->connector.digital.ycrcb444 = 1;
if (get_bit (edid[0x18], 4))
info->connector.digital.ycrcb422 = 1;
}
else
{
int bits = get_bits (edid[0x18], 3, 4);
ColorType color_type[4] =
{
MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
};
info->connector.analog.color_type = color_type[bits];
}
info->srgb_is_standard = get_bit (edid[0x18], 2);
/* In 1.3 this is called "has preferred timing" */
info->preferred_timing_includes_native = get_bit (edid[0x18], 1);
/* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
info->continuous_frequency = get_bit (edid[0x18], 0);
return TRUE;
}
static double
decode_fraction (int high, int low)
{
double result = 0.0;
int i;
high = (high << 2) | low;
for (i = 0; i < 10; ++i)
result += get_bit (high, i) * pow (2, i - 10);
return result;
}
static int
decode_color_characteristics (const uchar *edid, MonitorInfo *info)
{
info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7));
info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4));
info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3));
info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1));
info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7));
info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5));
info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3));
info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1));
return TRUE;
}
static int
decode_established_timings (const uchar *edid, MonitorInfo *info)
{
static const Timing established[][8] =
{
{
{ 800, 600, 60 },
{ 800, 600, 56 },
{ 640, 480, 75 },
{ 640, 480, 72 },
{ 640, 480, 67 },
{ 640, 480, 60 },
{ 720, 400, 88 },
{ 720, 400, 70 }
},
{
{ 1280, 1024, 75 },
{ 1024, 768, 75 },
{ 1024, 768, 70 },
{ 1024, 768, 60 },
{ 1024, 768, 87 },
{ 832, 624, 75 },
{ 800, 600, 75 },
{ 800, 600, 72 }
},
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1152, 870, 75 }
},
};
int i, j, idx;
idx = 0;
for (i = 0; i < 3; ++i)
{
for (j = 0; j < 8; ++j)
{
int byte = edid[0x23 + i];
if (get_bit (byte, j) && established[i][j].frequency != 0)
info->established[idx++] = established[i][j];
}
}
return TRUE;
}
static int
decode_standard_timings (const uchar *edid, MonitorInfo *info)
{
int i;
for (i = 0; i < 8; i++)
{
int first = edid[0x26 + 2 * i];
int second = edid[0x27 + 2 * i];
if (first != 0x01 && second != 0x01)
{
int w = 8 * (first + 31);
int h = 0;
switch (get_bits (second, 6, 7))
{
case 0x00: h = (w / 16) * 10; break;
case 0x01: h = (w / 4) * 3; break;
case 0x02: h = (w / 5) * 4; break;
case 0x03: h = (w / 16) * 9; break;
}
info->standard[i].width = w;
info->standard[i].height = h;
info->standard[i].frequency = get_bits (second, 0, 5) + 60;
}
}
return TRUE;
}
static void
decode_lf_string (const uchar *s, int n_chars, char *result)
{
int i;
for (i = 0; i < n_chars; ++i)
{
if (s[i] == 0x0a)
{
*result++ = '\0';
break;
}
else if (s[i] == 0x00)
{
/* Convert embedded 0's to spaces */
*result++ = ' ';
}
else
{
*result++ = s[i];
}
}
}
static void
decode_display_descriptor (const uchar *desc,
MonitorInfo *info)
{
switch (desc[0x03])
{
case 0xFC:
decode_lf_string (desc + 5, 13, info->dsc_product_name);
break;
case 0xFF:
decode_lf_string (desc + 5, 13, info->dsc_serial_number);
break;
case 0xFE:
decode_lf_string (desc + 5, 13, info->dsc_string);
break;
case 0xFD:
/* Range Limits */
break;
case 0xFB:
/* Color Point */
break;
case 0xFA:
/* Timing Identifications */
break;
case 0xF9:
/* Color Management */
break;
case 0xF8:
/* Timing Codes */
break;
case 0xF7:
/* Established Timings */
break;
case 0x10:
break;
}
}
static void
decode_detailed_timing (const uchar *timing,
DetailedTiming *detailed)
{
int bits;
StereoType stereo[] =
{
NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
};
detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
detailed->v_front_porch =
get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
detailed->v_sync =
get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
detailed->right_border = timing[0x0f];
detailed->top_border = timing[0x10];
detailed->interlaced = get_bit (timing[0x11], 7);
/* Stereo */
bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0);
detailed->stereo = stereo[bits];
/* Sync */
bits = timing[0x11];
detailed->digital_sync = get_bit (bits, 4);
if (detailed->digital_sync)
{
detailed->connector.digital.composite = !get_bit (bits, 3);
if (detailed->connector.digital.composite)
{
detailed->connector.digital.serrations = get_bit (bits, 2);
detailed->connector.digital.negative_vsync = FALSE;
}
else
{
detailed->connector.digital.serrations = FALSE;
detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
}
detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
}
else
{
detailed->connector.analog.bipolar = get_bit (bits, 3);
detailed->connector.analog.serrations = get_bit (bits, 2);
detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
}
}
static int
decode_descriptors (const uchar *edid, MonitorInfo *info)
{
int i;
int timing_idx;
timing_idx = 0;
for (i = 0; i < 4; ++i)
{
int index = 0x36 + i * 18;
if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00)
{
decode_display_descriptor (edid + index, info);
}
else
{
decode_detailed_timing (edid + index, &(info->detailed_timings[timing_idx++]));
}
}
info->n_detailed_timings = timing_idx;
return TRUE;
}
static void
decode_check_sum (const uchar *edid,
MonitorInfo *info)
{
int i;
uchar check = 0;
for (i = 0; i < 128; ++i)
check += edid[i];
info->checksum = check;
}
MonitorInfo *
decode_edid (const uchar *edid)
{
MonitorInfo *info = g_new0 (MonitorInfo, 1);
decode_check_sum (edid, info);
if (decode_header (edid)
&& decode_vendor_and_product_identification (edid, info)
&& decode_edid_version (edid, info)
&& decode_display_parameters (edid, info)
&& decode_color_characteristics (edid, info)
&& decode_established_timings (edid, info)
&& decode_standard_timings (edid, info)
&& decode_descriptors (edid, info))
{
return info;
}
else
{
g_free (info);
return NULL;
}
}

195
src/core/edid.h Normal file
View File

@ -0,0 +1,195 @@
/* edid.h
*
* Copyright 2007, 2008, Red Hat, Inc.
*
* This file is part of the Gnome Library.
*
* The Gnome Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The Gnome Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the Gnome Library; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Author: Soren Sandmann <sandmann@redhat.com>
*/
#ifndef EDID_H
#define EDID_H
typedef unsigned char uchar;
typedef struct MonitorInfo MonitorInfo;
typedef struct Timing Timing;
typedef struct DetailedTiming DetailedTiming;
typedef enum
{
UNDEFINED,
DVI,
HDMI_A,
HDMI_B,
MDDI,
DISPLAY_PORT
} Interface;
typedef enum
{
UNDEFINED_COLOR,
MONOCHROME,
RGB,
OTHER_COLOR
} ColorType;
typedef enum
{
NO_STEREO,
FIELD_RIGHT,
FIELD_LEFT,
TWO_WAY_RIGHT_ON_EVEN,
TWO_WAY_LEFT_ON_EVEN,
FOUR_WAY_INTERLEAVED,
SIDE_BY_SIDE
} StereoType;
struct Timing
{
int width;
int height;
int frequency;
};
struct DetailedTiming
{
int pixel_clock;
int h_addr;
int h_blank;
int h_sync;
int h_front_porch;
int v_addr;
int v_blank;
int v_sync;
int v_front_porch;
int width_mm;
int height_mm;
int right_border;
int top_border;
int interlaced;
StereoType stereo;
int digital_sync;
union
{
struct
{
int bipolar;
int serrations;
int sync_on_green;
} analog;
struct
{
int composite;
int serrations;
int negative_vsync;
int negative_hsync;
} digital;
} connector;
};
struct MonitorInfo
{
int checksum;
char manufacturer_code[4];
int product_code;
unsigned int serial_number;
int production_week; /* -1 if not specified */
int production_year; /* -1 if not specified */
int model_year; /* -1 if not specified */
int major_version;
int minor_version;
int is_digital;
union
{
struct
{
int bits_per_primary;
Interface interface;
int rgb444;
int ycrcb444;
int ycrcb422;
} digital;
struct
{
double video_signal_level;
double sync_signal_level;
double total_signal_level;
int blank_to_black;
int separate_hv_sync;
int composite_sync_on_h;
int composite_sync_on_green;
int serration_on_vsync;
ColorType color_type;
} analog;
} connector;
int width_mm; /* -1 if not specified */
int height_mm; /* -1 if not specified */
double aspect_ratio; /* -1.0 if not specififed */
double gamma; /* -1.0 if not specified */
int standby;
int suspend;
int active_off;
int srgb_is_standard;
int preferred_timing_includes_native;
int continuous_frequency;
double red_x;
double red_y;
double green_x;
double green_y;
double blue_x;
double blue_y;
double white_x;
double white_y;
Timing established[24]; /* Terminated by 0x0x0 */
Timing standard[8];
int n_detailed_timings;
DetailedTiming detailed_timings[4]; /* If monitor has a preferred
* mode, it is the first one
* (whether it has, is
* determined by the
* preferred_timing_includes
* bit.
*/
/* Optional product description */
char dsc_serial_number[14];
char dsc_product_name[14];
char dsc_string[14]; /* Unspecified ASCII data */
};
MonitorInfo *decode_edid (const uchar *data);
char *make_display_name (const MonitorInfo *info);
char *make_display_size_string (int width_mm, int height_mm);
#endif

View File

@ -1965,6 +1965,23 @@ process_overlay_key (MetaDisplay *display,
return TRUE;
meta_display_overlay_key_activate (display);
}
else
{
/* In some rare race condition, mutter might not receive the Super_L
* KeyRelease event because:
* - the compositor might end the modal mode and call XIUngrabDevice
* while the key is still down
* - passive grabs are only activated on KeyPress and not KeyRelease.
*
* In this case, display->overlay_key_only_pressed might be wrong.
* Mutter still ought to acknowledge events, otherwise the X server
* will not send the next events.
*
* https://bugzilla.gnome.org/show_bug.cgi?id=666101
*/
XIAllowEvents (display->xdisplay, event->deviceid,
XIAsyncDevice, event->time);
}
return TRUE;
}

View File

@ -0,0 +1,40 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* 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.
*/
/* This file is shared between mutter (src/core/meta-xrandr-shared.h)
and gnome-desktop (libgnome-desktop/meta-xrandr-shared.h).
The canonical place for all changes is mutter.
There should be no includes in this file.
*/
#ifndef META_XRANDR_SHARED_H
#define META_XRANDR_SHARED_H
typedef enum {
META_POWER_SAVE_UNKNOWN = -1,
META_POWER_SAVE_ON = 0,
META_POWER_SAVE_STANDBY,
META_POWER_SAVE_SUSPEND,
META_POWER_SAVE_OFF,
} MetaPowerSave;
#endif

1769
src/core/monitor-config.c Normal file

File diff suppressed because it is too large Load Diff

390
src/core/monitor-private.h Normal file
View File

@ -0,0 +1,390 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* \file screen-private.h Handling of monitor configuration
*
* Managing multiple monitors
* This file contains structures and functions that handle
* multiple monitors, including reading the current configuration
* and available hardware, and applying it.
*
* This interface is private to mutter, API users should look
* at MetaScreen instead.
*/
/*
* Copyright (C) 2001 Havoc Pennington
* 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.
*/
#ifndef META_MONITOR_PRIVATE_H
#define META_MONITOR_PRIVATE_H
#include <cogl/cogl.h>
#include <libgnome-desktop/gnome-pnp-ids.h>
#include "display-private.h"
#include <meta/screen.h>
#include "stack-tracker.h"
#include "ui.h"
#ifdef HAVE_WAYLAND
#include <wayland-server.h>
#endif
#include "meta-xrandr-shared.h"
#include "meta-dbus-xrandr.h"
typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass;
typedef struct _MetaMonitorManager MetaMonitorManager;
typedef struct _MetaMonitorConfigClass MetaMonitorConfigClass;
typedef struct _MetaMonitorConfig MetaMonitorConfig;
#ifndef HAVE_WAYLAND
enum wl_output_transform {
WL_OUTPUT_TRANSFORM_NORMAL,
WL_OUTPUT_TRANSFORM_90,
WL_OUTPUT_TRANSFORM_180,
WL_OUTPUT_TRANSFORM_270,
WL_OUTPUT_TRANSFORM_FLIPPED,
WL_OUTPUT_TRANSFORM_FLIPPED_90,
WL_OUTPUT_TRANSFORM_FLIPPED_180,
WL_OUTPUT_TRANSFORM_FLIPPED_270
};
#endif
typedef struct _MetaOutput MetaOutput;
typedef struct _MetaCRTC MetaCRTC;
typedef struct _MetaMonitorMode MetaMonitorMode;
typedef struct _MetaMonitorInfo MetaMonitorInfo;
typedef struct _MetaCRTCInfo MetaCRTCInfo;
typedef struct _MetaOutputInfo MetaOutputInfo;
struct _MetaOutput
{
/* The CRTC driving this output, NULL if the output is not enabled */
MetaCRTC *crtc;
/* The low-level ID of this output, used to apply back configuration */
glong output_id;
char *name;
char *vendor;
char *product;
char *serial;
int width_mm;
int height_mm;
CoglSubpixelOrder subpixel_order;
MetaMonitorMode *preferred_mode;
MetaMonitorMode **modes;
unsigned int n_modes;
MetaCRTC **possible_crtcs;
unsigned int n_possible_crtcs;
MetaOutput **possible_clones;
unsigned int n_possible_clones;
int backlight;
int backlight_min;
int backlight_max;
/* Used when changing configuration */
gboolean is_dirty;
/* The low-level bits used to build the high-level info
in MetaMonitorInfo
XXX: flags maybe?
There is a lot of code that uses MonitorInfo->is_primary,
but nobody uses MetaOutput yet
*/
gboolean is_primary;
gboolean is_presentation;
};
struct _MetaCRTC
{
glong crtc_id;
MetaRectangle rect;
MetaMonitorMode *current_mode;
enum wl_output_transform transform;
unsigned int all_transforms;
/* Only used to build the logical configuration
from the HW one
*/
MetaMonitorInfo *logical_monitor;
/* Used when changing configuration */
gboolean is_dirty;
};
struct _MetaMonitorMode
{
/* The low-level ID of this mode, used to apply back configuration */
glong mode_id;
int width;
int height;
float refresh_rate;
};
/**
* MetaMonitorInfo:
*
* A structure with high-level information about monitors.
* This corresponds to a subset of the compositor coordinate space.
* Clones are only reported once, irrespective of the way
* they're implemented (two CRTCs configured for the same
* coordinates or one CRTCs driving two outputs). Inactive CRTCs
* are ignored, and so are disabled outputs.
*/
struct _MetaMonitorInfo
{
int number;
int xinerama_index;
MetaRectangle rect;
gboolean is_primary;
gboolean is_presentation; /* XXX: not yet used */
gboolean in_fullscreen;
/* The primary or first output for this monitor, 0 if we can't figure out.
It can be matched to an output_id of a MetaOutput.
This is used as an opaque token on reconfiguration when switching from
clone to extened, to decide on what output the windows should go next
(it's an attempt to keep windows on the same monitor, and preferably on
the primary one).
*/
glong output_id;
};
/*
* MetaCRTCInfo:
* This represents the writable part of a CRTC, as deserialized from DBus
* or built by MetaMonitorConfig
*
* Note: differently from the other structures in this file, MetaCRTCInfo
* is handled by pointer. This is to accomodate the usage in MetaMonitorConfig
*/
struct _MetaCRTCInfo {
MetaCRTC *crtc;
MetaMonitorMode *mode;
int x;
int y;
enum wl_output_transform transform;
GPtrArray *outputs;
};
/*
* MetaOutputInfo:
* this is the same as MetaOutputInfo, but for CRTCs
*/
struct _MetaOutputInfo {
MetaOutput *output;
gboolean is_primary;
gboolean is_presentation;
};
#define META_TYPE_MONITOR_MANAGER (meta_monitor_manager_get_type ())
#define META_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManager))
#define META_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass))
#define META_IS_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER))
#define META_IS_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER))
#define META_MONITOR_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass))
struct _MetaMonitorManager
{
MetaDBusDisplayConfigSkeleton parent_instance;
/* XXX: this structure is very badly
packed, but I like the logical organization
of fields */
gboolean in_init;
unsigned int serial;
MetaPowerSave power_save_mode;
int max_screen_width;
int max_screen_height;
int screen_width;
int screen_height;
/* 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
*/
MetaOutput *outputs;
unsigned int n_outputs;
MetaMonitorMode *modes;
unsigned int n_modes;
MetaCRTC *crtcs;
unsigned int n_crtcs;
MetaMonitorInfo *monitor_infos;
unsigned int n_monitor_infos;
int primary_monitor_index;
int dbus_name_id;
int persistent_timeout_id;
MetaMonitorConfig *config;
GnomePnpIds *pnp_ids;
};
struct _MetaMonitorManagerClass
{
MetaDBusDisplayConfigSkeletonClass parent_class;
void (*read_current) (MetaMonitorManager *);
char* (*get_edid_file) (MetaMonitorManager *,
MetaOutput *);
GBytes* (*read_edid) (MetaMonitorManager *,
MetaOutput *);
void (*apply_configuration) (MetaMonitorManager *,
MetaCRTCInfo **,
unsigned int ,
MetaOutputInfo **,
unsigned int);
void (*set_power_save_mode) (MetaMonitorManager *,
MetaPowerSave);
void (*change_backlight) (MetaMonitorManager *,
MetaOutput *,
int);
void (*get_crtc_gamma) (MetaMonitorManager *,
MetaCRTC *,
gsize *,
unsigned short **,
unsigned short **,
unsigned short **);
void (*set_crtc_gamma) (MetaMonitorManager *,
MetaCRTC *,
gsize ,
unsigned short *,
unsigned short *,
unsigned short *);
gboolean (*handle_xevent) (MetaMonitorManager *,
XEvent *);
};
GType meta_monitor_manager_get_type (void);
void meta_monitor_manager_initialize (void);
MetaMonitorManager *meta_monitor_manager_get (void);
MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
unsigned int *n_infos);
MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
unsigned int *n_outputs);
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);
int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
gboolean meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
XEvent *event);
void meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
int *width,
int *height);
void meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
int *width,
int *height);
void meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
MetaCRTCInfo **crtcs,
unsigned int n_crtcs,
MetaOutputInfo **outputs,
unsigned int n_outputs);
void meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager,
gboolean ok);
#define META_TYPE_MONITOR_MANAGER_XRANDR (meta_monitor_manager_xrandr_get_type ())
#define META_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandr))
#define META_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
#define META_IS_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_XRANDR))
#define META_IS_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_XRANDR))
#define META_MONITOR_MANAGER_XRANDR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
typedef struct _MetaMonitorManagerXrandrClass MetaMonitorManagerXrandrClass;
typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr;
GType meta_monitor_manager_xrandr_get_type (void);
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG))
#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG))
#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
GType meta_monitor_config_get_type (void) G_GNUC_CONST;
MetaMonitorConfig *meta_monitor_config_new (void);
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
MetaMonitorManager *manager);
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_monitor_config_make_default (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_monitor_config_update_current (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_monitor_config_make_persistent (MetaMonitorConfig *config);
void meta_monitor_config_restore_previous (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_crtc_info_free (MetaCRTCInfo *info);
void meta_output_info_free (MetaOutputInfo *info);
/* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */
static inline gboolean
meta_monitor_transform_is_rotated (enum wl_output_transform transform)
{
return (transform % 2);
}
#endif

1039
src/core/monitor-xrandr.c Normal file

File diff suppressed because it is too large Load Diff

1548
src/core/monitor.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -38,17 +38,7 @@
#include <X11/Xutil.h>
#include "stack-tracker.h"
#include "ui.h"
typedef struct _MetaMonitorInfo MetaMonitorInfo;
struct _MetaMonitorInfo
{
int number;
MetaRectangle rect;
gboolean is_primary;
gboolean in_fullscreen;
XID output; /* The primary or first output for this crtc, None if no xrandr */
};
#include "monitor-private.h"
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
gpointer user_data);
@ -103,8 +93,9 @@ struct _MetaScreen
guint32 wm_sn_timestamp;
MetaMonitorInfo *monitor_infos;
int primary_monitor_index;
int n_monitor_infos;
int primary_monitor_index;
gboolean has_xinerama_indices;
/* Cache the current monitor */
int last_monitor_index;
@ -232,10 +223,6 @@ void meta_screen_calc_workspace_layout (MetaScreen *screen,
MetaWorkspaceLayout *layout);
void meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout);
void meta_screen_resize (MetaScreen *screen,
int width,
int height);
void meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
MetaWindow *keep);
@ -263,4 +250,9 @@ Window meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen)
gboolean meta_screen_handle_xevent (MetaScreen *screen,
XEvent *xevent);
int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
int index);
int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
int index);
#endif

View File

@ -50,10 +50,6 @@
#include <X11/extensions/Xinerama.h>
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
#include <X11/Xatom.h>
#include <locale.h>
#include <string.h>
@ -78,6 +74,9 @@ static void meta_screen_sn_event (SnMonitorEvent *event,
void *user_data);
#endif
static void on_monitors_changed (MetaMonitorManager *manager,
MetaScreen *screen);
enum
{
PROP_N_WORKSPACES = 1,
@ -352,100 +351,71 @@ set_wm_icon_size_hint (MetaScreen *screen)
#undef N_VALS
}
/* The list of monitors reported by the windowing system might include
* mirrored monitors with identical bounds. Since mirrored monitors
* shouldn't be treated as separate monitors for most purposes, we
* filter them out here. (We ignore the possibility of partially
* overlapping monitors because they are rare and it's hard to come
* up with any sensible interpretation.)
*/
static void
filter_mirrored_monitors (MetaScreen *screen)
meta_screen_ensure_xinerama_indices (MetaScreen *screen)
{
int i, j;
XineramaScreenInfo *infos;
int n_infos, i, j;
/* Currently always true and simplifies things */
g_assert (screen->primary_monitor_index == 0);
if (screen->has_xinerama_indices)
return;
for (i = 1; i < screen->n_monitor_infos; i++)
screen->has_xinerama_indices = TRUE;
if (!XineramaIsActive (screen->display->xdisplay))
return;
infos = XineramaQueryScreens (screen->display->xdisplay, &n_infos);
if (n_infos <= 0 || infos == NULL)
{
/* In case we've filtered previous monitors */
screen->monitor_infos[i].number = i;
meta_XFree (infos);
return;
}
for (j = 0; j < i; j++)
for (i = 0; i < screen->n_monitor_infos; ++i)
{
if (meta_rectangle_equal (&screen->monitor_infos[i].rect,
&screen->monitor_infos[j].rect))
for (j = 0; j < n_infos; ++j)
{
memmove (&screen->monitor_infos[i],
&screen->monitor_infos[i + 1],
(screen->n_monitor_infos - i - 1) * sizeof (MetaMonitorInfo));
screen->n_monitor_infos--;
i--;
continue;
}
if (screen->monitor_infos[i].rect.x == infos[j].x_org &&
screen->monitor_infos[i].rect.y == infos[j].y_org &&
screen->monitor_infos[i].rect.width == infos[j].width &&
screen->monitor_infos[i].rect.height == infos[j].height)
screen->monitor_infos[i].xinerama_index = j;
}
}
meta_XFree (infos);
}
#ifdef HAVE_RANDR
static MetaMonitorInfo *
find_monitor_with_rect (MetaScreen *screen, int x, int y, int w, int h)
int
meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
int index)
{
meta_screen_ensure_xinerama_indices (screen);
return screen->monitor_infos[index].xinerama_index;
}
int
meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
int index)
{
MetaMonitorInfo *info;
int i;
meta_screen_ensure_xinerama_indices (screen);
for (i = 0; i < screen->n_monitor_infos; i++)
{
info = &screen->monitor_infos[i];
if (x == info->rect.x &&
y == info->rect.y &&
w == info->rect.width &&
h == info->rect.height)
return info;
}
return NULL;
if (screen->monitor_infos[i].xinerama_index == index)
return i;
return -1;
}
/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the
* outputs the "main". This is the one we consider "owning" the windows, so if
* the mirroring is changed to a dual monitor setup then the windows are moved to the
* crtc that now has that main output. If one of the outputs is the primary that is
* always the main, otherwise we just use the first.
*/
static XID
find_main_output_for_crtc (MetaScreen *screen, XRRScreenResources *resources, XRRCrtcInfo *crtc)
{
XRROutputInfo *output;
RROutput primary_output;
int i;
XID res;
primary_output = XRRGetOutputPrimary (screen->display->xdisplay, screen->xroot);
res = None;
for (i = 0; i < crtc->noutput; i++)
{
output = XRRGetOutputInfo (screen->display->xdisplay, resources, crtc->outputs[i]);
if (output->connection != RR_Disconnected &&
(res == None || crtc->outputs[i] == primary_output))
res = crtc->outputs[i];
XRRFreeOutputInfo (output);
}
return res;
}
#endif
static void
reload_monitor_infos (MetaScreen *screen)
{
MetaDisplay *display;
{
GList *tmp;
MetaMonitorManager *manager;
tmp = screen->workspaces;
while (tmp != NULL)
@ -456,146 +426,18 @@ reload_monitor_infos (MetaScreen *screen)
tmp = tmp->next;
}
}
display = screen->display;
/* Any previous screen->monitor_infos or screen->outputs is freed by the caller */
/* Any previous screen->monitor_infos is freed by the caller */
screen->monitor_infos = NULL;
screen->n_monitor_infos = 0;
screen->last_monitor_index = 0;
/* Xinerama doesn't have a concept of primary monitor, however XRandR
* does. However, the XRandR xinerama compat code always sorts the
* primary output first, so we rely on that here. We could use the
* native XRandR calls instead of xinerama, but that would be
* slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as
* that is defined in terms of xinerama monitor indexes.
* So, since we don't need anything in xrandr except the primary
* we can keep using xinerama and use the first monitor as the
* primary.
*/
screen->primary_monitor_index = 0;
screen->has_xinerama_indices = FALSE;
screen->display->monitor_cache_invalidated = TRUE;
if (g_getenv ("MUTTER_DEBUG_XINERAMA"))
{
meta_topic (META_DEBUG_XINERAMA,
"Pretending a single monitor has two Xinerama screens\n");
manager = meta_monitor_manager_get ();
screen->monitor_infos = g_new0 (MetaMonitorInfo, 2);
screen->n_monitor_infos = 2;
screen->monitor_infos[0].number = 0;
screen->monitor_infos[0].rect = screen->rect;
screen->monitor_infos[0].rect.width = screen->rect.width / 2;
screen->monitor_infos[0].in_fullscreen = -1;
screen->monitor_infos[1].number = 1;
screen->monitor_infos[1].rect = screen->rect;
screen->monitor_infos[1].rect.x = screen->rect.width / 2;
screen->monitor_infos[1].rect.width = screen->rect.width / 2;
screen->monitor_infos[0].in_fullscreen = -1;
}
if (screen->n_monitor_infos == 0 &&
XineramaIsActive (display->xdisplay))
{
XineramaScreenInfo *infos;
int n_infos;
int i;
n_infos = 0;
infos = XineramaQueryScreens (display->xdisplay, &n_infos);
meta_topic (META_DEBUG_XINERAMA,
"Found %d Xinerama screens on display %s\n",
n_infos, display->name);
if (n_infos > 0)
{
screen->monitor_infos = g_new0 (MetaMonitorInfo, n_infos);
screen->n_monitor_infos = n_infos;
i = 0;
while (i < n_infos)
{
screen->monitor_infos[i].number = infos[i].screen_number;
screen->monitor_infos[i].rect.x = infos[i].x_org;
screen->monitor_infos[i].rect.y = infos[i].y_org;
screen->monitor_infos[i].rect.width = infos[i].width;
screen->monitor_infos[i].rect.height = infos[i].height;
screen->monitor_infos[i].in_fullscreen = -1;
meta_topic (META_DEBUG_XINERAMA,
"Monitor %d is %d,%d %d x %d\n",
screen->monitor_infos[i].number,
screen->monitor_infos[i].rect.x,
screen->monitor_infos[i].rect.y,
screen->monitor_infos[i].rect.width,
screen->monitor_infos[i].rect.height);
++i;
}
}
meta_XFree (infos);
#ifdef HAVE_RANDR
{
XRRScreenResources *resources;
resources = XRRGetScreenResourcesCurrent (display->xdisplay, screen->xroot);
if (resources)
{
for (i = 0; i < resources->ncrtc; i++)
{
XRRCrtcInfo *crtc;
MetaMonitorInfo *info;
crtc = XRRGetCrtcInfo (display->xdisplay, resources, resources->crtcs[i]);
info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, (int)crtc->height);
if (info)
info->output = find_main_output_for_crtc (screen, resources, crtc);
XRRFreeCrtcInfo (crtc);
}
XRRFreeScreenResources (resources);
}
}
#endif
}
else if (screen->n_monitor_infos > 0)
{
meta_topic (META_DEBUG_XINERAMA,
"No Xinerama extension or Xinerama inactive on display %s\n",
display->name);
}
/* If no Xinerama, fill in the single screen info so
* we can use the field unconditionally
*/
if (screen->n_monitor_infos == 0)
{
meta_topic (META_DEBUG_XINERAMA,
"No Xinerama screens, using default screen info\n");
screen->monitor_infos = g_new0 (MetaMonitorInfo, 1);
screen->n_monitor_infos = 1;
screen->monitor_infos[0].number = 0;
screen->monitor_infos[0].rect = screen->rect;
screen->monitor_infos[0].in_fullscreen = -1;
}
filter_mirrored_monitors (screen);
screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE;
g_assert (screen->n_monitor_infos > 0);
g_assert (screen->monitor_infos != NULL);
screen->monitor_infos = meta_monitor_manager_get_monitor_infos (manager,
(unsigned*)&screen->n_monitor_infos);
screen->primary_monitor_index = meta_monitor_manager_get_primary_index (manager);
}
/* The guard window allows us to leave minimized windows mapped so
@ -674,6 +516,7 @@ meta_screen_new (MetaDisplay *display,
guint32 manager_timestamp;
gulong current_workspace;
MetaWaylandCompositor *compositor;
MetaMonitorManager *manager;
replace_current_wm = meta_get_replace_current_wm ();
@ -833,17 +676,15 @@ meta_screen_new (MetaDisplay *display,
screen->xroot = xroot;
screen->rect.x = screen->rect.y = 0;
if (meta_is_wayland_compositor ())
{
compositor = meta_wayland_compositor_get_default ();
screen->rect.width = clutter_actor_get_width (compositor->stage);
screen->rect.height = clutter_actor_get_height (compositor->stage);
}
else
{
screen->rect.width = WidthOfScreen (screen->xscreen);
screen->rect.height = HeightOfScreen (screen->xscreen);
}
meta_monitor_manager_initialize ();
manager = meta_monitor_manager_get ();
g_signal_connect (manager, "monitors-changed",
G_CALLBACK (on_monitors_changed), screen);
meta_monitor_manager_get_screen_size (manager,
&screen->rect.width,
&screen->rect.height);
screen->current_cursor = -1; /* invalid/unset */
screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
@ -869,10 +710,6 @@ meta_screen_new (MetaDisplay *display,
screen->compositor_data = NULL;
screen->guard_window = None;
screen->monitor_infos = NULL;
screen->n_monitor_infos = 0;
screen->last_monitor_index = 0;
reload_monitor_infos (screen);
meta_cursor_tracker_get_for_screen (screen);
@ -3007,19 +2844,15 @@ meta_screen_resize_func (MetaScreen *screen,
meta_window_recalc_features (window);
}
void
meta_screen_resize (MetaScreen *screen,
int width,
int height)
static void
on_monitors_changed (MetaMonitorManager *manager,
MetaScreen *screen)
{
GSList *windows, *tmp;
MetaMonitorInfo *old_monitor_infos;
GSList *tmp, *windows;
screen->rect.width = width;
screen->rect.height = height;
/* Save the old monitor infos, so they stay valid during the update */
old_monitor_infos = screen->monitor_infos;
meta_monitor_manager_get_screen_size (manager,
&screen->rect.width,
&screen->rect.height);
reload_monitor_infos (screen);
set_desktop_geometry_hint (screen);
@ -3031,8 +2864,8 @@ meta_screen_resize (MetaScreen *screen,
changes.x = 0;
changes.y = 0;
changes.width = width;
changes.height = height;
changes.width = screen->rect.width;
changes.height = screen->rect.height;
XConfigureWindow(screen->display->xdisplay,
screen->guard_window,
@ -3042,7 +2875,8 @@ meta_screen_resize (MetaScreen *screen,
if (screen->display->compositor)
meta_compositor_sync_screen_size (screen->display->compositor,
screen, width, height);
screen,
screen->rect.width, screen->rect.height);
/* Queue a resize on all the windows */
meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
@ -3058,7 +2892,6 @@ meta_screen_resize (MetaScreen *screen,
meta_window_update_for_monitors_changed (window);
}
g_free (old_monitor_infos);
g_slist_free (windows);
meta_screen_queue_check_fullscreen (screen);

View File

@ -345,6 +345,8 @@ topic_name (MetaDebugTopic topic)
return "COMPOSITOR";
case META_DEBUG_EDGE_RESISTANCE:
return "EDGE_RESISTANCE";
case META_DEBUG_DBUS:
return "DBUS";
case META_DEBUG_VERBOSE:
return "VERBOSE";
}
@ -650,8 +652,13 @@ meta_show_dialog (const char *type,
append_argument (args, "zenity");
append_argument (args, type);
if (display)
{
append_argument (args, "--display");
append_argument (args, display);
}
append_argument (args, "--class");
append_argument (args, "mutter-dialog");
append_argument (args, "--title");

View File

@ -179,7 +179,7 @@ struct _MetaWindow
* been overridden (via a client message), the window will cover the union of
* these monitors. If not, this is the single monitor which the window's
* origin is on. */
long fullscreen_monitors[4];
gint fullscreen_monitors[4];
/* Whether we're trying to constrain the window to be fully onscreen */
guint require_fully_onscreen : 1;

View File

@ -2281,10 +2281,14 @@ set_net_wm_state (MetaWindow *window)
if (window->fullscreen)
{
data[0] = window->fullscreen_monitors[0];
data[1] = window->fullscreen_monitors[1];
data[2] = window->fullscreen_monitors[2];
data[3] = window->fullscreen_monitors[3];
data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[0]);
data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[1]);
data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[2]);
data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[3]);
meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n");
meta_error_trap_push (window->display);
@ -4958,7 +4962,8 @@ meta_window_update_for_monitors_changed (MetaWindow *window)
{
MetaMonitorInfo *info = &window->screen->monitor_infos[i];
if (info->output == old->output)
if (info->output_id != 0 &&
info->output_id == old->output_id)
{
new = info;
break;
@ -7303,10 +7308,14 @@ meta_window_client_message (MetaWindow *window,
meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n",
window->desc);
top = event->xclient.data.l[0];
bottom = event->xclient.data.l[1];
left = event->xclient.data.l[2];
right = event->xclient.data.l[3];
top = meta_screen_xinerama_index_to_monitor_index (window->screen,
event->xclient.data.l[0]);
bottom = meta_screen_xinerama_index_to_monitor_index (window->screen,
event->xclient.data.l[1]);
left = meta_screen_xinerama_index_to_monitor_index (window->screen,
event->xclient.data.l[2]);
right = meta_screen_xinerama_index_to_monitor_index (window->screen,
event->xclient.data.l[3]);
/* source_indication = event->xclient.data.l[4]; */
meta_window_update_fullscreen_monitors (window, top, bottom, left, right);

View File

@ -72,6 +72,7 @@ item(_MUTTER_TIMESTAMP_PING)
item(_MUTTER_FOCUS_SET)
item(_MUTTER_SENTINEL)
item(_MUTTER_VERSION)
item(_MUTTER_PRESENTATION_OUTPUT)
item(WM_CLIENT_MACHINE)
item(MANAGER)
item(TARGETS)
@ -79,6 +80,7 @@ item(MULTIPLE)
item(TIMESTAMP)
item(VERSION)
item(ATOM_PAIR)
item(BACKLIGHT)
/* Oddities: These are used, and we need atoms for them,
* but when we need all _NET_WM hints (i.e. when we're making

View File

@ -205,6 +205,21 @@ struct _MetaPluginClass
gboolean (*keybinding_filter) (MetaPlugin *plugin,
MetaKeyBinding *binding);
/**
* MetaPluginClass::confirm_display_config:
* @plugin: a #MetaPlugin
*
* Virtual function called when the display configuration changes.
* The common way to implement this function is to show some form
* of modal dialog that should ask the user if everything was ok.
*
* When confirmed by the user, the plugin must call meta_plugin_complete_display_change()
* to make the configuration permanent. If that function is not
* called within the timeout, the previous configuration will be
* reapplied.
*/
void (*confirm_display_change) (MetaPlugin *plugin);
/**
* MetaPluginClass::plugin_info:
* @plugin: a #MetaPlugin
@ -214,6 +229,7 @@ struct _MetaPluginClass
* Returns: a #MetaPluginInfo.
*/
const MetaPluginInfo * (*plugin_info) (MetaPlugin *plugin);
};
/**
@ -360,6 +376,10 @@ void
meta_plugin_destroy_completed (MetaPlugin *plugin,
MetaWindowActor *actor);
void
meta_plugin_complete_display_change (MetaPlugin *plugin,
gboolean ok);
/**
* MetaModalOptions:
* @META_MODAL_POINTER_ALREADY_GRABBED: if set the pointer is already

View File

@ -102,7 +102,8 @@ typedef enum
META_DEBUG_RESIZING = 1 << 18,
META_DEBUG_SHAPES = 1 << 19,
META_DEBUG_COMPOSITOR = 1 << 20,
META_DEBUG_EDGE_RESISTANCE = 1 << 21
META_DEBUG_EDGE_RESISTANCE = 1 << 21,
META_DEBUG_DBUS = 1 << 22
} MetaDebugTopic;
void meta_topic_real (MetaDebugTopic topic,

293
src/xrandr.xml Normal file
View File

@ -0,0 +1,293 @@
<!DOCTYPE node PUBLIC
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
<node>
<!--
org.gnome.Mutter.DisplayConfig:
@short_description: display configuration interface
This interface is used by mutter and gnome-settings-daemon
to apply multiple monitor configuration.
-->
<interface name="org.gnome.Mutter.DisplayConfig">
<!--
GetResources:
@serial: configuration serial
@crtcs: available CRTCs
@outputs: available outputs
@modes: available modes
@max_screen_width:
@max_screen_height:
Retrieves the current layout of the hardware.
@serial is an unique identifier representing the current state
of the screen. It must be passed back to ApplyConfiguration()
and will be increased for every configuration change (so that
mutter can detect that the new configuration is based on old
state).
A CRTC (CRT controller) is a logical monitor, ie a portion
of the compositor coordinate space. It might correspond
to multiple monitors, when in clone mode, but not that
it is possible to implement clone mode also by setting different
CRTCs to the same coordinates.
The number of CRTCs represent the maximum number of monitors
that can be set to expand and it is a HW constraint; if more
monitors are connected, then necessarily some will clone. This
is complementary to the concept of the encoder (not exposed in
the API), which groups outputs that necessarily will show the
same image (again a HW constraint).
A CRTC is represented by a DBus structure with the following
layout:
* u ID: the ID in the API of this CRTC
* x winsys_id: the low-level ID of this CRTC (which might
be a XID, a KMS handle or something entirely
different)
* i x, y, width, height: the geometry of this CRTC
(might be invalid if the CRTC is not in
use)
* i current_mode: the current mode of the CRTC, or -1 if this
CRTC is not used
Note: the size of the mode will always correspond
to the width and height of the CRTC
* u current_transform: the current transform (espressed according
to the wayland protocol)
* au transforms: all possible transforms
* a{sv} properties: other high-level properties that affect this
CRTC; they are not necessarily reflected in
the hardware.
No property is specified in this version of the API.
Note: all geometry information refers to the untransformed
display.
An output represents a physical screen, connected somewhere to
the computer. Floating connectors are not exposed in the API.
An output is a DBus struct with the following fields:
* u ID: the ID in the API
* x winsys_id: the low-level ID of this output (XID or KMS handle)
* i current_crtc: the CRTC that is currently driving this output,
or -1 if the output is disabled
* au possible_crtcs: all CRTCs that can control this output
* s name: the name of the connector to which the output is attached
(like VGA1 or HDMI)
* au modes: valid modes for this output
* au clones: valid clones for this output, ie other outputs that
can be assigned the same CRTC as this one; if you
want to mirror two outputs that don't have each other
in the clone list, you must configure two different
CRTCs for the same geometry
* a{sv} properties: other high-level properties that affect this
output; they are not necessarily reflected in
the hardware.
Known properties:
- "vendor" (s): (readonly) the human readable name
of the manufacturer
- "product" (s): (readonly) the human readable name
of the display model
- "serial" (s): (readonly) the serial number of this
particular hardware part
- "display-name" (s): (readonly) a human readable name
of this output, to be shown in the UI
- "backlight" (i): (readonly, use the specific interface)
the backlight value as a percentage
(-1 if not supported)
- "primary" (b): whether this output is primary
or not
- "presentation" (b): whether this output is
for presentation only
Note: properties might be ignored if not consistenly
applied to all outputs in the same clone group. In
general, it's expected that presentation or primary
outputs will not be cloned.
A mode represents a set of parameters that are applied to
each output, such as resolution and refresh rate. It is a separate
object so that it can be referenced by CRTCs and outputs.
Multiple outputs in the same CRTCs must all have the same mode.
A mode is exposed as:
* u ID: the ID in the API
* x winsys_id: the low-level ID of this mode
* u width, height: the resolution
* d frequency: refresh rate
Output and modes are read-only objects (except for output properties),
they can change only in accordance to HW changes (such as hotplugging
a monitor), while CRTCs can be changed with ApplyConfiguration().
XXX: actually, if you insist enough, you can add new modes
through xrandr command line or the KMS API, overriding what the
kernel driver and the EDID say.
Usually, it only matters with old cards with broken drivers, or
old monitors with broken EDIDs, but it happens more often with
projectors (if for example the kernel driver doesn't add the
640x480 - 800x600 - 1024x768 default modes). Probably something
that we need to handle in mutter anyway.
-->
<method name="GetResources">
<arg name="serial" direction="out" type="u" />
<arg name="crtcs" direction="out" type="a(uxiiiiiuaua{sv})" />
<arg name="outputs" direction="out" type="a(uxiausauaua{sv})" />
<arg name="modes" direction="out" type="a(uxuud)" />
<arg name="max_screen_width" direction="out" type="i" />
<arg name="max_screen_height" direction="out" type="i" />
</method>
<!--
ApplyConfiguration:
@serial: configuration serial
@persistent: whether this configuration should be saved on disk
@crtcs: new data for CRTCs
@outputs: new data for outputs
Applies the requested configuration changes.
@serial must match the serial from the last GetResources() call,
or org.freedesktop.DBus.AccessDenied will be generated.
If @persistent is true, mutter will attempt to replicate this
configuration the next time this HW layout appears.
@crtcs represents the new logical configuration, as a list
of structures containing:
- u ID: the API ID from the corresponding GetResources() call
- i new_mode: the API ID of the new mode to configure the CRTC
with, or -1 if the CRTC should be disabled
- i x, y: the new coordinates of the top left corner
the geometry will be completed with the size information
from @new_mode
- u transform: the desired transform
- au outputs: the API ID of outputs that should be assigned to
this CRTC
- a{sv} properties: properties whose value should be changed
Note: CRTCs not referenced in the array will be disabled.
@outputs represent the output property changes as:
- u ID: the API ID of the output to change
- a{sv} properties: properties whose value should be changed
Note: both for CRTCs and outputs, properties not included in
the dictionary will not be changed.
Note: unrecognized properties will have no effect, but if the
configuration change succeeds the property will be reported
by the next GetResources() call, and if @persistent is true,
it will also be saved to disk.
If the configuration is invalid according to the previous
GetResources() call, for example because a CRTC references
an output it cannot drive, or not all outputs support the
chosen mode, the error org.freedesktop.DBus.InvalidArgs will
be generated.
If the configuration cannot be applied for any other reason
(eg. the screen size would exceed texture limits), the error
org.freedesktop.DBus.Error.LimitsExceeded will be generated.
-->
<method name="ApplyConfiguration">
<arg name="serial" direction="in" type="u" />
<arg name="persistent" direction="in" type="b" />
<arg name="crtcs" direction="in" type="a(uiiiuaua{sv})" />
<arg name="outputs" direction="in" type="a(ua{sv})" />
</method>
<!--
ChangeBacklight:
@serial: configuration serial
@output: the API id of the output
@value: the new backlight value
Changes the backlight of @output to @value, which is
expressed as a percentage and rounded to the HW limits.
Returns the new value after rounding.
-->
<method name="ChangeBacklight">
<arg name="serial" direction="in" type="u" />
<arg name="output" direction="in" type="u" />
<arg name="value" direction="in" type="i" />
<arg name="new_value" direction="out" type="i" />
</method>
<!--
GetCrtcGamma:
@serial: configuration serial
@crtc: API id of the crtc
@red: red gamma ramp
@green: green gamma ramp
@blue: blue gamma ramp
Requests the current gamma ramps of @crtc.
-->
<method name="GetCrtcGamma">
<arg name="serial" direction="in" type="u" />
<arg name="crtc" direction="in" type="u" />
<arg name="red" direction="out" type="aq" />
<arg name="green" direction="out" type="aq" />
<arg name="blue" direction="out" type="aq" />
</method>
<!--
SetCrtcGamma:
@serial: configuration serial
@crtc: API id of the crtc
@red: red gamma ramp
@green: green gamma ramp
@blue: blue gamma ramp
Changes the gamma ramps of @crtc.
-->
<method name="SetCrtcGamma">
<arg name="serial" direction="in" type="u" />
<arg name="crtc" direction="in" type="u" />
<arg name="red" direction="in" type="aq" />
<arg name="green" direction="in" type="aq" />
<arg name="blue" direction="in" type="aq" />
</method>
<!--
PowerSaveMode:
Contains the current power saving mode for the screen, and
allows changing it.
Possible values:
- 0: on
- 1: standby
- 2: suspend
- 3: off
- -1: unknown (unsupported)
A client should not attempt to change the powersave mode
from -1 (unknown) to any other value, and viceversa.
Note that the actual effects of the different values
depend on the hardware and the kernel driver in use, and
it's perfectly possible that all values different than on
have the same effect.
Also, setting the PowerSaveMode to 3 (off) may or may
not have the same effect as disabling all outputs by
setting no CRTC on them with ApplyConfiguration(), and
may or may not cause a configuration change.
Also note that this property might become out of date
if changed through different means (for example using the
XRandR interface directly).
-->
<property name="PowerSaveMode" type="i" access="readwrite" />
<!--
MonitorsChanged:
The signal is emitted every time the screen configuration
changes.
The client should then call GetResources() to read the new layout.
-->
<signal name="MonitorsChanged" />
</interface>
</node>