6 #include <gdk/gdkkeysyms.h>
7 #include <webkit/webkit.h>
10 #define DOWNLOAD_DIR "/tmp/tmp"
13 static void zea_adblock(WebKitWebView *, WebKitWebFrame *, WebKitWebResource *,
14 WebKitNetworkRequest *, WebKitNetworkResponse *, gpointer);
15 static void zea_destroy_client(GtkWidget *, gpointer);
16 static gboolean zea_do_download(WebKitWebView *, WebKitDownload *, gpointer);
17 static gboolean zea_download_request(WebKitWebView *, WebKitWebFrame *,
18 WebKitNetworkRequest *, gchar *,
19 WebKitWebPolicyDecision *, gpointer);
20 static void zea_load_adblock(void);
21 static void zea_load_status_changed(GObject *obj, GParamSpec *pspec,
23 static gboolean zea_location_key(GtkWidget *, GdkEvent *, gpointer);
24 static void zea_new_client(const gchar *uri);
25 static gboolean zea_new_client_request(WebKitWebView *, WebKitWebFrame *,
26 WebKitNetworkRequest *,
27 WebKitWebNavigationAction *,
28 WebKitWebPolicyDecision *, gpointer);
29 static void zea_search(gpointer, gint);
30 static void zea_scroll(GtkAdjustment *, gint, gdouble);
31 static void zea_title_changed(GObject *, GParamSpec *, gpointer);
32 static void zea_uri_changed(GObject *, GParamSpec *, gpointer);
33 static void zea_web_view_hover(WebKitWebView *, gchar *, gchar *, gpointer);
34 static gboolean zea_web_view_key(GtkWidget *, GdkEvent *, gpointer);
37 static Window embed = 0;
38 static gint clients = 0;
39 static gdouble global_zoom = 1.0;
40 static gchar *search_text = NULL;
41 static gchar *first_uri = NULL;
42 static gboolean show_all_requests = FALSE;
43 static GSList *adblock_patterns = NULL;
58 zea_adblock(WebKitWebView *web_view, WebKitWebFrame *frame,
59 WebKitWebResource *resource, WebKitNetworkRequest *request,
60 WebKitNetworkResponse *response, gpointer data)
62 GSList *it = adblock_patterns;
71 uri = webkit_network_request_get_uri(request);
72 if (show_all_requests)
73 fprintf(stderr, "-> %s\n", uri);
77 if (g_regex_match((GRegex *)(it->data), uri, 0, NULL))
79 webkit_network_request_set_uri(request, "about:blank");
80 if (show_all_requests)
81 fprintf(stderr, "\tBLOCKED!\n");
84 it = g_slist_next(it);
89 zea_destroy_client(GtkWidget *obj, gpointer data)
91 struct Client *c = (struct Client *)data;
95 webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(c->web_view));
96 gtk_widget_destroy(c->web_view);
97 gtk_widget_destroy(c->scroll);
98 gtk_widget_destroy(c->status);
99 gtk_widget_destroy(c->location);
100 gtk_widget_destroy(c->vbox);
101 gtk_widget_destroy(c->win);
110 zea_do_download(WebKitWebView *web_view, WebKitDownload *download, gpointer data)
119 uri = webkit_download_get_uri(download);
124 ret = execlp("xterm", "xterm", "-hold", "-e", "wget", uri, NULL);
127 if (snprintf(id, 16, "%ld", embed) >= 16)
129 fprintf(stderr, "zea: id for xterm embed truncated!\n");
132 ret = execlp("xterm", "xterm", "-hold", "-into", id, "-e", "wget",
138 fprintf(stderr, "zea: exec'ing xterm for download");
148 zea_download_request(WebKitWebView *web_view, WebKitWebFrame *frame,
149 WebKitNetworkRequest *request, gchar *mime_type,
150 WebKitWebPolicyDecision *policy_decision,
157 if (!webkit_web_view_can_show_mime_type(web_view, mime_type))
159 webkit_web_policy_decision_download(policy_decision);
166 zea_location_key(GtkWidget *widget, GdkEvent *event, gpointer data)
168 struct Client *c = (struct Client *)data;
173 if (event->type == GDK_KEY_PRESS)
175 if (((GdkEventKey *)event)->keyval == GDK_KEY_Return)
177 gtk_widget_grab_focus(c->web_view);
178 t = gtk_entry_get_text(GTK_ENTRY(c->location));
179 if (t != NULL && t[0] == '/')
181 if (search_text != NULL)
183 search_text = g_strdup(t + 1); /* XXX whacky */
187 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), t);
196 zea_new_client(const gchar *uri)
198 struct Client *c = malloc(sizeof(struct Client));
201 fprintf(stderr, "zea: fatal: malloc failed\n");
207 c->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
211 c->win = gtk_plug_new(embed);
214 /* When using Gtk2, zea only shows a white area when run in
215 * suckless' tabbed. It appears we need to set a default window size
216 * for this to work. This is not needed when using Gtk3. */
217 gtk_window_set_default_size(GTK_WINDOW(c->win), 1024, 768);
219 g_signal_connect(G_OBJECT(c->win), "destroy",
220 G_CALLBACK(zea_destroy_client), c);
221 gtk_window_set_title(GTK_WINDOW(c->win), "zea");
223 c->web_view = webkit_web_view_new();
224 webkit_web_view_set_full_content_zoom(WEBKIT_WEB_VIEW(c->web_view), TRUE);
225 webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->web_view), global_zoom);
226 g_signal_connect(G_OBJECT(c->web_view), "notify::title",
227 G_CALLBACK(zea_title_changed), c);
228 g_signal_connect(G_OBJECT(c->web_view), "notify::uri",
229 G_CALLBACK(zea_uri_changed), c);
230 g_signal_connect(G_OBJECT(c->web_view), "notify::load-status",
231 G_CALLBACK(zea_load_status_changed), c);
232 g_signal_connect(G_OBJECT(c->web_view),
233 "new-window-policy-decision-requested",
234 G_CALLBACK(zea_new_client_request), NULL);
235 g_signal_connect(G_OBJECT(c->web_view),
236 "mime-type-policy-decision-requested",
237 G_CALLBACK(zea_download_request), NULL);
238 g_signal_connect(G_OBJECT(c->web_view), "download-requested",
239 G_CALLBACK(zea_do_download), NULL);
240 g_signal_connect(G_OBJECT(c->web_view), "key-press-event",
241 G_CALLBACK(zea_web_view_key), c);
242 g_signal_connect(G_OBJECT(c->web_view), "hovering-over-link",
243 G_CALLBACK(zea_web_view_hover), c);
244 g_signal_connect(G_OBJECT(c->web_view), "resource-request-starting",
245 G_CALLBACK(zea_adblock), NULL);
247 c->scroll = gtk_scrolled_window_new(NULL, NULL);
249 gtk_container_add(GTK_CONTAINER(c->scroll), c->web_view);
251 c->location = gtk_entry_new();
252 g_signal_connect(G_OBJECT(c->location), "key-press-event",
253 G_CALLBACK(zea_location_key), c);
255 c->status = gtk_statusbar_new();
257 c->vbox = gtk_vbox_new(FALSE, 0);
258 gtk_box_pack_start(GTK_BOX(c->vbox), c->location, FALSE, FALSE, 0);
259 gtk_container_add(GTK_CONTAINER(c->vbox), c->scroll);
260 gtk_box_pack_end(GTK_BOX(c->vbox), c->status, FALSE, FALSE, 0);
262 gtk_container_add(GTK_CONTAINER(c->win), c->vbox);
264 gtk_widget_grab_focus(c->web_view);
265 gtk_widget_show_all(c->win);
267 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), uri);
273 zea_new_client_request(WebKitWebView *web_view, WebKitWebFrame *frame,
274 WebKitNetworkRequest *request,
275 WebKitWebNavigationAction *navigation_action,
276 WebKitWebPolicyDecision *policy_decision,
281 (void)navigation_action;
284 webkit_web_policy_decision_ignore(policy_decision);
285 zea_new_client(webkit_network_request_get_uri(request));
291 zea_search(gpointer data, gint direction)
293 struct Client *c = (struct Client *)data;
295 if (search_text == NULL)
298 webkit_web_view_search_text(WEBKIT_WEB_VIEW(c->web_view), search_text,
299 FALSE, direction == 1, TRUE);
303 zea_scroll(GtkAdjustment *a, gint step_type, gdouble factor)
305 gdouble new, lower, upper, step;
306 lower = gtk_adjustment_get_lower(a);
307 upper = gtk_adjustment_get_upper(a) - gtk_adjustment_get_page_size(a) + lower;
309 step = gtk_adjustment_get_step_increment(a);
311 step = gtk_adjustment_get_page_increment(a);
312 new = gtk_adjustment_get_value(a) + factor * step;
313 new = new < lower ? lower : new;
314 new = new > upper ? upper : new;
315 gtk_adjustment_set_value(a, new);
319 zea_title_changed(GObject *obj, GParamSpec *pspec, gpointer data)
322 struct Client *c = (struct Client *)data;
327 t = webkit_web_view_get_title(WEBKIT_WEB_VIEW(c->web_view));
328 gtk_window_set_title(GTK_WINDOW(c->win), (t == NULL ? "zea" : t));
332 zea_uri_changed(GObject *obj, GParamSpec *pspec, gpointer data)
335 struct Client *c = (struct Client *)data;
340 t = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
341 gtk_entry_set_text(GTK_ENTRY(c->location), (t == NULL ? "zea" : t));
345 zea_load_adblock(void)
349 GIOChannel *channel = NULL;
354 path = g_strdup_printf("%s/zea/adblock.black", g_get_user_config_dir());
355 channel = g_io_channel_new_file(path, "r", &err);
358 while (g_io_channel_read_line(channel, &buf, &length, &term, &err)
359 == G_IO_STATUS_NORMAL)
362 re = g_regex_new(buf,
363 G_REGEX_CASELESS | G_REGEX_OPTIMIZE,
364 G_REGEX_MATCH_PARTIAL, &err);
367 fprintf(stderr, "zea: Could not compile regex: %s\n", buf);
371 adblock_patterns = g_slist_append(adblock_patterns, re);
383 zea_load_status_changed(GObject *obj, GParamSpec *pspec, gpointer data)
385 struct Client *c = (struct Client *)data;
390 if (webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(c->web_view))
391 == WEBKIT_LOAD_FINISHED)
393 gtk_statusbar_pop(GTK_STATUSBAR(c->status), 1);
394 gtk_statusbar_push(GTK_STATUSBAR(c->status), 1, "Finished.");
398 gtk_statusbar_pop(GTK_STATUSBAR(c->status), 1);
399 gtk_statusbar_push(GTK_STATUSBAR(c->status), 1, "Loading...");
404 zea_web_view_hover(WebKitWebView *web_view, gchar *title, gchar *uri,
407 struct Client *c = (struct Client *)data;
412 gtk_statusbar_pop(GTK_STATUSBAR(c->status), 0);
414 gtk_statusbar_push(GTK_STATUSBAR(c->status), 0, uri);
418 zea_web_view_key(GtkWidget *widget, GdkEvent *event, gpointer data)
420 struct Client *c = (struct Client *)data;
424 if (event->type == GDK_KEY_PRESS)
426 if (((GdkEventKey *)event)->state & GDK_CONTROL_MASK)
428 if (((GdkEventKey *)event)->keyval == GDK_KEY_o)
430 gtk_widget_grab_focus(c->location);
433 else if (((GdkEventKey *)event)->keyval == GDK_KEY_h)
435 zea_scroll(gtk_scrolled_window_get_hadjustment(
436 GTK_SCROLLED_WINDOW(c->scroll)), 0, -1);
439 else if (((GdkEventKey *)event)->keyval == GDK_KEY_j)
441 zea_scroll(gtk_scrolled_window_get_vadjustment(
442 GTK_SCROLLED_WINDOW(c->scroll)), 0, 1);
445 else if (((GdkEventKey *)event)->keyval == GDK_KEY_k)
447 zea_scroll(gtk_scrolled_window_get_vadjustment(
448 GTK_SCROLLED_WINDOW(c->scroll)), 0, -1);
451 else if (((GdkEventKey *)event)->keyval == GDK_KEY_l)
453 zea_scroll(gtk_scrolled_window_get_hadjustment(
454 GTK_SCROLLED_WINDOW(c->scroll)), 0, 1);
457 else if (((GdkEventKey *)event)->keyval == GDK_KEY_f)
459 zea_scroll(gtk_scrolled_window_get_vadjustment(
460 GTK_SCROLLED_WINDOW(c->scroll)), 1, 0.5);
463 else if (((GdkEventKey *)event)->keyval == GDK_KEY_b)
465 zea_scroll(gtk_scrolled_window_get_vadjustment(
466 GTK_SCROLLED_WINDOW(c->scroll)), 1, -0.5);
469 else if (((GdkEventKey *)event)->keyval == GDK_KEY_n)
474 else if (((GdkEventKey *)event)->keyval == GDK_KEY_p)
479 else if (((GdkEventKey *)event)->keyval == GDK_KEY_g)
481 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view),
486 else if (((GdkEventKey *)event)->keyval == GDK_KEY_Escape)
488 webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(c->web_view));
489 gtk_statusbar_pop(GTK_STATUSBAR(c->status), 1);
490 gtk_statusbar_push(GTK_STATUSBAR(c->status), 1, "Aborted.");
498 main(int argc, char **argv)
502 gtk_init(&argc, &argv);
504 while ((opt = getopt(argc, argv, "z:e:R")) != -1)
509 global_zoom = atof(optarg);
512 embed = atol(optarg);
515 show_all_requests = TRUE;
522 fprintf(stderr, "Usage: zea [OPTIONS] <URI>\n");
528 first_uri = g_strdup(argv[optind]);
529 for (i = optind; i < argc; i++)
530 zea_new_client(argv[i]);