From 3f0921d983880544f204e72af8744a09610d4c65 Mon Sep 17 00:00:00 2001 From: bicarus <202771338+bicarus-dev@users.noreply.github.com> Date: Tue, 21 Jul 2026 00:54:09 -0700 Subject: [PATCH] gitadora: more windowed mode fixes (#819) ## Link to GitHub Issue or related Pull Request, if one exists User reported ## Description of change Sometimes the game moved the main window after `CreateWindowExA` returned but before D3D initialization called `graphics_capture_initial_window`. During this gap, `GRAPHICS_HOOKED_WINDOW` was not set, so the placement hooks could not identify the main window and preserve its monitor override. GITADORA main, LEFT, and RIGHT windows are now registered immediately after creation so later placement calls cannot undo their overrides. This also adds `-gdwsmallsize` and `-gdwsmallpos` for explicitly setting the SMALL window size and position. Explicit values override the corresponding monitor-derived geometry, allowing the SMALL window's 10:16 aspect ratio to be preserved instead of stretching it to fill a monitor. ## Testing --- src/spice2x/hooks/graphics/graphics.cpp | 15 ++++-- src/spice2x/hooks/graphics/graphics.h | 4 +- .../hooks/graphics/graphics_windowed.cpp | 53 +++++++++++++++++-- src/spice2x/launcher/launcher.cpp | 8 +++ src/spice2x/launcher/options.cpp | 20 +++++++ src/spice2x/launcher/options.h | 2 + 6 files changed, 92 insertions(+), 10 deletions(-) diff --git a/src/spice2x/hooks/graphics/graphics.cpp b/src/spice2x/hooks/graphics/graphics.cpp index 723ae6d..c21f72a 100644 --- a/src/spice2x/hooks/graphics/graphics.cpp +++ b/src/spice2x/hooks/graphics/graphics.cpp @@ -189,11 +189,13 @@ static bool gitadora_should_block_game_window_placement(HWND hWnd) { } const auto window_name = gitadora_window_name_for_hwnd(hWnd); - return window_name != nullptr && graphics_gitadora_has_window_monitor(window_name); + return window_name != nullptr && graphics_gitadora_has_window_override(window_name); } static void gitadora_remember_window(HWND hWnd, const std::string &window_name) { - if (window_name == "LEFT") { + if (window_name == "GITADORA") { + GRAPHICS_HOOKED_WINDOW = hWnd; + } else if (window_name == "LEFT") { GFDM_LEFT_WINDOW = hWnd; } else if (window_name == "RIGHT") { GFDM_RIGHT_WINDOW = hWnd; @@ -590,6 +592,12 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC hWndParent, hMenu, hInstance, lpParam); GRAPHICS_WINDOWS.push_back(result); + // remember these windows now because full capture happens later during D3D + // initialization; placement calls before then can undo creation-time overrides + if (result != nullptr && is_gfdm_window && !is_gfdm_sub_window) { + gitadora_remember_window(result, gfdm_window_name); + } + // theme the native title bar (dark/light) set_window_dark_titlebar(result); @@ -610,9 +618,6 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC } // only hook touch window if multiple windows are allowed - if (gfdm_window_name == "LEFT" || gfdm_window_name == "RIGHT") { - gitadora_remember_window(result, gfdm_window_name); - } if (is_gfdm_sub_window && GRAPHICS_WINDOWED && !GRAPHICS_PREVENT_SECONDARY_WINDOWS) { gitadora_remember_window(result, gfdm_window_name); graphics_hook_subscreen_window(GFDM_SUBSCREEN_WINDOW); diff --git a/src/spice2x/hooks/graphics/graphics.h b/src/spice2x/hooks/graphics/graphics.h index e5ab966..9c7cffe 100644 --- a/src/spice2x/hooks/graphics/graphics.h +++ b/src/spice2x/hooks/graphics/graphics.h @@ -88,6 +88,8 @@ extern std::string GRAPHICS_GITADORA_MAIN_MONITOR; extern std::string GRAPHICS_GITADORA_LEFT_MONITOR; extern std::string GRAPHICS_GITADORA_RIGHT_MONITOR; extern std::string GRAPHICS_GITADORA_SMALL_MONITOR; +extern std::optional GRAPHICS_GITADORA_SMALL_SIZE; +extern std::optional GRAPHICS_GITADORA_SMALL_POS; extern bool GRAPHICS_IIDX_WSUB; extern std::optional GRAPHICS_WSUB_SIZE; @@ -157,7 +159,7 @@ bool graphics_gitadora_apply_window_monitor( int &width, int &height, bool log_change); -bool graphics_gitadora_has_window_monitor(const std::string &window_name); +bool graphics_gitadora_has_window_override(const std::string &window_name); void change_primary_monitor(const std::string &monitor_name); void update_monitor_on_boot( diff --git a/src/spice2x/hooks/graphics/graphics_windowed.cpp b/src/spice2x/hooks/graphics/graphics_windowed.cpp index 0c67b45..634fa48 100644 --- a/src/spice2x/hooks/graphics/graphics_windowed.cpp +++ b/src/spice2x/hooks/graphics/graphics_windowed.cpp @@ -30,6 +30,8 @@ std::string GRAPHICS_GITADORA_MAIN_MONITOR; std::string GRAPHICS_GITADORA_LEFT_MONITOR; std::string GRAPHICS_GITADORA_RIGHT_MONITOR; std::string GRAPHICS_GITADORA_SMALL_MONITOR; +std::optional GRAPHICS_GITADORA_SMALL_SIZE; +std::optional GRAPHICS_GITADORA_SMALL_POS; // IIDX Windowed Subscreen - starts out as false, enabled by IIDX module on pre-attach as needed bool GRAPHICS_IIDX_WSUB = false; @@ -89,9 +91,12 @@ static const std::string &graphics_gitadora_monitor_for_window_name( return empty; } -bool graphics_gitadora_has_window_monitor(const std::string &window_name) { +bool graphics_gitadora_has_window_override(const std::string &window_name) { const auto &monitor_name = graphics_gitadora_monitor_for_window_name(window_name); - return !monitor_name.empty(); + return !monitor_name.empty() || + (window_name == "SMALL" && + (GRAPHICS_GITADORA_SMALL_SIZE.has_value() || + GRAPHICS_GITADORA_SMALL_POS.has_value())); } static bool graphics_monitor_rect_from_name( @@ -212,7 +217,11 @@ bool graphics_gitadora_apply_window_monitor( int &width, int &height, bool log_change) { - return graphics_gitadora_apply_monitor_rect( + if (!GRAPHICS_WINDOWED || !games::gitadora::is_arena_model()) { + return false; + } + + bool applied = graphics_gitadora_apply_monitor_rect( graphics_gitadora_monitor_for_window_name(window_name), window_name, x, @@ -220,6 +229,42 @@ bool graphics_gitadora_apply_window_monitor( width, height, log_change); + + if (window_name != "SMALL") { + return applied; + } + + std::pair result; + if (GRAPHICS_GITADORA_SMALL_SIZE.has_value()) { + if (parse_width_height(GRAPHICS_GITADORA_SMALL_SIZE.value(), result)) { + width = result.first; + height = result.second; + applied = true; + } else { + log_fatal("graphics-windowed", "failed to parse -gdwsmallsize"); + } + } + if (GRAPHICS_GITADORA_SMALL_POS.has_value()) { + if (parse_width_height(GRAPHICS_GITADORA_SMALL_POS.value(), result)) { + x = result.first; + y = result.second; + applied = true; + } else { + log_fatal("graphics-windowed", "failed to parse -gdwsmallpos"); + } + } + + if (applied && log_change && + (GRAPHICS_GITADORA_SMALL_SIZE.has_value() || GRAPHICS_GITADORA_SMALL_POS.has_value())) { + log_info( + "graphics-windowed", + "GITADORA SMALL custom override: pos=({}, {}), size={}x{}", + x, + y, + width, + height); + } + return applied; } void graphics_capture_initial_window(HWND hWnd) { @@ -254,7 +299,7 @@ void graphics_capture_initial_window(HWND hWnd) { cfg::SCREENRESIZE->init_client_width = client_w; cfg::SCREENRESIZE->init_client_height = client_h; cfg::SCREENRESIZE->init_client_aspect_ratio = (float)client_w / (float)client_h; - log_debug( + log_misc( "graphics-windowed", "[{}] graphics_capture_initial_window initial window size {}x{}, ratio {}", fmt::ptr(hWnd), diff --git a/src/spice2x/launcher/launcher.cpp b/src/spice2x/launcher/launcher.cpp index 7123592..172312d 100644 --- a/src/spice2x/launcher/launcher.cpp +++ b/src/spice2x/launcher/launcher.cpp @@ -1286,6 +1286,14 @@ int main_implementation(int argc, char *argv[]) { GRAPHICS_GITADORA_SMALL_MONITOR = options[launcher::Options::GitaDoraWindowedSmallMonitor].value_text(); } + if (options[launcher::Options::GitaDoraWindowedSmallSize].is_active()) { + GRAPHICS_GITADORA_SMALL_SIZE = + options[launcher::Options::GitaDoraWindowedSmallSize].value_text(); + } + if (options[launcher::Options::GitaDoraWindowedSmallPosition].is_active()) { + GRAPHICS_GITADORA_SMALL_POS = + options[launcher::Options::GitaDoraWindowedSmallPosition].value_text(); + } // IIDX/SDVX Windowed Subscreen if (options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].is_active()) { diff --git a/src/spice2x/launcher/options.cpp b/src/spice2x/launcher/options.cpp index d9b8315..f7ea7e1 100644 --- a/src/spice2x/launcher/options.cpp +++ b/src/spice2x/launcher/options.cpp @@ -2644,6 +2644,26 @@ static const std::vector OPTION_DEFINITIONS = { .category = "Game Windowed Settings", .picker = OptionPickerType::Monitor, }, + { + // GitaDoraWindowedSmallSize + .title = "GitaDora Windowed SMALL Size", + .name = "gdwsmallsize", + .desc = "Size of the GITADORA Arena SMALL touch window. Defaults to (800,1280).", + .type = OptionType::Text, + .setting_name = "800,1280", + .game_name = "GitaDora", + .category = "Game Windowed Settings", + }, + { + // GitaDoraWindowedSmallPosition + .title = "GitaDora Windowed SMALL Position", + .name = "gdwsmallpos", + .desc = "Initial position of the GITADORA Arena SMALL touch window. Defaults to (0,0).", + .type = OptionType::Text, + .setting_name = "0,0", + .game_name = "GitaDora", + .category = "Game Windowed Settings", + }, { // spice2x_IIDXWindowedSubscreenSize .title = "IIDX Windowed Subscreen Size", diff --git a/src/spice2x/launcher/options.h b/src/spice2x/launcher/options.h index 80f5dc0..9d78db5 100644 --- a/src/spice2x/launcher/options.h +++ b/src/spice2x/launcher/options.h @@ -258,6 +258,8 @@ namespace launcher { GitaDoraWindowedLeftMonitor, GitaDoraWindowedRightMonitor, GitaDoraWindowedSmallMonitor, + GitaDoraWindowedSmallSize, + GitaDoraWindowedSmallPosition, spice2x_IIDXWindowedSubscreenSize, spice2x_IIDXWindowedSubscreenPosition, IIDXWindowedSubscreenBorderless,