| 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/focus_controller.h" | |
| 6 | |
| 7 #include "base/auto_reset.h" | |
| 8 #include "ui/aura/client/activation_change_observer.h" | |
| 9 #include "ui/aura/client/aura_constants.h" | |
| 10 #include "ui/aura/client/capture_client.h" | |
| 11 #include "ui/aura/client/focus_change_observer.h" | |
| 12 #include "ui/aura/env.h" | |
| 13 #include "ui/aura/window_tracker.h" | |
| 14 #include "ui/events/event.h" | |
| 15 #include "ui/views/corewm/focus_rules.h" | |
| 16 #include "ui/views/corewm/window_util.h" | |
| 17 | |
| 18 namespace views { | |
| 19 namespace corewm { | |
| 20 namespace { | |
| 21 | |
| 22 // When a modal window is activated, we bring its entire transient parent chain | |
| 23 // to the front. This function must be called before the modal transient is | |
| 24 // stacked at the top to ensure correct stacking order. | |
| 25 void StackTransientParentsBelowModalWindow(aura::Window* window) { | |
| 26 if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_WINDOW) | |
| 27 return; | |
| 28 | |
| 29 aura::Window* transient_parent = views::corewm::GetTransientParent(window); | |
| 30 while (transient_parent) { | |
| 31 transient_parent->parent()->StackChildAtTop(transient_parent); | |
| 32 transient_parent = views::corewm::GetTransientParent(transient_parent); | |
| 33 } | |
| 34 } | |
| 35 | |
| 36 // Stack's |window|'s layer above |relative_to|'s layer. | |
| 37 void StackWindowLayerAbove(aura::Window* window, aura::Window* relative_to) { | |
| 38 // Stack |window| above the last transient child of |relative_to| that shares | |
| 39 // the same parent. | |
| 40 const aura::Window::Windows& window_transients( | |
| 41 GetTransientChildren(relative_to)); | |
| 42 for (aura::Window::Windows::const_iterator i = window_transients.begin(); | |
| 43 i != window_transients.end(); ++i) { | |
| 44 aura::Window* transient = *i; | |
| 45 if (transient->parent() == relative_to->parent()) | |
| 46 relative_to = transient; | |
| 47 } | |
| 48 if (window != relative_to) { | |
| 49 window->layer()->parent()->StackAbove(window->layer(), | |
| 50 relative_to->layer()); | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 } // namespace | |
| 55 | |
| 56 //////////////////////////////////////////////////////////////////////////////// | |
| 57 // FocusController, public: | |
| 58 | |
| 59 FocusController::FocusController(FocusRules* rules) | |
| 60 : active_window_(NULL), | |
| 61 focused_window_(NULL), | |
| 62 updating_focus_(false), | |
| 63 updating_activation_(false), | |
| 64 rules_(rules), | |
| 65 observer_manager_(this) { | |
| 66 DCHECK(rules); | |
| 67 } | |
| 68 | |
| 69 FocusController::~FocusController() { | |
| 70 } | |
| 71 | |
| 72 //////////////////////////////////////////////////////////////////////////////// | |
| 73 // FocusController, aura::client::ActivationClient implementation: | |
| 74 | |
| 75 void FocusController::AddObserver( | |
| 76 aura::client::ActivationChangeObserver* observer) { | |
| 77 activation_observers_.AddObserver(observer); | |
| 78 } | |
| 79 | |
| 80 void FocusController::RemoveObserver( | |
| 81 aura::client::ActivationChangeObserver* observer) { | |
| 82 activation_observers_.RemoveObserver(observer); | |
| 83 } | |
| 84 | |
| 85 void FocusController::ActivateWindow(aura::Window* window) { | |
| 86 FocusWindow(window); | |
| 87 } | |
| 88 | |
| 89 void FocusController::DeactivateWindow(aura::Window* window) { | |
| 90 if (window) | |
| 91 FocusWindow(rules_->GetNextActivatableWindow(window)); | |
| 92 } | |
| 93 | |
| 94 aura::Window* FocusController::GetActiveWindow() { | |
| 95 return active_window_; | |
| 96 } | |
| 97 | |
| 98 aura::Window* FocusController::GetActivatableWindow(aura::Window* window) { | |
| 99 return rules_->GetActivatableWindow(window); | |
| 100 } | |
| 101 | |
| 102 aura::Window* FocusController::GetToplevelWindow(aura::Window* window) { | |
| 103 return rules_->GetToplevelWindow(window); | |
| 104 } | |
| 105 | |
| 106 bool FocusController::OnWillFocusWindow(aura::Window* window, | |
| 107 const ui::Event* event) { | |
| 108 NOTREACHED(); | |
| 109 return false; | |
| 110 } | |
| 111 | |
| 112 bool FocusController::CanActivateWindow(aura::Window* window) const { | |
| 113 return rules_->CanActivateWindow(window); | |
| 114 } | |
| 115 | |
| 116 //////////////////////////////////////////////////////////////////////////////// | |
| 117 // FocusController, aura::client::FocusClient implementation: | |
| 118 | |
| 119 void FocusController::AddObserver( | |
| 120 aura::client::FocusChangeObserver* observer) { | |
| 121 focus_observers_.AddObserver(observer); | |
| 122 } | |
| 123 | |
| 124 void FocusController::RemoveObserver( | |
| 125 aura::client::FocusChangeObserver* observer) { | |
| 126 focus_observers_.RemoveObserver(observer); | |
| 127 } | |
| 128 | |
| 129 void FocusController::FocusWindow(aura::Window* window) { | |
| 130 if (window && | |
| 131 (window->Contains(focused_window_) || window->Contains(active_window_))) { | |
| 132 return; | |
| 133 } | |
| 134 | |
| 135 // We should not be messing with the focus if the window has capture, unless | |
| 136 // no has focus. | |
| 137 if (window && (aura::client::GetCaptureWindow(window) == window) && | |
| 138 focused_window_) { | |
| 139 return; | |
| 140 } | |
| 141 | |
| 142 // Focusing a window also activates its containing activatable window. Note | |
| 143 // that the rules could redirect activation activation and/or focus. | |
| 144 aura::Window* focusable = rules_->GetFocusableWindow(window); | |
| 145 aura::Window* activatable = | |
| 146 focusable ? rules_->GetActivatableWindow(focusable) : NULL; | |
| 147 | |
| 148 // We need valid focusable/activatable windows in the event we're not clearing | |
| 149 // focus. "Clearing focus" is inferred by whether or not |window| passed to | |
| 150 // this function is non-NULL. | |
| 151 if (window && (!focusable || !activatable)) | |
| 152 return; | |
| 153 DCHECK((focusable && activatable) || !window); | |
| 154 | |
| 155 // Activation change observers may change the focused window. If this happens | |
| 156 // we must not adjust the focus below since this will clobber that change. | |
| 157 aura::Window* last_focused_window = focused_window_; | |
| 158 if (!updating_activation_) | |
| 159 SetActiveWindow(window, activatable); | |
| 160 | |
| 161 // If the window's ActivationChangeObserver shifted focus to a valid window, | |
| 162 // we don't want to focus the window we thought would be focused by default. | |
| 163 bool activation_changed_focus = last_focused_window != focused_window_; | |
| 164 if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) { | |
| 165 if (active_window_ && focusable) | |
| 166 DCHECK(active_window_->Contains(focusable)); | |
| 167 SetFocusedWindow(focusable); | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) { | |
| 172 DCHECK(window); | |
| 173 if (!active_window_) | |
| 174 return; | |
| 175 if (!active_window_->Contains(window)) | |
| 176 return; | |
| 177 SetFocusedWindow(window); | |
| 178 } | |
| 179 | |
| 180 aura::Window* FocusController::GetFocusedWindow() { | |
| 181 return focused_window_; | |
| 182 } | |
| 183 | |
| 184 //////////////////////////////////////////////////////////////////////////////// | |
| 185 // FocusController, ui::EventHandler implementation: | |
| 186 void FocusController::OnKeyEvent(ui::KeyEvent* event) { | |
| 187 } | |
| 188 | |
| 189 void FocusController::OnMouseEvent(ui::MouseEvent* event) { | |
| 190 if (event->type() == ui::ET_MOUSE_PRESSED) | |
| 191 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target())); | |
| 192 } | |
| 193 | |
| 194 void FocusController::OnScrollEvent(ui::ScrollEvent* event) { | |
| 195 } | |
| 196 | |
| 197 void FocusController::OnTouchEvent(ui::TouchEvent* event) { | |
| 198 } | |
| 199 | |
| 200 void FocusController::OnGestureEvent(ui::GestureEvent* event) { | |
| 201 if (event->type() == ui::ET_GESTURE_BEGIN && | |
| 202 event->details().touch_points() == 1) { | |
| 203 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target())); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 //////////////////////////////////////////////////////////////////////////////// | |
| 208 // FocusController, aura::WindowObserver implementation: | |
| 209 | |
| 210 void FocusController::OnWindowVisibilityChanged(aura::Window* window, | |
| 211 bool visible) { | |
| 212 if (!visible) { | |
| 213 WindowLostFocusFromDispositionChange(window, window->parent()); | |
| 214 // Despite the focus change, we need to keep the window being hidden | |
| 215 // stacked above the new window so it stays open on top as it animates away. | |
| 216 aura::Window* next_window = GetActiveWindow(); | |
| 217 if (next_window && next_window->parent() == window->parent()) | |
| 218 StackWindowLayerAbove(window, next_window); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 void FocusController::OnWindowDestroying(aura::Window* window) { | |
| 223 WindowLostFocusFromDispositionChange(window, window->parent()); | |
| 224 } | |
| 225 | |
| 226 void FocusController::OnWindowHierarchyChanging( | |
| 227 const HierarchyChangeParams& params) { | |
| 228 if (params.receiver == active_window_ && | |
| 229 params.target->Contains(params.receiver) && (!params.new_parent || | |
| 230 aura::client::GetFocusClient(params.new_parent) != | |
| 231 aura::client::GetFocusClient(params.receiver))) { | |
| 232 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent); | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 void FocusController::OnWindowHierarchyChanged( | |
| 237 const HierarchyChangeParams& params) { | |
| 238 if (params.receiver == focused_window_ && | |
| 239 params.target->Contains(params.receiver) && (!params.new_parent || | |
| 240 aura::client::GetFocusClient(params.new_parent) != | |
| 241 aura::client::GetFocusClient(params.receiver))) { | |
| 242 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 //////////////////////////////////////////////////////////////////////////////// | |
| 247 // FocusController, private: | |
| 248 | |
| 249 void FocusController::SetFocusedWindow(aura::Window* window) { | |
| 250 if (updating_focus_ || window == focused_window_) | |
| 251 return; | |
| 252 DCHECK(rules_->CanFocusWindow(window)); | |
| 253 if (window) | |
| 254 DCHECK_EQ(window, rules_->GetFocusableWindow(window)); | |
| 255 | |
| 256 base::AutoReset<bool> updating_focus(&updating_focus_, true); | |
| 257 aura::Window* lost_focus = focused_window_; | |
| 258 // Allow for the window losing focus to be deleted during dispatch. If it is | |
| 259 // deleted pass NULL to observers instead of a deleted window. | |
| 260 aura::WindowTracker window_tracker; | |
| 261 if (lost_focus) | |
| 262 window_tracker.Add(lost_focus); | |
| 263 if (focused_window_ && observer_manager_.IsObserving(focused_window_) && | |
| 264 focused_window_ != active_window_) { | |
| 265 observer_manager_.Remove(focused_window_); | |
| 266 } | |
| 267 focused_window_ = window; | |
| 268 if (focused_window_ && !observer_manager_.IsObserving(focused_window_)) | |
| 269 observer_manager_.Add(focused_window_); | |
| 270 | |
| 271 FOR_EACH_OBSERVER(aura::client::FocusChangeObserver, | |
| 272 focus_observers_, | |
| 273 OnWindowFocused(focused_window_, | |
| 274 window_tracker.Contains(lost_focus) ? | |
| 275 lost_focus : NULL)); | |
| 276 if (window_tracker.Contains(lost_focus)) { | |
| 277 aura::client::FocusChangeObserver* observer = | |
| 278 aura::client::GetFocusChangeObserver(lost_focus); | |
| 279 if (observer) | |
| 280 observer->OnWindowFocused(focused_window_, lost_focus); | |
| 281 } | |
| 282 aura::client::FocusChangeObserver* observer = | |
| 283 aura::client::GetFocusChangeObserver(focused_window_); | |
| 284 if (observer) { | |
| 285 observer->OnWindowFocused( | |
| 286 focused_window_, | |
| 287 window_tracker.Contains(lost_focus) ? lost_focus : NULL); | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 void FocusController::SetActiveWindow(aura::Window* requested_window, | |
| 292 aura::Window* window) { | |
| 293 if (updating_activation_) | |
| 294 return; | |
| 295 | |
| 296 if (window == active_window_) { | |
| 297 if (requested_window) { | |
| 298 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver, | |
| 299 activation_observers_, | |
| 300 OnAttemptToReactivateWindow(requested_window, | |
| 301 active_window_)); | |
| 302 } | |
| 303 return; | |
| 304 } | |
| 305 | |
| 306 DCHECK(rules_->CanActivateWindow(window)); | |
| 307 if (window) | |
| 308 DCHECK_EQ(window, rules_->GetActivatableWindow(window)); | |
| 309 | |
| 310 base::AutoReset<bool> updating_activation(&updating_activation_, true); | |
| 311 aura::Window* lost_activation = active_window_; | |
| 312 // Allow for the window losing activation to be deleted during dispatch. If | |
| 313 // it is deleted pass NULL to observers instead of a deleted window. | |
| 314 aura::WindowTracker window_tracker; | |
| 315 if (lost_activation) | |
| 316 window_tracker.Add(lost_activation); | |
| 317 if (active_window_ && observer_manager_.IsObserving(active_window_) && | |
| 318 focused_window_ != active_window_) { | |
| 319 observer_manager_.Remove(active_window_); | |
| 320 } | |
| 321 active_window_ = window; | |
| 322 if (active_window_ && !observer_manager_.IsObserving(active_window_)) | |
| 323 observer_manager_.Add(active_window_); | |
| 324 if (active_window_) { | |
| 325 StackTransientParentsBelowModalWindow(active_window_); | |
| 326 active_window_->parent()->StackChildAtTop(active_window_); | |
| 327 } | |
| 328 | |
| 329 aura::client::ActivationChangeObserver* observer = NULL; | |
| 330 if (window_tracker.Contains(lost_activation)) { | |
| 331 observer = aura::client::GetActivationChangeObserver(lost_activation); | |
| 332 if (observer) | |
| 333 observer->OnWindowActivated(active_window_, lost_activation); | |
| 334 } | |
| 335 observer = aura::client::GetActivationChangeObserver(active_window_); | |
| 336 if (observer) { | |
| 337 observer->OnWindowActivated( | |
| 338 active_window_, | |
| 339 window_tracker.Contains(lost_activation) ? lost_activation : NULL); | |
| 340 } | |
| 341 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver, | |
| 342 activation_observers_, | |
| 343 OnWindowActivated(active_window_, | |
| 344 window_tracker.Contains(lost_activation) ? | |
| 345 lost_activation : NULL)); | |
| 346 } | |
| 347 | |
| 348 void FocusController::WindowLostFocusFromDispositionChange( | |
| 349 aura::Window* window, | |
| 350 aura::Window* next) { | |
| 351 // A window's modality state will interfere with focus restoration during its | |
| 352 // destruction. | |
| 353 window->ClearProperty(aura::client::kModalKey); | |
| 354 // TODO(beng): See if this function can be replaced by a call to | |
| 355 // FocusWindow(). | |
| 356 // Activation adjustments are handled first in the event of a disposition | |
| 357 // changed. If an activation change is necessary, focus is reset as part of | |
| 358 // that process so there's no point in updating focus independently. | |
| 359 if (window == active_window_) { | |
| 360 aura::Window* next_activatable = rules_->GetNextActivatableWindow(window); | |
| 361 SetActiveWindow(NULL, next_activatable); | |
| 362 if (!(active_window_ && active_window_->Contains(focused_window_))) | |
| 363 SetFocusedWindow(next_activatable); | |
| 364 } else if (window->Contains(focused_window_)) { | |
| 365 // Active window isn't changing, but focused window might be. | |
| 366 SetFocusedWindow(rules_->GetFocusableWindow(next)); | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 void FocusController::WindowFocusedFromInputEvent(aura::Window* window) { | |
| 371 // Only focus |window| if it or any of its parents can be focused. Otherwise | |
| 372 // FocusWindow() will focus the topmost window, which may not be the | |
| 373 // currently focused one. | |
| 374 if (rules_->CanFocusWindow(GetToplevelWindow(window))) | |
| 375 FocusWindow(window); | |
| 376 } | |
| 377 | |
| 378 } // namespace corewm | |
| 379 } // namespace views | |
| OLD | NEW |