feat(window): add exclusive fullscreen support with WM detection

This commit is contained in:
2026-07-17 17:42:52 +08:00
parent c5d90fe82e
commit 1f334567c8
6 changed files with 145 additions and 46 deletions

View File

@@ -9,5 +9,6 @@ struct Argument {
std::optional<bool> no_debug; std::optional<bool> no_debug;
std::optional<std::string> language; std::optional<std::string> language;
std::optional<std::string> video_driver; std::optional<std::string> video_driver;
std::optional<bool> enable_exclusive;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -184,14 +184,14 @@ inline std::string get_compiler_info() {
#else #else
result = "Unknown Compiler"; result = "Unknown Compiler";
#endif #endif
constexpr long cpp_version = constexpr long CPP_VERSION =
#ifdef _MSC_VER #ifdef _MSC_VER
_MSVC_LANG; _MSVC_LANG;
#else #else
__cplusplus; __cplusplus;
#endif #endif
result += " (C++"; result += " (C++";
result += std::to_string(cpp_version); result += std::to_string(CPP_VERSION);
result += ")"; result += ")";
return result; return result;

View File

@@ -0,0 +1,45 @@
#pragma once
#include "Cubed/tools/log.hpp"
#include <cstdlib>
#include <string>
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

View File

@@ -49,6 +49,7 @@ private:
bool m_mouse_enable = true; bool m_mouse_enable = true;
bool m_imgui_init = false; bool m_imgui_init = false;
bool m_game_running = false; bool m_game_running = false;
bool m_enable_exclusive = false;
SDL_Window* m_window; SDL_Window* m_window;
SDL_GLContext m_context; SDL_GLContext m_context;
int m_window_width = 0; int m_window_width = 0;
@@ -61,6 +62,9 @@ private:
bool handle_key_event(const KeyEvent& e); bool handle_key_event(const KeyEvent& e);
bool handle_window_resize_event(const WindowResizeEvent& e); bool handle_window_resize_event(const WindowResizeEvent& e);
bool handle_mouse_button_event(const MouseButtonEvent& e); bool handle_mouse_button_event(const MouseButtonEvent& e);
void set_exclusive_fullscreen(bool full);
void set_borderless_fullscreen(bool full);
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -132,9 +132,9 @@ void App::handle_argument(int argc, char** argv) {
[&](ArgParser& p) { [&](ArgParser& p) {
auto arg = p.require_next("--video-driver"); auto arg = p.require_next("--video-driver");
m_argument.video_driver = arg; m_argument.video_driver = arg;
} }},
{"--enable-exclusive",
} [&](ArgParser&) { m_argument.enable_exclusive = true; }}
}; };
ArgParser parser(argc, argv); ArgParser parser(argc, argv);

View File

@@ -6,6 +6,7 @@
#include "Cubed/tools/env_tools.hpp" #include "Cubed/tools/env_tools.hpp"
#include "Cubed/tools/font.hpp" #include "Cubed/tools/font.hpp"
#include "Cubed/tools/log.hpp" #include "Cubed/tools/log.hpp"
#include "Cubed/tools/system_window_manager.hpp"
#include <imgui.h> #include <imgui.h>
#include <imgui_impl_opengl3.h> #include <imgui_impl_opengl3.h>
@@ -110,6 +111,67 @@ bool Window::handle_mouse_button_event(const MouseButtonEvent& e) {
return false; 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) { void Window::init(const Argument& argument) {
auto video_driver = m_config.get("video_driver", std::string("auto")); auto video_driver = m_config.get("video_driver", std::string("auto"));
if (argument.video_driver) { if (argument.video_driver) {
@@ -125,6 +187,31 @@ void Window::init(const Argument& argument) {
Logger::warn("Unknow Vider Driver {}", video_driver); 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)) { if (!SDL_Init(SDL_INIT_VIDEO)) {
Logger::error("sdl3 init fail"); Logger::error("sdl3 init fail");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -194,49 +281,11 @@ void Window::toggle_fullscreen() {
void Window::set_fullscreen(bool full) { void Window::set_fullscreen(bool full) {
if (full == m_fullscreen) if (full == m_fullscreen)
return; return;
if (full) { if (m_enable_exclusive) {
// If the window is maximized, restore it first. set_exclusive_fullscreen(full);
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 { } else {
set_borderless_fullscreen(full);
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);
} }
int w, h; int w, h;
SDL_GetWindowSize(m_window, &w, &h); SDL_GetWindowSize(m_window, &w, &h);