mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-05-25 22:49:15 +00:00
Windows Fullscreen Fixes (#87)
This PR fixes two bugs introduced in #80 : - Exiting fullscreen could exit the Ryujinx window (https://github.com/Ryubing/Issues/issues/415) - Toggling fullscreen on would move the window to the primary monitor And two other bugs related to input view : - Exiting fullscreen when window was previously in a non maximized state now conserves the window coordinates and size properly (https://github.com/Ryubing/Issues/issues/425) - Opening the ryujinx app no makes the app grow slightly larger vertically on each launch (+31px on my 1080p monitor) (https://github.com/Ryubing/Issues/issues/425) Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/87
This commit is contained in:
@@ -63,6 +63,18 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct NativeRect
|
||||||
|
{
|
||||||
|
public int Left;
|
||||||
|
public int Top;
|
||||||
|
public int Right;
|
||||||
|
public int Bottom;
|
||||||
|
|
||||||
|
public int Width => Right - Left;
|
||||||
|
public int Height => Bottom - Top;
|
||||||
|
}
|
||||||
|
|
||||||
public static nint CreateEmptyCursor()
|
public static nint CreateEmptyCursor()
|
||||||
{
|
{
|
||||||
return CreateCursor(nint.Zero, 0, 0, 1, 1, [0xFF], [0x00]);
|
return CreateCursor(nint.Zero, 0, 0, 1, 1, [0xFF], [0x00]);
|
||||||
@@ -119,6 +131,10 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
[LibraryImport("user32.dll", SetLastError = true)]
|
[LibraryImport("user32.dll", SetLastError = true)]
|
||||||
public static partial nint SetWindowLongPtrW(nint hWnd, int nIndex, nint value);
|
public static partial nint SetWindowLongPtrW(nint hWnd, int nIndex, nint value);
|
||||||
|
|
||||||
|
[LibraryImport("user32.dll", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static partial bool GetWindowRect(nint hWnd, out NativeRect lpRect);
|
||||||
|
|
||||||
[LibraryImport("user32.dll", SetLastError = true)]
|
[LibraryImport("user32.dll", SetLastError = true)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static partial bool SetWindowPos(
|
public static partial bool SetWindowPos(
|
||||||
|
|||||||
@@ -2060,6 +2060,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
private nint _savedWindowStyle;
|
private nint _savedWindowStyle;
|
||||||
|
private WindowState _savedWindowState;
|
||||||
|
private PixelPoint _savedWindowPosition;
|
||||||
|
private double _savedWindowWidth;
|
||||||
|
private double _savedWindowHeight;
|
||||||
|
private Win32NativeInterop.NativeRect _savedWindowRect;
|
||||||
|
private bool _savedWindowRectValid;
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
private void MakeWindowFullscreen()
|
private void MakeWindowFullscreen()
|
||||||
@@ -2067,19 +2073,36 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
nint hwnd = Window.TryGetPlatformHandle()?.Handle ?? nint.Zero;
|
nint hwnd = Window.TryGetPlatformHandle()?.Handle ?? nint.Zero;
|
||||||
if (hwnd == nint.Zero) return;
|
if (hwnd == nint.Zero) return;
|
||||||
|
|
||||||
|
PixelPoint windowCenter = new(
|
||||||
|
Window.Position.X + (int)(Window.Bounds.Width / 2),
|
||||||
|
Window.Position.Y + (int)(Window.Bounds.Height / 2));
|
||||||
|
|
||||||
|
Avalonia.Platform.Screen? screen =
|
||||||
|
Window.Screens.ScreenFromVisual(Window) ??
|
||||||
|
Window.Screens.ScreenFromPoint(windowCenter) ??
|
||||||
|
Window.Screens.Primary;
|
||||||
|
|
||||||
|
if (screen == null)
|
||||||
|
{
|
||||||
|
return; // Can't determine screen size, don't attempt fullscreen
|
||||||
|
}
|
||||||
|
|
||||||
// Save current style and placement
|
// Save current style and placement
|
||||||
_savedWindowStyle = Win32NativeInterop.GetWindowLongPtrW(hwnd, Win32NativeInterop.GWL_STYLE);
|
_savedWindowStyle = Win32NativeInterop.GetWindowLongPtrW(hwnd, Win32NativeInterop.GWL_STYLE);
|
||||||
|
_savedWindowState = WindowState;
|
||||||
|
_savedWindowPosition = Window.Position;
|
||||||
|
_savedWindowWidth = Window.Width;
|
||||||
|
_savedWindowHeight = Window.Height;
|
||||||
|
_savedWindowRectValid = Win32NativeInterop.GetWindowRect(hwnd, out _savedWindowRect);
|
||||||
|
|
||||||
// Remove window chrome: WS_OVERLAPPEDWINDOW -> WS_POPUP | WS_VISIBLE
|
// Remove window chrome: WS_OVERLAPPEDWINDOW -> WS_POPUP | WS_VISIBLE
|
||||||
Win32NativeInterop.SetWindowLongPtrW(hwnd, Win32NativeInterop.GWL_STYLE,
|
Win32NativeInterop.SetWindowLongPtrW(hwnd, Win32NativeInterop.GWL_STYLE,
|
||||||
unchecked((nint)(Win32NativeInterop.WS_POPUP | Win32NativeInterop.WS_VISIBLE)));
|
unchecked((nint)(Win32NativeInterop.WS_POPUP | Win32NativeInterop.WS_VISIBLE)));
|
||||||
|
|
||||||
// TODO: why is this nullable
|
int w = screen.Bounds.Width;
|
||||||
Avalonia.Platform.Screen? screen = Window.Screens.ScreenFromVisual(Window);
|
int h = screen.Bounds.Height;
|
||||||
int w = screen?.Bounds.Width ?? 0;
|
|
||||||
int h = screen?.Bounds.Height ?? 0;
|
|
||||||
|
|
||||||
Win32NativeInterop.SetWindowPos(hwnd, nint.Zero, 0, 0, w, h,
|
Win32NativeInterop.SetWindowPos(hwnd, nint.Zero, screen.Bounds.X, screen.Bounds.Y, w, h,
|
||||||
Win32NativeInterop.SWP_NOZORDER | Win32NativeInterop.SWP_NOACTIVATE | Win32NativeInterop.SWP_FRAMECHANGED);
|
Win32NativeInterop.SWP_NOZORDER | Win32NativeInterop.SWP_NOACTIVATE | Win32NativeInterop.SWP_FRAMECHANGED);
|
||||||
|
|
||||||
WindowState = WindowState.FullScreen;
|
WindowState = WindowState.FullScreen;
|
||||||
@@ -2094,10 +2117,34 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
// Restore original window style
|
// Restore original window style
|
||||||
Win32NativeInterop.SetWindowLongPtrW(hwnd, Win32NativeInterop.GWL_STYLE, _savedWindowStyle);
|
Win32NativeInterop.SetWindowLongPtrW(hwnd, Win32NativeInterop.GWL_STYLE, _savedWindowStyle);
|
||||||
|
|
||||||
Win32NativeInterop.SetWindowPos(hwnd, nint.Zero, 0, 0, 0, 0,
|
if (_savedWindowState is WindowState.Maximized)
|
||||||
Win32NativeInterop.SWP_NOZORDER | Win32NativeInterop.SWP_NOACTIVATE |
|
{
|
||||||
Win32NativeInterop.SWP_FRAMECHANGED | Win32NativeInterop.SWP_NOMOVE | Win32NativeInterop.SWP_NOSIZE);
|
Win32NativeInterop.SetWindowPos(hwnd, nint.Zero, 0, 0, 0, 0,
|
||||||
|
Win32NativeInterop.SWP_NOZORDER | Win32NativeInterop.SWP_NOACTIVATE |
|
||||||
|
Win32NativeInterop.SWP_FRAMECHANGED | Win32NativeInterop.SWP_NOMOVE | Win32NativeInterop.SWP_NOSIZE);
|
||||||
|
}
|
||||||
|
else if (_savedWindowRectValid)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(() => RestoreSavedWindowRect(hwnd), DispatcherPriority.Background);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Win32NativeInterop.SetWindowPos(hwnd, nint.Zero, 0, 0, 0, 0,
|
||||||
|
Win32NativeInterop.SWP_NOZORDER | Win32NativeInterop.SWP_NOACTIVATE |
|
||||||
|
Win32NativeInterop.SWP_FRAMECHANGED | Win32NativeInterop.SWP_NOMOVE | Win32NativeInterop.SWP_NOSIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
private void RestoreSavedWindowRect(nint hwnd)
|
||||||
|
{
|
||||||
|
Window.Position = _savedWindowPosition;
|
||||||
|
Window.Width = _savedWindowWidth;
|
||||||
|
Window.Height = _savedWindowHeight;
|
||||||
|
|
||||||
|
Win32NativeInterop.SetWindowPos(hwnd, nint.Zero, _savedWindowRect.Left, _savedWindowRect.Top,
|
||||||
|
_savedWindowRect.Width, _savedWindowRect.Height,
|
||||||
|
Win32NativeInterop.SWP_NOZORDER | Win32NativeInterop.SWP_NOACTIVATE | Win32NativeInterop.SWP_FRAMECHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveConfig()
|
public static void SaveConfig()
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
private bool _isLoading;
|
private bool _isLoading;
|
||||||
private bool _applicationsLoadedOnce;
|
private bool _applicationsLoadedOnce;
|
||||||
|
private double _windowStartupWidthDelta;
|
||||||
|
private double _windowStartupHeightDelta;
|
||||||
|
|
||||||
private UserChannelPersistence _userChannelPersistence;
|
private UserChannelPersistence _userChannelPersistence;
|
||||||
private static bool _deferLoad;
|
private static bool _deferLoad;
|
||||||
@@ -477,8 +479,8 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
{
|
{
|
||||||
// Since scaling is being applied to the loaded settings from disk (see SetWindowSizePosition() above), scaling should be removed from width/height before saving out to disk
|
// Since scaling is being applied to the loaded settings from disk (see SetWindowSizePosition() above), scaling should be removed from width/height before saving out to disk
|
||||||
// as well - otherwise anyone not using a 1.0 scale factor their window will increase in size with every subsequent launch of the program when scaling is applied (Nov. 14, 2024)
|
// as well - otherwise anyone not using a 1.0 scale factor their window will increase in size with every subsequent launch of the program when scaling is applied (Nov. 14, 2024)
|
||||||
ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight.Value = (int)(Height / Program.WindowScaleFactor);
|
ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight.Value = (int)((Height - _windowStartupHeightDelta) / Program.WindowScaleFactor);
|
||||||
ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth.Value = (int)(Width / Program.WindowScaleFactor);
|
ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth.Value = (int)((Width - _windowStartupWidthDelta) / Program.WindowScaleFactor);
|
||||||
|
|
||||||
ConfigurationState.Instance.UI.WindowStartup.WindowPositionX.Value = Position.X;
|
ConfigurationState.Instance.UI.WindowStartup.WindowPositionX.Value = Position.X;
|
||||||
ConfigurationState.Instance.UI.WindowStartup.WindowPositionY.Value = Position.Y;
|
ConfigurationState.Instance.UI.WindowStartup.WindowPositionY.Value = Position.Y;
|
||||||
@@ -493,6 +495,9 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
|
_windowStartupWidthDelta = Math.Max(0, Width - ViewModel.WindowWidth);
|
||||||
|
_windowStartupHeightDelta = Math.Max(0, Height - ViewModel.WindowHeight);
|
||||||
|
|
||||||
PlatformSettings!.ColorValuesChanged += OnPlatformColorValuesChanged;
|
PlatformSettings!.ColorValuesChanged += OnPlatformColorValuesChanged;
|
||||||
|
|
||||||
ViewModel.Initialize(
|
ViewModel.Initialize(
|
||||||
|
|||||||
Reference in New Issue
Block a user