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