Browse Source

Rework system decorations

pull/3539/head
Nathan Garside 7 years ago
parent
commit
7b9d32af85
  1. 2
      native/Avalonia.Native/inc/avalonia-native.h
  2. 41
      native/Avalonia.Native/src/OSX/window.mm
  3. 11
      samples/ControlCatalog/MainView.xaml
  4. 14
      samples/ControlCatalog/MainView.xaml.cs
  5. 2
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  6. 44
      src/Avalonia.Controls/Window.cs
  7. 2
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  8. 2
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  9. 4
      src/Avalonia.Native/WindowImpl.cs
  10. 16
      src/Avalonia.X11/X11Window.cs
  11. 10
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  12. 20
      src/Windows/Avalonia.Win32/WindowImpl.cs
  13. 2
      src/iOS/Avalonia.iOS/EmbeddableImpl.cs

2
native/Avalonia.Native/inc/avalonia-native.h

@ -236,7 +236,7 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
{ {
virtual HRESULT ShowDialog (IAvnWindow* parent) = 0; virtual HRESULT ShowDialog (IAvnWindow* parent) = 0;
virtual HRESULT SetCanResize(bool value) = 0; virtual HRESULT SetCanResize(bool value) = 0;
virtual HRESULT SetHasDecorations(bool value) = 0; virtual HRESULT SetHasDecorations(int value) = 0;
virtual HRESULT SetTitle (void* utf8Title) = 0; virtual HRESULT SetTitle (void* utf8Title) = 0;
virtual HRESULT SetTitleBarColor (AvnColor color) = 0; virtual HRESULT SetTitleBarColor (AvnColor color) = 0;
virtual HRESULT SetWindowState(AvnWindowState state) = 0; virtual HRESULT SetWindowState(AvnWindowState state) = 0;

41
native/Avalonia.Native/src/OSX/window.mm

@ -115,7 +115,6 @@ public:
[NSApp activateIgnoringOtherApps:YES]; [NSApp activateIgnoringOtherApps:YES];
[Window setTitle:_lastTitle]; [Window setTitle:_lastTitle];
[Window setTitleVisibility:NSWindowTitleVisible];
return S_OK; return S_OK;
} }
@ -411,7 +410,7 @@ class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, pub
{ {
private: private:
bool _canResize = true; bool _canResize = true;
bool _hasDecorations = true; int _hasDecorations = 2;
CGRect _lastUndecoratedFrame; CGRect _lastUndecoratedFrame;
AvnWindowState _lastWindowState; AvnWindowState _lastWindowState;
@ -476,12 +475,12 @@ private:
bool IsZoomed () bool IsZoomed ()
{ {
return _hasDecorations ? [Window isZoomed] : UndecoratedIsMaximized(); return _hasDecorations > 0 ? [Window isZoomed] : UndecoratedIsMaximized();
} }
void DoZoom() void DoZoom()
{ {
if (_hasDecorations) if (_hasDecorations > 0)
{ {
[Window performZoom:Window]; [Window performZoom:Window];
} }
@ -506,13 +505,36 @@ private:
} }
} }
virtual HRESULT SetHasDecorations(bool value) override virtual HRESULT SetHasDecorations(int value) override
{ {
@autoreleasepool @autoreleasepool
{ {
_hasDecorations = value; _hasDecorations = value;
UpdateStyle(); UpdateStyle();
// full
if (_hasDecorations == 2)
{
[Window setHasShadow:YES];
[Window setTitleVisibility:NSWindowTitleVisible];
[Window setTitlebarAppearsTransparent:NO];
[Window setTitle:_lastTitle];
}
// border only
else if (_hasDecorations == 1)
{
[Window setHasShadow:YES];
[Window setTitleVisibility:NSWindowTitleHidden];
[Window setTitlebarAppearsTransparent:YES];
}
// none
else
{
[Window setHasShadow:NO];
[Window setTitleVisibility:NSWindowTitleHidden];
[Window setTitlebarAppearsTransparent:YES];
}
return S_OK; return S_OK;
} }
} }
@ -523,7 +545,6 @@ private:
{ {
_lastTitle = [NSString stringWithUTF8String:(const char*)utf8title]; _lastTitle = [NSString stringWithUTF8String:(const char*)utf8title];
[Window setTitle:_lastTitle]; [Window setTitle:_lastTitle];
[Window setTitleVisibility:NSWindowTitleVisible];
return S_OK; return S_OK;
} }
@ -645,9 +666,11 @@ protected:
virtual NSWindowStyleMask GetStyle() override virtual NSWindowStyleMask GetStyle() override
{ {
unsigned long s = NSWindowStyleMaskBorderless; unsigned long s = NSWindowStyleMaskBorderless;
if(_hasDecorations) if(_hasDecorations == 1)
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView;
if(_canResize) if(_hasDecorations == 2)
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskBorderless;
if(_hasDecorations == 2 && _canResize)
s = s | NSWindowStyleMaskResizable; s = s | NSWindowStyleMaskResizable;
return s; return s;
} }

11
samples/ControlCatalog/MainView.xaml

@ -58,10 +58,17 @@
<TabItem Header="TreeView"><pages:TreeViewPage/></TabItem> <TabItem Header="TreeView"><pages:TreeViewPage/></TabItem>
<TabItem Header="Viewbox"><pages:ViewboxPage/></TabItem> <TabItem Header="Viewbox"><pages:ViewboxPage/></TabItem>
<TabControl.Tag> <TabControl.Tag>
<ComboBox x:Name="Themes" SelectedIndex="0" Width="100" Margin="8" HorizontalAlignment="Right" VerticalAlignment="Bottom"> <StackPanel Width="115" Margin="8" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<ComboBox x:Name="Decorations" SelectedIndex="0" Margin="0,0,0,8">
<ComboBoxItem>No Decorations</ComboBoxItem>
<ComboBoxItem>Border Only</ComboBoxItem>
<ComboBoxItem>Full Decorations</ComboBoxItem>
</ComboBox>
<ComboBox x:Name="Themes" SelectedIndex="0">
<ComboBoxItem>Light</ComboBoxItem> <ComboBoxItem>Light</ComboBoxItem>
<ComboBoxItem>Dark</ComboBoxItem> <ComboBoxItem>Dark</ComboBoxItem>
</ComboBox> </ComboBox>
</StackPanel>
</TabControl.Tag> </TabControl.Tag>
</TabControl> </TabControl>
</Grid> </Grid>

14
samples/ControlCatalog/MainView.xaml.cs

@ -56,6 +56,20 @@ namespace ControlCatalog
} }
}; };
Styles.Add(light); Styles.Add(light);
var decorations = this.Find<ComboBox>("Decorations");
decorations.SelectionChanged += (sender, e) =>
{
Window window = (Window)VisualRoot;
window.SystemDecorations = (SystemDecorations)decorations.SelectedIndex;
};
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
var decorations = this.Find<ComboBox>("Decorations");
decorations.SelectedIndex = (int)((Window)VisualRoot).SystemDecorations;
} }
} }
} }

2
src/Avalonia.Controls/Platform/IWindowImpl.cs

@ -36,7 +36,7 @@ namespace Avalonia.Platform
/// <summary> /// <summary>
/// Enables or disables system window decorations (title bar, buttons, etc) /// Enables or disables system window decorations (title bar, buttons, etc)
/// </summary> /// </summary>
void SetSystemDecorations(bool enabled); void SetSystemDecorations(SystemDecorations enabled);
/// <summary> /// <summary>
/// Sets the icon of this window. /// Sets the icon of this window.

44
src/Avalonia.Controls/Window.cs

@ -45,6 +45,27 @@ namespace Avalonia.Controls
WidthAndHeight = 3, WidthAndHeight = 3,
} }
/// <summary>
/// Determines system decorations (title bar, border, etc) for a <see cref="Window"/>
/// </summary>
public enum SystemDecorations
{
/// <summary>
/// No decorations
/// </summary>
None = 0,
/// <summary>
/// Window border without titlebar
/// </summary>
BorderOnly = 1,
/// <summary>
/// Fully decorated (default)
/// </summary>
Full = 2
}
/// <summary> /// <summary>
/// A top-level window. /// A top-level window.
/// </summary> /// </summary>
@ -59,9 +80,16 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Enables or disables system window decorations (title bar, buttons, etc) /// Enables or disables system window decorations (title bar, buttons, etc)
/// </summary> /// </summary>
[Obsolete("Use SystemDecorationsProperty instead")]
public static readonly StyledProperty<bool> HasSystemDecorationsProperty = public static readonly StyledProperty<bool> HasSystemDecorationsProperty =
AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true); AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true);
/// <summary>
/// Defines the <see cref="SystemDecorations"/> property.
/// </summary>
public static readonly StyledProperty<SystemDecorations> SystemDecorationsProperty =
AvaloniaProperty.Register<Window, SystemDecorations>(nameof(SystemDecorations), SystemDecorations.Full);
/// <summary> /// <summary>
/// Enables or disables the taskbar icon /// Enables or disables the taskbar icon
/// </summary> /// </summary>
@ -125,7 +153,9 @@ namespace Avalonia.Controls
BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White); BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetTitle((string)e.NewValue)); TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetTitle((string)e.NewValue));
HasSystemDecorationsProperty.Changed.AddClassHandler<Window>( HasSystemDecorationsProperty.Changed.AddClassHandler<Window>(
(s, e) => s.PlatformImpl?.SetSystemDecorations((bool)e.NewValue)); (s, e) => s.PlatformImpl?.SetSystemDecorations(((bool)e.NewValue) ? SystemDecorations.Full : SystemDecorations.None));
SystemDecorationsProperty.Changed.AddClassHandler<Window>(
(s, e) => s.PlatformImpl?.SetSystemDecorations((SystemDecorations)e.NewValue));
ShowInTaskbarProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue)); ShowInTaskbarProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue));
@ -140,7 +170,6 @@ namespace Avalonia.Controls
MinHeightProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight))); MinHeightProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight)));
MaxWidthProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight))); MaxWidthProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight)));
MaxHeightProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size(w.MaxWidth, (double)e.NewValue))); MaxHeightProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size(w.MaxWidth, (double)e.NewValue)));
} }
/// <summary> /// <summary>
@ -192,12 +221,23 @@ namespace Avalonia.Controls
/// Enables or disables system window decorations (title bar, buttons, etc) /// Enables or disables system window decorations (title bar, buttons, etc)
/// </summary> /// </summary>
/// ///
[Obsolete("Use SystemDecorations instead")]
public bool HasSystemDecorations public bool HasSystemDecorations
{ {
get { return GetValue(HasSystemDecorationsProperty); } get { return GetValue(HasSystemDecorationsProperty); }
set { SetValue(HasSystemDecorationsProperty, value); } set { SetValue(HasSystemDecorationsProperty, value); }
} }
/// <summary>
/// Sets the system decorations (title bar, border, etc)
/// </summary>
///
public SystemDecorations SystemDecorations
{
get { return GetValue(SystemDecorationsProperty); }
set { SetValue(SystemDecorationsProperty, value); }
}
/// <summary> /// <summary>
/// Enables or disables the taskbar icon /// Enables or disables the taskbar icon
/// </summary> /// </summary>

2
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@ -96,7 +96,7 @@ namespace Avalonia.DesignerSupport.Remote
{ {
} }
public void SetSystemDecorations(bool enabled) public void SetSystemDecorations(SystemDecorations enabled)
{ {
} }

2
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -110,7 +110,7 @@ namespace Avalonia.DesignerSupport.Remote
{ {
} }
public void SetSystemDecorations(bool enabled) public void SetSystemDecorations(SystemDecorations enabled)
{ {
} }

4
src/Avalonia.Native/WindowImpl.cs

@ -68,9 +68,9 @@ namespace Avalonia.Native
_native.CanResize = value; _native.CanResize = value;
} }
public void SetSystemDecorations(bool enabled) public void SetSystemDecorations(SystemDecorations enabled)
{ {
_native.HasDecorations = enabled; _native.HasDecorations = (int)enabled;
} }
public void SetTitleBarColor (Avalonia.Media.Color color) public void SetTitleBarColor (Avalonia.Media.Color color)

16
src/Avalonia.X11/X11Window.cs

@ -173,6 +173,7 @@ namespace Avalonia.X11
Surfaces = surfaces.ToArray(); Surfaces = surfaces.ToArray();
UpdateMotifHints(); UpdateMotifHints();
UpdateSizeHints(null);
_xic = XCreateIC(_x11.Xim, XNames.XNInputStyle, XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing, _xic = XCreateIC(_x11.Xim, XNames.XNInputStyle, XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing,
XNames.XNClientWindow, _handle, IntPtr.Zero); XNames.XNClientWindow, _handle, IntPtr.Zero);
XFlush(_x11.Display); XFlush(_x11.Display);
@ -219,12 +220,16 @@ namespace Avalonia.X11
var decorations = MotifDecorations.Menu | MotifDecorations.Title | MotifDecorations.Border | var decorations = MotifDecorations.Menu | MotifDecorations.Title | MotifDecorations.Border |
MotifDecorations.Maximize | MotifDecorations.Minimize | MotifDecorations.ResizeH; MotifDecorations.Maximize | MotifDecorations.Minimize | MotifDecorations.ResizeH;
if (_popup || !_systemDecorations) if (_popup || _systemDecorations == SystemDecorations.None)
{ {
decorations = 0; decorations = 0;
} }
else if (_systemDecorations == SystemDecorations.BorderOnly)
{
decorations = MotifDecorations.Border;
}
if (!_canResize) if (!_canResize || _systemDecorations == SystemDecorations.BorderOnly)
{ {
functions &= ~(MotifFunctions.Resize | MotifFunctions.Maximize); functions &= ~(MotifFunctions.Resize | MotifFunctions.Maximize);
decorations &= ~(MotifDecorations.Maximize | MotifDecorations.ResizeH); decorations &= ~(MotifDecorations.Maximize | MotifDecorations.ResizeH);
@ -247,7 +252,7 @@ namespace Avalonia.X11
var min = _minMaxSize.minSize; var min = _minMaxSize.minSize;
var max = _minMaxSize.maxSize; var max = _minMaxSize.maxSize;
if (!_canResize) if (!_canResize || _systemDecorations == SystemDecorations.BorderOnly)
max = min = _realSize; max = min = _realSize;
if (preResize.HasValue) if (preResize.HasValue)
@ -621,7 +626,7 @@ namespace Avalonia.X11
return rv; return rv;
} }
private bool _systemDecorations = true; private SystemDecorations _systemDecorations = SystemDecorations.Full;
private bool _canResize = true; private bool _canResize = true;
private const int MaxWindowDimension = 100000; private const int MaxWindowDimension = 100000;
@ -777,10 +782,11 @@ namespace Avalonia.X11
(int)(point.X * Scaling + Position.X), (int)(point.X * Scaling + Position.X),
(int)(point.Y * Scaling + Position.Y)); (int)(point.Y * Scaling + Position.Y));
public void SetSystemDecorations(bool enabled) public void SetSystemDecorations(SystemDecorations enabled)
{ {
_systemDecorations = enabled; _systemDecorations = enabled;
UpdateMotifHints(); UpdateMotifHints();
UpdateSizeHints(null);
} }

10
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1298,7 +1298,17 @@ namespace Avalonia.Win32.Interop
[DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)] [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)]
internal static extern void DoDragDrop(IOleDataObject dataObject, IDropSource dropSource, int allowedEffects, out int finalEffect); internal static extern void DoDragDrop(IOleDataObject dataObject, IDropSource dropSource, int allowedEffects, out int finalEffect);
[DllImport("dwmapi.dll")]
public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
[StructLayout(LayoutKind.Sequential)]
internal struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
public enum MONITOR public enum MONITOR
{ {

20
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -34,7 +34,7 @@ namespace Avalonia.Win32
private IInputRoot _owner; private IInputRoot _owner;
private ManagedDeferredRendererLock _rendererLock = new ManagedDeferredRendererLock(); private ManagedDeferredRendererLock _rendererLock = new ManagedDeferredRendererLock();
private bool _trackingMouse; private bool _trackingMouse;
private bool _decorated = true; private SystemDecorations _decorated = SystemDecorations.Full;
private bool _resizable = true; private bool _resizable = true;
private bool _topmost = false; private bool _topmost = false;
private bool _taskbarIcon = true; private bool _taskbarIcon = true;
@ -97,7 +97,7 @@ namespace Avalonia.Win32
{ {
get get
{ {
if (_decorated) if (_decorated == SystemDecorations.Full)
{ {
var style = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); var style = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE);
var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE);
@ -281,7 +281,7 @@ namespace Avalonia.Win32
UnmanagedMethods.ShowWindow(_hwnd, UnmanagedMethods.ShowWindowCommand.Hide); UnmanagedMethods.ShowWindow(_hwnd, UnmanagedMethods.ShowWindowCommand.Hide);
} }
public void SetSystemDecorations(bool value) public void SetSystemDecorations(SystemDecorations value)
{ {
if (value == _decorated) if (value == _decorated)
{ {
@ -464,7 +464,7 @@ namespace Avalonia.Win32
return IntPtr.Zero; return IntPtr.Zero;
case WindowsMessage.WM_NCCALCSIZE: case WindowsMessage.WM_NCCALCSIZE:
if (ToInt32(wParam) == 1 && !_decorated) if (ToInt32(wParam) == 1 && _decorated != SystemDecorations.Full)
{ {
return IntPtr.Zero; return IntPtr.Zero;
} }
@ -682,14 +682,14 @@ namespace Avalonia.Win32
break; break;
case WindowsMessage.WM_NCPAINT: case WindowsMessage.WM_NCPAINT:
if (!_decorated) if (_decorated != SystemDecorations.Full)
{ {
return IntPtr.Zero; return IntPtr.Zero;
} }
break; break;
case WindowsMessage.WM_NCACTIVATE: case WindowsMessage.WM_NCACTIVATE:
if (!_decorated) if (_decorated != SystemDecorations.Full)
{ {
return new IntPtr(1); return new IntPtr(1);
} }
@ -1001,7 +1001,7 @@ namespace Avalonia.Win32
style |= WindowStyles.WS_OVERLAPPEDWINDOW; style |= WindowStyles.WS_OVERLAPPEDWINDOW;
if (!_decorated) if (_decorated != SystemDecorations.Full)
{ {
style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU); style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU);
} }
@ -1011,6 +1011,10 @@ namespace Avalonia.Win32
style ^= (WindowStyles.WS_SIZEFRAME); style ^= (WindowStyles.WS_SIZEFRAME);
} }
MARGINS margins = new MARGINS();
margins.cyBottomHeight = _decorated == SystemDecorations.BorderOnly ? 1 : 0;
UnmanagedMethods.DwmExtendFrameIntoClientArea(_hwnd, ref margins);
GetClientRect(_hwnd, out var oldClientRect); GetClientRect(_hwnd, out var oldClientRect);
var oldClientRectOrigin = new UnmanagedMethods.POINT(); var oldClientRectOrigin = new UnmanagedMethods.POINT();
ClientToScreen(_hwnd, ref oldClientRectOrigin); ClientToScreen(_hwnd, ref oldClientRectOrigin);
@ -1024,7 +1028,7 @@ namespace Avalonia.Win32
if (oldDecorated != _decorated) if (oldDecorated != _decorated)
{ {
var newRect = oldClientRect; var newRect = oldClientRect;
if (_decorated) if (_decorated == SystemDecorations.Full)
AdjustWindowRectEx(ref newRect, (uint)style, false, AdjustWindowRectEx(ref newRect, (uint)style, false,
GetWindowLong(_hwnd, (int)WindowLongParam.GWL_EXSTYLE)); GetWindowLong(_hwnd, (int)WindowLongParam.GWL_EXSTYLE));
SetWindowPos(_hwnd, IntPtr.Zero, newRect.left, newRect.top, newRect.Width, newRect.Height, SetWindowPos(_hwnd, IntPtr.Zero, newRect.left, newRect.top, newRect.Width, newRect.Height,

2
src/iOS/Avalonia.iOS/EmbeddableImpl.cs

@ -20,7 +20,7 @@ namespace Avalonia.iOS
return Disposable.Empty; return Disposable.Empty;
} }
public void SetSystemDecorations(bool enabled) public void SetSystemDecorations(SystemDecorations enabled)
{ {
} }

Loading…
Cancel
Save