~ubuntu-branches/ubuntu/utopic/unity-settings-daemon/utopic-proposed

« back to all changes in this revision

Viewing changes to gnome-settings-daemon/gsd-rr-config.c

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release, Robert Ancell, Rui Matos, Bastien Nocera, Tim Lunn
  • Date: 2014-09-22 11:29:11 UTC
  • mfrom: (1.1.13)
  • Revision ID: package-import@ubuntu.com-20140922112911-jcq0tddp30t7btep
Tags: 14.04.0+14.10.20140922-0ubuntu1
[ Robert Ancell ]
* Move libgnome-desktop RandR code into u-s-d since newer versions
  remove this unstable API (LP: #1372240)

[ Rui Matos ]
* Apply git patch that pulls in code removed from gnome-desktop3 3.12

[ Bastien Nocera ]
* common: Check the exit status of hotplug scripts correctly

[ Tim Lunn ]
* Apply git patch that pulls in code removed from gnome-desktop3 3.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gnome-rr-config.c
 
2
 * -*- c-basic-offset: 4 -*-
 
3
 *
 
4
 * Copyright 2007, 2008, Red Hat, Inc.
 
5
 * Copyright 2010 Giovanni Campagna
 
6
 * 
 
7
 * This file is part of the Gnome Library.
 
8
 * 
 
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.
 
13
 *
 
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.
 
18
 * 
 
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.
 
23
 * 
 
24
 * Author: Soren Sandmann <sandmann@redhat.com>
 
25
 */
 
26
 
 
27
#include <config.h>
 
28
#include <glib/gi18n-lib.h>
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
#include <glib.h>
 
32
#include <glib/gstdio.h>
 
33
 
 
34
#include <X11/Xlib.h>
 
35
#include <gdk/gdkx.h>
 
36
 
 
37
#include <unistd.h>
 
38
#include <sys/wait.h>
 
39
#include <signal.h>
 
40
 
 
41
#include "gsd-rr-config.h"
 
42
 
 
43
#include "edid.h"
 
44
#include "gsd-rr-private.h"
 
45
 
 
46
#define CONFIG_INTENDED_BASENAME "monitors.xml"
 
47
#define CONFIG_BACKUP_BASENAME "monitors.xml.backup"
 
48
 
 
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
 
53
 
 
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
 
56
 * like
 
57
 *
 
58
 *   <configuration>
 
59
 *     ...
 
60
 *   </configuration>
 
61
 *   <configuration>
 
62
 *     ...
 
63
 *   </configuration>
 
64
 *
 
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:
 
68
 *
 
69
 *   <monitors version="1">
 
70
 *     <configuration>
 
71
 *       ...
 
72
 *     </configuration>
 
73
 *     <configuration>
 
74
 *       ...
 
75
 *     </configuration>
 
76
 *   </monitors>
 
77
 */
 
78
 
 
79
/* A helper wrapper around the GMarkup parser stuff */
 
80
static gboolean parse_file_gmarkup (const gchar *file,
 
81
                                    const GMarkupParser *parser,
 
82
                                    gpointer data,
 
83
                                    GError **err);
 
84
 
 
85
typedef struct CrtcAssignment CrtcAssignment;
 
86
 
 
87
static gboolean         crtc_assignment_apply (CrtcAssignment   *assign,
 
88
                                               guint32           timestamp,
 
89
                                               GError          **error);
 
90
static CrtcAssignment  *crtc_assignment_new   (GsdRRScreen      *screen,
 
91
                                               GsdRROutputInfo **outputs,
 
92
                                               GError            **error);
 
93
static void             crtc_assignment_free  (CrtcAssignment   *assign);
 
94
 
 
95
enum {
 
96
  PROP_0,
 
97
  PROP_SCREEN,
 
98
  PROP_LAST
 
99
};
 
100
 
 
101
G_DEFINE_TYPE (GsdRRConfig, gsd_rr_config, G_TYPE_OBJECT)
 
102
 
 
103
typedef struct Parser Parser;
 
104
 
 
105
/* Parser for monitor configurations */
 
106
struct Parser
 
107
{
 
108
    int                 config_file_version;
 
109
    GsdRROutputInfo *   output;
 
110
    GsdRRConfig *       configuration;
 
111
    GPtrArray *         outputs;
 
112
    GPtrArray *         configurations;
 
113
    GQueue *            stack;
 
114
};
 
115
 
 
116
static int
 
117
parse_int (const char *text)
 
118
{
 
119
    return strtol (text, NULL, 0);
 
120
}
 
121
 
 
122
static guint
 
123
parse_uint (const char *text)
 
124
{
 
125
    return strtoul (text, NULL, 0);
 
126
}
 
127
 
 
128
static gboolean
 
129
stack_is (Parser *parser,
 
130
          const char *s1,
 
131
          ...)
 
132
{
 
133
    GList *stack = NULL;
 
134
    const char *s;
 
135
    GList *l1, *l2;
 
136
    va_list args;
 
137
    
 
138
    stack = g_list_prepend (stack, (gpointer)s1);
 
139
    
 
140
    va_start (args, s1);
 
141
    
 
142
    s = va_arg (args, const char *);
 
143
    while (s)
 
144
    {
 
145
        stack = g_list_prepend (stack, (gpointer)s);
 
146
        s = va_arg (args, const char *);
 
147
    }
 
148
        
 
149
    l1 = stack;
 
150
    l2 = parser->stack->head;
 
151
    
 
152
    while (l1 && l2)
 
153
    {
 
154
        if (strcmp (l1->data, l2->data) != 0)
 
155
        {
 
156
            g_list_free (stack);
 
157
            return FALSE;
 
158
        }
 
159
        
 
160
        l1 = l1->next;
 
161
        l2 = l2->next;
 
162
    }
 
163
    
 
164
    g_list_free (stack);
 
165
    
 
166
    return (!l1 && !l2);
 
167
}
 
168
 
 
169
static void
 
170
handle_start_element (GMarkupParseContext *context,
 
171
                      const gchar         *name,
 
172
                      const gchar        **attr_names,
 
173
                      const gchar        **attr_values,
 
174
                      gpointer             user_data,
 
175
                      GError             **err)
 
176
{
 
177
    Parser *parser = user_data;
 
178
 
 
179
    if (strcmp (name, "output") == 0)
 
180
    {
 
181
        int i;
 
182
        g_assert (parser->output == NULL);
 
183
 
 
184
        parser->output = g_object_new (GSD_TYPE_RR_OUTPUT_INFO, NULL);
 
185
        parser->output->priv->rotation = 0;
 
186
        
 
187
        for (i = 0; attr_names[i] != NULL; ++i)
 
188
        {
 
189
            if (strcmp (attr_names[i], "name") == 0)
 
190
            {
 
191
                parser->output->priv->name = g_strdup (attr_values[i]);
 
192
                break;
 
193
            }
 
194
        }
 
195
 
 
196
        if (!parser->output->priv->name)
 
197
        {
 
198
            /* This really shouldn't happen, but it's better to make
 
199
             * something up than to crash later.
 
200
             */
 
201
            g_warning ("Malformed monitor configuration file");
 
202
            
 
203
            parser->output->priv->name = g_strdup ("default");
 
204
        }       
 
205
        parser->output->priv->connected = FALSE;
 
206
        parser->output->priv->on = FALSE;
 
207
        parser->output->priv->primary = FALSE;
 
208
    }
 
209
    else if (strcmp (name, "configuration") == 0)
 
210
    {
 
211
        g_assert (parser->configuration == NULL);
 
212
        
 
213
        parser->configuration = g_object_new (GSD_TYPE_RR_CONFIG, NULL);
 
214
        parser->configuration->priv->clone = FALSE;
 
215
        parser->configuration->priv->outputs = NULL;
 
216
    }
 
217
    else if (strcmp (name, "monitors") == 0)
 
218
    {
 
219
        int i;
 
220
 
 
221
        for (i = 0; attr_names[i] != NULL; i++)
 
222
        {
 
223
            if (strcmp (attr_names[i], "version") == 0)
 
224
            {
 
225
                parser->config_file_version = parse_int (attr_values[i]);
 
226
                break;
 
227
            }
 
228
        }
 
229
    }
 
230
 
 
231
    g_queue_push_tail (parser->stack, g_strdup (name));
 
232
}
 
233
 
 
234
static void
 
235
handle_end_element (GMarkupParseContext *context,
 
236
                    const gchar         *name,
 
237
                    gpointer             user_data,
 
238
                    GError             **err)
 
239
{
 
240
    Parser *parser = user_data;
 
241
    
 
242
    if (strcmp (name, "output") == 0)
 
243
    {
 
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;
 
247
        
 
248
        g_ptr_array_add (parser->outputs, parser->output);
 
249
 
 
250
        parser->output = NULL;
 
251
    }
 
252
    else if (strcmp (name, "configuration") == 0)
 
253
    {
 
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;
 
260
    }
 
261
    
 
262
    g_free (g_queue_pop_tail (parser->stack));
 
263
}
 
264
 
 
265
#define TOPLEVEL_ELEMENT (parser->config_file_version > 0 ? "monitors" : NULL)
 
266
 
 
267
static void
 
268
handle_text (GMarkupParseContext *context,
 
269
             const gchar         *text,
 
270
             gsize                text_len,
 
271
             gpointer             user_data,
 
272
             GError             **err)
 
273
{
 
274
    Parser *parser = user_data;
 
275
    
 
276
    if (stack_is (parser, "vendor", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
277
    {
 
278
        parser->output->priv->connected = TRUE;
 
279
        
 
280
        strncpy ((gchar*) parser->output->priv->vendor, text, 3);
 
281
        parser->output->priv->vendor[3] = 0;
 
282
    }
 
283
    else if (stack_is (parser, "clone", "configuration", TOPLEVEL_ELEMENT, NULL))
 
284
    {
 
285
        if (strcmp (text, "yes") == 0)
 
286
            parser->configuration->priv->clone = TRUE;
 
287
    }
 
288
    else if (stack_is (parser, "product", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
289
    {
 
290
        parser->output->priv->connected = TRUE;
 
291
 
 
292
        parser->output->priv->product = parse_int (text);
 
293
    }
 
294
    else if (stack_is (parser, "serial", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
295
    {
 
296
        parser->output->priv->connected = TRUE;
 
297
 
 
298
        parser->output->priv->serial = parse_uint (text);
 
299
    }
 
300
    else if (stack_is (parser, "width", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
301
    {
 
302
        parser->output->priv->on = TRUE;
 
303
 
 
304
        parser->output->priv->width = parse_int (text);
 
305
    }
 
306
    else if (stack_is (parser, "x", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
307
    {
 
308
        parser->output->priv->on = TRUE;
 
309
 
 
310
        parser->output->priv->x = parse_int (text);
 
311
    }
 
312
    else if (stack_is (parser, "y", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
313
    {
 
314
        parser->output->priv->on = TRUE;
 
315
 
 
316
        parser->output->priv->y = parse_int (text);
 
317
    }
 
318
    else if (stack_is (parser, "height", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
319
    {
 
320
        parser->output->priv->on = TRUE;
 
321
 
 
322
        parser->output->priv->height = parse_int (text);
 
323
    }
 
324
    else if (stack_is (parser, "rate", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
325
    {
 
326
        parser->output->priv->on = TRUE;
 
327
 
 
328
        parser->output->priv->rate = parse_int (text);
 
329
    }
 
330
    else if (stack_is (parser, "rotation", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
331
    {
 
332
        if (strcmp (text, "normal") == 0)
 
333
        {
 
334
            parser->output->priv->rotation |= GSD_RR_ROTATION_0;
 
335
        }
 
336
        else if (strcmp (text, "left") == 0)
 
337
        {
 
338
            parser->output->priv->rotation |= GSD_RR_ROTATION_90;
 
339
        }
 
340
        else if (strcmp (text, "upside_down") == 0)
 
341
        {
 
342
            parser->output->priv->rotation |= GSD_RR_ROTATION_180;
 
343
        }
 
344
        else if (strcmp (text, "right") == 0)
 
345
        {
 
346
            parser->output->priv->rotation |= GSD_RR_ROTATION_270;
 
347
        }
 
348
    }
 
349
    else if (stack_is (parser, "reflect_x", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
350
    {
 
351
        if (strcmp (text, "yes") == 0)
 
352
        {
 
353
            parser->output->priv->rotation |= GSD_RR_REFLECT_X;
 
354
        }
 
355
    }
 
356
    else if (stack_is (parser, "reflect_y", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
357
    {
 
358
        if (strcmp (text, "yes") == 0)
 
359
        {
 
360
            parser->output->priv->rotation |= GSD_RR_REFLECT_Y;
 
361
        }
 
362
    }
 
363
    else if (stack_is (parser, "primary", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
 
364
    {
 
365
        if (strcmp (text, "yes") == 0)
 
366
        {
 
367
            parser->output->priv->primary = TRUE;
 
368
        }
 
369
    }
 
370
    else
 
371
    {
 
372
        /* Ignore other properties so we can expand the format in the future */
 
373
    }
 
374
}
 
375
 
 
376
static void
 
377
parser_free (Parser *parser)
 
378
{
 
379
    int i;
 
380
    GList *list;
 
381
 
 
382
    g_assert (parser != NULL);
 
383
 
 
384
    if (parser->output)
 
385
        g_object_unref (parser->output);
 
386
 
 
387
    if (parser->configuration)
 
388
        g_object_unref (parser->configuration);
 
389
 
 
390
    for (i = 0; i < parser->outputs->len; ++i)
 
391
    {
 
392
        GsdRROutputInfo *output = parser->outputs->pdata[i];
 
393
 
 
394
        g_object_unref (output);
 
395
    }
 
396
 
 
397
    g_ptr_array_free (parser->outputs, TRUE);
 
398
 
 
399
    for (i = 0; i < parser->configurations->len; ++i)
 
400
    {
 
401
        GsdRRConfig *config = parser->configurations->pdata[i];
 
402
 
 
403
        g_object_unref (config);
 
404
    }
 
405
 
 
406
    g_ptr_array_free (parser->configurations, TRUE);
 
407
 
 
408
    for (list = parser->stack->head; list; list = list->next)
 
409
        g_free (list->data);
 
410
    g_queue_free (parser->stack);
 
411
    
 
412
    g_free (parser);
 
413
}
 
414
 
 
415
static GsdRRConfig **
 
416
configurations_read_from_file (const gchar *filename, GError **error)
 
417
{
 
418
    Parser *parser = g_new0 (Parser, 1);
 
419
    GsdRRConfig **result;
 
420
    GMarkupParser callbacks = {
 
421
        handle_start_element,
 
422
        handle_end_element,
 
423
        handle_text,
 
424
        NULL, /* passthrough */
 
425
        NULL, /* error */
 
426
    };
 
427
 
 
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 ();
 
432
    
 
433
    if (!parse_file_gmarkup (filename, &callbacks, parser, error))
 
434
    {
 
435
        result = NULL;
 
436
        
 
437
        g_assert (parser->outputs);
 
438
        goto out;
 
439
    }
 
440
 
 
441
    g_assert (parser->outputs);
 
442
    
 
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 ();
 
446
    
 
447
    g_assert (parser->outputs);
 
448
out:
 
449
    parser_free (parser);
 
450
 
 
451
    return result;
 
452
}
 
453
 
 
454
static void
 
455
gsd_rr_config_init (GsdRRConfig *self)
 
456
{
 
457
    self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GSD_TYPE_RR_CONFIG, GsdRRConfigPrivate);
 
458
 
 
459
    self->priv->clone = FALSE;
 
460
    self->priv->screen = NULL;
 
461
    self->priv->outputs = NULL;
 
462
}
 
463
 
 
464
static void
 
465
gsd_rr_config_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *property)
 
466
{
 
467
    GsdRRConfig *self = GSD_RR_CONFIG (gobject);
 
468
 
 
469
    switch (property_id) {
 
470
        case PROP_SCREEN:
 
471
            self->priv->screen = g_value_dup_object (value);
 
472
            return;
 
473
        default:
 
474
            G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
 
475
    }
 
476
}
 
477
 
 
478
static void
 
479
gsd_rr_config_finalize (GObject *gobject)
 
480
{
 
481
    GsdRRConfig *self = GSD_RR_CONFIG (gobject);
 
482
 
 
483
    if (self->priv->screen)
 
484
        g_object_unref (self->priv->screen);
 
485
 
 
486
    if (self->priv->outputs) {
 
487
        int i;
 
488
 
 
489
        for (i = 0; self->priv->outputs[i] != NULL; i++) {
 
490
            GsdRROutputInfo *output = self->priv->outputs[i];
 
491
            g_object_unref (output);
 
492
        }
 
493
        g_free (self->priv->outputs);
 
494
    }
 
495
 
 
496
    G_OBJECT_CLASS (gsd_rr_config_parent_class)->finalize (gobject);
 
497
}
 
498
 
 
499
gboolean
 
500
gsd_rr_config_load_current (GsdRRConfig *config, GError **error)
 
501
{
 
502
    GPtrArray *a;
 
503
    GsdRROutput **rr_outputs;
 
504
    int i;
 
505
    int clone_width = -1;
 
506
    int clone_height = -1;
 
507
    int last_x;
 
508
 
 
509
    g_return_val_if_fail (GSD_IS_RR_CONFIG (config), FALSE);
 
510
 
 
511
    a = g_ptr_array_new ();
 
512
    rr_outputs = gsd_rr_screen_list_outputs (config->priv->screen);
 
513
 
 
514
    config->priv->clone = FALSE;
 
515
    
 
516
    for (i = 0; rr_outputs[i] != NULL; ++i)
 
517
    {
 
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);
 
522
        GsdRRCrtc *crtc;
 
523
 
 
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));
 
527
 
 
528
        if (!output->priv->connected)
 
529
        {
 
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;
 
536
        }
 
537
        else
 
538
        {
 
539
            MonitorInfo *info = NULL;
 
540
 
 
541
            if (edid_data)
 
542
                info = decode_edid (edid_data);
 
543
 
 
544
            if (info)
 
545
            {
 
546
                memcpy (output->priv->vendor, info->manufacturer_code,
 
547
                        sizeof (output->priv->vendor));
 
548
                
 
549
                output->priv->product = info->product_code;
 
550
                output->priv->serial = info->serial_number;
 
551
                output->priv->aspect = info->aspect_ratio;
 
552
            }
 
553
            else
 
554
            {
 
555
                strcpy (output->priv->vendor, "???");
 
556
                output->priv->product = 0;
 
557
                output->priv->serial = 0;
 
558
            }
 
559
            g_free (info);
 
560
                
 
561
            crtc = gsd_rr_output_get_crtc (rr_output);
 
562
            mode = crtc? gsd_rr_crtc_get_current_mode (crtc) : NULL;
 
563
            
 
564
            if (crtc && mode)
 
565
            {
 
566
                output->priv->on = TRUE;
 
567
                
 
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);
 
573
 
 
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;
 
581
                        }
 
582
                }
 
583
            }
 
584
            else
 
585
            {
 
586
                output->priv->on = FALSE;
 
587
                config->priv->clone = FALSE;
 
588
            }
 
589
 
 
590
            /* Get preferred size for the monitor */
 
591
            mode = gsd_rr_output_get_preferred_mode (rr_output);
 
592
            
 
593
            if (!mode)
 
594
            {
 
595
                GsdRRMode **modes = gsd_rr_output_list_modes (rr_output);
 
596
                
 
597
                /* FIXME: we should pick the "best" mode here, where best is
 
598
                 * sorted wrt
 
599
                 *
 
600
                 * - closest aspect ratio
 
601
                 * - mode area
 
602
                 * - refresh rate
 
603
                 * - We may want to extend randrwrap so that get_preferred
 
604
                 *   returns that - although that could also depend on
 
605
                 *   the crtc.
 
606
                 */
 
607
                if (modes[0])
 
608
                    mode = modes[0];
 
609
            }
 
610
            
 
611
            if (mode)
 
612
            {
 
613
                output->priv->pref_width = gsd_rr_mode_get_width (mode);
 
614
                output->priv->pref_height = gsd_rr_mode_get_height (mode);
 
615
            }
 
616
            else
 
617
            {
 
618
                /* Pick some random numbers. This should basically never happen */
 
619
                output->priv->pref_width = 1024;
 
620
                output->priv->pref_height = 768;
 
621
            }
 
622
        }
 
623
 
 
624
        output->priv->primary = gsd_rr_output_get_is_primary (rr_output);
 
625
 
 
626
        g_ptr_array_add (a, output);
 
627
    }
 
628
 
 
629
    g_ptr_array_add (a, NULL);
 
630
    
 
631
    config->priv->outputs = (GsdRROutputInfo **)g_ptr_array_free (a, FALSE);
 
632
 
 
633
    /* Walk the outputs computing the right-most edge of all
 
634
     * lit-up displays
 
635
     */
 
636
    last_x = 0;
 
637
    for (i = 0; config->priv->outputs[i] != NULL; ++i)
 
638
    {
 
639
        GsdRROutputInfo *output = config->priv->outputs[i];
 
640
 
 
641
        if (output->priv->on)
 
642
        {
 
643
            last_x = MAX (last_x, output->priv->x + output->priv->width);
 
644
        }
 
645
    }
 
646
 
 
647
    /* Now position all off displays to the right of the
 
648
     * on displays
 
649
     */
 
650
    for (i = 0; config->priv->outputs[i] != NULL; ++i)
 
651
    {
 
652
        GsdRROutputInfo *output = config->priv->outputs[i];
 
653
 
 
654
        if (output->priv->connected && !output->priv->on)
 
655
        {
 
656
            output->priv->x = last_x;
 
657
            last_x = output->priv->x + output->priv->width;
 
658
        }
 
659
    }
 
660
    
 
661
    g_assert (gsd_rr_config_match (config, config));
 
662
 
 
663
    return TRUE;
 
664
}
 
665
 
 
666
gboolean
 
667
gsd_rr_config_load_filename (GsdRRConfig *result, const char *filename, GError **error)
 
668
{
 
669
    GsdRRConfig *current;
 
670
    GsdRRConfig **configs;
 
671
    gboolean found = FALSE;
 
672
 
 
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);
 
676
 
 
677
    current = gsd_rr_config_new_current (result->priv->screen, error);
 
678
 
 
679
    configs = configurations_read_from_file (filename, error);
 
680
 
 
681
    if (configs)
 
682
    {
 
683
        int i;
 
684
 
 
685
        for (i = 0; configs[i] != NULL; ++i)
 
686
        {
 
687
            if (gsd_rr_config_match (configs[i], current))
 
688
            {
 
689
                int j;
 
690
                GPtrArray *array;
 
691
                result->priv->clone = configs[i]->priv->clone;
 
692
 
 
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]);
 
697
                }
 
698
                g_ptr_array_add (array, NULL);
 
699
                result->priv->outputs = (GsdRROutputInfo **) g_ptr_array_free (array, FALSE);
 
700
 
 
701
                found = TRUE;
 
702
                break;
 
703
            }
 
704
            g_object_unref (configs[i]);
 
705
        }
 
706
        g_free (configs);
 
707
 
 
708
        if (!found)
 
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"));
 
711
    }
 
712
 
 
713
    g_object_unref (current);
 
714
    return found;
 
715
}
 
716
 
 
717
static void
 
718
gsd_rr_config_class_init (GsdRRConfigClass *klass)
 
719
{
 
720
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
721
 
 
722
    g_type_class_add_private (klass, sizeof (GsdRROutputInfoPrivate));
 
723
 
 
724
    gobject_class->set_property = gsd_rr_config_set_property;
 
725
    gobject_class->finalize = gsd_rr_config_finalize;
 
726
 
 
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));
 
730
}
 
731
 
 
732
GsdRRConfig *
 
733
gsd_rr_config_new_current (GsdRRScreen *screen, GError **error)
 
734
{
 
735
    GsdRRConfig *self = g_object_new (GSD_TYPE_RR_CONFIG, "screen", screen, NULL);
 
736
 
 
737
    if (gsd_rr_config_load_current (self, error))
 
738
      return self;
 
739
    else
 
740
      {
 
741
        g_object_unref (self);
 
742
        return NULL;
 
743
      }
 
744
}
 
745
 
 
746
GsdRRConfig *
 
747
gsd_rr_config_new_stored (GsdRRScreen *screen, GError **error)
 
748
{
 
749
    GsdRRConfig *self = g_object_new (GSD_TYPE_RR_CONFIG, "screen", screen, NULL);
 
750
    char *filename;
 
751
    gboolean success;
 
752
 
 
753
    filename = gsd_rr_config_get_intended_filename ();
 
754
 
 
755
    success = gsd_rr_config_load_filename (self, filename, error);
 
756
 
 
757
    g_free (filename);
 
758
 
 
759
    if (success)
 
760
      return self;
 
761
    else
 
762
      {
 
763
        g_object_unref (self);
 
764
        return NULL;
 
765
      }
 
766
}
 
767
 
 
768
static gboolean
 
769
parse_file_gmarkup (const gchar          *filename,
 
770
                    const GMarkupParser  *parser,
 
771
                    gpointer             data,
 
772
                    GError              **err)
 
773
{
 
774
    GMarkupParseContext *context = NULL;
 
775
    gchar *contents = NULL;
 
776
    gboolean result = TRUE;
 
777
    gsize len;
 
778
 
 
779
    if (!g_file_get_contents (filename, &contents, &len, err))
 
780
    {
 
781
        result = FALSE;
 
782
        goto out;
 
783
    }
 
784
    
 
785
    context = g_markup_parse_context_new (parser, 0, data, NULL);
 
786
 
 
787
    if (!g_markup_parse_context_parse (context, contents, len, err))
 
788
    {
 
789
        result = FALSE;
 
790
        goto out;
 
791
    }
 
792
 
 
793
    if (!g_markup_parse_context_end_parse (context, err))
 
794
    {
 
795
        result = FALSE;
 
796
        goto out;
 
797
    }
 
798
 
 
799
out:
 
800
    if (contents)
 
801
        g_free (contents);
 
802
 
 
803
    if (context)
 
804
        g_markup_parse_context_free (context);
 
805
 
 
806
    return result;
 
807
}
 
808
 
 
809
static gboolean
 
810
output_match (GsdRROutputInfo *output1, GsdRROutputInfo *output2)
 
811
{
 
812
    g_assert (GSD_IS_RR_OUTPUT_INFO (output1));
 
813
    g_assert (GSD_IS_RR_OUTPUT_INFO (output2));
 
814
 
 
815
    if (strcmp (output1->priv->name, output2->priv->name) != 0)
 
816
        return FALSE;
 
817
 
 
818
    if (strcmp (output1->priv->vendor, output2->priv->vendor) != 0)
 
819
        return FALSE;
 
820
 
 
821
    if (output1->priv->product != output2->priv->product)
 
822
        return FALSE;
 
823
 
 
824
    if (output1->priv->serial != output2->priv->serial)
 
825
        return FALSE;
 
826
 
 
827
    if (output1->priv->connected != output2->priv->connected)
 
828
        return FALSE;
 
829
    
 
830
    return TRUE;
 
831
}
 
832
 
 
833
static gboolean
 
834
output_equal (GsdRROutputInfo *output1, GsdRROutputInfo *output2)
 
835
{
 
836
    g_assert (GSD_IS_RR_OUTPUT_INFO (output1));
 
837
    g_assert (GSD_IS_RR_OUTPUT_INFO (output2));
 
838
 
 
839
    if (!output_match (output1, output2))
 
840
        return FALSE;
 
841
 
 
842
    if (output1->priv->on != output2->priv->on)
 
843
        return FALSE;
 
844
 
 
845
    if (output1->priv->on)
 
846
    {
 
847
        if (output1->priv->width != output2->priv->width)
 
848
            return FALSE;
 
849
        
 
850
        if (output1->priv->height != output2->priv->height)
 
851
            return FALSE;
 
852
        
 
853
        if (output1->priv->rate != output2->priv->rate)
 
854
            return FALSE;
 
855
        
 
856
        if (output1->priv->x != output2->priv->x)
 
857
            return FALSE;
 
858
        
 
859
        if (output1->priv->y != output2->priv->y)
 
860
            return FALSE;
 
861
        
 
862
        if (output1->priv->rotation != output2->priv->rotation)
 
863
            return FALSE;
 
864
    }
 
865
 
 
866
    return TRUE;
 
867
}
 
868
 
 
869
static GsdRROutputInfo *
 
870
find_output (GsdRRConfig *config, const char *name)
 
871
{
 
872
    int i;
 
873
 
 
874
    for (i = 0; config->priv->outputs[i] != NULL; ++i)
 
875
    {
 
876
        GsdRROutputInfo *output = config->priv->outputs[i];
 
877
        
 
878
        if (strcmp (name, output->priv->name) == 0)
 
879
            return output;
 
880
    }
 
881
 
 
882
    return NULL;
 
883
}
 
884
 
 
885
/* Match means "these configurations apply to the same hardware
 
886
 * setups"
 
887
 */
 
888
gboolean
 
889
gsd_rr_config_match (GsdRRConfig *c1, GsdRRConfig *c2)
 
890
{
 
891
    int i;
 
892
    g_return_val_if_fail (GSD_IS_RR_CONFIG (c1), FALSE);
 
893
    g_return_val_if_fail (GSD_IS_RR_CONFIG (c2), FALSE);
 
894
 
 
895
    for (i = 0; c1->priv->outputs[i] != NULL; ++i)
 
896
    {
 
897
        GsdRROutputInfo *output1 = c1->priv->outputs[i];
 
898
        GsdRROutputInfo *output2;
 
899
 
 
900
        output2 = find_output (c2, output1->priv->name);
 
901
        if (!output2 || !output_match (output1, output2))
 
902
            return FALSE;
 
903
    }
 
904
    
 
905
    return TRUE;
 
906
}
 
907
 
 
908
/* Equal means "the configurations will result in the same
 
909
 * modes being set on the outputs"
 
910
 */
 
911
gboolean
 
912
gsd_rr_config_equal (GsdRRConfig  *c1,
 
913
                       GsdRRConfig  *c2)
 
914
{
 
915
    int i;
 
916
    g_return_val_if_fail (GSD_IS_RR_CONFIG (c1), FALSE);
 
917
    g_return_val_if_fail (GSD_IS_RR_CONFIG (c2), FALSE);
 
918
 
 
919
    for (i = 0; c1->priv->outputs[i] != NULL; ++i)
 
920
    {
 
921
        GsdRROutputInfo *output1 = c1->priv->outputs[i];
 
922
        GsdRROutputInfo *output2;
 
923
 
 
924
        output2 = find_output (c2, output1->priv->name);
 
925
        if (!output2 || !output_equal (output1, output2))
 
926
            return FALSE;
 
927
    }
 
928
    
 
929
    return TRUE;
 
930
}
 
931
 
 
932
static GsdRROutputInfo **
 
933
make_outputs (GsdRRConfig *config)
 
934
{
 
935
    GPtrArray *outputs;
 
936
    GsdRROutputInfo *first_on;
 
937
    int i;
 
938
 
 
939
    outputs = g_ptr_array_new ();
 
940
 
 
941
    first_on = NULL;
 
942
    
 
943
    for (i = 0; config->priv->outputs[i] != NULL; ++i)
 
944
    {
 
945
        GsdRROutputInfo *old = config->priv->outputs[i];
 
946
        GsdRROutputInfo *new = g_object_new (GSD_TYPE_RR_OUTPUT_INFO, NULL);
 
947
        *(new->priv) = *(old->priv);
 
948
        if (old->priv->name)
 
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);
 
952
 
 
953
        if (old->priv->on && !first_on)
 
954
            first_on = old;
 
955
        
 
956
        if (config->priv->clone && new->priv->on)
 
957
        {
 
958
            g_assert (first_on);
 
959
 
 
960
            new->priv->width = first_on->priv->width;
 
961
            new->priv->height = first_on->priv->height;
 
962
            new->priv->rotation = first_on->priv->rotation;
 
963
            new->priv->x = 0;
 
964
            new->priv->y = 0;
 
965
        }
 
966
 
 
967
        g_ptr_array_add (outputs, new);
 
968
    }
 
969
 
 
970
    g_ptr_array_add (outputs, NULL);
 
971
 
 
972
    return (GsdRROutputInfo **)g_ptr_array_free (outputs, FALSE);
 
973
}
 
974
 
 
975
gboolean
 
976
gsd_rr_config_applicable (GsdRRConfig  *configuration,
 
977
                            GsdRRScreen  *screen,
 
978
                            GError        **error)
 
979
{
 
980
    GsdRROutputInfo **outputs;
 
981
    CrtcAssignment *assign;
 
982
    gboolean result;
 
983
    int i;
 
984
 
 
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);
 
988
 
 
989
    outputs = make_outputs (configuration);
 
990
    assign = crtc_assignment_new (screen, outputs, error);
 
991
 
 
992
    if (assign)
 
993
    {
 
994
        result = TRUE;
 
995
        crtc_assignment_free (assign);
 
996
    }
 
997
    else
 
998
    {
 
999
        result = FALSE;
 
1000
    }
 
1001
 
 
1002
    for (i = 0; outputs[i] != NULL; i++) {
 
1003
         g_object_unref (outputs[i]);
 
1004
    }
 
1005
 
 
1006
    return result;
 
1007
}
 
1008
 
 
1009
/* Database management */
 
1010
 
 
1011
static void
 
1012
ensure_config_directory (void)
 
1013
{
 
1014
    g_mkdir_with_parents (g_get_user_config_dir (), 0700);
 
1015
}
 
1016
 
 
1017
char *
 
1018
gsd_rr_config_get_backup_filename (void)
 
1019
{
 
1020
    ensure_config_directory ();
 
1021
    return g_build_filename (g_get_user_config_dir (), CONFIG_BACKUP_BASENAME, NULL);
 
1022
}
 
1023
 
 
1024
char *
 
1025
gsd_rr_config_get_intended_filename (void)
 
1026
{
 
1027
    ensure_config_directory ();
 
1028
    return g_build_filename (g_get_user_config_dir (), CONFIG_INTENDED_BASENAME, NULL);
 
1029
}
 
1030
 
 
1031
static const char *
 
1032
get_rotation_name (GsdRRRotation r)
 
1033
{
 
1034
    if (r & GSD_RR_ROTATION_0)
 
1035
        return "normal";
 
1036
    if (r & GSD_RR_ROTATION_90)
 
1037
        return "left";
 
1038
    if (r & GSD_RR_ROTATION_180)
 
1039
        return "upside_down";
 
1040
    if (r & GSD_RR_ROTATION_270)
 
1041
        return "right";
 
1042
 
 
1043
    return "normal";
 
1044
}
 
1045
 
 
1046
static const char *
 
1047
yes_no (int x)
 
1048
{
 
1049
    return x? "yes" : "no";
 
1050
}
 
1051
 
 
1052
static const char *
 
1053
get_reflect_x (GsdRRRotation r)
 
1054
{
 
1055
    return yes_no (r & GSD_RR_REFLECT_X);
 
1056
}
 
1057
 
 
1058
static const char *
 
1059
get_reflect_y (GsdRRRotation r)
 
1060
{
 
1061
    return yes_no (r & GSD_RR_REFLECT_Y);
 
1062
}
 
1063
 
 
1064
static void
 
1065
emit_configuration (GsdRRConfig *config,
 
1066
                    GString *string)
 
1067
{
 
1068
    int j;
 
1069
 
 
1070
    g_string_append_printf (string, "  <configuration>\n");
 
1071
 
 
1072
    g_string_append_printf (string, "      <clone>%s</clone>\n", yes_no (config->priv->clone));
 
1073
    
 
1074
    for (j = 0; config->priv->outputs[j] != NULL; ++j)
 
1075
    {
 
1076
        GsdRROutputInfo *output = config->priv->outputs[j];
 
1077
        
 
1078
        g_string_append_printf (
 
1079
            string, "      <output name=\"%s\">\n", output->priv->name);
 
1080
        
 
1081
        if (output->priv->connected && *output->priv->vendor != '\0')
 
1082
        {
 
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);
 
1089
        }
 
1090
        
 
1091
        /* An unconnected output which is on does not make sense */
 
1092
        if (output->priv->connected && output->priv->on)
 
1093
        {
 
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));
 
1112
        }
 
1113
        
 
1114
        g_string_append_printf (string, "      </output>\n");
 
1115
    }
 
1116
    
 
1117
    g_string_append_printf (string, "  </configuration>\n");
 
1118
}
 
1119
 
 
1120
void
 
1121
gsd_rr_config_sanitize (GsdRRConfig *config)
 
1122
{
 
1123
    int i;
 
1124
    int x_offset, y_offset;
 
1125
    gboolean found;
 
1126
 
 
1127
    /* Offset everything by the top/left-most coordinate to
 
1128
     * make sure the configuration starts at (0, 0)
 
1129
     */
 
1130
    x_offset = y_offset = G_MAXINT;
 
1131
    for (i = 0; config->priv->outputs[i]; ++i)
 
1132
    {
 
1133
        GsdRROutputInfo *output = config->priv->outputs[i];
 
1134
 
 
1135
        if (output->priv->on)
 
1136
        {
 
1137
            x_offset = MIN (x_offset, output->priv->x);
 
1138
            y_offset = MIN (y_offset, output->priv->y);
 
1139
        }
 
1140
    }
 
1141
 
 
1142
    for (i = 0; config->priv->outputs[i]; ++i)
 
1143
    {
 
1144
        GsdRROutputInfo *output = config->priv->outputs[i];
 
1145
        
 
1146
        if (output->priv->on)
 
1147
        {
 
1148
            output->priv->x -= x_offset;
 
1149
            output->priv->y -= y_offset;
 
1150
        }
 
1151
    }
 
1152
 
 
1153
    /* Only one primary, please */
 
1154
    found = FALSE;
 
1155
    for (i = 0; config->priv->outputs[i]; ++i)
 
1156
    {
 
1157
        if (config->priv->outputs[i]->priv->primary)
 
1158
        {
 
1159
            if (found)
 
1160
            {
 
1161
                config->priv->outputs[i]->priv->primary = FALSE;
 
1162
            }
 
1163
            else
 
1164
            {
 
1165
                found = TRUE;
 
1166
            }
 
1167
        }
 
1168
    }
 
1169
}
 
1170
 
 
1171
gboolean
 
1172
gsd_rr_config_ensure_primary (GsdRRConfig *configuration)
 
1173
{
 
1174
        int i;
 
1175
        GsdRROutputInfo  *laptop;
 
1176
        GsdRROutputInfo  *top_left;
 
1177
        gboolean found;
 
1178
        GsdRRConfigPrivate *priv;
 
1179
 
 
1180
        g_return_val_if_fail (GSD_IS_RR_CONFIG (configuration), FALSE);
 
1181
 
 
1182
        laptop = NULL;
 
1183
        top_left = NULL;
 
1184
        found = FALSE;
 
1185
        priv = configuration->priv;
 
1186
 
 
1187
        for (i = 0; priv->outputs[i] != NULL; ++i) {
 
1188
                GsdRROutputInfo *info = priv->outputs[i];
 
1189
 
 
1190
                if (!info->priv->on) {
 
1191
                       info->priv->primary = FALSE;
 
1192
                       continue;
 
1193
                }
 
1194
 
 
1195
                /* ensure only one */
 
1196
                if (info->priv->primary) {
 
1197
                        if (found) {
 
1198
                                info->priv->primary = FALSE;
 
1199
                        } else {
 
1200
                                found = TRUE;
 
1201
                        }
 
1202
                }
 
1203
 
 
1204
                if (top_left == NULL
 
1205
                    || (info->priv->x < top_left->priv->x
 
1206
                        && info->priv->y < top_left->priv->y)) {
 
1207
                        top_left = info;
 
1208
                }
 
1209
                if (laptop == NULL
 
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 */
 
1213
                        laptop = info;
 
1214
                }
 
1215
        }
 
1216
 
 
1217
        if (!found) {
 
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;
 
1223
                }
 
1224
        }
 
1225
 
 
1226
        return !found;
 
1227
}
 
1228
 
 
1229
gboolean
 
1230
gsd_rr_config_save (GsdRRConfig *configuration, GError **error)
 
1231
{
 
1232
    GsdRRConfig **configurations;
 
1233
    GString *output;
 
1234
    int i;
 
1235
    gchar *intended_filename;
 
1236
    gchar *backup_filename;
 
1237
    gboolean result;
 
1238
 
 
1239
    g_return_val_if_fail (GSD_IS_RR_CONFIG (configuration), FALSE);
 
1240
    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1241
 
 
1242
    output = g_string_new ("");
 
1243
 
 
1244
    backup_filename = gsd_rr_config_get_backup_filename ();
 
1245
    intended_filename = gsd_rr_config_get_intended_filename ();
 
1246
 
 
1247
    configurations = configurations_read_from_file (intended_filename, NULL); /* NULL-GError */
 
1248
    
 
1249
    g_string_append_printf (output, "<monitors version=\"1\">\n");
 
1250
 
 
1251
    if (configurations)
 
1252
    {
 
1253
        for (i = 0; configurations[i] != NULL; ++i)
 
1254
        {
 
1255
            if (!gsd_rr_config_match (configurations[i], configuration))
 
1256
                emit_configuration (configurations[i], output);
 
1257
            g_object_unref (configurations[i]);
 
1258
        }
 
1259
 
 
1260
        g_free (configurations);
 
1261
    }
 
1262
 
 
1263
    emit_configuration (configuration, output);
 
1264
 
 
1265
    g_string_append_printf (output, "</monitors>\n");
 
1266
 
 
1267
    /* backup the file first */
 
1268
    rename (intended_filename, backup_filename); /* no error checking because the intended file may not even exist */
 
1269
 
 
1270
    result = g_file_set_contents (intended_filename, output->str, -1, error);
 
1271
 
 
1272
    if (!result)
 
1273
        rename (backup_filename, intended_filename); /* no error checking because the backup may not even exist */
 
1274
 
 
1275
    g_free (backup_filename);
 
1276
    g_free (intended_filename);
 
1277
 
 
1278
    return result;
 
1279
}
 
1280
 
 
1281
gboolean
 
1282
gsd_rr_config_apply_with_time (GsdRRConfig *config,
 
1283
                                 GsdRRScreen *screen,
 
1284
                                 guint32        timestamp,
 
1285
                                 GError       **error)
 
1286
{
 
1287
    CrtcAssignment *assignment;
 
1288
    GsdRROutputInfo **outputs;
 
1289
    gboolean result = FALSE;
 
1290
    int i;
 
1291
 
 
1292
    g_return_val_if_fail (GSD_IS_RR_CONFIG (config), FALSE);
 
1293
    g_return_val_if_fail (GSD_IS_RR_SCREEN (screen), FALSE);
 
1294
 
 
1295
    outputs = make_outputs (config);
 
1296
 
 
1297
    assignment = crtc_assignment_new (screen, outputs, error);
 
1298
 
 
1299
    for (i = 0; outputs[i] != NULL; i++)
 
1300
        g_object_unref (outputs[i]);
 
1301
    g_free (outputs);
 
1302
    
 
1303
    if (assignment)
 
1304
    {
 
1305
        if (crtc_assignment_apply (assignment, timestamp, error))
 
1306
            result = TRUE;
 
1307
 
 
1308
        crtc_assignment_free (assignment);
 
1309
 
 
1310
        gdk_flush ();
 
1311
    }
 
1312
 
 
1313
    return result;
 
1314
}
 
1315
 
 
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
 
1321
 *
 
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.
 
1325
 *
 
1326
 * Typically, @filename is the result of gsd_rr_config_get_intended_filename() or
 
1327
 * gsd_rr_config_get_backup_filename().
 
1328
 *
 
1329
 * Returns: TRUE if the RANDR configuration was loaded and applied from
 
1330
 * the specified file, or FALSE otherwise:
 
1331
 *
 
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.
 
1337
 *
 
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.
 
1342
 */
 
1343
gboolean
 
1344
gsd_rr_config_apply_from_filename_with_time (GsdRRScreen *screen, const char *filename, guint32 timestamp, GError **error)
 
1345
{
 
1346
    GsdRRConfig *stored;
 
1347
 
 
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);
 
1351
 
 
1352
    stored = g_object_new (GSD_TYPE_RR_CONFIG, "screen", screen, NULL);
 
1353
 
 
1354
    if (gsd_rr_config_load_filename (stored, filename, error))
 
1355
    {
 
1356
        gboolean result;
 
1357
 
 
1358
        gsd_rr_config_ensure_primary (stored);
 
1359
        result = gsd_rr_config_apply_with_time (stored, screen, timestamp, error);
 
1360
 
 
1361
        g_object_unref (stored);
 
1362
        return result;
 
1363
    }
 
1364
    else
 
1365
    {
 
1366
        g_object_unref (stored);
 
1367
        return FALSE;
 
1368
    }
 
1369
}
 
1370
 
 
1371
/**
 
1372
 * gsd_rr_config_get_outputs:
 
1373
 *
 
1374
 * Returns: (array zero-terminated=1) (element-type GnomeDesktop.RROutputInfo) (transfer none): the output configuration for this #GsdRRConfig
 
1375
 */
 
1376
GsdRROutputInfo **
 
1377
gsd_rr_config_get_outputs (GsdRRConfig *self)
 
1378
{
 
1379
    g_return_val_if_fail (GSD_IS_RR_CONFIG (self), NULL);
 
1380
 
 
1381
    return self->priv->outputs;
 
1382
}
 
1383
 
 
1384
/**
 
1385
 * gsd_rr_config_get_clone:
 
1386
 *
 
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).
 
1390
 */
 
1391
gboolean
 
1392
gsd_rr_config_get_clone (GsdRRConfig *self)
 
1393
{
 
1394
    g_return_val_if_fail (GSD_IS_RR_CONFIG (self), FALSE);
 
1395
 
 
1396
    return self->priv->clone;
 
1397
}
 
1398
 
 
1399
void
 
1400
gsd_rr_config_set_clone (GsdRRConfig *self, gboolean clone)
 
1401
{
 
1402
    g_return_if_fail (GSD_IS_RR_CONFIG (self));
 
1403
 
 
1404
    self->priv->clone = clone;
 
1405
}
 
1406
 
 
1407
/*
 
1408
 * CRTC assignment
 
1409
 */
 
1410
typedef struct CrtcInfo CrtcInfo;
 
1411
 
 
1412
struct CrtcInfo
 
1413
{
 
1414
    GsdRRMode    *mode;
 
1415
    int        x;
 
1416
    int        y;
 
1417
    GsdRRRotation rotation;
 
1418
    GPtrArray *outputs;
 
1419
};
 
1420
 
 
1421
struct CrtcAssignment
 
1422
{
 
1423
    GsdRRScreen *screen;
 
1424
    GHashTable *info;
 
1425
    GsdRROutput *primary;
 
1426
};
 
1427
 
 
1428
static gboolean
 
1429
can_clone (CrtcInfo *info,
 
1430
           GsdRROutput *output)
 
1431
{
 
1432
    int i;
 
1433
 
 
1434
    for (i = 0; i < info->outputs->len; ++i)
 
1435
    {
 
1436
        GsdRROutput *clone = info->outputs->pdata[i];
 
1437
 
 
1438
        if (!gsd_rr_output_can_clone (clone, output))
 
1439
            return FALSE;
 
1440
    }
 
1441
 
 
1442
    return TRUE;
 
1443
}
 
1444
 
 
1445
static gboolean
 
1446
crtc_assignment_assign (CrtcAssignment   *assign,
 
1447
                        GsdRRCrtc      *crtc,
 
1448
                        GsdRRMode      *mode,
 
1449
                        int               x,
 
1450
                        int               y,
 
1451
                        GsdRRRotation   rotation,
 
1452
                        gboolean          primary,
 
1453
                        GsdRROutput    *output,
 
1454
                        GError          **error)
 
1455
{
 
1456
    CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
 
1457
    guint32 crtc_id;
 
1458
    const char *output_name;
 
1459
 
 
1460
    crtc_id = gsd_rr_crtc_get_id (crtc);
 
1461
    output_name = gsd_rr_output_get_name (output);
 
1462
 
 
1463
    if (!gsd_rr_crtc_can_drive_output (crtc, output))
 
1464
    {
 
1465
        g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
 
1466
                     _("CRTC %d cannot drive output %s"), crtc_id, output_name);
 
1467
        return FALSE;
 
1468
    }
 
1469
 
 
1470
    if (!gsd_rr_output_supports_mode (output, mode))
 
1471
    {
 
1472
        g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
 
1473
                     _("output %s does not support mode %dx%d@%dHz"),
 
1474
                     output_name,
 
1475
                     gsd_rr_mode_get_width (mode),
 
1476
                     gsd_rr_mode_get_height (mode),
 
1477
                     gsd_rr_mode_get_freq (mode));
 
1478
        return FALSE;
 
1479
    }
 
1480
 
 
1481
    if (!gsd_rr_crtc_supports_rotation (crtc, rotation))
 
1482
    {
 
1483
        g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
 
1484
                     _("CRTC %d does not support rotation=%s"),
 
1485
                     crtc_id,
 
1486
                     get_rotation_name (rotation));
 
1487
        return FALSE;
 
1488
    }
 
1489
 
 
1490
    if (info)
 
1491
    {
 
1492
        if (!(info->mode == mode        &&
 
1493
              info->x == x              &&
 
1494
              info->y == y              &&
 
1495
              info->rotation == rotation))
 
1496
        {
 
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"),
 
1502
                         output_name,
 
1503
                         gsd_rr_mode_get_id (info->mode), gsd_rr_mode_get_id (mode),
 
1504
                         info->x, info->y,
 
1505
                         x, y,
 
1506
                         get_rotation_name (info->rotation), get_rotation_name (rotation));
 
1507
            return FALSE;
 
1508
        }
 
1509
 
 
1510
        if (!can_clone (info, output))
 
1511
        {
 
1512
            g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
 
1513
                         _("cannot clone to output %s"),
 
1514
                         output_name);
 
1515
            return FALSE;
 
1516
        }
 
1517
 
 
1518
        g_ptr_array_add (info->outputs, output);
 
1519
 
 
1520
        if (primary && !assign->primary)
 
1521
        {
 
1522
            assign->primary = output;
 
1523
        }
 
1524
 
 
1525
        return TRUE;
 
1526
    }
 
1527
    else
 
1528
    {   
 
1529
        CrtcInfo *info = g_new0 (CrtcInfo, 1);
 
1530
        
 
1531
        info->mode = mode;
 
1532
        info->x = x;
 
1533
        info->y = y;
 
1534
        info->rotation = rotation;
 
1535
        info->outputs = g_ptr_array_new ();
 
1536
        
 
1537
        g_ptr_array_add (info->outputs, output);
 
1538
        
 
1539
        g_hash_table_insert (assign->info, crtc, info);
 
1540
            
 
1541
        if (primary && !assign->primary)
 
1542
        {
 
1543
            assign->primary = output;
 
1544
        }
 
1545
 
 
1546
        return TRUE;
 
1547
    }
 
1548
}
 
1549
 
 
1550
static void
 
1551
crtc_assignment_unassign (CrtcAssignment *assign,
 
1552
                          GsdRRCrtc         *crtc,
 
1553
                          GsdRROutput       *output)
 
1554
{
 
1555
    CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
 
1556
 
 
1557
    if (info)
 
1558
    {
 
1559
        g_ptr_array_remove (info->outputs, output);
 
1560
 
 
1561
        if (assign->primary == output)
 
1562
        {
 
1563
            assign->primary = NULL;
 
1564
        }
 
1565
 
 
1566
        if (info->outputs->len == 0)
 
1567
            g_hash_table_remove (assign->info, crtc);
 
1568
    }
 
1569
}
 
1570
 
 
1571
static void
 
1572
crtc_assignment_free (CrtcAssignment *assign)
 
1573
{
 
1574
    g_hash_table_destroy (assign->info);
 
1575
 
 
1576
    g_free (assign);
 
1577
}
 
1578
 
 
1579
typedef struct {
 
1580
    guint32 timestamp;
 
1581
    gboolean has_error;
 
1582
    GError **error;
 
1583
} ConfigureCrtcState;
 
1584
 
 
1585
static void
 
1586
configure_crtc (gpointer key,
 
1587
                gpointer value,
 
1588
                gpointer data)
 
1589
{
 
1590
    GsdRRCrtc *crtc = key;
 
1591
    CrtcInfo *info = value;
 
1592
    ConfigureCrtcState *state = data;
 
1593
 
 
1594
    if (state->has_error)
 
1595
        return;
 
1596
 
 
1597
    if (!gsd_rr_crtc_set_config_with_time (crtc,
 
1598
                                             state->timestamp,
 
1599
                                             info->x, info->y,
 
1600
                                             info->mode,
 
1601
                                             info->rotation,
 
1602
                                             (GsdRROutput **)info->outputs->pdata,
 
1603
                                             info->outputs->len,
 
1604
                                             state->error))
 
1605
        state->has_error = TRUE;
 
1606
}
 
1607
 
 
1608
static gboolean
 
1609
mode_is_rotated (CrtcInfo *info)
 
1610
{
 
1611
    if ((info->rotation & GSD_RR_ROTATION_270)          ||
 
1612
        (info->rotation & GSD_RR_ROTATION_90))
 
1613
    {
 
1614
        return TRUE;
 
1615
    }
 
1616
    return FALSE;
 
1617
}
 
1618
 
 
1619
static gboolean
 
1620
crtc_is_rotated (GsdRRCrtc *crtc)
 
1621
{
 
1622
    GsdRRRotation r = gsd_rr_crtc_get_current_rotation (crtc);
 
1623
 
 
1624
    if ((r & GSD_RR_ROTATION_270)               ||
 
1625
        (r & GSD_RR_ROTATION_90))
 
1626
    {
 
1627
        return TRUE;
 
1628
    }
 
1629
 
 
1630
    return FALSE;
 
1631
}
 
1632
 
 
1633
static void
 
1634
accumulate_error (GString *accumulated_error, GError *error)
 
1635
{
 
1636
    g_string_append_printf (accumulated_error, "    %s\n", error->message);
 
1637
    g_error_free (error);
 
1638
}
 
1639
 
 
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.
 
1643
 *
 
1644
 * Brute force - the number of objects involved is small
 
1645
 * enough that it doesn't matter.
 
1646
 */
 
1647
static gboolean
 
1648
real_assign_crtcs (GsdRRScreen *screen,
 
1649
                   GsdRROutputInfo **outputs,
 
1650
                   CrtcAssignment *assignment,
 
1651
                   GError **error)
 
1652
{
 
1653
    GsdRRCrtc **crtcs = gsd_rr_screen_list_crtcs (screen);
 
1654
    GsdRROutputInfo *output;
 
1655
    int i;
 
1656
    gboolean tried_mode;
 
1657
    GError *my_error;
 
1658
    GString *accumulated_error;
 
1659
    gboolean success;
 
1660
 
 
1661
    output = *outputs;
 
1662
    if (!output)
 
1663
        return TRUE;
 
1664
 
 
1665
    /* It is always allowed for an output to be turned off */
 
1666
    if (!output->priv->on)
 
1667
    {
 
1668
        return real_assign_crtcs (screen, outputs + 1, assignment, error);
 
1669
    }
 
1670
 
 
1671
    success = FALSE;
 
1672
    tried_mode = FALSE;
 
1673
    accumulated_error = g_string_new (NULL);
 
1674
 
 
1675
    for (i = 0; crtcs[i] != NULL; ++i)
 
1676
    {
 
1677
        GsdRRCrtc *crtc = crtcs[i];
 
1678
        int crtc_id = gsd_rr_crtc_get_id (crtc);
 
1679
        int pass;
 
1680
 
 
1681
        g_string_append_printf (accumulated_error,
 
1682
                                _("Trying modes for CRTC %d\n"),
 
1683
                                crtc_id);
 
1684
 
 
1685
        /* Make two passes, one where frequencies must match, then
 
1686
         * one where they don't have to
 
1687
         */
 
1688
        for (pass = 0; pass < 2; ++pass)
 
1689
        {
 
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);
 
1692
            int j;
 
1693
 
 
1694
            for (j = 0; modes[j] != NULL; ++j)
 
1695
            {
 
1696
                GsdRRMode *mode = modes[j];
 
1697
                int mode_width;
 
1698
                int mode_height;
 
1699
                int mode_freq;
 
1700
 
 
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);
 
1704
 
 
1705
                g_string_append_printf (accumulated_error,
 
1706
                                        _("CRTC %d: trying mode %dx%d@%dHz with output at %dx%d@%dHz (pass %d)\n"),
 
1707
                                        crtc_id,
 
1708
                                        mode_width, mode_height, mode_freq,
 
1709
                                        output->priv->width, output->priv->height, output->priv->rate,
 
1710
                                        pass);
 
1711
 
 
1712
                if (mode_width == output->priv->width   &&
 
1713
                    mode_height == output->priv->height &&
 
1714
                    (pass == 1 || mode_freq == output->priv->rate))
 
1715
                {
 
1716
                    tried_mode = TRUE;
 
1717
 
 
1718
                    my_error = NULL;
 
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,
 
1724
                            gsd_rr_output,
 
1725
                            &my_error))
 
1726
                    {
 
1727
                        my_error = NULL;
 
1728
                        if (real_assign_crtcs (screen, outputs + 1, assignment, &my_error)) {
 
1729
                            success = TRUE;
 
1730
                            goto out;
 
1731
                        } else
 
1732
                            accumulate_error (accumulated_error, my_error);
 
1733
 
 
1734
                        crtc_assignment_unassign (assignment, crtc, gsd_rr_output);
 
1735
                    } else
 
1736
                        accumulate_error (accumulated_error, my_error);
 
1737
                }
 
1738
            }
 
1739
        }
 
1740
    }
 
1741
 
 
1742
out:
 
1743
 
 
1744
    if (success)
 
1745
        g_string_free (accumulated_error, TRUE);
 
1746
    else {
 
1747
        char *str;
 
1748
 
 
1749
        str = g_string_free (accumulated_error, FALSE);
 
1750
 
 
1751
        if (tried_mode)
 
1752
            g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
 
1753
                         _("could not assign CRTCs to outputs:\n%s"),
 
1754
                         str);
 
1755
        else
 
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"),
 
1758
                         str);
 
1759
 
 
1760
        g_free (str);
 
1761
    }
 
1762
 
 
1763
    return success;
 
1764
}
 
1765
 
 
1766
static void
 
1767
crtc_info_free (CrtcInfo *info)
 
1768
{
 
1769
    g_ptr_array_free (info->outputs, TRUE);
 
1770
    g_free (info);
 
1771
}
 
1772
 
 
1773
static void
 
1774
get_required_virtual_size (CrtcAssignment *assign, int *width, int *height)
 
1775
{
 
1776
    GList *active_crtcs = g_hash_table_get_keys (assign->info);
 
1777
    GList *list;
 
1778
    int d;
 
1779
 
 
1780
    if (!width)
 
1781
        width = &d;
 
1782
    if (!height)
 
1783
        height = &d;
 
1784
    
 
1785
    /* Compute size of the screen */
 
1786
    *width = *height = 1;
 
1787
    for (list = active_crtcs; list != NULL; list = list->next)
 
1788
    {
 
1789
        GsdRRCrtc *crtc = list->data;
 
1790
        CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
 
1791
        int w, h;
 
1792
 
 
1793
        w = gsd_rr_mode_get_width (info->mode);
 
1794
        h = gsd_rr_mode_get_height (info->mode);
 
1795
        
 
1796
        if (mode_is_rotated (info))
 
1797
        {
 
1798
            int tmp = h;
 
1799
            h = w;
 
1800
            w = tmp;
 
1801
        }
 
1802
        
 
1803
        *width = MAX (*width, info->x + w);
 
1804
        *height = MAX (*height, info->y + h);
 
1805
    }
 
1806
 
 
1807
    g_list_free (active_crtcs);
 
1808
}
 
1809
 
 
1810
static gboolean
 
1811
unity_running (void)
 
1812
{
 
1813
    const gchar *desktop_environment = g_getenv ("DESKTOP_SESSION");
 
1814
    
 
1815
    return !g_strcmp0 (desktop_environment, "ubuntu");
 
1816
}
 
1817
 
 
1818
static gint _max_texture_size_cache = -1;
 
1819
 
 
1820
static gint
 
1821
get_max_texture_size (GsdRRScreen *screen)
 
1822
{
 
1823
    if (_max_texture_size_cache != -1)
 
1824
    {
 
1825
        return _max_texture_size_cache;
 
1826
    } else {
 
1827
        /* 
 
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
 
1831
         * down the app.
 
1832
         */
 
1833
        int pipe_fd[2];
 
1834
        pid_t canary_pid;
 
1835
 
 
1836
        char * const canary_argv[] = { LIBEXECDIR "/check_gl_texture_size", NULL };
 
1837
        char *canary_env[2];
 
1838
        char display_env[80];
 
1839
          
 
1840
        snprintf (display_env, sizeof (display_env), "DISPLAY=%s", DisplayString (screen->priv->xdisplay));
 
1841
        canary_env[0] = display_env;
 
1842
        canary_env[1] = NULL;
 
1843
 
 
1844
 
 
1845
        if (pipe (pipe_fd) == -1)
 
1846
        {
 
1847
            _max_texture_size_cache = 0;
 
1848
            return 0;
 
1849
        }
 
1850
        canary_pid = fork ();
 
1851
        if (canary_pid == -1)
 
1852
        {
 
1853
            _max_texture_size_cache = 0;
 
1854
            return 0;
 
1855
        }
 
1856
 
 
1857
        if (canary_pid == 0)
 
1858
        {
 
1859
          close (pipe_fd[0]);
 
1860
          dup2 (pipe_fd[1], 1);
 
1861
          close (pipe_fd[1]);
 
1862
         
 
1863
          execve (canary_argv[0], canary_argv, canary_env);
 
1864
        } else {
 
1865
            char buffer[10];
 
1866
            gint max_texture_size;
 
1867
            int child_status;
 
1868
            int num_char;
 
1869
            struct timespec fifty_msec = {0, 50000000};
 
1870
            int wait_count = 0;
 
1871
            
 
1872
            close (pipe_fd[1]);
 
1873
 
 
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.
 
1877
             *
 
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
 
1880
             * set up.
 
1881
             */
 
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);
 
1885
                wait_count++;
 
1886
            }
 
1887
 
 
1888
            if (WIFEXITED (child_status) && WEXITSTATUS (child_status) == EXIT_SUCCESS) 
 
1889
            {
 
1890
                if ((num_char = read (pipe_fd[0], buffer, sizeof(buffer) - 1)) <= 0) 
 
1891
                {
 
1892
                    g_warning ("Failed to read GL_MAX_TEXTURE_SIZE from helper.");
 
1893
                    max_texture_size = 0;
 
1894
                } else {
 
1895
                    buffer[num_char] = '\0';
 
1896
                    sscanf (buffer, "%u", &max_texture_size);
 
1897
                    /* 
 
1898
                     * Sanity check the numbers.  No hardware I know of has a
 
1899
                     * GL_MAX_TEXTURE_SIZE smaller than 1024.
 
1900
                     */
 
1901
                    if (max_texture_size < 1024)
 
1902
                        max_texture_size = 0;
 
1903
                }
 
1904
            } else {
 
1905
                if (wait_count == 10) {
 
1906
                    g_warning ("Timed out waiting for GL_MAX_TEXTURE_SIZE helper");
 
1907
 
 
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);
 
1911
                } else {
 
1912
                    g_warning ("GL_MAX_TEXTURE_SIZE helper quit unexpectedly");
 
1913
                }
 
1914
                max_texture_size = 0;
 
1915
            }
 
1916
 
 
1917
            close (pipe_fd[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;
 
1921
        }
 
1922
    }
 
1923
}
 
1924
 
 
1925
static CrtcAssignment *
 
1926
crtc_assignment_new (GsdRRScreen *screen, GsdRROutputInfo **outputs, GError **error)
 
1927
{
 
1928
    CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1);
 
1929
 
 
1930
    assignment->info = g_hash_table_new_full (
 
1931
        g_direct_hash, g_direct_equal, NULL, (GFreeFunc)crtc_info_free);
 
1932
 
 
1933
    if (real_assign_crtcs (screen, outputs, assignment, error))
 
1934
    {
 
1935
        int width, height;
 
1936
        int min_width, max_width, min_height, max_height;
 
1937
        int max_texture_size;
 
1938
 
 
1939
        get_required_virtual_size (assignment, &width, &height);
 
1940
 
 
1941
        gsd_rr_screen_get_ranges (
 
1942
            screen, &min_width, &max_width, &min_height, &max_height);
 
1943
    
 
1944
        if (width < min_width || width > max_width ||
 
1945
            height < min_height || height > max_height)
 
1946
        {
 
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)"),
 
1953
                         width, height,
 
1954
                         min_width, min_height,
 
1955
                         max_width, max_height);
 
1956
            goto fail;
 
1957
        }
 
1958
 
 
1959
        /* Hack:
 
1960
         * This should either be solved by
 
1961
         * (a) Allowing the compositor to veto RandR changes
 
1962
         * (b) Fixing the compositor
 
1963
         * 
 
1964
         * Nethier of these are feasible at this point, so just fix Unity.
 
1965
         */
 
1966
 
 
1967
        if (unity_running ())
 
1968
        {
 
1969
            max_texture_size = get_max_texture_size (screen);
 
1970
            if (max_texture_size > 0 && (width > max_texture_size || height > max_texture_size))
 
1971
            {
 
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);
 
1977
                goto fail;
 
1978
            }
 
1979
        }
 
1980
            
 
1981
        
 
1982
        assignment->screen = screen;
 
1983
        
 
1984
        return assignment;
 
1985
    }
 
1986
 
 
1987
fail:
 
1988
    crtc_assignment_free (assignment);
 
1989
    
 
1990
    return NULL;
 
1991
}
 
1992
 
 
1993
static gboolean
 
1994
crtc_assignment_apply (CrtcAssignment *assign, guint32 timestamp, GError **error)
 
1995
{
 
1996
    GsdRRCrtc **all_crtcs = gsd_rr_screen_list_crtcs (assign->screen);
 
1997
    int width, height;
 
1998
    int i;
 
1999
    int min_width, max_width, min_height, max_height;
 
2000
    int width_mm, height_mm;
 
2001
    gboolean success = TRUE;
 
2002
 
 
2003
    /* Compute size of the screen */
 
2004
    get_required_virtual_size (assign, &width, &height);
 
2005
 
 
2006
    gsd_rr_screen_get_ranges (
 
2007
        assign->screen, &min_width, &max_width, &min_height, &max_height);
 
2008
 
 
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.
 
2011
     */
 
2012
    width = MAX (min_width, width);
 
2013
    width = MIN (max_width, width);
 
2014
    height = MAX (min_height, height);
 
2015
    height = MIN (max_height, height);
 
2016
 
 
2017
    /* FMQ: do we need to check the sizes instead of clamping them? */
 
2018
 
 
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
 
2021
     * status.
 
2022
     */
 
2023
 
 
2024
    gdk_x11_display_grab (gdk_screen_get_display (assign->screen->priv->gdk_screen));
 
2025
 
 
2026
    /* Turn off all crtcs that are currently displaying outside the new screen,
 
2027
     * or are not used in the new setup
 
2028
     */
 
2029
    for (i = 0; all_crtcs[i] != NULL; ++i)
 
2030
    {
 
2031
        GsdRRCrtc *crtc = all_crtcs[i];
 
2032
        GsdRRMode *mode = gsd_rr_crtc_get_current_mode (crtc);
 
2033
        int x, y;
 
2034
 
 
2035
        if (mode)
 
2036
        {
 
2037
            int w, h;
 
2038
            gsd_rr_crtc_get_position (crtc, &x, &y);
 
2039
 
 
2040
            w = gsd_rr_mode_get_width (mode);
 
2041
            h = gsd_rr_mode_get_height (mode);
 
2042
 
 
2043
            if (crtc_is_rotated (crtc))
 
2044
            {
 
2045
                int tmp = h;
 
2046
                h = w;
 
2047
                w = tmp;
 
2048
            }
 
2049
            
 
2050
            if (x + w > width || y + h > height || !g_hash_table_lookup (assign->info, crtc))
 
2051
            {
 
2052
                if (!gsd_rr_crtc_set_config_with_time (crtc, timestamp, 0, 0, NULL, GSD_RR_ROTATION_0, NULL, 0, error))
 
2053
                {
 
2054
                    success = FALSE;
 
2055
                    break;
 
2056
                }
 
2057
                
 
2058
            }
 
2059
        }
 
2060
    }
 
2061
 
 
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
 
2064
     * dpi 96.
 
2065
     *
 
2066
     * Firefox and Evince apparently believe what X tells them.
 
2067
     */
 
2068
    width_mm = (width / DPI_FALLBACK) * 25.4 + 0.5;
 
2069
    height_mm = (height / DPI_FALLBACK) * 25.4 + 0.5;
 
2070
 
 
2071
    if (success)
 
2072
    {
 
2073
        ConfigureCrtcState state;
 
2074
 
 
2075
        gsd_rr_screen_set_size (assign->screen, width, height, width_mm, height_mm);
 
2076
 
 
2077
        state.timestamp = timestamp;
 
2078
        state.has_error = FALSE;
 
2079
        state.error = error;
 
2080
        
 
2081
        g_hash_table_foreach (assign->info, configure_crtc, &state);
 
2082
 
 
2083
        success = !state.has_error;
 
2084
    }
 
2085
 
 
2086
    gsd_rr_screen_set_primary_output (assign->screen, assign->primary);
 
2087
 
 
2088
    gdk_x11_display_ungrab (gdk_screen_get_display (assign->screen->priv->gdk_screen));
 
2089
 
 
2090
    return success;
 
2091
}