2
* -*- c-basic-offset: 4 -*-
4
* Copyright 2007, 2008, Red Hat, Inc.
5
* Copyright 2010 Giovanni Campagna
7
* This file is part of the Gnome Library.
9
* The Gnome Library is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Library General Public License as
11
* published by the Free Software Foundation; either version 2 of the
12
* License, or (at your option) any later version.
14
* The Gnome Library is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Library General Public License for more details.
19
* You should have received a copy of the GNU Library General Public
20
* License along with the Gnome Library; see the file COPYING.LIB. If not,
21
* write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22
* Boston, MA 02110-1301, USA.
24
* Author: Soren Sandmann <sandmann@redhat.com>
28
#include <glib/gi18n-lib.h>
32
#include <glib/gstdio.h>
41
#include "gsd-rr-config.h"
44
#include "gsd-rr-private.h"
46
#define CONFIG_INTENDED_BASENAME "monitors.xml"
47
#define CONFIG_BACKUP_BASENAME "monitors.xml.backup"
49
/* Look for DPI_FALLBACK in:
50
* http://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/gsd-xsettings-manager.c
51
* for the reasoning */
52
#define DPI_FALLBACK 96.0
54
/* In version 0 of the config file format, we had several <configuration>
55
* toplevel elements and no explicit version number. So, the filed looked
65
* Since version 1 of the config file, the file has a toplevel <monitors>
66
* element to group all the configurations. That element has a "version"
67
* attribute which is an integer. So, the file looks like this:
69
* <monitors version="1">
79
/* A helper wrapper around the GMarkup parser stuff */
80
static gboolean parse_file_gmarkup (const gchar *file,
81
const GMarkupParser *parser,
85
typedef struct CrtcAssignment CrtcAssignment;
87
static gboolean crtc_assignment_apply (CrtcAssignment *assign,
90
static CrtcAssignment *crtc_assignment_new (GsdRRScreen *screen,
91
GsdRROutputInfo **outputs,
93
static void crtc_assignment_free (CrtcAssignment *assign);
101
G_DEFINE_TYPE (GsdRRConfig, gsd_rr_config, G_TYPE_OBJECT)
103
typedef struct Parser Parser;
105
/* Parser for monitor configurations */
108
int config_file_version;
109
GsdRROutputInfo * output;
110
GsdRRConfig * configuration;
112
GPtrArray * configurations;
117
parse_int (const char *text)
119
return strtol (text, NULL, 0);
123
parse_uint (const char *text)
125
return strtoul (text, NULL, 0);
129
stack_is (Parser *parser,
138
stack = g_list_prepend (stack, (gpointer)s1);
142
s = va_arg (args, const char *);
145
stack = g_list_prepend (stack, (gpointer)s);
146
s = va_arg (args, const char *);
150
l2 = parser->stack->head;
154
if (strcmp (l1->data, l2->data) != 0)
170
handle_start_element (GMarkupParseContext *context,
172
const gchar **attr_names,
173
const gchar **attr_values,
177
Parser *parser = user_data;
179
if (strcmp (name, "output") == 0)
182
g_assert (parser->output == NULL);
184
parser->output = g_object_new (GSD_TYPE_RR_OUTPUT_INFO, NULL);
185
parser->output->priv->rotation = 0;
187
for (i = 0; attr_names[i] != NULL; ++i)
189
if (strcmp (attr_names[i], "name") == 0)
191
parser->output->priv->name = g_strdup (attr_values[i]);
196
if (!parser->output->priv->name)
198
/* This really shouldn't happen, but it's better to make
199
* something up than to crash later.
201
g_warning ("Malformed monitor configuration file");
203
parser->output->priv->name = g_strdup ("default");
205
parser->output->priv->connected = FALSE;
206
parser->output->priv->on = FALSE;
207
parser->output->priv->primary = FALSE;
209
else if (strcmp (name, "configuration") == 0)
211
g_assert (parser->configuration == NULL);
213
parser->configuration = g_object_new (GSD_TYPE_RR_CONFIG, NULL);
214
parser->configuration->priv->clone = FALSE;
215
parser->configuration->priv->outputs = NULL;
217
else if (strcmp (name, "monitors") == 0)
221
for (i = 0; attr_names[i] != NULL; i++)
223
if (strcmp (attr_names[i], "version") == 0)
225
parser->config_file_version = parse_int (attr_values[i]);
231
g_queue_push_tail (parser->stack, g_strdup (name));
235
handle_end_element (GMarkupParseContext *context,
240
Parser *parser = user_data;
242
if (strcmp (name, "output") == 0)
244
/* If no rotation properties were set, just use GSD_RR_ROTATION_0 */
245
if (parser->output->priv->rotation == 0)
246
parser->output->priv->rotation = GSD_RR_ROTATION_0;
248
g_ptr_array_add (parser->outputs, parser->output);
250
parser->output = NULL;
252
else if (strcmp (name, "configuration") == 0)
254
g_ptr_array_add (parser->outputs, NULL);
255
parser->configuration->priv->outputs =
256
(GsdRROutputInfo **)g_ptr_array_free (parser->outputs, FALSE);
257
parser->outputs = g_ptr_array_new ();
258
g_ptr_array_add (parser->configurations, parser->configuration);
259
parser->configuration = NULL;
262
g_free (g_queue_pop_tail (parser->stack));
265
#define TOPLEVEL_ELEMENT (parser->config_file_version > 0 ? "monitors" : NULL)
268
handle_text (GMarkupParseContext *context,
274
Parser *parser = user_data;
276
if (stack_is (parser, "vendor", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
278
parser->output->priv->connected = TRUE;
280
strncpy ((gchar*) parser->output->priv->vendor, text, 3);
281
parser->output->priv->vendor[3] = 0;
283
else if (stack_is (parser, "clone", "configuration", TOPLEVEL_ELEMENT, NULL))
285
if (strcmp (text, "yes") == 0)
286
parser->configuration->priv->clone = TRUE;
288
else if (stack_is (parser, "product", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
290
parser->output->priv->connected = TRUE;
292
parser->output->priv->product = parse_int (text);
294
else if (stack_is (parser, "serial", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
296
parser->output->priv->connected = TRUE;
298
parser->output->priv->serial = parse_uint (text);
300
else if (stack_is (parser, "width", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
302
parser->output->priv->on = TRUE;
304
parser->output->priv->width = parse_int (text);
306
else if (stack_is (parser, "x", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
308
parser->output->priv->on = TRUE;
310
parser->output->priv->x = parse_int (text);
312
else if (stack_is (parser, "y", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
314
parser->output->priv->on = TRUE;
316
parser->output->priv->y = parse_int (text);
318
else if (stack_is (parser, "height", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
320
parser->output->priv->on = TRUE;
322
parser->output->priv->height = parse_int (text);
324
else if (stack_is (parser, "rate", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
326
parser->output->priv->on = TRUE;
328
parser->output->priv->rate = parse_int (text);
330
else if (stack_is (parser, "rotation", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
332
if (strcmp (text, "normal") == 0)
334
parser->output->priv->rotation |= GSD_RR_ROTATION_0;
336
else if (strcmp (text, "left") == 0)
338
parser->output->priv->rotation |= GSD_RR_ROTATION_90;
340
else if (strcmp (text, "upside_down") == 0)
342
parser->output->priv->rotation |= GSD_RR_ROTATION_180;
344
else if (strcmp (text, "right") == 0)
346
parser->output->priv->rotation |= GSD_RR_ROTATION_270;
349
else if (stack_is (parser, "reflect_x", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
351
if (strcmp (text, "yes") == 0)
353
parser->output->priv->rotation |= GSD_RR_REFLECT_X;
356
else if (stack_is (parser, "reflect_y", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
358
if (strcmp (text, "yes") == 0)
360
parser->output->priv->rotation |= GSD_RR_REFLECT_Y;
363
else if (stack_is (parser, "primary", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
365
if (strcmp (text, "yes") == 0)
367
parser->output->priv->primary = TRUE;
372
/* Ignore other properties so we can expand the format in the future */
377
parser_free (Parser *parser)
382
g_assert (parser != NULL);
385
g_object_unref (parser->output);
387
if (parser->configuration)
388
g_object_unref (parser->configuration);
390
for (i = 0; i < parser->outputs->len; ++i)
392
GsdRROutputInfo *output = parser->outputs->pdata[i];
394
g_object_unref (output);
397
g_ptr_array_free (parser->outputs, TRUE);
399
for (i = 0; i < parser->configurations->len; ++i)
401
GsdRRConfig *config = parser->configurations->pdata[i];
403
g_object_unref (config);
406
g_ptr_array_free (parser->configurations, TRUE);
408
for (list = parser->stack->head; list; list = list->next)
410
g_queue_free (parser->stack);
415
static GsdRRConfig **
416
configurations_read_from_file (const gchar *filename, GError **error)
418
Parser *parser = g_new0 (Parser, 1);
419
GsdRRConfig **result;
420
GMarkupParser callbacks = {
421
handle_start_element,
424
NULL, /* passthrough */
428
parser->config_file_version = 0;
429
parser->configurations = g_ptr_array_new ();
430
parser->outputs = g_ptr_array_new ();
431
parser->stack = g_queue_new ();
433
if (!parse_file_gmarkup (filename, &callbacks, parser, error))
437
g_assert (parser->outputs);
441
g_assert (parser->outputs);
443
g_ptr_array_add (parser->configurations, NULL);
444
result = (GsdRRConfig **)g_ptr_array_free (parser->configurations, FALSE);
445
parser->configurations = g_ptr_array_new ();
447
g_assert (parser->outputs);
449
parser_free (parser);
455
gsd_rr_config_init (GsdRRConfig *self)
457
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GSD_TYPE_RR_CONFIG, GsdRRConfigPrivate);
459
self->priv->clone = FALSE;
460
self->priv->screen = NULL;
461
self->priv->outputs = NULL;
465
gsd_rr_config_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *property)
467
GsdRRConfig *self = GSD_RR_CONFIG (gobject);
469
switch (property_id) {
471
self->priv->screen = g_value_dup_object (value);
474
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
479
gsd_rr_config_finalize (GObject *gobject)
481
GsdRRConfig *self = GSD_RR_CONFIG (gobject);
483
if (self->priv->screen)
484
g_object_unref (self->priv->screen);
486
if (self->priv->outputs) {
489
for (i = 0; self->priv->outputs[i] != NULL; i++) {
490
GsdRROutputInfo *output = self->priv->outputs[i];
491
g_object_unref (output);
493
g_free (self->priv->outputs);
496
G_OBJECT_CLASS (gsd_rr_config_parent_class)->finalize (gobject);
500
gsd_rr_config_load_current (GsdRRConfig *config, GError **error)
503
GsdRROutput **rr_outputs;
505
int clone_width = -1;
506
int clone_height = -1;
509
g_return_val_if_fail (GSD_IS_RR_CONFIG (config), FALSE);
511
a = g_ptr_array_new ();
512
rr_outputs = gsd_rr_screen_list_outputs (config->priv->screen);
514
config->priv->clone = FALSE;
516
for (i = 0; rr_outputs[i] != NULL; ++i)
518
GsdRROutput *rr_output = rr_outputs[i];
519
GsdRROutputInfo *output = g_object_new (GSD_TYPE_RR_OUTPUT_INFO, NULL);
520
GsdRRMode *mode = NULL;
521
const guint8 *edid_data = gsd_rr_output_get_edid_data (rr_output, NULL);
524
output->priv->name = g_strdup (gsd_rr_output_get_name (rr_output));
525
output->priv->connected = gsd_rr_output_is_connected (rr_output);
526
output->priv->display_name = g_strdup (gsd_rr_output_get_display_name (rr_output));
528
if (!output->priv->connected)
530
output->priv->x = -1;
531
output->priv->y = -1;
532
output->priv->width = -1;
533
output->priv->height = -1;
534
output->priv->rate = -1;
535
output->priv->rotation = GSD_RR_ROTATION_0;
539
MonitorInfo *info = NULL;
542
info = decode_edid (edid_data);
546
memcpy (output->priv->vendor, info->manufacturer_code,
547
sizeof (output->priv->vendor));
549
output->priv->product = info->product_code;
550
output->priv->serial = info->serial_number;
551
output->priv->aspect = info->aspect_ratio;
555
strcpy (output->priv->vendor, "???");
556
output->priv->product = 0;
557
output->priv->serial = 0;
561
crtc = gsd_rr_output_get_crtc (rr_output);
562
mode = crtc? gsd_rr_crtc_get_current_mode (crtc) : NULL;
566
output->priv->on = TRUE;
568
gsd_rr_crtc_get_position (crtc, &output->priv->x, &output->priv->y);
569
output->priv->width = gsd_rr_mode_get_width (mode);
570
output->priv->height = gsd_rr_mode_get_height (mode);
571
output->priv->rate = gsd_rr_mode_get_freq (mode);
572
output->priv->rotation = gsd_rr_crtc_get_current_rotation (crtc);
574
if (output->priv->x == 0 && output->priv->y == 0) {
575
if (clone_width == -1) {
576
clone_width = output->priv->width;
577
clone_height = output->priv->height;
578
} else if (clone_width == output->priv->width &&
579
clone_height == output->priv->height) {
580
config->priv->clone = TRUE;
586
output->priv->on = FALSE;
587
config->priv->clone = FALSE;
590
/* Get preferred size for the monitor */
591
mode = gsd_rr_output_get_preferred_mode (rr_output);
595
GsdRRMode **modes = gsd_rr_output_list_modes (rr_output);
597
/* FIXME: we should pick the "best" mode here, where best is
600
* - closest aspect ratio
603
* - We may want to extend randrwrap so that get_preferred
604
* returns that - although that could also depend on
613
output->priv->pref_width = gsd_rr_mode_get_width (mode);
614
output->priv->pref_height = gsd_rr_mode_get_height (mode);
618
/* Pick some random numbers. This should basically never happen */
619
output->priv->pref_width = 1024;
620
output->priv->pref_height = 768;
624
output->priv->primary = gsd_rr_output_get_is_primary (rr_output);
626
g_ptr_array_add (a, output);
629
g_ptr_array_add (a, NULL);
631
config->priv->outputs = (GsdRROutputInfo **)g_ptr_array_free (a, FALSE);
633
/* Walk the outputs computing the right-most edge of all
637
for (i = 0; config->priv->outputs[i] != NULL; ++i)
639
GsdRROutputInfo *output = config->priv->outputs[i];
641
if (output->priv->on)
643
last_x = MAX (last_x, output->priv->x + output->priv->width);
647
/* Now position all off displays to the right of the
650
for (i = 0; config->priv->outputs[i] != NULL; ++i)
652
GsdRROutputInfo *output = config->priv->outputs[i];
654
if (output->priv->connected && !output->priv->on)
656
output->priv->x = last_x;
657
last_x = output->priv->x + output->priv->width;
661
g_assert (gsd_rr_config_match (config, config));
667
gsd_rr_config_load_filename (GsdRRConfig *result, const char *filename, GError **error)
669
GsdRRConfig *current;
670
GsdRRConfig **configs;
671
gboolean found = FALSE;
673
g_return_val_if_fail (GSD_IS_RR_CONFIG (result), FALSE);
674
g_return_val_if_fail (filename != NULL, FALSE);
675
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
677
current = gsd_rr_config_new_current (result->priv->screen, error);
679
configs = configurations_read_from_file (filename, error);
685
for (i = 0; configs[i] != NULL; ++i)
687
if (gsd_rr_config_match (configs[i], current))
691
result->priv->clone = configs[i]->priv->clone;
693
array = g_ptr_array_new ();
694
for (j = 0; configs[i]->priv->outputs[j] != NULL; j++) {
695
g_object_ref (configs[i]->priv->outputs[j]);
696
g_ptr_array_add (array, configs[i]->priv->outputs[j]);
698
g_ptr_array_add (array, NULL);
699
result->priv->outputs = (GsdRROutputInfo **) g_ptr_array_free (array, FALSE);
704
g_object_unref (configs[i]);
709
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_NO_MATCHING_CONFIG,
710
_("none of the saved display configurations matched the active configuration"));
713
g_object_unref (current);
718
gsd_rr_config_class_init (GsdRRConfigClass *klass)
720
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
722
g_type_class_add_private (klass, sizeof (GsdRROutputInfoPrivate));
724
gobject_class->set_property = gsd_rr_config_set_property;
725
gobject_class->finalize = gsd_rr_config_finalize;
727
g_object_class_install_property (gobject_class, PROP_SCREEN,
728
g_param_spec_object ("screen", "Screen", "The GsdRRScreen this config applies to", GSD_TYPE_RR_SCREEN,
729
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
733
gsd_rr_config_new_current (GsdRRScreen *screen, GError **error)
735
GsdRRConfig *self = g_object_new (GSD_TYPE_RR_CONFIG, "screen", screen, NULL);
737
if (gsd_rr_config_load_current (self, error))
741
g_object_unref (self);
747
gsd_rr_config_new_stored (GsdRRScreen *screen, GError **error)
749
GsdRRConfig *self = g_object_new (GSD_TYPE_RR_CONFIG, "screen", screen, NULL);
753
filename = gsd_rr_config_get_intended_filename ();
755
success = gsd_rr_config_load_filename (self, filename, error);
763
g_object_unref (self);
769
parse_file_gmarkup (const gchar *filename,
770
const GMarkupParser *parser,
774
GMarkupParseContext *context = NULL;
775
gchar *contents = NULL;
776
gboolean result = TRUE;
779
if (!g_file_get_contents (filename, &contents, &len, err))
785
context = g_markup_parse_context_new (parser, 0, data, NULL);
787
if (!g_markup_parse_context_parse (context, contents, len, err))
793
if (!g_markup_parse_context_end_parse (context, err))
804
g_markup_parse_context_free (context);
810
output_match (GsdRROutputInfo *output1, GsdRROutputInfo *output2)
812
g_assert (GSD_IS_RR_OUTPUT_INFO (output1));
813
g_assert (GSD_IS_RR_OUTPUT_INFO (output2));
815
if (strcmp (output1->priv->name, output2->priv->name) != 0)
818
if (strcmp (output1->priv->vendor, output2->priv->vendor) != 0)
821
if (output1->priv->product != output2->priv->product)
824
if (output1->priv->serial != output2->priv->serial)
827
if (output1->priv->connected != output2->priv->connected)
834
output_equal (GsdRROutputInfo *output1, GsdRROutputInfo *output2)
836
g_assert (GSD_IS_RR_OUTPUT_INFO (output1));
837
g_assert (GSD_IS_RR_OUTPUT_INFO (output2));
839
if (!output_match (output1, output2))
842
if (output1->priv->on != output2->priv->on)
845
if (output1->priv->on)
847
if (output1->priv->width != output2->priv->width)
850
if (output1->priv->height != output2->priv->height)
853
if (output1->priv->rate != output2->priv->rate)
856
if (output1->priv->x != output2->priv->x)
859
if (output1->priv->y != output2->priv->y)
862
if (output1->priv->rotation != output2->priv->rotation)
869
static GsdRROutputInfo *
870
find_output (GsdRRConfig *config, const char *name)
874
for (i = 0; config->priv->outputs[i] != NULL; ++i)
876
GsdRROutputInfo *output = config->priv->outputs[i];
878
if (strcmp (name, output->priv->name) == 0)
885
/* Match means "these configurations apply to the same hardware
889
gsd_rr_config_match (GsdRRConfig *c1, GsdRRConfig *c2)
892
g_return_val_if_fail (GSD_IS_RR_CONFIG (c1), FALSE);
893
g_return_val_if_fail (GSD_IS_RR_CONFIG (c2), FALSE);
895
for (i = 0; c1->priv->outputs[i] != NULL; ++i)
897
GsdRROutputInfo *output1 = c1->priv->outputs[i];
898
GsdRROutputInfo *output2;
900
output2 = find_output (c2, output1->priv->name);
901
if (!output2 || !output_match (output1, output2))
908
/* Equal means "the configurations will result in the same
909
* modes being set on the outputs"
912
gsd_rr_config_equal (GsdRRConfig *c1,
916
g_return_val_if_fail (GSD_IS_RR_CONFIG (c1), FALSE);
917
g_return_val_if_fail (GSD_IS_RR_CONFIG (c2), FALSE);
919
for (i = 0; c1->priv->outputs[i] != NULL; ++i)
921
GsdRROutputInfo *output1 = c1->priv->outputs[i];
922
GsdRROutputInfo *output2;
924
output2 = find_output (c2, output1->priv->name);
925
if (!output2 || !output_equal (output1, output2))
932
static GsdRROutputInfo **
933
make_outputs (GsdRRConfig *config)
936
GsdRROutputInfo *first_on;
939
outputs = g_ptr_array_new ();
943
for (i = 0; config->priv->outputs[i] != NULL; ++i)
945
GsdRROutputInfo *old = config->priv->outputs[i];
946
GsdRROutputInfo *new = g_object_new (GSD_TYPE_RR_OUTPUT_INFO, NULL);
947
*(new->priv) = *(old->priv);
949
new->priv->name = g_strdup (old->priv->name);
950
if (old->priv->display_name)
951
new->priv->display_name = g_strdup (old->priv->display_name);
953
if (old->priv->on && !first_on)
956
if (config->priv->clone && new->priv->on)
960
new->priv->width = first_on->priv->width;
961
new->priv->height = first_on->priv->height;
962
new->priv->rotation = first_on->priv->rotation;
967
g_ptr_array_add (outputs, new);
970
g_ptr_array_add (outputs, NULL);
972
return (GsdRROutputInfo **)g_ptr_array_free (outputs, FALSE);
976
gsd_rr_config_applicable (GsdRRConfig *configuration,
980
GsdRROutputInfo **outputs;
981
CrtcAssignment *assign;
985
g_return_val_if_fail (GSD_IS_RR_CONFIG (configuration), FALSE);
986
g_return_val_if_fail (GSD_IS_RR_SCREEN (screen), FALSE);
987
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
989
outputs = make_outputs (configuration);
990
assign = crtc_assignment_new (screen, outputs, error);
995
crtc_assignment_free (assign);
1002
for (i = 0; outputs[i] != NULL; i++) {
1003
g_object_unref (outputs[i]);
1009
/* Database management */
1012
ensure_config_directory (void)
1014
g_mkdir_with_parents (g_get_user_config_dir (), 0700);
1018
gsd_rr_config_get_backup_filename (void)
1020
ensure_config_directory ();
1021
return g_build_filename (g_get_user_config_dir (), CONFIG_BACKUP_BASENAME, NULL);
1025
gsd_rr_config_get_intended_filename (void)
1027
ensure_config_directory ();
1028
return g_build_filename (g_get_user_config_dir (), CONFIG_INTENDED_BASENAME, NULL);
1032
get_rotation_name (GsdRRRotation r)
1034
if (r & GSD_RR_ROTATION_0)
1036
if (r & GSD_RR_ROTATION_90)
1038
if (r & GSD_RR_ROTATION_180)
1039
return "upside_down";
1040
if (r & GSD_RR_ROTATION_270)
1049
return x? "yes" : "no";
1053
get_reflect_x (GsdRRRotation r)
1055
return yes_no (r & GSD_RR_REFLECT_X);
1059
get_reflect_y (GsdRRRotation r)
1061
return yes_no (r & GSD_RR_REFLECT_Y);
1065
emit_configuration (GsdRRConfig *config,
1070
g_string_append_printf (string, " <configuration>\n");
1072
g_string_append_printf (string, " <clone>%s</clone>\n", yes_no (config->priv->clone));
1074
for (j = 0; config->priv->outputs[j] != NULL; ++j)
1076
GsdRROutputInfo *output = config->priv->outputs[j];
1078
g_string_append_printf (
1079
string, " <output name=\"%s\">\n", output->priv->name);
1081
if (output->priv->connected && *output->priv->vendor != '\0')
1083
g_string_append_printf (
1084
string, " <vendor>%s</vendor>\n", output->priv->vendor);
1085
g_string_append_printf (
1086
string, " <product>0x%04x</product>\n", output->priv->product);
1087
g_string_append_printf (
1088
string, " <serial>0x%08x</serial>\n", output->priv->serial);
1091
/* An unconnected output which is on does not make sense */
1092
if (output->priv->connected && output->priv->on)
1094
g_string_append_printf (
1095
string, " <width>%d</width>\n", output->priv->width);
1096
g_string_append_printf (
1097
string, " <height>%d</height>\n", output->priv->height);
1098
g_string_append_printf (
1099
string, " <rate>%d</rate>\n", output->priv->rate);
1100
g_string_append_printf (
1101
string, " <x>%d</x>\n", output->priv->x);
1102
g_string_append_printf (
1103
string, " <y>%d</y>\n", output->priv->y);
1104
g_string_append_printf (
1105
string, " <rotation>%s</rotation>\n", get_rotation_name (output->priv->rotation));
1106
g_string_append_printf (
1107
string, " <reflect_x>%s</reflect_x>\n", get_reflect_x (output->priv->rotation));
1108
g_string_append_printf (
1109
string, " <reflect_y>%s</reflect_y>\n", get_reflect_y (output->priv->rotation));
1110
g_string_append_printf (
1111
string, " <primary>%s</primary>\n", yes_no (output->priv->primary));
1114
g_string_append_printf (string, " </output>\n");
1117
g_string_append_printf (string, " </configuration>\n");
1121
gsd_rr_config_sanitize (GsdRRConfig *config)
1124
int x_offset, y_offset;
1127
/* Offset everything by the top/left-most coordinate to
1128
* make sure the configuration starts at (0, 0)
1130
x_offset = y_offset = G_MAXINT;
1131
for (i = 0; config->priv->outputs[i]; ++i)
1133
GsdRROutputInfo *output = config->priv->outputs[i];
1135
if (output->priv->on)
1137
x_offset = MIN (x_offset, output->priv->x);
1138
y_offset = MIN (y_offset, output->priv->y);
1142
for (i = 0; config->priv->outputs[i]; ++i)
1144
GsdRROutputInfo *output = config->priv->outputs[i];
1146
if (output->priv->on)
1148
output->priv->x -= x_offset;
1149
output->priv->y -= y_offset;
1153
/* Only one primary, please */
1155
for (i = 0; config->priv->outputs[i]; ++i)
1157
if (config->priv->outputs[i]->priv->primary)
1161
config->priv->outputs[i]->priv->primary = FALSE;
1172
gsd_rr_config_ensure_primary (GsdRRConfig *configuration)
1175
GsdRROutputInfo *laptop;
1176
GsdRROutputInfo *top_left;
1178
GsdRRConfigPrivate *priv;
1180
g_return_val_if_fail (GSD_IS_RR_CONFIG (configuration), FALSE);
1185
priv = configuration->priv;
1187
for (i = 0; priv->outputs[i] != NULL; ++i) {
1188
GsdRROutputInfo *info = priv->outputs[i];
1190
if (!info->priv->on) {
1191
info->priv->primary = FALSE;
1195
/* ensure only one */
1196
if (info->priv->primary) {
1198
info->priv->primary = FALSE;
1204
if (top_left == NULL
1205
|| (info->priv->x < top_left->priv->x
1206
&& info->priv->y < top_left->priv->y)) {
1210
&& _gsd_rr_output_name_is_laptop (info->priv->name)) {
1211
/* shame we can't find the connector type
1212
as with gsd_rr_output_is_laptop */
1218
if (laptop != NULL) {
1219
laptop->priv->primary = TRUE;
1220
} else if (top_left != NULL) {
1221
/* Note: top_left can be NULL if all outputs are off */
1222
top_left->priv->primary = TRUE;
1230
gsd_rr_config_save (GsdRRConfig *configuration, GError **error)
1232
GsdRRConfig **configurations;
1235
gchar *intended_filename;
1236
gchar *backup_filename;
1239
g_return_val_if_fail (GSD_IS_RR_CONFIG (configuration), FALSE);
1240
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1242
output = g_string_new ("");
1244
backup_filename = gsd_rr_config_get_backup_filename ();
1245
intended_filename = gsd_rr_config_get_intended_filename ();
1247
configurations = configurations_read_from_file (intended_filename, NULL); /* NULL-GError */
1249
g_string_append_printf (output, "<monitors version=\"1\">\n");
1253
for (i = 0; configurations[i] != NULL; ++i)
1255
if (!gsd_rr_config_match (configurations[i], configuration))
1256
emit_configuration (configurations[i], output);
1257
g_object_unref (configurations[i]);
1260
g_free (configurations);
1263
emit_configuration (configuration, output);
1265
g_string_append_printf (output, "</monitors>\n");
1267
/* backup the file first */
1268
rename (intended_filename, backup_filename); /* no error checking because the intended file may not even exist */
1270
result = g_file_set_contents (intended_filename, output->str, -1, error);
1273
rename (backup_filename, intended_filename); /* no error checking because the backup may not even exist */
1275
g_free (backup_filename);
1276
g_free (intended_filename);
1282
gsd_rr_config_apply_with_time (GsdRRConfig *config,
1283
GsdRRScreen *screen,
1287
CrtcAssignment *assignment;
1288
GsdRROutputInfo **outputs;
1289
gboolean result = FALSE;
1292
g_return_val_if_fail (GSD_IS_RR_CONFIG (config), FALSE);
1293
g_return_val_if_fail (GSD_IS_RR_SCREEN (screen), FALSE);
1295
outputs = make_outputs (config);
1297
assignment = crtc_assignment_new (screen, outputs, error);
1299
for (i = 0; outputs[i] != NULL; i++)
1300
g_object_unref (outputs[i]);
1305
if (crtc_assignment_apply (assignment, timestamp, error))
1308
crtc_assignment_free (assignment);
1316
/* gsd_rr_config_apply_from_filename_with_time:
1317
* @screen: A #GsdRRScreen
1318
* @filename: Path of the file to look in for stored RANDR configurations.
1319
* @timestamp: X server timestamp from the event that causes the screen configuration to change (a user's button press, for example)
1320
* @error: Location to store error, or %NULL
1322
* Loads the file in @filename and looks for suitable matching RANDR
1323
* configurations in the file; if one is found, that configuration will be
1324
* applied to the current set of RANDR outputs.
1326
* Typically, @filename is the result of gsd_rr_config_get_intended_filename() or
1327
* gsd_rr_config_get_backup_filename().
1329
* Returns: TRUE if the RANDR configuration was loaded and applied from
1330
* the specified file, or FALSE otherwise:
1332
* If the file in question is loaded successfully but the configuration cannot
1333
* be applied, the @error will have a domain of #GSD_RR_ERROR. Note that an
1334
* error code of #GSD_RR_ERROR_NO_MATCHING_CONFIG is not a real error; it
1335
* simply means that there were no stored configurations that match the current
1336
* set of RANDR outputs.
1338
* If the file in question cannot be loaded, the @error will have a domain of
1339
* #G_FILE_ERROR. Note that an error code of G_FILE_ERROR_NOENT is not really
1340
* an error, either; it means that there was no stored configuration file and so
1341
* nothing is changed.
1344
gsd_rr_config_apply_from_filename_with_time (GsdRRScreen *screen, const char *filename, guint32 timestamp, GError **error)
1346
GsdRRConfig *stored;
1348
g_return_val_if_fail (GSD_IS_RR_SCREEN (screen), FALSE);
1349
g_return_val_if_fail (filename != NULL, FALSE);
1350
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1352
stored = g_object_new (GSD_TYPE_RR_CONFIG, "screen", screen, NULL);
1354
if (gsd_rr_config_load_filename (stored, filename, error))
1358
gsd_rr_config_ensure_primary (stored);
1359
result = gsd_rr_config_apply_with_time (stored, screen, timestamp, error);
1361
g_object_unref (stored);
1366
g_object_unref (stored);
1372
* gsd_rr_config_get_outputs:
1374
* Returns: (array zero-terminated=1) (element-type GnomeDesktop.RROutputInfo) (transfer none): the output configuration for this #GsdRRConfig
1377
gsd_rr_config_get_outputs (GsdRRConfig *self)
1379
g_return_val_if_fail (GSD_IS_RR_CONFIG (self), NULL);
1381
return self->priv->outputs;
1385
* gsd_rr_config_get_clone:
1387
* Returns: whether at least two outputs are at (0, 0) offset and they
1388
* have the same width/height. Those outputs are of course connected and on
1389
* (i.e. they have a CRTC assigned).
1392
gsd_rr_config_get_clone (GsdRRConfig *self)
1394
g_return_val_if_fail (GSD_IS_RR_CONFIG (self), FALSE);
1396
return self->priv->clone;
1400
gsd_rr_config_set_clone (GsdRRConfig *self, gboolean clone)
1402
g_return_if_fail (GSD_IS_RR_CONFIG (self));
1404
self->priv->clone = clone;
1410
typedef struct CrtcInfo CrtcInfo;
1417
GsdRRRotation rotation;
1421
struct CrtcAssignment
1423
GsdRRScreen *screen;
1425
GsdRROutput *primary;
1429
can_clone (CrtcInfo *info,
1430
GsdRROutput *output)
1434
for (i = 0; i < info->outputs->len; ++i)
1436
GsdRROutput *clone = info->outputs->pdata[i];
1438
if (!gsd_rr_output_can_clone (clone, output))
1446
crtc_assignment_assign (CrtcAssignment *assign,
1451
GsdRRRotation rotation,
1453
GsdRROutput *output,
1456
CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
1458
const char *output_name;
1460
crtc_id = gsd_rr_crtc_get_id (crtc);
1461
output_name = gsd_rr_output_get_name (output);
1463
if (!gsd_rr_crtc_can_drive_output (crtc, output))
1465
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
1466
_("CRTC %d cannot drive output %s"), crtc_id, output_name);
1470
if (!gsd_rr_output_supports_mode (output, mode))
1472
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
1473
_("output %s does not support mode %dx%d@%dHz"),
1475
gsd_rr_mode_get_width (mode),
1476
gsd_rr_mode_get_height (mode),
1477
gsd_rr_mode_get_freq (mode));
1481
if (!gsd_rr_crtc_supports_rotation (crtc, rotation))
1483
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
1484
_("CRTC %d does not support rotation=%s"),
1486
get_rotation_name (rotation));
1492
if (!(info->mode == mode &&
1495
info->rotation == rotation))
1497
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
1498
_("output %s does not have the same parameters as another cloned output:\n"
1499
"existing mode = %d, new mode = %d\n"
1500
"existing coordinates = (%d, %d), new coordinates = (%d, %d)\n"
1501
"existing rotation = %s, new rotation = %s"),
1503
gsd_rr_mode_get_id (info->mode), gsd_rr_mode_get_id (mode),
1506
get_rotation_name (info->rotation), get_rotation_name (rotation));
1510
if (!can_clone (info, output))
1512
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
1513
_("cannot clone to output %s"),
1518
g_ptr_array_add (info->outputs, output);
1520
if (primary && !assign->primary)
1522
assign->primary = output;
1529
CrtcInfo *info = g_new0 (CrtcInfo, 1);
1534
info->rotation = rotation;
1535
info->outputs = g_ptr_array_new ();
1537
g_ptr_array_add (info->outputs, output);
1539
g_hash_table_insert (assign->info, crtc, info);
1541
if (primary && !assign->primary)
1543
assign->primary = output;
1551
crtc_assignment_unassign (CrtcAssignment *assign,
1553
GsdRROutput *output)
1555
CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
1559
g_ptr_array_remove (info->outputs, output);
1561
if (assign->primary == output)
1563
assign->primary = NULL;
1566
if (info->outputs->len == 0)
1567
g_hash_table_remove (assign->info, crtc);
1572
crtc_assignment_free (CrtcAssignment *assign)
1574
g_hash_table_destroy (assign->info);
1583
} ConfigureCrtcState;
1586
configure_crtc (gpointer key,
1590
GsdRRCrtc *crtc = key;
1591
CrtcInfo *info = value;
1592
ConfigureCrtcState *state = data;
1594
if (state->has_error)
1597
if (!gsd_rr_crtc_set_config_with_time (crtc,
1602
(GsdRROutput **)info->outputs->pdata,
1605
state->has_error = TRUE;
1609
mode_is_rotated (CrtcInfo *info)
1611
if ((info->rotation & GSD_RR_ROTATION_270) ||
1612
(info->rotation & GSD_RR_ROTATION_90))
1620
crtc_is_rotated (GsdRRCrtc *crtc)
1622
GsdRRRotation r = gsd_rr_crtc_get_current_rotation (crtc);
1624
if ((r & GSD_RR_ROTATION_270) ||
1625
(r & GSD_RR_ROTATION_90))
1634
accumulate_error (GString *accumulated_error, GError *error)
1636
g_string_append_printf (accumulated_error, " %s\n", error->message);
1637
g_error_free (error);
1640
/* Check whether the given set of settings can be used
1641
* at the same time -- ie. whether there is an assignment
1642
* of CRTC's to outputs.
1644
* Brute force - the number of objects involved is small
1645
* enough that it doesn't matter.
1648
real_assign_crtcs (GsdRRScreen *screen,
1649
GsdRROutputInfo **outputs,
1650
CrtcAssignment *assignment,
1653
GsdRRCrtc **crtcs = gsd_rr_screen_list_crtcs (screen);
1654
GsdRROutputInfo *output;
1656
gboolean tried_mode;
1658
GString *accumulated_error;
1665
/* It is always allowed for an output to be turned off */
1666
if (!output->priv->on)
1668
return real_assign_crtcs (screen, outputs + 1, assignment, error);
1673
accumulated_error = g_string_new (NULL);
1675
for (i = 0; crtcs[i] != NULL; ++i)
1677
GsdRRCrtc *crtc = crtcs[i];
1678
int crtc_id = gsd_rr_crtc_get_id (crtc);
1681
g_string_append_printf (accumulated_error,
1682
_("Trying modes for CRTC %d\n"),
1685
/* Make two passes, one where frequencies must match, then
1686
* one where they don't have to
1688
for (pass = 0; pass < 2; ++pass)
1690
GsdRROutput *gsd_rr_output = gsd_rr_screen_get_output_by_name (screen, output->priv->name);
1691
GsdRRMode **modes = gsd_rr_output_list_modes (gsd_rr_output);
1694
for (j = 0; modes[j] != NULL; ++j)
1696
GsdRRMode *mode = modes[j];
1701
mode_width = gsd_rr_mode_get_width (mode);
1702
mode_height = gsd_rr_mode_get_height (mode);
1703
mode_freq = gsd_rr_mode_get_freq (mode);
1705
g_string_append_printf (accumulated_error,
1706
_("CRTC %d: trying mode %dx%d@%dHz with output at %dx%d@%dHz (pass %d)\n"),
1708
mode_width, mode_height, mode_freq,
1709
output->priv->width, output->priv->height, output->priv->rate,
1712
if (mode_width == output->priv->width &&
1713
mode_height == output->priv->height &&
1714
(pass == 1 || mode_freq == output->priv->rate))
1719
if (crtc_assignment_assign (
1720
assignment, crtc, modes[j],
1721
output->priv->x, output->priv->y,
1722
output->priv->rotation,
1723
output->priv->primary,
1728
if (real_assign_crtcs (screen, outputs + 1, assignment, &my_error)) {
1732
accumulate_error (accumulated_error, my_error);
1734
crtc_assignment_unassign (assignment, crtc, gsd_rr_output);
1736
accumulate_error (accumulated_error, my_error);
1745
g_string_free (accumulated_error, TRUE);
1749
str = g_string_free (accumulated_error, FALSE);
1752
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
1753
_("could not assign CRTCs to outputs:\n%s"),
1756
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
1757
_("none of the selected modes were compatible with the possible modes:\n%s"),
1767
crtc_info_free (CrtcInfo *info)
1769
g_ptr_array_free (info->outputs, TRUE);
1774
get_required_virtual_size (CrtcAssignment *assign, int *width, int *height)
1776
GList *active_crtcs = g_hash_table_get_keys (assign->info);
1785
/* Compute size of the screen */
1786
*width = *height = 1;
1787
for (list = active_crtcs; list != NULL; list = list->next)
1789
GsdRRCrtc *crtc = list->data;
1790
CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
1793
w = gsd_rr_mode_get_width (info->mode);
1794
h = gsd_rr_mode_get_height (info->mode);
1796
if (mode_is_rotated (info))
1803
*width = MAX (*width, info->x + w);
1804
*height = MAX (*height, info->y + h);
1807
g_list_free (active_crtcs);
1811
unity_running (void)
1813
const gchar *desktop_environment = g_getenv ("DESKTOP_SESSION");
1815
return !g_strcmp0 (desktop_environment, "ubuntu");
1818
static gint _max_texture_size_cache = -1;
1821
get_max_texture_size (GsdRRScreen *screen)
1823
if (_max_texture_size_cache != -1)
1825
return _max_texture_size_cache;
1828
* Spawn a second process to check the GL texture limits
1829
* We do this across a process boundary to ensure that crashes
1830
* in the GL driver (which are unfortunately common) don't take
1836
char * const canary_argv[] = { LIBEXECDIR "/check_gl_texture_size", NULL };
1837
char *canary_env[2];
1838
char display_env[80];
1840
snprintf (display_env, sizeof (display_env), "DISPLAY=%s", DisplayString (screen->priv->xdisplay));
1841
canary_env[0] = display_env;
1842
canary_env[1] = NULL;
1845
if (pipe (pipe_fd) == -1)
1847
_max_texture_size_cache = 0;
1850
canary_pid = fork ();
1851
if (canary_pid == -1)
1853
_max_texture_size_cache = 0;
1857
if (canary_pid == 0)
1860
dup2 (pipe_fd[1], 1);
1863
execve (canary_argv[0], canary_argv, canary_env);
1866
gint max_texture_size;
1869
struct timespec fifty_msec = {0, 50000000};
1874
/* Empirical testing suggests this check takes < 150msec on my
1875
* crappy Atom netbook with slow rotating HDD. A 500msec timeout
1876
* should be generous while not being *too* long if it triggers.
1878
* Do a sleep/poll dance because we're a library and there's no
1879
* guarantee that waiting on SIGCHLD won't stomp over a client's
1882
while (waitpid (canary_pid, &child_status, WNOHANG) == 0 && wait_count < 10) {
1883
g_debug ("Waiting for GL_MAX_TEXTURE_SIZE helper...");
1884
nanosleep (&fifty_msec, NULL);
1888
if (WIFEXITED (child_status) && WEXITSTATUS (child_status) == EXIT_SUCCESS)
1890
if ((num_char = read (pipe_fd[0], buffer, sizeof(buffer) - 1)) <= 0)
1892
g_warning ("Failed to read GL_MAX_TEXTURE_SIZE from helper.");
1893
max_texture_size = 0;
1895
buffer[num_char] = '\0';
1896
sscanf (buffer, "%u", &max_texture_size);
1898
* Sanity check the numbers. No hardware I know of has a
1899
* GL_MAX_TEXTURE_SIZE smaller than 1024.
1901
if (max_texture_size < 1024)
1902
max_texture_size = 0;
1905
if (wait_count == 10) {
1906
g_warning ("Timed out waiting for GL_MAX_TEXTURE_SIZE helper");
1908
/* Ensure we don't leave processes sitting around. Who knows what they're doing? */
1909
kill (canary_pid, SIGTERM);
1910
waitpid (canary_pid, &child_status, 0);
1912
g_warning ("GL_MAX_TEXTURE_SIZE helper quit unexpectedly");
1914
max_texture_size = 0;
1918
g_debug ("Found GL_MAX_TEXTURE_SIZE of %u", max_texture_size);
1919
_max_texture_size_cache = max_texture_size;
1920
return _max_texture_size_cache;
1925
static CrtcAssignment *
1926
crtc_assignment_new (GsdRRScreen *screen, GsdRROutputInfo **outputs, GError **error)
1928
CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1);
1930
assignment->info = g_hash_table_new_full (
1931
g_direct_hash, g_direct_equal, NULL, (GFreeFunc)crtc_info_free);
1933
if (real_assign_crtcs (screen, outputs, assignment, error))
1936
int min_width, max_width, min_height, max_height;
1937
int max_texture_size;
1939
get_required_virtual_size (assignment, &width, &height);
1941
gsd_rr_screen_get_ranges (
1942
screen, &min_width, &max_width, &min_height, &max_height);
1944
if (width < min_width || width > max_width ||
1945
height < min_height || height > max_height)
1947
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_BOUNDS_ERROR,
1948
/* Translators: the "requested", "minimum", and
1949
* "maximum" words here are not keywords; please
1950
* translate them as usual. */
1951
_("required virtual size does not fit available size: "
1952
"requested=(%d, %d), minimum=(%d, %d), maximum=(%d, %d)"),
1954
min_width, min_height,
1955
max_width, max_height);
1960
* This should either be solved by
1961
* (a) Allowing the compositor to veto RandR changes
1962
* (b) Fixing the compositor
1964
* Nethier of these are feasible at this point, so just fix Unity.
1967
if (unity_running ())
1969
max_texture_size = get_max_texture_size (screen);
1970
if (max_texture_size > 0 && (width > max_texture_size || height > max_texture_size))
1972
g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_BOUNDS_ERROR,
1973
_("Requested size (%d, %d) exceeds 3D hardware limit (%d, %d).\n"
1974
"You must either rearrange the displays so that they fit within a (%d, %d) square."),
1975
width, height, max_texture_size, max_texture_size,
1976
max_texture_size, max_texture_size);
1982
assignment->screen = screen;
1988
crtc_assignment_free (assignment);
1994
crtc_assignment_apply (CrtcAssignment *assign, guint32 timestamp, GError **error)
1996
GsdRRCrtc **all_crtcs = gsd_rr_screen_list_crtcs (assign->screen);
1999
int min_width, max_width, min_height, max_height;
2000
int width_mm, height_mm;
2001
gboolean success = TRUE;
2003
/* Compute size of the screen */
2004
get_required_virtual_size (assign, &width, &height);
2006
gsd_rr_screen_get_ranges (
2007
assign->screen, &min_width, &max_width, &min_height, &max_height);
2009
/* We should never get here if the dimensions don't fit in the virtual size,
2010
* but just in case we do, fix it up.
2012
width = MAX (min_width, width);
2013
width = MIN (max_width, width);
2014
height = MAX (min_height, height);
2015
height = MIN (max_height, height);
2017
/* FMQ: do we need to check the sizes instead of clamping them? */
2019
/* Grab the server while we fiddle with the CRTCs and the screen, so that
2020
* apps that listen for RANDR notifications will only receive the final
2024
gdk_x11_display_grab (gdk_screen_get_display (assign->screen->priv->gdk_screen));
2026
/* Turn off all crtcs that are currently displaying outside the new screen,
2027
* or are not used in the new setup
2029
for (i = 0; all_crtcs[i] != NULL; ++i)
2031
GsdRRCrtc *crtc = all_crtcs[i];
2032
GsdRRMode *mode = gsd_rr_crtc_get_current_mode (crtc);
2038
gsd_rr_crtc_get_position (crtc, &x, &y);
2040
w = gsd_rr_mode_get_width (mode);
2041
h = gsd_rr_mode_get_height (mode);
2043
if (crtc_is_rotated (crtc))
2050
if (x + w > width || y + h > height || !g_hash_table_lookup (assign->info, crtc))
2052
if (!gsd_rr_crtc_set_config_with_time (crtc, timestamp, 0, 0, NULL, GSD_RR_ROTATION_0, NULL, 0, error))
2062
/* The 'physical size' of an X screen is meaningless if that screen
2063
* can consist of many monitors. So just pick a size that make the
2066
* Firefox and Evince apparently believe what X tells them.
2068
width_mm = (width / DPI_FALLBACK) * 25.4 + 0.5;
2069
height_mm = (height / DPI_FALLBACK) * 25.4 + 0.5;
2073
ConfigureCrtcState state;
2075
gsd_rr_screen_set_size (assign->screen, width, height, width_mm, height_mm);
2077
state.timestamp = timestamp;
2078
state.has_error = FALSE;
2079
state.error = error;
2081
g_hash_table_foreach (assign->info, configure_crtc, &state);
2083
success = !state.has_error;
2086
gsd_rr_screen_set_primary_output (assign->screen, assign->primary);
2088
gdk_x11_display_ungrab (gdk_screen_get_display (assign->screen->priv->gdk_screen));