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