3
* Copyright 2007, 2008, Red Hat, Inc.
5
* This file is part of the Gnome Library.
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.
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.
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.
22
* Author: Soren Sandmann <sandmann@redhat.com>
25
#define GNOME_DESKTOP_USE_UNSTABLE_API
28
#include <glib/gi18n-lib.h>
32
#include <X11/extensions/Xrandr.h>
36
#include <X11/Xatom.h>
37
#include <X11/extensions/dpms.h>
39
#undef GNOME_DISABLE_DEPRECATED
41
#include "gnome-rr-config.h"
44
#include "gnome-rr-private.h"
46
#define DISPLAY(o) ((o)->info->screen->priv->xdisplay)
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))
52
SCREEN_PROP_GDK_SCREEN,
58
SCREEN_OUTPUT_CONNECTED,
59
SCREEN_OUTPUT_DISCONNECTED,
63
gint screen_signals[SCREEN_SIGNAL_LAST];
72
GnomeRRCrtc * current_crtc;
76
GnomeRRCrtc ** possible_crtcs;
77
GnomeRROutput ** clones;
82
char * connector_type;
87
struct GnomeRROutputWrap
97
GnomeRRMode * current_mode;
98
GnomeRROutput ** current_outputs;
99
GnomeRROutput ** possible_outputs;
103
GnomeRRRotation current_rotation;
104
GnomeRRRotation rotations;
115
int freq; /* in mHz */
119
static GnomeRRCrtc * crtc_new (ScreenInfo *info,
121
static GnomeRRCrtc * crtc_copy (const GnomeRRCrtc *from);
122
static void crtc_free (GnomeRRCrtc *crtc);
124
static gboolean crtc_initialize (GnomeRRCrtc *crtc,
125
XRRScreenResources *res,
129
static GnomeRROutput *output_new (ScreenInfo *info,
132
static gboolean output_initialize (GnomeRROutput *output,
133
XRRScreenResources *res,
136
static GnomeRROutput *output_copy (const GnomeRROutput *from);
137
static void output_free (GnomeRROutput *output);
140
static GnomeRRMode * mode_new (ScreenInfo *info,
143
static void mode_initialize (GnomeRRMode *mode,
146
static GnomeRRMode * mode_copy (const GnomeRRMode *from);
147
static void mode_free (GnomeRRMode *mode);
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))
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)
164
* gnome_rr_error_quark:
166
* Returns the #GQuark that will be used for #GError values returned by the
169
* Return value: a #GQuark used to identify errors coming from the GnomeRR API.
172
gnome_rr_error_quark (void)
174
return g_quark_from_static_string ("gnome-rr-error-quark");
178
static GnomeRROutput *
179
gnome_rr_output_by_id (ScreenInfo *info, RROutput id)
181
GnomeRROutput **output;
183
g_assert (info != NULL);
185
for (output = info->outputs; *output; ++output)
187
if ((*output)->id == id)
195
crtc_by_id (ScreenInfo *info, RRCrtc id)
202
for (crtc = info->crtcs; *crtc; ++crtc)
204
if ((*crtc)->id == id)
212
mode_by_id (ScreenInfo *info, RRMode id)
216
g_assert (info != NULL);
218
for (mode = info->modes; *mode; ++mode)
220
if ((*mode)->id == id)
228
screen_info_free (ScreenInfo *info)
230
GnomeRROutput **output;
234
g_assert (info != NULL);
238
XRRFreeScreenResources (info->resources);
240
info->resources = NULL;
245
for (output = info->outputs; *output; ++output)
246
output_free (*output);
247
g_free (info->outputs);
252
for (crtc = info->crtcs; *crtc; ++crtc)
254
g_free (info->crtcs);
259
for (mode = info->modes; *mode; ++mode)
261
g_free (info->modes);
264
if (info->clone_modes)
266
/* The modes themselves were freed above */
267
g_free (info->clone_modes);
274
has_similar_mode (GnomeRROutput *output, GnomeRRMode *mode)
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);
281
for (i = 0; modes[i] != NULL; ++i)
283
GnomeRRMode *m = modes[i];
285
if (gnome_rr_mode_get_width (m) == width &&
286
gnome_rr_mode_get_height (m) == height)
296
gather_clone_modes (ScreenInfo *info)
299
GPtrArray *result = g_ptr_array_new ();
301
for (i = 0; info->outputs[i] != NULL; ++i)
304
GnomeRROutput *output1, *output2;
306
output1 = info->outputs[i];
308
if (!output1->connected)
311
for (j = 0; output1->modes[j] != NULL; ++j)
313
GnomeRRMode *mode = output1->modes[j];
318
for (k = 0; info->outputs[k] != NULL; ++k)
320
output2 = info->outputs[k];
322
if (!output2->connected)
325
if (!has_similar_mode (output2, mode))
333
g_ptr_array_add (result, mode);
337
g_ptr_array_add (result, NULL);
339
info->clone_modes = (GnomeRRMode **)g_ptr_array_free (result, FALSE);
343
fill_screen_info_from_resources (ScreenInfo *info,
344
XRRScreenResources *resources,
350
GnomeRROutput **output;
352
info->resources = resources;
354
/* We create all the structures before initializing them, so
355
* that they can refer to each other.
357
a = g_ptr_array_new ();
358
for (i = 0; i < resources->ncrtc; ++i)
360
GnomeRRCrtc *crtc = crtc_new (info, resources->crtcs[i]);
362
g_ptr_array_add (a, crtc);
364
g_ptr_array_add (a, NULL);
365
info->crtcs = (GnomeRRCrtc **)g_ptr_array_free (a, FALSE);
367
a = g_ptr_array_new ();
368
for (i = 0; i < resources->noutput; ++i)
370
GnomeRROutput *output = output_new (info, resources->outputs[i]);
372
g_ptr_array_add (a, output);
374
g_ptr_array_add (a, NULL);
375
info->outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
377
a = g_ptr_array_new ();
378
for (i = 0; i < resources->nmode; ++i)
380
GnomeRRMode *mode = mode_new (info, resources->modes[i].id);
382
g_ptr_array_add (a, mode);
384
g_ptr_array_add (a, NULL);
385
info->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
388
for (crtc = info->crtcs; *crtc; ++crtc)
390
if (!crtc_initialize (*crtc, resources, error))
394
for (output = info->outputs; *output; ++output)
396
if (!output_initialize (*output, resources, error))
400
for (i = 0; i < resources->nmode; ++i)
402
GnomeRRMode *mode = mode_by_id (info, resources->modes[i].id);
404
mode_initialize (mode, &(resources->modes[i]));
407
gather_clone_modes (info);
413
fill_out_screen_info (Display *xdisplay,
416
gboolean needs_reprobe,
419
XRRScreenResources *resources;
420
GnomeRRScreenPrivate *priv;
422
g_assert (xdisplay != NULL);
423
g_assert (info != NULL);
425
priv = info->screen->priv;
427
/* First update the screen resources */
430
resources = XRRGetScreenResources (xdisplay, xroot);
433
/* XRRGetScreenResourcesCurrent is less expensive than
434
* XRRGetScreenResources, however it is available only
435
* in RandR 1.3 or higher
437
if (SERVERS_RANDR_IS_AT_LEAST_1_3 (priv))
438
resources = XRRGetScreenResourcesCurrent (xdisplay, xroot);
440
resources = XRRGetScreenResources (xdisplay, xroot);
445
if (!fill_screen_info_from_resources (info, resources, error))
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)"));
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.
463
gdk_error_trap_push ();
464
success = XRRGetScreenSizeRange (xdisplay, xroot,
468
&(info->max_height));
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"));
477
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
478
_("could not get the range of screen sizes"));
484
gnome_rr_screen_get_ranges (info->screen,
488
&(info->max_height));
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 ();
498
/* can the screen do DPMS? */
499
gdk_error_trap_push ();
500
priv->dpms_capable = DPMSCapable (priv->xdisplay);
501
gdk_error_trap_pop_ignored ();
507
screen_info_new (GnomeRRScreen *screen, gboolean needs_reprobe, GError **error)
509
ScreenInfo *info = g_new0 (ScreenInfo, 1);
510
GnomeRRScreenPrivate *priv;
512
g_assert (screen != NULL);
516
info->outputs = NULL;
519
info->screen = screen;
521
if (fill_out_screen_info (priv->xdisplay, priv->xroot, info, needs_reprobe, error))
527
screen_info_free (info);
532
static GnomeRROutput *
533
find_output_by_id (GnomeRROutput **haystack, guint32 id)
537
for (i = 0; haystack[i] != NULL; i++)
539
if (gnome_rr_output_get_id (haystack[i]) == id)
546
diff_outputs_and_emit_signals (ScreenInfo *old, ScreenInfo *new)
549
guint32 id_old, id_new;
550
GnomeRROutput *output_old;
551
GnomeRROutput *output_new;
553
/* have any outputs been removed or disconnected */
554
for (i = 0; old->outputs[i] != NULL; i++)
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)
560
/* output removed (and disconnected) */
561
if (gnome_rr_output_is_connected (old->outputs[i]))
563
g_signal_emit (G_OBJECT (new->screen),
564
screen_signals[SCREEN_OUTPUT_DISCONNECTED], 0,
569
if (gnome_rr_output_is_connected (old->outputs[i]) &&
570
!gnome_rr_output_is_connected (output_new))
572
/* output disconnected */
573
g_signal_emit (G_OBJECT (new->screen),
574
screen_signals[SCREEN_OUTPUT_DISCONNECTED], 0,
579
/* have any outputs been created or connected */
580
for (i = 0; new->outputs[i] != NULL; i++)
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)
587
if (gnome_rr_output_is_connected (new->outputs[i]))
589
g_signal_emit (G_OBJECT (new->screen),
590
screen_signals[SCREEN_OUTPUT_CONNECTED], 0,
595
if (!gnome_rr_output_is_connected (output_old) &&
596
gnome_rr_output_is_connected (new->outputs[i]))
598
/* output connected */
599
g_signal_emit (G_OBJECT (new->screen),
600
screen_signals[SCREEN_OUTPUT_CONNECTED], 0,
607
screen_update (GnomeRRScreen *screen, gboolean force_callback, gboolean needs_reprobe, GError **error)
610
gboolean changed = FALSE;
612
g_assert (screen != NULL);
614
info = screen_info_new (screen, needs_reprobe, error);
618
if (info->resources->configTimestamp != screen->priv->info->resources->configTimestamp)
621
/* work out if any outputs have changed connected state */
622
diff_outputs_and_emit_signals (screen->priv->info, info);
624
screen_info_free (screen->priv->info);
626
screen->priv->info = info;
628
if (changed || force_callback)
629
g_signal_emit (G_OBJECT (screen), screen_signals[SCREEN_CHANGED], 0);
634
static GdkFilterReturn
635
screen_on_event (GdkXEvent *xevent,
639
GnomeRRScreen *screen = data;
640
GnomeRRScreenPrivate *priv = screen->priv;
645
return GDK_FILTER_CONTINUE;
647
event_num = e->type - priv->randr_event_base;
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!
654
screen_update (screen, TRUE, FALSE, NULL); /* NULL-GError */
656
/* Enable this code to get a dialog showing the RANDR timestamps, for debugging purposes */
659
XRRScreenChangeNotifyEvent *rr_event;
660
static int dialog_num;
662
rr_event = (XRRScreenChangeNotifyEvent *) e;
664
dialog = gtk_message_dialog_new (NULL,
668
"RRScreenChangeNotify timestamps (%d):\n"
671
"event serial: %lu\n"
672
"----------------------"
673
"screen change: %u\n"
674
"screen config: %u\n",
676
(guint32) rr_event->timestamp,
677
(guint32) rr_event->config_timestamp,
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);
688
/* WHY THIS CODE IS DISABLED:
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"
696
* If we ever run into a situtation that could benefit from processing more
697
* detailed events, we can enable this code again.
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().
702
else if (event_num == RRNotify)
704
/* Other RandR events */
706
XRRNotifyEvent *event = (XRRNotifyEvent *)e;
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().
713
switch (event->subtype)
719
/* No need to reprobe hardware here */
720
screen_update (screen, TRUE, FALSE, NULL); /* NULL-GError */
724
/* Pass the event on to GTK+ */
725
return GDK_FILTER_CONTINUE;
729
gnome_rr_screen_initable_init (GInitable *initable, GCancellable *canc, GError **error)
731
GnomeRRScreen *self = GNOME_RR_SCREEN (initable);
732
GnomeRRScreenPrivate *priv = self->priv;
733
Display *dpy = GDK_SCREEN_XDISPLAY (self->priv->gdk_screen);
737
priv->connector_type_atom = XInternAtom (dpy, "ConnectorType", FALSE);
739
if (XRRQueryExtension (dpy, &event_base, &ignore))
741
priv->randr_event_base = event_base;
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)");
750
priv->info = screen_info_new (self, TRUE, error);
756
XRRSelectInput (priv->xdisplay,
758
RRScreenChangeNotifyMask);
759
gdk_x11_register_standard_event_type (gdk_screen_get_display (priv->gdk_screen),
762
gdk_window_add_filter (priv->gdk_root, screen_on_event, self);
768
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_RANDR_EXTENSION,
769
_("RANDR extension is not present"));
776
gnome_rr_screen_initable_iface_init (GInitableIface *iface)
778
iface->init = gnome_rr_screen_initable_init;
782
gnome_rr_screen_finalize (GObject *gobject)
784
GnomeRRScreen *screen = GNOME_RR_SCREEN (gobject);
786
gdk_window_remove_filter (screen->priv->gdk_root, screen_on_event, screen);
788
if (screen->priv->info)
789
screen_info_free (screen->priv->info);
791
G_OBJECT_CLASS (gnome_rr_screen_parent_class)->finalize (gobject);
795
gnome_rr_screen_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *property)
797
GnomeRRScreen *self = GNOME_RR_SCREEN (gobject);
798
GnomeRRScreenPrivate *priv = self->priv;
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);
810
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
816
gnome_rr_screen_get_property (GObject *gobject, guint property_id, GValue *value, GParamSpec *property)
818
GnomeRRScreen *self = GNOME_RR_SCREEN (gobject);
819
GnomeRRScreenPrivate *priv = self->priv;
823
case SCREEN_PROP_GDK_SCREEN:
824
g_value_set_object (value, priv->gdk_screen);
827
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
833
gnome_rr_screen_class_init (GnomeRRScreenClass *klass)
835
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
836
g_type_class_add_private (klass, sizeof (GnomeRRScreenPrivate));
838
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
839
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
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;
845
g_object_class_install_property(
847
SCREEN_PROP_GDK_SCREEN,
848
g_param_spec_object (
851
"The GDK Screen represented by this GnomeRRScreen",
854
G_PARAM_CONSTRUCT_ONLY |
855
G_PARAM_STATIC_STRINGS)
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),
864
g_cclosure_marshal_VOID__VOID,
869
* GnomeRRScreen::output-connected:
870
* @screen: the #GnomeRRScreen that emitted the signal
871
* @output: the #GnomeRROutput that was connected
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
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
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),
893
g_cclosure_marshal_VOID__POINTER,
898
* GnomeRRScreen::output-disconnected:
899
* @screen: the #GnomeRRScreen that emitted the signal
900
* @output: the #GnomeRROutput that was disconnected
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.
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
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),
921
g_cclosure_marshal_VOID__POINTER,
927
gnome_rr_screen_init (GnomeRRScreen *self)
929
GnomeRRScreenPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_RR_SCREEN, GnomeRRScreenPrivate);
932
priv->gdk_screen = NULL;
933
priv->gdk_root = NULL;
934
priv->xdisplay = NULL;
936
priv->xscreen = NULL;
938
priv->rr_major_version = 0;
939
priv->rr_minor_version = 0;
942
/* Weak reference callback set in gnome_rr_screen_new(); we remove the GObject data from the GdkScreen. */
944
rr_screen_weak_notify_cb (gpointer data, GObject *where_the_object_was)
946
GdkScreen *screen = GDK_SCREEN (data);
948
g_object_set_data (G_OBJECT (screen), "GnomeRRScreen", NULL);
952
* gnome_rr_screen_new:
953
* @screen: the #GdkScreen on which to operate
954
* @error: will be set if XRandR is not supported
956
* Creates a unique #GnomeRRScreen instance for the specified @screen.
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.
963
gnome_rr_screen_new (GdkScreen *screen,
966
GnomeRRScreen *rr_screen;
968
g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
969
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
971
rr_screen = g_object_get_data (G_OBJECT (screen), "GnomeRRScreen");
973
g_object_ref (rr_screen);
975
rr_screen = g_initable_new (GNOME_TYPE_RR_SCREEN, NULL, error, "gdk-screen", screen, NULL);
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);
986
gnome_rr_screen_set_size (GnomeRRScreen *screen,
992
g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
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 ();
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
1008
* Get the ranges of the screen
1011
gnome_rr_screen_get_ranges (GnomeRRScreen *screen,
1017
GnomeRRScreenPrivate *priv;
1019
g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
1021
priv = screen->priv;
1024
*min_width = priv->info->min_width;
1027
*max_width = priv->info->max_width;
1030
*min_height = priv->info->min_height;
1033
*max_height = priv->info->max_height;
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
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.
1049
gnome_rr_screen_get_timestamps (GnomeRRScreen *screen,
1050
guint32 *change_timestamp_ret,
1051
guint32 *config_timestamp_ret)
1053
GnomeRRScreenPrivate *priv;
1055
g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
1057
priv = screen->priv;
1059
if (change_timestamp_ret)
1060
*change_timestamp_ret = priv->info->resources->timestamp;
1062
if (config_timestamp_ret)
1063
*config_timestamp_ret = priv->info->resources->configTimestamp;
1067
force_timestamp_update (GnomeRRScreen *screen)
1069
GnomeRRScreenPrivate *priv = screen->priv;
1071
XRRCrtcInfo *current_info;
1073
gboolean timestamp_updated;
1075
timestamp_updated = FALSE;
1077
crtc = priv->info->crtcs[0];
1082
current_info = XRRGetCrtcInfo (priv->xdisplay,
1083
priv->info->resources,
1086
if (current_info == NULL)
1089
gdk_error_trap_push ();
1090
status = XRRSetCrtcConfig (priv->xdisplay,
1091
priv->info->resources,
1093
current_info->timestamp,
1097
current_info->rotation,
1098
current_info->outputs,
1099
current_info->noutput);
1101
XRRFreeCrtcInfo (current_info);
1104
if (gdk_error_trap_pop ())
1107
if (status == RRSetConfigSuccess)
1108
timestamp_updated = TRUE;
1110
return timestamp_updated;
1114
* gnome_rr_screen_refresh:
1115
* @screen: a #GnomeRRScreen
1116
* @error: location to store error, or %NULL
1118
* Refreshes the screen configuration, and calls the screen's callback if it
1119
* exists and if the screen's configuration changed.
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
1127
gnome_rr_screen_refresh (GnomeRRScreen *screen,
1132
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1134
gdk_x11_display_grab (gdk_screen_get_display (screen->priv->gdk_screen));
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 */
1139
gdk_x11_display_ungrab (gdk_screen_get_display (screen->priv->gdk_screen));
1145
* gnome_rr_screen_get_dpms_mode:
1146
* @mode: (out): The current #GnomeRRDpmsMode of this screen
1149
gnome_rr_screen_get_dpms_mode (GnomeRRScreen *screen,
1150
GnomeRRDpmsMode *mode,
1153
BOOL enabled = FALSE;
1155
gboolean ret = FALSE;
1157
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1158
g_return_val_if_fail (mode != NULL, FALSE);
1160
if (!screen->priv->dpms_capable) {
1161
g_set_error_literal (error,
1163
GNOME_RR_ERROR_NO_DPMS_EXTENSION,
1164
"Display is not DPMS capable");
1168
if (!DPMSInfo (screen->priv->xdisplay,
1171
g_set_error_literal (error,
1173
GNOME_RR_ERROR_UNKNOWN,
1174
"Unable to get DPMS state");
1178
/* DPMS not enabled is a valid mode */
1180
*mode = GNOME_RR_DPMS_DISABLED;
1187
*mode = GNOME_RR_DPMS_ON;
1189
case DPMSModeStandby:
1190
*mode = GNOME_RR_DPMS_STANDBY;
1192
case DPMSModeSuspend:
1193
*mode = GNOME_RR_DPMS_SUSPEND;
1196
*mode = GNOME_RR_DPMS_OFF;
1199
g_assert_not_reached ();
1208
* gnome_rr_screen_clear_dpms_timeouts:
1211
gnome_rr_screen_clear_dpms_timeouts (GnomeRRScreen *screen,
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,
1220
GNOME_RR_ERROR_UNKNOWN,
1221
"Could not set DPMS timeouts");
1228
* gnome_rr_screen_set_dpms_mode:
1230
* This method also disables the DPMS timeouts.
1233
gnome_rr_screen_set_dpms_mode (GnomeRRScreen *screen,
1234
GnomeRRDpmsMode mode,
1239
GnomeRRDpmsMode current_mode;
1241
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1243
/* set, if the new mode is different */
1244
ret = gnome_rr_screen_get_dpms_mode (screen, ¤t_mode, error);
1247
if (current_mode == mode) {
1248
ret = gnome_rr_screen_clear_dpms_timeouts (screen, error);
1253
case GNOME_RR_DPMS_ON:
1256
case GNOME_RR_DPMS_STANDBY:
1257
state = DPMSModeStandby;
1259
case GNOME_RR_DPMS_SUSPEND:
1260
state = DPMSModeSuspend;
1262
case GNOME_RR_DPMS_OFF:
1263
state = DPMSModeOff;
1266
g_assert_not_reached ();
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 ()) {
1276
g_set_error_literal (error,
1278
GNOME_RR_ERROR_UNKNOWN,
1279
"Could not change DPMS mode");
1283
ret = gnome_rr_screen_clear_dpms_timeouts (screen, error);
1291
* gnome_rr_screen_list_modes:
1293
* List available XRandR modes
1295
* Returns: (array zero-terminated=1) (transfer none):
1298
gnome_rr_screen_list_modes (GnomeRRScreen *screen)
1300
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1301
g_return_val_if_fail (screen->priv->info != NULL, NULL);
1303
return screen->priv->info->modes;
1307
* gnome_rr_screen_list_clone_modes:
1309
* List available XRandR clone modes
1311
* Returns: (array zero-terminated=1) (transfer none):
1314
gnome_rr_screen_list_clone_modes (GnomeRRScreen *screen)
1316
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1317
g_return_val_if_fail (screen->priv->info != NULL, NULL);
1319
return screen->priv->info->clone_modes;
1323
* gnome_rr_screen_list_crtcs:
1327
* Returns: (array zero-terminated=1) (transfer none):
1330
gnome_rr_screen_list_crtcs (GnomeRRScreen *screen)
1332
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1333
g_return_val_if_fail (screen->priv->info != NULL, NULL);
1335
return screen->priv->info->crtcs;
1339
* gnome_rr_screen_list_outputs:
1343
* Returns: (array zero-terminated=1) (transfer none):
1346
gnome_rr_screen_list_outputs (GnomeRRScreen *screen)
1348
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1349
g_return_val_if_fail (screen->priv->info != NULL, NULL);
1351
return screen->priv->info->outputs;
1355
* gnome_rr_screen_get_crtc_by_id:
1357
* Returns: (transfer none): the CRTC identified by @id
1360
gnome_rr_screen_get_crtc_by_id (GnomeRRScreen *screen,
1363
GnomeRRCrtc **crtcs;
1366
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1367
g_return_val_if_fail (screen->priv->info != NULL, NULL);
1369
crtcs = screen->priv->info->crtcs;
1371
for (i = 0; crtcs[i] != NULL; ++i)
1373
if (crtcs[i]->id == id)
1381
* gnome_rr_screen_get_output_by_id:
1383
* Returns: (transfer none): the output identified by @id
1386
gnome_rr_screen_get_output_by_id (GnomeRRScreen *screen,
1389
GnomeRROutput **outputs;
1392
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1393
g_return_val_if_fail (screen->priv->info != NULL, NULL);
1395
outputs = screen->priv->info->outputs;
1397
for (i = 0; outputs[i] != NULL; ++i)
1399
if (outputs[i]->id == id)
1407
static GnomeRROutput *
1408
output_new (ScreenInfo *info, RROutput id)
1410
GnomeRROutput *output = g_slice_new0 (GnomeRROutput);
1413
output->info = info;
1419
get_property (Display *dpy,
1424
unsigned char *prop;
1426
unsigned long nitems, bytes_after;
1430
XRRGetOutputProperty (dpy, output, atom,
1431
0, 100, False, False,
1433
&actual_type, &actual_format,
1434
&nitems, &bytes_after, &prop);
1436
if (actual_type == XA_INTEGER && actual_format == 8)
1438
result = g_memdup (prop, nitems);
1453
read_edid_data (GnomeRROutput *output, gsize *len)
1458
edid_atom = XInternAtom (DISPLAY (output), "EDID", FALSE);
1459
result = get_property (DISPLAY (output),
1460
output->id, edid_atom, len);
1464
edid_atom = XInternAtom (DISPLAY (output), "EDID_DATA", FALSE);
1465
result = get_property (DISPLAY (output),
1466
output->id, edid_atom, len);
1471
edid_atom = XInternAtom (DISPLAY (output), "XFree86_DDC_EDID1_RAWDATA", FALSE);
1472
result = get_property (DISPLAY (output),
1473
output->id, edid_atom, len);
1478
if (*len % 128 == 0)
1488
get_connector_type_string (GnomeRROutput *output)
1491
unsigned char *prop;
1493
unsigned long nitems, bytes_after;
1495
Atom connector_type;
1496
char *connector_type_str;
1500
if (XRRGetOutputProperty (DISPLAY (output), output->id, output->info->screen->priv->connector_type_atom,
1501
0, 100, False, False,
1503
&actual_type, &actual_format,
1504
&nitems, &bytes_after, &prop) != Success)
1507
if (!(actual_type == XA_ATOM && actual_format == 32 && nitems == 1))
1510
connector_type = *((Atom *) prop);
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);
1526
update_brightness_limits (GnomeRROutput *output)
1530
XRRPropertyInfo *info;
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 ();
1539
g_warning ("could not get output property for %s, rc: %i",
1545
g_warning ("could not get output property for %s",
1549
if (!info->range || info->num_values != 2)
1551
g_debug ("backlight %s was not range", output->name);
1554
output->backlight_min = info->values[0];
1555
output->backlight_max = info->values[1];
1564
output_initialize (GnomeRROutput *output, XRRScreenResources *res, GError **error)
1566
XRROutputInfo *info = XRRGetOutputInfo (
1567
DISPLAY (output), res, output->id);
1572
g_print ("Output %lx Timestamp: %u\n", output->id, (guint32)info->timestamp);
1575
if (!info || !output->info)
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"),
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);
1593
/* Possible crtcs */
1594
a = g_ptr_array_new ();
1596
for (i = 0; i < info->ncrtc; ++i)
1598
GnomeRRCrtc *crtc = crtc_by_id (output->info, info->crtcs[i]);
1601
g_ptr_array_add (a, crtc);
1603
g_ptr_array_add (a, NULL);
1604
output->possible_crtcs = (GnomeRRCrtc **)g_ptr_array_free (a, FALSE);
1607
a = g_ptr_array_new ();
1608
for (i = 0; i < info->nclone; ++i)
1610
GnomeRROutput *gnome_rr_output = gnome_rr_output_by_id (output->info, info->clones[i]);
1612
if (gnome_rr_output)
1613
g_ptr_array_add (a, gnome_rr_output);
1615
g_ptr_array_add (a, NULL);
1616
output->clones = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
1619
a = g_ptr_array_new ();
1620
for (i = 0; i < info->nmode; ++i)
1622
GnomeRRMode *mode = mode_by_id (output->info, info->modes[i]);
1625
g_ptr_array_add (a, mode);
1627
g_ptr_array_add (a, NULL);
1628
output->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
1630
output->n_preferred = info->npreferred;
1633
output->edid_data = read_edid_data (output, &output->edid_size);
1635
/* brightness data */
1636
if (output->connected)
1637
update_brightness_limits (output);
1639
XRRFreeOutputInfo (info);
1644
static GnomeRROutput*
1645
output_copy (const GnomeRROutput *from)
1648
GnomeRRCrtc **p_crtc;
1649
GnomeRROutput **p_output;
1650
GnomeRRMode **p_mode;
1651
GnomeRROutput *output = g_slice_new0 (GnomeRROutput);
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;
1665
array = g_ptr_array_new ();
1666
for (p_crtc = from->possible_crtcs; *p_crtc != NULL; p_crtc++)
1668
g_ptr_array_add (array, *p_crtc);
1670
output->possible_crtcs = (GnomeRRCrtc**) g_ptr_array_free (array, FALSE);
1672
array = g_ptr_array_new ();
1673
for (p_output = from->clones; *p_output != NULL; p_output++)
1675
g_ptr_array_add (array, *p_output);
1677
output->clones = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
1679
array = g_ptr_array_new ();
1680
for (p_mode = from->modes; *p_mode != NULL; p_mode++)
1682
g_ptr_array_add (array, *p_mode);
1684
output->modes = (GnomeRRMode**) g_ptr_array_free (array, FALSE);
1686
output->edid_size = from->edid_size;
1687
output->edid_data = g_memdup (from->edid_data, from->edid_size);
1693
output_free (GnomeRROutput *output)
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);
1706
gnome_rr_output_get_id (GnomeRROutput *output)
1708
g_assert(output != NULL);
1714
gnome_rr_output_get_edid_data (GnomeRROutput *output, gsize *size)
1716
g_return_val_if_fail (output != NULL, NULL);
1718
*size = output->edid_size;
1719
return output->edid_data;
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):
1730
gnome_rr_output_get_ids_from_edid (GnomeRROutput *output,
1737
g_return_val_if_fail (output != NULL, FALSE);
1739
if (!output->edid_data)
1741
info = decode_edid (output->edid_data);
1745
*vendor = g_memdup (info->manufacturer_code, 4);
1747
*product = info->product_code;
1749
*serial = info->serial_number;
1758
ensure_display_name (GnomeRROutput *output)
1760
if (output->display_name != NULL)
1763
if (gnome_rr_output_is_laptop (output))
1764
output->display_name = g_strdup (_("Built-in Display"));
1766
if (output->display_name == NULL
1767
&& output->edid_data != NULL) {
1770
info = decode_edid (output->edid_data);
1772
output->display_name = make_display_name (info);
1777
if (output->display_name == NULL) {
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);
1787
/* last chance on the stairway */
1788
if (output->display_name == NULL) {
1789
output->display_name = g_strdup (_("Unknown Display"));
1794
gnome_rr_output_get_display_name (GnomeRROutput *output)
1796
g_return_val_if_fail (output != NULL, NULL);
1798
ensure_display_name (output);
1800
return output->display_name;
1804
* gnome_rr_output_get_backlight_min:
1806
* Returns: The mimimum backlight value, or -1 if not supported
1809
gnome_rr_output_get_backlight_min (GnomeRROutput *output)
1811
g_return_val_if_fail (output != NULL, -1);
1812
return output->backlight_min;
1816
* gnome_rr_output_get_backlight_max:
1818
* Returns: The maximum backlight value, or -1 if not supported
1821
gnome_rr_output_get_backlight_max (GnomeRROutput *output)
1823
g_return_val_if_fail (output != NULL, -1);
1824
return output->backlight_max;
1828
* gnome_rr_output_get_backlight:
1830
* Returns: The currently set backlight brightness
1833
gnome_rr_output_get_backlight (GnomeRROutput *output, GError **error)
1836
unsigned long nitems;
1837
unsigned long bytes_after;
1844
g_return_val_if_fail (output != NULL, -1);
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));
1853
if (gdk_error_trap_pop ())
1855
g_set_error_literal (error,
1857
GNOME_RR_ERROR_UNKNOWN,
1858
"unhandled X error while getting the range of backlight values");
1862
if (retval != Success) {
1863
g_set_error_literal (error,
1865
GNOME_RR_ERROR_RANDR_ERROR,
1866
"could not get the range of backlight values");
1869
if (actual_type == XA_INTEGER &&
1871
actual_format == 32)
1873
memcpy (&now, prop, sizeof (guint));
1879
GNOME_RR_ERROR_RANDR_ERROR,
1880
"failed to get correct property type, got %lu,%i",
1881
nitems, actual_format);
1889
* gnome_rr_output_set_backlight:
1890
* @value: the absolute value which is min >= this <= max
1892
* Returns: %TRUE for success
1895
gnome_rr_output_set_backlight (GnomeRROutput *output, gint value, GError **error)
1897
gboolean ret = FALSE;
1900
g_return_val_if_fail (output != NULL, FALSE);
1902
/* check this is sane */
1903
if (value < output->backlight_min ||
1904
value > output->backlight_max)
1908
GNOME_RR_ERROR_BOUNDS_ERROR,
1909
"out of brightness range: %i, has to be %i -> %i",
1911
output->backlight_max, output->backlight_min);
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 ())
1923
g_set_error_literal (error,
1925
GNOME_RR_ERROR_UNKNOWN,
1926
"unhandled X error while setting the backlight values");
1930
/* we assume this succeeded as there's no return value */
1937
* gnome_rr_screen_get_output_by_name:
1939
* Returns: (transfer none): the output identified by @name
1942
gnome_rr_screen_get_output_by_name (GnomeRRScreen *screen,
1947
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1948
g_return_val_if_fail (screen->priv->info != NULL, NULL);
1950
for (i = 0; screen->priv->info->outputs[i] != NULL; ++i)
1952
GnomeRROutput *output = screen->priv->info->outputs[i];
1954
if (strcmp (output->name, name) == 0)
1962
gnome_rr_output_get_crtc (GnomeRROutput *output)
1964
g_return_val_if_fail (output != NULL, NULL);
1966
return output->current_crtc;
1969
/* Returns NULL if the ConnectorType property is not available */
1971
gnome_rr_output_get_connector_type (GnomeRROutput *output)
1973
g_return_val_if_fail (output != NULL, NULL);
1975
return output->connector_type;
1979
_gnome_rr_output_name_is_laptop (const char *name)
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 */
1996
gnome_rr_output_is_laptop (GnomeRROutput *output)
1998
g_return_val_if_fail (output != NULL, FALSE);
2000
if (!output->connected)
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)
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.
2010
if (_gnome_rr_output_name_is_laptop (output->name))
2017
gnome_rr_output_get_current_mode (GnomeRROutput *output)
2021
g_return_val_if_fail (output != NULL, NULL);
2023
if ((crtc = gnome_rr_output_get_crtc (output)))
2024
return gnome_rr_crtc_get_current_mode (crtc);
2030
* gnome_rr_output_get_position:
2031
* @output: a #GnomeRROutput
2032
* @x: (out) (allow-none):
2033
* @y: (out) (allow-none):
2036
gnome_rr_output_get_position (GnomeRROutput *output,
2042
g_return_if_fail (output != NULL);
2044
if ((crtc = gnome_rr_output_get_crtc (output)))
2045
gnome_rr_crtc_get_position (crtc, x, y);
2049
gnome_rr_output_get_name (GnomeRROutput *output)
2051
g_assert (output != NULL);
2052
return output->name;
2056
gnome_rr_output_get_width_mm (GnomeRROutput *output)
2058
g_assert (output != NULL);
2059
return output->width_mm;
2063
gnome_rr_output_get_height_mm (GnomeRROutput *output)
2065
g_assert (output != NULL);
2066
return output->height_mm;
2070
gnome_rr_output_get_preferred_mode (GnomeRROutput *output)
2072
g_return_val_if_fail (output != NULL, NULL);
2073
if (output->n_preferred)
2074
return output->modes[0];
2080
gnome_rr_output_list_modes (GnomeRROutput *output)
2082
g_return_val_if_fail (output != NULL, NULL);
2083
return output->modes;
2087
gnome_rr_output_is_connected (GnomeRROutput *output)
2089
g_return_val_if_fail (output != NULL, FALSE);
2090
return output->connected;
2094
gnome_rr_output_supports_mode (GnomeRROutput *output,
2099
g_return_val_if_fail (output != NULL, FALSE);
2100
g_return_val_if_fail (mode != NULL, FALSE);
2102
for (i = 0; output->modes[i] != NULL; ++i)
2104
if (output->modes[i] == mode)
2112
gnome_rr_output_can_clone (GnomeRROutput *output,
2113
GnomeRROutput *clone)
2117
g_return_val_if_fail (output != NULL, FALSE);
2118
g_return_val_if_fail (clone != NULL, FALSE);
2120
for (i = 0; output->clones[i] != NULL; ++i)
2122
if (output->clones[i] == clone)
2130
gnome_rr_output_get_is_primary (GnomeRROutput *output)
2132
return output->info->primary == output->id;
2136
gnome_rr_screen_set_primary_output (GnomeRRScreen *screen,
2137
GnomeRROutput *output)
2139
GnomeRRScreenPrivate *priv;
2142
g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
2144
priv = screen->priv;
2151
if (SERVERS_RANDR_IS_AT_LEAST_1_3 (priv))
2152
XRRSetOutputPrimary (priv->xdisplay, priv->xroot, id);
2159
GnomeRRRotation rot;
2162
static const RotationMap rotation_map[] =
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 },
2172
static GnomeRRRotation
2173
gnome_rr_rotation_from_xrotation (Rotation r)
2176
GnomeRRRotation result = 0;
2178
for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i)
2180
if (r & rotation_map[i].xrot)
2181
result |= rotation_map[i].rot;
2188
xrotation_from_rotation (GnomeRRRotation r)
2191
Rotation result = 0;
2193
for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i)
2195
if (r & rotation_map[i].rot)
2196
result |= rotation_map[i].xrot;
2203
gnome_rr_crtc_set_config_with_time (GnomeRRCrtc *crtc,
2208
GnomeRRRotation rotation,
2209
GnomeRROutput **outputs,
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);
2227
if (x + mode->width > info->max_width
2228
|| y + mode->height > info->max_height)
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)"),
2238
mode->width, mode->height,
2239
info->max_width, info->max_height);
2244
output_ids = g_array_new (FALSE, FALSE, sizeof (RROutput));
2248
for (i = 0; i < n_outputs; ++i)
2249
g_array_append_val (output_ids, outputs[i]->id);
2252
gdk_error_trap_push ();
2253
status = XRRSetCrtcConfig (DISPLAY (crtc), info->resources, crtc->id,
2256
mode ? mode->id : None,
2257
xrotation_from_rotation (rotation),
2258
(RROutput *)output_ids->data,
2261
g_array_free (output_ids, TRUE);
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"),
2279
gnome_rr_crtc_get_current_mode (GnomeRRCrtc *crtc)
2281
g_return_val_if_fail (crtc != NULL, NULL);
2283
return crtc->current_mode;
2287
gnome_rr_crtc_get_id (GnomeRRCrtc *crtc)
2289
g_return_val_if_fail (crtc != NULL, 0);
2295
gnome_rr_crtc_can_drive_output (GnomeRRCrtc *crtc,
2296
GnomeRROutput *output)
2300
g_return_val_if_fail (crtc != NULL, FALSE);
2301
g_return_val_if_fail (output != NULL, FALSE);
2303
for (i = 0; crtc->possible_outputs[i] != NULL; ++i)
2305
if (crtc->possible_outputs[i] == output)
2312
/* FIXME: merge with get_mode()? */
2314
* gnome_rr_crtc_get_position:
2315
* @crtc: a #GnomeRRCrtc
2316
* @x: (out) (allow-none):
2317
* @y: (out) (allow-none):
2320
gnome_rr_crtc_get_position (GnomeRRCrtc *crtc,
2324
g_return_if_fail (crtc != NULL);
2333
/* FIXME: merge with get_mode()? */
2335
gnome_rr_crtc_get_current_rotation (GnomeRRCrtc *crtc)
2337
g_assert(crtc != NULL);
2338
return crtc->current_rotation;
2342
gnome_rr_crtc_get_rotations (GnomeRRCrtc *crtc)
2344
g_assert(crtc != NULL);
2345
return crtc->rotations;
2349
gnome_rr_crtc_supports_rotation (GnomeRRCrtc * crtc,
2350
GnomeRRRotation rotation)
2352
g_return_val_if_fail (crtc != NULL, FALSE);
2353
return (crtc->rotations & rotation);
2356
static GnomeRRCrtc *
2357
crtc_new (ScreenInfo *info, RROutput id)
2359
GnomeRRCrtc *crtc = g_slice_new0 (GnomeRRCrtc);
2367
static GnomeRRCrtc *
2368
crtc_copy (const GnomeRRCrtc *from)
2370
GnomeRROutput **p_output;
2372
GnomeRRCrtc *to = g_slice_new0 (GnomeRRCrtc);
2374
to->info = from->info;
2376
to->current_mode = from->current_mode;
2379
to->current_rotation = from->current_rotation;
2380
to->rotations = from->rotations;
2381
to->gamma_size = from->gamma_size;
2383
array = g_ptr_array_new ();
2384
for (p_output = from->current_outputs; *p_output != NULL; p_output++)
2386
g_ptr_array_add (array, *p_output);
2388
to->current_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
2390
array = g_ptr_array_new ();
2391
for (p_output = from->possible_outputs; *p_output != NULL; p_output++)
2393
g_ptr_array_add (array, *p_output);
2395
to->possible_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
2401
crtc_initialize (GnomeRRCrtc *crtc,
2402
XRRScreenResources *res,
2405
XRRCrtcInfo *info = XRRGetCrtcInfo (DISPLAY (crtc), res, crtc->id);
2410
g_print ("CRTC %lx Timestamp: %u\n", crtc->id, (guint32)info->timestamp);
2415
/* FIXME: We need to reaquire the screen resources */
2416
/* FIXME: can we actually catch BadRRCrtc, and does it make sense to emit that? */
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"),
2428
crtc->current_mode = mode_by_id (crtc->info, info->mode);
2433
/* Current outputs */
2434
a = g_ptr_array_new ();
2435
for (i = 0; i < info->noutput; ++i)
2437
GnomeRROutput *output = gnome_rr_output_by_id (crtc->info, info->outputs[i]);
2440
g_ptr_array_add (a, output);
2442
g_ptr_array_add (a, NULL);
2443
crtc->current_outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
2445
/* Possible outputs */
2446
a = g_ptr_array_new ();
2447
for (i = 0; i < info->npossible; ++i)
2449
GnomeRROutput *output = gnome_rr_output_by_id (crtc->info, info->possible[i]);
2452
g_ptr_array_add (a, output);
2454
g_ptr_array_add (a, NULL);
2455
crtc->possible_outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
2458
crtc->current_rotation = gnome_rr_rotation_from_xrotation (info->rotation);
2459
crtc->rotations = gnome_rr_rotation_from_xrotation (info->rotations);
2461
XRRFreeCrtcInfo (info);
2463
/* get an store gamma size */
2464
crtc->gamma_size = XRRGetCrtcGammaSize (DISPLAY (crtc), crtc->id);
2470
crtc_free (GnomeRRCrtc *crtc)
2472
g_free (crtc->current_outputs);
2473
g_free (crtc->possible_outputs);
2474
g_slice_free (GnomeRRCrtc, crtc);
2478
static GnomeRRMode *
2479
mode_new (ScreenInfo *info, RRMode id)
2481
GnomeRRMode *mode = g_slice_new0 (GnomeRRMode);
2490
gnome_rr_mode_get_id (GnomeRRMode *mode)
2492
g_return_val_if_fail (mode != NULL, 0);
2497
gnome_rr_mode_get_width (GnomeRRMode *mode)
2499
g_return_val_if_fail (mode != NULL, 0);
2504
gnome_rr_mode_get_freq (GnomeRRMode *mode)
2506
g_return_val_if_fail (mode != NULL, 0);
2507
return (mode->freq) / 1000;
2511
gnome_rr_mode_get_height (GnomeRRMode *mode)
2513
g_return_val_if_fail (mode != NULL, 0);
2514
return mode->height;
2518
mode_initialize (GnomeRRMode *mode, XRRModeInfo *info)
2520
g_assert (mode != NULL);
2521
g_assert (info != NULL);
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;
2529
static GnomeRRMode *
2530
mode_copy (const GnomeRRMode *from)
2532
GnomeRRMode *to = g_slice_new0 (GnomeRRMode);
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;
2545
mode_free (GnomeRRMode *mode)
2547
g_free (mode->name);
2548
g_slice_free (GnomeRRMode, mode);
2552
gnome_rr_crtc_set_gamma (GnomeRRCrtc *crtc, int size,
2553
unsigned short *red,
2554
unsigned short *green,
2555
unsigned short *blue)
2558
XRRCrtcGamma *gamma;
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);
2565
if (size != crtc->gamma_size)
2568
gamma = XRRAllocGamma (crtc->gamma_size);
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);
2575
XRRSetCrtcGamma (DISPLAY (crtc), crtc->id, gamma);
2576
XRRFreeGamma (gamma);
2580
gnome_rr_crtc_get_gamma (GnomeRRCrtc *crtc, int *size,
2581
unsigned short **red, unsigned short **green,
2582
unsigned short **blue)
2585
unsigned short *r, *g, *b;
2586
XRRCrtcGamma *gamma;
2588
g_return_val_if_fail (crtc != NULL, FALSE);
2590
gamma = XRRGetCrtcGamma (DISPLAY (crtc), crtc->id);
2594
copy_size = crtc->gamma_size * sizeof (unsigned short);
2597
r = g_new0 (unsigned short, crtc->gamma_size);
2598
memcpy (r, gamma->red, copy_size);
2603
g = g_new0 (unsigned short, crtc->gamma_size);
2604
memcpy (g, gamma->green, copy_size);
2609
b = g_new0 (unsigned short, crtc->gamma_size);
2610
memcpy (b, gamma->blue, copy_size);
2614
XRRFreeGamma (gamma);
2617
*size = crtc->gamma_size;