diff --git a/clients/meson.build b/clients/meson.build index 02d972e1..4df4a63c 100644 --- a/clients/meson.build +++ b/clients/meson.build @@ -128,8 +128,12 @@ simple_clients = [ 'name': 'egl', 'sources': [ 'simple-egl.c', + fractional_scale_v1_client_protocol_h, + fractional_scale_v1_protocol_c, tearing_control_v1_client_protocol_h, tearing_control_v1_protocol_c, + viewporter_client_protocol_h, + viewporter_protocol_c, xdg_shell_client_protocol_h, xdg_shell_protocol_c, ivi_application_client_protocol_h, diff --git a/clients/simple-egl.c b/clients/simple-egl.c index 8c81edd3..9284f165 100644 --- a/clients/simple-egl.c +++ b/clients/simple-egl.c @@ -42,6 +42,8 @@ #include #include +#include "fractional-scale-v1-client-protocol.h" +#include "viewporter-client-protocol.h" #include "xdg-shell-client-protocol.h" #include "tearing-control-v1-client-protocol.h" @@ -71,6 +73,8 @@ struct display { struct wl_cursor *default_cursor; struct wl_surface *cursor_surface; struct wp_tearing_control_manager_v1 *tearing_manager; + struct wp_viewporter *viewporter; + struct wp_fractional_scale_manager_v1 *fractional_scale_manager; struct { EGLDisplay dpy; EGLContext ctx; @@ -93,6 +97,7 @@ struct window { struct geometry logical_size; struct geometry buffer_size; int32_t buffer_scale; + double fractional_buffer_scale; enum wl_output_transform buffer_transform; bool needs_buffer_geometry_update; @@ -112,6 +117,8 @@ struct window { EGLSurface egl_surface; int fullscreen, maximized, opaque, buffer_bpp, frame_sync, delay; struct wp_tearing_control_v1 *tear_control; + struct wp_viewport *viewport; + struct wp_fractional_scale_v1 *fractional_scale_obj; bool tearing, toggled_tearing, tear_enabled; bool vertical_bar; bool fullscreen_ratio; @@ -326,8 +333,8 @@ static void update_buffer_geometry(struct window *window) { enum wl_output_transform new_buffer_transform; - int32_t new_buffer_scale; struct geometry new_buffer_size; + struct geometry new_viewport_dest_size; new_buffer_transform = compute_buffer_transform(window); if (window->buffer_transform != new_buffer_transform) { @@ -336,13 +343,6 @@ update_buffer_geometry(struct window *window) window->buffer_transform); } - new_buffer_scale = compute_buffer_scale(window); - if (window->buffer_scale != new_buffer_scale) { - window->buffer_scale = new_buffer_scale; - wl_surface_set_buffer_scale(window->surface, - window->buffer_scale); - } - switch (window->buffer_transform) { case WL_OUTPUT_TRANSFORM_NORMAL: case WL_OUTPUT_TRANSFORM_180: @@ -360,14 +360,47 @@ update_buffer_geometry(struct window *window) break; } - new_buffer_size.width *= window->buffer_scale; - new_buffer_size.height *= window->buffer_scale; + if (window->fractional_buffer_scale > 0.0) { + if (window->buffer_scale > 1) { + window->buffer_scale = 1; + wl_surface_set_buffer_scale(window->surface, + window->buffer_scale); + } + + new_buffer_size.width = ceil(new_buffer_size.width * + window->fractional_buffer_scale); + new_buffer_size.height = ceil(new_buffer_size.height * + window->fractional_buffer_scale); + } else { + int32_t new_buffer_scale; + + new_buffer_scale = compute_buffer_scale(window); + if (window->buffer_scale != new_buffer_scale) { + window->buffer_scale = new_buffer_scale; + wl_surface_set_buffer_scale(window->surface, + window->buffer_scale); + } + + new_buffer_size.width *= window->buffer_scale; + new_buffer_size.height *= window->buffer_scale; + } if (window->fullscreen && window->fullscreen_ratio) { - int new_buffer_size_min = MIN(new_buffer_size.width, - new_buffer_size.height); + int new_buffer_size_min; + int new_viewport_dest_size_min; + + new_buffer_size_min = MIN(new_buffer_size.width, + new_buffer_size.height); new_buffer_size.width = new_buffer_size_min; new_buffer_size.height = new_buffer_size_min; + + new_viewport_dest_size_min = MIN(window->logical_size.width, + window->logical_size.height); + new_viewport_dest_size.width = new_viewport_dest_size_min; + new_viewport_dest_size.height = new_viewport_dest_size_min; + } else { + new_viewport_dest_size.width = window->logical_size.width; + new_viewport_dest_size.height = window->logical_size.height; } if (window->buffer_size.width != new_buffer_size.width || @@ -379,10 +412,14 @@ update_buffer_geometry(struct window *window) window->buffer_size.height, 0, 0); } + if (window->fractional_buffer_scale > 0.0) + wp_viewport_set_destination(window->viewport, + new_viewport_dest_size.width, + new_viewport_dest_size.height); + window->needs_buffer_geometry_update = false; } - static void init_gl(struct window *window) { @@ -686,6 +723,19 @@ static const struct wl_surface_listener surface_listener = { surface_leave }; +static void fractional_scale_handle_preferred_scale(void *data, + struct wp_fractional_scale_v1 *info, + uint32_t wire_scale) { + struct window *window = data; + + window->fractional_buffer_scale = wire_scale / 120.0; + window->needs_buffer_geometry_update = true; +} + +static const struct wp_fractional_scale_v1_listener fractional_scale_listener = { + .preferred_scale = fractional_scale_handle_preferred_scale, +}; + static void create_surface(struct window *window) { @@ -720,6 +770,17 @@ create_surface(struct window *window) else if (window->maximized) xdg_toplevel_set_maximized(window->xdg_toplevel); + if (display->viewporter && display->fractional_scale_manager) { + window->viewport = wp_viewporter_get_viewport(display->viewporter, + window->surface); + window->fractional_scale_obj = + wp_fractional_scale_manager_v1_get_fractional_scale(display->fractional_scale_manager, + window->surface); + wp_fractional_scale_v1_add_listener(window->fractional_scale_obj, + &fractional_scale_listener, + window); + } + window->wait_for_configure = true; wl_surface_commit(window->surface); } @@ -740,6 +801,10 @@ destroy_surface(struct window *window) xdg_toplevel_destroy(window->xdg_toplevel); if (window->xdg_surface) xdg_surface_destroy(window->xdg_surface); + if (window->viewport) + wp_viewport_destroy(window->viewport); + if (window->fractional_scale_obj) + wp_fractional_scale_v1_destroy(window->fractional_scale_obj); wl_surface_destroy(window->surface); } @@ -1178,6 +1243,15 @@ registry_handle_global(void *data, struct wl_registry *registry, d->tearing_manager = wl_registry_bind(registry, name, &wp_tearing_control_manager_v1_interface, 1); + } else if (strcmp(interface, wp_viewporter_interface.name) == 0) { + d->viewporter = wl_registry_bind(registry, name, + &wp_viewporter_interface, + 1); + } else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) { + d->fractional_scale_manager = + wl_registry_bind(registry, name, + &wp_fractional_scale_manager_v1_interface, + 1); } } @@ -1352,6 +1426,12 @@ out_no_xdg_shell: if (display.compositor) wl_compositor_destroy(display.compositor); + if (display.viewporter) + wp_viewporter_destroy(display.viewporter); + + if (display.fractional_scale_manager) + wp_fractional_scale_manager_v1_destroy(display.fractional_scale_manager); + wl_registry_destroy(display.registry); wl_display_flush(display.display); wl_display_disconnect(display.display); diff --git a/protocol/meson.build b/protocol/meson.build index 382bbbe6..b055816b 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,7 +1,7 @@ dep_scanner = dependency('wayland-scanner', native: true) prog_scanner = find_program(dep_scanner.get_variable(pkgconfig: 'wayland_scanner')) -dep_wp = dependency('wayland-protocols', version: '>= 1.30', +dep_wp = dependency('wayland-protocols', version: '>= 1.31', fallback: ['wayland-protocols', 'wayland_protocols']) dir_wp_base = dep_wp.get_variable(pkgconfig: 'pkgdatadir', internal: 'pkgdatadir') @@ -16,11 +16,12 @@ install_data( ) generated_protocols = [ + [ 'fullscreen-shell', 'unstable', 'v1' ], + [ 'fractional-scale', 'staging', 'v1' ], [ 'input-method', 'unstable', 'v1' ], [ 'input-timestamps', 'unstable', 'v1' ], [ 'ivi-application', 'internal' ], [ 'ivi-hmi-controller', 'internal' ], - [ 'fullscreen-shell', 'unstable', 'v1' ], [ 'linux-dmabuf', 'unstable', 'v1' ], [ 'linux-explicit-synchronization', 'unstable', 'v1' ], [ 'presentation-time', 'stable' ],