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.
5 #include "content/shell/browser/shell.h"
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/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"
31 #if defined(OS_CHROMEOS)
32 #include "chromeos/dbus/dbus_thread_manager.h"
33 #include "ui/aura/test/test_screen.h"
34 #include "ui/shell/minimal_shell.h"
45 // ViewDelegate implementation for aura content shell
46 class ShellViewsDelegateAura
: public views::DesktopTestViewsDelegate
{
48 ShellViewsDelegateAura() : use_transparent_windows_(false) {
51 virtual ~ShellViewsDelegateAura() {
54 void SetUseTransparentWindows(bool transparent
) {
55 use_transparent_windows_
= transparent
;
58 // Overridden from views::TestViewsDelegate:
59 virtual bool UseTransparentWindows() const OVERRIDE
{
60 return use_transparent_windows_
;
64 bool use_transparent_windows_
;
66 DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura
);
69 // Maintain the UI controls and web view for content shell
70 class ShellWindowDelegateView
: public views::WidgetDelegateView
,
71 public views::TextfieldController
,
72 public views::ButtonListener
{
80 ShellWindowDelegateView(Shell
* shell
)
82 toolbar_view_(new View
),
83 contents_view_(new View
) {
85 virtual ~ShellWindowDelegateView() {}
87 // Update the state of UI controls
88 void SetAddressBarURL(const GURL
& url
) {
89 url_entry_
->SetText(ASCIIToUTF16(url
.spec()));
91 void SetWebContents(WebContents
* web_contents
) {
92 contents_view_
->SetLayoutManager(new views::FillLayout());
93 web_view_
= new views::WebView(web_contents
->GetBrowserContext());
94 web_view_
->SetWebContents(web_contents
);
95 web_contents
->GetView()->Focus();
96 contents_view_
->AddChildView(web_view_
);
99 void SetWindowTitle(const string16
& title
) { title_
= title
; }
100 void EnableUIControl(UIControl control
, bool is_enabled
) {
101 if (control
== BACK_BUTTON
) {
102 back_button_
->SetState(is_enabled
? views::CustomButton::STATE_NORMAL
103 : views::CustomButton::STATE_DISABLED
);
104 } else if (control
== FORWARD_BUTTON
) {
105 forward_button_
->SetState(is_enabled
? views::CustomButton::STATE_NORMAL
106 : views::CustomButton::STATE_DISABLED
);
107 } else if (control
== STOP_BUTTON
) {
108 stop_button_
->SetState(is_enabled
? views::CustomButton::STATE_NORMAL
109 : views::CustomButton::STATE_DISABLED
);
114 // Initialize the UI control contained in shell window
115 void InitShellWindow() {
116 set_background(views::Background::CreateStandardPanelBackground());
118 views::GridLayout
* layout
= new views::GridLayout(this);
119 SetLayoutManager(layout
);
121 views::ColumnSet
* column_set
= layout
->AddColumnSet(0);
122 column_set
->AddPaddingColumn(0, 2);
123 column_set
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 1,
124 views::GridLayout::USE_PREF
, 0, 0);
125 column_set
->AddPaddingColumn(0, 2);
127 layout
->AddPaddingRow(0, 2);
129 // Add toolbar buttons and URL text field
131 layout
->StartRow(0, 0);
132 views::GridLayout
* toolbar_layout
= new views::GridLayout(toolbar_view_
);
133 toolbar_view_
->SetLayoutManager(toolbar_layout
);
135 views::ColumnSet
* toolbar_column_set
=
136 toolbar_layout
->AddColumnSet(0);
138 back_button_
= new views::LabelButton(this, ASCIIToUTF16("Back"));
139 back_button_
->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON
);
140 gfx::Size back_button_size
= back_button_
->GetPreferredSize();
141 toolbar_column_set
->AddColumn(views::GridLayout::CENTER
,
142 views::GridLayout::CENTER
, 0,
143 views::GridLayout::FIXED
,
144 back_button_size
.width(),
145 back_button_size
.width() / 2);
147 forward_button_
= new views::LabelButton(this, ASCIIToUTF16("Forward"));
148 forward_button_
->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON
);
149 gfx::Size forward_button_size
= forward_button_
->GetPreferredSize();
150 toolbar_column_set
->AddColumn(views::GridLayout::CENTER
,
151 views::GridLayout::CENTER
, 0,
152 views::GridLayout::FIXED
,
153 forward_button_size
.width(),
154 forward_button_size
.width() / 2);
156 refresh_button_
= new views::LabelButton(this, ASCIIToUTF16("Refresh"));
157 refresh_button_
->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON
);
158 gfx::Size refresh_button_size
= refresh_button_
->GetPreferredSize();
159 toolbar_column_set
->AddColumn(views::GridLayout::CENTER
,
160 views::GridLayout::CENTER
, 0,
161 views::GridLayout::FIXED
,
162 refresh_button_size
.width(),
163 refresh_button_size
.width() / 2);
165 stop_button_
= new views::LabelButton(this, ASCIIToUTF16("Stop"));
166 stop_button_
->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON
);
167 gfx::Size stop_button_size
= stop_button_
->GetPreferredSize();
168 toolbar_column_set
->AddColumn(views::GridLayout::CENTER
,
169 views::GridLayout::CENTER
, 0,
170 views::GridLayout::FIXED
,
171 stop_button_size
.width(),
172 stop_button_size
.width() / 2);
173 toolbar_column_set
->AddPaddingColumn(0, 2);
175 url_entry_
= new views::Textfield();
176 url_entry_
->SetController(this);
177 toolbar_column_set
->AddColumn(views::GridLayout::FILL
,
178 views::GridLayout::FILL
, 1,
179 views::GridLayout::USE_PREF
, 0, 0);
181 // Fill up the first row
182 toolbar_layout
->StartRow(0, 0);
183 toolbar_layout
->AddView(back_button_
);
184 toolbar_layout
->AddView(forward_button_
);
185 toolbar_layout
->AddView(refresh_button_
);
186 toolbar_layout
->AddView(stop_button_
);
187 toolbar_layout
->AddView(url_entry_
);
189 layout
->AddView(toolbar_view_
);
192 layout
->AddPaddingRow(0, 5);
194 // Add web contents view as the second row
196 layout
->StartRow(1, 0);
197 layout
->AddView(contents_view_
);
200 layout
->AddPaddingRow(0, 5);
202 // Overridden from TextfieldController
203 virtual void ContentsChanged(views::Textfield
* sender
,
204 const string16
& new_contents
) OVERRIDE
{
206 virtual bool HandleKeyEvent(views::Textfield
* sender
,
207 const ui::KeyEvent
& key_event
) OVERRIDE
{
208 if (sender
== url_entry_
&& key_event
.key_code() == ui::VKEY_RETURN
) {
209 std::string text
= UTF16ToUTF8(url_entry_
->text());
211 if (!url
.has_scheme()) {
212 url
= GURL(std::string("http://") + std::string(text
));
213 url_entry_
->SetText(ASCIIToUTF16(url
.spec()));
215 shell_
->LoadURL(url
);
221 // Overridden from ButtonListener
222 virtual void ButtonPressed(views::Button
* sender
,
223 const ui::Event
& event
) OVERRIDE
{
224 if (sender
== back_button_
)
225 shell_
->GoBackOrForward(-1);
226 else if (sender
== forward_button_
)
227 shell_
->GoBackOrForward(1);
228 else if (sender
== refresh_button_
)
230 else if (sender
== stop_button_
)
234 // Overridden from WidgetDelegateView
235 virtual bool CanResize() const OVERRIDE
{ return true; }
236 virtual bool CanMaximize() const OVERRIDE
{ return true; }
237 virtual string16
GetWindowTitle() const OVERRIDE
{
240 virtual void WindowClosing() OVERRIDE
{
246 virtual View
* GetContentsView() OVERRIDE
{ return this; }
248 // Overridden from View
249 virtual void ViewHierarchyChanged(
250 const ViewHierarchyChangedDetails
& details
) OVERRIDE
{
251 if (details
.is_add
&& details
.child
== this) {
257 // Hold a reference of Shell for deleting it when the window is closing
263 // Toolbar view contains forward/backward/reload button and URL entry
265 views::LabelButton
* back_button_
;
266 views::LabelButton
* forward_button_
;
267 views::LabelButton
* refresh_button_
;
268 views::LabelButton
* stop_button_
;
269 views::Textfield
* url_entry_
;
271 // Contents view contains the web contents view
272 View
* contents_view_
;
273 views::WebView
* web_view_
;
275 DISALLOW_COPY_AND_ASSIGN(ShellWindowDelegateView
);
280 #if defined(OS_CHROMEOS)
281 shell::MinimalShell
* Shell::minimal_shell_
= NULL
;
283 views::ViewsDelegate
* Shell::views_delegate_
= NULL
;
286 void Shell::PlatformInitialize(const gfx::Size
& default_window_size
) {
288 _setmode(_fileno(stdout
), _O_BINARY
);
289 _setmode(_fileno(stderr
), _O_BINARY
);
291 #if defined(OS_CHROMEOS)
292 chromeos::DBusThreadManager::Initialize();
293 gfx::Screen::SetScreenInstance(
294 gfx::SCREEN_TYPE_NATIVE
, aura::TestScreen::Create());
295 minimal_shell_
= new shell::MinimalShell(default_window_size
);
297 gfx::Screen::SetScreenInstance(
298 gfx::SCREEN_TYPE_NATIVE
, views::CreateDesktopScreen());
300 views_delegate_
= new ShellViewsDelegateAura();
303 void Shell::PlatformExit() {
304 std::vector
<Shell
*> windows
= windows_
;
305 for (std::vector
<Shell
*>::iterator it
= windows
.begin();
306 it
!= windows
.end(); ++it
) {
307 (*it
)->window_widget_
->Close();
309 #if defined(OS_CHROMEOS)
311 delete minimal_shell_
;
314 delete views_delegate_
;
315 #if defined(OS_CHROMEOS)
316 chromeos::DBusThreadManager::Shutdown();
318 aura::Env::DeleteInstance();
321 void Shell::PlatformCleanUp() {
324 void Shell::PlatformEnableUIControl(UIControl control
, bool is_enabled
) {
325 ShellWindowDelegateView
* delegate_view
=
326 static_cast<ShellWindowDelegateView
*>(window_widget_
->widget_delegate());
327 if (control
== BACK_BUTTON
) {
328 delegate_view
->EnableUIControl(ShellWindowDelegateView::BACK_BUTTON
,
330 } else if (control
== FORWARD_BUTTON
) {
331 delegate_view
->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON
,
333 } else if (control
== STOP_BUTTON
) {
334 delegate_view
->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON
,
339 void Shell::PlatformSetAddressBarURL(const GURL
& url
) {
340 ShellWindowDelegateView
* delegate_view
=
341 static_cast<ShellWindowDelegateView
*>(window_widget_
->widget_delegate());
342 delegate_view
->SetAddressBarURL(url
);
345 void Shell::PlatformSetIsLoading(bool loading
) {
348 void Shell::PlatformCreateWindow(int width
, int height
) {
349 #if defined(OS_CHROMEOS)
351 views::Widget::CreateWindowWithContextAndBounds(
352 new ShellWindowDelegateView(this),
353 minimal_shell_
->GetDefaultParent(NULL
, NULL
, gfx::Rect()),
354 gfx::Rect(0, 0, width
, height
));
357 views::Widget::CreateWindowWithBounds(new ShellWindowDelegateView(this),
358 gfx::Rect(0, 0, width
, height
));
361 window_
= window_widget_
->GetNativeWindow();
362 // Call ShowRootWindow on RootWindow created by MinimalShell without
363 // which XWindow owned by RootWindow doesn't get mapped.
364 window_
->GetRootWindow()->ShowRootWindow();
365 window_widget_
->Show();
368 void Shell::PlatformSetContents() {
369 ShellWindowDelegateView
* delegate_view
=
370 static_cast<ShellWindowDelegateView
*>(window_widget_
->widget_delegate());
371 delegate_view
->SetWebContents(web_contents_
.get());
374 void Shell::PlatformResizeSubViews() {
377 void Shell::Close() {
378 window_widget_
->CloseNow();
381 void Shell::PlatformSetTitle(const string16
& title
) {
382 ShellWindowDelegateView
* delegate_view
=
383 static_cast<ShellWindowDelegateView
*>(window_widget_
->widget_delegate());
384 delegate_view
->SetWindowTitle(title
);
385 window_widget_
->UpdateWindowTitle();
388 } // namespace content