Пример #1
0
void FocusedAXObserverCallback(AXObserverRef Observer, AXUIElementRef Element, CFStringRef Notification, void *ContextData)
{
    pthread_mutex_lock(&KWMThread.Lock);

    window_info *Window = KWMFocus.Window;
    if(Window && CFEqual(Notification, kAXTitleChangedNotification))
        Window->Name = AXLibGetWindowTitle(Element);
    else if(CFEqual(Notification, kAXFocusedWindowChangedNotification))
    {
        if(!Window || Window->WID != AXLibGetWindowID(Element))
        {
            window_info *OSXWindow = GetWindowByID(AXLibGetWindowID(Element));
            screen_info *OSXScreen = GetDisplayOfWindow(OSXWindow);
            if(OSXWindow && OSXScreen)
            {
                screen_info *ScreenOfWindow = GetDisplayOfWindow(Window);
                bool SameScreen = ScreenOfWindow == OSXScreen;
                if(ScreenOfWindow && !SameScreen)
                    UpdateActiveWindowList(ScreenOfWindow);

                if(ScreenOfWindow && Window &&
                   GetWindowByID(Window->WID) == NULL &&
                   !SameScreen)
                {
                    space_info *SpaceOfWindow = GetActiveSpaceOfScreen(ScreenOfWindow);
                    if(SpaceOfWindow->Settings.Mode == SpaceModeBSP)
                        RemoveWindowFromBSPTree(ScreenOfWindow, Window->WID, false, false);
                    else if(SpaceOfWindow->Settings.Mode == SpaceModeMonocle)
                        RemoveWindowFromMonocleTree(ScreenOfWindow, Window->WID, false, false);

                    SpaceOfWindow->FocusedWindowID = -1;
                }

                if(!SameScreen)
                    GiveFocusToScreen(OSXScreen->ID, NULL, false, false);

                SetKwmFocus(Element);
                if(SameScreen && !IsFocusedWindowFloating())
                    KWMFocus.InsertionPoint = KWMFocus.Cache;
            }
        }
    }
    else if(Window &&
           (CFEqual(Notification, kAXWindowResizedNotification) ||
            CFEqual(Notification, kAXWindowMovedNotification)))
    {
        if(KWMTiling.LockToContainer)
            LockWindowToContainerSize(Window);

        UpdateBorder("focused");
    }
    else if(CFEqual(Notification, kAXUIElementDestroyedNotification) ||
            CFEqual(Notification, kAXWindowMiniaturizedNotification))
    {
        UpdateBorder("focused");
    }

    pthread_mutex_unlock(&KWMThread.Lock);
}
Пример #2
0
ax_window *AXLibConstructWindow(ax_application *Application, AXUIElementRef WindowRef)
{
    ax_window *Window = (ax_window *) malloc(sizeof(ax_window));
    memset(Window, '\0', sizeof(ax_window));

    Window->Ref = (AXUIElementRef) CFRetain(WindowRef);
    Window->Application = Application;
    Window->ID = AXLibGetWindowID(Window->Ref);
    Window->Name = AXLibGetWindowTitle(Window->Ref);
    Window->Position = AXLibGetWindowPosition(Window->Ref);
    Window->Size = AXLibGetWindowSize(Window->Ref);

    if(AXLibIsWindowMovable(Window->Ref))
        AXLibAddFlags(Window, AXWindow_Movable);

    if(AXLibIsWindowResizable(Window->Ref))
        AXLibAddFlags(Window, AXWindow_Resizable);

    if(AXLibIsWindowMinimized(Window->Ref))
        AXLibAddFlags(Window, AXWindow_Minimized);

    AXLibGetWindowRole(Window->Ref, &Window->Type.Role);
    AXLibGetWindowSubrole(Window->Ref, &Window->Type.Subrole);

    return Window;
}
Пример #3
0
ax_window *AXLibGetFocusedWindow(ax_application *Application)
{
    AXUIElementRef Ref = (AXUIElementRef) AXLibGetWindowProperty(Application->Ref, kAXFocusedWindowAttribute);
    if(Ref)
    {
        uint32_t WID = AXLibGetWindowID(Ref);
        CFRelease(Ref);

        ax_window *Window = AXLibFindApplicationWindow(Application, WID);
        return Window;
    }

    return NULL;
}
Пример #4
0
internal OBSERVER_CALLBACK(AXApplicationCallback)
{
    ax_application *Application = (ax_application *) Reference;

    if(CFEqual(Notification, kAXWindowCreatedNotification))
    {
        ax_window *Window = AXLibConstructWindow(Application, Element);
        if(AXLibAddObserverNotification(&Application->Observer, Window->Ref, kAXUIElementDestroyedNotification, Window) == kAXErrorSuccess)
        {
            AXLibAddApplicationWindow(Application, Window);

            /* NOTE(koekeishiya): Triggers an AXEvent_WindowCreated and passes a pointer to the new ax_window */
            uint32_t *WindowID = (uint32_t *) malloc(sizeof(uint32_t));
            *WindowID = Window->ID;
            AXLibConstructEvent(AXEvent_WindowCreated, WindowID, false);

            /* NOTE(koekeishiya): When a new window is created, we incorrectly receive the kAXFocusedWindowChangedNotification
                                  first, for some reason. We discard that notification and restore it when we have the window to work with. */
            AXApplicationCallback(Observer, Window->Ref, kAXFocusedWindowChangedNotification, Application);
        }
        else
        {
            /* NOTE(koekeishiya): This element is not destructible and cannot be an application window (?) */
            AXLibDestroyInvalidWindow(Window);
        }
    }
    else if(CFEqual(Notification, kAXUIElementDestroyedNotification))
    {
        /* NOTE(koekeishiya): If the destroyed UIElement is a window, remove it from the list. */
        ax_window *Window = (ax_window *) Reference;
        if(Window)
        {
            Window->Application->Focus = AXLibGetFocusedWindow(Window->Application);

            /* NOTE(koekeishiya): The callback is responsible for calling AXLibDestroyWindow(Window);
                                  and AXLibRemoveApplicationWindow(Window->Application, Window->ID); */
            uint32_t *WindowID = (uint32_t *) malloc(sizeof(uint32_t));
            *WindowID = Window->ID;
            AXLibConstructEvent(AXEvent_WindowDestroyed, WindowID, false);
        }
    }
    else if(CFEqual(Notification, kAXFocusedWindowChangedNotification))
    {
        /* NOTE(koekeishiya): This notification could be received before the window itself is created.
                              Make sure that the window actually exists before we notify our callback. */
        ax_window *Window = AXLibGetWindowByRef(Application, Element);
        if(Window)
        {
            /* NOTE(koekeishiya): If the currently focused window and the window requesting
             * focus are both on the same display, reset our IgnoreFocus flag. */
            if((AXLibHasFlags(Application, AXApplication_IgnoreFocus)) &&
               (Application->Focus) &&
               (AXLibWindowDisplay(Window) == AXLibWindowDisplay(Application->Focus)))
            {
                AXLibClearFlags(Application, AXApplication_IgnoreFocus);
            }

            if(AXLibHasFlags(Application, AXApplication_IgnoreFocus))
            {
                /* NOTE(koekeishiya): When Kwm tries to focus the window of an application that
                 * has windows open on multiple displays, OSX prioritizes the window on the
                 * active display. If this application has been flagged, we ignore the OSX notification. */
                AXLibClearFlags(Application, AXApplication_IgnoreFocus);

                /* NOTE(koekeishiya): Even if this request is ignored, OSX does make that window
                 * the focused window for the application in question. We restore focus back to
                 * the window that had focus before OSX decided to **** things up. */
                AXLibAddFlags(Application, AXApplication_RestoreFocus);
                AXLibSetWindowProperty(Application->Focus->Ref, kAXMainAttribute, kCFBooleanTrue);
            }
            else if(AXLibHasFlags(Application, AXApplication_RestoreFocus))
            {
                /* NOTE(koekeishiya): The window that we restore focus to is already marked as the focused
                 * window for this application as far as Kwm is concerned and we do not have to update our
                 * state, which is why we do not emit a new AXEvent_WindowFocused event. */
                AXLibClearFlags(Application, AXApplication_RestoreFocus);
            }
            else
            {
                /* NOTE(koekeishiya): When a window is deminimized, we receive a FocusedWindowChanged notification before the
                   window is visible. Only notify our callback when we know that we can interact with the window in question. */
                if(!AXLibHasFlags(Window, AXWindow_Minimized))
                {
                    uint32_t *WindowID = (uint32_t *) malloc(sizeof(uint32_t));
                    *WindowID = Window->ID;
                    AXLibConstructEvent(AXEvent_WindowFocused, WindowID, false);
                }

                /* NOTE(koekeishiya): If the application corresponding to this window is flagged for activation and
                                      the window is visible to the user, this should be the focused application. */
                if(AXLibHasFlags(Window->Application, AXApplication_Activate))
                {
                    AXLibClearFlags(Window->Application, AXApplication_Activate);
                    if(!AXLibHasFlags(Window, AXWindow_Minimized))
                    {
                        pid_t *ApplicationPID = (pid_t *) malloc(sizeof(pid_t));
                        *ApplicationPID = Window->Application->PID;
                        AXLibConstructEvent(AXEvent_ApplicationActivated, ApplicationPID, false);
                    }
                }
            }
        }
    }
    else if(CFEqual(Notification, kAXWindowMiniaturizedNotification))
    {
        /* NOTE(koekeishiya): Triggers an AXEvent_WindowMinimized and passes a pointer to the ax_window */
        ax_window *Window = (ax_window *) Reference;
        if(Window)
        {
            AXLibAddFlags(Window, AXWindow_Minimized);
            uint32_t *WindowID = (uint32_t *) malloc(sizeof(uint32_t));
            *WindowID = Window->ID;
            AXLibConstructEvent(AXEvent_WindowMinimized, WindowID, false);
        }
    }
    else if(CFEqual(Notification, kAXWindowDeminiaturizedNotification))
    {
        /* NOTE(koekeishiya): Triggers an AXEvent_WindowDeminimized and passes a pointer to the ax_window */
        ax_window *Window = (ax_window *) Reference;
        if(Window)
        {
            /* NOTE(koekeishiya): If a window was minimized before AXLib is initialized, the WindowID is
                                  reported as 0. We check if this window is one of these, update the
                                  WindowID and place it in our managed window list. */
            if(Window->ID == 0)
            {
                for(int Index = 0; Index < Window->Application->NullWindows.size(); ++Index)
                {
                    if(Window->Application->NullWindows[Index] == Window)
                    {
                        Window->Application->NullWindows.erase(Window->Application->NullWindows.begin() + Index);
                        break;
                    }
                }

                Window->ID = AXLibGetWindowID(Window->Ref);
                Window->Application->Windows[Window->ID] = Window;
            }

            /* NOTE(koekeishiya): kAXWindowDeminiaturized is sent before didActiveSpaceChange, when a deminimized
                                  window pulls you to the space of that window. If the active space of the display
                                  is not equal to the space of the window, we should ignore this event and let the
                                  next space changed event handle it. */

            AXLibClearFlags(Window, AXWindow_Minimized);
            ax_display *Display = AXLibWindowDisplay(Window);
            if(AXLibSpaceHasWindow(Window, Display->Space->ID))
            {
                uint32_t *WindowID = (uint32_t *) malloc(sizeof(uint32_t));
                *WindowID = Window->ID;
                AXLibConstructEvent(AXEvent_WindowDeminimized, WindowID, false);

                pid_t *ApplicationPID = (pid_t *) malloc(sizeof(pid_t));
                *ApplicationPID = Window->Application->PID;
                AXLibConstructEvent(AXEvent_ApplicationActivated, ApplicationPID, false);

                WindowID = (uint32_t *) malloc(sizeof(uint32_t));
                *WindowID = Window->ID;
                AXLibConstructEvent(AXEvent_WindowFocused, WindowID, false);
            }
        }
    }
    else if(CFEqual(Notification, kAXWindowMovedNotification))
    {
        /* NOTE(koekeishiya): Triggers an AXEvent_WindowMoved and passes a pointer to the ax_window */
        ax_window *Window = AXLibGetWindowByRef(Application, Element);
        if(Window)
        {
            Window->Position = AXLibGetWindowPosition(Window->Ref);

            bool Intrinsic = AXLibHasFlags(Window, AXWindow_MoveIntrinsic);
            uint32_t *WindowID = (uint32_t *) malloc(sizeof(uint32_t));
            *WindowID = Window->ID;

            AXLibClearFlags(Window, AXWindow_MoveIntrinsic);
            AXLibConstructEvent(AXEvent_WindowMoved, WindowID, Intrinsic);
        }
    }
    else if(CFEqual(Notification, kAXWindowResizedNotification))
    {
        /* NOTE(koekeishiya): Triggers an AXEvent_WindowResized and passes a pointer to the ax_window */
        ax_window *Window = AXLibGetWindowByRef(Application, Element);
        if(Window)
        {
            Window->Position = AXLibGetWindowPosition(Window->Ref);
            Window->Size = AXLibGetWindowSize(Window->Ref);

            bool Intrinsic = AXLibHasFlags(Window, AXWindow_SizeIntrinsic);
            uint32_t *WindowID = (uint32_t *) malloc(sizeof(uint32_t));
            *WindowID = Window->ID;

            AXLibClearFlags(Window, AXWindow_SizeIntrinsic);
            AXLibConstructEvent(AXEvent_WindowResized, WindowID, Intrinsic);
        }
    }
    else if(CFEqual(Notification, kAXTitleChangedNotification))
    {
        uint32_t *WindowID = (uint32_t *) malloc(sizeof(uint32_t));
        *WindowID = AXLibGetWindowID(Element);
        AXLibConstructEvent(AXEvent_WindowTitleChanged, WindowID, false);
    }
}
Пример #5
0
internal inline ax_window *
AXLibGetWindowByRef(ax_application *Application, AXUIElementRef WindowRef)
{
    uint32_t WID = AXLibGetWindowID(WindowRef);
    return AXLibFindApplicationWindow(Application, WID);
}