~ubuntu-branches/ubuntu/vivid/gnome-desktop3/vivid-proposed

« back to all changes in this revision

Viewing changes to .pc/ignore_errors_with_primary_outputs.patch/libgnome-desktop/gnome-rr.c

  • Committer: Package Import Robot
  • Author(s): Alberto Milone
  • Date: 2013-12-03 15:58:57 UTC
  • Revision ID: package-import@ubuntu.com-20131203155857-ts8zhvwl1l63nlln
Tags: 3.8.4-0ubuntu2
* debian/patches/ignore_errors_with_primary_outputs.patch:
  - Ignore failures when setting the primary output (LP: 1224254).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gnome-rr.c
 
2
 *
 
3
 * Copyright 2007, 2008, Red Hat, Inc.
 
4
 * 
 
5
 * This file is part of the Gnome Library.
 
6
 * 
 
7
 * The Gnome Library is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU Library General Public License as
 
9
 * published by the Free Software Foundation; either version 2 of the
 
10
 * License, or (at your option) any later version.
 
11
 *
 
12
 * The Gnome Library is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * Library General Public License for more details.
 
16
 * 
 
17
 * You should have received a copy of the GNU Library General Public
 
18
 * License along with the Gnome Library; see the file COPYING.LIB.  If not,
 
19
 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
20
 * Boston, MA 02110-1301, USA.
 
21
 * 
 
22
 * Author: Soren Sandmann <sandmann@redhat.com>
 
23
 */
 
24
 
 
25
#define GNOME_DESKTOP_USE_UNSTABLE_API
 
26
 
 
27
#include <config.h>
 
28
#include <glib/gi18n-lib.h>
 
29
#include <string.h>
 
30
#include <X11/Xlib.h>
 
31
 
 
32
#include <X11/extensions/Xrandr.h>
 
33
 
 
34
#include <gtk/gtk.h>
 
35
#include <gdk/gdkx.h>
 
36
#include <X11/Xatom.h>
 
37
#include <X11/extensions/dpms.h>
 
38
 
 
39
#undef GNOME_DISABLE_DEPRECATED
 
40
#include "gnome-rr.h"
 
41
#include "gnome-rr-config.h"
 
42
 
 
43
#include "edid.h"
 
44
#include "gnome-rr-private.h"
 
45
 
 
46
#define DISPLAY(o) ((o)->info->screen->priv->xdisplay)
 
47
 
 
48
#define SERVERS_RANDR_IS_AT_LEAST_1_3(priv) (priv->rr_major_version > 1 || (priv->rr_major_version == 1 && priv->rr_minor_version >= 3))
 
49
 
 
50
enum {
 
51
    SCREEN_PROP_0,
 
52
    SCREEN_PROP_GDK_SCREEN,
 
53
    SCREEN_PROP_LAST,
 
54
};
 
55
 
 
56
enum {
 
57
    SCREEN_CHANGED,
 
58
    SCREEN_OUTPUT_CONNECTED,
 
59
    SCREEN_OUTPUT_DISCONNECTED,
 
60
    SCREEN_SIGNAL_LAST,
 
61
};
 
62
 
 
63
gint screen_signals[SCREEN_SIGNAL_LAST];
 
64
 
 
65
struct GnomeRROutput
 
66
{
 
67
    ScreenInfo *        info;
 
68
    RROutput            id;
 
69
    
 
70
    char *              name;
 
71
    char *              display_name;
 
72
    GnomeRRCrtc *       current_crtc;
 
73
    gboolean            connected;
 
74
    gulong              width_mm;
 
75
    gulong              height_mm;
 
76
    GnomeRRCrtc **      possible_crtcs;
 
77
    GnomeRROutput **    clones;
 
78
    GnomeRRMode **      modes;
 
79
    int                 n_preferred;
 
80
    guint8 *            edid_data;
 
81
    gsize               edid_size;
 
82
    char *              connector_type;
 
83
    gint                backlight_min;
 
84
    gint                backlight_max;
 
85
};
 
86
 
 
87
struct GnomeRROutputWrap
 
88
{
 
89
    RROutput            id;
 
90
};
 
91
 
 
92
struct GnomeRRCrtc
 
93
{
 
94
    ScreenInfo *        info;
 
95
    RRCrtc              id;
 
96
    
 
97
    GnomeRRMode *       current_mode;
 
98
    GnomeRROutput **    current_outputs;
 
99
    GnomeRROutput **    possible_outputs;
 
100
    int                 x;
 
101
    int                 y;
 
102
    
 
103
    GnomeRRRotation     current_rotation;
 
104
    GnomeRRRotation     rotations;
 
105
    int                 gamma_size;
 
106
};
 
107
 
 
108
struct GnomeRRMode
 
109
{
 
110
    ScreenInfo *        info;
 
111
    RRMode              id;
 
112
    char *              name;
 
113
    int                 width;
 
114
    int                 height;
 
115
    int                 freq;           /* in mHz */
 
116
};
 
117
 
 
118
/* GnomeRRCrtc */
 
119
static GnomeRRCrtc *  crtc_new          (ScreenInfo         *info,
 
120
                                         RRCrtc              id);
 
121
static GnomeRRCrtc *  crtc_copy         (const GnomeRRCrtc  *from);
 
122
static void           crtc_free         (GnomeRRCrtc        *crtc);
 
123
 
 
124
static gboolean       crtc_initialize   (GnomeRRCrtc        *crtc,
 
125
                                         XRRScreenResources *res,
 
126
                                         GError            **error);
 
127
 
 
128
/* GnomeRROutput */
 
129
static GnomeRROutput *output_new        (ScreenInfo         *info,
 
130
                                         RROutput            id);
 
131
 
 
132
static gboolean       output_initialize (GnomeRROutput      *output,
 
133
                                         XRRScreenResources *res,
 
134
                                         GError            **error);
 
135
 
 
136
static GnomeRROutput *output_copy       (const GnomeRROutput *from);
 
137
static void           output_free       (GnomeRROutput      *output);
 
138
 
 
139
/* GnomeRRMode */
 
140
static GnomeRRMode *  mode_new          (ScreenInfo         *info,
 
141
                                         RRMode              id);
 
142
 
 
143
static void           mode_initialize   (GnomeRRMode        *mode,
 
144
                                         XRRModeInfo        *info);
 
145
 
 
146
static GnomeRRMode *  mode_copy         (const GnomeRRMode  *from);
 
147
static void           mode_free         (GnomeRRMode        *mode);
 
148
 
 
149
static void gnome_rr_screen_finalize (GObject*);
 
150
static void gnome_rr_screen_set_property (GObject*, guint, const GValue*, GParamSpec*);
 
151
static void gnome_rr_screen_get_property (GObject*, guint, GValue*, GParamSpec*);
 
152
static gboolean gnome_rr_screen_initable_init (GInitable*, GCancellable*, GError**);
 
153
static void gnome_rr_screen_initable_iface_init (GInitableIface *iface);
 
154
G_DEFINE_TYPE_WITH_CODE (GnomeRRScreen, gnome_rr_screen, G_TYPE_OBJECT,
 
155
        G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gnome_rr_screen_initable_iface_init))
 
156
 
 
157
G_DEFINE_BOXED_TYPE (GnomeRRCrtc, gnome_rr_crtc, crtc_copy, crtc_free)
 
158
G_DEFINE_BOXED_TYPE (GnomeRROutput, gnome_rr_output, output_copy, output_free)
 
159
G_DEFINE_BOXED_TYPE (GnomeRRMode, gnome_rr_mode, mode_copy, mode_free)
 
160
 
 
161
/* Errors */
 
162
 
 
163
/**
 
164
 * gnome_rr_error_quark:
 
165
 *
 
166
 * Returns the #GQuark that will be used for #GError values returned by the
 
167
 * GnomeRR API.
 
168
 *
 
169
 * Return value: a #GQuark used to identify errors coming from the GnomeRR API.
 
170
 */
 
171
GQuark
 
172
gnome_rr_error_quark (void)
 
173
{
 
174
    return g_quark_from_static_string ("gnome-rr-error-quark");
 
175
}
 
176
 
 
177
/* Screen */
 
178
static GnomeRROutput *
 
179
gnome_rr_output_by_id (ScreenInfo *info, RROutput id)
 
180
{
 
181
    GnomeRROutput **output;
 
182
    
 
183
    g_assert (info != NULL);
 
184
    
 
185
    for (output = info->outputs; *output; ++output)
 
186
    {
 
187
        if ((*output)->id == id)
 
188
            return *output;
 
189
    }
 
190
    
 
191
    return NULL;
 
192
}
 
193
 
 
194
static GnomeRRCrtc *
 
195
crtc_by_id (ScreenInfo *info, RRCrtc id)
 
196
{
 
197
    GnomeRRCrtc **crtc;
 
198
    
 
199
    if (!info)
 
200
        return NULL;
 
201
    
 
202
    for (crtc = info->crtcs; *crtc; ++crtc)
 
203
    {
 
204
        if ((*crtc)->id == id)
 
205
            return *crtc;
 
206
    }
 
207
    
 
208
    return NULL;
 
209
}
 
210
 
 
211
static GnomeRRMode *
 
212
mode_by_id (ScreenInfo *info, RRMode id)
 
213
{
 
214
    GnomeRRMode **mode;
 
215
    
 
216
    g_assert (info != NULL);
 
217
    
 
218
    for (mode = info->modes; *mode; ++mode)
 
219
    {
 
220
        if ((*mode)->id == id)
 
221
            return *mode;
 
222
    }
 
223
    
 
224
    return NULL;
 
225
}
 
226
 
 
227
static void
 
228
screen_info_free (ScreenInfo *info)
 
229
{
 
230
    GnomeRROutput **output;
 
231
    GnomeRRCrtc **crtc;
 
232
    GnomeRRMode **mode;
 
233
    
 
234
    g_assert (info != NULL);
 
235
 
 
236
    if (info->resources)
 
237
    {
 
238
        XRRFreeScreenResources (info->resources);
 
239
        
 
240
        info->resources = NULL;
 
241
    }
 
242
    
 
243
    if (info->outputs)
 
244
    {
 
245
        for (output = info->outputs; *output; ++output)
 
246
            output_free (*output);
 
247
        g_free (info->outputs);
 
248
    }
 
249
    
 
250
    if (info->crtcs)
 
251
    {
 
252
        for (crtc = info->crtcs; *crtc; ++crtc)
 
253
            crtc_free (*crtc);
 
254
        g_free (info->crtcs);
 
255
    }
 
256
    
 
257
    if (info->modes)
 
258
    {
 
259
        for (mode = info->modes; *mode; ++mode)
 
260
            mode_free (*mode);
 
261
        g_free (info->modes);
 
262
    }
 
263
 
 
264
    if (info->clone_modes)
 
265
    {
 
266
        /* The modes themselves were freed above */
 
267
        g_free (info->clone_modes);
 
268
    }
 
269
    
 
270
    g_free (info);
 
271
}
 
272
 
 
273
static gboolean
 
274
has_similar_mode (GnomeRROutput *output, GnomeRRMode *mode)
 
275
{
 
276
    int i;
 
277
    GnomeRRMode **modes = gnome_rr_output_list_modes (output);
 
278
    int width = gnome_rr_mode_get_width (mode);
 
279
    int height = gnome_rr_mode_get_height (mode);
 
280
 
 
281
    for (i = 0; modes[i] != NULL; ++i)
 
282
    {
 
283
        GnomeRRMode *m = modes[i];
 
284
 
 
285
        if (gnome_rr_mode_get_width (m) == width        &&
 
286
            gnome_rr_mode_get_height (m) == height)
 
287
        {
 
288
            return TRUE;
 
289
        }
 
290
    }
 
291
 
 
292
    return FALSE;
 
293
}
 
294
 
 
295
static void
 
296
gather_clone_modes (ScreenInfo *info)
 
297
{
 
298
    int i;
 
299
    GPtrArray *result = g_ptr_array_new ();
 
300
 
 
301
    for (i = 0; info->outputs[i] != NULL; ++i)
 
302
    {
 
303
        int j;
 
304
        GnomeRROutput *output1, *output2;
 
305
 
 
306
        output1 = info->outputs[i];
 
307
        
 
308
        if (!output1->connected)
 
309
            continue;
 
310
        
 
311
        for (j = 0; output1->modes[j] != NULL; ++j)
 
312
        {
 
313
            GnomeRRMode *mode = output1->modes[j];
 
314
            gboolean valid;
 
315
            int k;
 
316
 
 
317
            valid = TRUE;
 
318
            for (k = 0; info->outputs[k] != NULL; ++k)
 
319
            {
 
320
                output2 = info->outputs[k];
 
321
                
 
322
                if (!output2->connected)
 
323
                    continue;
 
324
                
 
325
                if (!has_similar_mode (output2, mode))
 
326
                {
 
327
                    valid = FALSE;
 
328
                    break;
 
329
                }
 
330
            }
 
331
 
 
332
            if (valid)
 
333
                g_ptr_array_add (result, mode);
 
334
        }
 
335
    }
 
336
 
 
337
    g_ptr_array_add (result, NULL);
 
338
    
 
339
    info->clone_modes = (GnomeRRMode **)g_ptr_array_free (result, FALSE);
 
340
}
 
341
 
 
342
static gboolean
 
343
fill_screen_info_from_resources (ScreenInfo *info,
 
344
                                 XRRScreenResources *resources,
 
345
                                 GError **error)
 
346
{
 
347
    int i;
 
348
    GPtrArray *a;
 
349
    GnomeRRCrtc **crtc;
 
350
    GnomeRROutput **output;
 
351
 
 
352
    info->resources = resources;
 
353
 
 
354
    /* We create all the structures before initializing them, so
 
355
     * that they can refer to each other.
 
356
     */
 
357
    a = g_ptr_array_new ();
 
358
    for (i = 0; i < resources->ncrtc; ++i)
 
359
    {
 
360
        GnomeRRCrtc *crtc = crtc_new (info, resources->crtcs[i]);
 
361
 
 
362
        g_ptr_array_add (a, crtc);
 
363
    }
 
364
    g_ptr_array_add (a, NULL);
 
365
    info->crtcs = (GnomeRRCrtc **)g_ptr_array_free (a, FALSE);
 
366
 
 
367
    a = g_ptr_array_new ();
 
368
    for (i = 0; i < resources->noutput; ++i)
 
369
    {
 
370
        GnomeRROutput *output = output_new (info, resources->outputs[i]);
 
371
 
 
372
        g_ptr_array_add (a, output);
 
373
    }
 
374
    g_ptr_array_add (a, NULL);
 
375
    info->outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
 
376
 
 
377
    a = g_ptr_array_new ();
 
378
    for (i = 0;  i < resources->nmode; ++i)
 
379
    {
 
380
        GnomeRRMode *mode = mode_new (info, resources->modes[i].id);
 
381
 
 
382
        g_ptr_array_add (a, mode);
 
383
    }
 
384
    g_ptr_array_add (a, NULL);
 
385
    info->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
 
386
 
 
387
    /* Initialize */
 
388
    for (crtc = info->crtcs; *crtc; ++crtc)
 
389
    {
 
390
        if (!crtc_initialize (*crtc, resources, error))
 
391
            return FALSE;
 
392
    }
 
393
 
 
394
    for (output = info->outputs; *output; ++output)
 
395
    {
 
396
        if (!output_initialize (*output, resources, error))
 
397
            return FALSE;
 
398
    }
 
399
 
 
400
    for (i = 0; i < resources->nmode; ++i)
 
401
    {
 
402
        GnomeRRMode *mode = mode_by_id (info, resources->modes[i].id);
 
403
 
 
404
        mode_initialize (mode, &(resources->modes[i]));
 
405
    }
 
406
 
 
407
    gather_clone_modes (info);
 
408
 
 
409
    return TRUE;
 
410
}
 
411
 
 
412
static gboolean
 
413
fill_out_screen_info (Display *xdisplay,
 
414
                      Window xroot,
 
415
                      ScreenInfo *info,
 
416
                      gboolean needs_reprobe,
 
417
                      GError **error)
 
418
{
 
419
    XRRScreenResources *resources;
 
420
    GnomeRRScreenPrivate *priv;
 
421
    
 
422
    g_assert (xdisplay != NULL);
 
423
    g_assert (info != NULL);
 
424
 
 
425
    priv = info->screen->priv;
 
426
 
 
427
    /* First update the screen resources */
 
428
 
 
429
    if (needs_reprobe)
 
430
        resources = XRRGetScreenResources (xdisplay, xroot);
 
431
    else
 
432
    {
 
433
        /* XRRGetScreenResourcesCurrent is less expensive than
 
434
         * XRRGetScreenResources, however it is available only
 
435
         * in RandR 1.3 or higher
 
436
         */
 
437
        if (SERVERS_RANDR_IS_AT_LEAST_1_3 (priv))
 
438
            resources = XRRGetScreenResourcesCurrent (xdisplay, xroot);
 
439
        else
 
440
            resources = XRRGetScreenResources (xdisplay, xroot);
 
441
    }
 
442
 
 
443
    if (resources)
 
444
    {
 
445
        if (!fill_screen_info_from_resources (info, resources, error))
 
446
            return FALSE;
 
447
    }
 
448
    else
 
449
    {
 
450
        g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
 
451
                     /* Translators: a CRTC is a CRT Controller (this is X terminology). */
 
452
                     _("could not get the screen resources (CRTCs, outputs, modes)"));
 
453
        return FALSE;
 
454
    }
 
455
 
 
456
    /* Then update the screen size range.  We do this after XRRGetScreenResources() so that
 
457
     * the X server will already have an updated view of the outputs.
 
458
     */
 
459
 
 
460
    if (needs_reprobe) {
 
461
        gboolean success;
 
462
 
 
463
        gdk_error_trap_push ();
 
464
        success = XRRGetScreenSizeRange (xdisplay, xroot,
 
465
                                         &(info->min_width),
 
466
                                         &(info->min_height),
 
467
                                         &(info->max_width),
 
468
                                         &(info->max_height));
 
469
        gdk_flush ();
 
470
        if (gdk_error_trap_pop ()) {
 
471
            g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_UNKNOWN,
 
472
                         _("unhandled X error while getting the range of screen sizes"));
 
473
            return FALSE;
 
474
        }
 
475
 
 
476
        if (!success) {
 
477
            g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
 
478
                         _("could not get the range of screen sizes"));
 
479
            return FALSE;
 
480
        }
 
481
    }
 
482
    else
 
483
    {
 
484
        gnome_rr_screen_get_ranges (info->screen, 
 
485
                                         &(info->min_width),
 
486
                                         &(info->max_width),
 
487
                                         &(info->min_height),
 
488
                                         &(info->max_height));
 
489
    }
 
490
 
 
491
    info->primary = None;
 
492
    if (SERVERS_RANDR_IS_AT_LEAST_1_3 (priv)) {
 
493
        gdk_error_trap_push ();
 
494
        info->primary = XRRGetOutputPrimary (xdisplay, xroot);
 
495
        gdk_error_trap_pop_ignored ();
 
496
    }
 
497
 
 
498
    /* can the screen do DPMS? */
 
499
    gdk_error_trap_push ();
 
500
    priv->dpms_capable = DPMSCapable (priv->xdisplay);
 
501
    gdk_error_trap_pop_ignored ();
 
502
 
 
503
    return TRUE;
 
504
}
 
505
 
 
506
static ScreenInfo *
 
507
screen_info_new (GnomeRRScreen *screen, gboolean needs_reprobe, GError **error)
 
508
{
 
509
    ScreenInfo *info = g_new0 (ScreenInfo, 1);
 
510
    GnomeRRScreenPrivate *priv;
 
511
 
 
512
    g_assert (screen != NULL);
 
513
 
 
514
    priv = screen->priv;
 
515
 
 
516
    info->outputs = NULL;
 
517
    info->crtcs = NULL;
 
518
    info->modes = NULL;
 
519
    info->screen = screen;
 
520
    
 
521
    if (fill_out_screen_info (priv->xdisplay, priv->xroot, info, needs_reprobe, error))
 
522
    {
 
523
        return info;
 
524
    }
 
525
    else
 
526
    {
 
527
        screen_info_free (info);
 
528
        return NULL;
 
529
    }
 
530
}
 
531
 
 
532
static GnomeRROutput *
 
533
find_output_by_id (GnomeRROutput **haystack, guint32 id)
 
534
{
 
535
    guint i;
 
536
 
 
537
    for (i = 0; haystack[i] != NULL; i++)
 
538
    {
 
539
        if (gnome_rr_output_get_id (haystack[i]) == id)
 
540
            return haystack[i];
 
541
    }
 
542
    return NULL;
 
543
}
 
544
 
 
545
static void
 
546
diff_outputs_and_emit_signals (ScreenInfo *old, ScreenInfo *new)
 
547
{
 
548
    guint i;
 
549
    guint32 id_old, id_new;
 
550
    GnomeRROutput *output_old;
 
551
    GnomeRROutput *output_new;
 
552
 
 
553
    /* have any outputs been removed or disconnected */
 
554
    for (i = 0; old->outputs[i] != NULL; i++)
 
555
    {
 
556
        id_old = gnome_rr_output_get_id (old->outputs[i]);
 
557
        output_new = find_output_by_id (new->outputs, id_old);
 
558
        if (output_new == NULL)
 
559
        {
 
560
            /* output removed (and disconnected) */
 
561
            if (gnome_rr_output_is_connected (old->outputs[i]))
 
562
             {
 
563
                g_signal_emit (G_OBJECT (new->screen),
 
564
                               screen_signals[SCREEN_OUTPUT_DISCONNECTED], 0,
 
565
                               old->outputs[i]);
 
566
             }
 
567
            continue;
 
568
        }
 
569
        if (gnome_rr_output_is_connected (old->outputs[i]) &&
 
570
            !gnome_rr_output_is_connected (output_new))
 
571
        {
 
572
            /* output disconnected */
 
573
            g_signal_emit (G_OBJECT (new->screen),
 
574
                           screen_signals[SCREEN_OUTPUT_DISCONNECTED], 0,
 
575
                           old->outputs[i]);
 
576
        }
 
577
    }
 
578
 
 
579
    /* have any outputs been created or connected */
 
580
    for (i = 0; new->outputs[i] != NULL; i++)
 
581
    {
 
582
        id_new = gnome_rr_output_get_id (new->outputs[i]);
 
583
        output_old = find_output_by_id (old->outputs, id_new);
 
584
        if (output_old == NULL)
 
585
        {
 
586
            /* output created */
 
587
            if (gnome_rr_output_is_connected (new->outputs[i]))
 
588
             {
 
589
                g_signal_emit (G_OBJECT (new->screen),
 
590
                               screen_signals[SCREEN_OUTPUT_CONNECTED], 0,
 
591
                               new->outputs[i]);
 
592
            }
 
593
            continue;
 
594
        }
 
595
        if (!gnome_rr_output_is_connected (output_old) &&
 
596
            gnome_rr_output_is_connected (new->outputs[i]))
 
597
        {
 
598
            /* output connected */
 
599
            g_signal_emit (G_OBJECT (new->screen),
 
600
                           screen_signals[SCREEN_OUTPUT_CONNECTED], 0,
 
601
                           new->outputs[i]);
 
602
         }
 
603
    }
 
604
}
 
605
 
 
606
static gboolean
 
607
screen_update (GnomeRRScreen *screen, gboolean force_callback, gboolean needs_reprobe, GError **error)
 
608
{
 
609
    ScreenInfo *info;
 
610
    gboolean changed = FALSE;
 
611
    
 
612
    g_assert (screen != NULL);
 
613
 
 
614
    info = screen_info_new (screen, needs_reprobe, error);
 
615
    if (!info)
 
616
            return FALSE;
 
617
 
 
618
    if (info->resources->configTimestamp != screen->priv->info->resources->configTimestamp)
 
619
            changed = TRUE;
 
620
 
 
621
    /* work out if any outputs have changed connected state */
 
622
    diff_outputs_and_emit_signals (screen->priv->info, info);
 
623
 
 
624
    screen_info_free (screen->priv->info);
 
625
        
 
626
    screen->priv->info = info;
 
627
 
 
628
    if (changed || force_callback)
 
629
        g_signal_emit (G_OBJECT (screen), screen_signals[SCREEN_CHANGED], 0);
 
630
    
 
631
    return changed;
 
632
}
 
633
 
 
634
static GdkFilterReturn
 
635
screen_on_event (GdkXEvent *xevent,
 
636
                 GdkEvent *event,
 
637
                 gpointer data)
 
638
{
 
639
    GnomeRRScreen *screen = data;
 
640
    GnomeRRScreenPrivate *priv = screen->priv;
 
641
    XEvent *e = xevent;
 
642
    int event_num;
 
643
 
 
644
    if (!e)
 
645
        return GDK_FILTER_CONTINUE;
 
646
 
 
647
    event_num = e->type - priv->randr_event_base;
 
648
 
 
649
    if (event_num == RRScreenChangeNotify) {
 
650
        /* We don't reprobe the hardware; we just fetch the X server's latest
 
651
         * state.  The server already knows the new state of the outputs; that's
 
652
         * why it sent us an event!
 
653
         */
 
654
        screen_update (screen, TRUE, FALSE, NULL); /* NULL-GError */
 
655
#if 0
 
656
        /* Enable this code to get a dialog showing the RANDR timestamps, for debugging purposes */
 
657
        {
 
658
            GtkWidget *dialog;
 
659
            XRRScreenChangeNotifyEvent *rr_event;
 
660
            static int dialog_num;
 
661
 
 
662
            rr_event = (XRRScreenChangeNotifyEvent *) e;
 
663
 
 
664
            dialog = gtk_message_dialog_new (NULL,
 
665
                                             0,
 
666
                                             GTK_MESSAGE_INFO,
 
667
                                             GTK_BUTTONS_CLOSE,
 
668
                                             "RRScreenChangeNotify timestamps (%d):\n"
 
669
                                             "event change: %u\n"
 
670
                                             "event config: %u\n"
 
671
                                             "event serial: %lu\n"
 
672
                                             "----------------------"
 
673
                                             "screen change: %u\n"
 
674
                                             "screen config: %u\n",
 
675
                                             dialog_num++,
 
676
                                             (guint32) rr_event->timestamp,
 
677
                                             (guint32) rr_event->config_timestamp,
 
678
                                             rr_event->serial,
 
679
                                             (guint32) priv->info->resources->timestamp,
 
680
                                             (guint32) priv->info->resources->configTimestamp);
 
681
            g_signal_connect (dialog, "response",
 
682
                              G_CALLBACK (gtk_widget_destroy), NULL);
 
683
            gtk_widget_show (dialog);
 
684
        }
 
685
#endif
 
686
    }
 
687
#if 0
 
688
    /* WHY THIS CODE IS DISABLED:
 
689
     *
 
690
     * Note that in gnome_rr_screen_new(), we only select for
 
691
     * RRScreenChangeNotifyMask.  We used to select for other values in
 
692
     * RR*NotifyMask, but we weren't really doing anything useful with those
 
693
     * events.  We only care about "the screens changed in some way or another"
 
694
     * for now.
 
695
     *
 
696
     * If we ever run into a situtation that could benefit from processing more
 
697
     * detailed events, we can enable this code again.
 
698
     *
 
699
     * Note that the X server sends RRScreenChangeNotify in conjunction with the
 
700
     * more detailed events from RANDR 1.2 - see xserver/randr/randr.c:TellChanged().
 
701
     */
 
702
    else if (event_num == RRNotify)
 
703
    {
 
704
        /* Other RandR events */
 
705
 
 
706
        XRRNotifyEvent *event = (XRRNotifyEvent *)e;
 
707
 
 
708
        /* Here we can distinguish between RRNotify events supported
 
709
         * since RandR 1.2 such as RRNotify_OutputProperty.  For now, we
 
710
         * don't have anything special to do for particular subevent types, so
 
711
         * we leave this as an empty switch().
 
712
         */
 
713
        switch (event->subtype)
 
714
        {
 
715
        default:
 
716
            break;
 
717
        }
 
718
 
 
719
        /* No need to reprobe hardware here */
 
720
        screen_update (screen, TRUE, FALSE, NULL); /* NULL-GError */
 
721
    }
 
722
#endif
 
723
 
 
724
    /* Pass the event on to GTK+ */
 
725
    return GDK_FILTER_CONTINUE;
 
726
}
 
727
 
 
728
static gboolean
 
729
gnome_rr_screen_initable_init (GInitable *initable, GCancellable *canc, GError **error)
 
730
{
 
731
    GnomeRRScreen *self = GNOME_RR_SCREEN (initable);
 
732
    GnomeRRScreenPrivate *priv = self->priv;
 
733
    Display *dpy = GDK_SCREEN_XDISPLAY (self->priv->gdk_screen);
 
734
    int event_base;
 
735
    int ignore;
 
736
 
 
737
    priv->connector_type_atom = XInternAtom (dpy, "ConnectorType", FALSE);
 
738
 
 
739
    if (XRRQueryExtension (dpy, &event_base, &ignore))
 
740
    {
 
741
        priv->randr_event_base = event_base;
 
742
 
 
743
        XRRQueryVersion (dpy, &priv->rr_major_version, &priv->rr_minor_version);
 
744
        if (priv->rr_major_version < 1 || (priv->rr_major_version == 1 && priv->rr_minor_version < 2)) {
 
745
            g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_RANDR_EXTENSION,
 
746
                    "RANDR extension is too old (must be at least 1.2)");
 
747
            return FALSE;
 
748
        }
 
749
 
 
750
        priv->info = screen_info_new (self, TRUE, error);
 
751
 
 
752
        if (!priv->info) {
 
753
            return FALSE;
 
754
        }
 
755
 
 
756
        XRRSelectInput (priv->xdisplay,
 
757
                priv->xroot,
 
758
                RRScreenChangeNotifyMask);
 
759
        gdk_x11_register_standard_event_type (gdk_screen_get_display (priv->gdk_screen),
 
760
                          event_base,
 
761
                          RRNotify + 1);
 
762
        gdk_window_add_filter (priv->gdk_root, screen_on_event, self);
 
763
 
 
764
        return TRUE;
 
765
    }
 
766
    else
 
767
    {
 
768
      g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_RANDR_EXTENSION,
 
769
                   _("RANDR extension is not present"));
 
770
 
 
771
      return FALSE;
 
772
   }
 
773
}
 
774
 
 
775
void
 
776
gnome_rr_screen_initable_iface_init (GInitableIface *iface)
 
777
{
 
778
    iface->init = gnome_rr_screen_initable_init;
 
779
}
 
780
 
 
781
void
 
782
gnome_rr_screen_finalize (GObject *gobject)
 
783
{
 
784
    GnomeRRScreen *screen = GNOME_RR_SCREEN (gobject);
 
785
 
 
786
    gdk_window_remove_filter (screen->priv->gdk_root, screen_on_event, screen);
 
787
 
 
788
    if (screen->priv->info)
 
789
      screen_info_free (screen->priv->info);
 
790
 
 
791
    G_OBJECT_CLASS (gnome_rr_screen_parent_class)->finalize (gobject);
 
792
}
 
793
 
 
794
void
 
795
gnome_rr_screen_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *property)
 
796
{
 
797
    GnomeRRScreen *self = GNOME_RR_SCREEN (gobject);
 
798
    GnomeRRScreenPrivate *priv = self->priv;
 
799
 
 
800
    switch (property_id)
 
801
    {
 
802
    case SCREEN_PROP_GDK_SCREEN:
 
803
        priv->gdk_screen = g_value_get_object (value);
 
804
        priv->gdk_root = gdk_screen_get_root_window (priv->gdk_screen);
 
805
        priv->xroot = gdk_x11_window_get_xid (priv->gdk_root);
 
806
        priv->xdisplay = GDK_SCREEN_XDISPLAY (priv->gdk_screen);
 
807
        priv->xscreen = gdk_x11_screen_get_xscreen (priv->gdk_screen);
 
808
        return;
 
809
    default:
 
810
        G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
 
811
        return;
 
812
    }
 
813
}
 
814
 
 
815
void
 
816
gnome_rr_screen_get_property (GObject *gobject, guint property_id, GValue *value, GParamSpec *property)
 
817
{
 
818
    GnomeRRScreen *self = GNOME_RR_SCREEN (gobject);
 
819
    GnomeRRScreenPrivate *priv = self->priv;
 
820
 
 
821
    switch (property_id)
 
822
    {
 
823
    case SCREEN_PROP_GDK_SCREEN:
 
824
        g_value_set_object (value, priv->gdk_screen);
 
825
        return;
 
826
    default:
 
827
        G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
 
828
        return;
 
829
    }
 
830
}
 
831
 
 
832
void
 
833
gnome_rr_screen_class_init (GnomeRRScreenClass *klass)
 
834
{
 
835
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
836
    g_type_class_add_private (klass, sizeof (GnomeRRScreenPrivate));
 
837
 
 
838
    bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
 
839
    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 
840
 
 
841
    gobject_class->set_property = gnome_rr_screen_set_property;
 
842
    gobject_class->get_property = gnome_rr_screen_get_property;
 
843
    gobject_class->finalize = gnome_rr_screen_finalize;
 
844
 
 
845
    g_object_class_install_property(
 
846
            gobject_class,
 
847
            SCREEN_PROP_GDK_SCREEN,
 
848
            g_param_spec_object (
 
849
                    "gdk-screen",
 
850
                    "GDK Screen",
 
851
                    "The GDK Screen represented by this GnomeRRScreen",
 
852
                    GDK_TYPE_SCREEN,
 
853
                    G_PARAM_READWRITE |
 
854
                    G_PARAM_CONSTRUCT_ONLY |
 
855
                    G_PARAM_STATIC_STRINGS)
 
856
            );
 
857
 
 
858
    screen_signals[SCREEN_CHANGED] = g_signal_new("changed",
 
859
            G_TYPE_FROM_CLASS (gobject_class),
 
860
            G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
 
861
            G_STRUCT_OFFSET (GnomeRRScreenClass, changed),
 
862
            NULL,
 
863
            NULL,
 
864
            g_cclosure_marshal_VOID__VOID,
 
865
            G_TYPE_NONE,
 
866
            0);
 
867
 
 
868
    /**
 
869
     * GnomeRRScreen::output-connected:
 
870
     * @screen: the #GnomeRRScreen that emitted the signal
 
871
     * @output: the #GnomeRROutput that was connected
 
872
     *
 
873
     * This signal is emitted when a display device is connected to a
 
874
     * port, or a port is hotplugged with an active output. The latter
 
875
     * can happen if a laptop is docked, and the dock provides a new
 
876
     * active output.
 
877
     *
 
878
     * The @output value is not a #GObject. The returned @output value can
 
879
     * only assume to be valid during the emission of the signal (i.e. within
 
880
     * your signal handler only), as it may change later when the @screen
 
881
     * is modified due to an event from the X server, or due to another
 
882
     * place in the application modifying the @screen and the @output.
 
883
     * Therefore, deal with changes to the @output right in your signal
 
884
     * handler, instead of keeping the @output reference for an async or
 
885
     * idle function.
 
886
     **/
 
887
    screen_signals[SCREEN_OUTPUT_CONNECTED] = g_signal_new("output-connected",
 
888
            G_TYPE_FROM_CLASS (gobject_class),
 
889
            G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
 
890
            G_STRUCT_OFFSET (GnomeRRScreenClass, output_connected),
 
891
            NULL,
 
892
            NULL,
 
893
            g_cclosure_marshal_VOID__POINTER,
 
894
            G_TYPE_NONE,
 
895
            1, G_TYPE_POINTER);
 
896
 
 
897
    /**
 
898
     * GnomeRRScreen::output-disconnected:
 
899
     * @screen: the #GnomeRRScreen that emitted the signal
 
900
     * @output: the #GnomeRROutput that was disconnected
 
901
     *
 
902
     * This signal is emitted when a display device is disconnected from
 
903
     * a port, or a port output is hot-unplugged. The latter can happen
 
904
     * if a laptop is undocked, and the dock provided the output.
 
905
     *
 
906
     * The @output value is not a #GObject. The returned @output value can
 
907
     * only assume to be valid during the emission of the signal (i.e. within
 
908
     * your signal handler only), as it may change later when the @screen
 
909
     * is modified due to an event from the X server, or due to another
 
910
     * place in the application modifying the @screen and the @output.
 
911
     * Therefore, deal with changes to the @output right in your signal
 
912
     * handler, instead of keeping the @output reference for an async or
 
913
     * idle function.
 
914
     **/
 
915
    screen_signals[SCREEN_OUTPUT_DISCONNECTED] = g_signal_new("output-disconnected",
 
916
            G_TYPE_FROM_CLASS (gobject_class),
 
917
            G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
 
918
            G_STRUCT_OFFSET (GnomeRRScreenClass, output_disconnected),
 
919
            NULL,
 
920
            NULL,
 
921
            g_cclosure_marshal_VOID__POINTER,
 
922
            G_TYPE_NONE,
 
923
            1, G_TYPE_POINTER);
 
924
}
 
925
 
 
926
void
 
927
gnome_rr_screen_init (GnomeRRScreen *self)
 
928
{
 
929
    GnomeRRScreenPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_RR_SCREEN, GnomeRRScreenPrivate);
 
930
    self->priv = priv;
 
931
 
 
932
    priv->gdk_screen = NULL;
 
933
    priv->gdk_root = NULL;
 
934
    priv->xdisplay = NULL;
 
935
    priv->xroot = None;
 
936
    priv->xscreen = NULL;
 
937
    priv->info = NULL;
 
938
    priv->rr_major_version = 0;
 
939
    priv->rr_minor_version = 0;
 
940
}
 
941
 
 
942
/* Weak reference callback set in gnome_rr_screen_new(); we remove the GObject data from the GdkScreen. */
 
943
static void
 
944
rr_screen_weak_notify_cb (gpointer data, GObject *where_the_object_was)
 
945
{
 
946
    GdkScreen *screen = GDK_SCREEN (data);
 
947
 
 
948
    g_object_set_data (G_OBJECT (screen), "GnomeRRScreen", NULL);
 
949
}
 
950
 
 
951
/**
 
952
 * gnome_rr_screen_new:
 
953
 * @screen: the #GdkScreen on which to operate
 
954
 * @error: will be set if XRandR is not supported
 
955
 *
 
956
 * Creates a unique #GnomeRRScreen instance for the specified @screen.
 
957
 *
 
958
 * Returns: a unique #GnomeRRScreen instance, specific to the @screen, or NULL
 
959
 * if this could not be created, for instance if the driver does not support
 
960
 * Xrandr 1.2.  Each #GdkScreen thus has a single instance of #GnomeRRScreen.
 
961
 */
 
962
GnomeRRScreen *
 
963
gnome_rr_screen_new (GdkScreen *screen,
 
964
                     GError **error)
 
965
{
 
966
    GnomeRRScreen *rr_screen;
 
967
 
 
968
    g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
 
969
    g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
970
 
 
971
    rr_screen = g_object_get_data (G_OBJECT (screen), "GnomeRRScreen");
 
972
    if (rr_screen)
 
973
        g_object_ref (rr_screen);
 
974
    else {
 
975
        rr_screen = g_initable_new (GNOME_TYPE_RR_SCREEN, NULL, error, "gdk-screen", screen, NULL);
 
976
        if (rr_screen) {
 
977
            g_object_set_data (G_OBJECT (screen), "GnomeRRScreen", rr_screen);
 
978
            g_object_weak_ref (G_OBJECT (rr_screen), rr_screen_weak_notify_cb, screen);
 
979
        }
 
980
    }
 
981
 
 
982
    return rr_screen;
 
983
}
 
984
 
 
985
void
 
986
gnome_rr_screen_set_size (GnomeRRScreen *screen,
 
987
                          int         width,
 
988
                          int       height,
 
989
                          int       mm_width,
 
990
                          int       mm_height)
 
991
{
 
992
    g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
 
993
 
 
994
    gdk_error_trap_push ();
 
995
    XRRSetScreenSize (screen->priv->xdisplay, screen->priv->xroot,
 
996
                      width, height, mm_width, mm_height);
 
997
    gdk_error_trap_pop_ignored ();
 
998
}
 
999
 
 
1000
/**
 
1001
 * gnome_rr_screen_get_ranges:
 
1002
 * @screen: a #GnomeRRScreen
 
1003
 * @min_width: (out): the minimum width
 
1004
 * @max_width: (out): the maximum width
 
1005
 * @min_height: (out): the minimum height
 
1006
 * @max_height: (out): the maximum height
 
1007
 *
 
1008
 * Get the ranges of the screen
 
1009
 */
 
1010
void
 
1011
gnome_rr_screen_get_ranges (GnomeRRScreen *screen,
 
1012
                            int           *min_width,
 
1013
                            int           *max_width,
 
1014
                            int           *min_height,
 
1015
                            int           *max_height)
 
1016
{
 
1017
    GnomeRRScreenPrivate *priv;
 
1018
 
 
1019
    g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
 
1020
 
 
1021
    priv = screen->priv;
 
1022
    
 
1023
    if (min_width)
 
1024
        *min_width = priv->info->min_width;
 
1025
    
 
1026
    if (max_width)
 
1027
        *max_width = priv->info->max_width;
 
1028
    
 
1029
    if (min_height)
 
1030
        *min_height = priv->info->min_height;
 
1031
    
 
1032
    if (max_height)
 
1033
        *max_height = priv->info->max_height;
 
1034
}
 
1035
 
 
1036
/**
 
1037
 * gnome_rr_screen_get_timestamps:
 
1038
 * @screen: a #GnomeRRScreen
 
1039
 * @change_timestamp_ret: (out): Location in which to store the timestamp at which the RANDR configuration was last changed
 
1040
 * @config_timestamp_ret: (out): Location in which to store the timestamp at which the RANDR configuration was last obtained
 
1041
 *
 
1042
 * Queries the two timestamps that the X RANDR extension maintains.  The X
 
1043
 * server will prevent change requests for stale configurations, those whose
 
1044
 * timestamp is not equal to that of the latest request for configuration.  The
 
1045
 * X server will also prevent change requests that have an older timestamp to
 
1046
 * the latest change request.
 
1047
 */
 
1048
void
 
1049
gnome_rr_screen_get_timestamps (GnomeRRScreen *screen,
 
1050
                                guint32       *change_timestamp_ret,
 
1051
                                guint32       *config_timestamp_ret)
 
1052
{
 
1053
    GnomeRRScreenPrivate *priv;
 
1054
 
 
1055
    g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
 
1056
 
 
1057
    priv = screen->priv;
 
1058
 
 
1059
    if (change_timestamp_ret)
 
1060
        *change_timestamp_ret = priv->info->resources->timestamp;
 
1061
 
 
1062
    if (config_timestamp_ret)
 
1063
        *config_timestamp_ret = priv->info->resources->configTimestamp;
 
1064
}
 
1065
 
 
1066
static gboolean
 
1067
force_timestamp_update (GnomeRRScreen *screen)
 
1068
{
 
1069
    GnomeRRScreenPrivate *priv = screen->priv;
 
1070
    GnomeRRCrtc *crtc;
 
1071
    XRRCrtcInfo *current_info;
 
1072
    Status status;
 
1073
    gboolean timestamp_updated;
 
1074
 
 
1075
    timestamp_updated = FALSE;
 
1076
 
 
1077
    crtc = priv->info->crtcs[0];
 
1078
 
 
1079
    if (crtc == NULL)
 
1080
        goto out;
 
1081
 
 
1082
    current_info = XRRGetCrtcInfo (priv->xdisplay,
 
1083
                                   priv->info->resources,
 
1084
                                   crtc->id);
 
1085
 
 
1086
    if (current_info == NULL)
 
1087
        goto out;
 
1088
 
 
1089
    gdk_error_trap_push ();
 
1090
    status = XRRSetCrtcConfig (priv->xdisplay,
 
1091
                               priv->info->resources,
 
1092
                               crtc->id,
 
1093
                               current_info->timestamp,
 
1094
                               current_info->x,
 
1095
                               current_info->y,
 
1096
                               current_info->mode,
 
1097
                               current_info->rotation,
 
1098
                               current_info->outputs,
 
1099
                               current_info->noutput);
 
1100
 
 
1101
    XRRFreeCrtcInfo (current_info);
 
1102
 
 
1103
    gdk_flush ();
 
1104
    if (gdk_error_trap_pop ())
 
1105
        goto out;
 
1106
 
 
1107
    if (status == RRSetConfigSuccess)
 
1108
        timestamp_updated = TRUE;
 
1109
out:
 
1110
    return timestamp_updated;
 
1111
}
 
1112
 
 
1113
/**
 
1114
 * gnome_rr_screen_refresh:
 
1115
 * @screen: a #GnomeRRScreen
 
1116
 * @error: location to store error, or %NULL
 
1117
 *
 
1118
 * Refreshes the screen configuration, and calls the screen's callback if it
 
1119
 * exists and if the screen's configuration changed.
 
1120
 *
 
1121
 * Return value: TRUE if the screen's configuration changed; otherwise, the
 
1122
 * function returns FALSE and a NULL error if the configuration didn't change,
 
1123
 * or FALSE and a non-NULL error if there was an error while refreshing the
 
1124
 * configuration.
 
1125
 */
 
1126
gboolean
 
1127
gnome_rr_screen_refresh (GnomeRRScreen *screen,
 
1128
                         GError       **error)
 
1129
{
 
1130
    gboolean refreshed;
 
1131
 
 
1132
    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1133
 
 
1134
    gdk_x11_display_grab (gdk_screen_get_display (screen->priv->gdk_screen));
 
1135
 
 
1136
    refreshed = screen_update (screen, FALSE, TRUE, error);
 
1137
    force_timestamp_update (screen); /* this is to keep other clients from thinking that the X server re-detected things by itself - bgo#621046 */
 
1138
 
 
1139
    gdk_x11_display_ungrab (gdk_screen_get_display (screen->priv->gdk_screen));
 
1140
 
 
1141
    return refreshed;
 
1142
}
 
1143
 
 
1144
/**
 
1145
 * gnome_rr_screen_get_dpms_mode:
 
1146
 * @mode: (out): The current #GnomeRRDpmsMode of this screen
 
1147
 **/
 
1148
gboolean
 
1149
gnome_rr_screen_get_dpms_mode (GnomeRRScreen *screen,
 
1150
                               GnomeRRDpmsMode *mode,
 
1151
                               GError **error)
 
1152
{
 
1153
    BOOL enabled = FALSE;
 
1154
    CARD16 state;
 
1155
    gboolean ret = FALSE;
 
1156
 
 
1157
    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1158
    g_return_val_if_fail (mode != NULL, FALSE);
 
1159
 
 
1160
    if (!screen->priv->dpms_capable) {
 
1161
        g_set_error_literal (error,
 
1162
                             GNOME_RR_ERROR,
 
1163
                             GNOME_RR_ERROR_NO_DPMS_EXTENSION,
 
1164
                             "Display is not DPMS capable");
 
1165
        goto out;
 
1166
    }
 
1167
 
 
1168
    if (!DPMSInfo (screen->priv->xdisplay,
 
1169
                   &state,
 
1170
                   &enabled)) {
 
1171
        g_set_error_literal (error,
 
1172
                             GNOME_RR_ERROR,
 
1173
                             GNOME_RR_ERROR_UNKNOWN,
 
1174
                             "Unable to get DPMS state");
 
1175
        goto out;
 
1176
    }
 
1177
 
 
1178
    /* DPMS not enabled is a valid mode */
 
1179
    if (!enabled) {
 
1180
        *mode = GNOME_RR_DPMS_DISABLED;
 
1181
        ret = TRUE;
 
1182
        goto out;
 
1183
    }
 
1184
 
 
1185
    switch (state) {
 
1186
    case DPMSModeOn:
 
1187
        *mode = GNOME_RR_DPMS_ON;
 
1188
        break;
 
1189
    case DPMSModeStandby:
 
1190
        *mode = GNOME_RR_DPMS_STANDBY;
 
1191
        break;
 
1192
    case DPMSModeSuspend:
 
1193
        *mode = GNOME_RR_DPMS_SUSPEND;
 
1194
        break;
 
1195
    case DPMSModeOff:
 
1196
        *mode = GNOME_RR_DPMS_OFF;
 
1197
        break;
 
1198
    default:
 
1199
        g_assert_not_reached ();
 
1200
        break;
 
1201
    }
 
1202
    ret = TRUE;
 
1203
out:
 
1204
    return ret;
 
1205
}
 
1206
 
 
1207
/**
 
1208
 * gnome_rr_screen_clear_dpms_timeouts:
 
1209
 **/
 
1210
static gboolean
 
1211
gnome_rr_screen_clear_dpms_timeouts (GnomeRRScreen *screen,
 
1212
                                     GError **error)
 
1213
{
 
1214
    gdk_error_trap_push ();
 
1215
    /* DPMSSetTimeouts() return value is often a lie, so ignore it */
 
1216
    DPMSSetTimeouts (screen->priv->xdisplay, 0, 0, 0);
 
1217
    if (gdk_error_trap_pop ()) {
 
1218
        g_set_error_literal (error,
 
1219
                             GNOME_RR_ERROR,
 
1220
                             GNOME_RR_ERROR_UNKNOWN,
 
1221
                             "Could not set DPMS timeouts");
 
1222
        return FALSE;
 
1223
    }
 
1224
    return TRUE;
 
1225
}
 
1226
 
 
1227
/**
 
1228
 * gnome_rr_screen_set_dpms_mode:
 
1229
 *
 
1230
 * This method also disables the DPMS timeouts.
 
1231
 **/
 
1232
gboolean
 
1233
gnome_rr_screen_set_dpms_mode (GnomeRRScreen *screen,
 
1234
                               GnomeRRDpmsMode mode,
 
1235
                               GError **error)
 
1236
{
 
1237
    CARD16 state = 0;
 
1238
    gboolean ret;
 
1239
    GnomeRRDpmsMode current_mode;
 
1240
 
 
1241
    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1242
 
 
1243
    /* set, if the new mode is different */
 
1244
    ret = gnome_rr_screen_get_dpms_mode (screen, &current_mode, error);
 
1245
    if (!ret)
 
1246
        goto out;
 
1247
    if (current_mode == mode) {
 
1248
        ret = gnome_rr_screen_clear_dpms_timeouts (screen, error);
 
1249
        goto out;
 
1250
    }
 
1251
 
 
1252
    switch (mode) {
 
1253
    case GNOME_RR_DPMS_ON:
 
1254
        state = DPMSModeOn;
 
1255
        break;
 
1256
    case GNOME_RR_DPMS_STANDBY:
 
1257
        state = DPMSModeStandby;
 
1258
        break;
 
1259
    case GNOME_RR_DPMS_SUSPEND:
 
1260
        state = DPMSModeSuspend;
 
1261
        break;
 
1262
    case GNOME_RR_DPMS_OFF:
 
1263
        state = DPMSModeOff;
 
1264
        break;
 
1265
    default:
 
1266
        g_assert_not_reached ();
 
1267
        break;
 
1268
    }
 
1269
 
 
1270
    gdk_error_trap_push ();
 
1271
    /* DPMSForceLevel() return value is often a lie, so ignore it */
 
1272
    DPMSForceLevel (screen->priv->xdisplay, state);
 
1273
    XSync (screen->priv->xdisplay, False);
 
1274
    if (gdk_error_trap_pop ()) {
 
1275
        ret = FALSE;
 
1276
        g_set_error_literal (error,
 
1277
                             GNOME_RR_ERROR,
 
1278
                             GNOME_RR_ERROR_UNKNOWN,
 
1279
                             "Could not change DPMS mode");
 
1280
        goto out;
 
1281
    }
 
1282
 
 
1283
    ret = gnome_rr_screen_clear_dpms_timeouts (screen, error);
 
1284
    if (!ret)
 
1285
        goto out;
 
1286
out:
 
1287
    return ret;
 
1288
}
 
1289
 
 
1290
/**
 
1291
 * gnome_rr_screen_list_modes:
 
1292
 *
 
1293
 * List available XRandR modes
 
1294
 *
 
1295
 * Returns: (array zero-terminated=1) (transfer none):
 
1296
 */
 
1297
GnomeRRMode **
 
1298
gnome_rr_screen_list_modes (GnomeRRScreen *screen)
 
1299
{
 
1300
    g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
 
1301
    g_return_val_if_fail (screen->priv->info != NULL, NULL);
 
1302
    
 
1303
    return screen->priv->info->modes;
 
1304
}
 
1305
 
 
1306
/**
 
1307
 * gnome_rr_screen_list_clone_modes:
 
1308
 *
 
1309
 * List available XRandR clone modes
 
1310
 *
 
1311
 * Returns: (array zero-terminated=1) (transfer none):
 
1312
 */
 
1313
GnomeRRMode **
 
1314
gnome_rr_screen_list_clone_modes   (GnomeRRScreen *screen)
 
1315
{
 
1316
    g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
 
1317
    g_return_val_if_fail (screen->priv->info != NULL, NULL);
 
1318
 
 
1319
    return screen->priv->info->clone_modes;
 
1320
}
 
1321
 
 
1322
/**
 
1323
 * gnome_rr_screen_list_crtcs:
 
1324
 *
 
1325
 * List all CRTCs
 
1326
 *
 
1327
 * Returns: (array zero-terminated=1) (transfer none):
 
1328
 */
 
1329
GnomeRRCrtc **
 
1330
gnome_rr_screen_list_crtcs (GnomeRRScreen *screen)
 
1331
{
 
1332
    g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
 
1333
    g_return_val_if_fail (screen->priv->info != NULL, NULL);
 
1334
    
 
1335
    return screen->priv->info->crtcs;
 
1336
}
 
1337
 
 
1338
/**
 
1339
 * gnome_rr_screen_list_outputs:
 
1340
 *
 
1341
 * List all outputs
 
1342
 *
 
1343
 * Returns: (array zero-terminated=1) (transfer none):
 
1344
 */
 
1345
GnomeRROutput **
 
1346
gnome_rr_screen_list_outputs (GnomeRRScreen *screen)
 
1347
{
 
1348
    g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
 
1349
    g_return_val_if_fail (screen->priv->info != NULL, NULL);
 
1350
    
 
1351
    return screen->priv->info->outputs;
 
1352
}
 
1353
 
 
1354
/**
 
1355
 * gnome_rr_screen_get_crtc_by_id:
 
1356
 *
 
1357
 * Returns: (transfer none): the CRTC identified by @id
 
1358
 */
 
1359
GnomeRRCrtc *
 
1360
gnome_rr_screen_get_crtc_by_id (GnomeRRScreen *screen,
 
1361
                                guint32        id)
 
1362
{
 
1363
    GnomeRRCrtc **crtcs;
 
1364
    int i;
 
1365
    
 
1366
    g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
 
1367
    g_return_val_if_fail (screen->priv->info != NULL, NULL);
 
1368
 
 
1369
    crtcs = screen->priv->info->crtcs;
 
1370
    
 
1371
    for (i = 0; crtcs[i] != NULL; ++i)
 
1372
    {
 
1373
        if (crtcs[i]->id == id)
 
1374
            return crtcs[i];
 
1375
    }
 
1376
    
 
1377
    return NULL;
 
1378
}
 
1379
 
 
1380
/**
 
1381
 * gnome_rr_screen_get_output_by_id:
 
1382
 *
 
1383
 * Returns: (transfer none): the output identified by @id
 
1384
 */
 
1385
GnomeRROutput *
 
1386
gnome_rr_screen_get_output_by_id (GnomeRRScreen *screen,
 
1387
                                  guint32        id)
 
1388
{
 
1389
    GnomeRROutput **outputs;
 
1390
    int i;
 
1391
    
 
1392
    g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
 
1393
    g_return_val_if_fail (screen->priv->info != NULL, NULL);
 
1394
 
 
1395
    outputs = screen->priv->info->outputs;
 
1396
 
 
1397
    for (i = 0; outputs[i] != NULL; ++i)
 
1398
    {
 
1399
        if (outputs[i]->id == id)
 
1400
            return outputs[i];
 
1401
    }
 
1402
    
 
1403
    return NULL;
 
1404
}
 
1405
 
 
1406
/* GnomeRROutput */
 
1407
static GnomeRROutput *
 
1408
output_new (ScreenInfo *info, RROutput id)
 
1409
{
 
1410
    GnomeRROutput *output = g_slice_new0 (GnomeRROutput);
 
1411
    
 
1412
    output->id = id;
 
1413
    output->info = info;
 
1414
    
 
1415
    return output;
 
1416
}
 
1417
 
 
1418
static guint8 *
 
1419
get_property (Display *dpy,
 
1420
              RROutput output,
 
1421
              Atom atom,
 
1422
              gsize *len)
 
1423
{
 
1424
    unsigned char *prop;
 
1425
    int actual_format;
 
1426
    unsigned long nitems, bytes_after;
 
1427
    Atom actual_type;
 
1428
    guint8 *result;
 
1429
    
 
1430
    XRRGetOutputProperty (dpy, output, atom,
 
1431
                          0, 100, False, False,
 
1432
                          AnyPropertyType,
 
1433
                          &actual_type, &actual_format,
 
1434
                          &nitems, &bytes_after, &prop);
 
1435
    
 
1436
    if (actual_type == XA_INTEGER && actual_format == 8)
 
1437
    {
 
1438
        result = g_memdup (prop, nitems);
 
1439
        if (len)
 
1440
            *len = nitems;
 
1441
    }
 
1442
    else
 
1443
    {
 
1444
        result = NULL;
 
1445
    }
 
1446
    
 
1447
    XFree (prop);
 
1448
    
 
1449
    return result;
 
1450
}
 
1451
 
 
1452
static guint8 *
 
1453
read_edid_data (GnomeRROutput *output, gsize *len)
 
1454
{
 
1455
    Atom edid_atom;
 
1456
    guint8 *result;
 
1457
 
 
1458
    edid_atom = XInternAtom (DISPLAY (output), "EDID", FALSE);
 
1459
    result = get_property (DISPLAY (output),
 
1460
                           output->id, edid_atom, len);
 
1461
 
 
1462
    if (!result)
 
1463
    {
 
1464
        edid_atom = XInternAtom (DISPLAY (output), "EDID_DATA", FALSE);
 
1465
        result = get_property (DISPLAY (output),
 
1466
                               output->id, edid_atom, len);
 
1467
    }
 
1468
 
 
1469
    if (!result)
 
1470
    {
 
1471
        edid_atom = XInternAtom (DISPLAY (output), "XFree86_DDC_EDID1_RAWDATA", FALSE);
 
1472
        result = get_property (DISPLAY (output),
 
1473
                               output->id, edid_atom, len);
 
1474
    }
 
1475
 
 
1476
    if (result)
 
1477
    {
 
1478
        if (*len % 128 == 0)
 
1479
            return result;
 
1480
        else
 
1481
            g_free (result);
 
1482
    }
 
1483
    
 
1484
    return NULL;
 
1485
}
 
1486
 
 
1487
static char *
 
1488
get_connector_type_string (GnomeRROutput *output)
 
1489
{
 
1490
    char *result;
 
1491
    unsigned char *prop;
 
1492
    int actual_format;
 
1493
    unsigned long nitems, bytes_after;
 
1494
    Atom actual_type;
 
1495
    Atom connector_type;
 
1496
    char *connector_type_str;
 
1497
 
 
1498
    result = NULL;
 
1499
 
 
1500
    if (XRRGetOutputProperty (DISPLAY (output), output->id, output->info->screen->priv->connector_type_atom,
 
1501
                              0, 100, False, False,
 
1502
                              AnyPropertyType,
 
1503
                              &actual_type, &actual_format,
 
1504
                              &nitems, &bytes_after, &prop) != Success)
 
1505
        return NULL;
 
1506
 
 
1507
    if (!(actual_type == XA_ATOM && actual_format == 32 && nitems == 1))
 
1508
        goto out;
 
1509
 
 
1510
    connector_type = *((Atom *) prop);
 
1511
 
 
1512
    connector_type_str = XGetAtomName (DISPLAY (output), connector_type);
 
1513
    if (connector_type_str) {
 
1514
        result = g_strdup (connector_type_str); /* so the caller can g_free() it */
 
1515
        XFree (connector_type_str);
 
1516
    }
 
1517
 
 
1518
out:
 
1519
 
 
1520
    XFree (prop);
 
1521
 
 
1522
    return result;
 
1523
}
 
1524
 
 
1525
static void
 
1526
update_brightness_limits (GnomeRROutput *output)
 
1527
{
 
1528
    gint rc;
 
1529
    Atom atom;
 
1530
    XRRPropertyInfo *info;
 
1531
 
 
1532
    gdk_error_trap_push ();
 
1533
    atom = XInternAtom (DISPLAY (output), "BACKLIGHT", FALSE);
 
1534
    info = XRRQueryOutputProperty (DISPLAY (output), output->id, atom);
 
1535
    rc = gdk_error_trap_pop ();
 
1536
    if (rc != Success)
 
1537
    {
 
1538
        if (rc != BadName)
 
1539
          g_warning ("could not get output property for %s, rc: %i",
 
1540
                     output->name, rc);
 
1541
        goto out;
 
1542
    }
 
1543
    if (info == NULL)
 
1544
    {
 
1545
        g_warning ("could not get output property for %s",
 
1546
                   output->name);
 
1547
        goto out;
 
1548
    }
 
1549
    if (!info->range || info->num_values != 2)
 
1550
    {
 
1551
        g_debug ("backlight %s was not range", output->name);
 
1552
        goto out;
 
1553
    }
 
1554
    output->backlight_min = info->values[0];
 
1555
    output->backlight_max = info->values[1];
 
1556
out:
 
1557
    if (info != NULL)
 
1558
    {
 
1559
        XFree (info);
 
1560
    }
 
1561
}
 
1562
 
 
1563
static gboolean
 
1564
output_initialize (GnomeRROutput *output, XRRScreenResources *res, GError **error)
 
1565
{
 
1566
    XRROutputInfo *info = XRRGetOutputInfo (
 
1567
        DISPLAY (output), res, output->id);
 
1568
    GPtrArray *a;
 
1569
    int i;
 
1570
    
 
1571
#if 0
 
1572
    g_print ("Output %lx Timestamp: %u\n", output->id, (guint32)info->timestamp);
 
1573
#endif
 
1574
    
 
1575
    if (!info || !output->info)
 
1576
    {
 
1577
        /* FIXME: see the comment in crtc_initialize() */
 
1578
        /* Translators: here, an "output" is a video output */
 
1579
        g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
 
1580
                     _("could not get information about output %d"),
 
1581
                     (int) output->id);
 
1582
        return FALSE;
 
1583
    }
 
1584
    
 
1585
    output->name = g_strdup (info->name); /* FIXME: what is nameLen used for? */
 
1586
    output->display_name = NULL; /* set first time the getter is used */
 
1587
    output->current_crtc = crtc_by_id (output->info, info->crtc);
 
1588
    output->width_mm = info->mm_width;
 
1589
    output->height_mm = info->mm_height;
 
1590
    output->connected = (info->connection == RR_Connected);
 
1591
    output->connector_type = get_connector_type_string (output);
 
1592
 
 
1593
    /* Possible crtcs */
 
1594
    a = g_ptr_array_new ();
 
1595
    
 
1596
    for (i = 0; i < info->ncrtc; ++i)
 
1597
    {
 
1598
        GnomeRRCrtc *crtc = crtc_by_id (output->info, info->crtcs[i]);
 
1599
        
 
1600
        if (crtc)
 
1601
            g_ptr_array_add (a, crtc);
 
1602
    }
 
1603
    g_ptr_array_add (a, NULL);
 
1604
    output->possible_crtcs = (GnomeRRCrtc **)g_ptr_array_free (a, FALSE);
 
1605
    
 
1606
    /* Clones */
 
1607
    a = g_ptr_array_new ();
 
1608
    for (i = 0; i < info->nclone; ++i)
 
1609
    {
 
1610
        GnomeRROutput *gnome_rr_output = gnome_rr_output_by_id (output->info, info->clones[i]);
 
1611
        
 
1612
        if (gnome_rr_output)
 
1613
            g_ptr_array_add (a, gnome_rr_output);
 
1614
    }
 
1615
    g_ptr_array_add (a, NULL);
 
1616
    output->clones = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
 
1617
    
 
1618
    /* Modes */
 
1619
    a = g_ptr_array_new ();
 
1620
    for (i = 0; i < info->nmode; ++i)
 
1621
    {
 
1622
        GnomeRRMode *mode = mode_by_id (output->info, info->modes[i]);
 
1623
        
 
1624
        if (mode)
 
1625
            g_ptr_array_add (a, mode);
 
1626
    }
 
1627
    g_ptr_array_add (a, NULL);
 
1628
    output->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
 
1629
    
 
1630
    output->n_preferred = info->npreferred;
 
1631
    
 
1632
    /* Edid data */
 
1633
    output->edid_data = read_edid_data (output, &output->edid_size);
 
1634
 
 
1635
    /* brightness data */
 
1636
    if (output->connected)
 
1637
        update_brightness_limits (output);
 
1638
 
 
1639
    XRRFreeOutputInfo (info);
 
1640
 
 
1641
    return TRUE;
 
1642
}
 
1643
 
 
1644
static GnomeRROutput*
 
1645
output_copy (const GnomeRROutput *from)
 
1646
{
 
1647
    GPtrArray *array;
 
1648
    GnomeRRCrtc **p_crtc;
 
1649
    GnomeRROutput **p_output;
 
1650
    GnomeRRMode **p_mode;
 
1651
    GnomeRROutput *output = g_slice_new0 (GnomeRROutput);
 
1652
 
 
1653
    output->id = from->id;
 
1654
    output->info = from->info;
 
1655
    output->name = g_strdup (from->name);
 
1656
    output->current_crtc = from->current_crtc;
 
1657
    output->width_mm = from->width_mm;
 
1658
    output->height_mm = from->height_mm;
 
1659
    output->connected = from->connected;
 
1660
    output->n_preferred = from->n_preferred;
 
1661
    output->connector_type = g_strdup (from->connector_type);
 
1662
    output->backlight_min = -1;
 
1663
    output->backlight_max = -1;
 
1664
 
 
1665
    array = g_ptr_array_new ();
 
1666
    for (p_crtc = from->possible_crtcs; *p_crtc != NULL; p_crtc++)
 
1667
    {
 
1668
        g_ptr_array_add (array, *p_crtc);
 
1669
    }
 
1670
    output->possible_crtcs = (GnomeRRCrtc**) g_ptr_array_free (array, FALSE);
 
1671
 
 
1672
    array = g_ptr_array_new ();
 
1673
    for (p_output = from->clones; *p_output != NULL; p_output++)
 
1674
    {
 
1675
        g_ptr_array_add (array, *p_output);
 
1676
    }
 
1677
    output->clones = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
 
1678
 
 
1679
    array = g_ptr_array_new ();
 
1680
    for (p_mode = from->modes; *p_mode != NULL; p_mode++)
 
1681
    {
 
1682
        g_ptr_array_add (array, *p_mode);
 
1683
    }
 
1684
    output->modes = (GnomeRRMode**) g_ptr_array_free (array, FALSE);
 
1685
 
 
1686
    output->edid_size = from->edid_size;
 
1687
    output->edid_data = g_memdup (from->edid_data, from->edid_size);
 
1688
 
 
1689
    return output;
 
1690
}
 
1691
 
 
1692
static void
 
1693
output_free (GnomeRROutput *output)
 
1694
{
 
1695
    g_free (output->clones);
 
1696
    g_free (output->modes);
 
1697
    g_free (output->possible_crtcs);
 
1698
    g_free (output->edid_data);
 
1699
    g_free (output->name);
 
1700
    g_free (output->display_name);
 
1701
    g_free (output->connector_type);
 
1702
    g_slice_free (GnomeRROutput, output);
 
1703
}
 
1704
 
 
1705
guint32
 
1706
gnome_rr_output_get_id (GnomeRROutput *output)
 
1707
{
 
1708
    g_assert(output != NULL);
 
1709
    
 
1710
    return output->id;
 
1711
}
 
1712
 
 
1713
const guint8 *
 
1714
gnome_rr_output_get_edid_data (GnomeRROutput *output, gsize *size)
 
1715
{
 
1716
    g_return_val_if_fail (output != NULL, NULL);
 
1717
    if (size)
 
1718
        *size = output->edid_size;
 
1719
    return output->edid_data;
 
1720
}
 
1721
 
 
1722
/**
 
1723
 * gnome_rr_output_get_ids_from_edid:
 
1724
 * @output: a #GnomeRROutput
 
1725
 * @vendor: (out) (allow-none):
 
1726
 * @product: (out) (allow-none):
 
1727
 * @serial: (out) (allow-none):
 
1728
 */
 
1729
gboolean
 
1730
gnome_rr_output_get_ids_from_edid (GnomeRROutput         *output,
 
1731
                                   char                 **vendor,
 
1732
                                   int                   *product,
 
1733
                                   int                   *serial)
 
1734
{
 
1735
    MonitorInfo *info;
 
1736
 
 
1737
    g_return_val_if_fail (output != NULL, FALSE);
 
1738
 
 
1739
    if (!output->edid_data)
 
1740
        return FALSE;
 
1741
    info = decode_edid (output->edid_data);
 
1742
    if (!info)
 
1743
        return FALSE;
 
1744
    if (vendor)
 
1745
        *vendor = g_memdup (info->manufacturer_code, 4);
 
1746
    if (product)
 
1747
        *product = info->product_code;
 
1748
    if (serial)
 
1749
        *serial = info->serial_number;
 
1750
 
 
1751
    g_free (info);
 
1752
 
 
1753
    return TRUE;
 
1754
 
 
1755
}
 
1756
 
 
1757
static void
 
1758
ensure_display_name (GnomeRROutput *output)
 
1759
{
 
1760
    if (output->display_name != NULL)
 
1761
        return;
 
1762
 
 
1763
    if (gnome_rr_output_is_laptop (output))
 
1764
        output->display_name = g_strdup (_("Built-in Display"));
 
1765
 
 
1766
    if (output->display_name == NULL
 
1767
        && output->edid_data != NULL) {
 
1768
        MonitorInfo *info;
 
1769
 
 
1770
        info = decode_edid (output->edid_data);
 
1771
        if (info != NULL)
 
1772
            output->display_name = make_display_name (info);
 
1773
 
 
1774
        g_free (info);
 
1775
    }
 
1776
 
 
1777
    if (output->display_name == NULL) {
 
1778
        char *inches;
 
1779
        inches = make_display_size_string (output->width_mm, output->height_mm);
 
1780
        if (inches != NULL) {
 
1781
            /* Translators: %s is the size of the monitor in inches */
 
1782
            output->display_name = g_strdup_printf (_("%s Display"), inches);
 
1783
        }
 
1784
        g_free (inches);
 
1785
    }
 
1786
 
 
1787
    /* last chance on the stairway */
 
1788
    if (output->display_name == NULL) {
 
1789
      output->display_name = g_strdup (_("Unknown Display"));
 
1790
    }
 
1791
}
 
1792
 
 
1793
const char *
 
1794
gnome_rr_output_get_display_name (GnomeRROutput *output)
 
1795
{
 
1796
    g_return_val_if_fail (output != NULL, NULL);
 
1797
 
 
1798
    ensure_display_name (output);
 
1799
 
 
1800
    return output->display_name;
 
1801
}
 
1802
 
 
1803
/**
 
1804
 * gnome_rr_output_get_backlight_min:
 
1805
 *
 
1806
 * Returns: The mimimum backlight value, or -1 if not supported
 
1807
 */
 
1808
gint
 
1809
gnome_rr_output_get_backlight_min (GnomeRROutput *output)
 
1810
{
 
1811
    g_return_val_if_fail (output != NULL, -1);
 
1812
    return output->backlight_min;
 
1813
}
 
1814
 
 
1815
/**
 
1816
 * gnome_rr_output_get_backlight_max:
 
1817
 *
 
1818
 * Returns: The maximum backlight value, or -1 if not supported
 
1819
 */
 
1820
gint
 
1821
gnome_rr_output_get_backlight_max (GnomeRROutput *output)
 
1822
{
 
1823
    g_return_val_if_fail (output != NULL, -1);
 
1824
    return output->backlight_max;
 
1825
}
 
1826
 
 
1827
/**
 
1828
 * gnome_rr_output_get_backlight:
 
1829
 *
 
1830
 * Returns: The currently set backlight brightness
 
1831
 */
 
1832
gint
 
1833
gnome_rr_output_get_backlight (GnomeRROutput *output, GError **error)
 
1834
{
 
1835
    guint now = -1;
 
1836
    unsigned long nitems;
 
1837
    unsigned long bytes_after;
 
1838
    guint *prop;
 
1839
    Atom atom;
 
1840
    Atom actual_type;
 
1841
    int actual_format;
 
1842
    gint retval;
 
1843
 
 
1844
    g_return_val_if_fail (output != NULL, -1);
 
1845
 
 
1846
    gdk_error_trap_push ();
 
1847
    atom = XInternAtom (DISPLAY (output), "BACKLIGHT", FALSE);
 
1848
    retval = XRRGetOutputProperty (DISPLAY (output), output->id, atom,
 
1849
                                   0, 4, False, False, None,
 
1850
                                   &actual_type, &actual_format,
 
1851
                                   &nitems, &bytes_after, ((unsigned char **)&prop));
 
1852
    gdk_flush ();
 
1853
    if (gdk_error_trap_pop ())
 
1854
    {
 
1855
        g_set_error_literal (error,
 
1856
                             GNOME_RR_ERROR,
 
1857
                             GNOME_RR_ERROR_UNKNOWN,
 
1858
                             "unhandled X error while getting the range of backlight values");
 
1859
        goto out;
 
1860
    }
 
1861
 
 
1862
    if (retval != Success) {
 
1863
        g_set_error_literal (error,
 
1864
                             GNOME_RR_ERROR,
 
1865
                             GNOME_RR_ERROR_RANDR_ERROR,
 
1866
                             "could not get the range of backlight values");
 
1867
        goto out;
 
1868
    }
 
1869
    if (actual_type == XA_INTEGER &&
 
1870
        nitems == 1 &&
 
1871
        actual_format == 32)
 
1872
    {
 
1873
        memcpy (&now, prop, sizeof (guint));
 
1874
    }
 
1875
    else
 
1876
    {
 
1877
        g_set_error (error,
 
1878
                     GNOME_RR_ERROR,
 
1879
                     GNOME_RR_ERROR_RANDR_ERROR,
 
1880
                     "failed to get correct property type, got %lu,%i",
 
1881
                     nitems, actual_format);
 
1882
    }
 
1883
out:
 
1884
    XFree (prop);
 
1885
    return now;
 
1886
}
 
1887
 
 
1888
/**
 
1889
 * gnome_rr_output_set_backlight:
 
1890
 * @value: the absolute value which is min >= this <= max
 
1891
 *
 
1892
 * Returns: %TRUE for success
 
1893
 */
 
1894
gboolean
 
1895
gnome_rr_output_set_backlight (GnomeRROutput *output, gint value, GError **error)
 
1896
{
 
1897
    gboolean ret = FALSE;
 
1898
    Atom atom;
 
1899
 
 
1900
    g_return_val_if_fail (output != NULL, FALSE);
 
1901
 
 
1902
    /* check this is sane */
 
1903
    if (value < output->backlight_min ||
 
1904
        value > output->backlight_max)
 
1905
    {
 
1906
        g_set_error (error,
 
1907
                     GNOME_RR_ERROR,
 
1908
                     GNOME_RR_ERROR_BOUNDS_ERROR,
 
1909
                     "out of brightness range: %i, has to be %i -> %i",
 
1910
                     value,
 
1911
                     output->backlight_max, output->backlight_min);
 
1912
        goto out;
 
1913
    }
 
1914
 
 
1915
    /* don't abort on error */
 
1916
    gdk_error_trap_push ();
 
1917
    atom = XInternAtom (DISPLAY (output), "BACKLIGHT", FALSE);
 
1918
    XRRChangeOutputProperty (DISPLAY (output), output->id, atom,
 
1919
                             XA_INTEGER, 32, PropModeReplace,
 
1920
                             (unsigned char *) &value, 1);
 
1921
    if (gdk_error_trap_pop ())
 
1922
    {
 
1923
        g_set_error_literal (error,
 
1924
                             GNOME_RR_ERROR,
 
1925
                             GNOME_RR_ERROR_UNKNOWN,
 
1926
                             "unhandled X error while setting the backlight values");
 
1927
        goto out;
 
1928
    }
 
1929
 
 
1930
    /* we assume this succeeded as there's no return value */
 
1931
    ret = TRUE;
 
1932
out:
 
1933
    return ret;
 
1934
}
 
1935
 
 
1936
/**
 
1937
 * gnome_rr_screen_get_output_by_name:
 
1938
 *
 
1939
 * Returns: (transfer none): the output identified by @name
 
1940
 */
 
1941
GnomeRROutput *
 
1942
gnome_rr_screen_get_output_by_name (GnomeRRScreen *screen,
 
1943
                                    const char    *name)
 
1944
{
 
1945
    int i;
 
1946
    
 
1947
    g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
 
1948
    g_return_val_if_fail (screen->priv->info != NULL, NULL);
 
1949
    
 
1950
    for (i = 0; screen->priv->info->outputs[i] != NULL; ++i)
 
1951
    {
 
1952
        GnomeRROutput *output = screen->priv->info->outputs[i];
 
1953
        
 
1954
        if (strcmp (output->name, name) == 0)
 
1955
            return output;
 
1956
    }
 
1957
    
 
1958
    return NULL;
 
1959
}
 
1960
 
 
1961
GnomeRRCrtc *
 
1962
gnome_rr_output_get_crtc (GnomeRROutput *output)
 
1963
{
 
1964
    g_return_val_if_fail (output != NULL, NULL);
 
1965
    
 
1966
    return output->current_crtc;
 
1967
}
 
1968
 
 
1969
/* Returns NULL if the ConnectorType property is not available */
 
1970
const char *
 
1971
gnome_rr_output_get_connector_type (GnomeRROutput *output)
 
1972
{
 
1973
    g_return_val_if_fail (output != NULL, NULL);
 
1974
 
 
1975
    return output->connector_type;
 
1976
}
 
1977
 
 
1978
gboolean
 
1979
_gnome_rr_output_name_is_laptop (const char *name)
 
1980
{
 
1981
    if (!name)
 
1982
        return FALSE;
 
1983
 
 
1984
    if (strstr (name, "lvds") ||  /* Most drivers use an "LVDS" prefix... */
 
1985
        strstr (name, "LVDS") ||
 
1986
        strstr (name, "Lvds") ||
 
1987
        strstr (name, "LCD")  ||  /* ... but fglrx uses "LCD" in some versions.  Shoot me now, kthxbye. */
 
1988
        strstr (name, "eDP")  ||  /* eDP is for internal laptop panel connections */
 
1989
        strstr (name, "default")) /* Finally, NVidia and all others that don't bother to do RANDR properly */
 
1990
        return TRUE;
 
1991
 
 
1992
    return FALSE;
 
1993
}
 
1994
 
 
1995
gboolean
 
1996
gnome_rr_output_is_laptop (GnomeRROutput *output)
 
1997
{
 
1998
    g_return_val_if_fail (output != NULL, FALSE);
 
1999
 
 
2000
    if (!output->connected)
 
2001
        return FALSE;
 
2002
 
 
2003
    /* The ConnectorType property is present in RANDR 1.3 and greater */
 
2004
    if (g_strcmp0 (output->connector_type, GNOME_RR_CONNECTOR_TYPE_PANEL) == 0)
 
2005
        return TRUE;
 
2006
 
 
2007
    /* Older versions of RANDR - this is a best guess, as @#$% RANDR doesn't have standard output names,
 
2008
     * so drivers can use whatever they like.
 
2009
     */
 
2010
    if (_gnome_rr_output_name_is_laptop (output->name))
 
2011
        return TRUE;
 
2012
 
 
2013
    return FALSE;
 
2014
}
 
2015
 
 
2016
GnomeRRMode *
 
2017
gnome_rr_output_get_current_mode (GnomeRROutput *output)
 
2018
{
 
2019
    GnomeRRCrtc *crtc;
 
2020
    
 
2021
    g_return_val_if_fail (output != NULL, NULL);
 
2022
    
 
2023
    if ((crtc = gnome_rr_output_get_crtc (output)))
 
2024
        return gnome_rr_crtc_get_current_mode (crtc);
 
2025
    
 
2026
    return NULL;
 
2027
}
 
2028
 
 
2029
/**
 
2030
 * gnome_rr_output_get_position:
 
2031
 * @output: a #GnomeRROutput
 
2032
 * @x: (out) (allow-none):
 
2033
 * @y: (out) (allow-none):
 
2034
 */
 
2035
void
 
2036
gnome_rr_output_get_position (GnomeRROutput   *output,
 
2037
                              int             *x,
 
2038
                              int             *y)
 
2039
{
 
2040
    GnomeRRCrtc *crtc;
 
2041
    
 
2042
    g_return_if_fail (output != NULL);
 
2043
    
 
2044
    if ((crtc = gnome_rr_output_get_crtc (output)))
 
2045
        gnome_rr_crtc_get_position (crtc, x, y);
 
2046
}
 
2047
 
 
2048
const char *
 
2049
gnome_rr_output_get_name (GnomeRROutput *output)
 
2050
{
 
2051
    g_assert (output != NULL);
 
2052
    return output->name;
 
2053
}
 
2054
 
 
2055
int
 
2056
gnome_rr_output_get_width_mm (GnomeRROutput *output)
 
2057
{
 
2058
    g_assert (output != NULL);
 
2059
    return output->width_mm;
 
2060
}
 
2061
 
 
2062
int
 
2063
gnome_rr_output_get_height_mm (GnomeRROutput *output)
 
2064
{
 
2065
    g_assert (output != NULL);
 
2066
    return output->height_mm;
 
2067
}
 
2068
 
 
2069
GnomeRRMode *
 
2070
gnome_rr_output_get_preferred_mode (GnomeRROutput *output)
 
2071
{
 
2072
    g_return_val_if_fail (output != NULL, NULL);
 
2073
    if (output->n_preferred)
 
2074
        return output->modes[0];
 
2075
    
 
2076
    return NULL;
 
2077
}
 
2078
 
 
2079
GnomeRRMode **
 
2080
gnome_rr_output_list_modes (GnomeRROutput *output)
 
2081
{
 
2082
    g_return_val_if_fail (output != NULL, NULL);
 
2083
    return output->modes;
 
2084
}
 
2085
 
 
2086
gboolean
 
2087
gnome_rr_output_is_connected (GnomeRROutput *output)
 
2088
{
 
2089
    g_return_val_if_fail (output != NULL, FALSE);
 
2090
    return output->connected;
 
2091
}
 
2092
 
 
2093
gboolean
 
2094
gnome_rr_output_supports_mode (GnomeRROutput *output,
 
2095
                               GnomeRRMode   *mode)
 
2096
{
 
2097
    int i;
 
2098
    
 
2099
    g_return_val_if_fail (output != NULL, FALSE);
 
2100
    g_return_val_if_fail (mode != NULL, FALSE);
 
2101
    
 
2102
    for (i = 0; output->modes[i] != NULL; ++i)
 
2103
    {
 
2104
        if (output->modes[i] == mode)
 
2105
            return TRUE;
 
2106
    }
 
2107
    
 
2108
    return FALSE;
 
2109
}
 
2110
 
 
2111
gboolean
 
2112
gnome_rr_output_can_clone (GnomeRROutput *output,
 
2113
                           GnomeRROutput *clone)
 
2114
{
 
2115
    int i;
 
2116
    
 
2117
    g_return_val_if_fail (output != NULL, FALSE);
 
2118
    g_return_val_if_fail (clone != NULL, FALSE);
 
2119
    
 
2120
    for (i = 0; output->clones[i] != NULL; ++i)
 
2121
    {
 
2122
        if (output->clones[i] == clone)
 
2123
            return TRUE;
 
2124
    }
 
2125
    
 
2126
    return FALSE;
 
2127
}
 
2128
 
 
2129
gboolean
 
2130
gnome_rr_output_get_is_primary (GnomeRROutput *output)
 
2131
{
 
2132
    return output->info->primary == output->id;
 
2133
}
 
2134
 
 
2135
void
 
2136
gnome_rr_screen_set_primary_output (GnomeRRScreen *screen,
 
2137
                                    GnomeRROutput *output)
 
2138
{
 
2139
    GnomeRRScreenPrivate *priv;
 
2140
    RROutput id;
 
2141
 
 
2142
    g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
 
2143
 
 
2144
    priv = screen->priv;
 
2145
 
 
2146
    if (output)
 
2147
        id = output->id;
 
2148
    else
 
2149
        id = None;
 
2150
 
 
2151
    if (SERVERS_RANDR_IS_AT_LEAST_1_3 (priv))
 
2152
        XRRSetOutputPrimary (priv->xdisplay, priv->xroot, id);
 
2153
}
 
2154
 
 
2155
/* GnomeRRCrtc */
 
2156
typedef struct
 
2157
{
 
2158
    Rotation xrot;
 
2159
    GnomeRRRotation rot;
 
2160
} RotationMap;
 
2161
 
 
2162
static const RotationMap rotation_map[] =
 
2163
{
 
2164
    { RR_Rotate_0, GNOME_RR_ROTATION_0 },
 
2165
    { RR_Rotate_90, GNOME_RR_ROTATION_90 },
 
2166
    { RR_Rotate_180, GNOME_RR_ROTATION_180 },
 
2167
    { RR_Rotate_270, GNOME_RR_ROTATION_270 },
 
2168
    { RR_Reflect_X, GNOME_RR_REFLECT_X },
 
2169
    { RR_Reflect_Y, GNOME_RR_REFLECT_Y },
 
2170
};
 
2171
 
 
2172
static GnomeRRRotation
 
2173
gnome_rr_rotation_from_xrotation (Rotation r)
 
2174
{
 
2175
    int i;
 
2176
    GnomeRRRotation result = 0;
 
2177
    
 
2178
    for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i)
 
2179
    {
 
2180
        if (r & rotation_map[i].xrot)
 
2181
            result |= rotation_map[i].rot;
 
2182
    }
 
2183
    
 
2184
    return result;
 
2185
}
 
2186
 
 
2187
static Rotation
 
2188
xrotation_from_rotation (GnomeRRRotation r)
 
2189
{
 
2190
    int i;
 
2191
    Rotation result = 0;
 
2192
    
 
2193
    for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i)
 
2194
    {
 
2195
        if (r & rotation_map[i].rot)
 
2196
            result |= rotation_map[i].xrot;
 
2197
    }
 
2198
    
 
2199
    return result;
 
2200
}
 
2201
 
 
2202
gboolean
 
2203
gnome_rr_crtc_set_config_with_time (GnomeRRCrtc      *crtc,
 
2204
                                    guint32           timestamp,
 
2205
                                    int               x,
 
2206
                                    int               y,
 
2207
                                    GnomeRRMode      *mode,
 
2208
                                    GnomeRRRotation   rotation,
 
2209
                                    GnomeRROutput   **outputs,
 
2210
                                    int               n_outputs,
 
2211
                                    GError          **error)
 
2212
{
 
2213
    ScreenInfo *info;
 
2214
    GArray *output_ids;
 
2215
    Status status;
 
2216
    gboolean result;
 
2217
    int i;
 
2218
    
 
2219
    g_return_val_if_fail (crtc != NULL, FALSE);
 
2220
    g_return_val_if_fail (mode != NULL || outputs == NULL || n_outputs == 0, FALSE);
 
2221
    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
2222
    
 
2223
    info = crtc->info;
 
2224
    
 
2225
    if (mode)
 
2226
    {
 
2227
        if (x + mode->width > info->max_width
 
2228
            || y + mode->height > info->max_height)
 
2229
        {
 
2230
            g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR,
 
2231
                         /* Translators: the "position", "size", and "maximum"
 
2232
                          * words here are not keywords; please translate them
 
2233
                          * as usual.  A CRTC is a CRT Controller (this is X terminology) */
 
2234
                         _("requested position/size for CRTC %d is outside the allowed limit: "
 
2235
                           "position=(%d, %d), size=(%d, %d), maximum=(%d, %d)"),
 
2236
                         (int) crtc->id,
 
2237
                         x, y,
 
2238
                         mode->width, mode->height,
 
2239
                         info->max_width, info->max_height);
 
2240
            return FALSE;
 
2241
        }
 
2242
    }
 
2243
    
 
2244
    output_ids = g_array_new (FALSE, FALSE, sizeof (RROutput));
 
2245
    
 
2246
    if (outputs)
 
2247
    {
 
2248
        for (i = 0; i < n_outputs; ++i)
 
2249
            g_array_append_val (output_ids, outputs[i]->id);
 
2250
    }
 
2251
 
 
2252
    gdk_error_trap_push ();
 
2253
    status = XRRSetCrtcConfig (DISPLAY (crtc), info->resources, crtc->id,
 
2254
                               timestamp, 
 
2255
                               x, y,
 
2256
                               mode ? mode->id : None,
 
2257
                               xrotation_from_rotation (rotation),
 
2258
                               (RROutput *)output_ids->data,
 
2259
                               output_ids->len);
 
2260
    
 
2261
    g_array_free (output_ids, TRUE);
 
2262
 
 
2263
    if (gdk_error_trap_pop () || status != RRSetConfigSuccess) {
 
2264
        /* Translators: CRTC is a CRT Controller (this is X terminology).
 
2265
         * It is *very* unlikely that you'll ever get this error, so it is
 
2266
         * only listed for completeness. */
 
2267
        g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
 
2268
                     _("could not set the configuration for CRTC %d"),
 
2269
                     (int) crtc->id);
 
2270
        return FALSE;
 
2271
    } else {
 
2272
        result = TRUE;
 
2273
    }
 
2274
    
 
2275
    return result;
 
2276
}
 
2277
 
 
2278
GnomeRRMode *
 
2279
gnome_rr_crtc_get_current_mode (GnomeRRCrtc *crtc)
 
2280
{
 
2281
    g_return_val_if_fail (crtc != NULL, NULL);
 
2282
    
 
2283
    return crtc->current_mode;
 
2284
}
 
2285
 
 
2286
guint32
 
2287
gnome_rr_crtc_get_id (GnomeRRCrtc *crtc)
 
2288
{
 
2289
    g_return_val_if_fail (crtc != NULL, 0);
 
2290
    
 
2291
    return crtc->id;
 
2292
}
 
2293
 
 
2294
gboolean
 
2295
gnome_rr_crtc_can_drive_output (GnomeRRCrtc   *crtc,
 
2296
                                GnomeRROutput *output)
 
2297
{
 
2298
    int i;
 
2299
    
 
2300
    g_return_val_if_fail (crtc != NULL, FALSE);
 
2301
    g_return_val_if_fail (output != NULL, FALSE);
 
2302
    
 
2303
    for (i = 0; crtc->possible_outputs[i] != NULL; ++i)
 
2304
    {
 
2305
        if (crtc->possible_outputs[i] == output)
 
2306
            return TRUE;
 
2307
    }
 
2308
    
 
2309
    return FALSE;
 
2310
}
 
2311
 
 
2312
/* FIXME: merge with get_mode()? */
 
2313
/**
 
2314
 * gnome_rr_crtc_get_position:
 
2315
 * @crtc: a #GnomeRRCrtc
 
2316
 * @x: (out) (allow-none):
 
2317
 * @y: (out) (allow-none):
 
2318
 */
 
2319
void
 
2320
gnome_rr_crtc_get_position (GnomeRRCrtc *crtc,
 
2321
                            int         *x,
 
2322
                            int         *y)
 
2323
{
 
2324
    g_return_if_fail (crtc != NULL);
 
2325
    
 
2326
    if (x)
 
2327
        *x = crtc->x;
 
2328
    
 
2329
    if (y)
 
2330
        *y = crtc->y;
 
2331
}
 
2332
 
 
2333
/* FIXME: merge with get_mode()? */
 
2334
GnomeRRRotation
 
2335
gnome_rr_crtc_get_current_rotation (GnomeRRCrtc *crtc)
 
2336
{
 
2337
    g_assert(crtc != NULL);
 
2338
    return crtc->current_rotation;
 
2339
}
 
2340
 
 
2341
GnomeRRRotation
 
2342
gnome_rr_crtc_get_rotations (GnomeRRCrtc *crtc)
 
2343
{
 
2344
    g_assert(crtc != NULL);
 
2345
    return crtc->rotations;
 
2346
}
 
2347
 
 
2348
gboolean
 
2349
gnome_rr_crtc_supports_rotation (GnomeRRCrtc *   crtc,
 
2350
                                 GnomeRRRotation rotation)
 
2351
{
 
2352
    g_return_val_if_fail (crtc != NULL, FALSE);
 
2353
    return (crtc->rotations & rotation);
 
2354
}
 
2355
 
 
2356
static GnomeRRCrtc *
 
2357
crtc_new (ScreenInfo *info, RROutput id)
 
2358
{
 
2359
    GnomeRRCrtc *crtc = g_slice_new0 (GnomeRRCrtc);
 
2360
    
 
2361
    crtc->id = id;
 
2362
    crtc->info = info;
 
2363
    
 
2364
    return crtc;
 
2365
}
 
2366
 
 
2367
static GnomeRRCrtc *
 
2368
crtc_copy (const GnomeRRCrtc *from)
 
2369
{
 
2370
    GnomeRROutput **p_output;
 
2371
    GPtrArray *array;
 
2372
    GnomeRRCrtc *to = g_slice_new0 (GnomeRRCrtc);
 
2373
 
 
2374
    to->info = from->info;
 
2375
    to->id = from->id;
 
2376
    to->current_mode = from->current_mode;
 
2377
    to->x = from->x;
 
2378
    to->y = from->y;
 
2379
    to->current_rotation = from->current_rotation;
 
2380
    to->rotations = from->rotations;
 
2381
    to->gamma_size = from->gamma_size;
 
2382
 
 
2383
    array = g_ptr_array_new ();
 
2384
    for (p_output = from->current_outputs; *p_output != NULL; p_output++)
 
2385
    {
 
2386
        g_ptr_array_add (array, *p_output);
 
2387
    }
 
2388
    to->current_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
 
2389
 
 
2390
    array = g_ptr_array_new ();
 
2391
    for (p_output = from->possible_outputs; *p_output != NULL; p_output++)
 
2392
    {
 
2393
        g_ptr_array_add (array, *p_output);
 
2394
    }
 
2395
    to->possible_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
 
2396
 
 
2397
    return to;
 
2398
}
 
2399
 
 
2400
static gboolean
 
2401
crtc_initialize (GnomeRRCrtc        *crtc,
 
2402
                 XRRScreenResources *res,
 
2403
                 GError            **error)
 
2404
{
 
2405
    XRRCrtcInfo *info = XRRGetCrtcInfo (DISPLAY (crtc), res, crtc->id);
 
2406
    GPtrArray *a;
 
2407
    int i;
 
2408
    
 
2409
#if 0
 
2410
    g_print ("CRTC %lx Timestamp: %u\n", crtc->id, (guint32)info->timestamp);
 
2411
#endif
 
2412
    
 
2413
    if (!info)
 
2414
    {
 
2415
        /* FIXME: We need to reaquire the screen resources */
 
2416
        /* FIXME: can we actually catch BadRRCrtc, and does it make sense to emit that? */
 
2417
 
 
2418
        /* Translators: CRTC is a CRT Controller (this is X terminology).
 
2419
         * It is *very* unlikely that you'll ever get this error, so it is
 
2420
         * only listed for completeness. */
 
2421
        g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
 
2422
                     _("could not get information about CRTC %d"),
 
2423
                     (int) crtc->id);
 
2424
        return FALSE;
 
2425
    }
 
2426
    
 
2427
    /* GnomeRRMode */
 
2428
    crtc->current_mode = mode_by_id (crtc->info, info->mode);
 
2429
    
 
2430
    crtc->x = info->x;
 
2431
    crtc->y = info->y;
 
2432
    
 
2433
    /* Current outputs */
 
2434
    a = g_ptr_array_new ();
 
2435
    for (i = 0; i < info->noutput; ++i)
 
2436
    {
 
2437
        GnomeRROutput *output = gnome_rr_output_by_id (crtc->info, info->outputs[i]);
 
2438
        
 
2439
        if (output)
 
2440
            g_ptr_array_add (a, output);
 
2441
    }
 
2442
    g_ptr_array_add (a, NULL);
 
2443
    crtc->current_outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
 
2444
    
 
2445
    /* Possible outputs */
 
2446
    a = g_ptr_array_new ();
 
2447
    for (i = 0; i < info->npossible; ++i)
 
2448
    {
 
2449
        GnomeRROutput *output = gnome_rr_output_by_id (crtc->info, info->possible[i]);
 
2450
        
 
2451
        if (output)
 
2452
            g_ptr_array_add (a, output);
 
2453
    }
 
2454
    g_ptr_array_add (a, NULL);
 
2455
    crtc->possible_outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
 
2456
    
 
2457
    /* Rotations */
 
2458
    crtc->current_rotation = gnome_rr_rotation_from_xrotation (info->rotation);
 
2459
    crtc->rotations = gnome_rr_rotation_from_xrotation (info->rotations);
 
2460
    
 
2461
    XRRFreeCrtcInfo (info);
 
2462
 
 
2463
    /* get an store gamma size */
 
2464
    crtc->gamma_size = XRRGetCrtcGammaSize (DISPLAY (crtc), crtc->id);
 
2465
 
 
2466
    return TRUE;
 
2467
}
 
2468
 
 
2469
static void
 
2470
crtc_free (GnomeRRCrtc *crtc)
 
2471
{
 
2472
    g_free (crtc->current_outputs);
 
2473
    g_free (crtc->possible_outputs);
 
2474
    g_slice_free (GnomeRRCrtc, crtc);
 
2475
}
 
2476
 
 
2477
/* GnomeRRMode */
 
2478
static GnomeRRMode *
 
2479
mode_new (ScreenInfo *info, RRMode id)
 
2480
{
 
2481
    GnomeRRMode *mode = g_slice_new0 (GnomeRRMode);
 
2482
    
 
2483
    mode->id = id;
 
2484
    mode->info = info;
 
2485
    
 
2486
    return mode;
 
2487
}
 
2488
 
 
2489
guint32
 
2490
gnome_rr_mode_get_id (GnomeRRMode *mode)
 
2491
{
 
2492
    g_return_val_if_fail (mode != NULL, 0);
 
2493
    return mode->id;
 
2494
}
 
2495
 
 
2496
guint
 
2497
gnome_rr_mode_get_width (GnomeRRMode *mode)
 
2498
{
 
2499
    g_return_val_if_fail (mode != NULL, 0);
 
2500
    return mode->width;
 
2501
}
 
2502
 
 
2503
int
 
2504
gnome_rr_mode_get_freq (GnomeRRMode *mode)
 
2505
{
 
2506
    g_return_val_if_fail (mode != NULL, 0);
 
2507
    return (mode->freq) / 1000;
 
2508
}
 
2509
 
 
2510
guint
 
2511
gnome_rr_mode_get_height (GnomeRRMode *mode)
 
2512
{
 
2513
    g_return_val_if_fail (mode != NULL, 0);
 
2514
    return mode->height;
 
2515
}
 
2516
 
 
2517
static void
 
2518
mode_initialize (GnomeRRMode *mode, XRRModeInfo *info)
 
2519
{
 
2520
    g_assert (mode != NULL);
 
2521
    g_assert (info != NULL);
 
2522
    
 
2523
    mode->name = g_strdup (info->name);
 
2524
    mode->width = info->width;
 
2525
    mode->height = info->height;
 
2526
    mode->freq = ((info->dotClock / (double)info->hTotal) / info->vTotal + 0.5) * 1000;
 
2527
}
 
2528
 
 
2529
static GnomeRRMode *
 
2530
mode_copy (const GnomeRRMode *from)
 
2531
{
 
2532
    GnomeRRMode *to = g_slice_new0 (GnomeRRMode);
 
2533
 
 
2534
    to->id = from->id;
 
2535
    to->info = from->info;
 
2536
    to->name = g_strdup (from->name);
 
2537
    to->width = from->width;
 
2538
    to->height = from->height;
 
2539
    to->freq = from->freq;
 
2540
 
 
2541
    return to;
 
2542
}
 
2543
 
 
2544
static void
 
2545
mode_free (GnomeRRMode *mode)
 
2546
{
 
2547
    g_free (mode->name);
 
2548
    g_slice_free (GnomeRRMode, mode);
 
2549
}
 
2550
 
 
2551
void
 
2552
gnome_rr_crtc_set_gamma (GnomeRRCrtc *crtc, int size,
 
2553
                         unsigned short *red,
 
2554
                         unsigned short *green,
 
2555
                         unsigned short *blue)
 
2556
{
 
2557
    int copy_size;
 
2558
    XRRCrtcGamma *gamma;
 
2559
 
 
2560
    g_return_if_fail (crtc != NULL);
 
2561
    g_return_if_fail (red != NULL);
 
2562
    g_return_if_fail (green != NULL);
 
2563
    g_return_if_fail (blue != NULL);
 
2564
 
 
2565
    if (size != crtc->gamma_size)
 
2566
        return;
 
2567
 
 
2568
    gamma = XRRAllocGamma (crtc->gamma_size);
 
2569
 
 
2570
    copy_size = crtc->gamma_size * sizeof (unsigned short);
 
2571
    memcpy (gamma->red, red, copy_size);
 
2572
    memcpy (gamma->green, green, copy_size);
 
2573
    memcpy (gamma->blue, blue, copy_size);
 
2574
 
 
2575
    XRRSetCrtcGamma (DISPLAY (crtc), crtc->id, gamma);
 
2576
    XRRFreeGamma (gamma);
 
2577
}
 
2578
 
 
2579
gboolean
 
2580
gnome_rr_crtc_get_gamma (GnomeRRCrtc *crtc, int *size,
 
2581
                         unsigned short **red, unsigned short **green,
 
2582
                         unsigned short **blue)
 
2583
{
 
2584
    int copy_size;
 
2585
    unsigned short *r, *g, *b;
 
2586
    XRRCrtcGamma *gamma;
 
2587
 
 
2588
    g_return_val_if_fail (crtc != NULL, FALSE);
 
2589
 
 
2590
    gamma = XRRGetCrtcGamma (DISPLAY (crtc), crtc->id);
 
2591
    if (!gamma)
 
2592
        return FALSE;
 
2593
 
 
2594
    copy_size = crtc->gamma_size * sizeof (unsigned short);
 
2595
 
 
2596
    if (red) {
 
2597
        r = g_new0 (unsigned short, crtc->gamma_size);
 
2598
        memcpy (r, gamma->red, copy_size);
 
2599
        *red = r;
 
2600
    }
 
2601
 
 
2602
    if (green) {
 
2603
        g = g_new0 (unsigned short, crtc->gamma_size);
 
2604
        memcpy (g, gamma->green, copy_size);
 
2605
        *green = g;
 
2606
    }
 
2607
 
 
2608
    if (blue) {
 
2609
        b = g_new0 (unsigned short, crtc->gamma_size);
 
2610
        memcpy (b, gamma->blue, copy_size);
 
2611
        *blue = b;
 
2612
    }
 
2613
 
 
2614
    XRRFreeGamma (gamma);
 
2615
 
 
2616
    if (size)
 
2617
        *size = crtc->gamma_size;
 
2618
 
 
2619
    return TRUE;
 
2620
}
 
2621