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/widget/desktop_aura/desktop_activation_client.h" 6 7 #include "base/auto_reset.h" 8 #include "base/compiler_specific.h" 9 #include "ui/aura/client/activation_delegate.h" 10 #include "ui/aura/client/activation_change_observer.h" 11 #include "ui/aura/client/focus_client.h" 12 #include "ui/aura/root_window.h" 13 #include "ui/aura/window.h" 14 15 namespace views { 16 17 namespace { 18 19 aura::Window* FindFocusableWindowFor(aura::Window* window) { 20 while (window && !window->CanFocus()) 21 window = window->parent(); 22 return window; 23 } 24 25 } // namespace 26 27 DesktopActivationClient::DesktopActivationClient(aura::RootWindow* root_window) 28 : root_window_(root_window), 29 current_active_(NULL), 30 updating_activation_(false), 31 observer_manager_(this) { 32 aura::client::GetFocusClient(root_window_)->AddObserver(this); 33 aura::client::SetActivationClient(root_window_, this); 34 root_window->AddPreTargetHandler(this); 35 } 36 37 DesktopActivationClient::~DesktopActivationClient() { 38 root_window_->RemovePreTargetHandler(this); 39 aura::client::GetFocusClient(root_window_)->RemoveObserver(this); 40 aura::client::SetActivationClient(root_window_, NULL); 41 } 42 43 void DesktopActivationClient::AddObserver( 44 aura::client::ActivationChangeObserver* observer) { 45 observers_.AddObserver(observer); 46 } 47 48 void DesktopActivationClient::RemoveObserver( 49 aura::client::ActivationChangeObserver* observer) { 50 observers_.RemoveObserver(observer); 51 } 52 53 void DesktopActivationClient::ActivateWindow(aura::Window* window) { 54 // Prevent recursion when called from focus. 55 if (updating_activation_) 56 return; 57 58 base::AutoReset<bool> in_activate_window(&updating_activation_, true); 59 // Nothing may actually have changed. 60 if (current_active_ == window) 61 return; 62 // The stacking client may impose rules on what window configurations can be 63 // activated or deactivated. 64 if (window && !CanActivateWindow(window)) 65 return; 66 // Switch internal focus before we change the activation. Will probably cause 67 // recursion. 68 if (window && 69 !window->Contains(aura::client::GetFocusClient(window)-> 70 GetFocusedWindow())) { 71 aura::client::GetFocusClient(window)->FocusWindow(window); 72 } 73 74 aura::Window* old_active = current_active_; 75 current_active_ = window; 76 if (window && !observer_manager_.IsObserving(window)) 77 observer_manager_.Add(window); 78 79 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver, 80 observers_, 81 OnWindowActivated(window, old_active)); 82 aura::client::ActivationChangeObserver* observer = 83 aura::client::GetActivationChangeObserver(old_active); 84 if (observer) 85 observer->OnWindowActivated(window, old_active); 86 observer = aura::client::GetActivationChangeObserver(window); 87 if (observer) 88 observer->OnWindowActivated(window, old_active); 89 } 90 91 void DesktopActivationClient::DeactivateWindow(aura::Window* window) { 92 if (window == current_active_) 93 current_active_ = NULL; 94 } 95 96 aura::Window* DesktopActivationClient::GetActiveWindow() { 97 return current_active_; 98 } 99 100 aura::Window* DesktopActivationClient::GetActivatableWindow( 101 aura::Window* window) { 102 aura::Window* parent = window->parent(); 103 aura::Window* child = window; 104 while (parent) { 105 if (CanActivateWindow(child)) 106 return child; 107 // If |child| isn't activatable, but has transient parent, trace 108 // that path instead. 109 if (child->transient_parent()) 110 return GetActivatableWindow(child->transient_parent()); 111 parent = parent->parent(); 112 child = child->parent(); 113 } 114 return NULL; 115 } 116 117 aura::Window* DesktopActivationClient::GetToplevelWindow(aura::Window* window) { 118 aura::Window* parent = window->parent(); 119 aura::Window* child = window; 120 aura::Window* root = child->GetRootWindow(); 121 while (parent) { 122 if (parent == root) 123 return child; 124 parent = parent->parent(); 125 child = child->parent(); 126 } 127 return NULL; 128 } 129 130 bool DesktopActivationClient::OnWillFocusWindow(aura::Window* window, 131 const ui::Event* event) { 132 return CanActivateWindow(GetActivatableWindow(window)); 133 } 134 135 void DesktopActivationClient::OnWindowDestroying(aura::Window* window) { 136 if (current_active_ == window) { 137 current_active_ = NULL; 138 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver, 139 observers_, 140 OnWindowActivated(NULL, window)); 141 142 // ash::ActivationController will also activate the next window here; we 143 // don't do this because that's the desktop environment's job. 144 } 145 observer_manager_.Remove(window); 146 } 147 148 void DesktopActivationClient::OnWindowFocused(aura::Window* gained_focus, 149 aura::Window* lost_focus) { 150 if (gained_focus) 151 ActivateWindow(GetActivatableWindow(gained_focus)); 152 } 153 154 bool DesktopActivationClient::CanActivateWindow(aura::Window* window) const { 155 return window && 156 window->IsVisible() && 157 (!aura::client::GetActivationDelegate(window) || 158 aura::client::GetActivationDelegate(window)->ShouldActivate()); 159 } 160 161 void DesktopActivationClient::OnKeyEvent(ui::KeyEvent* event) { 162 } 163 164 void DesktopActivationClient::OnMouseEvent(ui::MouseEvent* event) { 165 if (event->type() == ui::ET_MOUSE_PRESSED) 166 FocusWindowWithEvent(event); 167 } 168 169 void DesktopActivationClient::OnScrollEvent(ui::ScrollEvent* event) { 170 } 171 172 void DesktopActivationClient::OnTouchEvent(ui::TouchEvent* event) { 173 } 174 175 void DesktopActivationClient::OnGestureEvent(ui::GestureEvent* event) { 176 if (event->type() == ui::ET_GESTURE_BEGIN && 177 event->details().touch_points() == 1) { 178 FocusWindowWithEvent(event); 179 } 180 } 181 182 void DesktopActivationClient::FocusWindowWithEvent(const ui::Event* event) { 183 aura::Window* window = static_cast<aura::Window*>(event->target()); 184 if (GetActiveWindow() != window) { 185 aura::client::GetFocusClient(window)->FocusWindow( 186 FindFocusableWindowFor(window)); 187 } 188 } 189 190 } // namespace views 191