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 |