Skip to content

Commit ba56d9a

Browse files
authored
Fix windows not being draggable (SubnauticaNitrox#2703)
1 parent 93b4062 commit ba56d9a

9 files changed

Lines changed: 57 additions & 37 deletions

File tree

Nitrox.Launcher/Models/Controls/CustomTitlebar.axaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
xmlns="https://github.com/avaloniaui"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:controls="clr-namespace:Nitrox.Launcher.Models.Controls"
5+
xmlns:design="clr-namespace:Nitrox.Launcher.Models.Design"
56
xmlns:converters="clr-namespace:Nitrox.Launcher.Models.Converters">
67
<Design.PreviewWith>
78
<StackPanel Width="200">
@@ -77,6 +78,7 @@
7778
<Setter Property="HorizontalAlignment" Value="Stretch" />
7879
<Setter Property="VerticalAlignment" Value="Top" />
7980
<Setter Property="ShowTitle" Value="False" />
81+
<Setter Property="IsVisible" Value="{Binding $parent[Window].(design:NitroxAttached.UseCustomTitleBar)}" />
8082

8183
<Style Selector="^ /template/ StackPanel">
8284
<Setter Property="Orientation" Value="Horizontal" />

Nitrox.Launcher/Models/Extensions/VisualExtensions.cs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,44 @@
1-
using System.Runtime.InteropServices;
1+
using System;
22
using Avalonia;
33
using Avalonia.Controls;
4+
using Nitrox.Launcher.Models.Design;
45
using Nitrox.Model.Platforms.OS.Windows;
56

67
namespace Nitrox.Launcher.Models.Extensions;
78

89
public static class VisualExtensions
910
{
10-
public static void ApplyOsWindowStyling(this Visual visual)
11+
public static void ApplyPlatformWindowStyle(this Window window)
1112
{
1213
if (IsDesignMode)
1314
{
1415
return;
1516
}
16-
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
17+
18+
if (OperatingSystem.IsLinux())
1719
{
18-
return;
20+
// On Linux systems, Avalonia has trouble allowing windows to resize without "decorations". So we enable it in full, but hide the custom titlebar as it'll look bad.
21+
window.SystemDecorations = SystemDecorations.Full;
22+
NitroxAttached.SetUseCustomTitleBar(window, false);
1923
}
20-
if (visual.GetWindow() is not { } window)
24+
else if (OperatingSystem.IsMacOS())
2125
{
22-
return;
26+
// On MacOS, it's uncommon to override the system titlebar
27+
window.SystemDecorations = SystemDecorations.Full;
28+
window.ExtendClientAreaToDecorationsHint = false;
29+
window.ExtendClientAreaTitleBarHeightHint = -1;
30+
NitroxAttached.SetUseCustomTitleBar(window, false);
2331
}
24-
nint? windowHandle = window.TryGetPlatformHandle()?.Handle;
25-
if (!windowHandle.HasValue)
32+
else if (OperatingSystem.IsWindows())
2633
{
27-
return;
28-
}
34+
nint? windowHandle = window.TryGetPlatformHandle()?.Handle;
35+
if (!windowHandle.HasValue)
36+
{
37+
return;
38+
}
2939

30-
WindowsApi.EnableDefaultWindowAnimations(windowHandle.Value, window.CanResize);
40+
WindowsApi.EnableDefaultWindowAnimations(windowHandle.Value, window.CanResize);
41+
}
3142
}
3243

3344
public static Window? GetWindow(this Visual visual) => TopLevel.GetTopLevel(visual) as Window;
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
using Avalonia.Controls;
1+
using Avalonia.Controls;
22

33
namespace Nitrox.Launcher.Views.Abstract;
44

55
public abstract class ModalBase : Window
66
{
7-
protected override void OnInitialized() => this.ApplyOsWindowStyling();
7+
protected override void OnInitialized()
8+
{
9+
this.ApplyPlatformWindowStyle();
10+
}
811
}
Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System;
21
using Avalonia.Controls;
3-
using Nitrox.Launcher.Models.Design;
42
using Nitrox.Launcher.ViewModels.Abstract;
53

64
namespace Nitrox.Launcher.Views.Abstract;
@@ -9,14 +7,6 @@ internal abstract class WindowEx<T> : Window where T : ViewModelBase
97
{
108
protected override void OnInitialized()
119
{
12-
this.ApplyOsWindowStyling();
13-
14-
// On Linux systems, Avalonia has trouble allowing windows to resize without "decorations". So we enable it in full, but hide the custom titlebar as it'll look bad.
15-
// On macOS, we need the native toolbar as every app is using it
16-
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
17-
{
18-
SystemDecorations = SystemDecorations.Full;
19-
NitroxAttached.SetUseCustomTitleBar(this, false);
20-
}
10+
this.ApplyPlatformWindowStyle();
2111
}
2212
}

Nitrox.Launcher/Views/BackupRestoreModal.axaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
MinWidth="500"
55
SizeToContent="WidthAndHeight"
66
Title="{Binding Title}"
7-
d:DesignHeight="450"
7+
d:DesignHeight="500"
88
d:DesignWidth="800"
99
mc:Ignorable="d"
1010
x:Class="Nitrox.Launcher.Views.BackupRestoreModal"
@@ -19,7 +19,8 @@
1919
<vm:BackupRestoreViewModel />
2020
</Design.DataContext>
2121
<Grid RowDefinitions="Auto, *, Auto">
22-
<controls:CustomTitlebar CanMinimize="False" Grid.Row="0" />
22+
<controls:CustomTitlebar CanMinimize="False"
23+
Grid.Row="0" />
2324

2425
<TextBlock
2526
Classes="modalHeader"

Nitrox.Launcher/Views/CrashWindow.axaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
</viewModels:CrashWindowViewModel>
4444
</Design.DataContext>
4545
<DockPanel LastChildFill="True">
46-
<controls:CustomTitlebar DockPanel.Dock="Top" IsVisible="{Binding $parent[Window].(design:NitroxAttached.UseCustomTitleBar)}" ShowTitle="True" />
46+
<controls:CustomTitlebar DockPanel.Dock="Top" ShowTitle="True" />
4747
<Grid RowDefinitions="*,Auto">
4848
<ScrollViewer>
4949
<!-- TODO: Nice color highlighting (with option to click on line to open the source file?) -->

Nitrox.Launcher/Views/DialogBoxModal.axaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
<Grid RowDefinitions="Auto,*,Auto">
2525
<controls:CustomTitlebar
2626
CanMinimize="False"
27-
Grid.RowSpan="2"
28-
ShowTitle="False" />
27+
Grid.RowSpan="2" />
2928
<TextBlock
3029
FontSize="{Binding TitleFontSize}"
3130
FontWeight="{Binding TitleFontWeight}"

Nitrox.Launcher/Views/MainWindow.axaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@
178178
</Interaction.Behaviors>
179179

180180
<Panel>
181-
<controls:CustomTitlebar IsVisible="{Binding $parent[Window].(design:NitroxAttached.UseCustomTitleBar)}" Opacity="0.6" />
181+
<controls:CustomTitlebar Opacity="0.6" />
182182

183183
<Grid ColumnDefinitions="274,*" RowDefinitions="*">
184184
<!-- Navigation (left side) -->

Nitrox.Model/Platforms/OS/Windows/WindowsApi.cs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
using System;
22
using System.Runtime.InteropServices;
3-
using Nitrox.Model.Platforms.OS.Windows.Internal;
43
using static Nitrox.Model.Platforms.OS.Windows.Internal.Win32Native;
54

65
namespace Nitrox.Model.Platforms.OS.Windows;
76

8-
public class WindowsApi
7+
public static partial class WindowsApi
98
{
109
/// <summary>
1110
/// Applies default OS animations to the window handle.
1211
/// </summary>
1312
/// <remarks>
14-
/// Note on Windows OS: it will force enable resizing of a Window if <see cref="canResize"/> is true. Make sure to set it correctly.
13+
/// Note on Windows OS: it will force enable resizing of a Window if <see cref="canResize" /> is true. Make sure to set
14+
/// it correctly.
1515
/// </remarks>
1616
public static void EnableDefaultWindowAnimations(nint windowHandle, bool canResize)
1717
{
@@ -20,10 +20,10 @@ public static void EnableDefaultWindowAnimations(nint windowHandle, bool canResi
2020
return;
2121
}
2222

23-
Win32Native.WS dwNewLong = Win32Native.WS.WS_CAPTION | Win32Native.WS.WS_CLIPCHILDREN | Win32Native.WS.WS_MINIMIZEBOX | Win32Native.WS.WS_MAXIMIZEBOX | Win32Native.WS.WS_SYSMENU;
23+
WS dwNewLong = WS.WS_CAPTION | WS.WS_CLIPCHILDREN | WS.WS_MINIMIZEBOX | WS.WS_MAXIMIZEBOX | WS.WS_SYSMENU;
2424
if (canResize)
2525
{
26-
dwNewLong |= Win32Native.WS.WS_SIZEBOX;
26+
dwNewLong |= WS.WS_SIZEBOX;
2727
}
2828

2929
HandleRef handle = new(null, windowHandle);
@@ -53,12 +53,26 @@ public static void BringProcessToFront(IntPtr windowHandle)
5353
SetForegroundWindow(windowHandle);
5454
}
5555

56+
#if NET
57+
[LibraryImport("User32.dll")]
58+
[return: MarshalAs(UnmanagedType.Bool)]
59+
private static partial bool SetForegroundWindow(IntPtr handle);
60+
61+
[LibraryImport("User32.dll")]
62+
[return: MarshalAs(UnmanagedType.Bool)]
63+
private static partial bool ShowWindow(IntPtr handle, int nCmdShow);
64+
65+
[LibraryImport("User32.dll")]
66+
[return: MarshalAs(UnmanagedType.Bool)]
67+
private static partial bool IsIconic(IntPtr handle);
68+
#else
5669
[DllImport("User32.dll")]
5770
private static extern bool SetForegroundWindow(IntPtr handle);
71+
5872
[DllImport("User32.dll")]
5973
private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
74+
6075
[DllImport("User32.dll")]
6176
private static extern bool IsIconic(IntPtr handle);
62-
[DllImport("User32.dll", CharSet = CharSet.Unicode)]
63-
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
77+
#endif
6478
}

0 commit comments

Comments
 (0)