Resolved Get Prior Active Application?

Discussion in 'Mac Programming' started by ArtOfWarfare, Oct 16, 2013.

  1. ArtOfWarfare, Oct 16, 2013
    Last edited: Oct 17, 2013

    ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #1
    I implemented this in my Application Delegate expecting that it would tell me which Application had been active before my own became active:

    Code:
    - (void)applicationWillBecomeActive:(NSNotification *)notification {
        NSLog(@"Am I active? %hhd", [NSRunningApplication currentApplication].active);
        for (NSRunningApplication * application in [[NSWorkspace sharedWorkspace] runningApplications]) {
            if (application.active) {
                NSLog(@"%@ is active <----------------", application.localizedName);
            } else {
                NSLog(@"%@ is not active", application.localizedName);
            }
        }
        NSLog(@"Becoming active!");
    }
    
    - (void)applicationDidBecomeActive:(NSNotification *)notification {
        NSLog(@"Did become active!");
    }
    Unfortunately, despite what the title of the method would suggest, it seems that this code is called after the application has already become active. When I run the code, I consistently see printed to the console:

    "Am I active? 1", meaning it's active immediately when this method is entered.
    long list of running but not active applications, mine not in that part of the list
    my application, marked as the active one, immediately follow by
    "Becoming active!", immediately followed by
    "Did become active!"

    So... any suggestions about how I can get the previously activated application? I'd rather not poll in the background continuously.

    The reason I want this is because I have a button in my application which toggles whether it floats above all other applications or has ordinary windows. When this button is clicked toggling it off, I don't want the application to become active by the button being clicked. I can't find any way to block it from becoming active, so I'd rather just check, when the button is clicked, which application was active immediately prior and how long ago was it deactivated - if it was deactivated only 0.02 seconds ago or so, it means that it only was deactivated by the button being pressed and so it should be made the active application now.

    Edit: Just checked - I can poll for the current application in the background, but this doesn't seem like a particularly good solution to my problem. I intend for my application to be running 24/7, but for it to only want this kind of information once or twice an hour (if that often)... it's an awfully high cost for an awfully low priority feature.
     
  2. Red Menace macrumors 6502

    Joined:
    May 29, 2011
    Location:
    Littleton, Colorado, USA
    #2
    Maybe register for a NSWorkspaceDidActivateApplicationNotification notification and keep track of the latest one that isn't your application?
     
  3. ArtOfWarfare, Oct 16, 2013
    Last edited: Oct 17, 2013

    ArtOfWarfare thread starter macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #3
    Hmmm... yes, that looks like it should work. I'll try implementing it in the morning and post back with an update.

    Edit: Yep, this seems to be working exactly as I intended (my entire .m file below):

    Code:
    @interface BNApplicationDelegate () {
        NSTimer *_changeActiveApplicationDelayTimer;
        NSRunningApplication *_activeApplication;
    }
    
    @end
    
    @implementation BNApplicationDelegate
    
    - (void)awakeFromNib {
        [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                                                               selector:@selector(activeApplicationChanged:)
                                                                   name:NSWorkspaceDidActivateApplicationNotification
                                                                 object:NULL];
    }
    
    - (void)activeApplicationChanged:(NSNotification *)notification {
        [_changeActiveApplicationDelayTimer invalidate];
        NSRunningApplication *app = [notification.userInfo objectForKey:NSWorkspaceApplicationKey];
        if (![app isEqual:NSRunningApplication.currentApplication]) {
            _activeApplication = app;
        } else {
            _changeActiveApplicationDelayTimer = [NSTimer scheduledTimerWithTimeInterval:0.2
                                                                                  target:self
                                                                                selector:@selector(becomeActiveApplication:)
                                                                                userInfo:NULL
                                                                                 repeats:NO];
        }
    }
    
    - (void)becomeActiveApplication:(NSDictionary *)userInfo {
        _activeApplication = NSRunningApplication.currentApplication;
    }
    
    - (void)activateActiveApplication {
        [_activeApplication activateWithOptions:NSApplicationActivateIgnoringOtherApps];
    }
    The activateActiveApplication method is exposed in the header; the rest is private.
     

Share This Page