aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config.def.h92
-rw-r--r--config.mk7
-rw-r--r--surf.156
-rw-r--r--surf.c264
4 files changed, 241 insertions, 178 deletions
diff --git a/config.def.h b/config.def.h
index 9b0f6f6..e4fc503 100644
--- a/config.def.h
+++ b/config.def.h
@@ -6,6 +6,9 @@ static char *styledir = "~/.surf/styles/";
static char *certdir = "~/.surf/certificates/";
static char *cachedir = "~/.surf/cache/";
static char *cookiefile = "~/.surf/cookies.txt";
+/* a macro too, the GO() shell command below needs it as a constant */
+#define HISTFILE "~/.surf/history"
+static char *histfile = HISTFILE;
/* Webkit default features */
/* Highest priority value will be used.
@@ -20,7 +23,7 @@ static Parameter defconfig[ParameterLast] = {
[Certificate] = { { .i = 0 }, },
[CaretBrowsing] = { { .i = 0 }, },
[CookiePolicies] = { { .v = "@Aa" }, },
- [DarkMode] = { { .i = 0 }, },
+ [DarkMode] = { { .i = 1 }, },
[DefaultCharset] = { { .v = "UTF-8" }, },
[DiskCache] = { { .i = 1 }, },
[DNSPrefetch] = { { .i = 0 }, },
@@ -46,7 +49,7 @@ static Parameter defconfig[ParameterLast] = {
[StrictTLS] = { { .i = 1 }, },
[Style] = { { .i = 1 }, },
[WebGL] = { { .i = 0 }, },
- [ZoomLevel] = { { .f = 1.0 }, },
+ [ZoomLevel] = { { .f = 1.4 }, },
};
static UriParameters uriparams[] = {
@@ -62,20 +65,48 @@ static WebKitFindOptions findopts = WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
WEBKIT_FIND_OPTIONS_WRAP_AROUND;
#define PROMPT_GO "Go:"
+#define PROMPT_GO_TAB "Go(TAB):"
+#define PROMPT_SEARCH "Search:"
#define PROMPT_FIND "Find:"
-/* SETPROP(readprop, setprop, prompt)*/
-#define SETPROP(r, s, p) { \
+/* SETPROP(command, current value, prompt) */
+/* Prompts for a value and writes "command value" to the control fifo of the
+ * window the key was pressed in, see initctl() in surf.c. */
+#define SETPROP(cmd, cur, prompt) { \
.v = (const char *[]){ "/bin/sh", "-c", \
- "prop=\"$(printf '%b' \"$(xprop -id $1 "r" " \
- "| sed -e 's/^"r"(UTF8_STRING) = \"\\(.*\\)\"/\\1/' " \
- " -e 's/\\\\\\(.\\)/\\1/g')\" " \
- "| dmenu -p '"p"' -w $1)\" " \
- "&& xprop -id $1 -f "s" 8u -set "s" \"$prop\"", \
- "surf-setprop", winid, NULL \
+ "val=\"$(printf '%s' \"$3\" | wmenu -bi -l 25 -M aa00aa -m 000000 -S aa00aa -s 000000 -p \"$4\")\" " \
+ "&& printf '%s %s\\n' \"$2\" \"$val\" >\"$1\"", \
+ "surf-setprop", winid, cmd, cur, prompt, NULL \
} \
}
+/* GO(prompt) */
+/* Prompts for a URI, offering the current one first and then the history
+ * ranked by visit count. Drop the sort pipeline for a plain prompt. */
+#define GO(prompt) { \
+ .v = (const char *[]){ "/bin/sh", "-c", \
+ "val=\"$({ printf '%s\\n' \"$3\"; " \
+ "sort " HISTFILE " | uniq -c | sort -rn | sed 's/^ *[0-9]* //'; } " \
+ "| awk '!seen[$0]++' | wmenu -bi -l 25 -S aa00aa -s 000000 -M aa00aa -m 000000 -p \"$4\")\" " \
+ "&& printf '%s %s\\n' \"$2\" \"$val\" >\"$1\"", \
+ "surf-go", winid, "uri", winuri, prompt, NULL \
+ } \
+}
+
+/* GO_TAB(prompt) */
+/* Prompts for a URI, offering the current one first and then the history
+ * ranked by visit count. Drop the sort pipeline for a plain prompt. */
+#define GO_TAB(prompt) { \
+ .v = (const char *[]){ "/bin/sh", "-c", \
+ "val=\"$({ printf '%s\\n' \"$1\"; " \
+ "sort " HISTFILE " | uniq -c | sort -rn | sed 's/^ *[0-9]* //'; } " \
+ "| awk '!seen[$0]++' | wmenu -bi -l 25 -S aa00aa -s 000000 -M aa00aa -m 000000 -p \"$2\")\" " \
+ "&& surf \"$val\"", \
+ "surf", winuri, prompt, NULL \
+ } \
+}
+
+
/* DOWNLOAD(URI, referer) */
#define DOWNLOAD(u, r) { \
.v = (const char *[]){ "st", "-e", "/bin/sh", "-c",\
@@ -95,6 +126,23 @@ static WebKitFindOptions findopts = WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
} \
}
+
+#define COPYURL() {\
+ .v = (const char *[]){ "/bin/sh", "-c", \
+ "printf '%s' \"$0\" | wl-copy", winuri , NULL \
+ } \
+}
+
+#define SEARCH(u) {\
+ .v = (const char *[]){ "/bin/sh", "-c", \
+ "val=\"$(echo \"\" | wmenu -bi -S aa00aa -s 000000 -M aa00aa -m 000000 -p \"$4\")\" " \
+ "&& printf '%s %s\\n' \"$2\" \"https://www.google.com/search?q=$val\" >\"$1\"", \
+ "surf-go", winid, "uri", winuri, u, NULL \
+ } \
+}
+
+
+
/* VIDEOPLAY(URI) */
#define VIDEOPLAY(u) {\
.v = (const char *[]){ "/bin/sh", "-c", \
@@ -130,12 +178,13 @@ static SiteSpecific certs[] = {
*/
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) },
+ { MODKEY, GDK_KEY_g, spawn, GO(PROMPT_GO) },
+ { MODKEY, GDK_KEY_f, spawn, SETPROP("find", winfind, PROMPT_FIND) },
+ { MODKEY, GDK_KEY_slash, spawn, SETPROP("find", winfind, PROMPT_FIND) },
{ 0, GDK_KEY_Escape, stop, { 0 } },
- { MODKEY, GDK_KEY_c, stop, { 0 } },
+ { MODKEY, GDK_KEY_e, spawn, COPYURL() },
+ { MODKEY, GDK_KEY_s, spawn, SEARCH(PROMPT_SEARCH) },
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_r, reload, { .i = 1 } },
{ MODKEY, GDK_KEY_r, reload, { .i = 0 } },
@@ -165,19 +214,12 @@ static Key keys[] = {
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_n, find, { .i = -1 } },
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_p, print, { 0 } },
- { MODKEY, GDK_KEY_t, showcert, { 0 } },
+ { MODKEY, GDK_KEY_t, spawn, GO_TAB(PROMPT_GO_TAB) },
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_a, togglecookiepolicy, { 0 } },
{ 0, GDK_KEY_F11, togglefullscreen, { 0 } },
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_o, toggleinspector, { 0 } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_c, toggle, { .i = CaretBrowsing } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_g, toggle, { .i = Geolocation } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_s, toggle, { .i = JavaScript } },
- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_i, toggle, { .i = LoadImages } },
- { 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_SHIFT_MASK, GDK_KEY_d, toggle, { .i = DarkMode } },
};
@@ -185,9 +227,9 @@ static Key keys[] = {
/* target can be OnDoc, OnLink, OnImg, OnMedia, OnEdit, OnBar, OnSel, OnAny */
static Button buttons[] = {
/* target event mask button function argument stop event */
- { OnLink, 0, 2, clicknewwindow, { .i = 0 }, 1 },
- { OnLink, MODKEY, 2, clicknewwindow, { .i = 1 }, 1 },
- { OnLink, MODKEY, 1, clicknewwindow, { .i = 1 }, 1 },
+ { OnLink, 0, 2, clicknewwindow, { 0 }, 1 },
+ { OnLink, MODKEY, 2, clicknewwindow, { 0 }, 1 },
+ { OnLink, MODKEY, 1, clicknewwindow, { 0 }, 1 },
{ OnAny, 0, 8, clicknavigate, { .i = -1 }, 1 },
{ OnAny, 0, 9, clicknavigate, { .i = +1 }, 1 },
{ OnMedia, MODKEY, 1, clickexternplayer, { 0 }, 1 },
diff --git a/config.mk b/config.mk
index 544e123..f47b436 100644
--- a/config.mk
+++ b/config.mk
@@ -9,17 +9,14 @@ MANPREFIX = $(PREFIX)/share/man
LIBPREFIX = $(PREFIX)/lib
LIBDIR = $(LIBPREFIX)/surf
-X11INC = `pkg-config --cflags x11`
-X11LIB = `pkg-config --libs x11`
-
GTKINC = `pkg-config --cflags gtk+-3.0 gcr-3 webkit2gtk-4.1`
GTKLIB = `pkg-config --libs gtk+-3.0 gcr-3 webkit2gtk-4.1`
WEBEXTINC = `pkg-config --cflags webkit2gtk-4.1 webkit2gtk-web-extension-4.1 gio-2.0`
WEBEXTLIBS = `pkg-config --libs webkit2gtk-4.1 webkit2gtk-web-extension-4.1 gio-2.0`
# includes and libs
-INCS = $(X11INC) $(GTKINC)
-LIBS = $(X11LIB) $(GTKLIB) -lgthread-2.0
+INCS = $(GTKINC)
+LIBS = $(GTKLIB) -lgthread-2.0
# flags
CPPFLAGS = -DVERSION=\"$(VERSION)\" -DGCR_API_SUBJECT_TO_CHANGE \
diff --git a/surf.1 b/surf.1
index c1a7744..1034fb8 100644
--- a/surf.1
+++ b/surf.1
@@ -7,16 +7,16 @@ surf \- simple webkit-based browser
.RB [-a\ cookiepolicies]
.RB [-c\ cookiefile]
.RB [-C\ stylefile]
-.RB [-e\ xid]
.RB [-r\ scriptfile]
.RB [-u\ useragent]
.RB [-z\ zoomlevel]
.RB [URI]
.SH DESCRIPTION
-surf is a simple Web browser based on WebKit/GTK+. It is able
-to display websites and follow links. It supports the XEmbed protocol
-which makes it possible to embed it in another application. Furthermore,
-one can point surf to another URI by setting its XProperties.
+surf is a simple Web browser based on WebKit/GTK+, running as a native
+Wayland client. It is able to display websites and follow links.
+Furthermore, one can point surf to another URI by writing to the control
+fifo of its window, see
+.BR "CONTROL FIFO" .
.SH OPTIONS
.TP
.B \-a cookiepolicies
@@ -51,10 +51,6 @@ Disable the disk cache.
.B \-D
Enable the disk cache.
.TP
-.B \-e xid
-Reparents to window specified by
-.IR xid .
-.TP
.B \-f
Start surf in windowed mode (not fullscreen).
.TP
@@ -116,9 +112,9 @@ which surf should use.
Prints version information to standard output, then exits.
.TP
.B \-w
-Prints xid to standard output. This can be used to script the browser in for
-example
-.BR xdotool(1) .
+Prints the path of the window's control fifo to standard output, so that
+scripts can drive the browser without having to guess the path. See
+.BR "CONTROL FIFO" .
.TP
.B -x
Disable custom certificates.
@@ -285,6 +281,37 @@ no proxy
.TP
.B P
using proxy
+.SH CONTROL FIFO
+Each window creates a fifo
+.IR $XDG_RUNTIME_DIR/surf/pid-pageid ,
+whose path is printed by
+.BR \-w .
+Writing a line of the form
+.I "command argument"
+to it drives that window:
+.TP
+.B uri \fIURI\fR
+Load
+.IR URI ,
+resolved the same way as a
+.I URI
+given on the command line.
+.TP
+.B find \fItext\fR
+Search the page for
+.IR text .
+An empty
+.I text
+aborts the search.
+.PP
+For example:
+.PP
+.RS
+printf 'uri %s\\n' https://suckless.org >"$XDG_RUNTIME_DIR"/surf/*
+.RE
+.PP
+The fifo is removed when the window closes; a stale one is left behind if
+surf is killed. No fifo is created in kiosk mode.
.SH ENVIRONMENT
.B SURF_USERAGENT
If this variable is set upon startup, surf will use it as the
@@ -297,9 +324,6 @@ If this variable is set and not empty upon startup, surf will use it as the http
Surf will reload the current page on
.BR SIGHUP .
.SH SEE ALSO
-.BR dmenu(1),
-.BR xprop(1),
-.BR tabbed(1),
-.BR xdotool(1)
+.BR dmenu(1)
.SH BUGS
Please report them!
diff --git a/surf.c b/surf.c
index 7a0f624..462608b 100644
--- a/surf.c
+++ b/surf.c
@@ -4,8 +4,10 @@
*/
#include <sys/file.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <fcntl.h>
#include <glib.h>
#include <inttypes.h>
#include <libgen.h>
@@ -20,17 +22,12 @@
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
-#include <gdk/gdkx.h>
#include <gio/gunixfdlist.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
-#include <gtk/gtkx.h>
#include <gcr/gcr.h>
#include <JavaScriptCore/JavaScript.h>
#include <webkit2/webkit2.h>
-#include <X11/X.h>
-#include <X11/Xatom.h>
-#include <glib.h>
#include "arg.h"
#include "common.h"
@@ -38,8 +35,6 @@
#define LENGTH(x) (sizeof(x) / sizeof(x[0]))
#define CLEANMASK(mask) (mask & (MODKEY|GDK_SHIFT_MASK))
-enum { AtomFind, AtomGo, AtomUri, AtomUTF8, AtomLast };
-
enum {
OnDoc = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT,
OnLink = WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK,
@@ -108,11 +103,12 @@ typedef struct Client {
WebKitHitTestResult *mousepos;
GTlsCertificate *cert, *failedcert;
GTlsCertificateFlags tlserr;
- Window xid;
guint64 pageid;
+ char *ctlfile; /* control fifo, see initctl() */
+ guint ctlsrc;
int progress, fullscreen, https, insecure, errorpage;
const char *title, *overtitle, *targeturi;
- const char *needle;
+ char *needle;
struct Client *next;
} Client;
@@ -158,8 +154,7 @@ static const char *getcurrentuserhomedir(void);
static Client *newclient(Client *c);
static void loaduri(Client *c, const Arg *a);
static const char *geturi(Client *c);
-static void setatom(Client *c, int a, const char *v);
-static const char *getatom(Client *c, int a);
+static void addhistory(const char *uri);
static void updatetitle(Client *c);
static void gettogglestats(Client *c);
static void getpagestats(Client *c);
@@ -173,9 +168,9 @@ static const char *getstyle(const char *uri);
static void setstyle(Client *c, const char *file);
static void runscript(Client *c);
static void evalscript(Client *c, const char *jsstr, ...);
-static void updatewinid(Client *c);
+static void updatewinvars(Client *c);
static void handleplumb(Client *c, const char *uri);
-static void newwindow(Client *c, const Arg *a, int noembed);
+static void newwindow(Client *c, const Arg *a);
static void spawn(Client *c, const Arg *a);
static void msgext(Client *c, char type, const Arg *a);
static void destroyclient(Client *c);
@@ -187,8 +182,8 @@ static void initwebextensions(WebKitWebContext *wc, Client *c);
static GtkWidget *createview(WebKitWebView *v, WebKitNavigationAction *a,
Client *c);
static gboolean buttonreleased(GtkWidget *w, GdkEvent *e, Client *c);
-static GdkFilterReturn processx(GdkXEvent *xevent, GdkEvent *event,
- gpointer d);
+static void initctl(Client *c);
+static gboolean readctl(GIOChannel *ch, GIOCondition cond, gpointer d);
static gboolean winevent(GtkWidget *w, GdkEvent *e, Client *c);
static void showview(WebKitWebView *v, Client *c);
static GtkWidget *createwindow(Client *c);
@@ -243,14 +238,15 @@ static void clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h);
static void clicknewwindow(Client *c, const Arg *a, WebKitHitTestResult *h);
static void clickexternplayer(Client *c, const Arg *a, WebKitHitTestResult *h);
-static char winid[64];
+/* state of the client last interacted with, for use in config.h commands;
+ * these must stay arrays, config.h puts them in static initializers */
+static char winid[PATH_MAX];
+static char winuri[BUFSIZ];
+static char winfind[BUFSIZ];
static char togglestats[11];
static char pagestats[2];
-static Atom atoms[AtomLast];
-static Window embed;
-static int showxid;
+static int showwinid;
static int cookiepolicy;
-static Display *dpy;
static Client *clients;
static GdkDevice *gdkkb;
static char *stylefile;
@@ -320,7 +316,7 @@ void
usage(void)
{
die("usage: surf [-bBdDfFgGiIkKmMnNsStTvwxX]\n"
- "[-a cookiepolicies ] [-c cookiefile] [-C stylefile] [-e xid]\n"
+ "[-a cookiepolicies ] [-c cookiefile] [-C stylefile]\n"
"[-r scriptfile] [-u useragent] [-z zoomlevel] [uri]\n");
}
@@ -336,16 +332,12 @@ setup(void)
if (signal(SIGHUP, sighup) == SIG_ERR)
die("Can't install SIGHUP handler");
- if (!(dpy = XOpenDisplay(NULL)))
- die("Can't open default display");
-
- /* atoms */
- atoms[AtomFind] = XInternAtom(dpy, "_SURF_FIND", False);
- atoms[AtomGo] = XInternAtom(dpy, "_SURF_GO", False);
- atoms[AtomUri] = XInternAtom(dpy, "_SURF_URI", False);
- atoms[AtomUTF8] = XInternAtom(dpy, "UTF8_STRING", False);
+ /* the wayland app_id is taken from the program name */
+ g_set_prgname("surf");
- gtk_init(NULL, NULL);
+ gdk_set_allowed_backends("wayland");
+ if (!gtk_init_check(NULL, NULL))
+ die("Can't open wayland display\n");
gdpy = gdk_display_get_default();
@@ -355,10 +347,13 @@ setup(void)
cookiefile = buildfile(cookiefile);
scriptfile = buildfile(scriptfile);
certdir = buildpath(certdir);
- if (curconfig[Ephemeral].val.i)
+ if (curconfig[Ephemeral].val.i) {
cachedir = NULL;
- else
+ histfile = NULL;
+ } else {
cachedir = buildpath(cachedir);
+ histfile = buildfile(histfile);
+ }
gdkkb = gdk_seat_get_keyboard(gdk_display_get_default_seat(gdpy));
@@ -587,8 +582,6 @@ loaduri(Client *c, const Arg *a)
free(apath);
}
- setatom(c, AtomUri, url);
-
if (strcmp(url, geturi(c)) == 0) {
reload(c, a);
} else {
@@ -609,35 +602,29 @@ geturi(Client *c)
return uri;
}
+/* One visit per line, oldest first; rank them with sort(1), see GO().
+ * Other surf processes append to the same file, so the line has to go out
+ * in a single write(2), or long URIs get interleaved with theirs. */
void
-setatom(Client *c, int a, const char *v)
-{
- XChangeProperty(dpy, c->xid,
- atoms[a], atoms[AtomUTF8], 8, PropModeReplace,
- (unsigned char *)v, strlen(v) + 1);
- XSync(dpy, False);
-}
-
-const char *
-getatom(Client *c, int a)
+addhistory(const char *uri)
{
- static char buf[BUFSIZ];
- Atom adummy;
- int idummy;
- unsigned long ldummy;
- unsigned char *p = NULL;
+ char *line;
+ size_t len;
+ int fd;
- XSync(dpy, False);
- XGetWindowProperty(dpy, c->xid,
- atoms[a], 0L, BUFSIZ, False, atoms[AtomUTF8],
- &adummy, &idummy, &ldummy, &ldummy, &p);
- if (p)
- strncpy(buf, (char *)p, LENGTH(buf) - 1);
- else
- buf[0] = '\0';
- XFree(p);
+ if (!histfile || g_str_has_prefix(uri, "about:"))
+ return;
- return buf;
+ line = g_strdup_printf("%s\n", uri);
+ len = strlen(line);
+ fd = open(histfile, O_WRONLY|O_APPEND|O_CREAT|O_CLOEXEC, 0600);
+ if (fd >= 0) {
+ if (write(fd, line, len) != (ssize_t)len)
+ fprintf(stderr, "%s: can't append to %s\n",
+ argv0, histfile);
+ close(fd);
+ }
+ g_free(line);
}
void
@@ -980,10 +967,13 @@ evalscript(Client *c, const char *jsstr, ...)
g_free(script);
}
+/* publish the state of c to the commands spawned on its behalf */
void
-updatewinid(Client *c)
+updatewinvars(Client *c)
{
- snprintf(winid, LENGTH(winid), "%lu", c->xid);
+ g_strlcpy(winid, c->ctlfile ? c->ctlfile : "", sizeof(winid));
+ g_strlcpy(winuri, geturi(c), sizeof(winuri));
+ g_strlcpy(winfind, c->needle ? c->needle : "", sizeof(winfind));
}
void
@@ -994,11 +984,10 @@ handleplumb(Client *c, const char *uri)
}
void
-newwindow(Client *c, const Arg *a, int noembed)
+newwindow(Client *c, const Arg *a)
{
int i = 0;
- char tmp[64];
- const char *cmd[29], *uri;
+ const char *cmd[27], *uri;
const Arg arg = { .v = cmd };
cmd[i++] = argv0;
@@ -1014,11 +1003,6 @@ newwindow(Client *c, const Arg *a, int noembed)
cmd[i++] = stylefile;
}
cmd[i++] = curconfig[DiskCache].val.i ? "-D" : "-d";
- if (embed && !noembed) {
- cmd[i++] = "-e";
- snprintf(tmp, LENGTH(tmp), "%lu", embed);
- cmd[i++] = tmp;
- }
cmd[i++] = curconfig[RunInFullscreen].val.i ? "-F" : "-f" ;
cmd[i++] = curconfig[Geolocation].val.i ? "-G" : "-g" ;
cmd[i++] = curconfig[LoadImages].val.i ? "-I" : "-i" ;
@@ -1035,7 +1019,7 @@ newwindow(Client *c, const Arg *a, int noembed)
cmd[i++] = "-u";
cmd[i++] = fulluseragent;
}
- if (showxid)
+ if (showwinid)
cmd[i++] = "-w";
cmd[i++] = curconfig[Certificate].val.i ? "-X" : "-x" ;
/* do not keep zoom level */
@@ -1051,8 +1035,6 @@ void
spawn(Client *c, const Arg *a)
{
if (fork() == 0) {
- if (dpy)
- close(ConnectionNumber(dpy));
close(spair[0]);
close(spair[1]);
setsid();
@@ -1073,6 +1055,13 @@ destroyclient(Client *c)
gtk_widget_destroy(c->win);
*/
+ if (c->ctlfile) {
+ g_source_remove(c->ctlsrc);
+ unlink(c->ctlfile);
+ g_free(c->ctlfile);
+ }
+ g_free(c->needle);
+
for (p = clients; p && p->next != c; p = p->next)
;
if (p)
@@ -1094,7 +1083,7 @@ cleanup(void)
g_free(scriptfile);
g_free(stylefile);
g_free(cachedir);
- XCloseDisplay(dpy);
+ g_free(histfile);
}
WebKitWebView *
@@ -1283,29 +1272,68 @@ buttonreleased(GtkWidget *w, GdkEvent *e, Client *c)
return FALSE;
}
-GdkFilterReturn
-processx(GdkXEvent *e, GdkEvent *event, gpointer d)
+/* Every window is driven from the outside through a fifo of its own, taking
+ * one "command argument" line per write:
+ *
+ * printf 'uri %s\n' https://suckless.org >"$XDG_RUNTIME_DIR"/surf/1234-1
+ */
+void
+initctl(Client *c)
+{
+ GIOChannel *ch;
+ char *dir;
+ int fd;
+
+ dir = g_build_filename(g_get_user_runtime_dir(), "surf", NULL);
+ if (g_mkdir_with_parents(dir, 0700) < 0)
+ die("Can't create %s\n", dir);
+ c->ctlfile = g_strdup_printf("%s/%d-%"PRIu64, dir, getpid(), c->pageid);
+ g_free(dir);
+
+ unlink(c->ctlfile); /* leftover of a surf that died unclean */
+ if (mkfifo(c->ctlfile, 0600) < 0)
+ die("Can't create %s\n", c->ctlfile);
+ /* O_RDWR so that we do not see EOF whenever a writer is done */
+ if ((fd = open(c->ctlfile, O_RDWR|O_NONBLOCK|O_CLOEXEC)) < 0)
+ die("Can't open %s\n", c->ctlfile);
+
+ ch = g_io_channel_unix_new(fd);
+ g_io_channel_set_encoding(ch, NULL, NULL);
+ g_io_channel_set_close_on_unref(ch, TRUE);
+ c->ctlsrc = g_io_add_watch(ch, G_IO_IN, readctl, c);
+ g_io_channel_unref(ch);
+}
+
+gboolean
+readctl(GIOChannel *ch, GIOCondition cond, gpointer d)
{
Client *c = (Client *)d;
- XPropertyEvent *ev;
+ char *line, *arg;
Arg a;
- if (((XEvent *)e)->type == PropertyNotify) {
- ev = &((XEvent *)e)->xproperty;
- if (ev->state == PropertyNewValue) {
- if (ev->atom == atoms[AtomFind]) {
- find(c, NULL);
-
- return GDK_FILTER_REMOVE;
- } else if (ev->atom == atoms[AtomGo]) {
- a.v = getatom(c, AtomGo);
- loaduri(c, &a);
+ while (g_io_channel_read_line(ch, &line, NULL, NULL, NULL)
+ == G_IO_STATUS_NORMAL) {
+ g_strstrip(line);
+ if ((arg = strchr(line, ' ')))
+ *arg++ = '\0';
+ else
+ arg = "";
- return GDK_FILTER_REMOVE;
- }
+ if (!strcmp(line, "uri")) {
+ a.v = arg;
+ loaduri(c, &a);
+ } else if (!strcmp(line, "find")) {
+ g_free(c->needle);
+ c->needle = g_strdup(arg);
+ find(c, NULL);
+ } else if (line[0]) {
+ fprintf(stderr, "%s: no such command: %s\n",
+ argv0, line);
}
+ g_free(line);
}
- return GDK_FILTER_CONTINUE;
+
+ return TRUE;
}
gboolean
@@ -1325,7 +1353,7 @@ winevent(GtkWidget *w, GdkEvent *e, Client *c)
keys[i].keyval &&
CLEANMASK(e->key.state) == keys[i].mod &&
keys[i].func) {
- updatewinid(c);
+ updatewinvars(c);
keys[i].func(c, &(keys[i].arg));
return TRUE;
}
@@ -1352,7 +1380,6 @@ void
showview(WebKitWebView *v, Client *c)
{
GdkRGBA bgcolor = { 0 };
- GdkWindow *gwin;
c->finder = webkit_web_view_get_find_controller(c->view);
c->inspector = webkit_web_view_get_inspector(c->view);
@@ -1364,55 +1391,33 @@ showview(WebKitWebView *v, Client *c)
gtk_widget_show_all(c->win);
gtk_widget_grab_focus(GTK_WIDGET(c->view));
- gwin = gtk_widget_get_window(GTK_WIDGET(c->win));
- c->xid = gdk_x11_window_get_xid(gwin);
- updatewinid(c);
- if (showxid) {
- gdk_display_sync(gtk_widget_get_display(c->win));
- puts(winid);
- fflush(stdout);
+ if (!curconfig[KioskMode].val.i) {
+ initctl(c);
+ updatewinvars(c);
+ if (showwinid) {
+ puts(winid);
+ fflush(stdout);
+ }
}
if (curconfig[HideBackground].val.i)
webkit_web_view_set_background_color(c->view, &bgcolor);
- if (!curconfig[KioskMode].val.i) {
- gdk_window_set_events(gwin, GDK_ALL_EVENTS_MASK);
- gdk_window_add_filter(gwin, processx, c);
- }
-
if (curconfig[RunInFullscreen].val.i)
togglefullscreen(c, NULL);
if (curconfig[ZoomLevel].val.f != 1.0)
webkit_web_view_set_zoom_level(c->view,
curconfig[ZoomLevel].val.f);
-
- setatom(c, AtomFind, "");
- setatom(c, AtomUri, "about:blank");
}
GtkWidget *
createwindow(Client *c)
{
- char *wmstr;
GtkWidget *w;
- if (embed) {
- w = gtk_plug_new(embed);
- } else {
- w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
- wmstr = g_path_get_basename(argv0);
- gtk_window_set_wmclass(GTK_WINDOW(w), wmstr, "Surf");
- g_free(wmstr);
-
- wmstr = g_strdup_printf("%s[%"PRIu64"]", "Surf", c->pageid);
- gtk_window_set_role(GTK_WINDOW(w), wmstr);
- g_free(wmstr);
-
- gtk_window_set_default_size(GTK_WINDOW(w), winsize[0], winsize[1]);
- }
+ w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size(GTK_WINDOW(w), winsize[0], winsize[1]);
g_signal_connect(G_OBJECT(w), "destroy",
G_CALLBACK(destroywin), c);
@@ -1484,7 +1489,6 @@ loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c)
switch (e) {
case WEBKIT_LOAD_STARTED:
- setatom(c, AtomUri, uri);
c->title = uri;
c->https = c->insecure = 0;
seturiparameters(c, uri, loadtransient);
@@ -1494,13 +1498,12 @@ loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c)
g_clear_object(&c->failedcert);
break;
case WEBKIT_LOAD_REDIRECTED:
- setatom(c, AtomUri, uri);
c->title = uri;
seturiparameters(c, uri, loadtransient);
break;
case WEBKIT_LOAD_COMMITTED:
- setatom(c, AtomUri, uri);
c->title = uri;
+ addhistory(uri);
seturiparameters(c, uri, loadcommitted);
c->https = webkit_web_view_get_tls_info(c->view, &c->cert,
&c->tlserr);
@@ -1674,7 +1677,7 @@ decidenewwindow(WebKitPolicyDecision *d, Client *c)
* test for link clicked but no button ? */
arg.v = webkit_uri_request_get_uri(
webkit_navigation_action_get_request(a));
- newwindow(c, &arg, 0);
+ newwindow(c, &arg);
break;
case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */
default:
@@ -1949,7 +1952,7 @@ find(Client *c, const Arg *a)
else
webkit_find_controller_search_previous(c->finder);
} else {
- s = getatom(c, AtomFind);
+ s = c->needle ? c->needle : "";
f = webkit_find_controller_get_search_text(c->finder);
if (g_strcmp0(f, s) == 0) /* reset search */
@@ -1976,7 +1979,7 @@ clicknewwindow(Client *c, const Arg *a, WebKitHitTestResult *h)
Arg arg;
arg.v = webkit_hit_test_result_get_link_uri(h);
- newwindow(c, &arg, a->i);
+ newwindow(c, &arg);
}
void
@@ -2024,9 +2027,6 @@ main(int argc, char *argv[])
defconfig[DiskCache].val.i = 1;
defconfig[DiskCache].prio = 2;
break;
- case 'e':
- embed = strtol(EARGF(usage()), NULL, 0);
- break;
case 'f':
defconfig[RunInFullscreen].val.i = 0;
defconfig[RunInFullscreen].prio = 2;
@@ -2100,7 +2100,7 @@ main(int argc, char *argv[])
case 'v':
die("surf-"VERSION", see LICENSE for © details\n");
case 'w':
- showxid = 1;
+ showwinid = 1;
break;
case 'x':
defconfig[Certificate].val.i = 0;