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