Gtk/Wayland: Support fractional scale.

This commit is contained in:
BearOso 2023-03-05 17:43:05 -06:00
parent 9972e2df56
commit f1286eda4c
4 changed files with 97 additions and 19 deletions

View File

@ -140,7 +140,9 @@ if(USE_WAYLAND)
src/gtk_wayland_egl_context.h
src/gtk_wayland_surface.cpp
src/gtk_wayland_surface.h
src/wayland-idle-inhibit-unstable-v1.c)
src/wayland-idle-inhibit-unstable-v1.c
src/viewporter-client-protocol.c
src/fractional-scale-v1.c)
list(APPEND ARGS ${WAYLAND_CFLAGS})
list(APPEND LIBS ${WAYLAND_LIBRARIES})
endif()

View File

@ -31,26 +31,29 @@ void S9xVulkanDisplayDriver::refresh()
if (!context)
return;
bool vsync_changed = context->swapchain->set_vsync(gui_config->sync_to_vblank);
context->swapchain->set_vsync(gui_config->sync_to_vblank);
int new_width, new_height;
auto new_width = drawing_area->get_width() * drawing_area->get_scale_factor();
auto new_height = drawing_area->get_height() * drawing_area->get_scale_factor();
if (new_width != current_width || new_height != current_height || vsync_changed)
{
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(drawing_area->get_window()->gobj()))
{
wayland_surface->resize();
std::tie(new_width, new_height) = wayland_surface->get_size();
}
else
#endif
{
new_width = drawing_area->get_width() * drawing_area->get_scale_factor();
new_height = drawing_area->get_height() * drawing_area->get_scale_factor();
}
if (new_width != current_width || new_height != current_height)
{
context->recreate_swapchain(new_width, new_height);
context->wait_idle();
current_width = new_width;
current_height = new_height;
}
context->swapchain->set_vsync(gui_config->sync_to_vblank);
}
int S9xVulkanDisplayDriver::init()

View File

@ -6,10 +6,13 @@
#include <stdio.h>
#include <string.h>
#include <wayland-util.h>
#include "fractional-scale-v1.h"
#include "gtk_s9x.h"
#include "gtk_wayland_surface.h"
#include "wayland-idle-inhibit-unstable-v1.h"
#include "viewporter-client-protocol.h"
static void wl_global(void *data,
struct wl_registry *wl_registry,
@ -25,6 +28,10 @@ static void wl_global(void *data,
wl->subcompositor = (struct wl_subcompositor *)wl_registry_bind(wl_registry, name, &wl_subcompositor_interface, 1);
else if (!strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name))
wl->idle_inhibit_manager = (struct zwp_idle_inhibit_manager_v1 *)wl_registry_bind(wl_registry, name, &zwp_idle_inhibit_manager_v1_interface, 1);
else if (!strcmp(interface, wp_viewporter_interface.name))
wl->viewporter = (struct wp_viewporter *)wl_registry_bind(wl_registry, name, &wp_viewporter_interface, 1);
else if (!strcmp(interface, wp_fractional_scale_manager_v1_interface.name))
wl->fractional_scale_manager = (struct wp_fractional_scale_manager_v1 *)wl_registry_bind(wl_registry, name, &wp_fractional_scale_manager_v1_interface, 1);
}
static void wl_global_remove(void *data,
@ -50,6 +57,11 @@ WaylandSurface::WaylandSurface()
subsurface = nullptr;
idle_inhibit_manager = nullptr;
idle_inhibitor = nullptr;
viewporter = nullptr;
viewport = nullptr;
fractional_scale_manager = nullptr;
fractional_scale = nullptr;
actual_scale = 0.0;
}
WaylandSurface::~WaylandSurface()
@ -68,8 +80,32 @@ WaylandSurface::~WaylandSurface()
if (child)
wl_surface_destroy(child);
if (viewporter)
wp_viewporter_destroy(viewporter);
if (viewport)
wp_viewport_destroy(viewport);
if (fractional_scale_manager)
wp_fractional_scale_manager_v1_destroy(fractional_scale_manager);
if (fractional_scale)
wp_fractional_scale_v1_destroy(fractional_scale);
}
static void preferred_scale(void *data,
struct wp_fractional_scale_v1 *wp_fractional_scale_v1,
uint32_t scale)
{
((WaylandSurface *)data)->actual_scale = scale / 120.0;
}
wp_fractional_scale_v1_listener fractional_scale_v1_listener =
{
preferred_scale
};
bool WaylandSurface::attach(GtkWidget *widget)
{
GdkWindow *window = gtk_widget_get_window(widget);
@ -79,6 +115,7 @@ bool WaylandSurface::attach(GtkWidget *widget)
gdk_window = window;
gdk_window_get_geometry(gdk_window, &x, &y, &width, &height);
gdk_scale = gdk_window_get_scale_factor(gdk_window);
display = gdk_wayland_display_get_wl_display(gdk_window_get_display(gdk_window));
parent = gdk_wayland_window_get_wl_surface(gdk_window);
@ -98,22 +135,47 @@ bool WaylandSurface::attach(GtkWidget *widget)
wl_subsurface_set_desync(subsurface);
wl_subsurface_set_position(subsurface, x, y);
if (fractional_scale_manager)
{
fractional_scale = wp_fractional_scale_manager_v1_get_fractional_scale(fractional_scale_manager, child);
wp_fractional_scale_v1_add_listener(fractional_scale, &fractional_scale_v1_listener, this);
}
if (idle_inhibit_manager && gui_config->prevent_screensaver)
{
printf("Inhibiting screensaver.\n");
zwp_idle_inhibit_manager_v1_create_inhibitor(idle_inhibit_manager, child);
}
auto scale = gdk_window_get_scale_factor(window);
wl_surface_set_buffer_scale(child, scale);
return true;
}
std::tuple<int, int> WaylandSurface::get_size()
{
gdk_window_get_geometry(gdk_window, &x, &y, &width, &height);
if (actual_scale == 0.0)
{
gdk_scale = gdk_window_get_scale_factor(gdk_window);
return { width * gdk_scale, height * gdk_scale };
}
return { width * actual_scale, height * actual_scale };
}
void WaylandSurface::resize()
{
gdk_window_get_geometry(gdk_window, &x, &y, &width, &height);
auto scale = gdk_window_get_scale_factor(gdk_window);
int w, h; std::tie(w, h) = get_size();
wl_subsurface_set_position(subsurface, x, y);
wl_surface_set_buffer_scale(child, scale);
if (!viewport)
viewport = wp_viewporter_get_viewport(viewporter, child);
wp_viewport_set_source(viewport,
wl_fixed_from_int(0), wl_fixed_from_int(0),
wl_fixed_from_int(w), wl_fixed_from_int(h));
wp_viewport_set_destination(viewport, width, height);
wl_surface_commit(child);
}

View File

@ -7,6 +7,8 @@
#pragma once
#include "gtk_compat.h"
#include "viewporter-client-protocol.h"
#include "fractional-scale-v1.h"
class WaylandSurface
{
@ -15,6 +17,7 @@ class WaylandSurface
~WaylandSurface();
bool attach(GtkWidget *widget);
void resize();
std::tuple<int, int> get_size();
GdkWindow *gdk_window;
@ -32,7 +35,15 @@ class WaylandSurface
int y;
int width;
int height;
int gdk_scale;
double actual_scale;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
struct wp_viewporter *viewporter;
struct wp_viewport *viewport;
struct wp_fractional_scale_manager_v1 *fractional_scale_manager;
struct wp_fractional_scale_v1 *fractional_scale;
};