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 @@
+
+
+
+ 1
+ 0
+
+
+
+ tag
+
+
+ tagnum
+ in
+ tagtype
+
+
+
+
+ zoom
+
+
+ setstatus
+
+
+ status
+ in
+ statustype
+
+
+
+
+
+
+ tagtype
+ ui2
+ 0
+
+
+ statustype
+ string
+ Undefined
+
+
+
+
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 @@
+
+
+
+ 1
+ 0
+
+
+ urn:schemas-upnp-org:device:Application:1
+ Dynamic Window Manager
+ 10kloc.org
+ http://www.10kloc.org
+ DWM
+ uuid:00000000-abcd-0000-abcd-000000000000
+
+
+ image/gif
+ 118
+ 119
+ 32
+ /dwm.gif
+
+
+
+
+ urn:schemas-dwm:service:dwm:1
+ urn:dwm:serviceId:dwm1
+ /dwm
+ /dwm
+ /dwm-service.xml
+
+
+
+
+
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
+#include
+#include
+#include
+#include
+
+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), "\n\n"
+ "", 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();
+}
+