Merge lp:~fourdollars/ubuntu/trusty/gnome-desktop3/fix-lowest-brightness into lp:ubuntu/trusty-proposed/gnome-desktop3

Proposed by Shih-Yuan Lee
Status: Merged
Merge reported by: Martin Pitt
Merged at revision: not available
Proposed branch: lp:~fourdollars/ubuntu/trusty/gnome-desktop3/fix-lowest-brightness
Merge into: lp:ubuntu/trusty-proposed/gnome-desktop3
Diff against target: 2705 lines (+2659/-0)
6 files modified
.pc/applied-patches (+1/-0)
.pc/fix_lowest_brightness.patch/libgnome-desktop/gnome-rr.c (+2624/-0)
debian/changelog (+7/-0)
debian/patches/fix_lowest_brightness.patch (+21/-0)
debian/patches/series (+1/-0)
libgnome-desktop/gnome-rr.c (+5/-0)
To merge this branch: bzr merge lp:~fourdollars/ubuntu/trusty/gnome-desktop3/fix-lowest-brightness
Reviewer Review Type Date Requested Status
Martin Pitt Approve
Review via email: mp+278110@code.launchpad.net

Commit message

Apply the similar method from the power plugin in unity-settings-daemon to fix the lowest brightness issue.

Description of the change

Please help to review this change.
This change has been applied in xenial.
I am backporting it into trusty.

To post a comment you must log in.
Revision history for this message
Martin Pitt (pitti) wrote :

Uploaded. I didn't merge this into bzr, just grabbed the diff, so closing this manually. Further tracking happens in the SRU bug.

Thank you!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2015-03-31 10:59:01 +0000
+++ .pc/applied-patches 2015-11-20 08:10:07 +0000
@@ -8,3 +8,4 @@
8ignore_errors_with_primary_outputs.patch8ignore_errors_with_primary_outputs.patch
9backlight-property-name.patch9backlight-property-name.patch
10idletime_sanity_checks.patch10idletime_sanity_checks.patch
11fix_lowest_brightness.patch
1112
=== added directory '.pc/fix_lowest_brightness.patch'
=== added directory '.pc/fix_lowest_brightness.patch/libgnome-desktop'
=== added file '.pc/fix_lowest_brightness.patch/libgnome-desktop/gnome-rr.c'
--- .pc/fix_lowest_brightness.patch/libgnome-desktop/gnome-rr.c 1970-01-01 00:00:00 +0000
+++ .pc/fix_lowest_brightness.patch/libgnome-desktop/gnome-rr.c 2015-11-20 08:10:07 +0000
@@ -0,0 +1,2624 @@
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
50enum {
51 SCREEN_PROP_0,
52 SCREEN_PROP_GDK_SCREEN,
53 SCREEN_PROP_LAST,
54};
55
56enum {
57 SCREEN_CHANGED,
58 SCREEN_OUTPUT_CONNECTED,
59 SCREEN_OUTPUT_DISCONNECTED,
60 SCREEN_SIGNAL_LAST,
61};
62
63gint screen_signals[SCREEN_SIGNAL_LAST];
64
65struct 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
87struct GnomeRROutputWrap
88{
89 RROutput id;
90};
91
92struct 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
108struct 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 */
119static GnomeRRCrtc * crtc_new (ScreenInfo *info,
120 RRCrtc id);
121static GnomeRRCrtc * crtc_copy (const GnomeRRCrtc *from);
122static void crtc_free (GnomeRRCrtc *crtc);
123
124static gboolean crtc_initialize (GnomeRRCrtc *crtc,
125 XRRScreenResources *res,
126 GError **error);
127
128/* GnomeRROutput */
129static GnomeRROutput *output_new (ScreenInfo *info,
130 RROutput id);
131
132static gboolean output_initialize (GnomeRROutput *output,
133 XRRScreenResources *res,
134 GError **error);
135
136static GnomeRROutput *output_copy (const GnomeRROutput *from);
137static void output_free (GnomeRROutput *output);
138
139/* GnomeRRMode */
140static GnomeRRMode * mode_new (ScreenInfo *info,
141 RRMode id);
142
143static void mode_initialize (GnomeRRMode *mode,
144 XRRModeInfo *info);
145
146static GnomeRRMode * mode_copy (const GnomeRRMode *from);
147static void mode_free (GnomeRRMode *mode);
148
149static void gnome_rr_screen_finalize (GObject*);
150static void gnome_rr_screen_set_property (GObject*, guint, const GValue*, GParamSpec*);
151static void gnome_rr_screen_get_property (GObject*, guint, GValue*, GParamSpec*);
152static gboolean gnome_rr_screen_initable_init (GInitable*, GCancellable*, GError**);
153static void gnome_rr_screen_initable_iface_init (GInitableIface *iface);
154G_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
157G_DEFINE_BOXED_TYPE (GnomeRRCrtc, gnome_rr_crtc, crtc_copy, crtc_free)
158G_DEFINE_BOXED_TYPE (GnomeRROutput, gnome_rr_output, output_copy, output_free)
159G_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 */
171GQuark
172gnome_rr_error_quark (void)
173{
174 return g_quark_from_static_string ("gnome-rr-error-quark");
175}
176
177/* Screen */
178static GnomeRROutput *
179gnome_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
194static GnomeRRCrtc *
195crtc_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
211static GnomeRRMode *
212mode_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
227static void
228screen_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
273static gboolean
274has_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
295static void
296gather_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
342static gboolean
343fill_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
412static gboolean
413fill_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
506static ScreenInfo *
507screen_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
532static GnomeRROutput *
533find_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
545static void
546diff_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
606static gboolean
607screen_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
634static GdkFilterReturn
635screen_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
728static gboolean
729gnome_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
775void
776gnome_rr_screen_initable_iface_init (GInitableIface *iface)
777{
778 iface->init = gnome_rr_screen_initable_init;
779}
780
781void
782gnome_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
794void
795gnome_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
815void
816gnome_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
832void
833gnome_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
926void
927gnome_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. */
943static void
944rr_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 */
962GnomeRRScreen *
963gnome_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
985void
986gnome_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 */
1010void
1011gnome_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 */
1048void
1049gnome_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
1066static gboolean
1067force_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;
1109out:
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 */
1126gboolean
1127gnome_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 **/
1148gboolean
1149gnome_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;
1203out:
1204 return ret;
1205}
1206
1207/**
1208 * gnome_rr_screen_clear_dpms_timeouts:
1209 **/
1210static gboolean
1211gnome_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 **/
1232gboolean
1233gnome_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;
1286out:
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 */
1297GnomeRRMode **
1298gnome_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 */
1313GnomeRRMode **
1314gnome_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 */
1329GnomeRRCrtc **
1330gnome_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 */
1345GnomeRROutput **
1346gnome_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 */
1359GnomeRRCrtc *
1360gnome_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 */
1385GnomeRROutput *
1386gnome_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 */
1407static GnomeRROutput *
1408output_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
1418static guint8 *
1419get_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
1452static guint8 *
1453read_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
1487static char *
1488get_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
1518out:
1519
1520 XFree (prop);
1521
1522 return result;
1523}
1524
1525static void
1526update_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];
1556out:
1557 if (info != NULL)
1558 {
1559 XFree (info);
1560 }
1561}
1562
1563static gboolean
1564output_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
1644static GnomeRROutput*
1645output_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
1692static void
1693output_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
1705guint32
1706gnome_rr_output_get_id (GnomeRROutput *output)
1707{
1708 g_assert(output != NULL);
1709
1710 return output->id;
1711}
1712
1713const guint8 *
1714gnome_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 */
1729gboolean
1730gnome_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
1757static void
1758ensure_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
1793const char *
1794gnome_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 */
1808gint
1809gnome_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 */
1820gint
1821gnome_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 */
1832gint
1833gnome_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 }
1883out:
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 */
1894gboolean
1895gnome_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;
1932out:
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 */
1941GnomeRROutput *
1942gnome_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
1961GnomeRRCrtc *
1962gnome_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 */
1970const char *
1971gnome_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
1978gboolean
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
1995gboolean
1996gnome_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
2016GnomeRRMode *
2017gnome_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 */
2035void
2036gnome_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
2048const char *
2049gnome_rr_output_get_name (GnomeRROutput *output)
2050{
2051 g_assert (output != NULL);
2052 return output->name;
2053}
2054
2055int
2056gnome_rr_output_get_width_mm (GnomeRROutput *output)
2057{
2058 g_assert (output != NULL);
2059 return output->width_mm;
2060}
2061
2062int
2063gnome_rr_output_get_height_mm (GnomeRROutput *output)
2064{
2065 g_assert (output != NULL);
2066 return output->height_mm;
2067}
2068
2069GnomeRRMode *
2070gnome_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
2079GnomeRRMode **
2080gnome_rr_output_list_modes (GnomeRROutput *output)
2081{
2082 g_return_val_if_fail (output != NULL, NULL);
2083 return output->modes;
2084}
2085
2086gboolean
2087gnome_rr_output_is_connected (GnomeRROutput *output)
2088{
2089 g_return_val_if_fail (output != NULL, FALSE);
2090 return output->connected;
2091}
2092
2093gboolean
2094gnome_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
2111gboolean
2112gnome_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
2129gboolean
2130gnome_rr_output_get_is_primary (GnomeRROutput *output)
2131{
2132 return output->info->primary == output->id;
2133}
2134
2135void
2136gnome_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 gdk_error_trap_push ();
2153 XRRSetOutputPrimary (priv->xdisplay, priv->xroot, id);
2154 gdk_error_trap_pop_ignored ();
2155 }
2156}
2157
2158/* GnomeRRCrtc */
2159typedef struct
2160{
2161 Rotation xrot;
2162 GnomeRRRotation rot;
2163} RotationMap;
2164
2165static const RotationMap rotation_map[] =
2166{
2167 { RR_Rotate_0, GNOME_RR_ROTATION_0 },
2168 { RR_Rotate_90, GNOME_RR_ROTATION_90 },
2169 { RR_Rotate_180, GNOME_RR_ROTATION_180 },
2170 { RR_Rotate_270, GNOME_RR_ROTATION_270 },
2171 { RR_Reflect_X, GNOME_RR_REFLECT_X },
2172 { RR_Reflect_Y, GNOME_RR_REFLECT_Y },
2173};
2174
2175static GnomeRRRotation
2176gnome_rr_rotation_from_xrotation (Rotation r)
2177{
2178 int i;
2179 GnomeRRRotation result = 0;
2180
2181 for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i)
2182 {
2183 if (r & rotation_map[i].xrot)
2184 result |= rotation_map[i].rot;
2185 }
2186
2187 return result;
2188}
2189
2190static Rotation
2191xrotation_from_rotation (GnomeRRRotation r)
2192{
2193 int i;
2194 Rotation result = 0;
2195
2196 for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i)
2197 {
2198 if (r & rotation_map[i].rot)
2199 result |= rotation_map[i].xrot;
2200 }
2201
2202 return result;
2203}
2204
2205gboolean
2206gnome_rr_crtc_set_config_with_time (GnomeRRCrtc *crtc,
2207 guint32 timestamp,
2208 int x,
2209 int y,
2210 GnomeRRMode *mode,
2211 GnomeRRRotation rotation,
2212 GnomeRROutput **outputs,
2213 int n_outputs,
2214 GError **error)
2215{
2216 ScreenInfo *info;
2217 GArray *output_ids;
2218 Status status;
2219 gboolean result;
2220 int i;
2221
2222 g_return_val_if_fail (crtc != NULL, FALSE);
2223 g_return_val_if_fail (mode != NULL || outputs == NULL || n_outputs == 0, FALSE);
2224 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2225
2226 info = crtc->info;
2227
2228 if (mode)
2229 {
2230 if (x + mode->width > info->max_width
2231 || y + mode->height > info->max_height)
2232 {
2233 g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR,
2234 /* Translators: the "position", "size", and "maximum"
2235 * words here are not keywords; please translate them
2236 * as usual. A CRTC is a CRT Controller (this is X terminology) */
2237 _("requested position/size for CRTC %d is outside the allowed limit: "
2238 "position=(%d, %d), size=(%d, %d), maximum=(%d, %d)"),
2239 (int) crtc->id,
2240 x, y,
2241 mode->width, mode->height,
2242 info->max_width, info->max_height);
2243 return FALSE;
2244 }
2245 }
2246
2247 output_ids = g_array_new (FALSE, FALSE, sizeof (RROutput));
2248
2249 if (outputs)
2250 {
2251 for (i = 0; i < n_outputs; ++i)
2252 g_array_append_val (output_ids, outputs[i]->id);
2253 }
2254
2255 gdk_error_trap_push ();
2256 status = XRRSetCrtcConfig (DISPLAY (crtc), info->resources, crtc->id,
2257 timestamp,
2258 x, y,
2259 mode ? mode->id : None,
2260 xrotation_from_rotation (rotation),
2261 (RROutput *)output_ids->data,
2262 output_ids->len);
2263
2264 g_array_free (output_ids, TRUE);
2265
2266 if (gdk_error_trap_pop () || status != RRSetConfigSuccess) {
2267 /* Translators: CRTC is a CRT Controller (this is X terminology).
2268 * It is *very* unlikely that you'll ever get this error, so it is
2269 * only listed for completeness. */
2270 g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
2271 _("could not set the configuration for CRTC %d"),
2272 (int) crtc->id);
2273 return FALSE;
2274 } else {
2275 result = TRUE;
2276 }
2277
2278 return result;
2279}
2280
2281GnomeRRMode *
2282gnome_rr_crtc_get_current_mode (GnomeRRCrtc *crtc)
2283{
2284 g_return_val_if_fail (crtc != NULL, NULL);
2285
2286 return crtc->current_mode;
2287}
2288
2289guint32
2290gnome_rr_crtc_get_id (GnomeRRCrtc *crtc)
2291{
2292 g_return_val_if_fail (crtc != NULL, 0);
2293
2294 return crtc->id;
2295}
2296
2297gboolean
2298gnome_rr_crtc_can_drive_output (GnomeRRCrtc *crtc,
2299 GnomeRROutput *output)
2300{
2301 int i;
2302
2303 g_return_val_if_fail (crtc != NULL, FALSE);
2304 g_return_val_if_fail (output != NULL, FALSE);
2305
2306 for (i = 0; crtc->possible_outputs[i] != NULL; ++i)
2307 {
2308 if (crtc->possible_outputs[i] == output)
2309 return TRUE;
2310 }
2311
2312 return FALSE;
2313}
2314
2315/* FIXME: merge with get_mode()? */
2316/**
2317 * gnome_rr_crtc_get_position:
2318 * @crtc: a #GnomeRRCrtc
2319 * @x: (out) (allow-none):
2320 * @y: (out) (allow-none):
2321 */
2322void
2323gnome_rr_crtc_get_position (GnomeRRCrtc *crtc,
2324 int *x,
2325 int *y)
2326{
2327 g_return_if_fail (crtc != NULL);
2328
2329 if (x)
2330 *x = crtc->x;
2331
2332 if (y)
2333 *y = crtc->y;
2334}
2335
2336/* FIXME: merge with get_mode()? */
2337GnomeRRRotation
2338gnome_rr_crtc_get_current_rotation (GnomeRRCrtc *crtc)
2339{
2340 g_assert(crtc != NULL);
2341 return crtc->current_rotation;
2342}
2343
2344GnomeRRRotation
2345gnome_rr_crtc_get_rotations (GnomeRRCrtc *crtc)
2346{
2347 g_assert(crtc != NULL);
2348 return crtc->rotations;
2349}
2350
2351gboolean
2352gnome_rr_crtc_supports_rotation (GnomeRRCrtc * crtc,
2353 GnomeRRRotation rotation)
2354{
2355 g_return_val_if_fail (crtc != NULL, FALSE);
2356 return (crtc->rotations & rotation);
2357}
2358
2359static GnomeRRCrtc *
2360crtc_new (ScreenInfo *info, RROutput id)
2361{
2362 GnomeRRCrtc *crtc = g_slice_new0 (GnomeRRCrtc);
2363
2364 crtc->id = id;
2365 crtc->info = info;
2366
2367 return crtc;
2368}
2369
2370static GnomeRRCrtc *
2371crtc_copy (const GnomeRRCrtc *from)
2372{
2373 GnomeRROutput **p_output;
2374 GPtrArray *array;
2375 GnomeRRCrtc *to = g_slice_new0 (GnomeRRCrtc);
2376
2377 to->info = from->info;
2378 to->id = from->id;
2379 to->current_mode = from->current_mode;
2380 to->x = from->x;
2381 to->y = from->y;
2382 to->current_rotation = from->current_rotation;
2383 to->rotations = from->rotations;
2384 to->gamma_size = from->gamma_size;
2385
2386 array = g_ptr_array_new ();
2387 for (p_output = from->current_outputs; *p_output != NULL; p_output++)
2388 {
2389 g_ptr_array_add (array, *p_output);
2390 }
2391 to->current_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
2392
2393 array = g_ptr_array_new ();
2394 for (p_output = from->possible_outputs; *p_output != NULL; p_output++)
2395 {
2396 g_ptr_array_add (array, *p_output);
2397 }
2398 to->possible_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
2399
2400 return to;
2401}
2402
2403static gboolean
2404crtc_initialize (GnomeRRCrtc *crtc,
2405 XRRScreenResources *res,
2406 GError **error)
2407{
2408 XRRCrtcInfo *info = XRRGetCrtcInfo (DISPLAY (crtc), res, crtc->id);
2409 GPtrArray *a;
2410 int i;
2411
2412#if 0
2413 g_print ("CRTC %lx Timestamp: %u\n", crtc->id, (guint32)info->timestamp);
2414#endif
2415
2416 if (!info)
2417 {
2418 /* FIXME: We need to reaquire the screen resources */
2419 /* FIXME: can we actually catch BadRRCrtc, and does it make sense to emit that? */
2420
2421 /* Translators: CRTC is a CRT Controller (this is X terminology).
2422 * It is *very* unlikely that you'll ever get this error, so it is
2423 * only listed for completeness. */
2424 g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
2425 _("could not get information about CRTC %d"),
2426 (int) crtc->id);
2427 return FALSE;
2428 }
2429
2430 /* GnomeRRMode */
2431 crtc->current_mode = mode_by_id (crtc->info, info->mode);
2432
2433 crtc->x = info->x;
2434 crtc->y = info->y;
2435
2436 /* Current outputs */
2437 a = g_ptr_array_new ();
2438 for (i = 0; i < info->noutput; ++i)
2439 {
2440 GnomeRROutput *output = gnome_rr_output_by_id (crtc->info, info->outputs[i]);
2441
2442 if (output)
2443 g_ptr_array_add (a, output);
2444 }
2445 g_ptr_array_add (a, NULL);
2446 crtc->current_outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
2447
2448 /* Possible outputs */
2449 a = g_ptr_array_new ();
2450 for (i = 0; i < info->npossible; ++i)
2451 {
2452 GnomeRROutput *output = gnome_rr_output_by_id (crtc->info, info->possible[i]);
2453
2454 if (output)
2455 g_ptr_array_add (a, output);
2456 }
2457 g_ptr_array_add (a, NULL);
2458 crtc->possible_outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
2459
2460 /* Rotations */
2461 crtc->current_rotation = gnome_rr_rotation_from_xrotation (info->rotation);
2462 crtc->rotations = gnome_rr_rotation_from_xrotation (info->rotations);
2463
2464 XRRFreeCrtcInfo (info);
2465
2466 /* get an store gamma size */
2467 crtc->gamma_size = XRRGetCrtcGammaSize (DISPLAY (crtc), crtc->id);
2468
2469 return TRUE;
2470}
2471
2472static void
2473crtc_free (GnomeRRCrtc *crtc)
2474{
2475 g_free (crtc->current_outputs);
2476 g_free (crtc->possible_outputs);
2477 g_slice_free (GnomeRRCrtc, crtc);
2478}
2479
2480/* GnomeRRMode */
2481static GnomeRRMode *
2482mode_new (ScreenInfo *info, RRMode id)
2483{
2484 GnomeRRMode *mode = g_slice_new0 (GnomeRRMode);
2485
2486 mode->id = id;
2487 mode->info = info;
2488
2489 return mode;
2490}
2491
2492guint32
2493gnome_rr_mode_get_id (GnomeRRMode *mode)
2494{
2495 g_return_val_if_fail (mode != NULL, 0);
2496 return mode->id;
2497}
2498
2499guint
2500gnome_rr_mode_get_width (GnomeRRMode *mode)
2501{
2502 g_return_val_if_fail (mode != NULL, 0);
2503 return mode->width;
2504}
2505
2506int
2507gnome_rr_mode_get_freq (GnomeRRMode *mode)
2508{
2509 g_return_val_if_fail (mode != NULL, 0);
2510 return (mode->freq) / 1000;
2511}
2512
2513guint
2514gnome_rr_mode_get_height (GnomeRRMode *mode)
2515{
2516 g_return_val_if_fail (mode != NULL, 0);
2517 return mode->height;
2518}
2519
2520static void
2521mode_initialize (GnomeRRMode *mode, XRRModeInfo *info)
2522{
2523 g_assert (mode != NULL);
2524 g_assert (info != NULL);
2525
2526 mode->name = g_strdup (info->name);
2527 mode->width = info->width;
2528 mode->height = info->height;
2529 mode->freq = ((info->dotClock / (double)info->hTotal) / info->vTotal + 0.5) * 1000;
2530}
2531
2532static GnomeRRMode *
2533mode_copy (const GnomeRRMode *from)
2534{
2535 GnomeRRMode *to = g_slice_new0 (GnomeRRMode);
2536
2537 to->id = from->id;
2538 to->info = from->info;
2539 to->name = g_strdup (from->name);
2540 to->width = from->width;
2541 to->height = from->height;
2542 to->freq = from->freq;
2543
2544 return to;
2545}
2546
2547static void
2548mode_free (GnomeRRMode *mode)
2549{
2550 g_free (mode->name);
2551 g_slice_free (GnomeRRMode, mode);
2552}
2553
2554void
2555gnome_rr_crtc_set_gamma (GnomeRRCrtc *crtc, int size,
2556 unsigned short *red,
2557 unsigned short *green,
2558 unsigned short *blue)
2559{
2560 int copy_size;
2561 XRRCrtcGamma *gamma;
2562
2563 g_return_if_fail (crtc != NULL);
2564 g_return_if_fail (red != NULL);
2565 g_return_if_fail (green != NULL);
2566 g_return_if_fail (blue != NULL);
2567
2568 if (size != crtc->gamma_size)
2569 return;
2570
2571 gamma = XRRAllocGamma (crtc->gamma_size);
2572
2573 copy_size = crtc->gamma_size * sizeof (unsigned short);
2574 memcpy (gamma->red, red, copy_size);
2575 memcpy (gamma->green, green, copy_size);
2576 memcpy (gamma->blue, blue, copy_size);
2577
2578 XRRSetCrtcGamma (DISPLAY (crtc), crtc->id, gamma);
2579 XRRFreeGamma (gamma);
2580}
2581
2582gboolean
2583gnome_rr_crtc_get_gamma (GnomeRRCrtc *crtc, int *size,
2584 unsigned short **red, unsigned short **green,
2585 unsigned short **blue)
2586{
2587 int copy_size;
2588 unsigned short *r, *g, *b;
2589 XRRCrtcGamma *gamma;
2590
2591 g_return_val_if_fail (crtc != NULL, FALSE);
2592
2593 gamma = XRRGetCrtcGamma (DISPLAY (crtc), crtc->id);
2594 if (!gamma)
2595 return FALSE;
2596
2597 copy_size = crtc->gamma_size * sizeof (unsigned short);
2598
2599 if (red) {
2600 r = g_new0 (unsigned short, crtc->gamma_size);
2601 memcpy (r, gamma->red, copy_size);
2602 *red = r;
2603 }
2604
2605 if (green) {
2606 g = g_new0 (unsigned short, crtc->gamma_size);
2607 memcpy (g, gamma->green, copy_size);
2608 *green = g;
2609 }
2610
2611 if (blue) {
2612 b = g_new0 (unsigned short, crtc->gamma_size);
2613 memcpy (b, gamma->blue, copy_size);
2614 *blue = b;
2615 }
2616
2617 XRRFreeGamma (gamma);
2618
2619 if (size)
2620 *size = crtc->gamma_size;
2621
2622 return TRUE;
2623}
2624
02625
=== modified file 'debian/changelog'
--- debian/changelog 2015-03-31 10:59:01 +0000
+++ debian/changelog 2015-11-20 08:10:07 +0000
@@ -1,3 +1,10 @@
1gnome-desktop3 (3.8.4-0ubuntu3.2) trusty-proposed; urgency=medium
2
3 * Apply the similar method from the power plugin in unity-settings-daemon to
4 fix the lowest brightness issue. (LP: #1381625)
5
6 -- Shih-Yuan Lee (FourDollars) <sylee@canonical.com> Fri, 20 Nov 2015 15:35:36 +0800
7
1gnome-desktop3 (3.8.4-0ubuntu3.1) trusty; urgency=medium8gnome-desktop3 (3.8.4-0ubuntu3.1) trusty; urgency=medium
29
3 * debian/patches/idletime_sanity_checks.patch: Ensure the argument to 10 * debian/patches/idletime_sanity_checks.patch: Ensure the argument to
411
=== added file 'debian/patches/fix_lowest_brightness.patch'
--- debian/patches/fix_lowest_brightness.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/fix_lowest_brightness.patch 2015-11-20 08:10:07 +0000
@@ -0,0 +1,21 @@
1Description: Apply the similar method to fix the lowest brightness issue. (LP: #1381625)
2Author: Shih-Yuan Lee (FourDollars) <sylee@canonical.com>
3Bug: https://bugs.launchpad.net/bugs/1381625
4---
5This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
6Index: trusty/libgnome-desktop/gnome-rr.c
7===================================================================
8--- trusty.orig/libgnome-desktop/gnome-rr.c 2015-11-20 15:20:59.316229000 +0800
9+++ trusty/libgnome-desktop/gnome-rr.c 2015-11-20 15:30:13.759172830 +0800
10@@ -1553,6 +1553,11 @@
11 }
12 output->backlight_min = info->values[0];
13 output->backlight_max = info->values[1];
14+ /* If the interface has more than 99 possible values, it's
15+ * * likely that 0 turns the backlight off so we let 1 be
16+ * * set in that case. */
17+ if (output->backlight_max > 99 && output->backlight_min == 0)
18+ output->backlight_min = 1;
19 out:
20 if (info != NULL)
21 {
022
=== modified file 'debian/patches/series'
--- debian/patches/series 2015-03-31 10:59:01 +0000
+++ debian/patches/series 2015-11-20 08:10:07 +0000
@@ -9,3 +9,4 @@
9ignore_errors_with_primary_outputs.patch9ignore_errors_with_primary_outputs.patch
10backlight-property-name.patch10backlight-property-name.patch
11idletime_sanity_checks.patch11idletime_sanity_checks.patch
12fix_lowest_brightness.patch
1213
=== modified file 'libgnome-desktop/gnome-rr.c'
--- libgnome-desktop/gnome-rr.c 2014-03-17 17:28:55 +0000
+++ libgnome-desktop/gnome-rr.c 2015-11-20 08:10:07 +0000
@@ -1553,6 +1553,11 @@
1553 }1553 }
1554 output->backlight_min = info->values[0];1554 output->backlight_min = info->values[0];
1555 output->backlight_max = info->values[1];1555 output->backlight_max = info->values[1];
1556 /* If the interface has more than 99 possible values, it's
1557 * * likely that 0 turns the backlight off so we let 1 be
1558 * * set in that case. */
1559 if (output->backlight_max > 99 && output->backlight_min == 0)
1560 output->backlight_min = 1;
1556out:1561out:
1557 if (info != NULL)1562 if (info != NULL)
1558 {1563 {

Subscribers

People subscribed via source and target branches

to all changes: