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 <gdk/gdkkeysyms.h>
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"
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.
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
);
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
);
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
);
58 void Shell::PlatformInitialize(const gfx::Size
& default_window_size
) {
61 void Shell::PlatformCleanUp() {
62 // Nothing to clean up; GTK will clean up the widgets shortly after.
65 void Shell::PlatformEnableUIControl(UIControl control
, bool is_enabled
) {
69 GtkToolItem
* item
= NULL
;
75 item
= forward_button_
;
81 NOTREACHED() << "Unknown UI control";
84 gtk_widget_set_sensitive(GTK_WIDGET(item
), is_enabled
);
87 void Shell::PlatformSetAddressBarURL(const GURL
& url
) {
91 gtk_entry_set_text(GTK_ENTRY(url_edit_view_
), url
.spec().c_str());
94 void Shell::PlatformSetIsLoading(bool loading
) {
99 gtk_spinner_start(GTK_SPINNER(spinner_
));
101 gtk_spinner_stop(GTK_SPINNER(spinner_
));
104 void Shell::PlatformCreateWindow(int width
, int height
) {
105 ui_elements_height_
= 0;
107 content_width_
= width
;
108 content_height_
= height
;
112 window_
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
113 gtk_window_set_title(window_
, "Content Shell");
114 g_signal_connect(G_OBJECT(window_
), "destroy",
115 G_CALLBACK(OnWindowDestroyedThunk
), this);
117 vbox_
= gtk_vbox_new(FALSE
, 0);
119 // Create the menu bar.
120 GtkWidget
* menu_bar
= CreateMenuBar(this);
121 gtk_box_pack_start(GTK_BOX(vbox_
), menu_bar
, FALSE
, FALSE
, 0);
123 // Create the object that mediates accelerators.
124 GtkAccelGroup
* accel_group
= gtk_accel_group_new();
125 gtk_window_add_accel_group(GTK_WINDOW(window_
), accel_group
);
127 // Set global window handling accelerators:
128 gtk_accel_group_connect(
129 accel_group
, GDK_w
, GDK_CONTROL_MASK
,
131 g_cclosure_new(G_CALLBACK(OnCloseWindowKeyPressedThunk
),
134 gtk_accel_group_connect(
135 accel_group
, GDK_n
, GDK_CONTROL_MASK
,
137 g_cclosure_new(G_CALLBACK(OnNewWindowKeyPressedThunk
),
140 gtk_accel_group_connect(
141 accel_group
, GDK_F5
, (GdkModifierType
)0,
143 g_cclosure_new(G_CALLBACK(OnReloadKeyPressedThunk
),
146 GtkWidget
* toolbar
= gtk_toolbar_new();
147 // Turn off the labels on the toolbar buttons.
148 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_ICONS
);
150 back_button_
= gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK
);
151 g_signal_connect(back_button_
, "clicked",
152 G_CALLBACK(&OnBackButtonClickedThunk
), this);
153 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), back_button_
, -1 /* append */);
154 gtk_widget_add_accelerator(GTK_WIDGET(back_button_
), "clicked", accel_group
,
155 GDK_Left
, GDK_MOD1_MASK
, GTK_ACCEL_VISIBLE
);
157 forward_button_
= gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD
);
158 g_signal_connect(forward_button_
, "clicked",
159 G_CALLBACK(&OnForwardButtonClickedThunk
), this);
160 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), forward_button_
, -1 /* append */);
161 gtk_widget_add_accelerator(GTK_WIDGET(forward_button_
), "clicked",
163 GDK_Right
, GDK_MOD1_MASK
, GTK_ACCEL_VISIBLE
);
165 reload_button_
= gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH
);
166 g_signal_connect(reload_button_
, "clicked",
167 G_CALLBACK(&OnReloadButtonClickedThunk
), this);
168 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), reload_button_
, -1 /* append */);
169 gtk_widget_add_accelerator(GTK_WIDGET(reload_button_
), "clicked",
171 GDK_r
, GDK_CONTROL_MASK
, GTK_ACCEL_VISIBLE
);
173 stop_button_
= gtk_tool_button_new_from_stock(GTK_STOCK_STOP
);
174 g_signal_connect(stop_button_
, "clicked",
175 G_CALLBACK(&OnStopButtonClickedThunk
), this);
176 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), stop_button_
, -1 /* append */);
178 url_edit_view_
= gtk_entry_new();
179 g_signal_connect(G_OBJECT(url_edit_view_
), "activate",
180 G_CALLBACK(&OnURLEntryActivateThunk
), this);
182 gtk_accel_group_connect(
183 accel_group
, GDK_l
, GDK_CONTROL_MASK
,
185 g_cclosure_new(G_CALLBACK(OnHighlightURLViewThunk
),
188 GtkToolItem
* tool_item
= gtk_tool_item_new();
189 gtk_container_add(GTK_CONTAINER(tool_item
), url_edit_view_
);
190 gtk_tool_item_set_expand(tool_item
, TRUE
);
191 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), tool_item
, -1 /* append */);
193 // Center a 20x20 spinner in a 26x24 area.
194 GtkWidget
* spinner_alignment
= gtk_alignment_new(0.5, 0.5, 0, 0);
195 gtk_alignment_set_padding(GTK_ALIGNMENT(spinner_alignment
), 2, 2, 4, 4);
196 spinner_
= gtk_spinner_new();
197 gtk_widget_set_size_request(spinner_
, 20, 20);
198 gtk_container_add(GTK_CONTAINER(spinner_alignment
), spinner_
);
200 spinner_item_
= gtk_tool_item_new();
201 gtk_container_add(GTK_CONTAINER(spinner_item_
), spinner_alignment
);
202 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), spinner_item_
, -1 /* append */);
204 gtk_box_pack_start(GTK_BOX(vbox_
), toolbar
, FALSE
, FALSE
, 0);
206 gtk_container_add(GTK_CONTAINER(window_
), vbox_
);
208 // Trigger layout of the UI elements, so that we can measure their
209 // heights. The width and height passed to this method are meant for the web
210 // contents view, not the top-level window. Since Gtk only seems to provide a
211 // suitable resizing function for top-level windows, we need to know how to
212 // convert from web contents view size to top-level window size.
213 gtk_widget_show_all(GTK_WIDGET(vbox_
));
215 // Measure the heights of the UI elements, now that they have been laid out.
216 GtkRequisition elm_size
;
217 gtk_widget_size_request(menu_bar
, &elm_size
);
218 ui_elements_height_
+= elm_size
.height
;
219 gtk_widget_size_request(toolbar
, &elm_size
);
220 ui_elements_height_
+= elm_size
.height
;
222 // We're ready to set an initial window size.
223 SizeTo(width
, height
);
225 // Finally, show the window.
226 gtk_widget_show_all(GTK_WIDGET(window_
));
229 void Shell::PlatformSetContents() {
231 SizeTo(content_width_
, content_height_
);
235 WebContentsView
* content_view
= web_contents_
->GetView();
236 gtk_container_add(GTK_CONTAINER(vbox_
), content_view
->GetNativeView());
239 void Shell::SizeTo(int width
, int height
) {
240 content_width_
= width
;
241 content_height_
= height
;
244 gtk_window_resize(window_
, width
, height
+ ui_elements_height_
);
245 } else if (web_contents_
) {
246 RenderWidgetHostView
* render_widget_host_view
=
247 web_contents_
->GetRenderWidgetHostView();
248 if (render_widget_host_view
)
249 render_widget_host_view
->SetSize(gfx::Size(width
, height
));
253 void Shell::PlatformResizeSubViews() {
254 // Not needed; the subviews are bound.
257 void Shell::Close() {
263 gtk_widget_destroy(GTK_WIDGET(window_
));
266 void Shell::OnBackButtonClicked(GtkWidget
* widget
) {
270 void Shell::OnForwardButtonClicked(GtkWidget
* widget
) {
274 void Shell::OnReloadButtonClicked(GtkWidget
* widget
) {
278 void Shell::OnStopButtonClicked(GtkWidget
* widget
) {
282 void Shell::OnURLEntryActivate(GtkWidget
* entry
) {
283 const gchar
* str
= gtk_entry_get_text(GTK_ENTRY(entry
));
285 if (!url
.has_scheme())
286 url
= GURL(std::string("http://") + std::string(str
));
291 // Callback for when the main window is destroyed.
292 gboolean
Shell::OnWindowDestroyed(GtkWidget
* window
) {
294 return FALSE
; // Don't stop this message.
297 gboolean
Shell::OnCloseWindowKeyPressed(GtkAccelGroup
* accel_group
,
298 GObject
* acceleratable
,
300 GdkModifierType modifier
) {
301 gtk_widget_destroy(GTK_WIDGET(window_
));
305 gboolean
Shell::OnNewWindowKeyPressed(GtkAccelGroup
* accel_group
,
306 GObject
* acceleratable
,
308 GdkModifierType modifier
) {
309 ShellBrowserContext
* browser_context
=
310 ShellContentBrowserClient::Get()->browser_context();
311 Shell::CreateNewWindow(browser_context
,
319 gboolean
Shell::OnHighlightURLView(GtkAccelGroup
* accel_group
,
320 GObject
* acceleratable
,
322 GdkModifierType modifier
) {
323 gtk_widget_grab_focus(GTK_WIDGET(url_edit_view_
));
327 gboolean
Shell::OnReloadKeyPressed(GtkAccelGroup
* accel_group
,
328 GObject
* acceleratable
,
330 GdkModifierType modifier
) {
335 void Shell::PlatformSetTitle(const string16
& title
) {
339 std::string title_utf8
= UTF16ToUTF8(title
);
340 gtk_window_set_title(GTK_WINDOW(window_
), title_utf8
.c_str());
343 } // namespace content