Add an option to disable the indicators.
[surf.git] / surf.c
diff --git a/surf.c b/surf.c
index 17f7750..e325126 100644 (file)
--- a/surf.c
+++ b/surf.c
@@ -77,9 +77,10 @@ static GdkNativeWindow embed = 0;
 static gboolean showxid = FALSE;
 static char winid[64];
 static gboolean usingproxy = 0;
-static char togglestat[5];
+static char togglestat[6];
 static char pagestat[3];
 
+static void addaccelgroup(Client *c);
 static void beforerequest(WebKitWebView *w, WebKitWebFrame *f,
                WebKitWebResource *r, WebKitNetworkRequest *req,
                WebKitNetworkResponse *resp, gpointer d);
@@ -124,7 +125,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,7 +156,9 @@ 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 update(Client *c);
+static void togglescrollbars(Client *c, const Arg *arg);
+static void togglestyle(Client *c, const Arg *arg);
+static void updatetitle(Client *c);
 static void updatewinid(Client *c);
 static void usage(void);
 static void windowobjectcleared(GtkWidget *w, WebKitWebFrame *frame,
@@ -163,11 +168,26 @@ 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,
                gpointer d) {
        const gchar *uri = webkit_network_request_get_uri(req);
+
        if(g_str_has_suffix(uri, "/favicon.ico"))
                webkit_network_request_set_uri(req, "about:blank");
 }
@@ -290,7 +310,8 @@ evalscript(JSContextRef js, char *script, char* scriptname) {
 
        jsscript = JSStringCreateWithUTF8CString(script);
        jsscriptname = JSStringCreateWithUTF8CString(scriptname);
-       JSEvaluateScript(js, jsscript, JSContextGetGlobalObject(js), jsscriptname, 0, &exception);
+       JSEvaluateScript(js, jsscript, JSContextGetGlobalObject(js),
+                       jsscriptname, 0, &exception);
        JSStringRelease(jsscript);
        JSStringRelease(jsscriptname);
 }
@@ -301,7 +322,8 @@ runscript(WebKitWebFrame *frame) {
        GError *error;
 
        if(g_file_get_contents(scriptfile, &script, NULL, &error)) {
-               evalscript(webkit_web_frame_get_global_context(frame), script, scriptfile);
+               evalscript(webkit_web_frame_get_global_context(frame),
+                               script, scriptfile);
        }
 }
 
@@ -309,10 +331,15 @@ static void
 clipboard(Client *c, const Arg *arg) {
        gboolean paste = *(gboolean *)arg;
 
-       if(paste)
-               gtk_clipboard_request_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), pasteuri, c);
-       else
-               gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), c->linkhover ? c->linkhover : geturi(c), -1);
+       if(paste) {
+               gtk_clipboard_request_text(
+                               gtk_clipboard_get(GDK_SELECTION_PRIMARY),
+                               pasteuri, c);
+       } else {
+               gtk_clipboard_set_text(
+                               gtk_clipboard_get(GDK_SELECTION_PRIMARY),
+                               c->linkhover ? c->linkhover : geturi(c), -1);
+       }
 }
 
 static char *
@@ -425,11 +452,13 @@ getatom(Client *c, int a) {
        XGetWindowProperty(dpy, GDK_WINDOW_XID(GTK_WIDGET(c->win)->window),
                        atoms[a], 0L, BUFSIZ, False, XA_STRING,
                        &adummy, &idummy, &ldummy, &ldummy, &p);
-       if(p)
+       if(p) {
                strncpy(buf, (char *)p, LENGTH(buf)-1);
-       else
+       } else {
                buf[0] = '\0';
+       }
        XFree(p);
+
        return buf;
 }
 
@@ -502,14 +531,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;
@@ -527,7 +559,7 @@ linkhover(WebKitWebView *v, const char* t, const char* l, Client *c) {
                free(c->linkhover);
                c->linkhover = NULL;
        }
-       update(c);
+       updatetitle(c);
 }
 
 static void
@@ -553,7 +585,7 @@ loadstatuschange(WebKitWebView *view, GParamSpec *pspec, Client *c) {
                break;
        case WEBKIT_LOAD_FINISHED:
                c->progress = 100;
-               update(c);
+               updatetitle(c);
                break;
        default:
                break;
@@ -565,12 +597,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);
@@ -587,7 +620,7 @@ loaduri(Client *c, const Arg *arg) {
                c->progress = 0;
                c->title = copystr(&c->title, u);
                g_free(u);
-               update(c);
+               updatetitle(c);
        }
 }
 
@@ -632,9 +665,9 @@ newclient(void) {
        g_signal_connect(G_OBJECT(c->win),
                        "destroy",
                        G_CALLBACK(destroywin), c);
-       g_signal_connect(G_OBJECT(c->win),
-                       "key-press-event",
-                       G_CALLBACK(keypress), c);
+
+       if(!kioskmode)
+               addaccelgroup(c);
 
        /* Pane */
        c->pane = gtk_vpaned_new();
@@ -643,13 +676,9 @@ newclient(void) {
        c->vbox = gtk_vbox_new(FALSE, 0);
        gtk_paned_pack1(GTK_PANED(c->pane), c->vbox, TRUE, TRUE);
 
-       /* Scrolled Window */
-       c->scroll = gtk_scrolled_window_new(NULL, NULL);
-       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(c->scroll),
-                       GTK_POLICY_NEVER, GTK_POLICY_NEVER);
-
        /* Webview */
        c->view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+
        g_signal_connect(G_OBJECT(c->view),
                        "title-changed",
                        G_CALLBACK(titlechange), c);
@@ -687,6 +716,21 @@ newclient(void) {
                        "resource-request-starting",
                        G_CALLBACK(beforerequest), c);
 
+       /* Scrolled Window */
+       c->scroll = gtk_scrolled_window_new(NULL, NULL);
+
+       frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(c->view));
+       g_signal_connect(G_OBJECT(frame), "scrollbars-policy-changed",
+                       G_CALLBACK(gtk_true), NULL);
+
+       if(!enablescrollbars) {
+               gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(c->scroll),
+                               GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+       } else {
+               gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(c->scroll),
+                               GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       }
+
        /* Arranging */
        gtk_container_add(GTK_CONTAINER(c->scroll), GTK_WIDGET(c->view));
        gtk_container_add(GTK_CONTAINER(c->win), c->pane);
@@ -707,8 +751,8 @@ newclient(void) {
        gdk_window_add_filter(GTK_WIDGET(c->win)->window, processx, c);
        webkit_web_view_set_full_content_zoom(c->view, TRUE);
 
-       frame = webkit_web_view_get_main_frame(c->view);
        runscript(frame);
+
        settings = webkit_web_view_get_settings(c->view);
        if(!(ua = getenv("SURF_USERAGENT")))
                ua = useragent;
@@ -725,6 +769,10 @@ newclient(void) {
                        enablespatialbrowsing, NULL);
        g_object_set(G_OBJECT(settings), "enable-developer-extras",
                        enableinspector, NULL);
+       g_object_set(G_OBJECT(settings), "enable-default-context-menu",
+                       kioskmode ^ 1, NULL);
+       g_object_set(G_OBJECT(settings), "default-font-size",
+                       defaultfontsize, NULL);
 
        if(enableinspector) {
                c->inspector = WEBKIT_WEB_INSPECTOR(
@@ -767,22 +815,26 @@ newclient(void) {
 static void
 newwindow(Client *c, const Arg *arg, gboolean noembed) {
        guint i = 0;
-       const char *cmd[10], *uri;
+       const char *cmd[12], *uri;
        const Arg a = { .v = (void *)cmd };
        char tmp[64];
 
        cmd[i++] = argv0;
+       if(!enablescrollbars)
+               cmd[i++] = "-b";
        if(embed && !noembed) {
                cmd[i++] = "-e";
                snprintf(tmp, LENGTH(tmp), "%u\n", (int)embed);
                cmd[i++] = tmp;
        }
-       if(!enablescripts)
-               cmd[i++] = "-s";
-       if(!enableplugins)
-               cmd[i++] = "-p";
        if(!loadimages)
                cmd[i++] = "-i";
+       if(kioskmode)
+               cmd[i++] = "-k";
+       if(!enableplugins)
+               cmd[i++] = "-p";
+       if(!enablescripts)
+               cmd[i++] = "-s";
        if(showxid)
                cmd[i++] = "-x";
        cmd[i++] = "--";
@@ -856,11 +908,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;
                        }
                }
@@ -871,16 +924,17 @@ 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
 reload(Client *c, const Arg *arg) {
        gboolean nocache = *(gboolean *)arg;
-       if(nocache)
+       if(nocache) {
                 webkit_web_view_reload_bypass_cache(c->view);
-       else
+       } else {
                 webkit_web_view_reload(c->view);
+       }
 }
 
 static void
@@ -1018,7 +1072,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
@@ -1035,9 +1089,61 @@ toggle(Client *c, const Arg *arg) {
        reload(c,&a);
 }
 
+static void
+twitch(Client *c, const Arg *arg) {
+       GtkAdjustment *a;
+       gdouble v;
+
+       a = gtk_scrolled_window_get_vadjustment(
+                       GTK_SCROLLED_WINDOW(c->scroll));
+
+       v = gtk_adjustment_get_value(a);
+
+       v += arg->i;
+
+       v = MAX(v, 0.0);
+       v = MIN(v, gtk_adjustment_get_upper(a) -
+                       gtk_adjustment_get_page_size(a));
+       gtk_adjustment_set_value(a, v);
+}
+
+static void
+togglescrollbars(Client *c, const Arg *arg) {
+       GtkPolicyType vspolicy;
+       Arg a;
+
+       gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(c->scroll), NULL, &vspolicy);
+
+       if(vspolicy == GTK_POLICY_AUTOMATIC) {
+               gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(c->scroll),
+                               GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+       } else {
+               gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(c->scroll),
+                               GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+               a.i = +1;
+               twitch(c, &a);
+               a.i = -1;
+               twitch(c, &a);
+       }
+}
+
+static void
+togglestyle(Client *c, const Arg *arg) {
+       WebKitWebSettings *settings;
+       char *uri;
+
+       settings = webkit_web_view_get_settings(c->view);
+       g_object_get(G_OBJECT(settings), "user-stylesheet-uri", &uri, NULL);
+       uri = uri[0] ? g_strdup("") : g_strconcat("file://", stylefile, NULL);
+       g_object_set(G_OBJECT(settings), "user-stylesheet-uri", uri, NULL);
+
+       updatetitle(c);
+}
+
 static void
 gettogglestat(Client *c){
        gboolean value;
+       char *uri;
        WebKitWebSettings *settings = webkit_web_view_get_settings(c->view);
 
        g_object_get(G_OBJECT(settings), "enable-caret-browsing",
@@ -1053,7 +1159,10 @@ gettogglestat(Client *c){
        g_object_get(G_OBJECT(settings), "enable-plugins", &value, NULL);
        togglestat[3] = value? 'V': 'v';
 
-       togglestat[4] = '\0';
+       g_object_get(G_OBJECT(settings), "user-stylesheet-uri", &uri, NULL);
+       togglestat[4] = uri[0] ? 'M': 'm';
+
+       togglestat[5] = '\0';
 }
 
 static void
@@ -1072,23 +1181,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
@@ -1099,7 +1214,7 @@ updatewinid(Client *c) {
 
 static void
 usage(void) {
-       die("usage: %s [-inpsvx] [-c cookiefile] [-e xid] [-r scriptfile]"
+       die("usage: %s [-biknpsvx] [-c cookiefile] [-e xid] [-r scriptfile]"
                " [-t stylefile] [-u useragent] [uri]\n", basename(argv0));
 }
 
@@ -1133,6 +1248,9 @@ main(int argc, char *argv[]) {
 
        /* command line args */
        ARGBEGIN {
+       case 'b':
+               enablescrollbars = 0;
+               break;
        case 'c':
                cookiefile = EARGF(usage());
                break;
@@ -1142,6 +1260,9 @@ main(int argc, char *argv[]) {
        case 'i':
                loadimages = 0;
                break;
+       case 'k':
+               kioskmode = 1;
+               break;
        case 'n':
                enableinspector = 0;
                break;