1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 
3 /*
4  * Copyright (C) 2001, 2002 Havoc Pennington
5  * Copyright (C) 2002, 2003 Red Hat Inc.
6  * Some ICCCM manager selection code derived from fvwm2,
7  * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
8  * Copyright (C) 2003 Rob Adams
9  * Copyright (C) 2004-2006 Elijah Newren
10  * Copyright (C) 2013 Red Hat Inc.
11  * Copyright (C) 2020 NVIDIA CORPORATION
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License as
15  * published by the Free Software Foundation; either version 2 of the
16  * License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 /**
28  * SECTION:meta-monitor-manager
29  * @title: MetaMonitorManager
30  * @short_description: A manager for multiple monitors
31  *
32  * #MetaMonitorManager is an abstract class which contains methods to handle
33  * multiple monitors (both #MetaMonitor and #MetaLogicalMonitor) and GPU's
34  * (#MetaGpu). Its functions include reading and/or changing the current
35  * configuration and available capabiliies.
36  *
37  * The #MetaMonitorManager also provides the "org.gnome.Mutter.DisplayConfig"
38  * DBus service, so apps like GNOME Settings can use this functionality.
39  */
40 
41 #include "config.h"
42 
43 #include "backends/meta-monitor-manager-private.h"
44 
45 #include <string.h>
46 #include <math.h>
47 #include <stdlib.h>
48 
49 #include "backends/meta-backend-private.h"
50 #include "backends/meta-crtc.h"
51 #include "backends/meta-logical-monitor.h"
52 #include "backends/meta-monitor.h"
53 #include "backends/meta-monitor-config-manager.h"
54 #include "backends/meta-orientation-manager.h"
55 #include "backends/meta-output.h"
56 #include "backends/meta-virtual-monitor.h"
57 #include "backends/x11/meta-monitor-manager-xrandr.h"
58 #include "clutter/clutter.h"
59 #include "core/util-private.h"
60 #include "meta/main.h"
61 #include "meta/meta-x11-errors.h"
62 
63 #include "meta-dbus-display-config.h"
64 
65 #define DEFAULT_DISPLAY_CONFIGURATION_TIMEOUT 20
66 
67 enum
68 {
69   PROP_0,
70 
71   PROP_BACKEND,
72   PROP_PANEL_ORIENTATION_MANAGED,
73 
74   PROP_LAST
75 };
76 
77 static GParamSpec *obj_props[PROP_LAST];
78 
79 enum
80 {
81   MONITORS_CHANGED,
82   MONITORS_CHANGED_INTERNAL,
83   POWER_SAVE_MODE_CHANGED,
84   CONFIRM_DISPLAY_CHANGE,
85   SIGNALS_LAST
86 };
87 
88 /* Array index matches MetaMonitorTransform */
89 static gfloat transform_matrices[][6] = {
90   {  1,  0,  0,  0,  1,  0 }, /* normal */
91   {  0, -1,  1,  1,  0,  0 }, /* 90° */
92   { -1,  0,  1,  0, -1,  1 }, /* 180° */
93   {  0,  1,  0, -1,  0,  1 }, /* 270° */
94   { -1,  0,  1,  0,  1,  0 }, /* normal flipped */
95   {  0,  1,  0,  1,  0,  0 }, /* 90° flipped */
96   {  1,  0,  0,  0, -1,  1 }, /* 180° flipped */
97   {  0, -1,  1, -1,  0,  1 }, /* 270° flipped */
98 };
99 
100 static int signals[SIGNALS_LAST];
101 
102 typedef struct _MetaMonitorManagerPrivate
103 {
104   MetaPowerSave power_save_mode;
105   gboolean      initial_orient_change_done;
106 
107   GList *virtual_monitors;
108 
109   gboolean shutting_down;
110 } MetaMonitorManagerPrivate;
111 
112 G_DEFINE_TYPE_WITH_PRIVATE (MetaMonitorManager, meta_monitor_manager,
113                             G_TYPE_OBJECT)
114 
115 static void initialize_dbus_interface (MetaMonitorManager *manager);
116 static void monitor_manager_setup_dbus_config_handlers (MetaMonitorManager *manager);
117 
118 static gboolean
119 meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
120                                          MetaMonitorsConfig *config);
121 
122 static void
123 meta_monitor_manager_real_read_current_state (MetaMonitorManager *manager);
124 
125 static gboolean
126 is_global_scale_matching_in_config (MetaMonitorsConfig *config,
127                                     float               scale);
128 
129 MetaBackend *
meta_monitor_manager_get_backend(MetaMonitorManager * manager)130 meta_monitor_manager_get_backend (MetaMonitorManager *manager)
131 {
132   return manager->backend;
133 }
134 
135 static void
meta_monitor_manager_init(MetaMonitorManager * manager)136 meta_monitor_manager_init (MetaMonitorManager *manager)
137 {
138 }
139 
140 static void
meta_monitor_manager_set_primary_logical_monitor(MetaMonitorManager * manager,MetaLogicalMonitor * logical_monitor)141 meta_monitor_manager_set_primary_logical_monitor (MetaMonitorManager *manager,
142                                                   MetaLogicalMonitor *logical_monitor)
143 {
144   manager->primary_logical_monitor = logical_monitor;
145   if (logical_monitor)
146     meta_logical_monitor_make_primary (logical_monitor);
147 }
148 
149 static gboolean
is_main_tiled_monitor_output(MetaOutput * output)150 is_main_tiled_monitor_output (MetaOutput *output)
151 {
152   const MetaOutputInfo *output_info = meta_output_get_info (output);
153 
154   return (output_info->tile_info.loc_h_tile == 0 &&
155           output_info->tile_info.loc_v_tile == 0);
156 }
157 
158 static MetaLogicalMonitor *
logical_monitor_from_layout(MetaMonitorManager * manager,GList * logical_monitors,MetaRectangle * layout)159 logical_monitor_from_layout (MetaMonitorManager *manager,
160                              GList              *logical_monitors,
161                              MetaRectangle      *layout)
162 {
163   GList *l;
164 
165   for (l = logical_monitors; l; l = l->next)
166     {
167       MetaLogicalMonitor *logical_monitor = l->data;
168 
169       if (meta_rectangle_equal (layout, &logical_monitor->rect))
170         return logical_monitor;
171     }
172 
173   return NULL;
174 }
175 
176 static void
meta_monitor_manager_rebuild_logical_monitors(MetaMonitorManager * manager,MetaMonitorsConfig * config)177 meta_monitor_manager_rebuild_logical_monitors (MetaMonitorManager *manager,
178                                                MetaMonitorsConfig *config)
179 {
180   GList *logical_monitor_configs;
181   GList *logical_monitors = NULL;
182   GList *l;
183   int monitor_number = 0;
184   MetaLogicalMonitor *primary_logical_monitor = NULL;
185 
186   logical_monitor_configs = config ? config->logical_monitor_configs : NULL;
187   for (l = logical_monitor_configs; l; l = l->next)
188     {
189       MetaLogicalMonitorConfig *logical_monitor_config = l->data;
190       MetaLogicalMonitor *logical_monitor;
191 
192       logical_monitor = meta_logical_monitor_new (manager,
193                                                   logical_monitor_config,
194                                                   monitor_number);
195       monitor_number++;
196 
197       if (logical_monitor_config->is_primary)
198         primary_logical_monitor = logical_monitor;
199 
200       logical_monitors = g_list_append (logical_monitors, logical_monitor);
201     }
202 
203   /*
204    * If no monitor was marked as primary, fall back on marking the first
205    * logical monitor the primary one.
206    */
207   if (!primary_logical_monitor && logical_monitors)
208     primary_logical_monitor = g_list_first (logical_monitors)->data;
209 
210   manager->logical_monitors = logical_monitors;
211   meta_monitor_manager_set_primary_logical_monitor (manager,
212                                                     primary_logical_monitor);
213 }
214 
215 static float
derive_configured_global_scale(MetaMonitorManager * manager,MetaMonitorsConfig * config)216 derive_configured_global_scale (MetaMonitorManager *manager,
217                                 MetaMonitorsConfig *config)
218 {
219   GList *l;
220 
221   for (l = config->logical_monitor_configs; l; l = l->next)
222     {
223       MetaLogicalMonitorConfig *monitor_config = l->data;
224 
225       if (is_global_scale_matching_in_config (config, monitor_config->scale))
226         return monitor_config->scale;
227     }
228 
229   return 1.0;
230 }
231 
232 static float
calculate_monitor_scale(MetaMonitorManager * manager,MetaMonitor * monitor)233 calculate_monitor_scale (MetaMonitorManager *manager,
234                          MetaMonitor        *monitor)
235 {
236   MetaMonitorMode *monitor_mode;
237 
238   monitor_mode = meta_monitor_get_current_mode (monitor);
239   return meta_monitor_manager_calculate_monitor_mode_scale (manager,
240                                                             manager->layout_mode,
241                                                             monitor,
242                                                             monitor_mode);
243 }
244 
245 static gboolean
meta_monitor_manager_is_scale_supported_by_other_monitors(MetaMonitorManager * manager,MetaMonitor * not_this_one,float scale)246 meta_monitor_manager_is_scale_supported_by_other_monitors (MetaMonitorManager *manager,
247                                                            MetaMonitor        *not_this_one,
248                                                            float               scale)
249 {
250   GList *l;
251 
252   for (l = manager->monitors; l; l = l->next)
253     {
254       MetaMonitor *monitor = l->data;
255       MetaMonitorMode *mode;
256 
257       if (monitor == not_this_one || !meta_monitor_is_active (monitor))
258         continue;
259 
260       mode = meta_monitor_get_current_mode (monitor);
261       if (!meta_monitor_manager_is_scale_supported (manager,
262                                                     manager->layout_mode,
263                                                     monitor, mode, scale))
264         return FALSE;
265     }
266 
267   return TRUE;
268 }
269 
270 static float
derive_calculated_global_scale(MetaMonitorManager * manager)271 derive_calculated_global_scale (MetaMonitorManager *manager)
272 {
273   MetaMonitor *monitor = NULL;
274   float scale;
275   GList *l;
276 
277   scale = 1.0;
278   monitor = meta_monitor_manager_get_primary_monitor (manager);
279 
280   if (monitor && meta_monitor_is_active (monitor))
281     {
282       scale = calculate_monitor_scale (manager, monitor);
283       if (meta_monitor_manager_is_scale_supported_by_other_monitors (manager,
284                                                                      monitor,
285                                                                      scale))
286         return scale;
287     }
288 
289   for (l = manager->monitors; l; l = l->next)
290     {
291       MetaMonitor *other_monitor = l->data;
292       float monitor_scale;
293 
294       if (other_monitor == monitor || !meta_monitor_is_active (other_monitor))
295         continue;
296 
297       monitor_scale = calculate_monitor_scale (manager, other_monitor);
298       if (meta_monitor_manager_is_scale_supported_by_other_monitors (manager,
299                                                                      other_monitor,
300                                                                      monitor_scale))
301         scale = MAX (scale, monitor_scale);
302     }
303 
304   return scale;
305 }
306 
307 static float
derive_scale_from_config(MetaMonitorManager * manager,MetaMonitorsConfig * config,MetaRectangle * layout)308 derive_scale_from_config (MetaMonitorManager *manager,
309                           MetaMonitorsConfig *config,
310                           MetaRectangle      *layout)
311 {
312   GList *l;
313 
314   for (l = config->logical_monitor_configs; l; l = l->next)
315     {
316       MetaLogicalMonitorConfig *logical_monitor_config = l->data;
317 
318       if (meta_rectangle_equal (layout, &logical_monitor_config->layout))
319         return logical_monitor_config->scale;
320     }
321 
322   g_warning ("Missing logical monitor, using scale 1");
323   return 1.0;
324 }
325 
326 static void
meta_monitor_manager_rebuild_logical_monitors_derived(MetaMonitorManager * manager,MetaMonitorsConfig * config)327 meta_monitor_manager_rebuild_logical_monitors_derived (MetaMonitorManager *manager,
328                                                        MetaMonitorsConfig *config)
329 {
330   GList *logical_monitors = NULL;
331   GList *l;
332   int monitor_number;
333   MetaLogicalMonitor *primary_logical_monitor = NULL;
334   gboolean use_global_scale;
335   float global_scale = 0.0;
336   MetaMonitorManagerCapability capabilities;
337 
338   monitor_number = 0;
339 
340   capabilities = meta_monitor_manager_get_capabilities (manager);
341   use_global_scale =
342     !!(capabilities & META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
343 
344   if (use_global_scale)
345     {
346       if (config)
347         global_scale = derive_configured_global_scale (manager, config);
348       else
349         global_scale = derive_calculated_global_scale (manager);
350     }
351 
352   for (l = manager->monitors; l; l = l->next)
353     {
354       MetaMonitor *monitor = l->data;
355       MetaLogicalMonitor *logical_monitor;
356       MetaRectangle layout;
357 
358       if (!meta_monitor_is_active (monitor))
359         continue;
360 
361       meta_monitor_derive_layout (monitor, &layout);
362       logical_monitor = logical_monitor_from_layout (manager, logical_monitors,
363                                                      &layout);
364       if (logical_monitor)
365         {
366           meta_logical_monitor_add_monitor (logical_monitor, monitor);
367         }
368       else
369         {
370           float scale;
371 
372           if (use_global_scale)
373             scale = global_scale;
374           else if (config)
375             scale = derive_scale_from_config (manager, config, &layout);
376           else
377             scale = calculate_monitor_scale (manager, monitor);
378 
379           g_assert (scale > 0);
380 
381           logical_monitor = meta_logical_monitor_new_derived (manager,
382                                                               monitor,
383                                                               &layout,
384                                                               scale,
385                                                               monitor_number);
386           logical_monitors = g_list_append (logical_monitors, logical_monitor);
387           monitor_number++;
388         }
389 
390       if (meta_monitor_is_primary (monitor))
391         primary_logical_monitor = logical_monitor;
392     }
393 
394   manager->logical_monitors = logical_monitors;
395 
396   /*
397    * If no monitor was marked as primary, fall back on marking the first
398    * logical monitor the primary one.
399    */
400   if (!primary_logical_monitor && manager->logical_monitors)
401     primary_logical_monitor = g_list_first (manager->logical_monitors)->data;
402 
403   meta_monitor_manager_set_primary_logical_monitor (manager,
404                                                     primary_logical_monitor);
405 }
406 
407 void
meta_monitor_manager_power_save_mode_changed(MetaMonitorManager * manager,MetaPowerSave mode)408 meta_monitor_manager_power_save_mode_changed (MetaMonitorManager *manager,
409                                               MetaPowerSave       mode)
410 {
411   MetaMonitorManagerPrivate *priv =
412     meta_monitor_manager_get_instance_private (manager);
413 
414   if (priv->power_save_mode == mode)
415     return;
416 
417   priv->power_save_mode = mode;
418   g_signal_emit (manager, signals[POWER_SAVE_MODE_CHANGED], 0);
419 }
420 
421 static void
power_save_mode_changed(MetaMonitorManager * manager,GParamSpec * pspec,gpointer user_data)422 power_save_mode_changed (MetaMonitorManager *manager,
423                          GParamSpec         *pspec,
424                          gpointer            user_data)
425 {
426   MetaMonitorManagerPrivate *priv =
427     meta_monitor_manager_get_instance_private (manager);
428   MetaMonitorManagerClass *klass;
429   int mode = meta_dbus_display_config_get_power_save_mode (manager->display_config);
430 
431   if (mode == META_POWER_SAVE_UNSUPPORTED)
432     return;
433 
434   /* If DPMS is unsupported, force the property back. */
435   if (priv->power_save_mode == META_POWER_SAVE_UNSUPPORTED)
436     {
437       meta_dbus_display_config_set_power_save_mode (manager->display_config, META_POWER_SAVE_UNSUPPORTED);
438       return;
439     }
440 
441   klass = META_MONITOR_MANAGER_GET_CLASS (manager);
442   if (klass->set_power_save_mode)
443     klass->set_power_save_mode (manager, mode);
444 
445   meta_monitor_manager_power_save_mode_changed (manager, mode);
446 }
447 
448 void
meta_monitor_manager_lid_is_closed_changed(MetaMonitorManager * manager)449 meta_monitor_manager_lid_is_closed_changed (MetaMonitorManager *manager)
450 {
451   meta_monitor_manager_ensure_configured (manager);
452 }
453 
454 static void
lid_is_closed_changed(MetaBackend * backend,gboolean lid_is_closed,gpointer user_data)455 lid_is_closed_changed (MetaBackend *backend,
456                        gboolean     lid_is_closed,
457                        gpointer     user_data)
458 {
459   MetaMonitorManager *manager = user_data;
460   meta_monitor_manager_lid_is_closed_changed (manager);
461 }
462 
463 static void
prepare_shutdown(MetaBackend * backend,MetaMonitorManager * manager)464 prepare_shutdown (MetaBackend        *backend,
465                   MetaMonitorManager *manager)
466 {
467   MetaMonitorManagerPrivate *priv =
468     meta_monitor_manager_get_instance_private (manager);
469 
470   priv->shutting_down = TRUE;
471 }
472 
473 /**
474  * meta_monitor_manager_is_headless:
475  * @manager: A #MetaMonitorManager object
476  *
477  * Returns whether the monitor manager is headless, i.e. without
478  * any #MetaLogicalMonitor<!-- -->s attached to it.
479  *
480  * Returns: %TRUE if no monitors are attached, %FALSE otherwise.
481  */
482 gboolean
meta_monitor_manager_is_headless(MetaMonitorManager * manager)483 meta_monitor_manager_is_headless (MetaMonitorManager *manager)
484 {
485   return !manager->logical_monitors;
486 }
487 
488 float
meta_monitor_manager_calculate_monitor_mode_scale(MetaMonitorManager * manager,MetaLogicalMonitorLayoutMode layout_mode,MetaMonitor * monitor,MetaMonitorMode * monitor_mode)489 meta_monitor_manager_calculate_monitor_mode_scale (MetaMonitorManager           *manager,
490                                                    MetaLogicalMonitorLayoutMode  layout_mode,
491                                                    MetaMonitor                  *monitor,
492                                                    MetaMonitorMode              *monitor_mode)
493 {
494   MetaMonitorManagerClass *manager_class =
495     META_MONITOR_MANAGER_GET_CLASS (manager);
496 
497   return manager_class->calculate_monitor_mode_scale (manager,
498                                                       layout_mode,
499                                                       monitor,
500                                                       monitor_mode);
501 }
502 
503 float *
meta_monitor_manager_calculate_supported_scales(MetaMonitorManager * manager,MetaLogicalMonitorLayoutMode layout_mode,MetaMonitor * monitor,MetaMonitorMode * monitor_mode,int * n_supported_scales)504 meta_monitor_manager_calculate_supported_scales (MetaMonitorManager           *manager,
505                                                  MetaLogicalMonitorLayoutMode  layout_mode,
506                                                  MetaMonitor                  *monitor,
507                                                  MetaMonitorMode              *monitor_mode,
508                                                  int                          *n_supported_scales)
509 {
510   MetaMonitorManagerClass *manager_class =
511     META_MONITOR_MANAGER_GET_CLASS (manager);
512 
513   return manager_class->calculate_supported_scales (manager,
514                                                     layout_mode,
515                                                     monitor,
516                                                     monitor_mode,
517                                                     n_supported_scales);
518 }
519 
520 /**
521  * meta_monitor_manager_get_capabilities:
522  * @manager: A #MetaMonitorManager object
523  *
524  * Queries the capabilities of the monitor manager.
525  *
526  * Returns: #MetaMonitorManagerCapability flags representing the capabilities.
527  */
528 MetaMonitorManagerCapability
meta_monitor_manager_get_capabilities(MetaMonitorManager * manager)529 meta_monitor_manager_get_capabilities (MetaMonitorManager *manager)
530 {
531   MetaMonitorManagerClass *manager_class =
532     META_MONITOR_MANAGER_GET_CLASS (manager);
533 
534   return manager_class->get_capabilities (manager);
535 }
536 
537 gboolean
meta_monitor_manager_get_max_screen_size(MetaMonitorManager * manager,int * max_width,int * max_height)538 meta_monitor_manager_get_max_screen_size (MetaMonitorManager *manager,
539                                           int                *max_width,
540                                           int                *max_height)
541 {
542   MetaMonitorManagerClass *manager_class =
543     META_MONITOR_MANAGER_GET_CLASS (manager);
544 
545   return manager_class->get_max_screen_size (manager, max_width, max_height);
546 }
547 
548 
549 MetaLogicalMonitorLayoutMode
meta_monitor_manager_get_default_layout_mode(MetaMonitorManager * manager)550 meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager)
551 {
552   MetaMonitorManagerClass *manager_class =
553     META_MONITOR_MANAGER_GET_CLASS (manager);
554 
555   return manager_class->get_default_layout_mode (manager);
556 }
557 
558 static void
on_virtual_monitor_destroyed(MetaVirtualMonitor * virtual_monitor,MetaMonitorManager * manager)559 on_virtual_monitor_destroyed (MetaVirtualMonitor *virtual_monitor,
560                               MetaMonitorManager *manager)
561 {
562   MetaMonitorManagerPrivate *priv =
563     meta_monitor_manager_get_instance_private (manager);
564   MetaOutput *output;
565 
566   output = meta_virtual_monitor_get_output (virtual_monitor);
567   g_message ("Removed virtual monitor %s", meta_output_get_name (output));
568   priv->virtual_monitors = g_list_remove (priv->virtual_monitors,
569                                           virtual_monitor);
570 
571   if (!priv->shutting_down)
572     meta_monitor_manager_reload (manager);
573 }
574 
575 MetaVirtualMonitor *
meta_monitor_manager_create_virtual_monitor(MetaMonitorManager * manager,const MetaVirtualMonitorInfo * info,GError ** error)576 meta_monitor_manager_create_virtual_monitor (MetaMonitorManager            *manager,
577                                              const MetaVirtualMonitorInfo  *info,
578                                              GError                       **error)
579 {
580   MetaMonitorManagerPrivate *priv =
581     meta_monitor_manager_get_instance_private (manager);
582   MetaMonitorManagerClass *manager_class =
583     META_MONITOR_MANAGER_GET_CLASS (manager);
584   MetaVirtualMonitor *virtual_monitor;
585   MetaOutput *output;
586 
587   if (!manager_class->create_virtual_monitor)
588     {
589       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
590                    "Backend doesn't support creating virtual monitors");
591       return NULL;
592     }
593 
594   virtual_monitor = manager_class->create_virtual_monitor (manager, info,
595                                                            error);
596   if (!virtual_monitor)
597     return NULL;
598 
599   g_signal_connect (virtual_monitor, "destroy",
600                     G_CALLBACK (on_virtual_monitor_destroyed),
601                     manager);
602 
603   priv->virtual_monitors = g_list_append (priv->virtual_monitors,
604                                           virtual_monitor);
605 
606   output = meta_virtual_monitor_get_output (virtual_monitor);
607   g_message ("Added virtual monitor %s", meta_output_get_name (output));
608 
609   return virtual_monitor;
610 }
611 
612 static void
meta_monitor_manager_ensure_initial_config(MetaMonitorManager * manager)613 meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager)
614 {
615   META_MONITOR_MANAGER_GET_CLASS (manager)->ensure_initial_config (manager);
616 }
617 
618 static gboolean
meta_monitor_manager_apply_monitors_config(MetaMonitorManager * manager,MetaMonitorsConfig * config,MetaMonitorsConfigMethod method,GError ** error)619 meta_monitor_manager_apply_monitors_config (MetaMonitorManager      *manager,
620                                             MetaMonitorsConfig      *config,
621                                             MetaMonitorsConfigMethod method,
622                                             GError                 **error)
623 {
624   MetaMonitorManagerClass *manager_class =
625     META_MONITOR_MANAGER_GET_CLASS (manager);
626 
627   g_assert (!config ||
628             !(config->flags & META_MONITORS_CONFIG_FLAG_MIGRATED));
629 
630   if (!manager_class->apply_monitors_config (manager, config, method, error))
631     return FALSE;
632 
633   switch (method)
634     {
635     case META_MONITORS_CONFIG_METHOD_TEMPORARY:
636     case META_MONITORS_CONFIG_METHOD_PERSISTENT:
637       meta_monitor_config_manager_set_current (manager->config_manager, config);
638       break;
639     case META_MONITORS_CONFIG_METHOD_VERIFY:
640       break;
641     }
642 
643   return TRUE;
644 }
645 
646 gboolean
meta_monitor_manager_has_hotplug_mode_update(MetaMonitorManager * manager)647 meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
648 {
649   GList *gpus;
650   GList *l;
651 
652   gpus = meta_backend_get_gpus (manager->backend);
653   for (l = gpus; l; l = l->next)
654     {
655       MetaGpu *gpu = l->data;
656 
657       if (meta_gpu_has_hotplug_mode_update (gpu))
658         return TRUE;
659     }
660 
661   return FALSE;
662 }
663 
664 static gboolean
should_use_stored_config(MetaMonitorManager * manager)665 should_use_stored_config (MetaMonitorManager *manager)
666 {
667   return (manager->in_init ||
668           !meta_monitor_manager_has_hotplug_mode_update (manager));
669 }
670 
671 MetaMonitorsConfig *
meta_monitor_manager_ensure_configured(MetaMonitorManager * manager)672 meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
673 {
674   MetaMonitorsConfig *config = NULL;
675   GError *error = NULL;
676   gboolean use_stored_config;
677   MetaMonitorsConfigMethod method;
678   MetaMonitorsConfigMethod fallback_method =
679     META_MONITORS_CONFIG_METHOD_TEMPORARY;
680 
681   use_stored_config = should_use_stored_config (manager);
682   if (use_stored_config)
683     method = META_MONITORS_CONFIG_METHOD_PERSISTENT;
684   else
685     method = META_MONITORS_CONFIG_METHOD_TEMPORARY;
686 
687   if (use_stored_config)
688     {
689       config = meta_monitor_config_manager_get_stored (manager->config_manager);
690       if (config)
691         {
692           g_autoptr (MetaMonitorsConfig) oriented_config = NULL;
693 
694           if (manager->panel_orientation_managed)
695             {
696               oriented_config = meta_monitor_config_manager_create_for_builtin_orientation (
697                 manager->config_manager, config);
698 
699               if (oriented_config)
700                 config = oriented_config;
701             }
702 
703           if (!meta_monitor_manager_apply_monitors_config (manager,
704                                                            config,
705                                                            method,
706                                                            &error))
707             {
708               config = NULL;
709               g_warning ("Failed to use stored monitor configuration: %s",
710                          error->message);
711               g_clear_error (&error);
712             }
713           else
714             {
715               g_object_ref (config);
716               goto done;
717             }
718         }
719     }
720 
721   if (manager->panel_orientation_managed)
722     {
723       MetaMonitorsConfig *current_config =
724         meta_monitor_config_manager_get_current (manager->config_manager);
725 
726       if (current_config)
727         {
728           config = meta_monitor_config_manager_create_for_builtin_orientation (
729             manager->config_manager, current_config);
730         }
731     }
732 
733   if (config)
734     {
735       if (meta_monitor_manager_is_config_complete (manager, config))
736         {
737           if (!meta_monitor_manager_apply_monitors_config (manager,
738                                                            config,
739                                                            method,
740                                                            &error))
741             {
742               g_clear_object (&config);
743               g_warning ("Failed to use current monitor configuration: %s",
744                          error->message);
745               g_clear_error (&error);
746             }
747           else
748             {
749               goto done;
750             }
751         }
752     }
753 
754   config = meta_monitor_config_manager_create_suggested (manager->config_manager);
755   if (config)
756     {
757       if (!meta_monitor_manager_apply_monitors_config (manager,
758                                                        config,
759                                                        method,
760                                                        &error))
761         {
762           g_clear_object (&config);
763           g_warning ("Failed to use suggested monitor configuration: %s",
764                      error->message);
765           g_clear_error (&error);
766         }
767       else
768         {
769           goto done;
770         }
771     }
772 
773   config = meta_monitor_config_manager_get_previous (manager->config_manager);
774   if (config)
775     {
776       g_autoptr (MetaMonitorsConfig) oriented_config = NULL;
777 
778       if (manager->panel_orientation_managed)
779         {
780           oriented_config =
781             meta_monitor_config_manager_create_for_builtin_orientation (
782               manager->config_manager, config);
783 
784           if (oriented_config)
785             config = oriented_config;
786         }
787 
788       config = g_object_ref (config);
789 
790       if (meta_monitor_manager_is_config_complete (manager, config))
791         {
792           if (!meta_monitor_manager_apply_monitors_config (manager,
793                                                            config,
794                                                            method,
795                                                            &error))
796             {
797               g_warning ("Failed to use suggested monitor configuration: %s",
798                          error->message);
799               g_clear_error (&error);
800             }
801           else
802             {
803               goto done;
804             }
805         }
806 
807       g_clear_object (&config);
808     }
809 
810   config = meta_monitor_config_manager_create_linear (manager->config_manager);
811   if (config)
812     {
813       if (!meta_monitor_manager_apply_monitors_config (manager,
814                                                        config,
815                                                        method,
816                                                        &error))
817         {
818           g_clear_object (&config);
819           g_warning ("Failed to use linear monitor configuration: %s",
820                      error->message);
821           g_clear_error (&error);
822         }
823       else
824         {
825           goto done;
826         }
827     }
828 
829   config = meta_monitor_config_manager_create_fallback (manager->config_manager);
830   if (config)
831     {
832       if (!meta_monitor_manager_apply_monitors_config (manager,
833                                                        config,
834                                                        fallback_method,
835                                                        &error))
836         {
837           g_clear_object (&config);
838           g_warning ("Failed to use fallback monitor configuration: %s",
839                      error->message);
840           g_clear_error (&error);
841         }
842       else
843         {
844           goto done;
845         }
846     }
847 
848 done:
849   if (!config)
850     {
851       meta_monitor_manager_apply_monitors_config (manager,
852                                                   NULL,
853                                                   fallback_method,
854                                                   &error);
855       return NULL;
856     }
857 
858   g_object_unref (config);
859 
860   return config;
861 }
862 
863 static void
handle_orientation_change(MetaOrientationManager * orientation_manager,MetaMonitorManager * manager)864 handle_orientation_change (MetaOrientationManager *orientation_manager,
865                            MetaMonitorManager     *manager)
866 {
867   MetaOrientation orientation;
868   MetaMonitorTransform transform;
869   GError *error = NULL;
870   MetaMonitorsConfig *config;
871   MetaMonitor *laptop_panel;
872   MetaLogicalMonitor *laptop_logical_monitor;
873   MetaMonitorsConfig *current_config;
874 
875   laptop_panel = meta_monitor_manager_get_laptop_panel (manager);
876   g_return_if_fail (laptop_panel);
877 
878   if (!meta_monitor_is_active (laptop_panel))
879     return;
880 
881   orientation = meta_orientation_manager_get_orientation (orientation_manager);
882   transform = meta_monitor_transform_from_orientation (orientation);
883 
884   laptop_logical_monitor = meta_monitor_get_logical_monitor (laptop_panel);
885   if (meta_logical_monitor_get_transform (laptop_logical_monitor) == transform)
886     return;
887 
888   current_config =
889     meta_monitor_config_manager_get_current (manager->config_manager);
890   if (!current_config)
891     return;
892 
893   config =
894     meta_monitor_config_manager_create_for_orientation (manager->config_manager,
895                                                         current_config,
896                                                         transform);
897   if (!config)
898     return;
899 
900   if (!meta_monitor_manager_apply_monitors_config (manager,
901                                                    config,
902                                                    META_MONITORS_CONFIG_METHOD_TEMPORARY,
903                                                    &error))
904     {
905       g_warning ("Failed to use orientation monitor configuration: %s",
906                  error->message);
907       g_error_free (error);
908     }
909   g_object_unref (config);
910 }
911 
912 /*
913  * Special case for tablets with a native portrait mode and a keyboard dock,
914  * where the device gets docked in landscape mode. For this combo to work
915  * properly with mutter starting while the tablet is docked, we need to take
916  * the accelerometer reported orientation into account (at mutter startup)
917  * even if there is a tablet-mode-switch which indicates that the device is
918  * NOT in tablet-mode (because it is docked).
919  */
920 static gboolean
handle_initial_orientation_change(MetaOrientationManager * orientation_manager,MetaMonitorManager * manager)921 handle_initial_orientation_change (MetaOrientationManager *orientation_manager,
922                                    MetaMonitorManager     *manager)
923 {
924   ClutterBackend *clutter_backend;
925   ClutterSeat *seat;
926   MetaMonitor *monitor;
927   MetaMonitorMode *mode;
928   int width, height;
929 
930   clutter_backend = meta_backend_get_clutter_backend (manager->backend);
931   seat = clutter_backend_get_default_seat (clutter_backend);
932 
933   /*
934    * This is a workaround to ignore the tablet mode switch on the initial config
935    * of devices with a native portrait mode panel. The touchscreen and
936    * accelerometer requirements for applying the orientation must still be met.
937    */
938   if (!clutter_seat_has_touchscreen (seat) ||
939       !meta_orientation_manager_has_accelerometer (orientation_manager))
940     return FALSE;
941 
942   /* Check for a portrait mode panel */
943   monitor = meta_monitor_manager_get_laptop_panel (manager);
944   if (!monitor)
945     return FALSE;
946 
947   mode = meta_monitor_get_preferred_mode (monitor);
948   meta_monitor_mode_get_resolution (mode, &width, &height);
949   if (width > height)
950     return FALSE;
951 
952   handle_orientation_change (orientation_manager, manager);
953   return TRUE;
954 }
955 
956 static void
orientation_changed(MetaOrientationManager * orientation_manager,MetaMonitorManager * manager)957 orientation_changed (MetaOrientationManager *orientation_manager,
958                      MetaMonitorManager     *manager)
959 {
960   MetaMonitorManagerPrivate *priv =
961     meta_monitor_manager_get_instance_private (manager);
962 
963   if (!priv->initial_orient_change_done)
964     {
965       priv->initial_orient_change_done = TRUE;
966       if (handle_initial_orientation_change (orientation_manager, manager))
967         return;
968     }
969 
970   if (!manager->panel_orientation_managed)
971     return;
972 
973   handle_orientation_change (orientation_manager, manager);
974 }
975 
976 static void
experimental_features_changed(MetaSettings * settings,MetaExperimentalFeature old_experimental_features,MetaMonitorManager * manager)977 experimental_features_changed (MetaSettings           *settings,
978                                MetaExperimentalFeature old_experimental_features,
979                                MetaMonitorManager     *manager)
980 {
981   gboolean was_stage_views_scaled;
982   gboolean is_stage_views_scaled;
983   gboolean should_reconfigure = FALSE;
984 
985   was_stage_views_scaled =
986     !!(old_experimental_features &
987        META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
988   is_stage_views_scaled =
989     meta_settings_is_experimental_feature_enabled (
990       settings,
991       META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
992 
993   if (is_stage_views_scaled != was_stage_views_scaled)
994     should_reconfigure = TRUE;
995 
996   if (should_reconfigure)
997     meta_monitor_manager_reconfigure (manager);
998 
999   meta_settings_update_ui_scaling_factor (settings);
1000 }
1001 
1002 static void
update_panel_orientation_managed(MetaMonitorManager * manager)1003 update_panel_orientation_managed (MetaMonitorManager *manager)
1004 {
1005   MetaOrientationManager *orientation_manager;
1006   ClutterBackend *clutter_backend;
1007   ClutterSeat *seat;
1008   gboolean panel_orientation_managed;
1009 
1010   clutter_backend = meta_backend_get_clutter_backend (manager->backend);
1011   seat = clutter_backend_get_default_seat (clutter_backend);
1012 
1013   orientation_manager = meta_backend_get_orientation_manager (manager->backend);
1014 
1015   panel_orientation_managed =
1016     (clutter_seat_get_touch_mode (seat) &&
1017      meta_orientation_manager_has_accelerometer (orientation_manager) &&
1018      meta_monitor_manager_get_laptop_panel (manager));
1019 
1020   if (manager->panel_orientation_managed == panel_orientation_managed)
1021     return;
1022 
1023   manager->panel_orientation_managed = panel_orientation_managed;
1024   g_object_notify_by_pspec (G_OBJECT (manager),
1025                             obj_props[PROP_PANEL_ORIENTATION_MANAGED]);
1026 
1027   meta_dbus_display_config_set_panel_orientation_managed (manager->display_config,
1028                                                           manager->panel_orientation_managed);
1029 
1030   /* The orientation may have changed while it was unmanaged */
1031   if (panel_orientation_managed)
1032     handle_orientation_change (orientation_manager, manager);
1033 }
1034 
1035 void
meta_monitor_manager_setup(MetaMonitorManager * manager)1036 meta_monitor_manager_setup (MetaMonitorManager *manager)
1037 {
1038   manager->in_init = TRUE;
1039 
1040   manager->config_manager = meta_monitor_config_manager_new (manager);
1041 
1042   meta_monitor_manager_read_current_state (manager);
1043 
1044   meta_monitor_manager_ensure_initial_config (manager);
1045 
1046   manager->in_init = FALSE;
1047 }
1048 
1049 static void
meta_monitor_manager_constructed(GObject * object)1050 meta_monitor_manager_constructed (GObject *object)
1051 {
1052   MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
1053   MetaBackend *backend = manager->backend;
1054   MetaSettings *settings = meta_backend_get_settings (backend);
1055 
1056   manager->display_config = meta_dbus_display_config_skeleton_new ();
1057 
1058   g_signal_connect_object (settings,
1059                            "experimental-features-changed",
1060                            G_CALLBACK (experimental_features_changed),
1061                            manager, 0);
1062 
1063   monitor_manager_setup_dbus_config_handlers (manager);
1064 
1065   g_signal_connect_object (manager->display_config, "notify::power-save-mode",
1066                            G_CALLBACK (power_save_mode_changed), manager,
1067                            G_CONNECT_SWAPPED);
1068 
1069   g_signal_connect_object (meta_backend_get_orientation_manager (backend),
1070                            "orientation-changed",
1071                            G_CALLBACK (orientation_changed),
1072                            manager, 0);
1073 
1074   g_signal_connect_object (meta_backend_get_orientation_manager (backend),
1075                            "notify::has-accelerometer",
1076                            G_CALLBACK (update_panel_orientation_managed), manager,
1077                            G_CONNECT_SWAPPED);
1078 
1079   g_signal_connect_object (backend,
1080                            "lid-is-closed-changed",
1081                            G_CALLBACK (lid_is_closed_changed),
1082                            manager, 0);
1083 
1084   g_signal_connect (backend, "prepare-shutdown",
1085                     G_CALLBACK (prepare_shutdown),
1086                     manager);
1087 
1088   manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
1089 
1090   initialize_dbus_interface (manager);
1091 }
1092 
1093 static void
meta_monitor_manager_finalize(GObject * object)1094 meta_monitor_manager_finalize (GObject *object)
1095 {
1096   MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
1097   MetaMonitorManagerPrivate *priv =
1098     meta_monitor_manager_get_instance_private (manager);
1099 
1100   g_list_free_full (manager->logical_monitors, g_object_unref);
1101 
1102   g_warn_if_fail (!priv->virtual_monitors);
1103 
1104   G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
1105 }
1106 
1107 static void
meta_monitor_manager_dispose(GObject * object)1108 meta_monitor_manager_dispose (GObject *object)
1109 {
1110   MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
1111 
1112   if (manager->dbus_name_id != 0)
1113     {
1114       g_bus_unown_name (manager->dbus_name_id);
1115       manager->dbus_name_id = 0;
1116     }
1117 
1118   g_clear_object (&manager->display_config);
1119   g_clear_object (&manager->config_manager);
1120 
1121   g_clear_handle_id (&manager->persistent_timeout_id, g_source_remove);
1122 
1123   G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
1124 }
1125 
1126 static GBytes *
meta_monitor_manager_real_read_edid(MetaMonitorManager * manager,MetaOutput * output)1127 meta_monitor_manager_real_read_edid (MetaMonitorManager *manager,
1128                                      MetaOutput         *output)
1129 {
1130   return NULL;
1131 }
1132 
1133 static void
meta_monitor_manager_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1134 meta_monitor_manager_set_property (GObject      *object,
1135                                    guint         prop_id,
1136                                    const GValue *value,
1137                                    GParamSpec   *pspec)
1138 {
1139   MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
1140 
1141   switch (prop_id)
1142     {
1143     case PROP_BACKEND:
1144       manager->backend = g_value_get_object (value);
1145       break;
1146     case PROP_PANEL_ORIENTATION_MANAGED:
1147     default:
1148       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1149     }
1150 }
1151 
1152 static void
meta_monitor_manager_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1153 meta_monitor_manager_get_property (GObject    *object,
1154                                    guint       prop_id,
1155                                    GValue     *value,
1156                                    GParamSpec *pspec)
1157 {
1158   MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
1159 
1160   switch (prop_id)
1161     {
1162     case PROP_BACKEND:
1163       g_value_set_object (value, manager->backend);
1164       break;
1165     case PROP_PANEL_ORIENTATION_MANAGED:
1166       g_value_set_boolean (value, manager->panel_orientation_managed);
1167       break;
1168     default:
1169       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1170     }
1171 }
1172 
1173 static void
meta_monitor_manager_class_init(MetaMonitorManagerClass * klass)1174 meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
1175 {
1176   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1177 
1178   object_class->constructed = meta_monitor_manager_constructed;
1179   object_class->dispose = meta_monitor_manager_dispose;
1180   object_class->finalize = meta_monitor_manager_finalize;
1181   object_class->get_property = meta_monitor_manager_get_property;
1182   object_class->set_property = meta_monitor_manager_set_property;
1183 
1184   klass->read_edid = meta_monitor_manager_real_read_edid;
1185   klass->read_current_state = meta_monitor_manager_real_read_current_state;
1186 
1187   signals[MONITORS_CHANGED] =
1188     g_signal_new ("monitors-changed",
1189                   G_TYPE_FROM_CLASS (object_class),
1190                   G_SIGNAL_RUN_LAST,
1191                   0,
1192                   NULL, NULL, NULL,
1193                   G_TYPE_NONE, 0);
1194 
1195   signals[MONITORS_CHANGED_INTERNAL] =
1196     g_signal_new ("monitors-changed-internal",
1197                   G_TYPE_FROM_CLASS (object_class),
1198                   G_SIGNAL_RUN_LAST,
1199                   0,
1200                   NULL, NULL, NULL,
1201                   G_TYPE_NONE, 0);
1202 
1203   signals[POWER_SAVE_MODE_CHANGED] =
1204     g_signal_new ("power-save-mode-changed",
1205                   G_TYPE_FROM_CLASS (object_class),
1206                   G_SIGNAL_RUN_LAST,
1207                   0,
1208                   NULL, NULL, NULL,
1209                   G_TYPE_NONE, 0);
1210 
1211   signals[CONFIRM_DISPLAY_CHANGE] =
1212     g_signal_new ("confirm-display-change",
1213 		  G_TYPE_FROM_CLASS (object_class),
1214 		  G_SIGNAL_RUN_LAST,
1215 		  0,
1216                   NULL, NULL, NULL,
1217 		  G_TYPE_NONE, 0);
1218 
1219   obj_props[PROP_BACKEND] =
1220     g_param_spec_object ("backend",
1221                          "backend",
1222                          "MetaBackend",
1223                          META_TYPE_BACKEND,
1224                          G_PARAM_READWRITE |
1225                          G_PARAM_CONSTRUCT_ONLY |
1226                          G_PARAM_STATIC_STRINGS);
1227 
1228   obj_props[PROP_PANEL_ORIENTATION_MANAGED] =
1229     g_param_spec_boolean ("panel-orientation-managed",
1230                           "Panel orientation managed",
1231                           "Panel orientation is managed",
1232                           FALSE,
1233                           G_PARAM_READABLE |
1234                           G_PARAM_EXPLICIT_NOTIFY |
1235                           G_PARAM_STATIC_STRINGS);
1236   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
1237 }
1238 
1239 gboolean
meta_monitor_has_aspect_as_size(MetaMonitor * monitor)1240 meta_monitor_has_aspect_as_size (MetaMonitor *monitor)
1241 {
1242   int width_mm;
1243   int height_mm;
1244 
1245   meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm);
1246 
1247   return (width_mm == 1600 && height_mm == 900) ||
1248      (width_mm == 1600 && height_mm == 1000) ||
1249      (width_mm == 160 && height_mm == 90) ||
1250      (width_mm == 160 && height_mm == 100) ||
1251      (width_mm == 16 && height_mm == 9) ||
1252      (width_mm == 16 && height_mm == 10);
1253 }
1254 
1255 static const char *
get_connector_type_name(MetaConnectorType connector_type)1256 get_connector_type_name (MetaConnectorType connector_type)
1257 {
1258   switch (connector_type)
1259     {
1260     case META_CONNECTOR_TYPE_Unknown: return "Unknown";
1261     case META_CONNECTOR_TYPE_VGA: return "VGA";
1262     case META_CONNECTOR_TYPE_DVII: return "DVII";
1263     case META_CONNECTOR_TYPE_DVID: return "DVID";
1264     case META_CONNECTOR_TYPE_DVIA: return "DVIA";
1265     case META_CONNECTOR_TYPE_Composite: return "Composite";
1266     case META_CONNECTOR_TYPE_SVIDEO: return "SVIDEO";
1267     case META_CONNECTOR_TYPE_LVDS: return "LVDS";
1268     case META_CONNECTOR_TYPE_Component: return "Component";
1269     case META_CONNECTOR_TYPE_9PinDIN: return "9PinDIN";
1270     case META_CONNECTOR_TYPE_DisplayPort: return "DisplayPort";
1271     case META_CONNECTOR_TYPE_HDMIA: return "HDMIA";
1272     case META_CONNECTOR_TYPE_HDMIB: return "HDMIB";
1273     case META_CONNECTOR_TYPE_TV: return "TV";
1274     case META_CONNECTOR_TYPE_eDP: return "eDP";
1275     case META_CONNECTOR_TYPE_VIRTUAL: return "VIRTUAL";
1276     case META_CONNECTOR_TYPE_DSI: return "DSI";
1277     default: g_assert_not_reached ();
1278     }
1279   return NULL;
1280 }
1281 
1282 static GList *
combine_gpu_lists(MetaMonitorManager * manager,GList * (* list_getter)(MetaGpu * gpu))1283 combine_gpu_lists (MetaMonitorManager    *manager,
1284                    GList              * (*list_getter) (MetaGpu *gpu))
1285 {
1286   GList *gpus;
1287   GList *list = NULL;
1288   GList *l;
1289 
1290   gpus = meta_backend_get_gpus (manager->backend);
1291   for (l = gpus; l; l = l->next)
1292     {
1293       MetaGpu *gpu = l->data;
1294 
1295       list = g_list_concat (list, g_list_copy (list_getter (gpu)));
1296     }
1297 
1298   return list;
1299 }
1300 
1301 static gboolean
meta_monitor_manager_handle_get_resources(MetaDBusDisplayConfig * skeleton,GDBusMethodInvocation * invocation,MetaMonitorManager * manager)1302 meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
1303                                            GDBusMethodInvocation *invocation,
1304                                            MetaMonitorManager    *manager)
1305 {
1306   MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_GET_CLASS (manager);
1307   GList *combined_modes;
1308   GList *combined_outputs;
1309   GList *combined_crtcs;
1310   GVariantBuilder crtc_builder, output_builder, mode_builder;
1311   GList *l;
1312   unsigned int i, j;
1313   int max_screen_width;
1314   int max_screen_height;
1315 
1316   combined_modes = combine_gpu_lists (manager, meta_gpu_get_modes);
1317   combined_outputs = combine_gpu_lists (manager, meta_gpu_get_outputs);
1318   combined_crtcs = combine_gpu_lists (manager, meta_gpu_get_crtcs);
1319 
1320   g_variant_builder_init (&crtc_builder, G_VARIANT_TYPE ("a(uxiiiiiuaua{sv})"));
1321   g_variant_builder_init (&output_builder, G_VARIANT_TYPE ("a(uxiausauaua{sv})"));
1322   g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uxuudu)"));
1323 
1324   for (l = combined_crtcs, i = 0; l; l = l->next, i++)
1325     {
1326       MetaCrtc *crtc = l->data;
1327       GVariantBuilder transforms;
1328       const MetaCrtcConfig *crtc_config;
1329 
1330       g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au"));
1331       for (j = 0; j <= META_MONITOR_TRANSFORM_FLIPPED_270; j++)
1332         {
1333           if (meta_crtc_get_all_transforms (crtc) & (1 << j))
1334             g_variant_builder_add (&transforms, "u", j);
1335         }
1336 
1337       crtc_config = meta_crtc_get_config (crtc);
1338       if (crtc_config)
1339         {
1340           int current_mode_index;
1341 
1342           current_mode_index = g_list_index (combined_modes, crtc_config->mode);
1343           g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})",
1344                                  i, /* ID */
1345                                  (int64_t) meta_crtc_get_id (crtc),
1346                                  (int) roundf (crtc_config->layout.origin.x),
1347                                  (int) roundf (crtc_config->layout.origin.y),
1348                                  (int) roundf (crtc_config->layout.size.width),
1349                                  (int) roundf (crtc_config->layout.size.height),
1350                                  current_mode_index,
1351                                  (uint32_t) crtc_config->transform,
1352                                  &transforms,
1353                                  NULL /* properties */);
1354         }
1355       else
1356         {
1357           g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})",
1358                                  i, /* ID */
1359                                  (int64_t) meta_crtc_get_id (crtc),
1360                                  0,
1361                                  0,
1362                                  0,
1363                                  0,
1364                                  -1,
1365                                  (uint32_t) META_MONITOR_TRANSFORM_NORMAL,
1366                                  &transforms,
1367                                  NULL /* properties */);
1368         }
1369     }
1370 
1371   for (l = combined_outputs, i = 0; l; l = l->next, i++)
1372     {
1373       MetaOutput *output = l->data;
1374       const MetaOutputInfo *output_info = meta_output_get_info (output);
1375       GVariantBuilder crtcs, modes, clones, properties;
1376       GBytes *edid;
1377       MetaCrtc *crtc;
1378       int crtc_index;
1379       int backlight;
1380       int min_backlight_step;
1381       gboolean is_primary;
1382       gboolean is_presentation;
1383       const char * connector_type_name;
1384       gboolean is_underscanning;
1385       gboolean supports_underscanning;
1386       gboolean supports_color_transform;
1387 
1388       g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au"));
1389       for (j = 0; j < output_info->n_possible_crtcs; j++)
1390         {
1391           MetaCrtc *possible_crtc = output_info->possible_crtcs[j];
1392           unsigned possible_crtc_index;
1393 
1394           possible_crtc_index = g_list_index (combined_crtcs, possible_crtc);
1395           g_variant_builder_add (&crtcs, "u", possible_crtc_index);
1396         }
1397 
1398       g_variant_builder_init (&modes, G_VARIANT_TYPE ("au"));
1399       for (j = 0; j < output_info->n_modes; j++)
1400         {
1401           unsigned mode_index;
1402 
1403           mode_index = g_list_index (combined_modes, output_info->modes[j]);
1404           g_variant_builder_add (&modes, "u", mode_index);
1405         }
1406 
1407       g_variant_builder_init (&clones, G_VARIANT_TYPE ("au"));
1408       for (j = 0; j < output_info->n_possible_clones; j++)
1409         {
1410           unsigned int possible_clone_index;
1411 
1412           possible_clone_index = g_list_index (combined_outputs,
1413                                                output_info->possible_clones[j]);
1414           g_variant_builder_add (&clones, "u", possible_clone_index);
1415         }
1416 
1417       backlight = meta_output_get_backlight (output);
1418       min_backlight_step =
1419         output_info->backlight_max - output_info->backlight_min
1420         ? 100 / (output_info->backlight_max - output_info->backlight_min)
1421         : -1;
1422       is_primary = meta_output_is_primary (output);
1423       is_presentation = meta_output_is_presentation (output);
1424       is_underscanning = meta_output_is_underscanning (output);
1425       connector_type_name = get_connector_type_name (output_info->connector_type);
1426       supports_underscanning = output_info->supports_underscanning;
1427       supports_color_transform = output_info->supports_color_transform;
1428 
1429       g_variant_builder_init (&properties, G_VARIANT_TYPE ("a{sv}"));
1430       g_variant_builder_add (&properties, "{sv}", "vendor",
1431                              g_variant_new_string (output_info->vendor));
1432       g_variant_builder_add (&properties, "{sv}", "product",
1433                              g_variant_new_string (output_info->product));
1434       g_variant_builder_add (&properties, "{sv}", "serial",
1435                              g_variant_new_string (output_info->serial));
1436       g_variant_builder_add (&properties, "{sv}", "width-mm",
1437                              g_variant_new_int32 (output_info->width_mm));
1438       g_variant_builder_add (&properties, "{sv}", "height-mm",
1439                              g_variant_new_int32 (output_info->height_mm));
1440       g_variant_builder_add (&properties, "{sv}", "display-name",
1441                              g_variant_new_string (output_info->name));
1442       g_variant_builder_add (&properties, "{sv}", "backlight",
1443                              g_variant_new_int32 (backlight));
1444       g_variant_builder_add (&properties, "{sv}", "min-backlight-step",
1445                              g_variant_new_int32 (min_backlight_step));
1446       g_variant_builder_add (&properties, "{sv}", "primary",
1447                              g_variant_new_boolean (is_primary));
1448       g_variant_builder_add (&properties, "{sv}", "presentation",
1449                              g_variant_new_boolean (is_presentation));
1450       g_variant_builder_add (&properties, "{sv}", "connector-type",
1451                              g_variant_new_string (connector_type_name));
1452       g_variant_builder_add (&properties, "{sv}", "underscanning",
1453                              g_variant_new_boolean (is_underscanning));
1454       g_variant_builder_add (&properties, "{sv}", "supports-underscanning",
1455                              g_variant_new_boolean (supports_underscanning));
1456       g_variant_builder_add (&properties, "{sv}", "supports-color-transform",
1457                              g_variant_new_boolean (supports_color_transform));
1458 
1459       edid = manager_class->read_edid (manager, output);
1460       if (edid)
1461         {
1462           g_variant_builder_add (&properties, "{sv}", "edid",
1463                                  g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"),
1464                                                            edid, TRUE));
1465           g_bytes_unref (edid);
1466         }
1467 
1468       if (output_info->tile_info.group_id)
1469         {
1470           GVariant *tile_variant;
1471 
1472           tile_variant = g_variant_new ("(uuuuuuuu)",
1473                                         output_info->tile_info.group_id,
1474                                         output_info->tile_info.flags,
1475                                         output_info->tile_info.max_h_tiles,
1476                                         output_info->tile_info.max_v_tiles,
1477                                         output_info->tile_info.loc_h_tile,
1478                                         output_info->tile_info.loc_v_tile,
1479                                         output_info->tile_info.tile_w,
1480                                         output_info->tile_info.tile_h);
1481           g_variant_builder_add (&properties, "{sv}", "tile", tile_variant);
1482         }
1483 
1484       crtc = meta_output_get_assigned_crtc (output);
1485       crtc_index = crtc ? g_list_index (combined_crtcs, crtc) : -1;
1486       g_variant_builder_add (&output_builder, "(uxiausauaua{sv})",
1487                              i, /* ID */
1488                              meta_output_get_id (output),
1489                              crtc_index,
1490                              &crtcs,
1491                              meta_output_get_name (output),
1492                              &modes,
1493                              &clones,
1494                              &properties);
1495     }
1496 
1497   for (l = combined_modes, i = 0; l; l = l->next, i++)
1498     {
1499       MetaCrtcMode *mode = l->data;
1500       const MetaCrtcModeInfo *crtc_mode_info =
1501         meta_crtc_mode_get_info (mode);
1502 
1503       g_variant_builder_add (&mode_builder, "(uxuudu)",
1504                              i, /* ID */
1505                              (int64_t) meta_crtc_mode_get_id (mode),
1506                              (uint32_t) crtc_mode_info->width,
1507                              (uint32_t) crtc_mode_info->height,
1508                              (double) crtc_mode_info->refresh_rate,
1509                              (uint32_t) crtc_mode_info->flags);
1510     }
1511 
1512   if (!meta_monitor_manager_get_max_screen_size (manager,
1513                                                  &max_screen_width,
1514                                                  &max_screen_height))
1515     {
1516       /* No max screen size, just send something large */
1517       max_screen_width = 65535;
1518       max_screen_height = 65535;
1519     }
1520 
1521   meta_dbus_display_config_complete_get_resources (skeleton,
1522                                                    invocation,
1523                                                    manager->serial,
1524                                                    g_variant_builder_end (&crtc_builder),
1525                                                    g_variant_builder_end (&output_builder),
1526                                                    g_variant_builder_end (&mode_builder),
1527                                                    max_screen_width,
1528                                                    max_screen_height);
1529 
1530   g_list_free (combined_modes);
1531   g_list_free (combined_outputs);
1532   g_list_free (combined_crtcs);
1533 
1534   return TRUE;
1535 }
1536 
1537 static void
restore_previous_config(MetaMonitorManager * manager)1538 restore_previous_config (MetaMonitorManager *manager)
1539 {
1540   MetaMonitorsConfig *previous_config;
1541   GError *error = NULL;
1542 
1543   previous_config =
1544     meta_monitor_config_manager_pop_previous (manager->config_manager);
1545 
1546   if (previous_config)
1547     {
1548       MetaMonitorsConfigMethod method;
1549 
1550       if (manager->panel_orientation_managed)
1551         {
1552           g_autoptr (MetaMonitorsConfig) oriented_config = NULL;
1553 
1554           oriented_config =
1555             meta_monitor_config_manager_create_for_builtin_orientation (
1556               manager->config_manager, previous_config);
1557 
1558           if (oriented_config)
1559             g_set_object (&previous_config, oriented_config);
1560         }
1561 
1562       method = META_MONITORS_CONFIG_METHOD_TEMPORARY;
1563       if (meta_monitor_manager_apply_monitors_config (manager,
1564                                                       previous_config,
1565                                                       method,
1566                                                       &error))
1567         {
1568           g_object_unref (previous_config);
1569           return;
1570         }
1571       else
1572         {
1573           g_object_unref (previous_config);
1574           g_warning ("Failed to restore previous configuration: %s",
1575                      error->message);
1576           g_error_free (error);
1577         }
1578     }
1579 
1580   meta_monitor_manager_ensure_configured (manager);
1581 }
1582 
1583 gint
meta_monitor_manager_get_display_configuration_timeout(void)1584 meta_monitor_manager_get_display_configuration_timeout (void)
1585 {
1586   return DEFAULT_DISPLAY_CONFIGURATION_TIMEOUT;
1587 }
1588 
1589 static gboolean
save_config_timeout(gpointer user_data)1590 save_config_timeout (gpointer user_data)
1591 {
1592   MetaMonitorManager *manager = user_data;
1593 
1594   restore_previous_config (manager);
1595   manager->persistent_timeout_id = 0;
1596 
1597   return G_SOURCE_REMOVE;
1598 }
1599 
1600 static void
cancel_persistent_confirmation(MetaMonitorManager * manager)1601 cancel_persistent_confirmation (MetaMonitorManager *manager)
1602 {
1603   g_clear_handle_id (&manager->persistent_timeout_id, g_source_remove);
1604 }
1605 
1606 static void
request_persistent_confirmation(MetaMonitorManager * manager)1607 request_persistent_confirmation (MetaMonitorManager *manager)
1608 {
1609   manager->persistent_timeout_id = g_timeout_add_seconds (meta_monitor_manager_get_display_configuration_timeout (),
1610                                                           save_config_timeout,
1611                                                           manager);
1612   g_source_set_name_by_id (manager->persistent_timeout_id,
1613                            "[mutter] save_config_timeout");
1614 
1615   g_signal_emit (manager, signals[CONFIRM_DISPLAY_CHANGE], 0);
1616 }
1617 
1618 #define META_DISPLAY_CONFIG_MODE_FLAGS_PREFERRED (1 << 0)
1619 #define META_DISPLAY_CONFIG_MODE_FLAGS_CURRENT (1 << 1)
1620 
1621 #define MODE_FORMAT "(siiddada{sv})"
1622 #define MODES_FORMAT "a" MODE_FORMAT
1623 #define MONITOR_SPEC_FORMAT "(ssss)"
1624 #define MONITOR_FORMAT "(" MONITOR_SPEC_FORMAT MODES_FORMAT "a{sv})"
1625 #define MONITORS_FORMAT "a" MONITOR_FORMAT
1626 
1627 #define LOGICAL_MONITOR_MONITORS_FORMAT "a" MONITOR_SPEC_FORMAT
1628 #define LOGICAL_MONITOR_FORMAT "(iidub" LOGICAL_MONITOR_MONITORS_FORMAT "a{sv})"
1629 #define LOGICAL_MONITORS_FORMAT "a" LOGICAL_MONITOR_FORMAT
1630 
1631 static gboolean
meta_monitor_manager_handle_get_current_state(MetaDBusDisplayConfig * skeleton,GDBusMethodInvocation * invocation,MetaMonitorManager * manager)1632 meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton,
1633                                                GDBusMethodInvocation *invocation,
1634                                                MetaMonitorManager    *manager)
1635 {
1636   MetaSettings *settings = meta_backend_get_settings (manager->backend);
1637   GVariantBuilder monitors_builder;
1638   GVariantBuilder logical_monitors_builder;
1639   GVariantBuilder properties_builder;
1640   GList *l;
1641   int i;
1642   MetaMonitorManagerCapability capabilities;
1643   int ui_scaling_factor;
1644   int max_screen_width, max_screen_height;
1645 
1646   g_variant_builder_init (&monitors_builder,
1647                           G_VARIANT_TYPE (MONITORS_FORMAT));
1648   g_variant_builder_init (&logical_monitors_builder,
1649                           G_VARIANT_TYPE (LOGICAL_MONITORS_FORMAT));
1650 
1651   for (l = manager->monitors; l; l = l->next)
1652     {
1653       MetaMonitor *monitor = l->data;
1654       MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor);
1655       MetaMonitorMode *current_mode;
1656       MetaMonitorMode *preferred_mode;
1657       GVariantBuilder modes_builder;
1658       GVariantBuilder monitor_properties_builder;
1659       GList *k;
1660       gboolean is_builtin;
1661       const char *display_name;
1662 
1663       current_mode = meta_monitor_get_current_mode (monitor);
1664       preferred_mode = meta_monitor_get_preferred_mode (monitor);
1665 
1666       g_variant_builder_init (&modes_builder, G_VARIANT_TYPE (MODES_FORMAT));
1667       for (k = meta_monitor_get_modes (monitor); k; k = k->next)
1668         {
1669           MetaMonitorMode *monitor_mode = k->data;
1670           GVariantBuilder supported_scales_builder;
1671           const char *mode_id;
1672           int mode_width, mode_height;
1673           float refresh_rate;
1674           float preferred_scale;
1675           float *supported_scales;
1676           int n_supported_scales;
1677           GVariantBuilder mode_properties_builder;
1678           MetaCrtcModeFlag mode_flags;
1679 
1680           if (!meta_monitor_mode_should_be_advertised (monitor_mode))
1681             continue;
1682 
1683           mode_id = meta_monitor_mode_get_id (monitor_mode);
1684           meta_monitor_mode_get_resolution (monitor_mode,
1685                                             &mode_width, &mode_height);
1686 
1687           refresh_rate = meta_monitor_mode_get_refresh_rate (monitor_mode);
1688 
1689           preferred_scale =
1690             meta_monitor_manager_calculate_monitor_mode_scale (manager,
1691                                                                manager->layout_mode,
1692                                                                monitor,
1693                                                                monitor_mode);
1694 
1695           g_variant_builder_init (&supported_scales_builder,
1696                                   G_VARIANT_TYPE ("ad"));
1697           supported_scales =
1698             meta_monitor_manager_calculate_supported_scales (manager,
1699                                                              manager->layout_mode,
1700                                                              monitor,
1701                                                              monitor_mode,
1702                                                              &n_supported_scales);
1703           for (i = 0; i < n_supported_scales; i++)
1704             g_variant_builder_add (&supported_scales_builder, "d",
1705                                    (double) supported_scales[i]);
1706           g_free (supported_scales);
1707 
1708           mode_flags = meta_monitor_mode_get_flags (monitor_mode);
1709 
1710           g_variant_builder_init (&mode_properties_builder,
1711                                   G_VARIANT_TYPE ("a{sv}"));
1712           if (monitor_mode == current_mode)
1713             g_variant_builder_add (&mode_properties_builder, "{sv}",
1714                                    "is-current",
1715                                    g_variant_new_boolean (TRUE));
1716           if (monitor_mode == preferred_mode)
1717             g_variant_builder_add (&mode_properties_builder, "{sv}",
1718                                    "is-preferred",
1719                                    g_variant_new_boolean (TRUE));
1720           if (mode_flags & META_CRTC_MODE_FLAG_INTERLACE)
1721             g_variant_builder_add (&mode_properties_builder, "{sv}",
1722                                    "is-interlaced",
1723                                    g_variant_new_boolean (TRUE));
1724 
1725           g_variant_builder_add (&modes_builder, MODE_FORMAT,
1726                                  mode_id,
1727                                  mode_width,
1728                                  mode_height,
1729                                  refresh_rate,
1730                                  (double) preferred_scale,
1731                                  &supported_scales_builder,
1732                                  &mode_properties_builder);
1733         }
1734 
1735       g_variant_builder_init (&monitor_properties_builder,
1736                               G_VARIANT_TYPE ("a{sv}"));
1737       if (meta_monitor_supports_underscanning (monitor))
1738         {
1739           gboolean is_underscanning = meta_monitor_is_underscanning (monitor);
1740 
1741           g_variant_builder_add (&monitor_properties_builder, "{sv}",
1742                                  "is-underscanning",
1743                                  g_variant_new_boolean (is_underscanning));
1744         }
1745 
1746       is_builtin = meta_monitor_is_laptop_panel (monitor);
1747       g_variant_builder_add (&monitor_properties_builder, "{sv}",
1748                              "is-builtin",
1749                              g_variant_new_boolean (is_builtin));
1750 
1751       display_name = meta_monitor_get_display_name (monitor);
1752       g_variant_builder_add (&monitor_properties_builder, "{sv}",
1753                              "display-name",
1754                              g_variant_new_string (display_name));
1755 
1756       g_variant_builder_add (&monitors_builder, MONITOR_FORMAT,
1757                              monitor_spec->connector,
1758                              monitor_spec->vendor,
1759                              monitor_spec->product,
1760                              monitor_spec->serial,
1761                              &modes_builder,
1762                              &monitor_properties_builder);
1763     }
1764 
1765   for (l = manager->logical_monitors; l; l = l->next)
1766     {
1767       MetaLogicalMonitor *logical_monitor = l->data;
1768       GVariantBuilder logical_monitor_monitors_builder;
1769       GList *k;
1770 
1771       g_variant_builder_init (&logical_monitor_monitors_builder,
1772                               G_VARIANT_TYPE (LOGICAL_MONITOR_MONITORS_FORMAT));
1773 
1774       for (k = logical_monitor->monitors; k; k = k->next)
1775         {
1776           MetaMonitor *monitor = k->data;
1777           MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor);
1778 
1779           g_variant_builder_add (&logical_monitor_monitors_builder,
1780                                  MONITOR_SPEC_FORMAT,
1781                                  monitor_spec->connector,
1782                                  monitor_spec->vendor,
1783                                  monitor_spec->product,
1784                                  monitor_spec->serial);
1785         }
1786 
1787       g_variant_builder_add (&logical_monitors_builder,
1788                              LOGICAL_MONITOR_FORMAT,
1789                              logical_monitor->rect.x,
1790                              logical_monitor->rect.y,
1791                              (double) logical_monitor->scale,
1792                              logical_monitor->transform,
1793                              logical_monitor->is_primary,
1794                              &logical_monitor_monitors_builder,
1795                              NULL);
1796     }
1797 
1798   g_variant_builder_init (&properties_builder, G_VARIANT_TYPE ("a{sv}"));
1799   capabilities = meta_monitor_manager_get_capabilities (manager);
1800 
1801   g_variant_builder_add (&properties_builder, "{sv}",
1802                          "layout-mode",
1803                          g_variant_new_uint32 (manager->layout_mode));
1804   if (capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
1805     {
1806       g_variant_builder_add (&properties_builder, "{sv}",
1807                              "supports-changing-layout-mode",
1808                              g_variant_new_boolean (TRUE));
1809     }
1810 
1811   if (capabilities & META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED)
1812     {
1813       g_variant_builder_add (&properties_builder, "{sv}",
1814                              "global-scale-required",
1815                              g_variant_new_boolean (TRUE));
1816     }
1817 
1818   ui_scaling_factor = meta_settings_get_ui_scaling_factor (settings);
1819   g_variant_builder_add (&properties_builder, "{sv}",
1820                          "legacy-ui-scaling-factor",
1821                          g_variant_new_int32 (ui_scaling_factor));
1822 
1823   if (meta_monitor_manager_get_max_screen_size (manager,
1824                                                 &max_screen_width,
1825                                                 &max_screen_height))
1826     {
1827       GVariantBuilder max_screen_size_builder;
1828 
1829       g_variant_builder_init (&max_screen_size_builder,
1830                               G_VARIANT_TYPE ("(ii)"));
1831       g_variant_builder_add (&max_screen_size_builder, "i",
1832                              max_screen_width);
1833       g_variant_builder_add (&max_screen_size_builder, "i",
1834                              max_screen_height);
1835 
1836       g_variant_builder_add (&properties_builder, "{sv}",
1837                              "max-screen-size",
1838                              g_variant_builder_end (&max_screen_size_builder));
1839     }
1840 
1841   meta_dbus_display_config_complete_get_current_state (
1842     skeleton,
1843     invocation,
1844     manager->serial,
1845     g_variant_builder_end (&monitors_builder),
1846     g_variant_builder_end (&logical_monitors_builder),
1847     g_variant_builder_end (&properties_builder));
1848 
1849   return TRUE;
1850 }
1851 
1852 #undef MODE_FORMAT
1853 #undef MODES_FORMAT
1854 #undef MONITOR_SPEC_FORMAT
1855 #undef MONITOR_FORMAT
1856 #undef MONITORS_FORMAT
1857 #undef LOGICAL_MONITOR_MONITORS_FORMAT
1858 #undef LOGICAL_MONITOR_FORMAT
1859 #undef LOGICAL_MONITORS_FORMAT
1860 
1861 gboolean
meta_monitor_manager_is_scale_supported(MetaMonitorManager * manager,MetaLogicalMonitorLayoutMode layout_mode,MetaMonitor * monitor,MetaMonitorMode * monitor_mode,float scale)1862 meta_monitor_manager_is_scale_supported (MetaMonitorManager          *manager,
1863                                          MetaLogicalMonitorLayoutMode layout_mode,
1864                                          MetaMonitor                 *monitor,
1865                                          MetaMonitorMode             *monitor_mode,
1866                                          float                        scale)
1867 {
1868   g_autofree float *supported_scales = NULL;
1869   int n_supported_scales;
1870   int i;
1871 
1872   supported_scales =
1873     meta_monitor_manager_calculate_supported_scales (manager,
1874                                                      layout_mode,
1875                                                      monitor,
1876                                                      monitor_mode,
1877                                                      &n_supported_scales);
1878   for (i = 0; i < n_supported_scales; i++)
1879     {
1880       if (supported_scales[i] == scale)
1881         return TRUE;
1882     }
1883 
1884   return FALSE;
1885 }
1886 
1887 static gboolean
is_global_scale_matching_in_config(MetaMonitorsConfig * config,float scale)1888 is_global_scale_matching_in_config (MetaMonitorsConfig *config,
1889                                     float               scale)
1890 {
1891   GList *l;
1892 
1893   for (l = config->logical_monitor_configs; l; l = l->next)
1894     {
1895       MetaLogicalMonitorConfig *logical_monitor_config = l->data;
1896 
1897       if (!G_APPROX_VALUE (logical_monitor_config->scale, scale, FLT_EPSILON))
1898         return FALSE;
1899     }
1900 
1901   return TRUE;
1902 }
1903 
1904 static gboolean
meta_monitor_manager_is_scale_supported_for_config(MetaMonitorManager * manager,MetaMonitorsConfig * config,MetaMonitor * monitor,MetaMonitorMode * monitor_mode,float scale)1905 meta_monitor_manager_is_scale_supported_for_config (MetaMonitorManager *manager,
1906                                                     MetaMonitorsConfig *config,
1907                                                     MetaMonitor        *monitor,
1908                                                     MetaMonitorMode    *monitor_mode,
1909                                                     float               scale)
1910 {
1911   if (meta_monitor_manager_is_scale_supported (manager, config->layout_mode,
1912                                                monitor, monitor_mode, scale))
1913     {
1914       if (meta_monitor_manager_get_capabilities (manager) &
1915           META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED)
1916         return is_global_scale_matching_in_config (config, scale);
1917 
1918       return TRUE;
1919     }
1920 
1921   return FALSE;
1922 }
1923 
1924 static gboolean
meta_monitor_manager_is_config_applicable(MetaMonitorManager * manager,MetaMonitorsConfig * config,GError ** error)1925 meta_monitor_manager_is_config_applicable (MetaMonitorManager *manager,
1926                                            MetaMonitorsConfig *config,
1927                                            GError            **error)
1928 {
1929   GList *l;
1930 
1931   for (l = config->logical_monitor_configs; l; l = l->next)
1932     {
1933       MetaLogicalMonitorConfig *logical_monitor_config = l->data;
1934       float scale = logical_monitor_config->scale;
1935       GList *k;
1936 
1937       for (k = logical_monitor_config->monitor_configs; k; k = k->next)
1938         {
1939           MetaMonitorConfig *monitor_config = k->data;
1940           MetaMonitorSpec *monitor_spec = monitor_config->monitor_spec;
1941           MetaMonitorModeSpec *mode_spec = monitor_config->mode_spec;
1942           MetaMonitor *monitor;
1943           MetaMonitorMode *monitor_mode;
1944 
1945           monitor = meta_monitor_manager_get_monitor_from_spec (manager,
1946                                                                 monitor_spec);
1947           if (!monitor)
1948             {
1949               g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1950                            "Specified monitor not found");
1951               return FALSE;
1952             }
1953 
1954           monitor_mode = meta_monitor_get_mode_from_spec (monitor, mode_spec);
1955           if (!monitor_mode)
1956             {
1957               g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1958                            "Specified monitor mode not available");
1959               return FALSE;
1960             }
1961 
1962           if (!meta_monitor_manager_is_scale_supported_for_config (manager,
1963                                                                    config,
1964                                                                    monitor,
1965                                                                    monitor_mode,
1966                                                                    scale))
1967             {
1968               g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1969                            "Scale not supported by backend");
1970               return FALSE;
1971             }
1972 
1973           if (meta_monitor_is_laptop_panel (monitor) &&
1974               meta_backend_is_lid_closed (manager->backend))
1975             {
1976               g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1977                            "Refusing to activate a closed laptop panel");
1978               return FALSE;
1979             }
1980         }
1981     }
1982 
1983   return TRUE;
1984 }
1985 
1986 static gboolean
meta_monitor_manager_is_config_complete(MetaMonitorManager * manager,MetaMonitorsConfig * config)1987 meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
1988                                          MetaMonitorsConfig *config)
1989 {
1990   MetaMonitorsConfigKey *current_state_key;
1991   gboolean is_config_complete;
1992 
1993   current_state_key =
1994     meta_create_monitors_config_key_for_current_state (manager);
1995   if (!current_state_key)
1996     return FALSE;
1997 
1998   is_config_complete = meta_monitors_config_key_equal (current_state_key,
1999                                                        config->key);
2000   meta_monitors_config_key_free (current_state_key);
2001 
2002   if (!is_config_complete)
2003     return FALSE;
2004 
2005   return meta_monitor_manager_is_config_applicable (manager, config, NULL);
2006 }
2007 
2008 static MetaMonitor *
find_monitor_from_connector(MetaMonitorManager * manager,char * connector)2009 find_monitor_from_connector (MetaMonitorManager *manager,
2010                              char               *connector)
2011 {
2012   GList *monitors;
2013   GList *l;
2014 
2015   if (!connector)
2016     return NULL;
2017 
2018   monitors = meta_monitor_manager_get_monitors (manager);
2019   for (l = monitors; l; l = l->next)
2020     {
2021       MetaMonitor *monitor = l->data;
2022       MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor);
2023 
2024       if (g_str_equal (connector, monitor_spec->connector))
2025         return monitor;
2026     }
2027 
2028   return NULL;
2029 }
2030 
2031 #define MONITOR_CONFIG_FORMAT "(ssa{sv})"
2032 #define MONITOR_CONFIGS_FORMAT "a" MONITOR_CONFIG_FORMAT
2033 
2034 #define LOGICAL_MONITOR_CONFIG_FORMAT "(iidub" MONITOR_CONFIGS_FORMAT ")"
2035 
2036 static MetaMonitorConfig *
create_monitor_config_from_variant(MetaMonitorManager * manager,GVariant * monitor_config_variant,GError ** error)2037 create_monitor_config_from_variant (MetaMonitorManager *manager,
2038                                     GVariant           *monitor_config_variant,
2039                                     GError            **error)
2040 {
2041 
2042   MetaMonitorConfig *monitor_config = NULL;
2043   g_autofree char *connector = NULL;
2044   g_autofree char *mode_id = NULL;
2045   MetaMonitorMode *monitor_mode;
2046   MetaMonitor *monitor;
2047   MetaMonitorSpec *monitor_spec;
2048   MetaMonitorModeSpec *monitor_mode_spec;
2049   g_autoptr (GVariant) properties_variant = NULL;
2050   gboolean enable_underscanning = FALSE;
2051   gboolean set_underscanning = FALSE;
2052 
2053   g_variant_get (monitor_config_variant, "(ss@a{sv})",
2054                  &connector,
2055                  &mode_id,
2056                  &properties_variant);
2057 
2058   monitor = find_monitor_from_connector (manager, connector);
2059   if (!monitor)
2060     {
2061       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
2062                    "Invalid connector '%s' specified", connector);
2063       return NULL;
2064     }
2065 
2066   monitor_mode = meta_monitor_get_mode_from_id (monitor, mode_id);
2067   if (!monitor_mode)
2068     {
2069       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
2070                    "Invalid mode '%s' specified", mode_id);
2071       return NULL;
2072     }
2073 
2074   set_underscanning =
2075     g_variant_lookup (properties_variant, "underscanning", "b",
2076                       &enable_underscanning);
2077   if (set_underscanning)
2078     {
2079       if (enable_underscanning && !meta_monitor_supports_underscanning (monitor))
2080         {
2081           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
2082                        "Underscanning requested but unsupported");
2083           return NULL;
2084         }
2085     }
2086 
2087   monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor));
2088 
2089   monitor_mode_spec = g_new0 (MetaMonitorModeSpec, 1);
2090   *monitor_mode_spec = *meta_monitor_mode_get_spec (monitor_mode);
2091 
2092   monitor_config = g_new0 (MetaMonitorConfig, 1);
2093   *monitor_config = (MetaMonitorConfig) {
2094     .monitor_spec = monitor_spec,
2095     .mode_spec = monitor_mode_spec,
2096     .enable_underscanning = enable_underscanning
2097   };
2098 
2099   return monitor_config;
2100 }
2101 
2102 static gboolean
find_monitor_mode_scale(MetaMonitorManager * manager,MetaLogicalMonitorLayoutMode layout_mode,MetaMonitorConfig * monitor_config,float scale,float * out_scale,GError ** error)2103 find_monitor_mode_scale (MetaMonitorManager          *manager,
2104                          MetaLogicalMonitorLayoutMode layout_mode,
2105                          MetaMonitorConfig           *monitor_config,
2106                          float                        scale,
2107                          float                       *out_scale,
2108                          GError                     **error)
2109 {
2110   MetaMonitorSpec *monitor_spec;
2111   MetaMonitor *monitor;
2112   MetaMonitorModeSpec *monitor_mode_spec;
2113   MetaMonitorMode *monitor_mode;
2114   g_autofree float *supported_scales = NULL;
2115   int n_supported_scales;
2116   int i;
2117 
2118   monitor_spec = monitor_config->monitor_spec;
2119   monitor = meta_monitor_manager_get_monitor_from_spec (manager,
2120                                                         monitor_spec);
2121   if (!monitor)
2122     {
2123       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
2124                    "Monitor not found");
2125       return FALSE;
2126     }
2127 
2128   monitor_mode_spec = monitor_config->mode_spec;
2129   monitor_mode = meta_monitor_get_mode_from_spec (monitor,
2130                                                   monitor_mode_spec);
2131   if (!monitor_mode)
2132     {
2133       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
2134                    "Monitor mode not found");
2135       return FALSE;
2136     }
2137 
2138   supported_scales =
2139     meta_monitor_manager_calculate_supported_scales (manager, layout_mode,
2140                                                      monitor, monitor_mode,
2141                                                      &n_supported_scales);
2142 
2143   for (i = 0; i < n_supported_scales; i++)
2144     {
2145       float supported_scale = supported_scales[i];
2146 
2147       if (fabsf (supported_scale - scale) < FLT_EPSILON)
2148         {
2149           *out_scale = supported_scale;
2150           return TRUE;
2151         }
2152     }
2153 
2154   g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
2155                "Scale %g not valid for resolution %dx%d",
2156                scale,
2157                monitor_mode_spec->width,
2158                monitor_mode_spec->height);
2159   return FALSE;
2160 }
2161 
2162 static gboolean
derive_logical_monitor_size(MetaMonitorConfig * monitor_config,int * out_width,int * out_height,float scale,MetaMonitorTransform transform,MetaLogicalMonitorLayoutMode layout_mode,GError ** error)2163 derive_logical_monitor_size (MetaMonitorConfig           *monitor_config,
2164                              int                         *out_width,
2165                              int                         *out_height,
2166                              float                        scale,
2167                              MetaMonitorTransform         transform,
2168                              MetaLogicalMonitorLayoutMode layout_mode,
2169                              GError                     **error)
2170 {
2171   int width, height;
2172 
2173   if (meta_monitor_transform_is_rotated (transform))
2174     {
2175       width = monitor_config->mode_spec->height;
2176       height = monitor_config->mode_spec->width;
2177     }
2178   else
2179     {
2180       width = monitor_config->mode_spec->width;
2181       height = monitor_config->mode_spec->height;
2182     }
2183 
2184   switch (layout_mode)
2185     {
2186     case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
2187       width = roundf (width / scale);
2188       height = roundf (height / scale);
2189       break;
2190     case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
2191       break;
2192     }
2193 
2194   *out_width = width;
2195   *out_height = height;
2196 
2197   return TRUE;
2198 }
2199 
2200 static MetaLogicalMonitorConfig *
create_logical_monitor_config_from_variant(MetaMonitorManager * manager,GVariant * logical_monitor_config_variant,MetaLogicalMonitorLayoutMode layout_mode,GError ** error)2201 create_logical_monitor_config_from_variant (MetaMonitorManager          *manager,
2202                                             GVariant                    *logical_monitor_config_variant,
2203                                             MetaLogicalMonitorLayoutMode layout_mode,
2204                                             GError                     **error)
2205 {
2206   MetaLogicalMonitorConfig *logical_monitor_config;
2207   int x, y, width, height;
2208   double scale_d;
2209   float scale;
2210   MetaMonitorTransform transform;
2211   gboolean is_primary;
2212   GVariantIter *monitor_configs_iter;
2213   GList *monitor_configs = NULL;
2214   MetaMonitorConfig *monitor_config;
2215 
2216   g_variant_get (logical_monitor_config_variant, LOGICAL_MONITOR_CONFIG_FORMAT,
2217                  &x,
2218                  &y,
2219                  &scale_d,
2220                  &transform,
2221                  &is_primary,
2222                  &monitor_configs_iter);
2223   scale = (float) scale_d;
2224 
2225   while (TRUE)
2226     {
2227       GVariant *monitor_config_variant =
2228         g_variant_iter_next_value (monitor_configs_iter);
2229       MetaMonitorConfig *monitor_config;
2230 
2231       if (!monitor_config_variant)
2232         break;
2233 
2234       monitor_config =
2235         create_monitor_config_from_variant (manager,
2236                                             monitor_config_variant, error);
2237       g_variant_unref (monitor_config_variant);
2238 
2239       if (!monitor_config)
2240         goto err;
2241 
2242       if (!meta_verify_monitor_config (monitor_config, error))
2243         {
2244           meta_monitor_config_free (monitor_config);
2245           goto err;
2246         }
2247 
2248       monitor_configs = g_list_append (monitor_configs, monitor_config);
2249     }
2250   g_variant_iter_free (monitor_configs_iter);
2251 
2252   if (!monitor_configs)
2253     {
2254       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
2255                    "Empty logical monitor");
2256       goto err;
2257     }
2258 
2259   monitor_config = monitor_configs->data;
2260   if (!find_monitor_mode_scale (manager,
2261                                 layout_mode,
2262                                 monitor_config,
2263                                 scale,
2264                                 &scale,
2265                                 error))
2266     goto err;
2267 
2268   if (!derive_logical_monitor_size (monitor_config, &width, &height,
2269                                     scale, transform, layout_mode, error))
2270     goto err;
2271 
2272   logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
2273   *logical_monitor_config = (MetaLogicalMonitorConfig) {
2274     .layout = {
2275       .x = x,
2276       .y = y,
2277       .width = width,
2278       .height = height
2279     },
2280     .transform = transform,
2281     .scale = scale,
2282     .is_primary = is_primary,
2283     .monitor_configs = monitor_configs
2284   };
2285 
2286   if (!meta_verify_logical_monitor_config (logical_monitor_config,
2287                                            layout_mode,
2288                                            manager,
2289                                            error))
2290     {
2291       meta_logical_monitor_config_free (logical_monitor_config);
2292       return NULL;
2293     }
2294 
2295   return logical_monitor_config;
2296 
2297 err:
2298   g_list_free_full (monitor_configs, (GDestroyNotify) meta_monitor_config_free);
2299   return NULL;
2300 }
2301 
2302 static gboolean
is_valid_layout_mode(MetaLogicalMonitorLayoutMode layout_mode)2303 is_valid_layout_mode (MetaLogicalMonitorLayoutMode layout_mode)
2304 {
2305   switch (layout_mode)
2306     {
2307     case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
2308     case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
2309       return TRUE;
2310     }
2311 
2312   return FALSE;
2313 }
2314 
2315 static gboolean
meta_monitor_manager_handle_apply_monitors_config(MetaDBusDisplayConfig * skeleton,GDBusMethodInvocation * invocation,guint serial,guint method,GVariant * logical_monitor_configs_variant,GVariant * properties_variant,MetaMonitorManager * manager)2316 meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skeleton,
2317                                                    GDBusMethodInvocation *invocation,
2318                                                    guint                  serial,
2319                                                    guint                  method,
2320                                                    GVariant              *logical_monitor_configs_variant,
2321                                                    GVariant              *properties_variant,
2322                                                    MetaMonitorManager    *manager)
2323 {
2324   MetaMonitorManagerCapability capabilities;
2325   GVariant *layout_mode_variant = NULL;
2326   MetaLogicalMonitorLayoutMode layout_mode;
2327   GVariantIter logical_monitor_configs_iter;
2328   MetaMonitorsConfig *config;
2329   GList *logical_monitor_configs = NULL;
2330   GError *error = NULL;
2331 
2332   if (serial != manager->serial)
2333     {
2334       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2335                                              G_DBUS_ERROR_ACCESS_DENIED,
2336                                              "The requested configuration is based on stale information");
2337       return TRUE;
2338     }
2339 
2340   capabilities = meta_monitor_manager_get_capabilities (manager);
2341 
2342   if (properties_variant)
2343     layout_mode_variant = g_variant_lookup_value (properties_variant,
2344                                                   "layout-mode",
2345                                                   G_VARIANT_TYPE ("u"));
2346 
2347   if (layout_mode_variant &&
2348       capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
2349     {
2350       g_variant_get (layout_mode_variant, "u", &layout_mode);
2351     }
2352   else if (!layout_mode_variant)
2353     {
2354       layout_mode =
2355         meta_monitor_manager_get_default_layout_mode (manager);
2356     }
2357   else
2358     {
2359       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2360                                              G_DBUS_ERROR_INVALID_ARGS,
2361                                              "Can't set layout mode");
2362       return TRUE;
2363     }
2364 
2365   if (!is_valid_layout_mode (layout_mode))
2366     {
2367       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2368                                              G_DBUS_ERROR_ACCESS_DENIED,
2369                                              "Invalid layout mode specified");
2370       return TRUE;
2371     }
2372 
2373   g_variant_iter_init (&logical_monitor_configs_iter,
2374                        logical_monitor_configs_variant);
2375   while (TRUE)
2376     {
2377       GVariant *logical_monitor_config_variant =
2378         g_variant_iter_next_value (&logical_monitor_configs_iter);
2379       MetaLogicalMonitorConfig *logical_monitor_config;
2380 
2381       if (!logical_monitor_config_variant)
2382         break;
2383 
2384       logical_monitor_config =
2385         create_logical_monitor_config_from_variant (manager,
2386                                                     logical_monitor_config_variant,
2387                                                     layout_mode,
2388                                                     &error);
2389       g_variant_unref (logical_monitor_config_variant);
2390 
2391       if (!logical_monitor_config)
2392         {
2393           g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2394                                                  G_DBUS_ERROR_INVALID_ARGS,
2395                                                  "%s", error->message);
2396           g_error_free (error);
2397           g_list_free_full (logical_monitor_configs,
2398                             (GDestroyNotify) meta_logical_monitor_config_free);
2399           return TRUE;
2400         }
2401 
2402       logical_monitor_configs = g_list_append (logical_monitor_configs,
2403                                                logical_monitor_config);
2404     }
2405 
2406   config = meta_monitors_config_new (manager,
2407                                      logical_monitor_configs,
2408                                      layout_mode,
2409                                      META_MONITORS_CONFIG_FLAG_NONE);
2410   if (!meta_verify_monitors_config (config, manager, &error))
2411     {
2412       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2413                                              G_DBUS_ERROR_INVALID_ARGS,
2414                                              "%s", error->message);
2415       g_error_free (error);
2416       g_object_unref (config);
2417       return TRUE;
2418     }
2419 
2420   if (!meta_monitor_manager_is_config_applicable (manager, config, &error))
2421     {
2422       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2423                                              G_DBUS_ERROR_INVALID_ARGS,
2424                                              "%s", error->message);
2425       g_error_free (error);
2426       g_object_unref (config);
2427       return TRUE;
2428     }
2429 
2430   if (manager->persistent_timeout_id &&
2431       method != META_MONITORS_CONFIG_METHOD_VERIFY)
2432     cancel_persistent_confirmation (manager);
2433 
2434   if (!meta_monitor_manager_apply_monitors_config (manager,
2435                                                    config,
2436                                                    method,
2437                                                    &error))
2438     {
2439       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2440                                              G_DBUS_ERROR_INVALID_ARGS,
2441                                              "%s", error->message);
2442       g_error_free (error);
2443       g_object_unref (config);
2444       return TRUE;
2445     }
2446 
2447   if (method == META_MONITORS_CONFIG_METHOD_PERSISTENT)
2448     request_persistent_confirmation (manager);
2449 
2450   meta_dbus_display_config_complete_apply_monitors_config (skeleton, invocation);
2451 
2452   return TRUE;
2453 }
2454 
2455 #undef MONITOR_MODE_SPEC_FORMAT
2456 #undef MONITOR_CONFIG_FORMAT
2457 #undef MONITOR_CONFIGS_FORMAT
2458 #undef LOGICAL_MONITOR_CONFIG_FORMAT
2459 
2460 static void
confirm_configuration(MetaMonitorManager * manager,gboolean confirmed)2461 confirm_configuration (MetaMonitorManager *manager,
2462                        gboolean            confirmed)
2463 {
2464   if (confirmed)
2465     meta_monitor_config_manager_save_current (manager->config_manager);
2466   else
2467     restore_previous_config (manager);
2468 }
2469 
2470 void
meta_monitor_manager_confirm_configuration(MetaMonitorManager * manager,gboolean ok)2471 meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager,
2472                                             gboolean            ok)
2473 {
2474   if (!manager->persistent_timeout_id)
2475     {
2476       /* too late */
2477       return;
2478     }
2479 
2480   cancel_persistent_confirmation (manager);
2481   confirm_configuration (manager, ok);
2482 }
2483 
2484 static gboolean
meta_monitor_manager_handle_change_backlight(MetaDBusDisplayConfig * skeleton,GDBusMethodInvocation * invocation,guint serial,guint output_index,gint value,MetaMonitorManager * manager)2485 meta_monitor_manager_handle_change_backlight  (MetaDBusDisplayConfig *skeleton,
2486                                                GDBusMethodInvocation *invocation,
2487                                                guint                  serial,
2488                                                guint                  output_index,
2489                                                gint                   value,
2490                                                MetaMonitorManager    *manager)
2491 {
2492   GList *combined_outputs;
2493   MetaOutput *output;
2494   const MetaOutputInfo *output_info;
2495   int new_backlight;
2496 
2497   if (serial != manager->serial)
2498     {
2499       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2500                                              G_DBUS_ERROR_ACCESS_DENIED,
2501                                              "The requested configuration is based on stale information");
2502       return TRUE;
2503     }
2504 
2505   combined_outputs = combine_gpu_lists (manager, meta_gpu_get_outputs);
2506 
2507   if (output_index >= g_list_length (combined_outputs))
2508     {
2509       g_list_free (combined_outputs);
2510       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2511                                              G_DBUS_ERROR_INVALID_ARGS,
2512                                              "Invalid output id");
2513       return TRUE;
2514     }
2515   output = g_list_nth_data (combined_outputs, output_index);
2516   g_list_free (combined_outputs);
2517 
2518   if (value < 0 || value > 100)
2519     {
2520       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2521                                              G_DBUS_ERROR_INVALID_ARGS,
2522                                              "Invalid backlight value");
2523       return TRUE;
2524     }
2525 
2526   output_info = meta_output_get_info (output);
2527   if (meta_output_get_backlight (output) == -1 ||
2528       (output_info->backlight_min == 0 &&
2529        output_info->backlight_max == 0))
2530     {
2531       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2532                                              G_DBUS_ERROR_INVALID_ARGS,
2533                                              "Output does not support changing backlight");
2534       return TRUE;
2535     }
2536 
2537   META_MONITOR_MANAGER_GET_CLASS (manager)->change_backlight (manager, output, value);
2538 
2539   new_backlight = meta_output_get_backlight (output);
2540   meta_dbus_display_config_complete_change_backlight (skeleton,
2541                                                       invocation,
2542                                                       new_backlight);
2543   return TRUE;
2544 }
2545 
2546 static gboolean
meta_monitor_manager_handle_get_crtc_gamma(MetaDBusDisplayConfig * skeleton,GDBusMethodInvocation * invocation,guint serial,guint crtc_id,MetaMonitorManager * manager)2547 meta_monitor_manager_handle_get_crtc_gamma  (MetaDBusDisplayConfig *skeleton,
2548                                              GDBusMethodInvocation *invocation,
2549                                              guint                  serial,
2550                                              guint                  crtc_id,
2551                                              MetaMonitorManager    *manager)
2552 {
2553   MetaMonitorManagerClass *klass;
2554   GList *combined_crtcs;
2555   MetaCrtc *crtc;
2556   gsize size;
2557   unsigned short *red;
2558   unsigned short *green;
2559   unsigned short *blue;
2560   GBytes *red_bytes, *green_bytes, *blue_bytes;
2561   GVariant *red_v, *green_v, *blue_v;
2562 
2563   if (serial != manager->serial)
2564     {
2565       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2566                                              G_DBUS_ERROR_ACCESS_DENIED,
2567                                              "The requested configuration is based on stale information");
2568       return TRUE;
2569     }
2570 
2571   combined_crtcs = combine_gpu_lists (manager, meta_gpu_get_crtcs);
2572   if (crtc_id >= g_list_length (combined_crtcs))
2573     {
2574       g_list_free (combined_crtcs);
2575       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2576                                              G_DBUS_ERROR_INVALID_ARGS,
2577                                              "Invalid crtc id");
2578       return TRUE;
2579     }
2580 
2581   crtc = g_list_nth_data (combined_crtcs, crtc_id);
2582   g_list_free (combined_crtcs);
2583 
2584   klass = META_MONITOR_MANAGER_GET_CLASS (manager);
2585   if (klass->get_crtc_gamma)
2586     klass->get_crtc_gamma (manager, crtc, &size, &red, &green, &blue);
2587   else
2588     {
2589       size = 0;
2590       red = green = blue = NULL;
2591     }
2592 
2593   red_bytes = g_bytes_new_take (red, size * sizeof (unsigned short));
2594   green_bytes = g_bytes_new_take (green, size * sizeof (unsigned short));
2595   blue_bytes = g_bytes_new_take (blue, size * sizeof (unsigned short));
2596 
2597   red_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), red_bytes, TRUE);
2598   green_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), green_bytes, TRUE);
2599   blue_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), blue_bytes, TRUE);
2600 
2601   meta_dbus_display_config_complete_get_crtc_gamma (skeleton, invocation,
2602                                                     red_v, green_v, blue_v);
2603 
2604   g_bytes_unref (red_bytes);
2605   g_bytes_unref (green_bytes);
2606   g_bytes_unref (blue_bytes);
2607 
2608   return TRUE;
2609 }
2610 
2611 static gboolean
meta_monitor_manager_handle_set_crtc_gamma(MetaDBusDisplayConfig * skeleton,GDBusMethodInvocation * invocation,guint serial,guint crtc_id,GVariant * red_v,GVariant * green_v,GVariant * blue_v,MetaMonitorManager * manager)2612 meta_monitor_manager_handle_set_crtc_gamma  (MetaDBusDisplayConfig *skeleton,
2613                                              GDBusMethodInvocation *invocation,
2614                                              guint                  serial,
2615                                              guint                  crtc_id,
2616                                              GVariant              *red_v,
2617                                              GVariant              *green_v,
2618                                              GVariant              *blue_v,
2619                                              MetaMonitorManager    *manager)
2620 {
2621   MetaMonitorManagerClass *klass;
2622   GList *combined_crtcs;
2623   MetaCrtc *crtc;
2624   gsize size, dummy;
2625   unsigned short *red;
2626   unsigned short *green;
2627   unsigned short *blue;
2628   GBytes *red_bytes, *green_bytes, *blue_bytes;
2629 
2630   if (serial != manager->serial)
2631     {
2632       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2633                                              G_DBUS_ERROR_ACCESS_DENIED,
2634                                              "The requested configuration is based on stale information");
2635       return TRUE;
2636     }
2637 
2638   combined_crtcs = combine_gpu_lists (manager, meta_gpu_get_crtcs);
2639 
2640   if (crtc_id >= g_list_length (combined_crtcs))
2641     {
2642       g_list_free (combined_crtcs);
2643       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2644                                              G_DBUS_ERROR_INVALID_ARGS,
2645                                              "Invalid crtc id");
2646       return TRUE;
2647     }
2648 
2649   crtc = g_list_nth_data (combined_crtcs, crtc_id);
2650   g_list_free (combined_crtcs);
2651 
2652   red_bytes = g_variant_get_data_as_bytes (red_v);
2653   green_bytes = g_variant_get_data_as_bytes (green_v);
2654   blue_bytes = g_variant_get_data_as_bytes (blue_v);
2655 
2656   size = g_bytes_get_size (red_bytes) / sizeof (unsigned short);
2657   red = (unsigned short*) g_bytes_get_data (red_bytes, &dummy);
2658   green = (unsigned short*) g_bytes_get_data (green_bytes, &dummy);
2659   blue = (unsigned short*) g_bytes_get_data (blue_bytes, &dummy);
2660 
2661   klass = META_MONITOR_MANAGER_GET_CLASS (manager);
2662   if (klass->set_crtc_gamma)
2663     klass->set_crtc_gamma (manager, crtc, size, red, green, blue);
2664   meta_dbus_display_config_complete_set_crtc_gamma (skeleton, invocation);
2665 
2666   g_bytes_unref (red_bytes);
2667   g_bytes_unref (green_bytes);
2668   g_bytes_unref (blue_bytes);
2669 
2670   return TRUE;
2671 }
2672 
2673 static gboolean
meta_monitor_manager_handle_set_output_ctm(MetaDBusDisplayConfig * skeleton,GDBusMethodInvocation * invocation,guint serial,guint output_id,GVariant * ctm_var,MetaMonitorManager * manager)2674 meta_monitor_manager_handle_set_output_ctm  (MetaDBusDisplayConfig *skeleton,
2675                                              GDBusMethodInvocation *invocation,
2676                                              guint                  serial,
2677                                              guint                  output_id,
2678                                              GVariant              *ctm_var,
2679                                              MetaMonitorManager    *manager)
2680 {
2681   MetaMonitorManagerClass *klass;
2682   GList *combined_outputs;
2683   MetaOutput *output;
2684   MetaOutputCtm ctm;
2685   int i;
2686 
2687   if (serial != manager->serial)
2688     {
2689       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2690                                              G_DBUS_ERROR_ACCESS_DENIED,
2691                                              "The requested configuration is based on stale information");
2692       return TRUE;
2693     }
2694 
2695   combined_outputs = combine_gpu_lists (manager, meta_gpu_get_outputs);
2696 
2697   if (output_id >= g_list_length (combined_outputs))
2698     {
2699       g_list_free (combined_outputs);
2700       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2701                                              G_DBUS_ERROR_INVALID_ARGS,
2702                                              "Invalid output id");
2703       return TRUE;
2704     }
2705 
2706   output = g_list_nth_data (combined_outputs, output_id);
2707   g_list_free (combined_outputs);
2708 
2709   if (g_variant_n_children (ctm_var) != 9)
2710     {
2711       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
2712                                              G_DBUS_ERROR_INVALID_ARGS,
2713                                              "Unexpected color transform matrix variant length");
2714       return TRUE;
2715     }
2716 
2717   for (i = 0; i < 9; i++)
2718     {
2719       GVariant *tmp = g_variant_get_child_value (ctm_var, i);
2720       ctm.matrix[i] = g_variant_get_uint64 (tmp);
2721       g_variant_unref (tmp);
2722     }
2723 
2724   klass = META_MONITOR_MANAGER_GET_CLASS (manager);
2725   if (klass->set_output_ctm)
2726     klass->set_output_ctm (output, &ctm);
2727   meta_dbus_display_config_complete_set_output_ctm (skeleton, invocation);
2728 
2729   return TRUE;
2730 }
2731 
2732 static void
monitor_manager_setup_dbus_config_handlers(MetaMonitorManager * manager)2733 monitor_manager_setup_dbus_config_handlers (MetaMonitorManager *manager)
2734 {
2735   g_signal_connect_object (manager->display_config, "handle-get-resources",
2736                            G_CALLBACK (meta_monitor_manager_handle_get_resources),
2737                            manager, 0);
2738   g_signal_connect_object (manager->display_config, "handle-change-backlight",
2739                            G_CALLBACK (meta_monitor_manager_handle_change_backlight),
2740                            manager, 0);
2741   g_signal_connect_object (manager->display_config, "handle-get-crtc-gamma",
2742                            G_CALLBACK (meta_monitor_manager_handle_get_crtc_gamma),
2743                            manager, 0);
2744   g_signal_connect_object (manager->display_config, "handle-set-crtc-gamma",
2745                            G_CALLBACK (meta_monitor_manager_handle_set_crtc_gamma),
2746                            manager, 0);
2747   g_signal_connect_object (manager->display_config, "handle-get-current-state",
2748                            G_CALLBACK (meta_monitor_manager_handle_get_current_state),
2749                            manager, 0);
2750   g_signal_connect_object (manager->display_config, "handle-apply-monitors-config",
2751                            G_CALLBACK (meta_monitor_manager_handle_apply_monitors_config),
2752                            manager, 0);
2753   g_signal_connect_object (manager->display_config, "handle-set-output-ctm",
2754                            G_CALLBACK (meta_monitor_manager_handle_set_output_ctm),
2755                            manager, 0);
2756 }
2757 
2758 static void
on_bus_acquired(GDBusConnection * connection,const char * name,gpointer user_data)2759 on_bus_acquired (GDBusConnection *connection,
2760                  const char      *name,
2761                  gpointer         user_data)
2762 {
2763   MetaMonitorManager *manager = user_data;
2764 
2765   g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager->display_config),
2766                                     connection,
2767                                     "/org/gnome/Mutter/DisplayConfig",
2768                                     NULL);
2769 }
2770 
2771 static void
on_name_acquired(GDBusConnection * connection,const char * name,gpointer user_data)2772 on_name_acquired (GDBusConnection *connection,
2773                   const char      *name,
2774                   gpointer         user_data)
2775 {
2776   meta_topic (META_DEBUG_DBUS, "Acquired name %s", name);
2777 }
2778 
2779 static void
on_name_lost(GDBusConnection * connection,const char * name,gpointer user_data)2780 on_name_lost (GDBusConnection *connection,
2781               const char      *name,
2782               gpointer         user_data)
2783 {
2784   meta_topic (META_DEBUG_DBUS, "Lost or failed to acquire name %s", name);
2785 }
2786 
2787 static void
initialize_dbus_interface(MetaMonitorManager * manager)2788 initialize_dbus_interface (MetaMonitorManager *manager)
2789 {
2790   MetaContext *context = meta_backend_get_context (manager->backend);
2791 
2792   manager->dbus_name_id =
2793     g_bus_own_name (G_BUS_TYPE_SESSION,
2794                     "org.gnome.Mutter.DisplayConfig",
2795                     G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
2796                     (meta_context_is_replacing (context) ?
2797                      G_BUS_NAME_OWNER_FLAGS_REPLACE :
2798                      G_BUS_NAME_OWNER_FLAGS_NONE),
2799                     on_bus_acquired,
2800                     on_name_acquired,
2801                     on_name_lost,
2802                     g_object_ref (manager),
2803                     g_object_unref);
2804 }
2805 
2806 /**
2807  * meta_monitor_manager_get:
2808  *
2809  * Accessor for the singleton MetaMonitorManager.
2810  *
2811  * Returns: (transfer none): The only #MetaMonitorManager there is.
2812  */
2813 MetaMonitorManager *
meta_monitor_manager_get(void)2814 meta_monitor_manager_get (void)
2815 {
2816   MetaBackend *backend = meta_get_backend ();
2817 
2818   return meta_backend_get_monitor_manager (backend);
2819 }
2820 
2821 /**
2822  * meta_monitor_manager_get_num_logical_monitors:
2823  * @manager: A #MetaMonitorManager object
2824  *
2825  * Returns the number of #MetaLogicalMonitor<!-- -->s (can be 0 in case of a
2826  * headless setup).
2827  *
2828  * Returns: the total number of #MetaLogicalMonitor<!-- -->s.
2829  */
2830 int
meta_monitor_manager_get_num_logical_monitors(MetaMonitorManager * manager)2831 meta_monitor_manager_get_num_logical_monitors (MetaMonitorManager *manager)
2832 {
2833   return g_list_length (manager->logical_monitors);
2834 }
2835 
2836 /**
2837  * meta_monitor_manager_get_logical_monitors:
2838  * @manager: A #MetaMonitorManager object
2839  *
2840  * Returns the list of #MetaLogicalMonitor<!-- -->s that is handled. See also
2841  * meta_monitor_manager_get_num_logical_monitors() if you only need the size of
2842  * the list.
2843  *
2844  * Returns: (transfer none) (nullable): the list of logical monitors.
2845  */
2846 GList *
meta_monitor_manager_get_logical_monitors(MetaMonitorManager * manager)2847 meta_monitor_manager_get_logical_monitors (MetaMonitorManager *manager)
2848 {
2849   return manager->logical_monitors;
2850 }
2851 
2852 MetaLogicalMonitor *
meta_monitor_manager_get_logical_monitor_from_number(MetaMonitorManager * manager,int number)2853 meta_monitor_manager_get_logical_monitor_from_number (MetaMonitorManager *manager,
2854                                                       int                 number)
2855 {
2856   g_return_val_if_fail ((unsigned int) number < g_list_length (manager->logical_monitors), NULL);
2857 
2858   return g_list_nth (manager->logical_monitors, number)->data;
2859 }
2860 
2861 MetaLogicalMonitor *
meta_monitor_manager_get_primary_logical_monitor(MetaMonitorManager * manager)2862 meta_monitor_manager_get_primary_logical_monitor (MetaMonitorManager *manager)
2863 {
2864   return manager->primary_logical_monitor;
2865 }
2866 
2867 static MetaMonitor *
find_monitor(MetaMonitorManager * monitor_manager,gboolean (* match_func)(MetaMonitor * monitor))2868 find_monitor (MetaMonitorManager *monitor_manager,
2869               gboolean (*match_func) (MetaMonitor *monitor))
2870 {
2871   GList *monitors;
2872   GList *l;
2873 
2874   monitors = meta_monitor_manager_get_monitors (monitor_manager);
2875   for (l = monitors; l; l = l->next)
2876     {
2877       MetaMonitor *monitor = l->data;
2878 
2879       if (match_func (monitor))
2880         return monitor;
2881     }
2882 
2883   return NULL;
2884 }
2885 
2886 /**
2887  * meta_monitor_manager_get_primary_monitor:
2888  * @manager: A #MetaMonitorManager object
2889  *
2890  * Returns the primary monitor. This can be %NULL (e.g. when running headless).
2891  *
2892  * Returns: (transfer none) (nullable): The primary #MetaMonitor, or %NULL if
2893  *          none.
2894  */
2895 MetaMonitor *
meta_monitor_manager_get_primary_monitor(MetaMonitorManager * manager)2896 meta_monitor_manager_get_primary_monitor (MetaMonitorManager *manager)
2897 {
2898   return find_monitor (manager, meta_monitor_is_primary);
2899 }
2900 
2901 /**
2902  * meta_monitor_manager_get_laptop_panel:
2903  * @manager: A #MetaMonitorManager object
2904  *
2905  * Returns the #MetaMonitor that represents the built-in laptop panel (if
2906  * applicable).
2907  *
2908  * Returns: (transfer none) (nullable): The laptop panel, or %NULL if none.
2909  */
2910 MetaMonitor *
meta_monitor_manager_get_laptop_panel(MetaMonitorManager * manager)2911 meta_monitor_manager_get_laptop_panel (MetaMonitorManager *manager)
2912 {
2913   return find_monitor (manager, meta_monitor_is_laptop_panel);
2914 }
2915 
2916 MetaMonitor *
meta_monitor_manager_get_monitor_from_connector(MetaMonitorManager * manager,const char * connector)2917 meta_monitor_manager_get_monitor_from_connector (MetaMonitorManager *manager,
2918                                                  const char         *connector)
2919 {
2920   GList *l;
2921 
2922   for (l = manager->monitors; l; l = l->next)
2923     {
2924       MetaMonitor *monitor = l->data;
2925 
2926       if (g_str_equal (meta_monitor_get_connector (monitor),
2927                        connector))
2928         return monitor;
2929     }
2930 
2931   return NULL;
2932 }
2933 
2934 MetaMonitor *
meta_monitor_manager_get_monitor_from_spec(MetaMonitorManager * manager,MetaMonitorSpec * monitor_spec)2935 meta_monitor_manager_get_monitor_from_spec (MetaMonitorManager *manager,
2936                                             MetaMonitorSpec    *monitor_spec)
2937 {
2938   GList *l;
2939 
2940   for (l = manager->monitors; l; l = l->next)
2941     {
2942       MetaMonitor *monitor = l->data;
2943 
2944       if (meta_monitor_spec_equals (meta_monitor_get_spec (monitor),
2945                                     monitor_spec))
2946         return monitor;
2947     }
2948 
2949   return NULL;
2950 }
2951 
2952 /**
2953  * meta_monitor_manager_get_logical_monitor_at:
2954  * @manager: A #MetaMonitorManager object
2955  * @x: The x-coordinate
2956  * @y: The y-coordinate
2957  *
2958  * Finds the #MetaLogicalMonitor at the given @x and @y coordinates in the
2959  * total layout.
2960  *
2961  * Returns: (transfer none) (nullable): The #MetaLogicalMonitor at the given
2962  *          point, or %NULL if none.
2963  */
2964 MetaLogicalMonitor *
meta_monitor_manager_get_logical_monitor_at(MetaMonitorManager * manager,float x,float y)2965 meta_monitor_manager_get_logical_monitor_at (MetaMonitorManager *manager,
2966                                              float               x,
2967                                              float               y)
2968 {
2969   GList *l;
2970 
2971   for (l = manager->logical_monitors; l; l = l->next)
2972     {
2973       MetaLogicalMonitor *logical_monitor = l->data;
2974 
2975       if (META_POINT_IN_RECT (x, y, logical_monitor->rect))
2976         return logical_monitor;
2977     }
2978 
2979   return NULL;
2980 }
2981 
2982 /**
2983  * meta_monitor_manager_get_logical_monitor_from_rect:
2984  * @manager: A #MetaMonitorManager object
2985  * @rect: The rectangle
2986  *
2987  * Finds the #MetaLogicalMonitor which has the largest area in common with the
2988  * given @rect in the total layout.
2989  *
2990  * Returns: (transfer none) (nullable): The #MetaLogicalMonitor which
2991  *          corresponds the most to the given @rect, or %NULL if none.
2992  */
2993 MetaLogicalMonitor *
meta_monitor_manager_get_logical_monitor_from_rect(MetaMonitorManager * manager,MetaRectangle * rect)2994 meta_monitor_manager_get_logical_monitor_from_rect (MetaMonitorManager *manager,
2995                                                     MetaRectangle      *rect)
2996 {
2997   MetaLogicalMonitor *best_logical_monitor;
2998   int best_logical_monitor_area;
2999   GList *l;
3000 
3001   best_logical_monitor = NULL;
3002   best_logical_monitor_area = 0;
3003 
3004   for (l = manager->logical_monitors; l; l = l->next)
3005     {
3006       MetaLogicalMonitor *logical_monitor = l->data;
3007       MetaRectangle intersection;
3008       int intersection_area;
3009 
3010       if (!meta_rectangle_intersect (&logical_monitor->rect,
3011                                      rect,
3012                                      &intersection))
3013         continue;
3014 
3015       intersection_area = meta_rectangle_area (&intersection);
3016 
3017       if (intersection_area > best_logical_monitor_area)
3018         {
3019           best_logical_monitor = logical_monitor;
3020           best_logical_monitor_area = intersection_area;
3021         }
3022     }
3023 
3024   if (!best_logical_monitor && (rect->width == 0 || rect->height == 0))
3025     best_logical_monitor =
3026       meta_monitor_manager_get_logical_monitor_at (manager, rect->x, rect->y);
3027 
3028   if (!best_logical_monitor)
3029     best_logical_monitor = manager->primary_logical_monitor;
3030 
3031   return best_logical_monitor;
3032 }
3033 
3034 MetaLogicalMonitor *
meta_monitor_manager_get_logical_monitor_neighbor(MetaMonitorManager * manager,MetaLogicalMonitor * logical_monitor,MetaDisplayDirection direction)3035 meta_monitor_manager_get_logical_monitor_neighbor (MetaMonitorManager  *manager,
3036                                                    MetaLogicalMonitor  *logical_monitor,
3037                                                    MetaDisplayDirection direction)
3038 {
3039   GList *l;
3040 
3041   for (l = manager->logical_monitors; l; l = l->next)
3042     {
3043       MetaLogicalMonitor *other = l->data;
3044 
3045       if (meta_logical_monitor_has_neighbor (logical_monitor, other, direction))
3046         return other;
3047     }
3048 
3049   return NULL;
3050 }
3051 
3052 /**
3053  * meta_monitor_manager_get_monitors:
3054  * @manager: A #MetaMonitorManager object
3055  *
3056  * Returns the list of #MetaMonitor<!-- -->s. See also
3057  * meta_monitor_manager_get_logical_monitors() for a list of
3058  * #MetaLogicalMonitor<!-- -->s.
3059  *
3060  * Returns: (transfer none) (nullable): the list of #MetaMonitor<!-- -->s.
3061  */
3062 GList *
meta_monitor_manager_get_monitors(MetaMonitorManager * manager)3063 meta_monitor_manager_get_monitors (MetaMonitorManager *manager)
3064 {
3065   return manager->monitors;
3066 }
3067 
3068 void
meta_monitor_manager_get_screen_size(MetaMonitorManager * manager,int * width,int * height)3069 meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
3070                                       int                *width,
3071                                       int                *height)
3072 {
3073   *width = manager->screen_width;
3074   *height = manager->screen_height;
3075 }
3076 
3077 MetaPowerSave
meta_monitor_manager_get_power_save_mode(MetaMonitorManager * manager)3078 meta_monitor_manager_get_power_save_mode (MetaMonitorManager *manager)
3079 {
3080   MetaMonitorManagerPrivate *priv =
3081     meta_monitor_manager_get_instance_private (manager);
3082 
3083   return priv->power_save_mode;
3084 }
3085 
3086 static void
destroy_monitor(MetaMonitor * monitor)3087 destroy_monitor (MetaMonitor *monitor)
3088 {
3089   g_object_run_dispose (G_OBJECT (monitor));
3090   g_object_unref (monitor);
3091 }
3092 
3093 static void
rebuild_monitors(MetaMonitorManager * manager)3094 rebuild_monitors (MetaMonitorManager *manager)
3095 {
3096   GList *gpus;
3097   GList *l;
3098 
3099   if (manager->monitors)
3100     {
3101       g_list_free_full (manager->monitors, (GDestroyNotify) destroy_monitor);
3102       manager->monitors = NULL;
3103     }
3104 
3105   gpus = meta_backend_get_gpus (manager->backend);
3106   for (l = gpus; l; l = l->next)
3107     {
3108       MetaGpu *gpu = l->data;
3109       GList *k;
3110 
3111       for (k = meta_gpu_get_outputs (gpu); k; k = k->next)
3112         {
3113           MetaOutput *output = k->data;
3114           const MetaOutputInfo *output_info = meta_output_get_info (output);
3115 
3116           if (output_info->tile_info.group_id)
3117             {
3118               if (is_main_tiled_monitor_output (output))
3119                 {
3120                   MetaMonitorTiled *monitor_tiled;
3121 
3122                   monitor_tiled = meta_monitor_tiled_new (manager, output);
3123                   manager->monitors = g_list_append (manager->monitors,
3124                                                      monitor_tiled);
3125                 }
3126             }
3127           else
3128             {
3129               MetaMonitorNormal *monitor_normal;
3130 
3131               monitor_normal = meta_monitor_normal_new (manager, output);
3132               manager->monitors = g_list_append (manager->monitors,
3133                                                  monitor_normal);
3134             }
3135         }
3136     }
3137 
3138   for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next)
3139     {
3140       MetaVirtualMonitor *virtual_monitor = l->data;
3141       MetaOutput *output = meta_virtual_monitor_get_output (virtual_monitor);
3142       MetaMonitorNormal *monitor_normal;
3143 
3144       monitor_normal = meta_monitor_normal_new (manager, output);
3145       manager->monitors = g_list_append (manager->monitors,
3146                                          monitor_normal);
3147 
3148     }
3149 
3150   update_panel_orientation_managed (manager);
3151 }
3152 
3153 void
meta_monitor_manager_tiled_monitor_added(MetaMonitorManager * manager,MetaMonitor * monitor)3154 meta_monitor_manager_tiled_monitor_added (MetaMonitorManager *manager,
3155                                           MetaMonitor        *monitor)
3156 {
3157   MetaMonitorManagerClass *manager_class =
3158     META_MONITOR_MANAGER_GET_CLASS (manager);
3159 
3160   if (manager_class->tiled_monitor_added)
3161     manager_class->tiled_monitor_added (manager, monitor);
3162 }
3163 
3164 void
meta_monitor_manager_tiled_monitor_removed(MetaMonitorManager * manager,MetaMonitor * monitor)3165 meta_monitor_manager_tiled_monitor_removed (MetaMonitorManager *manager,
3166                                             MetaMonitor        *monitor)
3167 {
3168   MetaMonitorManagerClass *manager_class =
3169     META_MONITOR_MANAGER_GET_CLASS (manager);
3170 
3171   if (manager_class->tiled_monitor_removed)
3172     manager_class->tiled_monitor_removed (manager, monitor);
3173 }
3174 
3175 gboolean
meta_monitor_manager_is_transform_handled(MetaMonitorManager * manager,MetaCrtc * crtc,MetaMonitorTransform transform)3176 meta_monitor_manager_is_transform_handled (MetaMonitorManager  *manager,
3177                                            MetaCrtc            *crtc,
3178                                            MetaMonitorTransform transform)
3179 {
3180   MetaMonitorManagerClass *manager_class =
3181     META_MONITOR_MANAGER_GET_CLASS (manager);
3182 
3183   return manager_class->is_transform_handled (manager, crtc, transform);
3184 }
3185 
3186 static void
meta_monitor_manager_real_read_current_state(MetaMonitorManager * manager)3187 meta_monitor_manager_real_read_current_state (MetaMonitorManager *manager)
3188 {
3189   GList *l;
3190 
3191   manager->serial++;
3192 
3193   for (l = meta_backend_get_gpus (manager->backend); l; l = l->next)
3194     {
3195       MetaGpu *gpu = l->data;
3196       GError *error = NULL;
3197 
3198       if (!meta_gpu_read_current (gpu, &error))
3199         {
3200           g_warning ("Failed to read current KMS state: %s", error->message);
3201           g_clear_error (&error);
3202         }
3203     }
3204 
3205   rebuild_monitors (manager);
3206 }
3207 
3208 void
meta_monitor_manager_read_current_state(MetaMonitorManager * manager)3209 meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
3210 {
3211   MetaMonitorManagerClass *manager_class =
3212     META_MONITOR_MANAGER_GET_CLASS (manager);
3213 
3214   manager_class->read_current_state (manager);
3215 }
3216 
3217 static void
meta_monitor_manager_notify_monitors_changed(MetaMonitorManager * manager)3218 meta_monitor_manager_notify_monitors_changed (MetaMonitorManager *manager)
3219 {
3220   meta_backend_monitors_changed (manager->backend);
3221 
3222   g_signal_emit (manager, signals[MONITORS_CHANGED_INTERNAL], 0);
3223   g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
3224 
3225   meta_dbus_display_config_emit_monitors_changed (manager->display_config);
3226 }
3227 
3228 static void
set_logical_monitor_modes(MetaMonitorManager * manager,MetaLogicalMonitorConfig * logical_monitor_config)3229 set_logical_monitor_modes (MetaMonitorManager       *manager,
3230                            MetaLogicalMonitorConfig *logical_monitor_config)
3231 {
3232   GList *l;
3233 
3234   for (l = logical_monitor_config->monitor_configs; l; l = l->next)
3235     {
3236       MetaMonitorConfig *monitor_config = l->data;
3237       MetaMonitorSpec *monitor_spec;
3238       MetaMonitor *monitor;
3239       MetaMonitorModeSpec *monitor_mode_spec;
3240       MetaMonitorMode *monitor_mode;
3241 
3242       monitor_spec = monitor_config->monitor_spec;
3243       monitor = meta_monitor_manager_get_monitor_from_spec (manager,
3244                                                             monitor_spec);
3245       monitor_mode_spec = monitor_config->mode_spec;
3246       monitor_mode = meta_monitor_get_mode_from_spec (monitor,
3247                                                       monitor_mode_spec);
3248 
3249       meta_monitor_set_current_mode (monitor, monitor_mode);
3250     }
3251 }
3252 
3253 static void
meta_monitor_manager_update_monitor_modes(MetaMonitorManager * manager,MetaMonitorsConfig * config)3254 meta_monitor_manager_update_monitor_modes (MetaMonitorManager *manager,
3255                                            MetaMonitorsConfig *config)
3256 {
3257   GList *logical_monitor_configs;
3258   GList *l;
3259 
3260   g_list_foreach (manager->monitors,
3261                   (GFunc) meta_monitor_set_current_mode,
3262                   NULL);
3263 
3264   logical_monitor_configs = config ? config->logical_monitor_configs : NULL;
3265   for (l = logical_monitor_configs; l; l = l->next)
3266     {
3267       MetaLogicalMonitorConfig *logical_monitor_config = l->data;
3268 
3269       set_logical_monitor_modes (manager, logical_monitor_config);
3270     }
3271 }
3272 
3273 void
meta_monitor_manager_update_logical_state(MetaMonitorManager * manager,MetaMonitorsConfig * config)3274 meta_monitor_manager_update_logical_state (MetaMonitorManager *manager,
3275                                            MetaMonitorsConfig *config)
3276 {
3277   if (config)
3278     {
3279       manager->layout_mode = config->layout_mode;
3280       manager->current_switch_config =
3281         meta_monitors_config_get_switch_config (config);
3282     }
3283   else
3284     {
3285       manager->layout_mode =
3286         meta_monitor_manager_get_default_layout_mode (manager);
3287       manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
3288     }
3289 
3290   meta_monitor_manager_rebuild_logical_monitors (manager, config);
3291 }
3292 
3293 void
meta_monitor_manager_rebuild(MetaMonitorManager * manager,MetaMonitorsConfig * config)3294 meta_monitor_manager_rebuild (MetaMonitorManager *manager,
3295                               MetaMonitorsConfig *config)
3296 {
3297   GList *old_logical_monitors;
3298 
3299   meta_monitor_manager_update_monitor_modes (manager, config);
3300 
3301   if (manager->in_init)
3302     return;
3303 
3304   old_logical_monitors = manager->logical_monitors;
3305 
3306   meta_monitor_manager_update_logical_state (manager, config);
3307 
3308   meta_monitor_manager_notify_monitors_changed (manager);
3309 
3310   g_list_free_full (old_logical_monitors, g_object_unref);
3311 }
3312 
3313 static void
meta_monitor_manager_update_monitor_modes_derived(MetaMonitorManager * manager)3314 meta_monitor_manager_update_monitor_modes_derived (MetaMonitorManager *manager)
3315 {
3316   GList *l;
3317 
3318   for (l = manager->monitors; l; l = l->next)
3319     {
3320       MetaMonitor *monitor = l->data;
3321 
3322       meta_monitor_derive_current_mode (monitor);
3323     }
3324 }
3325 
3326 void
meta_monitor_manager_update_logical_state_derived(MetaMonitorManager * manager,MetaMonitorsConfig * config)3327 meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager,
3328                                                    MetaMonitorsConfig *config)
3329 {
3330   if (config)
3331     manager->current_switch_config =
3332       meta_monitors_config_get_switch_config (config);
3333   else
3334     manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
3335 
3336   manager->layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
3337 
3338   meta_monitor_manager_rebuild_logical_monitors_derived (manager, config);
3339 }
3340 
3341 void
meta_monitor_manager_rebuild_derived(MetaMonitorManager * manager,MetaMonitorsConfig * config)3342 meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager,
3343                                       MetaMonitorsConfig *config)
3344 {
3345   GList *old_logical_monitors;
3346 
3347   meta_monitor_manager_update_monitor_modes_derived (manager);
3348 
3349   if (manager->in_init)
3350     return;
3351 
3352   old_logical_monitors = manager->logical_monitors;
3353 
3354   meta_monitor_manager_update_logical_state_derived (manager, config);
3355 
3356   meta_monitor_manager_notify_monitors_changed (manager);
3357 
3358   g_list_free_full (old_logical_monitors, g_object_unref);
3359 }
3360 
3361 void
meta_monitor_manager_reconfigure(MetaMonitorManager * manager)3362 meta_monitor_manager_reconfigure (MetaMonitorManager *manager)
3363 {
3364   meta_monitor_manager_ensure_configured (manager);
3365 }
3366 
3367 void
meta_monitor_manager_reload(MetaMonitorManager * manager)3368 meta_monitor_manager_reload (MetaMonitorManager *manager)
3369 {
3370   meta_monitor_manager_read_current_state (manager);
3371   meta_monitor_manager_reconfigure (manager);
3372 }
3373 
3374 static gboolean
calculate_viewport_matrix(MetaMonitorManager * manager,MetaLogicalMonitor * logical_monitor,gfloat viewport[6])3375 calculate_viewport_matrix (MetaMonitorManager *manager,
3376                            MetaLogicalMonitor *logical_monitor,
3377                            gfloat              viewport[6])
3378 {
3379   gfloat x, y, width, height;
3380 
3381   x = (float) logical_monitor->rect.x / manager->screen_width;
3382   y = (float) logical_monitor->rect.y / manager->screen_height;
3383   width  = (float) logical_monitor->rect.width / manager->screen_width;
3384   height = (float) logical_monitor->rect.height / manager->screen_height;
3385 
3386   viewport[0] = width;
3387   viewport[1] = 0.0f;
3388   viewport[2] = x;
3389   viewport[3] = 0.0f;
3390   viewport[4] = height;
3391   viewport[5] = y;
3392 
3393   return TRUE;
3394 }
3395 
3396 static inline void
multiply_matrix(float a[6],float b[6],float res[6])3397 multiply_matrix (float a[6],
3398 		 float b[6],
3399 		 float res[6])
3400 {
3401   res[0] = a[0] * b[0] + a[1] * b[3];
3402   res[1] = a[0] * b[1] + a[1] * b[4];
3403   res[2] = a[0] * b[2] + a[1] * b[5] + a[2];
3404   res[3] = a[3] * b[0] + a[4] * b[3];
3405   res[4] = a[3] * b[1] + a[4] * b[4];
3406   res[5] = a[3] * b[2] + a[4] * b[5] + a[5];
3407 }
3408 
3409 gboolean
meta_monitor_manager_get_monitor_matrix(MetaMonitorManager * manager,MetaMonitor * monitor,MetaLogicalMonitor * logical_monitor,gfloat matrix[6])3410 meta_monitor_manager_get_monitor_matrix (MetaMonitorManager *manager,
3411                                          MetaMonitor        *monitor,
3412                                          MetaLogicalMonitor *logical_monitor,
3413                                          gfloat              matrix[6])
3414 {
3415   MetaMonitorTransform transform;
3416   gfloat viewport[9];
3417 
3418   if (!calculate_viewport_matrix (manager, logical_monitor, viewport))
3419     return FALSE;
3420 
3421   /* Get transform corrected for LCD panel-orientation. */
3422   transform = logical_monitor->transform;
3423   transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
3424   multiply_matrix (viewport, transform_matrices[transform],
3425                    matrix);
3426   return TRUE;
3427 }
3428 
3429 /**
3430  * meta_monitor_manager_get_monitor_for_connector:
3431  * @manager: A #MetaMonitorManager
3432  * @connector: A valid connector name
3433  *
3434  * Returns: The monitor index or -1 if @id isn't valid or the connector
3435  * isn't associated with a logical monitor.
3436  */
3437 gint
meta_monitor_manager_get_monitor_for_connector(MetaMonitorManager * manager,const char * connector)3438 meta_monitor_manager_get_monitor_for_connector (MetaMonitorManager *manager,
3439                                                 const char         *connector)
3440 {
3441   GList *l;
3442 
3443   for (l = manager->monitors; l; l = l->next)
3444     {
3445       MetaMonitor *monitor = l->data;
3446 
3447       if (meta_monitor_is_active (monitor) &&
3448           g_str_equal (connector, meta_monitor_get_connector (monitor)))
3449         return meta_monitor_get_logical_monitor (monitor)->number;
3450     }
3451 
3452   return -1;
3453 }
3454 
3455 /**
3456  * meta_monitor_manager_get_is_builtin_display_on:
3457  * @manager: A #MetaMonitorManager object
3458  *
3459  * Returns whether the built-in display (i.e. a laptop panel) is turned on.
3460  */
3461 gboolean
meta_monitor_manager_get_is_builtin_display_on(MetaMonitorManager * manager)3462 meta_monitor_manager_get_is_builtin_display_on (MetaMonitorManager *manager)
3463 {
3464   MetaMonitor *laptop_panel;
3465 
3466   g_return_val_if_fail (META_IS_MONITOR_MANAGER (manager), FALSE);
3467 
3468   laptop_panel = meta_monitor_manager_get_laptop_panel (manager);
3469   if (!laptop_panel)
3470     return FALSE;
3471 
3472   return meta_monitor_is_active (laptop_panel);
3473 }
3474 
3475 void
meta_monitor_manager_rotate_monitor(MetaMonitorManager * manager)3476 meta_monitor_manager_rotate_monitor (MetaMonitorManager *manager)
3477 {
3478   GError *error = NULL;
3479   MetaMonitorsConfig *config =
3480     meta_monitor_config_manager_create_for_rotate_monitor (manager->config_manager);
3481 
3482   if (!config)
3483     return;
3484 
3485   if (!meta_monitor_manager_apply_monitors_config (manager,
3486                                                    config,
3487                                                    META_MONITORS_CONFIG_METHOD_TEMPORARY,
3488                                                    &error))
3489     {
3490       g_warning ("Failed to use rotate monitor configuration: %s",
3491                  error->message);
3492       g_error_free (error);
3493     }
3494   g_object_unref (config);
3495 }
3496 
3497 void
meta_monitor_manager_switch_config(MetaMonitorManager * manager,MetaMonitorSwitchConfigType config_type)3498 meta_monitor_manager_switch_config (MetaMonitorManager          *manager,
3499                                     MetaMonitorSwitchConfigType  config_type)
3500 {
3501   GError *error = NULL;
3502   MetaMonitorsConfig *config;
3503 
3504   g_return_if_fail (config_type != META_MONITOR_SWITCH_CONFIG_UNKNOWN);
3505 
3506   config =
3507     meta_monitor_config_manager_create_for_switch_config (manager->config_manager,
3508                                                           config_type);
3509   if (!config)
3510     return;
3511 
3512   if (!meta_monitor_manager_apply_monitors_config (manager,
3513                                                    config,
3514                                                    META_MONITORS_CONFIG_METHOD_TEMPORARY,
3515                                                    &error))
3516     {
3517       g_warning ("Failed to use switch monitor configuration: %s",
3518                  error->message);
3519       g_error_free (error);
3520     }
3521   else
3522     {
3523       manager->current_switch_config = config_type;
3524     }
3525   g_object_unref (config);
3526 }
3527 
3528 gboolean
meta_monitor_manager_can_switch_config(MetaMonitorManager * manager)3529 meta_monitor_manager_can_switch_config (MetaMonitorManager *manager)
3530 {
3531   return (!meta_backend_is_lid_closed (manager->backend) &&
3532           g_list_length (manager->monitors) > 1);
3533 }
3534 
3535 MetaMonitorSwitchConfigType
meta_monitor_manager_get_switch_config(MetaMonitorManager * manager)3536 meta_monitor_manager_get_switch_config (MetaMonitorManager *manager)
3537 {
3538   return manager->current_switch_config;
3539 }
3540 
3541 MetaMonitorConfigManager *
meta_monitor_manager_get_config_manager(MetaMonitorManager * manager)3542 meta_monitor_manager_get_config_manager (MetaMonitorManager *manager)
3543 {
3544   return manager->config_manager;
3545 }
3546 
3547 /**
3548  * meta_monitor_manager_get_vendor_name:
3549  * @manager: A #MetaMonitorManager object
3550  * @vendor:  the PNP ID of the monitor
3551  *
3552  * Find the full vendor name from the given monitor PNP ID.
3553  *
3554  * Returns: (transfer full): A string containing the vendor name,
3555  *                           or NULL when not found.
3556  */
3557 char *
meta_monitor_manager_get_vendor_name(MetaMonitorManager * manager,const char * vendor)3558 meta_monitor_manager_get_vendor_name (MetaMonitorManager *manager,
3559                                       const char         *vendor)
3560 {
3561   if (!manager->pnp_ids)
3562     manager->pnp_ids = gnome_pnp_ids_new ();
3563 
3564   return gnome_pnp_ids_get_pnp_id (manager->pnp_ids, vendor);
3565 }
3566 
3567 gboolean
meta_monitor_manager_get_panel_orientation_managed(MetaMonitorManager * manager)3568 meta_monitor_manager_get_panel_orientation_managed (MetaMonitorManager *manager)
3569 {
3570   g_return_val_if_fail (META_IS_MONITOR_MANAGER (manager), FALSE);
3571 
3572   return manager->panel_orientation_managed;
3573 }
3574 
3575 void
meta_monitor_manager_post_init(MetaMonitorManager * manager)3576 meta_monitor_manager_post_init (MetaMonitorManager *manager)
3577 {
3578   ClutterBackend *clutter_backend;
3579   ClutterSeat *seat;
3580 
3581   clutter_backend = meta_backend_get_clutter_backend (manager->backend);
3582   seat = clutter_backend_get_default_seat (clutter_backend);
3583 
3584   g_signal_connect_object (seat, "notify::touch-mode",
3585                            G_CALLBACK (update_panel_orientation_managed), manager,
3586                            G_CONNECT_SWAPPED);
3587 }
3588 
3589 MetaViewportInfo *
meta_monitor_manager_get_viewports(MetaMonitorManager * manager)3590 meta_monitor_manager_get_viewports (MetaMonitorManager *manager)
3591 {
3592   MetaViewportInfo *info;
3593   GArray *views, *scales;
3594   GList *logical_monitors, *l;
3595 
3596   views = g_array_new (FALSE, FALSE, sizeof (cairo_rectangle_int_t));
3597   scales = g_array_new (FALSE, FALSE, sizeof (float));
3598 
3599   logical_monitors = meta_monitor_manager_get_logical_monitors (manager);
3600 
3601   for (l = logical_monitors; l; l = l->next)
3602     {
3603       MetaLogicalMonitor *logical_monitor = l->data;
3604       cairo_rectangle_int_t rect;
3605       float scale;
3606 
3607       rect = logical_monitor->rect;
3608       g_array_append_val (views, rect);
3609 
3610       scale = logical_monitor->scale;
3611       g_array_append_val (scales, scale);
3612     }
3613 
3614   info = meta_viewport_info_new ((cairo_rectangle_int_t *) views->data,
3615                                  (float *) scales->data,
3616                                  views->len,
3617                                  meta_is_stage_views_scaled ());
3618   g_array_unref (views);
3619   g_array_unref (scales);
3620 
3621   return info;
3622 }
3623 
3624 GList *
meta_monitor_manager_get_virtual_monitors(MetaMonitorManager * manager)3625 meta_monitor_manager_get_virtual_monitors (MetaMonitorManager *manager)
3626 {
3627   MetaMonitorManagerPrivate *priv =
3628     meta_monitor_manager_get_instance_private (manager);
3629 
3630   return priv->virtual_monitors;
3631 }
3632