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