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