[GTK][WK2] MiniBrowser fullscreen signals support
[WebKit-https.git] / Tools / MiniBrowser / gtk / BrowserWindow.c
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc.
3  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
4  * Copyright (C) 2011 Igalia S.L.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25  * THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "BrowserWindow.h"
29
30 #include "BrowserDownloadsBar.h"
31 #include "BrowserSettingsDialog.h"
32 #include <string.h>
33
34 enum {
35     PROP_0,
36
37     PROP_VIEW
38 };
39
40 struct _BrowserWindow {
41     GtkWindow parent;
42
43     GtkWidget *mainBox;
44     GtkWidget *toolbar;
45     GtkWidget *uriEntry;
46     GtkWidget *backItem;
47     GtkWidget *forwardItem;
48     GtkWidget *zoomInItem;
49     GtkWidget *zoomOutItem;
50     GtkWidget *statusLabel;
51     GtkWidget *settingsDialog;
52     WebKitWebView *webView;
53     GtkWidget *downloadsBar;
54     GdkPixbuf *favicon;
55 #if GTK_CHECK_VERSION(3, 2, 0)
56     GtkWidget *fullScreenMessageLabel;
57     guint fullScreenMessageLabelId;
58 #endif
59 };
60
61 struct _BrowserWindowClass {
62     GtkWindowClass parent;
63 };
64
65 static const char *defaultWindowTitle = "WebKitGTK+ MiniBrowser";
66 static const gdouble minimumZoomLevel = 0.5;
67 static const gdouble maximumZoomLevel = 3;
68 static const gdouble zoomStep = 1.2;
69 static gint windowCount = 0;
70
71 G_DEFINE_TYPE(BrowserWindow, browser_window, GTK_TYPE_WINDOW)
72
73 static void browserWindowSetStatusText(BrowserWindow *window, const char *text)
74 {
75 #if GTK_CHECK_VERSION(3, 2, 0)
76     gtk_label_set_text(GTK_LABEL(window->statusLabel), text);
77     gtk_widget_set_visible(window->statusLabel, !!text);
78 #endif
79 }
80
81 static void resetStatusText(GtkWidget *widget, BrowserWindow *window)
82 {
83     browserWindowSetStatusText(window, NULL);
84 }
85
86 static void activateUriEntryCallback(BrowserWindow *window)
87 {
88     browser_window_load_uri(window, gtk_entry_get_text(GTK_ENTRY(window->uriEntry)));
89 }
90
91 static void reloadCallback(BrowserWindow *window)
92 {
93     webkit_web_view_reload(window->webView);
94 }
95
96 static void goBackCallback(BrowserWindow *window)
97 {
98     webkit_web_view_go_back(window->webView);
99 }
100
101 static void goForwardCallback(BrowserWindow *window)
102 {
103     webkit_web_view_go_forward(window->webView);
104 }
105
106 static void settingsCallback(BrowserWindow *window)
107 {
108     if (window->settingsDialog) {
109         gtk_window_present(GTK_WINDOW(window->settingsDialog));
110         return;
111     }
112
113     window->settingsDialog = browser_settings_dialog_new(webkit_web_view_get_settings(window->webView));
114     gtk_window_set_transient_for(GTK_WINDOW(window->settingsDialog), GTK_WINDOW(window));
115     g_object_add_weak_pointer(G_OBJECT(window->settingsDialog), (gpointer *)&window->settingsDialog);
116     gtk_widget_show(window->settingsDialog);
117 }
118
119 static void webViewURIChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
120 {
121     gtk_entry_set_text(GTK_ENTRY(window->uriEntry), webkit_web_view_get_uri(webView));
122 }
123
124 static void webViewTitleChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
125 {
126     const char *title = webkit_web_view_get_title(webView);
127     gtk_window_set_title(GTK_WINDOW(window), title ? title : defaultWindowTitle);
128 }
129
130 static gboolean resetEntryProgress(GtkEntry *entry)
131 {
132     gtk_entry_set_progress_fraction(entry, 0);
133     return FALSE;
134 }
135
136 static void webViewLoadProgressChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
137 {
138     gdouble progress = webkit_web_view_get_estimated_load_progress(webView);
139     gtk_entry_set_progress_fraction(GTK_ENTRY(window->uriEntry), progress);
140     if (progress == 1.0)
141         g_timeout_add(500, (GSourceFunc)resetEntryProgress, window->uriEntry);
142 }
143
144 static void downloadStarted(WebKitWebContext *webContext, WebKitDownload *download, BrowserWindow *window)
145 {
146     if (!window->downloadsBar) {
147         window->downloadsBar = browser_downloads_bar_new();
148         gtk_box_pack_start(GTK_BOX(window->mainBox), window->downloadsBar, FALSE, FALSE, 0);
149         gtk_box_reorder_child(GTK_BOX(window->mainBox), window->downloadsBar, 0);
150         g_object_add_weak_pointer(G_OBJECT(window->downloadsBar), (gpointer *)&(window->downloadsBar));
151         gtk_widget_show(window->downloadsBar);
152     }
153     browser_downloads_bar_add_download(BROWSER_DOWNLOADS_BAR(window->downloadsBar), download);
154 }
155
156 static void browserWindowHistoryItemSelected(BrowserWindow *window, GtkMenuItem *item)
157 {
158     GtkAction *action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(item));
159     browserWindowSetStatusText(window, action ? gtk_action_get_name(action) : NULL);
160 }
161
162 static void browserWindowHistoryItemActivated(BrowserWindow *window, GtkAction *action)
163 {
164     WebKitBackForwardListItem *item = g_object_get_data(G_OBJECT(action), "back-forward-list-item");
165     if (!item)
166         return;
167
168     webkit_web_view_go_to_back_forward_list_item(window->webView, item);
169 }
170
171 static GtkWidget *browserWindowCreateBackForwardMenu(BrowserWindow *window, GList *list)
172 {
173     if (!list)
174         return NULL;
175
176     GtkWidget *menu = gtk_menu_new();
177     GList *listItem;
178     for (listItem = list; listItem; listItem = g_list_next(listItem)) {
179         WebKitBackForwardListItem *item = (WebKitBackForwardListItem *)listItem->data;
180         const char *uri = webkit_back_forward_list_item_get_uri(item);
181         const char *title = webkit_back_forward_list_item_get_title(item);
182
183         GtkAction *action = gtk_action_new(uri, title, NULL, NULL);
184         g_object_set_data_full(G_OBJECT(action), "back-forward-list-item", g_object_ref(item), g_object_unref);
185         g_signal_connect_swapped(action, "activate", G_CALLBACK(browserWindowHistoryItemActivated), window);
186
187         GtkWidget *menuItem = gtk_action_create_menu_item(action);
188         g_signal_connect_swapped(menuItem, "select", G_CALLBACK(browserWindowHistoryItemSelected), window);
189         g_object_unref(action);
190
191         gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuItem);
192         gtk_widget_show(menuItem);
193     }
194
195     g_signal_connect(menu, "hide", G_CALLBACK(resetStatusText), window);
196
197     return menu;
198 }
199
200 static void browserWindowUpdateNavigationActions(BrowserWindow *window, WebKitBackForwardList *backForwadlist)
201 {
202     gtk_widget_set_sensitive(window->backItem, webkit_web_view_can_go_back(window->webView));
203     gtk_widget_set_sensitive(window->forwardItem, webkit_web_view_can_go_forward(window->webView));
204
205     GList *list = webkit_back_forward_list_get_back_list_with_limit(backForwadlist, 10);
206     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->backItem),
207                                   browserWindowCreateBackForwardMenu(window, list));
208     g_list_free(list);
209
210     list = webkit_back_forward_list_get_forward_list_with_limit(backForwadlist, 10);
211     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->forwardItem),
212                                   browserWindowCreateBackForwardMenu(window, list));
213     g_list_free(list);
214 }
215
216 static void backForwadlistChanged(WebKitBackForwardList *backForwadlist, WebKitBackForwardListItem *itemAdded, GList *itemsRemoved, BrowserWindow *window)
217 {
218     browserWindowUpdateNavigationActions(window, backForwadlist);
219 }
220
221 static void geolocationRequestDialogCallback(GtkDialog *dialog, gint response, WebKitPermissionRequest *request)
222 {
223     switch (response) {
224     case GTK_RESPONSE_YES:
225         webkit_permission_request_allow(request);
226         break;
227     default:
228         webkit_permission_request_deny(request);
229         break;
230     }
231
232     gtk_widget_destroy(GTK_WIDGET(dialog));
233     g_object_unref(request);
234 }
235
236 static void webViewClose(WebKitWebView *webView, BrowserWindow *window)
237 {
238     gtk_widget_destroy(GTK_WIDGET(window));
239 }
240
241 static void webViewRunAsModal(WebKitWebView *webView, BrowserWindow *window)
242 {
243     gtk_window_set_modal(GTK_WINDOW(window), TRUE);
244 }
245
246 static void webViewReadyToShow(WebKitWebView *webView, BrowserWindow *window)
247 {
248     WebKitWindowProperties *windowProperties = webkit_web_view_get_window_properties(webView);
249
250     GdkRectangle geometry;
251     webkit_window_properties_get_geometry(windowProperties, &geometry);
252     if (geometry.x >= 0 && geometry.y >= 0)
253         gtk_window_move(GTK_WINDOW(window), geometry.x, geometry.y);
254     if (geometry.width > 0 && geometry.height > 0)
255         gtk_window_resize(GTK_WINDOW(window), geometry.width, geometry.height);
256
257     if (!webkit_window_properties_get_toolbar_visible(windowProperties))
258         gtk_widget_hide(window->toolbar);
259     else if (!webkit_window_properties_get_locationbar_visible(windowProperties))
260         gtk_widget_hide(window->uriEntry);
261
262     if (!webkit_window_properties_get_resizable(windowProperties))
263         gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
264
265     gtk_widget_show(GTK_WIDGET(window));
266 }
267
268 #if GTK_CHECK_VERSION(3, 2, 0)
269 static gboolean fullScreenMessageTimeoutCallback(BrowserWindow *window)
270 {
271     gtk_widget_hide(window->fullScreenMessageLabel);
272     window->fullScreenMessageLabelId = 0;
273     return FALSE;
274 }
275 #endif
276
277 static gboolean webViewEnterFullScreen(WebKitWebView *webView, BrowserWindow *window)
278 {
279 #if GTK_CHECK_VERSION(3, 2, 0)
280     const gchar *titleOrURI = webkit_web_view_get_title(window->webView);
281     if (!titleOrURI)
282         titleOrURI = webkit_web_view_get_uri(window->webView);
283     gchar *message = g_strdup_printf("%s is now full screen. Press ESC or f to exit.", titleOrURI);
284     gtk_label_set_text(GTK_LABEL(window->fullScreenMessageLabel), message);
285     g_free(message);
286
287     gtk_widget_show(window->fullScreenMessageLabel);
288
289     window->fullScreenMessageLabelId = g_timeout_add_seconds(2, (GSourceFunc)fullScreenMessageTimeoutCallback, window);
290 #endif
291
292     gtk_widget_hide(window->toolbar);
293
294     return FALSE;
295 }
296
297 static gboolean webViewLeaveFullScreen(WebKitWebView *webView, BrowserWindow *window)
298 {
299 #if GTK_CHECK_VERSION(3, 2, 0)
300     if (window->fullScreenMessageLabelId) {
301         g_source_remove(window->fullScreenMessageLabelId);
302         window->fullScreenMessageLabelId = 0;
303     }
304     gtk_widget_hide(window->fullScreenMessageLabel);
305 #endif
306
307     gtk_widget_show(window->toolbar);
308
309     return FALSE;
310 }
311
312 static GtkWidget *webViewCreate(WebKitWebView *webView, BrowserWindow *window)
313 {
314     WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(webkit_web_view_get_context(webView)));
315     webkit_web_view_set_settings(newWebView, webkit_web_view_get_settings(webView));
316
317     GtkWidget *newWindow = browser_window_new(newWebView, GTK_WINDOW(window));
318     g_signal_connect(newWebView, "ready-to-show", G_CALLBACK(webViewReadyToShow), newWindow);
319     g_signal_connect(newWebView, "run-as-modal", G_CALLBACK(webViewRunAsModal), newWindow);
320     g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), newWindow);
321     return GTK_WIDGET(newWebView);
322 }
323
324 static gboolean webViewLoadFailed(WebKitWebView *webView, WebKitLoadEvent loadEvent, const char *failingURI, GError *error, BrowserWindow *window)
325 {
326     gtk_entry_set_progress_fraction(GTK_ENTRY(window->uriEntry), 0.);
327     return FALSE;
328 }
329
330 static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, BrowserWindow *window)
331 {
332     if (decisionType != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
333         return FALSE;
334
335     WebKitNavigationPolicyDecision *navigationDecision = WEBKIT_NAVIGATION_POLICY_DECISION(decision);
336     if (webkit_navigation_policy_decision_get_navigation_type(navigationDecision) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED
337         || webkit_navigation_policy_decision_get_mouse_button(navigationDecision) != 2)
338         return FALSE;
339
340     WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(webkit_web_view_get_context(webView)));
341     webkit_web_view_set_settings(newWebView, webkit_web_view_get_settings(webView));
342     GtkWidget *newWindow = browser_window_new(newWebView, GTK_WINDOW(window));
343     webkit_web_view_load_request(newWebView, webkit_navigation_policy_decision_get_request(navigationDecision));
344     gtk_widget_show(newWindow);
345
346     webkit_policy_decision_ignore(decision);
347     return TRUE;
348 }
349
350 static gboolean webViewDecidePermissionRequest(WebKitWebView *webView, WebKitPermissionRequest *request, BrowserWindow *window)
351 {
352     if (!WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(request))
353         return FALSE;
354
355     GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window),
356                                                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
357                                                GTK_MESSAGE_QUESTION,
358                                                GTK_BUTTONS_YES_NO,
359                                                "Geolocation request");
360
361     gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "Allow geolocation request?");
362     g_signal_connect(dialog, "response", G_CALLBACK(geolocationRequestDialogCallback), g_object_ref(request));
363     gtk_widget_show(dialog);
364
365     return TRUE;
366 }
367
368 static void webViewMouseTargetChanged(WebKitWebView *webView, WebKitHitTestResult *hitTestResult, guint mouseModifiers, BrowserWindow *window)
369 {
370     if (!webkit_hit_test_result_context_is_link(hitTestResult)) {
371         browserWindowSetStatusText(window, NULL);
372         return;
373     }
374     browserWindowSetStatusText(window, webkit_hit_test_result_get_link_uri(hitTestResult));
375 }
376
377 static gboolean browserWindowCanZoomIn(BrowserWindow *window)
378 {
379     gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) * zoomStep;
380     return zoomLevel < maximumZoomLevel;
381 }
382
383 static gboolean browserWindowCanZoomOut(BrowserWindow *window)
384 {
385     gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) / zoomStep;
386     return zoomLevel > minimumZoomLevel;
387 }
388
389 static void browserWindowUpdateZoomActions(BrowserWindow *window)
390 {
391     gtk_widget_set_sensitive(window->zoomInItem, browserWindowCanZoomIn(window));
392     gtk_widget_set_sensitive(window->zoomOutItem, browserWindowCanZoomOut(window));
393 }
394
395 static void webViewZoomLevelChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow *window)
396 {
397     browserWindowUpdateZoomActions(window);
398 }
399
400 static void updateUriEntryIcon(BrowserWindow *window)
401 {
402     GtkEntry *entry = GTK_ENTRY(window->uriEntry);
403     if (window->favicon)
404         gtk_entry_set_icon_from_pixbuf(entry, GTK_ENTRY_ICON_PRIMARY, window->favicon);
405     else
406         gtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_NEW);
407 }
408
409 static void faviconChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow *window)
410 {
411     GdkPixbuf *favicon = NULL;
412     cairo_surface_t *surface = webkit_web_view_get_favicon(window->webView);
413
414     if (surface) {
415         int width = cairo_image_surface_get_width(surface);
416         int height = cairo_image_surface_get_height(surface);
417         favicon = gdk_pixbuf_get_from_surface(surface, 0, 0, width, height);
418     }
419
420     if (window->favicon)
421         g_object_unref(window->favicon);
422     window->favicon = favicon;
423
424     updateUriEntryIcon(window);
425 }
426
427 static void zoomInCallback(BrowserWindow *window)
428 {
429     gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) * zoomStep;
430     webkit_web_view_set_zoom_level(window->webView, zoomLevel);
431 }
432
433 static void zoomOutCallback(BrowserWindow *window)
434 {
435     gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) / zoomStep;
436     webkit_web_view_set_zoom_level(window->webView, zoomLevel);
437 }
438
439 static void browserWindowFinalize(GObject *gObject)
440 {
441     BrowserWindow *window = BROWSER_WINDOW(gObject);
442     if (window->favicon) {
443         g_object_unref(window->favicon);
444         window->favicon = NULL;
445     }
446
447 #if GTK_CHECK_VERSION(3, 2, 0)
448     if (window->fullScreenMessageLabelId)
449         g_source_remove(window->fullScreenMessageLabelId);
450 #endif
451
452     G_OBJECT_CLASS(browser_window_parent_class)->finalize(gObject);
453
454     if (g_atomic_int_dec_and_test(&windowCount))
455         gtk_main_quit();
456 }
457
458 static void browserWindowGetProperty(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
459 {
460     BrowserWindow *window = BROWSER_WINDOW(object);
461
462     switch (propId) {
463     case PROP_VIEW:
464         g_value_set_object(value, browser_window_get_view(window));
465         break;
466     default:
467         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
468     }
469 }
470
471 static void browserWindowSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
472 {
473     BrowserWindow* window = BROWSER_WINDOW(object);
474
475     switch (propId) {
476     case PROP_VIEW:
477         window->webView = g_value_get_object(value);
478         break;
479     default:
480         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
481     }
482 }
483
484 static void browser_window_init(BrowserWindow *window)
485 {
486     g_atomic_int_inc(&windowCount);
487
488     gtk_window_set_title(GTK_WINDOW(window), defaultWindowTitle);
489     gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
490
491     window->uriEntry = gtk_entry_new();
492     g_signal_connect_swapped(window->uriEntry, "activate", G_CALLBACK(activateUriEntryCallback), (gpointer)window);
493     gtk_entry_set_icon_activatable(GTK_ENTRY(window->uriEntry), GTK_ENTRY_ICON_PRIMARY, FALSE);
494     updateUriEntryIcon(window);
495
496     GtkWidget *toolbar = gtk_toolbar_new();
497     window->toolbar = toolbar;
498     gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
499     gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
500
501     GtkToolItem *item = gtk_menu_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
502     window->backItem = GTK_WIDGET(item);
503     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(item), 0);
504     g_signal_connect_swapped(item, "clicked", G_CALLBACK(goBackCallback), (gpointer)window);
505     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
506     gtk_widget_show(GTK_WIDGET(item));
507
508     item = gtk_menu_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
509     window->forwardItem = GTK_WIDGET(item);
510     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(item), 0);
511     g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(goForwardCallback), (gpointer)window);
512     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
513     gtk_widget_show(GTK_WIDGET(item));
514
515     item = gtk_tool_button_new_from_stock(GTK_STOCK_PREFERENCES);
516     g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(settingsCallback), window);
517     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
518     gtk_widget_show(GTK_WIDGET(item));
519
520     item = gtk_tool_button_new_from_stock(GTK_STOCK_ZOOM_OUT);
521     window->zoomOutItem = GTK_WIDGET(item);
522     g_signal_connect_swapped(item, "clicked", G_CALLBACK(zoomOutCallback), window);
523     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
524     gtk_widget_show(GTK_WIDGET(item));
525
526     item = gtk_tool_button_new_from_stock(GTK_STOCK_ZOOM_IN);
527     window->zoomInItem = GTK_WIDGET(item);
528     g_signal_connect_swapped(item, "clicked", G_CALLBACK(zoomInCallback), window);
529     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
530     gtk_widget_show(GTK_WIDGET(item));
531
532     item = gtk_tool_item_new();
533     gtk_tool_item_set_expand(item, TRUE);
534     gtk_container_add(GTK_CONTAINER(item), window->uriEntry);
535     gtk_widget_show(window->uriEntry);
536     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
537     gtk_widget_show(GTK_WIDGET(item));
538
539     item = gtk_tool_button_new_from_stock(GTK_STOCK_OK);
540     g_signal_connect_swapped(item, "clicked", G_CALLBACK(reloadCallback), window);
541     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
542     gtk_widget_show(GTK_WIDGET(item));
543
544     GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
545     window->mainBox = vbox;
546     gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
547     gtk_widget_show(toolbar);
548
549     gtk_container_add(GTK_CONTAINER(window), vbox);
550     gtk_widget_show(vbox);
551 }
552
553 static void browserWindowConstructed(GObject *gObject)
554 {
555     BrowserWindow *window = BROWSER_WINDOW(gObject);
556
557     browserWindowUpdateZoomActions(window);
558
559     g_signal_connect(window->webView, "notify::uri", G_CALLBACK(webViewURIChanged), window);
560     g_signal_connect(window->webView, "notify::estimated-load-progress", G_CALLBACK(webViewLoadProgressChanged), window);
561     g_signal_connect(window->webView, "notify::title", G_CALLBACK(webViewTitleChanged), window);
562     g_signal_connect(window->webView, "create", G_CALLBACK(webViewCreate), window);
563     g_signal_connect(window->webView, "load-failed", G_CALLBACK(webViewLoadFailed), window);
564     g_signal_connect(window->webView, "decide-policy", G_CALLBACK(webViewDecidePolicy), window);
565     g_signal_connect(window->webView, "permission-request", G_CALLBACK(webViewDecidePermissionRequest), window);
566     g_signal_connect(window->webView, "mouse-target-changed", G_CALLBACK(webViewMouseTargetChanged), window);
567     g_signal_connect(window->webView, "notify::zoom-level", G_CALLBACK(webViewZoomLevelChanged), window);
568     g_signal_connect(window->webView, "notify::favicon", G_CALLBACK(faviconChanged), window);
569     g_signal_connect(window->webView, "enter-fullscreen", G_CALLBACK(webViewEnterFullScreen), window);
570     g_signal_connect(window->webView, "leave-fullscreen", G_CALLBACK(webViewLeaveFullScreen), window);
571
572     g_signal_connect(webkit_web_view_get_context(window->webView), "download-started", G_CALLBACK(downloadStarted), window);
573
574     WebKitBackForwardList *backForwadlist = webkit_web_view_get_back_forward_list(window->webView);
575     g_signal_connect(backForwadlist, "changed", G_CALLBACK(backForwadlistChanged), window);
576
577 #if GTK_CHECK_VERSION(3, 2, 0)
578     GtkWidget *overlay = gtk_overlay_new();
579     gtk_box_pack_start(GTK_BOX(window->mainBox), overlay, TRUE, TRUE, 0);
580     gtk_widget_show(overlay);
581
582     window->statusLabel = gtk_label_new(NULL);
583     gtk_widget_set_halign(window->statusLabel, GTK_ALIGN_START);
584     gtk_widget_set_valign(window->statusLabel, GTK_ALIGN_END);
585     gtk_widget_set_margin_left(window->statusLabel, 1);
586     gtk_widget_set_margin_right(window->statusLabel, 1);
587     gtk_widget_set_margin_top(window->statusLabel, 1);
588     gtk_widget_set_margin_bottom(window->statusLabel, 1);
589     gtk_overlay_add_overlay(GTK_OVERLAY(overlay), window->statusLabel);
590
591     gtk_container_add(GTK_CONTAINER(overlay), GTK_WIDGET(window->webView));
592
593     window->fullScreenMessageLabel = gtk_label_new(NULL);
594     gtk_widget_set_halign(window->fullScreenMessageLabel, GTK_ALIGN_CENTER);
595     gtk_widget_set_valign(window->fullScreenMessageLabel, GTK_ALIGN_CENTER);
596     gtk_widget_set_no_show_all(window->fullScreenMessageLabel, TRUE);
597     gtk_overlay_add_overlay(GTK_OVERLAY(overlay), window->fullScreenMessageLabel);
598 #else
599     gtk_box_pack_start(GTK_BOX(window->mainBox), GTK_WIDGET(window->webView), TRUE, TRUE, 0);
600 #endif
601     gtk_widget_show(GTK_WIDGET(window->webView));
602 }
603
604 static void browser_window_class_init(BrowserWindowClass *klass)
605 {
606     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
607
608     gobjectClass->constructed = browserWindowConstructed;
609     gobjectClass->get_property = browserWindowGetProperty;
610     gobjectClass->set_property = browserWindowSetProperty;
611     gobjectClass->finalize = browserWindowFinalize;
612
613     g_object_class_install_property(gobjectClass,
614                                     PROP_VIEW,
615                                     g_param_spec_object("view",
616                                                         "View",
617                                                         "The web view of this window",
618                                                         WEBKIT_TYPE_WEB_VIEW,
619                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
620 }
621
622 // Public API.
623 GtkWidget *browser_window_new(WebKitWebView *view, GtkWindow *parent)
624 {
625     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(view), 0);
626
627     return GTK_WIDGET(g_object_new(BROWSER_TYPE_WINDOW,
628                                    "transient-for", parent,
629                                    "type", GTK_WINDOW_TOPLEVEL,
630                                    "view", view, NULL));
631 }
632
633 WebKitWebView *browser_window_get_view(BrowserWindow *window)
634 {
635     g_return_val_if_fail(BROWSER_IS_WINDOW(window), 0);
636
637     return window->webView;
638 }
639
640 void browser_window_load_uri(BrowserWindow *window, const char *uri)
641 {
642     g_return_if_fail(BROWSER_IS_WINDOW(window));
643     g_return_if_fail(uri);
644
645     if (!g_str_has_prefix(uri, "javascript:")) {
646         webkit_web_view_load_uri(window->webView, uri);
647         return;
648     }
649
650     webkit_web_view_run_javascript(window->webView, strstr(uri, "javascript:"), NULL, NULL, NULL);
651 }