Add fullscreen mode as flag and config option.
[surf.git] / surf.c
diff --git a/surf.c b/surf.c
index 830665a..42bc393 100644 (file)
--- a/surf.c
+++ b/surf.c
@@ -2,6 +2,7 @@
  *
  * To understand surf, start reading main().
  */
+
 #include <signal.h>
 #include <X11/X.h>
 #include <X11/Xatom.h>
@@ -77,9 +78,10 @@ static GdkNativeWindow embed = 0;
 static gboolean showxid = FALSE;
 static char winid[64];
 static gboolean usingproxy = 0;
-static char togglestat[6];
+static char togglestat[7];
 static char pagestat[3];
 
+static void addaccelgroup(Client *c);
 static void beforerequest(WebKitWebView *w, WebKitWebFrame *f,
                WebKitWebResource *r, WebKitNetworkRequest *req,
                WebKitNetworkResponse *resp, gpointer d);
@@ -105,12 +107,16 @@ static gboolean decidedownload(WebKitWebView *v, WebKitWebFrame *f,
 static gboolean decidewindow(WebKitWebView *v, WebKitWebFrame *f,
                WebKitNetworkRequest *r, WebKitWebNavigationAction *n,
                WebKitWebPolicyDecision *p, Client *c);
+static gboolean deletion_interface(WebKitWebView *view,
+               WebKitDOMHTMLElement *arg1, Client *c);
 static void destroyclient(Client *c);
 static void destroywin(GtkWidget* w, Client *c);
 static void die(const char *errstr, ...);
 static void eval(Client *c, const Arg *arg);
 static void find(Client *c, const Arg *arg);
 static void fullscreen(Client *c, const Arg *arg);
+static void geopolicyrequested(WebKitWebView *v, WebKitWebFrame *f,
+               WebKitGeolocationPolicyDecision *d, Client *c);
 static const char *getatom(Client *c, int a);
 static void gettogglestat(Client *c);
 static void getpagestat(Client *c);
@@ -124,7 +130,9 @@ static gboolean inspector_show(WebKitWebInspector *i, Client *c);
 static gboolean inspector_close(WebKitWebInspector *i, Client *c);
 static void inspector_finished(WebKitWebInspector *i, Client *c);
 
-static gboolean keypress(GtkWidget *w, GdkEventKey *ev, Client *c);
+static gboolean keypress(GtkAccelGroup *group,
+               GObject *obj, guint key, GdkModifierType mods,
+               Client *c);
 static void linkhover(WebKitWebView *v, const char* t, const char* l,
                Client *c);
 static void loadstatuschange(WebKitWebView *view, GParamSpec *pspec,
@@ -153,9 +161,10 @@ static void stop(Client *c, const Arg *arg);
 static void titlechange(WebKitWebView *v, WebKitWebFrame *frame,
                const char *title, Client *c);
 static void toggle(Client *c, const Arg *arg);
+static void togglegeolocation(Client *c, const Arg *arg);
 static void togglescrollbars(Client *c, const Arg *arg);
 static void togglestyle(Client *c, const Arg *arg);
-static void update(Client *c);
+static void updatetitle(Client *c);
 static void updatewinid(Client *c);
 static void usage(void);
 static void windowobjectcleared(GtkWidget *w, WebKitWebFrame *frame,
@@ -165,6 +174,20 @@ static void zoom(Client *c, const Arg *arg);
 /* configuration, allows nested code to access above variables */
 #include "config.h"
 
+static void
+addaccelgroup(Client *c) {
+       int i;
+       GtkAccelGroup *group = gtk_accel_group_new();
+       GClosure *closure;
+
+       for(i = 0; i < LENGTH(keys); i++) {
+               closure = g_cclosure_new(G_CALLBACK(keypress), c, NULL);
+               gtk_accel_group_connect(group, keys[i].keyval, keys[i].mod,
+                               0, closure);
+       }
+       gtk_window_add_accel_group(GTK_WINDOW(c->win), group);
+}
+
 static void
 beforerequest(WebKitWebView *w, WebKitWebFrame *f, WebKitWebResource *r,
                WebKitNetworkRequest *req, WebKitNetworkResponse *resp,
@@ -369,6 +392,12 @@ decidewindow(WebKitWebView *view, WebKitWebFrame *f, WebKitNetworkRequest *r,
        return FALSE;
 }
 
+static gboolean
+deletion_interface(WebKitWebView *view,
+               WebKitDOMHTMLElement *arg1, Client *c) {
+       return FALSE;
+}
+
 static void
 destroyclient(Client *c) {
        Client *p;
@@ -424,6 +453,16 @@ fullscreen(Client *c, const Arg *arg) {
        c->fullscreen = !c->fullscreen;
 }
 
+static void
+geopolicyrequested(WebKitWebView *v, WebKitWebFrame *f,
+               WebKitGeolocationPolicyDecision *d, Client *c) {
+       if(allowgeolocation) {
+               webkit_geolocation_policy_allow(d);
+       } else {
+               webkit_geolocation_policy_deny(d);
+       }
+}
+
 static const char *
 getatom(Client *c, int a) {
        static char buf[BUFSIZ];
@@ -514,14 +553,17 @@ inspector_finished(WebKitWebInspector *i, Client *c) {
 }
 
 static gboolean
-keypress(GtkWidget* w, GdkEventKey *ev, Client *c) {
+keypress(GtkAccelGroup *group, GObject *obj,
+               guint key, GdkModifierType mods, Client *c) {
        guint i;
        gboolean processed = FALSE;
 
+       mods = CLEANMASK(mods);
+       key = gdk_keyval_to_lower(key);
        updatewinid(c);
        for(i = 0; i < LENGTH(keys); i++) {
-               if(gdk_keyval_to_lower(ev->keyval) == keys[i].keyval
-                               && CLEANMASK(ev->state) == keys[i].mod
+               if(key == keys[i].keyval
+                               && mods == keys[i].mod
                                && keys[i].func) {
                        keys[i].func(c, &(keys[i].arg));
                        processed = TRUE;
@@ -539,7 +581,7 @@ linkhover(WebKitWebView *v, const char* t, const char* l, Client *c) {
                free(c->linkhover);
                c->linkhover = NULL;
        }
-       update(c);
+       updatetitle(c);
 }
 
 static void
@@ -565,7 +607,7 @@ loadstatuschange(WebKitWebView *view, GParamSpec *pspec, Client *c) {
                break;
        case WEBKIT_LOAD_FINISHED:
                c->progress = 100;
-               update(c);
+               updatetitle(c);
                break;
        default:
                break;
@@ -577,12 +619,13 @@ loaduri(Client *c, const Arg *arg) {
        char *u, *rp;
        const char *uri = (char *)arg->v;
        Arg a = { .b = FALSE };
+       struct stat st;
 
        if(strcmp(uri, "") == 0)
                return;
 
        /* In case it's a file path. */
-       if(uri[0] == '/') {
+       if(stat(uri, &st) == 0) {
                rp = realpath(uri, NULL);
                u = g_strdup_printf("file://%s", rp);
                free(rp);
@@ -599,7 +642,7 @@ loaduri(Client *c, const Arg *arg) {
                c->progress = 0;
                c->title = copystr(&c->title, u);
                g_free(u);
-               update(c);
+               updatetitle(c);
        }
 }
 
@@ -615,6 +658,8 @@ newclient(void) {
        WebKitWebSettings *settings;
        WebKitWebFrame *frame;
        GdkGeometry hints = { 1, 1 };
+       GdkScreen *screen;
+       gdouble dpi;
        char *uri, *ua;
 
        if(!(c = calloc(1, sizeof(Client))))
@@ -644,11 +689,9 @@ newclient(void) {
        g_signal_connect(G_OBJECT(c->win),
                        "destroy",
                        G_CALLBACK(destroywin), c);
-       if(!kioskmode) {
-               g_signal_connect(G_OBJECT(c->win),
-                               "key-press-event",
-                               G_CALLBACK(keypress), c);
-       }
+
+       if(!kioskmode)
+               addaccelgroup(c);
 
        /* Pane */
        c->pane = gtk_vpaned_new();
@@ -666,6 +709,9 @@ newclient(void) {
        g_signal_connect(G_OBJECT(c->view),
                        "hovering-over-link",
                        G_CALLBACK(linkhover), c);
+       g_signal_connect(G_OBJECT(c->view),
+                       "geolocation-policy-decision-requested",
+                       G_CALLBACK(geopolicyrequested), c);
        g_signal_connect(G_OBJECT(c->view),
                        "create-web-view",
                        G_CALLBACK(createwindow), c);
@@ -696,6 +742,9 @@ newclient(void) {
        g_signal_connect(G_OBJECT(c->view),
                        "resource-request-starting",
                        G_CALLBACK(beforerequest), c);
+       g_signal_connect(G_OBJECT(c->view),
+                       "should-show-delete-interface-for-element",
+                       G_CALLBACK(deletion_interface), c);
 
        /* Scrolled Window */
        c->scroll = gtk_scrolled_window_new(NULL, NULL);
@@ -755,6 +804,21 @@ newclient(void) {
        g_object_set(G_OBJECT(settings), "default-font-size",
                        defaultfontsize, NULL);
 
+       /*
+        * While stupid, CSS specifies that a pixel represents 1/96 of an inch.
+        * This ensures websites are not unusably small with a high DPI screen.
+        * It is equivalent to firefox's "layout.css.devPixelsPerPx" setting.
+        */
+       if(zoomto96dpi) {
+               screen = gdk_window_get_screen(GTK_WIDGET(c->win)->window);
+               dpi = gdk_screen_get_resolution(screen);
+               if(dpi != -1) {
+                       g_object_set(G_OBJECT(settings), "enforce-96-dpi", true,
+                                       NULL);
+                       webkit_web_view_set_zoom_level(c->view, dpi/96);
+               }
+       }
+
        if(enableinspector) {
                c->inspector = WEBKIT_WEB_INSPECTOR(
                                webkit_web_view_get_inspector(c->view));
@@ -769,6 +833,11 @@ newclient(void) {
                c->isinspecting = false;
        }
 
+       if(runinfullscreen) {
+               c->fullscreen = 0;
+               fullscreen(c, NULL);
+       }
+
        g_free(uri);
 
        setatom(c, AtomFind, "");
@@ -796,7 +865,7 @@ newclient(void) {
 static void
 newwindow(Client *c, const Arg *arg, gboolean noembed) {
        guint i = 0;
-       const char *cmd[12], *uri;
+       const char *cmd[14], *uri;
        const Arg a = { .v = (void *)cmd };
        char tmp[64];
 
@@ -818,6 +887,8 @@ newwindow(Client *c, const Arg *arg, gboolean noembed) {
                cmd[i++] = "-s";
        if(showxid)
                cmd[i++] = "-x";
+       cmd[i++] = "-c";
+       cmd[i++] = cookiefile;
        cmd[i++] = "--";
        uri = arg->v ? (char *)arg->v : c->linkhover;
        if(uri)
@@ -889,11 +960,12 @@ processx(GdkXEvent *e, GdkEvent *event, gpointer d) {
                        if(ev->atom == atoms[AtomFind]) {
                                arg.b = TRUE;
                                find(c, &arg);
+
                                return GDK_FILTER_REMOVE;
-                       }
-                       else if(ev->atom == atoms[AtomGo]) {
+                       } else if(ev->atom == atoms[AtomGo]) {
                                arg.v = getatom(c, AtomGo);
                                loaduri(c, &arg);
+
                                return GDK_FILTER_REMOVE;
                        }
                }
@@ -904,7 +976,7 @@ processx(GdkXEvent *e, GdkEvent *event, gpointer d) {
 static void
 progresschange(WebKitWebView *view, GParamSpec *pspec, Client *c) {
        c->progress = webkit_web_view_get_progress(c->view) * 100;
-       update(c);
+       updatetitle(c);
 }
 
 static void
@@ -1052,7 +1124,7 @@ stop(Client *c, const Arg *arg) {
 static void
 titlechange(WebKitWebView *v, WebKitWebFrame *f, const char *t, Client *c) {
        c->title = copystr(&c->title, t);
-       update(c);
+       updatetitle(c);
 }
 
 static void
@@ -1066,7 +1138,7 @@ toggle(Client *c, const Arg *arg) {
        g_object_get(G_OBJECT(settings), name, &value, NULL);
        g_object_set(G_OBJECT(settings), name, !value, NULL);
 
-       reload(c,&a);
+       reload(c, &a);
 }
 
 static void
@@ -1087,6 +1159,15 @@ twitch(Client *c, const Arg *arg) {
        gtk_adjustment_set_value(a, v);
 }
 
+static void
+togglegeolocation(Client *c, const Arg *arg) {
+       Arg a = { .b = FALSE };
+
+       allowgeolocation ^= 1;
+
+       reload(c, &a);
+}
+
 static void
 togglescrollbars(Client *c, const Arg *arg) {
        GtkPolicyType vspolicy;
@@ -1117,7 +1198,7 @@ togglestyle(Client *c, const Arg *arg) {
        uri = uri[0] ? g_strdup("") : g_strconcat("file://", stylefile, NULL);
        g_object_set(G_OBJECT(settings), "user-stylesheet-uri", uri, NULL);
 
-       update(c);
+       updatetitle(c);
 }
 
 static void
@@ -1130,19 +1211,21 @@ gettogglestat(Client *c){
                        &value, NULL);
        togglestat[0] = value? 'C': 'c';
 
+       togglestat[1] = allowgeolocation? 'G': 'g';
+
        g_object_get(G_OBJECT(settings), "auto-load-images", &value, NULL);
-       togglestat[1] = value? 'I': 'i';
+       togglestat[2] = value? 'I': 'i';
 
        g_object_get(G_OBJECT(settings), "enable-scripts", &value, NULL);
-       togglestat[2] = value? 'S': 's';
+       togglestat[3] = value? 'S': 's';
 
        g_object_get(G_OBJECT(settings), "enable-plugins", &value, NULL);
-       togglestat[3] = value? 'V': 'v';
+       togglestat[4] = value? 'V': 'v';
 
        g_object_get(G_OBJECT(settings), "user-stylesheet-uri", &uri, NULL);
-       togglestat[4] = uri[0] ? 'M': 'm';
+       togglestat[5] = uri[0] ? 'M': 'm';
 
-       togglestat[5] = '\0';
+       togglestat[6] = '\0';
 }
 
 static void
@@ -1161,23 +1244,29 @@ getpagestat(Client *c) {
 }
 
 static void
-update(Client *c) {
+updatetitle(Client *c) {
        char *t;
 
-       gettogglestat(c);
-       getpagestat(c);
+       if(showindicators) {
+               gettogglestat(c);
+               getpagestat(c);
 
-       if(c->linkhover) {
-               t = g_strdup_printf("%s:%s | %s", togglestat, pagestat, c->linkhover);
-       } else if(c->progress != 100) {
-               t = g_strdup_printf("[%i%%] %s:%s | %s", c->progress, togglestat,
-                       pagestat, c->title);
+               if(c->linkhover) {
+                       t = g_strdup_printf("%s:%s | %s", togglestat,
+                                       pagestat, c->linkhover);
+               } else if(c->progress != 100) {
+                       t = g_strdup_printf("[%i%%] %s:%s | %s", c->progress,
+                                       togglestat, pagestat, c->title);
+               } else {
+                       t = g_strdup_printf("%s:%s | %s", togglestat, pagestat,
+                                       c->title);
+               }
+
+               gtk_window_set_title(GTK_WINDOW(c->win), t);
+               g_free(t);
        } else {
-               t = g_strdup_printf("%s:%s | %s", togglestat, pagestat, c->title);
+               gtk_window_set_title(GTK_WINDOW(c->win), c->title);
        }
-
-       gtk_window_set_title(GTK_WINDOW(c->win), t);
-       g_free(t);
 }
 
 static void
@@ -1225,30 +1314,57 @@ main(int argc, char *argv[]) {
        case 'b':
                enablescrollbars = 0;
                break;
+       case 'B':
+               enablescrollbars = 1;
+               break;
        case 'c':
                cookiefile = EARGF(usage());
                break;
        case 'e':
                embed = strtol(EARGF(usage()), NULL, 0);
                break;
+       case 'f':
+               runinfullscreen = 1;
+               break;
+       case 'g':
+               allowgeolocation = 0;
+               break;
+       case 'G':
+               allowgeolocation = 1;
+               break;
        case 'i':
                loadimages = 0;
                break;
+       case 'I':
+               loadimages = 1;
+               break;
        case 'k':
+               kioskmode = 0;
+               break;
+       case 'K':
                kioskmode = 1;
                break;
        case 'n':
                enableinspector = 0;
                break;
+       case 'N':
+               enableinspector = 1;
+               break;
        case 'p':
                enableplugins = 0;
                break;
+       case 'P':
+               enableplugins = 1;
+               break;
        case 'r':
                scriptfile = EARGF(usage());
                break;
        case 's':
                enablescripts = 0;
                break;
+       case 'S':
+               enablescripts = 1;
+               break;
        case 't':
                stylefile = EARGF(usage());
                break;