Update ASan/Android runtime and setup script to LLVM r200682.
[chromium-blink-merge.git] / content / shell / browser / shell_views.cc
blob8c29e072bedbd2a978a080fa0a429434178190b0
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/render_widget_host_view.h"
10 #include "content/public/browser/web_contents.h"
11 #include "content/public/browser/web_contents_view.h"
12 #include "content/shell/browser/shell_platform_data_aura.h"
13 #include "ui/aura/env.h"
14 #include "ui/aura/root_window.h"
15 #include "ui/aura/window.h"
16 #include "ui/base/accessibility/accessibility_types.h"
17 #include "ui/base/clipboard/clipboard.h"
18 #include "ui/base/models/simple_menu_model.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/events/event.h"
21 #include "ui/gfx/screen.h"
22 #include "ui/views/background.h"
23 #include "ui/views/controls/button/label_button.h"
24 #include "ui/views/controls/button/menu_button.h"
25 #include "ui/views/controls/button/menu_button_listener.h"
26 #include "ui/views/controls/menu/menu_item_view.h"
27 #include "ui/views/controls/menu/menu_runner.h"
28 #include "ui/views/controls/textfield/textfield.h"
29 #include "ui/views/controls/textfield/textfield_controller.h"
30 #include "ui/views/controls/webview/webview.h"
31 #include "ui/views/layout/fill_layout.h"
32 #include "ui/views/layout/grid_layout.h"
33 #include "ui/views/test/desktop_test_views_delegate.h"
34 #include "ui/views/view.h"
35 #include "ui/views/widget/desktop_aura/desktop_screen.h"
36 #include "ui/views/widget/widget.h"
37 #include "ui/views/widget/widget_delegate.h"
39 #if defined(OS_CHROMEOS)
40 #include "chromeos/dbus/dbus_thread_manager.h"
41 #include "ui/aura/test/test_screen.h"
42 #include "ui/wm/test/wm_test_helper.h"
43 #endif
45 #if defined(OS_WIN)
46 #include <fcntl.h>
47 #include <io.h>
48 #endif
50 namespace content {
52 namespace {
53 // ViewDelegate implementation for aura content shell
54 class ShellViewsDelegateAura : public views::DesktopTestViewsDelegate {
55 public:
56 ShellViewsDelegateAura() : use_transparent_windows_(false) {
59 virtual ~ShellViewsDelegateAura() {
62 void SetUseTransparentWindows(bool transparent) {
63 use_transparent_windows_ = transparent;
66 private:
67 bool use_transparent_windows_;
69 DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura);
72 // Model for the "Debug" menu
73 class DevToolsMenuModel : public ui::SimpleMenuModel,
74 public ui::SimpleMenuModel::Delegate {
75 public:
76 explicit DevToolsMenuModel(Shell* shell)
77 : ui::SimpleMenuModel(this),
78 shell_(shell) {
79 AddItem(COMMAND_OPEN_DEVTOOLS, base::ASCIIToUTF16("Developer Tools"));
82 // ui::SimpleMenuModel::Delegate:
83 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
84 return false;
86 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
87 return true;
89 virtual bool GetAcceleratorForCommandId(
90 int command_id,
91 ui::Accelerator* accelerator) OVERRIDE { return false; }
92 virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
93 switch (command_id) {
94 case COMMAND_OPEN_DEVTOOLS:
95 shell_->ShowDevTools();
96 break;
100 private:
101 enum CommandID {
102 COMMAND_OPEN_DEVTOOLS
105 Shell* shell_;
107 DISALLOW_COPY_AND_ASSIGN(DevToolsMenuModel);
110 class DebugMenuButton : public views::MenuButton,
111 public views::MenuButtonListener {
112 public:
113 explicit DebugMenuButton(Shell* shell)
114 : MenuButton(NULL, base::ASCIIToUTF16("Debug"), this, true),
115 menu_model_(shell) {
118 private:
119 // MenuButtonListener:
120 virtual void OnMenuButtonClicked(View* source,
121 const gfx::Point& point) OVERRIDE {
122 menu_runner_.reset(new views::MenuRunner(&menu_model_));
124 if (menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(),
125 this, gfx::Rect(point, gfx::Size()),
126 views::MenuItemView::TOPRIGHT, ui::MENU_SOURCE_NONE,
127 views::MenuRunner::HAS_MNEMONICS) ==
128 views::MenuRunner::MENU_DELETED)
129 return;
132 DevToolsMenuModel menu_model_;
133 scoped_ptr<views::MenuRunner> menu_runner_;
135 DISALLOW_COPY_AND_ASSIGN(DebugMenuButton);
138 // Maintain the UI controls and web view for content shell
139 class ShellWindowDelegateView : public views::WidgetDelegateView,
140 public views::TextfieldController,
141 public views::ButtonListener {
142 public:
143 enum UIControl {
144 BACK_BUTTON,
145 FORWARD_BUTTON,
146 STOP_BUTTON
149 ShellWindowDelegateView(Shell* shell)
150 : shell_(shell),
151 toolbar_view_(new View),
152 contents_view_(new View) {
154 virtual ~ShellWindowDelegateView() {}
156 // Update the state of UI controls
157 void SetAddressBarURL(const GURL& url) {
158 url_entry_->SetText(base::ASCIIToUTF16(url.spec()));
160 void SetWebContents(WebContents* web_contents, const gfx::Size& size) {
161 contents_view_->SetLayoutManager(new views::FillLayout());
162 web_view_ = new views::WebView(web_contents->GetBrowserContext());
163 web_view_->SetWebContents(web_contents);
164 web_view_->SetPreferredSize(size);
165 web_contents->GetView()->Focus();
166 contents_view_->AddChildView(web_view_);
167 Layout();
169 // Resize the widget, keeping the same origin.
170 gfx::Rect bounds = GetWidget()->GetWindowBoundsInScreen();
171 bounds.set_size(GetWidget()->GetRootView()->GetPreferredSize());
172 GetWidget()->SetBounds(bounds);
174 // Resizing a widget on chromeos doesn't automatically resize the root, need
175 // to explicitly do that.
176 #if defined(OS_CHROMEOS)
177 GetWidget()->GetNativeWindow()->GetDispatcher()->host()->SetBounds(bounds);
178 #endif
181 void SetWindowTitle(const base::string16& title) { title_ = title; }
182 void EnableUIControl(UIControl control, bool is_enabled) {
183 if (control == BACK_BUTTON) {
184 back_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
185 : views::CustomButton::STATE_DISABLED);
186 } else if (control == FORWARD_BUTTON) {
187 forward_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
188 : views::CustomButton::STATE_DISABLED);
189 } else if (control == STOP_BUTTON) {
190 stop_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
191 : views::CustomButton::STATE_DISABLED);
195 private:
196 // Initialize the UI control contained in shell window
197 void InitShellWindow() {
198 set_background(views::Background::CreateStandardPanelBackground());
200 views::GridLayout* layout = new views::GridLayout(this);
201 SetLayoutManager(layout);
203 views::ColumnSet* column_set = layout->AddColumnSet(0);
204 column_set->AddPaddingColumn(0, 2);
205 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
206 views::GridLayout::USE_PREF, 0, 0);
207 column_set->AddPaddingColumn(0, 2);
209 layout->AddPaddingRow(0, 2);
211 // Add toolbar buttons and URL text field
213 layout->StartRow(0, 0);
214 views::GridLayout* toolbar_layout = new views::GridLayout(toolbar_view_);
215 toolbar_view_->SetLayoutManager(toolbar_layout);
217 views::ColumnSet* toolbar_column_set =
218 toolbar_layout->AddColumnSet(0);
219 // Back button
220 back_button_ = new views::LabelButton(this, base::ASCIIToUTF16("Back"));
221 back_button_->SetStyle(views::Button::STYLE_BUTTON);
222 gfx::Size back_button_size = back_button_->GetPreferredSize();
223 toolbar_column_set->AddColumn(views::GridLayout::CENTER,
224 views::GridLayout::CENTER, 0,
225 views::GridLayout::FIXED,
226 back_button_size.width(),
227 back_button_size.width() / 2);
228 // Forward button
229 forward_button_ =
230 new views::LabelButton(this, base::ASCIIToUTF16("Forward"));
231 forward_button_->SetStyle(views::Button::STYLE_BUTTON);
232 gfx::Size forward_button_size = forward_button_->GetPreferredSize();
233 toolbar_column_set->AddColumn(views::GridLayout::CENTER,
234 views::GridLayout::CENTER, 0,
235 views::GridLayout::FIXED,
236 forward_button_size.width(),
237 forward_button_size.width() / 2);
238 // Refresh button
239 refresh_button_ =
240 new views::LabelButton(this, base::ASCIIToUTF16("Refresh"));
241 refresh_button_->SetStyle(views::Button::STYLE_BUTTON);
242 gfx::Size refresh_button_size = refresh_button_->GetPreferredSize();
243 toolbar_column_set->AddColumn(views::GridLayout::CENTER,
244 views::GridLayout::CENTER, 0,
245 views::GridLayout::FIXED,
246 refresh_button_size.width(),
247 refresh_button_size.width() / 2);
248 // Stop button
249 stop_button_ = new views::LabelButton(this, base::ASCIIToUTF16("Stop"));
250 stop_button_->SetStyle(views::Button::STYLE_BUTTON);
251 gfx::Size stop_button_size = stop_button_->GetPreferredSize();
252 toolbar_column_set->AddColumn(views::GridLayout::CENTER,
253 views::GridLayout::CENTER, 0,
254 views::GridLayout::FIXED,
255 stop_button_size.width(),
256 stop_button_size.width() / 2);
257 toolbar_column_set->AddPaddingColumn(0, 2);
258 // URL entry
259 url_entry_ = new views::Textfield();
260 url_entry_->set_controller(this);
261 toolbar_column_set->AddColumn(views::GridLayout::FILL,
262 views::GridLayout::FILL, 1,
263 views::GridLayout::USE_PREF, 0, 0);
264 toolbar_column_set->AddPaddingColumn(0, 2);
265 // Debug button
266 debug_button_ = new DebugMenuButton(shell_);
267 gfx::Size debug_button_size = debug_button_->GetPreferredSize();
268 toolbar_column_set->AddColumn(views::GridLayout::CENTER,
269 views::GridLayout::CENTER, 0,
270 views::GridLayout::FIXED,
271 debug_button_size.width(),
272 debug_button_size.width() / 2);
274 // Fill up the first row
275 toolbar_layout->StartRow(0, 0);
276 toolbar_layout->AddView(back_button_);
277 toolbar_layout->AddView(forward_button_);
278 toolbar_layout->AddView(refresh_button_);
279 toolbar_layout->AddView(stop_button_);
280 toolbar_layout->AddView(url_entry_);
281 toolbar_layout->AddView(debug_button_);
283 layout->AddView(toolbar_view_);
286 layout->AddPaddingRow(0, 5);
288 // Add web contents view as the second row
290 layout->StartRow(1, 0);
291 layout->AddView(contents_view_);
294 layout->AddPaddingRow(0, 5);
296 InitAccelerators();
298 void InitAccelerators() {
299 static const ui::KeyboardCode keys[] = { ui::VKEY_F5,
300 ui::VKEY_BROWSER_BACK,
301 ui::VKEY_BROWSER_FORWARD };
302 for (size_t i = 0; i < arraysize(keys); ++i) {
303 GetFocusManager()->RegisterAccelerator(
304 ui::Accelerator(keys[i], ui::EF_NONE),
305 ui::AcceleratorManager::kNormalPriority,
306 this);
309 // Overridden from TextfieldController
310 virtual void ContentsChanged(views::Textfield* sender,
311 const base::string16& new_contents) OVERRIDE {
313 virtual bool HandleKeyEvent(views::Textfield* sender,
314 const ui::KeyEvent& key_event) OVERRIDE {
315 if (sender == url_entry_ && key_event.key_code() == ui::VKEY_RETURN) {
316 std::string text = base::UTF16ToUTF8(url_entry_->text());
317 GURL url(text);
318 if (!url.has_scheme()) {
319 url = GURL(std::string("http://") + std::string(text));
320 url_entry_->SetText(base::ASCIIToUTF16(url.spec()));
322 shell_->LoadURL(url);
323 return true;
325 return false;
328 // Overridden from ButtonListener
329 virtual void ButtonPressed(views::Button* sender,
330 const ui::Event& event) OVERRIDE {
331 if (sender == back_button_)
332 shell_->GoBackOrForward(-1);
333 else if (sender == forward_button_)
334 shell_->GoBackOrForward(1);
335 else if (sender == refresh_button_)
336 shell_->Reload();
337 else if (sender == stop_button_)
338 shell_->Stop();
341 // Overridden from WidgetDelegateView
342 virtual bool CanResize() const OVERRIDE { return true; }
343 virtual bool CanMaximize() const OVERRIDE { return true; }
344 virtual base::string16 GetWindowTitle() const OVERRIDE {
345 return title_;
347 virtual void WindowClosing() OVERRIDE {
348 if (shell_) {
349 delete shell_;
350 shell_ = NULL;
353 virtual View* GetContentsView() OVERRIDE { return this; }
355 // Overridden from View
356 virtual gfx::Size GetMinimumSize() OVERRIDE {
357 // We want to be able to make the window smaller than its initial
358 // (preferred) size.
359 return gfx::Size();
361 virtual void ViewHierarchyChanged(
362 const ViewHierarchyChangedDetails& details) OVERRIDE {
363 if (details.is_add && details.child == this) {
364 InitShellWindow();
368 // Overridden from AcceleratorTarget:
369 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE {
370 switch (accelerator.key_code()) {
371 case ui::VKEY_F5:
372 shell_->Reload();
373 return true;
374 case ui::VKEY_BROWSER_BACK:
375 shell_->GoBackOrForward(-1);
376 return true;
377 case ui::VKEY_BROWSER_FORWARD:
378 shell_->GoBackOrForward(1);
379 return true;
380 default:
381 return views::WidgetDelegateView::AcceleratorPressed(accelerator);
385 private:
386 // Hold a reference of Shell for deleting it when the window is closing
387 Shell* shell_;
389 // Window title
390 base::string16 title_;
392 // Toolbar view contains forward/backward/reload button and URL entry
393 View* toolbar_view_;
394 views::LabelButton* back_button_;
395 views::LabelButton* forward_button_;
396 views::LabelButton* refresh_button_;
397 views::LabelButton* stop_button_;
398 views::Textfield* url_entry_;
399 DebugMenuButton* debug_button_;
401 // Contents view contains the web contents view
402 View* contents_view_;
403 views::WebView* web_view_;
405 DISALLOW_COPY_AND_ASSIGN(ShellWindowDelegateView);
408 } // namespace
410 #if defined(OS_CHROMEOS)
411 wm::WMTestHelper* Shell::wm_test_helper_ = NULL;
412 #endif
413 views::ViewsDelegate* Shell::views_delegate_ = NULL;
415 // static
416 void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
417 #if defined(OS_WIN)
418 _setmode(_fileno(stdout), _O_BINARY);
419 _setmode(_fileno(stderr), _O_BINARY);
420 #endif
421 #if defined(OS_CHROMEOS)
422 chromeos::DBusThreadManager::Initialize();
423 gfx::Screen::SetScreenInstance(
424 gfx::SCREEN_TYPE_NATIVE, aura::TestScreen::Create());
425 wm_test_helper_ = new wm::WMTestHelper(default_window_size);
426 #else
427 gfx::Screen::SetScreenInstance(
428 gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
429 #endif
430 views_delegate_ = new ShellViewsDelegateAura();
433 void Shell::PlatformExit() {
434 #if defined(OS_CHROMEOS)
435 delete wm_test_helper_;
436 #endif
437 delete views_delegate_;
438 views_delegate_ = NULL;
439 delete platform_;
440 platform_ = NULL;
441 #if defined(OS_CHROMEOS)
442 chromeos::DBusThreadManager::Shutdown();
443 #endif
444 aura::Env::DeleteInstance();
447 void Shell::PlatformCleanUp() {
450 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
451 if (headless_)
452 return;
453 ShellWindowDelegateView* delegate_view =
454 static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
455 if (control == BACK_BUTTON) {
456 delegate_view->EnableUIControl(ShellWindowDelegateView::BACK_BUTTON,
457 is_enabled);
458 } else if (control == FORWARD_BUTTON) {
459 delegate_view->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON,
460 is_enabled);
461 } else if (control == STOP_BUTTON) {
462 delegate_view->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON,
463 is_enabled);
467 void Shell::PlatformSetAddressBarURL(const GURL& url) {
468 if (headless_)
469 return;
470 ShellWindowDelegateView* delegate_view =
471 static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
472 delegate_view->SetAddressBarURL(url);
475 void Shell::PlatformSetIsLoading(bool loading) {
478 void Shell::PlatformCreateWindow(int width, int height) {
479 if (headless_) {
480 content_size_ = gfx::Size(width, height);
481 if (!platform_)
482 platform_ = new ShellPlatformDataAura(content_size_);
483 else
484 platform_->ResizeWindow(content_size_);
485 return;
487 #if defined(OS_CHROMEOS)
488 window_widget_ = views::Widget::CreateWindowWithContextAndBounds(
489 new ShellWindowDelegateView(this),
490 wm_test_helper_->GetDefaultParent(NULL, NULL, gfx::Rect()),
491 gfx::Rect(0, 0, width, height));
492 #else
493 window_widget_ = views::Widget::CreateWindowWithBounds(
494 new ShellWindowDelegateView(this), gfx::Rect(0, 0, width, height));
495 #endif
497 content_size_ = gfx::Size(width, height);
499 window_ = window_widget_->GetNativeWindow();
500 // Call ShowRootWindow on RootWindow created by WMTestHelper without
501 // which XWindow owned by RootWindow doesn't get mapped.
502 window_->GetDispatcher()->host()->Show();
503 window_widget_->Show();
506 void Shell::PlatformSetContents() {
507 if (headless_) {
508 CHECK(platform_);
509 aura::Window* content = web_contents_->GetView()->GetNativeView();
510 aura::Window* parent = platform_->window()->window();
511 if (!parent->Contains(content)) {
512 parent->AddChild(content);
513 content->Show();
515 content->SetBounds(gfx::Rect(content_size_));
516 RenderWidgetHostView* host_view = web_contents_->GetRenderWidgetHostView();
517 if (host_view)
518 host_view->SetSize(content_size_);
519 } else {
520 views::WidgetDelegate* widget_delegate = window_widget_->widget_delegate();
521 ShellWindowDelegateView* delegate_view =
522 static_cast<ShellWindowDelegateView*>(widget_delegate);
523 delegate_view->SetWebContents(web_contents_.get(), content_size_);
527 void Shell::PlatformResizeSubViews() {
530 void Shell::Close() {
531 if (headless_)
532 delete this;
533 else
534 window_widget_->CloseNow();
537 void Shell::PlatformSetTitle(const base::string16& title) {
538 if (headless_)
539 return;
540 ShellWindowDelegateView* delegate_view =
541 static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
542 delegate_view->SetWindowTitle(title);
543 window_widget_->UpdateWindowTitle();
546 } // namespace content