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