1 /* 2 * Copyright (C) 2006, 2007 Apple Inc. 3 * Copyright (C) 2007 Alp Toker <alp (at) atoker.com> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <gtk/gtk.h> 28 #include <webkit/webkit.h> 29 30 static gint windowCount = 0; 31 32 static GtkWidget* createWindow(WebKitWebView** outWebView); 33 34 static void activateUriEntryCb(GtkWidget* entry, gpointer data) 35 { 36 WebKitWebView *webView = g_object_get_data(G_OBJECT(entry), "web-view"); 37 const gchar* uri = gtk_entry_get_text(GTK_ENTRY(entry)); 38 g_assert(uri); 39 webkit_web_view_load_uri(webView, uri); 40 } 41 42 static void updateTitle(GtkWindow* window, WebKitWebView* webView) 43 { 44 GString *string = g_string_new(webkit_web_view_get_title(webView)); 45 gdouble loadProgress = webkit_web_view_get_progress(webView) * 100; 46 g_string_append(string, " - WebKit Launcher"); 47 if (loadProgress < 100) 48 g_string_append_printf(string, " (%f%%)", loadProgress); 49 gchar *title = g_string_free(string, FALSE); 50 gtk_window_set_title(window, title); 51 g_free(title); 52 } 53 54 static void linkHoverCb(WebKitWebView* page, const gchar* title, const gchar* link, GtkStatusbar* statusbar) 55 { 56 guint statusContextId = 57 GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(statusbar), "link-hover-context")); 58 /* underflow is allowed */ 59 gtk_statusbar_pop(statusbar, statusContextId); 60 if (link) 61 gtk_statusbar_push(statusbar, statusContextId, link); 62 } 63 64 static void notifyTitleCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* window) 65 { 66 updateTitle(GTK_WINDOW(window), webView); 67 } 68 69 static void notifyLoadStatusCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* uriEntry) 70 { 71 if (webkit_web_view_get_load_status(webView) == WEBKIT_LOAD_COMMITTED) { 72 WebKitWebFrame *frame = webkit_web_view_get_main_frame(webView); 73 const gchar *uri = webkit_web_frame_get_uri(frame); 74 if (uri) 75 gtk_entry_set_text(GTK_ENTRY(uriEntry), uri); 76 } 77 } 78 79 static void notifyProgressCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* window) 80 { 81 updateTitle(GTK_WINDOW(window), webView); 82 } 83 84 static void destroyCb(GtkWidget* widget, GtkWidget* window) 85 { 86 if (g_atomic_int_dec_and_test(&windowCount)) 87 gtk_main_quit(); 88 } 89 90 static void goBackCb(GtkWidget* widget, WebKitWebView* webView) 91 { 92 webkit_web_view_go_back(webView); 93 } 94 95 static void goForwardCb(GtkWidget* widget, WebKitWebView* webView) 96 { 97 webkit_web_view_go_forward(webView); 98 } 99 100 static WebKitWebView* 101 createWebViewCb(WebKitWebView* webView, WebKitWebFrame* web_frame, GtkWidget* window) 102 { 103 WebKitWebView *newWebView; 104 createWindow(&newWebView); 105 return newWebView; 106 } 107 108 static gboolean webViewReadyCb(WebKitWebView* webView, GtkWidget* window) 109 { 110 gtk_widget_grab_focus(GTK_WIDGET(webView)); 111 gtk_widget_show_all(window); 112 return FALSE; 113 } 114 115 static gboolean closeWebViewCb(WebKitWebView* webView, GtkWidget* window) 116 { 117 gtk_widget_destroy(window); 118 return TRUE; 119 } 120 121 static GtkWidget* createBrowser(GtkWidget* window, GtkWidget* uriEntry, GtkWidget* statusbar, WebKitWebView* webView) 122 { 123 GtkWidget *scrolledWindow = gtk_scrolled_window_new(NULL, NULL); 124 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 125 126 gtk_container_add(GTK_CONTAINER(scrolledWindow), GTK_WIDGET(webView)); 127 128 g_signal_connect(webView, "notify::title", G_CALLBACK(notifyTitleCb), window); 129 g_signal_connect(webView, "notify::load-status", G_CALLBACK(notifyLoadStatusCb), uriEntry); 130 g_signal_connect(webView, "notify::progress", G_CALLBACK(notifyProgressCb), window); 131 g_signal_connect(webView, "hovering-over-link", G_CALLBACK(linkHoverCb), statusbar); 132 g_signal_connect(webView, "create-web-view", G_CALLBACK(createWebViewCb), window); 133 g_signal_connect(webView, "web-view-ready", G_CALLBACK(webViewReadyCb), window); 134 g_signal_connect(webView, "close-web-view", G_CALLBACK(closeWebViewCb), window); 135 136 return scrolledWindow; 137 } 138 139 static GtkWidget* createStatusbar() 140 { 141 GtkStatusbar *statusbar = GTK_STATUSBAR(gtk_statusbar_new()); 142 guint statusContextId = gtk_statusbar_get_context_id(statusbar, "Link Hover"); 143 g_object_set_data(G_OBJECT(statusbar), "link-hover-context", 144 GUINT_TO_POINTER(statusContextId)); 145 146 return GTK_WIDGET(statusbar); 147 } 148 149 static GtkWidget* createToolbar(GtkWidget* uriEntry, WebKitWebView* webView) 150 { 151 GtkWidget *toolbar = gtk_toolbar_new(); 152 153 #if GTK_CHECK_VERSION(2, 15, 0) 154 gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL); 155 #else 156 gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL); 157 #endif 158 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ); 159 160 GtkToolItem *item; 161 162 /* the back button */ 163 item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK); 164 g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(goBackCb), webView); 165 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); 166 167 /* The forward button */ 168 item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD); 169 g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(goForwardCb), webView); 170 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); 171 172 /* The URL entry */ 173 item = gtk_tool_item_new(); 174 gtk_tool_item_set_expand(item, TRUE); 175 gtk_container_add(GTK_CONTAINER(item), uriEntry); 176 g_signal_connect(G_OBJECT(uriEntry), "activate", G_CALLBACK(activateUriEntryCb), NULL); 177 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); 178 179 /* The go button */ 180 g_object_set_data(G_OBJECT(uriEntry), "web-view", webView); 181 item = gtk_tool_button_new_from_stock(GTK_STOCK_OK); 182 g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(activateUriEntryCb), (gpointer)uriEntry); 183 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); 184 185 return toolbar; 186 } 187 188 static GtkWidget* createWindow(WebKitWebView** outWebView) 189 { 190 WebKitWebView *webView; 191 GtkWidget *vbox; 192 GtkWidget *window; 193 GtkWidget *uriEntry; 194 GtkWidget *statusbar; 195 196 g_atomic_int_inc(&windowCount); 197 198 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 199 gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); 200 gtk_widget_set_name(window, "GtkLauncher"); 201 202 webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 203 uriEntry = gtk_entry_new(); 204 205 vbox = gtk_vbox_new(FALSE, 0); 206 statusbar = createStatusbar(webView); 207 gtk_box_pack_start(GTK_BOX(vbox), createToolbar(uriEntry, webView), FALSE, FALSE, 0); 208 gtk_box_pack_start(GTK_BOX(vbox), createBrowser(window, uriEntry, statusbar, webView), TRUE, TRUE, 0); 209 gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); 210 211 gtk_container_add(GTK_CONTAINER(window), vbox); 212 213 g_signal_connect(window, "destroy", G_CALLBACK(destroyCb), NULL); 214 215 if (outWebView) 216 *outWebView = webView; 217 218 return window; 219 } 220 221 static gchar* filenameToURL(const char* filename) 222 { 223 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) 224 return 0; 225 226 GFile *gfile = g_file_new_for_path(filename); 227 gchar *fileURL = g_file_get_uri(gfile); 228 g_object_unref(gfile); 229 230 return fileURL; 231 } 232 233 int main(int argc, char* argv[]) 234 { 235 WebKitWebView *webView; 236 GtkWidget *main_window; 237 238 gtk_init(&argc, &argv); 239 if (!g_thread_supported()) 240 g_thread_init(NULL); 241 242 main_window = createWindow(&webView); 243 244 gchar *uri =(gchar*)(argc > 1 ? argv[1] : "http://www.google.com/"); 245 gchar *fileURL = filenameToURL(uri); 246 247 webkit_web_view_load_uri(webView, fileURL ? fileURL : uri); 248 g_free(fileURL); 249 250 gtk_widget_grab_focus(GTK_WIDGET(webView)); 251 gtk_widget_show_all(main_window); 252 gtk_main(); 253 254 return 0; 255 } 256