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
This commit is contained in:
parent
5d310e06ba
commit
31c925c602
@ -73,6 +73,7 @@ struct _MetaOutput
|
||||
int width_mm;
|
||||
int height_mm;
|
||||
CoglSubpixelOrder subpixel_order;
|
||||
int scale;
|
||||
|
||||
MetaMonitorMode *preferred_mode;
|
||||
MetaMonitorMode **modes;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user