1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /*
4 * Copyright (C) 2016 Red Hat
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 #include "config.h"
23
24 #include "backends/meta-monitor.h"
25
26 #include "backends/meta-backend-private.h"
27 #include "backends/meta-crtc.h"
28 #include "backends/meta-gpu.h"
29 #include "backends/meta-monitor-manager-private.h"
30 #include "backends/meta-settings-private.h"
31 #include "backends/meta-output.h"
32 #include "core/boxes-private.h"
33
34 #define SCALE_FACTORS_PER_INTEGER 4
35 #define SCALE_FACTORS_STEPS (1.0 / (float) SCALE_FACTORS_PER_INTEGER)
36 #define MINIMUM_SCALE_FACTOR 1.0f
37 #define MAXIMUM_SCALE_FACTOR 4.0f
38 #define MINIMUM_LOGICAL_AREA (800 * 480)
39 #define MAXIMUM_REFRESH_RATE_DIFF 0.001
40
41 typedef struct _MetaMonitorMode
42 {
43 MetaMonitor *monitor;
44 char *id;
45 MetaMonitorModeSpec spec;
46 MetaMonitorCrtcMode *crtc_modes;
47 } MetaMonitorMode;
48
49 typedef struct _MetaMonitorModeTiled
50 {
51 MetaMonitorMode parent;
52
53 gboolean is_tiled;
54 } MetaMonitorModeTiled;
55
56 typedef struct _MetaMonitorPrivate
57 {
58 MetaBackend *backend;
59
60 GList *outputs;
61 GList *modes;
62 GHashTable *mode_ids;
63
64 MetaMonitorMode *preferred_mode;
65 MetaMonitorMode *current_mode;
66
67 MetaMonitorSpec *spec;
68
69 MetaLogicalMonitor *logical_monitor;
70
71 /*
72 * The primary or first output for this monitor, 0 if we can't figure out.
73 * It can be matched to a winsys_id of a MetaOutput.
74 *
75 * This is used as an opaque token on reconfiguration when switching from
76 * clone to extended, to decide on what output the windows should go next
77 * (it's an attempt to keep windows on the same monitor, and preferably on
78 * the primary one).
79 */
80 uint64_t winsys_id;
81
82 char *display_name;
83 } MetaMonitorPrivate;
84
85 G_DEFINE_TYPE_WITH_PRIVATE (MetaMonitor, meta_monitor, G_TYPE_OBJECT)
86
87 struct _MetaMonitorNormal
88 {
89 MetaMonitor parent;
90 };
91
92 G_DEFINE_TYPE (MetaMonitorNormal, meta_monitor_normal, META_TYPE_MONITOR)
93
94 struct _MetaMonitorTiled
95 {
96 MetaMonitor parent;
97
98 MetaMonitorManager *monitor_manager;
99
100 uint32_t tile_group_id;
101
102 /* The tile (0, 0) output. */
103 MetaOutput *origin_output;
104
105 /* The output enabled even when a non-tiled mode is used. */
106 MetaOutput *main_output;
107 };
108
109 G_DEFINE_TYPE (MetaMonitorTiled, meta_monitor_tiled, META_TYPE_MONITOR)
110
111 static void
112 meta_monitor_mode_free (MetaMonitorMode *mode);
113
114 MetaMonitorSpec *
meta_monitor_spec_clone(MetaMonitorSpec * monitor_spec)115 meta_monitor_spec_clone (MetaMonitorSpec *monitor_spec)
116 {
117 MetaMonitorSpec *new_monitor_spec;
118
119 new_monitor_spec = g_new0 (MetaMonitorSpec, 1);
120 *new_monitor_spec = (MetaMonitorSpec) {
121 .connector = g_strdup (monitor_spec->connector),
122 .vendor = g_strdup (monitor_spec->vendor),
123 .product = g_strdup (monitor_spec->product),
124 .serial = g_strdup (monitor_spec->serial),
125 };
126
127 return new_monitor_spec;
128 }
129
130 guint
meta_monitor_spec_hash(gconstpointer key)131 meta_monitor_spec_hash (gconstpointer key)
132 {
133 const MetaMonitorSpec *monitor_spec = key;
134
135 return (g_str_hash (monitor_spec->connector) +
136 g_str_hash (monitor_spec->vendor) +
137 g_str_hash (monitor_spec->product) +
138 g_str_hash (monitor_spec->serial));
139 }
140
141 gboolean
meta_monitor_spec_equals(MetaMonitorSpec * monitor_spec,MetaMonitorSpec * other_monitor_spec)142 meta_monitor_spec_equals (MetaMonitorSpec *monitor_spec,
143 MetaMonitorSpec *other_monitor_spec)
144 {
145 return (g_str_equal (monitor_spec->connector, other_monitor_spec->connector) &&
146 g_str_equal (monitor_spec->vendor, other_monitor_spec->vendor) &&
147 g_str_equal (monitor_spec->product, other_monitor_spec->product) &&
148 g_str_equal (monitor_spec->serial, other_monitor_spec->serial));
149 }
150
151 int
meta_monitor_spec_compare(MetaMonitorSpec * monitor_spec_a,MetaMonitorSpec * monitor_spec_b)152 meta_monitor_spec_compare (MetaMonitorSpec *monitor_spec_a,
153 MetaMonitorSpec *monitor_spec_b)
154 {
155 int ret;
156
157 ret = strcmp (monitor_spec_a->connector, monitor_spec_b->connector);
158 if (ret != 0)
159 return ret;
160
161 ret = strcmp (monitor_spec_a->vendor, monitor_spec_b->vendor);
162 if (ret != 0)
163 return ret;
164
165 ret = strcmp (monitor_spec_a->product, monitor_spec_b->product);
166 if (ret != 0)
167 return ret;
168
169 return strcmp (monitor_spec_a->serial, monitor_spec_b->serial);
170 }
171
172 void
meta_monitor_spec_free(MetaMonitorSpec * monitor_spec)173 meta_monitor_spec_free (MetaMonitorSpec *monitor_spec)
174 {
175 g_free (monitor_spec->connector);
176 g_free (monitor_spec->vendor);
177 g_free (monitor_spec->product);
178 g_free (monitor_spec->serial);
179 g_free (monitor_spec);
180 }
181
182 static const MetaOutputInfo *
meta_monitor_get_main_output_info(MetaMonitor * monitor)183 meta_monitor_get_main_output_info (MetaMonitor *monitor)
184 {
185 MetaOutput *output = meta_monitor_get_main_output (monitor);
186
187 return meta_output_get_info (output);
188 }
189
190 static void
meta_monitor_generate_spec(MetaMonitor * monitor)191 meta_monitor_generate_spec (MetaMonitor *monitor)
192 {
193 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
194 const MetaOutputInfo *output_info =
195 meta_monitor_get_main_output_info (monitor);
196 MetaMonitorSpec *monitor_spec;
197
198 monitor_spec = g_new0 (MetaMonitorSpec, 1);
199 *monitor_spec = (MetaMonitorSpec) {
200 .connector = g_strdup (output_info->name),
201 .vendor = g_strdup (output_info->vendor),
202 .product = g_strdup (output_info->product),
203 .serial = g_strdup (output_info->serial),
204 };
205
206 priv->spec = monitor_spec;
207 }
208
209 static const double known_diagonals[] = {
210 12.1,
211 13.3,
212 15.6
213 };
214
215 static char *
diagonal_to_str(double d)216 diagonal_to_str (double d)
217 {
218 unsigned int i;
219
220 for (i = 0; i < G_N_ELEMENTS (known_diagonals); i++)
221 {
222 double delta;
223
224 delta = fabs(known_diagonals[i] - d);
225 if (delta < 0.1)
226 return g_strdup_printf ("%0.1lf\"", known_diagonals[i]);
227 }
228
229 return g_strdup_printf ("%d\"", (int) (d + 0.5));
230 }
231
232 static char *
meta_monitor_make_display_name(MetaMonitor * monitor,MetaMonitorManager * monitor_manager)233 meta_monitor_make_display_name (MetaMonitor *monitor,
234 MetaMonitorManager *monitor_manager)
235 {
236 g_autofree char *inches = NULL;
237 g_autofree char *vendor_name = NULL;
238 const char *vendor = NULL;
239 const char *product_name = NULL;
240 int width_mm;
241 int height_mm;
242
243 meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm);
244
245 if (meta_monitor_is_laptop_panel (monitor))
246 return g_strdup (_("Built-in display"));
247
248 if (width_mm > 0 && height_mm > 0)
249 {
250 if (!meta_monitor_has_aspect_as_size (monitor))
251 {
252 double d = sqrt (width_mm * width_mm +
253 height_mm * height_mm);
254 inches = diagonal_to_str (d / 25.4);
255 }
256 else
257 {
258 product_name = meta_monitor_get_product (monitor);
259 }
260 }
261
262 vendor = meta_monitor_get_vendor (monitor);
263
264 if (g_strcmp0 (vendor, "unknown") != 0)
265 {
266 vendor_name = meta_monitor_manager_get_vendor_name (monitor_manager,
267 vendor);
268
269 if (!vendor_name)
270 vendor_name = g_strdup (vendor);
271 }
272 else
273 {
274 if (inches != NULL)
275 vendor_name = g_strdup (_("Unknown"));
276 else
277 vendor_name = g_strdup (_("Unknown Display"));
278 }
279
280 if (inches != NULL)
281 {
282 /**/
283 return g_strdup_printf (C_("This is a monitor vendor name, followed by a "
284 "size in inches, like 'Dell 15\"'",
285 "%s %s"),
286 vendor_name, inches);
287 }
288 else if (product_name != NULL)
289 {
290 return g_strdup_printf (C_("This is a monitor vendor name followed by "
291 "product/model name where size in inches "
292 "could not be calculated, e.g. Dell U2414H",
293 "%s %s"),
294 vendor_name, product_name);
295 }
296 else
297 {
298 return g_strdup (vendor_name);
299 }
300 }
301
302 MetaBackend *
meta_monitor_get_backend(MetaMonitor * monitor)303 meta_monitor_get_backend (MetaMonitor *monitor)
304 {
305 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
306
307 return priv->backend;
308 }
309
310 GList *
meta_monitor_get_outputs(MetaMonitor * monitor)311 meta_monitor_get_outputs (MetaMonitor *monitor)
312 {
313 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
314
315 return priv->outputs;
316 }
317
318 MetaOutput *
meta_monitor_get_main_output(MetaMonitor * monitor)319 meta_monitor_get_main_output (MetaMonitor *monitor)
320 {
321 return META_MONITOR_GET_CLASS (monitor)->get_main_output (monitor);
322 }
323
324 gboolean
meta_monitor_is_active(MetaMonitor * monitor)325 meta_monitor_is_active (MetaMonitor *monitor)
326 {
327 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
328
329 return !!priv->current_mode;
330 }
331
332 gboolean
meta_monitor_is_primary(MetaMonitor * monitor)333 meta_monitor_is_primary (MetaMonitor *monitor)
334 {
335 MetaOutput *output;
336
337 output = meta_monitor_get_main_output (monitor);
338
339 return meta_output_is_primary (output);
340 }
341
342 gboolean
meta_monitor_supports_underscanning(MetaMonitor * monitor)343 meta_monitor_supports_underscanning (MetaMonitor *monitor)
344 {
345 const MetaOutputInfo *output_info =
346 meta_monitor_get_main_output_info (monitor);
347
348 return output_info->supports_underscanning;
349 }
350
351 gboolean
meta_monitor_is_underscanning(MetaMonitor * monitor)352 meta_monitor_is_underscanning (MetaMonitor *monitor)
353 {
354 MetaOutput *output;
355
356 output = meta_monitor_get_main_output (monitor);
357
358 return meta_output_is_underscanning (output);
359 }
360
361 gboolean
meta_monitor_is_laptop_panel(MetaMonitor * monitor)362 meta_monitor_is_laptop_panel (MetaMonitor *monitor)
363 {
364 const MetaOutputInfo *output_info =
365 meta_monitor_get_main_output_info (monitor);
366
367 switch (output_info->connector_type)
368 {
369 case META_CONNECTOR_TYPE_eDP:
370 case META_CONNECTOR_TYPE_LVDS:
371 case META_CONNECTOR_TYPE_DSI:
372 return TRUE;
373 default:
374 return FALSE;
375 }
376 }
377
378 gboolean
meta_monitor_is_same_as(MetaMonitor * monitor,MetaMonitor * other_monitor)379 meta_monitor_is_same_as (MetaMonitor *monitor,
380 MetaMonitor *other_monitor)
381 {
382 MetaMonitorPrivate *priv =
383 meta_monitor_get_instance_private (monitor);
384 MetaMonitorPrivate *other_priv =
385 meta_monitor_get_instance_private (other_monitor);
386
387 return priv->winsys_id == other_priv->winsys_id;
388 }
389
390 void
meta_monitor_get_current_resolution(MetaMonitor * monitor,int * width,int * height)391 meta_monitor_get_current_resolution (MetaMonitor *monitor,
392 int *width,
393 int *height)
394 {
395 MetaMonitorMode *mode = meta_monitor_get_current_mode (monitor);
396
397 *width = mode->spec.width;
398 *height = mode->spec.height;
399 }
400
401 void
meta_monitor_derive_layout(MetaMonitor * monitor,MetaRectangle * layout)402 meta_monitor_derive_layout (MetaMonitor *monitor,
403 MetaRectangle *layout)
404 {
405 META_MONITOR_GET_CLASS (monitor)->derive_layout (monitor, layout);
406 }
407
408 void
meta_monitor_get_physical_dimensions(MetaMonitor * monitor,int * width_mm,int * height_mm)409 meta_monitor_get_physical_dimensions (MetaMonitor *monitor,
410 int *width_mm,
411 int *height_mm)
412 {
413 const MetaOutputInfo *output_info =
414 meta_monitor_get_main_output_info (monitor);
415
416 *width_mm = output_info->width_mm;
417 *height_mm = output_info->height_mm;
418 }
419
420 CoglSubpixelOrder
meta_monitor_get_subpixel_order(MetaMonitor * monitor)421 meta_monitor_get_subpixel_order (MetaMonitor *monitor)
422 {
423 const MetaOutputInfo *output_info =
424 meta_monitor_get_main_output_info (monitor);
425
426 return output_info->subpixel_order;
427 }
428
429 const char *
meta_monitor_get_connector(MetaMonitor * monitor)430 meta_monitor_get_connector (MetaMonitor *monitor)
431 {
432 const MetaOutputInfo *output_info =
433 meta_monitor_get_main_output_info (monitor);
434
435 return output_info->name;
436 }
437
438 const char *
meta_monitor_get_vendor(MetaMonitor * monitor)439 meta_monitor_get_vendor (MetaMonitor *monitor)
440 {
441 const MetaOutputInfo *output_info =
442 meta_monitor_get_main_output_info (monitor);
443
444 return output_info->vendor;
445 }
446
447 const char *
meta_monitor_get_product(MetaMonitor * monitor)448 meta_monitor_get_product (MetaMonitor *monitor)
449 {
450 const MetaOutputInfo *output_info =
451 meta_monitor_get_main_output_info (monitor);
452
453 return output_info->product;
454 }
455
456 const char *
meta_monitor_get_serial(MetaMonitor * monitor)457 meta_monitor_get_serial (MetaMonitor *monitor)
458 {
459 const MetaOutputInfo *output_info =
460 meta_monitor_get_main_output_info (monitor);
461
462 return output_info->serial;
463 }
464
465 MetaConnectorType
meta_monitor_get_connector_type(MetaMonitor * monitor)466 meta_monitor_get_connector_type (MetaMonitor *monitor)
467 {
468 const MetaOutputInfo *output_info =
469 meta_monitor_get_main_output_info (monitor);
470
471 return output_info->connector_type;
472 }
473
474 MetaMonitorTransform
meta_monitor_logical_to_crtc_transform(MetaMonitor * monitor,MetaMonitorTransform transform)475 meta_monitor_logical_to_crtc_transform (MetaMonitor *monitor,
476 MetaMonitorTransform transform)
477 {
478 MetaOutput *output = meta_monitor_get_main_output (monitor);
479
480 return meta_output_logical_to_crtc_transform (output, transform);
481 }
482
483 MetaMonitorTransform
meta_monitor_crtc_to_logical_transform(MetaMonitor * monitor,MetaMonitorTransform transform)484 meta_monitor_crtc_to_logical_transform (MetaMonitor *monitor,
485 MetaMonitorTransform transform)
486 {
487 MetaOutput *output = meta_monitor_get_main_output (monitor);
488
489 return meta_output_crtc_to_logical_transform (output, transform);
490 }
491
492 static void
meta_monitor_dispose(GObject * object)493 meta_monitor_dispose (GObject *object)
494 {
495 MetaMonitor *monitor = META_MONITOR (object);
496 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
497
498 if (priv->outputs)
499 {
500 g_list_foreach (priv->outputs, (GFunc) meta_output_unset_monitor, NULL);
501 g_list_free_full (priv->outputs, g_object_unref);
502 priv->outputs = NULL;
503 }
504
505 G_OBJECT_CLASS (meta_monitor_parent_class)->dispose (object);
506 }
507
508 static void
meta_monitor_finalize(GObject * object)509 meta_monitor_finalize (GObject *object)
510 {
511 MetaMonitor *monitor = META_MONITOR (object);
512 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
513
514 g_hash_table_destroy (priv->mode_ids);
515 g_list_free_full (priv->modes, (GDestroyNotify) meta_monitor_mode_free);
516 meta_monitor_spec_free (priv->spec);
517 g_free (priv->display_name);
518
519 G_OBJECT_CLASS (meta_monitor_parent_class)->finalize (object);
520 }
521
522 static void
meta_monitor_init(MetaMonitor * monitor)523 meta_monitor_init (MetaMonitor *monitor)
524 {
525 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
526
527 priv->mode_ids = g_hash_table_new (g_str_hash, g_str_equal);
528 }
529
530 static void
meta_monitor_class_init(MetaMonitorClass * klass)531 meta_monitor_class_init (MetaMonitorClass *klass)
532 {
533 GObjectClass *object_class = G_OBJECT_CLASS (klass);
534
535 object_class->dispose = meta_monitor_dispose;
536 object_class->finalize = meta_monitor_finalize;
537 }
538
539 static char *
generate_mode_id(MetaMonitorModeSpec * monitor_mode_spec)540 generate_mode_id (MetaMonitorModeSpec *monitor_mode_spec)
541 {
542 gboolean is_interlaced;
543 char refresh_rate_str[G_ASCII_DTOSTR_BUF_SIZE];
544
545 is_interlaced = !!(monitor_mode_spec->flags & META_CRTC_MODE_FLAG_INTERLACE);
546 g_ascii_dtostr (refresh_rate_str, G_ASCII_DTOSTR_BUF_SIZE,
547 monitor_mode_spec->refresh_rate);
548
549 return g_strdup_printf ("%dx%d%s@%s",
550 monitor_mode_spec->width,
551 monitor_mode_spec->height,
552 is_interlaced ? "i" : "",
553 refresh_rate_str);
554 }
555
556 static gboolean
meta_monitor_add_mode(MetaMonitor * monitor,MetaMonitorMode * monitor_mode,gboolean replace)557 meta_monitor_add_mode (MetaMonitor *monitor,
558 MetaMonitorMode *monitor_mode,
559 gboolean replace)
560 {
561 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
562 MetaMonitorMode *existing_mode;
563
564 existing_mode = g_hash_table_lookup (priv->mode_ids,
565 meta_monitor_mode_get_id (monitor_mode));
566 if (existing_mode && !replace)
567 return FALSE;
568
569 if (existing_mode)
570 priv->modes = g_list_remove (priv->modes, existing_mode);
571
572 priv->modes = g_list_append (priv->modes, monitor_mode);
573 g_hash_table_replace (priv->mode_ids, monitor_mode->id, monitor_mode);
574
575 return TRUE;
576 }
577
578 static MetaMonitorModeSpec
meta_monitor_create_spec(MetaMonitor * monitor,int width,int height,MetaCrtcMode * crtc_mode)579 meta_monitor_create_spec (MetaMonitor *monitor,
580 int width,
581 int height,
582 MetaCrtcMode *crtc_mode)
583 {
584 const MetaOutputInfo *output_info =
585 meta_monitor_get_main_output_info (monitor);
586 const MetaCrtcModeInfo *crtc_mode_info =
587 meta_crtc_mode_get_info (crtc_mode);
588
589 if (meta_monitor_transform_is_rotated (output_info->panel_orientation_transform))
590 {
591 int temp = width;
592 width = height;
593 height = temp;
594 }
595
596 return (MetaMonitorModeSpec) {
597 .width = width,
598 .height = height,
599 .refresh_rate = crtc_mode_info->refresh_rate,
600 .flags = crtc_mode_info->flags & HANDLED_CRTC_MODE_FLAGS
601 };
602 }
603
604 static void
meta_monitor_normal_generate_modes(MetaMonitorNormal * monitor_normal)605 meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal)
606 {
607 MetaMonitor *monitor = META_MONITOR (monitor_normal);
608 MetaMonitorPrivate *monitor_priv =
609 meta_monitor_get_instance_private (monitor);
610 MetaOutput *output;
611 const MetaOutputInfo *output_info;
612 MetaCrtcMode *preferred_mode;
613 MetaCrtcModeFlag preferred_mode_flags;
614 unsigned int i;
615
616 output = meta_monitor_get_main_output (monitor);
617 output_info = meta_output_get_info (output);
618 preferred_mode = output_info->preferred_mode;
619 preferred_mode_flags = meta_crtc_mode_get_info (preferred_mode)->flags;
620
621 for (i = 0; i < output_info->n_modes; i++)
622 {
623 MetaCrtcMode *crtc_mode = output_info->modes[i];
624 const MetaCrtcModeInfo *crtc_mode_info =
625 meta_crtc_mode_get_info (crtc_mode);
626 MetaCrtc *crtc;
627 MetaMonitorMode *mode;
628 gboolean replace;
629
630 mode = g_new0 (MetaMonitorMode, 1);
631 mode->monitor = monitor;
632 mode->spec = meta_monitor_create_spec (monitor,
633 crtc_mode_info->width,
634 crtc_mode_info->height,
635 crtc_mode);
636 mode->id = generate_mode_id (&mode->spec);
637 mode->crtc_modes = g_new (MetaMonitorCrtcMode, 1);
638 mode->crtc_modes[0] = (MetaMonitorCrtcMode) {
639 .output = output,
640 .crtc_mode = crtc_mode
641 };
642
643 /*
644 * We don't distinguish between all available mode flags, just the ones
645 * that are configurable. We still need to pick some mode though, so
646 * prefer ones that has the same set of flags as the preferred mode;
647 * otherwise take the first one in the list. This guarantees that the
648 * preferred mode is always added.
649 */
650 replace = crtc_mode_info->flags == preferred_mode_flags;
651
652 if (!meta_monitor_add_mode (monitor, mode, replace))
653 {
654 g_assert (crtc_mode != output_info->preferred_mode);
655 meta_monitor_mode_free (mode);
656 continue;
657 }
658
659 if (crtc_mode == output_info->preferred_mode)
660 monitor_priv->preferred_mode = mode;
661
662 crtc = meta_output_get_assigned_crtc (output);
663 if (crtc)
664 {
665 const MetaCrtcConfig *crtc_config;
666
667 crtc_config = meta_crtc_get_config (crtc);
668 if (crtc_config && crtc_mode == crtc_config->mode)
669 monitor_priv->current_mode = mode;
670 }
671 }
672 }
673
674 MetaMonitorNormal *
meta_monitor_normal_new(MetaMonitorManager * monitor_manager,MetaOutput * output)675 meta_monitor_normal_new (MetaMonitorManager *monitor_manager,
676 MetaOutput *output)
677 {
678 MetaMonitorNormal *monitor_normal;
679 MetaMonitor *monitor;
680 MetaMonitorPrivate *monitor_priv;
681
682 monitor_normal = g_object_new (META_TYPE_MONITOR_NORMAL, NULL);
683 monitor = META_MONITOR (monitor_normal);
684 monitor_priv = meta_monitor_get_instance_private (monitor);
685
686 monitor_priv->backend = meta_monitor_manager_get_backend (monitor_manager);
687
688 monitor_priv->outputs = g_list_append (NULL, g_object_ref (output));
689 meta_output_set_monitor (output, monitor);
690
691 monitor_priv->winsys_id = meta_output_get_id (output);
692 meta_monitor_generate_spec (monitor);
693
694 meta_monitor_normal_generate_modes (monitor_normal);
695
696 monitor_priv->display_name = meta_monitor_make_display_name (monitor,
697 monitor_manager);
698
699 return monitor_normal;
700 }
701
702 static MetaOutput *
meta_monitor_normal_get_main_output(MetaMonitor * monitor)703 meta_monitor_normal_get_main_output (MetaMonitor *monitor)
704 {
705 MetaMonitorPrivate *monitor_priv =
706 meta_monitor_get_instance_private (monitor);
707
708 return monitor_priv->outputs->data;
709 }
710
711 static void
meta_monitor_normal_derive_layout(MetaMonitor * monitor,MetaRectangle * layout)712 meta_monitor_normal_derive_layout (MetaMonitor *monitor,
713 MetaRectangle *layout)
714 {
715 MetaOutput *output;
716 MetaCrtc *crtc;
717 const MetaCrtcConfig *crtc_config;
718
719 output = meta_monitor_get_main_output (monitor);
720 crtc = meta_output_get_assigned_crtc (output);
721 crtc_config = meta_crtc_get_config (crtc);
722
723 g_return_if_fail (crtc_config);
724
725 meta_rectangle_from_graphene_rect (&crtc_config->layout,
726 META_ROUNDING_STRATEGY_ROUND,
727 layout);
728 }
729
730 static gboolean
meta_monitor_normal_get_suggested_position(MetaMonitor * monitor,int * x,int * y)731 meta_monitor_normal_get_suggested_position (MetaMonitor *monitor,
732 int *x,
733 int *y)
734 {
735 const MetaOutputInfo *output_info =
736 meta_monitor_get_main_output_info (monitor);
737
738 if (!output_info->hotplug_mode_update)
739 return FALSE;
740
741 if (output_info->suggested_x < 0 && output_info->suggested_y < 0)
742 return FALSE;
743
744 if (x)
745 *x = output_info->suggested_x;
746
747 if (y)
748 *y = output_info->suggested_y;
749
750 return TRUE;
751 }
752
753 static void
meta_monitor_normal_calculate_crtc_pos(MetaMonitor * monitor,MetaMonitorMode * monitor_mode,MetaOutput * output,MetaMonitorTransform crtc_transform,int * out_x,int * out_y)754 meta_monitor_normal_calculate_crtc_pos (MetaMonitor *monitor,
755 MetaMonitorMode *monitor_mode,
756 MetaOutput *output,
757 MetaMonitorTransform crtc_transform,
758 int *out_x,
759 int *out_y)
760 {
761 *out_x = 0;
762 *out_y = 0;
763 }
764
765 static void
meta_monitor_normal_init(MetaMonitorNormal * monitor)766 meta_monitor_normal_init (MetaMonitorNormal *monitor)
767 {
768 }
769
770 static void
meta_monitor_normal_class_init(MetaMonitorNormalClass * klass)771 meta_monitor_normal_class_init (MetaMonitorNormalClass *klass)
772 {
773 MetaMonitorClass *monitor_class = META_MONITOR_CLASS (klass);
774
775 monitor_class->get_main_output = meta_monitor_normal_get_main_output;
776 monitor_class->derive_layout = meta_monitor_normal_derive_layout;
777 monitor_class->calculate_crtc_pos = meta_monitor_normal_calculate_crtc_pos;
778 monitor_class->get_suggested_position = meta_monitor_normal_get_suggested_position;
779 }
780
781 uint32_t
meta_monitor_tiled_get_tile_group_id(MetaMonitorTiled * monitor_tiled)782 meta_monitor_tiled_get_tile_group_id (MetaMonitorTiled *monitor_tiled)
783 {
784 return monitor_tiled->tile_group_id;
785 }
786
787 gboolean
meta_monitor_get_suggested_position(MetaMonitor * monitor,int * x,int * y)788 meta_monitor_get_suggested_position (MetaMonitor *monitor,
789 int *x,
790 int *y)
791 {
792 return META_MONITOR_GET_CLASS (monitor)->get_suggested_position (monitor,
793 x, y);
794 }
795
796 static void
add_tiled_monitor_outputs(MetaGpu * gpu,MetaMonitorTiled * monitor_tiled)797 add_tiled_monitor_outputs (MetaGpu *gpu,
798 MetaMonitorTiled *monitor_tiled)
799 {
800 MetaMonitorPrivate *monitor_priv =
801 meta_monitor_get_instance_private (META_MONITOR (monitor_tiled));
802 GList *outputs;
803 GList *l;
804
805 outputs = meta_gpu_get_outputs (gpu);
806 for (l = outputs; l; l = l->next)
807 {
808 MetaOutput *output = l->data;
809 const MetaOutputInfo *output_info = meta_output_get_info (output);
810 const MetaOutputInfo *origin_output_info;
811
812 if (output_info->tile_info.group_id != monitor_tiled->tile_group_id)
813 continue;
814
815 origin_output_info = meta_output_get_info (monitor_tiled->origin_output);
816 g_warn_if_fail (output_info->subpixel_order ==
817 origin_output_info->subpixel_order);
818
819 monitor_priv->outputs = g_list_append (monitor_priv->outputs,
820 g_object_ref (output));
821
822 meta_output_set_monitor (output, META_MONITOR (monitor_tiled));
823 }
824 }
825
826 static void
calculate_tile_coordinate(MetaMonitor * monitor,MetaOutput * output,MetaMonitorTransform crtc_transform,int * out_x,int * out_y)827 calculate_tile_coordinate (MetaMonitor *monitor,
828 MetaOutput *output,
829 MetaMonitorTransform crtc_transform,
830 int *out_x,
831 int *out_y)
832 {
833 MetaMonitorPrivate *monitor_priv =
834 meta_monitor_get_instance_private (monitor);
835 const MetaOutputInfo *output_info = meta_output_get_info (output);
836 GList *l;
837 int x = 0;
838 int y = 0;
839
840 for (l = monitor_priv->outputs; l; l = l->next)
841 {
842 const MetaOutputInfo *other_output_info = meta_output_get_info (l->data);
843
844 switch (crtc_transform)
845 {
846 case META_MONITOR_TRANSFORM_NORMAL:
847 case META_MONITOR_TRANSFORM_FLIPPED:
848 if ((other_output_info->tile_info.loc_v_tile ==
849 output_info->tile_info.loc_v_tile) &&
850 (other_output_info->tile_info.loc_h_tile <
851 output_info->tile_info.loc_h_tile))
852 x += other_output_info->tile_info.tile_w;
853 if ((other_output_info->tile_info.loc_h_tile ==
854 output_info->tile_info.loc_h_tile) &&
855 (other_output_info->tile_info.loc_v_tile <
856 output_info->tile_info.loc_v_tile))
857 y += other_output_info->tile_info.tile_h;
858 break;
859 case META_MONITOR_TRANSFORM_180:
860 case META_MONITOR_TRANSFORM_FLIPPED_180:
861 if ((other_output_info->tile_info.loc_v_tile ==
862 output_info->tile_info.loc_v_tile) &&
863 (other_output_info->tile_info.loc_h_tile >
864 output_info->tile_info.loc_h_tile))
865 x += other_output_info->tile_info.tile_w;
866 if ((other_output_info->tile_info.loc_h_tile ==
867 output_info->tile_info.loc_h_tile) &&
868 (other_output_info->tile_info.loc_v_tile >
869 output_info->tile_info.loc_v_tile))
870 y += other_output_info->tile_info.tile_h;
871 break;
872 case META_MONITOR_TRANSFORM_270:
873 case META_MONITOR_TRANSFORM_FLIPPED_270:
874 if ((other_output_info->tile_info.loc_v_tile ==
875 output_info->tile_info.loc_v_tile) &&
876 (other_output_info->tile_info.loc_h_tile >
877 output_info->tile_info.loc_h_tile))
878 y += other_output_info->tile_info.tile_w;
879 if ((other_output_info->tile_info.loc_h_tile ==
880 output_info->tile_info.loc_h_tile) &&
881 (other_output_info->tile_info.loc_v_tile >
882 output_info->tile_info.loc_v_tile))
883 x += other_output_info->tile_info.tile_h;
884 break;
885 case META_MONITOR_TRANSFORM_90:
886 case META_MONITOR_TRANSFORM_FLIPPED_90:
887 if ((other_output_info->tile_info.loc_v_tile ==
888 output_info->tile_info.loc_v_tile) &&
889 (other_output_info->tile_info.loc_h_tile <
890 output_info->tile_info.loc_h_tile))
891 y += other_output_info->tile_info.tile_w;
892 if ((other_output_info->tile_info.loc_h_tile ==
893 output_info->tile_info.loc_h_tile) &&
894 (other_output_info->tile_info.loc_v_tile <
895 output_info->tile_info.loc_v_tile))
896 x += other_output_info->tile_info.tile_h;
897 break;
898 }
899 }
900
901 *out_x = x;
902 *out_y = y;
903 }
904
905 static void
meta_monitor_tiled_calculate_tiled_size(MetaMonitor * monitor,int * out_width,int * out_height)906 meta_monitor_tiled_calculate_tiled_size (MetaMonitor *monitor,
907 int *out_width,
908 int *out_height)
909 {
910 MetaMonitorPrivate *monitor_priv =
911 meta_monitor_get_instance_private (monitor);
912 GList *l;
913 int width;
914 int height;
915
916 width = 0;
917 height = 0;
918 for (l = monitor_priv->outputs; l; l = l->next)
919 {
920 const MetaOutputInfo *output_info = meta_output_get_info (l->data);
921
922 if (output_info->tile_info.loc_v_tile == 0)
923 width += output_info->tile_info.tile_w;
924
925 if (output_info->tile_info.loc_h_tile == 0)
926 height += output_info->tile_info.tile_h;
927 }
928
929 *out_width = width;
930 *out_height = height;
931 }
932
933 static gboolean
is_monitor_mode_assigned(MetaMonitor * monitor,MetaMonitorMode * mode)934 is_monitor_mode_assigned (MetaMonitor *monitor,
935 MetaMonitorMode *mode)
936 {
937 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
938 GList *l;
939 int i;
940
941 for (l = priv->outputs, i = 0; l; l = l->next, i++)
942 {
943 MetaOutput *output = l->data;
944 MetaMonitorCrtcMode *monitor_crtc_mode = &mode->crtc_modes[i];
945 MetaCrtc *crtc;
946 const MetaCrtcConfig *crtc_config;
947
948 crtc = meta_output_get_assigned_crtc (output);
949 crtc_config = crtc ? meta_crtc_get_config (crtc) : NULL;
950
951 if (monitor_crtc_mode->crtc_mode &&
952 (!crtc || !crtc_config ||
953 crtc_config->mode != monitor_crtc_mode->crtc_mode))
954 return FALSE;
955 else if (!monitor_crtc_mode->crtc_mode && crtc)
956 return FALSE;
957 }
958
959 return TRUE;
960 }
961
962 static gboolean
is_crtc_mode_tiled(MetaOutput * output,MetaCrtcMode * crtc_mode)963 is_crtc_mode_tiled (MetaOutput *output,
964 MetaCrtcMode *crtc_mode)
965 {
966 const MetaOutputInfo *output_info = meta_output_get_info (output);
967 const MetaCrtcModeInfo *crtc_mode_info = meta_crtc_mode_get_info (crtc_mode);
968
969 return (crtc_mode_info->width == (int) output_info->tile_info.tile_w &&
970 crtc_mode_info->height == (int) output_info->tile_info.tile_h);
971 }
972
973 static MetaCrtcMode *
find_tiled_crtc_mode(MetaOutput * output,MetaCrtcMode * reference_crtc_mode)974 find_tiled_crtc_mode (MetaOutput *output,
975 MetaCrtcMode *reference_crtc_mode)
976 {
977 const MetaOutputInfo *output_info = meta_output_get_info (output);
978 const MetaCrtcModeInfo *reference_crtc_mode_info =
979 meta_crtc_mode_get_info (reference_crtc_mode);
980 MetaCrtcMode *crtc_mode;
981 unsigned int i;
982
983 crtc_mode = output_info->preferred_mode;
984 if (is_crtc_mode_tiled (output, crtc_mode))
985 return crtc_mode;
986
987 for (i = 0; i < output_info->n_modes; i++)
988 {
989 const MetaCrtcModeInfo *crtc_mode_info;
990
991 crtc_mode = output_info->modes[i];
992 crtc_mode_info = meta_crtc_mode_get_info (crtc_mode);
993
994 if (!is_crtc_mode_tiled (output, crtc_mode))
995 continue;
996
997 if (crtc_mode_info->refresh_rate != reference_crtc_mode_info->refresh_rate)
998 continue;
999
1000 if (crtc_mode_info->flags != reference_crtc_mode_info->flags)
1001 continue;
1002
1003 return crtc_mode;
1004 }
1005
1006 return NULL;
1007 }
1008
1009 static MetaMonitorMode *
create_tiled_monitor_mode(MetaMonitorTiled * monitor_tiled,MetaCrtcMode * reference_crtc_mode,gboolean * out_is_preferred)1010 create_tiled_monitor_mode (MetaMonitorTiled *monitor_tiled,
1011 MetaCrtcMode *reference_crtc_mode,
1012 gboolean *out_is_preferred)
1013 {
1014 MetaMonitor *monitor = META_MONITOR (monitor_tiled);
1015 MetaMonitorPrivate *monitor_priv =
1016 meta_monitor_get_instance_private (monitor);
1017 MetaMonitorModeTiled *mode;
1018 int width, height;
1019 GList *l;
1020 unsigned int i;
1021 gboolean is_preferred = TRUE;
1022
1023 mode = g_new0 (MetaMonitorModeTiled, 1);
1024 mode->is_tiled = TRUE;
1025 meta_monitor_tiled_calculate_tiled_size (monitor, &width, &height);
1026 mode->parent.monitor = monitor;
1027 mode->parent.spec =
1028 meta_monitor_create_spec (monitor, width, height, reference_crtc_mode);
1029 mode->parent.id = generate_mode_id (&mode->parent.spec);
1030
1031 mode->parent.crtc_modes = g_new0 (MetaMonitorCrtcMode,
1032 g_list_length (monitor_priv->outputs));
1033 for (l = monitor_priv->outputs, i = 0; l; l = l->next, i++)
1034 {
1035 MetaOutput *output = l->data;
1036 const MetaOutputInfo *output_info = meta_output_get_info (output);
1037 MetaCrtcMode *tiled_crtc_mode;
1038
1039 tiled_crtc_mode = find_tiled_crtc_mode (output, reference_crtc_mode);
1040 if (!tiled_crtc_mode)
1041 {
1042 g_warning ("No tiled mode found on %s", meta_output_get_name (output));
1043 meta_monitor_mode_free ((MetaMonitorMode *) mode);
1044 return NULL;
1045 }
1046
1047 mode->parent.crtc_modes[i] = (MetaMonitorCrtcMode) {
1048 .output = output,
1049 .crtc_mode = tiled_crtc_mode
1050 };
1051
1052 is_preferred = (is_preferred &&
1053 tiled_crtc_mode == output_info->preferred_mode);
1054 }
1055
1056 *out_is_preferred = is_preferred;
1057
1058 return (MetaMonitorMode *) mode;
1059 }
1060
1061 static void
generate_tiled_monitor_modes(MetaMonitorTiled * monitor_tiled)1062 generate_tiled_monitor_modes (MetaMonitorTiled *monitor_tiled)
1063 {
1064 MetaMonitor *monitor = META_MONITOR (monitor_tiled);
1065 MetaMonitorPrivate *monitor_priv =
1066 meta_monitor_get_instance_private (monitor);
1067 MetaOutput *main_output;
1068 const MetaOutputInfo *main_output_info;
1069 GList *tiled_modes = NULL;
1070 unsigned int i;
1071 MetaMonitorMode *best_mode = NULL;
1072 GList *l;
1073
1074 main_output = meta_monitor_get_main_output (META_MONITOR (monitor_tiled));
1075 main_output_info = meta_output_get_info (main_output);
1076
1077 for (i = 0; i < main_output_info->n_modes; i++)
1078 {
1079 MetaCrtcMode *reference_crtc_mode = main_output_info->modes[i];
1080 MetaMonitorMode *mode;
1081 gboolean is_preferred;
1082
1083 if (!is_crtc_mode_tiled (main_output, reference_crtc_mode))
1084 continue;
1085
1086 mode = create_tiled_monitor_mode (monitor_tiled, reference_crtc_mode,
1087 &is_preferred);
1088 if (!mode)
1089 continue;
1090
1091 tiled_modes = g_list_append (tiled_modes, mode);
1092
1093 if (is_monitor_mode_assigned (monitor, mode))
1094 monitor_priv->current_mode = mode;
1095
1096 if (is_preferred)
1097 monitor_priv->preferred_mode = mode;
1098 }
1099
1100 while ((l = tiled_modes))
1101 {
1102 MetaMonitorMode *mode = l->data;
1103
1104 tiled_modes = g_list_remove_link (tiled_modes, l);
1105
1106 if (!meta_monitor_add_mode (monitor, mode, FALSE))
1107 {
1108 meta_monitor_mode_free (mode);
1109 continue;
1110 }
1111
1112 if (!monitor_priv->preferred_mode)
1113 {
1114 if (!best_mode ||
1115 mode->spec.refresh_rate > best_mode->spec.refresh_rate)
1116 best_mode = mode;
1117 }
1118 }
1119
1120 if (best_mode)
1121 monitor_priv->preferred_mode = best_mode;
1122 }
1123
1124 static MetaMonitorMode *
create_untiled_monitor_mode(MetaMonitorTiled * monitor_tiled,MetaOutput * main_output,MetaCrtcMode * crtc_mode)1125 create_untiled_monitor_mode (MetaMonitorTiled *monitor_tiled,
1126 MetaOutput *main_output,
1127 MetaCrtcMode *crtc_mode)
1128 {
1129 MetaMonitor *monitor = META_MONITOR (monitor_tiled);
1130 MetaMonitorPrivate *monitor_priv =
1131 meta_monitor_get_instance_private (monitor);
1132 MetaMonitorModeTiled *mode;
1133 const MetaCrtcModeInfo *crtc_mode_info;
1134 GList *l;
1135 int i;
1136
1137 if (is_crtc_mode_tiled (main_output, crtc_mode))
1138 return NULL;
1139
1140 mode = g_new0 (MetaMonitorModeTiled, 1);
1141 mode->is_tiled = FALSE;
1142 mode->parent.monitor = monitor;
1143
1144 crtc_mode_info = meta_crtc_mode_get_info (crtc_mode);
1145 mode->parent.spec = meta_monitor_create_spec (monitor,
1146 crtc_mode_info->width,
1147 crtc_mode_info->height,
1148 crtc_mode);
1149 mode->parent.id = generate_mode_id (&mode->parent.spec);
1150 mode->parent.crtc_modes = g_new0 (MetaMonitorCrtcMode,
1151 g_list_length (monitor_priv->outputs));
1152
1153 for (l = monitor_priv->outputs, i = 0; l; l = l->next, i++)
1154 {
1155 MetaOutput *output = l->data;
1156
1157 if (output == main_output)
1158 {
1159 mode->parent.crtc_modes[i] = (MetaMonitorCrtcMode) {
1160 .output = output,
1161 .crtc_mode = crtc_mode
1162 };
1163 }
1164 else
1165 {
1166 mode->parent.crtc_modes[i] = (MetaMonitorCrtcMode) {
1167 .output = output,
1168 .crtc_mode = NULL
1169 };
1170 }
1171 }
1172
1173 return &mode->parent;
1174 }
1175
1176 static int
count_untiled_crtc_modes(MetaOutput * output)1177 count_untiled_crtc_modes (MetaOutput *output)
1178 {
1179 const MetaOutputInfo *output_info = meta_output_get_info (output);
1180 int count;
1181 unsigned int i;
1182
1183 count = 0;
1184 for (i = 0; i < output_info->n_modes; i++)
1185 {
1186 MetaCrtcMode *crtc_mode = output_info->modes[i];
1187
1188 if (!is_crtc_mode_tiled (output, crtc_mode))
1189 count++;
1190 }
1191
1192 return count;
1193 }
1194
1195 static MetaOutput *
find_untiled_output(MetaMonitorTiled * monitor_tiled)1196 find_untiled_output (MetaMonitorTiled *monitor_tiled)
1197 {
1198 MetaMonitor *monitor = META_MONITOR (monitor_tiled);
1199 MetaMonitorPrivate *monitor_priv =
1200 meta_monitor_get_instance_private (monitor);
1201 MetaOutput *best_output;
1202 int best_untiled_crtc_mode_count;
1203 GList *l;
1204
1205 best_output = monitor_tiled->origin_output;
1206 best_untiled_crtc_mode_count =
1207 count_untiled_crtc_modes (monitor_tiled->origin_output);
1208
1209 for (l = monitor_priv->outputs; l; l = l->next)
1210 {
1211 MetaOutput *output = l->data;
1212 int untiled_crtc_mode_count;
1213
1214 if (output == monitor_tiled->origin_output)
1215 continue;
1216
1217 untiled_crtc_mode_count = count_untiled_crtc_modes (output);
1218 if (untiled_crtc_mode_count > best_untiled_crtc_mode_count)
1219 {
1220 best_untiled_crtc_mode_count = untiled_crtc_mode_count;
1221 best_output = output;
1222 }
1223 }
1224
1225 return best_output;
1226 }
1227
1228 static void
generate_untiled_monitor_modes(MetaMonitorTiled * monitor_tiled)1229 generate_untiled_monitor_modes (MetaMonitorTiled *monitor_tiled)
1230 {
1231 MetaMonitor *monitor = META_MONITOR (monitor_tiled);
1232 MetaMonitorPrivate *monitor_priv =
1233 meta_monitor_get_instance_private (monitor);
1234 MetaOutput *main_output;
1235 const MetaOutputInfo *main_output_info;
1236 unsigned int i;
1237
1238 main_output = meta_monitor_get_main_output (monitor);
1239 main_output_info = meta_output_get_info (main_output);
1240
1241 for (i = 0; i < main_output_info->n_modes; i++)
1242 {
1243 MetaCrtcMode *crtc_mode = main_output_info->modes[i];
1244 MetaMonitorMode *mode;
1245
1246 mode = create_untiled_monitor_mode (monitor_tiled,
1247 main_output,
1248 crtc_mode);
1249 if (!mode)
1250 continue;
1251
1252 if (!meta_monitor_add_mode (monitor, mode, FALSE))
1253 {
1254 meta_monitor_mode_free (mode);
1255 continue;
1256 }
1257
1258 if (is_monitor_mode_assigned (monitor, mode))
1259 {
1260 g_assert (!monitor_priv->current_mode);
1261 monitor_priv->current_mode = mode;
1262 }
1263
1264 if (!monitor_priv->preferred_mode &&
1265 crtc_mode == main_output_info->preferred_mode)
1266 monitor_priv->preferred_mode = mode;
1267 }
1268 }
1269
1270 static MetaMonitorMode *
find_best_mode(MetaMonitor * monitor)1271 find_best_mode (MetaMonitor *monitor)
1272 {
1273 MetaMonitorPrivate *monitor_priv =
1274 meta_monitor_get_instance_private (monitor);
1275 MetaMonitorMode *best_mode = NULL;
1276 GList *l;
1277
1278 for (l = monitor_priv->modes; l; l = l->next)
1279 {
1280 MetaMonitorMode *mode = l->data;
1281 int area, best_area;
1282
1283 if (!best_mode)
1284 {
1285 best_mode = mode;
1286 continue;
1287 }
1288
1289 area = mode->spec.width * mode->spec.height;
1290 best_area = best_mode->spec.width * best_mode->spec.height;
1291 if (area > best_area)
1292 {
1293 best_mode = mode;
1294 continue;
1295 }
1296
1297 if (mode->spec.refresh_rate > best_mode->spec.refresh_rate)
1298 {
1299 best_mode = mode;
1300 continue;
1301 }
1302 }
1303
1304 return best_mode;
1305 }
1306
1307 static void
meta_monitor_tiled_generate_modes(MetaMonitorTiled * monitor_tiled)1308 meta_monitor_tiled_generate_modes (MetaMonitorTiled *monitor_tiled)
1309 {
1310 MetaMonitor *monitor = META_MONITOR (monitor_tiled);
1311 MetaMonitorPrivate *monitor_priv =
1312 meta_monitor_get_instance_private (monitor);
1313
1314 /*
1315 * Tiled monitors may look a bit different from each other, depending on the
1316 * monitor itself, the driver, etc.
1317 *
1318 * On some, the tiled modes will be the preferred CRTC modes, and running
1319 * untiled is done by only enabling (0, 0) tile. In this case, things are
1320 * pretty straight forward.
1321 *
1322 * Other times a monitor may have some bogus mode preferred on the main tile,
1323 * and an untiled mode preferred on the non-main tile, and there seems to be
1324 * no guarantee that the (0, 0) tile is the one that should drive the
1325 * non-tiled mode.
1326 *
1327 * To handle both these cases, the following hueristics are implemented:
1328 *
1329 * 1) Find all the tiled CRTC modes of the (0, 0) tile, and create tiled
1330 * monitor modes for all tiles based on these.
1331 * 2) If there is any tiled monitor mode combination where all CRTC modes
1332 * are the preferred ones, that one is marked as preferred.
1333 * 3) If there is no preferred mode determined so far, assume the tiled
1334 * monitor mode with the highest refresh rate is preferred.
1335 * 4) Find the tile with highest number of untiled CRTC modes available,
1336 * assume this is the one driving the monitor in untiled mode, and
1337 * create monitor modes for all untiled CRTC modes of that tile. If
1338 * there is still no preferred mode, set any untiled mode as preferred
1339 * if the CRTC mode is marked as such.
1340 * 5) If at this point there is still no preferred mode, just pick the one
1341 * with the highest number of pixels and highest refresh rate.
1342 *
1343 * Note that this ignores the preference if the preference is a non-tiled
1344 * mode. This seems to be the case on some systems, where the user tends to
1345 * manually set up the tiled mode anyway.
1346 */
1347
1348 generate_tiled_monitor_modes (monitor_tiled);
1349
1350 if (!monitor_priv->preferred_mode)
1351 g_warning ("Tiled monitor on %s didn't have any tiled modes",
1352 monitor_priv->spec->connector);
1353
1354 generate_untiled_monitor_modes (monitor_tiled);
1355
1356 if (!monitor_priv->preferred_mode)
1357 {
1358 g_warning ("Tiled monitor on %s didn't have a valid preferred mode",
1359 monitor_priv->spec->connector);
1360 monitor_priv->preferred_mode = find_best_mode (monitor);
1361 }
1362 }
1363
1364 MetaMonitorTiled *
meta_monitor_tiled_new(MetaMonitorManager * monitor_manager,MetaOutput * output)1365 meta_monitor_tiled_new (MetaMonitorManager *monitor_manager,
1366 MetaOutput *output)
1367 {
1368 const MetaOutputInfo *output_info = meta_output_get_info (output);
1369 MetaMonitorTiled *monitor_tiled;
1370 MetaMonitor *monitor;
1371 MetaMonitorPrivate *monitor_priv;
1372
1373 monitor_tiled = g_object_new (META_TYPE_MONITOR_TILED, NULL);
1374 monitor = META_MONITOR (monitor_tiled);
1375 monitor_priv = meta_monitor_get_instance_private (monitor);
1376
1377 monitor_priv->backend = meta_monitor_manager_get_backend (monitor_manager);
1378
1379 monitor_tiled->tile_group_id = output_info->tile_info.group_id;
1380 monitor_priv->winsys_id = meta_output_get_id (output);
1381
1382 monitor_tiled->origin_output = output;
1383 add_tiled_monitor_outputs (meta_output_get_gpu (output), monitor_tiled);
1384
1385 monitor_tiled->main_output = find_untiled_output (monitor_tiled);
1386
1387 meta_monitor_generate_spec (monitor);
1388
1389 monitor_tiled->monitor_manager = monitor_manager;
1390 meta_monitor_manager_tiled_monitor_added (monitor_manager,
1391 META_MONITOR (monitor_tiled));
1392
1393 meta_monitor_tiled_generate_modes (monitor_tiled);
1394
1395 monitor_priv->display_name = meta_monitor_make_display_name (monitor,
1396 monitor_manager);
1397
1398 return monitor_tiled;
1399 }
1400
1401 static MetaOutput *
meta_monitor_tiled_get_main_output(MetaMonitor * monitor)1402 meta_monitor_tiled_get_main_output (MetaMonitor *monitor)
1403 {
1404 MetaMonitorTiled *monitor_tiled = META_MONITOR_TILED (monitor);
1405
1406 return monitor_tiled->main_output;
1407 }
1408
1409 static void
meta_monitor_tiled_derive_layout(MetaMonitor * monitor,MetaRectangle * layout)1410 meta_monitor_tiled_derive_layout (MetaMonitor *monitor,
1411 MetaRectangle *layout)
1412 {
1413 MetaMonitorPrivate *monitor_priv =
1414 meta_monitor_get_instance_private (monitor);
1415 GList *l;
1416 float min_x, min_y, max_x, max_y;
1417
1418 min_x = FLT_MAX;
1419 min_y = FLT_MAX;
1420 max_x = 0.0;
1421 max_y = 0.0;
1422 for (l = monitor_priv->outputs; l; l = l->next)
1423 {
1424 MetaOutput *output = l->data;
1425 MetaCrtc *crtc;
1426 const MetaCrtcConfig *crtc_config;
1427 const graphene_rect_t *crtc_layout;
1428
1429 crtc = meta_output_get_assigned_crtc (output);
1430 if (!crtc)
1431 continue;
1432
1433 crtc_config = meta_crtc_get_config (crtc);
1434 g_return_if_fail (crtc_config);
1435
1436 crtc_layout = &crtc_config->layout;
1437
1438 min_x = MIN (crtc_layout->origin.x, min_x);
1439 min_y = MIN (crtc_layout->origin.y, min_y);
1440 max_x = MAX (crtc_layout->origin.x + crtc_layout->size.width, max_x);
1441 max_y = MAX (crtc_layout->origin.y + crtc_layout->size.height, max_y);
1442 }
1443
1444 *layout = (MetaRectangle) {
1445 .x = roundf (min_x),
1446 .y = roundf (min_y),
1447 .width = roundf (max_x - min_x),
1448 .height = roundf (max_y - min_y)
1449 };
1450 }
1451
1452 static gboolean
meta_monitor_tiled_get_suggested_position(MetaMonitor * monitor,int * x,int * y)1453 meta_monitor_tiled_get_suggested_position (MetaMonitor *monitor,
1454 int *x,
1455 int *y)
1456 {
1457 return FALSE;
1458 }
1459
1460 static void
meta_monitor_tiled_calculate_crtc_pos(MetaMonitor * monitor,MetaMonitorMode * monitor_mode,MetaOutput * output,MetaMonitorTransform crtc_transform,int * out_x,int * out_y)1461 meta_monitor_tiled_calculate_crtc_pos (MetaMonitor *monitor,
1462 MetaMonitorMode *monitor_mode,
1463 MetaOutput *output,
1464 MetaMonitorTransform crtc_transform,
1465 int *out_x,
1466 int *out_y)
1467 {
1468 MetaMonitorModeTiled *mode_tiled = (MetaMonitorModeTiled *) monitor_mode;
1469
1470 if (mode_tiled->is_tiled)
1471 {
1472 calculate_tile_coordinate (monitor, output, crtc_transform,
1473 out_x, out_y);
1474 }
1475 else
1476 {
1477 *out_x = 0;
1478 *out_y = 0;
1479 }
1480 }
1481
1482 static void
meta_monitor_tiled_finalize(GObject * object)1483 meta_monitor_tiled_finalize (GObject *object)
1484 {
1485 MetaMonitorTiled *monitor_tiled = META_MONITOR_TILED (object);
1486
1487 meta_monitor_manager_tiled_monitor_removed (monitor_tiled->monitor_manager,
1488 META_MONITOR (monitor_tiled));
1489
1490 G_OBJECT_CLASS (meta_monitor_tiled_parent_class)->finalize (object);
1491 }
1492
1493 static void
meta_monitor_tiled_init(MetaMonitorTiled * monitor)1494 meta_monitor_tiled_init (MetaMonitorTiled *monitor)
1495 {
1496 }
1497
1498 static void
meta_monitor_tiled_class_init(MetaMonitorTiledClass * klass)1499 meta_monitor_tiled_class_init (MetaMonitorTiledClass *klass)
1500 {
1501 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1502 MetaMonitorClass *monitor_class = META_MONITOR_CLASS (klass);
1503
1504 object_class->finalize = meta_monitor_tiled_finalize;
1505
1506 monitor_class->get_main_output = meta_monitor_tiled_get_main_output;
1507 monitor_class->derive_layout = meta_monitor_tiled_derive_layout;
1508 monitor_class->calculate_crtc_pos = meta_monitor_tiled_calculate_crtc_pos;
1509 monitor_class->get_suggested_position = meta_monitor_tiled_get_suggested_position;
1510 }
1511
1512 static void
meta_monitor_mode_free(MetaMonitorMode * monitor_mode)1513 meta_monitor_mode_free (MetaMonitorMode *monitor_mode)
1514 {
1515 g_free (monitor_mode->id);
1516 g_free (monitor_mode->crtc_modes);
1517 g_free (monitor_mode);
1518 }
1519
1520 MetaMonitorSpec *
meta_monitor_get_spec(MetaMonitor * monitor)1521 meta_monitor_get_spec (MetaMonitor *monitor)
1522 {
1523 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
1524
1525 return priv->spec;
1526 }
1527
1528 MetaLogicalMonitor *
meta_monitor_get_logical_monitor(MetaMonitor * monitor)1529 meta_monitor_get_logical_monitor (MetaMonitor *monitor)
1530 {
1531 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
1532
1533 return priv->logical_monitor;
1534 }
1535
1536 MetaMonitorMode *
meta_monitor_get_mode_from_id(MetaMonitor * monitor,const char * monitor_mode_id)1537 meta_monitor_get_mode_from_id (MetaMonitor *monitor,
1538 const char *monitor_mode_id)
1539 {
1540 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
1541
1542 return g_hash_table_lookup (priv->mode_ids, monitor_mode_id);
1543 }
1544
1545 static gboolean
meta_monitor_mode_spec_equals(MetaMonitorModeSpec * monitor_mode_spec,MetaMonitorModeSpec * other_monitor_mode_spec)1546 meta_monitor_mode_spec_equals (MetaMonitorModeSpec *monitor_mode_spec,
1547 MetaMonitorModeSpec *other_monitor_mode_spec)
1548 {
1549 return (monitor_mode_spec->width == other_monitor_mode_spec->width &&
1550 monitor_mode_spec->height == other_monitor_mode_spec->height &&
1551 ABS (monitor_mode_spec->refresh_rate -
1552 other_monitor_mode_spec->refresh_rate) < MAXIMUM_REFRESH_RATE_DIFF &&
1553 monitor_mode_spec->flags == other_monitor_mode_spec->flags);
1554 }
1555
1556 MetaMonitorMode *
meta_monitor_get_mode_from_spec(MetaMonitor * monitor,MetaMonitorModeSpec * monitor_mode_spec)1557 meta_monitor_get_mode_from_spec (MetaMonitor *monitor,
1558 MetaMonitorModeSpec *monitor_mode_spec)
1559 {
1560 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
1561 GList *l;
1562
1563 for (l = priv->modes; l; l = l->next)
1564 {
1565 MetaMonitorMode *monitor_mode = l->data;
1566
1567 if (meta_monitor_mode_spec_equals (monitor_mode_spec,
1568 &monitor_mode->spec))
1569 return monitor_mode;
1570 }
1571
1572 return NULL;
1573 }
1574
1575 MetaMonitorMode *
meta_monitor_get_preferred_mode(MetaMonitor * monitor)1576 meta_monitor_get_preferred_mode (MetaMonitor *monitor)
1577 {
1578 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
1579
1580 return priv->preferred_mode;
1581 }
1582
1583 MetaMonitorMode *
meta_monitor_get_current_mode(MetaMonitor * monitor)1584 meta_monitor_get_current_mode (MetaMonitor *monitor)
1585 {
1586 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
1587
1588 return priv->current_mode;
1589 }
1590
1591 static gboolean
is_current_mode_known(MetaMonitor * monitor)1592 is_current_mode_known (MetaMonitor *monitor)
1593 {
1594 MetaOutput *output;
1595 MetaCrtc *crtc;
1596
1597 output = meta_monitor_get_main_output (monitor);
1598 crtc = meta_output_get_assigned_crtc (output);
1599
1600 return (meta_monitor_is_active (monitor) ==
1601 (crtc && meta_crtc_get_config (crtc)));
1602 }
1603
1604 void
meta_monitor_derive_current_mode(MetaMonitor * monitor)1605 meta_monitor_derive_current_mode (MetaMonitor *monitor)
1606 {
1607 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
1608 MetaMonitorMode *current_mode = NULL;
1609 GList *l;
1610
1611 for (l = priv->modes; l; l = l->next)
1612 {
1613 MetaMonitorMode *mode = l->data;
1614
1615 if (is_monitor_mode_assigned (monitor, mode))
1616 {
1617 current_mode = mode;
1618 break;
1619 }
1620 }
1621
1622 priv->current_mode = current_mode;
1623
1624 g_warn_if_fail (is_current_mode_known (monitor));
1625 }
1626
1627 void
meta_monitor_set_current_mode(MetaMonitor * monitor,MetaMonitorMode * mode)1628 meta_monitor_set_current_mode (MetaMonitor *monitor,
1629 MetaMonitorMode *mode)
1630 {
1631 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
1632
1633 priv->current_mode = mode;
1634 }
1635
1636 GList *
meta_monitor_get_modes(MetaMonitor * monitor)1637 meta_monitor_get_modes (MetaMonitor *monitor)
1638 {
1639 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
1640
1641 return priv->modes;
1642 }
1643
1644 void
meta_monitor_calculate_crtc_pos(MetaMonitor * monitor,MetaMonitorMode * monitor_mode,MetaOutput * output,MetaMonitorTransform crtc_transform,int * out_x,int * out_y)1645 meta_monitor_calculate_crtc_pos (MetaMonitor *monitor,
1646 MetaMonitorMode *monitor_mode,
1647 MetaOutput *output,
1648 MetaMonitorTransform crtc_transform,
1649 int *out_x,
1650 int *out_y)
1651 {
1652 META_MONITOR_GET_CLASS (monitor)->calculate_crtc_pos (monitor,
1653 monitor_mode,
1654 output,
1655 crtc_transform,
1656 out_x,
1657 out_y);
1658 }
1659
1660 /* The minimum resolution at which we turn on a window-scale of 2 */
1661 #define HIDPI_LIMIT 192
1662
1663 /*
1664 * The minimum screen height at which we turn on a window-scale of 2;
1665 * below this there just isn't enough vertical real estate for GNOME
1666 * apps to work, and it's better to just be tiny
1667 */
1668 #define HIDPI_MIN_HEIGHT 1200
1669
1670 /* From http://en.wikipedia.org/wiki/4K_resolution#Resolutions_of_common_formats */
1671 #define SMALLEST_4K_WIDTH 3656
1672
1673 static float
calculate_scale(MetaMonitor * monitor,MetaMonitorMode * monitor_mode,MetaMonitorScalesConstraint constraints)1674 calculate_scale (MetaMonitor *monitor,
1675 MetaMonitorMode *monitor_mode,
1676 MetaMonitorScalesConstraint constraints)
1677 {
1678 int resolution_width, resolution_height;
1679 int width_mm, height_mm;
1680 int scale;
1681
1682 scale = 1.0;
1683
1684 meta_monitor_mode_get_resolution (monitor_mode,
1685 &resolution_width,
1686 &resolution_height);
1687
1688 if (resolution_height < HIDPI_MIN_HEIGHT)
1689 return scale;
1690
1691 /* 4K TV */
1692 switch (meta_monitor_get_connector_type (monitor))
1693 {
1694 case META_CONNECTOR_TYPE_HDMIA:
1695 case META_CONNECTOR_TYPE_HDMIB:
1696 if (resolution_width < SMALLEST_4K_WIDTH)
1697 return scale;
1698 break;
1699 default:
1700 break;
1701 }
1702
1703 meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm);
1704
1705 /*
1706 * Somebody encoded the aspect ratio (16/9 or 16/10) instead of the physical
1707 * size.
1708 */
1709 if (meta_monitor_has_aspect_as_size (monitor))
1710 return scale;
1711
1712 if (width_mm > 0 && height_mm > 0)
1713 {
1714 double dpi_x, dpi_y;
1715
1716 dpi_x = (double) resolution_width / (width_mm / 25.4);
1717 dpi_y = (double) resolution_height / (height_mm / 25.4);
1718
1719 /*
1720 * We don't completely trust these values so both must be high, and never
1721 * pick higher ratio than 2 automatically.
1722 */
1723 if (dpi_x > HIDPI_LIMIT && dpi_y > HIDPI_LIMIT)
1724 scale = 2.0;
1725 }
1726
1727 return scale;
1728 }
1729
1730 float
meta_monitor_calculate_mode_scale(MetaMonitor * monitor,MetaMonitorMode * monitor_mode,MetaMonitorScalesConstraint constraints)1731 meta_monitor_calculate_mode_scale (MetaMonitor *monitor,
1732 MetaMonitorMode *monitor_mode,
1733 MetaMonitorScalesConstraint constraints)
1734 {
1735 MetaBackend *backend = meta_get_backend ();
1736 MetaSettings *settings = meta_backend_get_settings (backend);
1737 int global_scaling_factor;
1738
1739 if (meta_settings_get_global_scaling_factor (settings,
1740 &global_scaling_factor))
1741 return global_scaling_factor;
1742
1743 return calculate_scale (monitor, monitor_mode, constraints);
1744 }
1745
1746 static gboolean
is_logical_size_large_enough(int width,int height)1747 is_logical_size_large_enough (int width,
1748 int height)
1749 {
1750 return width * height >= MINIMUM_LOGICAL_AREA;
1751 }
1752
1753 static gboolean
is_scale_valid_for_size(float width,float height,float scale)1754 is_scale_valid_for_size (float width,
1755 float height,
1756 float scale)
1757 {
1758 if (scale < MINIMUM_SCALE_FACTOR || scale > MAXIMUM_SCALE_FACTOR)
1759 return FALSE;
1760
1761 return is_logical_size_large_enough (floorf (width / scale),
1762 floorf (height / scale));
1763 }
1764
1765 gboolean
meta_monitor_mode_should_be_advertised(MetaMonitorMode * monitor_mode)1766 meta_monitor_mode_should_be_advertised (MetaMonitorMode *monitor_mode)
1767 {
1768 MetaMonitorMode *preferred_mode;
1769
1770 g_return_val_if_fail (monitor_mode != NULL, FALSE);
1771
1772 preferred_mode = meta_monitor_get_preferred_mode (monitor_mode->monitor);
1773 if (monitor_mode->spec.width == preferred_mode->spec.width &&
1774 monitor_mode->spec.height == preferred_mode->spec.height)
1775 return TRUE;
1776
1777 return is_logical_size_large_enough (monitor_mode->spec.width,
1778 monitor_mode->spec.height);
1779 }
1780
1781 static float
get_closest_scale_factor_for_resolution(float width,float height,float scale,float threshold)1782 get_closest_scale_factor_for_resolution (float width,
1783 float height,
1784 float scale,
1785 float threshold)
1786 {
1787 unsigned int i, j;
1788 float scaled_h;
1789 float scaled_w;
1790 float best_scale;
1791 int base_scaled_w;
1792 gboolean found_one;
1793
1794 best_scale = 0;
1795
1796 if (!is_scale_valid_for_size (width, height, scale))
1797 return best_scale;
1798
1799 if (fmodf (width, scale) == 0.0 && fmodf (height, scale) == 0.0)
1800 return scale;
1801
1802 i = 0;
1803 found_one = FALSE;
1804 base_scaled_w = floorf (width / scale);
1805
1806 do
1807 {
1808 for (j = 0; j < 2; j++)
1809 {
1810 float current_scale;
1811 int offset = i * (j ? 1 : -1);
1812
1813 scaled_w = base_scaled_w + offset;
1814 current_scale = width / scaled_w;
1815 scaled_h = height / current_scale;
1816
1817 if (current_scale >= scale + threshold ||
1818 current_scale <= scale - threshold ||
1819 current_scale < MINIMUM_SCALE_FACTOR ||
1820 current_scale > MAXIMUM_SCALE_FACTOR)
1821 {
1822 return best_scale;
1823 }
1824
1825 if (floorf (scaled_h) == scaled_h)
1826 {
1827 found_one = TRUE;
1828
1829 if (fabsf (current_scale - scale) < fabsf (best_scale - scale))
1830 best_scale = current_scale;
1831 }
1832 }
1833
1834 i++;
1835 }
1836 while (!found_one);
1837
1838 return best_scale;
1839 }
1840
1841 float *
meta_monitor_calculate_supported_scales(MetaMonitor * monitor,MetaMonitorMode * monitor_mode,MetaMonitorScalesConstraint constraints,int * n_supported_scales)1842 meta_monitor_calculate_supported_scales (MetaMonitor *monitor,
1843 MetaMonitorMode *monitor_mode,
1844 MetaMonitorScalesConstraint constraints,
1845 int *n_supported_scales)
1846 {
1847 unsigned int i, j;
1848 int width, height;
1849 GArray *supported_scales;
1850
1851 supported_scales = g_array_new (FALSE, FALSE, sizeof (float));
1852
1853 meta_monitor_mode_get_resolution (monitor_mode, &width, &height);
1854
1855 for (i = floorf (MINIMUM_SCALE_FACTOR);
1856 i <= ceilf (MAXIMUM_SCALE_FACTOR);
1857 i++)
1858 {
1859 if (constraints & META_MONITOR_SCALES_CONSTRAINT_NO_FRAC)
1860 {
1861 if (is_scale_valid_for_size (width, height, i))
1862 {
1863 float scale = i;
1864 g_array_append_val (supported_scales, scale);
1865 }
1866 }
1867 else
1868 {
1869 float max_bound;
1870
1871 if (i == floorf (MINIMUM_SCALE_FACTOR) ||
1872 i == ceilf (MAXIMUM_SCALE_FACTOR))
1873 max_bound = SCALE_FACTORS_STEPS;
1874 else
1875 max_bound = SCALE_FACTORS_STEPS / 2.0;
1876
1877 for (j = 0; j < SCALE_FACTORS_PER_INTEGER; j++)
1878 {
1879 float scale;
1880 float scale_value = i + j * SCALE_FACTORS_STEPS;
1881
1882 scale = get_closest_scale_factor_for_resolution (width, height,
1883 scale_value,
1884 max_bound);
1885 if (scale > 0.0)
1886 g_array_append_val (supported_scales, scale);
1887 }
1888 }
1889 }
1890
1891 if (supported_scales->len == 0)
1892 {
1893 float fallback_scale;
1894
1895 fallback_scale = 1.0;
1896 g_array_append_val (supported_scales, fallback_scale);
1897 }
1898
1899 *n_supported_scales = supported_scales->len;
1900 return (float *) g_array_free (supported_scales, FALSE);
1901 }
1902
1903 MetaMonitorModeSpec *
meta_monitor_mode_get_spec(MetaMonitorMode * monitor_mode)1904 meta_monitor_mode_get_spec (MetaMonitorMode *monitor_mode)
1905 {
1906 return &monitor_mode->spec;
1907 }
1908
1909 const char *
meta_monitor_mode_get_id(MetaMonitorMode * monitor_mode)1910 meta_monitor_mode_get_id (MetaMonitorMode *monitor_mode)
1911 {
1912 return monitor_mode->id;
1913 }
1914
1915 void
meta_monitor_mode_get_resolution(MetaMonitorMode * monitor_mode,int * width,int * height)1916 meta_monitor_mode_get_resolution (MetaMonitorMode *monitor_mode,
1917 int *width,
1918 int *height)
1919 {
1920 *width = monitor_mode->spec.width;
1921 *height = monitor_mode->spec.height;
1922 }
1923
1924 float
meta_monitor_mode_get_refresh_rate(MetaMonitorMode * monitor_mode)1925 meta_monitor_mode_get_refresh_rate (MetaMonitorMode *monitor_mode)
1926 {
1927 return monitor_mode->spec.refresh_rate;
1928 }
1929
1930 MetaCrtcModeFlag
meta_monitor_mode_get_flags(MetaMonitorMode * monitor_mode)1931 meta_monitor_mode_get_flags (MetaMonitorMode *monitor_mode)
1932 {
1933 return monitor_mode->spec.flags;
1934 }
1935
1936 gboolean
meta_monitor_mode_foreach_crtc(MetaMonitor * monitor,MetaMonitorMode * mode,MetaMonitorModeFunc func,gpointer user_data,GError ** error)1937 meta_monitor_mode_foreach_crtc (MetaMonitor *monitor,
1938 MetaMonitorMode *mode,
1939 MetaMonitorModeFunc func,
1940 gpointer user_data,
1941 GError **error)
1942 {
1943 MetaMonitorPrivate *monitor_priv =
1944 meta_monitor_get_instance_private (monitor);
1945 GList *l;
1946 int i;
1947
1948 for (l = monitor_priv->outputs, i = 0; l; l = l->next, i++)
1949 {
1950 MetaMonitorCrtcMode *monitor_crtc_mode = &mode->crtc_modes[i];
1951
1952 if (!monitor_crtc_mode->crtc_mode)
1953 continue;
1954
1955 if (!func (monitor, mode, monitor_crtc_mode, user_data, error))
1956 return FALSE;
1957 }
1958
1959 return TRUE;
1960 }
1961
1962 gboolean
meta_monitor_mode_foreach_output(MetaMonitor * monitor,MetaMonitorMode * mode,MetaMonitorModeFunc func,gpointer user_data,GError ** error)1963 meta_monitor_mode_foreach_output (MetaMonitor *monitor,
1964 MetaMonitorMode *mode,
1965 MetaMonitorModeFunc func,
1966 gpointer user_data,
1967 GError **error)
1968 {
1969 MetaMonitorPrivate *monitor_priv =
1970 meta_monitor_get_instance_private (monitor);
1971 GList *l;
1972 int i;
1973
1974 for (l = monitor_priv->outputs, i = 0; l; l = l->next, i++)
1975 {
1976 MetaMonitorCrtcMode *monitor_crtc_mode = &mode->crtc_modes[i];
1977
1978 if (!func (monitor, mode, monitor_crtc_mode, user_data, error))
1979 return FALSE;
1980 }
1981
1982 return TRUE;
1983 }
1984
1985 MetaMonitorCrtcMode *
meta_monitor_get_crtc_mode_for_output(MetaMonitor * monitor,MetaMonitorMode * mode,MetaOutput * output)1986 meta_monitor_get_crtc_mode_for_output (MetaMonitor *monitor,
1987 MetaMonitorMode *mode,
1988 MetaOutput *output)
1989 {
1990 MetaMonitorPrivate *monitor_priv =
1991 meta_monitor_get_instance_private (monitor);
1992 GList *l;
1993 int i;
1994
1995 for (l = monitor_priv->outputs, i = 0; l; l = l->next, i++)
1996 {
1997 MetaMonitorCrtcMode *monitor_crtc_mode = &mode->crtc_modes[i];
1998
1999 if (monitor_crtc_mode->output == output)
2000 return monitor_crtc_mode;
2001 }
2002
2003 g_warn_if_reached ();
2004 return NULL;
2005 }
2006
2007 const char *
meta_monitor_get_display_name(MetaMonitor * monitor)2008 meta_monitor_get_display_name (MetaMonitor *monitor)
2009 {
2010 MetaMonitorPrivate *monitor_priv =
2011 meta_monitor_get_instance_private (monitor);
2012
2013 return monitor_priv->display_name;
2014 }
2015
2016 void
meta_monitor_set_logical_monitor(MetaMonitor * monitor,MetaLogicalMonitor * logical_monitor)2017 meta_monitor_set_logical_monitor (MetaMonitor *monitor,
2018 MetaLogicalMonitor *logical_monitor)
2019 {
2020 MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
2021
2022 priv->logical_monitor = logical_monitor;
2023 }
2024