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.
5 #include "content/shell/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/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"
31 #if defined(OS_CHROMEOS)
32 #include "chromeos/dbus/dbus_thread_manager.h"
33 #include "content/shell/minimal_ash.h"
34 #include "ui/aura/test/test_screen.h"
40 // ViewDelegate implementation for aura content shell
41 class ShellViewsDelegateAura
: public views::DesktopTestViewsDelegate
{
43 ShellViewsDelegateAura() : use_transparent_windows_(false) {
46 virtual ~ShellViewsDelegateAura() {
49 void SetUseTransparentWindows(bool transparent
) {
50 use_transparent_windows_
= transparent
;
53 // Overridden from views::TestViewsDelegate:
54 virtual bool UseTransparentWindows() const OVERRIDE
{
55 return use_transparent_windows_
;
59 bool use_transparent_windows_
;
61 DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura
);
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
{
75 ShellWindowDelegateView(Shell
* shell
)
77 toolbar_view_(new View
),
78 contents_view_(new View
) {
80 virtual ~ShellWindowDelegateView() {}
82 // Update the state of UI controls
83 void SetAddressBarURL(const GURL
& url
) {
84 url_entry_
->SetText(ASCIIToUTF16(url
.spec()));
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_
);
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
);
109 // Initialize the UI control contained in shell window
110 void InitShellWindow() {
111 set_background(views::Background::CreateStandardPanelBackground());
113 views::GridLayout
* layout
= new views::GridLayout(this);
114 SetLayoutManager(layout
);
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);
122 layout
->AddPaddingRow(0, 2);
124 // Add toolbar buttons and URL text field
126 layout
->StartRow(0, 0);
127 views::GridLayout
* toolbar_layout
= new views::GridLayout(toolbar_view_
);
128 toolbar_view_
->SetLayoutManager(toolbar_layout
);
130 views::ColumnSet
* toolbar_column_set
=
131 toolbar_layout
->AddColumnSet(0);
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);
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);
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);
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);
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);
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_
);
184 layout
->AddView(toolbar_view_
);
187 layout
->AddPaddingRow(0, 5);
189 // Add web contents view as the second row
191 layout
->StartRow(1, 0);
192 layout
->AddView(contents_view_
);
195 layout
->AddPaddingRow(0, 5);
197 // Overridden from TextfieldController
198 virtual void ContentsChanged(views::Textfield
* sender
,
199 const string16
& new_contents
) OVERRIDE
{
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());
206 if (!url
.has_scheme()) {
207 url
= GURL(std::string("http://") + std::string(text
));
208 url_entry_
->SetText(ASCIIToUTF16(url
.spec()));
210 shell_
->LoadURL(url
);
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_
)
225 else if (sender
== stop_button_
)
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
{
235 virtual void WindowClosing() OVERRIDE
{
241 virtual View
* GetContentsView() OVERRIDE
{ return this; }
243 // Overridden from View
244 virtual void ViewHierarchyChanged(
245 const ViewHierarchyChangedDetails
& details
) OVERRIDE
{
246 if (details
.is_add
&& details
.child
== this) {
252 // Hold a reference of Shell for deleting it when the window is closing
258 // Toolbar view contains forward/backward/reload button and URL entry
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_
;
266 // Contents view contains the web contents view
267 View
* contents_view_
;
268 views::WebView
* web_view_
;
270 DISALLOW_COPY_AND_ASSIGN(ShellWindowDelegateView
);
275 #if defined(OS_CHROMEOS)
276 MinimalAsh
* Shell::minimal_ash_
= NULL
;
278 views::ViewsDelegate
* Shell::views_delegate_
= NULL
;
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_ash_
= new content::MinimalAsh(default_window_size
);
288 gfx::Screen::SetScreenInstance(
289 gfx::SCREEN_TYPE_NATIVE
, views::CreateDesktopScreen());
291 views_delegate_
= new ShellViewsDelegateAura();
294 void Shell::PlatformExit() {
295 #if defined(OS_CHROMEOS)
300 delete views_delegate_
;
301 #if defined(OS_CHROMEOS)
302 chromeos::DBusThreadManager::Shutdown();
304 aura::Env::DeleteInstance();
307 void Shell::PlatformCleanUp() {
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
,
316 } else if (control
== FORWARD_BUTTON
) {
317 delegate_view
->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON
,
319 } else if (control
== STOP_BUTTON
) {
320 delegate_view
->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON
,
325 void Shell::PlatformSetAddressBarURL(const GURL
& url
) {
326 ShellWindowDelegateView
* delegate_view
=
327 static_cast<ShellWindowDelegateView
*>(window_widget_
->widget_delegate());
328 delegate_view
->SetAddressBarURL(url
);
331 void Shell::PlatformSetIsLoading(bool loading
) {
334 void Shell::PlatformCreateWindow(int width
, int height
) {
335 #if defined(OS_CHROMEOS)
337 views::Widget::CreateWindowWithContextAndBounds(
338 new ShellWindowDelegateView(this),
339 minimal_ash_
->GetDefaultParent(NULL
, NULL
, gfx::Rect()),
340 gfx::Rect(0, 0, width
, height
));
343 views::Widget::CreateWindowWithBounds(new ShellWindowDelegateView(this),
344 gfx::Rect(0, 0, width
, height
));
347 window_
= window_widget_
->GetNativeWindow();
348 // Call ShowRootWindow on RootWindow created by MinimalAsh without
349 // which XWindow owned by RootWindow doesn't get mapped.
350 window_
->GetRootWindow()->ShowRootWindow();
351 window_widget_
->Show();
354 void Shell::PlatformSetContents() {
355 ShellWindowDelegateView
* delegate_view
=
356 static_cast<ShellWindowDelegateView
*>(window_widget_
->widget_delegate());
357 delegate_view
->SetWebContents(web_contents_
.get());
360 void Shell::PlatformResizeSubViews() {
363 void Shell::Close() {
364 window_widget_
->Close();
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();
374 } // namespace content