sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

surf-fifo-20220310-c5c1646.diff (8358B)


      1 From c5c1646470c4a278a9e44dc3934b4e0346518d40 Mon Sep 17 00:00:00 2001
      2 From: avalonwilliams <avalonwilliams@protonmail.com>
      3 Date: Wed, 9 Mar 2022 23:53:08 -0500
      4 Subject: [PATCH] fifo patch
      5 
      6 Adds a small command language for remote control of surf through
      7 a fifo pipe, allowing for more complex scripts and features to be
      8 added through shell scripts. Also adds a javascript injection function
      9 that you can bind keys to.
     10 ---
     11  config.def.h |   1 +
     12  surf.c       | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++
     13  2 files changed, 211 insertions(+)
     14 
     15 diff --git a/config.def.h b/config.def.h
     16 index 1355ba3..dcc8d64 100644
     17 --- a/config.def.h
     18 +++ b/config.def.h
     19 @@ -6,6 +6,7 @@ static char *styledir       = "~/.surf/styles/";
     20  static char *certdir        = "~/.surf/certificates/";
     21  static char *cachedir       = "~/.surf/cache/";
     22  static char *cookiefile     = "~/.surf/cookies.txt";
     23 +static char *fifodir        = "~/.surf/fifo/";
     24  
     25  /* Webkit default features */
     26  /* Highest priority value will be used.
     27 diff --git a/surf.c b/surf.c
     28 index 03d8242..327698e 100644
     29 --- a/surf.c
     30 +++ b/surf.c
     31 @@ -17,6 +17,8 @@
     32  #include <stdlib.h>
     33  #include <string.h>
     34  #include <unistd.h>
     35 +#include <sys/types.h>
     36 +#include <sys/stat.h>
     37  
     38  #include <gdk/gdk.h>
     39  #include <gdk/gdkkeysyms.h>
     40 @@ -141,6 +143,24 @@ typedef struct {
     41  	regex_t re;
     42  } SiteSpecific;
     43  
     44 +typedef enum {
     45 +	ARGTYPE_INT,
     46 +	ARGTYPE_FLT,
     47 +	ARGTYPE_STR,
     48 +	ARGTYPE_NIL,
     49 +} ArgType;
     50 +
     51 +typedef struct {
     52 +	char *cmd;
     53 +	void (*func)(Client *c, const Arg *a);
     54 +	ArgType t;
     55 +} Cmd;
     56 +
     57 +typedef struct {
     58 +	char *p;
     59 +	ParamName pv;
     60 +} ParamMap;
     61 +
     62  /* Surf */
     63  static void die(const char *errstr, ...);
     64  static void usage(void);
     65 @@ -239,6 +259,13 @@ static void clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h);
     66  static void clicknewwindow(Client *c, const Arg *a, WebKitHitTestResult *h);
     67  static void clickexternplayer(Client *c, const Arg *a, WebKitHitTestResult *h);
     68  
     69 +static gboolean init_fifo(Client *c);
     70 +static gboolean start_fifo(Client *c, char *path);
     71 +static void fifo_read_cb(GObject *f, GAsyncResult *r, gpointer d);
     72 +static void dispatchcmd(Client *c, char *cmd, char *a);
     73 +static void injectjs(Client *c, const Arg *a);
     74 +static void togglewrapper(Client *c, const Arg *a);
     75 +
     76  static char winid[64];
     77  static char togglestats[11];
     78  static char pagestats[2];
     79 @@ -255,6 +282,7 @@ static Parameter *curconfig;
     80  static int modparams[ParameterLast];
     81  static int spair[2];
     82  char *argv0;
     83 +static GFile *fifof;
     84  
     85  static ParamName loadtransient[] = {
     86  	Certificate,
     87 @@ -298,6 +326,45 @@ static ParamName loadfinished[] = {
     88  	ParameterLast
     89  };
     90  
     91 +static ParamMap paramnames[] = {
     92 +	{ "autoplay",     MediaManualPlay  },
     93 +	{ "caret",        CaretBrowsing    },
     94 +	{ "frameflat",    FrameFlattening  },
     95 +	{ "geolocation",  Geolocation      },
     96 +	{ "hidebg",       HideBackground   },
     97 +	{ "images",       LoadImages       },
     98 +	{ "indicators",   ShowIndicators   },
     99 +	{ "java",         Java             },
    100 +	{ "js",           JavaScript       },
    101 +	{ "kiosk",        KioskMode        },
    102 +	{ "microphone",   AccessMicrophone },
    103 +	{ "scrollbars",   ScrollBars       },
    104 +	{ "smoothscroll", SmoothScrolling  },
    105 +	{ "spellcheck",   SpellChecking    },
    106 +	{ "stricttls",    StrictTLS        },
    107 +	{ "style",        Style            },
    108 +	{ "webcam",       AccessWebcam     },
    109 +	{ "webgl",        WebGL            },
    110 +};
    111 +
    112 +static Cmd commands[] = {
    113 +	{ "clipboard",        clipboard,          ARGTYPE_INT },
    114 +	{ "find",             find,               ARGTYPE_INT },
    115 +	{ "inject",           injectjs,           ARGTYPE_STR },
    116 +	{ "loaduri",          loaduri,            ARGTYPE_STR },
    117 +	{ "reload",           reload,             ARGTYPE_INT },
    118 +	{ "scrollh",          scrollh,            ARGTYPE_INT },
    119 +	{ "scrollv",          scrollv,            ARGTYPE_INT },
    120 +	{ "showcert",         showcert,           ARGTYPE_NIL },
    121 +	{ "spawn",            spawn,              ARGTYPE_STR },
    122 +	{ "stop",             stop,               ARGTYPE_NIL },
    123 +	{ "toggle",           togglewrapper,      ARGTYPE_STR },
    124 +	{ "togglecookies",    togglecookiepolicy, ARGTYPE_NIL },
    125 +	{ "togglefullscreen", togglefullscreen,   ARGTYPE_NIL },
    126 +	{ "toggleinspector",  toggleinspector,    ARGTYPE_NIL },
    127 +	{ "zoom",             zoom,               ARGTYPE_INT },
    128 +};
    129 +
    130  /* configuration, allows nested code to access above variables */
    131  #include "config.h"
    132  
    133 @@ -351,6 +418,7 @@ setup(void)
    134  	cookiefile = buildfile(cookiefile);
    135  	scriptfile = buildfile(scriptfile);
    136  	certdir    = buildpath(certdir);
    137 +	fifodir    = buildpath(fifodir);
    138  	if (curconfig[Ephemeral].val.i)
    139  		cachedir = NULL;
    140  	else
    141 @@ -1080,9 +1148,15 @@ destroyclient(Client *c)
    142  void
    143  cleanup(void)
    144  {
    145 +	GError *error = NULL;
    146 +
    147  	while (clients)
    148  		destroyclient(clients);
    149  
    150 +	if (fifof != NULL)
    151 +		if (!g_file_delete(fifof, NULL, &error))
    152 +			g_warning("cleanup: couldn't delete fifo: %s\n", error->message);
    153 +
    154  	close(spair[0]);
    155  	close(spair[1]);
    156  	g_free(cookiefile);
    157 @@ -1874,6 +1948,141 @@ msgext(Client *c, char type, const Arg *a)
    158  		        c->pageid, type, a->i, ret);
    159  }
    160  
    161 +gboolean
    162 +init_fifo(Client *c)
    163 +{
    164 +	gboolean r = FALSE;
    165 +	char *path = g_strconcat(fifodir, "/", winid, NULL);
    166 +
    167 +	if (path) {
    168 +		if (g_file_test(path, G_FILE_TEST_EXISTS) && unlink(path))
    169 +			fprintf(stderr, "surf: couldn't unlink old fifo: %s\n", path);
    170 +
    171 +		if (!mkfifo(path, 0600)) {
    172 +			r = start_fifo(c, path);
    173 +		} else {
    174 +			fprintf(stderr, "init_fifo: couldn't create fifo: %s\n", path);
    175 +			r = FALSE;
    176 +		}
    177 +	}
    178 +
    179 +
    180 +	// fifo info no longer needed
    181 +	g_free(fifodir);
    182 +	if (path)
    183 +		g_free(path);
    184 +
    185 +	return r;
    186 +}
    187 +
    188 +gboolean
    189 +start_fifo(Client *c, char *path)
    190 +{
    191 +	GError *error = NULL;
    192 +	GFileIOStream *fs;
    193 +	GOutputStream *os;
    194 +	GDataInputStream *is;
    195 +	fifof = g_file_new_for_path (path);
    196 +
    197 +	/* open in read/write so no blocking occurs */
    198 +	fs = g_file_open_readwrite(fifof, NULL, &error);
    199 +	if (!fs) {
    200 +		fprintf(stderr, "surf: can't open: %s\n", error->message);
    201 +		g_error_free(error);
    202 +		return FALSE;
    203 +	}
    204 +
    205 +	os = g_io_stream_get_output_stream(G_IO_STREAM(fs));
    206 +	if (!g_output_stream_close(os, NULL, &error)) {
    207 +		fprintf(stderr, "start_fifo: failed to close write end: %s\n",
    208 +		          error->message);
    209 +		g_error_free(error);
    210 +		return FALSE;
    211 +	}
    212 +
    213 +	is = g_data_input_stream_new(g_io_stream_get_input_stream(G_IO_STREAM(fs)));
    214 +
    215 +	g_data_input_stream_read_line_async(is, G_PRIORITY_DEFAULT, NULL,
    216 +	                                    &fifo_read_cb, c);
    217 +
    218 +	g_setenv("SURF_FIFO", path, TRUE);
    219 +
    220 +	return TRUE;
    221 +}
    222 +
    223 +void
    224 +fifo_read_cb(GObject *f, GAsyncResult *r, gpointer d)
    225 +{
    226 +	Client *c = (Client *)d;
    227 +	GDataInputStream *s = (GDataInputStream *)f;
    228 +	GError *error = NULL;
    229 +	gsize length;
    230 +	gchar *rest;
    231 +
    232 +	gchar *line = g_data_input_stream_read_line_finish(s, r, &length, &error);
    233 +	if (error) {
    234 +		fprintf(stderr, "fifo_read_cb: error reading: %s\n", error->message);
    235 +		return;
    236 +	}
    237 +
    238 +	if (!line)
    239 +		return;
    240 +
    241 +	line = strtok_r(line, " ", &rest);
    242 +
    243 +	dispatchcmd(c, line, rest);
    244 +
    245 +	g_data_input_stream_read_line_async(s, G_PRIORITY_DEFAULT, NULL,
    246 +	                                    &fifo_read_cb, c);
    247 +}
    248 +
    249 +void
    250 +dispatchcmd(Client *c, char *cmd, char *a)
    251 +{
    252 +	Arg arg;
    253 +	int i;
    254 +
    255 +	for (i = 0; i < LENGTH(commands); i++) {
    256 +		if (strcmp(cmd, commands[i].cmd) == 0) {
    257 +			switch (commands[i].t) {
    258 +			case ARGTYPE_STR: arg = (Arg)(const void *)a; break;
    259 +			case ARGTYPE_INT: arg = (Arg)atoi(a);         break;
    260 +			case ARGTYPE_FLT: arg = (Arg)(float)atof(a);  break;
    261 +			case ARGTYPE_NIL: arg = (Arg)0;               break;
    262 +			}
    263 +
    264 +			if (commands[i].t == ARGTYPE_INT) {
    265 +				printf("%i\n", arg.i);
    266 +			}
    267 +			commands[i].func(c, (const Arg *)&arg);
    268 +			return;
    269 +		}
    270 +	}
    271 +
    272 +	fprintf(stderr, "%s: no such command\n", cmd);
    273 +}
    274 +
    275 +void
    276 +injectjs(Client *c, const Arg *a)
    277 +{
    278 +	evalscript(c, "%s", (char *)a->v);
    279 +}
    280 +
    281 +void
    282 +togglewrapper(Client *c, const Arg *a)
    283 +{
    284 +	int i;
    285 +
    286 +	for (i = 0; i < LENGTH(paramnames); i++) {
    287 +		if (strcmp(paramnames[i].p, (char *)a->v) == 0) {
    288 +			Arg targ = (Arg)(const void *)paramnames[i].pv;
    289 +			return toggle(c, &targ);
    290 +		}
    291 +	}
    292 +
    293 +	fprintf(stderr, "toggle: no such setting '%s'", (char *)a->v);
    294 +}
    295 +
    296  void
    297  scrollv(Client *c, const Arg *a)
    298  {
    299 @@ -2123,6 +2332,7 @@ main(int argc, char *argv[])
    300  	setup();
    301  	c = newclient(NULL);
    302  	showview(NULL, c);
    303 +	init_fifo(c);
    304  
    305  	loaduri(c, &arg);
    306  	updatetitle(c);
    307 -- 
    308 2.35.1
    309