shell_desktop_controller.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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 "extensions/shell/browser/shell_desktop_controller.h" 6 7#include "base/command_line.h" 8#include "content/public/browser/context_factory.h" 9#include "extensions/shell/browser/shell_app_window_controller.h" 10#include "extensions/shell/common/switches.h" 11#include "ui/aura/client/cursor_client.h" 12#include "ui/aura/client/default_capture_client.h" 13#include "ui/aura/env.h" 14#include "ui/aura/layout_manager.h" 15#include "ui/aura/test/test_screen.h" 16#include "ui/aura/window.h" 17#include "ui/aura/window_event_dispatcher.h" 18#include "ui/aura/window_tree_host.h" 19#include "ui/base/cursor/cursor.h" 20#include "ui/base/cursor/image_cursors.h" 21#include "ui/base/ime/input_method_initializer.h" 22#include "ui/gfx/native_widget_types.h" 23#include "ui/gfx/screen.h" 24#include "ui/wm/core/base_focus_rules.h" 25#include "ui/wm/core/compound_event_filter.h" 26#include "ui/wm/core/cursor_manager.h" 27#include "ui/wm/core/focus_controller.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#if defined(OS_CHROMEOS) 34#include "ui/chromeos/user_activity_power_manager_notifier.h" 35#include "ui/display/types/chromeos/display_mode.h" 36#include "ui/display/types/chromeos/display_snapshot.h" 37#endif 38 39namespace extensions { 40namespace { 41 42// A simple layout manager that makes each new window fill its parent. 43class FillLayout : public aura::LayoutManager { 44 public: 45 FillLayout() {} 46 virtual ~FillLayout() {} 47 48 private: 49 // aura::LayoutManager: 50 virtual void OnWindowResized() OVERRIDE {} 51 52 virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE { 53 if (!child->parent()) 54 return; 55 56 // Create a rect at 0,0 with the size of the parent. 57 gfx::Size parent_size = child->parent()->bounds().size(); 58 child->SetBounds(gfx::Rect(parent_size)); 59 } 60 61 virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {} 62 63 virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {} 64 65 virtual void OnChildWindowVisibilityChanged(aura::Window* child, 66 bool visible) OVERRIDE {} 67 68 virtual void SetChildBounds(aura::Window* child, 69 const gfx::Rect& requested_bounds) OVERRIDE { 70 SetChildBoundsDirect(child, requested_bounds); 71 } 72 73 DISALLOW_COPY_AND_ASSIGN(FillLayout); 74}; 75 76// A class that bridges the gap between CursorManager and Aura. It borrows 77// heavily from AshNativeCursorManager. 78class ShellNativeCursorManager : public wm::NativeCursorManager { 79 public: 80 explicit ShellNativeCursorManager(aura::WindowTreeHost* host) 81 : host_(host), image_cursors_(new ui::ImageCursors) {} 82 virtual ~ShellNativeCursorManager() {} 83 84 // wm::NativeCursorManager overrides. 85 virtual void SetDisplay(const gfx::Display& display, 86 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 87 if (image_cursors_->SetDisplay(display, display.device_scale_factor())) 88 SetCursor(delegate->GetCursor(), delegate); 89 } 90 91 virtual void SetCursor(gfx::NativeCursor cursor, 92 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 93 image_cursors_->SetPlatformCursor(&cursor); 94 cursor.set_device_scale_factor(image_cursors_->GetScale()); 95 delegate->CommitCursor(cursor); 96 97 if (delegate->IsCursorVisible()) 98 ApplyCursor(cursor); 99 } 100 101 virtual void SetVisibility( 102 bool visible, 103 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 104 delegate->CommitVisibility(visible); 105 106 if (visible) { 107 SetCursor(delegate->GetCursor(), delegate); 108 } else { 109 gfx::NativeCursor invisible_cursor(ui::kCursorNone); 110 image_cursors_->SetPlatformCursor(&invisible_cursor); 111 ApplyCursor(invisible_cursor); 112 } 113 } 114 115 virtual void SetCursorSet( 116 ui::CursorSetType cursor_set, 117 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 118 image_cursors_->SetCursorSet(cursor_set); 119 delegate->CommitCursorSet(cursor_set); 120 if (delegate->IsCursorVisible()) 121 SetCursor(delegate->GetCursor(), delegate); 122 } 123 124 virtual void SetMouseEventsEnabled( 125 bool enabled, 126 wm::NativeCursorManagerDelegate* delegate) OVERRIDE { 127 delegate->CommitMouseEventsEnabled(enabled); 128 SetVisibility(delegate->IsCursorVisible(), delegate); 129 } 130 131 private: 132 // Sets |cursor| as the active cursor within Aura. 133 void ApplyCursor(gfx::NativeCursor cursor) { host_->SetCursor(cursor); } 134 135 aura::WindowTreeHost* host_; // Not owned. 136 137 scoped_ptr<ui::ImageCursors> image_cursors_; 138 139 DISALLOW_COPY_AND_ASSIGN(ShellNativeCursorManager); 140}; 141 142class AppsFocusRules : public wm::BaseFocusRules { 143 public: 144 AppsFocusRules() {} 145 virtual ~AppsFocusRules() {} 146 147 virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE { 148 return true; 149 } 150 151 private: 152 DISALLOW_COPY_AND_ASSIGN(AppsFocusRules); 153}; 154 155ShellDesktopController* g_instance = NULL; 156 157} // namespace 158 159ShellDesktopController::ShellDesktopController() { 160#if defined(OS_CHROMEOS) 161 display_configurator_.reset(new ui::DisplayConfigurator); 162 display_configurator_->Init(false); 163 display_configurator_->ForceInitialConfigure(0); 164 display_configurator_->AddObserver(this); 165#endif 166 aura::Env::CreateInstance(true); 167 aura::Env::GetInstance()->set_context_factory(content::GetContextFactory()); 168 169 g_instance = this; 170} 171 172ShellDesktopController::~ShellDesktopController() { 173 app_window_controller_.reset(); 174 g_instance = NULL; 175 DestroyRootWindow(); 176 aura::Env::DeleteInstance(); 177} 178 179// static 180ShellDesktopController* ShellDesktopController::instance() { 181 return g_instance; 182} 183 184void ShellDesktopController::SetAppWindowController( 185 ShellAppWindowController* app_window_controller) { 186 app_window_controller_.reset(app_window_controller); 187} 188 189ShellAppWindow* ShellDesktopController::CreateAppWindow( 190 content::BrowserContext* context, 191 const Extension* extension) { 192 return app_window_controller_->CreateAppWindow(context, extension); 193} 194 195void ShellDesktopController::CloseAppWindows() { 196 if (app_window_controller_) 197 app_window_controller_->CloseAppWindows(); 198} 199 200void ShellDesktopController::SetDisplayWorkAreaInsets( 201 const gfx::Insets& insets) { 202 test_screen_->SetWorkAreaInsets(insets); 203} 204 205aura::Window* ShellDesktopController::GetDefaultParent( 206 aura::Window* context, 207 aura::Window* window, 208 const gfx::Rect& bounds) { 209 return host_->window(); 210} 211 212#if defined(OS_CHROMEOS) 213void ShellDesktopController::OnDisplayModeChanged( 214 const std::vector<ui::DisplayConfigurator::DisplayState>& displays) { 215 gfx::Size size = GetPrimaryDisplaySize(); 216 if (!size.IsEmpty()) 217 host_->UpdateRootWindowSize(size); 218} 219#endif 220 221void ShellDesktopController::OnHostCloseRequested( 222 const aura::WindowTreeHost* host) { 223 DCHECK_EQ(host_.get(), host); 224 CloseAppWindows(); 225 base::MessageLoop::current()->PostTask(FROM_HERE, 226 base::MessageLoop::QuitClosure()); 227} 228 229void ShellDesktopController::CreateRootWindow() { 230 // Set up basic pieces of ui::wm. 231 gfx::Size size; 232 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); 233 if (command_line->HasSwitch(switches::kAppShellHostWindowBounds)) { 234 const std::string size_str = 235 command_line->GetSwitchValueASCII(switches::kAppShellHostWindowBounds); 236 int width, height; 237 CHECK_EQ(2, sscanf(size_str.c_str(), "%dx%d", &width, &height)); 238 size = gfx::Size(width, height); 239 } else { 240 size = GetPrimaryDisplaySize(); 241 } 242 if (size.IsEmpty()) 243 size = gfx::Size(1280, 720); 244 245 test_screen_.reset(aura::TestScreen::Create(size)); 246 // TODO(jamescook): Replace this with a real Screen implementation. 247 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen_.get()); 248 // TODO(mukai): Set up input method. 249 250 host_.reset(test_screen_->CreateHostForPrimaryDisplay()); 251 host_->InitHost(); 252 aura::client::SetWindowTreeClient(host_->window(), this); 253 root_window_event_filter_.reset(new wm::CompoundEventFilter); 254 host_->window()->AddPreTargetHandler(root_window_event_filter_.get()); 255 InitWindowManager(); 256 257 host_->AddObserver(this); 258 259 // Ensure the X window gets mapped. 260 host_->Show(); 261} 262 263void ShellDesktopController::InitWindowManager() { 264 wm::FocusController* focus_controller = 265 new wm::FocusController(CreateFocusRules()); 266 aura::client::SetFocusClient(host_->window(), focus_controller); 267 host_->window()->AddPreTargetHandler(focus_controller); 268 aura::client::SetActivationClient(host_->window(), focus_controller); 269 focus_client_.reset(focus_controller); 270 271 input_method_filter_.reset( 272 new wm::InputMethodEventFilter(host_->GetAcceleratedWidget())); 273 input_method_filter_->SetInputMethodPropertyInRootWindow(host_->window()); 274 root_window_event_filter_->AddHandler(input_method_filter_.get()); 275 276 capture_client_.reset( 277 new aura::client::DefaultCaptureClient(host_->window())); 278 279 // Ensure new windows fill the display. 280 host_->window()->SetLayoutManager(new FillLayout); 281 282 cursor_manager_.reset( 283 new wm::CursorManager(scoped_ptr<wm::NativeCursorManager>( 284 new ShellNativeCursorManager(host_.get())))); 285 cursor_manager_->SetDisplay( 286 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay()); 287 cursor_manager_->SetCursor(ui::kCursorPointer); 288 aura::client::SetCursorClient(host_->window(), cursor_manager_.get()); 289 290 user_activity_detector_.reset(new wm::UserActivityDetector); 291 host_->event_processor()->GetRootTarget()->AddPreTargetHandler( 292 user_activity_detector_.get()); 293#if defined(OS_CHROMEOS) 294 user_activity_notifier_.reset( 295 new ui::UserActivityPowerManagerNotifier(user_activity_detector_.get())); 296#endif 297} 298 299wm::FocusRules* ShellDesktopController::CreateFocusRules() { 300 return new AppsFocusRules(); 301} 302 303void ShellDesktopController::DestroyRootWindow() { 304 host_->RemoveObserver(this); 305 if (input_method_filter_) 306 root_window_event_filter_->RemoveHandler(input_method_filter_.get()); 307 if (user_activity_detector_) { 308 host_->event_processor()->GetRootTarget()->RemovePreTargetHandler( 309 user_activity_detector_.get()); 310 } 311 wm::FocusController* focus_controller = 312 static_cast<wm::FocusController*>(focus_client_.get()); 313 if (focus_controller) { 314 host_->window()->RemovePreTargetHandler(focus_controller); 315 aura::client::SetActivationClient(host_->window(), NULL); 316 } 317 root_window_event_filter_.reset(); 318 capture_client_.reset(); 319 input_method_filter_.reset(); 320 focus_client_.reset(); 321 cursor_manager_.reset(); 322#if defined(OS_CHROMEOS) 323 user_activity_notifier_.reset(); 324#endif 325 user_activity_detector_.reset(); 326 host_.reset(); 327} 328 329gfx::Size ShellDesktopController::GetPrimaryDisplaySize() { 330#if defined(OS_CHROMEOS) 331 const std::vector<ui::DisplayConfigurator::DisplayState>& displays = 332 display_configurator_->cached_displays(); 333 if (displays.empty()) 334 return gfx::Size(); 335 const ui::DisplayMode* mode = displays[0].display->current_mode(); 336 return mode ? mode->size() : gfx::Size(); 337#else 338 return gfx::Size(); 339#endif 340} 341 342} // namespace extensions 343