X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=surf.c;h=ee4bfeeef7c12014740c9dd04e25ed15864e2a73;hb=344efec3fb932a9c5baae582fe70c72a0bc4a747;hp=e96767283075dfbcb45109c0c865408db5077fcf;hpb=fa9b1873936934bfd7ccc6da9cf66b92d193e72e;p=surf.git diff --git a/surf.c b/surf.c index e967672..ee4bfee 100644 --- a/surf.c +++ b/surf.c @@ -23,13 +23,14 @@ #include #include #include +#include #include "arg.h" char *argv0; #define LENGTH(x) (sizeof x / sizeof x[0]) -#define CLEANMASK(mask) (mask & (MODKEY|GDK_SHIFT_MASK)) +#define CLEANMASK(mask) (mask & (MODKEY|GDK_SHIFT_MASK)) #define COOKIEJAR_TYPE (cookiejar_get_type ()) #define COOKIEJAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COOKIEJAR_TYPE, CookieJar)) @@ -71,6 +72,12 @@ typedef struct { G_DEFINE_TYPE(CookieJar, cookiejar, SOUP_TYPE_COOKIE_JAR_TEXT) +typedef struct { + char *regex; + char *style; + regex_t re; +} SiteStyle; + static Display *dpy; static Atom atoms[AtomLast]; static Client *clients = NULL; @@ -78,15 +85,17 @@ static GdkNativeWindow embed = 0; static gboolean showxid = FALSE; static char winid[64]; static gboolean usingproxy = 0; -static char togglestat[8]; +static char togglestat[9]; static char pagestat[3]; static GTlsDatabase *tlsdb; static int policysel = 0; +static char *stylefile = NULL; +static SoupCache *diskcache = NULL; static void addaccelgroup(Client *c); static void beforerequest(WebKitWebView *w, WebKitWebFrame *f, WebKitWebResource *r, WebKitNetworkRequest *req, - WebKitNetworkResponse *resp, gpointer d); + WebKitNetworkResponse *resp, Client *c); static char *buildpath(const char *path); static gboolean buttonrelease(WebKitWebView *web, GdkEventButton *e, GList *gl); @@ -127,6 +136,10 @@ static const char *getatom(Client *c, int a); static void gettogglestat(Client *c); static void getpagestat(Client *c); static char *geturi(Client *c); +static gchar *getstyle(const char *uri); + +static void handleplumb(Client *c, WebKitWebView *w, const gchar *uri); + static gboolean initdownload(WebKitWebView *v, WebKitDownload *o, Client *c); static void inspector(Client *c, const Arg *arg); @@ -148,8 +161,9 @@ static void navigate(Client *c, const Arg *arg); static Client *newclient(void); static void newwindow(Client *c, const Arg *arg, gboolean noembed); static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d); -static void populatepopup(WebKitWebView *web, GtkMenu *menu, Client *c); -static void popupactivate(GtkMenuItem *menu, Client *); +static gboolean contextmenu(WebKitWebView *view, GtkWidget *menu, + WebKitHitTestResult *target, gboolean keyboard, Client *c); +static void menuactivate(GtkMenuItem *item, Client *c); static void print(Client *c, const Arg *arg); static GdkFilterReturn processx(GdkXEvent *xevent, GdkEvent *event, gpointer d); @@ -164,8 +178,7 @@ static void sigchld(int unused); static void source(Client *c, const Arg *arg); static void spawn(Client *c, const Arg *arg); static void stop(Client *c, const Arg *arg); -static void titlechange(WebKitWebView *v, WebKitWebFrame *frame, - const char *title, Client *c); +static void titlechange(WebKitWebView *view, GParamSpec *pspec, Client *c); static void toggle(Client *c, const Arg *arg); static void togglecookiepolicy(Client *c, const Arg *arg); static void togglegeolocation(Client *c, const Arg *arg); @@ -198,11 +211,30 @@ addaccelgroup(Client *c) { static void beforerequest(WebKitWebView *w, WebKitWebFrame *f, WebKitWebResource *r, WebKitNetworkRequest *req, WebKitNetworkResponse *resp, - gpointer d) { + Client *c) { const gchar *uri = webkit_network_request_get_uri(req); + int i, isascii = 1; if(g_str_has_suffix(uri, "/favicon.ico")) webkit_network_request_set_uri(req, "about:blank"); + + if(!g_str_has_prefix(uri, "http://") \ + && !g_str_has_prefix(uri, "https://") \ + && !g_str_has_prefix(uri, "about:") \ + && !g_str_has_prefix(uri, "file://") \ + && !g_str_has_prefix(uri, "data:") \ + && !g_str_has_prefix(uri, "blob:") \ + && strlen(uri) > 0) { + + for(i = 0; i < strlen(uri); i++) { + if(!g_ascii_isprint(uri[i])) { + isascii = 0; + break; + } + } + if(isascii) + handleplumb(c, w, uri); + } } static char * @@ -260,6 +292,10 @@ buttonrelease(WebKitWebView *web, GdkEventButton *e, GList *gl) { static void cleanup(void) { + if (diskcache) { + soup_cache_flush(diskcache); + soup_cache_dump(diskcache); + } while(clients) destroyclient(clients); g_free(cookiefile); @@ -533,6 +569,28 @@ geturi(Client *c) { return uri; } +static gchar * +getstyle(const char *uri) { + int i; + + for(i = 0; i < LENGTH(styles); i++) { + if(styles[i].regex && !regexec(&(styles[i].re), uri, 0, + NULL, 0)) { + return g_strconcat("file://", styles[i].style, NULL); + } + } + return g_strdup(""); +} + +static void +handleplumb(Client *c, WebKitWebView *w, const gchar *uri) { + Arg arg; + + webkit_web_view_stop_loading(w); + arg = (Arg)PLUMB((char *)uri); + spawn(c, &arg); +} + static gboolean initdownload(WebKitWebView *view, WebKitDownload *o, Client *c) { Arg arg; @@ -629,6 +687,7 @@ loadstatuschange(WebKitWebView *view, GParamSpec *pspec, Client *c) { WebKitWebFrame *frame; WebKitWebDataSource *src; WebKitNetworkRequest *request; + WebKitWebSettings *set = webkit_web_view_get_settings(c->view); SoupMessage *msg; char *uri; @@ -644,10 +703,19 @@ loadstatuschange(WebKitWebView *view, GParamSpec *pspec, Client *c) { & SOUP_MESSAGE_CERTIFICATE_TRUSTED); } setatom(c, AtomUri, uri); + + if(stylefile == NULL && enablestyles) { + g_object_set(G_OBJECT(set), "user-stylesheet-uri", + getstyle(uri), NULL); + } break; case WEBKIT_LOAD_FINISHED: c->progress = 100; updatetitle(c); + if (diskcache) { + soup_cache_flush(diskcache); + soup_cache_dump(diskcache); + } break; default: break; @@ -656,7 +724,7 @@ loadstatuschange(WebKitWebView *view, GParamSpec *pspec, Client *c) { static void loaduri(Client *c, const Arg *arg) { - char *u, *rp; + char *u = NULL, *rp; const char *uri = (char *)arg->v; Arg a = { .b = FALSE }; struct stat st; @@ -683,9 +751,9 @@ loaduri(Client *c, const Arg *arg) { webkit_web_view_load_uri(c->view, u); c->progress = 0; c->title = copystr(&c->title, u); - g_free(u); updatetitle(c); } + g_free(u); } static void @@ -702,11 +770,14 @@ newclient(void) { GdkGeometry hints = { 1, 1 }; GdkScreen *screen; gdouble dpi; - char *uri, *ua; + char *uri = NULL, *ua; if(!(c = calloc(1, sizeof(Client)))) die("Cannot malloc!\n"); + c->title = NULL; + c->progress = 100; + /* Window */ if(embed) { c->win = gtk_plug_new(embed); @@ -746,7 +817,7 @@ newclient(void) { c->view = WEBKIT_WEB_VIEW(webkit_web_view_new()); g_signal_connect(G_OBJECT(c->view), - "title-changed", + "notify::title", G_CALLBACK(titlechange), c); g_signal_connect(G_OBJECT(c->view), "hovering-over-link", @@ -779,8 +850,8 @@ newclient(void) { "button-release-event", G_CALLBACK(buttonrelease), c); g_signal_connect(G_OBJECT(c->view), - "populate-popup", - G_CALLBACK(populatepopup), c); + "context-menu", + G_CALLBACK(contextmenu), c); g_signal_connect(G_OBJECT(c->view), "resource-request-starting", G_CALLBACK(beforerequest), c); @@ -829,8 +900,10 @@ newclient(void) { if(!(ua = getenv("SURF_USERAGENT"))) ua = useragent; g_object_set(G_OBJECT(settings), "user-agent", ua, NULL); - uri = g_strconcat("file://", stylefile, NULL); - g_object_set(G_OBJECT(settings), "user-stylesheet-uri", uri, NULL); + if (stylefile != NULL) { + uri = g_strconcat("file://", stylefile, NULL); + g_object_set(G_OBJECT(settings), "user-stylesheet-uri", uri, NULL); + } g_object_set(G_OBJECT(settings), "auto-load-images", loadimages, NULL); g_object_set(G_OBJECT(settings), "enable-plugins", enableplugins, @@ -845,6 +918,8 @@ newclient(void) { kioskmode ^ 1, NULL); g_object_set(G_OBJECT(settings), "default-font-size", defaultfontsize, NULL); + g_object_set(G_OBJECT(settings), "resizable-text-areas", + 1, NULL); /* * While stupid, CSS specifies that a pixel represents 1/96 of an inch. @@ -883,14 +958,14 @@ newclient(void) { fullscreen(c, NULL); } - g_free(uri); + if(stylefile != NULL) + g_free(uri); setatom(c, AtomFind, ""); setatom(c, AtomUri, "about:blank"); if(hidebackground) webkit_web_view_set_transparent(c->view, TRUE); - c->title = NULL; c->next = clients; clients = c; @@ -910,18 +985,22 @@ newclient(void) { static void newwindow(Client *c, const Arg *arg, gboolean noembed) { guint i = 0; - const char *cmd[14], *uri; + const char *cmd[18], *uri; const Arg a = { .v = (void *)cmd }; char tmp[64]; cmd[i++] = argv0; + cmd[i++] = "-a"; + cmd[i++] = cookiepolicies; if(!enablescrollbars) cmd[i++] = "-b"; if(embed && !noembed) { cmd[i++] = "-e"; - snprintf(tmp, LENGTH(tmp), "%u\n", (int)embed); + snprintf(tmp, LENGTH(tmp), "%u", (int)embed); cmd[i++] = tmp; } + if(!allowgeolocation) + cmd[i++] = "-g"; if(!loadimages) cmd[i++] = "-i"; if(kioskmode) @@ -932,6 +1011,8 @@ newwindow(Client *c, const Arg *arg, gboolean noembed) { cmd[i++] = "-s"; if(showxid) cmd[i++] = "-x"; + if(enablediskcache) + cmd[i++] = "-D"; cmd[i++] = "-c"; cmd[i++] = cookiefile; cmd[i++] = "--"; @@ -942,24 +1023,27 @@ newwindow(Client *c, const Arg *arg, gboolean noembed) { spawn(NULL, &a); } -static void -populatepopup(WebKitWebView *web, GtkMenu *menu, Client *c) { - GList *items = gtk_container_get_children(GTK_CONTAINER(menu)); +static gboolean +contextmenu(WebKitWebView *view, GtkWidget *menu, WebKitHitTestResult *target, + gboolean keyboard, Client *c) { + GList *items = gtk_container_get_children(GTK_CONTAINER(GTK_MENU(menu))); for(GList *l = items; l; l = l->next) { - g_signal_connect(l->data, "activate", G_CALLBACK(popupactivate), c); + g_signal_connect(l->data, "activate", G_CALLBACK(menuactivate), c); } g_list_free(items); + return FALSE; } static void -popupactivate(GtkMenuItem *menu, Client *c) { +menuactivate(GtkMenuItem *item, Client *c) { /* * context-menu-action-2000 open link * context-menu-action-1 open link in window * context-menu-action-2 download linked file * context-menu-action-3 copy link location + * context-menu-action-7 copy image address * context-menu-action-13 reload * context-menu-action-10 back * context-menu-action-11 forward @@ -967,10 +1051,10 @@ popupactivate(GtkMenuItem *menu, Client *c) { */ GtkAction *a = NULL; - const char *name; - GtkClipboard *prisel; + const char *name, *uri; + GtkClipboard *prisel, *clpbrd; - a = gtk_activatable_get_related_action(GTK_ACTIVATABLE(menu)); + a = gtk_activatable_get_related_action(GTK_ACTIVATABLE(item)); if(a == NULL) return; @@ -978,6 +1062,12 @@ popupactivate(GtkMenuItem *menu, Client *c) { if(!g_strcmp0(name, "context-menu-action-3")) { prisel = gtk_clipboard_get(GDK_SELECTION_PRIMARY); gtk_clipboard_set_text(prisel, c->linkhover, -1); + } else if(!g_strcmp0(name, "context-menu-action-7")) { + prisel = gtk_clipboard_get(GDK_SELECTION_PRIMARY); + clpbrd = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + uri = gtk_clipboard_wait_for_text(clpbrd); + if(uri) + gtk_clipboard_set_text(prisel, uri, -1); } } @@ -1079,6 +1169,7 @@ setatom(Client *c, int a, const char *v) { static void setup(void) { + int i; char *proxy; char *new_proxy; SoupURI *puri; @@ -1099,7 +1190,24 @@ setup(void) { /* dirs and files */ cookiefile = buildpath(cookiefile); scriptfile = buildpath(scriptfile); - stylefile = buildpath(stylefile); + cachefolder = buildpath(cachefolder); + styledir = buildpath(styledir); + if(stylefile == NULL && enablestyles) { + for(i = 0; i < LENGTH(styles); i++) { + if(regcomp(&(styles[i].re), styles[i].regex, + REG_EXTENDED)) { + fprintf(stderr, + "Could not compile regex: %s\n", + styles[i].regex); + styles[i].regex = NULL; + } + styles[i].style = buildpath( + g_strconcat(styledir, + styles[i].style, NULL)); + } + } else { + stylefile = buildpath(stylefile); + } /* request handler */ s = webkit_get_default_session(); @@ -1109,6 +1217,14 @@ setup(void) { SOUP_SESSION_FEATURE(cookiejar_new(cookiefile, FALSE, cookiepolicy_get()))); + /* disk cache */ + if(enablediskcache) { + diskcache = soup_cache_new(cachefolder, SOUP_CACHE_SINGLE_USER); + soup_cache_set_max_size(diskcache, diskcachebytes); + soup_cache_load(diskcache); + soup_session_add_feature(s, SOUP_SESSION_FEATURE(diskcache)); + } + /* ssl */ tlsdb = g_tls_file_database_new(cafile, &error); @@ -1174,9 +1290,12 @@ stop(Client *c, const Arg *arg) { } static void -titlechange(WebKitWebView *v, WebKitWebFrame *f, const char *t, Client *c) { - c->title = copystr(&c->title, t); - updatetitle(c); +titlechange(WebKitWebView *view, GParamSpec *pspec, Client *c) { + const gchar *t = webkit_web_view_get_title(view); + if (t) { + c->title = copystr(&c->title, t); + updatetitle(c); + } } static void @@ -1264,12 +1383,16 @@ togglescrollbars(Client *c, const Arg *arg) { static void togglestyle(Client *c, const Arg *arg) { - WebKitWebSettings *settings; + WebKitWebSettings *settings = webkit_web_view_get_settings(c->view); 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); + if(stylefile == NULL && enablestyles) { + uri = (uri && uri[0])? g_strdup("") : getstyle(geturi(c)); + } else { + uri = uri[0]? g_strdup("") : g_strconcat("file://", + stylefile, NULL); + } g_object_set(G_OBJECT(settings), "user-stylesheet-uri", uri, NULL); updatetitle(c); @@ -1290,6 +1413,8 @@ gettogglestat(Client *c){ togglestat[p++] = allowgeolocation? 'G': 'g'; + togglestat[p++] = enablediskcache? 'D': 'd'; + g_object_get(G_OBJECT(settings), "auto-load-images", &value, NULL); togglestat[p++] = value? 'I': 'i'; @@ -1300,7 +1425,7 @@ gettogglestat(Client *c){ togglestat[p++] = value? 'V': 'v'; g_object_get(G_OBJECT(settings), "user-stylesheet-uri", &uri, NULL); - togglestat[p++] = uri[0] ? 'M': 'm'; + togglestat[p++] = (uri && uri[0]) ? 'M': 'm'; togglestat[p] = '\0'; } @@ -1333,16 +1458,18 @@ updatetitle(Client *c) { pagestat, c->linkhover); } else if(c->progress != 100) { t = g_strdup_printf("[%i%%] %s:%s | %s", c->progress, - togglestat, pagestat, c->title); + togglestat, pagestat, + (c->title == NULL)? "" : c->title); } else { t = g_strdup_printf("%s:%s | %s", togglestat, pagestat, - c->title); + (c->title == NULL)? "" : c->title); } gtk_window_set_title(GTK_WINDOW(c->win), t); g_free(t); } else { - gtk_window_set_title(GTK_WINDOW(c->win), c->title); + gtk_window_set_title(GTK_WINDOW(c->win), + (c->title == NULL)? "" : c->title); } } @@ -1386,6 +1513,7 @@ zoom(Client *c, const Arg *arg) { int main(int argc, char *argv[]) { Arg arg; + Client *c; memset(&arg, 0, sizeof(arg)); @@ -1403,6 +1531,12 @@ main(int argc, char *argv[]) { case 'c': cookiefile = EARGF(usage()); break; + case 'd': + enablediskcache = 0; + break; + case 'D': + enablediskcache = 1; + break; case 'e': embed = strtol(EARGF(usage()), NULL, 0); break; @@ -1430,6 +1564,12 @@ main(int argc, char *argv[]) { case 'K': kioskmode = 1; break; + case 'm': + enablestyles = 0; + break; + case 'M': + enablestyles = 1; + break; case 'n': enableinspector = 0; break; @@ -1458,7 +1598,7 @@ main(int argc, char *argv[]) { useragent = EARGF(usage()); break; case 'v': - die("surf-"VERSION", ©2009-2012 surf engineers, " + die("surf-"VERSION", ©2009-2014 surf engineers, " "see LICENSE for details\n"); case 'x': showxid = TRUE; @@ -1473,9 +1613,12 @@ main(int argc, char *argv[]) { arg.v = argv[0]; setup(); - newclient(); - if(arg.v) + c = newclient(); + if(arg.v) { loaduri(clients, &arg); + } else { + updatetitle(c); + } gtk_main(); cleanup();