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