How to detect if the active window has changed on Mac OS X











up vote
0
down vote

favorite












I'm trying to create a program that tracks the focused window of an application. I've come across a few partial answers, but I don't think it's working.



This is an Objective C++ part of a Qt application, so it might have to do with the RunLoop, but I'm not certain.



void focusObserverCallback( AXObserverRef observer, AXUIElementRef element,
CFStringRef notificationName, void * contextData )
{
// Never executes.
qInfo("Focus changed.");
}

QString updateActiveWindow (void)
{
NSRunningApplication* app = [[NSWorkspace sharedWorkspace]
frontmostApplication];
pid_t pid = [app processIdentifier];
AXUIElementRef appElem = AXUIElementCreateApplication(pid);
if (!appElem) {
qInfo() << "!appElem";
return nullptr;
}

// Get the accessibility element corresponding to the frontmost window
// of the frontmost application.
CFStringRef appName=nullptr;
AXUIElementRef window = nullptr;
if (AXUIElementCopyAttributeValue (appElem, kAXTitleAttribute, ((CFTypeRef*)&appName)) !=kAXErrorSuccess){
if(appElem)
CFRelease(appElem);
}
focusedAppName=toQString(appName);
if (AXUIElementCopyAttributeValue (appElem, kAXFocusedWindowAttribute, (CFTypeRef*)&window) != kAXErrorSuccess) {
if(appElem)
CFRelease(appElem);
}

AXObserverRef observer = nullptr;
if(AXObserverCreate(pid, focusObserverCallback, &observer) !=kAXErrorSuccess){
qInfo("Failed to register observer");
}

AXObserverAddNotification(observer, window, kAXApplicationActivatedNotification, nullptr);

CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop],
AXObserverGetRunLoopSource(observer),
kCFRunLoopDefaultMode );

// Finally, get the title of the frontmost window.
CFStringRef title = nullptr;
if(AXUIElementCopyAttributeValue(window, kAXTitleAttribute, (CFTypeRef*)&title)!=kAXErrorSuccess){
qInfo("Problem Copying title");
}
focusedAppTitle= toQString(title);
return toQString(title);
}


What this code does, is it runs once to grab the name and the title of the frontmost application's frontmost window. That part works like a charm.



Problem is, it doesn't register the callback, and it doesn't fire when the window loses focus. I'm completely new to Objective C, so there might be other issues (e.g. Garbage Collection). If you can suggest some changes to those, I'd be doubly obliged.










share|improve this question


























    up vote
    0
    down vote

    favorite












    I'm trying to create a program that tracks the focused window of an application. I've come across a few partial answers, but I don't think it's working.



    This is an Objective C++ part of a Qt application, so it might have to do with the RunLoop, but I'm not certain.



    void focusObserverCallback( AXObserverRef observer, AXUIElementRef element,
    CFStringRef notificationName, void * contextData )
    {
    // Never executes.
    qInfo("Focus changed.");
    }

    QString updateActiveWindow (void)
    {
    NSRunningApplication* app = [[NSWorkspace sharedWorkspace]
    frontmostApplication];
    pid_t pid = [app processIdentifier];
    AXUIElementRef appElem = AXUIElementCreateApplication(pid);
    if (!appElem) {
    qInfo() << "!appElem";
    return nullptr;
    }

    // Get the accessibility element corresponding to the frontmost window
    // of the frontmost application.
    CFStringRef appName=nullptr;
    AXUIElementRef window = nullptr;
    if (AXUIElementCopyAttributeValue (appElem, kAXTitleAttribute, ((CFTypeRef*)&appName)) !=kAXErrorSuccess){
    if(appElem)
    CFRelease(appElem);
    }
    focusedAppName=toQString(appName);
    if (AXUIElementCopyAttributeValue (appElem, kAXFocusedWindowAttribute, (CFTypeRef*)&window) != kAXErrorSuccess) {
    if(appElem)
    CFRelease(appElem);
    }

    AXObserverRef observer = nullptr;
    if(AXObserverCreate(pid, focusObserverCallback, &observer) !=kAXErrorSuccess){
    qInfo("Failed to register observer");
    }

    AXObserverAddNotification(observer, window, kAXApplicationActivatedNotification, nullptr);

    CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop],
    AXObserverGetRunLoopSource(observer),
    kCFRunLoopDefaultMode );

    // Finally, get the title of the frontmost window.
    CFStringRef title = nullptr;
    if(AXUIElementCopyAttributeValue(window, kAXTitleAttribute, (CFTypeRef*)&title)!=kAXErrorSuccess){
    qInfo("Problem Copying title");
    }
    focusedAppTitle= toQString(title);
    return toQString(title);
    }


    What this code does, is it runs once to grab the name and the title of the frontmost application's frontmost window. That part works like a charm.



    Problem is, it doesn't register the callback, and it doesn't fire when the window loses focus. I'm completely new to Objective C, so there might be other issues (e.g. Garbage Collection). If you can suggest some changes to those, I'd be doubly obliged.










    share|improve this question
























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I'm trying to create a program that tracks the focused window of an application. I've come across a few partial answers, but I don't think it's working.



      This is an Objective C++ part of a Qt application, so it might have to do with the RunLoop, but I'm not certain.



      void focusObserverCallback( AXObserverRef observer, AXUIElementRef element,
      CFStringRef notificationName, void * contextData )
      {
      // Never executes.
      qInfo("Focus changed.");
      }

      QString updateActiveWindow (void)
      {
      NSRunningApplication* app = [[NSWorkspace sharedWorkspace]
      frontmostApplication];
      pid_t pid = [app processIdentifier];
      AXUIElementRef appElem = AXUIElementCreateApplication(pid);
      if (!appElem) {
      qInfo() << "!appElem";
      return nullptr;
      }

      // Get the accessibility element corresponding to the frontmost window
      // of the frontmost application.
      CFStringRef appName=nullptr;
      AXUIElementRef window = nullptr;
      if (AXUIElementCopyAttributeValue (appElem, kAXTitleAttribute, ((CFTypeRef*)&appName)) !=kAXErrorSuccess){
      if(appElem)
      CFRelease(appElem);
      }
      focusedAppName=toQString(appName);
      if (AXUIElementCopyAttributeValue (appElem, kAXFocusedWindowAttribute, (CFTypeRef*)&window) != kAXErrorSuccess) {
      if(appElem)
      CFRelease(appElem);
      }

      AXObserverRef observer = nullptr;
      if(AXObserverCreate(pid, focusObserverCallback, &observer) !=kAXErrorSuccess){
      qInfo("Failed to register observer");
      }

      AXObserverAddNotification(observer, window, kAXApplicationActivatedNotification, nullptr);

      CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop],
      AXObserverGetRunLoopSource(observer),
      kCFRunLoopDefaultMode );

      // Finally, get the title of the frontmost window.
      CFStringRef title = nullptr;
      if(AXUIElementCopyAttributeValue(window, kAXTitleAttribute, (CFTypeRef*)&title)!=kAXErrorSuccess){
      qInfo("Problem Copying title");
      }
      focusedAppTitle= toQString(title);
      return toQString(title);
      }


      What this code does, is it runs once to grab the name and the title of the frontmost application's frontmost window. That part works like a charm.



      Problem is, it doesn't register the callback, and it doesn't fire when the window loses focus. I'm completely new to Objective C, so there might be other issues (e.g. Garbage Collection). If you can suggest some changes to those, I'd be doubly obliged.










      share|improve this question













      I'm trying to create a program that tracks the focused window of an application. I've come across a few partial answers, but I don't think it's working.



      This is an Objective C++ part of a Qt application, so it might have to do with the RunLoop, but I'm not certain.



      void focusObserverCallback( AXObserverRef observer, AXUIElementRef element,
      CFStringRef notificationName, void * contextData )
      {
      // Never executes.
      qInfo("Focus changed.");
      }

      QString updateActiveWindow (void)
      {
      NSRunningApplication* app = [[NSWorkspace sharedWorkspace]
      frontmostApplication];
      pid_t pid = [app processIdentifier];
      AXUIElementRef appElem = AXUIElementCreateApplication(pid);
      if (!appElem) {
      qInfo() << "!appElem";
      return nullptr;
      }

      // Get the accessibility element corresponding to the frontmost window
      // of the frontmost application.
      CFStringRef appName=nullptr;
      AXUIElementRef window = nullptr;
      if (AXUIElementCopyAttributeValue (appElem, kAXTitleAttribute, ((CFTypeRef*)&appName)) !=kAXErrorSuccess){
      if(appElem)
      CFRelease(appElem);
      }
      focusedAppName=toQString(appName);
      if (AXUIElementCopyAttributeValue (appElem, kAXFocusedWindowAttribute, (CFTypeRef*)&window) != kAXErrorSuccess) {
      if(appElem)
      CFRelease(appElem);
      }

      AXObserverRef observer = nullptr;
      if(AXObserverCreate(pid, focusObserverCallback, &observer) !=kAXErrorSuccess){
      qInfo("Failed to register observer");
      }

      AXObserverAddNotification(observer, window, kAXApplicationActivatedNotification, nullptr);

      CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop],
      AXObserverGetRunLoopSource(observer),
      kCFRunLoopDefaultMode );

      // Finally, get the title of the frontmost window.
      CFStringRef title = nullptr;
      if(AXUIElementCopyAttributeValue(window, kAXTitleAttribute, (CFTypeRef*)&title)!=kAXErrorSuccess){
      qInfo("Problem Copying title");
      }
      focusedAppTitle= toQString(title);
      return toQString(title);
      }


      What this code does, is it runs once to grab the name and the title of the frontmost application's frontmost window. That part works like a charm.



      Problem is, it doesn't register the callback, and it doesn't fire when the window loses focus. I'm completely new to Objective C, so there might be other issues (e.g. Garbage Collection). If you can suggest some changes to those, I'd be doubly obliged.







      objective-c macos qt accessibility






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 7 at 9:24









      Alex Petrosyan

      10411




      10411
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          An application sends kAXApplicationActivatedNotification when the application is activated and becomes the front most application. Observe the application's kAXFocusedWindowChangedNotification to observe focused window changes of the application.






          share|improve this answer





















            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














             

            draft saved


            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53186576%2fhow-to-detect-if-the-active-window-has-changed-on-mac-os-x%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            2
            down vote



            accepted










            An application sends kAXApplicationActivatedNotification when the application is activated and becomes the front most application. Observe the application's kAXFocusedWindowChangedNotification to observe focused window changes of the application.






            share|improve this answer

























              up vote
              2
              down vote



              accepted










              An application sends kAXApplicationActivatedNotification when the application is activated and becomes the front most application. Observe the application's kAXFocusedWindowChangedNotification to observe focused window changes of the application.






              share|improve this answer























                up vote
                2
                down vote



                accepted







                up vote
                2
                down vote



                accepted






                An application sends kAXApplicationActivatedNotification when the application is activated and becomes the front most application. Observe the application's kAXFocusedWindowChangedNotification to observe focused window changes of the application.






                share|improve this answer












                An application sends kAXApplicationActivatedNotification when the application is activated and becomes the front most application. Observe the application's kAXFocusedWindowChangedNotification to observe focused window changes of the application.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 7 at 11:21









                Willeke

                7,40621023




                7,40621023






























                     

                    draft saved


                    draft discarded



















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53186576%2fhow-to-detect-if-the-active-window-has-changed-on-mac-os-x%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    這個網誌中的熱門文章

                    Xamarin.form Move up view when keyboard appear

                    Post-Redirect-Get with Spring WebFlux and Thymeleaf

                    Anylogic : not able to use stopDelay()