From ed4fcee4c62a50c1b4fa612f4ba0fc96031cb9af Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Tue, 4 Jun 2013 11:39:36 +0200 Subject: [PATCH] wayland: Support gdk_window_get_scale We track the list of outputs each window is on, and set the scale to the largest scale value of the outputs. Any time the scale changes we also emit a configure event. --- gdk/wayland/gdkwindow-wayland.c | 96 +++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 10 deletions(-) diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c index 1e7eba1f6c..f872049d04 100644 --- a/gdk/wayland/gdkwindow-wayland.c +++ b/gdk/wayland/gdkwindow-wayland.c @@ -145,6 +145,7 @@ struct _GdkWindowImplWayland gboolean use_custom_surface; + guint32 scale; gboolean pending_commit; gint64 pending_frame_counter; }; @@ -154,11 +155,15 @@ struct _GdkWindowImplWaylandClass GdkWindowImplClass parent_class; }; +static void gdk_wayland_window_configure (GdkWindow *window, + int width, int height, int edges); + G_DEFINE_TYPE (GdkWindowImplWayland, _gdk_window_impl_wayland, GDK_TYPE_WINDOW_IMPL) static void _gdk_window_impl_wayland_init (GdkWindowImplWayland *impl) { + impl->scale = 1; } void @@ -391,6 +396,7 @@ typedef struct _GdkWaylandCairoSurfaceData { struct wl_buffer *buffer; GdkWaylandDisplay *display; int32_t width, height; + uint32_t scale; gboolean busy; } GdkWaylandCairoSurfaceData; @@ -419,6 +425,44 @@ on_frame_clock_after_paint (GdkFrameClock *clock, data->busy = TRUE; } +static void +window_update_scale (GdkWindow *window) +{ + GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); + GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window)); + guint32 scale; + GSList *l; + + scale = 1; + for (l = impl->outputs; l != NULL; l = l->next) + { + guint32 output_scale = + _gdk_wayland_screen_get_output_scale (wayland_display->screen, + l->data); + scale = MAX (scale, output_scale); + } + +#ifndef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE + /* Don't announce a scale if we can't support it */ + scale = 1; +#endif + + if (scale != impl->scale) + { + impl->scale = scale; + + /* Notify app that scale changed */ + gdk_wayland_window_configure (window, window->width, window->height, impl->resize_edges); + } +} + +static void +on_monitors_changed (GdkScreen *screen, + GdkWindow *window) +{ + window_update_scale (window); +} + void _gdk_wayland_display_create_window_impl (GdkDisplay *display, GdkWindow *window, @@ -449,6 +493,9 @@ _gdk_wayland_display_create_window_impl (GdkDisplay *display, g_object_ref (window); + /* More likely to be right than just assuming 1 */ + impl->scale = gdk_screen_get_monitor_scale_factor (screen, 0); + impl->title = NULL; switch (GDK_WINDOW_TYPE (window)) @@ -477,6 +524,9 @@ _gdk_wayland_display_create_window_impl (GdkDisplay *display, G_CALLBACK (on_frame_clock_before_paint), window); g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), window); + + g_signal_connect (screen, "monitors-changed", + G_CALLBACK (on_monitors_changed), window); } static void @@ -528,6 +578,8 @@ gdk_wayland_window_attach_image (GdkWindow *window) /* Attach this new buffer to the surface */ wl_surface_attach (impl->surface, data->buffer, dx, dy); + wl_surface_set_buffer_scale (impl->surface, data->scale); + impl->pending_commit = TRUE; } @@ -609,7 +661,7 @@ static const struct wl_buffer_listener buffer_listener = { static cairo_surface_t * gdk_wayland_create_cairo_surface (GdkWaylandDisplay *display, - int width, int height) + int width, int height, guint scale) { GdkWaylandCairoSurfaceData *data; cairo_surface_t *surface = NULL; @@ -621,29 +673,34 @@ gdk_wayland_create_cairo_surface (GdkWaylandDisplay *display, data->buffer = NULL; data->width = width; data->height = height; + data->scale = scale; data->busy = FALSE; stride = width * 4; data->pool = _create_shm_pool (display->shm, - width, height, + width*scale, height*scale, &data->buf_length, &data->buf); data->buffer = wl_shm_pool_create_buffer (data->pool, 0, - width, height, - stride, WL_SHM_FORMAT_ARGB8888); + width*scale, height*scale, + stride*scale, WL_SHM_FORMAT_ARGB8888); wl_buffer_add_listener (data->buffer, &buffer_listener, data); surface = cairo_image_surface_create_for_data (data->buf, CAIRO_FORMAT_ARGB32, - width, - height, - stride); + width*scale, + height*scale, + stride*scale); cairo_surface_set_user_data (surface, &gdk_wayland_cairo_key, data, gdk_wayland_cairo_surface_destroy); +#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE + cairo_surface_set_device_scale (surface, scale, scale); +#endif + status = cairo_surface_status (surface); if (status != CAIRO_STATUS_SUCCESS) { @@ -665,8 +722,9 @@ gdk_wayland_window_ensure_cairo_surface (GdkWindow *window) impl->cairo_surface = gdk_wayland_create_cairo_surface (display_wayland, - impl->wrapper->width, - impl->wrapper->height); + impl->wrapper->width, + impl->wrapper->height, + impl->scale); } } @@ -727,7 +785,7 @@ gdk_wayland_window_configure (GdkWindow *window, display = gdk_window_get_display (window); - /* TODO: Only generate a configure event if width or height have actually + /* TODO: Only generate a configure event if width/height/scale have actually * changed? */ event = gdk_event_new (GDK_CONFIGURE); @@ -841,6 +899,8 @@ surface_enter (void *data, GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); impl->outputs = g_slist_prepend (impl->outputs, output); + + window_update_scale (window); } static void @@ -852,8 +912,11 @@ surface_leave (void *data, GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); impl->outputs = g_slist_remove (impl->outputs, output); + + window_update_scale (window); } + static void shell_surface_handle_configure(void *data, struct wl_shell_surface *shell_surface, @@ -1905,6 +1968,18 @@ gdk_wayland_window_delete_property (GdkWindow *window, { } +static gint +gdk_wayland_window_get_scale_factor (GdkWindow *window) +{ + GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); + + if (GDK_WINDOW_DESTROYED (window)) + return 1; + + return impl->scale; +} + + static void _gdk_window_impl_wayland_class_init (GdkWindowImplWaylandClass *klass) { @@ -1991,6 +2066,7 @@ _gdk_window_impl_wayland_class_init (GdkWindowImplWaylandClass *klass) impl_class->get_property = gdk_wayland_window_get_property; impl_class->change_property = gdk_wayland_window_change_property; impl_class->delete_property = gdk_wayland_window_delete_property; + impl_class->get_scale_factor = gdk_wayland_window_get_scale_factor; }