Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / ui / base / cocoa / focus_window_set.mm
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 namespace {
12
13 // This attempts to match OS X's native behavior, namely that a window
14 // is only ever deminiaturized if ALL windows on ALL workspaces are
15 // miniaturized.
16 void FocusWindowSetHelper(const std::set<NSWindow*>& windows,
17                           bool allow_workspace_switch,
18                           bool visible_windows_only) {
19   NSArray* ordered_windows = [NSApp orderedWindows];
20   NSWindow* frontmost_window = nil;
21   NSWindow* frontmost_window_all_spaces = nil;
22   NSWindow* frontmost_miniaturized_window = nil;
23   bool all_miniaturized = true;
24   for (int i = [ordered_windows count] - 1; i >= 0; i--) {
25     NSWindow* win = [ordered_windows objectAtIndex:i];
26     if (windows.find(win) == windows.end())
27       continue;
28     if ([win isMiniaturized]) {
29       frontmost_miniaturized_window = win;
30     } else if (!visible_windows_only || [win isVisible]) {
31       all_miniaturized = false;
32       frontmost_window_all_spaces = win;
33       if ([win isOnActiveSpace]) {
34         [win orderFront:nil];
35         frontmost_window = win;
36       }
37     }
38   }
39   if (all_miniaturized && frontmost_miniaturized_window) {
40     [frontmost_miniaturized_window deminiaturize:nil];
41     frontmost_window = frontmost_miniaturized_window;
42   }
43   // If we couldn't find one on this window, consider all spaces.
44   if (allow_workspace_switch &&
45       !frontmost_window && frontmost_window_all_spaces) {
46     frontmost_window = frontmost_window_all_spaces;
47     [frontmost_window orderFront:nil];
48   }
49   if (frontmost_window) {
50     [NSApp activateIgnoringOtherApps:YES];
51     [frontmost_window makeMainWindow];
52     [frontmost_window makeKeyWindow];
53   }
54 }
55
56 }  // namespace
57
58 void FocusWindowSet(const std::set<NSWindow*>& windows) {
59   FocusWindowSetHelper(windows, true, true);
60 }
61
62 void FocusWindowSetOnCurrentSpace(const std::set<NSWindow*>& windows) {
63   // This callback runs before AppKit picks its own window to
64   // deminiaturize, so we get to pick one from the right set. Limit to
65   // the windows on the current workspace. Otherwise we jump spaces
66   // haphazardly.
67   //
68   // Also consider both visible and hidden windows; this call races
69   // with the system unhiding the application. http://crbug.com/368238
70   //
71   // NOTE: If this is called in the
72   // applicationShouldHandleReopen:hasVisibleWindows: hook when
73   // clicking the dock icon, and that caused OS X to begin switch
74   // spaces, isOnActiveSpace gives the answer for the PREVIOUS
75   // space. This means that we actually raise and focus the wrong
76   // space's windows, leaving the new key window off-screen. To detect
77   // this, check if the key window is on the active space prior to
78   // calling.
79   //
80   // Also, if we decide to deminiaturize a window during a space switch,
81   // that can switch spaces and then switch back. Fortunately, this only
82   // happens if, say, space 1 contains an app, space 2 contains a
83   // miniaturized browser. We click the icon, OS X switches to space 1,
84   // we deminiaturize the browser, and that triggers switching back.
85   //
86   // TODO(davidben): To limit those cases, consider preferentially
87   // deminiaturizing a window on the current space.
88   FocusWindowSetHelper(windows, false, false);
89 }
90
91 }  // namespace ui