<commit_before>#include "window.h"
#include "container.h"
#include "node.h"
#include "display.h"
#include "space.h"
#include "tree.h"
#include "border.h"
#include "helpers.h"
#include "rules.h"
#include "serializer.h"
#include "cursor.h"

#include "axlib/axlib.h"

#include <cmath>

#define internal static
#define local_persist static

extern std::map<CFStringRef, space_info> WindowTree;

extern ax_state AXState;
extern ax_display *FocusedDisplay;
extern ax_application *FocusedApplication;

extern kwm_screen KWMScreen;
extern kwm_focus KWMFocus;
extern kwm_toggles KWMToggles;
extern kwm_mode KWMMode;
extern kwm_tiling KWMTiling;
extern kwm_path KWMPath;
extern kwm_thread KWMThread;
extern kwm_border MarkedBorder;
extern kwm_border FocusedBorder;

internal void
UpdateSpaceOfDisplay(ax_display *Display, space_info *Space)
{
    if(Space->RootNode)
    {
        if(Space->Settings.Mode == SpaceModeBSP)
        {
            SetRootNodeContainer(Display, Space->RootNode);
            CreateNodeContainers(Display, Space->RootNode, true);
        }
        else if(Space->Settings.Mode == SpaceModeMonocle)
        {
            link_node *Link = Space->RootNode->List;
            while(Link)
            {
                SetLinkNodeContainer(Display, Link);
                Link = Link->Next;
            }
        }

        ApplyTreeNodeContainer(Space->RootNode);
        Space->NeedsUpdate = false;
    }
}

EVENT_CALLBACK(Callback_AXEvent_DisplayAdded)
{
    DEBUG("AXEvent_DisplayAdded");
}

EVENT_CALLBACK(Callback_AXEvent_DisplayRemoved)
{
    DEBUG("AXEvent_DisplayRemoved");
}

EVENT_CALLBACK(Callback_AXEvent_DisplayResized)
{
    ax_display *Display = (ax_display *) Event->Context;
    DEBUG("AXEvent_DisplayResized");

    std::map<CGSSpaceID, ax_space>::iterator It;
    for(It = Display->Spaces.begin(); It != Display->Spaces.end(); ++It)
    {
        ax_space *Space = &It->second;
        space_info *SpaceInfo = &WindowTree[Space->Identifier];
        if(Space == Display->Space)
            UpdateSpaceOfDisplay(Display, SpaceInfo);
        else
            SpaceInfo->NeedsUpdate = true;
    }
}

EVENT_CALLBACK(Callback_AXEvent_DisplayMoved)
{
    ax_display *Display = (ax_display *) Event->Context;
    DEBUG("AXEvent_DisplayMoved");

    std::map<CGSSpaceID, ax_space>::iterator It;
    for(It = Display->Spaces.begin(); It != Display->Spaces.end(); ++It)
    {
        ax_space *Space = &It->second;
        space_info *SpaceInfo = &WindowTree[Space->Identifier];
        if(Space == Display->Space)
            UpdateSpaceOfDisplay(Display, SpaceInfo);
        else
            SpaceInfo->NeedsUpdate = true;
    }
}

EVENT_CALLBACK(Callback_AXEvent_DisplayChanged)
{
    FocusedDisplay = AXLibMainDisplay();
    printf("%d: AXEvent_DisplayChanged\n", FocusedDisplay->ArrangementID);

    AXLibRunningApplications();
    CreateWindowNodeTree(FocusedDisplay);
    RebalanceNodeTree(FocusedDisplay);
}

internal void
AddMinimizedWindowsToTree(ax_display *Display)
{
    std::vector<ax_window *> Windows = AXLibGetAllVisibleWindows();
    for(std::size_t Index = 0; Index < Windows.size(); ++Index)
    {
        ax_window *Window = Windows[Index];
        if(AXLibHasFlags(Window, AXWindow_Minimized))
        {
            AXLibClearFlags(Window, AXWindow_Minimized);
            if((AXLibIsWindowStandard(Window) || AXLibIsWindowCustom(Window)) &&
               (!AXLibHasFlags(Window, AXWindow_Floating)))
            {
                AddWindowToNodeTree(Display, Window->ID);
            }
        }
    }
}

EVENT_CALLBACK(Callback_AXEvent_SpaceChanged)
{
    DEBUG("AXEvent_SpaceChanged");
    ClearBorder(&FocusedBorder);

    /* NOTE(koekeishiya): OSX APIs are horrible, so we need to detect which display
                          this event was triggered for. */
    ax_display *MainDisplay = AXLibMainDisplay();
    ax_display *Display = MainDisplay;
    do
    {
        ax_space *PrevSpace = Display->Space;
        Display->Space = AXLibGetActiveSpace(Display);
        Display->PrevSpace = PrevSpace;
        if(Display->Space != Display->PrevSpace)
            break;

        Display = AXLibNextDisplay(Display);
    } while(Display != MainDisplay);

    FocusedDisplay = Display;
    ax_space *PrevSpace = FocusedDisplay->PrevSpace;
    space_info *SpaceInfo = &WindowTree[FocusedDisplay->Space->Identifier];
    printf("Display: CGDirectDisplayID %d, Arrangement %d\n", FocusedDisplay->ID, FocusedDisplay->ArrangementID);
    printf("OldSpace %d : NewSpace %d\n", PrevSpace->ID, FocusedDisplay->Space->ID);

    AXLibRunningApplications();
    RebalanceNodeTree(FocusedDisplay);

    /* NOTE(koekeishiya): This space transition was invoked through deminiaturizing a window.
                          We have no way of passing the actual window in question, to this callback,
                          so we have marked the window through AXWindow_Minimized. We iterate through
                          all visible windows to locate the window we need. */
    if(AXLibHasFlags(PrevSpace, AXSpace_DeminimizedTransition))
    {
        AXLibClearFlags(PrevSpace, AXSpace_DeminimizedTransition);
        AddMinimizedWindowsToTree(Display);
    }

    /* NOTE(koekeishiya): This space transition was invoked after a window was moved to this space.
                          We have marked the window through AXWindow_Minimized. We iterate through
                          all visible windows to locate the window we need. */
    if(SpaceInfo->Initialized &&
       AXLibHasFlags(Display->Space, AXSpace_NeedsUpdate))
    {
        AXLibClearFlags(Display->Space, AXSpace_NeedsUpdate);
        AddMinimizedWindowsToTree(Display);
    }

    /* NOTE(koekeishiya): If we trigger a space changed event through cmd+tab, we receive the 'didApplicationActivate'
                          notification before the 'didActiveSpaceChange' notification. If a space has not been visited
                          before, this will cause us to end up on that space with an unsynchronized focused application state.

                          Always update state of focused application and its window after a space transition. */
    CreateWindowNodeTree(FocusedDisplay);
    FocusedApplication = AXLibGetFocusedApplication();
    if(FocusedApplication)
    {
        FocusedApplication->Focus = AXLibGetFocusedWindow(FocusedApplication);
        if((FocusedApplication->Focus) &&
           (AXLibIsWindowOnSpace(FocusedApplication->Focus, FocusedDisplay->Space->ID)))
            UpdateBorder("focused");
    }
}

/* TODO(koekeishiya): Is this interesting (?)
EVENT_CALLBACK(Callback_AXEvent_SpaceCreated)
{
    ax_space *Space = (ax_space *) Event->Context;
}<commit_msg>fixed update of tree upon resolution change<commit_after>#include "window.h"
#include "container.h"
#include "node.h"
#include "display.h"
#include "space.h"
#include "tree.h"
#include "border.h"
#include "helpers.h"
#include "rules.h"
#include "serializer.h"
#include "cursor.h"

#include "axlib/axlib.h"

#include <cmath>

#define internal static
#define local_persist static

/* TODO(koekeishiya): std::map cannot properly compare CFStringRefs. Consider writing
                      our own map type or switch back to CGSSpaceID. Using a CGSSpaceID
                      would require a remap between old and new CGSSpaceIDs in certain cases.
                      Is there a better alternative (?) */
extern std::map<CFStringRef, space_info> WindowTree;

extern ax_state AXState;
extern ax_display *FocusedDisplay;
extern ax_application *FocusedApplication;

extern kwm_screen KWMScreen;
extern kwm_focus KWMFocus;
extern kwm_toggles KWMToggles;
extern kwm_mode KWMMode;
extern kwm_tiling KWMTiling;
extern kwm_path KWMPath;
extern kwm_thread KWMThread;
extern kwm_border MarkedBorder;
extern kwm_border FocusedBorder;

internal void
UpdateSpaceOfDisplay(ax_display *Display, space_info *Space)
{
    if(Space->RootNode)
    {
        if(Space->Settings.Mode == SpaceModeBSP)
        {
            SetRootNodeContainer(Display, Space->RootNode);
            CreateNodeContainers(Display, Space->RootNode, true);
        }
        else if(Space->Settings.Mode == SpaceModeMonocle)
        {
            link_node *Link = Space->RootNode->List;
            while(Link)
            {
                SetLinkNodeContainer(Display, Link);
                Link = Link->Next;
            }
        }

        ApplyTreeNodeContainer(Space->RootNode);
        Space->NeedsUpdate = false;
    }
}

EVENT_CALLBACK(Callback_AXEvent_DisplayAdded)
{
    DEBUG("AXEvent_DisplayAdded");
}

EVENT_CALLBACK(Callback_AXEvent_DisplayRemoved)
{
    DEBUG("AXEvent_DisplayRemoved");
}

EVENT_CALLBACK(Callback_AXEvent_DisplayResized)
{
    ax_display *Display = (ax_display *) Event->Context;
    DEBUG("AXEvent_DisplayResized");

    std::map<CGSSpaceID, ax_space>::iterator It;
    for(It = Display->Spaces.begin(); It != Display->Spaces.end(); ++It)
    {
        ax_space *Space = &It->second;
        space_info *SpaceInfo = &WindowTree[Space->Identifier];
        if(Space == Display->Space)
            UpdateSpaceOfDisplay(Display, SpaceInfo);
        else
            SpaceInfo->NeedsUpdate = true;
    }
}

EVENT_CALLBACK(Callback_AXEvent_DisplayMoved)
{
    ax_display *Display = (ax_display *) Event->Context;
    DEBUG("AXEvent_DisplayMoved");

    std::map<CGSSpaceID, ax_space>::iterator It;
    for(It = Display->Spaces.begin(); It != Display->Spaces.end(); ++It)
    {
        ax_space *Space = &It->second;
        space_info *SpaceInfo = &WindowTree[Space->Identifier];
        if(Space == Display->Space)
            UpdateSpaceOfDisplay(Display, SpaceInfo);
        else
            SpaceInfo->NeedsUpdate = true;
    }
}

EVENT_CALLBACK(Callback_AXEvent_DisplayChanged)
{
    FocusedDisplay = AXLibMainDisplay();
    printf("%d: AXEvent_DisplayChanged\n", FocusedDisplay->ArrangementID);

    AXLibRunningApplications();
    CreateWindowNodeTree(FocusedDisplay);
    RebalanceNodeTree(FocusedDisplay);
}

internal void
AddMinimizedWindowsToTree(ax_display *Display)
{
    std::vector<ax_window *> Windows = AXLibGetAllVisibleWindows();
    for(std::size_t Index = 0; Index < Windows.size(); ++Index)
    {
        ax_window *Window = Windows[Index];
        if(AXLibHasFlags(Window, AXWindow_Minimized))
        {
            AXLibClearFlags(Window, AXWindow_Minimized);
            if((AXLibIsWindowStandard(Window) || AXLibIsWindowCustom(Window)) &&
               (!AXLibHasFlags(Window, AXWindow_Floating)))
            {
                AddWindowToNodeTree(Display, Window->ID);
            }
        }
    }
}

EVENT_CALLBACK(Callback_AXEvent_SpaceChanged)
{
    DEBUG("AXEvent_SpaceChanged");
    ClearBorder(&FocusedBorder);

    /* NOTE(koekeishiya): OSX APIs are horrible, so we need to detect which display
                          this event was triggered for. */
    ax_display *MainDisplay = AXLibMainDisplay();
    ax_display *Display = MainDisplay;
    do
    {
        ax_space *PrevSpace = Display->Space;
        Display->Space = AXLibGetActiveSpace(Display);
        Display->PrevSpace = PrevSpace;
        if(Display->Space != Display->PrevSpace)
            break;

        Display = AXLibNextDisplay(Display);
    } while(Display != MainDisplay);

    FocusedDisplay = Display;
    ax_space *PrevSpace = Display->PrevSpace;
    space_info *SpaceInfo = &WindowTree[Display->Space->Identifier];
    printf("Display: CGDirectDisplayID %d, Arrangement %d\n", Display->ID, Display->ArrangementID);
    printf("OldSpace %d : NewSpace %d\n", PrevSpace->ID, Display->Space->ID);

    AXLibRunningApplications();
    RebalanceNodeTree(Display);
    if(SpaceInfo->NeedsUpdate)
        UpdateSpaceOfDisplay(Display, SpaceInfo);

    /* NOTE(koekeishiya): This space transition was invoked through deminiaturizing a window.
                          We have no way of passing the actual window in question, to this callback,
                          so we have marked the window through AXWindow_Minimized. We iterate through
                          all visible windows to locate the window we need. */
    if(AXLibHasFlags(PrevSpace, AXSpace_DeminimizedTransition))
    {
        AXLibClearFlags(PrevSpace, AXSpace_DeminimizedTransition);
        AddMinimizedWindowsToTree(Display);
    }

    /* NOTE(koekeishiya): This space transition was invoked after a window was moved to this space.
                          We have marked the window through AXWindow_Minimized. We iterate through
                          all visible windows to locate the window we need. */
    if(SpaceInfo->Initialized &&
       AXLibHasFlags(Display->Space, AXSpace_NeedsUpdate))
    {
        AXLibClearFlags(Display->Space, AXSpace_NeedsUpdate);
        AddMinimizedWindowsToTree(Display);
    }

    /* NOTE(koekeishiya): If we trigger a space changed event through cmd+tab, we receive the 'didApplicationActivate'
                          notification before the 'didActiveSpaceChange' notification. If a space has not been visited
                          before, this will cause us to end up on that space with an unsynchronized focused application state.

                          Always update state of focused application and its window after a space transition. */
    CreateWindowNodeTree(Display);
    FocusedApplication = AXLibGetFocusedApplication();
    if(FocusedApplication)
    {
        FocusedApplication->Focus = AXLibGetFocusedWindow(FocusedApplication);
        if((FocusedApplication->Focus) &&
           (AXLibIsWindowOnSpace(FocusedApplication->Focus, Display->Space->ID)))
            UpdateBorder("focused");
    }
}

/* TODO(koekeishiya): Is this interesting (?)
EVENT_CALLBACK(Callback_AXEvent_SpaceCreated)
{
    ax_space *Space = (ax_space *) Event->Context;
}
{'fraction_non_alphanumeric': 0.09882710686359687, 'fraction_numerical': 0.0001448016217781639, 'mean_word_length': 3.103683897801545, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 110, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6386159', 'n_tokens_mistral': 4059, 'n_tokens_neox': 3929, 'n_words': 887}