diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs
index 1f84574318..3f2c977718 100644
--- a/src/Avalonia.Controls/Platform/IWindowImpl.cs
+++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs
@@ -45,6 +45,11 @@ namespace Avalonia.Platform
///
void ShowTaskbarIcon(bool value);
+ ///
+ /// Enables or disables resizing of the window
+ ///
+ void CanResize(bool value);
+
///
/// Gets or sets a method called before the underlying implementation is destroyed.
/// Return true to prevent the underlying implementation from closing.
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index c66209d3c6..16ee3a46b3 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -95,6 +95,9 @@ namespace Avalonia.Controls
o => o.WindowStartupLocation,
(o, v) => o.WindowStartupLocation = v);
+ public static readonly StyledProperty CanResizeProperty =
+ AvaloniaProperty.Register(nameof(CanResize), true);
+
private readonly NameScope _nameScope = new NameScope();
private object _dialogResult;
private readonly Size _maxPlatformClientSize;
@@ -113,6 +116,8 @@ namespace Avalonia.Controls
ShowInTaskbarProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue));
IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
+
+ CanResizeProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue));
}
///
@@ -208,6 +213,15 @@ namespace Avalonia.Controls
}
}
+ ///
+ /// Enables or disables resizing of the window
+ ///
+ public bool CanResize
+ {
+ get { return GetValue(CanResizeProperty); }
+ set { SetValue(CanResizeProperty, value); }
+ }
+
///
/// Gets or sets the icon of the window.
///
diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
index fc9541abb7..f949d05171 100644
--- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
+++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
@@ -93,5 +93,9 @@ namespace Avalonia.DesignerSupport.Remote
public void ShowTaskbarIcon(bool value)
{
}
+
+ public void CanResize(bool value)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
index 560425286e..01c3065486 100644
--- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs
+++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
@@ -95,6 +95,10 @@ namespace Avalonia.DesignerSupport.Remote
public void ShowTaskbarIcon(bool value)
{
}
+
+ public void CanResize(bool value)
+ {
+ }
}
class ClipboardStub : IClipboard
diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs
index d4618e7bc1..f33623dd91 100644
--- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs
+++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs
@@ -115,6 +115,8 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_set_title(GtkWindow gtkWindow, Utf8Buffer title);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
+ public delegate void gtk_window_set_resizable(GtkWindow gtkWindow, bool resizable);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_set_decorated(GtkWindow gtkWindow, bool decorated);
@@ -395,6 +397,7 @@ namespace Avalonia.Gtk3.Interop
public static D.gdk_screen_get_monitor_geometry GdkScreenGetMonitorGeometry;
public static D.gdk_screen_get_monitor_workarea GdkScreenGetMonitorWorkarea;
public static D.gtk_window_set_decorated GtkWindowSetDecorated;
+ public static D.gtk_window_set_resizable GtkWindowSetResizable;
public static D.gtk_window_set_skip_taskbar_hint GtkWindowSetSkipTaskbarHint;
public static D.gtk_window_get_skip_taskbar_hint GtkWindowGetSkipTaskbarHint;
public static D.gtk_window_set_skip_pager_hint GtkWindowSetSkipPagerHint;
diff --git a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs
index c586661a7a..2d309e19d4 100644
--- a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs
+++ b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs
@@ -61,6 +61,8 @@ namespace Avalonia.Gtk3
}
public void ShowTaskbarIcon(bool value) => Native.GtkWindowSetSkipTaskbarHint(GtkWidget, !value);
+
+ public void CanResize(bool value) => Native.GtkWindowSetResizable(GtkWidget, value);
class EmptyDisposable : IDisposable
diff --git a/src/OSX/Avalonia.MonoMac/WindowImpl.cs b/src/OSX/Avalonia.MonoMac/WindowImpl.cs
index 6825fce82e..d01cbd6ae3 100644
--- a/src/OSX/Avalonia.MonoMac/WindowImpl.cs
+++ b/src/OSX/Avalonia.MonoMac/WindowImpl.cs
@@ -9,6 +9,7 @@ namespace Avalonia.MonoMac
class WindowImpl : WindowBaseImpl, IWindowImpl
{
public bool IsDecorated = true;
+ public bool IsResizable = true;
public CGRect? UndecoratedLastUnmaximizedFrame;
public WindowImpl()
@@ -76,10 +77,15 @@ namespace Avalonia.MonoMac
protected override NSWindowStyle GetStyle()
{
+ var windowStyle = NSWindowStyle.Borderless;
+
if (IsDecorated)
- return NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Miniaturizable |
- NSWindowStyle.Titled;
- return NSWindowStyle.Borderless;
+ windowStyle |= NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Titled;
+
+ if (IsResizable)
+ windowStyle |= NSWindowStyle.Resizable;
+
+ return windowStyle;
}
public void SetSystemDecorations(bool enabled)
@@ -88,6 +94,12 @@ namespace Avalonia.MonoMac
UpdateStyle();
}
+ public void CanResize(bool value)
+ {
+ IsResizable = value;
+ UpdateStyle();
+ }
+
public void SetTitle(string title) => Window.Title = title;
class ModalDisposable : IDisposable
diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
index c5ef006b84..3639cfab55 100644
--- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
+++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
@@ -558,7 +558,18 @@ namespace Avalonia.Win32.Interop
{
DIB_RGB_COLORS = 0, /* color table in RGBs */
DIB_PAL_COLORS /* color table in palette indices */
- };
+ }
+
+ public enum WindowLongParam
+ {
+ GWL_WNDPROC = -4,
+ GWL_HINSTANCE = -6,
+ GWL_HWNDPARENT = -8,
+ GWL_ID = -12,
+ GWL_STYLE = -16,
+ GWL_EXSTYLE = -20,
+ GWL_USERDATA = -21
+ }
[StructLayout(LayoutKind.Sequential)]
public struct RGBQUAD
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index bb3c4cf6e6..ce1eaed13c 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -31,6 +31,7 @@ namespace Avalonia.Win32
private IInputRoot _owner;
private bool _trackingMouse;
private bool _decorated = true;
+ private bool _resizable = true;
private double _scaling = 1;
private WindowState _showWindowState;
private FramebufferManager _framebuffer;
@@ -77,8 +78,8 @@ namespace Avalonia.Win32
{
get
{
- var style = UnmanagedMethods.GetWindowLong(_hwnd, -16);
- var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, -20);
+ var style = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE);
+ var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE);
var padding = new UnmanagedMethods.RECT();
if (UnmanagedMethods.AdjustWindowRectEx(ref padding, style, false, exStyle))
@@ -235,13 +236,19 @@ namespace Avalonia.Win32
return;
}
- var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -16);
+ var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE);
- style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW;
+ var systemDecorationStyles = UnmanagedMethods.WindowStyles.WS_OVERLAPPED
+ | UnmanagedMethods.WindowStyles.WS_CAPTION
+ | UnmanagedMethods.WindowStyles.WS_SYSMENU
+ | UnmanagedMethods.WindowStyles.WS_MINIMIZEBOX
+ | UnmanagedMethods.WindowStyles.WS_MAXIMIZEBOX;
+
+ style |= systemDecorationStyles;
if (!value)
{
- style ^= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW;
+ style ^= systemDecorationStyles;
}
UnmanagedMethods.RECT windowRect;
@@ -251,7 +258,7 @@ namespace Avalonia.Win32
Rect newRect;
var oldThickness = BorderThickness;
- UnmanagedMethods.SetWindowLong(_hwnd, -16, (uint)style);
+ UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style);
if (value)
{
@@ -798,11 +805,11 @@ namespace Avalonia.Win32
public void ShowTaskbarIcon(bool value)
{
- var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -20);
-
- style &= ~(UnmanagedMethods.WindowStyles.WS_VISIBLE);
+ var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE);
- style |= UnmanagedMethods.WindowStyles.WS_EX_TOOLWINDOW;
+ style &= ~(UnmanagedMethods.WindowStyles.WS_VISIBLE);
+
+ style |= UnmanagedMethods.WindowStyles.WS_EX_TOOLWINDOW;
if (value)
style |= UnmanagedMethods.WindowStyles.WS_EX_APPWINDOW;
else
@@ -813,9 +820,27 @@ namespace Avalonia.Win32
{
//Toggle to make the styles stick
UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide);
- UnmanagedMethods.SetWindowLong(_hwnd, -20, (uint)style);
+ UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE, (uint)style);
UnmanagedMethods.ShowWindow(_hwnd, windowPlacement.ShowCmd);
}
}
+
+ public void CanResize(bool value)
+ {
+ if (value == _resizable)
+ {
+ return;
+ }
+
+ var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE);
+
+ if (value)
+ style |= UnmanagedMethods.WindowStyles.WS_SIZEFRAME;
+ else
+ style &= ~(UnmanagedMethods.WindowStyles.WS_SIZEFRAME);
+
+ UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style);
+ _resizable = value;
+ }
}
}