Good day.

Attached to this email is a patch to add UPnP support to dwm. You will
need libupnp for compiling it. This feature is quiet useless, but dwm
is too simple and I have the sexual interference to write a mass of use-
less code once in a while. At

        http://www.r-36.net/ctrldwm-0.1.tar.gz

is the corresponding controlling client.

The usage is:

        % ctrldwm status $somestatus
        [Some seconds lag. It's SOAP dude!]
        %

This sets the status line of dwm.

Have fun guys, while using usless code!

Sincerely,

Christoph
diff -r 74739798b0b2 Makefile
--- a/Makefile	Fri Sep  1 13:31:59 2006
+++ b/Makefile	Wed Sep  6 12:06:50 2006
@@ -3,8 +3,9 @@
 
 include config.mk
 
-SRC = client.c draw.c event.c main.c tag.c util.c view.c
+SRC = client.c draw.c event.c main.c tag.c util.c view.c upnp.c
 OBJ = ${SRC:.c=.o}
+UPNP = dwm-service.xml dwm.xml
 
 all: options dwm
 
@@ -38,7 +39,7 @@
 	@echo creating dist tarball
 	@mkdir -p dwm-${VERSION}
 	@cp -R LICENSE Makefile README config.*.h config.mk \
-		dwm.1 dwm.h ${SRC} dwm-${VERSION}
+		dwm.1 dwm.h ${SRC} ${UPNP} dwm-${VERSION}
 	@tar -cf dwm-${VERSION}.tar dwm-${VERSION}
 	@gzip dwm-${VERSION}.tar
 	@rm -rf dwm-${VERSION}
@@ -52,6 +53,9 @@
 	@mkdir -p ${DESTDIR}${MANPREFIX}/man1
 	@sed 's/VERSION/${VERSION}/g' < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
 	@chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
+	@echo installing UPnP files to /var/dwm/upnp
+	@mkdir -p /var/dwm/upnp
+	@cp ${UPNP} /var/dwm/upnp
 
 uninstall:
 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
diff -r 74739798b0b2 config.mk
--- a/config.mk	Fri Sep  1 13:31:59 2006
+++ b/config.mk	Wed Sep  6 12:06:50 2006
@@ -1,5 +1,5 @@
 # dwm version
-VERSION = 1.3
+VERSION = upnp-1.3
 
 # Customize below to fit your system
 
@@ -12,7 +12,7 @@
 
 # includes and libs
 INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lupnp
 
 # flags
 CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\"
diff -r 74739798b0b2 dwm.h
--- a/dwm.h	Fri Sep  1 13:31:59 2006
+++ b/dwm.h	Wed Sep  6 12:06:50 2006
@@ -69,6 +69,7 @@
 extern const char *tags[];
 extern char stext[1024];
 extern int bx, by, bw, bh, bmw, mw, screen, sx, sy, sw, sh;
+extern int doevent, doingevent;
 extern unsigned int ntags, numlockmask;
 extern void (*handler[LASTEvent])(XEvent *);
 extern void (*arrange)(Arg *);
@@ -139,3 +140,8 @@
 extern void view(Arg *arg);
 extern void viewall(Arg *arg);
 extern void zoom(Arg *arg);
+
+/* upnp.c */
+extern void startupnp(void);
+extern void endupnp(void);
+
diff -r 74739798b0b2 main.c
--- a/main.c	Fri Sep  1 13:31:59 2006
+++ b/main.c	Wed Sep  6 12:06:50 2006
@@ -20,6 +20,7 @@
 char stext[1024];
 Bool *seltag;
 int bx, by, bw, bh, bmw, mw, screen, sx, sy, sw, sh;
+int doevent = 1, doingevent;
 unsigned int ntags, numlockmask;
 Atom wmatom[WMLast], netatom[NetLast];
 Bool running = True;
@@ -268,11 +269,19 @@
 	drawstatus();
 	scan();
 
+	/* Let's get masochist here. */
+	startupnp();
+	
 	/* main event loop, also reads status text from stdin */
 	XSync(dpy, False);
 	procevent();
 	readin = True;
 	while(running) {
+		if(!doevent) {
+			sleep(1);
+			continue;
+		}
+
 		FD_ZERO(&rd);
 		if(readin)
 			FD_SET(STDIN_FILENO, &rd);
@@ -280,6 +289,7 @@
 		r = select(xfd + 1, &rd, NULL, NULL, NULL);
 		if((r == -1) && (errno == EINTR))
 			continue;
+		doingevent = 1;
 		if(r > 0) {
 			if(readin && FD_ISSET(STDIN_FILENO, &rd)) {
 				readin = NULL != fgets(stext, sizeof(stext), stdin);
@@ -292,10 +302,13 @@
 		}
 		else if(r < 0)
 			eprint("select failed\n");
-		procevent();
+		if(doevent)
+			procevent();
+		doingevent = 0;
 	}
 	cleanup();
 	XCloseDisplay(dpy);
+	endupnp();
 
 	return 0;
 }
diff -r 74739798b0b2 dwm-service.xml
--- /dev/null	Fri Sep  1 13:31:59 2006
+++ b/dwm-service.xml	Wed Sep  6 12:06:50 2006
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<scpd xmlns="urn:schemas-upnp-org:service-1-0">
+	<specVersion>
+		<major>1</major>
+		<minor>0</minor>
+	</specVersion>
+	<actionList>
+		<action>
+			<name>tag</name>
+			<argumentList>
+				<argument>
+					<name>tagnum</name>
+					<direction>in</direction>
+					<relatedStateVariable>tagtype</relatedStateVariable>
+				</argument>
+			</argumentList>
+		</action>
+		<action>
+			<name>zoom</name>
+		</action>
+		<action>
+			<name>setstatus</name>
+			<argumentList>
+				<argument>
+					<name>status</name>
+					<direction>in</direction>
+					<relatedStateVariable>statustype</relatedStateVariable>
+				</argument>
+			</argumentList>
+		</action>
+	</actionList>
+	<serviceStateTable>
+		<stateVariable sendEvents="no">
+			<name>tagtype</name>
+			<dataType>ui2</dataType>
+			<defaultValue>0</defaultValue>
+		</stateVariable>
+		<stateVariable>
+			<name>statustype</name>
+			<dataType>string</dataType>
+			<defaultValue>Undefined</defaultValue>
+		</stateVariable>
+	</serviceStateTable>
+</scpd>
+
diff -r 74739798b0b2 dwm.xml
--- /dev/null	Fri Sep  1 13:31:59 2006
+++ b/dwm.xml	Wed Sep  6 12:06:50 2006
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<root xmlns="urn:schemas-upnp-org:device-1-0">
+	<specVersion>
+		<major>1</major>
+		<minor>0</minor>
+	</specVersion>
+	<device>
+		<deviceType>urn:schemas-upnp-org:device:Application:1</deviceType>
+		<friendlyName>Dynamic Window Manager</friendlyName>
+		<manufacturer>10kloc.org</manufacturer>
+		<manufacturerURL>http://www.10kloc.org</manufacturerURL>
+		<modelName>DWM</modelName>
+		<UDN>uuid:00000000-abcd-0000-abcd-000000000000</UDN>
+		<iconList>
+			<icon>
+				<mimetype>image/gif</mimetype>
+				<width>118</width>
+				<height>119</height>
+				<depth>32</depth>
+				<url>/dwm.gif</url>
+			</icon>
+		</iconList>
+		<serviceList>
+			<service>
+				<serviceType>urn:schemas-dwm:service:dwm:1</serviceType>
+				<serviceId>urn:dwm:serviceId:dwm1</serviceId>
+				<controlURL>/dwm</controlURL>
+				<eventSubURL>/dwm</eventSubURL>
+				<SCPDURL>/dwm-service.xml</SCPDURL>
+			</service>
+		</serviceList>
+	</device>
+</root>
+	
diff -r 74739798b0b2 upnp.c
--- /dev/null	Fri Sep  1 13:31:59 2006
+++ b/upnp.c	Wed Sep  6 12:06:50 2006
@@ -0,0 +1,260 @@
+#include "dwm.h"
+#include <stdlib.h>
+#include <upnp/ixml.h>
+#include <string.h>
+#include <upnp/upnp.h>
+#include <upnp/upnptools.h>
+
+char *dwmUDN;
+ithread_mutex_t umutex = PTHREAD_MUTEX_INITIALIZER;
+int devicehandle;
+
+char *
+getfirstdocitem(IXML_Document *doc, const char *item)
+{
+	IXML_NodeList *nodelist;
+	IXML_Node *textnode;
+	IXML_Node *tmpnode;
+	char *ret;
+
+	textnode = tmpnode = NULL;
+	ret = NULL;
+	nodelist = NULL;
+
+	nodelist = ixmlDocument_getElementsByTagName(doc, (char *)item);
+	if(nodelist) {
+		tmpnode = ixmlNodeList_item(nodelist, 0);
+		if(tmpnode) {
+			textnode = ixmlNode_getFirstChild(tmpnode);
+			if(textnode != NULL)
+				ret = strdup(ixmlNode_getNodeValue(textnode));
+		}
+	}
+	if(nodelist)
+		ixmlNodeList_free(nodelist);
+
+	return ret;
+}
+
+int
+dwmsubscribereq(struct Upnp_Subscription_Request *e)
+{
+	IXML_Document *propSet;
+
+	propSet = NULL;
+	
+	ithread_mutex_lock(&umutex);
+
+	if(strcmp(e->UDN, dwmUDN) == 0) {	
+		UpnpAddToPropertySet(&propSet, "running", "1");
+		UpnpAcceptSubscriptionExt(devicehandle, e->UDN, e->ServiceId,
+				propSet, e->Sid);
+		ixmlDocument_free(propSet);
+	}
+
+	ithread_mutex_unlock(&umutex);
+
+	return 1;
+}	
+
+struct Upnp_Action_Request *
+mkanswer(struct Upnp_Action_Request *e, int succ)
+{
+	char resultstr[513];
+
+	if(succ) {
+		snprintf(resultstr, sizeof(resultstr), "<u:%sResponse "
+			"xmlns:u=\""
+			"urn:schemas-dwm:service:dwm\">\n\n"
+			"</u:%sResponse>", e->ActionName, e->ActionName);
+		e->ErrCode = UPNP_E_SUCCESS;
+		e->ActionResult = ixmlParseBuffer(resultstr);
+	} else {
+		e->ErrCode = 402;
+		strcpy(e->ErrStr, "Invalid Args");
+		e->ActionResult = NULL;
+	}
+
+	return e;
+}	
+
+void
+waitfordwm(void)
+{
+
+	doevent = 0;
+	while(doingevent)
+		sleep(1);
+}
+
+void
+allowdwm(void)
+{
+
+	doevent = 1;
+}
+
+int
+dodwmstatus(struct Upnp_Action_Request *e)
+{
+	char *status;
+	int succ;
+
+	succ = 0;
+
+	status = getfirstdocitem(e->ActionRequest, "status");
+	if(status != NULL) {
+		strncpy(stext, status, sizeof(stext) - 1);
+		stext[sizeof(stext) - 1] = '\0';
+		waitfordwm();
+		drawstatus();
+		allowdwm();
+		succ = 1;
+	}
+
+	e = mkanswer(e, succ);
+
+	return e->ErrCode;
+}
+
+int
+dodwmtag(struct Upnp_Action_Request *e)
+{
+	char *tagnum;
+	int succ;
+	Arg arg;
+
+	succ = 0;
+	
+	tagnum = getfirstdocitem(e->ActionRequest, "tagnum");
+       	if(tagnum != NULL) {
+		arg.i = atoi(tagnum);
+		waitfordwm();
+		tag(&arg);
+		allowdwm();
+		succ = 1;
+	}
+
+	e = mkanswer(e, succ);
+
+	return e->ErrCode;
+}
+
+int
+dodwmzoom(struct Upnp_Action_Request *e)
+{
+
+	waitfordwm();
+	zoom(NULL);
+	allowdwm();
+
+	e = mkanswer(e, 1);
+
+	return e->ErrCode;
+}
+
+int
+dwmactionreq(struct Upnp_Action_Request *e)
+{
+	int result;
+
+	result = 0;
+	
+	ithread_mutex_lock(&umutex);
+
+	if(strcmp(e->DevUDN, dwmUDN) == 0) {
+		if(strcmp(e->ActionName, "tag") == 0)
+			result = dodwmtag(e);
+		else if(strcmp(e->ActionName, "zoom") == 0)
+			result = dodwmzoom(e);
+		else if(strcmp(e->ActionName, "status") == 0)
+			result = dodwmstatus(e);
+	}
+
+	ithread_mutex_unlock(&umutex);
+	
+	return result;
+}	
+
+int
+dwmupnpcallback(Upnp_EventType et, void *e, void *c)
+{
+
+	switch(et) {
+	case UPNP_EVENT_SUBSCRIPTION_REQUEST:
+		dwmsubscribereq((struct Upnp_Subscription_Request *)e);
+		break;
+	case UPNP_CONTROL_GET_VAR_REQUEST:
+		break;
+	case UPNP_CONTROL_ACTION_REQUEST:
+		dwmactionreq((struct Upnp_Action_Request *)e);
+		break;
+	default:
+		eprint("dwm: unknown event type for UPnP: %d\n", et);
+	}
+
+	return 0;
+}
+
+int
+statetableinit(char *descurl)
+{
+	IXML_Document *ixmldoc;
+	int ret;
+
+	ret = UpnpDownloadXmlDoc(descurl, &ixmldoc);
+	if(ret != UPNP_E_SUCCESS) {
+		UpnpFinish();
+		eprint("dwm: Could not parse description document.\n");
+	}
+
+	dwmUDN = getfirstdocitem(ixmldoc, "UDN");
+	ixmlDocument_free(ixmldoc);
+
+	return ret;
+}
+
+void
+startupnp(void)
+{
+	char descurl[513];
+	int ret;
+
+	ret = UpnpInit(NULL, 0);
+	if(ret != UPNP_E_SUCCESS) {
+		UpnpFinish();
+		eprint("dwm: Error in UpnpInit -- %d\n", ret);
+	}
+
+	ret = UpnpSetWebServerRootDir("/var/dwm/upnp");
+	if(ret != UPNP_E_SUCCESS) {
+		UpnpFinish();
+		eprint("dwm: Error specifying root directory -- %d\n", ret);
+	}
+
+	snprintf(descurl, 512, "http://%s:%d/%s";, UpnpGetServerIpAddress(),
+			UpnpGetServerPort(), "dwm.xml");
+	ret = UpnpRegisterRootDevice(descurl, dwmupnpcallback, &devicehandle,
+					&devicehandle);
+	if(ret != UPNP_E_SUCCESS) {
+		UpnpFinish();
+		eprint("dwm: Error registering the rootdevice: %d\n", ret);
+	}
+
+	statetableinit(descurl);
+	
+	ret = UpnpSendAdvertisement(devicehandle, 100);
+	if(ret != UPNP_E_SUCCESS) {
+		UpnpFinish();
+		eprint("dwm: Error sending advertisements: %d\n", ret);
+	}
+}
+
+void
+endupnp(void)
+{
+
+	UpnpUnRegisterRootDevice(devicehandle);
+	UpnpFinish();
+}
+

Reply via email to