]> git.armaanb.net Git - chorizo.git/blob - browser.c
Use ensure_http_prefix() in client_new()
[chorizo.git] / browser.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <string.h>
7
8 #include <gtk/gtk.h>
9 #include <gdk/gdkx.h>
10 #include <gdk/gdkkeysyms.h>
11 #include <gio/gio.h>
12 #include <webkit/webkit.h>
13
14
15 #define DOWNLOAD_DIR "/tmp/tmp"
16 #define LANGUAGE "en-US"
17
18
19 static void adblock(WebKitWebView *, WebKitWebFrame *, WebKitWebResource *,
20                     WebKitNetworkRequest *, WebKitNetworkResponse *, gpointer);
21 static void adblock_load(void);
22 static void client_destroy(GtkWidget *, gpointer);
23 static void client_new(const gchar *uri);
24 static gboolean client_new_request(WebKitWebView *, WebKitWebFrame *,
25                                    WebKitNetworkRequest *,
26                                    WebKitWebNavigationAction *,
27                                    WebKitWebPolicyDecision *, gpointer);
28 static void cooperation_setup(void);
29 static void changed_load_status(GObject *obj, GParamSpec *pspec,
30                                 gpointer data);
31 static void changed_title(GObject *, GParamSpec *, gpointer);
32 static void changed_uri(GObject *, GParamSpec *, gpointer);
33 static gboolean download_request(WebKitWebView *, WebKitWebFrame *,
34                                  WebKitNetworkRequest *, gchar *,
35                                  WebKitWebPolicyDecision *, gpointer);
36 static gboolean download_wget(WebKitWebView *, WebKitDownload *, gpointer);
37 static gchar *ensure_http_prefix(const gchar *);
38 static void hover_web_view(WebKitWebView *, gchar *, gchar *, gpointer);
39 static gboolean key_location(GtkWidget *, GdkEvent *, gpointer);
40 static gboolean key_web_view(GtkWidget *, GdkEvent *, gpointer);
41 static gboolean remote_msg(GIOChannel *, GIOCondition, gpointer);
42 static void search(gpointer, gint);
43 static void scroll(GtkAdjustment *, gint, gdouble);
44 static Window tabbed_launch(void);
45 static void usage(void);
46
47
48 struct Client
49 {
50         GtkWidget *win;
51         GtkWidget *vbox;
52         GtkWidget *location;
53         GtkWidget *status;
54         GtkWidget *scroll;
55         GtkWidget *web_view;
56 };
57
58
59 static GSList *adblock_patterns = NULL;
60 static gint clients = 0;
61 static gboolean cooperative_alone = TRUE;
62 static gboolean cooperative_instances = TRUE;
63 static int cooperative_pipe_fp = 0;
64 static Window embed = 0;
65 static gchar *first_uri = NULL;
66 static gdouble global_zoom = 1.0;
67 static gboolean language_is_set = FALSE;
68 static gchar *search_text = NULL;
69 static gboolean show_all_requests = FALSE;
70 static gboolean tabbed_automagic = TRUE;
71
72
73 void
74 adblock(WebKitWebView *web_view, WebKitWebFrame *frame,
75         WebKitWebResource *resource, WebKitNetworkRequest *request,
76         WebKitNetworkResponse *response, gpointer data)
77 {
78         GSList *it = adblock_patterns;
79         const gchar *uri;
80
81         (void)web_view;
82         (void)frame;
83         (void)resource;
84         (void)response;
85         (void)data;
86
87         uri = webkit_network_request_get_uri(request);
88         if (show_all_requests)
89                 fprintf(stderr, "-> %s\n", uri);
90
91         while (it)
92         {
93                 if (g_regex_match((GRegex *)(it->data), uri, 0, NULL))
94                 {
95                         webkit_network_request_set_uri(request, "about:blank");
96                         if (show_all_requests)
97                                 fprintf(stderr, "\tBLOCKED!\n");
98                         return;
99                 }
100                 it = g_slist_next(it);
101         }
102 }
103
104 void
105 adblock_load(void)
106 {
107         GRegex *re = NULL;
108         GError *err = NULL;
109         GIOChannel *channel = NULL;
110         gchar *path = NULL;
111         gchar *buf = NULL;
112
113         path = g_build_filename(g_get_user_config_dir(), __NAME__, "adblock.black",
114                                 NULL);
115         channel = g_io_channel_new_file(path, "r", &err);
116         if (channel != NULL)
117         {
118                 while (g_io_channel_read_line(channel, &buf, NULL, NULL, NULL)
119                        == G_IO_STATUS_NORMAL)
120                 {
121                         g_strstrip(buf);
122                         re = g_regex_new(buf,
123                                          G_REGEX_CASELESS | G_REGEX_OPTIMIZE,
124                                          G_REGEX_MATCH_PARTIAL, &err);
125                         if (err != NULL)
126                         {
127                                 fprintf(stderr, __NAME__": Could not compile regex: %s\n", buf);
128                                 g_error_free(err);
129                                 err = NULL;
130                         }
131                         adblock_patterns = g_slist_append(adblock_patterns, re);
132
133                         g_free(buf);
134                 }
135         }
136         g_free(path);
137 }
138
139 void
140 client_destroy(GtkWidget *obj, gpointer data)
141 {
142         struct Client *c = (struct Client *)data;
143
144         (void)obj;
145
146         webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(c->web_view));
147         gtk_widget_destroy(c->web_view);
148         gtk_widget_destroy(c->scroll);
149         gtk_widget_destroy(c->status);
150         gtk_widget_destroy(c->location);
151         gtk_widget_destroy(c->vbox);
152         gtk_widget_destroy(c->win);
153         free(c);
154
155         clients--;
156         if (clients == 0)
157                 gtk_main_quit();
158 }
159
160 void
161 client_new(const gchar *uri)
162 {
163         struct Client *c;
164         gchar *capitalized_name = NULL, *f;
165
166         if (cooperative_instances && !cooperative_alone)
167         {
168                 write(cooperative_pipe_fp, uri, strlen(uri));
169                 write(cooperative_pipe_fp, "\n", 1);
170                 return;
171         }
172
173         c = malloc(sizeof(struct Client));
174         if (!c)
175         {
176                 fprintf(stderr, __NAME__": fatal: malloc failed\n");
177                 exit(EXIT_FAILURE);
178         }
179
180         c->win = NULL;
181         if (embed != 0)
182         {
183                 c->win = gtk_plug_new(embed);
184                 if (!gtk_plug_get_embedded(GTK_PLUG(c->win)))
185                 {
186                         fprintf(stderr, __NAME__": Can't plug-in to XID %ld.\n", embed);
187                         gtk_widget_destroy(c->win);
188                         c->win = NULL;
189                         embed = 0;
190                 }
191         }
192
193         if (c->win == NULL)
194         {
195                 c->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
196
197                 capitalized_name = g_strdup(__NAME__);
198                 capitalized_name[0] = g_ascii_toupper(capitalized_name[0]);
199                 gtk_window_set_wmclass(GTK_WINDOW(c->win), __NAME__, capitalized_name);
200                 g_free(capitalized_name);
201         }
202
203         /* When using Gtk2, it only shows a white area when run in suckless'
204          * tabbed. It appears we need to set a default window size for this
205          * to work. This is not needed when using Gtk3. */
206         gtk_window_set_default_size(GTK_WINDOW(c->win), 1024, 768);
207
208         g_signal_connect(G_OBJECT(c->win), "destroy",
209                          G_CALLBACK(client_destroy), c);
210         gtk_window_set_title(GTK_WINDOW(c->win), __NAME__);
211
212         c->web_view = webkit_web_view_new();
213         webkit_web_view_set_full_content_zoom(WEBKIT_WEB_VIEW(c->web_view), TRUE);
214         webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->web_view), global_zoom);
215         g_signal_connect(G_OBJECT(c->web_view), "notify::title",
216                          G_CALLBACK(changed_title), c);
217         g_signal_connect(G_OBJECT(c->web_view), "notify::uri",
218                          G_CALLBACK(changed_uri), c);
219         g_signal_connect(G_OBJECT(c->web_view), "notify::load-status",
220                          G_CALLBACK(changed_load_status), c);
221         g_signal_connect(G_OBJECT(c->web_view),
222                          "new-window-policy-decision-requested",
223                          G_CALLBACK(client_new_request), NULL);
224         g_signal_connect(G_OBJECT(c->web_view),
225                          "mime-type-policy-decision-requested",
226                          G_CALLBACK(download_request), NULL);
227         g_signal_connect(G_OBJECT(c->web_view), "download-requested",
228                          G_CALLBACK(download_wget), NULL);
229         g_signal_connect(G_OBJECT(c->web_view), "key-press-event",
230                          G_CALLBACK(key_web_view), c);
231         g_signal_connect(G_OBJECT(c->web_view), "button-press-event",
232                          G_CALLBACK(key_web_view), c);
233         g_signal_connect(G_OBJECT(c->web_view), "hovering-over-link",
234                          G_CALLBACK(hover_web_view), c);
235         g_signal_connect(G_OBJECT(c->web_view), "resource-request-starting",
236                          G_CALLBACK(adblock), NULL);
237
238         if (!language_is_set)
239         {
240                 g_object_set(webkit_get_default_session(), "accept-language", LANGUAGE,
241                              NULL);
242                 language_is_set = TRUE;
243         }
244
245         c->scroll = gtk_scrolled_window_new(NULL, NULL);
246
247         gtk_container_add(GTK_CONTAINER(c->scroll), c->web_view);
248
249         c->location = gtk_entry_new();
250         g_signal_connect(G_OBJECT(c->location), "key-press-event",
251                          G_CALLBACK(key_location), c);
252
253         c->status = gtk_statusbar_new();
254         gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(c->status), FALSE);
255
256         c->vbox = gtk_vbox_new(FALSE, 2);
257         gtk_box_pack_start(GTK_BOX(c->vbox), c->location, FALSE, FALSE, 0);
258         gtk_container_add(GTK_CONTAINER(c->vbox), c->scroll);
259         gtk_box_pack_end(GTK_BOX(c->vbox), c->status, FALSE, FALSE, 0);
260
261         gtk_container_add(GTK_CONTAINER(c->win), c->vbox);
262
263         gtk_widget_grab_focus(c->web_view);
264         gtk_widget_show_all(c->win);
265
266         f = ensure_http_prefix(uri);
267         webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), f);
268         g_free(f);
269
270         clients++;
271 }
272
273 gboolean
274 client_new_request(WebKitWebView *web_view, WebKitWebFrame *frame,
275                    WebKitNetworkRequest *request,
276                    WebKitWebNavigationAction *navigation_action,
277                    WebKitWebPolicyDecision *policy_decision, gpointer user_data)
278 {
279         (void)web_view;
280         (void)frame;
281         (void)navigation_action;
282         (void)user_data;
283
284         webkit_web_policy_decision_ignore(policy_decision);
285         client_new(webkit_network_request_get_uri(request));
286
287         return TRUE;
288 }
289
290 void
291 cooperation_setup(void)
292 {
293         GIOChannel *towatch;
294         gchar *fifopath;
295
296         fifopath = g_build_filename(g_get_user_runtime_dir(), __NAME__".fifo", NULL);
297
298         if (!g_file_test(fifopath, G_FILE_TEST_EXISTS))
299                 mkfifo(fifopath, 0600);
300
301         cooperative_pipe_fp = open(fifopath, O_WRONLY | O_NONBLOCK);
302         if (!cooperative_pipe_fp)
303         {
304                 fprintf(stderr, __NAME__": Can't open FIFO at all.\n");
305         }
306         else
307         {
308                 if (write(cooperative_pipe_fp, "", 0) == -1)
309                 {
310                         /* Could not do an empty write to the FIFO which means there's
311                          * no one listening. */
312                         close(cooperative_pipe_fp);
313                         towatch = g_io_channel_new_file(fifopath, "r+", NULL);
314                         g_io_add_watch(towatch, G_IO_IN, (GIOFunc)remote_msg, NULL);
315                 }
316                 else
317                         cooperative_alone = FALSE;
318         }
319
320         g_free(fifopath);
321 }
322
323 void
324 changed_load_status(GObject *obj, GParamSpec *pspec, gpointer data)
325 {
326         struct Client *c = (struct Client *)data;
327
328         (void)obj;
329         (void)pspec;
330
331         if (webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(c->web_view))
332             == WEBKIT_LOAD_FINISHED)
333         {
334                 gtk_statusbar_pop(GTK_STATUSBAR(c->status), 1);
335                 gtk_statusbar_push(GTK_STATUSBAR(c->status), 1, "Finished.");
336         }
337         else
338         {
339                 gtk_statusbar_pop(GTK_STATUSBAR(c->status), 1);
340                 gtk_statusbar_push(GTK_STATUSBAR(c->status), 1, "Loading...");
341         }
342 }
343
344 void
345 changed_title(GObject *obj, GParamSpec *pspec, gpointer data)
346 {
347         const gchar *t;
348         struct Client *c = (struct Client *)data;
349
350         (void)obj;
351         (void)pspec;
352
353         t = webkit_web_view_get_title(WEBKIT_WEB_VIEW(c->web_view));
354         gtk_window_set_title(GTK_WINDOW(c->win), (t == NULL ? __NAME__ : t));
355 }
356
357 void
358 changed_uri(GObject *obj, GParamSpec *pspec, gpointer data)
359 {
360         const gchar *t;
361         struct Client *c = (struct Client *)data;
362
363         (void)obj;
364         (void)pspec;
365
366         t = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
367         gtk_entry_set_text(GTK_ENTRY(c->location), (t == NULL ? __NAME__ : t));
368 }
369
370 gboolean
371 download_request(WebKitWebView *web_view, WebKitWebFrame *frame,
372                  WebKitNetworkRequest *request, gchar *mime_type,
373                  WebKitWebPolicyDecision *policy_decision, gpointer data)
374 {
375         (void)frame;
376         (void)request;
377         (void)data;
378
379         if (!webkit_web_view_can_show_mime_type(web_view, mime_type))
380         {
381                 webkit_web_policy_decision_download(policy_decision);
382                 return TRUE;
383         }
384         return FALSE;
385 }
386
387 gboolean
388 download_wget(WebKitWebView *web_view, WebKitDownload *download, gpointer data)
389 {
390         const gchar *uri;
391         char id[16] = "";
392         gint ret;
393
394         (void)web_view;
395         (void)data;
396
397         uri = webkit_download_get_uri(download);
398         if (fork() == 0)
399         {
400                 chdir(DOWNLOAD_DIR);
401                 if (embed == 0)
402                         ret = execlp("xterm", "xterm", "-hold", "-e", "wget", uri, NULL);
403                 else
404                 {
405                         if (snprintf(id, 16, "%ld", embed) >= 16)
406                         {
407                                 fprintf(stderr, __NAME__": id for xterm embed truncated!\n");
408                                 exit(EXIT_FAILURE);
409                         }
410                         ret = execlp("xterm", "xterm", "-hold", "-into", id, "-e", "wget",
411                                      uri, NULL);
412                 }
413
414                 if (ret == -1)
415                 {
416                         fprintf(stderr, __NAME__": exec'ing xterm for download");
417                         perror(" failed");
418                         exit(EXIT_FAILURE);
419                 }
420         }
421
422         return FALSE;
423 }
424
425 gchar *
426 ensure_http_prefix(const gchar *t)
427 {
428         gchar *f;
429
430         f = g_ascii_strdown(t, -1);
431         if (!g_str_has_prefix(f, "http://") &&
432                 !g_str_has_prefix(f, "https://"))
433         {
434                 g_free(f);
435                 f = g_strdup_printf("http://%s", t);
436                 return f;
437         }
438         else
439                 return g_strdup(t);
440 }
441
442 void
443 hover_web_view(WebKitWebView *web_view, gchar *title, gchar *uri,
444                    gpointer data)
445 {
446         struct Client *c = (struct Client *)data;
447
448         (void)web_view;
449         (void)title;
450
451         gtk_statusbar_pop(GTK_STATUSBAR(c->status), 0);
452         if (uri != NULL)
453                 gtk_statusbar_push(GTK_STATUSBAR(c->status), 0, uri);
454 }
455
456 gboolean
457 key_location(GtkWidget *widget, GdkEvent *event, gpointer data)
458 {
459         struct Client *c = (struct Client *)data;
460         const gchar *t;
461         gchar *f;
462
463         (void)widget;
464
465         if (event->type == GDK_KEY_PRESS)
466         {
467                 switch (((GdkEventKey *)event)->keyval)
468                 {
469                         case GDK_KEY_Return:
470                                 gtk_widget_grab_focus(c->web_view);
471                                 t = gtk_entry_get_text(GTK_ENTRY(c->location));
472                                 if (t != NULL && t[0] == '/')
473                                 {
474                                         if (search_text != NULL)
475                                                 g_free(search_text);
476                                         search_text = g_strdup(t + 1);  /* XXX whacky */
477                                         search(c, 1);
478                                 }
479                                 else
480                                 {
481                                         f = ensure_http_prefix(t);
482                                         webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), f);
483                                         g_free(f);
484                                 }
485                                 return TRUE;
486                         case GDK_KEY_Escape:
487                                 t = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
488                                 gtk_entry_set_text(GTK_ENTRY(c->location),
489                                                    (t == NULL ? __NAME__ : t));
490                                 return TRUE;
491                 }
492         }
493
494         return FALSE;
495 }
496
497 gboolean
498 key_web_view(GtkWidget *widget, GdkEvent *event, gpointer data)
499 {
500         struct Client *c = (struct Client *)data;
501         WebKitHitTestResultContext ht_context;
502         WebKitHitTestResult *ht_result = NULL;
503         char *ht_uri =  NULL;
504
505         (void)widget;
506
507         if (event->type == GDK_KEY_PRESS)
508         {
509                 if (((GdkEventKey *)event)->state & GDK_CONTROL_MASK)
510                 {
511                         switch (((GdkEventKey *)event)->keyval)
512                         {
513                                 case GDK_KEY_o:
514                                         gtk_widget_grab_focus(c->location);
515                                         return TRUE;
516                                 case GDK_KEY_h:
517                                         scroll(gtk_scrolled_window_get_hadjustment(
518                                                GTK_SCROLLED_WINDOW(c->scroll)), 0, -1);
519                                         return TRUE;
520                                 case GDK_KEY_j:
521                                         scroll(gtk_scrolled_window_get_vadjustment(
522                                                GTK_SCROLLED_WINDOW(c->scroll)), 0, 1);
523                                         return TRUE;
524                                 case GDK_KEY_k:
525                                         scroll(gtk_scrolled_window_get_vadjustment(
526                                                GTK_SCROLLED_WINDOW(c->scroll)), 0, -1);
527                                         return TRUE;
528                                 case GDK_KEY_l:
529                                         scroll(gtk_scrolled_window_get_hadjustment(
530                                                GTK_SCROLLED_WINDOW(c->scroll)), 0, 1);
531                                         return TRUE;
532                                 case GDK_KEY_f:
533                                         scroll(gtk_scrolled_window_get_vadjustment(
534                                                GTK_SCROLLED_WINDOW(c->scroll)), 1, 0.5);
535                                         return TRUE;
536                                 case GDK_KEY_b:
537                                         scroll(gtk_scrolled_window_get_vadjustment(
538                                                GTK_SCROLLED_WINDOW(c->scroll)), 1, -0.5);
539                                         return TRUE;
540                                 case GDK_KEY_n:
541                                         search(c, 1);
542                                         return TRUE;
543                                 case GDK_KEY_p:
544                                         search(c, -1);
545                                         return TRUE;
546                                 case GDK_KEY_g:
547                                         webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view),
548                                                                  first_uri);
549                                         return TRUE;
550                         }
551                 }
552                 else if (((GdkEventKey *)event)->keyval == GDK_KEY_Escape)
553                 {
554                         webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(c->web_view));
555                         gtk_statusbar_pop(GTK_STATUSBAR(c->status), 1);
556                         gtk_statusbar_push(GTK_STATUSBAR(c->status), 1, "Aborted.");
557                 }
558         }
559         else if (event->type == GDK_BUTTON_PRESS)
560         {
561                 switch (((GdkEventButton *)event)->button)
562                 {
563                         case 2:
564                                 ht_result = webkit_web_view_get_hit_test_result(
565                                                                    WEBKIT_WEB_VIEW(c->web_view),
566                                                                        (GdkEventButton *)event);
567                                 g_object_get(ht_result, "context", &ht_context, NULL);
568                                 if (ht_context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
569                                 {
570                                         g_object_get(ht_result, "link-uri", &ht_uri, NULL);
571                                         client_new(ht_uri);
572                                         g_object_unref(ht_result);
573                                         return TRUE;
574                                 }
575                                 g_object_unref(ht_result);
576                                 return FALSE;
577                         case 8:
578                                 webkit_web_view_go_back(WEBKIT_WEB_VIEW(c->web_view));
579                                 return TRUE;
580                         case 9:
581                                 webkit_web_view_go_forward(WEBKIT_WEB_VIEW(c->web_view));
582                                 return TRUE;
583                 }
584         }
585
586         return FALSE;
587 }
588
589 gboolean
590 remote_msg(GIOChannel *channel, GIOCondition condition, gpointer data)
591 {
592         gchar *uri = NULL;
593
594         (void)condition;
595         (void)data;
596
597         g_io_channel_read_line(channel, &uri, NULL, NULL, NULL);
598         if (uri)
599         {
600                 g_strstrip(uri);
601                 client_new(uri);
602                 g_free(uri);
603         }
604         return TRUE;
605 }
606
607 void
608 search(gpointer data, gint direction)
609 {
610         struct Client *c = (struct Client *)data;
611
612         if (search_text == NULL)
613                 return;
614
615         webkit_web_view_search_text(WEBKIT_WEB_VIEW(c->web_view), search_text,
616                                     FALSE, direction == 1, TRUE);
617 }
618
619 void
620 scroll(GtkAdjustment *a, gint step_type, gdouble factor)
621 {
622         gdouble new, lower, upper, step;
623         lower = gtk_adjustment_get_lower(a);
624         upper = gtk_adjustment_get_upper(a) - gtk_adjustment_get_page_size(a) + lower;
625         if (step_type == 0)
626                 step = gtk_adjustment_get_step_increment(a);
627         else
628                 step = gtk_adjustment_get_page_increment(a);
629         new = gtk_adjustment_get_value(a) + factor * step;
630         new = new < lower ? lower : new;
631         new = new > upper ? upper : new;
632         gtk_adjustment_set_value(a, new);
633 }
634
635 Window
636 tabbed_launch(void)
637 {
638         gint tabbed_stdout;
639         GIOChannel *tabbed_stdout_channel;
640         GError *err = NULL;
641         gchar *output = NULL;
642         char *argv[] = { "tabbed", "-c", "-d", "-n", __NAME__, NULL };
643         Window plug_into;
644
645         if (!g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
646                                       NULL, NULL, NULL, &tabbed_stdout, NULL,
647                                       &err))
648         {
649                 fprintf(stderr, __NAME__": Could not launch tabbed: %s\n", err->message);
650                 g_error_free(err);
651                 return 0;
652         }
653
654         tabbed_stdout_channel = g_io_channel_unix_new(tabbed_stdout);
655         g_io_channel_read_line(tabbed_stdout_channel, &output, NULL, NULL, NULL);
656         if (output == NULL)
657         {
658                 fprintf(stderr, __NAME__": Could not read XID from tabbed\n");
659                 return 0;
660         }
661
662         g_io_channel_shutdown(tabbed_stdout_channel, FALSE, NULL);
663
664         g_strstrip(output);
665         plug_into = strtol(output, NULL, 16);
666         g_free(output);
667         return plug_into;
668 }
669
670 void
671 usage(void)
672 {
673         fprintf(stderr, "Usage: "__NAME__" [OPTION]... <URI>...\n");
674         exit(EXIT_FAILURE);
675 }
676
677
678 int
679 main(int argc, char **argv)
680 {
681         int opt, i;
682
683         gtk_init(&argc, &argv);
684
685         while ((opt = getopt(argc, argv, "z:e:rCT")) != -1)
686         {
687                 switch (opt)
688                 {
689                         case 'z':
690                                 global_zoom = atof(optarg);
691                                 break;
692                         case 'e':
693                                 embed = atol(optarg);
694                                 tabbed_automagic = FALSE;
695                                 break;
696                         case 'r':
697                                 show_all_requests = TRUE;
698                                 break;
699                         case 'C':
700                                 cooperative_instances = FALSE;
701                                 break;
702                         case 'T':
703                                 tabbed_automagic = FALSE;
704                                 break;
705                         default:
706                                 usage();
707                 }
708         }
709
710         if (optind >= argc)
711                 usage();
712
713         adblock_load();
714         cooperation_setup();
715
716         if (tabbed_automagic && !(cooperative_instances && !cooperative_alone))
717                 embed = tabbed_launch();
718
719         first_uri = g_strdup(argv[optind]);
720         for (i = optind; i < argc; i++)
721                 client_new(argv[i]);
722         if (!cooperative_instances || cooperative_alone)
723                 gtk_main();
724         exit(EXIT_SUCCESS);
725 }