Browse Source

[OSX] programatically implement child window relationship

pull/8211/head
Dan Walmsley 4 years ago
parent
commit
2e555be402
  1. 5
      native/Avalonia.Native/src/OSX/AvnView.mm
  2. 38
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  3. 2
      native/Avalonia.Native/src/OSX/WindowBaseImpl.h
  4. 7
      native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
  5. 8
      native/Avalonia.Native/src/OSX/WindowImpl.h
  6. 66
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  7. 1
      native/Avalonia.Native/src/OSX/WindowProtocol.h

5
native/Avalonia.Native/src/OSX/AvnView.mm

@ -300,6 +300,11 @@
- (void)mouseDown:(NSEvent *)event - (void)mouseDown:(NSEvent *)event
{ {
if(_parent != nullptr)
{
_parent->BringToFront();
}
_isLeftPressed = true; _isLeftPressed = true;
_lastMouseDownEvent = event; _lastMouseDownEvent = event;
[self mouseEvent:event withType:LeftButtonDown]; [self mouseEvent:event withType:LeftButtonDown];

38
native/Avalonia.Native/src/OSX/AvnWindow.mm

@ -183,6 +183,11 @@
return self; return self;
} }
- (void)mouseDown:(NSEvent *)event
{
_parent->BringToFront();
}
- (BOOL)windowShouldClose:(NSWindow *)sender - (BOOL)windowShouldClose:(NSWindow *)sender
{ {
auto window = dynamic_cast<WindowImpl*>(_parent.getRaw()); auto window = dynamic_cast<WindowImpl*>(_parent.getRaw());
@ -209,7 +214,14 @@
{ {
ComPtr<WindowBaseImpl> parent = _parent; ComPtr<WindowBaseImpl> parent = _parent;
_parent = NULL; _parent = NULL;
[self restoreParentWindow];
auto window = dynamic_cast<WindowImpl*>(parent.getRaw());
if(window != nullptr)
{
window->SetParent(nullptr);
}
parent->BaseEvents->Closed(); parent->BaseEvents->Closed();
[parent->View onClosed]; [parent->View onClosed];
} }
@ -220,17 +232,11 @@
if(_canBecomeKeyWindow) if(_canBecomeKeyWindow)
{ {
// If the window has a child window being shown as a dialog then don't allow it to become the key window. // If the window has a child window being shown as a dialog then don't allow it to become the key window.
for(NSWindow* uch in [self childWindows]) auto parent = dynamic_cast<WindowImpl*>(_parent.getRaw());
if(parent != nullptr)
{ {
if (![uch conformsToProtocol:@protocol(AvnWindowProtocol)]) return parent->CanBecomeKeyWindow();
{
continue;
}
id <AvnWindowProtocol> ch = (id <AvnWindowProtocol>) uch;
if(ch.isDialog)
return false;
} }
return true; return true;
@ -273,16 +279,6 @@
[super becomeKeyWindow]; [super becomeKeyWindow];
} }
-(void) restoreParentWindow;
{
auto parent = [self parentWindow];
if(parent != nil)
{
[parent removeChildWindow:self];
}
}
- (void)windowDidMiniaturize:(NSNotification *)notification - (void)windowDidMiniaturize:(NSNotification *)notification
{ {
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->()); auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());

2
native/Avalonia.Native/src/OSX/WindowBaseImpl.h

@ -99,6 +99,8 @@ BEGIN_INTERFACE_MAP()
virtual bool IsDialog(); virtual bool IsDialog();
id<AvnWindowProtocol> GetWindowProtocol (); id<AvnWindowProtocol> GetWindowProtocol ();
virtual void BringToFront ();
protected: protected:
virtual NSWindowStyleMask GetStyle(); virtual NSWindowStyleMask GetStyle();

7
native/Avalonia.Native/src/OSX/WindowBaseImpl.mm

@ -143,8 +143,6 @@ HRESULT WindowBaseImpl::Hide() {
@autoreleasepool { @autoreleasepool {
if (Window != nullptr) { if (Window != nullptr) {
[Window orderOut:Window]; [Window orderOut:Window];
[GetWindowProtocol() restoreParentWindow];
} }
return S_OK; return S_OK;
@ -610,6 +608,11 @@ id <AvnWindowProtocol> WindowBaseImpl::GetWindowProtocol() {
return (id <AvnWindowProtocol>) Window; return (id <AvnWindowProtocol>) Window;
} }
void WindowBaseImpl::BringToFront()
{
// do nothing.
}
extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl) extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl)
{ {
@autoreleasepool @autoreleasepool

8
native/Avalonia.Native/src/OSX/WindowImpl.h

@ -8,6 +8,7 @@
#import "WindowBaseImpl.h" #import "WindowBaseImpl.h"
#include "IWindowStateChanged.h" #include "IWindowStateChanged.h"
#include <list>
class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged
{ {
@ -22,7 +23,8 @@ private:
bool _transitioningWindowState; bool _transitioningWindowState;
bool _isClientAreaExtended; bool _isClientAreaExtended;
bool _isDialog; bool _isDialog;
WindowImpl* _lastParent; WindowImpl* _parent;
std::list<WindowImpl*> _children;
AvnExtendClientAreaChromeHints _extendClientHints; AvnExtendClientAreaChromeHints _extendClientHints;
FORWARD_IUNKNOWN() FORWARD_IUNKNOWN()
@ -91,6 +93,10 @@ BEGIN_INTERFACE_MAP()
virtual bool IsDialog() override; virtual bool IsDialog() override;
virtual void OnInitialiseNSWindow() override; virtual void OnInitialiseNSWindow() override;
virtual void BringToFront () override;
bool CanBecomeKeyWindow ();
protected: protected:
virtual NSWindowStyleMask GetStyle() override; virtual NSWindowStyleMask GetStyle() override;

66
native/Avalonia.Native/src/OSX/WindowImpl.mm

@ -10,6 +10,7 @@
#include "WindowProtocol.h" #include "WindowProtocol.h"
WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) { WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) {
_children = std::list<WindowImpl*>();
_isClientAreaExtended = false; _isClientAreaExtended = false;
_extendClientHints = AvnDefaultChrome; _extendClientHints = AvnDefaultChrome;
_fullScreenActive = false; _fullScreenActive = false;
@ -20,7 +21,7 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase
_lastWindowState = Normal; _lastWindowState = Normal;
_actualWindowState = Normal; _actualWindowState = Normal;
_lastTitle = @""; _lastTitle = @"";
_lastParent = nullptr; _parent = nullptr;
WindowEvents = events; WindowEvents = events;
} }
@ -63,9 +64,9 @@ void WindowImpl::OnInitialiseNSWindow(){
SetExtendClientArea(true); SetExtendClientArea(true);
} }
if(_lastParent != nullptr) if(_parent != nullptr)
{ {
SetParent(_lastParent); SetParent(_parent);
} }
} }
@ -96,33 +97,56 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) {
START_COM_CALL; START_COM_CALL;
@autoreleasepool { @autoreleasepool {
if (parent == nullptr) if(_parent != nullptr)
return E_POINTER; {
_parent->_children.remove(this);
}
auto cparent = dynamic_cast<WindowImpl *>(parent); auto cparent = dynamic_cast<WindowImpl *>(parent);
if (cparent == nullptr)
return E_INVALIDARG;
_lastParent = cparent; _parent = cparent;
if(Window != nullptr){ if(_parent != nullptr && Window != nullptr){
// If one tries to show a child window with a minimized parent window, then the parent window will be // If one tries to show a child window with a minimized parent window, then the parent window will be
// restored but macOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive // restored but macOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive
// state. Detect this and explicitly restore the parent window ourselves to avoid this situation. // state. Detect this and explicitly restore the parent window ourselves to avoid this situation.
if (cparent->WindowState() == Minimized) if (cparent->WindowState() == Minimized)
cparent->SetWindowState(Normal); cparent->SetWindowState(Normal);
[Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
[cparent->Window addChildWindow:Window ordered:NSWindowAbove];
cparent->_children.push_back(this);
UpdateStyle();
UpdateStyle();
} }
return S_OK; return S_OK;
} }
} }
void WindowImpl::BringToFront()
{
Activate();
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
(*iterator)->BringToFront();
}
}
bool WindowImpl::CanBecomeKeyWindow()
{
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
if((*iterator)->IsDialog())
{
return false;
}
}
return true;
}
void WindowImpl::StartStateTransition() { void WindowImpl::StartStateTransition() {
_transitioningWindowState = true; _transitioningWindowState = true;
} }
@ -534,7 +558,7 @@ bool WindowImpl::IsDialog() {
} }
NSWindowStyleMask WindowImpl::GetStyle() { NSWindowStyleMask WindowImpl::GetStyle() {
unsigned long s = this->_isDialog ? NSWindowStyleMaskDocModalWindow : NSWindowStyleMaskBorderless; unsigned long s = NSWindowStyleMaskBorderless;
switch (_decorations) { switch (_decorations) {
case SystemDecorationsNone: case SystemDecorationsNone:

1
native/Avalonia.Native/src/OSX/WindowProtocol.h

@ -11,7 +11,6 @@
@protocol AvnWindowProtocol @protocol AvnWindowProtocol
-(void) pollModalSession: (NSModalSession _Nonnull) session; -(void) pollModalSession: (NSModalSession _Nonnull) session;
-(void) restoreParentWindow;
-(bool) shouldTryToHandleEvents; -(bool) shouldTryToHandleEvents;
-(void) setEnabled: (bool) enable; -(void) setEnabled: (bool) enable;
-(void) showAppMenuOnly; -(void) showAppMenuOnly;

Loading…
Cancel
Save