742938330c9c628c3c61b055df308c8fa3fc4896
[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 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 *backItem;
42     GtkWidget *forwardItem;
43     WebKitWebView *webView;
44
45 };
46
47 struct _BrowserWindowClass {
48     GtkWindowClass parent;
49 };
50
51 static gint windowCount = 0;
52
53 G_DEFINE_TYPE(BrowserWindow, browser_window, GTK_TYPE_WINDOW)
54
55 static void activateUriEntryCallback(BrowserWindow *window)
56 {
57     webkit_web_view_load_uri(window->webView, gtk_entry_get_text(GTK_ENTRY(window->uriEntry)));
58 }
59
60 static void goBackCallback(BrowserWindow *window)
61 {
62     webkit_web_view_go_back(window->webView);
63 }
64
65 static void goForwardCallback(BrowserWindow *window)
66 {
67     webkit_web_view_go_forward(window->webView);
68 }
69
70 static void webViewURIChanged(WebKitWebView *webView,  GParamSpec *pspec, BrowserWindow *window)
71 {
72     gtk_entry_set_text(GTK_ENTRY(window->uriEntry), webkit_web_view_get_uri(webView));
73 }
74
75 static gboolean resetEntryProgress(GtkEntry *entry)
76 {
77     gtk_entry_set_progress_fraction(entry, 0);
78     return FALSE;
79 }
80
81 static void webViewLoadProgressChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
82 {
83     gdouble progress = webkit_web_view_get_estimated_load_progress(webView);
84     gtk_entry_set_progress_fraction(GTK_ENTRY(window->uriEntry), progress);
85     if (progress == 1.0)
86         g_timeout_add(500, (GSourceFunc)resetEntryProgress, window->uriEntry);
87 }
88
89 static void browserWindowHistoryItemActivated(BrowserWindow *window, GtkAction *action)
90 {
91     WebKitBackForwardListItem *item = g_object_get_data(G_OBJECT(action), "back-forward-list-item");
92     if (!item)
93         return;
94
95     webkit_web_view_go_to_back_forward_list_item(window->webView, item);
96 }
97
98 static GtkWidget *browserWindowCreateBackForwardMenu(BrowserWindow *window, GList *list)
99 {
100     if (!list)
101         return NULL;
102
103     GtkWidget *menu = gtk_menu_new();
104     GList *listItem;
105     for (listItem = list; listItem; listItem = g_list_next(listItem)) {
106         WebKitBackForwardListItem *item = (WebKitBackForwardListItem *)listItem->data;
107         const char *uri = webkit_back_forward_list_item_get_uri(item);
108         const char *title = webkit_back_forward_list_item_get_title(item);
109
110         GtkAction *action = gtk_action_new(uri, title, NULL, NULL);
111         g_object_set_data_full(G_OBJECT(action), "back-forward-list-item", g_object_ref(item), g_object_unref);
112         g_signal_connect_swapped(action, "activate", G_CALLBACK(browserWindowHistoryItemActivated), window);
113
114         GtkWidget *menuItem = gtk_action_create_menu_item(action);
115         g_object_unref(action);
116
117         gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuItem);
118         gtk_widget_show(menuItem);
119     }
120
121     return menu;
122 }
123
124 static void browserWindowUpdateNavigationActions(BrowserWindow *window, WebKitBackForwardList *backForwadlist)
125 {
126     gtk_widget_set_sensitive(window->backItem, webkit_web_view_can_go_back(window->webView));
127     gtk_widget_set_sensitive(window->forwardItem, webkit_web_view_can_go_forward(window->webView));
128
129     GList *list = webkit_back_forward_list_get_back_list_with_limit(backForwadlist, 10);
130     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->backItem),
131                                   browserWindowCreateBackForwardMenu(window, list));
132     g_list_free(list);
133
134     list = webkit_back_forward_list_get_forward_list_with_limit(backForwadlist, 10);
135     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->forwardItem),
136                                   browserWindowCreateBackForwardMenu(window, list));
137     g_list_free(list);
138 }
139
140 static void backForwadlistChanged(WebKitBackForwardList *backForwadlist, WebKitBackForwardListItem *itemAdded, GList *itemsRemoved, BrowserWindow *window)
141 {
142     browserWindowUpdateNavigationActions(window, backForwadlist);
143 }
144
145 static void browserWindowFinalize(GObject *gObject)
146 {
147     G_OBJECT_CLASS(browser_window_parent_class)->finalize(gObject);
148
149     if (g_atomic_int_dec_and_test(&windowCount))
150         gtk_main_quit();
151 }
152
153 static void browserWindowGetProperty(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
154 {
155     BrowserWindow *window = BROWSER_WINDOW(object);
156
157     switch (propId) {
158     case PROP_VIEW:
159         g_value_set_object(value, browser_window_get_view(window));
160         break;
161     default:
162         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
163     }
164 }
165
166 static void browserWindowSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
167 {
168     BrowserWindow* window = BROWSER_WINDOW(object);
169
170     switch (propId) {
171     case PROP_VIEW:
172         window->webView = g_value_get_object(value);
173         break;
174     default:
175         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
176     }
177 }
178
179 static void browser_window_init(BrowserWindow *window)
180 {
181     g_atomic_int_inc(&windowCount);
182
183     gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
184
185     window->uriEntry = gtk_entry_new();
186     g_signal_connect_swapped(window->uriEntry, "activate", G_CALLBACK(activateUriEntryCallback), (gpointer)window);
187
188     GtkWidget *toolbar = gtk_toolbar_new();
189     gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
190     gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
191
192     GtkToolItem *item = gtk_menu_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
193     window->backItem = GTK_WIDGET(item);
194     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(item), 0);
195     g_signal_connect_swapped(item, "clicked", G_CALLBACK(goBackCallback), (gpointer)window);
196     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
197     gtk_widget_show(GTK_WIDGET(item));
198
199     item = gtk_menu_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
200     window->forwardItem = GTK_WIDGET(item);
201     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(item), 0);
202     g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(goForwardCallback), (gpointer)window);
203     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
204     gtk_widget_show(GTK_WIDGET(item));
205
206     item = gtk_tool_item_new();
207     gtk_tool_item_set_expand(item, TRUE);
208     gtk_container_add(GTK_CONTAINER(item), window->uriEntry);
209     gtk_widget_show(window->uriEntry);
210     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
211     gtk_widget_show(GTK_WIDGET(item));
212
213     item = gtk_tool_button_new_from_stock(GTK_STOCK_OK);
214     g_signal_connect_swapped(item, "clicked", G_CALLBACK(activateUriEntryCallback), (gpointer)window);
215     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
216     gtk_widget_show(GTK_WIDGET(item));
217
218     GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
219     window->mainBox = vbox;
220     gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
221     gtk_widget_show(toolbar);
222
223     gtk_container_add(GTK_CONTAINER(window), vbox);
224     gtk_widget_show(vbox);
225 }
226
227 static void browserWindowConstructed(GObject *gObject)
228 {
229     BrowserWindow *window = BROWSER_WINDOW(gObject);
230
231     g_signal_connect(window->webView, "notify::uri", G_CALLBACK(webViewURIChanged), window);
232     g_signal_connect(window->webView, "notify::estimated-load-progress", G_CALLBACK(webViewLoadProgressChanged), window);
233
234     WebKitBackForwardList *backForwadlist = webkit_web_view_get_back_forward_list(window->webView);
235     g_signal_connect(backForwadlist, "changed", G_CALLBACK(backForwadlistChanged), window);
236
237     gtk_box_pack_start(GTK_BOX(window->mainBox), GTK_WIDGET(window->webView), TRUE, TRUE, 0);
238     gtk_widget_show(GTK_WIDGET(window->webView));
239 }
240
241 static void browser_window_class_init(BrowserWindowClass *klass)
242 {
243     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
244
245     gobjectClass->constructed = browserWindowConstructed;
246     gobjectClass->get_property = browserWindowGetProperty;
247     gobjectClass->set_property = browserWindowSetProperty;
248     gobjectClass->finalize = browserWindowFinalize;
249
250     g_object_class_install_property(gobjectClass,
251                                     PROP_VIEW,
252                                     g_param_spec_object("view",
253                                                         "View",
254                                                         "The web view of this window",
255                                                         WEBKIT_TYPE_WEB_VIEW,
256                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
257 }
258
259 // Public API.
260 GtkWidget *browser_window_new(WebKitWebView *view)
261 {
262     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(view), 0);
263
264     return GTK_WIDGET(g_object_new(BROWSER_TYPE_WINDOW,
265                                    "type", GTK_WINDOW_TOPLEVEL,
266                                    "view", view, NULL));
267 }
268
269 WebKitWebView *browser_window_get_view(BrowserWindow *window)
270 {
271     g_return_val_if_fail(BROWSER_IS_WINDOW(window), 0);
272
273     return window->webView;
274 }