Home | History | Annotate | Download | only in browser
      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