Browse Source

Merge pull request #3943 from AvaloniaUI/features/child-windows-api

Refactor Child Window API
pull/3955/head
danwalmsley 6 years ago
committed by GitHub
parent
commit
ff282711bd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      native/Avalonia.Native/inc/avalonia-native.h
  2. 3
      native/Avalonia.Native/src/OSX/window.h
  3. 74
      native/Avalonia.Native/src/OSX/window.mm
  4. 16
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  5. 109
      src/Avalonia.Controls/Window.cs
  6. 2
      src/Avalonia.Controls/WindowBase.cs
  7. 9
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  8. 10
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  9. 5
      src/Avalonia.Native/PopupImpl.cs
  10. 26
      src/Avalonia.Native/WindowImpl.cs
  11. 49
      src/Avalonia.X11/X11Window.cs
  12. 6
      src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs
  13. 29
      src/Windows/Avalonia.Win32/WindowImpl.cs
  14. 5
      tests/Avalonia.Controls.UnitTests/WindowTests.cs

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

@ -267,7 +267,8 @@ AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
{ {
virtual HRESULT ShowDialog (IAvnWindow* parent) = 0; virtual HRESULT SetEnabled (bool enable) = 0;
virtual HRESULT SetParent (IAvnWindow* parent) = 0;
virtual HRESULT SetCanResize(bool value) = 0; virtual HRESULT SetCanResize(bool value) = 0;
virtual HRESULT SetDecorations(SystemDecorations value) = 0; virtual HRESULT SetDecorations(SystemDecorations value) = 0;
virtual HRESULT SetTitle (void* utf8Title) = 0; virtual HRESULT SetTitle (void* utf8Title) = 0;
@ -309,6 +310,8 @@ AVNCOM(IAvnWindowEvents, 06) : IAvnWindowBaseEvents
virtual bool Closing () = 0; virtual bool Closing () = 0;
virtual void WindowStateChanged (AvnWindowState state) = 0; virtual void WindowStateChanged (AvnWindowState state) = 0;
virtual void GotInputWhenDisabled () = 0;
}; };
AVNCOM(IAvnMacOptions, 07) : IUnknown AVNCOM(IAvnMacOptions, 07) : IUnknown

3
native/Avalonia.Native/src/OSX/window.h

@ -19,8 +19,7 @@ class WindowBaseImpl;
-(void) pollModalSession: (NSModalSession _Nonnull) session; -(void) pollModalSession: (NSModalSession _Nonnull) session;
-(void) restoreParentWindow; -(void) restoreParentWindow;
-(bool) shouldTryToHandleEvents; -(bool) shouldTryToHandleEvents;
-(bool) isModal; -(void) setEnabled: (bool) enable;
-(void) setModal: (bool) isModal;
-(void) showAppMenuOnly; -(void) showAppMenuOnly;
-(void) showWindowMenuWithAppMenu; -(void) showWindowMenuWithAppMenu;
-(void) applyMenu:(NSMenu* _Nullable)menu; -(void) applyMenu:(NSMenu* _Nullable)menu;

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

@ -497,12 +497,7 @@ private:
virtual HRESULT Show () override virtual HRESULT Show () override
{ {
@autoreleasepool @autoreleasepool
{ {
if([Window parentWindow] != nil)
[[Window parentWindow] removeChildWindow:Window];
[Window setModal:FALSE];
WindowBaseImpl::Show(); WindowBaseImpl::Show();
HideOrShowTrafficLights(); HideOrShowTrafficLights();
@ -511,7 +506,16 @@ private:
} }
} }
virtual HRESULT ShowDialog (IAvnWindow* parent) override virtual HRESULT SetEnabled (bool enable) override
{
@autoreleasepool
{
[Window setEnabled:enable];
return S_OK;
}
}
virtual HRESULT SetParent (IAvnWindow* parent) override
{ {
@autoreleasepool @autoreleasepool
{ {
@ -522,12 +526,9 @@ private:
if(cparent == nullptr) if(cparent == nullptr)
return E_INVALIDARG; return E_INVALIDARG;
[Window setModal:TRUE];
[cparent->Window addChildWindow:Window ordered:NSWindowAbove]; [cparent->Window addChildWindow:Window ordered:NSWindowAbove];
WindowBaseImpl::Show();
HideOrShowTrafficLights(); UpdateStyle();
return S_OK; return S_OK;
} }
@ -883,15 +884,15 @@ protected:
switch (_decorations) switch (_decorations)
{ {
case SystemDecorationsNone: case SystemDecorationsNone:
s = s | NSWindowStyleMaskFullSizeContentView | NSWindowStyleMaskMiniaturizable; s = s | NSWindowStyleMaskFullSizeContentView;
break; break;
case SystemDecorationsBorderOnly: case SystemDecorationsBorderOnly:
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView | NSWindowStyleMaskMiniaturizable; s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView;
break; break;
case SystemDecorationsFull: case SystemDecorationsFull:
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskBorderless; s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskBorderless;
if(_canResize) if(_canResize)
{ {
@ -900,6 +901,10 @@ protected:
break; break;
} }
if([Window parentWindow] == nullptr)
{
s |= NSWindowStyleMaskMiniaturizable;
}
return s; return s;
} }
}; };
@ -1081,15 +1086,28 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
- (bool) ignoreUserInput - (bool) ignoreUserInput
{ {
auto parentWindow = objc_cast<AvnWindow>([self window]); auto parentWindow = objc_cast<AvnWindow>([self window]);
if(parentWindow == nil || ![parentWindow shouldTryToHandleEvents]) if(parentWindow == nil || ![parentWindow shouldTryToHandleEvents])
{
auto window = dynamic_cast<WindowImpl*>(_parent.getRaw());
if(window != nullptr)
{
window->WindowEvents->GotInputWhenDisabled();
}
return TRUE; return TRUE;
}
return FALSE; return FALSE;
} }
- (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
{ {
if([self ignoreUserInput]) if([self ignoreUserInput])
{
return; return;
}
[self becomeFirstResponder]; [self becomeFirstResponder];
auto localPoint = [self convertPoint:[event locationInWindow] toView:self]; auto localPoint = [self convertPoint:[event locationInWindow] toView:self];
@ -1234,7 +1252,10 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type - (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
{ {
if([self ignoreUserInput]) if([self ignoreUserInput])
{
return; return;
}
auto key = s_KeyMap[[event keyCode]]; auto key = s_KeyMap[[event keyCode]];
auto timestamp = [event timestamp] * 1000; auto timestamp = [event timestamp] * 1000;
@ -1416,7 +1437,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
ComPtr<WindowBaseImpl> _parent; ComPtr<WindowBaseImpl> _parent;
bool _canBecomeKeyAndMain; bool _canBecomeKeyAndMain;
bool _closed; bool _closed;
bool _isModal; bool _isEnabled;
AvnMenu* _menu; AvnMenu* _menu;
double _lastScaling; double _lastScaling;
} }
@ -1538,6 +1559,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
_parent = parent; _parent = parent;
[self setDelegate:self]; [self setDelegate:self];
_closed = false; _closed = false;
_isEnabled = true;
_lastScaling = [self backingScaleFactor]; _lastScaling = [self backingScaleFactor];
[self setOpaque:NO]; [self setOpaque:NO];
@ -1604,28 +1626,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
-(bool)shouldTryToHandleEvents -(bool)shouldTryToHandleEvents
{ {
for(NSWindow* uch in [self childWindows]) return _isEnabled;
{
auto ch = objc_cast<AvnWindow>(uch);
if(ch == nil)
continue;
if(![ch isModal])
continue;
return FALSE;
}
return TRUE;
}
-(bool) isModal
{
return _isModal;
} }
-(void) setModal: (bool) isModal -(void) setEnabled:(bool)enable
{ {
_isModal = isModal; _isEnabled = enable;
} }
-(void)makeKeyWindow -(void)makeKeyWindow

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

@ -26,9 +26,21 @@ namespace Avalonia.Platform
void SetTitle(string title); void SetTitle(string title);
/// <summary> /// <summary>
/// Shows the window as a dialog. /// Sets the parent of the window.
/// </summary> /// </summary>
void ShowDialog(IWindowImpl parent); /// <param name="parent">The parent <see cref="IWindowImpl"/>.</param>
void SetParent(IWindowImpl parent);
/// <summary>
/// Disables the window for example when a modal dialog is open.
/// </summary>
/// <param name="enable">true if the window is enabled, or false if it is disabled.</param>
void SetEnabled(bool enable);
/// <summary>
/// Called when a disabled window received input. Can be used to activate child windows.
/// </summary>
Action GotInputWhenDisabled { get; set; }
/// <summary> /// <summary>
/// Enables or disables system window decorations (title bar, buttons, etc) /// Enables or disables system window decorations (title bar, buttons, etc)

109
src/Avalonia.Controls/Window.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
@ -68,6 +69,8 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot
{ {
private List<Window> _children = new List<Window>();
/// <summary> /// <summary>
/// Defines the <see cref="SizeToContent"/> property. /// Defines the <see cref="SizeToContent"/> property.
/// </summary> /// </summary>
@ -131,7 +134,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public static readonly RoutedEvent WindowClosedEvent = public static readonly RoutedEvent WindowClosedEvent =
RoutedEvent.Register<Window, RoutedEventArgs>("WindowClosed", RoutingStrategies.Direct); RoutedEvent.Register<Window, RoutedEventArgs>("WindowClosed", RoutingStrategies.Direct);
/// <summary> /// <summary>
/// Routed event that can be used for global tracking of opening windows /// Routed event that can be used for global tracking of opening windows
/// </summary> /// </summary>
@ -183,6 +186,7 @@ namespace Avalonia.Controls
: base(impl) : base(impl)
{ {
impl.Closing = HandleClosing; impl.Closing = HandleClosing;
impl.GotInputWhenDisabled = OnGotInputWhenDisabled;
impl.WindowStateChanged = HandleWindowStateChanged; impl.WindowStateChanged = HandleWindowStateChanged;
_maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size); _maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size);
this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x)); this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x));
@ -302,7 +306,7 @@ namespace Avalonia.Controls
PlatformImpl?.Move(value); PlatformImpl?.Move(value);
} }
} }
/// <summary> /// <summary>
/// Starts moving a window with left button being held. Should be called from left mouse button press event handler /// Starts moving a window with left button being held. Should be called from left mouse button press event handler
/// </summary> /// </summary>
@ -323,7 +327,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Fired before a window is closed. /// Fired before a window is closed.
/// </summary> /// </summary>
public event EventHandler<CancelEventArgs> Closing; public event EventHandler<CancelEventArgs> Closing;
/// <summary> /// <summary>
/// Closes the window. /// Closes the window.
@ -365,19 +369,59 @@ namespace Avalonia.Controls
{ {
if (close) if (close)
{ {
PlatformImpl?.Dispose(); CloseInternal();
} }
} }
} }
private void CloseInternal()
{
foreach (var child in _children.ToList())
{
// if we HandleClosing() before then there will be no children.
child.CloseInternal();
}
if (Owner is Window owner)
{
owner.RemoveChild(this);
}
Owner = null;
PlatformImpl?.Dispose();
}
/// <summary> /// <summary>
/// Handles a closing notification from <see cref="IWindowImpl.Closing"/>. /// Handles a closing notification from <see cref="IWindowImpl.Closing"/>.
/// </summary> /// </summary>
protected virtual bool HandleClosing() protected virtual bool HandleClosing()
{ {
var args = new CancelEventArgs(); bool canClose = true;
OnClosing(args);
return args.Cancel; foreach (var child in _children.ToList())
{
if (!child.HandleClosing())
{
child.CloseInternal();
}
else
{
canClose = false;
}
}
if (canClose)
{
var args = new CancelEventArgs();
OnClosing(args);
return args.Cancel;
}
else
{
return !canClose;
}
} }
protected virtual void HandleWindowStateChanged(WindowState state) protected virtual void HandleWindowStateChanged(WindowState state)
@ -407,6 +451,14 @@ namespace Avalonia.Controls
using (BeginAutoSizing()) using (BeginAutoSizing())
{ {
Renderer?.Stop(); Renderer?.Stop();
if (Owner is Window owner)
{
owner.RemoveChild(this);
}
Owner = null;
PlatformImpl?.Hide(); PlatformImpl?.Hide();
} }
@ -519,7 +571,10 @@ namespace Avalonia.Controls
using (BeginAutoSizing()) using (BeginAutoSizing())
{ {
PlatformImpl?.ShowDialog(owner.PlatformImpl); PlatformImpl.SetParent(owner.PlatformImpl);
Owner = owner;
owner.AddChild(this);
PlatformImpl?.Show();
Renderer?.Start(); Renderer?.Start();
@ -541,6 +596,37 @@ namespace Avalonia.Controls
return result.Task; return result.Task;
} }
private void UpdateEnabled()
{
PlatformImpl.SetEnabled(_children.Count == 0);
}
private void AddChild(Window window)
{
_children.Add(window);
UpdateEnabled();
}
private void RemoveChild(Window window)
{
_children.Remove(window);
UpdateEnabled();
}
private void OnGotInputWhenDisabled()
{
var firstChild = _children.FirstOrDefault();
if (firstChild != null)
{
firstChild.OnGotInputWhenDisabled();
}
else
{
Activate();
}
}
private void SetWindowStartupLocation(IWindowBaseImpl owner = null) private void SetWindowStartupLocation(IWindowBaseImpl owner = null)
{ {
var scaling = owner?.Scaling ?? PlatformImpl?.Scaling ?? 1; var scaling = owner?.Scaling ?? PlatformImpl?.Scaling ?? 1;
@ -631,6 +717,13 @@ namespace Avalonia.Controls
RaiseEvent(new RoutedEventArgs(WindowClosedEvent)); RaiseEvent(new RoutedEventArgs(WindowClosedEvent));
base.HandleClosed(); base.HandleClosed();
if (Owner is Window owner)
{
owner.RemoveChild(this);
}
Owner = null;
} }
/// <inheritdoc/> /// <inheritdoc/>

2
src/Avalonia.Controls/WindowBase.cs

@ -109,7 +109,7 @@ namespace Avalonia.Controls
public WindowBase Owner public WindowBase Owner
{ {
get { return _owner; } get { return _owner; }
set { SetAndRaise(OwnerProperty, ref _owner, value); } protected set { SetAndRaise(OwnerProperty, ref _owner, value); }
} }
/// <summary> /// <summary>

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

@ -83,6 +83,7 @@ namespace Avalonia.DesignerSupport.Remote
} }
public IScreenImpl Screen { get; } = new ScreenStub(); public IScreenImpl Screen { get; } = new ScreenStub();
public Action GotInputWhenDisabled { get; set; }
public void Activate() public void Activate()
{ {
@ -115,5 +116,13 @@ namespace Avalonia.DesignerSupport.Remote
public void SetTopmost(bool value) public void SetTopmost(bool value)
{ {
} }
public void SetParent(IWindowImpl parent)
{
}
public void SetEnabled(bool enable)
{
}
} }
} }

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

@ -130,7 +130,17 @@ namespace Avalonia.DesignerSupport.Remote
{ {
} }
public void SetParent(IWindowImpl parent)
{
}
public void SetEnabled(bool enable)
{
}
public IPopupPositioner PopupPositioner { get; } public IPopupPositioner PopupPositioner { get; }
public Action GotInputWhenDisabled { get; set; }
} }
class ClipboardStub : IClipboard class ClipboardStub : IClipboard

5
src/Avalonia.Native/PopupImpl.cs

@ -43,6 +43,11 @@ namespace Avalonia.Native
_parent = parent; _parent = parent;
} }
public void GotInputWhenDisabled()
{
// NOP on Popup
}
bool IAvnWindowEvents.Closing() bool IAvnWindowEvents.Closing()
{ {
return true; return true;

26
src/Avalonia.Native/WindowImpl.cs

@ -40,7 +40,7 @@ namespace Avalonia.Native
bool IAvnWindowEvents.Closing() bool IAvnWindowEvents.Closing()
{ {
if(_parent.Closing != null) if (_parent.Closing != null)
{ {
return _parent.Closing(); return _parent.Closing();
} }
@ -52,15 +52,15 @@ namespace Avalonia.Native
{ {
_parent.WindowStateChanged?.Invoke((WindowState)state); _parent.WindowStateChanged?.Invoke((WindowState)state);
} }
void IAvnWindowEvents.GotInputWhenDisabled()
{
_parent.GotInputWhenDisabled?.Invoke();
}
} }
public IAvnWindow Native => _native; public IAvnWindow Native => _native;
public void ShowDialog(IWindowImpl window)
{
_native.ShowDialog(((WindowImpl)window).Native);
}
public void CanResize(bool value) public void CanResize(bool value)
{ {
_native.CanResize = value; _native.CanResize = value;
@ -71,7 +71,7 @@ namespace Avalonia.Native
_native.Decorations = (Interop.SystemDecorations)enabled; _native.Decorations = (Interop.SystemDecorations)enabled;
} }
public void SetTitleBarColor (Avalonia.Media.Color color) public void SetTitleBarColor(Avalonia.Media.Color color)
{ {
_native.SetTitleBarColor(new AvnColor { Alpha = color.A, Red = color.R, Green = color.G, Blue = color.B }); _native.SetTitleBarColor(new AvnColor { Alpha = color.A, Red = color.R, Green = color.G, Blue = color.B });
} }
@ -116,5 +116,17 @@ namespace Avalonia.Native
public override IPopupImpl CreatePopup() => public override IPopupImpl CreatePopup() =>
_opts.OverlayPopups ? null : new PopupImpl(_factory, _opts, _glFeature, this); _opts.OverlayPopups ? null : new PopupImpl(_factory, _opts, _glFeature, this);
public Action GotInputWhenDisabled { get; set; }
public void SetParent(IWindowImpl parent)
{
_native.SetParent(((WindowImpl)parent).Native);
}
public void SetEnabled(bool enable)
{
_native.SetEnabled(enable);
}
} }
} }

49
src/Avalonia.X11/X11Window.cs

@ -41,9 +41,9 @@ namespace Avalonia.X11
private IntPtr _renderHandle; private IntPtr _renderHandle;
private bool _mapped; private bool _mapped;
private bool _wasMappedAtLeastOnce = false; private bool _wasMappedAtLeastOnce = false;
private HashSet<X11Window> _transientChildren = new HashSet<X11Window>();
private X11Window _transientParent;
private double? _scalingOverride; private double? _scalingOverride;
private bool _disabled;
public object SyncRoot { get; } = new object(); public object SyncRoot { get; } = new object();
class InputEventContainer class InputEventContainer
@ -746,7 +746,6 @@ namespace Avalonia.X11
void Cleanup() void Cleanup()
{ {
SetTransientParent(null, false);
if (_xic != IntPtr.Zero) if (_xic != IntPtr.Zero)
{ {
XDestroyIC(_xic); XDestroyIC(_xic);
@ -773,38 +772,24 @@ namespace Avalonia.X11
bool ActivateTransientChildIfNeeded() bool ActivateTransientChildIfNeeded()
{ {
if (_transientChildren.Count == 0) if (_disabled)
return false; {
var child = _transientChildren.First(); GotInputWhenDisabled?.Invoke();
if (!child.ActivateTransientChildIfNeeded()) return true;
child.Activate(); }
return true;
} return false;
void SetTransientParent(X11Window window, bool informServer = true)
{
_transientParent?._transientChildren.Remove(this);
_transientParent = window;
_transientParent?._transientChildren.Add(this);
if (informServer)
SetTransientForHint(_transientParent?._handle);
} }
void SetTransientForHint(IntPtr? parent) public void SetParent(IWindowImpl parent)
{ {
if (parent == null || parent == IntPtr.Zero) if (parent == null || parent.Handle == null || parent.Handle.Handle == IntPtr.Zero)
XDeleteProperty(_x11.Display, _handle, _x11.Atoms.XA_WM_TRANSIENT_FOR); XDeleteProperty(_x11.Display, _handle, _x11.Atoms.XA_WM_TRANSIENT_FOR);
else else
XSetTransientForHint(_x11.Display, _handle, parent.Value); XSetTransientForHint(_x11.Display, _handle, parent.Handle.Handle);
} }
public void Show() public void Show()
{
SetTransientParent(null);
ShowCore();
}
void ShowCore()
{ {
_wasMappedAtLeastOnce = true; _wasMappedAtLeastOnce = true;
XMapWindow(_x11.Display, _handle); XMapWindow(_x11.Display, _handle);
@ -813,7 +798,6 @@ namespace Avalonia.X11
public void Hide() => XUnmapWindow(_x11.Display, _handle); public void Hide() => XUnmapWindow(_x11.Display, _handle);
public Point PointToClient(PixelPoint point) => new Point((point.X - Position.X) / Scaling, (point.Y - Position.Y) / Scaling); public Point PointToClient(PixelPoint point) => new Point((point.X - Position.X) / Scaling, (point.Y - Position.Y) / Scaling);
public PixelPoint PointToScreen(Point point) => new PixelPoint( public PixelPoint PointToScreen(Point point) => new PixelPoint(
@ -1034,13 +1018,14 @@ namespace Avalonia.X11
{ {
ChangeWMAtoms(value, _x11.Atoms._NET_WM_STATE_ABOVE); ChangeWMAtoms(value, _x11.Atoms._NET_WM_STATE_ABOVE);
} }
public void ShowDialog(IWindowImpl parent) public void SetEnabled(bool enable)
{ {
SetTransientParent((X11Window)parent); _disabled = !enable;
ShowCore();
} }
public Action GotInputWhenDisabled { get; set; }
public void SetIcon(IWindowIconImpl icon) public void SetIcon(IWindowIconImpl icon)
{ {
if (icon != null) if (icon != null)

6
src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs

@ -77,12 +77,6 @@ namespace Avalonia.Win32
s_instances.Remove(this); s_instances.Remove(this);
Closed?.Invoke(); Closed?.Invoke();
if (_parent != null)
{
_parent._disabledBy.Remove(this);
_parent.UpdateEnabled();
}
_mouseDevice.Dispose(); _mouseDevice.Dispose();
_touchDevice?.Dispose(); _touchDevice?.Dispose();
//Free other resources //Free other resources

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

@ -45,7 +45,6 @@ namespace Avalonia.Win32
#endif #endif
private const WindowStyles WindowStateMask = (WindowStyles.WS_MAXIMIZE | WindowStyles.WS_MINIMIZE); private const WindowStyles WindowStateMask = (WindowStyles.WS_MAXIMIZE | WindowStyles.WS_MINIMIZE);
private readonly List<WindowImpl> _disabledBy;
private readonly TouchDevice _touchDevice; private readonly TouchDevice _touchDevice;
private readonly MouseDevice _mouseDevice; private readonly MouseDevice _mouseDevice;
private readonly ManagedDeferredRendererLock _rendererLock; private readonly ManagedDeferredRendererLock _rendererLock;
@ -70,7 +69,6 @@ namespace Avalonia.Win32
public WindowImpl() public WindowImpl()
{ {
_disabledBy = new List<WindowImpl>();
_touchDevice = new TouchDevice(); _touchDevice = new TouchDevice();
_mouseDevice = new WindowsMouseDevice(); _mouseDevice = new WindowsMouseDevice();
@ -342,31 +340,25 @@ namespace Avalonia.Win32
public void Hide() public void Hide()
{ {
if (_parent != null)
{
_parent._disabledBy.Remove(this);
_parent.UpdateEnabled();
_parent = null;
}
UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide); UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide);
} }
public virtual void Show() public virtual void Show()
{ {
SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, IntPtr.Zero); SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent != null ? _parent._hwnd : IntPtr.Zero);
ShowWindow(_showWindowState); ShowWindow(_showWindowState);
} }
public void ShowDialog(IWindowImpl parent) public Action GotInputWhenDisabled { get; set; }
public void SetParent(IWindowImpl parent)
{ {
_parent = (WindowImpl)parent; _parent = (WindowImpl)parent;
_parent._disabledBy.Add(this); SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent._hwnd);
_parent.UpdateEnabled();
SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, ((WindowImpl)parent)._hwnd);
ShowWindow(_showWindowState);
} }
public void SetEnabled(bool enable) => EnableWindow(_hwnd, enable);
public void BeginMoveDrag(PointerPressedEventArgs e) public void BeginMoveDrag(PointerPressedEventArgs e)
{ {
_mouseDevice.Capture(null); _mouseDevice.Capture(null);
@ -666,7 +658,7 @@ namespace Avalonia.Win32
} }
} }
private WindowStyles GetWindowStateStyles () private WindowStyles GetWindowStateStyles()
{ {
return GetStyle() & WindowStateMask; return GetStyle() & WindowStateMask;
} }
@ -721,11 +713,6 @@ namespace Avalonia.Win32
} }
} }
private void UpdateEnabled()
{
EnableWindow(_hwnd, _disabledBy.Count == 0);
}
private void UpdateWindowProperties(WindowProperties newProperties, bool forceChanges = false) private void UpdateWindowProperties(WindowProperties newProperties, bool forceChanges = false)
{ {
var oldProperties = _windowProperties; var oldProperties = _windowProperties;

5
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@ -322,10 +322,9 @@ namespace Avalonia.Controls.UnitTests
{ {
var window = new Window(); var window = new Window();
window.WindowStartupLocation = WindowStartupLocation.CenterOwner; window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
window.Position = new PixelPoint(60, 40); window.Position = new PixelPoint(60, 40);
window.Owner = parentWindow;
window.Show(); window.ShowDialog(parentWindow);
var expectedPosition = new PixelPoint( var expectedPosition = new PixelPoint(
(int)(parentWindow.Position.X + parentWindow.ClientSize.Width / 2 - window.ClientSize.Width / 2), (int)(parentWindow.Position.X + parentWindow.ClientSize.Width / 2 - window.ClientSize.Width / 2),

Loading…
Cancel
Save