1 // Copyright 2014 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 "athena/env/public/athena_env.h" 6 7 #include <vector> 8 9 #include "athena/util/fill_layout_manager.h" 10 #include "base/sys_info.h" 11 #include "ui/aura/client/aura_constants.h" 12 #include "ui/aura/client/cursor_client.h" 13 #include "ui/aura/client/default_capture_client.h" 14 #include "ui/aura/env.h" 15 #include "ui/aura/test/test_screen.h" 16 #include "ui/aura/window_event_dispatcher.h" 17 #include "ui/aura/window_tree_host.h" 18 #include "ui/aura/window_tree_host_observer.h" 19 #include "ui/base/cursor/cursor.h" 20 #include "ui/base/cursor/image_cursors.h" 21 #include "ui/chromeos/user_activity_power_manager_notifier.h" 22 #include "ui/display/chromeos/display_configurator.h" 23 #include "ui/display/types/display_mode.h" 24 #include "ui/display/types/display_snapshot.h" 25 #include "ui/gfx/screen.h" 26 #include "ui/wm/core/compound_event_filter.h" 27 #include "ui/wm/core/cursor_manager.h" 28 #include "ui/wm/core/input_method_event_filter.h" 29 #include "ui/wm/core/native_cursor_manager.h" 30 #include "ui/wm/core/native_cursor_manager_delegate.h" 31 #include "ui/wm/core/user_activity_detector.h" 32 33 namespace athena { 34 35 namespace { 36 37 AthenaEnv* instance = NULL; 38 39 // Screen object used during shutdown. 40 gfx::Screen* screen_for_shutdown = NULL; 41 42 // TODO(flackr:oshima): Remove this once athena switches to share 43 // ash::DisplayManager. 44 class ScreenForShutdown : public gfx::Screen { 45 public: 46 // Creates and sets the screen for shutdown. Deletes existing one if any. 47 static void Create(const gfx::Screen* screen) { 48 delete screen_for_shutdown; 49 screen_for_shutdown = new ScreenForShutdown(screen->GetPrimaryDisplay()); 50 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, 51 screen_for_shutdown); 52 } 53 54 private: 55 explicit ScreenForShutdown(const gfx::Display& primary_display) 56 : primary_display_(primary_display) {} 57 58 // gfx::Screen overrides: 59 virtual bool IsDIPEnabled() OVERRIDE { return true; } 60 virtual gfx::Point GetCursorScreenPoint() OVERRIDE { return gfx::Point(); } 61 virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { return NULL; } 62 virtual gfx::NativeWindow GetWindowAtScreenPoint( 63 const gfx::Point& point) OVERRIDE { 64 return NULL; 65 } 66 virtual int GetNumDisplays() const OVERRIDE { return 1; } 67 virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { 68 std::vector<gfx::Display> displays(1, primary_display_); 69 return displays; 70 } 71 virtual gfx::Display GetDisplayNearestWindow( 72 gfx::NativeView view) const OVERRIDE { 73 return primary_display_; 74 } 75 virtual gfx::Display GetDisplayNearestPoint( 76 const gfx::Point& point) const OVERRIDE { 77 return primary_display_; 78 } 79 virtual gfx::Display GetDisplayMatching( 80 const gfx::Rect& match_rect) const OVERRIDE { 81 return primary_display_; 82 } 83 virtual gfx::Display GetPrimaryDisplay() const OVERRIDE { 84 return primary_display_; 85 } 86 virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE { 87 NOTREACHED() << "Observer should not be added during shutdown"; 88 } 89 virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE {} 90 91 const gfx::Display primary_display_; 92 93 DISALLOW_COPY_AND_ASSIGN(ScreenForShutdown); 94 }; 95 96 // A class that bridges the gap between CursorManager and Aura. It borrows 97 // heavily from AshNativeCursorManager. 98 class AthenaNativeCursorManager : public wm::NativeCursorManager { 99 public: 100 explicit AthenaNativeCursorManager(aura::WindowTreeHost* host) 101 : host_(host), image_cursors_(new ui::ImageCursors) {} 102 virtual ~AthenaNativeCursorManager() {} 103 104 // wm::NativeCursorManager overrides. 105 virtual void SetDisplay(const gfx::Display& display, 106 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 107 if (image_cursors_->SetDisplay(display, display.device_scale_factor())) 108 SetCursor(delegate->GetCursor(), delegate); 109 } 110 111 virtual void SetCursor(gfx::NativeCursor cursor, 112 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 113 image_cursors_->SetPlatformCursor(&cursor); 114 cursor.set_device_scale_factor(image_cursors_->GetScale()); 115 delegate->CommitCursor(cursor); 116 117 if (delegate->IsCursorVisible()) 118 ApplyCursor(cursor); 119 } 120 121 virtual void SetVisibility( 122 bool visible, 123 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 124 delegate->CommitVisibility(visible); 125 126 if (visible) { 127 SetCursor(delegate->GetCursor(), delegate); 128 } else { 129 gfx::NativeCursor invisible_cursor(ui::kCursorNone); 130 image_cursors_->SetPlatformCursor(&invisible_cursor); 131 ApplyCursor(invisible_cursor); 132 } 133 } 134 135 virtual void SetCursorSet( 136 ui::CursorSetType cursor_set, 137 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 138 image_cursors_->SetCursorSet(cursor_set); 139 delegate->CommitCursorSet(cursor_set); 140 if (delegate->IsCursorVisible()) 141 SetCursor(delegate->GetCursor(), delegate); 142 } 143 144 virtual void SetMouseEventsEnabled( 145 bool enabled, 146 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 147 delegate->CommitMouseEventsEnabled(enabled); 148 SetVisibility(delegate->IsCursorVisible(), delegate); 149 } 150 151 private: 152 // Sets |cursor| as the active cursor within Aura. 153 void ApplyCursor(gfx::NativeCursor cursor) { host_->SetCursor(cursor); } 154 155 aura::WindowTreeHost* host_; // Not owned. 156 157 scoped_ptr<ui::ImageCursors> image_cursors_; 158 159 DISALLOW_COPY_AND_ASSIGN(AthenaNativeCursorManager); 160 }; 161 162 class AthenaEnvImpl : public AthenaEnv, 163 public aura::WindowTreeHostObserver, 164 public ui::DisplayConfigurator::Observer { 165 public: 166 AthenaEnvImpl() : display_configurator_(new ui::DisplayConfigurator) { 167 display_configurator_->Init(false); 168 display_configurator_->ForceInitialConfigure(0); 169 display_configurator_->AddObserver(this); 170 171 gfx::Size screen_size = GetPrimaryDisplaySize(); 172 if (screen_size.IsEmpty()) { 173 // TODO(oshima): Remove this hack. 174 if (base::SysInfo::IsRunningOnChromeOS()) 175 screen_size.SetSize(2560, 1600); 176 else 177 screen_size.SetSize(1280, 720); 178 } 179 screen_.reset(aura::TestScreen::Create(screen_size)); 180 181 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get()); 182 host_.reset(screen_->CreateHostForPrimaryDisplay()); 183 host_->InitHost(); 184 185 aura::Window* root_window = GetHost()->window(); 186 input_method_filter_.reset( 187 new wm::InputMethodEventFilter(host_->GetAcceleratedWidget())); 188 input_method_filter_->SetInputMethodPropertyInRootWindow(root_window); 189 190 root_window_event_filter_.reset(new wm::CompoundEventFilter); 191 host_->window()->AddPreTargetHandler(root_window_event_filter_.get()); 192 193 input_method_filter_.reset( 194 new wm::InputMethodEventFilter(host_->GetAcceleratedWidget())); 195 input_method_filter_->SetInputMethodPropertyInRootWindow(host_->window()); 196 root_window_event_filter_->AddHandler(input_method_filter_.get()); 197 198 capture_client_.reset( 199 new aura::client::DefaultCaptureClient(host_->window())); 200 201 // Ensure new windows fill the display. 202 root_window->SetLayoutManager(new FillLayoutManager(root_window)); 203 204 cursor_manager_.reset( 205 new wm::CursorManager(scoped_ptr<wm::NativeCursorManager>( 206 new AthenaNativeCursorManager(host_.get())))); 207 cursor_manager_->SetDisplay( 208 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay()); 209 cursor_manager_->SetCursor(ui::kCursorPointer); 210 aura::client::SetCursorClient(host_->window(), cursor_manager_.get()); 211 212 user_activity_detector_.reset(new wm::UserActivityDetector); 213 host_->event_processor()->GetRootTarget()->AddPreTargetHandler( 214 user_activity_detector_.get()); 215 user_activity_notifier_.reset(new ui::UserActivityPowerManagerNotifier( 216 user_activity_detector_.get())); 217 218 host_->AddObserver(this); 219 host_->Show(); 220 221 DCHECK(!instance); 222 instance = this; 223 } 224 225 virtual ~AthenaEnvImpl() { 226 instance = NULL; 227 228 host_->RemoveObserver(this); 229 if (input_method_filter_) 230 root_window_event_filter_->RemoveHandler(input_method_filter_.get()); 231 if (user_activity_detector_) { 232 host_->event_processor()->GetRootTarget()->RemovePreTargetHandler( 233 user_activity_detector_.get()); 234 } 235 root_window_event_filter_.reset(); 236 capture_client_.reset(); 237 input_method_filter_.reset(); 238 cursor_manager_.reset(); 239 user_activity_notifier_.reset(); 240 user_activity_detector_.reset(); 241 242 input_method_filter_.reset(); 243 host_.reset(); 244 245 ScreenForShutdown::Create(screen_.get()); 246 screen_.reset(); 247 aura::Env::DeleteInstance(); 248 249 display_configurator_->RemoveObserver(this); 250 display_configurator_.reset(); 251 } 252 253 private: 254 struct Finder { 255 explicit Finder(const base::Closure& c) : closure(c) {} 256 bool operator()(const base::Closure& other) { 257 return closure.Equals(other); 258 } 259 base::Closure closure; 260 }; 261 262 // AthenaEnv: 263 virtual aura::WindowTreeHost* GetHost() OVERRIDE { return host_.get(); } 264 265 virtual void SetDisplayWorkAreaInsets(const gfx::Insets& insets) OVERRIDE { 266 screen_->SetWorkAreaInsets(insets); 267 } 268 269 virtual void AddTerminatingCallback(const base::Closure& closure) OVERRIDE { 270 if (closure.is_null()) 271 return; 272 DCHECK(terminating_callbacks_.end() == 273 std::find_if(terminating_callbacks_.begin(), 274 terminating_callbacks_.end(), 275 Finder(closure))); 276 terminating_callbacks_.push_back(closure); 277 } 278 279 virtual void RemoveTerminatingCallback( 280 const base::Closure& closure) OVERRIDE { 281 std::vector<base::Closure>::iterator iter = 282 std::find_if(terminating_callbacks_.begin(), 283 terminating_callbacks_.end(), 284 Finder(closure)); 285 if (iter != terminating_callbacks_.end()) 286 terminating_callbacks_.erase(iter); 287 } 288 289 virtual void OnTerminating() OVERRIDE { 290 for (std::vector<base::Closure>::iterator iter = 291 terminating_callbacks_.begin(); 292 iter != terminating_callbacks_.end(); 293 ++iter) { 294 iter->Run(); 295 } 296 } 297 298 // ui::DisplayConfigurator::Observer: 299 virtual void OnDisplayModeChanged(const std::vector< 300 ui::DisplayConfigurator::DisplayState>& displays) OVERRIDE { 301 gfx::Size size = GetPrimaryDisplaySize(); 302 if (!size.IsEmpty()) 303 host_->UpdateRootWindowSize(size); 304 } 305 306 // aura::WindowTreeHostObserver: 307 virtual void OnHostCloseRequested(const aura::WindowTreeHost* host) OVERRIDE { 308 base::MessageLoopForUI::current()->PostTask( 309 FROM_HERE, base::MessageLoop::QuitClosure()); 310 } 311 312 gfx::Size GetPrimaryDisplaySize() const { 313 const std::vector<ui::DisplayConfigurator::DisplayState>& displays = 314 display_configurator_->cached_displays(); 315 if (displays.empty()) 316 return gfx::Size(); 317 const ui::DisplayMode* mode = displays[0].display->current_mode(); 318 return mode ? mode->size() : gfx::Size(); 319 } 320 321 scoped_ptr<aura::TestScreen> screen_; 322 scoped_ptr<aura::WindowTreeHost> host_; 323 324 scoped_ptr<wm::InputMethodEventFilter> input_method_filter_; 325 scoped_ptr<wm::CompoundEventFilter> root_window_event_filter_; 326 scoped_ptr<aura::client::DefaultCaptureClient> capture_client_; 327 scoped_ptr<wm::CursorManager> cursor_manager_; 328 scoped_ptr<wm::UserActivityDetector> user_activity_detector_; 329 scoped_ptr<ui::DisplayConfigurator> display_configurator_; 330 scoped_ptr<ui::UserActivityPowerManagerNotifier> user_activity_notifier_; 331 332 std::vector<base::Closure> terminating_callbacks_; 333 334 DISALLOW_COPY_AND_ASSIGN(AthenaEnvImpl); 335 }; 336 337 } // namespace 338 339 // static 340 void AthenaEnv::Create() { 341 DCHECK(!instance); 342 new AthenaEnvImpl(); 343 } 344 345 AthenaEnv* AthenaEnv::Get() { 346 DCHECK(instance); 347 return instance; 348 } 349 350 // static 351 352 // static 353 void AthenaEnv::Shutdown() { 354 DCHECK(instance); 355 delete instance; 356 } 357 358 } // namespace athena 359