From 1f334567c8b37e20df074ec761119f8786e4b40f Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Fri, 17 Jul 2026 17:42:52 +0800 Subject: [PATCH] feat(window): add exclusive fullscreen support with WM detection --- include/Cubed/argument.hpp | 1 + include/Cubed/tools/system_info.hpp | 4 +- include/Cubed/tools/system_window_manager.hpp | 45 ++++++ include/Cubed/window.hpp | 4 + src/app.cpp | 6 +- src/window.cpp | 131 ++++++++++++------ 6 files changed, 145 insertions(+), 46 deletions(-) create mode 100644 include/Cubed/tools/system_window_manager.hpp diff --git a/include/Cubed/argument.hpp b/include/Cubed/argument.hpp index 7124ceb..0df551b 100644 --- a/include/Cubed/argument.hpp +++ b/include/Cubed/argument.hpp @@ -9,5 +9,6 @@ struct Argument { std::optional no_debug; std::optional language; std::optional video_driver; + std::optional enable_exclusive; }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/tools/system_info.hpp b/include/Cubed/tools/system_info.hpp index c041111..5e103f0 100644 --- a/include/Cubed/tools/system_info.hpp +++ b/include/Cubed/tools/system_info.hpp @@ -184,14 +184,14 @@ inline std::string get_compiler_info() { #else result = "Unknown Compiler"; #endif - constexpr long cpp_version = + constexpr long CPP_VERSION = #ifdef _MSC_VER _MSVC_LANG; #else __cplusplus; #endif result += " (C++"; - result += std::to_string(cpp_version); + result += std::to_string(CPP_VERSION); result += ")"; return result; diff --git a/include/Cubed/tools/system_window_manager.hpp b/include/Cubed/tools/system_window_manager.hpp new file mode 100644 index 0000000..a573504 --- /dev/null +++ b/include/Cubed/tools/system_window_manager.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "Cubed/tools/log.hpp" + +#include +#include +namespace Cubed { +enum class WindowManager { WINDOWS, UNKNOWN, NIRI, SWAY, HYPRLAND, KDE, GNOME }; + +namespace Tools { +inline WindowManager detect_wm() { +#ifdef _WIN32 + return WindowManager::WINDOWS; +#endif +#ifdef __linux__ + + const char* desktop = getenv("XDG_CURRENT_DESKTOP"); + + if (!desktop) + return WindowManager::UNKNOWN; + Logger::info("XDG_CURRENT_DESKTOP {}", desktop); + std::string wm(desktop); + + if (wm.find("niri") != std::string::npos) + return WindowManager::NIRI; + + if (wm.find("sway") != std::string::npos) + return WindowManager::SWAY; + + if (wm.find("Hyprland") != std::string::npos) + return WindowManager::HYPRLAND; + + if (wm.find("KDE") != std::string::npos) + return WindowManager::KDE; + + if (wm.find("GNOME") != std::string::npos) + return WindowManager::GNOME; + +#endif + + return WindowManager::UNKNOWN; +} +} // namespace Tools + +} // namespace Cubed diff --git a/include/Cubed/window.hpp b/include/Cubed/window.hpp index 120944d..8be876a 100644 --- a/include/Cubed/window.hpp +++ b/include/Cubed/window.hpp @@ -49,6 +49,7 @@ private: bool m_mouse_enable = true; bool m_imgui_init = false; bool m_game_running = false; + bool m_enable_exclusive = false; SDL_Window* m_window; SDL_GLContext m_context; int m_window_width = 0; @@ -61,6 +62,9 @@ private: bool handle_key_event(const KeyEvent& e); bool handle_window_resize_event(const WindowResizeEvent& e); bool handle_mouse_button_event(const MouseButtonEvent& e); + + void set_exclusive_fullscreen(bool full); + void set_borderless_fullscreen(bool full); }; } // namespace Cubed \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index d5cfbc9..f26b999 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -132,9 +132,9 @@ void App::handle_argument(int argc, char** argv) { [&](ArgParser& p) { auto arg = p.require_next("--video-driver"); m_argument.video_driver = arg; - } - - } + }}, + {"--enable-exclusive", + [&](ArgParser&) { m_argument.enable_exclusive = true; }} }; ArgParser parser(argc, argv); diff --git a/src/window.cpp b/src/window.cpp index 34eefcf..0b00deb 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -6,6 +6,7 @@ #include "Cubed/tools/env_tools.hpp" #include "Cubed/tools/font.hpp" #include "Cubed/tools/log.hpp" +#include "Cubed/tools/system_window_manager.hpp" #include #include @@ -110,6 +111,67 @@ bool Window::handle_mouse_button_event(const MouseButtonEvent& e) { return false; } +void Window::set_exclusive_fullscreen(bool full) { + + if (full) { + SDL_GetWindowPosition(m_window, &windowed_xpos, &windowed_ypos); + SDL_GetWindowSize(m_window, &windowed_width, &windowed_height); + SDL_SetWindowFullscreen(m_window, true); + m_fullscreen = true; + m_config.set("window.fullscreen", true); + } else { + SDL_SetWindowFullscreen(m_window, false); + SDL_SetWindowPosition(m_window, windowed_xpos, windowed_ypos); + SDL_SetWindowSize(m_window, windowed_width, windowed_height); + m_fullscreen = false; + m_config.set("window.fullscreen", false); + } +} +void Window::set_borderless_fullscreen(bool full) { + if (full) { + // If the window is maximized, restore it first. + if (SDL_GetWindowFlags(m_window) & SDL_WINDOW_MAXIMIZED) { + SDL_RestoreWindow(m_window); + } + + SDL_GetWindowPosition(m_window, &windowed_xpos, &windowed_ypos); + + SDL_GetWindowSize(m_window, &windowed_width, &windowed_height); + + m_windowed_display = SDL_GetDisplayForWindow(m_window); + + SDL_Rect display_bounds{}; + if (!SDL_GetDisplayBounds(m_windowed_display, &display_bounds)) { + + Logger::error("SDL_GetDisplayBounds failed: {}", SDL_GetError()); + return; + } + + SDL_SetWindowBordered(m_window, false); + + SDL_SetWindowPosition(m_window, display_bounds.x, display_bounds.y); + + SDL_SetWindowSize(m_window, display_bounds.w, display_bounds.h); + + SDL_RaiseWindow(m_window); + + m_fullscreen = true; + m_config.set("window.fullscreen", true); + } else { + + SDL_SetWindowBordered(m_window, true); + + SDL_SetWindowSize(m_window, windowed_width, windowed_height); + + SDL_SetWindowPosition(m_window, windowed_xpos, windowed_ypos); + + SDL_RaiseWindow(m_window); + + m_fullscreen = false; + m_config.set("window.fullscreen", false); + } +} + void Window::init(const Argument& argument) { auto video_driver = m_config.get("video_driver", std::string("auto")); if (argument.video_driver) { @@ -125,6 +187,31 @@ void Window::init(const Argument& argument) { Logger::warn("Unknow Vider Driver {}", video_driver); } + bool default_exclusive = false; + auto wm = Tools::detect_wm(); + switch (wm) { + case WindowManager::NIRI: + case WindowManager::SWAY: + case WindowManager::HYPRLAND: + default_exclusive = true; + break; + case WindowManager::WINDOWS: + case WindowManager::GNOME: + case WindowManager::KDE: + case WindowManager::UNKNOWN: + default_exclusive = false; + break; + } + + m_enable_exclusive = + m_config.get("enable_exclusive_fullscreen", default_exclusive); + + if (argument.enable_exclusive) { + m_enable_exclusive = *argument.enable_exclusive; + } + + Logger::info("Exclusive Fullscreen {}", m_enable_exclusive); + if (!SDL_Init(SDL_INIT_VIDEO)) { Logger::error("sdl3 init fail"); exit(EXIT_FAILURE); @@ -194,49 +281,11 @@ void Window::toggle_fullscreen() { void Window::set_fullscreen(bool full) { if (full == m_fullscreen) return; - if (full) { - // If the window is maximized, restore it first. - if (SDL_GetWindowFlags(m_window) & SDL_WINDOW_MAXIMIZED) { - SDL_RestoreWindow(m_window); - } - - SDL_GetWindowPosition(m_window, &windowed_xpos, &windowed_ypos); - - SDL_GetWindowSize(m_window, &windowed_width, &windowed_height); - - m_windowed_display = SDL_GetDisplayForWindow(m_window); - - SDL_Rect display_bounds{}; - if (!SDL_GetDisplayBounds(m_windowed_display, &display_bounds)) { - - Logger::error("SDL_GetDisplayBounds failed: {}", SDL_GetError()); - return; - } - - SDL_SetWindowBordered(m_window, false); - - SDL_SetWindowPosition(m_window, display_bounds.x, display_bounds.y); - - SDL_SetWindowSize(m_window, display_bounds.w, display_bounds.h); - - SDL_RaiseWindow(m_window); - - m_fullscreen = true; - m_config.set("window.fullscreen", true); + if (m_enable_exclusive) { + set_exclusive_fullscreen(full); } else { - - SDL_SetWindowBordered(m_window, true); - - SDL_SetWindowSize(m_window, windowed_width, windowed_height); - - SDL_SetWindowPosition(m_window, windowed_xpos, windowed_ypos); - - SDL_RaiseWindow(m_window); - - m_fullscreen = false; - m_config.set("window.fullscreen", false); + set_borderless_fullscreen(full); } - int w, h; SDL_GetWindowSize(m_window, &w, &h);