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