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