diff --git a/clients/meson.build b/clients/meson.build index eca13b15..7461cd2e 100644 --- a/clients/meson.build +++ b/clients/meson.build @@ -14,6 +14,8 @@ srcs_toytoolkit = [ pointer_constraints_unstable_v1_protocol_c, ivi_application_client_protocol_h, ivi_application_protocol_c, + viewporter_client_protocol_h, + viewporter_protocol_c, ] deps_toytoolkit = [ dep_wayland_client, diff --git a/clients/window.c b/clients/window.c index 06a74321..5f250d52 100644 --- a/clients/window.c +++ b/clients/window.c @@ -82,6 +82,7 @@ typedef void *EGLContext; #include "shared/string-helpers.h" #include "window.h" +#include "viewporter-client-protocol.h" #define ZWP_RELATIVE_POINTER_MANAGER_V1_VERSION 1 #define ZWP_POINTER_CONSTRAINTS_V1_VERSION 1 @@ -147,6 +148,7 @@ struct display { int has_rgb565; int data_device_manager_version; + struct wp_viewporter *viewporter; }; struct window_output { @@ -222,6 +224,7 @@ struct surface { cairo_surface_t *cairo_surface; struct wl_list link; + struct wp_viewport *viewport; }; struct window { @@ -320,6 +323,8 @@ struct widget { * redraw handler is going to do completely custom rendering * such as using EGL directly */ int use_cairo; + int viewport_dest_width; + int viewport_dest_height; }; struct touch_point { @@ -1398,6 +1403,7 @@ display_get_pointer_image(struct display *display, int pointer) static void surface_flush(struct surface *surface) { + struct widget *widget = surface->widget; if (!surface->cairo_surface) return; @@ -1415,6 +1421,12 @@ surface_flush(struct surface *surface) surface->input_region = NULL; } + if (surface->viewport) { + wp_viewport_set_destination(surface->viewport, + widget->viewport_dest_width, + widget->viewport_dest_height); + } + surface->toysurface->swap(surface->toysurface, surface->buffer_transform, surface->buffer_scale, &surface->server_allocation); @@ -1620,6 +1632,8 @@ static struct widget * widget_find_widget(struct widget *widget, int32_t x, int32_t y) { struct widget *child, *target; + int alloc_x, alloc_y, width, height; + double scale; wl_list_for_each(child, &widget->child_list, link) { target = widget_find_widget(child, x, y); @@ -1627,10 +1641,24 @@ widget_find_widget(struct widget *widget, int32_t x, int32_t y) return target; } - if (widget->allocation.x <= x && - x < widget->allocation.x + widget->allocation.width && - widget->allocation.y <= y && - y < widget->allocation.y + widget->allocation.height) { + alloc_x = widget->allocation.x; + alloc_y = widget->allocation.y; + width = widget->allocation.width; + height = widget->allocation.height; + + if (widget->viewport_dest_width != -1 && + widget->viewport_dest_height != -1) { + scale = widget->viewport_dest_width / (double) width; + alloc_x = alloc_x * scale; + width = widget->viewport_dest_width; + + scale = widget->viewport_dest_height / (double) height; + alloc_y = alloc_y * scale; + height = widget->viewport_dest_height; + } + + if (alloc_x <= x && x < alloc_x + width && + alloc_y <= y && y < alloc_y + height) { return widget; } @@ -1668,6 +1696,8 @@ widget_create(struct window *window, struct surface *surface, void *data) widget->tooltip_count = 0; widget->default_cursor = CURSOR_LEFT_PTR; widget->use_cairo = 1; + widget->viewport_dest_width = -1; + widget->viewport_dest_height = -1; return widget; } @@ -2025,6 +2055,39 @@ widget_set_use_cairo(struct widget *widget, widget->use_cairo = use_cairo; } +int +widget_set_viewport_destination(struct widget *widget, int width, int height) +{ + struct window *window = widget->window; + struct display *display = window->display; + struct surface *surface = widget->surface; + if (!display->viewporter) + return -1; + + if (width == -1 && height == -1) { + if (surface->viewport) { + wp_viewport_destroy(surface->viewport); + surface->viewport = NULL; + } + + widget->viewport_dest_width = -1; + widget->viewport_dest_height = -1; + return 0; + } + + if (!surface->viewport) { + surface->viewport = wp_viewporter_get_viewport(display->viewporter, + surface->surface); + if (!surface->viewport) + return -1; + } + + widget->viewport_dest_width = width; + widget->viewport_dest_height = height; + + return 0; +} + cairo_surface_t * window_get_surface(struct window *window) { @@ -5165,6 +5228,7 @@ surface_create(struct window *window) wl_surface_add_listener(surface->surface, &surface_listener, window); wl_list_insert(&window->subsurface_list, &surface->link); + surface->viewport = NULL; return surface; } @@ -6003,6 +6067,10 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, d->subcompositor = wl_registry_bind(registry, id, &wl_subcompositor_interface, 1); + } else if (!strcmp(interface, "wp_viewporter")) { + d->viewporter = + wl_registry_bind(registry, id, + &wp_viewporter_interface, 1); } if (d->global_handler) diff --git a/clients/window.h b/clients/window.h index 57e24331..53bcb083 100644 --- a/clients/window.h +++ b/clients/window.h @@ -613,6 +613,14 @@ widget_schedule_redraw(struct widget *widget); void widget_set_use_cairo(struct widget *widget, int use_cairo); +/* + * Sets the viewport destination for the widget's surface + * return 0 on success and -1 on failure. Set width and height to + * -1 to reset the viewport. + */ +int +widget_set_viewport_destination(struct widget *widget, int width, int height); + struct widget * window_frame_create(struct window *window, void *data);