- add sources.
[platform/framework/web/crosswalk.git] / src / content / shell / browser / shell_gtk.cc
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::PlatformCleanUp() {
62   // Nothing to clean up; GTK will clean up the widgets shortly after.
63 }
64
65 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
66   if (headless_)
67     return;
68
69   GtkToolItem* item = NULL;
70   switch (control) {
71     case BACK_BUTTON:
72       item = back_button_;
73       break;
74     case FORWARD_BUTTON:
75       item = forward_button_;
76       break;
77     case STOP_BUTTON:
78       item = stop_button_;
79       break;
80     default:
81       NOTREACHED() << "Unknown UI control";
82       return;
83   }
84   gtk_widget_set_sensitive(GTK_WIDGET(item), is_enabled);
85 }
86
87 void Shell::PlatformSetAddressBarURL(const GURL& url) {
88   if (headless_)
89     return;
90
91   gtk_entry_set_text(GTK_ENTRY(url_edit_view_), url.spec().c_str());
92 }
93
94 void Shell::PlatformSetIsLoading(bool loading) {
95   if (headless_)
96     return;
97
98   if (loading)
99     gtk_spinner_start(GTK_SPINNER(spinner_));
100   else
101     gtk_spinner_stop(GTK_SPINNER(spinner_));
102 }
103
104 void Shell::PlatformCreateWindow(int width, int height) {
105   ui_elements_height_ = 0;
106   if (headless_) {
107     content_width_ = width;
108     content_height_ = height;
109     return;
110   }
111
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);
116
117   vbox_ = gtk_vbox_new(FALSE, 0);
118
119   // Create the menu bar.
120   GtkWidget* menu_bar = CreateMenuBar(this);
121   gtk_box_pack_start(GTK_BOX(vbox_), menu_bar, FALSE, FALSE, 0);
122
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);
126
127   // Set global window handling accelerators:
128   gtk_accel_group_connect(
129       accel_group, GDK_w, GDK_CONTROL_MASK,
130       GTK_ACCEL_VISIBLE,
131       g_cclosure_new(G_CALLBACK(OnCloseWindowKeyPressedThunk),
132                      this, NULL));
133
134   gtk_accel_group_connect(
135       accel_group, GDK_n, GDK_CONTROL_MASK,
136       GTK_ACCEL_VISIBLE,
137       g_cclosure_new(G_CALLBACK(OnNewWindowKeyPressedThunk),
138                     this, NULL));
139
140   gtk_accel_group_connect(
141     accel_group, GDK_F5, (GdkModifierType)0,
142       GTK_ACCEL_VISIBLE,
143       g_cclosure_new(G_CALLBACK(OnReloadKeyPressedThunk),
144                     this, NULL));
145
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);
149
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);
156
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",
162                              accel_group,
163                              GDK_Right, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
164
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",
170                              accel_group,
171                              GDK_r, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
172
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 */);
177
178   url_edit_view_ = gtk_entry_new();
179   g_signal_connect(G_OBJECT(url_edit_view_), "activate",
180                    G_CALLBACK(&OnURLEntryActivateThunk), this);
181
182   gtk_accel_group_connect(
183       accel_group, GDK_l, GDK_CONTROL_MASK,
184       GTK_ACCEL_VISIBLE,
185       g_cclosure_new(G_CALLBACK(OnHighlightURLViewThunk),
186                      this, NULL));
187
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 */);
192
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_);
199
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 */);
203
204   gtk_box_pack_start(GTK_BOX(vbox_), toolbar, FALSE, FALSE, 0);
205
206   gtk_container_add(GTK_CONTAINER(window_), vbox_);
207
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_));
214
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;
221
222   // We're ready to set an initial window size.
223   SizeTo(width, height);
224
225   // Finally, show the window.
226   gtk_widget_show_all(GTK_WIDGET(window_));
227 }
228
229 void Shell::PlatformSetContents() {
230   if (headless_) {
231     SizeTo(content_width_, content_height_);
232     return;
233   }
234
235   WebContentsView* content_view = web_contents_->GetView();
236   gtk_container_add(GTK_CONTAINER(vbox_), content_view->GetNativeView());
237 }
238
239 void Shell::SizeTo(int width, int height) {
240   content_width_ = width;
241   content_height_ = height;
242
243   if (window_) {
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));
250   }
251 }
252
253 void Shell::PlatformResizeSubViews() {
254   // Not needed; the subviews are bound.
255 }
256
257 void Shell::Close() {
258   if (headless_) {
259     delete this;
260     return;
261   }
262
263   gtk_widget_destroy(GTK_WIDGET(window_));
264 }
265
266 void Shell::OnBackButtonClicked(GtkWidget* widget) {
267   GoBackOrForward(-1);
268 }
269
270 void Shell::OnForwardButtonClicked(GtkWidget* widget) {
271   GoBackOrForward(1);
272 }
273
274 void Shell::OnReloadButtonClicked(GtkWidget* widget) {
275   Reload();
276 }
277
278 void Shell::OnStopButtonClicked(GtkWidget* widget) {
279   Stop();
280 }
281
282 void Shell::OnURLEntryActivate(GtkWidget* entry) {
283   const gchar* str = gtk_entry_get_text(GTK_ENTRY(entry));
284   GURL url(str);
285   if (!url.has_scheme())
286     url = GURL(std::string("http://") + std::string(str));
287   if (url.is_valid())
288     LoadURL(url);
289 }
290
291 // Callback for when the main window is destroyed.
292 gboolean Shell::OnWindowDestroyed(GtkWidget* window) {
293   delete this;
294   return FALSE;  // Don't stop this message.
295 }
296
297 gboolean Shell::OnCloseWindowKeyPressed(GtkAccelGroup* accel_group,
298                                         GObject* acceleratable,
299                                         guint keyval,
300                                         GdkModifierType modifier) {
301   gtk_widget_destroy(GTK_WIDGET(window_));
302   return TRUE;
303 }
304
305 gboolean Shell::OnNewWindowKeyPressed(GtkAccelGroup* accel_group,
306                                       GObject* acceleratable,
307                                       guint keyval,
308                                       GdkModifierType modifier) {
309   ShellBrowserContext* browser_context =
310       ShellContentBrowserClient::Get()->browser_context();
311   Shell::CreateNewWindow(browser_context,
312                          GURL(),
313                          NULL,
314                          MSG_ROUTING_NONE,
315                          gfx::Size());
316   return TRUE;
317 }
318
319 gboolean Shell::OnHighlightURLView(GtkAccelGroup* accel_group,
320                                    GObject* acceleratable,
321                                    guint keyval,
322                                    GdkModifierType modifier) {
323   gtk_widget_grab_focus(GTK_WIDGET(url_edit_view_));
324   return TRUE;
325 }
326
327 gboolean Shell::OnReloadKeyPressed(GtkAccelGroup* accel_group,
328                                    GObject* acceleratable,
329                                    guint keyval,
330                                    GdkModifierType modifier) {
331   Reload();
332   return TRUE;
333 }
334
335 void Shell::PlatformSetTitle(const string16& title) {
336   if (headless_)
337     return;
338
339   std::string title_utf8 = UTF16ToUTF8(title);
340   gtk_window_set_title(GTK_WINDOW(window_), title_utf8.c_str());
341 }
342
343 }  // namespace content