~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): Tim Lunn
  • Date: 2014-09-12 07:22:38 UTC
  • mfrom: (1.6.4) (31.1.1 utopic-proposed)
  • Revision ID: package-import@ubuntu.com-20140912072238-fv5g0rpwuk5yynip
Tags: 3.12.2-2ubuntu1
* New upstream release (LP: #1372346)
* Merge with Debian, Remaining changes:
  - debian/patches:
    + 04_compute_average_color.patch: Compute the avergage color in
      gnome-desktop itself, not in unity to fix some races (LP #963140)
    + tweak_color_computation.patch, Patch from Gord, no patch header,
      no bug link.
    + git_revert_draw_background.patch
    + ubuntu_language.patch, Ported relevant bits from g-c-c 
      52_region_language.patch, as required for gnome 3.8 region panel
    + ubuntu_language_list_from_SUPPORTED.patch,
      adds api to get list of available languages from SUPPORTED file.
      To be used by gnome 3.8 region panel language installation.
  - debian/rules:
    + drop obsolete --disable-scrollkeeper configure flag
  - debian/libgnome-desktop-3-10.symbols:
    + Add symbols included in Ubuntu patches
  - debian/control.in:
    + Mark gnome-desktop3-data Multi-Arch: foreign
* Dropped changes:
  - 02_refuse_to_break_GL_compositors.patch:
    + xrandr code has moved into libunity-settings-daemon now

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