Gtk: Make wayland surfaces toolkit-agnostic.

This commit is contained in:
BearOso 2023-05-31 17:08:52 -05:00
parent 02ebcb496a
commit cb6df570a4
6 changed files with 65 additions and 51 deletions

View File

@ -65,6 +65,14 @@ static const GLchar *stock_fragment_shader_140 =
" fragcolor = texture(texmap, texcoord);\n" " fragcolor = texture(texmap, texcoord);\n"
"}\n"; "}\n";
#ifdef GDK_WINDOWING_WAYLAND
static WaylandSurface::Metrics get_metrics(Gtk::DrawingArea &w)
{
int x, y, width, height;
w.get_window()->get_geometry(x, y, width, height);
return { x, y, width, height, w.get_window()->get_scale_factor() };
}
#endif
static GLfloat coords[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, static GLfloat coords[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, };
@ -335,7 +343,20 @@ void S9xOpenGLDisplayDriver::refresh()
void S9xOpenGLDisplayDriver::resize() void S9xOpenGLDisplayDriver::resize()
{ {
context->resize(); #ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(gdk_window))
{
((WaylandEGLContext *)context)->resize(get_metrics(*drawing_area));
}
#endif
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_WINDOW(gdk_window))
{
context->resize();
}
#endif
context->swap_interval(config->sync_to_vblank); context->swap_interval(config->sync_to_vblank);
Gtk::Allocation allocation = drawing_area->get_allocation(); Gtk::Allocation allocation = drawing_area->get_allocation();
output_window_width = allocation.get_width(); output_window_width = allocation.get_width();
@ -350,7 +371,9 @@ bool S9xOpenGLDisplayDriver::create_context()
#ifdef GDK_WINDOWING_WAYLAND #ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(gdk_window)) if (GDK_IS_WAYLAND_WINDOW(gdk_window))
{ {
if (!wl.attach(GTK_WIDGET(drawing_area->gobj()))) wl_surface *surface = gdk_wayland_window_get_wl_surface(drawing_area->get_window()->gobj());
wl_display *display = gdk_wayland_display_get_wl_display(drawing_area->get_display()->gobj());
if (!wl.attach(display, surface, get_metrics(*drawing_area)))
return false; return false;
context = &wl; context = &wl;
} }

View File

@ -15,6 +15,15 @@
#include "snes9x_imgui.h" #include "snes9x_imgui.h"
#include "../../external/imgui/imgui_impl_vulkan.h" #include "../../external/imgui/imgui_impl_vulkan.h"
#ifdef GDK_WINDOWING_WAYLAND
static WaylandSurface::Metrics get_metrics(Gtk::DrawingArea &w)
{
int x, y, width, height;
w.get_window()->get_geometry(x, y, width, height);
return { x, y, width, height, w.get_window()->get_scale_factor() };
}
#endif
S9xVulkanDisplayDriver::S9xVulkanDisplayDriver(Snes9xWindow *_window, Snes9xConfig *_config) S9xVulkanDisplayDriver::S9xVulkanDisplayDriver(Snes9xWindow *_window, Snes9xConfig *_config)
{ {
window = _window; window = _window;
@ -83,7 +92,7 @@ void S9xVulkanDisplayDriver::refresh()
#ifdef GDK_WINDOWING_WAYLAND #ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(drawing_area->get_window()->gobj())) if (GDK_IS_WAYLAND_WINDOW(drawing_area->get_window()->gobj()))
{ {
wayland_surface->resize(); wayland_surface->resize(get_metrics(*drawing_area));
std::tie(new_width, new_height) = wayland_surface->get_size(); std::tie(new_width, new_height) = wayland_surface->get_size();
} }
else else
@ -113,7 +122,9 @@ int S9xVulkanDisplayDriver::init()
if (GDK_IS_WAYLAND_WINDOW(drawing_area->get_window()->gobj())) if (GDK_IS_WAYLAND_WINDOW(drawing_area->get_window()->gobj()))
{ {
wayland_surface = std::make_unique<WaylandSurface>(); wayland_surface = std::make_unique<WaylandSurface>();
if (!wayland_surface->attach(GTK_WIDGET(drawing_area->gobj()))) wl_surface *surface = gdk_wayland_window_get_wl_surface(drawing_area->get_window()->gobj());
wl_display *display = gdk_wayland_display_get_wl_display(drawing_area->get_display()->gobj());
if (!wayland_surface->attach(display, surface, get_metrics(*drawing_area)))
{ {
return -1; return -1;
} }

View File

@ -33,15 +33,10 @@ WaylandEGLContext::~WaylandEGLContext()
wl_egl_window_destroy(egl_window); wl_egl_window_destroy(egl_window);
} }
bool WaylandEGLContext::attach(GtkWidget *widget) bool WaylandEGLContext::attach(wl_display *display, wl_surface *surface, WaylandSurface::Metrics m)
{ {
GdkWindow *window = gtk_widget_get_window(widget);
if (!GDK_IS_WAYLAND_WINDOW(window))
return false;
wayland_surface = std::make_unique<WaylandSurface>(); wayland_surface = std::make_unique<WaylandSurface>();
wayland_surface->attach(widget); wayland_surface->attach(display, surface, m);
return true; return true;
} }
@ -109,9 +104,9 @@ bool WaylandEGLContext::create_context()
return true; return true;
} }
void WaylandEGLContext::resize() void WaylandEGLContext::resize(WaylandSurface::Metrics m)
{ {
wayland_surface->resize(); wayland_surface->resize(m);
std::tie(width, height) = wayland_surface->get_size(); std::tie(width, height) = wayland_surface->get_size();
wl_egl_window_resize(egl_window, width, height, 0, 0); wl_egl_window_resize(egl_window, width, height, 0, 0);

View File

@ -9,7 +9,6 @@
#include "gtk_opengl_context.h" #include "gtk_opengl_context.h"
#include "gtk_wayland_surface.h" #include "gtk_wayland_surface.h"
#include "gtk_compat.h"
#include <epoxy/egl.h> #include <epoxy/egl.h>
#include <memory> #include <memory>
@ -20,16 +19,15 @@ class WaylandEGLContext : public OpenGLContext
public: public:
WaylandEGLContext(); WaylandEGLContext();
~WaylandEGLContext(); ~WaylandEGLContext();
bool attach(GtkWidget *widget); bool attach(wl_display *display, wl_surface *surface, WaylandSurface::Metrics m);
bool create_context(); bool create_context();
void resize(); void resize() {};
void resize(WaylandSurface::Metrics m);
void swap_buffers(); void swap_buffers();
void swap_interval(int frames); void swap_interval(int frames);
void make_current(); void make_current();
bool ready(); bool ready();
GdkWindow *gdk_window;
EGLDisplay egl_display; EGLDisplay egl_display;
EGLSurface egl_surface; EGLSurface egl_surface;
EGLContext egl_context; EGLContext egl_context;

View File

@ -106,19 +106,11 @@ wp_fractional_scale_v1_listener fractional_scale_v1_listener =
preferred_scale preferred_scale
}; };
bool WaylandSurface::attach(GtkWidget *widget) bool WaylandSurface::attach(wl_display *display, wl_surface *surface, Metrics m)
{ {
GdkWindow *window = gtk_widget_get_window(widget); metrics = m;
this->display = display;
if (!GDK_IS_WAYLAND_WINDOW(window)) parent = surface;
return false;
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);
registry = wl_display_get_registry(display); registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &wl_registry_listener, this); wl_registry_add_listener(registry, &wl_registry_listener, this);
@ -133,7 +125,7 @@ bool WaylandSurface::attach(GtkWidget *widget)
wl_surface_set_input_region(child, region); wl_surface_set_input_region(child, region);
wl_subsurface_set_desync(subsurface); wl_subsurface_set_desync(subsurface);
wl_subsurface_set_position(subsurface, x, y); wl_subsurface_set_position(subsurface, m.x, m.y);
if (fractional_scale_manager) if (fractional_scale_manager)
{ {
@ -147,29 +139,26 @@ bool WaylandSurface::attach(GtkWidget *widget)
zwp_idle_inhibit_manager_v1_create_inhibitor(idle_inhibit_manager, child); zwp_idle_inhibit_manager_v1_create_inhibitor(idle_inhibit_manager, child);
} }
resize(); resize(m);
return true; return true;
} }
std::tuple<int, int> WaylandSurface::get_size() std::tuple<int, int> WaylandSurface::get_size()
{ {
gdk_window_get_geometry(gdk_window, &x, &y, &width, &height);
if (actual_scale == 0.0) if (actual_scale == 0.0)
{ {
gdk_scale = gdk_window_get_scale_factor(gdk_window); return { metrics.width * metrics.scale, metrics.height * metrics.scale };
return { width * gdk_scale, height * gdk_scale };
} }
return { width * actual_scale, height * actual_scale }; return { metrics.width * actual_scale, metrics.height * actual_scale };
} }
void WaylandSurface::resize() void WaylandSurface::resize(Metrics m)
{ {
metrics = m;
auto [w, h] = get_size(); auto [w, h] = get_size();
wl_subsurface_set_position(subsurface, x, y); wl_subsurface_set_position(subsurface, m.x, m.y);
if (!viewport) if (!viewport)
viewport = wp_viewporter_get_viewport(viewporter, child); viewport = wp_viewporter_get_viewport(viewporter, child);
@ -177,7 +166,7 @@ void WaylandSurface::resize()
wp_viewport_set_source(viewport, wp_viewport_set_source(viewport,
wl_fixed_from_int(0), wl_fixed_from_int(0), wl_fixed_from_int(0), wl_fixed_from_int(0),
wl_fixed_from_int(w), wl_fixed_from_int(h)); wl_fixed_from_int(w), wl_fixed_from_int(h));
wp_viewport_set_destination(viewport, width, height); wp_viewport_set_destination(viewport, m.width, m.height);
wl_surface_commit(child); wl_surface_commit(child);
wl_surface_commit(parent); wl_surface_commit(parent);

View File

@ -6,7 +6,6 @@
#pragma once #pragma once
#include "gtk_compat.h"
#include "viewporter-client-protocol.h" #include "viewporter-client-protocol.h"
#include "fractional-scale-v1.h" #include "fractional-scale-v1.h"
@ -15,11 +14,14 @@ class WaylandSurface
public: public:
WaylandSurface(); WaylandSurface();
~WaylandSurface(); ~WaylandSurface();
bool attach(GtkWidget *widget);
void resize();
std::tuple<int, int> get_size();
GdkWindow *gdk_window; struct Metrics {
int x, y, width, height, scale;
};
bool attach(wl_display *display, wl_surface *surface, Metrics source_metrics);
void resize(Metrics new_metrics);
std::tuple<int, int> get_size();
struct wl_display *display; struct wl_display *display;
struct wl_registry *registry; struct wl_registry *registry;
@ -31,11 +33,7 @@ class WaylandSurface
struct wl_subsurface *subsurface; struct wl_subsurface *subsurface;
struct wl_region *region; struct wl_region *region;
int x; Metrics metrics;
int y;
int width;
int height;
int gdk_scale;
double actual_scale; double actual_scale;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager; struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;