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(); +} +