Search code examples
objective-ccocoaaccessibilityaccessibility-api

ObjectiveC Accessibility API: UnMaximize Window


I’m not sure if I am referring to this correctly, but when I use the word “UnMaximize”, I’m referring to:

When you click on the green button which is third on the top left of a Chrome Window, it Maximizes the Window. When I use the word “UnMaximize” above, I’m referring to the behavior that clicks that button again so that it is no longer in full screen.

(By the way, what is the correct word for this in MacOS Terminology?)

I enjoy using the Easy Move+Resize App. While it can move Windows around, unfortunately, it has no effect on windows that are Maximized. Fortunately, the code is available on Github.

I’m curious if anyone can point me how to UnMaximize a Window using the Accessibility API

Does anyone what is the UnMaximize equivalent to kAXCloseButtonAttribute

I’m using MacOs 10.12 if that helps.


Solution

  • I’m grateful to @Willeke - Willeke for pointing me in the correct direction.

    As mentioned in my question, I was looking at the code of the Easy Move+Resize App on GitHub. The problem with this code/app is that it does not work for Windows that are currently Maximized i.e. it tries to move these Windows, but it cannot, because they are fixed. (Note: This only has use and is relevant in a multi-monitor setup.) This app works correctly for Windows that are not Maximized.

    Here, I am trying to add code that would UnMaximize a window in order to move it, and then Maximize it again after it has been moved. Obviously, the code below is in the context of this app, but I’m sure would be useful to users in other contexts.

    I first added a wasMaximized property to EMRMoveResize.h

    //EMRMoveResize.h
    @property bool wasMaximized;
    

    Next, I moved to EMRAppDelegate.m where the actual Event Callback code is. It should be noted that we are only concerned with moving i.e. only concerned with the Left Mouse Button. (This app uses the Right Mouse Button for resizing, which is not relavent when the Window has been maximized.) So, we are only concerned with kCGEventLeftMouseDown, kCGEventLeftMouseDragged and finally with kCGEventLeftMouseUp. In pseudo code, I have done something like:

    If (LeftMouseDown) {
        Find out if Window is Maximized
        If (Window is Maximized) {
            set the wasMaximized property
            Click FullScreen Button to UnMaximize the Window in Order to Move it
    }
    

    The Window is now UnMaximized would now move as other windows in the LeftMouseDragged event, which I have not made any changes to. Finally,

    If(LeftMouseUp) {
        If(wasMaximized value was set) {
            Click FullScreen Button again to Maximize the Window (Since it started out as Maximized)
            Reset the wasMaximized property
        }
    }
    

    Now for the snippets of code changes to EMRAppDelegate.m

    if (type == kCGEventLeftMouseDown
                || type == kCGEventRightMouseDown) {
    
    //..
    //Skipped Unchanged Code
    //..
    //Find out if Window is Maximized
    CFTypeRef TypeRef = nil;
                if (AXUIElementCopyAttributeValue((AXUIElementRef)_clickedWindow, CFSTR("AXFullScreen"), &TypeRef)) {
                    if(Debug) NSLog(@"Could not get wasMaximized Value");
                } else {
                    [moveResize setWasMaximized: CFBooleanGetValue(TypeRef)];
                    if(Debug) NSLog(CFBooleanGetValue(TypeRef) ? @"Updated Maximized to True" : @"Updated Maximized to False");
                }
            //Click FullScreen Button to UnMaximize the Window in Order to Move it
                if([moveResize wasMaximized]) {
                    AXUIElementRef buttonRef = nil;
                    AXUIElementCopyAttributeValue(_clickedWindow, kAXFullScreenButtonAttribute, (CFTypeRef*)&buttonRef);
                    if(Debug) NSLog(@"buttonRef: %p", buttonRef);
                    AXUIElementPerformAction(buttonRef, kAXPressAction);
                    CFRelease(buttonRef);
                }
    //..
    //Skipped Unchanged Code
    //..
    }
    
    if (type == kCGEventLeftMouseUp
                || type == kCGEventRightMouseUp) {
    //..
    //Skipped Unchanged Code
    //..
    //Click FullScreen Button again to Maximize the Window (Since it started out as Maximized)
    AXUIElementRef _clickedWindow = [moveResize window];
            if([moveResize wasMaximized]) {
                AXUIElementRef buttonRef = nil;
                AXUIElementCopyAttributeValue(_clickedWindow, kAXFullScreenButtonAttribute, (CFTypeRef*)&buttonRef);
                if(Debug) NSLog(@"buttonRef: %p", buttonRef);
                AXUIElementPerformAction(buttonRef, kAXPressAction);
                CFRelease(buttonRef);
                [moveResize setWasMaximized: false];
            }
    //..
    //Skipped Unchanged Code
    //..
    }
    

    This worked for me. But I'm not an expert in Objective C or MacOS, so if you feel something can be improved, feel free to edit this post.