diff --git a/common/video/opengl/wayland_egl_context.cpp b/common/video/opengl/wayland_egl_context.cpp index 2b528c5a..1f362a68 100644 --- a/common/video/opengl/wayland_egl_context.cpp +++ b/common/video/opengl/wayland_egl_context.cpp @@ -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(); +} \ No newline at end of file diff --git a/common/video/opengl/wayland_egl_context.hpp b/common/video/opengl/wayland_egl_context.hpp index c8bc023a..95f1f3d4 100644 --- a/common/video/opengl/wayland_egl_context.hpp +++ b/common/video/opengl/wayland_egl_context.hpp @@ -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; diff --git a/common/video/wayland/wayland_surface.cpp b/common/video/wayland/wayland_surface.cpp index 04fc687b..1e694e10 100644 --- a/common/video/wayland/wayland_surface.cpp +++ b/common/video/wayland/wayland_surface.cpp @@ -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, @@ -161,10 +161,37 @@ std::tuple 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); diff --git a/common/video/wayland/wayland_surface.hpp b/common/video/wayland/wayland_surface.hpp index 5239737a..5352e539 100644 --- a/common/video/wayland/wayland_surface.hpp +++ b/common/video/wayland/wayland_surface.hpp @@ -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 get_size(); std::tuple get_size_for_metrics(Metrics m); diff --git a/gtk/src/gtk_display_driver.h b/gtk/src/gtk_display_driver.h index da0bba7f..e66e571a 100644 --- a/gtk/src/gtk_display_driver.h +++ b/gtk/src/gtk_display_driver.h @@ -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; diff --git a/gtk/src/gtk_display_driver_opengl.cpp b/gtk/src/gtk_display_driver_opengl.cpp index 039bf38b..bd8e4d6c 100644 --- a/gtk/src/gtk_display_driver_opengl.cpp +++ b/gtk/src/gtk_display_driver_opengl.cpp @@ -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 +} diff --git a/gtk/src/gtk_display_driver_opengl.h b/gtk/src/gtk_display_driver_opengl.h index b94fc82f..473167a8 100644 --- a/gtk/src/gtk_display_driver_opengl.h +++ b/gtk/src/gtk_display_driver_opengl.h @@ -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(); diff --git a/gtk/src/gtk_display_driver_vulkan.cpp b/gtk/src/gtk_display_driver_vulkan.cpp index ce860e4d..54d737e8 100644 --- a/gtk/src/gtk_display_driver_vulkan.cpp +++ b/gtk/src/gtk_display_driver_vulkan.cpp @@ -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 } \ No newline at end of file diff --git a/gtk/src/gtk_display_driver_vulkan.h b/gtk/src/gtk_display_driver_vulkan.h index 78761596..cb363675 100644 --- a/gtk/src/gtk_display_driver_vulkan.h +++ b/gtk/src/gtk_display_driver_vulkan.h @@ -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(); diff --git a/gtk/src/gtk_s9xwindow.cpp b/gtk/src/gtk_s9xwindow.cpp index 4c0dafa5..fa3d5db8 100644 --- a/gtk/src/gtk_s9xwindow.cpp +++ b/gtk/src/gtk_s9xwindow.cpp @@ -1144,7 +1144,7 @@ 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; @@ -1152,8 +1152,8 @@ void Snes9xWindow::enter_fullscreen_mode() 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)) @@ -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; @@ -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)) @@ -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 @@ -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