| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 #include "ui/views/corewm/base_focus_rules.h" | |
| 6 | |
| 7 #include "ui/aura/client/activation_delegate.h" | |
| 8 #include "ui/aura/client/focus_client.h" | |
| 9 #include "ui/aura/window.h" | |
| 10 #include "ui/aura/window_event_dispatcher.h" | |
| 11 #include "ui/views/corewm/window_modality_controller.h" | |
| 12 #include "ui/views/corewm/window_util.h" | |
| 13 | |
| 14 namespace views { | |
| 15 namespace corewm { | |
| 16 namespace { | |
| 17 | |
| 18 aura::Window* GetFocusedWindow(aura::Window* context) { | |
| 19 aura::client::FocusClient* focus_client = | |
| 20 aura::client::GetFocusClient(context); | |
| 21 return focus_client ? focus_client->GetFocusedWindow() : NULL; | |
| 22 } | |
| 23 | |
| 24 } // namespace | |
| 25 | |
| 26 //////////////////////////////////////////////////////////////////////////////// | |
| 27 // BaseFocusRules, protected: | |
| 28 | |
| 29 BaseFocusRules::BaseFocusRules() { | |
| 30 } | |
| 31 | |
| 32 BaseFocusRules::~BaseFocusRules() { | |
| 33 } | |
| 34 | |
| 35 bool BaseFocusRules::IsWindowConsideredVisibleForActivation( | |
| 36 aura::Window* window) const { | |
| 37 return window->IsVisible(); | |
| 38 } | |
| 39 | |
| 40 //////////////////////////////////////////////////////////////////////////////// | |
| 41 // BaseFocusRules, FocusRules implementation: | |
| 42 | |
| 43 bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const { | |
| 44 // The window must in a valid hierarchy. | |
| 45 if (!window->GetRootWindow()) | |
| 46 return false; | |
| 47 | |
| 48 // The window must exist within a container that supports activation. | |
| 49 // The window cannot be blocked by a modal transient. | |
| 50 return SupportsChildActivation(window->parent()); | |
| 51 } | |
| 52 | |
| 53 bool BaseFocusRules::CanActivateWindow(aura::Window* window) const { | |
| 54 // It is possible to activate a NULL window, it is equivalent to clearing | |
| 55 // activation. | |
| 56 if (!window) | |
| 57 return true; | |
| 58 | |
| 59 // Only toplevel windows can be activated. | |
| 60 if (!IsToplevelWindow(window)) | |
| 61 return false; | |
| 62 | |
| 63 // The window must be visible. | |
| 64 if (!IsWindowConsideredVisibleForActivation(window)) | |
| 65 return false; | |
| 66 | |
| 67 // The window's activation delegate must allow this window to be activated. | |
| 68 if (aura::client::GetActivationDelegate(window) && | |
| 69 !aura::client::GetActivationDelegate(window)->ShouldActivate()) { | |
| 70 return false; | |
| 71 } | |
| 72 | |
| 73 // A window must be focusable to be activatable. We don't call | |
| 74 // CanFocusWindow() from here because it will call back to us via | |
| 75 // GetActivatableWindow(). | |
| 76 if (!window->CanFocus()) | |
| 77 return false; | |
| 78 | |
| 79 // The window cannot be blocked by a modal transient. | |
| 80 return !GetModalTransient(window); | |
| 81 } | |
| 82 | |
| 83 bool BaseFocusRules::CanFocusWindow(aura::Window* window) const { | |
| 84 // It is possible to focus a NULL window, it is equivalent to clearing focus. | |
| 85 if (!window) | |
| 86 return true; | |
| 87 | |
| 88 // The focused window is always inside the active window, so windows that | |
| 89 // aren't activatable can't contain the focused window. | |
| 90 aura::Window* activatable = GetActivatableWindow(window); | |
| 91 if (!activatable || !activatable->Contains(window)) | |
| 92 return false; | |
| 93 return window->CanFocus(); | |
| 94 } | |
| 95 | |
| 96 aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const { | |
| 97 aura::Window* parent = window->parent(); | |
| 98 aura::Window* child = window; | |
| 99 while (parent) { | |
| 100 if (IsToplevelWindow(child)) | |
| 101 return child; | |
| 102 | |
| 103 parent = parent->parent(); | |
| 104 child = child->parent(); | |
| 105 } | |
| 106 return NULL; | |
| 107 } | |
| 108 | |
| 109 aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const { | |
| 110 aura::Window* parent = window->parent(); | |
| 111 aura::Window* child = window; | |
| 112 while (parent) { | |
| 113 if (CanActivateWindow(child)) | |
| 114 return child; | |
| 115 | |
| 116 // CanActivateWindow() above will return false if |child| is blocked by a | |
| 117 // modal transient. In this case the modal is or contains the activatable | |
| 118 // window. We recurse because the modal may itself be blocked by a modal | |
| 119 // transient. | |
| 120 aura::Window* modal_transient = GetModalTransient(child); | |
| 121 if (modal_transient) | |
| 122 return GetActivatableWindow(modal_transient); | |
| 123 | |
| 124 if (views::corewm::GetTransientParent(child)) { | |
| 125 // To avoid infinite recursion, if |child| has a transient parent | |
| 126 // whose own modal transient is |child| itself, just return |child|. | |
| 127 aura::Window* parent_modal_transient = | |
| 128 GetModalTransient(views::corewm::GetTransientParent(child)); | |
| 129 if (parent_modal_transient == child) | |
| 130 return child; | |
| 131 | |
| 132 return GetActivatableWindow(views::corewm::GetTransientParent(child)); | |
| 133 } | |
| 134 | |
| 135 parent = parent->parent(); | |
| 136 child = child->parent(); | |
| 137 } | |
| 138 return NULL; | |
| 139 } | |
| 140 | |
| 141 aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const { | |
| 142 if (CanFocusWindow(window)) | |
| 143 return window; | |
| 144 | |
| 145 // |window| may be in a hierarchy that is non-activatable, in which case we | |
| 146 // need to cut over to the activatable hierarchy. | |
| 147 aura::Window* activatable = GetActivatableWindow(window); | |
| 148 if (!activatable) { | |
| 149 // There may not be a related activatable hierarchy to cut over to, in which | |
| 150 // case we try an unrelated one. | |
| 151 aura::Window* toplevel = GetToplevelWindow(window); | |
| 152 if (toplevel) | |
| 153 activatable = GetNextActivatableWindow(toplevel); | |
| 154 if (!activatable) | |
| 155 return NULL; | |
| 156 } | |
| 157 | |
| 158 if (!activatable->Contains(window)) { | |
| 159 // If there's already a child window focused in the activatable hierarchy, | |
| 160 // just use that (i.e. don't shift focus), otherwise we need to at least cut | |
| 161 // over to the activatable hierarchy. | |
| 162 aura::Window* focused = GetFocusedWindow(activatable); | |
| 163 return activatable->Contains(focused) ? focused : activatable; | |
| 164 } | |
| 165 | |
| 166 while (window && !CanFocusWindow(window)) | |
| 167 window = window->parent(); | |
| 168 return window; | |
| 169 } | |
| 170 | |
| 171 aura::Window* BaseFocusRules::GetNextActivatableWindow( | |
| 172 aura::Window* ignore) const { | |
| 173 DCHECK(ignore); | |
| 174 | |
| 175 // Can be called from the RootWindow's destruction, which has a NULL parent. | |
| 176 if (!ignore->parent()) | |
| 177 return NULL; | |
| 178 | |
| 179 // In the basic scenarios handled by BasicFocusRules, the pool of activatable | |
| 180 // windows is limited to the |ignore|'s siblings. | |
| 181 const aura::Window::Windows& siblings = ignore->parent()->children(); | |
| 182 DCHECK(!siblings.empty()); | |
| 183 | |
| 184 for (aura::Window::Windows::const_reverse_iterator rit = siblings.rbegin(); | |
| 185 rit != siblings.rend(); | |
| 186 ++rit) { | |
| 187 aura::Window* cur = *rit; | |
| 188 if (cur == ignore) | |
| 189 continue; | |
| 190 if (CanActivateWindow(cur)) | |
| 191 return cur; | |
| 192 } | |
| 193 return NULL; | |
| 194 } | |
| 195 | |
| 196 } // namespace corewm | |
| 197 } // namespace views | |
| OLD | NEW |