Hi all,

This is my first journey into the DWM code.  I've added
a FIFO control file that you can use to simulate any of the existing
keybinds.

The command names are similar to the functions implementing them.

A simple example would be:

   echo -n term > /tmp/dwm.fifo
   echo -n focusmon+ > /tmp/dwm.fifo
   echo -n term > /tmp/dwm.fifo

This will spawn a terminal on the first monitor, then move to the
second and spawn one there.

It is possible to script simple layouts like this.

Let me know if this is of interest to anyone and I will post it
to the patches section on the wiki.

One command that is missing but would be nice is "exec <cmd>".

cheers,
sin
>From de46334b2342368e5d1fbb1900291994deaca35f Mon Sep 17 00:00:00 2001
From: sin <s...@2f30.org>
Date: Wed, 29 Jan 2014 11:58:56 +0000
Subject: [PATCH] Add DWM control FIFO

I've added the corresponding commands for all assigned
keybinds.

To use simply create the fifo in your .xinitrc, the
default path is at /tmp/dwm.fifo.

A simple command sequence would be:

   echo -n term > /tmp/dwm.fifo
   echo -n focusmon+ > /tmp/dwm.fifo
   echo -n term > /tmp/dwm.fifo
---
 config.def.h |   62 ++++++++++++++++++++
 dwm.c        |  179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 238 insertions(+), 3 deletions(-)

diff --git a/config.def.h b/config.def.h
index 875885b..9264465 100644
--- a/config.def.h
+++ b/config.def.h
@@ -108,3 +108,65 @@ static Button buttons[] = {
        { ClkTagBar,            MODKEY,         Button3,        toggletag,      
{0} },
 };
 
+static const char *dwmfifo = "/tmp/dwm.fifo";
+static Command commands[] = {
+       { "dmenu",           dodmenu,          {.v = dmenucmd} },
+       { "term",            doterm,           {.v = termcmd} },
+       { "togglebar",       dotogglebar,      {0} },
+       { "focusstack+",     dofocusstack,     {.i = +1} },
+       { "focusstack-",     dofocusstack,     {.i = -1} },
+       { "incnmaster+",     doincnmaster,     {.i = +1} },
+       { "incnmaster-",     doincnmaster,     {.i = -1} },
+       { "setmfact+",       dosetmfact,       {.f = +0.05} },
+       { "setmfact-",       dosetmfact,       {.f = -0.05} },
+       { "zoom",            dozoom,           {0} },
+       { "view",            doview,           {0} },
+       { "killclient",      dokillclient,     {0} },
+       { "setlayout-tiled", dosetlayout,      {.v = &layouts[0]} },
+       { "setlayout-float", dosetlayout,      {.v = &layouts[1]} },
+       { "setlayout-mono",  dosetlayout,      {.v = &layouts[2]} },
+       { "togglelayout",    dosetlayout,      {0} },
+       { "togglefloating",  dotogglefloating, {0} },
+       { "viewall",         doview,           {.ui = ~0} },
+       { "tag",             dotag,            {.ui = ~0} },
+       { "focusmon+",       dofocusmon,       {.i = +1} },
+       { "focusmon-",       dofocusmon,       {.i = -1} },
+       { "tagmon+",         dotagmon,         {.i = +1} },
+       { "tagmon-",         dotagmon,         {.i = -1} },
+       { "view1",           doview,           {.ui = 1 << 0} },
+       { "view2",           doview,           {.ui = 1 << 1} },
+       { "view3",           doview,           {.ui = 1 << 2} },
+       { "view4",           doview,           {.ui = 1 << 3} },
+       { "view5",           doview,           {.ui = 1 << 4} },
+       { "view6",           doview,           {.ui = 1 << 5} },
+       { "view7",           doview,           {.ui = 1 << 6} },
+       { "view8",           doview,           {.ui = 1 << 7} },
+       { "view9",           doview,           {.ui = 1 << 8} },
+       { "toggleview1",     dotoggleview,     {.ui = 1 << 0} },
+       { "toggleview2",     dotoggleview,     {.ui = 1 << 1} },
+       { "toggleview3",     dotoggleview,     {.ui = 1 << 2} },
+       { "toggleview4",     dotoggleview,     {.ui = 1 << 3} },
+       { "toggleview5",     dotoggleview,     {.ui = 1 << 4} },
+       { "toggleview6",     dotoggleview,     {.ui = 1 << 5} },
+       { "toggleview7",     dotoggleview,     {.ui = 1 << 6} },
+       { "toggleview8",     dotoggleview,     {.ui = 1 << 7} },
+       { "toggleview9",     dotoggleview,     {.ui = 1 << 8} },
+       { "tag1",            dotag,            {.ui = 1 << 0} },
+       { "tag2",            dotag,            {.ui = 1 << 1} },
+       { "tag3",            dotag,            {.ui = 1 << 2} },
+       { "tag4",            dotag,            {.ui = 1 << 3} },
+       { "tag5",            dotag,            {.ui = 1 << 4} },
+       { "tag6",            dotag,            {.ui = 1 << 5} },
+       { "tag7",            dotag,            {.ui = 1 << 6} },
+       { "tag8",            dotag,            {.ui = 1 << 7} },
+       { "tag9",            dotag,            {.ui = 1 << 8} },
+       { "toggletag1",      dotoggletag,      {.ui = 1 << 0} },
+       { "toggletag2",      dotoggletag,      {.ui = 1 << 1} },
+       { "toggletag3",      dotoggletag,      {.ui = 1 << 2} },
+       { "toggletag4",      dotoggletag,      {.ui = 1 << 3} },
+       { "toggletag5",      dotoggletag,      {.ui = 1 << 4} },
+       { "toggletag6",      dotoggletag,      {.ui = 1 << 5} },
+       { "toggletag7",      dotoggletag,      {.ui = 1 << 6} },
+       { "toggletag8",      dotoggletag,      {.ui = 1 << 7} },
+       { "toggletag9",      dotoggletag,      {.ui = 1 << 8} },
+};
diff --git a/dwm.c b/dwm.c
index 1bbb4b3..7b1b8af 100644
--- a/dwm.c
+++ b/dwm.c
@@ -21,6 +21,7 @@
  * To understand everything else, start reading main().
  */
 #include <errno.h>
+#include <fcntl.h>
 #include <locale.h>
 #include <stdarg.h>
 #include <signal.h>
@@ -28,6 +29,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/select.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <X11/cursorfont.h>
@@ -140,6 +143,12 @@ typedef struct {
        int monitor;
 } Rule;
 
+typedef struct {
+       const char *name;
+       void (*func)(const Arg *arg);
+       const Arg arg;
+} Command;
+
 /* function declarations */
 static void applyrules(Client *c);
 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool 
interact);
@@ -161,9 +170,27 @@ static void destroynotify(XEvent *e);
 static void detach(Client *c);
 static void detachstack(Client *c);
 static Monitor *dirtomon(int dir);
+static void dispatchcmd(void);
+static void dodmenu(const Arg *arg);
+static void dofocusmon(const Arg *arg);
+static void dofocusstack(const Arg *arg);
+static void doincnmaster(const Arg *arg);
+static void dokillclient(const Arg *arg);
+static void dosetlayout(const Arg *arg);
+static void dosetmfact(const Arg *arg);
+static void dotag(const Arg *arg);
+static void dotagmon(const Arg *arg);
+static void doterm(const Arg *arg);
+static void dotogglebar(const Arg *arg);
+static void dotogglefloating(const Arg *arg);
+static void dotoggletag(const Arg *arg);
+static void dotoggleview(const Arg *arg);
+static void doview(const Arg *arg);
+static void dozoom(const Arg *arg);
 static void drawbar(Monitor *m);
 static void drawbars(void);
 static void enternotify(XEvent *e);
+static Bool evpredicate();
 static void expose(XEvent *e);
 static void focus(Client *c);
 static void focusin(XEvent *e);
@@ -266,6 +293,7 @@ static Drw *drw;
 static Fnt *fnt;
 static Monitor *mons, *selmon;
 static Window root;
+static int fifofd;
 
 /* configuration, allows nested code to access above variables */
 #include "config.h"
@@ -485,6 +513,8 @@ cleanup(void) {
        XSync(dpy, False);
        XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
        XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+       if (fifofd != -1)
+               close(fifofd);
 }
 
 void
@@ -691,6 +721,121 @@ dirtomon(int dir) {
 }
 
 void
+dispatchcmd(void)
+{
+       int i;
+       char buf[BUFSIZ];
+       ssize_t n;
+
+       n = read(fifofd, buf, sizeof(buf) - 1);
+       if (n == -1)
+               die("Failed to read from DWM fifo\n");
+       buf[n] = '\0';
+       for (i = 0; i < LENGTH(commands); i++) {
+               if (strcmp(commands[i].name, buf) == 0) {
+                       commands[i].func(&commands[i].arg);
+                       break;
+               }
+       }
+}
+
+void
+dodmenu(const Arg *arg)
+{
+       spawn(arg);
+}
+
+static void
+dofocusmon(const Arg *arg)
+{
+       focusmon(arg);
+}
+
+void
+dofocusstack(const Arg *arg)
+{
+       focusstack(arg);
+}
+
+void
+doincnmaster(const Arg *arg)
+{
+       incnmaster(arg);
+}
+
+void
+dokillclient(const Arg *arg)
+{
+       killclient(arg);
+}
+
+void
+dosetlayout(const Arg *arg)
+{
+       setlayout(arg);
+}
+
+void
+dosetmfact(const Arg *arg)
+{
+       setmfact(arg);
+}
+
+static void
+dotag(const Arg *arg)
+{
+       tag(arg);
+}
+
+static void
+dotagmon(const Arg *arg)
+{
+       tagmon(arg);
+}
+
+void
+doterm(const Arg *arg)
+{
+       spawn(arg);
+}
+
+void
+dotogglebar(const Arg *arg)
+{
+       togglebar(arg);
+}
+
+static void
+dotogglefloating(const Arg *arg)
+{
+       togglefloating(arg);
+}
+
+static void
+dotoggletag(const Arg *arg)
+{
+       toggletag(arg);
+}
+
+static void
+dotoggleview(const Arg *arg)
+{
+       toggleview(arg);
+}
+
+void
+doview(const Arg *arg)
+{
+       view(arg);
+}
+
+void
+dozoom(const Arg *arg)
+{
+       zoom(arg);
+}
+
+void
 drawbar(Monitor *m) {
        int x, xx, w;
        unsigned int i, occ = 0, urg = 0;
@@ -768,6 +913,12 @@ enternotify(XEvent *e) {
        focus(c);
 }
 
+Bool
+evpredicate()
+{
+       return True;
+}
+
 void
 expose(XEvent *e) {
        Monitor *m;
@@ -1341,11 +1492,30 @@ restack(Monitor *m) {
 void
 run(void) {
        XEvent ev;
+       fd_set rfds;
+       int n;
+       int x11fd, maxfd;
        /* main event loop */
        XSync(dpy, False);
-       while(running && !XNextEvent(dpy, &ev))
-               if(handler[ev.type])
-                       handler[ev.type](&ev); /* call handler */
+       x11fd = ConnectionNumber(dpy);
+       maxfd = fifofd;
+       if (x11fd > maxfd)
+               maxfd = x11fd;
+       maxfd++;
+       while (running) {
+               FD_ZERO(&rfds);
+               FD_SET(fifofd, &rfds);
+               FD_SET(x11fd, &rfds);
+               n = select(maxfd, &rfds, NULL, NULL, NULL);
+               if (n > 0) {
+                       if (FD_ISSET(fifofd, &rfds))
+                               dispatchcmd();
+                       if (FD_ISSET(x11fd, &rfds))
+                               if (XCheckIfEvent(dpy, &ev, evpredicate, NULL))
+                                       if (handler[ev.type])
+                                               handler[ev.type](&ev); /* call 
handler */
+               }
+       }
 }
 
 void
@@ -1543,6 +1713,9 @@ setup(void) {
        XSelectInput(dpy, root, wa.event_mask);
        grabkeys();
        focus(NULL);
+       fifofd = open(dwmfifo, O_RDWR | O_NONBLOCK);
+       if (fifofd < 0)
+               die("Failed to open DWM fifo\n");
 }
 
 void
-- 
1.7.10.4

Reply via email to