From 4379517c25b136f4628c436254a54852542ebadf Mon Sep 17 00:00:00 2001 From: bakkeby Date: Mon, 7 Sep 2020 17:48:58 +0200 Subject: [PATCH] Adding IPC v1.5.5 patch --- .gitignore | 1 + Makefile | 16 +++++++++ README.md | 6 +++- config.def.h | 20 +++++++++++ config.mk | 8 +++-- dwm.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ patch/dwmc.c | 8 +++++ patch/include.c | 9 +++++ patch/include.h | 5 +++ patches.def.h | 14 ++++++++ util.h | 6 ++++ 11 files changed, 181 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 88d2ee6..ca093f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o dwm +dwm-msg config.h patches.h diff --git a/Makefile b/Makefile index 25258d5..f35c614 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,11 @@ include config.mk SRC = drw.c dwm.c util.c OBJ = ${SRC:.c=.o} +ifdef YAJLLIBS +all: options dwm dwm-msg +else all: options dwm +endif options: @echo dwm build options: @@ -28,8 +32,14 @@ patches.h: dwm: ${OBJ} ${CC} -o $@ ${OBJ} ${LDFLAGS} +ifdef YAJLLIBS +dwm-msg: + ${CC} -o $@ patch/ipc/dwm-msg.c ${LDFLAGS} +endif + clean: rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz + rm -f dwm-msg dist: clean mkdir -p dwm-${VERSION} @@ -42,8 +52,14 @@ dist: clean install: all mkdir -p ${DESTDIR}${PREFIX}/bin cp -f dwm ${DESTDIR}${PREFIX}/bin +ifdef YAJLLIBS + cp -f dwm-msg ${DESTDIR}${PREFIX}/bin +endif #cp -f patch/dwmc ${DESTDIR}${PREFIX}/bin chmod 755 ${DESTDIR}${PREFIX}/bin/dwm +ifdef YAJLLIBS + chmod 755 ${DESTDIR}${PREFIX}/bin/dwm-msg +endif mkdir -p ${DESTDIR}${MANPREFIX}/man1 sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 diff --git a/README.md b/README.md index 412a6b3..1953fb0 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t ### Changelog: -2020-09-07 - Scratchpads improvement (multi-monitor support) +2020-09-07 - Scratchpads improvement (multi-monitor support). Added ipc v1.5.5 patch. 2020-09-05 - Assortment of fullscreen improvements @@ -350,6 +350,10 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t - lets custom insets from each edge of the screen to be defined - an example use case would be to make space for an external bar + - [ipc](https://github.com/mihirlad55/dwm-ipc) + - implements inter-process communication through a UNIX socket for dwm + - allows for the window manager to be queried for information, e.g. listen for events such as tag or layout changes, as well as send commands to control the window manager via other programs + - [ispermanent](https://dwm.suckless.org/patches/ispermanent/) - adds rule option for clients to avoid accidental termination by killclient for sticky windows diff --git a/config.def.h b/config.def.h index 2a5dbf9..695b50c 100644 --- a/config.def.h +++ b/config.def.h @@ -1308,3 +1308,23 @@ static Button buttons[] = { { ClkTagBar, MODKEY, Button1, tag, {0} }, { ClkTagBar, MODKEY, Button3, toggletag, {0} }, }; + +#if IPC_PATCH +static const char *ipcsockpath = "/tmp/dwm.sock"; +static IPCCommand ipccommands[] = { + IPCCOMMAND( view, 1, {ARG_TYPE_UINT} ), + IPCCOMMAND( toggleview, 1, {ARG_TYPE_UINT} ), + IPCCOMMAND( tag, 1, {ARG_TYPE_UINT} ), + IPCCOMMAND( toggletag, 1, {ARG_TYPE_UINT} ), + IPCCOMMAND( tagmon, 1, {ARG_TYPE_UINT} ), + IPCCOMMAND( focusmon, 1, {ARG_TYPE_SINT} ), + IPCCOMMAND( focusstack, 1, {ARG_TYPE_SINT} ), + IPCCOMMAND( zoom, 1, {ARG_TYPE_NONE} ), + IPCCOMMAND( incnmaster, 1, {ARG_TYPE_SINT} ), + IPCCOMMAND( killclient, 1, {ARG_TYPE_SINT} ), + IPCCOMMAND( togglefloating, 1, {ARG_TYPE_NONE} ), + IPCCOMMAND( setmfact, 1, {ARG_TYPE_FLOAT} ), + IPCCOMMAND( setlayoutsafe, 1, {ARG_TYPE_PTR} ), + IPCCOMMAND( quit, 1, {ARG_TYPE_NONE} ) +}; +#endif // IPC_PATCH \ No newline at end of file diff --git a/config.mk b/config.mk index e92e380..5abe400 100644 --- a/config.mk +++ b/config.mk @@ -30,6 +30,10 @@ FREETYPEINC = /usr/include/freetype2 #PANGOINC = `pkg-config --cflags xft pango pangoxft` #PANGOLIB = `pkg-config --libs xft pango pangoxft` +# Uncomment for the ipc patch / IPC_PATCH +#YAJLLIBS = -I-lyajl +#YAJLINC = /usr/include/yajl + # Uncomment this for the rounded corners patch / ROUNDED_CORNERS_PATCH #XEXTLIB = -lXext @@ -37,8 +41,8 @@ FREETYPEINC = /usr/include/freetype2 #XCBLIBS = -lX11-xcb -lxcb -lxcb-res # includes and libs -INCS = -I${X11INC} -I${FREETYPEINC} ${PANGOINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XRENDER} ${MPDCLIENT} ${XEXTLIB} ${XCBLIBS} ${PANGOLIB} +INCS = -I${X11INC} -I${FREETYPEINC} ${PANGOINC} ${YAJLLIBS} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XRENDER} ${MPDCLIENT} ${XEXTLIB} ${XCBLIBS} ${PANGOLIB} ${YAJLLIBS} # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/dwm.c b/dwm.c index e58d758..769cd71 100644 --- a/dwm.c +++ b/dwm.c @@ -219,9 +219,28 @@ enum { BAR_ALIGN_LAST }; /* bar alignment */ +#if IPC_PATCH +typedef struct TagState TagState; +struct TagState { + int selected; + int occupied; + int urgent; +}; + +typedef struct ClientState ClientState; +struct ClientState { + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; +}; +#endif // IPC_PATCH + typedef union { + #if IPC_PATCH + long i; + unsigned long ui; + #else int i; unsigned int ui; + #endif // IPC_PATCH float f; const void *v; } Arg; @@ -333,6 +352,9 @@ struct Client { #endif // SWALLOW_PATCH Monitor *mon; Window win; + #if IPC_PATCH + ClientState prevstate; + #endif // IPC_PATCH }; typedef struct { @@ -414,6 +436,12 @@ struct Monitor { #if INSETS_PATCH Inset inset; #endif // INSETS_PATCH + #if IPC_PATCH + char lastltsymbol[16]; + TagState tagstate; + Client *lastsel; + const Layout *lastlt; + #endif // IPC_PATCH }; typedef struct { @@ -1039,6 +1067,13 @@ cleanup(void) XSync(dpy, False); XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + + #if IPC_PATCH + ipc_cleanup(); + + if (close(epoll_fd) < 0) + fprintf(stderr, "Failed to close epoll file descriptor\n"); + #endif // IPC_PATCH } void @@ -2638,6 +2673,46 @@ restack(Monitor *m) #endif // WARP_PATCH } +#if IPC_PATCH +void +run(void) +{ + int event_count = 0; + const int MAX_EVENTS = 10; + struct epoll_event events[MAX_EVENTS]; + + XSync(dpy, False); + + /* main event loop */ + while (running) { + event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); + + for (int i = 0; i < event_count; i++) { + int event_fd = events[i].data.fd; + DEBUG("Got event from fd %d\n", event_fd); + + if (event_fd == dpy_fd) { + // -1 means EPOLLHUP + if (handlexevent(events + i) == -1) + return; + } else if (event_fd == ipc_get_sock_fd()) { + ipc_handle_socket_epoll_event(events + i); + } else if (ipc_is_client_registered(event_fd)) { + if (ipc_handle_client_epoll_event(events + i, mons, &lastselmon, selmon, + NUMTAGS, layouts, LENGTH(layouts)) < 0) { + fprintf(stderr, "Error handling IPC event on fd %d\n", event_fd); + } + } else { + fprintf(stderr, "Got event from unknown fd %d, ptr %p, u32 %d, u64 %lu", + event_fd, events[i].data.ptr, events[i].data.u32, + events[i].data.u64); + fprintf(stderr, " with events %d\n", events[i].events); + return; + } + } + } +} +#else void run(void) { @@ -2648,6 +2723,7 @@ run(void) if (handler[ev.type]) handler[ev.type](&ev); /* call handler */ } +#endif // IPC_PATCH void scan(void) @@ -3096,6 +3172,9 @@ setup(void) XSelectInput(dpy, root, wa.event_mask); grabkeys(); focus(NULL); + #if IPC_PATCH + setupepoll(); + #endif // IPC_PATCH } @@ -3910,10 +3989,22 @@ updatestatus(void) void updatetitle(Client *c) { + #if IPC_PATCH + char oldname[sizeof(c->name)]; + strcpy(oldname, c->name); + #endif // IPC_PATCH + if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); if (c->name[0] == '\0') /* hack to mark broken clients */ strcpy(c->name, broken); + + #if IPC_PATCH + for (Monitor *m = mons; m; m = m->next) { + if (m->sel == c && strcmp(oldname, c->name) != 0) + ipc_focused_title_change_event(m->num, c->win, oldname, c->name); + } + #endif // IPC_PATCH } void diff --git a/patch/dwmc.c b/patch/dwmc.c index 065e64d..4dedcbc 100644 --- a/patch/dwmc.c +++ b/patch/dwmc.c @@ -62,9 +62,17 @@ fake_signal(void) if (paramn == 1) arg = (Arg) {0}; else if (paramn > 2) return 1; else if (strncmp(param, "i", n - len_str_sig) == 0) + #if IPC_PATCH + sscanf(fsignal + len_indicator + n, "%li", &(arg.i)); + #else sscanf(fsignal + len_indicator + n, "%i", &(arg.i)); + #endif // IPC_PATCH else if (strncmp(param, "ui", n - len_str_sig) == 0) + #if IPC_PATCH + sscanf(fsignal + len_indicator + n, "%lu", &(arg.ui)); + #else sscanf(fsignal + len_indicator + n, "%u", &(arg.ui)); + #endif // IPC_PATCH else if (strncmp(param, "f", n - len_str_sig) == 0) sscanf(fsignal + len_indicator + n, "%f", &(arg.f)); else return 1; diff --git a/patch/include.c b/patch/include.c index e13348e..66eba15 100644 --- a/patch/include.c +++ b/patch/include.c @@ -138,6 +138,15 @@ #if INPLACEROTATE_PATCH #include "inplacerotate.c" #endif +#if IPC_PATCH +#include "ipc.c" +#ifdef VERSION +#include "ipc/IPCClient.c" +#include "ipc/yajl_dumps.c" +#include "ipc/ipc.c" +#include "ipc/util.c" +#endif +#endif // IPC_PATCH #if INSETS_PATCH #include "insets.c" #endif diff --git a/patch/include.h b/patch/include.h index 9130311..94b5a59 100644 --- a/patch/include.h +++ b/patch/include.h @@ -138,6 +138,11 @@ #if INPLACEROTATE_PATCH #include "inplacerotate.h" #endif +#if IPC_PATCH +#include "ipc.h" +#include "ipc/ipc.h" +#include "ipc/util.h" +#endif #if INSETS_PATCH #include "insets.h" #endif diff --git a/patches.def.h b/patches.def.h index bbed419..4a5048d 100644 --- a/patches.def.h +++ b/patches.def.h @@ -532,6 +532,20 @@ */ #define INSETS_PATCH 0 +/* This patch (v1.5.5) implements inter-process communication through a UNIX socket for dwm. This + * allows for the window manager to be queried for information, e.g. listen for events such as tag + * or layout changes, as well as send commands to control the window manager via other programs. + * + * You need to uncomment the corresponding lines in config.mk to use the -lyajl library + * when including this patch. + * This patch depends on the following additional library: + * - yajl + * + * https://github.com/mihirlad55/dwm-ipc + * https://dwm.suckless.org/patches/ipc/ + */ +#define IPC_PATCH 0 + /* Adds rule option for clients to avoid accidental termination by killclient for sticky windows. * https://dwm.suckless.org/patches/ispermanent/ */ diff --git a/util.h b/util.h index 531ab25..3059148 100644 --- a/util.h +++ b/util.h @@ -8,5 +8,11 @@ #endif #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) +#ifdef _DEBUG +#define DEBUG(...) fprintf(stderr, __VA_ARGS__) +#else +#define DEBUG(...) +#endif + void die(const char *fmt, ...); void *ecalloc(size_t nmemb, size_t size);