initial import
[vuplus_webkit] / 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 enum {
31     PROP_0,
32
33     PROP_VIEW
34 };
35
36 struct _BrowserWindow {
37     GtkWindow parent;
38
39     GtkWidget *mainBox;
40     GtkWidget *uriEntry;
41     GtkWidget *statusBar;
42     GtkWidget *backItem;
43     GtkWidget *forwardItem;
44     WKViewRef webView;
45
46     guint statusBarContextId;
47     WKBackForwardListRef history;
48
49     gchar *title;
50     gdouble loadProgress;
51 };
52
53 struct _BrowserWindowClass {
54     GtkWindowClass parent;
55 };
56
57 static void browserWindowLoaderClientInit(BrowserWindow*);
58 static void browserWindowUIClientInit(BrowserWindow*);
59 static void browserWindowPolicyClientInit(BrowserWindow*);
60
61 static gint windowCount = 0;
62
63 G_DEFINE_TYPE(BrowserWindow, browser_window, GTK_TYPE_WINDOW)
64
65 static void activateUriEntryCallback(BrowserWindow* window)
66 {
67     const gchar *uri = gtk_entry_get_text(GTK_ENTRY(window->uriEntry));
68     WKPageLoadURL(WKViewGetPage(window->webView), WKURLCreateWithUTF8CString(uri));
69 }
70
71 static void goBackCallback(BrowserWindow* window)
72 {
73     WKPageGoBack(WKViewGetPage(window->webView));
74 }
75
76 static void goForwardCallback(BrowserWindow* window)
77 {
78     WKPageGoForward(WKViewGetPage(window->webView));
79 }
80
81 static void browserWindowFinalize(GObject* gObject)
82 {
83     BrowserWindow* window = BROWSER_WINDOW(gObject);
84
85     g_free(window->title);
86
87     G_OBJECT_CLASS(browser_window_parent_class)->finalize(gObject);
88
89     if (g_atomic_int_dec_and_test(&windowCount))
90         gtk_main_quit();
91 }
92
93 static void browserWindowGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* pspec)
94 {
95     BrowserWindow* window = BROWSER_WINDOW(object);
96
97     switch (propId) {
98     case PROP_VIEW:
99         g_value_set_object(value, (gpointer)browser_window_get_view(window));
100         break;
101     default:
102         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
103     }
104 }
105
106 static void browserWindowSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* pspec)
107 {
108     BrowserWindow* window = BROWSER_WINDOW(object);
109
110     switch (propId) {
111     case PROP_VIEW:
112         window->webView = g_value_get_object(value);
113         break;
114     default:
115         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
116     }
117 }
118
119 static void browser_window_init(BrowserWindow* window)
120 {
121     g_atomic_int_inc(&windowCount);
122
123     gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
124
125     window->uriEntry = gtk_entry_new();
126     g_signal_connect_swapped(window->uriEntry, "activate", G_CALLBACK(activateUriEntryCallback), (gpointer)window);
127
128     GtkWidget *toolbar = gtk_toolbar_new();
129 #if GTK_CHECK_VERSION(2, 15, 0)
130     gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
131 #else
132     gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL);
133 #endif
134     gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
135
136     GtkToolItem *item = gtk_menu_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
137     window->backItem = GTK_WIDGET(item);
138     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(item), 0);
139     g_signal_connect_swapped(item, "clicked", G_CALLBACK(goBackCallback), (gpointer)window);
140     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
141     gtk_widget_show(GTK_WIDGET(item));
142
143     item = gtk_menu_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
144     window->forwardItem = GTK_WIDGET(item);
145     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(item), 0);
146     g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(goForwardCallback), (gpointer)window);
147     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
148     gtk_widget_show(GTK_WIDGET(item));
149
150     item = gtk_tool_item_new();
151     gtk_tool_item_set_expand(item, TRUE);
152     gtk_container_add(GTK_CONTAINER(item), window->uriEntry);
153     gtk_widget_show(window->uriEntry);
154     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
155     gtk_widget_show(GTK_WIDGET(item));
156
157     item = gtk_tool_button_new_from_stock(GTK_STOCK_OK);
158     g_signal_connect_swapped(item, "clicked", G_CALLBACK(activateUriEntryCallback), (gpointer)window);
159     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
160     gtk_widget_show(GTK_WIDGET(item));
161
162     GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
163     window->mainBox = vbox;
164     gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
165     gtk_widget_show(toolbar);
166
167     gtk_container_add(GTK_CONTAINER(window), vbox);
168     gtk_widget_show(vbox);
169 }
170
171 static void browserWindowConstructed(GObject* gObject)
172 {
173     BrowserWindow* window = BROWSER_WINDOW(gObject);
174
175     gtk_box_pack_start(GTK_BOX(window->mainBox), GTK_WIDGET(window->webView), TRUE, TRUE, 0);
176     gtk_widget_show(GTK_WIDGET(window->webView));
177
178     window->statusBar = gtk_statusbar_new();
179     window->statusBarContextId = gtk_statusbar_get_context_id(GTK_STATUSBAR(window->statusBar), "Link Hover");
180     gtk_box_pack_start(GTK_BOX(window->mainBox), window->statusBar, FALSE, FALSE, 0);
181     gtk_widget_show(window->statusBar);
182
183     window->history = WKPageGetBackForwardList(WKViewGetPage(window->webView));
184
185     browserWindowLoaderClientInit(window);
186     browserWindowUIClientInit(window);
187     browserWindowPolicyClientInit(window);
188 }
189
190 static void browser_window_class_init(BrowserWindowClass* klass)
191 {
192     GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
193     gobjectClass->constructed = browserWindowConstructed;
194     gobjectClass->get_property = browserWindowGetProperty;
195     gobjectClass->set_property = browserWindowSetProperty;
196     gobjectClass->finalize = browserWindowFinalize;
197
198     g_object_class_install_property(gobjectClass,
199                                     PROP_VIEW,
200                                     g_param_spec_object("view",
201                                                         "View",
202                                                         "The web view of this window",
203                                                         GTK_TYPE_WIDGET,
204                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
205 }
206
207 static char* WKStringGetCString(WKStringRef string)
208 {
209     size_t length = WKStringGetMaximumUTF8CStringSize(string);
210     char *buffer = (char *) g_malloc(length);
211     WKStringGetUTF8CString(string, buffer, length);
212     return buffer;
213 }
214
215 static char* WKURLGetCString(WKURLRef url)
216 {
217     WKStringRef urlString = WKURLCopyString(url);
218     char *urlText = WKStringGetCString(urlString);
219     WKRelease(urlString);
220     return urlText;
221 }
222
223 static void browserWindowUpdateTitle(BrowserWindow* window)
224 {
225     GString *string = g_string_new(window->title);
226     gdouble loadProgress = window->loadProgress * 100;
227     g_string_append(string, " - WebKit Launcher");
228     if (loadProgress < 100)
229         g_string_append_printf(string, " (%f%%)", loadProgress);
230     gchar *title = g_string_free(string, FALSE);
231     gtk_window_set_title(GTK_WINDOW(window), title);
232     g_free(title);
233 }
234
235 static void browserWindowSetTitle(BrowserWindow* window, const gchar* title)
236 {
237     if (!g_strcmp0(window->title, title))
238         return;
239
240     g_free(window->title);
241     window->title = g_strdup(title);
242     browserWindowUpdateTitle(window);
243 }
244
245 static void browserWindowSetLoadProgress(BrowserWindow* window, gdouble progress)
246 {
247     window->loadProgress = progress;
248     browserWindowUpdateTitle(window);
249 }
250
251 static void browserWindowUpdateURL(BrowserWindow* window, WKURLRef url)
252 {
253     if (!url) {
254         gtk_entry_set_text(GTK_ENTRY(window->uriEntry), "");
255         return;
256     }
257
258     char *urlText = WKURLGetCString(url);
259     gtk_entry_set_text(GTK_ENTRY(window->uriEntry), urlText);
260     g_free(urlText);
261 }
262
263 static void browserWindowHistoryItemActivated(BrowserWindow *window, GtkAction *action)
264 {
265     WKBackForwardListItemRef item = g_object_get_data(G_OBJECT(action), "back-forward-list-item");
266     if (!item)
267         return;
268
269     WKPageGoToBackForwardListItem(WKViewGetPage(window->webView), item);
270 }
271
272 static void browserWindowHistoryItemSelected(BrowserWindow *window, GtkMenuItem *item)
273 {
274     gtk_statusbar_pop(GTK_STATUSBAR(window->statusBar), window->statusBarContextId);
275
276     GtkAction *action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(item));
277     if (!action)
278         return;
279
280     gtk_statusbar_push(GTK_STATUSBAR(window->statusBar), window->statusBarContextId, gtk_action_get_name(action));
281 }
282
283 static GtkAction *createGtkActionFromBackForwardItem(WKBackForwardListItemRef item)
284 {
285     if (!item)
286         return 0;
287
288     WKURLRef url = WKBackForwardListItemCopyURL(item);
289     char *name = WKURLGetCString(url);
290     WKRelease(url);
291
292     WKStringRef title = WKBackForwardListItemCopyTitle(item);
293     char *label = WKStringGetCString(title);
294     WKRelease(title);
295
296     GtkAction *action = gtk_action_new(name, label, 0, 0);
297     g_free(name);
298     g_free(label);
299
300     return action;
301 }
302
303 static GtkWidget *browserWindowCreateMenuItemFromBackForwardItem(BrowserWindow *window, WKBackForwardListItemRef item)
304 {
305     GtkAction *action = createGtkActionFromBackForwardItem(item);
306     if (!action)
307         return 0;
308
309     g_object_set_data_full(G_OBJECT(action), "back-forward-list-item", (gpointer)WKRetain(item), (GDestroyNotify)WKRelease);
310     g_signal_connect_swapped(action, "activate", G_CALLBACK(browserWindowHistoryItemActivated), window);
311
312     GtkWidget *menuItem = gtk_action_create_menu_item(action);
313     g_signal_connect_swapped(menuItem, "select", G_CALLBACK(browserWindowHistoryItemSelected), window);
314     g_object_unref(action);
315
316     return menuItem;
317 }
318
319 static GtkWidget *browserWindowCreateBackForwardMenu(BrowserWindow *window, WKArrayRef list)
320 {
321     if (!list)
322         return 0;
323
324     guint listCount = WKArrayGetSize(list);
325     if (!listCount)
326         return 0;
327
328     GtkWidget *menu = gtk_menu_new();
329     gboolean hasItems = FALSE;
330     guint i;
331     for (i = 0; i < listCount; i++) {
332         WKBackForwardListItemRef item = WKArrayGetItemAtIndex(list, i);
333         GtkWidget *menuItem = browserWindowCreateMenuItemFromBackForwardItem(window, item);
334         if (!menuItem)
335             continue;
336
337         gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuItem);
338         gtk_widget_show(menuItem);
339         hasItems = TRUE;
340     }
341
342     if (!hasItems) {
343         gtk_widget_destroy(menu);
344         return 0;
345     }
346
347     return menu;
348 }
349
350 static void browserWindowUpdateNavigationActions(BrowserWindow* window)
351 {
352     gtk_widget_set_sensitive(window->backItem, WKPageCanGoBack(WKViewGetPage(window->webView)));
353     gtk_widget_set_sensitive(window->forwardItem, WKPageCanGoForward(WKViewGetPage(window->webView)));
354
355     WKArrayRef list = WKBackForwardListCopyBackListWithLimit(window->history, 10);
356     GtkWidget *menu = browserWindowCreateBackForwardMenu(window, list);
357     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->backItem), menu);
358     if (list)
359         WKRelease(list);
360
361     list = WKBackForwardListCopyForwardListWithLimit(window->history, 10);
362     menu = browserWindowCreateBackForwardMenu(window, list);
363     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->forwardItem), menu);
364     if (list)
365         WKRelease(list);
366 }
367
368 // Loader client.
369 static void didStartProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
370 {
371     if (!WKFrameIsMainFrame(frame))
372         return;
373
374     WKURLRef url = WKFrameCopyProvisionalURL(frame);
375     browserWindowUpdateURL(BROWSER_WINDOW(clientInfo), url);
376     if (url)
377         WKRelease(url);
378 }
379
380 static void didReceiveServerRedirectForProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
381 {
382     if (!WKFrameIsMainFrame(frame))
383         return;
384
385     WKURLRef url = WKFrameCopyProvisionalURL(frame);
386     browserWindowUpdateURL(BROWSER_WINDOW(clientInfo), url);
387     if (url)
388         WKRelease(url);
389 }
390
391 static void didFailProvisionalLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
392 {
393     if (!WKFrameIsMainFrame(frame))
394         return;
395
396     WKURLRef url = WKFrameCopyProvisionalURL(frame);
397     browserWindowUpdateURL(BROWSER_WINDOW(clientInfo), url);
398     if (url)
399         WKRelease(url);
400 }
401
402 static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
403 {
404     if (!WKFrameIsMainFrame(frame))
405         return;
406
407     WKURLRef url = WKFrameCopyURL(frame);
408     browserWindowUpdateURL(BROWSER_WINDOW(clientInfo), url);
409     if (url)
410         WKRelease(url);
411 }
412
413 static void didFinishDocumentLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
414 {
415     if (!WKFrameIsMainFrame(frame))
416         return;
417 }
418
419 static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
420 {
421     if (!WKFrameIsMainFrame(frame))
422         return;
423
424     BrowserWindow* window = BROWSER_WINDOW(clientInfo);
425     gtk_widget_grab_focus(GTK_WIDGET(window->webView));
426 }
427
428 static void didFailLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
429 {
430     if (!WKFrameIsMainFrame(frame))
431         return;
432 }
433
434 static void didReceiveTitleForFrame(WKPageRef page, WKStringRef title, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
435 {
436     if (!WKFrameIsMainFrame(frame))
437         return;
438
439     char *titleText = WKStringGetCString(title);
440     browserWindowSetTitle(BROWSER_WINDOW(clientInfo), titleText);
441     g_free(titleText);
442 }
443
444 static void didFirstLayoutForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
445 {
446     if (!WKFrameIsMainFrame(frame))
447         return;
448 }
449
450 static void didFirstVisuallyNonEmptyLayoutForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
451 {
452     if (!WKFrameIsMainFrame(frame))
453         return;
454 }
455
456 static void didRemoveFrameFromHierarchy(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
457 {
458     if (!WKFrameIsMainFrame(frame))
459         return;
460 }
461
462 static void didStartProgress(WKPageRef page, const void* clientInfo)
463 {
464     browserWindowSetLoadProgress(BROWSER_WINDOW(clientInfo), 0.);
465 }
466
467 static void didChangeProgress(WKPageRef page, const void* clientInfo)
468 {
469     browserWindowSetLoadProgress(BROWSER_WINDOW(clientInfo), WKPageGetEstimatedProgress(page));
470 }
471
472 static void didFinishProgress(WKPageRef page, const void* clientInfo)
473 {
474     browserWindowSetLoadProgress(BROWSER_WINDOW(clientInfo), 1.);
475 }
476
477 static void didBecomeUnresponsive(WKPageRef page, const void* clientInfo)
478 {
479 }
480
481 static void didBecomeResponsive(WKPageRef page, const void* clientInfo)
482 {
483 }
484
485 static void didChangeBackForwardList(WKPageRef page, WKBackForwardListItemRef addedItem, WKArrayRef removedItems, const void *clientInfo)
486 {
487     browserWindowUpdateNavigationActions(BROWSER_WINDOW(clientInfo));
488 }
489
490 static void browserWindowLoaderClientInit(BrowserWindow* window)
491 {
492     WKPageLoaderClient loadClient = {
493         kWKPageLoaderClientCurrentVersion,
494         window,  /* clientInfo */
495         didStartProvisionalLoadForFrame,
496         didReceiveServerRedirectForProvisionalLoadForFrame,
497         didFailProvisionalLoadWithErrorForFrame,
498         didCommitLoadForFrame,
499         didFinishDocumentLoadForFrame,
500         didFinishLoadForFrame,
501         didFailLoadWithErrorForFrame,
502         0,       /* didSameDocumentNavigationForFrame */
503         didReceiveTitleForFrame,
504         didFirstLayoutForFrame,
505         didFirstVisuallyNonEmptyLayoutForFrame,
506         didRemoveFrameFromHierarchy,
507         0,       /* didDisplayInsecureContentForFrame */
508         0,       /* didRunInsecureContentForFrame */
509         0,       /* canAuthenticateAgainstProtectionSpaceInFrame */
510         0,       /* didReceiveAuthenticationChallengeInFrame */
511         didStartProgress,
512         didChangeProgress,
513         didFinishProgress,
514         didBecomeUnresponsive,
515         didBecomeResponsive,
516         0,       /* processDidCrash */
517         didChangeBackForwardList,
518         0,       /* shouldGoToBackForwardListItem */
519         0        /* didFailToInitializePlugin */
520     };
521     WKPageSetPageLoaderClient(WKViewGetPage(window->webView), &loadClient);
522 }
523
524 // UI Client.
525 static WKPageRef createNewPage(WKPageRef page, WKURLRequestRef request, WKDictionaryRef features, WKEventModifiers modifiers, WKEventMouseButton button, const void *clientInfo)
526 {
527     WKViewRef webView = WKViewCreate(WKPageGetContext(page), 0);
528     BrowserWindow* window = BROWSER_WINDOW(browser_window_new(webView));
529     return WKRetain(WKViewGetPage(window->webView));
530 }
531
532 static void showPage(WKPageRef page, const void *clientInfo)
533 {
534     gtk_widget_show(GTK_WIDGET(clientInfo));
535 }
536
537 static void closePage(WKPageRef page, const void *clientInfo)
538 {
539     gtk_widget_destroy(GTK_WIDGET(clientInfo));
540 }
541
542 static GtkWidget* createMessageDialog(GtkWindow *parent, GtkMessageType type, GtkButtonsType buttons, gint defaultResponse, WKStringRef message, WKFrameRef frame)
543 {
544     char *messageText = WKStringGetCString(message);
545     GtkWidget *dialog = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, type, buttons, "%s", messageText);
546     g_free(messageText);
547
548     WKURLRef url = WKFrameCopyURL(frame);
549     char *urlText = WKURLGetCString(url);
550     WKRelease(url);
551     gchar *title = g_strdup_printf("JavaScript - %s", urlText);
552     g_free(urlText);
553     gtk_window_set_title(GTK_WINDOW(dialog), title);
554     g_free(title);
555
556     gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse);
557
558     return dialog;
559 }
560
561 static void runJavaScriptAlert(WKPageRef page, WKStringRef message, WKFrameRef frame, const void *clientInfo)
562 {
563     GtkWidget *dialog = createMessageDialog(GTK_WINDOW(clientInfo), GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, GTK_RESPONSE_CLOSE, message, frame);
564     gtk_dialog_run(GTK_DIALOG(dialog));
565     gtk_widget_destroy(dialog);
566 }
567
568 static bool runJavaScriptConfirm(WKPageRef page, WKStringRef message, WKFrameRef frame, const void* clientInfo)
569 {
570     GtkWidget *dialog = createMessageDialog(GTK_WINDOW(clientInfo), GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, message, frame);
571     bool returnValue = (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK);
572     gtk_widget_destroy(dialog);
573
574     return returnValue;
575 }
576
577 static WKStringRef runJavaScriptPrompt(WKPageRef page, WKStringRef message, WKStringRef defaultValue, WKFrameRef frame, const void* clientInfo)
578 {
579     GtkWidget *dialog = createMessageDialog(GTK_WINDOW(clientInfo), GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, message, frame);
580
581     GtkWidget *entry = gtk_entry_new();
582     char *value = WKStringGetCString(defaultValue);
583     gtk_entry_set_text(GTK_ENTRY(entry), value);
584     g_free(value);
585     gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry);
586     gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
587     gtk_widget_show(entry);
588
589     WKStringRef returnValue = (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) ? WKStringCreateWithUTF8CString(gtk_entry_get_text(GTK_ENTRY(entry))) : 0;
590     gtk_widget_destroy(dialog);
591
592     return returnValue;
593 }
594
595 static void mouseDidMoveOverElement(WKPageRef page, WKEventModifiers modifiers, WKTypeRef userData, const void *clientInfo)
596 {
597     BrowserWindow *window = BROWSER_WINDOW(clientInfo);
598     gtk_statusbar_pop(GTK_STATUSBAR(window->statusBar), window->statusBarContextId);
599
600     if (!userData)
601         return;
602
603     if (WKGetTypeID(userData) != WKURLGetTypeID())
604         return;
605
606     gchar *link = WKURLGetCString((WKURLRef)userData);
607     gtk_statusbar_push(GTK_STATUSBAR(window->statusBar), window->statusBarContextId, link);
608     g_free(link);
609 }
610
611 static void browserWindowUIClientInit(BrowserWindow *window)
612 {
613     WKPageUIClient uiClient = {
614         kWKPageUIClientCurrentVersion,
615         window, /* clientInfo */
616         0,      /* createNewPage_deprecatedForUseWithV0 */
617         showPage,
618         closePage,
619         0,      /* takeFocus */
620         0,      /* focus */
621         0,      /* unfocus */
622         runJavaScriptAlert,
623         runJavaScriptConfirm,
624         runJavaScriptPrompt,
625         0,      /* setStatusText */
626         mouseDidMoveOverElement,
627         0,      /* missingPluginButtonClicked */
628         0,      /* didNotHandleKeyEvent */
629         0,      /* didNotHandleWheelEvent */
630         0,      /* toolbarsAreVisible */
631         0,      /* setToolbarsAreVisible */
632         0,      /* menuBarIsVisible */
633         0,      /* setMenuBarIsVisible */
634         0,      /* statusBarIsVisible */
635         0,      /* setStatusBarIsVisible */
636         0,      /* isResizable */
637         0,      /* setIsResizable */
638         0,      /* getWindowFrame */
639         0,      /* setWindowFrame */
640         0,      /* runBeforeUnloadConfirmPanel */
641         0,      /* didDraw */
642         0,      /* pageDidScroll */
643         0,      /* exceededDatabaseQuota */
644         0,      /* runOpenPanel */
645         0,      /* decidePolicyForGeolocationPermissionRequest */
646         0,      /* headerHeight */
647         0,      /* footerHeight */
648         0,      /* drawHeader */
649         0,      /* drawFooter */
650         0,      /* printFrame */
651         0,      /* runModal */
652         0,      /* didCompleteRubberBandForMainFrame */
653         0,      /* saveDataToFileInDownloadsFolder */
654         0,      /* shouldInterruptJavaScript */
655         createNewPage
656     };
657     WKPageSetPageUIClient(WKViewGetPage(window->webView), &uiClient);
658 }
659
660 static void decidePolicyForNavigationAction(WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
661 {
662     if (navigationType != kWKFrameNavigationTypeLinkClicked || mouseButton != kWKEventMouseButtonMiddleButton) {
663         WKFramePolicyListenerUse(listener);
664         return;
665     }
666
667     WKViewRef webView = WKViewCreate(WKPageGetContext(page), 0);
668     GtkWidget *window = browser_window_new(webView);
669     WKURLRef url = WKURLRequestCopyURL(request);
670     WKPageLoadURL(WKViewGetPage(webView), url);
671     WKRelease(url);
672     gtk_widget_grab_focus(GTK_WIDGET(webView));
673     gtk_widget_show(window);
674
675     WKFramePolicyListenerIgnore(listener);
676 }
677
678 static void browserWindowPolicyClientInit(BrowserWindow* window)
679 {
680     WKPagePolicyClient policyClient = {
681         kWKPagePolicyClientCurrentVersion,
682         window, /* clientInfo */
683         decidePolicyForNavigationAction,
684         0,      /* decidePolicyForNewWindowAction */
685         0,      /* decidePolicyForResponse */
686         0       /* unableToImplementPolicy */
687     };
688     WKPageSetPagePolicyClient(WKViewGetPage(window->webView), &policyClient);
689 }
690
691 // Public API.
692 GtkWidget* browser_window_new(WKViewRef view)
693 {
694     g_return_val_if_fail(GTK_IS_WIDGET(view), 0);
695
696     return GTK_WIDGET(g_object_new(BROWSER_TYPE_WINDOW,
697                                    "type", GTK_WINDOW_TOPLEVEL,
698                                    "view", view, NULL));
699 }
700
701 WKViewRef browser_window_get_view(BrowserWindow* window)
702 {
703     g_return_val_if_fail(BROWSER_IS_WINDOW(window), 0);
704
705     return window->webView;
706 }