commit 7e12d072a2716bad730a238c28b32e23109c5d7d
parent d068a3878b6b9f2841a49cd7948cdf9d62b55585
Author: Cem Keylan <cem@ckyln.com>
Date: Fri, 22 Nov 2019 17:01:47 +0300
initial recommit
Diffstat:
A | .gitignore | | | 6 | ++++++ |
M | config.def.h | | | 111 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- |
M | surf.c | | | 145 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- |
3 files changed, 225 insertions(+), 37 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,6 @@
+surf
+*.o
+config.h
+*.diff
+*.orig
+*.rej
diff --git a/config.def.h b/config.def.h
@@ -6,6 +6,17 @@ static char *styledir = "~/.surf/styles/";
static char *certdir = "~/.surf/certificates/";
static char *cachedir = "~/.surf/cache/";
static char *cookiefile = "~/.surf/cookies.txt";
+static char *historyfile = "~/.surf/history.txt";
+
+/* Search Engines */
+static SearchEngine searchengines[] = {
+ { "s", "https://duckduckgo.com/?q=%s" },
+ { "aw", "https://wiki.archlinux.org/?search=%s" },
+ { "docker", "https://hub.docker.com/search?q=%s" },
+ { "gl", "https://gitlab.cemkeylan.com/cemkeylan/%s"},
+ { "gl3", "https://gitlab.cemkeylan.com/3c1b/%s" },
+ { "r", "https://reddit.com/r/%s" },
+};
/* Webkit default features */
/* Highest priority value will be used.
@@ -25,7 +36,7 @@ static Parameter defconfig[ParameterLast] = {
[DiskCache] = { { .i = 1 }, },
[DNSPrefetch] = { { .i = 0 }, },
[FileURLsCrossAccess] = { { .i = 0 }, },
- [FontSize] = { { .i = 12 }, },
+ [FontSize] = { { .i = 14 }, },
[FrameFlattening] = { { .i = 0 }, },
[Geolocation] = { { .i = 0 }, },
[HideBackground] = { { .i = 0 }, },
@@ -70,8 +81,9 @@ static WebKitFindOptions findopts = WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
#define SETPROP(r, s, p) { \
.v = (const char *[]){ "/bin/sh", "-c", \
"prop=\"$(printf '%b' \"$(xprop -id $1 $2 " \
- "| sed \"s/^$2(STRING) = //;s/^\\\"\\(.*\\)\\\"$/\\1/\")\" " \
- "| dmenu -p \"$4\" -w $1)\" && xprop -id $1 -f $3 8s -set $3 \"$prop\"", \
+ "| sed \"s/^$2(STRING) = //;s/^\\\"\\(.*\\)\\\"$/\\1/\" && cat ~/.surf/bookmarks)\" " \
+ "| dmenu -l 10 -p \"$4\" -w $1)\" && " \
+ "xprop -id $1 -f $3 8s -set $3 \"$prop\"", \
"surf-setprop", winid, r, s, p, NULL \
} \
}
@@ -102,6 +114,23 @@ static WebKitFindOptions findopts = WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
} \
}
+
+#define SETURI(p) { .v = (char *[]){ "/bin/sh", "-c", \
+"prop=\"`surf_history_dmenu.sh`\" &&" \
+"xprop -id $1 -f $0 8s -set $0 \"$prop\"", \
+p, winid, NULL } }
+
+/* BM_ADD(readprop) */
+#define BM_ADD(r) {\
+ .v = (const char *[]){ "/bin/sh", "-c", \
+ "(echo $(xprop -id $0 $1) | cut -d '\"' -f2 " \
+ "| sed 's/.*https*:\\/\\/\\(www\\.\\)\\?//' && cat ~/.surf/bookmarks) " \
+ "| awk '!seen[$0]++' > ~/.surf/bookmarks.tmp && " \
+ "mv ~/.surf/bookmarks.tmp ~/.surf/bookmarks", \
+ winid, r, NULL \
+ } \
+}
+
/* styles */
/*
* The iteration will stop at the first match, beginning at the beginning of
@@ -121,6 +150,16 @@ static SiteSpecific certs[] = {
{ "://suckless\\.org/", "suckless.org.crt" },
};
+static char *linkselect_curwin [] = { "/bin/sh", "-c",
+ "surf_linkselect.sh $0 'Link' | xargs -r xprop -id $0 -f _SURF_GO 8s -set _SURF_GO",
+ winid, NULL
+};
+static char *linkselect_newwin [] = { "/bin/sh", "-c",
+ "surf_linkselect.sh $0 'Link (new window)' | xargs -r surf",
+ winid, NULL
+};
+static char *editscreen[] = { "/bin/sh", "-c", "edit_screen.sh", NULL };
+
#define MODKEY GDK_CONTROL_MASK
/* hotkeys */
@@ -129,43 +168,47 @@ static SiteSpecific certs[] = {
* edit the CLEANMASK() macro.
*/
static Key keys[] = {
- /* modifier keyval function arg */
- { MODKEY, GDK_KEY_g, spawn, SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) },
- { MODKEY, GDK_KEY_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) },
- { MODKEY, GDK_KEY_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) },
+ /* modifier keyval function arg */
+ { 0, GDK_KEY_o, spawn, SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) },
+ { 0, GDK_KEY_f, externalpipe, { .v = linkselect_curwin } },
+ { 0|GDK_SHIFT_MASK, GDK_KEY_f, externalpipe, { .v = linkselect_newwin } },
+ { 0, GDK_KEY_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) },
- { 0, GDK_KEY_Escape, stop, { 0 } },
- { MODKEY, GDK_KEY_c, stop, { 0 } },
+ { 0, GDK_KEY_i, insert, { .i = 1 } },
+ { 0, GDK_KEY_Escape, insert, { .i = 0 } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_r, reload, { .i = 1 } },
- { MODKEY, GDK_KEY_r, reload, { .i = 0 } },
+ { 0, GDK_KEY_c, stop, { 0 } },
- { MODKEY, GDK_KEY_l, navigate, { .i = +1 } },
- { MODKEY, GDK_KEY_h, navigate, { .i = -1 } },
+ { MODKEY, GDK_KEY_r, reload, { .i = 1 } },
+ { 0, GDK_KEY_r, reload, { .i = 0 } },
- /* vertical and horizontal scrolling, in viewport percentage */
- { MODKEY, GDK_KEY_j, scrollv, { .i = +10 } },
- { MODKEY, GDK_KEY_k, scrollv, { .i = -10 } },
- { MODKEY, GDK_KEY_space, scrollv, { .i = +50 } },
- { MODKEY, GDK_KEY_b, scrollv, { .i = -50 } },
- { MODKEY, GDK_KEY_i, scrollh, { .i = +10 } },
- { MODKEY, GDK_KEY_u, scrollh, { .i = -10 } },
+ { 0|GDK_SHIFT_MASK, GDK_KEY_l, navigate, { .i = +1 } },
+ { 0|GDK_SHIFT_MASK, GDK_KEY_h, navigate, { .i = -1 } },
+ /* vertical and horizontal scrolling, in viewport per centage */
+ { 0, GDK_KEY_j, scrollv, { .i = +10 } },
+ { 0, GDK_KEY_k, scrollv, { .i = -10 } },
+ { MODKEY, GDK_KEY_d, scrollv, { .i = +50 } },
+ { MODKEY, GDK_KEY_u, scrollv, { .i = -50 } },
+ { 0, GDK_KEY_i, insert, { .i = 1 } },
+ { 0, GDK_KEY_Escape, insert, { .i = 0 } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_k, zoom, { .i = +1 } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_q, zoom, { .i = 0 } },
- { MODKEY, GDK_KEY_minus, zoom, { .i = -1 } },
- { MODKEY, GDK_KEY_plus, zoom, { .i = +1 } },
- { MODKEY, GDK_KEY_p, clipboard, { .i = 1 } },
- { MODKEY, GDK_KEY_y, clipboard, { .i = 0 } },
+ { MODKEY|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } },
+ { MODKEY|GDK_SHIFT_MASK, GDK_KEY_k, zoom, { .i = +1 } },
+ { MODKEY|GDK_SHIFT_MASK, GDK_KEY_h, zoom, { .i = 0 } },
+ { 0, GDK_KEY_minus, zoom, { .i = -1 } },
+ { 0|GDK_SHIFT_MASK, GDK_KEY_plus, zoom, { .i = +1 } },
+ { 0, GDK_KEY_equal, zoom, { .i = 0 } },
- { MODKEY, GDK_KEY_n, find, { .i = +1 } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_n, find, { .i = -1 } },
+ { 0, GDK_KEY_p, clipboard, { .i = 1 } },
+ { 0, GDK_KEY_y, clipboard, { .i = 0 } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_p, print, { 0 } },
- { MODKEY, GDK_KEY_t, showcert, { 0 } },
+ { 0, GDK_KEY_n, find, { .i = +1 } },
+ { 0|GDK_SHIFT_MASK, GDK_KEY_n, find, { .i = -1 } },
+
+ { MODKEY, GDK_KEY_p, print, { 0 } },
+ { MODKEY, GDK_KEY_t, showcert, { 0 } },
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_a, togglecookiepolicy, { 0 } },
{ 0, GDK_KEY_F11, togglefullscreen, { 0 } },
@@ -180,6 +223,10 @@ static Key keys[] = {
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_b, toggle, { .i = ScrollBars } },
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_t, toggle, { .i = StrictTLS } },
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_m, toggle, { .i = Style } },
+ { MODKEY , GDK_KEY_Return, spawn, SETURI("_SURF_GO") },
+
+ { MODKEY|GDK_SHIFT_MASK, GDK_KEY_e, externalpipe, { .v = editscreen } },
+ { MODKEY, GDK_KEY_m, spawn, BM_ADD("_SURF_URI") },
};
/* button definitions */
@@ -193,3 +240,5 @@ static Button buttons[] = {
{ OnAny, 0, 9, clicknavigate, { .i = +1 }, 1 },
{ OnMedia, MODKEY, 1, clickexternplayer, { 0 }, 1 },
};
+
+#define HOMEPAGE "https://duckduckgo.com/"
diff --git a/surf.c b/surf.c
@@ -129,6 +129,11 @@ typedef struct {
} Button;
typedef struct {
+ char *token;
+ char *uri;
+} SearchEngine;
+
+typedef struct {
const char *uri;
Parameter config[ParameterLast];
regex_t re;
@@ -175,6 +180,8 @@ static void spawn(Client *c, const Arg *a);
static void msgext(Client *c, char type, const Arg *a);
static void destroyclient(Client *c);
static void cleanup(void);
+static int insertmode = 0;
+static void updatehistory(const char *u, const char *t);
/* GTK/WebKit */
static WebKitWebView *newview(Client *c, WebKitWebView *rv);
@@ -214,6 +221,7 @@ static void webprocessterminated(WebKitWebView *v,
Client *c);
static void closeview(WebKitWebView *v, Client *c);
static void destroywin(GtkWidget* w, Client *c);
+static gchar *parseuri(const gchar *uri);
/* Hotkeys */
static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d);
@@ -231,6 +239,8 @@ static void togglefullscreen(Client *c, const Arg *a);
static void togglecookiepolicy(Client *c, const Arg *a);
static void toggleinspector(Client *c, const Arg *a);
static void find(Client *c, const Arg *a);
+static void insert(Client *c, const Arg *a);
+static void externalpipe(Client *c, const Arg *a);
/* Buttons */
static void clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h);
@@ -301,6 +311,80 @@ static ParamName loadfinished[] = {
/* configuration, allows nested code to access above variables */
#include "config.h"
+static void
+externalpipe_execute(char* buffer, Arg *arg) {
+ int to[2];
+ void (*oldsigpipe)(int);
+
+ if (pipe(to) == -1)
+ return;
+
+ switch (fork()) {
+ case -1:
+ close(to[0]);
+ close(to[1]);
+ return;
+ case 0:
+ dup2(to[0], STDIN_FILENO); close(to[0]); close(to[1]);
+ execvp(((char **)arg->v)[0], (char **)arg->v);
+ fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
+ perror("failed");
+ exit(0);
+ }
+
+ close(to[0]);
+ oldsigpipe = signal(SIGPIPE, SIG_IGN);
+ write(to[1], buffer, strlen(buffer));
+ close(to[1]);
+ signal(SIGPIPE, oldsigpipe);
+}
+
+static void
+externalpipe_resource_done(WebKitWebResource *r, GAsyncResult *s, Arg *arg)
+{
+ GError *gerr = NULL;
+ guchar *buffer = webkit_web_resource_get_data_finish(r, s, NULL, &gerr);
+ if (gerr == NULL) {
+ externalpipe_execute((char *) buffer, arg);
+ } else {
+ g_error_free(gerr);
+ }
+ g_free(buffer);
+}
+
+static void
+externalpipe_js_done(WebKitWebView *wv, GAsyncResult *s, Arg *arg)
+{
+ WebKitJavascriptResult *j = webkit_web_view_run_javascript_finish(
+ wv, s, NULL);
+ if (!j) {
+ return;
+ }
+ JSCValue *v = webkit_javascript_result_get_js_value(j);
+ if (jsc_value_is_string(v)) {
+ char *buffer = jsc_value_to_string(v);
+ externalpipe_execute(buffer, arg);
+ g_free(buffer);
+ }
+ webkit_javascript_result_unref(j);
+}
+
+void
+externalpipe(Client *c, const Arg *arg)
+{
+ if (curconfig[JavaScript].val.i) {
+ webkit_web_view_run_javascript(
+ c->view, "window.document.documentElement.outerHTML",
+ NULL, externalpipe_js_done, arg);
+ } else {
+ WebKitWebResource *resource = webkit_web_view_get_main_resource(c->view);
+ if (resource != NULL) {
+ webkit_web_resource_get_data(
+ resource, NULL, externalpipe_resource_done, arg);
+ }
+ }
+}
+
void
usage(void)
{
@@ -336,10 +420,11 @@ setup(void)
curconfig = defconfig;
/* dirs and files */
- cookiefile = buildfile(cookiefile);
- scriptfile = buildfile(scriptfile);
- cachedir = buildpath(cachedir);
- certdir = buildpath(certdir);
+ cookiefile = buildfile(cookiefile);
+ historyfile = buildfile(historyfile);
+ scriptfile = buildfile(scriptfile);
+ cachedir = buildpath(cachedir);
+ certdir = buildpath(certdir);
gdkkb = gdk_seat_get_keyboard(gdk_display_get_default_seat(gdpy));
@@ -559,7 +644,7 @@ loaduri(Client *c, const Arg *a)
url = g_strdup_printf("file://%s", path);
free(path);
} else {
- url = g_strdup_printf("http://%s", uri);
+ url = parseuri(uri);
}
if (apath != uri)
free(apath);
@@ -1076,12 +1161,28 @@ cleanup(void)
close(pipein[0]);
close(pipeout[1]);
g_free(cookiefile);
+ g_free(historyfile);
g_free(scriptfile);
g_free(stylefile);
g_free(cachedir);
XCloseDisplay(dpy);
}
+void
+updatehistory(const char *u, const char *t)
+{
+ FILE *f;
+ f = fopen(historyfile, "a+");
+
+ char b[20];
+ time_t now = time (0);
+ strftime (b, 20, "%Y-%m-%d %H:%M:%S", localtime (&now));
+ fputs(b, f);
+
+ fprintf(f, " %s %s\n", u, t);
+ fclose(f);
+}
+
WebKitWebView *
newview(Client *c, WebKitWebView *rv)
{
@@ -1333,7 +1434,11 @@ winevent(GtkWidget *w, GdkEvent *e, Client *c)
updatetitle(c);
break;
case GDK_KEY_PRESS:
- if (!curconfig[KioskMode].val.i) {
+ if (!curconfig[KioskMode].val.i &&
+ !insertmode ||
+ CLEANMASK(e->key.state) == (MODKEY|GDK_SHIFT_MASK) ||
+ CLEANMASK(e->key.state) == (MODKEY) ||
+ gdk_keyval_to_lower(e->key.keyval) == (GDK_KEY_Escape)) {
for (i = 0; i < LENGTH(keys); ++i) {
if (gdk_keyval_to_lower(e->key.keyval) ==
keys[i].keyval &&
@@ -1491,6 +1596,7 @@ loadfailedtls(WebKitWebView *v, gchar *uri, GTlsCertificate *cert,
return TRUE;
}
+
void
loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c)
{
@@ -1519,6 +1625,7 @@ loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c)
break;
case WEBKIT_LOAD_FINISHED:
seturiparameters(c, uri, loadfinished);
+ updatehistory(uri, c->title);
/* Disabled until we write some WebKitWebExtension for
* manipulating the DOM directly.
evalscript(c, "document.documentElement.style.overflow = '%s'",
@@ -1765,6 +1872,22 @@ destroywin(GtkWidget* w, Client *c)
gtk_main_quit();
}
+gchar *
+parseuri(const gchar *uri) {
+ guint i;
+
+ for (i = 0; i < LENGTH(searchengines); i++) {
+ if (searchengines[i].token == NULL || searchengines[i].uri == NULL ||
+ *(uri + strlen(searchengines[i].token)) != ' ')
+ continue;
+ if (g_str_has_prefix(uri, searchengines[i].token))
+ return g_strdup_printf(searchengines[i].uri,
+ uri + strlen(searchengines[i].token) + 1);
+ }
+
+ return g_strdup_printf("http://%s", uri);
+}
+
void
pasteuri(GtkClipboard *clipboard, const char *text, gpointer d)
{
@@ -1948,6 +2071,12 @@ find(Client *c, const Arg *a)
}
void
+insert(Client *c, const Arg *a)
+{
+ insertmode = (a->i);
+}
+
+void
clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h)
{
navigate(c, a);
@@ -2111,7 +2240,11 @@ main(int argc, char *argv[])
if (argc > 0)
arg.v = argv[0];
else
+#ifdef HOMEPAGE
+ arg.v = HOMEPAGE;
+#else
arg.v = "about:blank";
+#endif
setup();
c = newclient(NULL);