Home | History | Annotate | Download | only in cocoa
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #import <Cocoa/Cocoa.h>
      6 
      7 #include "ui/base/cocoa/focus_window_set.h"
      8 
      9 namespace ui {
     10 
     11 // This attempts to match OS X's native behavior, namely that a window
     12 // is only ever deminiaturized if ALL windows on ALL workspaces are
     13 // miniaturized. (This callback runs before AppKit picks its own
     14 // window to deminiaturize, so we get to pick one from the right set.)
     15 //
     16 // In addition, limit to the windows on the current
     17 // workspace. Otherwise we jump spaces haphazardly.
     18 //
     19 // NOTE: If this is called in the
     20 // applicationShouldHandleReopen:hasVisibleWindows: hook when clicking
     21 // the dock icon, and that caused OS X to begin switch spaces,
     22 // isOnActiveSpace gives the answer for the PREVIOUS space. This means
     23 // that we actually raise and focus the wrong space's windows, leaving
     24 // the new key window off-screen. To detect this, check if the key
     25 // window prior to calling is on an active space.
     26 //
     27 // Also, if we decide to deminiaturize a window during a space switch,
     28 // that can switch spaces and then switch back. Fortunately, this only
     29 // happens if, say, space 1 contains an app, space 2 contains a
     30 // miniaturized browser. We click the icon, OS X switches to space 1,
     31 // we deminiaturize the browser, and that triggers switching back.
     32 //
     33 // TODO(davidben): To limit those cases, consider preferentially
     34 // deminiaturizing a window on the current space.
     35 void FocusWindowSet(const std::set<NSWindow*>& windows,
     36                     bool allow_workspace_switch) {
     37   NSArray* ordered_windows = [NSApp orderedWindows];
     38   NSWindow* frontmost_window = nil;
     39   NSWindow* frontmost_window_all_spaces = nil;
     40   NSWindow* frontmost_miniaturized_window = nil;
     41   bool all_miniaturized = true;
     42   for (int i = [ordered_windows count] - 1; i >= 0; i--) {
     43     NSWindow* win = [ordered_windows objectAtIndex:i];
     44     if (windows.find(win) != windows.end()) {
     45       if ([win isMiniaturized]) {
     46         frontmost_miniaturized_window = win;
     47       } else if ([win isVisible]) {
     48         all_miniaturized = false;
     49         frontmost_window_all_spaces = win;
     50         if ([win isOnActiveSpace]) {
     51           [win orderFront:nil];
     52           frontmost_window = win;
     53         }
     54       }
     55     }
     56   }
     57   if (all_miniaturized && frontmost_miniaturized_window) {
     58     [frontmost_miniaturized_window deminiaturize:nil];
     59     frontmost_window = frontmost_miniaturized_window;
     60   }
     61   // If we couldn't find one on this window, consider all spaces.
     62   if (allow_workspace_switch &&
     63       !frontmost_window && frontmost_window_all_spaces) {
     64     frontmost_window = frontmost_window_all_spaces;
     65     [frontmost_window orderFront:nil];
     66   }
     67   if (frontmost_window) {
     68     [NSApp activateIgnoringOtherApps:YES];
     69     [frontmost_window makeMainWindow];
     70     [frontmost_window makeKeyWindow];
     71   }
     72 }
     73 
     74 }  // namespace ui
     75