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