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