1 /* gnome-rr.c
2 *
3 * Copyright 2007, 2008, 2013 Red Hat, Inc.
4 * Copyright 2020 NVIDIA CORPORATION
5 *
6 * This file is part of the Gnome Library.
7 *
8 * The Gnome Library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * The Gnome Library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with the Gnome Library; see the file COPYING.LIB. If not,
20 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 * Author: Soren Sandmann <sandmann@redhat.com>
24 * Giovanni Campagna <gcampagn@redhat.com>
25 */
26
27 #define GNOME_DESKTOP_USE_UNSTABLE_API
28
29 #include <config.h>
30 #include <glib/gi18n-lib.h>
31 #include <string.h>
32
33 #include <gtk/gtk.h>
34
35 #undef GNOME_DISABLE_DEPRECATED
36 #include "gnome-rr.h"
37 #include "gnome-rr-config.h"
38
39 #include "gnome-rr-private.h"
40
41 /* From xf86drmMode.h: it's ABI so it won't change */
42 #define DRM_MODE_FLAG_INTERLACE (1<<4)
43
44 enum {
45 SCREEN_PROP_0,
46 SCREEN_PROP_GDK_SCREEN,
47 SCREEN_PROP_DPMS_MODE,
48 SCREEN_PROP_LAST,
49 };
50
51 enum {
52 SCREEN_CHANGED,
53 SCREEN_OUTPUT_CONNECTED,
54 SCREEN_OUTPUT_DISCONNECTED,
55 SCREEN_SIGNAL_LAST,
56 };
57
58 static gint screen_signals[SCREEN_SIGNAL_LAST];
59
60 struct GnomeRROutput
61 {
62 ScreenInfo * info;
63 guint id;
64 glong winsys_id;
65
66 char * name;
67 char * display_name;
68 char * connector_type;
69 GnomeRRCrtc * current_crtc;
70 GnomeRRCrtc ** possible_crtcs;
71 GnomeRROutput ** clones;
72 GnomeRRMode ** modes;
73
74 char * vendor;
75 char * product;
76 char * serial;
77 int width_mm;
78 int height_mm;
79 GBytes * edid;
80 char * edid_file;
81
82 int backlight;
83 int min_backlight_step;
84
85 gboolean is_primary;
86 gboolean is_presentation;
87 gboolean is_underscanning;
88 gboolean supports_underscanning;
89 gboolean supports_color_transform;
90
91 GnomeRRTile tile_info;
92 };
93
94 struct GnomeRRCrtc
95 {
96 ScreenInfo * info;
97 guint id;
98 glong winsys_id;
99
100 GnomeRRMode * current_mode;
101 GnomeRROutput ** current_outputs;
102 GnomeRROutput ** possible_outputs;
103 int x;
104 int y;
105
106 enum wl_output_transform transform;
107 int all_transforms;
108 int gamma_size;
109 };
110
111 #define UNDEFINED_MODE_ID 0
112 struct GnomeRRMode
113 {
114 ScreenInfo * info;
115 guint id;
116 glong winsys_id;
117 int width;
118 int height;
119 int freq; /* in mHz */
120 gboolean tiled;
121 guint32 flags;
122 };
123
124 /* GnomeRRCrtc */
125 static GnomeRRCrtc * crtc_new (ScreenInfo *info,
126 guint id);
127 static GnomeRRCrtc * crtc_copy (const GnomeRRCrtc *from);
128 static void crtc_free (GnomeRRCrtc *crtc);
129
130 static void crtc_initialize (GnomeRRCrtc *crtc,
131 GVariant *res);
132
133 /* GnomeRROutput */
134 static GnomeRROutput *output_new (ScreenInfo *info,
135 guint id);
136
137 static void output_initialize (GnomeRROutput *output,
138 GVariant *res);
139
140 static GnomeRROutput *output_copy (const GnomeRROutput *from);
141 static void output_free (GnomeRROutput *output);
142
143 /* GnomeRRMode */
144 static GnomeRRMode * mode_new (ScreenInfo *info,
145 guint id);
146
147 static void mode_initialize (GnomeRRMode *mode,
148 GVariant *info);
149
150 static GnomeRRMode * mode_copy (const GnomeRRMode *from);
151 static void mode_free (GnomeRRMode *mode);
152
153 static void gnome_rr_screen_finalize (GObject*);
154 static void gnome_rr_screen_set_property (GObject*, guint, const GValue*, GParamSpec*);
155 static void gnome_rr_screen_get_property (GObject*, guint, GValue*, GParamSpec*);
156 static gboolean gnome_rr_screen_initable_init (GInitable*, GCancellable*, GError**);
157 static void gnome_rr_screen_initable_iface_init (GInitableIface *iface);
158 static void gnome_rr_screen_async_initable_init (GAsyncInitableIface *iface);
G_DEFINE_TYPE_WITH_CODE(GnomeRRScreen,gnome_rr_screen,G_TYPE_OBJECT,G_ADD_PRIVATE (GnomeRRScreen)G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,gnome_rr_screen_initable_iface_init)G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,gnome_rr_screen_async_initable_init))159 G_DEFINE_TYPE_WITH_CODE (GnomeRRScreen, gnome_rr_screen, G_TYPE_OBJECT,
160 G_ADD_PRIVATE (GnomeRRScreen)
161 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gnome_rr_screen_initable_iface_init)
162 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, gnome_rr_screen_async_initable_init))
163
164 G_DEFINE_BOXED_TYPE (GnomeRRCrtc, gnome_rr_crtc, crtc_copy, crtc_free)
165 G_DEFINE_BOXED_TYPE (GnomeRROutput, gnome_rr_output, output_copy, output_free)
166 G_DEFINE_BOXED_TYPE (GnomeRRMode, gnome_rr_mode, mode_copy, mode_free)
167
168 /* Errors */
169
170 /**
171 * gnome_rr_error_quark:
172 *
173 * Returns the #GQuark that will be used for #GError values returned by the
174 * GnomeRR API.
175 *
176 * Return value: a #GQuark used to identify errors coming from the GnomeRR API.
177 */
178 GQuark
179 gnome_rr_error_quark (void)
180 {
181 return g_quark_from_static_string ("gnome-rr-error-quark");
182 }
183
184 /* Screen */
185 static GnomeRROutput *
gnome_rr_output_by_id(ScreenInfo * info,guint id)186 gnome_rr_output_by_id (ScreenInfo *info, guint id)
187 {
188 GnomeRROutput **output;
189
190 g_assert (info != NULL);
191
192 for (output = info->outputs; *output; ++output)
193 {
194 if ((*output)->id == id)
195 return *output;
196 }
197
198 return NULL;
199 }
200
201 static GnomeRRCrtc *
crtc_by_id(ScreenInfo * info,guint id)202 crtc_by_id (ScreenInfo *info, guint id)
203 {
204 GnomeRRCrtc **crtc;
205
206 if (!info)
207 return NULL;
208
209 for (crtc = info->crtcs; *crtc; ++crtc)
210 {
211 if ((*crtc)->id == id)
212 return *crtc;
213 }
214
215 return NULL;
216 }
217
218 static GnomeRRMode *
mode_by_id(ScreenInfo * info,guint id)219 mode_by_id (ScreenInfo *info, guint id)
220 {
221 GnomeRRMode **mode;
222
223 g_assert (info != NULL);
224
225 for (mode = info->modes; *mode; ++mode)
226 {
227 if ((*mode)->id == id)
228 return *mode;
229 }
230
231 return NULL;
232 }
233
234 static void
screen_info_free(ScreenInfo * info)235 screen_info_free (ScreenInfo *info)
236 {
237 GnomeRROutput **output;
238 GnomeRRCrtc **crtc;
239 GnomeRRMode **mode;
240
241 g_assert (info != NULL);
242
243 if (info->outputs)
244 {
245 for (output = info->outputs; *output; ++output)
246 output_free (*output);
247 g_free (info->outputs);
248 }
249
250 if (info->crtcs)
251 {
252 for (crtc = info->crtcs; *crtc; ++crtc)
253 crtc_free (*crtc);
254 g_free (info->crtcs);
255 }
256
257 if (info->modes)
258 {
259 for (mode = info->modes; *mode; ++mode)
260 mode_free (*mode);
261 g_free (info->modes);
262 }
263
264 if (info->clone_modes)
265 {
266 /* The modes themselves were freed above */
267 g_free (info->clone_modes);
268 }
269
270 g_free (info);
271 }
272
273 static gboolean
has_similar_mode(GnomeRROutput * output,GnomeRRMode * mode)274 has_similar_mode (GnomeRROutput *output, GnomeRRMode *mode)
275 {
276 int i;
277 GnomeRRMode **modes = gnome_rr_output_list_modes (output);
278 guint width = gnome_rr_mode_get_width (mode);
279 guint height = gnome_rr_mode_get_height (mode);
280
281 for (i = 0; modes[i] != NULL; ++i)
282 {
283 GnomeRRMode *m = modes[i];
284
285 if (gnome_rr_mode_get_width (m) == width &&
286 gnome_rr_mode_get_height (m) == height)
287 {
288 return TRUE;
289 }
290 }
291
292 return FALSE;
293 }
294
295 gboolean
_gnome_rr_output_get_tiled_display_size(GnomeRROutput * output,int * tile_w,int * tile_h,int * total_width,int * total_height)296 _gnome_rr_output_get_tiled_display_size (GnomeRROutput *output,
297 int *tile_w, int *tile_h,
298 int *total_width, int *total_height)
299 {
300 GnomeRRTile tile;
301 guint ht, vt;
302 int i, total_h = 0, total_w = 0;
303
304 if (!_gnome_rr_output_get_tile_info (output, &tile))
305 return FALSE;
306
307 if (tile.loc_horiz != 0 ||
308 tile.loc_vert != 0)
309 return FALSE;
310
311 if (tile_w)
312 *tile_w = tile.width;
313 if (tile_h)
314 *tile_h = tile.height;
315
316 for (ht = 0; ht < tile.max_horiz_tiles; ht++)
317 {
318 for (vt = 0; vt < tile.max_vert_tiles; vt++)
319 {
320 for (i = 0; output->info->outputs[i]; i++)
321 {
322 GnomeRRTile this_tile;
323
324 if (!_gnome_rr_output_get_tile_info (output->info->outputs[i], &this_tile))
325 continue;
326
327 if (this_tile.group_id != tile.group_id)
328 continue;
329
330 if (this_tile.loc_horiz != ht ||
331 this_tile.loc_vert != vt)
332 continue;
333
334 if (this_tile.loc_horiz == 0)
335 total_h += this_tile.height;
336
337 if (this_tile.loc_vert == 0)
338 total_w += this_tile.width;
339 }
340 }
341 }
342
343 *total_width = total_w;
344 *total_height = total_h;
345 return TRUE;
346 }
347
348 static void
gather_tile_modes_output(ScreenInfo * info,GnomeRROutput * output)349 gather_tile_modes_output (ScreenInfo *info, GnomeRROutput *output)
350 {
351 GPtrArray *a;
352 GnomeRRMode *mode;
353 int width, height;
354 int tile_w, tile_h;
355 int i;
356
357 if (!_gnome_rr_output_get_tiled_display_size (output, &tile_w, &tile_h,
358 &width, &height))
359 return;
360
361 /* now stick the mode into the modelist */
362 a = g_ptr_array_new ();
363 mode = mode_new (info, UNDEFINED_MODE_ID);
364 mode->winsys_id = 0;
365 mode->width = width;
366 mode->height = height;
367 mode->freq = 0;
368 mode->tiled = TRUE;
369
370 g_ptr_array_add (a, mode);
371 for (i = 0; output->modes[i]; i++)
372 g_ptr_array_add (a, output->modes[i]);
373
374 g_ptr_array_add (a, NULL);
375 output->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
376 }
377
378 static void
gather_tile_modes(ScreenInfo * info)379 gather_tile_modes (ScreenInfo *info)
380 {
381 int i;
382
383 for (i = 0; info->outputs[i]; i++)
384 gather_tile_modes_output (info, info->outputs[i]);
385 }
386
387 static void
gather_clone_modes(ScreenInfo * info)388 gather_clone_modes (ScreenInfo *info)
389 {
390 int i;
391 GPtrArray *result = g_ptr_array_new ();
392
393 for (i = 0; info->outputs[i] != NULL; ++i)
394 {
395 int j;
396 GnomeRROutput *output1, *output2;
397
398 output1 = info->outputs[i];
399
400 for (j = 0; output1->modes[j] != NULL; ++j)
401 {
402 GnomeRRMode *mode = output1->modes[j];
403 gboolean valid;
404 int k;
405
406 valid = TRUE;
407 for (k = 0; info->outputs[k] != NULL; ++k)
408 {
409 output2 = info->outputs[k];
410
411 if (!has_similar_mode (output2, mode))
412 {
413 valid = FALSE;
414 break;
415 }
416 }
417
418 if (valid)
419 g_ptr_array_add (result, mode);
420 }
421 }
422
423 g_ptr_array_add (result, NULL);
424
425 info->clone_modes = (GnomeRRMode **)g_ptr_array_free (result, FALSE);
426 }
427
428 static void
fill_screen_info_from_resources(ScreenInfo * info,guint serial,GVariant * crtcs,GVariant * outputs,GVariant * modes,int max_width,int max_height)429 fill_screen_info_from_resources (ScreenInfo *info,
430 guint serial,
431 GVariant *crtcs,
432 GVariant *outputs,
433 GVariant *modes,
434 int max_width,
435 int max_height)
436 {
437 guint i;
438 GPtrArray *a;
439 GnomeRRCrtc **crtc;
440 GnomeRROutput **output;
441 GnomeRRMode **mode;
442 guint ncrtc, noutput, nmode;
443 guint id;
444
445 info->min_width = 312;
446 info->min_height = 312;
447 info->max_width = max_width;
448 info->max_height = max_height;
449 info->serial = serial;
450
451 ncrtc = g_variant_n_children (crtcs);
452 noutput = g_variant_n_children (outputs);
453 nmode = g_variant_n_children (modes);
454
455 /* We create all the structures before initializing them, so
456 * that they can refer to each other.
457 */
458 a = g_ptr_array_new ();
459 for (i = 0; i < ncrtc; ++i)
460 {
461 g_variant_get_child (crtcs, i, META_CRTC_STRUCT, &id,
462 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
463
464 g_ptr_array_add (a, crtc_new (info, id));
465 }
466 g_ptr_array_add (a, NULL);
467 info->crtcs = (GnomeRRCrtc **)g_ptr_array_free (a, FALSE);
468
469 a = g_ptr_array_new ();
470 for (i = 0; i < noutput; ++i)
471 {
472 g_variant_get_child (outputs, i, META_OUTPUT_STRUCT, &id,
473 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
474
475 g_ptr_array_add (a, output_new (info, id));
476 }
477 g_ptr_array_add (a, NULL);
478 info->outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
479
480 a = g_ptr_array_new ();
481 for (i = 0; i < nmode; ++i)
482 {
483 g_variant_get_child (modes, i, META_MONITOR_MODE_STRUCT, &id,
484 NULL, NULL, NULL, NULL, NULL);
485
486 g_ptr_array_add (a, mode_new (info, id));
487 }
488 g_ptr_array_add (a, NULL);
489 info->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
490
491 /* Initialize */
492 for (i = 0, crtc = info->crtcs; *crtc; ++i, ++crtc)
493 {
494 GVariant *child = g_variant_get_child_value (crtcs, i);
495 crtc_initialize (*crtc, child);
496 g_variant_unref (child);
497 }
498
499 for (i = 0, output = info->outputs; *output; ++i, ++output)
500 {
501 GVariant *child = g_variant_get_child_value (outputs, i);
502 output_initialize (*output, child);
503 g_variant_unref (child);
504 }
505
506 for (i = 0, mode = info->modes; *mode; ++i, ++mode)
507 {
508 GVariant *child = g_variant_get_child_value (modes, i);
509 mode_initialize (*mode, child);
510 g_variant_unref (child);
511 }
512
513 gather_clone_modes (info);
514
515 gather_tile_modes (info);
516 }
517
518 static gboolean
fill_out_screen_info(ScreenInfo * info,GError ** error)519 fill_out_screen_info (ScreenInfo *info,
520 GError **error)
521 {
522 GnomeRRScreenPrivate *priv;
523 guint serial;
524 GVariant *crtcs, *outputs, *modes;
525 int max_width, max_height;
526
527 g_assert (info != NULL);
528
529 priv = info->screen->priv;
530
531 if (!meta_dbus_display_config_call_get_resources_sync (priv->proxy,
532 &serial,
533 &crtcs,
534 &outputs,
535 &modes,
536 &max_width,
537 &max_height,
538 NULL,
539 error))
540 return FALSE;
541
542 fill_screen_info_from_resources (info, serial, crtcs, outputs,
543 modes, max_width, max_height);
544
545 g_variant_unref (crtcs);
546 g_variant_unref (outputs);
547 g_variant_unref (modes);
548
549 return TRUE;
550 }
551
552 static ScreenInfo *
screen_info_new(GnomeRRScreen * screen,GError ** error)553 screen_info_new (GnomeRRScreen *screen, GError **error)
554 {
555 ScreenInfo *info = g_new0 (ScreenInfo, 1);
556
557 g_assert (screen != NULL);
558
559 info->outputs = NULL;
560 info->crtcs = NULL;
561 info->modes = NULL;
562 info->screen = screen;
563
564 if (fill_out_screen_info (info, error))
565 {
566 return info;
567 }
568 else
569 {
570 screen_info_free (info);
571 return NULL;
572 }
573 }
574
575 static GnomeRROutput *
find_output_by_winsys_id(GnomeRROutput ** haystack,glong winsys_id)576 find_output_by_winsys_id (GnomeRROutput **haystack, glong winsys_id)
577 {
578 guint i;
579
580 for (i = 0; haystack[i] != NULL; i++)
581 {
582 if (haystack[i]->winsys_id == winsys_id)
583 return haystack[i];
584 }
585 return NULL;
586 }
587
588 static void
diff_outputs_and_emit_signals(ScreenInfo * old,ScreenInfo * new)589 diff_outputs_and_emit_signals (ScreenInfo *old, ScreenInfo *new)
590 {
591 guint i;
592 gulong winsys_id_old, winsys_id_new;
593 GnomeRROutput *output_old;
594 GnomeRROutput *output_new;
595
596 /* have any outputs been removed/disconnected */
597 for (i = 0; old->outputs[i] != NULL; i++)
598 {
599 winsys_id_old = old->outputs[i]->winsys_id;
600 output_new = find_output_by_winsys_id (new->outputs, winsys_id_old);
601 if (output_new == NULL)
602 {
603 g_signal_emit (G_OBJECT (new->screen),
604 screen_signals[SCREEN_OUTPUT_DISCONNECTED], 0,
605 old->outputs[i]);
606 }
607 }
608
609 /* have any outputs been created/connected */
610 for (i = 0; new->outputs[i] != NULL; i++)
611 {
612 winsys_id_new = new->outputs[i]->winsys_id;
613 output_old = find_output_by_winsys_id (old->outputs, winsys_id_new);
614 if (output_old == NULL)
615 {
616 g_signal_emit (G_OBJECT (new->screen),
617 screen_signals[SCREEN_OUTPUT_CONNECTED], 0,
618 new->outputs[i]);
619 }
620 }
621 }
622
623 typedef enum {
624 REFRESH_NONE = 0,
625 REFRESH_IGNORE_SERIAL = 1,
626 REFRESH_FORCE_CALLBACK = 2
627 } RefreshFlags;
628
629 static gboolean
screen_update(GnomeRRScreen * screen,RefreshFlags flags,GError ** error)630 screen_update (GnomeRRScreen *screen, RefreshFlags flags, GError **error)
631 {
632 ScreenInfo *info;
633 gboolean changed = FALSE;
634
635 g_assert (screen != NULL);
636
637 info = screen_info_new (screen, error);
638 if (!info)
639 return FALSE;
640
641 if ((flags & REFRESH_IGNORE_SERIAL) || info->serial != screen->priv->info->serial)
642 changed = TRUE;
643
644 /* work out if any outputs have changed connected state */
645 diff_outputs_and_emit_signals (screen->priv->info, info);
646
647 screen_info_free (screen->priv->info);
648 screen->priv->info = info;
649
650 if (changed || (flags & REFRESH_FORCE_CALLBACK))
651 g_signal_emit (G_OBJECT (screen), screen_signals[SCREEN_CHANGED], 0);
652
653 return changed;
654 }
655
656 static void
screen_on_monitors_changed(MetaDBusDisplayConfig * proxy,gpointer data)657 screen_on_monitors_changed (MetaDBusDisplayConfig *proxy,
658 gpointer data)
659 {
660 GnomeRRScreen *screen = data;
661
662 screen_update (screen, REFRESH_FORCE_CALLBACK, NULL);
663 }
664
665 static void
name_owner_changed(GObject * object,GParamSpec * pspec,GnomeRRScreen * self)666 name_owner_changed (GObject *object,
667 GParamSpec *pspec,
668 GnomeRRScreen *self)
669 {
670 GError *error;
671 char *new_name_owner;
672
673 new_name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object));
674 if (new_name_owner == NULL)
675 return;
676
677 error = NULL;
678 if (!screen_update (self, REFRESH_IGNORE_SERIAL | REFRESH_FORCE_CALLBACK, &error))
679 g_warning ("Failed to refresh screen configuration after mutter was restarted: %s",
680 error->message);
681
682 g_clear_error (&error);
683 g_free (new_name_owner);
684 }
685
686 static void
power_save_mode_changed(GObject * object,GParamSpec * pspec,GnomeRRScreen * self)687 power_save_mode_changed (GObject *object,
688 GParamSpec *pspec,
689 GnomeRRScreen *self)
690 {
691 g_object_notify (G_OBJECT (self), "dpms-mode");
692 }
693
694 static gboolean
gnome_rr_screen_initable_init(GInitable * initable,GCancellable * canc,GError ** error)695 gnome_rr_screen_initable_init (GInitable *initable, GCancellable *canc, GError **error)
696 {
697 GnomeRRScreen *self = GNOME_RR_SCREEN (initable);
698 GnomeRRScreenPrivate *priv = self->priv;
699 MetaDBusDisplayConfig *proxy;
700
701 proxy = meta_dbus_display_config_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
702 G_DBUS_PROXY_FLAGS_NONE,
703 "org.gnome.Mutter.DisplayConfig",
704 "/org/gnome/Mutter/DisplayConfig",
705 NULL, error);
706 if (!proxy)
707 return FALSE;
708
709 priv->proxy = META_DBUS_DISPLAY_CONFIG (proxy);
710
711 priv->info = screen_info_new (self, error);
712 if (!priv->info)
713 return FALSE;
714
715 g_signal_connect_object (priv->proxy, "notify::g-name-owner",
716 G_CALLBACK (name_owner_changed), self, 0);
717 g_signal_connect_object (priv->proxy, "monitors-changed",
718 G_CALLBACK (screen_on_monitors_changed), self, 0);
719 g_signal_connect_object (priv->proxy, "notify::power-save-mode",
720 G_CALLBACK (power_save_mode_changed), self, 0);
721 return TRUE;
722 }
723
724 static void
on_proxy_acquired(GObject * object,GAsyncResult * result,gpointer user_data)725 on_proxy_acquired (GObject *object,
726 GAsyncResult *result,
727 gpointer user_data)
728 {
729 GTask *task = user_data;
730 GnomeRRScreen *self = g_task_get_source_object (task);
731 GnomeRRScreenPrivate *priv = self->priv;
732 MetaDBusDisplayConfig *proxy;
733 GError *error;
734
735 error = NULL;
736 proxy = meta_dbus_display_config_proxy_new_for_bus_finish (result, &error);
737 if (!proxy)
738 return g_task_return_error (task, error);
739
740 priv->proxy = META_DBUS_DISPLAY_CONFIG (proxy);
741
742 priv->info = screen_info_new (self, &error);
743 if (!priv->info)
744 return g_task_return_error (task, error);
745
746 g_signal_connect_object (priv->proxy, "notify::g-name-owner",
747 G_CALLBACK (name_owner_changed), self, 0);
748 g_signal_connect_object (priv->proxy, "monitors-changed",
749 G_CALLBACK (screen_on_monitors_changed), self, 0);
750 g_signal_connect_object (priv->proxy, "notify::power-save-mode",
751 G_CALLBACK (power_save_mode_changed), self, 0);
752 g_task_return_boolean (task, TRUE);
753 }
754
755 static void
on_name_appeared(GDBusConnection * connection,const char * name,const char * name_owner,gpointer user_data)756 on_name_appeared (GDBusConnection *connection,
757 const char *name,
758 const char *name_owner,
759 gpointer user_data)
760 {
761 GTask *task = user_data;
762 GnomeRRScreen *self = g_task_get_source_object (task);
763 GnomeRRScreenPrivate *priv = self->priv;
764
765 meta_dbus_display_config_proxy_new_for_bus (G_BUS_TYPE_SESSION,
766 G_DBUS_PROXY_FLAGS_NONE,
767 "org.gnome.Mutter.DisplayConfig",
768 "/org/gnome/Mutter/DisplayConfig",
769 g_task_get_cancellable (task),
770 on_proxy_acquired, g_object_ref (task));
771
772 g_bus_unwatch_name (priv->init_name_watch_id);
773 }
774
775 static void
gnome_rr_screen_async_initable_init_async(GAsyncInitable * initable,int io_priority,GCancellable * canc,GAsyncReadyCallback callback,gpointer user_data)776 gnome_rr_screen_async_initable_init_async (GAsyncInitable *initable,
777 int io_priority,
778 GCancellable *canc,
779 GAsyncReadyCallback callback,
780 gpointer user_data)
781 {
782 GnomeRRScreen *self = GNOME_RR_SCREEN (initable);
783 GnomeRRScreenPrivate *priv = self->priv;
784 GTask *task;
785
786 task = g_task_new (self, canc, callback, user_data);
787
788 priv->init_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
789 "org.gnome.Mutter.DisplayConfig",
790 G_BUS_NAME_WATCHER_FLAGS_NONE,
791 on_name_appeared,
792 NULL,
793 task, g_object_unref);
794 }
795
796 static gboolean
gnome_rr_screen_async_initable_init_finish(GAsyncInitable * initable,GAsyncResult * result,GError ** error)797 gnome_rr_screen_async_initable_init_finish (GAsyncInitable *initable,
798 GAsyncResult *result,
799 GError **error)
800 {
801 return g_task_propagate_boolean (G_TASK (result), error);
802 }
803
804 static void
gnome_rr_screen_initable_iface_init(GInitableIface * iface)805 gnome_rr_screen_initable_iface_init (GInitableIface *iface)
806 {
807 iface->init = gnome_rr_screen_initable_init;
808 }
809
810 static void
gnome_rr_screen_async_initable_init(GAsyncInitableIface * iface)811 gnome_rr_screen_async_initable_init (GAsyncInitableIface *iface)
812 {
813 iface->init_async = gnome_rr_screen_async_initable_init_async;
814 iface->init_finish = gnome_rr_screen_async_initable_init_finish;
815 }
816
817 void
gnome_rr_screen_finalize(GObject * gobject)818 gnome_rr_screen_finalize (GObject *gobject)
819 {
820 GnomeRRScreen *screen = GNOME_RR_SCREEN (gobject);
821
822 if (screen->priv->info)
823 screen_info_free (screen->priv->info);
824
825 g_clear_object (&screen->priv->proxy);
826
827 G_OBJECT_CLASS (gnome_rr_screen_parent_class)->finalize (gobject);
828 }
829
830 void
gnome_rr_screen_set_property(GObject * gobject,guint property_id,const GValue * value,GParamSpec * property)831 gnome_rr_screen_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *property)
832 {
833 GnomeRRScreen *self = GNOME_RR_SCREEN (gobject);
834 GnomeRRScreenPrivate *priv = self->priv;
835
836 switch (property_id)
837 {
838 case SCREEN_PROP_GDK_SCREEN:
839 priv->gdk_screen = g_value_get_object (value);
840 return;
841 case SCREEN_PROP_DPMS_MODE:
842 gnome_rr_screen_set_dpms_mode (self, g_value_get_enum (value), NULL);
843 return;
844 default:
845 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
846 return;
847 }
848 }
849
850 void
gnome_rr_screen_get_property(GObject * gobject,guint property_id,GValue * value,GParamSpec * property)851 gnome_rr_screen_get_property (GObject *gobject, guint property_id, GValue *value, GParamSpec *property)
852 {
853 GnomeRRScreen *self = GNOME_RR_SCREEN (gobject);
854 GnomeRRScreenPrivate *priv = self->priv;
855
856 switch (property_id)
857 {
858 case SCREEN_PROP_GDK_SCREEN:
859 g_value_set_object (value, priv->gdk_screen);
860 return;
861 case SCREEN_PROP_DPMS_MODE: {
862 GnomeRRDpmsMode mode;
863 if (gnome_rr_screen_get_dpms_mode (self, &mode, NULL))
864 g_value_set_enum (value, mode);
865 else
866 g_value_set_enum (value, GNOME_RR_DPMS_UNKNOWN);
867 }
868 return;
869 default:
870 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
871 return;
872 }
873 }
874
875 void
gnome_rr_screen_class_init(GnomeRRScreenClass * klass)876 gnome_rr_screen_class_init (GnomeRRScreenClass *klass)
877 {
878 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
879
880 bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
881 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
882
883 gobject_class->set_property = gnome_rr_screen_set_property;
884 gobject_class->get_property = gnome_rr_screen_get_property;
885 gobject_class->finalize = gnome_rr_screen_finalize;
886
887 g_object_class_install_property(
888 gobject_class,
889 SCREEN_PROP_GDK_SCREEN,
890 g_param_spec_object (
891 "gdk-screen",
892 "GDK Screen",
893 "The GDK Screen represented by this GnomeRRScreen",
894 GDK_TYPE_SCREEN,
895 G_PARAM_READWRITE |
896 G_PARAM_CONSTRUCT_ONLY |
897 G_PARAM_STATIC_STRINGS)
898 );
899
900 g_object_class_install_property(
901 gobject_class,
902 SCREEN_PROP_DPMS_MODE,
903 g_param_spec_enum (
904 "dpms-mode",
905 "DPMS Mode",
906 "The DPMS mode for this GnomeRRScreen",
907 GNOME_TYPE_RR_DPMS_MODE,
908 GNOME_RR_DPMS_UNKNOWN,
909 G_PARAM_READWRITE |
910 G_PARAM_STATIC_STRINGS)
911 );
912
913 screen_signals[SCREEN_CHANGED] = g_signal_new("changed",
914 G_TYPE_FROM_CLASS (gobject_class),
915 G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
916 G_STRUCT_OFFSET (GnomeRRScreenClass, changed),
917 NULL,
918 NULL,
919 g_cclosure_marshal_VOID__VOID,
920 G_TYPE_NONE,
921 0);
922
923 /**
924 * GnomeRRScreen::output-connected:
925 * @screen: the #GnomeRRScreen that emitted the signal
926 * @output: the #GnomeRROutput that was connected
927 *
928 * This signal is emitted when a display device is connected to a
929 * port, or a port is hotplugged with an active output. The latter
930 * can happen if a laptop is docked, and the dock provides a new
931 * active output.
932 *
933 * The @output value is not a #GObject. The returned @output value can
934 * only assume to be valid during the emission of the signal (i.e. within
935 * your signal handler only), as it may change later when the @screen
936 * is modified due to an event from the X server, or due to another
937 * place in the application modifying the @screen and the @output.
938 * Therefore, deal with changes to the @output right in your signal
939 * handler, instead of keeping the @output reference for an async or
940 * idle function.
941 **/
942 screen_signals[SCREEN_OUTPUT_CONNECTED] = g_signal_new("output-connected",
943 G_TYPE_FROM_CLASS (gobject_class),
944 G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
945 G_STRUCT_OFFSET (GnomeRRScreenClass, output_connected),
946 NULL,
947 NULL,
948 g_cclosure_marshal_VOID__POINTER,
949 G_TYPE_NONE,
950 1, G_TYPE_POINTER);
951
952 /**
953 * GnomeRRScreen::output-disconnected:
954 * @screen: the #GnomeRRScreen that emitted the signal
955 * @output: the #GnomeRROutput that was disconnected
956 *
957 * This signal is emitted when a display device is disconnected from
958 * a port, or a port output is hot-unplugged. The latter can happen
959 * if a laptop is undocked, and the dock provided the output.
960 *
961 * The @output value is not a #GObject. The returned @output value can
962 * only assume to be valid during the emission of the signal (i.e. within
963 * your signal handler only), as it may change later when the @screen
964 * is modified due to an event from the X server, or due to another
965 * place in the application modifying the @screen and the @output.
966 * Therefore, deal with changes to the @output right in your signal
967 * handler, instead of keeping the @output reference for an async or
968 * idle function.
969 **/
970 screen_signals[SCREEN_OUTPUT_DISCONNECTED] = g_signal_new("output-disconnected",
971 G_TYPE_FROM_CLASS (gobject_class),
972 G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
973 G_STRUCT_OFFSET (GnomeRRScreenClass, output_disconnected),
974 NULL,
975 NULL,
976 g_cclosure_marshal_VOID__POINTER,
977 G_TYPE_NONE,
978 1, G_TYPE_POINTER);
979 }
980
981 void
gnome_rr_screen_init(GnomeRRScreen * self)982 gnome_rr_screen_init (GnomeRRScreen *self)
983 {
984 self->priv = gnome_rr_screen_get_instance_private (self);
985 }
986
987 /* Weak reference callback set in gnome_rr_screen_new(); we remove the GObject data from the GdkScreen. */
988 static void
rr_screen_weak_notify_cb(gpointer data,GObject * where_the_object_was)989 rr_screen_weak_notify_cb (gpointer data, GObject *where_the_object_was)
990 {
991 GdkScreen *screen = GDK_SCREEN (data);
992
993 g_object_set_data (G_OBJECT (screen), "GnomeRRScreen", NULL);
994 }
995
996 /**
997 * gnome_rr_screen_new:
998 * @screen: the #GdkScreen on which to operate
999 * @error: will be set if XRandR is not supported
1000 *
1001 * Creates a unique #GnomeRRScreen instance for the specified @screen.
1002 *
1003 * Returns: a unique #GnomeRRScreen instance, specific to the @screen, or NULL
1004 * if this could not be created, for instance if the driver does not support
1005 * Xrandr 1.2. Each #GdkScreen thus has a single instance of #GnomeRRScreen.
1006 */
1007 GnomeRRScreen *
gnome_rr_screen_new(GdkScreen * screen,GError ** error)1008 gnome_rr_screen_new (GdkScreen *screen,
1009 GError **error)
1010 {
1011 GnomeRRScreen *rr_screen;
1012
1013 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1014 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1015
1016 rr_screen = g_object_get_data (G_OBJECT (screen), "GnomeRRScreen");
1017 if (rr_screen)
1018 g_object_ref (rr_screen);
1019 else {
1020 rr_screen = g_initable_new (GNOME_TYPE_RR_SCREEN, NULL, error, "gdk-screen", screen, NULL);
1021 if (rr_screen) {
1022 g_object_set_data (G_OBJECT (screen), "GnomeRRScreen", rr_screen);
1023 g_object_weak_ref (G_OBJECT (rr_screen), rr_screen_weak_notify_cb, screen);
1024 }
1025 }
1026
1027 return rr_screen;
1028 }
1029
1030 void
gnome_rr_screen_new_async(GdkScreen * screen,GAsyncReadyCallback callback,gpointer user_data)1031 gnome_rr_screen_new_async (GdkScreen *screen,
1032 GAsyncReadyCallback callback,
1033 gpointer user_data)
1034 {
1035 g_return_if_fail (GDK_IS_SCREEN (screen));
1036
1037 g_async_initable_new_async (GNOME_TYPE_RR_SCREEN, G_PRIORITY_DEFAULT,
1038 NULL, callback, user_data,
1039 "gdk-screen", screen, NULL);
1040 }
1041
1042 GnomeRRScreen *
gnome_rr_screen_new_finish(GAsyncResult * result,GError ** error)1043 gnome_rr_screen_new_finish (GAsyncResult *result,
1044 GError **error)
1045 {
1046 GObject *source_object;
1047 GnomeRRScreen *screen;
1048
1049 source_object = g_async_result_get_source_object (result);
1050 screen = GNOME_RR_SCREEN (g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error));
1051
1052 g_object_unref (source_object);
1053 return screen;
1054 }
1055
1056 /**
1057 * gnome_rr_screen_get_ranges:
1058 * @screen: a #GnomeRRScreen
1059 * @min_width: (out): the minimum width
1060 * @max_width: (out): the maximum width
1061 * @min_height: (out): the minimum height
1062 * @max_height: (out): the maximum height
1063 *
1064 * Get the ranges of the screen
1065 */
1066 void
gnome_rr_screen_get_ranges(GnomeRRScreen * screen,int * min_width,int * max_width,int * min_height,int * max_height)1067 gnome_rr_screen_get_ranges (GnomeRRScreen *screen,
1068 int *min_width,
1069 int *max_width,
1070 int *min_height,
1071 int *max_height)
1072 {
1073 GnomeRRScreenPrivate *priv;
1074
1075 g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
1076
1077 priv = screen->priv;
1078
1079 if (min_width)
1080 *min_width = priv->info->min_width;
1081
1082 if (max_width)
1083 *max_width = priv->info->max_width;
1084
1085 if (min_height)
1086 *min_height = priv->info->min_height;
1087
1088 if (max_height)
1089 *max_height = priv->info->max_height;
1090 }
1091
1092 /**
1093 * gnome_rr_screen_refresh:
1094 * @screen: a #GnomeRRScreen
1095 * @error: location to store error, or %NULL
1096 *
1097 * Refreshes the screen configuration, and calls the screen's callback if it
1098 * exists and if the screen's configuration changed.
1099 *
1100 * Return value: TRUE if the screen's configuration changed; otherwise, the
1101 * function returns FALSE and a NULL error if the configuration didn't change,
1102 * or FALSE and a non-NULL error if there was an error while refreshing the
1103 * configuration.
1104 */
1105 gboolean
gnome_rr_screen_refresh(GnomeRRScreen * screen,GError ** error)1106 gnome_rr_screen_refresh (GnomeRRScreen *screen,
1107 GError **error)
1108 {
1109 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1110
1111 return screen_update (screen, REFRESH_NONE, error);
1112 }
1113
1114 /**
1115 * gnome_rr_screen_get_dpms_mode:
1116 * @mode: (out): The current #GnomeRRDpmsMode of this screen
1117 **/
1118 gboolean
gnome_rr_screen_get_dpms_mode(GnomeRRScreen * screen,GnomeRRDpmsMode * mode,GError ** error)1119 gnome_rr_screen_get_dpms_mode (GnomeRRScreen *screen,
1120 GnomeRRDpmsMode *mode,
1121 GError **error)
1122 {
1123 MetaPowerSave power_save;
1124
1125 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1126 g_return_val_if_fail (mode != NULL, FALSE);
1127
1128 power_save = meta_dbus_display_config_get_power_save_mode (screen->priv->proxy);
1129 switch (power_save) {
1130 case META_POWER_SAVE_UNKNOWN:
1131 g_set_error_literal (error,
1132 GNOME_RR_ERROR,
1133 GNOME_RR_ERROR_NO_DPMS_EXTENSION,
1134 "Display is not DPMS capable");
1135 return FALSE;
1136 case META_POWER_SAVE_ON:
1137 *mode = GNOME_RR_DPMS_ON;
1138 break;
1139 case META_POWER_SAVE_STANDBY:
1140 *mode = GNOME_RR_DPMS_STANDBY;
1141 break;
1142 case META_POWER_SAVE_SUSPEND:
1143 *mode = GNOME_RR_DPMS_SUSPEND;
1144 break;
1145 case META_POWER_SAVE_OFF:
1146 *mode = GNOME_RR_DPMS_OFF;
1147 break;
1148 default:
1149 g_assert_not_reached ();
1150 break;
1151 }
1152
1153 return TRUE;
1154 }
1155
1156 /**
1157 * gnome_rr_screen_set_dpms_mode:
1158 *
1159 * This method also disables the DPMS timeouts.
1160 **/
1161 gboolean
gnome_rr_screen_set_dpms_mode(GnomeRRScreen * screen,GnomeRRDpmsMode mode,GError ** error)1162 gnome_rr_screen_set_dpms_mode (GnomeRRScreen *screen,
1163 GnomeRRDpmsMode mode,
1164 GError **error)
1165 {
1166 MetaPowerSave power_save;
1167
1168 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1169
1170 switch (mode) {
1171 case GNOME_RR_DPMS_UNKNOWN:
1172 power_save = META_POWER_SAVE_UNKNOWN;
1173 break;
1174 case GNOME_RR_DPMS_ON:
1175 power_save = META_POWER_SAVE_ON;
1176 break;
1177 case GNOME_RR_DPMS_STANDBY:
1178 power_save = META_POWER_SAVE_STANDBY;
1179 break;
1180 case GNOME_RR_DPMS_SUSPEND:
1181 power_save = META_POWER_SAVE_SUSPEND;
1182 break;
1183 case GNOME_RR_DPMS_OFF:
1184 power_save = META_POWER_SAVE_OFF;
1185 break;
1186 default:
1187 g_assert_not_reached ();
1188 break;
1189 }
1190
1191 meta_dbus_display_config_set_power_save_mode (screen->priv->proxy, power_save);
1192
1193 return TRUE;
1194 }
1195
1196 /**
1197 * gnome_rr_screen_list_modes:
1198 *
1199 * List available XRandR modes
1200 *
1201 * Returns: (array zero-terminated=1) (transfer none):
1202 */
1203 GnomeRRMode **
gnome_rr_screen_list_modes(GnomeRRScreen * screen)1204 gnome_rr_screen_list_modes (GnomeRRScreen *screen)
1205 {
1206 g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1207 g_return_val_if_fail (screen->priv->info != NULL, NULL);
1208
1209 return screen->priv->info->modes;
1210 }
1211
1212 /**
1213 * gnome_rr_screen_list_clone_modes:
1214 *
1215 * List available XRandR clone modes
1216 *
1217 * Returns: (array zero-terminated=1) (transfer none):
1218 */
1219 GnomeRRMode **
gnome_rr_screen_list_clone_modes(GnomeRRScreen * screen)1220 gnome_rr_screen_list_clone_modes (GnomeRRScreen *screen)
1221 {
1222 g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1223 g_return_val_if_fail (screen->priv->info != NULL, NULL);
1224
1225 return screen->priv->info->clone_modes;
1226 }
1227
1228 /**
1229 * gnome_rr_screen_list_crtcs:
1230 *
1231 * List all CRTCs
1232 *
1233 * Returns: (array zero-terminated=1) (transfer none):
1234 */
1235 GnomeRRCrtc **
gnome_rr_screen_list_crtcs(GnomeRRScreen * screen)1236 gnome_rr_screen_list_crtcs (GnomeRRScreen *screen)
1237 {
1238 g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1239 g_return_val_if_fail (screen->priv->info != NULL, NULL);
1240
1241 return screen->priv->info->crtcs;
1242 }
1243
1244 /**
1245 * gnome_rr_screen_list_outputs:
1246 *
1247 * List all outputs
1248 *
1249 * Returns: (array zero-terminated=1) (transfer none):
1250 */
1251 GnomeRROutput **
gnome_rr_screen_list_outputs(GnomeRRScreen * screen)1252 gnome_rr_screen_list_outputs (GnomeRRScreen *screen)
1253 {
1254 g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1255 g_return_val_if_fail (screen->priv->info != NULL, NULL);
1256
1257 return screen->priv->info->outputs;
1258 }
1259
1260 /**
1261 * gnome_rr_screen_get_crtc_by_id:
1262 *
1263 * Returns: (transfer none): the CRTC identified by @id
1264 */
1265 GnomeRRCrtc *
gnome_rr_screen_get_crtc_by_id(GnomeRRScreen * screen,guint32 id)1266 gnome_rr_screen_get_crtc_by_id (GnomeRRScreen *screen,
1267 guint32 id)
1268 {
1269 GnomeRRCrtc **crtcs;
1270 int i;
1271
1272 g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1273 g_return_val_if_fail (screen->priv->info != NULL, NULL);
1274
1275 crtcs = screen->priv->info->crtcs;
1276
1277 for (i = 0; crtcs[i] != NULL; ++i)
1278 {
1279 if (crtcs[i]->id == id)
1280 return crtcs[i];
1281 }
1282
1283 return NULL;
1284 }
1285
1286 /**
1287 * gnome_rr_screen_get_output_by_id:
1288 *
1289 * Returns: (transfer none): the output identified by @id
1290 */
1291 GnomeRROutput *
gnome_rr_screen_get_output_by_id(GnomeRRScreen * screen,guint32 id)1292 gnome_rr_screen_get_output_by_id (GnomeRRScreen *screen,
1293 guint32 id)
1294 {
1295 GnomeRROutput **outputs;
1296 int i;
1297
1298 g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1299 g_return_val_if_fail (screen->priv->info != NULL, NULL);
1300
1301 outputs = screen->priv->info->outputs;
1302
1303 for (i = 0; outputs[i] != NULL; ++i)
1304 {
1305 if (outputs[i]->id == id)
1306 return outputs[i];
1307 }
1308
1309 return NULL;
1310 }
1311
1312 /* GnomeRROutput */
1313 static GnomeRROutput *
output_new(ScreenInfo * info,guint id)1314 output_new (ScreenInfo *info, guint id)
1315 {
1316 GnomeRROutput *output = g_slice_new0 (GnomeRROutput);
1317
1318 output->id = id;
1319 output->info = info;
1320
1321 return output;
1322 }
1323
1324 static void
append_output_array(GnomeRROutput *** array,GnomeRROutput * output)1325 append_output_array (GnomeRROutput ***array, GnomeRROutput *output)
1326 {
1327 unsigned i;
1328
1329 for (i = 0; (*array)[i]; i++);
1330
1331 *array = g_renew (GnomeRROutput *, *array, i + 2);
1332
1333 (*array)[i] = output;
1334 (*array)[i + 1] = NULL;
1335 }
1336
1337 static void
output_initialize(GnomeRROutput * output,GVariant * info)1338 output_initialize (GnomeRROutput *output, GVariant *info)
1339 {
1340 GPtrArray *a;
1341 GVariantIter *crtcs, *clones, *modes;
1342 GVariant *properties, *edid, *tile;
1343 gint32 current_crtc_id;
1344 guint32 id;
1345
1346 g_variant_get (info, META_OUTPUT_STRUCT,
1347 &output->id, &output->winsys_id,
1348 ¤t_crtc_id, &crtcs,
1349 &output->name,
1350 &modes, &clones, &properties);
1351
1352 /* Possible crtcs */
1353 a = g_ptr_array_new ();
1354 while (g_variant_iter_loop (crtcs, "u", &id))
1355 {
1356 GnomeRRCrtc *crtc = crtc_by_id (output->info, id);
1357
1358 if (!crtc)
1359 continue;
1360
1361 g_ptr_array_add (a, crtc);
1362
1363 if (current_crtc_id != -1 && crtc->id == (guint32) current_crtc_id)
1364 {
1365 output->current_crtc = crtc;
1366 append_output_array (&crtc->current_outputs, output);
1367 }
1368
1369 append_output_array (&crtc->possible_outputs, output);
1370 }
1371 g_ptr_array_add (a, NULL);
1372 output->possible_crtcs = (GnomeRRCrtc **)g_ptr_array_free (a, FALSE);
1373 g_variant_iter_free (crtcs);
1374
1375 /* Clones */
1376 a = g_ptr_array_new ();
1377 while (g_variant_iter_loop (clones, "u", &id))
1378 {
1379 GnomeRROutput *gnome_rr_output = gnome_rr_output_by_id (output->info, id);
1380
1381 if (gnome_rr_output)
1382 g_ptr_array_add (a, gnome_rr_output);
1383 }
1384 g_ptr_array_add (a, NULL);
1385 output->clones = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
1386 g_variant_iter_free (clones);
1387
1388 /* Modes */
1389 a = g_ptr_array_new ();
1390 while (g_variant_iter_loop (modes, "u", &id))
1391 {
1392 GnomeRRMode *mode = mode_by_id (output->info, id);
1393
1394 if (mode)
1395 g_ptr_array_add (a, mode);
1396 }
1397 g_ptr_array_add (a, NULL);
1398 output->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
1399 g_variant_iter_free (modes);
1400
1401 g_variant_lookup (properties, "vendor", "s", &output->vendor);
1402 g_variant_lookup (properties, "product", "s", &output->product);
1403 g_variant_lookup (properties, "serial", "s", &output->serial);
1404 g_variant_lookup (properties, "width-mm", "i", &output->width_mm);
1405 g_variant_lookup (properties, "height-mm", "i", &output->height_mm);
1406 g_variant_lookup (properties, "display-name", "s", &output->display_name);
1407 g_variant_lookup (properties, "connector-type", "s", &output->connector_type);
1408 g_variant_lookup (properties, "backlight", "i", &output->backlight);
1409 g_variant_lookup (properties, "min-backlight-step", "i", &output->min_backlight_step);
1410 g_variant_lookup (properties, "primary", "b", &output->is_primary);
1411 g_variant_lookup (properties, "presentation", "b", &output->is_presentation);
1412 g_variant_lookup (properties, "underscanning", "b", &output->is_underscanning);
1413 g_variant_lookup (properties, "supports-underscanning", "b", &output->supports_underscanning);
1414 g_variant_lookup (properties, "supports-color-transform", "b", &output->supports_color_transform);
1415
1416 if ((edid = g_variant_lookup_value (properties, "edid", G_VARIANT_TYPE ("ay"))))
1417 {
1418 output->edid = g_variant_get_data_as_bytes (edid);
1419 g_variant_unref (edid);
1420 }
1421 else
1422 g_variant_lookup (properties, "edid-file", "s", &output->edid_file);
1423
1424 if ((tile = g_variant_lookup_value (properties, "tile", G_VARIANT_TYPE ("(uuuuuuuu)"))))
1425 {
1426 g_variant_get (tile, "(uuuuuuuu)",
1427 &output->tile_info.group_id, &output->tile_info.flags,
1428 &output->tile_info.max_horiz_tiles, &output->tile_info.max_vert_tiles,
1429 &output->tile_info.loc_horiz, &output->tile_info.loc_vert,
1430 &output->tile_info.width, &output->tile_info.height);
1431 g_variant_unref (tile);
1432 }
1433 else
1434 memset(&output->tile_info, 0, sizeof(output->tile_info));
1435
1436 if (output->is_primary)
1437 output->info->primary = output;
1438
1439 g_variant_unref (properties);
1440 }
1441
1442 static GnomeRROutput*
output_copy(const GnomeRROutput * from)1443 output_copy (const GnomeRROutput *from)
1444 {
1445 GPtrArray *array;
1446 GnomeRRCrtc **p_crtc;
1447 GnomeRROutput **p_output;
1448 GnomeRRMode **p_mode;
1449 GnomeRROutput *output = g_slice_new0 (GnomeRROutput);
1450
1451 output->id = from->id;
1452 output->info = from->info;
1453 output->name = g_strdup (from->name);
1454 output->display_name = g_strdup (from->display_name);
1455 output->connector_type = g_strdup (from->connector_type);
1456 output->vendor = g_strdup (from->vendor);
1457 output->product = g_strdup (from->product);
1458 output->serial = g_strdup (from->serial);
1459 output->current_crtc = from->current_crtc;
1460 output->backlight = from->backlight;
1461 if (from->edid)
1462 output->edid = g_bytes_ref (from->edid);
1463 output->edid_file = g_strdup (from->edid_file);
1464
1465 output->is_primary = from->is_primary;
1466 output->is_presentation = from->is_presentation;
1467
1468 array = g_ptr_array_new ();
1469 for (p_crtc = from->possible_crtcs; *p_crtc != NULL; p_crtc++)
1470 {
1471 g_ptr_array_add (array, *p_crtc);
1472 }
1473 output->possible_crtcs = (GnomeRRCrtc**) g_ptr_array_free (array, FALSE);
1474
1475 array = g_ptr_array_new ();
1476 for (p_output = from->clones; *p_output != NULL; p_output++)
1477 {
1478 g_ptr_array_add (array, *p_output);
1479 }
1480 output->clones = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
1481
1482 array = g_ptr_array_new ();
1483 for (p_mode = from->modes; *p_mode != NULL; p_mode++)
1484 {
1485 g_ptr_array_add (array, *p_mode);
1486 }
1487 output->modes = (GnomeRRMode**) g_ptr_array_free (array, FALSE);
1488
1489 return output;
1490 }
1491
1492 static void
output_free(GnomeRROutput * output)1493 output_free (GnomeRROutput *output)
1494 {
1495 g_free (output->clones);
1496 g_free (output->modes);
1497 g_free (output->possible_crtcs);
1498 g_free (output->name);
1499 g_free (output->vendor);
1500 g_free (output->product);
1501 g_free (output->serial);
1502 g_free (output->display_name);
1503 g_free (output->connector_type);
1504 g_free (output->edid_file);
1505 if (output->edid)
1506 g_bytes_unref (output->edid);
1507 g_slice_free (GnomeRROutput, output);
1508 }
1509
1510 guint32
gnome_rr_output_get_id(GnomeRROutput * output)1511 gnome_rr_output_get_id (GnomeRROutput *output)
1512 {
1513 g_assert(output != NULL);
1514
1515 return output->id;
1516 }
1517
1518 const guint8 *
gnome_rr_output_get_edid_data(GnomeRROutput * output,gsize * size)1519 gnome_rr_output_get_edid_data (GnomeRROutput *output,
1520 gsize *size)
1521 {
1522 if (output->edid)
1523 return g_bytes_get_data (output->edid, size);
1524
1525 if (output->edid_file)
1526 {
1527 GMappedFile *mmap;
1528
1529 mmap = g_mapped_file_new (output->edid_file, FALSE, NULL);
1530
1531 if (mmap)
1532 {
1533 output->edid = g_mapped_file_get_bytes (mmap);
1534
1535 g_mapped_file_unref (mmap);
1536
1537 return g_bytes_get_data (output->edid, size);
1538 }
1539 }
1540
1541 return NULL;
1542 }
1543
1544 /**
1545 * gnome_rr_output_get_ids_from_edid:
1546 * @output: a #GnomeRROutput
1547 * @vendor: (out) (allow-none):
1548 * @product: (out) (allow-none):
1549 * @serial: (out) (allow-none):
1550 */
1551 void
gnome_rr_output_get_ids_from_edid(GnomeRROutput * output,char ** vendor,char ** product,char ** serial)1552 gnome_rr_output_get_ids_from_edid (GnomeRROutput *output,
1553 char **vendor,
1554 char **product,
1555 char **serial)
1556 {
1557 g_return_if_fail (output != NULL);
1558
1559 *vendor = g_strdup (output->vendor);
1560 *product = g_strdup (output->product);
1561 *serial = g_strdup (output->serial);
1562 }
1563
1564 /**
1565 * gnome_rr_output_get_physical_size:
1566 * @output: a #GnomeRROutput
1567 * @width_mm: (out) (allow-none):
1568 * @height_mm: (out) (allow-none):
1569 */
1570 void
gnome_rr_output_get_physical_size(GnomeRROutput * output,int * width_mm,int * height_mm)1571 gnome_rr_output_get_physical_size (GnomeRROutput *output,
1572 int *width_mm,
1573 int *height_mm)
1574 {
1575 g_return_if_fail (output != NULL);
1576
1577 if (width_mm)
1578 *width_mm = output->width_mm;
1579 if (height_mm)
1580 *height_mm = output->height_mm;
1581 }
1582
1583 const char *
gnome_rr_output_get_display_name(GnomeRROutput * output)1584 gnome_rr_output_get_display_name (GnomeRROutput *output)
1585 {
1586 g_return_val_if_fail (output != NULL, NULL);
1587
1588 return output->display_name;
1589 }
1590
1591 /**
1592 * gnome_rr_output_get_backlight:
1593 *
1594 * Returns: The currently set backlight brightness
1595 */
1596 int
gnome_rr_output_get_backlight(GnomeRROutput * output)1597 gnome_rr_output_get_backlight (GnomeRROutput *output)
1598 {
1599 g_return_val_if_fail (output != NULL, -1);
1600
1601 return output->backlight;
1602 }
1603
1604 /**
1605 * gnome_rr_output_get_min_backlight_step:
1606 *
1607 * Returns: The minimum backlight step available in percent
1608 */
1609 int
gnome_rr_output_get_min_backlight_step(GnomeRROutput * output)1610 gnome_rr_output_get_min_backlight_step (GnomeRROutput *output)
1611 {
1612 g_return_val_if_fail (output != NULL, -1);
1613
1614 return output->min_backlight_step;
1615 }
1616
1617 /**
1618 * gnome_rr_output_set_backlight:
1619 * @value: the absolute value which is 0 >= this <= 100
1620 *
1621 * Returns: %TRUE for success
1622 */
1623 gboolean
gnome_rr_output_set_backlight(GnomeRROutput * output,gint value,GError ** error)1624 gnome_rr_output_set_backlight (GnomeRROutput *output, gint value, GError **error)
1625 {
1626 g_return_val_if_fail (output != NULL, FALSE);
1627
1628 return meta_dbus_display_config_call_change_backlight_sync (output->info->screen->priv->proxy,
1629 output->info->serial,
1630 output->id, value,
1631 &output->backlight,
1632 NULL, error);
1633 }
1634
1635 gboolean
gnome_rr_output_set_color_transform(GnomeRROutput * output,GnomeRRCTM ctm,GError ** error)1636 gnome_rr_output_set_color_transform (GnomeRROutput *output, GnomeRRCTM ctm,
1637 GError **error)
1638 {
1639 GVariant *ctm_var;
1640 GVariant *values[9];
1641 int i;
1642
1643 g_return_val_if_fail (output != NULL, FALSE);
1644
1645 for (i = 0; i < 9; i++)
1646 values[i] = g_variant_new_uint64 (ctm.matrix[i]);
1647
1648 ctm_var = g_variant_new_tuple (values, 9);
1649
1650 return meta_dbus_display_config_call_set_output_ctm_sync (output->info->screen->priv->proxy,
1651 output->info->serial,
1652 output->id,
1653 ctm_var,
1654 NULL, error);
1655 }
1656
1657 /**
1658 * gnome_rr_screen_get_output_by_name:
1659 *
1660 * Returns: (transfer none): the output identified by @name
1661 */
1662 GnomeRROutput *
gnome_rr_screen_get_output_by_name(GnomeRRScreen * screen,const char * name)1663 gnome_rr_screen_get_output_by_name (GnomeRRScreen *screen,
1664 const char *name)
1665 {
1666 int i;
1667
1668 g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
1669 g_return_val_if_fail (screen->priv->info != NULL, NULL);
1670
1671 for (i = 0; screen->priv->info->outputs[i] != NULL; ++i)
1672 {
1673 GnomeRROutput *output = screen->priv->info->outputs[i];
1674
1675 if (strcmp (output->name, name) == 0)
1676 return output;
1677 }
1678
1679 return NULL;
1680 }
1681
1682 /**
1683 * gnome_rr_output_get_crtc:
1684 * @output: a #GnomeRROutput
1685 * Returns: (transfer none):
1686 */
1687 GnomeRRCrtc *
gnome_rr_output_get_crtc(GnomeRROutput * output)1688 gnome_rr_output_get_crtc (GnomeRROutput *output)
1689 {
1690 g_return_val_if_fail (output != NULL, NULL);
1691
1692 return output->current_crtc;
1693 }
1694
1695 /**
1696 * gnome_rr_output_get_possible_crtcs:
1697 * @output: a #GnomeRROutput
1698 * Returns: (array zero-terminated=1) (transfer none):
1699 */
1700 GnomeRRCrtc **
gnome_rr_output_get_possible_crtcs(GnomeRROutput * output)1701 gnome_rr_output_get_possible_crtcs (GnomeRROutput *output)
1702 {
1703 g_return_val_if_fail (output != NULL, NULL);
1704
1705 return output->possible_crtcs;
1706 }
1707
1708 gboolean
_gnome_rr_output_connector_type_is_builtin_display(const char * connector_type)1709 _gnome_rr_output_connector_type_is_builtin_display (const char *connector_type)
1710 {
1711 if (!connector_type)
1712 return FALSE;
1713
1714 if (strcmp (connector_type, "LVDS") == 0 ||
1715 strcmp (connector_type, "eDP") == 0 ||
1716 strcmp (connector_type, "DSI") == 0)
1717 return TRUE;
1718
1719 return FALSE;
1720 }
1721
1722 gboolean
gnome_rr_output_is_builtin_display(GnomeRROutput * output)1723 gnome_rr_output_is_builtin_display (GnomeRROutput *output)
1724 {
1725 g_return_val_if_fail (output != NULL, FALSE);
1726
1727 return _gnome_rr_output_connector_type_is_builtin_display (output->connector_type);
1728 }
1729
1730 /**
1731 * gnome_rr_output_get_current_mode:
1732 * @output: a #GnomeRROutput
1733 * Returns: (transfer none): the current mode of this output
1734 */
1735 GnomeRRMode *
gnome_rr_output_get_current_mode(GnomeRROutput * output)1736 gnome_rr_output_get_current_mode (GnomeRROutput *output)
1737 {
1738 GnomeRRCrtc *crtc;
1739 GnomeRRMode *mode;
1740 g_return_val_if_fail (output != NULL, NULL);
1741
1742 if ((crtc = gnome_rr_output_get_crtc (output)))
1743 {
1744 int total_w, total_h, tile_w, tile_h;
1745 mode = gnome_rr_crtc_get_current_mode (crtc);
1746
1747 if (_gnome_rr_output_get_tiled_display_size (output, &tile_w, &tile_h, &total_w, &total_h))
1748 {
1749 if (mode->width == tile_w &&
1750 mode->height == tile_h) {
1751 if (output->modes[0]->tiled)
1752 return output->modes[0];
1753 }
1754 }
1755 return gnome_rr_crtc_get_current_mode (crtc);
1756 }
1757 return NULL;
1758 }
1759
1760 /**
1761 * gnome_rr_output_get_position:
1762 * @output: a #GnomeRROutput
1763 * @x: (out) (allow-none):
1764 * @y: (out) (allow-none):
1765 */
1766 void
gnome_rr_output_get_position(GnomeRROutput * output,int * x,int * y)1767 gnome_rr_output_get_position (GnomeRROutput *output,
1768 int *x,
1769 int *y)
1770 {
1771 GnomeRRCrtc *crtc;
1772
1773 g_return_if_fail (output != NULL);
1774
1775 if ((crtc = gnome_rr_output_get_crtc (output)))
1776 gnome_rr_crtc_get_position (crtc, x, y);
1777 }
1778
1779 const char *
gnome_rr_output_get_name(GnomeRROutput * output)1780 gnome_rr_output_get_name (GnomeRROutput *output)
1781 {
1782 g_assert (output != NULL);
1783 return output->name;
1784 }
1785
1786 /**
1787 * gnome_rr_output_get_preferred_mode:
1788 * @output: a #GnomeRROutput
1789 * Returns: (transfer none):
1790 */
1791 GnomeRRMode *
gnome_rr_output_get_preferred_mode(GnomeRROutput * output)1792 gnome_rr_output_get_preferred_mode (GnomeRROutput *output)
1793 {
1794 g_return_val_if_fail (output != NULL, NULL);
1795 return output->modes[0];
1796 }
1797
1798 /**
1799 * gnome_rr_output_list_modes:
1800 * @output: a #GnomeRROutput
1801 * Returns: (array zero-terminated=1) (transfer none):
1802 */
1803 GnomeRRMode **
gnome_rr_output_list_modes(GnomeRROutput * output)1804 gnome_rr_output_list_modes (GnomeRROutput *output)
1805 {
1806 g_return_val_if_fail (output != NULL, NULL);
1807 return output->modes;
1808 }
1809
1810 gboolean
gnome_rr_output_supports_mode(GnomeRROutput * output,GnomeRRMode * mode)1811 gnome_rr_output_supports_mode (GnomeRROutput *output,
1812 GnomeRRMode *mode)
1813 {
1814 int i;
1815
1816 g_return_val_if_fail (output != NULL, FALSE);
1817 g_return_val_if_fail (mode != NULL, FALSE);
1818
1819 for (i = 0; output->modes[i] != NULL; ++i)
1820 {
1821 if (output->modes[i] == mode)
1822 return TRUE;
1823 }
1824
1825 return FALSE;
1826 }
1827
1828 gboolean
gnome_rr_output_can_clone(GnomeRROutput * output,GnomeRROutput * clone)1829 gnome_rr_output_can_clone (GnomeRROutput *output,
1830 GnomeRROutput *clone)
1831 {
1832 int i;
1833
1834 g_return_val_if_fail (output != NULL, FALSE);
1835 g_return_val_if_fail (clone != NULL, FALSE);
1836
1837 for (i = 0; output->clones[i] != NULL; ++i)
1838 {
1839 if (output->clones[i] == clone)
1840 return TRUE;
1841 }
1842
1843 return FALSE;
1844 }
1845
1846 gboolean
gnome_rr_output_get_is_primary(GnomeRROutput * output)1847 gnome_rr_output_get_is_primary (GnomeRROutput *output)
1848 {
1849 return output->is_primary;
1850 }
1851
1852 /* GnomeRRCrtc */
1853 static const GnomeRRRotation rotation_map[] =
1854 {
1855 GNOME_RR_ROTATION_0,
1856 GNOME_RR_ROTATION_90,
1857 GNOME_RR_ROTATION_180,
1858 GNOME_RR_ROTATION_270,
1859 GNOME_RR_REFLECT_X | GNOME_RR_ROTATION_0,
1860 GNOME_RR_REFLECT_X | GNOME_RR_ROTATION_90,
1861 GNOME_RR_REFLECT_X | GNOME_RR_ROTATION_180,
1862 GNOME_RR_REFLECT_X | GNOME_RR_ROTATION_270,
1863 };
1864
1865 static GnomeRRRotation
gnome_rr_rotation_from_transform(enum wl_output_transform transform)1866 gnome_rr_rotation_from_transform (enum wl_output_transform transform)
1867 {
1868 return rotation_map[transform];
1869 }
1870
1871 /**
1872 * gnome_rr_crtc_get_current_mode:
1873 * @crtc: a #GnomeRRCrtc
1874 * Returns: (transfer none): the current mode of this crtc
1875 */
1876 GnomeRRMode *
gnome_rr_crtc_get_current_mode(GnomeRRCrtc * crtc)1877 gnome_rr_crtc_get_current_mode (GnomeRRCrtc *crtc)
1878 {
1879 g_return_val_if_fail (crtc != NULL, NULL);
1880
1881 return crtc->current_mode;
1882 }
1883
1884 guint32
gnome_rr_crtc_get_id(GnomeRRCrtc * crtc)1885 gnome_rr_crtc_get_id (GnomeRRCrtc *crtc)
1886 {
1887 g_return_val_if_fail (crtc != NULL, 0);
1888
1889 return crtc->id;
1890 }
1891
1892 gboolean
gnome_rr_crtc_can_drive_output(GnomeRRCrtc * crtc,GnomeRROutput * output)1893 gnome_rr_crtc_can_drive_output (GnomeRRCrtc *crtc,
1894 GnomeRROutput *output)
1895 {
1896 int i;
1897
1898 g_return_val_if_fail (crtc != NULL, FALSE);
1899 g_return_val_if_fail (output != NULL, FALSE);
1900
1901 for (i = 0; crtc->possible_outputs[i] != NULL; ++i)
1902 {
1903 if (crtc->possible_outputs[i] == output)
1904 return TRUE;
1905 }
1906
1907 return FALSE;
1908 }
1909
1910 /**
1911 * gnome_rr_crtc_get_position:
1912 * @crtc: a #GnomeRRCrtc
1913 * @x: (out) (allow-none):
1914 * @y: (out) (allow-none):
1915 */
1916 void
gnome_rr_crtc_get_position(GnomeRRCrtc * crtc,int * x,int * y)1917 gnome_rr_crtc_get_position (GnomeRRCrtc *crtc,
1918 int *x,
1919 int *y)
1920 {
1921 g_return_if_fail (crtc != NULL);
1922
1923 if (x)
1924 *x = crtc->x;
1925
1926 if (y)
1927 *y = crtc->y;
1928 }
1929
1930 GnomeRRRotation
gnome_rr_crtc_get_current_rotation(GnomeRRCrtc * crtc)1931 gnome_rr_crtc_get_current_rotation (GnomeRRCrtc *crtc)
1932 {
1933 g_assert(crtc != NULL);
1934 return gnome_rr_rotation_from_transform (crtc->transform);
1935 }
1936
1937 static GnomeRRRotation
gnome_rr_rotation_from_all_transforms(int all_transforms)1938 gnome_rr_rotation_from_all_transforms (int all_transforms)
1939 {
1940 GnomeRRRotation ret = all_transforms & 0xF;
1941
1942 if (all_transforms & (1 << WL_OUTPUT_TRANSFORM_FLIPPED))
1943 ret |= GNOME_RR_REFLECT_X;
1944
1945 if (all_transforms & (1 << WL_OUTPUT_TRANSFORM_FLIPPED_180))
1946 ret |= GNOME_RR_REFLECT_Y;
1947
1948 return ret;
1949 }
1950
1951 GnomeRRRotation
gnome_rr_crtc_get_rotations(GnomeRRCrtc * crtc)1952 gnome_rr_crtc_get_rotations (GnomeRRCrtc *crtc)
1953 {
1954 g_assert(crtc != NULL);
1955 return gnome_rr_rotation_from_all_transforms (crtc->all_transforms);
1956 }
1957
1958 gboolean
gnome_rr_crtc_supports_rotation(GnomeRRCrtc * crtc,GnomeRRRotation rotation)1959 gnome_rr_crtc_supports_rotation (GnomeRRCrtc * crtc,
1960 GnomeRRRotation rotation)
1961 {
1962 g_return_val_if_fail (crtc != NULL, FALSE);
1963 return (gnome_rr_rotation_from_all_transforms (crtc->all_transforms) & rotation);
1964 }
1965
1966 static GnomeRRCrtc *
crtc_new(ScreenInfo * info,guint id)1967 crtc_new (ScreenInfo *info, guint id)
1968 {
1969 GnomeRRCrtc *crtc = g_slice_new0 (GnomeRRCrtc);
1970
1971 crtc->id = id;
1972 crtc->info = info;
1973 crtc->current_outputs = g_new0 (GnomeRROutput *, 1);
1974 crtc->possible_outputs = g_new0 (GnomeRROutput *, 1);
1975
1976 return crtc;
1977 }
1978
1979 static GnomeRRCrtc *
crtc_copy(const GnomeRRCrtc * from)1980 crtc_copy (const GnomeRRCrtc *from)
1981 {
1982 GnomeRROutput **p_output;
1983 GPtrArray *array;
1984 GnomeRRCrtc *to = g_slice_new0 (GnomeRRCrtc);
1985
1986 to->info = from->info;
1987 to->id = from->id;
1988 to->current_mode = from->current_mode;
1989 to->x = from->x;
1990 to->y = from->y;
1991 to->transform = from->transform;
1992 to->all_transforms = from->all_transforms;
1993 to->gamma_size = from->gamma_size;
1994
1995 array = g_ptr_array_new ();
1996 for (p_output = from->current_outputs; *p_output != NULL; p_output++)
1997 {
1998 g_ptr_array_add (array, *p_output);
1999 }
2000 to->current_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
2001
2002 array = g_ptr_array_new ();
2003 for (p_output = from->possible_outputs; *p_output != NULL; p_output++)
2004 {
2005 g_ptr_array_add (array, *p_output);
2006 }
2007 to->possible_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
2008
2009 return to;
2010 }
2011
2012 static void
crtc_initialize(GnomeRRCrtc * crtc,GVariant * info)2013 crtc_initialize (GnomeRRCrtc *crtc, GVariant *info)
2014 {
2015 GVariantIter *all_transforms;
2016 int current_mode_id;
2017 guint transform;
2018
2019 g_variant_get (info, META_CRTC_STRUCT,
2020 &crtc->id, &crtc->winsys_id,
2021 &crtc->x, &crtc->y,
2022 NULL, NULL,
2023 ¤t_mode_id,
2024 &crtc->transform, &all_transforms,
2025 NULL);
2026
2027 if (current_mode_id >= 0)
2028 crtc->current_mode = mode_by_id (crtc->info, current_mode_id);
2029
2030 while (g_variant_iter_loop (all_transforms, "u", &transform))
2031 crtc->all_transforms |= 1 << transform;
2032 g_variant_iter_free (all_transforms);
2033 }
2034
2035 static void
crtc_free(GnomeRRCrtc * crtc)2036 crtc_free (GnomeRRCrtc *crtc)
2037 {
2038 g_free (crtc->current_outputs);
2039 g_free (crtc->possible_outputs);
2040 g_slice_free (GnomeRRCrtc, crtc);
2041 }
2042
2043 /* GnomeRRMode */
2044 static GnomeRRMode *
mode_new(ScreenInfo * info,guint id)2045 mode_new (ScreenInfo *info, guint id)
2046 {
2047 GnomeRRMode *mode = g_slice_new0 (GnomeRRMode);
2048
2049 mode->id = id;
2050 mode->info = info;
2051
2052 return mode;
2053 }
2054
2055 guint32
gnome_rr_mode_get_id(GnomeRRMode * mode)2056 gnome_rr_mode_get_id (GnomeRRMode *mode)
2057 {
2058 g_return_val_if_fail (mode != NULL, 0);
2059 return mode->id;
2060 }
2061
2062 guint
gnome_rr_mode_get_width(GnomeRRMode * mode)2063 gnome_rr_mode_get_width (GnomeRRMode *mode)
2064 {
2065 g_return_val_if_fail (mode != NULL, 0);
2066 return mode->width;
2067 }
2068
2069 int
gnome_rr_mode_get_freq(GnomeRRMode * mode)2070 gnome_rr_mode_get_freq (GnomeRRMode *mode)
2071 {
2072 g_return_val_if_fail (mode != NULL, 0);
2073 return (mode->freq) / 1000;
2074 }
2075
2076 double
gnome_rr_mode_get_freq_f(GnomeRRMode * mode)2077 gnome_rr_mode_get_freq_f (GnomeRRMode *mode)
2078 {
2079 g_return_val_if_fail (mode != NULL, 0.0);
2080 return (mode->freq) / 1000.0;
2081 }
2082
2083 guint
gnome_rr_mode_get_height(GnomeRRMode * mode)2084 gnome_rr_mode_get_height (GnomeRRMode *mode)
2085 {
2086 g_return_val_if_fail (mode != NULL, 0);
2087 return mode->height;
2088 }
2089
2090 /**
2091 * gnome_rr_mode_get_is_tiled:
2092 * @mode: a #GnomeRRMode
2093 *
2094 * Returns TRUE if this mode is a tiled
2095 * mode created for span a tiled monitor.
2096 */
2097 gboolean
gnome_rr_mode_get_is_tiled(GnomeRRMode * mode)2098 gnome_rr_mode_get_is_tiled (GnomeRRMode *mode)
2099 {
2100 g_return_val_if_fail (mode != NULL, FALSE);
2101 return mode->tiled;
2102 }
2103
2104 gboolean
gnome_rr_mode_get_is_interlaced(GnomeRRMode * mode)2105 gnome_rr_mode_get_is_interlaced (GnomeRRMode *mode)
2106 {
2107 g_return_val_if_fail (mode != NULL, 0);
2108 return (mode->flags & DRM_MODE_FLAG_INTERLACE) != 0;
2109 }
2110
2111 static void
mode_initialize(GnomeRRMode * mode,GVariant * info)2112 mode_initialize (GnomeRRMode *mode, GVariant *info)
2113 {
2114 gdouble frequency;
2115
2116 g_variant_get (info, META_MONITOR_MODE_STRUCT,
2117 &mode->id, &mode->winsys_id,
2118 &mode->width, &mode->height,
2119 &frequency, &mode->flags);
2120
2121 mode->freq = frequency * 1000;
2122 }
2123
2124 static GnomeRRMode *
mode_copy(const GnomeRRMode * from)2125 mode_copy (const GnomeRRMode *from)
2126 {
2127 GnomeRRMode *to = g_slice_new0 (GnomeRRMode);
2128
2129 to->id = from->id;
2130 to->info = from->info;
2131 to->width = from->width;
2132 to->height = from->height;
2133 to->freq = from->freq;
2134
2135 return to;
2136 }
2137
2138 static void
mode_free(GnomeRRMode * mode)2139 mode_free (GnomeRRMode *mode)
2140 {
2141 g_slice_free (GnomeRRMode, mode);
2142 }
2143
2144 gboolean
_gnome_rr_screen_apply_configuration(GnomeRRScreen * screen,gboolean persistent,GVariant * crtcs,GVariant * outputs,GError ** error)2145 _gnome_rr_screen_apply_configuration (GnomeRRScreen *screen,
2146 gboolean persistent,
2147 GVariant *crtcs,
2148 GVariant *outputs,
2149 GError **error)
2150 {
2151 return meta_dbus_display_config_call_apply_configuration_sync (screen->priv->proxy,
2152 screen->priv->info->serial,
2153 persistent,
2154 crtcs, outputs,
2155 NULL, error);
2156 }
2157
2158 gboolean
gnome_rr_crtc_set_gamma(GnomeRRCrtc * crtc,int size,unsigned short * red,unsigned short * green,unsigned short * blue)2159 gnome_rr_crtc_set_gamma (GnomeRRCrtc *crtc,
2160 int size,
2161 unsigned short *red,
2162 unsigned short *green,
2163 unsigned short *blue)
2164 {
2165 GBytes *red_bytes, *green_bytes, *blue_bytes;
2166 GVariant *red_v, *green_v, *blue_v;
2167 gboolean ok;
2168
2169 red_bytes = g_bytes_new (red, size * sizeof (unsigned short));
2170 green_bytes = g_bytes_new (green, size * sizeof (unsigned short));
2171 blue_bytes = g_bytes_new (blue, size * sizeof (unsigned short));
2172
2173 red_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"),
2174 red_bytes, TRUE);
2175 green_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"),
2176 green_bytes, TRUE);
2177 blue_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"),
2178 blue_bytes, TRUE);
2179
2180 ok = meta_dbus_display_config_call_set_crtc_gamma_sync (crtc->info->screen->priv->proxy,
2181 crtc->info->serial,
2182 crtc->id,
2183 red_v,
2184 green_v,
2185 blue_v,
2186 NULL, NULL);
2187
2188 g_bytes_unref (red_bytes);
2189 g_bytes_unref (green_bytes);
2190 g_bytes_unref (blue_bytes);
2191 /* The variant above are floating, no need to free them */
2192
2193 return ok;
2194 }
2195
2196 /**
2197 * gnome_rr_crtc_get_gamma:
2198 * @crtc: a #GnomeRRCrtc
2199 * @size:
2200 * @red: (out): the minimum width
2201 * @green: (out): the maximum width
2202 * @blue: (out): the minimum height
2203 *
2204 * Returns: %TRUE for success
2205 */
2206 gboolean
gnome_rr_crtc_get_gamma(GnomeRRCrtc * crtc,int * size,unsigned short ** red,unsigned short ** green,unsigned short ** blue)2207 gnome_rr_crtc_get_gamma (GnomeRRCrtc *crtc,
2208 int *size,
2209 unsigned short **red,
2210 unsigned short **green,
2211 unsigned short **blue)
2212 {
2213 GBytes *red_bytes, *green_bytes, *blue_bytes;
2214 GVariant *red_v, *green_v, *blue_v;
2215 gboolean ok;
2216 gsize dummy;
2217
2218 ok = meta_dbus_display_config_call_get_crtc_gamma_sync (crtc->info->screen->priv->proxy,
2219 crtc->info->serial,
2220 crtc->id,
2221 &red_v,
2222 &green_v,
2223 &blue_v,
2224 NULL, NULL);
2225 if (!ok)
2226 return FALSE;
2227
2228 red_bytes = g_variant_get_data_as_bytes (red_v);
2229 green_bytes = g_variant_get_data_as_bytes (green_v);
2230 blue_bytes = g_variant_get_data_as_bytes (blue_v);
2231
2232 /* Unref the variant early so that the bytes hold the only reference to
2233 the data and we don't need to copy
2234 */
2235 g_variant_unref (red_v);
2236 g_variant_unref (green_v);
2237 g_variant_unref (blue_v);
2238
2239 if (size)
2240 *size = g_bytes_get_size (red_bytes) / sizeof (unsigned short);
2241
2242 if (red)
2243 *red = g_bytes_unref_to_data (red_bytes, &dummy);
2244 else
2245 g_bytes_unref (red_bytes);
2246 if (green)
2247 *green = g_bytes_unref_to_data (green_bytes, &dummy);
2248 else
2249 g_bytes_unref (green_bytes);
2250 if (blue)
2251 *blue = g_bytes_unref_to_data (blue_bytes, &dummy);
2252 else
2253 g_bytes_unref (blue_bytes);
2254
2255 return TRUE;
2256 }
2257
2258 gboolean
gnome_rr_output_get_is_underscanning(GnomeRROutput * output)2259 gnome_rr_output_get_is_underscanning (GnomeRROutput *output)
2260 {
2261 g_assert(output != NULL);
2262 return output->is_underscanning;
2263 }
2264
2265 gboolean
gnome_rr_output_supports_underscanning(GnomeRROutput * output)2266 gnome_rr_output_supports_underscanning (GnomeRROutput *output)
2267 {
2268 g_assert (output != NULL);
2269 return output->supports_underscanning;
2270 }
2271
2272 gboolean
gnome_rr_output_supports_color_transform(const GnomeRROutput * output)2273 gnome_rr_output_supports_color_transform (const GnomeRROutput *output)
2274 {
2275 g_assert (output != NULL);
2276 return output->supports_color_transform;
2277 }
2278
2279 const char *
_gnome_rr_output_get_connector_type(GnomeRROutput * output)2280 _gnome_rr_output_get_connector_type (GnomeRROutput *output)
2281 {
2282 g_return_val_if_fail (output != NULL, NULL);
2283
2284 return output->connector_type;
2285 }
2286
2287 gboolean
_gnome_rr_output_get_tile_info(GnomeRROutput * output,GnomeRRTile * tile)2288 _gnome_rr_output_get_tile_info (GnomeRROutput *output,
2289 GnomeRRTile *tile)
2290 {
2291 if (output->tile_info.group_id == UNDEFINED_GROUP_ID)
2292 return FALSE;
2293
2294 if (!tile)
2295 return FALSE;
2296
2297 *tile = output->tile_info;
2298 return TRUE;
2299 }
2300
2301 GType
gnome_rr_dpms_mode_get_type(void)2302 gnome_rr_dpms_mode_get_type (void)
2303 {
2304 static GType etype = 0;
2305 if (etype == 0) {
2306 static const GEnumValue values[] = {
2307 { GNOME_RR_DPMS_ON, "GNOME_RR_DPMS_ON", "on" },
2308 { GNOME_RR_DPMS_STANDBY, "GNOME_RR_DPMS_STANDBY", "standby" },
2309 { GNOME_RR_DPMS_SUSPEND, "GNOME_RR_DPMS_SUSPEND", "suspend" },
2310 { GNOME_RR_DPMS_OFF, "GNOME_RR_DPMS_OFF", "off" },
2311 { GNOME_RR_DPMS_UNKNOWN, "GNOME_RR_DPMS_UNKNOWN", "unknown" },
2312 { 0, NULL, NULL }
2313 };
2314 etype = g_enum_register_static ("GnomeRRDpmsModeType", values);
2315 }
2316 return etype;
2317 }
2318