Introduction
Introduction Statistics Contact Development Disclaimer Help
tsurf.c - surf - [fork] customized build of surf, the suckless webkit browser
git clone git://src.adamsgaard.dk/surf
Log
Files
Refs
README
LICENSE
---
tsurf.c (56046B)
---
1 /* See LICENSE file for copyright and license details.
2 *
3 * To understand surf, start reading main().
4 */
5 #include <sys/file.h>
6 #include <sys/socket.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
9 #include <glib.h>
10 #include <inttypes.h>
11 #include <libgen.h>
12 #include <limits.h>
13 #include <pwd.h>
14 #include <regex.h>
15 #include <signal.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #include <gdk/gdk.h>
22 #include <gdk/gdkkeysyms.h>
23 #include <gdk/gdkx.h>
24 #include <glib/gstdio.h>
25 #include <gtk/gtk.h>
26 #include <gtk/gtkx.h>
27 #include <gcr/gcr.h>
28 #include <JavaScriptCore/JavaScript.h>
29 #include <webkit2/webkit2.h>
30 #include <X11/X.h>
31 #include <X11/Xatom.h>
32 #include <glib.h>
33
34 #ifdef __OpenBSD__
35 #include <err.h>
36 #endif
37
38 #include "arg.h"
39 #include "common.h"
40
41 #define LENGTH(x) (sizeof(x) / sizeof(x[0]))
42 #define CLEANMASK(mask) (mask & (MODKEY|GDK_SHIFT_MASK))
43
44 enum { AtomFind, AtomGo, AtomUri, AtomUTF8, AtomLast };
45
46 enum {
47 OnDoc = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT,
48 OnLink = WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK,
49 OnImg = WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE,
50 OnMedia = WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA,
51 OnEdit = WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE,
52 OnBar = WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR,
53 OnSel = WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION,
54 OnAny = OnDoc | OnLink | OnImg | OnMedia | OnEdit | OnBar | On…
55 };
56
57 typedef enum {
58 AccessMicrophone,
59 AccessWebcam,
60 CaretBrowsing,
61 Certificate,
62 CookiePolicies,
63 DiskCache,
64 DefaultCharset,
65 DNSPrefetch,
66 Ephemeral,
67 FileURLsCrossAccess,
68 FontSize,
69 FrameFlattening,
70 Geolocation,
71 HideBackground,
72 Inspector,
73 Java,
74 JavaScript,
75 KioskMode,
76 LoadImages,
77 MediaManualPlay,
78 PreferredLanguages,
79 RunInFullscreen,
80 ScrollBars,
81 ShowIndicators,
82 SiteQuirks,
83 SmoothScrolling,
84 SpellChecking,
85 SpellLanguages,
86 StrictTLS,
87 Style,
88 WebGL,
89 ZoomLevel,
90 ParameterLast
91 } ParamName;
92
93 typedef union {
94 int i;
95 float f;
96 const void *v;
97 } Arg;
98
99 typedef struct {
100 Arg val;
101 int prio;
102 } Parameter;
103
104 typedef struct Client {
105 GtkWidget *win;
106 WebKitWebView *view;
107 WebKitWebInspector *inspector;
108 WebKitFindController *finder;
109 WebKitHitTestResult *mousepos;
110 GTlsCertificate *cert, *failedcert;
111 GTlsCertificateFlags tlserr;
112 Window xid;
113 guint64 pageid;
114 int progress, fullscreen, https, insecure, errorpage;
115 const char *title, *overtitle, *targeturi;
116 const char *needle;
117 struct Client *next;
118 } Client;
119
120 typedef struct {
121 guint mod;
122 guint keyval;
123 void (*func)(Client *c, const Arg *a);
124 const Arg arg;
125 } Key;
126
127 typedef struct {
128 unsigned int target;
129 unsigned int mask;
130 guint button;
131 void (*func)(Client *c, const Arg *a, WebKitHitTestResult *h);
132 const Arg arg;
133 unsigned int stopevent;
134 } Button;
135
136 typedef struct {
137 const char *uri;
138 Parameter config[ParameterLast];
139 regex_t re;
140 } UriParameters;
141
142 typedef struct {
143 char *regex;
144 char *file;
145 regex_t re;
146 } SiteSpecific;
147
148 /* Surf */
149 static void die(const char *errstr, ...);
150 static void usage(void);
151 static void setup(void);
152 static void sigchld(int unused);
153 static void sighup(int unused);
154 static char *buildfile(const char *path);
155 static char *buildpath(const char *path);
156 static char *untildepath(const char *path);
157 static const char *getuserhomedir(const char *user);
158 static const char *getcurrentuserhomedir(void);
159 static Client *newclient(Client *c);
160 static void loaduri(Client *c, const Arg *a);
161 static const char *geturi(Client *c);
162 static void setatom(Client *c, int a, const char *v);
163 static const char *getatom(Client *c, int a);
164 static void updatetitle(Client *c);
165 static void gettogglestats(Client *c);
166 static void getpagestats(Client *c);
167 static WebKitCookieAcceptPolicy cookiepolicy_get(void);
168 static char cookiepolicy_set(const WebKitCookieAcceptPolicy p);
169 static void seturiparameters(Client *c, const char *uri, ParamName *para…
170 static void setparameter(Client *c, int refresh, ParamName p, const Arg …
171 static const char *getcert(const char *uri);
172 static void setcert(Client *c, const char *file);
173 static const char *getstyle(const char *uri);
174 static void setstyle(Client *c, const char *file);
175 static void runscript(Client *c);
176 static void evalscript(Client *c, const char *jsstr, ...);
177 static void updatewinid(Client *c);
178 static void handleplumb(Client *c, const char *uri);
179 static void newwindow(Client *c, const Arg *a, int noembed);
180 static void spawn(Client *c, const Arg *a);
181 static void msgext(Client *c, char type, const Arg *a);
182 static void destroyclient(Client *c);
183 static void cleanup(void);
184
185 /* GTK/WebKit */
186 static WebKitWebView *newview(Client *c, WebKitWebView *rv);
187 static void initwebextensions(WebKitWebContext *wc, Client *c);
188 static GtkWidget *createview(WebKitWebView *v, WebKitNavigationAction *a,
189 Client *c);
190 static gboolean buttonreleased(GtkWidget *w, GdkEvent *e, Client *c);
191 static GdkFilterReturn processx(GdkXEvent *xevent, GdkEvent *event,
192 gpointer d);
193 static gboolean winevent(GtkWidget *w, GdkEvent *e, Client *c);
194 static gboolean readsock(GIOChannel *s, GIOCondition ioc, gpointer unuse…
195 static void showview(WebKitWebView *v, Client *c);
196 static GtkWidget *createwindow(Client *c);
197 static gboolean loadfailedtls(WebKitWebView *v, gchar *uri,
198 GTlsCertificate *cert,
199 GTlsCertificateFlags err, Client *c);
200 static void loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c);
201 static void progresschanged(WebKitWebView *v, GParamSpec *ps, Client *c);
202 static void titlechanged(WebKitWebView *view, GParamSpec *ps, Client *c);
203 static void mousetargetchanged(WebKitWebView *v, WebKitHitTestResult *h,
204 guint modifiers, Client *c);
205 static gboolean permissionrequested(WebKitWebView *v,
206 WebKitPermissionRequest *r, Client *…
207 static gboolean decidepolicy(WebKitWebView *v, WebKitPolicyDecision *d,
208 WebKitPolicyDecisionType dt, Client *c);
209 static void decidenavigation(WebKitPolicyDecision *d, Client *c);
210 static void decidenewwindow(WebKitPolicyDecision *d, Client *c);
211 static void decideresource(WebKitPolicyDecision *d, Client *c);
212 static void insecurecontent(WebKitWebView *v, WebKitInsecureContentEvent…
213 Client *c);
214 static void downloadstarted(WebKitWebContext *wc, WebKitDownload *d,
215 Client *c);
216 static void responsereceived(WebKitDownload *d, GParamSpec *ps, Client *…
217 static void download(Client *c, WebKitURIResponse *r);
218 static void webprocessterminated(WebKitWebView *v,
219 WebKitWebProcessTerminationReason r,
220 Client *c);
221 static void closeview(WebKitWebView *v, Client *c);
222 static void destroywin(GtkWidget* w, Client *c);
223
224 /* Hotkeys */
225 static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer…
226 static void reload(Client *c, const Arg *a);
227 static void print(Client *c, const Arg *a);
228 static void showcert(Client *c, const Arg *a);
229 static void clipboard(Client *c, const Arg *a);
230 static void zoom(Client *c, const Arg *a);
231 static void scrollv(Client *c, const Arg *a);
232 static void scrollh(Client *c, const Arg *a);
233 static void navigate(Client *c, const Arg *a);
234 static void stop(Client *c, const Arg *a);
235 static void toggle(Client *c, const Arg *a);
236 static void togglefullscreen(Client *c, const Arg *a);
237 static void togglecookiepolicy(Client *c, const Arg *a);
238 static void toggleinspector(Client *c, const Arg *a);
239 static void find(Client *c, const Arg *a);
240
241 /* Buttons */
242 static void clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *…
243 static void clicknewwindow(Client *c, const Arg *a, WebKitHitTestResult …
244 static void clickexternplayer(Client *c, const Arg *a, WebKitHitTestResu…
245
246 static char winid[64];
247 static char togglestats[11];
248 static char pagestats[2];
249 static Atom atoms[AtomLast];
250 static Window embed;
251 static int showxid;
252 static int cookiepolicy;
253 static Display *dpy;
254 static Client *clients;
255 static GdkDevice *gdkkb;
256 static char *stylefile;
257 static const char *useragent;
258 static Parameter *curconfig;
259 static int modparams[ParameterLast];
260 static int spair[2];
261 char *argv0;
262
263 static ParamName loadtransient[] = {
264 Certificate,
265 CookiePolicies,
266 DiskCache,
267 DNSPrefetch,
268 FileURLsCrossAccess,
269 JavaScript,
270 LoadImages,
271 PreferredLanguages,
272 ShowIndicators,
273 StrictTLS,
274 ParameterLast
275 };
276
277 static ParamName loadcommitted[] = {
278 // AccessMicrophone,
279 // AccessWebcam,
280 CaretBrowsing,
281 DefaultCharset,
282 FontSize,
283 FrameFlattening,
284 Geolocation,
285 HideBackground,
286 Inspector,
287 Java,
288 // KioskMode,
289 MediaManualPlay,
290 RunInFullscreen,
291 ScrollBars,
292 SiteQuirks,
293 SmoothScrolling,
294 SpellChecking,
295 SpellLanguages,
296 Style,
297 ZoomLevel,
298 ParameterLast
299 };
300
301 static ParamName loadfinished[] = {
302 ParameterLast
303 };
304
305 /* configuration, allows nested code to access above variables */
306 #include "config.h"
307
308 void
309 die(const char *errstr, ...)
310 {
311 va_list ap;
312
313 va_start(ap, errstr);
314 vfprintf(stderr, errstr, ap);
315 va_end(ap);
316 exit(1);
317 }
318
319 void
320 usage(void)
321 {
322 die("usage: surf [-bBdDfFgGiIkKmMnNpPsStTvwxX]\n"
323 "[-a cookiepolicies ] [-c cookiefile] [-C stylefile] [-e xid…
324 "[-r scriptfile] [-u useragent] [-z zoomlevel] [uri]\n");
325 }
326
327 void
328 setup(void)
329 {
330 GIOChannel *gchanin;
331 GdkDisplay *gdpy;
332 int i, j;
333
334 /* clean up any zombies immediately */
335 sigchld(0);
336 if (signal(SIGHUP, sighup) == SIG_ERR)
337 die("Can't install SIGHUP handler");
338
339 if (!(dpy = XOpenDisplay(NULL)))
340 die("Can't open default display");
341
342 /* atoms */
343 atoms[AtomFind] = XInternAtom(dpy, "_SURF_FIND", False);
344 atoms[AtomGo] = XInternAtom(dpy, "_SURF_GO", False);
345 atoms[AtomUri] = XInternAtom(dpy, "_SURF_URI", False);
346 atoms[AtomUTF8] = XInternAtom(dpy, "UTF8_STRING", False);
347
348 gtk_init(NULL, NULL);
349
350 gdpy = gdk_display_get_default();
351
352 curconfig = defconfig;
353
354 /* dirs and files */
355 cookiefile = buildfile(cookiefile);
356 scriptfile = buildfile(scriptfile);
357 certdir = buildpath(certdir);
358 if (curconfig[Ephemeral].val.i)
359 cachedir = NULL;
360 else
361 cachedir = buildpath(cachedir);
362
363 gdkkb = gdk_seat_get_keyboard(gdk_display_get_default_seat(gdpy)…
364
365 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, spair) < 0) {
366 fputs("Unable to create sockets\n", stderr);
367 spair[0] = spair[1] = -1;
368 } else {
369 gchanin = g_io_channel_unix_new(spair[0]);
370 g_io_channel_set_encoding(gchanin, NULL, NULL);
371 g_io_channel_set_flags(gchanin, g_io_channel_get_flags(g…
372 | G_IO_FLAG_NONBLOCK, NULL);
373 g_io_channel_set_close_on_unref(gchanin, TRUE);
374 g_io_add_watch(gchanin, G_IO_IN, readsock, NULL);
375 }
376
377
378 for (i = 0; i < LENGTH(certs); ++i) {
379 if (!regcomp(&(certs[i].re), certs[i].regex, REG_EXTENDE…
380 certs[i].file = g_strconcat(certdir, "/", certs[…
381 NULL);
382 } else {
383 fprintf(stderr, "Could not compile regex: %s\n",
384 certs[i].regex);
385 certs[i].regex = NULL;
386 }
387 }
388
389 if (!stylefile) {
390 styledir = buildpath(styledir);
391 for (i = 0; i < LENGTH(styles); ++i) {
392 if (!regcomp(&(styles[i].re), styles[i].regex,
393 REG_EXTENDED)) {
394 styles[i].file = g_strconcat(styledir, "…
395 styles[i].file, NULL…
396 } else {
397 fprintf(stderr, "Could not compile regex…
398 styles[i].regex);
399 styles[i].regex = NULL;
400 }
401 }
402 g_free(styledir);
403 } else {
404 stylefile = buildfile(stylefile);
405 }
406
407 for (i = 0; i < LENGTH(uriparams); ++i) {
408 if (regcomp(&(uriparams[i].re), uriparams[i].uri,
409 REG_EXTENDED)) {
410 fprintf(stderr, "Could not compile regex: %s\n",
411 uriparams[i].uri);
412 uriparams[i].uri = NULL;
413 continue;
414 }
415
416 /* copy default parameters with higher priority */
417 for (j = 0; j < ParameterLast; ++j) {
418 if (defconfig[j].prio >= uriparams[i].config[j].…
419 uriparams[i].config[j] = defconfig[j];
420 }
421 }
422 }
423
424 void
425 sigchld(int unused)
426 {
427 if (signal(SIGCHLD, sigchld) == SIG_ERR)
428 die("Can't install SIGCHLD handler");
429 while (waitpid(-1, NULL, WNOHANG) > 0)
430 ;
431 }
432
433 void
434 sighup(int unused)
435 {
436 Arg a = { .i = 0 };
437 Client *c;
438
439 for (c = clients; c; c = c->next)
440 reload(c, &a);
441 }
442
443 char *
444 buildfile(const char *path)
445 {
446 char *dname, *bname, *bpath, *fpath;
447 FILE *f;
448
449 dname = g_path_get_dirname(path);
450 bname = g_path_get_basename(path);
451
452 bpath = buildpath(dname);
453 g_free(dname);
454
455 fpath = g_build_filename(bpath, bname, NULL);
456 g_free(bpath);
457 g_free(bname);
458
459 if (!(f = fopen(fpath, "a")))
460 die("Could not open file: %s\n", fpath);
461
462 g_chmod(fpath, 0600); /* always */
463 fclose(f);
464
465 return fpath;
466 }
467
468 static const char*
469 getuserhomedir(const char *user)
470 {
471 struct passwd *pw = getpwnam(user);
472
473 if (!pw)
474 die("Can't get user %s login information.\n", user);
475
476 return pw->pw_dir;
477 }
478
479 static const char*
480 getcurrentuserhomedir(void)
481 {
482 const char *homedir;
483 const char *user;
484 struct passwd *pw;
485
486 homedir = getenv("HOME");
487 if (homedir)
488 return homedir;
489
490 user = getenv("USER");
491 if (user)
492 return getuserhomedir(user);
493
494 pw = getpwuid(getuid());
495 if (!pw)
496 die("Can't get current user home directory\n");
497
498 return pw->pw_dir;
499 }
500
501 char *
502 buildpath(const char *path)
503 {
504 char *apath, *fpath;
505
506 if (path[0] == '~')
507 apath = untildepath(path);
508 else
509 apath = g_strdup(path);
510
511 /* creating directory */
512 if (g_mkdir_with_parents(apath, 0700) < 0)
513 die("Could not access directory: %s\n", apath);
514
515 fpath = realpath(apath, NULL);
516 g_free(apath);
517
518 return fpath;
519 }
520
521 char *
522 untildepath(const char *path)
523 {
524 char *apath, *name, *p;
525 const char *homedir;
526
527 if (path[1] == '/' || path[1] == '\0') {
528 p = (char *)&path[1];
529 homedir = getcurrentuserhomedir();
530 } else {
531 if ((p = strchr(path, '/')))
532 name = g_strndup(&path[1], p - (path + 1));
533 else
534 name = g_strdup(&path[1]);
535
536 homedir = getuserhomedir(name);
537 g_free(name);
538 }
539 apath = g_build_filename(homedir, p, NULL);
540 return apath;
541 }
542
543 Client *
544 newclient(Client *rc)
545 {
546 Client *c;
547
548 if (!(c = calloc(1, sizeof(Client))))
549 die("Cannot malloc!\n");
550
551 c->next = clients;
552 clients = c;
553
554 c->progress = 100;
555 c->view = newview(c, rc ? rc->view : NULL);
556
557 return c;
558 }
559
560 void
561 loaduri(Client *c, const Arg *a)
562 {
563 struct stat st;
564 char *url, *path, *apath;
565 const char *uri = a->v;
566
567 if (g_strcmp0(uri, "") == 0)
568 return;
569
570 if (g_str_has_prefix(uri, "http://") ||
571 g_str_has_prefix(uri, "https://") ||
572 g_str_has_prefix(uri, "file://") ||
573 g_str_has_prefix(uri, "about:")) {
574 url = g_strdup(uri);
575 } else {
576 if (uri[0] == '~')
577 apath = untildepath(uri);
578 else
579 apath = (char *)uri;
580 if (!stat(apath, &st) && (path = realpath(apath, NULL)))…
581 url = g_strdup_printf("file://%s", path);
582 free(path);
583 } else {
584 url = g_strdup_printf("http://%s", uri);
585 }
586 if (apath != uri)
587 free(apath);
588 }
589
590 setatom(c, AtomUri, url);
591
592 if (strcmp(url, geturi(c)) == 0) {
593 reload(c, a);
594 } else {
595 webkit_web_view_load_uri(c->view, url);
596 updatetitle(c);
597 }
598
599 g_free(url);
600 }
601
602 const char *
603 geturi(Client *c)
604 {
605 const char *uri;
606
607 if (!(uri = webkit_web_view_get_uri(c->view)))
608 uri = "about:blank";
609 return uri;
610 }
611
612 void
613 setatom(Client *c, int a, const char *v)
614 {
615 XChangeProperty(dpy, c->xid,
616 atoms[a], atoms[AtomUTF8], 8, PropModeReplace,
617 (unsigned char *)v, strlen(v) + 1);
618 XSync(dpy, False);
619 }
620
621 const char *
622 getatom(Client *c, int a)
623 {
624 static char buf[BUFSIZ];
625 Atom adummy;
626 int idummy;
627 unsigned long ldummy;
628 unsigned char *p = NULL;
629
630 XSync(dpy, False);
631 XGetWindowProperty(dpy, c->xid,
632 atoms[a], 0L, BUFSIZ, False, atoms[AtomUTF8],
633 &adummy, &idummy, &ldummy, &ldummy, &p);
634 if (p)
635 strncpy(buf, (char *)p, LENGTH(buf) - 1);
636 else
637 buf[0] = '\0';
638 XFree(p);
639
640 return buf;
641 }
642
643 void
644 updatetitle(Client *c)
645 {
646 char *title;
647 const char *name = c->overtitle ? c->overtitle :
648 c->title ? c->title : "";
649
650 if (curconfig[ShowIndicators].val.i) {
651 gettogglestats(c);
652 getpagestats(c);
653
654 if (c->progress != 100)
655 title = g_strdup_printf("[%i%%] %s:%s | %s",
656 c->progress, togglestats, pagestats, nam…
657 else
658 title = g_strdup_printf("%s:%s | %s",
659 togglestats, pagestats, name);
660
661 gtk_window_set_title(GTK_WINDOW(c->win), title);
662 g_free(title);
663 } else {
664 gtk_window_set_title(GTK_WINDOW(c->win), name);
665 }
666 }
667
668 void
669 gettogglestats(Client *c)
670 {
671 togglestats[0] = cookiepolicy_set(cookiepolicy_get());
672 togglestats[1] = curconfig[CaretBrowsing].val.i ? 'C' : 'c';
673 togglestats[2] = curconfig[Geolocation].val.i ? 'G' : 'g';
674 togglestats[3] = curconfig[DiskCache].val.i ? 'D' : 'd';
675 togglestats[4] = curconfig[LoadImages].val.i ? 'I' : 'i';
676 togglestats[5] = curconfig[JavaScript].val.i ? 'S' : 's';
677 togglestats[6] = curconfig[Style].val.i ? 'M' : 'm';
678 togglestats[7] = curconfig[FrameFlattening].val.i ? 'F' : 'f';
679 togglestats[8] = curconfig[Certificate].val.i ? 'X' : 'x';
680 togglestats[9] = curconfig[StrictTLS].val.i ? 'T' : 't';
681 }
682
683 void
684 getpagestats(Client *c)
685 {
686 if (c->https)
687 pagestats[0] = (c->tlserr || c->insecure) ? 'U' : 'T';
688 else
689 pagestats[0] = '-';
690 pagestats[1] = '\0';
691 }
692
693 WebKitCookieAcceptPolicy
694 cookiepolicy_get(void)
695 {
696 switch (((char *)curconfig[CookiePolicies].val.v)[cookiepolicy])…
697 case 'a':
698 return WEBKIT_COOKIE_POLICY_ACCEPT_NEVER;
699 case '@':
700 return WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY;
701 default: /* fallthrough */
702 case 'A':
703 return WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS;
704 }
705 }
706
707 char
708 cookiepolicy_set(const WebKitCookieAcceptPolicy p)
709 {
710 switch (p) {
711 case WEBKIT_COOKIE_POLICY_ACCEPT_NEVER:
712 return 'a';
713 case WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY:
714 return '@';
715 default: /* fallthrough */
716 case WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS:
717 return 'A';
718 }
719 }
720
721 void
722 seturiparameters(Client *c, const char *uri, ParamName *params)
723 {
724 Parameter *config, *uriconfig = NULL;
725 int i, p;
726
727 for (i = 0; i < LENGTH(uriparams); ++i) {
728 if (uriparams[i].uri &&
729 !regexec(&(uriparams[i].re), uri, 0, NULL, 0)) {
730 uriconfig = uriparams[i].config;
731 break;
732 }
733 }
734
735 curconfig = uriconfig ? uriconfig : defconfig;
736
737 for (i = 0; (p = params[i]) != ParameterLast; ++i) {
738 switch(p) {
739 default: /* FALLTHROUGH */
740 if (!(defconfig[p].prio < curconfig[p].prio ||
741 defconfig[p].prio < modparams[p]))
742 continue;
743 case Certificate:
744 case CookiePolicies:
745 case Style:
746 setparameter(c, 0, p, &curconfig[p].val);
747 }
748 }
749 }
750
751 void
752 setparameter(Client *c, int refresh, ParamName p, const Arg *a)
753 {
754 GdkRGBA bgcolor = { 0 };
755 WebKitSettings *s = webkit_web_view_get_settings(c->view);
756
757 modparams[p] = curconfig[p].prio;
758
759 switch (p) {
760 case AccessMicrophone:
761 return; /* do nothing */
762 case AccessWebcam:
763 return; /* do nothing */
764 case CaretBrowsing:
765 webkit_settings_set_enable_caret_browsing(s, a->i);
766 refresh = 0;
767 break;
768 case Certificate:
769 if (a->i)
770 setcert(c, geturi(c));
771 return; /* do not update */
772 case CookiePolicies:
773 webkit_cookie_manager_set_accept_policy(
774 webkit_web_context_get_cookie_manager(
775 webkit_web_view_get_context(c->view)),
776 cookiepolicy_get());
777 refresh = 0;
778 break;
779 case DiskCache:
780 webkit_web_context_set_cache_model(
781 webkit_web_view_get_context(c->view), a->i ?
782 WEBKIT_CACHE_MODEL_WEB_BROWSER :
783 WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
784 return; /* do not update */
785 case DefaultCharset:
786 webkit_settings_set_default_charset(s, a->v);
787 return; /* do not update */
788 case DNSPrefetch:
789 webkit_settings_set_enable_dns_prefetching(s, a->i);
790 return; /* do not update */
791 case FileURLsCrossAccess:
792 webkit_settings_set_allow_file_access_from_file_urls(s, …
793 webkit_settings_set_allow_universal_access_from_file_url…
794 return; /* do not update */
795 case FontSize:
796 webkit_settings_set_default_font_size(s, a->i);
797 return; /* do not update */
798 case FrameFlattening:
799 webkit_settings_set_enable_frame_flattening(s, a->i);
800 break;
801 case Geolocation:
802 refresh = 0;
803 break;
804 case HideBackground:
805 if (a->i)
806 webkit_web_view_set_background_color(c->view, &b…
807 return; /* do not update */
808 case Inspector:
809 webkit_settings_set_enable_developer_extras(s, a->i);
810 return; /* do not update */
811 case Java:
812 webkit_settings_set_enable_java(s, a->i);
813 return; /* do not update */
814 case JavaScript:
815 webkit_settings_set_enable_javascript(s, a->i);
816 break;
817 case KioskMode:
818 return; /* do nothing */
819 case LoadImages:
820 webkit_settings_set_auto_load_images(s, a->i);
821 break;
822 case MediaManualPlay:
823 webkit_settings_set_media_playback_requires_user_gesture…
824 break;
825 case PreferredLanguages:
826 return; /* do nothing */
827 case RunInFullscreen:
828 return; /* do nothing */
829 case ScrollBars:
830 /* Disabled until we write some WebKitWebExtension for
831 * manipulating the DOM directly.
832 enablescrollbars = !enablescrollbars;
833 evalscript(c, "document.documentElement.style.overflow =…
834 enablescrollbars ? "auto" : "hidden");
835 */
836 return; /* do not update */
837 case ShowIndicators:
838 break;
839 case SmoothScrolling:
840 webkit_settings_set_enable_smooth_scrolling(s, a->i);
841 return; /* do not update */
842 case SiteQuirks:
843 webkit_settings_set_enable_site_specific_quirks(s, a->i);
844 break;
845 case SpellChecking:
846 webkit_web_context_set_spell_checking_enabled(
847 webkit_web_view_get_context(c->view), a->i);
848 return; /* do not update */
849 case SpellLanguages:
850 return; /* do nothing */
851 case StrictTLS:
852 webkit_web_context_set_tls_errors_policy(
853 webkit_web_view_get_context(c->view), a->i ?
854 WEBKIT_TLS_ERRORS_POLICY_FAIL :
855 WEBKIT_TLS_ERRORS_POLICY_IGNORE);
856 break;
857 case Style:
858 webkit_user_content_manager_remove_all_style_sheets(
859 webkit_web_view_get_user_content_manager(c->view));
860 if (a->i)
861 setstyle(c, getstyle(geturi(c)));
862 refresh = 0;
863 break;
864 case WebGL:
865 webkit_settings_set_enable_webgl(s, a->i);
866 break;
867 case ZoomLevel:
868 webkit_web_view_set_zoom_level(c->view, a->f);
869 return; /* do not update */
870 default:
871 return; /* do nothing */
872 }
873
874 updatetitle(c);
875 if (refresh)
876 reload(c, a);
877 }
878
879 const char *
880 getcert(const char *uri)
881 {
882 int i;
883
884 for (i = 0; i < LENGTH(certs); ++i) {
885 if (certs[i].regex &&
886 !regexec(&(certs[i].re), uri, 0, NULL, 0))
887 return certs[i].file;
888 }
889
890 return NULL;
891 }
892
893 void
894 setcert(Client *c, const char *uri)
895 {
896 const char *file = getcert(uri);
897 char *host;
898 GTlsCertificate *cert;
899
900 if (!file)
901 return;
902
903 if (!(cert = g_tls_certificate_new_from_file(file, NULL))) {
904 fprintf(stderr, "Could not read certificate file: %s\n",…
905 return;
906 }
907
908 if ((uri = strstr(uri, "https://"))) {
909 uri += sizeof("https://") - 1;
910 host = g_strndup(uri, strchr(uri, '/') - uri);
911 webkit_web_context_allow_tls_certificate_for_host(
912 webkit_web_view_get_context(c->view), cert, host);
913 g_free(host);
914 }
915
916 g_object_unref(cert);
917
918 }
919
920 const char *
921 getstyle(const char *uri)
922 {
923 int i;
924
925 if (stylefile)
926 return stylefile;
927
928 for (i = 0; i < LENGTH(styles); ++i) {
929 if (styles[i].regex &&
930 !regexec(&(styles[i].re), uri, 0, NULL, 0))
931 return styles[i].file;
932 }
933
934 return "";
935 }
936
937 void
938 setstyle(Client *c, const char *file)
939 {
940 gchar *style;
941
942 if (!g_file_get_contents(file, &style, NULL, NULL)) {
943 fprintf(stderr, "Could not read style file: %s\n", file);
944 return;
945 }
946
947 webkit_user_content_manager_add_style_sheet(
948 webkit_web_view_get_user_content_manager(c->view),
949 webkit_user_style_sheet_new(style,
950 WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
951 WEBKIT_USER_STYLE_LEVEL_USER,
952 NULL, NULL));
953
954 g_free(style);
955 }
956
957 void
958 runscript(Client *c)
959 {
960 gchar *script;
961 gsize l;
962
963 if (g_file_get_contents(scriptfile, &script, &l, NULL) && l)
964 evalscript(c, "%s", script);
965 g_free(script);
966 }
967
968 void
969 evalscript(Client *c, const char *jsstr, ...)
970 {
971 va_list ap;
972 gchar *script;
973
974 va_start(ap, jsstr);
975 script = g_strdup_vprintf(jsstr, ap);
976 va_end(ap);
977
978 webkit_web_view_run_javascript(c->view, script, NULL, NULL, NULL…
979 g_free(script);
980 }
981
982 void
983 updatewinid(Client *c)
984 {
985 snprintf(winid, LENGTH(winid), "%lu", c->xid);
986 }
987
988 void
989 handleplumb(Client *c, const char *uri)
990 {
991 Arg a = (Arg)PLUMB(uri);
992 spawn(c, &a);
993 }
994
995 void
996 newwindow(Client *c, const Arg *a, int noembed)
997 {
998 int i = 0;
999 char tmp[64];
1000 const char *cmd[29], *uri;
1001 const Arg arg = { .v = cmd };
1002
1003 cmd[i++] = argv0;
1004 cmd[i++] = "-a";
1005 cmd[i++] = curconfig[CookiePolicies].val.v;
1006 cmd[i++] = curconfig[ScrollBars].val.i ? "-B" : "-b";
1007 if (cookiefile && g_strcmp0(cookiefile, "")) {
1008 cmd[i++] = "-c";
1009 cmd[i++] = cookiefile;
1010 }
1011 if (stylefile && g_strcmp0(stylefile, "")) {
1012 cmd[i++] = "-C";
1013 cmd[i++] = stylefile;
1014 }
1015 cmd[i++] = curconfig[DiskCache].val.i ? "-D" : "-d";
1016 if (embed && !noembed) {
1017 cmd[i++] = "-e";
1018 snprintf(tmp, LENGTH(tmp), "%lu", embed);
1019 cmd[i++] = tmp;
1020 }
1021 cmd[i++] = curconfig[RunInFullscreen].val.i ? "-F" : "-f" ;
1022 cmd[i++] = curconfig[Geolocation].val.i ? "-G" : "-g" ;
1023 cmd[i++] = curconfig[LoadImages].val.i ? "-I" : "-i" ;
1024 cmd[i++] = curconfig[KioskMode].val.i ? "-K" : "-k" ;
1025 cmd[i++] = curconfig[Style].val.i ? "-M" : "-m" ;
1026 cmd[i++] = curconfig[Inspector].val.i ? "-N" : "-n" ;
1027 if (scriptfile && g_strcmp0(scriptfile, "")) {
1028 cmd[i++] = "-r";
1029 cmd[i++] = scriptfile;
1030 }
1031 cmd[i++] = curconfig[JavaScript].val.i ? "-S" : "-s";
1032 cmd[i++] = curconfig[StrictTLS].val.i ? "-T" : "-t";
1033 if (fulluseragent && g_strcmp0(fulluseragent, "")) {
1034 cmd[i++] = "-u";
1035 cmd[i++] = fulluseragent;
1036 }
1037 if (showxid)
1038 cmd[i++] = "-w";
1039 cmd[i++] = curconfig[Certificate].val.i ? "-X" : "-x" ;
1040 /* do not keep zoom level */
1041 cmd[i++] = "--";
1042 if ((uri = a->v))
1043 cmd[i++] = uri;
1044 cmd[i] = NULL;
1045
1046 spawn(c, &arg);
1047 }
1048
1049 void
1050 spawn(Client *c, const Arg *a)
1051 {
1052 if (fork() == 0) {
1053 if (dpy)
1054 close(ConnectionNumber(dpy));
1055 close(spair[0]);
1056 close(spair[1]);
1057 setsid();
1058 execvp(((char **)a->v)[0], (char **)a->v);
1059 fprintf(stderr, "%s: execvp %s", argv0, ((char **)a->v)[…
1060 perror(" failed");
1061 exit(1);
1062 }
1063 }
1064
1065 void
1066 destroyclient(Client *c)
1067 {
1068 Client *p;
1069
1070 webkit_web_view_stop_loading(c->view);
1071 /* Not needed, has already been called
1072 gtk_widget_destroy(c->win);
1073 */
1074
1075 for (p = clients; p && p->next != c; p = p->next)
1076 ;
1077 if (p)
1078 p->next = c->next;
1079 else
1080 clients = c->next;
1081 free(c);
1082 }
1083
1084 void
1085 cleanup(void)
1086 {
1087 while (clients)
1088 destroyclient(clients);
1089
1090 close(spair[0]);
1091 close(spair[1]);
1092 g_free(cookiefile);
1093 g_free(scriptfile);
1094 g_free(stylefile);
1095 g_free(cachedir);
1096 XCloseDisplay(dpy);
1097 }
1098
1099 WebKitWebView *
1100 newview(Client *c, WebKitWebView *rv)
1101 {
1102 WebKitWebView *v;
1103 WebKitSettings *settings;
1104 WebKitWebContext *context;
1105 WebKitCookieManager *cookiemanager;
1106 WebKitUserContentManager *contentmanager;
1107
1108 /* Webview */
1109 if (rv) {
1110 v = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_vie…
1111 } else {
1112 settings = webkit_settings_new_with_settings(
1113 "allow-file-access-from-file-urls", curconfig[FileURL…
1114 "allow-universal-access-from-file-urls", curconfig[Fi…
1115 "auto-load-images", curconfig[LoadImages].val.i,
1116 "default-charset", curconfig[DefaultCharset].val.v,
1117 "default-font-size", curconfig[FontSize].val.i,
1118 "enable-caret-browsing", curconfig[CaretBrowsing].val…
1119 "enable-developer-extras", curconfig[Inspector].val.i,
1120 "enable-dns-prefetching", curconfig[DNSPrefetch].val.…
1121 "enable-frame-flattening", curconfig[FrameFlattening]…
1122 "enable-html5-database", curconfig[DiskCache].val.i,
1123 "enable-html5-local-storage", curconfig[DiskCache].va…
1124 "enable-java", curconfig[Java].val.i,
1125 "enable-javascript", curconfig[JavaScript].val.i,
1126 "enable-site-specific-quirks", curconfig[SiteQuirks].…
1127 "enable-smooth-scrolling", curconfig[SmoothScrolling]…
1128 "enable-webgl", curconfig[WebGL].val.i,
1129 "media-playback-requires-user-gesture", curconfig[Med…
1130 NULL);
1131 /* For more interesting settings, have a look at
1132 * http://webkitgtk.org/reference/webkit2gtk/stable/WebKitSettings.html …
1133
1134 if (strcmp(fulluseragent, "")) {
1135 webkit_settings_set_user_agent(settings, fulluse…
1136 } else if (surfuseragent) {
1137 webkit_settings_set_user_agent_with_application_…
1138 settings, "Surf", VERSION);
1139 }
1140 useragent = webkit_settings_get_user_agent(settings);
1141
1142 contentmanager = webkit_user_content_manager_new();
1143
1144 if (curconfig[Ephemeral].val.i) {
1145 context = webkit_web_context_new_ephemeral();
1146 } else {
1147 context = webkit_web_context_new_with_website_da…
1148 webkit_website_data_manager_new(
1149 "base-cache-directory", cachedir,
1150 "base-data-directory", cachedir,
1151 NULL));
1152 }
1153
1154
1155 cookiemanager = webkit_web_context_get_cookie_manager(co…
1156
1157 /* rendering process model, can be a shared unique one
1158 * or one for each view */
1159 webkit_web_context_set_process_model(context,
1160 WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
1161 /* TLS */
1162 webkit_web_context_set_tls_errors_policy(context,
1163 curconfig[StrictTLS].val.i ? WEBKIT_TLS_ERRORS_POLIC…
1164 WEBKIT_TLS_ERRORS_POLICY_IGNORE);
1165 /* disk cache */
1166 webkit_web_context_set_cache_model(context,
1167 curconfig[DiskCache].val.i ? WEBKIT_CACHE_MODEL_WEB_…
1168 WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
1169
1170 /* Currently only works with text file to be compatible …
1171 if (!curconfig[Ephemeral].val.i)
1172 webkit_cookie_manager_set_persistent_storage(coo…
1173 cookiefile, WEBKIT_COOKIE_PERSISTENT_STORAGE…
1174 /* cookie policy */
1175 webkit_cookie_manager_set_accept_policy(cookiemanager,
1176 cookiepolicy_get());
1177 /* languages */
1178 webkit_web_context_set_preferred_languages(context,
1179 curconfig[PreferredLanguages].val.v);
1180 webkit_web_context_set_spell_checking_languages(context,
1181 curconfig[SpellLanguages].val.v);
1182 webkit_web_context_set_spell_checking_enabled(context,
1183 curconfig[SpellChecking].val.i);
1184
1185 g_signal_connect(G_OBJECT(context), "download-started",
1186 G_CALLBACK(downloadstarted), c);
1187 g_signal_connect(G_OBJECT(context), "initialize-web-exte…
1188 G_CALLBACK(initwebextensions), c);
1189
1190 v = g_object_new(WEBKIT_TYPE_WEB_VIEW,
1191 "settings", settings,
1192 "user-content-manager", contentmanager,
1193 "web-context", context,
1194 NULL);
1195 }
1196
1197 g_signal_connect(G_OBJECT(v), "notify::estimated-load-progress",
1198 G_CALLBACK(progresschanged), c);
1199 g_signal_connect(G_OBJECT(v), "notify::title",
1200 G_CALLBACK(titlechanged), c);
1201 g_signal_connect(G_OBJECT(v), "button-release-event",
1202 G_CALLBACK(buttonreleased), c);
1203 g_signal_connect(G_OBJECT(v), "close",
1204 G_CALLBACK(closeview), c);
1205 g_signal_connect(G_OBJECT(v), "create",
1206 G_CALLBACK(createview), c);
1207 g_signal_connect(G_OBJECT(v), "decide-policy",
1208 G_CALLBACK(decidepolicy), c);
1209 g_signal_connect(G_OBJECT(v), "insecure-content-detected",
1210 G_CALLBACK(insecurecontent), c);
1211 g_signal_connect(G_OBJECT(v), "load-failed-with-tls-errors",
1212 G_CALLBACK(loadfailedtls), c);
1213 g_signal_connect(G_OBJECT(v), "load-changed",
1214 G_CALLBACK(loadchanged), c);
1215 g_signal_connect(G_OBJECT(v), "mouse-target-changed",
1216 G_CALLBACK(mousetargetchanged), c);
1217 g_signal_connect(G_OBJECT(v), "permission-request",
1218 G_CALLBACK(permissionrequested), c);
1219 g_signal_connect(G_OBJECT(v), "ready-to-show",
1220 G_CALLBACK(showview), c);
1221 g_signal_connect(G_OBJECT(v), "web-process-terminated",
1222 G_CALLBACK(webprocessterminated), c);
1223
1224 return v;
1225 }
1226
1227 static gboolean
1228 readsock(GIOChannel *s, GIOCondition ioc, gpointer unused)
1229 {
1230 static char msg[MSGBUFSZ];
1231 GError *gerr = NULL;
1232 gsize msgsz;
1233
1234 if (g_io_channel_read_chars(s, msg, sizeof(msg), &msgsz, &gerr) …
1235 G_IO_STATUS_NORMAL) {
1236 if (gerr) {
1237 fprintf(stderr, "surf: error reading socket: %s\…
1238 gerr->message);
1239 g_error_free(gerr);
1240 }
1241 return TRUE;
1242 }
1243 if (msgsz < 2) {
1244 fprintf(stderr, "surf: message too short: %d\n", msgsz);
1245 return TRUE;
1246 }
1247
1248 return TRUE;
1249 }
1250
1251 void
1252 initwebextensions(WebKitWebContext *wc, Client *c)
1253 {
1254 GVariant *gv;
1255
1256 if (spair[1] < 0)
1257 return;
1258
1259 gv = g_variant_new("i", spair[1]);
1260
1261 webkit_web_context_set_web_extensions_initialization_user_data(w…
1262 webkit_web_context_set_web_extensions_directory(wc, WEBEXTDIR);
1263 }
1264
1265 GtkWidget *
1266 createview(WebKitWebView *v, WebKitNavigationAction *a, Client *c)
1267 {
1268 Client *n;
1269
1270 switch (webkit_navigation_action_get_navigation_type(a)) {
1271 case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */
1272 /*
1273 * popup windows of type “other” are almost always t…
1274 * by user gesture, so inverse the logic here
1275 */
1276 /* instead of this, compare destination uri to mouse-over uri for valida…
1277 if (webkit_navigation_action_is_user_gesture(a))
1278 return NULL;
1279 case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: /* fallthrough */
1280 case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: /* fallthrough */
1281 case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: /* fallthrough */
1282 case WEBKIT_NAVIGATION_TYPE_RELOAD: /* fallthrough */
1283 case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
1284 n = newclient(c);
1285 break;
1286 default:
1287 return NULL;
1288 }
1289
1290 return GTK_WIDGET(n->view);
1291 }
1292
1293 gboolean
1294 buttonreleased(GtkWidget *w, GdkEvent *e, Client *c)
1295 {
1296 WebKitHitTestResultContext element;
1297 int i;
1298
1299 element = webkit_hit_test_result_get_context(c->mousepos);
1300
1301 for (i = 0; i < LENGTH(buttons); ++i) {
1302 if (element & buttons[i].target &&
1303 e->button.button == buttons[i].button &&
1304 CLEANMASK(e->button.state) == CLEANMASK(buttons[i].m…
1305 buttons[i].func) {
1306 buttons[i].func(c, &buttons[i].arg, c->mousepos);
1307 return buttons[i].stopevent;
1308 }
1309 }
1310
1311 return FALSE;
1312 }
1313
1314 GdkFilterReturn
1315 processx(GdkXEvent *e, GdkEvent *event, gpointer d)
1316 {
1317 Client *c = (Client *)d;
1318 XPropertyEvent *ev;
1319 Arg a;
1320
1321 if (((XEvent *)e)->type == PropertyNotify) {
1322 ev = &((XEvent *)e)->xproperty;
1323 if (ev->state == PropertyNewValue) {
1324 if (ev->atom == atoms[AtomFind]) {
1325 find(c, NULL);
1326
1327 return GDK_FILTER_REMOVE;
1328 } else if (ev->atom == atoms[AtomGo]) {
1329 a.v = getatom(c, AtomGo);
1330 loaduri(c, &a);
1331
1332 return GDK_FILTER_REMOVE;
1333 }
1334 }
1335 }
1336 return GDK_FILTER_CONTINUE;
1337 }
1338
1339 gboolean
1340 winevent(GtkWidget *w, GdkEvent *e, Client *c)
1341 {
1342 int i;
1343
1344 switch (e->type) {
1345 case GDK_ENTER_NOTIFY:
1346 c->overtitle = c->targeturi;
1347 updatetitle(c);
1348 break;
1349 case GDK_KEY_PRESS:
1350 if (!curconfig[KioskMode].val.i) {
1351 for (i = 0; i < LENGTH(keys); ++i) {
1352 if (gdk_keyval_to_lower(e->key.keyval) ==
1353 keys[i].keyval &&
1354 CLEANMASK(e->key.state) == keys[i].m…
1355 keys[i].func) {
1356 updatewinid(c);
1357 keys[i].func(c, &(keys[i].arg));
1358 return TRUE;
1359 }
1360 }
1361 }
1362 case GDK_LEAVE_NOTIFY:
1363 c->overtitle = NULL;
1364 updatetitle(c);
1365 break;
1366 case GDK_WINDOW_STATE:
1367 if (e->window_state.changed_mask ==
1368 GDK_WINDOW_STATE_FULLSCREEN)
1369 c->fullscreen = e->window_state.new_window_state…
1370 GDK_WINDOW_STATE_FULLSCREEN;
1371 break;
1372 default:
1373 break;
1374 }
1375
1376 return FALSE;
1377 }
1378
1379 void
1380 showview(WebKitWebView *v, Client *c)
1381 {
1382 GdkRGBA bgcolor = { 0 };
1383 GdkWindow *gwin;
1384
1385 c->finder = webkit_web_view_get_find_controller(c->view);
1386 c->inspector = webkit_web_view_get_inspector(c->view);
1387
1388 c->pageid = webkit_web_view_get_page_id(c->view);
1389 c->win = createwindow(c);
1390
1391 gtk_container_add(GTK_CONTAINER(c->win), GTK_WIDGET(c->view));
1392 gtk_widget_show_all(c->win);
1393 gtk_widget_grab_focus(GTK_WIDGET(c->view));
1394
1395 gwin = gtk_widget_get_window(GTK_WIDGET(c->win));
1396 c->xid = gdk_x11_window_get_xid(gwin);
1397 updatewinid(c);
1398 if (showxid) {
1399 gdk_display_sync(gtk_widget_get_display(c->win));
1400 puts(winid);
1401 fflush(stdout);
1402 }
1403
1404 if (curconfig[HideBackground].val.i)
1405 webkit_web_view_set_background_color(c->view, &bgcolor);
1406
1407 if (!curconfig[KioskMode].val.i) {
1408 gdk_window_set_events(gwin, GDK_ALL_EVENTS_MASK);
1409 gdk_window_add_filter(gwin, processx, c);
1410 }
1411
1412 if (curconfig[RunInFullscreen].val.i)
1413 togglefullscreen(c, NULL);
1414
1415 if (curconfig[ZoomLevel].val.f != 1.0)
1416 webkit_web_view_set_zoom_level(c->view,
1417 curconfig[ZoomLevel].val.…
1418
1419 setatom(c, AtomFind, "");
1420 setatom(c, AtomUri, "about:blank");
1421 }
1422
1423 GtkWidget *
1424 createwindow(Client *c)
1425 {
1426 char *wmstr;
1427 GtkWidget *w;
1428
1429 if (embed) {
1430 w = gtk_plug_new(embed);
1431 } else {
1432 w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1433
1434 wmstr = g_path_get_basename(argv0);
1435 gtk_window_set_wmclass(GTK_WINDOW(w), wmstr, "Surf");
1436 g_free(wmstr);
1437
1438 wmstr = g_strdup_printf("%s[%"PRIu64"]", "Surf", c->page…
1439 gtk_window_set_role(GTK_WINDOW(w), wmstr);
1440 g_free(wmstr);
1441
1442 gtk_window_set_default_size(GTK_WINDOW(w), winsize[0], w…
1443 }
1444
1445 g_signal_connect(G_OBJECT(w), "destroy",
1446 G_CALLBACK(destroywin), c);
1447 g_signal_connect(G_OBJECT(w), "enter-notify-event",
1448 G_CALLBACK(winevent), c);
1449 g_signal_connect(G_OBJECT(w), "key-press-event",
1450 G_CALLBACK(winevent), c);
1451 g_signal_connect(G_OBJECT(w), "leave-notify-event",
1452 G_CALLBACK(winevent), c);
1453 g_signal_connect(G_OBJECT(w), "window-state-event",
1454 G_CALLBACK(winevent), c);
1455
1456 return w;
1457 }
1458
1459 gboolean
1460 loadfailedtls(WebKitWebView *v, gchar *uri, GTlsCertificate *cert,
1461 GTlsCertificateFlags err, Client *c)
1462 {
1463 GString *errmsg = g_string_new(NULL);
1464 gchar *html, *pem;
1465
1466 c->failedcert = g_object_ref(cert);
1467 c->tlserr = err;
1468 c->errorpage = 1;
1469
1470 if (err & G_TLS_CERTIFICATE_UNKNOWN_CA)
1471 g_string_append(errmsg,
1472 "The signing certificate authority is not known.<br>…
1473 if (err & G_TLS_CERTIFICATE_BAD_IDENTITY)
1474 g_string_append(errmsg,
1475 "The certificate does not match the expected identit…
1476 "of the site that it was retrieved from.<br>");
1477 if (err & G_TLS_CERTIFICATE_NOT_ACTIVATED)
1478 g_string_append(errmsg,
1479 "The certificate's activation time "
1480 "is still in the future.<br>");
1481 if (err & G_TLS_CERTIFICATE_EXPIRED)
1482 g_string_append(errmsg, "The certificate has expired.<br…
1483 if (err & G_TLS_CERTIFICATE_REVOKED)
1484 g_string_append(errmsg,
1485 "The certificate has been revoked according to "
1486 "the GTlsConnection's certificate revocation list.<b…
1487 if (err & G_TLS_CERTIFICATE_INSECURE)
1488 g_string_append(errmsg,
1489 "The certificate's algorithm is considered insecure.…
1490 if (err & G_TLS_CERTIFICATE_GENERIC_ERROR)
1491 g_string_append(errmsg,
1492 "Some error occurred validating the certificate.<br>…
1493
1494 g_object_get(cert, "certificate-pem", &pem, NULL);
1495 html = g_strdup_printf("<p>Could not validate TLS for “%s”<b…
1496 "<p>You can inspect the following certifi…
1497 "with Ctrl-t (default keybinding).</p>"
1498 "<p><pre>%s</pre></p>", uri, errmsg->str,…
1499 g_free(pem);
1500 g_string_free(errmsg, TRUE);
1501
1502 webkit_web_view_load_alternate_html(c->view, html, uri, NULL);
1503 g_free(html);
1504
1505 return TRUE;
1506 }
1507
1508 void
1509 loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c)
1510 {
1511 const char *uri = geturi(c);
1512
1513 switch (e) {
1514 case WEBKIT_LOAD_STARTED:
1515 setatom(c, AtomUri, uri);
1516 c->title = uri;
1517 c->https = c->insecure = 0;
1518 seturiparameters(c, uri, loadtransient);
1519 if (c->errorpage)
1520 c->errorpage = 0;
1521 else
1522 g_clear_object(&c->failedcert);
1523 break;
1524 case WEBKIT_LOAD_REDIRECTED:
1525 setatom(c, AtomUri, uri);
1526 c->title = uri;
1527 seturiparameters(c, uri, loadtransient);
1528 break;
1529 case WEBKIT_LOAD_COMMITTED:
1530 setatom(c, AtomUri, uri);
1531 c->title = uri;
1532 seturiparameters(c, uri, loadcommitted);
1533 c->https = webkit_web_view_get_tls_info(c->view, &c->cer…
1534 &c->tlserr);
1535 break;
1536 case WEBKIT_LOAD_FINISHED:
1537 seturiparameters(c, uri, loadfinished);
1538 /* Disabled until we write some WebKitWebExtension for
1539 * manipulating the DOM directly.
1540 evalscript(c, "document.documentElement.style.overflow =…
1541 enablescrollbars ? "auto" : "hidden");
1542 */
1543 runscript(c);
1544 break;
1545 }
1546 updatetitle(c);
1547 }
1548
1549 void
1550 progresschanged(WebKitWebView *v, GParamSpec *ps, Client *c)
1551 {
1552 c->progress = webkit_web_view_get_estimated_load_progress(c->vie…
1553 100;
1554 updatetitle(c);
1555 }
1556
1557 void
1558 titlechanged(WebKitWebView *view, GParamSpec *ps, Client *c)
1559 {
1560 c->title = webkit_web_view_get_title(c->view);
1561 updatetitle(c);
1562 }
1563
1564 void
1565 mousetargetchanged(WebKitWebView *v, WebKitHitTestResult *h, guint modif…
1566 Client *c)
1567 {
1568 WebKitHitTestResultContext hc = webkit_hit_test_result_get_conte…
1569
1570 /* Keep the hit test to know where is the pointer on the next cl…
1571 c->mousepos = h;
1572
1573 if (hc & OnLink)
1574 c->targeturi = webkit_hit_test_result_get_link_uri(h);
1575 else if (hc & OnImg)
1576 c->targeturi = webkit_hit_test_result_get_image_uri(h);
1577 else if (hc & OnMedia)
1578 c->targeturi = webkit_hit_test_result_get_media_uri(h);
1579 else
1580 c->targeturi = NULL;
1581
1582 c->overtitle = c->targeturi;
1583 updatetitle(c);
1584 }
1585
1586 gboolean
1587 permissionrequested(WebKitWebView *v, WebKitPermissionRequest *r, Client…
1588 {
1589 ParamName param = ParameterLast;
1590
1591 if (WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(r)) {
1592 param = Geolocation;
1593 } else if (WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(r)) {
1594 if (webkit_user_media_permission_is_for_audio_device(
1595 WEBKIT_USER_MEDIA_PERMISSION_REQUEST(r)))
1596 param = AccessMicrophone;
1597 else if (webkit_user_media_permission_is_for_video_devic…
1598 WEBKIT_USER_MEDIA_PERMISSION_REQUEST(r)))
1599 param = AccessWebcam;
1600 } else {
1601 return FALSE;
1602 }
1603
1604 if (curconfig[param].val.i)
1605 webkit_permission_request_allow(r);
1606 else
1607 webkit_permission_request_deny(r);
1608
1609 return TRUE;
1610 }
1611
1612 gboolean
1613 decidepolicy(WebKitWebView *v, WebKitPolicyDecision *d,
1614 WebKitPolicyDecisionType dt, Client *c)
1615 {
1616 switch (dt) {
1617 case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
1618 decidenavigation(d, c);
1619 break;
1620 case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
1621 decidenewwindow(d, c);
1622 break;
1623 case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
1624 decideresource(d, c);
1625 break;
1626 default:
1627 webkit_policy_decision_ignore(d);
1628 break;
1629 }
1630 return TRUE;
1631 }
1632
1633 void
1634 decidenavigation(WebKitPolicyDecision *d, Client *c)
1635 {
1636 WebKitNavigationAction *a =
1637 webkit_navigation_policy_decision_get_navigation_action(
1638 WEBKIT_NAVIGATION_POLICY_DECISION(d));
1639
1640 switch (webkit_navigation_action_get_navigation_type(a)) {
1641 case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: /* fallthrough */
1642 case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: /* fallthrough */
1643 case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: /* fallthrough */
1644 case WEBKIT_NAVIGATION_TYPE_RELOAD: /* fallthrough */
1645 case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: /* fallthrough */
1646 case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */
1647 default:
1648 /* Do not navigate to links with a "_blank" target (popu…
1649 if (webkit_navigation_policy_decision_get_frame_name(
1650 WEBKIT_NAVIGATION_POLICY_DECISION(d))) {
1651 webkit_policy_decision_ignore(d);
1652 } else {
1653 /* Filter out navigation to different domain ? */
1654 /* get action→urirequest, copy and load in new…
1655 * on Ctrl+Click ? */
1656 webkit_policy_decision_use(d);
1657 }
1658 break;
1659 }
1660 }
1661
1662 void
1663 decidenewwindow(WebKitPolicyDecision *d, Client *c)
1664 {
1665 Arg arg;
1666 WebKitNavigationAction *a =
1667 webkit_navigation_policy_decision_get_navigation_action(
1668 WEBKIT_NAVIGATION_POLICY_DECISION(d));
1669
1670
1671 switch (webkit_navigation_action_get_navigation_type(a)) {
1672 case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: /* fallthrough */
1673 case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: /* fallthrough */
1674 case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: /* fallthrough */
1675 case WEBKIT_NAVIGATION_TYPE_RELOAD: /* fallthrough */
1676 case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
1677 /* Filter domains here */
1678 /* If the value of “mouse-button” is not 0, then the navigation was …
1679 * test for link clicked but no button ? */
1680 arg.v = webkit_uri_request_get_uri(
1681 webkit_navigation_action_get_request(a));
1682 newwindow(c, &arg, 0);
1683 break;
1684 case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */
1685 default:
1686 break;
1687 }
1688
1689 webkit_policy_decision_ignore(d);
1690 }
1691
1692 void
1693 decideresource(WebKitPolicyDecision *d, Client *c)
1694 {
1695 int i, isascii = 1;
1696 WebKitResponsePolicyDecision *r = WEBKIT_RESPONSE_POLICY_DECISIO…
1697 WebKitURIResponse *res =
1698 webkit_response_policy_decision_get_response(r);
1699 const gchar *uri = webkit_uri_response_get_uri(res);
1700
1701 if (g_str_has_suffix(uri, "/favicon.ico")) {
1702 webkit_policy_decision_ignore(d);
1703 return;
1704 }
1705
1706 if (!g_str_has_prefix(uri, "http://")
1707 && !g_str_has_prefix(uri, "https://")
1708 && !g_str_has_prefix(uri, "about:")
1709 && !g_str_has_prefix(uri, "file://")
1710 && !g_str_has_prefix(uri, "data:")
1711 && !g_str_has_prefix(uri, "blob:")
1712 && strlen(uri) > 0) {
1713 for (i = 0; i < strlen(uri); i++) {
1714 if (!g_ascii_isprint(uri[i])) {
1715 isascii = 0;
1716 break;
1717 }
1718 }
1719 if (isascii) {
1720 handleplumb(c, uri);
1721 webkit_policy_decision_ignore(d);
1722 return;
1723 }
1724 }
1725
1726 if (webkit_response_policy_decision_is_mime_type_supported(r)) {
1727 webkit_policy_decision_use(d);
1728 } else {
1729 webkit_policy_decision_ignore(d);
1730 download(c, res);
1731 }
1732 }
1733
1734 void
1735 insecurecontent(WebKitWebView *v, WebKitInsecureContentEvent e, Client *…
1736 {
1737 c->insecure = 1;
1738 }
1739
1740 void
1741 downloadstarted(WebKitWebContext *wc, WebKitDownload *d, Client *c)
1742 {
1743 g_signal_connect(G_OBJECT(d), "notify::response",
1744 G_CALLBACK(responsereceived), c);
1745 }
1746
1747 void
1748 responsereceived(WebKitDownload *d, GParamSpec *ps, Client *c)
1749 {
1750 download(c, webkit_download_get_response(d));
1751 webkit_download_cancel(d);
1752 }
1753
1754 void
1755 download(Client *c, WebKitURIResponse *r)
1756 {
1757 Arg a = (Arg)DOWNLOAD(webkit_uri_response_get_uri(r), geturi(c));
1758 spawn(c, &a);
1759 }
1760
1761 void
1762 webprocessterminated(WebKitWebView *v, WebKitWebProcessTerminationReason…
1763 Client *c)
1764 {
1765 fprintf(stderr, "web process terminated: %s\n",
1766 r == WEBKIT_WEB_PROCESS_CRASHED ? "crashed" : "no memory…
1767 closeview(v, c);
1768 }
1769
1770 void
1771 closeview(WebKitWebView *v, Client *c)
1772 {
1773 gtk_widget_destroy(c->win);
1774 }
1775
1776 void
1777 destroywin(GtkWidget* w, Client *c)
1778 {
1779 destroyclient(c);
1780 if (!clients)
1781 gtk_main_quit();
1782 }
1783
1784 void
1785 pasteuri(GtkClipboard *clipboard, const char *text, gpointer d)
1786 {
1787 Arg a = {.v = text };
1788 if (text)
1789 loaduri((Client *) d, &a);
1790 }
1791
1792 void
1793 reload(Client *c, const Arg *a)
1794 {
1795 if (a->i)
1796 webkit_web_view_reload_bypass_cache(c->view);
1797 else
1798 webkit_web_view_reload(c->view);
1799 }
1800
1801 void
1802 print(Client *c, const Arg *a)
1803 {
1804 webkit_print_operation_run_dialog(webkit_print_operation_new(c->…
1805 GTK_WINDOW(c->win));
1806 }
1807
1808 void
1809 showcert(Client *c, const Arg *a)
1810 {
1811 GTlsCertificate *cert = c->failedcert ? c->failedcert : c->cert;
1812 GcrCertificate *gcrt;
1813 GByteArray *crt;
1814 GtkWidget *win;
1815 GcrCertificateWidget *wcert;
1816
1817 if (!cert)
1818 return;
1819
1820 g_object_get(cert, "certificate", &crt, NULL);
1821 gcrt = gcr_simple_certificate_new(crt->data, crt->len);
1822 g_byte_array_unref(crt);
1823
1824 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1825 wcert = gcr_certificate_widget_new(gcrt);
1826 g_object_unref(gcrt);
1827
1828 gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(wcert));
1829 gtk_widget_show_all(win);
1830 }
1831
1832 void
1833 clipboard(Client *c, const Arg *a)
1834 {
1835 if (a->i) { /* load clipboard uri */
1836 gtk_clipboard_request_text(gtk_clipboard_get(
1837 GDK_SELECTION_PRIMARY),
1838 pasteuri, c);
1839 } else { /* copy uri */
1840 gtk_clipboard_set_text(gtk_clipboard_get(
1841 GDK_SELECTION_PRIMARY), c->target…
1842 ? c->targeturi : geturi(c), -1);
1843 }
1844 }
1845
1846 void
1847 zoom(Client *c, const Arg *a)
1848 {
1849 if (a->i > 0)
1850 webkit_web_view_set_zoom_level(c->view,
1851 curconfig[ZoomLevel].val.…
1852 else if (a->i < 0)
1853 webkit_web_view_set_zoom_level(c->view,
1854 curconfig[ZoomLevel].val.…
1855 else
1856 webkit_web_view_set_zoom_level(c->view, 1.0);
1857
1858 curconfig[ZoomLevel].val.f = webkit_web_view_get_zoom_level(c->v…
1859 }
1860
1861 static void
1862 msgext(Client *c, char type, const Arg *a)
1863 {
1864 static char msg[MSGBUFSZ];
1865 int ret;
1866
1867 if (spair[0] < 0)
1868 return;
1869
1870 if ((ret = snprintf(msg, sizeof(msg), "%c%c%c", c->pageid, type,…
1871 >= sizeof(msg)) {
1872 fprintf(stderr, "surf: message too long: %d\n", ret);
1873 return;
1874 }
1875
1876 if (send(spair[0], msg, ret, 0) != ret)
1877 fprintf(stderr, "surf: error sending: %u%c%d (%d)\n",
1878 c->pageid, type, a->i, ret);
1879 }
1880
1881 void
1882 scrollv(Client *c, const Arg *a)
1883 {
1884 msgext(c, 'v', a);
1885 }
1886
1887 void
1888 scrollh(Client *c, const Arg *a)
1889 {
1890 msgext(c, 'h', a);
1891 }
1892
1893 void
1894 navigate(Client *c, const Arg *a)
1895 {
1896 if (a->i < 0)
1897 webkit_web_view_go_back(c->view);
1898 else if (a->i > 0)
1899 webkit_web_view_go_forward(c->view);
1900 }
1901
1902 void
1903 stop(Client *c, const Arg *a)
1904 {
1905 webkit_web_view_stop_loading(c->view);
1906 }
1907
1908 void
1909 toggle(Client *c, const Arg *a)
1910 {
1911 curconfig[a->i].val.i ^= 1;
1912 setparameter(c, 1, (ParamName)a->i, &curconfig[a->i].val);
1913 }
1914
1915 void
1916 togglefullscreen(Client *c, const Arg *a)
1917 {
1918 /* toggling value is handled in winevent() */
1919 if (c->fullscreen)
1920 gtk_window_unfullscreen(GTK_WINDOW(c->win));
1921 else
1922 gtk_window_fullscreen(GTK_WINDOW(c->win));
1923 }
1924
1925 void
1926 togglecookiepolicy(Client *c, const Arg *a)
1927 {
1928 ++cookiepolicy;
1929 cookiepolicy %= strlen(curconfig[CookiePolicies].val.v);
1930
1931 setparameter(c, 0, CookiePolicies, NULL);
1932 }
1933
1934 void
1935 toggleinspector(Client *c, const Arg *a)
1936 {
1937 if (webkit_web_inspector_is_attached(c->inspector))
1938 webkit_web_inspector_close(c->inspector);
1939 else if (curconfig[Inspector].val.i)
1940 webkit_web_inspector_show(c->inspector);
1941 }
1942
1943 void
1944 find(Client *c, const Arg *a)
1945 {
1946 const char *s, *f;
1947
1948 if (a && a->i) {
1949 if (a->i > 0)
1950 webkit_find_controller_search_next(c->finder);
1951 else
1952 webkit_find_controller_search_previous(c->finder…
1953 } else {
1954 s = getatom(c, AtomFind);
1955 f = webkit_find_controller_get_search_text(c->finder);
1956
1957 if (g_strcmp0(f, s) == 0) /* reset search */
1958 webkit_find_controller_search(c->finder, "", fin…
1959 G_MAXUINT);
1960
1961 webkit_find_controller_search(c->finder, s, findopts,
1962 G_MAXUINT);
1963
1964 if (strcmp(s, "") == 0)
1965 webkit_find_controller_search_finish(c->finder);
1966 }
1967 }
1968
1969 void
1970 clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h)
1971 {
1972 navigate(c, a);
1973 }
1974
1975 void
1976 clicknewwindow(Client *c, const Arg *a, WebKitHitTestResult *h)
1977 {
1978 Arg arg;
1979
1980 arg.v = webkit_hit_test_result_get_link_uri(h);
1981 newwindow(c, &arg, a->i);
1982 }
1983
1984 void
1985 clickexternplayer(Client *c, const Arg *a, WebKitHitTestResult *h)
1986 {
1987 Arg arg;
1988
1989 arg = (Arg)VIDEOPLAY(webkit_hit_test_result_get_media_uri(h));
1990 spawn(c, &arg);
1991 }
1992
1993 int
1994 main(int argc, char *argv[])
1995 {
1996 Arg arg;
1997 Client *c;
1998
1999 #ifdef __disabled_OpenBSD__
2000 char path[128];
2001 const char* home = getcurrentuserhomedir();
2002
2003 /* in new X session: surf doesn't start until another X program …
2004 if (snprintf(path, sizeof(path), "%s/.cache", home) < 0)
2005 err(1, "snprintf");
2006 if (unveil(path, "rwc") == -1)
2007 err(1, "unveil");
2008
2009 if (snprintf(path, sizeof(path), "%s/.config", home) < 0)
2010 err(1, "snprintf");
2011 if (unveil(path, "r") == -1)
2012 err(1, "unveil");
2013
2014 if (snprintf(path, sizeof(path), "%s/.config/surf", home) < 0)
2015 err(1, "snprintf");
2016 if (unveil(path, "rwxc") == -1)
2017 err(1, "unveil");
2018
2019 if (snprintf(path, sizeof(path), "%s/.icons", home) < 0)
2020 err(1, "snprintf");
2021 if (unveil(path, "r") == -1)
2022 err(1, "unveil");
2023
2024 if (snprintf(path, sizeof(path), "%s/.local", home) < 0)
2025 err(1, "snprintf");
2026 if (unveil(path, "rwc") == -1)
2027 err(1, "unveil");
2028
2029 if (snprintf(path, sizeof(path), "%s/.Xauthority", home) < 0)
2030 err(1, "snprintf");
2031 if (unveil(path, "r") == -1)
2032 err(1, "unveil");
2033
2034 if (snprintf(path, sizeof(path), "%s/.Xdefaults", home) < 0)
2035 err(1, "snprintf");
2036 if (unveil(path, "r") == -1)
2037 err(1, "unveil");
2038
2039 if (snprintf(path, sizeof(path), "%s/tmp", home) < 0)
2040 err(1, "snprintf");
2041 if (unveil(path, "rwc") == -1)
2042 err(1, "unveil");
2043
2044 if (unveil("/bin", "rx") == -1)
2045 err(1, "unveil");
2046
2047 if (unveil("/dev/urandom", "r") == -1)
2048 err(1, "unveil");
2049
2050 if (unveil("/etc/fonts", "r") == -1)
2051 err(1, "unveil");
2052
2053 if (unveil("/etc/gtk-3.0", "r") == -1)
2054 err(1, "unveil");
2055
2056 if (unveil("/etc/xdg", "r") == -1)
2057 err(1, "unveil");
2058
2059 if (unveil("/etc/aspell.conf", "r") == -1)
2060 err(1, "unveil");
2061
2062 if (unveil("/etc/localtime", "r") == -1)
2063 err(1, "unveil");
2064
2065 if (unveil("/etc/machine-id", "r") == -1)
2066 err(1, "unveil");
2067
2068 if (unveil("/tmp", "rwc") == -1)
2069 err(1, "unveil /tmp");
2070
2071 if (unveil("/proc", "rw") == -1)
2072 err(1, "unveil");
2073
2074 if (unveil("/usr/libexec", "r") == -1)
2075 err(1, "unveil");
2076
2077 if (unveil("/usr/local/bin", "rx") == -1)
2078 err(1, "unveil");
2079
2080 if (unveil("/usr/local/lib", "rx") == -1)
2081 err(1, "unveil");
2082
2083 if (unveil("/usr/local/libexec/webkit2gtk-4.0", "x") == -1)
2084 err(1, "unveil /usr/local/libexec/webkit2gtk-4.0");
2085
2086 if (unveil("/usr/local/lib/gdk-pixbuf-2.0", "x") == -1)
2087 err(1, "unveil /usr/local/libexec/gdk-pixbuf-2.0");
2088
2089 if (unveil("/usr/local/share", "r") == -1)
2090 err(1, "unveil");
2091
2092 if (unveil("/usr/local/share/locale", "r") == -1)
2093 err(1, "unveil");
2094
2095 if (unveil("/usr/share/locale", "r") == -1)
2096 err(1, "unveil");
2097
2098 if (unveil("/usr/X11R6/lib", "rx") == -1)
2099 err(1, "unveil");
2100
2101 if (unveil("/var", "rw") == -1)
2102 err(1, "unveil");
2103
2104 if (pledge("stdio rpath wpath cpath dpath tmppath fattr chown fl…
2105 "sendfd recvfd tty proc exec prot_exec ps", N…
2106 err(1, "pledge");
2107 #endif
2108
2109 memset(&arg, 0, sizeof(arg));
2110
2111 /* command line args */
2112 ARGBEGIN {
2113 case 'a':
2114 defconfig[CookiePolicies].val.v = EARGF(usage());
2115 defconfig[CookiePolicies].prio = 2;
2116 break;
2117 case 'b':
2118 defconfig[ScrollBars].val.i = 0;
2119 defconfig[ScrollBars].prio = 2;
2120 break;
2121 case 'B':
2122 defconfig[ScrollBars].val.i = 1;
2123 defconfig[ScrollBars].prio = 2;
2124 break;
2125 case 'c':
2126 cookiefile = EARGF(usage());
2127 break;
2128 case 'C':
2129 stylefile = EARGF(usage());
2130 break;
2131 case 'd':
2132 defconfig[DiskCache].val.i = 0;
2133 defconfig[DiskCache].prio = 2;
2134 break;
2135 case 'D':
2136 defconfig[DiskCache].val.i = 1;
2137 defconfig[DiskCache].prio = 2;
2138 break;
2139 case 'e':
2140 embed = strtol(EARGF(usage()), NULL, 0);
2141 break;
2142 case 'f':
2143 defconfig[RunInFullscreen].val.i = 0;
2144 defconfig[RunInFullscreen].prio = 2;
2145 break;
2146 case 'F':
2147 defconfig[RunInFullscreen].val.i = 1;
2148 defconfig[RunInFullscreen].prio = 2;
2149 break;
2150 case 'g':
2151 defconfig[Geolocation].val.i = 0;
2152 defconfig[Geolocation].prio = 2;
2153 break;
2154 case 'G':
2155 defconfig[Geolocation].val.i = 1;
2156 defconfig[Geolocation].prio = 2;
2157 break;
2158 case 'i':
2159 defconfig[LoadImages].val.i = 0;
2160 defconfig[LoadImages].prio = 2;
2161 break;
2162 case 'I':
2163 defconfig[LoadImages].val.i = 1;
2164 defconfig[LoadImages].prio = 2;
2165 break;
2166 case 'k':
2167 defconfig[KioskMode].val.i = 0;
2168 defconfig[KioskMode].prio = 2;
2169 break;
2170 case 'K':
2171 defconfig[KioskMode].val.i = 1;
2172 defconfig[KioskMode].prio = 2;
2173 break;
2174 case 'm':
2175 defconfig[Style].val.i = 0;
2176 defconfig[Style].prio = 2;
2177 break;
2178 case 'M':
2179 defconfig[Style].val.i = 1;
2180 defconfig[Style].prio = 2;
2181 break;
2182 case 'n':
2183 defconfig[Inspector].val.i = 0;
2184 defconfig[Inspector].prio = 2;
2185 break;
2186 case 'N':
2187 defconfig[Inspector].val.i = 1;
2188 defconfig[Inspector].prio = 2;
2189 break;
2190 case 'r':
2191 scriptfile = EARGF(usage());
2192 break;
2193 case 's':
2194 defconfig[JavaScript].val.i = 0;
2195 defconfig[JavaScript].prio = 2;
2196 break;
2197 case 'S':
2198 defconfig[JavaScript].val.i = 1;
2199 defconfig[JavaScript].prio = 2;
2200 break;
2201 case 't':
2202 defconfig[StrictTLS].val.i = 0;
2203 defconfig[StrictTLS].prio = 2;
2204 break;
2205 case 'T':
2206 defconfig[StrictTLS].val.i = 1;
2207 defconfig[StrictTLS].prio = 2;
2208 break;
2209 case 'u':
2210 fulluseragent = EARGF(usage());
2211 break;
2212 case 'v':
2213 die("surf-"VERSION", see LICENSE for © details\n");
2214 case 'w':
2215 showxid = 1;
2216 break;
2217 case 'x':
2218 defconfig[Certificate].val.i = 0;
2219 defconfig[Certificate].prio = 2;
2220 break;
2221 case 'X':
2222 defconfig[Certificate].val.i = 1;
2223 defconfig[Certificate].prio = 2;
2224 break;
2225 case 'z':
2226 defconfig[ZoomLevel].val.f = strtof(EARGF(usage()), NULL…
2227 defconfig[ZoomLevel].prio = 2;
2228 break;
2229 default:
2230 usage();
2231 } ARGEND;
2232 if (argc > 0)
2233 arg.v = argv[0];
2234 else
2235 arg.v = "about:blank";
2236
2237 setup();
2238 c = newclient(NULL);
2239 showview(NULL, c);
2240
2241 loaduri(c, &arg);
2242 updatetitle(c);
2243
2244 gtk_main();
2245 cleanup();
2246
2247 return 0;
2248 }
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.