Gtk/Wayland: Different workaround for Gtk damage bug.

Instead of completely shutting down the display driver, shrink the
subsurface when removing fullscreen so that when the parent window
sends events when it receives damage or is resized.
This commit is contained in:
BearOso 2024-09-12 14:09:00 -05:00
parent ea243051ed
commit 0c547f3486
10 changed files with 103 additions and 14 deletions

View File

@ -145,3 +145,13 @@ void WaylandEGLContext::swap_interval(int frames)
{ {
eglSwapInterval(egl_display, frames); eglSwapInterval(egl_display, frames);
} }
void WaylandEGLContext::shrink()
{
wayland_surface->shrink();
}
void WaylandEGLContext::regrow()
{
wayland_surface->regrow();
}

View File

@ -26,6 +26,8 @@ class WaylandEGLContext : public OpenGLContext
void swap_buffers(); void swap_buffers();
void swap_interval(int frames); void swap_interval(int frames);
void make_current(); void make_current();
void shrink();
void regrow();
bool ready(); bool ready();
EGLDisplay egl_display; EGLDisplay egl_display;

View File

@ -23,15 +23,15 @@ static void wl_global(void *data,
auto wl = (WaylandSurface *)data; auto wl = (WaylandSurface *)data;
if (!strcmp(interface, "wl_compositor")) if (!strcmp(interface, "wl_compositor"))
wl->compositor = (struct wl_compositor *)wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3); wl->compositor = (struct wl_compositor *)wl_registry_bind(wl_registry, name, &wl_compositor_interface, version);
else if (!strcmp(interface, "wl_subcompositor")) else if (!strcmp(interface, "wl_subcompositor"))
wl->subcompositor = (struct wl_subcompositor *)wl_registry_bind(wl_registry, name, &wl_subcompositor_interface, 1); wl->subcompositor = (struct wl_subcompositor *)wl_registry_bind(wl_registry, name, &wl_subcompositor_interface, version);
else if (!strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name)) 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); wl->idle_inhibit_manager = (struct zwp_idle_inhibit_manager_v1 *)wl_registry_bind(wl_registry, name, &zwp_idle_inhibit_manager_v1_interface, version);
else if (!strcmp(interface, wp_viewporter_interface.name)) else if (!strcmp(interface, wp_viewporter_interface.name))
wl->viewporter = (struct wp_viewporter *)wl_registry_bind(wl_registry, name, &wp_viewporter_interface, 1); wl->viewporter = (struct wp_viewporter *)wl_registry_bind(wl_registry, name, &wp_viewporter_interface, version);
else if (!strcmp(interface, wp_fractional_scale_manager_v1_interface.name)) 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); wl->fractional_scale_manager = (struct wp_fractional_scale_manager_v1 *)wl_registry_bind(wl_registry, name, &wp_fractional_scale_manager_v1_interface, version);
} }
static void wl_global_remove(void *data, static void wl_global_remove(void *data,
@ -161,10 +161,37 @@ std::tuple<int, int> WaylandSurface::get_size_for_metrics(Metrics m)
return { round(m.width * actual_scale), round(m.height * actual_scale) }; return { round(m.width * actual_scale), round(m.height * actual_scale) };
} }
void WaylandSurface::shrink()
{
if (!viewport)
viewport = wp_viewporter_get_viewport(viewporter, child);
wp_viewport_set_source(viewport,
wl_fixed_from_int(-1), wl_fixed_from_int(-1),
wl_fixed_from_int(-1), wl_fixed_from_int(-1));
wp_viewport_set_destination(viewport, 2, 2);
wl_surface_commit(child);
wl_surface_commit(parent);
}
void WaylandSurface::regrow()
{
if (!viewport)
viewport = wp_viewporter_get_viewport(viewporter, child);
wp_viewport_set_source(viewport,
wl_fixed_from_int(-1), wl_fixed_from_int(-1),
wl_fixed_from_int(-1), wl_fixed_from_int(-1));
wp_viewport_set_destination(viewport, metrics.width, metrics.height);
wl_surface_commit(child);
wl_surface_commit(parent);
}
void WaylandSurface::resize(Metrics m) void WaylandSurface::resize(Metrics m)
{ {
metrics = m; metrics = m;
auto [w, h] = get_size();
wl_subsurface_set_position(subsurface, m.x, m.y); wl_subsurface_set_position(subsurface, m.x, m.y);

View File

@ -22,6 +22,8 @@ class WaylandSurface
bool attach(wl_display *display, wl_surface *surface, Metrics source_metrics); bool attach(wl_display *display, wl_surface *surface, Metrics source_metrics);
void resize(Metrics new_metrics); void resize(Metrics new_metrics);
void shrink();
void regrow();
std::tuple<int, int> get_size(); std::tuple<int, int> get_size();
std::tuple<int, int> get_size_for_metrics(Metrics m); std::tuple<int, int> get_size_for_metrics(Metrics m);

View File

@ -25,6 +25,8 @@ class S9xDisplayDriver
virtual bool can_throttle() { return false; }; virtual bool can_throttle() { return false; };
virtual int get_width() = 0; virtual int get_width() = 0;
virtual int get_height() = 0; virtual int get_height() = 0;
virtual void shrink() {};
virtual void regrow() {};
protected: protected:
Snes9xWindow *window; Snes9xWindow *window;

View File

@ -522,3 +522,23 @@ bool S9xOpenGLDisplayDriver::is_ready()
return false; return false;
} }
void S9xOpenGLDisplayDriver::shrink()
{
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(gdk_window))
{
((WaylandEGLContext *)context)->shrink();
}
#endif
}
void S9xOpenGLDisplayDriver::regrow()
{
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(gdk_window))
{
((WaylandEGLContext *)context)->regrow();
}
#endif
}

View File

@ -42,6 +42,8 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver
bool can_throttle() override { return true; } bool can_throttle() override { return true; }
int get_width() final override { return output_window_width; } int get_width() final override { return output_window_width; }
int get_height() final override { return output_window_height; } int get_height() final override { return output_window_height; }
void shrink() override;
void regrow() override;
private: private:
bool opengl_defaults(); bool opengl_defaults();

View File

@ -253,4 +253,20 @@ void S9xVulkanDisplayDriver::save(const char *filename)
bool S9xVulkanDisplayDriver::is_ready() bool S9xVulkanDisplayDriver::is_ready()
{ {
return true; return true;
}
void S9xVulkanDisplayDriver::shrink()
{
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(drawing_area->get_window()->gobj()))
wayland_surface->shrink();
#endif
}
void S9xVulkanDisplayDriver::regrow()
{
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(drawing_area->get_window()->gobj()))
wayland_surface->regrow();
#endif
} }

View File

@ -31,6 +31,8 @@ class S9xVulkanDisplayDriver : public S9xDisplayDriver
bool can_throttle() override { return true; } bool can_throttle() override { return true; }
int get_width() final override { return current_width; } int get_width() final override { return current_width; }
int get_height() final override { return current_height; } int get_height() final override { return current_height; }
void shrink() override;
void regrow() override;
static int query_availability(); static int query_availability();

View File

@ -1144,7 +1144,7 @@ static void set_bypass_compositor(Display *dpy, Window window, unsigned char byp
void Snes9xWindow::enter_fullscreen_mode() void Snes9xWindow::enter_fullscreen_mode()
{ {
int rom_loaded = config->rom_loaded; bool rom_loaded = config->rom_loaded;
if (config->fullscreen) if (config->fullscreen)
return; return;
@ -1152,8 +1152,8 @@ void Snes9xWindow::enter_fullscreen_mode()
GdkDisplay *gdk_display = window->get_display()->gobj(); GdkDisplay *gdk_display = window->get_display()->gobj();
GdkWindow *gdk_window = window->get_window()->gobj(); GdkWindow *gdk_window = window->get_window()->gobj();
config->rom_loaded = 0; config->rom_loaded = false;
config->fullscreen = 1; config->fullscreen = true;
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
if (config->change_display_resolution && GDK_IS_X11_WINDOW(gdk_window)) if (config->change_display_resolution && GDK_IS_X11_WINDOW(gdk_window))
@ -1232,7 +1232,7 @@ void Snes9xWindow::enter_fullscreen_mode()
void Snes9xWindow::leave_fullscreen_mode() void Snes9xWindow::leave_fullscreen_mode()
{ {
int rom_loaded = config->rom_loaded; bool rom_loaded = config->rom_loaded;
if (!config->fullscreen) if (!config->fullscreen)
return; return;
@ -1250,7 +1250,7 @@ void Snes9xWindow::leave_fullscreen_mode()
GdkDisplay *gdk_display = window->get_display()->gobj(); GdkDisplay *gdk_display = window->get_display()->gobj();
GdkWindow *gdk_window = window->get_window()->gobj(); GdkWindow *gdk_window = window->get_window()->gobj();
config->rom_loaded = 0; config->rom_loaded = false;
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
if (config->change_display_resolution && GDK_IS_X11_WINDOW(gdk_window)) if (config->change_display_resolution && GDK_IS_X11_WINDOW(gdk_window))
@ -1280,10 +1280,15 @@ void Snes9xWindow::leave_fullscreen_mode()
} }
#endif #endif
// If the window is covered by a subsurface, for some reason Gtk doesn't
// send any resize events or do anything to resize the window. So shrink
// the subsurface's viewport to 2x2 temporarily.
auto driver = S9xDisplayGetDriver();
#ifdef GDK_WINDOWING_WAYLAND #ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(gdk_window)) if (GDK_IS_WAYLAND_WINDOW(gdk_window))
{ {
S9xDeinitDisplay(); if (driver)
driver->shrink();
} }
#endif #endif
@ -1301,14 +1306,15 @@ void Snes9xWindow::leave_fullscreen_mode()
#endif #endif
config->rom_loaded = rom_loaded; config->rom_loaded = rom_loaded;
config->fullscreen = 0; config->fullscreen = false;
configure_widgets(); configure_widgets();
window->show(); window->show();
#ifdef GDK_WINDOWING_WAYLAND #ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(gdk_window)) if (GDK_IS_WAYLAND_WINDOW(gdk_window))
{ {
S9xReinitDisplay(); if (driver)
driver->regrow();
} }
#endif #endif