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 9namespace 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. 35void 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