| OLD | NEW |
| (Empty) |
| 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 <gdk/gdkkeysyms.h> | |
| 8 #include <gtk/gtk.h> | |
| 9 | |
| 10 #include "base/logging.h" | |
| 11 #include "base/strings/string_piece.h" | |
| 12 #include "base/strings/utf_string_conversions.h" | |
| 13 #include "content/public/browser/browser_context.h" | |
| 14 #include "content/public/browser/native_web_keyboard_event.h" | |
| 15 #include "content/public/browser/render_widget_host_view.h" | |
| 16 #include "content/public/browser/web_contents.h" | |
| 17 #include "content/public/browser/web_contents_view.h" | |
| 18 #include "content/public/common/renderer_preferences.h" | |
| 19 #include "content/shell/browser/shell_browser_context.h" | |
| 20 #include "content/shell/browser/shell_content_browser_client.h" | |
| 21 | |
| 22 namespace content { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 // Callback for Debug > Show web inspector... menu item. | |
| 27 gboolean ShowWebInspectorActivated(GtkWidget* widget, Shell* shell) { | |
| 28 shell->ShowDevTools(); | |
| 29 return FALSE; // Don't stop this message. | |
| 30 } | |
| 31 | |
| 32 GtkWidget* AddMenuEntry(GtkWidget* menu_widget, const char* text, | |
| 33 GCallback callback, Shell* shell) { | |
| 34 GtkWidget* entry = gtk_menu_item_new_with_label(text); | |
| 35 g_signal_connect(entry, "activate", callback, shell); | |
| 36 gtk_menu_shell_append(GTK_MENU_SHELL(menu_widget), entry); | |
| 37 return entry; | |
| 38 } | |
| 39 | |
| 40 GtkWidget* CreateMenu(GtkWidget* menu_bar, const char* text) { | |
| 41 GtkWidget* menu_widget = gtk_menu_new(); | |
| 42 GtkWidget* menu_header = gtk_menu_item_new_with_label(text); | |
| 43 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_header), menu_widget); | |
| 44 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_header); | |
| 45 return menu_widget; | |
| 46 } | |
| 47 | |
| 48 GtkWidget* CreateMenuBar(Shell* shell) { | |
| 49 GtkWidget* menu_bar = gtk_menu_bar_new(); | |
| 50 GtkWidget* debug_menu = CreateMenu(menu_bar, "Debug"); | |
| 51 AddMenuEntry(debug_menu, "Show web inspector...", | |
| 52 G_CALLBACK(ShowWebInspectorActivated), shell); | |
| 53 return menu_bar; | |
| 54 } | |
| 55 | |
| 56 } // namespace | |
| 57 | |
| 58 void Shell::PlatformInitialize(const gfx::Size& default_window_size) { | |
| 59 } | |
| 60 | |
| 61 void Shell::PlatformExit() { | |
| 62 } | |
| 63 | |
| 64 void Shell::PlatformCleanUp() { | |
| 65 // Nothing to clean up; GTK will clean up the widgets shortly after. | |
| 66 } | |
| 67 | |
| 68 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) { | |
| 69 if (headless_) | |
| 70 return; | |
| 71 | |
| 72 GtkToolItem* item = NULL; | |
| 73 switch (control) { | |
| 74 case BACK_BUTTON: | |
| 75 item = back_button_; | |
| 76 break; | |
| 77 case FORWARD_BUTTON: | |
| 78 item = forward_button_; | |
| 79 break; | |
| 80 case STOP_BUTTON: | |
| 81 item = stop_button_; | |
| 82 break; | |
| 83 default: | |
| 84 NOTREACHED() << "Unknown UI control"; | |
| 85 return; | |
| 86 } | |
| 87 gtk_widget_set_sensitive(GTK_WIDGET(item), is_enabled); | |
| 88 } | |
| 89 | |
| 90 void Shell::PlatformSetAddressBarURL(const GURL& url) { | |
| 91 if (headless_) | |
| 92 return; | |
| 93 | |
| 94 gtk_entry_set_text(GTK_ENTRY(url_edit_view_), url.spec().c_str()); | |
| 95 } | |
| 96 | |
| 97 void Shell::PlatformSetIsLoading(bool loading) { | |
| 98 if (headless_) | |
| 99 return; | |
| 100 | |
| 101 if (loading) | |
| 102 gtk_spinner_start(GTK_SPINNER(spinner_)); | |
| 103 else | |
| 104 gtk_spinner_stop(GTK_SPINNER(spinner_)); | |
| 105 } | |
| 106 | |
| 107 void Shell::PlatformCreateWindow(int width, int height) { | |
| 108 ui_elements_height_ = 0; | |
| 109 if (headless_) { | |
| 110 content_size_ = gfx::Size(width, height); | |
| 111 return; | |
| 112 } | |
| 113 | |
| 114 window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); | |
| 115 gtk_window_set_title(window_, "Content Shell"); | |
| 116 g_signal_connect(G_OBJECT(window_), "destroy", | |
| 117 G_CALLBACK(OnWindowDestroyedThunk), this); | |
| 118 | |
| 119 vbox_ = gtk_vbox_new(FALSE, 0); | |
| 120 | |
| 121 // Create the menu bar. | |
| 122 GtkWidget* menu_bar = CreateMenuBar(this); | |
| 123 gtk_box_pack_start(GTK_BOX(vbox_), menu_bar, FALSE, FALSE, 0); | |
| 124 | |
| 125 // Create the object that mediates accelerators. | |
| 126 GtkAccelGroup* accel_group = gtk_accel_group_new(); | |
| 127 gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group); | |
| 128 | |
| 129 // Set global window handling accelerators: | |
| 130 gtk_accel_group_connect( | |
| 131 accel_group, GDK_w, GDK_CONTROL_MASK, | |
| 132 GTK_ACCEL_VISIBLE, | |
| 133 g_cclosure_new(G_CALLBACK(OnCloseWindowKeyPressedThunk), | |
| 134 this, NULL)); | |
| 135 | |
| 136 gtk_accel_group_connect( | |
| 137 accel_group, GDK_n, GDK_CONTROL_MASK, | |
| 138 GTK_ACCEL_VISIBLE, | |
| 139 g_cclosure_new(G_CALLBACK(OnNewWindowKeyPressedThunk), | |
| 140 this, NULL)); | |
| 141 | |
| 142 gtk_accel_group_connect( | |
| 143 accel_group, GDK_F5, (GdkModifierType)0, | |
| 144 GTK_ACCEL_VISIBLE, | |
| 145 g_cclosure_new(G_CALLBACK(OnReloadKeyPressedThunk), | |
| 146 this, NULL)); | |
| 147 | |
| 148 GtkWidget* toolbar = gtk_toolbar_new(); | |
| 149 // Turn off the labels on the toolbar buttons. | |
| 150 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); | |
| 151 | |
| 152 back_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK); | |
| 153 g_signal_connect(back_button_, "clicked", | |
| 154 G_CALLBACK(&OnBackButtonClickedThunk), this); | |
| 155 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), back_button_, -1 /* append */); | |
| 156 gtk_widget_add_accelerator(GTK_WIDGET(back_button_), "clicked", accel_group, | |
| 157 GDK_Left, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE); | |
| 158 | |
| 159 forward_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD); | |
| 160 g_signal_connect(forward_button_, "clicked", | |
| 161 G_CALLBACK(&OnForwardButtonClickedThunk), this); | |
| 162 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), forward_button_, -1 /* append */); | |
| 163 gtk_widget_add_accelerator(GTK_WIDGET(forward_button_), "clicked", | |
| 164 accel_group, | |
| 165 GDK_Right, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE); | |
| 166 | |
| 167 reload_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH); | |
| 168 g_signal_connect(reload_button_, "clicked", | |
| 169 G_CALLBACK(&OnReloadButtonClickedThunk), this); | |
| 170 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), reload_button_, -1 /* append */); | |
| 171 gtk_widget_add_accelerator(GTK_WIDGET(reload_button_), "clicked", | |
| 172 accel_group, | |
| 173 GDK_r, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); | |
| 174 | |
| 175 stop_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_STOP); | |
| 176 g_signal_connect(stop_button_, "clicked", | |
| 177 G_CALLBACK(&OnStopButtonClickedThunk), this); | |
| 178 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), stop_button_, -1 /* append */); | |
| 179 | |
| 180 url_edit_view_ = gtk_entry_new(); | |
| 181 g_signal_connect(G_OBJECT(url_edit_view_), "activate", | |
| 182 G_CALLBACK(&OnURLEntryActivateThunk), this); | |
| 183 | |
| 184 gtk_accel_group_connect( | |
| 185 accel_group, GDK_l, GDK_CONTROL_MASK, | |
| 186 GTK_ACCEL_VISIBLE, | |
| 187 g_cclosure_new(G_CALLBACK(OnHighlightURLViewThunk), | |
| 188 this, NULL)); | |
| 189 | |
| 190 GtkToolItem* tool_item = gtk_tool_item_new(); | |
| 191 gtk_container_add(GTK_CONTAINER(tool_item), url_edit_view_); | |
| 192 gtk_tool_item_set_expand(tool_item, TRUE); | |
| 193 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1 /* append */); | |
| 194 | |
| 195 // Center a 20x20 spinner in a 26x24 area. | |
| 196 GtkWidget* spinner_alignment = gtk_alignment_new(0.5, 0.5, 0, 0); | |
| 197 gtk_alignment_set_padding(GTK_ALIGNMENT(spinner_alignment), 2, 2, 4, 4); | |
| 198 spinner_ = gtk_spinner_new(); | |
| 199 gtk_widget_set_size_request(spinner_, 20, 20); | |
| 200 gtk_container_add(GTK_CONTAINER(spinner_alignment), spinner_); | |
| 201 | |
| 202 spinner_item_ = gtk_tool_item_new(); | |
| 203 gtk_container_add(GTK_CONTAINER(spinner_item_), spinner_alignment); | |
| 204 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), spinner_item_, -1 /* append */); | |
| 205 | |
| 206 gtk_box_pack_start(GTK_BOX(vbox_), toolbar, FALSE, FALSE, 0); | |
| 207 | |
| 208 gtk_container_add(GTK_CONTAINER(window_), vbox_); | |
| 209 | |
| 210 // Trigger layout of the UI elements, so that we can measure their | |
| 211 // heights. The width and height passed to this method are meant for the web | |
| 212 // contents view, not the top-level window. Since Gtk only seems to provide a | |
| 213 // suitable resizing function for top-level windows, we need to know how to | |
| 214 // convert from web contents view size to top-level window size. | |
| 215 gtk_widget_show_all(GTK_WIDGET(vbox_)); | |
| 216 | |
| 217 // Measure the heights of the UI elements, now that they have been laid out. | |
| 218 GtkRequisition elm_size; | |
| 219 gtk_widget_size_request(menu_bar, &elm_size); | |
| 220 ui_elements_height_ += elm_size.height; | |
| 221 gtk_widget_size_request(toolbar, &elm_size); | |
| 222 ui_elements_height_ += elm_size.height; | |
| 223 | |
| 224 // We're ready to set an initial window size. | |
| 225 SizeTo(gfx::Size(width, height)); | |
| 226 | |
| 227 // Finally, show the window. | |
| 228 gtk_widget_show_all(GTK_WIDGET(window_)); | |
| 229 } | |
| 230 | |
| 231 void Shell::PlatformSetContents() { | |
| 232 if (headless_) { | |
| 233 SizeTo(content_size_); | |
| 234 return; | |
| 235 } | |
| 236 | |
| 237 WebContentsView* content_view = web_contents_->GetView(); | |
| 238 gtk_container_add(GTK_CONTAINER(vbox_), content_view->GetNativeView()); | |
| 239 } | |
| 240 | |
| 241 void Shell::SizeTo(const gfx::Size& content_size) { | |
| 242 content_size_ = content_size; | |
| 243 | |
| 244 if (window_) { | |
| 245 gtk_window_resize(window_, | |
| 246 content_size.width(), | |
| 247 content_size.height() + ui_elements_height_); | |
| 248 } else if (web_contents_) { | |
| 249 RenderWidgetHostView* render_widget_host_view = | |
| 250 web_contents_->GetRenderWidgetHostView(); | |
| 251 if (render_widget_host_view) | |
| 252 render_widget_host_view->SetSize(content_size); | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 void Shell::PlatformResizeSubViews() { | |
| 257 // Not needed; the subviews are bound. | |
| 258 } | |
| 259 | |
| 260 bool Shell::PlatformHandleContextMenu( | |
| 261 const content::ContextMenuParams& params) { | |
| 262 return false; | |
| 263 } | |
| 264 | |
| 265 void Shell::Close() { | |
| 266 if (headless_) { | |
| 267 delete this; | |
| 268 return; | |
| 269 } | |
| 270 | |
| 271 gtk_widget_destroy(GTK_WIDGET(window_)); | |
| 272 } | |
| 273 | |
| 274 void Shell::OnBackButtonClicked(GtkWidget* widget) { | |
| 275 GoBackOrForward(-1); | |
| 276 } | |
| 277 | |
| 278 void Shell::OnForwardButtonClicked(GtkWidget* widget) { | |
| 279 GoBackOrForward(1); | |
| 280 } | |
| 281 | |
| 282 void Shell::OnReloadButtonClicked(GtkWidget* widget) { | |
| 283 Reload(); | |
| 284 } | |
| 285 | |
| 286 void Shell::OnStopButtonClicked(GtkWidget* widget) { | |
| 287 Stop(); | |
| 288 } | |
| 289 | |
| 290 void Shell::OnURLEntryActivate(GtkWidget* entry) { | |
| 291 const gchar* str = gtk_entry_get_text(GTK_ENTRY(entry)); | |
| 292 GURL url(str); | |
| 293 if (!url.has_scheme()) | |
| 294 url = GURL(std::string("http://") + std::string(str)); | |
| 295 if (url.is_valid()) | |
| 296 LoadURL(url); | |
| 297 } | |
| 298 | |
| 299 // Callback for when the main window is destroyed. | |
| 300 gboolean Shell::OnWindowDestroyed(GtkWidget* window) { | |
| 301 delete this; | |
| 302 return FALSE; // Don't stop this message. | |
| 303 } | |
| 304 | |
| 305 gboolean Shell::OnCloseWindowKeyPressed(GtkAccelGroup* accel_group, | |
| 306 GObject* acceleratable, | |
| 307 guint keyval, | |
| 308 GdkModifierType modifier) { | |
| 309 gtk_widget_destroy(GTK_WIDGET(window_)); | |
| 310 return TRUE; | |
| 311 } | |
| 312 | |
| 313 gboolean Shell::OnNewWindowKeyPressed(GtkAccelGroup* accel_group, | |
| 314 GObject* acceleratable, | |
| 315 guint keyval, | |
| 316 GdkModifierType modifier) { | |
| 317 ShellBrowserContext* browser_context = | |
| 318 ShellContentBrowserClient::Get()->browser_context(); | |
| 319 Shell::CreateNewWindow(browser_context, | |
| 320 GURL(), | |
| 321 NULL, | |
| 322 MSG_ROUTING_NONE, | |
| 323 gfx::Size()); | |
| 324 return TRUE; | |
| 325 } | |
| 326 | |
| 327 gboolean Shell::OnHighlightURLView(GtkAccelGroup* accel_group, | |
| 328 GObject* acceleratable, | |
| 329 guint keyval, | |
| 330 GdkModifierType modifier) { | |
| 331 gtk_widget_grab_focus(GTK_WIDGET(url_edit_view_)); | |
| 332 return TRUE; | |
| 333 } | |
| 334 | |
| 335 gboolean Shell::OnReloadKeyPressed(GtkAccelGroup* accel_group, | |
| 336 GObject* acceleratable, | |
| 337 guint keyval, | |
| 338 GdkModifierType modifier) { | |
| 339 Reload(); | |
| 340 return TRUE; | |
| 341 } | |
| 342 | |
| 343 void Shell::PlatformSetTitle(const base::string16& title) { | |
| 344 if (headless_) | |
| 345 return; | |
| 346 | |
| 347 std::string title_utf8 = base::UTF16ToUTF8(title); | |
| 348 gtk_window_set_title(GTK_WINDOW(window_), title_utf8.c_str()); | |
| 349 } | |
| 350 | |
| 351 } // namespace content | |
| OLD | NEW |