[mutter] wayland: Add basic hidpi support



commit 31c925c60293c3d72da533db0780e796e170bad1
Author: Adel Gadllah <adel gadllah gmail com>
Date:   Sat Apr 26 10:27:34 2014 +0200

    wayland: Add basic hidpi support
    
    Advertise the scale factor on the output and transform pointer and damage
    events as well as input and opaque regions for clients
    that scale up by themselves i.e use set_buffer_scale.
    
    We do not scale any 'legacy' apps yet.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=728902

 src/backends/meta-monitor-manager.h |    1 +
 src/wayland/meta-wayland-outputs.c  |   49 ++++++++++++++++++++++++++++
 src/wayland/meta-wayland-pointer.c  |    4 +-
 src/wayland/meta-wayland-surface.c  |   61 ++++++++++++++++++++++++++++++++---
 src/wayland/meta-wayland-surface.h  |    3 ++
 5 files changed, 111 insertions(+), 7 deletions(-)
---
diff --git a/src/backends/meta-monitor-manager.h b/src/backends/meta-monitor-manager.h
index 56dcb7d..b5bc927 100644
--- a/src/backends/meta-monitor-manager.h
+++ b/src/backends/meta-monitor-manager.h
@@ -73,6 +73,7 @@ struct _MetaOutput
   int width_mm;
   int height_mm;
   CoglSubpixelOrder subpixel_order;
+  int scale;
 
   MetaMonitorMode *preferred_mode;
   MetaMonitorMode **modes;
diff --git a/src/wayland/meta-wayland-outputs.c b/src/wayland/meta-wayland-outputs.c
index 8d02cd9..bef2b46 100644
--- a/src/wayland/meta-wayland-outputs.c
+++ b/src/wayland/meta-wayland-outputs.c
@@ -29,6 +29,8 @@
 #include "meta-wayland-private.h"
 #include "meta-monitor-manager.h"
 
+#include <string.h>
+
 typedef struct {
   MetaOutput               *output;
   struct wl_global         *global;
@@ -38,6 +40,17 @@ typedef struct {
   GList                    *resources;
 } MetaWaylandOutput;
 
+/* The minimum resolution at which we turn on a window-scale of 2 */
+#define HIDPI_LIMIT 192
+
+/* The minimum screen height at which we turn on a window-scale of 2;
+ * below this there just isn't enough vertical real estate for GNOME
+ * apps to work, and it's better to just be tiny */
+#define HIDPI_MIN_HEIGHT 1200
+
+/* From http://en.wikipedia.org/wiki/4K_resolution#Resolutions_of_common_formats */
+#define SMALLEST_4K_WIDTH 3656
+
 static void
 output_resource_destroy (struct wl_resource *res)
 {
@@ -47,6 +60,37 @@ output_resource_destroy (struct wl_resource *res)
   wayland_output->resources = g_list_remove (wayland_output->resources, res);
 }
 
+/* Based on code from gnome-settings-daemon */
+static int
+compute_scale (MetaOutput *output)
+{
+  int scale = 1;
+
+  /* Scaling makes no sense */
+  if (output->crtc->rect.width < HIDPI_MIN_HEIGHT)
+    goto out;
+
+  /* 4K TV */
+  if (output->name != NULL && strstr(output->name, "HDMI") != NULL &&
+      output->crtc->rect.width >= SMALLEST_4K_WIDTH)
+    goto out;
+
+  if (output->width_mm > 0 && output->height_mm > 0)
+    {
+      double dpi_x, dpi_y;
+      dpi_x = (double)output->crtc->rect.width / (output->width_mm / 25.4);
+      dpi_y = (double)output->crtc->rect.height / (output->height_mm / 25.4);
+      /* We don't completely trust these values so both
+         must be high, and never pick higher ratio than
+         2 automatically */
+      if (dpi_x > HIDPI_LIMIT && dpi_y > HIDPI_LIMIT)
+        scale = 2;
+    }
+
+out:
+  return scale;
+}
+
 static void
 bind_output (struct wl_client *client,
              void *data,
@@ -97,6 +141,11 @@ bind_output (struct wl_client *client,
                           (int)output->crtc->current_mode->height,
                           (int)output->crtc->current_mode->refresh_rate);
 
+  output->scale = compute_scale (output);
+  wl_resource_post_event (resource,
+                          WL_OUTPUT_SCALE,
+                          output->scale);
+
   if (version >= META_WL_OUTPUT_HAS_DONE)
     wl_resource_post_event (resource,
                             WL_OUTPUT_DONE);
diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c
index 388f92e..5a3a09c 100644
--- a/src/wayland/meta-wayland-pointer.c
+++ b/src/wayland/meta-wayland-pointer.c
@@ -724,8 +724,8 @@ meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
   clutter_actor_transform_stage_point (CLUTTER_ACTOR (surface->surface_actor),
                                        pos.x, pos.y, &xf, &yf);
 
-  *sx = wl_fixed_from_double (xf);
-  *sy = wl_fixed_from_double (yf);
+  *sx = wl_fixed_from_double (xf) / surface->scale;
+  *sy = wl_fixed_from_double (yf) / surface->scale;
 }
 
 void
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 0c7cfdb..7696ff4 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -108,6 +108,7 @@ surface_process_damage (MetaWaylandSurface *surface,
 {
   int i, n_rectangles;
   cairo_rectangle_int_t buffer_rect;
+  int scale = surface->scale;
 
   /* Damage without a buffer makes no sense so ignore that, otherwise we would crash */
   if (!surface->buffer)
@@ -129,7 +130,7 @@ surface_process_damage (MetaWaylandSurface *surface,
       cairo_rectangle_int_t rect;
       cairo_region_get_rectangle (region, i, &rect);
       meta_surface_actor_process_damage (surface->surface_actor,
-                                         rect.x, rect.y, rect.width, rect.height);
+                                         rect.x * scale, rect.y * scale, rect.width * scale, rect.height * 
scale);
     }
 }
 
@@ -206,6 +207,7 @@ pending_state_init (MetaWaylandPendingState *state)
   state->buffer = NULL;
   state->dx = 0;
   state->dy = 0;
+  state->scale = 0;
 
   state->input_region = NULL;
   state->opaque_region = NULL;
@@ -287,6 +289,36 @@ parent_surface_committed (gpointer data, gpointer user_data)
   subsurface_parent_surface_committed (data);
 }
 
+static cairo_region_t*
+scale_region (cairo_region_t *region, int scale)
+{
+  int n_rects, i;
+  cairo_rectangle_int_t *rects;
+  cairo_region_t *scaled_region;
+
+  if (scale == 1)
+    return region;
+
+  n_rects = cairo_region_num_rectangles (region);
+
+  rects = g_malloc (sizeof(cairo_rectangle_int_t) * n_rects);
+  for (i = 0; i < n_rects; i++)
+    {
+      cairo_region_get_rectangle (region, i, &rects[i]);
+      rects[i].x *= scale;
+      rects[i].y *= scale;
+      rects[i].width *= scale;
+      rects[i].height *= scale;
+    }
+
+  scaled_region = cairo_region_create_rectangles (rects, n_rects);
+
+  g_free (rects);
+  cairo_region_destroy (region);
+
+  return scaled_region;
+}
+
 static void
 commit_pending_state (MetaWaylandSurface      *surface,
                       MetaWaylandPendingState *pending)
@@ -316,13 +348,22 @@ commit_pending_state (MetaWaylandSurface      *surface,
         }
     }
 
+  if (pending->scale > 0)
+    surface->scale = pending->scale;
+
   if (!cairo_region_is_empty (pending->damage))
     surface_process_damage (surface, pending->damage);
 
   if (pending->opaque_region)
-    meta_surface_actor_set_opaque_region (surface->surface_actor, pending->opaque_region);
+    {
+      pending->opaque_region = scale_region (pending->opaque_region, surface->scale);
+      meta_surface_actor_set_opaque_region (surface->surface_actor, pending->opaque_region);
+    }
   if (pending->input_region)
-    meta_surface_actor_set_input_region (surface->surface_actor, pending->input_region);
+    {
+      pending->input_region = scale_region (pending->input_region, surface->scale);
+      meta_surface_actor_set_input_region (surface->surface_actor, pending->input_region);
+    }
 
   if (surface == compositor->seat->pointer.cursor_surface)
     cursor_surface_commit (surface, pending);
@@ -500,8 +541,11 @@ wl_surface_set_buffer_scale (struct wl_client *client,
                              struct wl_resource *resource,
                              int scale)
 {
-  if (scale != 1)
-    g_warning ("TODO: support set_buffer_scale request");
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+  if (scale > 0)
+    surface->pending.scale = scale;
+  else
+    g_warning ("Trying to set invalid buffer_scale of %d\n", scale);
 }
 
 const struct wl_surface_interface meta_wayland_wl_surface_interface = {
@@ -593,6 +637,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
   MetaWaylandSurface *surface = g_slice_new0 (MetaWaylandSurface);
 
   surface->compositor = compositor;
+  surface->scale = 1;
 
   surface->resource = wl_resource_create (client, &wl_surface_interface,
                                           MIN (META_WL_SURFACE_VERSION, wl_resource_get_version 
(compositor_resource)), id);
@@ -1684,6 +1729,12 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
                                       int                 new_width,
                                       int                 new_height)
 {
+  /* new_width and new_height comes from window->rect,
+   * which is based on the buffer size, not the surface
+   * size. The configure event requires surface size. */
+  new_width /= surface->scale;
+  new_height /= surface->scale;
+
   if (surface->xdg_surface.resource)
     xdg_surface_send_configure (surface->xdg_surface.resource,
                                 new_width, new_height);
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index fc744e8..91a0b10 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -50,6 +50,8 @@ typedef struct
   int32_t dx;
   int32_t dy;
 
+  int scale;
+
   /* wl_surface.damage */
   cairo_region_t *damage;
 
@@ -79,6 +81,7 @@ struct _MetaWaylandSurface
   MetaWaylandSurfaceExtension wl_shell_surface;
   MetaWaylandSurfaceExtension gtk_surface;
   MetaWaylandSurfaceExtension subsurface;
+  int scale;
 
   MetaWaylandBuffer *buffer;
   struct wl_listener buffer_destroy_listener;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]