Skip to content

Commit

Permalink
Gtk/Wayland: Different workaround for Gtk damage bug.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bearoso committed Sep 12, 2024
1 parent ea24305 commit 0c547f3
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 14 deletions.
10 changes: 10 additions & 0 deletions common/video/opengl/wayland_egl_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,13 @@ void WaylandEGLContext::swap_interval(int frames)
{
eglSwapInterval(egl_display, frames);
}

void WaylandEGLContext::shrink()
{
wayland_surface->shrink();
}

void WaylandEGLContext::regrow()
{
wayland_surface->regrow();
}
2 changes: 2 additions & 0 deletions common/video/opengl/wayland_egl_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class WaylandEGLContext : public OpenGLContext
void swap_buffers();
void swap_interval(int frames);
void make_current();
void shrink();
void regrow();
bool ready();

EGLDisplay egl_display;
Expand Down
39 changes: 33 additions & 6 deletions common/video/wayland/wayland_surface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ static void wl_global(void *data,
auto wl = (WaylandSurface *)data;

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"))
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))
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))
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))
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,
Expand Down Expand Up @@ -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) };
}

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)
{
metrics = m;
auto [w, h] = get_size();

wl_subsurface_set_position(subsurface, m.x, m.y);

Expand Down
2 changes: 2 additions & 0 deletions common/video/wayland/wayland_surface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class WaylandSurface

bool attach(wl_display *display, wl_surface *surface, Metrics source_metrics);
void resize(Metrics new_metrics);
void shrink();
void regrow();
std::tuple<int, int> get_size();
std::tuple<int, int> get_size_for_metrics(Metrics m);

Expand Down
2 changes: 2 additions & 0 deletions gtk/src/gtk_display_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class S9xDisplayDriver
virtual bool can_throttle() { return false; };
virtual int get_width() = 0;
virtual int get_height() = 0;
virtual void shrink() {};
virtual void regrow() {};

protected:
Snes9xWindow *window;
Expand Down
20 changes: 20 additions & 0 deletions gtk/src/gtk_display_driver_opengl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,3 +522,23 @@ bool S9xOpenGLDisplayDriver::is_ready()

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
}
2 changes: 2 additions & 0 deletions gtk/src/gtk_display_driver_opengl.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver
bool can_throttle() override { return true; }
int get_width() final override { return output_window_width; }
int get_height() final override { return output_window_height; }
void shrink() override;
void regrow() override;

private:
bool opengl_defaults();
Expand Down
16 changes: 16 additions & 0 deletions gtk/src/gtk_display_driver_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,20 @@ void S9xVulkanDisplayDriver::save(const char *filename)
bool S9xVulkanDisplayDriver::is_ready()
{
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
}
2 changes: 2 additions & 0 deletions gtk/src/gtk_display_driver_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class S9xVulkanDisplayDriver : public S9xDisplayDriver
bool can_throttle() override { return true; }
int get_width() final override { return current_width; }
int get_height() final override { return current_height; }
void shrink() override;
void regrow() override;

static int query_availability();

Expand Down
22 changes: 14 additions & 8 deletions gtk/src/gtk_s9xwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,16 +1144,16 @@ static void set_bypass_compositor(Display *dpy, Window window, unsigned char byp

void Snes9xWindow::enter_fullscreen_mode()
{
int rom_loaded = config->rom_loaded;
bool rom_loaded = config->rom_loaded;

if (config->fullscreen)
return;

GdkDisplay *gdk_display = window->get_display()->gobj();
GdkWindow *gdk_window = window->get_window()->gobj();

config->rom_loaded = 0;
config->fullscreen = 1;
config->rom_loaded = false;
config->fullscreen = true;

#ifdef GDK_WINDOWING_X11
if (config->change_display_resolution && GDK_IS_X11_WINDOW(gdk_window))
Expand Down Expand Up @@ -1232,7 +1232,7 @@ void Snes9xWindow::enter_fullscreen_mode()

void Snes9xWindow::leave_fullscreen_mode()
{
int rom_loaded = config->rom_loaded;
bool rom_loaded = config->rom_loaded;

if (!config->fullscreen)
return;
Expand All @@ -1250,7 +1250,7 @@ void Snes9xWindow::leave_fullscreen_mode()
GdkDisplay *gdk_display = window->get_display()->gobj();
GdkWindow *gdk_window = window->get_window()->gobj();

config->rom_loaded = 0;
config->rom_loaded = false;

#ifdef GDK_WINDOWING_X11
if (config->change_display_resolution && GDK_IS_X11_WINDOW(gdk_window))
Expand Down Expand Up @@ -1280,10 +1280,15 @@ void Snes9xWindow::leave_fullscreen_mode()
}
#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
if (GDK_IS_WAYLAND_WINDOW(gdk_window))
{
S9xDeinitDisplay();
if (driver)
driver->shrink();
}
#endif

Expand All @@ -1301,14 +1306,15 @@ void Snes9xWindow::leave_fullscreen_mode()
#endif

config->rom_loaded = rom_loaded;
config->fullscreen = 0;
config->fullscreen = false;
configure_widgets();
window->show();

#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(gdk_window))
{
S9xReinitDisplay();
if (driver)
driver->regrow();
}
#endif

Expand Down

0 comments on commit 0c547f3

Please sign in to comment.