1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /*
4 * Copyright (C) 2016 Red Hat
5 * Copyright (c) 2018 DisplayLink (UK) Ltd.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23 #include "config.h"
24
25 #include "backends/meta-monitor-config-manager.h"
26
27 #include "backends/meta-backend-private.h"
28 #include "backends/meta-monitor-config-migration.h"
29 #include "backends/meta-monitor-config-store.h"
30 #include "backends/meta-monitor-manager-private.h"
31 #include "backends/meta-output.h"
32 #include "core/boxes-private.h"
33 #include "meta/meta-monitor-manager.h"
34
35 #define CONFIG_HISTORY_MAX_SIZE 3
36
37 struct _MetaMonitorConfigManager
38 {
39 GObject parent;
40
41 MetaMonitorManager *monitor_manager;
42
43 MetaMonitorConfigStore *config_store;
44
45 MetaMonitorsConfig *current_config;
46 GQueue config_history;
47 };
48
49 G_DEFINE_TYPE (MetaMonitorConfigManager, meta_monitor_config_manager,
50 G_TYPE_OBJECT)
51
52 G_DEFINE_TYPE (MetaMonitorsConfig, meta_monitors_config,
53 G_TYPE_OBJECT)
54
55 static void
56 meta_crtc_assignment_free (MetaCrtcAssignment *assignment);
57
58 static void
59 meta_output_assignment_free (MetaOutputAssignment *assignment);
60
61 MetaMonitorConfigManager *
meta_monitor_config_manager_new(MetaMonitorManager * monitor_manager)62 meta_monitor_config_manager_new (MetaMonitorManager *monitor_manager)
63 {
64 MetaMonitorConfigManager *config_manager;
65
66 config_manager = g_object_new (META_TYPE_MONITOR_CONFIG_MANAGER, NULL);
67 config_manager->monitor_manager = monitor_manager;
68 config_manager->config_store =
69 meta_monitor_config_store_new (monitor_manager);
70
71 return config_manager;
72 }
73
74 MetaMonitorConfigStore *
meta_monitor_config_manager_get_store(MetaMonitorConfigManager * config_manager)75 meta_monitor_config_manager_get_store (MetaMonitorConfigManager *config_manager)
76 {
77 return config_manager->config_store;
78 }
79
80 static gboolean
is_crtc_reserved(MetaCrtc * crtc,GArray * reserved_crtcs)81 is_crtc_reserved (MetaCrtc *crtc,
82 GArray *reserved_crtcs)
83 {
84 unsigned int i;
85
86 for (i = 0; i < reserved_crtcs->len; i++)
87 {
88 uint64_t id;
89
90 id = g_array_index (reserved_crtcs, uint64_t, i);
91 if (id == meta_crtc_get_id (crtc))
92 return TRUE;
93 }
94
95 return FALSE;
96 }
97
98 static gboolean
is_crtc_assigned(MetaCrtc * crtc,GPtrArray * crtc_assignments)99 is_crtc_assigned (MetaCrtc *crtc,
100 GPtrArray *crtc_assignments)
101 {
102 unsigned int i;
103
104 for (i = 0; i < crtc_assignments->len; i++)
105 {
106 MetaCrtcAssignment *assigned_crtc_assignment =
107 g_ptr_array_index (crtc_assignments, i);
108
109 if (assigned_crtc_assignment->crtc == crtc)
110 return TRUE;
111 }
112
113 return FALSE;
114 }
115
116 static MetaCrtc *
find_unassigned_crtc(MetaOutput * output,GPtrArray * crtc_assignments,GArray * reserved_crtcs)117 find_unassigned_crtc (MetaOutput *output,
118 GPtrArray *crtc_assignments,
119 GArray *reserved_crtcs)
120 {
121 MetaCrtc *crtc;
122 const MetaOutputInfo *output_info;
123 unsigned int i;
124
125 crtc = meta_output_get_assigned_crtc (output);
126 if (crtc && !is_crtc_assigned (crtc, crtc_assignments))
127 return crtc;
128
129 output_info = meta_output_get_info (output);
130
131 /* then try to assign a CRTC that wasn't used */
132 for (i = 0; i < output_info->n_possible_crtcs; i++)
133 {
134 crtc = output_info->possible_crtcs[i];
135
136 if (is_crtc_assigned (crtc, crtc_assignments))
137 continue;
138
139 if (is_crtc_reserved (crtc, reserved_crtcs))
140 continue;
141
142 return crtc;
143 }
144
145 /* finally just give a CRTC that we haven't assigned */
146 for (i = 0; i < output_info->n_possible_crtcs; i++)
147 {
148 crtc = output_info->possible_crtcs[i];
149
150 if (is_crtc_assigned (crtc, crtc_assignments))
151 continue;
152
153 return crtc;
154 }
155
156 return NULL;
157 }
158
159 typedef struct
160 {
161 MetaMonitorManager *monitor_manager;
162 MetaMonitorsConfig *config;
163 MetaLogicalMonitorConfig *logical_monitor_config;
164 MetaMonitorConfig *monitor_config;
165 GPtrArray *crtc_assignments;
166 GPtrArray *output_assignments;
167 GArray *reserved_crtcs;
168 } MonitorAssignmentData;
169
170 static gboolean
assign_monitor_crtc(MetaMonitor * monitor,MetaMonitorMode * mode,MetaMonitorCrtcMode * monitor_crtc_mode,gpointer user_data,GError ** error)171 assign_monitor_crtc (MetaMonitor *monitor,
172 MetaMonitorMode *mode,
173 MetaMonitorCrtcMode *monitor_crtc_mode,
174 gpointer user_data,
175 GError **error)
176 {
177 MonitorAssignmentData *data = user_data;
178 MetaOutput *output;
179 MetaCrtc *crtc;
180 MetaMonitorTransform transform;
181 MetaMonitorTransform crtc_transform;
182 MetaMonitorTransform crtc_hw_transform;
183 int crtc_x, crtc_y;
184 float x_offset, y_offset;
185 float scale = 0.0;
186 float width, height;
187 MetaCrtcMode *crtc_mode;
188 const MetaCrtcModeInfo *crtc_mode_info;
189 graphene_rect_t crtc_layout;
190 MetaCrtcAssignment *crtc_assignment;
191 MetaOutputAssignment *output_assignment;
192 MetaMonitorConfig *first_monitor_config;
193 gboolean assign_output_as_primary;
194 gboolean assign_output_as_presentation;
195
196 output = monitor_crtc_mode->output;
197
198 crtc = find_unassigned_crtc (output,
199 data->crtc_assignments,
200 data->reserved_crtcs);
201
202 if (!crtc)
203 {
204 MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor);
205
206 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
207 "No available CRTC for monitor '%s %s' not found",
208 monitor_spec->vendor, monitor_spec->product);
209 return FALSE;
210 }
211
212 transform = data->logical_monitor_config->transform;
213 crtc_transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
214 if (meta_monitor_manager_is_transform_handled (data->monitor_manager,
215 crtc,
216 crtc_transform))
217 crtc_hw_transform = crtc_transform;
218 else
219 crtc_hw_transform = META_MONITOR_TRANSFORM_NORMAL;
220
221 meta_monitor_calculate_crtc_pos (monitor, mode, output, crtc_transform,
222 &crtc_x, &crtc_y);
223
224 x_offset = data->logical_monitor_config->layout.x;
225 y_offset = data->logical_monitor_config->layout.y;
226
227 switch (data->config->layout_mode)
228 {
229 case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
230 scale = data->logical_monitor_config->scale;
231 break;
232 case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
233 scale = 1.0;
234 break;
235 }
236
237 crtc_mode = monitor_crtc_mode->crtc_mode;
238 crtc_mode_info = meta_crtc_mode_get_info (monitor_crtc_mode->crtc_mode);
239
240 if (meta_monitor_transform_is_rotated (crtc_transform))
241 {
242 width = crtc_mode_info->height / scale;
243 height = crtc_mode_info->width / scale;
244 }
245 else
246 {
247 width = crtc_mode_info->width / scale;
248 height = crtc_mode_info->height / scale;
249 }
250
251 crtc_layout = GRAPHENE_RECT_INIT (x_offset + (crtc_x / scale),
252 y_offset + (crtc_y / scale),
253 width,
254 height);
255
256 crtc_assignment = g_new0 (MetaCrtcAssignment, 1);
257 *crtc_assignment = (MetaCrtcAssignment) {
258 .crtc = crtc,
259 .mode = crtc_mode,
260 .layout = crtc_layout,
261 .transform = crtc_hw_transform,
262 .outputs = g_ptr_array_new ()
263 };
264 g_ptr_array_add (crtc_assignment->outputs, output);
265
266 /*
267 * Only one output can be marked as primary (due to Xrandr limitation),
268 * so only mark the main output of the first monitor in the logical monitor
269 * as such.
270 */
271 first_monitor_config = data->logical_monitor_config->monitor_configs->data;
272 if (data->logical_monitor_config->is_primary &&
273 data->monitor_config == first_monitor_config &&
274 meta_monitor_get_main_output (monitor) == output)
275 assign_output_as_primary = TRUE;
276 else
277 assign_output_as_primary = FALSE;
278
279 if (data->logical_monitor_config->is_presentation)
280 assign_output_as_presentation = TRUE;
281 else
282 assign_output_as_presentation = FALSE;
283
284 output_assignment = g_new0 (MetaOutputAssignment, 1);
285 *output_assignment = (MetaOutputAssignment) {
286 .output = output,
287 .is_primary = assign_output_as_primary,
288 .is_presentation = assign_output_as_presentation,
289 .is_underscanning = data->monitor_config->enable_underscanning
290 };
291
292 g_ptr_array_add (data->crtc_assignments, crtc_assignment);
293 g_ptr_array_add (data->output_assignments, output_assignment);
294
295 return TRUE;
296 }
297
298 static gboolean
assign_monitor_crtcs(MetaMonitorManager * manager,MetaMonitorsConfig * config,MetaLogicalMonitorConfig * logical_monitor_config,MetaMonitorConfig * monitor_config,GPtrArray * crtc_assignments,GPtrArray * output_assignments,GArray * reserved_crtcs,GError ** error)299 assign_monitor_crtcs (MetaMonitorManager *manager,
300 MetaMonitorsConfig *config,
301 MetaLogicalMonitorConfig *logical_monitor_config,
302 MetaMonitorConfig *monitor_config,
303 GPtrArray *crtc_assignments,
304 GPtrArray *output_assignments,
305 GArray *reserved_crtcs,
306 GError **error)
307 {
308 MetaMonitorSpec *monitor_spec = monitor_config->monitor_spec;
309 MetaMonitorModeSpec *monitor_mode_spec = monitor_config->mode_spec;
310 MetaMonitor *monitor;
311 MetaMonitorMode *monitor_mode;
312 MonitorAssignmentData data;
313
314 monitor = meta_monitor_manager_get_monitor_from_spec (manager, monitor_spec);
315 if (!monitor)
316 {
317 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
318 "Configured monitor '%s %s' not found",
319 monitor_spec->vendor, monitor_spec->product);
320 return FALSE;
321 }
322
323 monitor_mode = meta_monitor_get_mode_from_spec (monitor, monitor_mode_spec);
324 if (!monitor_mode)
325 {
326 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
327 "Invalid mode %dx%d (%f) for monitor '%s %s'",
328 monitor_mode_spec->width, monitor_mode_spec->height,
329 monitor_mode_spec->refresh_rate,
330 monitor_spec->vendor, monitor_spec->product);
331 return FALSE;
332 }
333
334 data = (MonitorAssignmentData) {
335 .monitor_manager = manager,
336 .config = config,
337 .logical_monitor_config = logical_monitor_config,
338 .monitor_config = monitor_config,
339 .crtc_assignments = crtc_assignments,
340 .output_assignments = output_assignments,
341 .reserved_crtcs = reserved_crtcs
342 };
343 if (!meta_monitor_mode_foreach_crtc (monitor, monitor_mode,
344 assign_monitor_crtc,
345 &data,
346 error))
347 return FALSE;
348
349 return TRUE;
350 }
351
352 static gboolean
assign_logical_monitor_crtcs(MetaMonitorManager * manager,MetaMonitorsConfig * config,MetaLogicalMonitorConfig * logical_monitor_config,GPtrArray * crtc_assignments,GPtrArray * output_assignments,GArray * reserved_crtcs,GError ** error)353 assign_logical_monitor_crtcs (MetaMonitorManager *manager,
354 MetaMonitorsConfig *config,
355 MetaLogicalMonitorConfig *logical_monitor_config,
356 GPtrArray *crtc_assignments,
357 GPtrArray *output_assignments,
358 GArray *reserved_crtcs,
359 GError **error)
360 {
361 GList *l;
362
363 for (l = logical_monitor_config->monitor_configs; l; l = l->next)
364 {
365 MetaMonitorConfig *monitor_config = l->data;
366
367 if (!assign_monitor_crtcs (manager,
368 config,
369 logical_monitor_config,
370 monitor_config,
371 crtc_assignments, output_assignments,
372 reserved_crtcs, error))
373 return FALSE;
374 }
375
376 return TRUE;
377 }
378
379 gboolean
meta_monitor_config_manager_assign(MetaMonitorManager * manager,MetaMonitorsConfig * config,GPtrArray ** out_crtc_assignments,GPtrArray ** out_output_assignments,GError ** error)380 meta_monitor_config_manager_assign (MetaMonitorManager *manager,
381 MetaMonitorsConfig *config,
382 GPtrArray **out_crtc_assignments,
383 GPtrArray **out_output_assignments,
384 GError **error)
385 {
386 GPtrArray *crtc_assignments;
387 GPtrArray *output_assignments;
388 GArray *reserved_crtcs;
389 GList *l;
390
391 crtc_assignments =
392 g_ptr_array_new_with_free_func ((GDestroyNotify) meta_crtc_assignment_free);
393 output_assignments =
394 g_ptr_array_new_with_free_func ((GDestroyNotify) meta_output_assignment_free);
395 reserved_crtcs = g_array_new (FALSE, FALSE, sizeof (uint64_t));
396
397 for (l = config->logical_monitor_configs; l; l = l->next)
398 {
399 MetaLogicalMonitorConfig *logical_monitor_config = l->data;
400 GList *k;
401
402 for (k = logical_monitor_config->monitor_configs; k; k = k->next)
403 {
404 MetaMonitorConfig *monitor_config = k->data;
405 MetaMonitorSpec *monitor_spec = monitor_config->monitor_spec;
406 MetaMonitor *monitor;
407 GList *o;
408
409 monitor = meta_monitor_manager_get_monitor_from_spec (manager, monitor_spec);
410
411 for (o = meta_monitor_get_outputs (monitor); o; o = o->next)
412 {
413 MetaOutput *output = o->data;
414 MetaCrtc *crtc;
415
416 crtc = meta_output_get_assigned_crtc (output);
417 if (crtc)
418 {
419 uint64_t crtc_id = meta_crtc_get_id (crtc);
420
421 g_array_append_val (reserved_crtcs, crtc_id);
422 }
423 }
424 }
425 }
426
427 for (l = config->logical_monitor_configs; l; l = l->next)
428 {
429 MetaLogicalMonitorConfig *logical_monitor_config = l->data;
430
431 if (!assign_logical_monitor_crtcs (manager,
432 config, logical_monitor_config,
433 crtc_assignments, output_assignments,
434 reserved_crtcs, error))
435 {
436 g_ptr_array_free (crtc_assignments, TRUE);
437 g_ptr_array_free (output_assignments, TRUE);
438 g_array_free (reserved_crtcs, TRUE);
439 return FALSE;
440 }
441 }
442
443 g_array_free (reserved_crtcs, TRUE);
444
445 *out_crtc_assignments = crtc_assignments;
446 *out_output_assignments = output_assignments;
447
448 return TRUE;
449 }
450
451 static gboolean
is_lid_closed(MetaMonitorManager * monitor_manager)452 is_lid_closed (MetaMonitorManager *monitor_manager)
453 {
454 MetaBackend *backend;
455
456 backend = meta_monitor_manager_get_backend (monitor_manager);
457 return meta_backend_is_lid_closed (backend);
458 }
459
460 MetaMonitorsConfigKey *
meta_create_monitors_config_key_for_current_state(MetaMonitorManager * monitor_manager)461 meta_create_monitors_config_key_for_current_state (MetaMonitorManager *monitor_manager)
462 {
463 MetaMonitorsConfigKey *config_key;
464 MetaMonitorSpec *laptop_monitor_spec;
465 GList *l;
466 GList *monitor_specs;
467
468 laptop_monitor_spec = NULL;
469 monitor_specs = NULL;
470 for (l = monitor_manager->monitors; l; l = l->next)
471 {
472 MetaMonitor *monitor = l->data;
473 MetaMonitorSpec *monitor_spec;
474
475 if (meta_monitor_is_laptop_panel (monitor))
476 {
477 laptop_monitor_spec = meta_monitor_get_spec (monitor);
478
479 if (is_lid_closed (monitor_manager))
480 continue;
481 }
482
483 monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor));
484 monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
485 }
486
487 if (!monitor_specs && laptop_monitor_spec)
488 {
489 monitor_specs =
490 g_list_prepend (NULL, meta_monitor_spec_clone (laptop_monitor_spec));
491 }
492
493 if (!monitor_specs)
494 return NULL;
495
496 monitor_specs = g_list_sort (monitor_specs,
497 (GCompareFunc) meta_monitor_spec_compare);
498
499 config_key = g_new0 (MetaMonitorsConfigKey, 1);
500 *config_key = (MetaMonitorsConfigKey) {
501 .monitor_specs = monitor_specs
502 };
503
504 return config_key;
505 }
506
507 MetaMonitorsConfig *
meta_monitor_config_manager_get_stored(MetaMonitorConfigManager * config_manager)508 meta_monitor_config_manager_get_stored (MetaMonitorConfigManager *config_manager)
509 {
510 MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
511 MetaMonitorsConfigKey *config_key;
512 MetaMonitorsConfig *config;
513 GError *error = NULL;
514
515 config_key =
516 meta_create_monitors_config_key_for_current_state (monitor_manager);
517 if (!config_key)
518 return NULL;
519
520 config = meta_monitor_config_store_lookup (config_manager->config_store,
521 config_key);
522 meta_monitors_config_key_free (config_key);
523
524 if (!config)
525 return NULL;
526
527 if (config->flags & META_MONITORS_CONFIG_FLAG_MIGRATED)
528 {
529 if (!meta_finish_monitors_config_migration (monitor_manager, config,
530 &error))
531 {
532 g_warning ("Failed to finish monitors config migration: %s",
533 error->message);
534 g_error_free (error);
535 meta_monitor_config_store_remove (config_manager->config_store, config);
536 return NULL;
537 }
538 }
539
540 return config;
541 }
542
543 typedef enum _MonitorMatchRule
544 {
545 MONITOR_MATCH_ALL = 0,
546 MONITOR_MATCH_EXTERNAL = (1 << 0),
547 MONITOR_MATCH_BUILTIN = (1 << 1),
548 MONITOR_MATCH_VISIBLE = (1 << 2),
549 MONITOR_MATCH_WITH_SUGGESTED_POSITION = (1 << 3),
550 MONITOR_MATCH_PRIMARY = (1 << 4),
551 MONITOR_MATCH_ALLOW_FALLBACK = (1 << 5),
552 } MonitorMatchRule;
553
554 static gboolean
monitor_matches_rule(MetaMonitor * monitor,MetaMonitorManager * monitor_manager,MonitorMatchRule match_rule)555 monitor_matches_rule (MetaMonitor *monitor,
556 MetaMonitorManager *monitor_manager,
557 MonitorMatchRule match_rule)
558 {
559 if (!monitor)
560 return FALSE;
561
562 if (match_rule & MONITOR_MATCH_BUILTIN)
563 {
564 if (!meta_monitor_is_laptop_panel (monitor))
565 return FALSE;
566 }
567 else if (match_rule & MONITOR_MATCH_EXTERNAL)
568 {
569 if (meta_monitor_is_laptop_panel (monitor))
570 return FALSE;
571 }
572
573 if (match_rule & MONITOR_MATCH_VISIBLE)
574 {
575 if (meta_monitor_is_laptop_panel (monitor) &&
576 is_lid_closed (monitor_manager))
577 return FALSE;
578 }
579
580 if (match_rule & MONITOR_MATCH_WITH_SUGGESTED_POSITION)
581 {
582 if (!meta_monitor_get_suggested_position (monitor, NULL, NULL))
583 return FALSE;
584 }
585
586 return TRUE;
587 }
588
589 static GList *
find_monitors(MetaMonitorManager * monitor_manager,MonitorMatchRule match_rule,MetaMonitor * not_this_one)590 find_monitors (MetaMonitorManager *monitor_manager,
591 MonitorMatchRule match_rule,
592 MetaMonitor *not_this_one)
593 {
594 GList *result = NULL;
595 GList *monitors, *l;
596
597 monitors = meta_monitor_manager_get_monitors (monitor_manager);
598 for (l = g_list_last (monitors); l; l = l->prev)
599 {
600 MetaMonitor *monitor = l->data;
601
602 if (not_this_one && monitor == not_this_one)
603 continue;
604
605 if (monitor_matches_rule (monitor, monitor_manager, match_rule))
606 result = g_list_prepend (result, monitor);
607 }
608
609 return result;
610 }
611
612 static MetaMonitor *
find_monitor_with_highest_preferred_resolution(MetaMonitorManager * monitor_manager,MonitorMatchRule match_rule)613 find_monitor_with_highest_preferred_resolution (MetaMonitorManager *monitor_manager,
614 MonitorMatchRule match_rule)
615 {
616 g_autoptr (GList) monitors = NULL;
617 GList *l;
618 int largest_area = 0;
619 MetaMonitor *largest_monitor = NULL;
620
621 monitors = find_monitors (monitor_manager, match_rule, NULL);
622 for (l = monitors; l; l = l->next)
623 {
624 MetaMonitor *monitor = l->data;
625 MetaMonitorMode *mode;
626 int width, height;
627 int area;
628
629 mode = meta_monitor_get_preferred_mode (monitor);
630 meta_monitor_mode_get_resolution (mode, &width, &height);
631 area = width * height;
632
633 if (area > largest_area)
634 {
635 largest_area = area;
636 largest_monitor = monitor;
637 }
638 }
639
640 return largest_monitor;
641 }
642
643 /*
644 * Try to find the primary monitor. The priority of classification is:
645 *
646 * 1. Find the primary monitor as reported by the underlying system,
647 * 2. Find the laptop panel
648 * 3. Find the external monitor with highest resolution
649 *
650 * If the laptop lid is closed, exclude the laptop panel from possible
651 * alternatives, except if no other alternatives exist.
652 */
653 static MetaMonitor *
find_primary_monitor(MetaMonitorManager * monitor_manager,MonitorMatchRule match_rule)654 find_primary_monitor (MetaMonitorManager *monitor_manager,
655 MonitorMatchRule match_rule)
656 {
657 MetaMonitor *monitor;
658
659 monitor = meta_monitor_manager_get_primary_monitor (monitor_manager);
660 if (monitor_matches_rule (monitor, monitor_manager, match_rule))
661 return monitor;
662
663 monitor = meta_monitor_manager_get_laptop_panel (monitor_manager);
664 if (monitor_matches_rule (monitor, monitor_manager, match_rule))
665 return monitor;
666
667 monitor = find_monitor_with_highest_preferred_resolution (monitor_manager,
668 match_rule);
669 if (monitor)
670 return monitor;
671
672 if (match_rule & MONITOR_MATCH_ALLOW_FALLBACK)
673 return find_monitor_with_highest_preferred_resolution (monitor_manager,
674 MONITOR_MATCH_ALL);
675
676 return NULL;
677 }
678
679 static MetaMonitorConfig *
create_monitor_config(MetaMonitor * monitor,MetaMonitorMode * mode)680 create_monitor_config (MetaMonitor *monitor,
681 MetaMonitorMode *mode)
682 {
683 MetaMonitorSpec *monitor_spec;
684 MetaMonitorModeSpec *mode_spec;
685 MetaMonitorConfig *monitor_config;
686
687 monitor_spec = meta_monitor_get_spec (monitor);
688 mode_spec = meta_monitor_mode_get_spec (mode);
689
690 monitor_config = g_new0 (MetaMonitorConfig, 1);
691 *monitor_config = (MetaMonitorConfig) {
692 .monitor_spec = meta_monitor_spec_clone (monitor_spec),
693 .mode_spec = g_memdup2 (mode_spec, sizeof (MetaMonitorModeSpec)),
694 .enable_underscanning = meta_monitor_is_underscanning (monitor)
695 };
696
697 return monitor_config;
698 }
699
700 static MetaMonitorTransform
get_monitor_transform(MetaMonitorManager * monitor_manager,MetaMonitor * monitor)701 get_monitor_transform (MetaMonitorManager *monitor_manager,
702 MetaMonitor *monitor)
703 {
704 MetaOrientationManager *orientation_manager;
705 MetaOrientation orientation;
706 MetaBackend *backend;
707
708 if (!meta_monitor_is_laptop_panel (monitor) ||
709 !meta_monitor_manager_get_panel_orientation_managed (monitor_manager))
710 return META_MONITOR_TRANSFORM_NORMAL;
711
712 backend = meta_monitor_manager_get_backend (monitor_manager);
713 orientation_manager = meta_backend_get_orientation_manager (backend);
714 orientation = meta_orientation_manager_get_orientation (orientation_manager);
715
716 return meta_monitor_transform_from_orientation (orientation);
717 }
718
719 static MetaLogicalMonitorConfig *
create_preferred_logical_monitor_config(MetaMonitorManager * monitor_manager,MetaMonitor * monitor,int x,int y,float scale,MetaLogicalMonitorLayoutMode layout_mode)720 create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager,
721 MetaMonitor *monitor,
722 int x,
723 int y,
724 float scale,
725 MetaLogicalMonitorLayoutMode layout_mode)
726 {
727 MetaMonitorMode *mode;
728 int width, height;
729 MetaMonitorTransform transform;
730 MetaMonitorConfig *monitor_config;
731 MetaLogicalMonitorConfig *logical_monitor_config;
732
733 mode = meta_monitor_get_preferred_mode (monitor);
734 meta_monitor_mode_get_resolution (mode, &width, &height);
735
736 switch (layout_mode)
737 {
738 case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
739 width = (int) roundf (width / scale);
740 height = (int) roundf (height / scale);
741 break;
742 case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
743 break;
744 }
745
746 monitor_config = create_monitor_config (monitor, mode);
747
748 transform = get_monitor_transform (monitor_manager, monitor);
749 if (meta_monitor_transform_is_rotated (transform))
750 {
751 int temp = width;
752 width = height;
753 height = temp;
754 }
755
756 logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
757 *logical_monitor_config = (MetaLogicalMonitorConfig) {
758 .layout = (MetaRectangle) {
759 .x = x,
760 .y = y,
761 .width = width,
762 .height = height
763 },
764 .transform = transform,
765 .scale = scale,
766 .monitor_configs = g_list_append (NULL, monitor_config)
767 };
768
769 return logical_monitor_config;
770 }
771
772 static float
compute_scale_for_monitor(MetaMonitorManager * monitor_manager,MetaMonitor * monitor,MetaMonitor * primary_monitor)773 compute_scale_for_monitor (MetaMonitorManager *monitor_manager,
774 MetaMonitor *monitor,
775 MetaMonitor *primary_monitor)
776 {
777 MetaMonitor *target_monitor = monitor;
778 MetaLogicalMonitorLayoutMode layout_mode;
779 MetaMonitorMode *monitor_mode;
780
781 if ((meta_monitor_manager_get_capabilities (monitor_manager) &
782 META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED) &&
783 primary_monitor)
784 target_monitor = primary_monitor;
785
786 layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
787 monitor_mode = meta_monitor_get_preferred_mode (target_monitor);
788
789 return meta_monitor_manager_calculate_monitor_mode_scale (monitor_manager,
790 layout_mode,
791 target_monitor,
792 monitor_mode);
793 }
794
795 typedef enum _MonitorPositioningMode
796 {
797 MONITOR_POSITIONING_LINEAR,
798 MONITOR_POSITIONING_SUGGESTED,
799 } MonitorPositioningMode;
800
801 static gboolean
verify_suggested_monitors_config(GList * logical_monitor_configs)802 verify_suggested_monitors_config (GList *logical_monitor_configs)
803 {
804 g_autoptr (GList) region = NULL;
805 GList *l;
806
807 for (l = logical_monitor_configs; l; l = l->next)
808 {
809 MetaLogicalMonitorConfig *logical_monitor_config = l->data;
810 MetaRectangle *rect = &logical_monitor_config->layout;
811
812 if (meta_rectangle_overlaps_with_region (region, rect))
813 {
814 g_warning ("Suggested monitor config has overlapping region, "
815 "rejecting");
816 return FALSE;
817 }
818
819 region = g_list_prepend (region, rect);
820 }
821
822 for (l = region; region->next && l; l = l->next)
823 {
824 MetaRectangle *rect = l->data;
825
826 if (!meta_rectangle_is_adjacent_to_any_in_region (region, rect))
827 {
828 g_warning ("Suggested monitor config has monitors with no "
829 "neighbors, rejecting");
830 return FALSE;
831 }
832 }
833
834 return TRUE;
835 }
836
837 static MetaMonitorsConfig *
create_monitors_config(MetaMonitorConfigManager * config_manager,MonitorMatchRule match_rule,MonitorPositioningMode positioning,MetaMonitorsConfigFlag config_flags)838 create_monitors_config (MetaMonitorConfigManager *config_manager,
839 MonitorMatchRule match_rule,
840 MonitorPositioningMode positioning,
841 MetaMonitorsConfigFlag config_flags)
842 {
843 MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
844 g_autoptr (GList) monitors = NULL;
845 g_autolist (MetaLogicalMonitorConfig) logical_monitor_configs = NULL;
846 MetaMonitor *primary_monitor;
847 MetaLogicalMonitorLayoutMode layout_mode;
848 float scale;
849 GList *l;
850 int x, y;
851
852 primary_monitor = find_primary_monitor (monitor_manager,
853 match_rule | MONITOR_MATCH_VISIBLE);
854 if (!primary_monitor)
855 return NULL;
856
857 x = y = 0;
858 layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
859
860 if (!(match_rule & MONITOR_MATCH_PRIMARY))
861 monitors = find_monitors (monitor_manager, match_rule, primary_monitor);
862
863 /* The primary monitor needs to be at the head of the list for the
864 * linear positioning to be correct.
865 */
866 monitors = g_list_prepend (monitors, primary_monitor);
867
868 for (l = monitors; l; l = l->next)
869 {
870 MetaMonitor *monitor = l->data;
871 MetaLogicalMonitorConfig *logical_monitor_config;
872 gboolean has_suggested_position;
873
874 switch (positioning)
875 {
876 case MONITOR_POSITIONING_LINEAR:
877 break;
878 case MONITOR_POSITIONING_SUGGESTED:
879 has_suggested_position =
880 meta_monitor_get_suggested_position (monitor, &x, &y);
881 g_assert (has_suggested_position);
882 break;
883 }
884
885 scale = compute_scale_for_monitor (monitor_manager, monitor,
886 primary_monitor);
887 logical_monitor_config =
888 create_preferred_logical_monitor_config (monitor_manager,
889 monitor,
890 x, y, scale,
891 layout_mode);
892 logical_monitor_config->is_primary = (monitor == primary_monitor);
893 logical_monitor_configs = g_list_append (logical_monitor_configs,
894 logical_monitor_config);
895
896 x += logical_monitor_config->layout.width;
897 }
898
899 if (positioning == MONITOR_POSITIONING_SUGGESTED)
900 {
901 if (!verify_suggested_monitors_config (logical_monitor_configs))
902 return NULL;
903 }
904
905 return meta_monitors_config_new (monitor_manager,
906 g_steal_pointer (&logical_monitor_configs),
907 layout_mode,
908 config_flags);
909 }
910
911 MetaMonitorsConfig *
meta_monitor_config_manager_create_linear(MetaMonitorConfigManager * config_manager)912 meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager)
913 {
914 return create_monitors_config (config_manager,
915 MONITOR_MATCH_VISIBLE |
916 MONITOR_MATCH_ALLOW_FALLBACK,
917 MONITOR_POSITIONING_LINEAR,
918 META_MONITORS_CONFIG_FLAG_NONE);
919 }
920
921 MetaMonitorsConfig *
meta_monitor_config_manager_create_fallback(MetaMonitorConfigManager * config_manager)922 meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_manager)
923 {
924 return create_monitors_config (config_manager,
925 MONITOR_MATCH_PRIMARY |
926 MONITOR_MATCH_ALLOW_FALLBACK,
927 MONITOR_POSITIONING_LINEAR,
928 META_MONITORS_CONFIG_FLAG_NONE);
929 }
930
931 MetaMonitorsConfig *
meta_monitor_config_manager_create_suggested(MetaMonitorConfigManager * config_manager)932 meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_manager)
933 {
934 return create_monitors_config (config_manager,
935 MONITOR_MATCH_WITH_SUGGESTED_POSITION,
936 MONITOR_POSITIONING_SUGGESTED,
937 META_MONITORS_CONFIG_FLAG_NONE);
938 }
939
940 static GList *
clone_monitor_config_list(GList * monitor_configs_in)941 clone_monitor_config_list (GList *monitor_configs_in)
942 {
943 MetaMonitorConfig *monitor_config_in;
944 MetaMonitorConfig *monitor_config_out;
945 GList *monitor_configs_out = NULL;
946 GList *l;
947
948 for (l = monitor_configs_in; l; l = l->next)
949 {
950 monitor_config_in = l->data;
951 monitor_config_out = g_new0 (MetaMonitorConfig, 1);
952 *monitor_config_out = (MetaMonitorConfig) {
953 .monitor_spec = meta_monitor_spec_clone (monitor_config_in->monitor_spec),
954 .mode_spec = g_memdup2 (monitor_config_in->mode_spec,
955 sizeof (MetaMonitorModeSpec)),
956 .enable_underscanning = monitor_config_in->enable_underscanning
957 };
958 monitor_configs_out =
959 g_list_append (monitor_configs_out, monitor_config_out);
960 }
961
962 return monitor_configs_out;
963 }
964
965 static GList *
clone_logical_monitor_config_list(GList * logical_monitor_configs_in)966 clone_logical_monitor_config_list (GList *logical_monitor_configs_in)
967 {
968 MetaLogicalMonitorConfig *logical_monitor_config_in;
969 MetaLogicalMonitorConfig *logical_monitor_config_out;
970 GList *logical_monitor_configs_out = NULL;
971 GList *l;
972
973 for (l = logical_monitor_configs_in; l; l = l->next)
974 {
975 logical_monitor_config_in = l->data;
976
977 logical_monitor_config_out =
978 g_memdup2 (logical_monitor_config_in,
979 sizeof (MetaLogicalMonitorConfig));
980 logical_monitor_config_out->monitor_configs =
981 clone_monitor_config_list (logical_monitor_config_in->monitor_configs);
982
983 logical_monitor_configs_out =
984 g_list_append (logical_monitor_configs_out, logical_monitor_config_out);
985 }
986
987 return logical_monitor_configs_out;
988 }
989
990 static MetaLogicalMonitorConfig *
find_logical_config_for_builtin_monitor(MetaMonitorConfigManager * config_manager,GList * logical_monitor_configs)991 find_logical_config_for_builtin_monitor (MetaMonitorConfigManager *config_manager,
992 GList *logical_monitor_configs)
993 {
994 MetaLogicalMonitorConfig *logical_monitor_config;
995 MetaMonitorConfig *monitor_config;
996 MetaMonitor *panel;
997 GList *l;
998
999 panel = meta_monitor_manager_get_laptop_panel (config_manager->monitor_manager);
1000 if (panel)
1001 {
1002 for (l = logical_monitor_configs; l; l = l->next)
1003 {
1004 logical_monitor_config = l->data;
1005 /*
1006 * We only want to return the config for the panel if it is
1007 * configured on its own, so we skip configs which contain clones.
1008 */
1009 if (g_list_length (logical_monitor_config->monitor_configs) != 1)
1010 continue;
1011
1012 monitor_config = logical_monitor_config->monitor_configs->data;
1013 if (meta_monitor_spec_equals (meta_monitor_get_spec (panel),
1014 monitor_config->monitor_spec))
1015 {
1016 MetaMonitorMode *mode;
1017
1018 mode = meta_monitor_get_mode_from_spec (panel,
1019 monitor_config->mode_spec);
1020 if (mode)
1021 return logical_monitor_config;
1022 }
1023 }
1024 }
1025
1026 return NULL;
1027 }
1028
1029 static MetaMonitorsConfig *
create_for_builtin_display_rotation(MetaMonitorConfigManager * config_manager,MetaMonitorsConfig * base_config,gboolean rotate,MetaMonitorTransform transform)1030 create_for_builtin_display_rotation (MetaMonitorConfigManager *config_manager,
1031 MetaMonitorsConfig *base_config,
1032 gboolean rotate,
1033 MetaMonitorTransform transform)
1034 {
1035 MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
1036 MetaLogicalMonitorConfig *logical_monitor_config;
1037 MetaLogicalMonitorConfig *current_logical_monitor_config;
1038 MetaMonitorsConfig *config;
1039 GList *logical_monitor_configs, *current_configs;
1040 MetaLogicalMonitorLayoutMode layout_mode;
1041
1042 g_return_val_if_fail (base_config, NULL);
1043
1044 current_configs = base_config->logical_monitor_configs;
1045 current_logical_monitor_config =
1046 find_logical_config_for_builtin_monitor (config_manager, current_configs);
1047 if (!current_logical_monitor_config)
1048 return NULL;
1049
1050 if (rotate)
1051 transform = (current_logical_monitor_config->transform + 1) % META_MONITOR_TRANSFORM_FLIPPED;
1052 else
1053 {
1054 /*
1055 * The transform coming from the accelerometer should be applied to
1056 * the crtc as is, without taking panel-orientation into account, this
1057 * is done so that non panel-orientation aware desktop environments do the
1058 * right thing. Mutter corrects for panel-orientation when applying the
1059 * transform from a logical-monitor-config, so we must convert here.
1060 */
1061 MetaMonitor *panel =
1062 meta_monitor_manager_get_laptop_panel (config_manager->monitor_manager);
1063
1064 transform = meta_monitor_crtc_to_logical_transform (panel, transform);
1065 }
1066
1067 if (current_logical_monitor_config->transform == transform)
1068 return NULL;
1069
1070 logical_monitor_configs =
1071 clone_logical_monitor_config_list (base_config->logical_monitor_configs);
1072 logical_monitor_config =
1073 find_logical_config_for_builtin_monitor (config_manager,
1074 logical_monitor_configs);
1075 logical_monitor_config->transform = transform;
1076
1077 if (meta_monitor_transform_is_rotated (current_logical_monitor_config->transform) !=
1078 meta_monitor_transform_is_rotated (logical_monitor_config->transform))
1079 {
1080 int temp = logical_monitor_config->layout.width;
1081 logical_monitor_config->layout.width = logical_monitor_config->layout.height;
1082 logical_monitor_config->layout.height = temp;
1083 }
1084
1085 layout_mode = base_config->layout_mode;
1086 config = meta_monitors_config_new (monitor_manager,
1087 logical_monitor_configs,
1088 layout_mode,
1089 META_MONITORS_CONFIG_FLAG_NONE);
1090 meta_monitors_config_set_parent_config (config, base_config);
1091
1092 return config;
1093 }
1094
1095 MetaMonitorsConfig *
meta_monitor_config_manager_create_for_orientation(MetaMonitorConfigManager * config_manager,MetaMonitorsConfig * base_config,MetaMonitorTransform transform)1096 meta_monitor_config_manager_create_for_orientation (MetaMonitorConfigManager *config_manager,
1097 MetaMonitorsConfig *base_config,
1098 MetaMonitorTransform transform)
1099 {
1100 return create_for_builtin_display_rotation (config_manager, base_config,
1101 FALSE, transform);
1102 }
1103
1104 MetaMonitorsConfig *
meta_monitor_config_manager_create_for_builtin_orientation(MetaMonitorConfigManager * config_manager,MetaMonitorsConfig * base_config)1105 meta_monitor_config_manager_create_for_builtin_orientation (MetaMonitorConfigManager *config_manager,
1106 MetaMonitorsConfig *base_config)
1107 {
1108 MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
1109 MetaMonitorTransform current_transform;
1110 MetaMonitor *laptop_panel;
1111
1112 g_return_val_if_fail (
1113 meta_monitor_manager_get_panel_orientation_managed (monitor_manager), NULL);
1114
1115 laptop_panel = meta_monitor_manager_get_laptop_panel (monitor_manager);
1116 current_transform = get_monitor_transform (monitor_manager, laptop_panel);
1117
1118 return create_for_builtin_display_rotation (config_manager, base_config,
1119 FALSE, current_transform);
1120 }
1121
1122 MetaMonitorsConfig *
meta_monitor_config_manager_create_for_rotate_monitor(MetaMonitorConfigManager * config_manager)1123 meta_monitor_config_manager_create_for_rotate_monitor (MetaMonitorConfigManager *config_manager)
1124 {
1125 if (!config_manager->current_config)
1126 return NULL;
1127
1128 return create_for_builtin_display_rotation (config_manager,
1129 config_manager->current_config,
1130 TRUE,
1131 META_MONITOR_TRANSFORM_NORMAL);
1132 }
1133
1134 static MetaMonitorsConfig *
create_monitors_switch_config(MetaMonitorConfigManager * config_manager,MonitorMatchRule match_rule,MonitorPositioningMode positioning,MetaMonitorsConfigFlag config_flags,MetaMonitorSwitchConfigType switch_config)1135 create_monitors_switch_config (MetaMonitorConfigManager *config_manager,
1136 MonitorMatchRule match_rule,
1137 MonitorPositioningMode positioning,
1138 MetaMonitorsConfigFlag config_flags,
1139 MetaMonitorSwitchConfigType switch_config)
1140 {
1141 MetaMonitorsConfig *monitors_config;
1142
1143 monitors_config = create_monitors_config (config_manager, match_rule,
1144 positioning, config_flags);
1145
1146 if (!monitors_config)
1147 return NULL;
1148
1149 meta_monitors_config_set_switch_config (monitors_config, switch_config);
1150 return monitors_config;
1151 }
1152
1153 static MetaMonitorsConfig *
create_for_switch_config_all_mirror(MetaMonitorConfigManager * config_manager)1154 create_for_switch_config_all_mirror (MetaMonitorConfigManager *config_manager)
1155 {
1156 MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
1157 MetaLogicalMonitorLayoutMode layout_mode;
1158 MetaLogicalMonitorConfig *logical_monitor_config = NULL;
1159 GList *logical_monitor_configs;
1160 GList *monitor_configs = NULL;
1161 gint common_mode_w = 0, common_mode_h = 0;
1162 float best_scale = 1.0;
1163 MetaMonitor *monitor;
1164 GList *modes;
1165 GList *monitors;
1166 GList *l;
1167 MetaMonitorsConfig *monitors_config;
1168
1169 layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
1170 monitors = meta_monitor_manager_get_monitors (monitor_manager);
1171 monitor = monitors->data;
1172 modes = meta_monitor_get_modes (monitor);
1173 for (l = modes; l; l = l->next)
1174 {
1175 MetaMonitorMode *mode = l->data;
1176 gboolean common_mode_size = TRUE;
1177 gint mode_w, mode_h;
1178 GList *ll;
1179
1180 meta_monitor_mode_get_resolution (mode, &mode_w, &mode_h);
1181
1182 for (ll = monitors->next; ll; ll = ll->next)
1183 {
1184 MetaMonitor *monitor_b = ll->data;
1185 gboolean have_same_mode_size = FALSE;
1186 GList *mm;
1187
1188 for (mm = meta_monitor_get_modes (monitor_b); mm; mm = mm->next)
1189 {
1190 MetaMonitorMode *mode_b = mm->data;
1191 gint mode_b_w, mode_b_h;
1192
1193 meta_monitor_mode_get_resolution (mode_b, &mode_b_w, &mode_b_h);
1194
1195 if (mode_w == mode_b_w &&
1196 mode_h == mode_b_h)
1197 {
1198 have_same_mode_size = TRUE;
1199 break;
1200 }
1201 }
1202
1203 if (!have_same_mode_size)
1204 {
1205 common_mode_size = FALSE;
1206 break;
1207 }
1208 }
1209
1210 if (common_mode_size &&
1211 common_mode_w * common_mode_h < mode_w * mode_h)
1212 {
1213 common_mode_w = mode_w;
1214 common_mode_h = mode_h;
1215 }
1216 }
1217
1218 if (common_mode_w == 0 || common_mode_h == 0)
1219 return NULL;
1220
1221 for (l = monitors; l; l = l->next)
1222 {
1223 MetaMonitor *monitor = l->data;
1224 MetaMonitorMode *mode = NULL;
1225 GList *ll;
1226 float scale;
1227
1228 for (ll = meta_monitor_get_modes (monitor); ll; ll = ll->next)
1229 {
1230 gint mode_w, mode_h;
1231
1232 mode = ll->data;
1233 meta_monitor_mode_get_resolution (mode, &mode_w, &mode_h);
1234
1235 if (mode_w == common_mode_w && mode_h == common_mode_h)
1236 break;
1237 }
1238
1239 if (!mode)
1240 continue;
1241
1242 scale = meta_monitor_manager_calculate_monitor_mode_scale (monitor_manager,
1243 layout_mode,
1244 monitor, mode);
1245 best_scale = MAX (best_scale, scale);
1246 monitor_configs = g_list_prepend (monitor_configs, create_monitor_config (monitor, mode));
1247 }
1248
1249 logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
1250 *logical_monitor_config = (MetaLogicalMonitorConfig) {
1251 .layout = (MetaRectangle) {
1252 .x = 0,
1253 .y = 0,
1254 .width = common_mode_w,
1255 .height = common_mode_h
1256 },
1257 .scale = best_scale,
1258 .monitor_configs = monitor_configs
1259 };
1260
1261 logical_monitor_configs = g_list_append (NULL, logical_monitor_config);
1262 monitors_config = meta_monitors_config_new (monitor_manager,
1263 logical_monitor_configs,
1264 layout_mode,
1265 META_MONITORS_CONFIG_FLAG_NONE);
1266
1267 if (monitors_config)
1268 meta_monitors_config_set_switch_config (monitors_config, META_MONITOR_SWITCH_CONFIG_ALL_MIRROR);
1269
1270 return monitors_config;
1271 }
1272
1273 static MetaMonitorsConfig *
create_for_switch_config_external(MetaMonitorConfigManager * config_manager)1274 create_for_switch_config_external (MetaMonitorConfigManager *config_manager)
1275 {
1276 return create_monitors_switch_config (config_manager,
1277 MONITOR_MATCH_EXTERNAL,
1278 MONITOR_POSITIONING_LINEAR,
1279 META_MONITORS_CONFIG_FLAG_NONE,
1280 META_MONITOR_SWITCH_CONFIG_EXTERNAL);
1281 }
1282
1283 static MetaMonitorsConfig *
create_for_switch_config_builtin(MetaMonitorConfigManager * config_manager)1284 create_for_switch_config_builtin (MetaMonitorConfigManager *config_manager)
1285 {
1286 return create_monitors_switch_config (config_manager,
1287 MONITOR_MATCH_BUILTIN,
1288 MONITOR_POSITIONING_LINEAR,
1289 META_MONITORS_CONFIG_FLAG_NONE,
1290 META_MONITOR_SWITCH_CONFIG_BUILTIN);
1291 }
1292
1293 MetaMonitorsConfig *
meta_monitor_config_manager_create_for_switch_config(MetaMonitorConfigManager * config_manager,MetaMonitorSwitchConfigType config_type)1294 meta_monitor_config_manager_create_for_switch_config (MetaMonitorConfigManager *config_manager,
1295 MetaMonitorSwitchConfigType config_type)
1296 {
1297 MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
1298 MetaMonitorsConfig *config;
1299
1300 if (!meta_monitor_manager_can_switch_config (monitor_manager))
1301 return NULL;
1302
1303 switch (config_type)
1304 {
1305 case META_MONITOR_SWITCH_CONFIG_ALL_MIRROR:
1306 config = create_for_switch_config_all_mirror (config_manager);
1307 break;
1308 case META_MONITOR_SWITCH_CONFIG_ALL_LINEAR:
1309 config = meta_monitor_config_manager_create_linear (config_manager);
1310 break;
1311 case META_MONITOR_SWITCH_CONFIG_EXTERNAL:
1312 config = create_for_switch_config_external (config_manager);
1313 break;
1314 case META_MONITOR_SWITCH_CONFIG_BUILTIN:
1315 config = create_for_switch_config_builtin (config_manager);
1316 break;
1317 case META_MONITOR_SWITCH_CONFIG_UNKNOWN:
1318 default:
1319 g_warn_if_reached ();
1320 return NULL;
1321 }
1322
1323 return config;
1324 }
1325
1326 static MetaMonitorsConfig *
get_root_config(MetaMonitorsConfig * config)1327 get_root_config (MetaMonitorsConfig *config)
1328 {
1329 if (!config->parent_config)
1330 return config;
1331
1332 return get_root_config (config->parent_config);
1333 }
1334
1335 static gboolean
has_same_root_config(MetaMonitorsConfig * config_a,MetaMonitorsConfig * config_b)1336 has_same_root_config (MetaMonitorsConfig *config_a,
1337 MetaMonitorsConfig *config_b)
1338 {
1339 return get_root_config (config_a) == get_root_config (config_b);
1340 }
1341
1342 void
meta_monitor_config_manager_set_current(MetaMonitorConfigManager * config_manager,MetaMonitorsConfig * config)1343 meta_monitor_config_manager_set_current (MetaMonitorConfigManager *config_manager,
1344 MetaMonitorsConfig *config)
1345 {
1346 MetaMonitorsConfig *current_config = config_manager->current_config;
1347 gboolean overrides_current = FALSE;
1348
1349 if (config && current_config &&
1350 has_same_root_config (config, current_config))
1351 {
1352 overrides_current = meta_monitors_config_key_equal (config->key,
1353 current_config->key);
1354 }
1355
1356 if (current_config && !overrides_current)
1357 {
1358 g_queue_push_head (&config_manager->config_history,
1359 g_object_ref (config_manager->current_config));
1360 if (g_queue_get_length (&config_manager->config_history) >
1361 CONFIG_HISTORY_MAX_SIZE)
1362 g_object_unref (g_queue_pop_tail (&config_manager->config_history));
1363 }
1364
1365 g_set_object (&config_manager->current_config, config);
1366 }
1367
1368 void
meta_monitor_config_manager_save_current(MetaMonitorConfigManager * config_manager)1369 meta_monitor_config_manager_save_current (MetaMonitorConfigManager *config_manager)
1370 {
1371 g_return_if_fail (config_manager->current_config);
1372
1373 meta_monitor_config_store_add (config_manager->config_store,
1374 config_manager->current_config);
1375 }
1376
1377 MetaMonitorsConfig *
meta_monitor_config_manager_get_current(MetaMonitorConfigManager * config_manager)1378 meta_monitor_config_manager_get_current (MetaMonitorConfigManager *config_manager)
1379 {
1380 return config_manager->current_config;
1381 }
1382
1383 MetaMonitorsConfig *
meta_monitor_config_manager_pop_previous(MetaMonitorConfigManager * config_manager)1384 meta_monitor_config_manager_pop_previous (MetaMonitorConfigManager *config_manager)
1385 {
1386 return g_queue_pop_head (&config_manager->config_history);
1387 }
1388
1389 MetaMonitorsConfig *
meta_monitor_config_manager_get_previous(MetaMonitorConfigManager * config_manager)1390 meta_monitor_config_manager_get_previous (MetaMonitorConfigManager *config_manager)
1391 {
1392 return g_queue_peek_head (&config_manager->config_history);
1393 }
1394
1395 void
meta_monitor_config_manager_clear_history(MetaMonitorConfigManager * config_manager)1396 meta_monitor_config_manager_clear_history (MetaMonitorConfigManager *config_manager)
1397 {
1398 g_queue_foreach (&config_manager->config_history, (GFunc) g_object_unref, NULL);
1399 g_queue_clear (&config_manager->config_history);
1400 }
1401
1402 static void
meta_monitor_config_manager_dispose(GObject * object)1403 meta_monitor_config_manager_dispose (GObject *object)
1404 {
1405 MetaMonitorConfigManager *config_manager =
1406 META_MONITOR_CONFIG_MANAGER (object);
1407
1408 g_clear_object (&config_manager->current_config);
1409 meta_monitor_config_manager_clear_history (config_manager);
1410
1411 G_OBJECT_CLASS (meta_monitor_config_manager_parent_class)->dispose (object);
1412 }
1413
1414 static void
meta_monitor_config_manager_init(MetaMonitorConfigManager * config_manager)1415 meta_monitor_config_manager_init (MetaMonitorConfigManager *config_manager)
1416 {
1417 g_queue_init (&config_manager->config_history);
1418 }
1419
1420 static void
meta_monitor_config_manager_class_init(MetaMonitorConfigManagerClass * klass)1421 meta_monitor_config_manager_class_init (MetaMonitorConfigManagerClass *klass)
1422 {
1423 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1424
1425 object_class->dispose = meta_monitor_config_manager_dispose;
1426 }
1427
1428 void
meta_monitor_config_free(MetaMonitorConfig * monitor_config)1429 meta_monitor_config_free (MetaMonitorConfig *monitor_config)
1430 {
1431 if (monitor_config->monitor_spec)
1432 meta_monitor_spec_free (monitor_config->monitor_spec);
1433 g_free (monitor_config->mode_spec);
1434 g_free (monitor_config);
1435 }
1436
1437 void
meta_logical_monitor_config_free(MetaLogicalMonitorConfig * logical_monitor_config)1438 meta_logical_monitor_config_free (MetaLogicalMonitorConfig *logical_monitor_config)
1439 {
1440 g_list_free_full (logical_monitor_config->monitor_configs,
1441 (GDestroyNotify) meta_monitor_config_free);
1442 g_free (logical_monitor_config);
1443 }
1444
1445 static MetaMonitorsConfigKey *
meta_monitors_config_key_new(GList * logical_monitor_configs,GList * disabled_monitor_specs)1446 meta_monitors_config_key_new (GList *logical_monitor_configs,
1447 GList *disabled_monitor_specs)
1448 {
1449 MetaMonitorsConfigKey *config_key;
1450 GList *monitor_specs;
1451 GList *l;
1452
1453 monitor_specs = NULL;
1454 for (l = logical_monitor_configs; l; l = l->next)
1455 {
1456 MetaLogicalMonitorConfig *logical_monitor_config = l->data;
1457 GList *k;
1458
1459 for (k = logical_monitor_config->monitor_configs; k; k = k->next)
1460 {
1461 MetaMonitorConfig *monitor_config = k->data;
1462 MetaMonitorSpec *monitor_spec;
1463
1464 monitor_spec = meta_monitor_spec_clone (monitor_config->monitor_spec);
1465 monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
1466 }
1467 }
1468
1469 for (l = disabled_monitor_specs; l; l = l->next)
1470 {
1471 MetaMonitorSpec *monitor_spec = l->data;
1472
1473 monitor_spec = meta_monitor_spec_clone (monitor_spec);
1474 monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
1475 }
1476
1477 monitor_specs = g_list_sort (monitor_specs,
1478 (GCompareFunc) meta_monitor_spec_compare);
1479
1480 config_key = g_new0 (MetaMonitorsConfigKey, 1);
1481 *config_key = (MetaMonitorsConfigKey) {
1482 .monitor_specs = monitor_specs
1483 };
1484
1485 return config_key;
1486 }
1487
1488 void
meta_monitors_config_key_free(MetaMonitorsConfigKey * config_key)1489 meta_monitors_config_key_free (MetaMonitorsConfigKey *config_key)
1490 {
1491 g_list_free_full (config_key->monitor_specs,
1492 (GDestroyNotify) meta_monitor_spec_free);
1493 g_free (config_key);
1494 }
1495
1496 unsigned int
meta_monitors_config_key_hash(gconstpointer data)1497 meta_monitors_config_key_hash (gconstpointer data)
1498 {
1499 const MetaMonitorsConfigKey *config_key = data;
1500 GList *l;
1501 unsigned long hash;
1502
1503 hash = 0;
1504 for (l = config_key->monitor_specs; l; l = l->next)
1505 {
1506 MetaMonitorSpec *monitor_spec = l->data;
1507
1508 hash ^= (g_str_hash (monitor_spec->connector) ^
1509 g_str_hash (monitor_spec->vendor) ^
1510 g_str_hash (monitor_spec->product) ^
1511 g_str_hash (monitor_spec->serial));
1512 }
1513
1514 return hash;
1515 }
1516
1517 gboolean
meta_monitors_config_key_equal(gconstpointer data_a,gconstpointer data_b)1518 meta_monitors_config_key_equal (gconstpointer data_a,
1519 gconstpointer data_b)
1520 {
1521 const MetaMonitorsConfigKey *config_key_a = data_a;
1522 const MetaMonitorsConfigKey *config_key_b = data_b;
1523 GList *l_a, *l_b;
1524
1525 for (l_a = config_key_a->monitor_specs, l_b = config_key_b->monitor_specs;
1526 l_a && l_b;
1527 l_a = l_a->next, l_b = l_b->next)
1528 {
1529 MetaMonitorSpec *monitor_spec_a = l_a->data;
1530 MetaMonitorSpec *monitor_spec_b = l_b->data;
1531
1532 if (!meta_monitor_spec_equals (monitor_spec_a, monitor_spec_b))
1533 return FALSE;
1534 }
1535
1536 if (l_a || l_b)
1537 return FALSE;
1538
1539 return TRUE;
1540 }
1541
1542 MetaMonitorSwitchConfigType
meta_monitors_config_get_switch_config(MetaMonitorsConfig * config)1543 meta_monitors_config_get_switch_config (MetaMonitorsConfig *config)
1544 {
1545 return config->switch_config;
1546 }
1547
1548 void
meta_monitors_config_set_switch_config(MetaMonitorsConfig * config,MetaMonitorSwitchConfigType switch_config)1549 meta_monitors_config_set_switch_config (MetaMonitorsConfig *config,
1550 MetaMonitorSwitchConfigType switch_config)
1551 {
1552 config->switch_config = switch_config;
1553 }
1554
1555 void
meta_monitors_config_set_parent_config(MetaMonitorsConfig * config,MetaMonitorsConfig * parent_config)1556 meta_monitors_config_set_parent_config (MetaMonitorsConfig *config,
1557 MetaMonitorsConfig *parent_config)
1558 {
1559 g_assert (config != parent_config);
1560 g_assert (!parent_config || parent_config->parent_config != config);
1561
1562 g_set_object (&config->parent_config, parent_config);
1563 }
1564
1565 MetaMonitorsConfig *
meta_monitors_config_new_full(GList * logical_monitor_configs,GList * disabled_monitor_specs,MetaLogicalMonitorLayoutMode layout_mode,MetaMonitorsConfigFlag flags)1566 meta_monitors_config_new_full (GList *logical_monitor_configs,
1567 GList *disabled_monitor_specs,
1568 MetaLogicalMonitorLayoutMode layout_mode,
1569 MetaMonitorsConfigFlag flags)
1570 {
1571 MetaMonitorsConfig *config;
1572
1573 config = g_object_new (META_TYPE_MONITORS_CONFIG, NULL);
1574 config->logical_monitor_configs = logical_monitor_configs;
1575 config->disabled_monitor_specs = disabled_monitor_specs;
1576 config->key = meta_monitors_config_key_new (logical_monitor_configs,
1577 disabled_monitor_specs);
1578 config->layout_mode = layout_mode;
1579 config->flags = flags;
1580 config->switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
1581
1582 return config;
1583 }
1584
1585 MetaMonitorsConfig *
meta_monitors_config_new(MetaMonitorManager * monitor_manager,GList * logical_monitor_configs,MetaLogicalMonitorLayoutMode layout_mode,MetaMonitorsConfigFlag flags)1586 meta_monitors_config_new (MetaMonitorManager *monitor_manager,
1587 GList *logical_monitor_configs,
1588 MetaLogicalMonitorLayoutMode layout_mode,
1589 MetaMonitorsConfigFlag flags)
1590 {
1591 GList *disabled_monitor_specs = NULL;
1592 GList *monitors;
1593 GList *l;
1594
1595 monitors = meta_monitor_manager_get_monitors (monitor_manager);
1596 for (l = monitors; l; l = l->next)
1597 {
1598 MetaMonitor *monitor = l->data;
1599 MetaMonitorSpec *monitor_spec;
1600
1601 if (!monitor_matches_rule (monitor, monitor_manager,
1602 MONITOR_MATCH_VISIBLE))
1603 continue;
1604
1605 monitor_spec = meta_monitor_get_spec (monitor);
1606 if (meta_logical_monitor_configs_have_monitor (logical_monitor_configs,
1607 monitor_spec))
1608 continue;
1609
1610 disabled_monitor_specs =
1611 g_list_prepend (disabled_monitor_specs,
1612 meta_monitor_spec_clone (monitor_spec));
1613 }
1614
1615 return meta_monitors_config_new_full (logical_monitor_configs,
1616 disabled_monitor_specs,
1617 layout_mode,
1618 flags);
1619 }
1620
1621 static void
meta_monitors_config_finalize(GObject * object)1622 meta_monitors_config_finalize (GObject *object)
1623 {
1624 MetaMonitorsConfig *config = META_MONITORS_CONFIG (object);
1625
1626 g_clear_object (&config->parent_config);
1627 meta_monitors_config_key_free (config->key);
1628 g_list_free_full (config->logical_monitor_configs,
1629 (GDestroyNotify) meta_logical_monitor_config_free);
1630 g_list_free_full (config->disabled_monitor_specs,
1631 (GDestroyNotify) meta_monitor_spec_free);
1632
1633 G_OBJECT_CLASS (meta_monitors_config_parent_class)->finalize (object);
1634 }
1635
1636 static void
meta_monitors_config_init(MetaMonitorsConfig * config)1637 meta_monitors_config_init (MetaMonitorsConfig *config)
1638 {
1639 }
1640
1641 static void
meta_monitors_config_class_init(MetaMonitorsConfigClass * klass)1642 meta_monitors_config_class_init (MetaMonitorsConfigClass *klass)
1643 {
1644 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1645
1646 object_class->finalize = meta_monitors_config_finalize;
1647 }
1648
1649 static void
meta_crtc_assignment_free(MetaCrtcAssignment * assignment)1650 meta_crtc_assignment_free (MetaCrtcAssignment *assignment)
1651 {
1652 g_ptr_array_free (assignment->outputs, TRUE);
1653 g_free (assignment);
1654 }
1655
1656 static void
meta_output_assignment_free(MetaOutputAssignment * assignment)1657 meta_output_assignment_free (MetaOutputAssignment *assignment)
1658 {
1659 g_free (assignment);
1660 }
1661
1662 gboolean
meta_verify_monitor_mode_spec(MetaMonitorModeSpec * monitor_mode_spec,GError ** error)1663 meta_verify_monitor_mode_spec (MetaMonitorModeSpec *monitor_mode_spec,
1664 GError **error)
1665 {
1666 if (monitor_mode_spec->width > 0 &&
1667 monitor_mode_spec->height > 0 &&
1668 monitor_mode_spec->refresh_rate > 0.0f)
1669 {
1670 return TRUE;
1671 }
1672 else
1673 {
1674 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1675 "Monitor mode invalid");
1676 return FALSE;
1677 }
1678 }
1679
1680 gboolean
meta_verify_monitor_spec(MetaMonitorSpec * monitor_spec,GError ** error)1681 meta_verify_monitor_spec (MetaMonitorSpec *monitor_spec,
1682 GError **error)
1683 {
1684 if (monitor_spec->connector &&
1685 monitor_spec->vendor &&
1686 monitor_spec->product &&
1687 monitor_spec->serial)
1688 {
1689 return TRUE;
1690 }
1691 else
1692 {
1693 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1694 "Monitor spec incomplete");
1695 return FALSE;
1696 }
1697 }
1698
1699 gboolean
meta_verify_monitor_config(MetaMonitorConfig * monitor_config,GError ** error)1700 meta_verify_monitor_config (MetaMonitorConfig *monitor_config,
1701 GError **error)
1702 {
1703 if (monitor_config->monitor_spec && monitor_config->mode_spec)
1704 {
1705 return TRUE;
1706 }
1707 else
1708 {
1709 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1710 "Monitor config incomplete");
1711 return FALSE;
1712 }
1713 }
1714
1715 gboolean
meta_verify_logical_monitor_config(MetaLogicalMonitorConfig * logical_monitor_config,MetaLogicalMonitorLayoutMode layout_mode,MetaMonitorManager * monitor_manager,GError ** error)1716 meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config,
1717 MetaLogicalMonitorLayoutMode layout_mode,
1718 MetaMonitorManager *monitor_manager,
1719 GError **error)
1720 {
1721 GList *l;
1722 int expected_mode_width = 0;
1723 int expected_mode_height = 0;
1724
1725 if (logical_monitor_config->layout.x < 0 ||
1726 logical_monitor_config->layout.y < 0)
1727 {
1728 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1729 "Invalid logical monitor position (%d, %d)",
1730 logical_monitor_config->layout.x,
1731 logical_monitor_config->layout.y);
1732 return FALSE;
1733 }
1734
1735 if (!logical_monitor_config->monitor_configs)
1736 {
1737 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1738 "Logical monitor is empty");
1739 return FALSE;
1740 }
1741
1742 if (meta_monitor_transform_is_rotated (logical_monitor_config->transform))
1743 {
1744 expected_mode_width = logical_monitor_config->layout.height;
1745 expected_mode_height = logical_monitor_config->layout.width;
1746 }
1747 else
1748 {
1749 expected_mode_width = logical_monitor_config->layout.width;
1750 expected_mode_height = logical_monitor_config->layout.height;
1751 }
1752
1753 switch (layout_mode)
1754 {
1755 case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
1756 expected_mode_width = roundf (expected_mode_width *
1757 logical_monitor_config->scale);
1758 expected_mode_height = roundf (expected_mode_height *
1759 logical_monitor_config->scale);
1760 break;
1761 case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
1762 break;
1763 }
1764
1765 for (l = logical_monitor_config->monitor_configs; l; l = l->next)
1766 {
1767 MetaMonitorConfig *monitor_config = l->data;
1768
1769 if (monitor_config->mode_spec->width != expected_mode_width ||
1770 monitor_config->mode_spec->height != expected_mode_height)
1771 {
1772 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1773 "Monitor modes in logical monitor conflict");
1774 return FALSE;
1775 }
1776 }
1777
1778 return TRUE;
1779 }
1780
1781 static gboolean
has_adjacent_neighbour(MetaMonitorsConfig * config,MetaLogicalMonitorConfig * logical_monitor_config)1782 has_adjacent_neighbour (MetaMonitorsConfig *config,
1783 MetaLogicalMonitorConfig *logical_monitor_config)
1784 {
1785 GList *l;
1786
1787 if (!config->logical_monitor_configs->next)
1788 {
1789 g_assert (config->logical_monitor_configs->data ==
1790 logical_monitor_config);
1791 return TRUE;
1792 }
1793
1794 for (l = config->logical_monitor_configs; l; l = l->next)
1795 {
1796 MetaLogicalMonitorConfig *other_logical_monitor_config = l->data;
1797
1798 if (logical_monitor_config == other_logical_monitor_config)
1799 continue;
1800
1801 if (meta_rectangle_is_adjacent_to (&logical_monitor_config->layout,
1802 &other_logical_monitor_config->layout))
1803 return TRUE;
1804 }
1805
1806 return FALSE;
1807 }
1808
1809 gboolean
meta_logical_monitor_configs_have_monitor(GList * logical_monitor_configs,MetaMonitorSpec * monitor_spec)1810 meta_logical_monitor_configs_have_monitor (GList *logical_monitor_configs,
1811 MetaMonitorSpec *monitor_spec)
1812 {
1813 GList *l;
1814
1815 for (l = logical_monitor_configs; l; l = l->next)
1816 {
1817 MetaLogicalMonitorConfig *logical_monitor_config = l->data;
1818 GList *k;
1819
1820 for (k = logical_monitor_config->monitor_configs; k; k = k->next)
1821 {
1822 MetaMonitorConfig *monitor_config = k->data;
1823
1824 if (meta_monitor_spec_equals (monitor_spec,
1825 monitor_config->monitor_spec))
1826 return TRUE;
1827 }
1828 }
1829
1830 return FALSE;
1831 }
1832
1833 static gboolean
meta_monitors_config_is_monitor_enabled(MetaMonitorsConfig * config,MetaMonitorSpec * monitor_spec)1834 meta_monitors_config_is_monitor_enabled (MetaMonitorsConfig *config,
1835 MetaMonitorSpec *monitor_spec)
1836 {
1837 return meta_logical_monitor_configs_have_monitor (config->logical_monitor_configs,
1838 monitor_spec);
1839 }
1840
1841 gboolean
meta_verify_monitors_config(MetaMonitorsConfig * config,MetaMonitorManager * monitor_manager,GError ** error)1842 meta_verify_monitors_config (MetaMonitorsConfig *config,
1843 MetaMonitorManager *monitor_manager,
1844 GError **error)
1845 {
1846 int min_x, min_y;
1847 gboolean has_primary;
1848 GList *region;
1849 GList *l;
1850 gboolean global_scale_required;
1851
1852 if (!config->logical_monitor_configs)
1853 {
1854 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1855 "Monitors config incomplete");
1856 return FALSE;
1857 }
1858
1859 global_scale_required =
1860 !!(meta_monitor_manager_get_capabilities (monitor_manager) &
1861 META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
1862
1863 min_x = INT_MAX;
1864 min_y = INT_MAX;
1865 region = NULL;
1866 has_primary = FALSE;
1867 for (l = config->logical_monitor_configs; l; l = l->next)
1868 {
1869 MetaLogicalMonitorConfig *logical_monitor_config = l->data;
1870
1871 if (global_scale_required)
1872 {
1873 MetaLogicalMonitorConfig *prev_logical_monitor_config =
1874 l->prev ? l->prev->data : NULL;
1875
1876 if (prev_logical_monitor_config &&
1877 (prev_logical_monitor_config->scale !=
1878 logical_monitor_config->scale))
1879 {
1880 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1881 "Logical monitor scales must be identical");
1882 return FALSE;
1883 }
1884 }
1885
1886 if (meta_rectangle_overlaps_with_region (region,
1887 &logical_monitor_config->layout))
1888 {
1889 g_list_free (region);
1890 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1891 "Logical monitors overlap");
1892 return FALSE;
1893 }
1894
1895 if (has_primary && logical_monitor_config->is_primary)
1896 {
1897 g_list_free (region);
1898 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1899 "Config contains multiple primary logical monitors");
1900 return FALSE;
1901 }
1902 else if (logical_monitor_config->is_primary)
1903 {
1904 has_primary = TRUE;
1905 }
1906
1907 if (!has_adjacent_neighbour (config, logical_monitor_config))
1908 {
1909 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1910 "Logical monitors not adjacent");
1911 return FALSE;
1912 }
1913
1914 min_x = MIN (logical_monitor_config->layout.x, min_x);
1915 min_y = MIN (logical_monitor_config->layout.y, min_y);
1916
1917 region = g_list_prepend (region, &logical_monitor_config->layout);
1918 }
1919
1920 g_list_free (region);
1921
1922 for (l = config->disabled_monitor_specs; l; l = l->next)
1923 {
1924 MetaMonitorSpec *monitor_spec = l->data;
1925
1926 if (meta_monitors_config_is_monitor_enabled (config, monitor_spec))
1927 {
1928 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1929 "Assigned monitor explicitly disabled");
1930 return FALSE;
1931 }
1932 }
1933
1934 if (min_x != 0 || min_y != 0)
1935 {
1936 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1937 "Logical monitors positions are offset");
1938 return FALSE;
1939 }
1940
1941 if (!has_primary)
1942 {
1943 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1944 "Config is missing primary logical");
1945 return FALSE;
1946 }
1947
1948 return TRUE;
1949 }
1950