<commit_before>//
// Created by <NAME> on 04/05/2022.
// Copyright (c) 2022 Avalonia. All rights reserved.
//

#import <AppKit/AppKit.h>
#include "AutoFitContentView.h"
#include "AvnView.h"
#include "automation.h"
#include "WindowProtocol.h"

WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) {
    _isEnabled = true;
    _children = std::list<WindowImpl*>();
    _isClientAreaExtended = false;
    _extendClientHints = AvnDefaultChrome;
    _fullScreenActive = false;
    _canResize = true;
    _decorations = SystemDecorationsFull;
    _transitioningWindowState = false;
    _inSetWindowState = false;
    _lastWindowState = Normal;
    _actualWindowState = Normal;
    _lastTitle = @"";
    _parent = nullptr;
    WindowEvents = events;
}

void WindowImpl::HideOrShowTrafficLights() {
    if (Window == nil) {
        return;
    }

    bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
    bool hasTrafficLights = _isClientAreaExtended ? !wantsChrome : _decorations != SystemDecorationsFull;
    
    [[Window standardWindowButton:NSWindowCloseButton] setHidden:hasTrafficLights];
    [[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:hasTrafficLights];
    [[Window standardWindowButton:NSWindowZoomButton] setHidden:hasTrafficLights];
}

void WindowImpl::OnInitialiseNSWindow(){
    [GetWindowProtocol() setCanBecomeKeyWindow:true];
    [Window disableCursorRects];
    [Window setTabbingMode:NSWindowTabbingModeDisallowed];
    [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];

    [Window setTitle:_lastTitle];
    
    if(_isClientAreaExtended)
    {
        [GetWindowProtocol() setIsExtended:true];
        SetExtendClientArea(true);
    }
    
    if(_parent != nullptr)
    {
        SetParent(_parent);
    }
}

HRESULT WindowImpl::Show(bool activate, bool isDialog) {
    START_COM_CALL;

    @autoreleasepool {
        _isDialog = isDialog;

        WindowBaseImpl::Show(activate, isDialog);

        HideOrShowTrafficLights();

        return SetWindowState(_lastWindowState);
    }
}

HRESULT WindowImpl::SetEnabled(bool enable) {
    START_COM_CALL;

    @autoreleasepool {
        _isEnabled = enable;
        [GetWindowProtocol() setEnabled:enable];
        UpdateStyle();
        return S_OK;
    }
}

HRESULT WindowImpl::SetParent(IAvnWindow *parent) {
    START_COM_CALL;

    @autoreleasepool {
        if(_parent != nullptr)
        {
            _parent->_children.remove(this);
            auto parent = _parent;
            
            dispatch_async(dispatch_get_main_queue(), ^{
                parent->BringToFront();
            });
        }

        auto cparent = dynamic_cast<WindowImpl *>(parent);
        
        _parent = cparent;
        
        if(_parent != nullptr && Window != nullptr){
            // 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
            // state. Detect this and explicitly restore the parent window ourselves to avoid this situation.
            if (cparent->WindowState() == Minimized)
                cparent->SetWindowState(Normal);

            [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
                
            cparent->_children.push_back(this);
                
            UpdateStyle();
        }

        return S_OK;
    }
}

void WindowImpl::BringToFront()
{
    if(IsDialog())
    {
        Activate();
    }
    else
    {
        [Window orderFront:nullptr];
    }
    
    [Window invalidateShadow];
    
    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;
        }
    }<commit_msg>prevent segfault when closing app with child windows open.<commit_after>//
// Created by <NAME> on 04/05/2022.
// Copyright (c) 2022 Avalonia. All rights reserved.
//

#import <AppKit/AppKit.h>
#include "AutoFitContentView.h"
#include "AvnView.h"
#include "automation.h"
#include "WindowProtocol.h"

WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) {
    _isEnabled = true;
    _children = std::list<WindowImpl*>();
    _isClientAreaExtended = false;
    _extendClientHints = AvnDefaultChrome;
    _fullScreenActive = false;
    _canResize = true;
    _decorations = SystemDecorationsFull;
    _transitioningWindowState = false;
    _inSetWindowState = false;
    _lastWindowState = Normal;
    _actualWindowState = Normal;
    _lastTitle = @"";
    _parent = nullptr;
    WindowEvents = events;
}

void WindowImpl::HideOrShowTrafficLights() {
    if (Window == nil) {
        return;
    }

    bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
    bool hasTrafficLights = _isClientAreaExtended ? !wantsChrome : _decorations != SystemDecorationsFull;
    
    [[Window standardWindowButton:NSWindowCloseButton] setHidden:hasTrafficLights];
    [[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:hasTrafficLights];
    [[Window standardWindowButton:NSWindowZoomButton] setHidden:hasTrafficLights];
}

void WindowImpl::OnInitialiseNSWindow(){
    [GetWindowProtocol() setCanBecomeKeyWindow:true];
    [Window disableCursorRects];
    [Window setTabbingMode:NSWindowTabbingModeDisallowed];
    [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];

    [Window setTitle:_lastTitle];
    
    if(_isClientAreaExtended)
    {
        [GetWindowProtocol() setIsExtended:true];
        SetExtendClientArea(true);
    }
    
    if(_parent != nullptr)
    {
        SetParent(_parent);
    }
}

HRESULT WindowImpl::Show(bool activate, bool isDialog) {
    START_COM_CALL;

    @autoreleasepool {
        _isDialog = isDialog;

        WindowBaseImpl::Show(activate, isDialog);

        HideOrShowTrafficLights();

        return SetWindowState(_lastWindowState);
    }
}

HRESULT WindowImpl::SetEnabled(bool enable) {
    START_COM_CALL;

    @autoreleasepool {
        _isEnabled = enable;
        [GetWindowProtocol() setEnabled:enable];
        UpdateStyle();
        return S_OK;
    }
}

HRESULT WindowImpl::SetParent(IAvnWindow *parent) {
    START_COM_CALL;

    @autoreleasepool {
        if(_parent != nullptr)
        {
            _parent->_children.remove(this);
            
            _parent->BringToFront();
        }

        auto cparent = dynamic_cast<WindowImpl *>(parent);
        
        _parent = cparent;
        
        if(_parent != nullptr && Window != nullptr){
            // 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
            // state. Detect this and explicitly restore the parent window ourselves to avoid this situation.
            if (cparent->WindowState() == Minimized)
                cparent->SetWindowState(Normal);

            [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
                
            cparent->_children.push_back(this);
                
            UpdateStyle();
        }

        return S_OK;
    }
}

void WindowImpl::BringToFront()
{
    if(Window != nullptr)
    {
        if(IsDialog())
        {
            Activate();
        }
        else
        {
            [Window orderFront:nullptr];
        }
        
        [Window invalidateShadow];
        
        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;
        }
    }
{'fraction_non_alphanumeric': 0.10135462022254475, 'fraction_numerical': 0.002902757619738752, 'mean_word_length': 2.768915223336372, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5991325', 'n_tokens_mistral': 2425, 'n_tokens_neox': 2349, 'n_words': 486}