// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #import <Cocoa/Cocoa.h> #include "ui/base/cocoa/focus_window_set.h" namespace ui { // This attempts to match OS X's native behavior, namely that a window // is only ever deminiaturized if ALL windows on ALL workspaces are // miniaturized. (This callback runs before AppKit picks its own // window to deminiaturize, so we get to pick one from the right set.) // // In addition, limit to the windows on the current // workspace. Otherwise we jump spaces haphazardly. // // NOTE: If this is called in the // applicationShouldHandleReopen:hasVisibleWindows: hook when clicking // the dock icon, and that caused OS X to begin switch spaces, // isOnActiveSpace gives the answer for the PREVIOUS space. This means // that we actually raise and focus the wrong space's windows, leaving // the new key window off-screen. To detect this, check if the key // window prior to calling is on an active space. // // Also, if we decide to deminiaturize a window during a space switch, // that can switch spaces and then switch back. Fortunately, this only // happens if, say, space 1 contains an app, space 2 contains a // miniaturized browser. We click the icon, OS X switches to space 1, // we deminiaturize the browser, and that triggers switching back. // // TODO(davidben): To limit those cases, consider preferentially // deminiaturizing a window on the current space. void FocusWindowSet(const std::set<NSWindow*>& windows, bool allow_workspace_switch) { NSArray* ordered_windows = [NSApp orderedWindows]; NSWindow* frontmost_window = nil; NSWindow* frontmost_window_all_spaces = nil; NSWindow* frontmost_miniaturized_window = nil; bool all_miniaturized = true; for (int i = [ordered_windows count] - 1; i >= 0; i--) { NSWindow* win = [ordered_windows objectAtIndex:i]; if (windows.find(win) != windows.end()) { if ([win isMiniaturized]) { frontmost_miniaturized_window = win; } else if ([win isVisible]) { all_miniaturized = false; frontmost_window_all_spaces = win; if ([win isOnActiveSpace]) { [win orderFront:nil]; frontmost_window = win; } } } } if (all_miniaturized && frontmost_miniaturized_window) { [frontmost_miniaturized_window deminiaturize:nil]; frontmost_window = frontmost_miniaturized_window; } // If we couldn't find one on this window, consider all spaces. if (allow_workspace_switch && !frontmost_window && frontmost_window_all_spaces) { frontmost_window = frontmost_window_all_spaces; [frontmost_window orderFront:nil]; } if (frontmost_window) { [NSApp activateIgnoringOtherApps:YES]; [frontmost_window makeMainWindow]; [frontmost_window makeKeyWindow]; } } } // namespace ui