Home | History | Annotate | Download | only in shell
      1 // Copyright (c) 2012 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 "content/shell/shell.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "content/public/browser/web_contents.h"
     10 #include "content/public/browser/web_contents_view.h"
     11 #include "ui/aura/env.h"
     12 #include "ui/aura/root_window.h"
     13 #include "ui/aura/window.h"
     14 #include "ui/base/accessibility/accessibility_types.h"
     15 #include "ui/base/clipboard/clipboard.h"
     16 #include "ui/base/events/event.h"
     17 #include "ui/base/resource/resource_bundle.h"
     18 #include "ui/gfx/screen.h"
     19 #include "ui/views/controls/button/label_button.h"
     20 #include "ui/views/controls/textfield/textfield.h"
     21 #include "ui/views/controls/textfield/textfield_controller.h"
     22 #include "ui/views/controls/webview/webview.h"
     23 #include "ui/views/layout/fill_layout.h"
     24 #include "ui/views/layout/grid_layout.h"
     25 #include "ui/views/test/desktop_test_views_delegate.h"
     26 #include "ui/views/view.h"
     27 #include "ui/views/widget/desktop_aura/desktop_screen.h"
     28 #include "ui/views/widget/widget.h"
     29 #include "ui/views/widget/widget_delegate.h"
     30 
     31 #if defined(OS_CHROMEOS)
     32 #include "chromeos/dbus/dbus_thread_manager.h"
     33 #include "content/shell/minimal_shell.h"
     34 #include "ui/aura/test/test_screen.h"
     35 #endif
     36 
     37 namespace content {
     38 
     39 namespace {
     40 // ViewDelegate implementation for aura content shell
     41 class ShellViewsDelegateAura : public views::DesktopTestViewsDelegate {
     42  public:
     43   ShellViewsDelegateAura() : use_transparent_windows_(false) {
     44   }
     45 
     46   virtual ~ShellViewsDelegateAura() {
     47   }
     48 
     49   void SetUseTransparentWindows(bool transparent) {
     50     use_transparent_windows_ = transparent;
     51   }
     52 
     53   // Overridden from views::TestViewsDelegate:
     54   virtual bool UseTransparentWindows() const OVERRIDE {
     55     return use_transparent_windows_;
     56   }
     57 
     58  private:
     59   bool use_transparent_windows_;
     60 
     61   DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura);
     62 };
     63 
     64 // Maintain the UI controls and web view for content shell
     65 class ShellWindowDelegateView : public views::WidgetDelegateView,
     66                                 public views::TextfieldController,
     67                                 public views::ButtonListener {
     68  public:
     69   enum UIControl {
     70     BACK_BUTTON,
     71     FORWARD_BUTTON,
     72     STOP_BUTTON
     73   };
     74 
     75   ShellWindowDelegateView(Shell* shell)
     76     : shell_(shell),
     77       toolbar_view_(new View),
     78       contents_view_(new View) {
     79   }
     80   virtual ~ShellWindowDelegateView() {}
     81 
     82   // Update the state of UI controls
     83   void SetAddressBarURL(const GURL& url) {
     84     url_entry_->SetText(ASCIIToUTF16(url.spec()));
     85   }
     86   void SetWebContents(WebContents* web_contents) {
     87     contents_view_->SetLayoutManager(new views::FillLayout());
     88     web_view_ = new views::WebView(web_contents->GetBrowserContext());
     89     web_view_->SetWebContents(web_contents);
     90     web_contents->GetView()->Focus();
     91     contents_view_->AddChildView(web_view_);
     92     Layout();
     93   }
     94   void SetWindowTitle(const string16& title) { title_ = title; }
     95   void EnableUIControl(UIControl control, bool is_enabled) {
     96     if (control == BACK_BUTTON) {
     97       back_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
     98           : views::CustomButton::STATE_DISABLED);
     99     } else if (control == FORWARD_BUTTON) {
    100       forward_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
    101           : views::CustomButton::STATE_DISABLED);
    102     } else if (control == STOP_BUTTON) {
    103       stop_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
    104           : views::CustomButton::STATE_DISABLED);
    105     }
    106   }
    107 
    108  private:
    109   // Initialize the UI control contained in shell window
    110   void InitShellWindow() {
    111     set_background(views::Background::CreateStandardPanelBackground());
    112 
    113     views::GridLayout* layout = new views::GridLayout(this);
    114     SetLayoutManager(layout);
    115 
    116     views::ColumnSet* column_set = layout->AddColumnSet(0);
    117     column_set->AddPaddingColumn(0, 2);
    118     column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
    119                           views::GridLayout::USE_PREF, 0, 0);
    120     column_set->AddPaddingColumn(0, 2);
    121 
    122     layout->AddPaddingRow(0, 2);
    123 
    124     // Add toolbar buttons and URL text field
    125     {
    126       layout->StartRow(0, 0);
    127       views::GridLayout* toolbar_layout = new views::GridLayout(toolbar_view_);
    128       toolbar_view_->SetLayoutManager(toolbar_layout);
    129 
    130       views::ColumnSet* toolbar_column_set =
    131           toolbar_layout->AddColumnSet(0);
    132       // Back button
    133       back_button_ = new views::LabelButton(this, ASCIIToUTF16("Back"));
    134       back_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
    135       gfx::Size back_button_size = back_button_->GetPreferredSize();
    136       toolbar_column_set->AddColumn(views::GridLayout::CENTER,
    137                                     views::GridLayout::CENTER, 0,
    138                                     views::GridLayout::FIXED,
    139                                     back_button_size.width(),
    140                                     back_button_size.width() / 2);
    141       // Forward button
    142       forward_button_ = new views::LabelButton(this, ASCIIToUTF16("Forward"));
    143       forward_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
    144       gfx::Size forward_button_size = forward_button_->GetPreferredSize();
    145       toolbar_column_set->AddColumn(views::GridLayout::CENTER,
    146                                     views::GridLayout::CENTER, 0,
    147                                     views::GridLayout::FIXED,
    148                                     forward_button_size.width(),
    149                                     forward_button_size.width() / 2);
    150       // Refresh button
    151       refresh_button_ = new views::LabelButton(this, ASCIIToUTF16("Refresh"));
    152       refresh_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
    153       gfx::Size refresh_button_size = refresh_button_->GetPreferredSize();
    154       toolbar_column_set->AddColumn(views::GridLayout::CENTER,
    155                                     views::GridLayout::CENTER, 0,
    156                                     views::GridLayout::FIXED,
    157                                     refresh_button_size.width(),
    158                                     refresh_button_size.width() / 2);
    159       // Stop button
    160       stop_button_ = new views::LabelButton(this, ASCIIToUTF16("Stop"));
    161       stop_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
    162       gfx::Size stop_button_size = stop_button_->GetPreferredSize();
    163       toolbar_column_set->AddColumn(views::GridLayout::CENTER,
    164                                     views::GridLayout::CENTER, 0,
    165                                     views::GridLayout::FIXED,
    166                                     stop_button_size.width(),
    167                                     stop_button_size.width() / 2);
    168       toolbar_column_set->AddPaddingColumn(0, 2);
    169       // URL entry
    170       url_entry_ = new views::Textfield();
    171       url_entry_->SetController(this);
    172       toolbar_column_set->AddColumn(views::GridLayout::FILL,
    173                                     views::GridLayout::FILL, 1,
    174                                     views::GridLayout::USE_PREF, 0, 0);
    175 
    176       // Fill up the first row
    177       toolbar_layout->StartRow(0, 0);
    178       toolbar_layout->AddView(back_button_);
    179       toolbar_layout->AddView(forward_button_);
    180       toolbar_layout->AddView(refresh_button_);
    181       toolbar_layout->AddView(stop_button_);
    182       toolbar_layout->AddView(url_entry_);
    183 
    184       layout->AddView(toolbar_view_);
    185     }
    186 
    187     layout->AddPaddingRow(0, 5);
    188 
    189     // Add web contents view as the second row
    190     {
    191       layout->StartRow(1, 0);
    192       layout->AddView(contents_view_);
    193     }
    194 
    195     layout->AddPaddingRow(0, 5);
    196   }
    197   // Overridden from TextfieldController
    198   virtual void ContentsChanged(views::Textfield* sender,
    199                                const string16& new_contents) OVERRIDE {
    200   }
    201   virtual bool HandleKeyEvent(views::Textfield* sender,
    202                               const ui::KeyEvent& key_event) OVERRIDE {
    203    if (sender == url_entry_ && key_event.key_code() == ui::VKEY_RETURN) {
    204      std::string text = UTF16ToUTF8(url_entry_->text());
    205      GURL url(text);
    206      if (!url.has_scheme()) {
    207        url = GURL(std::string("http://") + std::string(text));
    208        url_entry_->SetText(ASCIIToUTF16(url.spec()));
    209      }
    210      shell_->LoadURL(url);
    211      return true;
    212    }
    213    return false;
    214   }
    215 
    216   // Overridden from ButtonListener
    217   virtual void ButtonPressed(views::Button* sender,
    218                              const ui::Event& event) OVERRIDE {
    219     if (sender == back_button_)
    220       shell_->GoBackOrForward(-1);
    221     else if (sender == forward_button_)
    222       shell_->GoBackOrForward(1);
    223     else if (sender == refresh_button_)
    224       shell_->Reload();
    225     else if (sender == stop_button_)
    226       shell_->Stop();
    227   }
    228 
    229   // Overridden from WidgetDelegateView
    230   virtual bool CanResize() const OVERRIDE { return true; }
    231   virtual bool CanMaximize() const OVERRIDE { return true; }
    232   virtual string16 GetWindowTitle() const OVERRIDE {
    233     return title_;
    234   }
    235   virtual void WindowClosing() OVERRIDE {
    236     if (shell_) {
    237       delete shell_;
    238       shell_ = NULL;
    239     }
    240   }
    241   virtual View* GetContentsView() OVERRIDE { return this; }
    242 
    243   // Overridden from View
    244   virtual void ViewHierarchyChanged(
    245       const ViewHierarchyChangedDetails& details) OVERRIDE {
    246     if (details.is_add && details.child == this) {
    247       InitShellWindow();
    248     }
    249   }
    250 
    251  private:
    252   // Hold a reference of Shell for deleting it when the window is closing
    253   Shell* shell_;
    254 
    255   // Window title
    256   string16 title_;
    257 
    258   // Toolbar view contains forward/backward/reload button and URL entry
    259   View* toolbar_view_;
    260   views::LabelButton* back_button_;
    261   views::LabelButton* forward_button_;
    262   views::LabelButton* refresh_button_;
    263   views::LabelButton* stop_button_;
    264   views::Textfield* url_entry_;
    265 
    266   // Contents view contains the web contents view
    267   View* contents_view_;
    268   views::WebView* web_view_;
    269 
    270   DISALLOW_COPY_AND_ASSIGN(ShellWindowDelegateView);
    271 };
    272 
    273 }  // namespace
    274 
    275 #if defined(OS_CHROMEOS)
    276 MinimalShell* Shell::minimal_shell_ = NULL;
    277 #endif
    278 views::ViewsDelegate* Shell::views_delegate_ = NULL;
    279 
    280 // static
    281 void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
    282 #if defined(OS_CHROMEOS)
    283   chromeos::DBusThreadManager::Initialize();
    284   gfx::Screen::SetScreenInstance(
    285       gfx::SCREEN_TYPE_NATIVE, aura::TestScreen::Create());
    286   minimal_shell_ = new content::MinimalShell(default_window_size);
    287 #else
    288   gfx::Screen::SetScreenInstance(
    289       gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
    290 #endif
    291   views_delegate_ = new ShellViewsDelegateAura();
    292 }
    293 
    294 void Shell::PlatformExit() {
    295 #if defined(OS_CHROMEOS)
    296   if (minimal_shell_)
    297     delete minimal_shell_;
    298 #endif
    299   if (views_delegate_)
    300     delete views_delegate_;
    301 #if defined(OS_CHROMEOS)
    302   chromeos::DBusThreadManager::Shutdown();
    303 #endif
    304   aura::Env::DeleteInstance();
    305 }
    306 
    307 void Shell::PlatformCleanUp() {
    308 }
    309 
    310 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
    311   ShellWindowDelegateView* delegate_view =
    312     static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
    313   if (control == BACK_BUTTON) {
    314     delegate_view->EnableUIControl(ShellWindowDelegateView::BACK_BUTTON,
    315         is_enabled);
    316   } else if (control == FORWARD_BUTTON) {
    317     delegate_view->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON,
    318         is_enabled);
    319   } else if (control == STOP_BUTTON) {
    320     delegate_view->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON,
    321         is_enabled);
    322   }
    323 }
    324 
    325 void Shell::PlatformSetAddressBarURL(const GURL& url) {
    326   ShellWindowDelegateView* delegate_view =
    327     static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
    328   delegate_view->SetAddressBarURL(url);
    329 }
    330 
    331 void Shell::PlatformSetIsLoading(bool loading) {
    332 }
    333 
    334 void Shell::PlatformCreateWindow(int width, int height) {
    335 #if defined(OS_CHROMEOS)
    336   window_widget_ =
    337       views::Widget::CreateWindowWithContextAndBounds(
    338           new ShellWindowDelegateView(this),
    339           minimal_shell_->GetDefaultParent(NULL, NULL, gfx::Rect()),
    340           gfx::Rect(0, 0, width, height));
    341 #else
    342   window_widget_ =
    343       views::Widget::CreateWindowWithBounds(new ShellWindowDelegateView(this),
    344                gfx::Rect(0, 0, width, height));
    345 #endif
    346 
    347   window_ = window_widget_->GetNativeWindow();
    348   // Call ShowRootWindow on RootWindow created by MinimalShell without
    349   // which XWindow owned by RootWindow doesn't get mapped.
    350   window_->GetRootWindow()->ShowRootWindow();
    351   window_widget_->Show();
    352 }
    353 
    354 void Shell::PlatformSetContents() {
    355   ShellWindowDelegateView* delegate_view =
    356     static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
    357   delegate_view->SetWebContents(web_contents_.get());
    358 }
    359 
    360 void Shell::PlatformResizeSubViews() {
    361 }
    362 
    363 void Shell::Close() {
    364   window_widget_->Close();
    365 }
    366 
    367 void Shell::PlatformSetTitle(const string16& title) {
    368   ShellWindowDelegateView* delegate_view =
    369     static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
    370   delegate_view->SetWindowTitle(title);
    371   window_widget_->UpdateWindowTitle();
    372 }
    373 
    374 }  // namespace content
    375