Bring any window to the front

A question was asked on the apple dev mailing list on how to bring a window with a certain name to the front.

Since I was already working on how to get the list of windows on the screen, I just added some AppleScript to bring the window to the front.

This snippet doesnt use any undocumented techniques, it uses the CGWindow API introduced in Leopard.

I dont consider this code to be production ready, but it works.

Of course, TIMTOWTDI 😉

See the code after the jump:


- (BOOL) bringWindowWithNameToFront:(NSString *) windowName
{
// Try to find a window named "windowName", and if found,
// bring it to the front
// Stephan Burlot 4/3/08

  CFArrayRef            windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
  ProcessSerialNumber   myPSN = {kNoProcess, kNoProcess};
  BOOL                  returnValue = FALSE;

  for (NSMutableDictionary *entry in (NSArray *)windowList) {
    NSString *currentWindow = [entry objectForKey:(id)kCGWindowName];
    if ((currentWindow != NULL) && ([currentWindow isEqualToString:windowName]))
    {
      NSString *applicationName = [entry objectForKey:(id)kCGWindowOwnerName];
      int pid = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue];
      GetProcessForPID(pid, &myPSN);

      NSString *script= [NSString stringWithFormat:@"tell application \"System Events\" to tell process \"%@\" to perform action \"AXRaise\" of window \"%@\"\ntell application \"%@\" to activate\n", applicationName, windowName, applicationName];
      NSAppleScript *as = [[NSAppleScript alloc] initWithSource:script];
      [as compileAndReturnError:NULL];
      [as executeAndReturnError:NULL];  // Bring it on!
      [as release];
      returnValue = TRUE;
    }
  }

  CFRelease(windowList);
  return returnValue;
}

Inspiration camed from the following codes:

4 rĂ©flexions au sujet de “Bring any window to the front”

  1. Thanks for the example, this is almost exactly what I’m looking for.

    Do you know of a way to tell the application to bring *just* the specified window to the foreground when it activates?

    I have a whole bunch of iTerm windows, and I’d like to be able to tell a specific one to raise and focus, without bringing *all* of them to the front.

    The other dilemma that I have is that the window name for many of my iTerm sessions is « Default ». Is there any way to use a window number instead of the window name?

    The right solution is probably for me to change how I use iTerm. But old habits die hard.

  2. Answered my own question. Get rid of the ‘tell application « foo » to raise » and instead do:

    SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly);

    after the AXRaise AppleScript stuff.

  3. Over the years (with privacy, accessibility and all sorts of restrictions) the code above stopped working. I did a bit of searching, found some things, but did not get to a full solution in Objective-C – thought I’d leave my latest status here for the next good soul who wants to update this answer.

    1) if you know the PID, this looks like it is the « current » way to raise the process to foreground, but ONLY the active window (i.e., replacement for SetFrontProcessWithOptions() which is deprecated ):
    NSRunningApplication* app = [NSRunningApplication
    runningApplicationWithProcessIdentifier: pid];
    [app activateWithOptions:0 ];

    2) CGWindowListCopyWindowInfo() no longer returns all top windows. It only returns the wallpaper window and a few other gadgets. So you can’t use it to list windows. Apparently, that’s somwhere in the accessiblity kit, I ran out of time to research.

    3) I managed to do all of it with AppleScript, though. Would love to know the equivalent Objective-C, but it looks like there’s no easy way to « translate ».

    « `
    use framework « AppKit »
    use scripting additions

    property windowCount : 0
    property winptr : missing value
    property procpid : missing value
    property runningappobj : missing value

    tell application « System Events »
    tell application process « Google Chrome »
    set procpid to (unix id)
    set runningappobj to current application’s NSRunningApplication’s runningApplicationWithProcessIdentifier:procpid
    set winptr to (first window whose name is equal to « YOUR WINDOW TITLE »)
    perform action « AXRaise » of winptr
    runningappobj’s activateWithOptions:0
    end tell
    end tell
    « `

Laisser un commentaire