diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index c1d24496b34d7..cf53acc37ec74 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -30,6 +30,9 @@ Interface changes - add `--force-render` - add `--wayland-content-type` - deprecate `--drm-atomic` + - add support for the fractional scale protocol in wayland + - in wayland, hidpi window scaling now scales the window by the compositor's + dpi scale factor by default (can be disabled with --no-hidpi-window-scale). --- mpv 0.35.0 --- - add the `--vo=gpu-next` video output driver, as well as the options `--allow-delayed-peak-detect`, `--builtin-scalers`, diff --git a/generated/wayland/meson.build b/generated/wayland/meson.build index 423fc7c76ea3b..368034631920e 100644 --- a/generated/wayland/meson.build +++ b/generated/wayland/meson.build @@ -16,6 +16,11 @@ if features['wayland_protocols_1_27'] [wl_protocol_dir, 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml']] endif +features += {'wayland_protocols_1_31': wayland['deps'][2].version().version_compare('>=1.31')} +if features['wayland_protocols_1_31'] + protocols += [[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml']] +endif + foreach p: protocols xml = join_paths(p) wl_protocols_source += custom_target(xml.underscorify() + '_c', diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c index 2782d465090a8..5a0ecf0806626 100644 --- a/video/out/opengl/context_wayland.c +++ b/video/out/opengl/context_wayland.c @@ -75,8 +75,8 @@ static void resize(struct ra_ctx *ctx) if (!p->egl_window) egl_create_window(ctx); - const int32_t width = wl->scaling * mp_rect_w(wl->geometry); - const int32_t height = wl->scaling * mp_rect_h(wl->geometry); + const int32_t width = mp_rect_w(wl->geometry); + const int32_t height = mp_rect_h(wl->geometry); vo_wayland_set_opaque_region(wl, ctx->opts.want_alpha); if (p->egl_window) @@ -84,6 +84,9 @@ static void resize(struct ra_ctx *ctx) wl->vo->dwidth = width; wl->vo->dheight = height; + + if (wl->fractional_viewport) + vo_wayland_handle_fractional_scale(wl); } static bool wayland_egl_check_visible(struct ra_ctx *ctx) diff --git a/video/out/vo_dmabuf_wayland.c b/video/out/vo_dmabuf_wayland.c index e6ce97f6439bc..626f78436ae27 100644 --- a/video/out/vo_dmabuf_wayland.c +++ b/video/out/vo_dmabuf_wayland.c @@ -156,8 +156,8 @@ static void resize(struct vo *vo) struct mp_rect src; struct mp_rect dst; struct mp_osd_res osd; - const int width = wl->scaling * mp_rect_w(wl->geometry); - const int height = wl->scaling * mp_rect_h(wl->geometry); + const int width = mp_rect_w(wl->geometry); + const int height = mp_rect_h(wl->geometry); vo_wayland_set_opaque_region(wl, 0); vo->dwidth = width; @@ -336,13 +336,6 @@ static int preinit(struct vo *vo) return VO_ERROR; } - if (!vo->wl->viewport) { - MP_FATAL(vo->wl, "Compositor doesn't support the %s protocol!\n", - wp_viewporter_interface.name); - return VO_ERROR; - } - - if (vo->wl->single_pixel_manager) { #if HAVE_WAYLAND_PROTOCOLS_1_27 p->solid_buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer( diff --git a/video/out/vo_wlshm.c b/video/out/vo_wlshm.c index fc9fc705fc1ac..74226673c861f 100644 --- a/video/out/vo_wlshm.c +++ b/video/out/vo_wlshm.c @@ -166,8 +166,8 @@ static int resize(struct vo *vo) { struct priv *p = vo->priv; struct vo_wayland_state *wl = vo->wl; - const int32_t width = wl->scaling * mp_rect_w(wl->geometry); - const int32_t height = wl->scaling * mp_rect_h(wl->geometry); + const int32_t width = mp_rect_w(wl->geometry); + const int32_t height = mp_rect_h(wl->geometry); struct buffer *buf; vo_wayland_set_opaque_region(wl, 0); @@ -188,6 +188,10 @@ static int resize(struct vo *vo) p->free_buffers = buf->next; talloc_free(buf); } + + if (wl->fractional_viewport) + vo_wayland_handle_fractional_scale(wl); + return mp_sws_reinit(p->sws); } diff --git a/video/out/vulkan/context_wayland.c b/video/out/vulkan/context_wayland.c index fe20336a9ef4d..11a544f24e525 100644 --- a/video/out/vulkan/context_wayland.c +++ b/video/out/vulkan/context_wayland.c @@ -114,10 +114,14 @@ static bool resize(struct ra_ctx *ctx) MP_VERBOSE(wl, "Handling resize on the vk side\n"); - const int32_t width = wl->scaling * mp_rect_w(wl->geometry); - const int32_t height = wl->scaling * mp_rect_h(wl->geometry); + const int32_t width = mp_rect_w(wl->geometry); + const int32_t height = mp_rect_h(wl->geometry); vo_wayland_set_opaque_region(wl, ctx->opts.want_alpha); + + if (wl->fractional_viewport) + vo_wayland_handle_fractional_scale(wl); + return ra_vk_ctx_resize(ctx, width, height); } diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index 7987dcef44d44..c5e1f2f5833cc 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -47,6 +47,10 @@ #include "generated/wayland/single-pixel-buffer-v1.h" #endif +#if HAVE_WAYLAND_PROTOCOLS_1_31 +#include "generated/wayland/fractional-scale-v1.h" +#endif + #if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 20 #define HAVE_WAYLAND_1_20 #endif @@ -171,7 +175,7 @@ static int spawn_cursor(struct vo_wayland_state *wl); static void greatest_common_divisor(struct vo_wayland_state *wl, int a, int b); static void remove_output(struct vo_wayland_output *out); static void request_decoration_mode(struct vo_wayland_state *wl, uint32_t mode); -static void set_geometry(struct vo_wayland_state *wl); +static void set_geometry(struct vo_wayland_state *wl, bool resize); static void set_surface_scaling(struct vo_wayland_state *wl); static void window_move(struct vo_wayland_state *wl, uint32_t serial); @@ -676,7 +680,7 @@ static void output_handle_done(void *data, struct wl_output *wl_output) if (wl->current_output && wl->current_output->output == wl_output) { set_surface_scaling(wl); spawn_cursor(wl); - set_geometry(wl); + set_geometry(wl, false); wl->pending_vo_events |= VO_EVENT_DPI; wl->pending_vo_events |= VO_EVENT_RESIZE; } @@ -750,14 +754,14 @@ static void surface_handle_enter(void *data, struct wl_surface *wl_surface, } if (!mp_rect_equals(&old_output_geometry, &wl->current_output->geometry)) { - set_geometry(wl); + set_geometry(wl, false); force_resize = true; } if (!mp_rect_equals(&old_geometry, &wl->geometry) || force_resize) wl->pending_vo_events |= VO_EVENT_RESIZE; - MP_VERBOSE(wl, "Surface entered output %s %s (0x%x), scale = %i, refresh rate = %f Hz\n", + MP_VERBOSE(wl, "Surface entered output %s %s (0x%x), scale = %f, refresh rate = %f Hz\n", o->make, o->model, o->id, wl->scaling, o->refresh_rate); wl->pending_vo_events |= VO_EVENT_WIN_STATE; @@ -909,21 +913,21 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel, } wl->window_size.x0 = 0; wl->window_size.y0 = 0; - wl->window_size.x1 = width; - wl->window_size.y1 = height; + wl->window_size.x1 = round(width * wl->scaling); + wl->window_size.y1 = round(height * wl->scaling); } wl->geometry.x0 = 0; wl->geometry.y0 = 0; - wl->geometry.x1 = width; - wl->geometry.y1 = height; + wl->geometry.x1 = round(width * wl->scaling); + wl->geometry.y1 = round(height * wl->scaling); if (mp_rect_equals(&old_geometry, &wl->geometry)) return; resize: MP_VERBOSE(wl, "Resizing due to xdg from %ix%i to %ix%i\n", - mp_rect_w(old_geometry)*wl->scaling, mp_rect_h(old_geometry)*wl->scaling, - mp_rect_w(wl->geometry)*wl->scaling, mp_rect_h(wl->geometry)*wl->scaling); + mp_rect_w(old_geometry), mp_rect_h(old_geometry), + mp_rect_w(wl->geometry), mp_rect_h(wl->geometry)); wl->pending_vo_events |= VO_EVENT_RESIZE; wl->toplevel_configured = true; @@ -953,6 +957,25 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = { #endif }; +#if HAVE_WAYLAND_PROTOCOLS_1_31 +static void preferred_scale(void *data, + struct wp_fractional_scale_v1 *fractional_scale, + uint32_t scale) +{ + struct vo_wayland_state *wl = data; + wl->scaling = (double)scale / 120; + MP_VERBOSE(wl, "Obtained preferred scale, %f, from the compositor.\n", + wl->scaling); + wl->pending_vo_events |= VO_EVENT_DPI; + if (wl->current_output) + set_geometry(wl, true); +} + +static const struct wp_fractional_scale_v1_listener fractional_scale_listener = { + preferred_scale, +}; +#endif + static const char *zxdg_decoration_mode_to_str(const uint32_t mode) { switch (mode) { @@ -1247,6 +1270,12 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id } #endif +#if HAVE_WAYLAND_PROTOCOLS_1_31 + if (!strcmp(interface, wp_fractional_scale_manager_v1_interface.name) && found++) { + wl->fractional_scale_manager = wl_registry_bind(reg, id, &wp_fractional_scale_manager_v1_interface, 1); + } +#endif + if (!strcmp(interface, wp_presentation_interface.name) && found++) { wl->presentation = wl_registry_bind(reg, id, &wp_presentation_interface, 1); wp_presentation_add_listener(wl->presentation, &pres_listener, wl); @@ -1385,6 +1414,21 @@ static bool create_input(struct vo_wayland_state *wl) return 0; } +static int create_viewports(struct vo_wayland_state *wl) +{ + if (wl->viewporter) { + wl->fractional_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface); + wl->viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface); + wl->video_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->video_surface); + } + + if (!wl->viewporter || !wl->fractional_viewport || !wl->viewport || !wl->video_viewport) { + MP_ERR(wl, "failed to create viewport interfaces!\n"); + return 1; + } + return 0; +} + static int create_xdg_surface(struct vo_wayland_state *wl) { wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->wm_base, wl->surface); @@ -1393,8 +1437,10 @@ static int create_xdg_surface(struct vo_wayland_state *wl) wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface); xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl); - if (!wl->xdg_surface || !wl->xdg_toplevel) + if (!wl->xdg_surface || !wl->xdg_toplevel) { + MP_ERR(wl, "failled to create xdg_surface and xdg_toplevel!\n"); return 1; + } return 0; } @@ -1561,7 +1607,8 @@ static int set_cursor_visibility(struct vo_wayland_state *wl, bool on) return VO_FALSE; wl_pointer_set_cursor(wl->pointer, wl->pointer_id, wl->cursor_surface, img->hotspot_x/wl->scaling, img->hotspot_y/wl->scaling); - wl_surface_set_buffer_scale(wl->cursor_surface, wl->scaling); + if (!wl->fractional_scale_manager) + wl_surface_set_buffer_scale(wl->cursor_surface, wl->scaling); wl_surface_attach(wl->cursor_surface, buffer, 0, 0); wl_surface_damage_buffer(wl->cursor_surface, 0, 0, img->width, img->height); wl_surface_commit(wl->cursor_surface); @@ -1571,14 +1618,14 @@ static int set_cursor_visibility(struct vo_wayland_state *wl, bool on) return VO_TRUE; } -static void set_geometry(struct vo_wayland_state *wl) +static void set_geometry(struct vo_wayland_state *wl, bool resize) { struct vo *vo = wl->vo; assert(wl->current_output); struct vo_win_geometry geo; struct mp_rect screenrc = wl->current_output->geometry; - vo_calc_window_geometry(vo, &screenrc, &geo); + vo_calc_window_geometry2(vo, &screenrc, wl->scaling, &geo); vo_apply_window_geometry(vo, &geo); greatest_common_divisor(wl, vo->dwidth, vo->dheight); @@ -1587,8 +1634,15 @@ static void set_geometry(struct vo_wayland_state *wl) wl->vdparams.x0 = 0; wl->vdparams.y0 = 0; - wl->vdparams.x1 = vo->dwidth / wl->scaling; - wl->vdparams.y1 = vo->dheight / wl->scaling; + wl->vdparams.x1 = vo->dwidth; + wl->vdparams.y1 = vo->dheight; + + if (resize) { + wl->window_size = wl->vdparams; + if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized) + wl->geometry = wl->window_size; + wl->pending_vo_events |= VO_EVENT_RESIZE; + } } static int set_screensaver_inhibitor(struct vo_wayland_state *wl, int state) @@ -1612,19 +1666,15 @@ static int set_screensaver_inhibitor(struct vo_wayland_state *wl, int state) static void set_surface_scaling(struct vo_wayland_state *wl) { bool dmabuf_wayland = !strcmp(wl->vo->driver->name, "dmabuf-wayland"); - int old_scale = wl->scaling; - if (wl->vo_opts->hidpi_window_scale && !dmabuf_wayland) { + if (wl->vo_opts->hidpi_window_scale && !dmabuf_wayland && !wl->fractional_scale_manager) { wl->scaling = wl->current_output->scale; } else { wl->scaling = 1; } - double factor = (double)old_scale / wl->scaling; - wl->vdparams.x1 *= factor; - wl->vdparams.y1 *= factor; - wl->window_size.x1 *= factor; - wl->window_size.y1 *= factor; - wl_surface_set_buffer_scale(wl->surface, wl->scaling); + if (!wl->fractional_scale_manager) { + wl_surface_set_buffer_scale(wl->surface, wl->scaling); + } } static void set_window_bounds(struct vo_wayland_state *wl) @@ -1837,7 +1887,11 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg) if (opt == &opts->fullscreen) toggle_fullscreen(wl); if (opt == &opts->hidpi_window_scale) + { set_surface_scaling(wl); + if (!wl->fractional_scale_manager) + wl->pending_vo_events |= VO_EVENT_RESIZE; + } if (opt == &opts->window_maximized) toggle_maximized(wl); if (opt == &opts->window_minimized) @@ -1845,13 +1899,8 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg) if (opt == &opts->geometry || opt == &opts->autofit || opt == &opts->autofit_smaller || opt == &opts->autofit_larger) { - if (wl->current_output) { - set_geometry(wl); - wl->window_size = wl->vdparams; - if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized) - wl->geometry = wl->window_size; - wl->pending_vo_events |= VO_EVENT_RESIZE; - } + if (wl->current_output) + set_geometry(wl, true); } } return VO_TRUE; @@ -1874,11 +1923,11 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg) case VOCTRL_GET_UNFS_WINDOW_SIZE: { int *s = arg; if (wl->vo_opts->window_maximized) { - s[0] = mp_rect_w(wl->geometry) * wl->scaling; - s[1] = mp_rect_h(wl->geometry) * wl->scaling; + s[0] = mp_rect_w(wl->geometry); + s[1] = mp_rect_h(wl->geometry); } else { - s[0] = mp_rect_w(wl->window_size) * wl->scaling; - s[1] = mp_rect_h(wl->window_size) * wl->scaling; + s[0] = mp_rect_w(wl->window_size); + s[1] = mp_rect_h(wl->window_size); } return VO_TRUE; } @@ -1886,8 +1935,8 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg) int *s = arg; wl->window_size.x0 = 0; wl->window_size.y0 = 0; - wl->window_size.x1 = s[0] / wl->scaling; - wl->window_size.y1 = s[1] / wl->scaling; + wl->window_size.x1 = s[0]; + wl->window_size.y1 = s[1]; if (!wl->vo_opts->fullscreen) { if (wl->vo_opts->window_maximized) { xdg_toplevel_unset_maximized(wl->xdg_toplevel); @@ -1935,6 +1984,13 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg) return VO_NOTIMPL; } +void vo_wayland_handle_fractional_scale(struct vo_wayland_state *wl) +{ + wp_viewport_set_destination(wl->fractional_viewport, + round(mp_rect_w(wl->geometry) / wl->scaling), + round(mp_rect_h(wl->geometry) / wl->scaling)); +} + int vo_wayland_init(struct vo *vo) { vo->wl = talloc_zero(NULL, struct vo_wayland_state); @@ -1988,6 +2044,9 @@ int vo_wayland_init(struct vo *vo) } /* Can't be initialized during registry due to multi-protocol dependence */ + if (create_viewports(wl)) + return false; + if (create_xdg_surface(wl)) return false; @@ -1996,11 +2055,6 @@ int vo_wayland_init(struct vo *vo) wl_subsurface_set_desync(wl->video_subsurface); } - if (wl->viewporter) { - wl->viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface); - wl->video_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->video_surface); - } - const char *xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP"); if (xdg_current_desktop != NULL && strstr(xdg_current_desktop, "GNOME")) MP_WARN(wl, "GNOME's wayland compositor lacks support for the idle inhibit protocol. This means the screen can blank during playback.\n"); @@ -2019,6 +2073,16 @@ int vo_wayland_init(struct vo *vo) } #endif +#if HAVE_WAYLAND_PROTOCOLS_1_31 + if (wl->fractional_scale_manager) { + wl->fractional_scale = wp_fractional_scale_manager_v1_get_fractional_scale(wl->fractional_scale_manager, wl->surface); + wp_fractional_scale_v1_add_listener(wl->fractional_scale, &fractional_scale_listener, wl); + } else { + MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n", + wp_fractional_scale_manager_v1_interface.name); + } +#endif + if (wl->dnd_devman && wl->seat) { wl->dnd_ddev = wl_data_device_manager_get_data_device(wl->dnd_devman, wl->seat); wl_data_device_add_listener(wl->dnd_ddev, &data_device_listener, wl); @@ -2084,7 +2148,7 @@ int vo_wayland_reconfig(struct vo *vo) wl->pending_vo_events |= VO_EVENT_DPI; } - set_geometry(wl); + set_geometry(wl, false); wl->window_size = wl->vdparams; if (wl->opts->configure_bounds) @@ -2112,8 +2176,8 @@ int vo_wayland_reconfig(struct vo *vo) void vo_wayland_set_opaque_region(struct vo_wayland_state *wl, int alpha) { - const int32_t width = wl->scaling * mp_rect_w(wl->geometry); - const int32_t height = wl->scaling * mp_rect_h(wl->geometry); + const int32_t width = mp_rect_w(wl->geometry); + const int32_t height = mp_rect_h(wl->geometry); if (!alpha) { struct wl_region *region = wl_compositor_create_region(wl->compositor); wl_region_add(region, 0, 0, width, height); @@ -2194,6 +2258,14 @@ void vo_wayland_uninit(struct vo *vo) if (wl->frame_callback) wl_callback_destroy(wl->frame_callback); +#if HAVE_WAYLAND_PROTOCOLS_1_31 + if (wl->fractional_scale) + wp_fractional_scale_v1_destroy(wl->fractional_scale); + + if (wl->fractional_scale_manager) + wp_fractional_scale_manager_v1_destroy(wl->fractional_scale_manager); +#endif + if (wl->idle_inhibitor) zwp_idle_inhibitor_v1_destroy(wl->idle_inhibitor); @@ -2215,6 +2287,9 @@ void vo_wayland_uninit(struct vo *vo) if (wl->viewporter) wp_viewporter_destroy(wl->viewporter); + if (wl->fractional_viewport) + wp_viewport_destroy(wl->fractional_viewport); + if (wl->viewport) wp_viewport_destroy(wl->viewport); diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h index 4f505b903bad6..e4ba32357e7c2 100644 --- a/video/out/wayland_common.h +++ b/video/out/wayland_common.h @@ -74,7 +74,7 @@ struct vo_wayland_state { int mouse_x; int mouse_y; int pending_vo_events; - int scaling; + double scaling; int timeout_count; int wakeup_pipe[2]; @@ -84,6 +84,10 @@ struct vo_wayland_state { void *content_type; int current_content_type; + /* fractional-scale */ + void *fractional_scale_manager; + void *fractional_scale; + /* idle-inhibit */ struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager; struct zwp_idle_inhibitor_v1 *idle_inhibitor; @@ -122,6 +126,7 @@ struct vo_wayland_state { /* viewporter */ struct wp_viewporter *viewporter; + struct wp_viewport *fractional_viewport; struct wp_viewport *viewport; struct wp_viewport *video_viewport; @@ -161,6 +166,7 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg); int vo_wayland_init(struct vo *vo); int vo_wayland_reconfig(struct vo *vo); +void vo_wayland_handle_fractional_scale(struct vo_wayland_state *wl); void vo_wayland_set_opaque_region(struct vo_wayland_state *wl, int alpha); void vo_wayland_sync_swap(struct vo_wayland_state *wl); void vo_wayland_uninit(struct vo *vo); diff --git a/wscript b/wscript index 9fc7583225a14..4e1c2a21c0962 100644 --- a/wscript +++ b/wscript @@ -540,6 +540,11 @@ video_output_features = [ 'desc': 'wayland-protocols version 1.27+', 'deps': 'wayland', 'func': check_pkg_config('wayland-protocols >= 1.27'), + } , { + 'name': 'wayland-protocols-1-31', + 'desc': 'wayland-protocols version 1.31+', + 'deps': 'wayland', + 'func': check_pkg_config('wayland-protocols >= 1.31'), } , { 'name': 'memfd_create', 'desc': "Linux's memfd_create()", diff --git a/wscript_build.py b/wscript_build.py index 46138982be27d..344f2c3559720 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -154,6 +154,14 @@ def build(ctx): protocol = "staging/single-pixel-buffer/single-pixel-buffer-v1", target = "generated/wayland/single-pixel-buffer-v1.h") + if ctx.dependency_satisfied('wayland-protocols-1-31'): + ctx.wayland_protocol_code(proto_dir = ctx.env.WL_PROTO_DIR, + protocol = "staging/fractional-scale/fractional-scale-v1", + target = "generated/wayland/fractional-scale-v1.c") + ctx.wayland_protocol_header(proto_dir = ctx.env.WL_PROTO_DIR, + protocol = "staging/content-type/fractional-scale-v1", + target = "generated/wayland/fractional-scale-v1.h") + ctx(features = "ebml_header", target = "generated/ebml_types.h") ctx(features = "ebml_definitions", target = "generated/ebml_defs.inc") @@ -556,6 +564,7 @@ def swift(task): ( "video/out/w32_common.c", "win32-desktop" ), ( "generated/wayland/single-pixel-buffer-v1.c", "wayland-protocols-1-27" ), ( "generated/wayland/content-type-v1.c", "wayland-protocols-1-27" ), + ( "generated/wayland/fractional-scale-v1.c", "wayland-protocols-1-31"), ( "generated/wayland/idle-inhibit-unstable-v1.c", "wayland" ), ( "generated/wayland/presentation-time.c", "wayland" ), ( "generated/wayland/xdg-decoration-unstable-v1.c", "wayland" ),