[hackers] [wmii] Add witray system tray program. || Kris Maglione

From: <hg_AT_suckless.org>
Date: Thu, 27 May 2010 07:58:20 +0000 (UTC)

changeset: 2647:91080b00b924
tag: tip
user: Kris Maglione <kris_AT_suckless.org>
date: Thu May 27 03:58:02 2010 -0400
files: PKGBUILD cmd/Makefile cmd/menu/Makefile cmd/menu/dat.h cmd/menu/main.c cmd/menu/menu.c cmd/strut/Makefile cmd/strut/dat.h cmd/strut/fns.h cmd/strut/main.c cmd/strut/win.c cmd/tray/Makefile cmd/tray/client.c cmd/tray/dat.h cmd/tray/ewmh.c cmd/tray/fns.h cmd/tray/main.c cmd/tray/selection.c cmd/tray/tray.c cmd/tray/xembed.c cmd/wmii/Makefile cmd/wmii/backtrace.c cmd/wmii/bar.c cmd/wmii/client.c cmd/wmii/dat.h cmd/wmii/debug.h cmd/wmii/div.c cmd/wmii/event.c cmd/wmii/frame.c cmd/wmii/layout.c cmd/wmii/main.c cmd/wmii/mouse.c cmd/wmii/root.c cmd/wmii/xdnd.c config.mk include/debug.h include/stuff/base.h include/stuff/util.h include/stuff/x.h include/stuff/x11.h lib/libstuff/Makefile lib/libstuff/clientutil.c lib/libstuff/event/buttonpress.c lib/libstuff/event/buttonrelease.c lib/libstuff/event/clientmessage.c lib/libstuff/event/configurenotify.c lib/libstuff/event/configurerequest.c lib/libstuff/event/destroynotify.c lib/libstuff/event/enternotify.c lib/libstuff/event/event.c lib/libstuff/event/expo
se.c lib/libstuff/event/focusin.c lib/libstuff/event/focusout.c lib/libstuff/event/ixp.c lib/libstuff/event/keypress.c lib/libstuff/event/leavenotify.c lib/libstuff/event/mapnotify.c lib/libstuff/event/maprequest.c lib/libstuff/event/motionnotify.c lib/libstuff/event/propertynotify.c lib/libstuff/event/reparentnotify.c lib/libstuff/event/selection.c lib/libstuff/event/selectionclear.c lib/libstuff/event/selectionrequest.c lib/libstuff/event/unmapnotify.c lib/libstuff/util/backtrace.c lib/libstuff/x11/errors.c lib/libstuff/x11/initdisplay.c lib/libstuff/x11/insanity/gethints.c lib/libstuff/x11/insanity/sethints.c lib/libstuff/x11/properties/changeprop_textlist.c lib/libstuff/x11/sendevent.c lib/libstuff/x11/sendmessage.c lib/libstuff/x11/windows/createwindow_visual.c lib/libstuff/x11/windows/destroywindow.c lib/libstuff/x11/windows/selectinput.c lib/libstuff/x11/windows/sethandler.c lib/libstuff/xext.c man/Makefile man/wimenu.1 man/wimenu.man1 man/wistrut.1 man/wistrut.man1 man/witray.1 man/witray.man1 util/c
ompile
description:
Add witray system tray program.

diff -r 4d765bd540b8 -r 91080b00b924 PKGBUILD
--- a/PKGBUILD Wed May 26 09:20:14 2010 -0400
+++ b/PKGBUILD Thu May 27 03:58:02 2010 -0400
@@ -1,6 +1,6 @@
 
 pkgname="wmii-hg"
-pkgver=2637
+pkgver=2647
 pkgrel=1
 pkgdesc="The latest hg pull of wmii, a lightweight, dynamic window manager for X11"
 url="http://wmii.suckless.org"
@@ -16,8 +16,6 @@
 conflicts=("wmii")
 source=()
 
-test -d src || mkdir src
-ln -snf .. src/wmii
 FORCE_VER=$(hg tip --template {rev})
 #_hgroot="http://hg.suckless.org/"
 #_hgrepo="wmii"
@@ -32,7 +30,7 @@
     make "${flags[@]}" || return 1
     make "${flags[@]}" install || return 1
 
- mkdir -p $startdir/pkg/etc/X11/sessions
+ install -m644 -D ./debian/file/wmii.desktop $startdir/pkg/etc/X11/sessions/wmii.desktop
     install -m644 -D ./LICENSE $startdir/pkg/usr/share/licenses/wmii/LICENSE
 }
 
diff -r 4d765bd540b8 -r 91080b00b924 cmd/Makefile
--- a/cmd/Makefile Wed May 26 09:20:14 2010 -0400
+++ b/cmd/Makefile Thu May 27 03:58:02 2010 -0400
@@ -6,7 +6,8 @@
 
 DIRS = wmii \
         menu \
- strut
+ strut \
+ tray
 TARG = wihack \
         wmii.rc \
         wmii.sh \
diff -r 4d765bd540b8 -r 91080b00b924 cmd/menu/Makefile
--- a/cmd/menu/Makefile Wed May 26 09:20:14 2010 -0400
+++ b/cmd/menu/Makefile Thu May 27 03:58:02 2010 -0400
@@ -12,7 +12,7 @@
 TARG = wimenu
 HFILES= dat.h fns.h
 
-PACKAGES += $(X11PACKAGES) xext xrandr xrender xinerama
+PACKAGES += $(X11PACKAGES)
 
 LIBS += -lm $(LIBS9) $(LIBIXP)
 CFLAGS += -DIXP_NEEDAPI=86
diff -r 4d765bd540b8 -r 91080b00b924 cmd/menu/dat.h
--- a/cmd/menu/dat.h Wed May 26 09:20:14 2010 -0400
+++ b/cmd/menu/dat.h Thu May 27 03:58:02 2010 -0400
@@ -7,9 +7,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <ixp.h>
 #include <stuff/x.h>
 #include <stuff/util.h>
-#include <ixp.h>
 
 #define BLOCK(x) do { x; }while(0)
 
diff -r 4d765bd540b8 -r 91080b00b924 cmd/menu/main.c
--- a/cmd/menu/main.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/menu/main.c Thu May 27 03:58:02 2010 -0400
@@ -171,20 +171,6 @@
                 update_input();
 }
 
-static void
-end(IxpConn *c) {
-
- USED(c);
- srv.running = 0;
-}
-
-static void
-preselect(IxpServer *s) {
-
- USED(s);
- event_check();
-}
-
 enum { PointerScreen = -1 };
 
 void
@@ -224,7 +210,6 @@
 
         quotefmtinstall();
         fmtinstall('r', errfmt);
- address = getenv("WMII_ADDRESS");
         screen_hint = PointerScreen;
 
         find = strstr;
@@ -283,17 +268,18 @@
 
         client_init(address);
 
- srv.preselect = preselect;
- ixp_listen(&srv, ConnectionNumber(display), nil, (void (*)(IxpConn*))preselect, end);
+ srv.preselect = event_preselect;
+ ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, event_fdclosed);
 
         ontop = !strcmp(readctl("bar on "), "top");
         loadcolor(&cnorm, readctl("normcolors "));
         loadcolor(&csel, readctl("focuscolors "));
         font = loadfont(readctl("font "));
- sscanf(readctl("fontpad "), "%d %d %d %d", &font->pad.min.x, &font->pad.max.x,
- &font->pad.min.x, &font->pad.max.y);
         if(!font)
                 fatal("Can't load font %q", readctl("font "));
+ sscanf(readctl("fontpad "), "%d %d %d %d",
+ &font->pad.min.x, &font->pad.max.x,
+ &font->pad.min.x, &font->pad.max.y);
 
         cmplbuf = Bfdopen(0, OREAD);
         items = populate_list(cmplbuf, false);
diff -r 4d765bd540b8 -r 91080b00b924 cmd/menu/menu.c
--- a/cmd/menu/menu.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/menu/menu.c Thu May 27 03:58:02 2010 -0400
@@ -255,7 +255,7 @@
 }
 
 static void
-kdown_event(Window *w, XKeyEvent *e) {
+kdown_event(Window *w, void *aux, XKeyEvent *e) {
         char **action, **p;
         char *key;
         char buf[32];
@@ -331,7 +331,7 @@
 }
 
 static void
-expose_event(Window *w, XExposeEvent *e) {
+expose_event(Window *w, void *aux, XExposeEvent *e) {
 
         USED(w);
         menu_draw();
diff -r 4d765bd540b8 -r 91080b00b924 cmd/strut/Makefile
--- a/cmd/strut/Makefile Wed May 26 09:20:14 2010 -0400
+++ b/cmd/strut/Makefile Thu May 27 03:58:02 2010 -0400
@@ -7,9 +7,8 @@
 TARG = wistrut
 HFILES= dat.h fns.h
 
-PACKAGES += $(X11PACKAGES) xext xrandr xinerama
+PACKAGES += $(X11PACKAGES)
 
-LIB = $(LIBIXP)
 LIBS += -lm $(LIBS9)
 CFLAGS += -DIXP_NEEDAPI=86
 OBJ = main \
diff -r 4d765bd540b8 -r 91080b00b924 cmd/strut/dat.h
--- a/cmd/strut/dat.h Wed May 26 09:20:14 2010 -0400
+++ b/cmd/strut/dat.h Thu May 27 03:58:02 2010 -0400
@@ -5,7 +5,6 @@
 #include <unistd.h>
 #include <stuff/x.h>
 #include <stuff/util.h>
-#include <ixp.h>
 
 #ifndef EXTERN
 # define EXTERN extern
diff -r 4d765bd540b8 -r 91080b00b924 cmd/strut/fns.h
--- a/cmd/strut/fns.h Wed May 26 09:20:14 2010 -0400
+++ b/cmd/strut/fns.h Thu May 27 03:58:02 2010 -0400
@@ -1,15 +1,6 @@
-
-void debug(int, const char*, ...);
-void dispatch_event(XEvent*);
-uint flushevents(long, bool);
-uint flushenterevents(void);
-void xevent_loop(void);
-void xtime_kludge(void);
 
 void restrut(Window*);
 
 void ewmh_getstrut(Window*, Rectangle[4]);
 void ewmh_setstrut(Window*, Rectangle[4]);
 
-void printevent(XEvent *e);
-
diff -r 4d765bd540b8 -r 91080b00b924 cmd/strut/main.c
--- a/cmd/strut/main.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/strut/main.c Thu May 27 03:58:02 2010 -0400
@@ -21,11 +21,6 @@
         fatal("usage: %s [-HV] <window|class>...\n", argv0);
 }
 
-static int
-errfmt(Fmt *f) {
- return fmtstrcpy(f, ixp_errbuf());
-}
-
 static void
 search_wins(char *pattern) {
         ulong *wins;
@@ -135,7 +130,6 @@
         ulong win;
         char *s;
 
- fmtinstall('r', errfmt);
         fmtinstall('E', fmtevent);
 
         ARGBEGIN{
diff -r 4d765bd540b8 -r 91080b00b924 cmd/strut/win.c
--- a/cmd/strut/win.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/strut/win.c Thu May 27 03:58:02 2010 -0400
@@ -80,22 +80,23 @@
 }
 
 static void
-config(Window *frame, XConfigureEvent *ev) {
+config_event(Window *frame, void *aux, XConfigureEvent *ev) {
 
- frame->r = rectaddpt(Rect(0, 0, ev->width, ev->height),
- Pt(ev->x+ev->border_width, ev->y+ev->border_width));
+ frame->r = rectaddpt(Rect(ev->x, ev->y, ev->width, ev->height),
+ Pt(ev->border_width, ev->border_width));
         restrut(frame);
 }
 
 static void
-destroy(Window *w, XDestroyWindowEvent *ev) {
- USED(w, ev);
+destroy_event(Window *w, void *aux, XDestroyWindowEvent *ev) {
+
+ USED(ev);
         sethandler(w, nil);
         event_looprunning = windowmap.nmemb > 0;
 }
 
 Handlers handlers = {
- .config = config,
- .destroy = destroy,
+ .config = config_event,
+ .destroy = destroy_event,
 };
 
diff -r 4d765bd540b8 -r 91080b00b924 cmd/tray/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tray/Makefile Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,22 @@
+ROOT= ../..
+include $(ROOT)/mk/hdr.mk
+include $(ROOT)/mk/wmii.mk
+
+main.c: $(ROOT)/mk/wmii.mk
+
+TARG = witray
+HFILES= dat.h fns.h
+
+PACKAGES += $(X11PACKAGES)
+
+LIBS += -lm $(LIBS9) $(LIBIXP)
+OBJ = \
+ client \
+ ewmh \
+ main \
+ selection \
+ tray \
+ xembed
+
+include $(ROOT)/mk/one.mk
+
diff -r 4d765bd540b8 -r 91080b00b924 cmd/tray/client.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tray/client.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,190 @@
+/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "dat.h"
+#include "fns.h"
+#include <string.h>
+
+static Handlers handlers;
+
+static void client_cleanup(XEmbed*);
+
+void
+client_manage(XWindow w) {
+ Client **cp;
+ Client *c;
+ WinAttr wa;
+ int size;
+
+ c = emallocz(sizeof *c);
+ c->w.type = WWindow;
+ c->w.xid = w;
+ c->w.aux = c;
+
+ Dprint("client_manage(%W)\n", &c->w);
+
+ traperrors(true);
+ XAddToSaveSet(display, w);
+ c->xembed = xembed_swallow(tray.win, &c->w, client_cleanup);
+ if(traperrors(false)) {
+ fprint(1, "client_manage(0x%ulx): Caught error.\n", w);
+ if(c->xembed)
+ xembed_disown(c->xembed);
+ return;
+ }
+
+ wa.background_pixel = tray.selcolors.bg.pixel;
+ size = max(tray.iconsize / 4, 4);
+
+ c->indicator = createwindow(tray.win, Rect(0, 0, size, size), scr.depth,
+ InputOutput, &wa, CWBackPixel);
+ setborder(c->indicator, 1, tray.selcolors.border);
+
+ sethandler(&c->w, &handlers);
+
+ for(cp=&tray.clients; *cp; cp=&(*cp)->next)
+ ;
+ *cp = c;
+
+ tray_update();
+}
+
+void
+client_disown(Client *c) {
+
+ Dprint("client_disown(%W)\n", &c->w);
+ xembed_disown(c->xembed);
+}
+
+static void
+client_cleanup(XEmbed *e) {
+ Client **cp;
+ Client *c;
+
+ c = e->w->aux;
+ destroywindow(c->indicator);
+
+ for(cp=&tray.clients; *cp; cp=&(*cp)->next)
+ if(*cp == c) {
+ *cp = c->next;
+ break;
+ }
+ free(c);
+ tray_update();
+}
+
+Client*
+client_find(Window *w) {
+ Client *c;
+
+ for(c=tray.clients; c; c=c->next)
+ if(&c->w == w)
+ return c;
+ return nil;
+}
+
+void
+message_cancel(Client *c, long id) {
+ Message *m, **mp;
+
+ for(mp=&c->message; (m = *mp) && m->id != id; mp=&m->next)
+ ;
+
+ if(m) {
+ *mp = m->next;
+ free(m->msg.data);
+ free(m);
+ }
+}
+
+bool
+client_hasmessage(Client *c) {
+ Message *m;
+
+ for(m=c->message; m; m=m->next)
+ if(m->msg.pos == m->msg.end)
+ return true;
+ return false;
+}
+
+void
+client_opcode(Client *c, long message, long l1, long l2, long l3) {
+ Message *m, **mp;
+
+ Dprint("client_opcode(%p, %s, %lx, %lx, %lx)\n",
+ c,
+ message == TrayRequestDock ? "TrayRequestDock" :
+ message == TrayBeginMessage ? "TrayBeginMessage" :
+ message == TrayCancelMessage ? "TrayCancelMessage" :
+ sxprint("%lx", message),
+ l1, l2, l3);
+
+ if(message == TrayBeginMessage)
+ message_cancel(c, l1);
+ else if(message == TrayBeginMessage) {
+ if(l2 > 5 * 1024) /* Don't bother with absurdly large messages. */
+ return;
+
+ m = emallocz(sizeof *m);
+ m->timeout = l1;
+ m->msg = ixp_message(emallocz(l2), l2, MsgPack);
+ m->id = l3;
+
+ /* Add the message to the end of the queue. */
+ for(mp=&c->message; *mp; mp=&(*mp)->next)
+ ;
+ *mp = m;
+ }
+}
+
+void
+client_message(Client *c, long type, int format, ClientMessageData* data) {
+ Message *m;
+
+ if(format == 8 && type == NET("SYSTEM_TRAY_MESSAGE_DATA")) {
+ /* Append the data to the last incomplete message. */
+ for(m = c->message; m && m->msg.pos >= m->msg.end; m++)
+ ;
+ if(m) {
+ memcpy(m->msg.pos, data, min(20, m->msg.end - m->msg.pos));
+ m->msg.pos += min(20, m->msg.end - m->msg.pos);
+ }
+ }
+}
+
+static void
+config_event(Window *w, void *aux, XConfigureEvent *e) {
+ Client *c;
+
+ c = aux;
+ if(false)
+ movewin(c->indicator, addpt(w->r.min, Pt(1, 1)));
+}
+
+static void
+configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) {
+
+ Dprint("configreq_event(%W)\n", w);
+ /* This seems, sadly, to be necessary. */
+ tray_update();
+}
+
+static void
+map_event(Window *w, void *aux, XMapEvent *e) {
+
+ tray_update();
+}
+
+static void
+unmap_event(Window *w, void *aux, XUnmapEvent *e) {
+
+ tray_update();
+}
+
+static Handlers handlers = {
+ .config = config_event,
+ .configreq = configreq_event,
+ .map = map_event,
+ .unmap = unmap_event,
+};
+
diff -r 4d765bd540b8 -r 91080b00b924 cmd/tray/dat.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tray/dat.h Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,82 @@
+#include <fmt.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ixp.h>
+#include <stuff/x.h>
+#include <stuff/util.h>
+
+#ifndef EXTERN
+# define EXTERN extern
+#endif
+
+enum { OAuto, OHorizontal, OVertical };
+
+enum XEmbedFlags {
+ XEmbedMapped = (1 << 0),
+};
+
+enum TrayOpcodes {
+ TrayRequestDock,
+ TrayBeginMessage,
+ TrayCancelMessage,
+};
+
+typedef struct Client Client;
+typedef struct Message Message;
+typedef struct Selection Selection;
+typedef struct XEmbed XEmbed;
+
+struct Client {
+ Client* next;
+ XEmbed* xembed;
+ Window w;
+ Window* indicator;
+ Message* message;
+};
+
+struct Message {
+ Message* next;
+ long id;
+ ulong timeout;
+ IxpMsg msg;
+};
+
+struct Selection {
+ Window* owner;
+ char* selection;
+ ulong time_start;
+ ulong time_end;
+ void (*cleanup)(Selection*);
+ void (*message)(Selection*, XClientMessageEvent*);
+ void (*request)(Selection*, XSelectionRequestEvent*);
+};
+
+struct XEmbed {
+ Window* w;
+ Window* owner;
+ void (*cleanup)(XEmbed*);
+ int version;
+ ulong flags;
+};
+
+EXTERN IxpServer srv;
+EXTERN char** program_args;
+EXTERN int debug;
+
+EXTERN struct {
+ Window* win;
+ Image* pixmap;
+ Client* clients;
+ Selection* selection;
+ char* tags;
+ ulong iconsize;
+ ulong padding;
+ long edge;
+ int orientation;
+ Font* font;
+ CTuple selcolors;
+ CTuple normcolors;
+} tray;
+
diff -r 4d765bd540b8 -r 91080b00b924 cmd/tray/ewmh.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tray/ewmh.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,45 @@
+/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "dat.h"
+#include <limits.h>
+#include <string.h>
+#include "fns.h"
+
+enum {
+ Left, Right, Top, Bottom,
+ LeftMin, LeftMax,
+ RightMin, RightMax,
+ TopMin, TopMax,
+ BottomMin, BottomMax,
+ Last
+};
+
+void
+ewmh_setstrut(Window *w, Rectangle struts[4]) {
+ long strut[Last];
+ int i;
+
+ strut[LeftMin] = struts[Left].min.y;
+ strut[Left] = struts[Left].max.x;
+ strut[LeftMax] = struts[Left].max.y;
+
+ strut[RightMin] = struts[Right].min.y;
+ strut[Right] = -struts[Right].min.x;
+ strut[RightMax] = struts[Right].max.y;
+
+ strut[TopMin] = struts[Top].min.x;
+ strut[Top] = struts[Top].max.y;
+ strut[TopMax] = struts[Top].max.x;
+
+ strut[BottomMin] = struts[Bottom].min.x;
+ strut[Bottom] = -struts[Bottom].min.y;
+ strut[BottomMax] = struts[Bottom].max.x;
+
+ for(i=0; i<Last; i++)
+ if(strut[i] < 0)
+ strut[i] = 0;
+
+ changeprop_long(w, Net("WM_STRUT_PARTIAL"), "CARDINAL", strut, nelem(strut));
+}
+
diff -r 4d765bd540b8 -r 91080b00b924 cmd/tray/fns.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tray/fns.h Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,34 @@
+
+#define Net(x) ("_NET_" x)
+#define Action(x) ("_NET_WM_ACTION_" x)
+#define State(x) ("_NET_WM_STATE_" x)
+#define Type(x) ("_NET_WM_WINDOW_TYPE_" x)
+#define NET(x) xatom(Net(x))
+#define ACTION(x) xatom(Action(x))
+#define STATE(x) xatom(State(x))
+#define TYPE(x) xatom(Type(x))
+
+void cleanup(Selection*);
+Client* client_find(Window*);
+bool client_hasmessage(Client*);
+void client_disown(Client*);
+void client_manage(XWindow);
+void client_message(Client*, long, int, ClientMessageData*);
+void client_opcode(Client*, long, long, long, long);
+void ewmh_setstrut(Window*, Rectangle[4]);
+int main(int, char*[]);
+void message(Selection*, XClientMessageEvent*);
+void message_cancel(Client*, long);
+void restrut(Window*, int);
+Selection* selection_create(char*, ulong, void (*)(Selection*, XSelectionRequestEvent*), void (*)(Selection*));
+Selection* selection_manage(char*, ulong, void (*)(Selection*, XClientMessageEvent*), void (*)(Selection*));
+void selection_release(Selection*);
+void tray_init(void);
+void tray_resize(Rectangle);
+void tray_update(void);
+void xembed_disown(XEmbed*);
+XEmbed* xembed_swallow(Window*, Window*, void (*)(XEmbed*));
+
+#define Debug if(debug)
+#define Dprint Debug print
+
diff -r 4d765bd540b8 -r 91080b00b924 cmd/tray/main.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tray/main.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,216 @@
+/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#define EXTERN
+#include "dat.h"
+#include <X11/Xproto.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <stuff/clientutil.h>
+#include <sys/signal.h>
+#include "fns.h"
+
+static const char version[] = "witray-"VERSION", "COPYRIGHT"\n";
+
+static int exitsignal;
+static struct sigaction sa;
+
+static void
+usage(void) {
+ fprint(2, "usage: %s [-a <address>] [-NESW] [-HV] [-p <padding>] [-s <iconsize>] [-t tags]\n"
+ " %s -v\n", argv0, argv0);
+ exit(1);
+}
+
+static int
+errfmt(Fmt *f) {
+ return fmtstrcpy(f, ixp_errbuf());
+}
+
+static void
+cleanup_handler(int signal) {
+ sa.sa_handler = SIG_DFL;
+ sigaction(signal, &sa, nil);
+
+ srv.running = false;
+
+ switch(signal) {
+ case SIGTERM:
+ sa.sa_handler = cleanup_handler;
+ sigaction(SIGALRM, &sa, nil);
+ alarm(1);
+ default:
+ exitsignal = signal;
+ break;
+ case SIGALRM:
+ raise(SIGTERM);
+ case SIGINT:
+ break;
+ }
+}
+
+static void
+init_traps(void) {
+
+ sa.sa_flags = 0;
+ sa.sa_handler = cleanup_handler;
+ sigaction(SIGINT, &sa, nil);
+ sigaction(SIGTERM, &sa, nil);
+ sigaction(SIGQUIT, &sa, nil);
+ sigaction(SIGHUP, &sa, nil);
+ sigaction(SIGUSR1, &sa, nil);
+ sigaction(SIGUSR2, &sa, nil);
+}
+
+void
+cleanup(Selection *s) {
+ USED(s);
+
+ while(tray.clients)
+ client_disown(tray.clients);
+}
+
+void
+message(Selection *s, XClientMessageEvent *ev) {
+ Window *w;
+ Client *c;
+
+ USED(s);
+
+ Dprint("message(%s) 0x%lx\n", XGetAtomName(display, ev->message_type), ev->window);
+ Dprint("\t0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx\n",
+ ev->data.l[0], ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]);
+
+ w = findwin(ev->window);
+ if(w == nil)
+ return;
+
+ if(w == tray.selection->owner) {
+ if(ev->message_type == NET("SYSTEM_TRAY_OPCODE") && ev->format == 32)
+ if(ev->data.l[1] == TrayRequestDock)
+ client_manage(ev->data.l[2]);
+ return;
+ }
+
+ if((c = client_find(w))) {
+ if(ev->message_type == NET("SYSTEM_TRAY_OPCODE") && ev->format == 32)
+ client_opcode(w->aux, ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]);
+ else
+ client_message(w->aux, ev->message_type, ev->format, (ClientMessageData*)&ev->data);
+ return;
+ }
+}
+
+ErrorCode ignored_xerrors[] = {
+ { 0, BadWindow },
+ { X_GetAtomName, BadAtom },
+};
+
+int
+main(int argc, char *argv[]) {
+ static char* address;
+
+ program_args = argv;
+
+ setlocale(LC_CTYPE, "");
+
+ fmtinstall('r', errfmt);
+ fmtinstall('E', fmtevent);
+
+ tray.orientation = OHorizontal;
+ tray.tags = "/./";
+ tray.padding = 1;
+
+ ARGBEGIN{
+ case 'N':
+ tray.edge = (tray.edge & ~South) | North;
+ break;
+ case 'S':
+ tray.edge = (tray.edge & ~North) | South;
+ break;
+ case 'E':
+ tray.edge = (tray.edge & ~West) | East;
+ break;
+ case 'W':
+ tray.edge = (tray.edge & ~East) | West;
+ break;
+ case 'H':
+ tray.orientation = OHorizontal;
+ break;
+ case 'V':
+ tray.orientation = OVertical;
+ break;
+ case 'p':
+ if(!getulong(EARGF(usage()), &tray.padding))
+ usage();
+ tray.padding = max(1, min(10, (int)tray.padding));
+ break;
+ case 's':
+ if(!getulong(EARGF(usage()), &tray.iconsize))
+ usage();
+ tray.iconsize = max(1, (int)tray.iconsize);
+ break;
+ case 't':
+ tray.tags = EARGF(usage());
+ break;
+ case 'a':
+ address = EARGF(usage());
+ break;
+ case 'D':
+ debug++;
+ break;
+ case 'v':
+ print("%s", version);
+ return 0;
+ default:
+ usage();
+ }ARGEND;
+
+ if(argc)
+ usage();
+
+ init_traps();
+ initdisplay();
+
+ srv.preselect = event_preselect;
+ ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, event_fdclosed);
+
+ event_updatextime();
+ tray.selection = selection_manage(sxprint(Net("SYSTEM_TRAY_S%d"), scr.screen),
+ event_xtime, message, cleanup);
+ if(tray.selection == nil)
+ fatal("Another system tray is already running.");
+
+ xext_init();
+ tray_init();
+
+ client_init(nil);
+
+ if(tray.edge == 0)
+ tray.edge = West | (!strcmp(readctl("bar on "), "top") ? North : South);
+
+ loadcolor(&tray.normcolors, readctl("normcolors "));
+ loadcolor(&tray.selcolors, readctl("focuscolors "));
+ tray.font = loadfont(readctl("font "));
+ if(!tray.font)
+ fatal("Can't load font %q", readctl("font "));
+ sscanf(readctl("fontpad "), "%d %d %d %d",
+ &tray.font->pad.min.x, &tray.font->pad.max.x,
+ &tray.font->pad.min.x, &tray.font->pad.max.y);
+
+ if(tray.iconsize == 0) /* Default to wmii's bar size. */
+ tray.iconsize = labelh(tray.font) - 2 * tray.padding;
+
+ srv.running = true;
+ ixp_serverloop(&srv);
+
+ selection_release(tray.selection);
+
+ XCloseDisplay(display);
+
+ if(exitsignal)
+ raise(exitsignal);
+ return 0;
+}
+
diff -r 4d765bd540b8 -r 91080b00b924 cmd/tray/selection.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tray/selection.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,144 @@
+/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "dat.h"
+#include "fns.h"
+
+static Handlers selection_handlers;
+
+Selection*
+selection_create(char *selection, ulong time,
+ void (*request)(Selection*, XSelectionRequestEvent*),
+ void (*cleanup)(Selection*)) {
+ Selection *s;
+
+ if(time == 0)
+ time = event_xtime;
+
+ s = emallocz(sizeof *s);
+ s->owner = createwindow(&scr.root, Rect(0, 0, 1, 1), 0,
+ InputOnly, nil, 0);
+ s->owner->aux = s;
+ s->request = request;
+ s->cleanup = cleanup;
+ s->time_start = time;
+
+ sethandler(s->owner, &selection_handlers);
+
+ XSetSelectionOwner(display, xatom(selection), s->owner->xid, time);
+
+ /*
+ * There is a race here that ICCCM doesn't mention. It's
+ * possible that we've gained and lost the selection in this
+ * time, and a client's sent us a selection request. We're
+ * required to reply to it, but since we're destroying the
+ * window, we'll never hear about it. Since ICCCM doesn't
+ * mention it, we assume that other clients behave likewise,
+ * and therefore clients must be prepared to deal with such
+ * behavior regardless.
+ */
+ if(XGetSelectionOwner(display, xatom(selection)) != s->owner->xid) {
+ destroywindow(s->owner);
+ free(s);
+ return nil;
+ }
+
+ s->selection = estrdup(selection);
+ return s;
+}
+
+#include <X11/Xlib-xcb.h>
+#include <xcb/xproto.h>
+
+Selection*
+selection_manage(char *selection, ulong time,
+ void (*message)(Selection*, XClientMessageEvent*),
+ void (*cleanup)(Selection*)) {
+ Selection *s;
+
+ if(XGetSelectionOwner(display, xatom(selection)) != None)
+ return nil;
+
+ s = selection_create(selection, time, nil, cleanup);
+ if(s) {
+ s->message = message;
+ clientmessage(&scr.root, "MANAGER", SubstructureNotifyMask|StructureNotifyMask, 32,
+ (ClientMessageData){ .l = {time, xatom(selection), s->owner->xid} });
+ }
+
+ return s;
+}
+
+void
+selection_release(Selection *s) {
+ if(!s->time_end)
+ XSetSelectionOwner(display, xatom(s->selection), None, s->time_start);
+ destroywindow(s->owner);
+ if(s->cleanup)
+ s->cleanup(s);
+ free(s->selection);
+ free(s);
+}
+
+static void
+selection_notify(Selection *s, XSelectionRequestEvent *ev, bool success) {
+ XSelectionEvent notify;
+
+ notify.type = SelectionNotify;
+ notify.requestor = ev->requestor;
+ notify.selection = ev->selection;
+ notify.target = ev->target;
+ notify.property = success ? ev->property : None;
+ notify.time = ev->time;
+
+ sendevent(window(ev->requestor), false, 0L, &notify);
+}
+
+static void
+message_event(Window *w, void *aux, XClientMessageEvent *ev) {
+ Selection *s;
+
+ s = aux;
+ if(s->message)
+ s->message(s, ev);
+}
+
+static void
+selectionclear_event(Window *w, void *aux, XSelectionClearEvent *ev) {
+ Selection *s;
+
+ USED(w, ev);
+ s = aux;
+ s->time_end = ev->time;
+ selection_release(s);
+}
+
+static void
+selectionrequest_event(Window *w, void *aux, XSelectionRequestEvent *ev) {
+ Selection *s;
+
+ s = aux;
+ if(ev->property == None)
+ ev->property = ev->target; /* Per ICCCM §2.2. */
+
+ if(ev->target == xatom("TIMESTAMP")) {
+ /* Per ICCCM §2.6.2. */
+ changeprop_ulong(window(ev->requestor),
+ XGetAtomName(display, ev->property), "TIMESTAMP",
+ &s->time_start, 1);
+ selection_notify(s, ev, true);
+ return;
+ }
+
+ if(s->request)
+ s->request(s, ev);
+ else
+ selection_notify(s, ev, false);
+}
+
+static Handlers selection_handlers = {
+ .message = message_event,
+ .selectionclear = selectionclear_event,
+ .selectionrequest = selectionrequest_event,
+};
+
diff -r 4d765bd540b8 -r 91080b00b924 cmd/tray/tray.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tray/tray.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,257 @@
+/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "dat.h"
+#include <string.h>
+#include "fns.h"
+
+static Handlers handlers;
+
+void
+restrut(Window *w, int orientation) {
+ enum { Left, Right, Top, Bottom };
+ Rectangle strut[4];
+ Rectangle r;
+
+ r = w->r;
+ memset(strut, 0, sizeof strut);
+ if(Dx(r) < Dx(scr.rect)/2 && orientation != OHorizontal) {
+ if(r.min.x <= scr.rect.min.x) {
+ strut[Left] = r;
+ strut[Left].min.x = 0;
+ strut[Left].max.x -= scr.rect.min.x;
+ }
+ if(r.max.x >= scr.rect.max.x) {
+ strut[Right] = r;
+ strut[Right].min.x -= scr.rect.max.x;
+ strut[Right].max.x = 0;
+ }
+ }
+ if(Dy(r) < Dy(scr.rect)/2 && orientation != OVertical) {
+ if(r.min.y <= scr.rect.min.y) {
+ strut[Top] = r;
+ strut[Top].min.y = 0;
+ strut[Top].max.y -= scr.rect.min.y;
+ }
+ if(r.max.y >= scr.rect.max.y) {
+ strut[Bottom] = r;
+ strut[Bottom].min.y -= scr.rect.max.y;
+ strut[Bottom].max.y = 0;
+ }
+ }
+
+#if 0
+#define pstrut(name) \
+ if(!eqrect(strut[name], ZR)) \
+ fprint(2, "strut["#name"] = %R\n", strut[name])
+ pstrut(Left);
+ pstrut(Right);
+ pstrut(Top);
+ pstrut(Bottom);
+#endif
+
+ ewmh_setstrut(w, strut);
+}
+
+void
+tray_init(void) {
+ WinAttr wa;
+ XWMHints hints = { 0, };
+
+ wa.background_pixmap = None;
+ wa.bit_gravity = NorthEastGravity;
+ wa.border_pixel = 0;
+ wa.event_mask = ExposureMask
+ | ButtonPressMask
+ | ButtonReleaseMask
+ | StructureNotifyMask
+ | SubstructureNotifyMask
+ /* Disallow clients reconfiguring themselves. */
+ | SubstructureRedirectMask;
+ if(true)
+ tray.win = createwindow(&scr.root, Rect(0, 0, 1, 1), scr.depth, InputOutput,
+ &wa, CWBackPixmap
+ | CWBitGravity
+ | CWEventMask);
+ else {
+ wa.colormap = XCreateColormap(display, scr.root.xid, scr.visual32, AllocNone);
+ tray.win = createwindow_visual(&scr.root, Rect(0, 0, 1, 1), 32, scr.visual32, InputOutput,
+ &wa, CWBackPixmap
+ | CWBorderPixel
+ | CWColormap
+ | CWBitGravity
+ | CWEventMask);
+ XFreeColormap(display, wa.colormap);
+ }
+ sethandler(tray.win, &handlers);
+
+ changeprop_string(tray.win, "_WMII_TAGS", tray.tags);
+
+ changeprop_ulong(tray.selection->owner, Net("SYSTEM_TRAY_VISUAL"), "VISUALID",
+ &scr.visual->visualid, 1);
+ changeprop_long(tray.win, Net("WM_WINDOW_TYPE"), "ATOM",
+ (long[1]){ TYPE("DOCK") }, 1);
+
+ changeprop_string(tray.win, Net("WM_NAME"), "witray");
+ changeprop_textlist(tray.win, "WM_NAME", "STRING",
+ (char*[2]){ "witray", nil });
+ changeprop_textlist(tray.win, "WM_CLASS", "STRING",
+ (char*[3]){ "witray", "witray", nil });
+ changeprop_textlist(tray.win, "WM_COMMAND", "STRING", program_args);
+
+ hints.flags = InputHint;
+ hints.input = false;
+ XSetWMHints(display, tray.win->xid, &hints);
+ tray_resize(tray.win->r);
+}
+
+static void
+tray_draw(Rectangle r) {
+ int borderwidth;
+
+ if(!tray.pixmap)
+ return;
+
+ borderwidth = 1;
+
+ r = rectsetorigin(r, ZP);
+ border(tray.pixmap, r, borderwidth, tray.selcolors.border);
+ r = insetrect(r, borderwidth);
+ fill(tray.pixmap, r, tray.selcolors.bg);
+ XClearWindow(display, tray.win->xid);
+}
+
+void
+tray_resize(Rectangle r) {
+ WinHints hints;
+ Image *oldimage;
+ WinAttr wa;
+
+ hints = ZWinHints;
+ hints.position = true;
+ hints.min = hints.max = Pt(Dx(r), Dy(r));
+ hints.grav = Pt(tray.edge & East ? 0 :
+ tray.edge & West ? 2 : 1,
+ tray.edge & North ? 0 :
+ tray.edge & South ? 2 : 1);
+ /* Not necessary, since we specify fixed size, but... */
+ // hints.base = Pt(2, 2);
+ // hints.inc = Pt(tray.iconsize, tray.iconsize);
+ sethints(tray.win, &hints);
+
+ if(!eqrect(tray.win->r, r)) {
+ oldimage = tray.pixmap;
+
+ tray.pixmap = allocimage(Dx(r), Dy(r), tray.win->depth);
+ tray_draw(r);
+ wa.background_pixmap = tray.pixmap->xid;
+ setwinattr(tray.win, &wa, CWBackPixmap);
+
+ freeimage(oldimage);
+ }
+
+ reshapewin(tray.win, r);
+ restrut(tray.win, tray.orientation);
+
+}
+
+void
+tray_update(void) {
+ Rectangle r;
+ Point p, offset, padding;
+ Client *c;
+
+ r = Rect(0, 0, tray.iconsize, tray.iconsize);
+ padding = Pt(tray.padding, tray.padding);
+ offset = padding;
+ Dprint("tray_update()\n");
+ for(c=tray.clients; c; c=c->next) {
+ if(c->w.mapped) {
+ reshapewin(&c->w, rectaddpt(r, offset));
+ /* This seems, sadly, to be necessary. */
+ sendevent(&c->w, false, StructureNotifyMask, &(XEvent){
+ .xconfigure = {
+ .type = ConfigureNotify,
+ .event = c->w.xid,
+ .window = c->w.xid,
+ .above = None,
+ .x = c->w.r.min.x,
+ .y = c->w.r.min.y,
+ .width = Dx(c->w.r),
+ .height = Dy(c->w.r),
+ .border_width = 0,
+ }
+ });
+
+ movewin(c->indicator, addpt(offset, Pt(2, 2)));
+ if(tray.orientation == OHorizontal)
+ offset.x += tray.iconsize + tray.padding;
+ else
+ offset.y += tray.iconsize + tray.padding;
+ }
+ if(c->w.mapped && client_hasmessage(c))
+ mapwin(c->indicator);
+ else
+ unmapwin(c->indicator);
+ }
+
+ if(eqpt(offset, padding))
+ unmapwin(tray.win);
+ else {
+ if(tray.orientation == OHorizontal)
+ offset.y += tray.iconsize + tray.padding;
+ else
+ offset.x += tray.iconsize + tray.padding;
+
+ r = Rpt(ZP, offset);
+ p = subpt(scr.rect.max, r.max);
+ if(tray.edge & East)
+ p.x = 0;
+ if(tray.edge & North)
+ p.y = 0;
+ tray_resize(rectaddpt(r, p));
+ mapwin(tray.win);
+ }
+
+ tray_draw(tray.win->r);
+}
+
+static void
+config_event(Window *w, void *aux, XConfigureEvent *ev) {
+
+ USED(aux);
+ if(ev->send_event) {
+ /*
+ * Per ICCCM §4.2.3, the window manager sends
+ * synthetic configure events in the root coordinate
+ * space when it changes the window configuration.
+ * This code assumes wmii's generous behavior of
+ * supplying all relevant members in every configure
+ * notify event.
+ */
+ w->r = rectaddpt(rectsetorigin(Rect(0, 0, ev->width, ev->height),
+ Pt(ev->x, ev->y)),
+ Pt(ev->border_width, ev->border_width));
+ restrut(w, tray.orientation);
+ }
+}
+
+static void
+expose_event(Window *w, void *aux, XExposeEvent *ev) {
+
+ USED(w, aux, ev);
+ tray_draw(tray.win->r);
+}
+
+static void
+message_event(Window *w, void *aux, XClientMessageEvent *ev) {
+
+ Dprint("tray_message: %s\n", XGetAtomName(display, ev->message_type));
+}
+
+static Handlers handlers = {
+ .message = message_event,
+ .config = config_event,
+ .expose = expose_event,
+};
+
diff -r 4d765bd540b8 -r 91080b00b924 cmd/tray/xembed.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tray/xembed.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,128 @@
+/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "dat.h"
+#include "fns.h"
+
+#define DEAD ~0UL
+
+enum { XEmbedVersion = 0 };
+
+enum XEmbedMessage {
+ XEmbedEmbeddedNotify,
+ XEmbedWindowActivate,
+ XEmbedWindowDeactivate,
+ XEmbedRequestFocus,
+ XEmbedFocusIn,
+ XEmbedFocusOut,
+ XEmbedFocusNext,
+ XEmbedFocusPrev,
+ XEmbedModalityOn = 10,
+ XEmbedModalityOff,
+ XEmbedRegisterAccelerator,
+ XEmbedUnregisterAccelerator,
+ XEmbedActivateAccelerator,
+};
+
+enum XEmbedFocusDetail {
+ XEmbedFocusCurrent,
+ XEmbedFocusFirst,
+ XEmbedFocusLast,
+};
+
+static Handlers handlers;
+
+static void xembed_updateinfo(XEmbed*);
+static void xembed_sendmessage(XEmbed*, long, long, long, long);
+
+XEmbed*
+xembed_swallow(Window *parent, Window *client, void (*cleanup)(XEmbed*)) {
+ XEmbed *xembed;
+
+ xembed = emallocz(sizeof *xembed);
+ xembed->w = client;
+ xembed->owner = parent;
+ xembed->cleanup = cleanup;
+ selectinput(client, client->eventmask | PropertyChangeMask | StructureNotifyMask);
+ pushhandler(client, &handlers, xembed);
+
+ reparentwindow(client, parent, ZP);
+ xembed_updateinfo(xembed);
+ xembed_sendmessage(xembed, XEmbedEmbeddedNotify, 0, parent->xid, min(XEmbedVersion, xembed->version));
+ return xembed;
+}
+
+void
+xembed_disown(XEmbed *xembed) {
+
+ pophandler(xembed->w, &handlers);
+ if(xembed->flags != DEAD)
+ reparentwindow(xembed->w, &scr.root, ZP);
+ if(xembed->cleanup)
+ xembed->cleanup(xembed);
+ free(xembed);
+}
+
+static void
+xembed_updateinfo(XEmbed *xembed) {
+ ulong *res;
+ int n;
+
+ n = getprop_ulong(xembed->w, "_XEMBED_INFO", "_XEMBED_INFO", 0, &res, 2);
+ xembed->flags = 0UL;
+ if(n >= 2) {
+ xembed->version = res[0];
+ xembed->flags = res[1];
+ }
+ free(res);
+
+ if(xembed->flags & XEmbedMapped)
+ mapwin(xembed->w);
+ else
+ unmapwin(xembed->w);
+}
+
+static void
+xembed_sendmessage(XEmbed *xembed, long message, long detail, long data1, long data2) {
+
+ traperrors(true);
+ sendmessage(xembed->w, "_XEMBED", event_xtime, message, detail, data1, data2);
+ traperrors(false);
+}
+
+static void
+destroy_event(Window *w, void *aux, XDestroyWindowEvent *ev) {
+ XEmbed *xembed;
+
+ xembed = aux;
+ xembed->flags = DEAD;
+ xembed_disown(xembed);
+}
+
+static void
+property_event(Window *w, void *aux, XPropertyEvent *ev) {
+ XEmbed *xembed;
+
+ Dprint("property_event(%W, %p, %s)\n",
+ w, aux, XGetAtomName(display, ev->atom));
+ xembed = aux;
+ if(ev->atom == xatom("_XEMBED_INFO"))
+ xembed_updateinfo(xembed);
+}
+
+static void
+reparent_event(Window *w, void *aux, XReparentEvent *ev) {
+ XEmbed *xembed;
+
+ xembed = aux;
+ if(ev->parent != xembed->owner->xid) {
+ xembed->flags = DEAD;
+ xembed_disown(xembed);
+ }
+}
+
+static Handlers handlers = {
+ .destroy = destroy_event,
+ .property = property_event,
+ .reparent = reparent_event,
+};
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/Makefile
--- a/cmd/wmii/Makefile Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/Makefile Thu May 27 03:58:02 2010 -0400
@@ -15,6 +15,7 @@
 CFLAGS += $(INCICONV) -DIXP_NEEDAPI=97
 OBJ = area \
         bar \
+ backtrace \
         client \
         column \
         div \
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/backtrace.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/wmii/backtrace.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,87 @@
+/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <bio.h>
+#include <plan9.h>
+#undef nelem
+#include <stuff/util.h>
+#include "debug.h"
+
+#ifdef __linux__
+# define PROGTXT "exe"
+#else
+# define PROGTXT "file"
+#endif
+
+static void
+_backtrace(int pid, char *btarg) {
+ char *proc, *spid, *gdbcmd;
+ int fd[3], p[2];
+ int status, cmdfd;
+
+ gdbcmd = estrdup("/tmp/gdbcmd.XXXXXX");
+ if(pipe(p) < 0)
+ goto done;
+ closeexec(p[0]);
+
+ cmdfd = mkstemp(gdbcmd);
+ if(cmdfd < 0)
+ goto done;
+
+ fprint(cmdfd, "bt %s\n", btarg);
+ fprint(cmdfd, "detach\n");
+ close(cmdfd);
+
+ fd[0] = open("/dev/null", O_RDONLY);
+ fd[1] = p[1];
+ fd[2] = dup(2);
+
+ proc = sxprint("/proc/%d/" PROGTXT, pid);
+ spid = sxprint("%d", pid);
+ if(spawn3l(fd, "gdb", "gdb", "-batch", "-x", gdbcmd, proc, spid, nil) < 0) {
+ unlink(gdbcmd);
+ goto done;
+ }
+
+ Biobuf bp;
+ char *s;
+
+ Binit(&bp, p[0], OREAD);
+ while((s = Brdstr(&bp, '\n', 1))) {
+ Dprint(DStack, "%s\n", s);
+ free(s);
+ }
+ unlink(gdbcmd);
+
+done:
+ free(gdbcmd);
+ kill(pid, SIGKILL);
+ waitpid(pid, &status, 0);
+}
+
+void
+backtrace(char *btarg) {
+ int pid;
+
+ /* Fork so we can backtrace the child. Keep this stack
+ * frame minimal, so the trace is fairly clean.
+ */
+ Debug(DStack)
+ switch(pid = fork()) {
+ case -1:
+ return;
+ case 0:
+ kill(getpid(), SIGSTOP);
+ _exit(0);
+ default:
+ _backtrace(pid, btarg);
+ break;
+ }
+
+}
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/bar.c
--- a/cmd/wmii/bar.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/bar.c Thu May 27 03:58:02 2010 -0400
@@ -246,7 +246,7 @@
 }
 
 static void
-bdown_event(Window *w, XButtonPressedEvent *e) {
+bdown_event(Window *w, void *aux, XButtonPressedEvent *e) {
         WMScreen *s;
         Bar *b;
 
@@ -254,29 +254,29 @@
         XUngrabPointer(display, e->time);
         sync();
 
- s = w->aux;
+ s = aux;
         b = findbar(s, Pt(e->x, e->y));
         if(b)
                 event("%sBarMouseDown %d %s\n", barside[b->bar], e->button, b->name);
 }
 
 static void
-bup_event(Window *w, XButtonPressedEvent *e) {
+bup_event(Window *w, void *aux, XButtonPressedEvent *e) {
         WMScreen *s;
         Bar *b;
         
- s = w->aux;
+ s = aux;
         b = findbar(s, Pt(e->x, e->y));
         if(b)
                 event("%sBarClick %d %s\n", barside[b->bar], e->button, b->name);
 }
 
 static Rectangle
-dndmotion_event(Window *w, Point p) {
+dndmotion_event(Window *w, void *aux, Point p) {
         WMScreen *s;
         Bar *b;
 
- s = w->aux;
+ s = aux;
         b = findbar(s, p);
         if(b) {
                 event("%sBarDND 1 %s\n", barside[b->bar], b->name);
@@ -286,9 +286,9 @@
 }
 
 static void
-expose_event(Window *w, XExposeEvent *e) {
+expose_event(Window *w, void *aux, XExposeEvent *e) {
         USED(w, e);
- bar_draw(w->aux);
+ bar_draw(aux);
 }
 
 static Handlers handlers = {
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/client.c
--- a/cmd/wmii/client.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/client.c Thu May 27 03:58:02 2010 -0400
@@ -101,9 +101,8 @@
         c->fullscreen = -1;
         c->border = wa->border_width;
 
- c->r.min = Pt(wa->x, wa->y);
- c->r.max = addpt(c->r.min,
- Pt(wa->width, wa->height));
+ c->r = rectsetorigin(Rect(0, 0, wa->width, wa->height),
+ Pt(wa->x, wa->y));
 
         c->w.type = WWindow;
         c->w.xid = w;
@@ -115,7 +114,7 @@
         c->ibuf = &ibuf;
         if(render_argb_p(wa->visual)) {
                 depth = 32;
- vis = render_visual;
+ vis = scr.visual32;
                 c->ibuf = &ibuf32;
         }
 
@@ -589,7 +588,7 @@
         e.height = Dy(r);
         e.border_width = c->border;
 
- sendevent(&c->w, false, StructureNotifyMask, (XEvent*)&e);
+ sendevent(&c->w, false, StructureNotifyMask, &e);
 }
 
 void
@@ -809,7 +808,7 @@
                 memset(&h, 0, sizeof h);
                 if(c->w.hints)
                         bcopy(c->w.hints, &h, sizeof h);
- sethints(&c->w);
+ gethints(&c->w);
                 if(c->w.hints)
                         c->fixedsize = eqpt(c->w.hints->min, c->w.hints->max);
                 if(memcmp(&h, c->w.hints, sizeof h))
@@ -841,11 +840,11 @@
 
 /* Handlers */
 static void
-configreq_event(Window *w, XConfigureRequestEvent *e) {
+configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) {
         Rectangle r, cr;
         Client *c;
 
- c = w->aux;
+ c = aux;
 
         r = client_grav(c, ZR);
         r.max = subpt(r.max, r.min);
@@ -875,17 +874,17 @@
 }
 
 static void
-destroy_event(Window *w, XDestroyWindowEvent *e) {
+destroy_event(Window *w, void *aux, XDestroyWindowEvent *e) {
         USED(w, e);
 
- client_destroy(w->aux);
+ client_destroy(aux);
 }
 
 static void
-enter_event(Window *w, XCrossingEvent *e) {
+enter_event(Window *w, void *aux, XCrossingEvent *e) {
         Client *c;
         
- c = w->aux;
+ c = aux;
         if(e->detail != NotifyInferior) {
                 if(e->detail != NotifyVirtual)
                 if(e->serial != ignoreenter && disp.focus != c) {
@@ -898,10 +897,10 @@
 }
 
 static void
-focusin_event(Window *w, XFocusChangeEvent *e) {
+focusin_event(Window *w, void *aux, XFocusChangeEvent *e) {
         Client *c, *old;
 
- c = w->aux;
+ c = aux;
 
         print_focus("focusin_event", c, c->name);
 
@@ -918,10 +917,10 @@
 }
 
 static void
-focusout_event(Window *w, XFocusChangeEvent *e) {
+focusout_event(Window *w, void *aux, XFocusChangeEvent *e) {
         Client *c;
 
- c = w->aux;
+ c = aux;
         if((e->mode == NotifyWhileGrabbed) && (disp.hasgrab != &c_root)) {
                 if(disp.focus)
                         disp.hasgrab = disp.focus;
@@ -934,34 +933,34 @@
 }
 
 static void
-unmap_event(Window *w, XUnmapEvent *e) {
+unmap_event(Window *w, void *aux, XUnmapEvent *e) {
         Client *c;
         
- c = w->aux;
+ c = aux;
         if(!e->send_event)
                 c->unmapped--;
         client_destroy(c);
 }
 
 static void
-map_event(Window *w, XMapEvent *e) {
+map_event(Window *w, void *aux, XMapEvent *e) {
         Client *c;
 
         USED(e);
         
- c = w->aux;
+ c = aux;
         if(c == selclient())
                 client_focus(c);
 }
 
 static void
-property_event(Window *w, XPropertyEvent *e) {
+property_event(Window *w, void *aux, XPropertyEvent *e) {
         Client *c;
 
         if(e->state == PropertyDelete) /* FIXME */
                 return;
 
- c = w->aux;
+ c = aux;
         client_prop(c, e->atom);
 }
 
@@ -1002,6 +1001,7 @@
                 if(*tags) {
                         if(!*fp || cmp > 0) {
                                 f = frame_create(c, view_create(*tags));
+ Dprint(DGeneric, "%#C %p %R %R %R %C\n", c, c->sel, c->r, f->floatr, c->sel ? c->sel->floatr : ZR, c);
                                 if(f->view == selview || !c->sel)
                                         c->sel = f;
                                 kludge = c; /* FIXME */
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/dat.h
--- a/cmd/wmii/dat.h Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/dat.h Thu May 27 03:58:02 2010 -0400
@@ -12,10 +12,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <utf.h>
+#include <ixp.h>
 #include <stuff/x.h>
 #include <stuff/util.h>
-#include <debug.h>
-#include <ixp.h>
+#include "debug.h"
 
 #define FONT "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*"
 #define FOCUSCOLORS "#ffffff #335577 #447799"
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/debug.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/wmii/debug.h Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,24 @@
+#include <stdbool.h>
+
+enum DebugOpt {
+ D9p = 1<<0,
+ DDnd = 1<<1,
+ DEvent = 1<<2,
+ DEwmh = 1<<3,
+ DFocus = 1<<4,
+ DGeneric= 1<<5,
+ DStack = 1<<6,
+ NDebugOpt = 7,
+};
+
+#define Debug(x) if(((debugflag|debugfile)&(x)) && setdebug(x))
+#define Dprint(x, ...) BLOCK( if((debugflag|debugfile)&(x)) debug(x, __VA_ARGS__) )
+
+void debug(int, const char*, ...);
+void dprint(const char*, ...);
+void dwrite(int, void*, int, bool);
+bool setdebug(int);
+void vdebug(int, const char*, va_list);
+
+int debugflag;
+int debugfile;
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/div.c
--- a/cmd/wmii/div.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/div.c Thu May 27 03:58:02 2010 -0400
@@ -164,22 +164,22 @@
 
 /* Div Handlers */
 static void
-bdown_event(Window *w, XButtonEvent *e) {
+bdown_event(Window *w, void *aux, XButtonEvent *e) {
         Divide *d;
 
         USED(e);
         
- d = w->aux;
+ d = aux;
         mouse_resizecol(d);
 }
 
 static void
-expose_event(Window *w, XExposeEvent *e) {
+expose_event(Window *w, void *aux, XExposeEvent *e) {
         Divide *d;
         
         USED(e);
         
- d = w->aux;
+ d = aux;
         drawdiv(d);
 }
 
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/event.c
--- a/cmd/wmii/event.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/event.c Thu May 27 03:58:02 2010 -0400
@@ -10,15 +10,12 @@
         Dprint(DEvent, "%E\n", e);
 }
 
-#define handle(w, fn, ev) \
- BLOCK(if((w)->handler->fn) (w)->handler->fn((w), ev))
-
 void
 event_buttonpress(XButtonPressedEvent *ev) {
         Window *w;
 
         if((w = findwin(ev->window)))
- handle(w, bdown, ev);
+ event_handle(w, bdown, ev);
         else
                 XAllowEvents(display, ReplayPointer, ev->time);
 }
@@ -29,7 +26,7 @@
 
         ignoreenter = ev->serial;
         if((w = findwin(ev->window)))
- handle(w, config, ev);
+ event_handle(w, config, ev);
 }
 
 void
@@ -47,7 +44,7 @@
         Client *c;
 
         if((w = findwin(ev->window)))
- handle(w, destroy, ev);
+ event_handle(w, destroy, ev);
         else if((c = win2client(ev->window)))
                 fprint(2, "Badness: Unhandled DestroyNotify: Client: %p, Window: %W, Name: %s\n",
                        c, &c->w, c->name);
@@ -87,7 +84,7 @@
                 disp.focus = nil;
         }
         else if((w = findwin(ev->window)))
- handle(w, focusin, ev);
+ event_handle(w, focusin, ev);
         else if(ev->mode == NotifyGrab) {
                 /* Some unmanaged window has grabbed focus */
                 if((c = disp.focus)) {
@@ -117,7 +114,7 @@
         && XCheckMaskEvent(display, KeyPressMask, &me))
                 event_dispatch(&me);
         else if((w = findwin(ev->window)))
- handle(w, focusout, ev);
+ event_handle(w, focusout, ev);
 }
 
 void
@@ -126,7 +123,7 @@
 
        ignoreenter = ev->serial;
        if((w = findwin(ev->window)))
- handle(w, map, ev);
+ event_handle(w, map, ev);
 }
 
 void
@@ -137,7 +134,7 @@
         if((w = findwin(ev->window)) && (ev->event == w->parent->xid)) {
                 w->mapped = false;
                 if(ev->send_event || w->unmapped-- == 0)
- handle(w, unmap, ev);
+ event_handle(w, unmap, ev);
         }
 }
 
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/frame.c
--- a/cmd/wmii/frame.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/frame.c Thu May 27 03:58:02 2010 -0400
@@ -29,6 +29,9 @@
         if(c->sel) {
                 f->floatr = c->sel->floatr;
                 f->r = c->sel->r;
+ }else if(c->sel) {
+ f->floatr = c->frame->floatr;
+ f->r = c->frame->r;
         }else {
                 f->r = client_grav(c, c->r);
                 f->floatr = f->r;
@@ -140,20 +143,20 @@
 
 /* Handlers */
 static void
-bup_event(Window *w, XButtonEvent *e) {
+bup_event(Window *w, void *aux, XButtonEvent *e) {
         if((e->state & def.mod) != def.mod)
                 XAllowEvents(display, ReplayPointer, e->time);
         else
                 XUngrabPointer(display, e->time);
- event("ClientClick %#C %d\n", w->aux, e->button);
+ event("ClientClick %#C %d\n", aux, e->button);
 }
 
 static void
-bdown_event(Window *w, XButtonEvent *e) {
+bdown_event(Window *w, void *aux, XButtonEvent *e) {
         Frame *f;
         Client *c;
 
- c = w->aux;
+ c = aux;
         f = c->sel;
 
         if((e->state & def.mod) == def.mod) {
@@ -200,17 +203,17 @@
 }
 
 static void
-config_event(Window *w, XConfigureEvent *e) {
+config_event(Window *w, void *aux, XConfigureEvent *e) {
 
         USED(w, e);
 }
 
 static void
-enter_event(Window *w, XCrossingEvent *e) {
+enter_event(Window *w, void *aux, XCrossingEvent *e) {
         Client *c;
         Frame *f;
 
- c = w->aux;
+ c = aux;
         f = c->sel;
         if(disp.focus != c || selclient() != c) {
                 Dprint(DFocus, "enter_notify(f) => [%#C]%s%s\n",
@@ -225,12 +228,12 @@
 }
 
 static void
-expose_event(Window *w, XExposeEvent *e) {
+expose_event(Window *w, void *aux, XExposeEvent *e) {
         Client *c;
 
         USED(e);
 
- c = w->aux;
+ c = aux;
         if(c->sel)
                 frame_draw(c->sel);
         else
@@ -239,10 +242,10 @@
 }
 
 static void
-motion_event(Window *w, XMotionEvent *e) {
+motion_event(Window *w, void *aux, XMotionEvent *e) {
         Client *c;
         
- c = w->aux;
+ c = aux;
         mouse_checkresize(c->sel, Pt(e->x, e->y), false);
 }
 
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/layout.c
--- a/cmd/wmii/layout.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/layout.c Thu May 27 03:58:02 2010 -0400
@@ -99,7 +99,7 @@
 }
 
 static void
-expose_event(Window *w, XExposeEvent *e) {
+expose_event(Window *w, void *aux, XExposeEvent *e) {
         Rectangle r;
         Framewin *f;
         Image *buf;
@@ -107,7 +107,7 @@
         
         USED(e);
 
- f = w->aux;
+ f = aux;
         c = &def.focuscolor;
         buf = disp.ibuf;
         
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/main.c
--- a/cmd/wmii/main.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/main.c Thu May 27 03:58:02 2010 -0400
@@ -318,13 +318,6 @@
 }
 
 static void
-check_preselect(IxpServer *s) {
- USED(s);
-
- event_check();
-}
-
-static void
 closedisplay(IxpConn *c) {
         USED(c);
 
@@ -412,9 +405,9 @@
 
         event_debug = debug_event;
 
- srv.preselect = check_preselect;
+ srv.preselect = event_preselect;
         ixp_listen(&srv, sock, &p9srv, serve_9pcon, nil);
- ixp_listen(&srv, ConnectionNumber(display), nil, (void (*)(IxpConn*))check_preselect, closedisplay);
+ ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, closedisplay);
 
         def.border = 1;
         def.colmode = Colstack;
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/mouse.c
--- a/cmd/wmii/mouse.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/mouse.c Thu May 27 03:58:02 2010 -0400
@@ -29,7 +29,7 @@
 }
 
 static void
-cwin_expose(Window *w, XExposeEvent *e) {
+cwin_expose(Window *w, void *aux, XExposeEvent *e) {
 
         fill(w, rectsubpt(w->r, w->r.min), def.focuscolor.bg);
         fill(w, w->r, def.focuscolor.bg);
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/root.c
--- a/cmd/wmii/root.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/root.c Thu May 27 03:58:02 2010 -0400
@@ -24,13 +24,13 @@
 }
 
 static void
-enter_event(Window *w, XCrossingEvent *e) {
+enter_event(Window *w, void *aux, XCrossingEvent *e) {
         disp.sel = true;
         frame_draw_all();
 }
 
 static void
-leave_event(Window *w, XCrossingEvent *e) {
+leave_event(Window *w, void *aux, XCrossingEvent *e) {
         if(!e->same_screen) {
                 disp.sel = false;
                 frame_draw_all();
@@ -38,13 +38,13 @@
 }
 
 static void
-focusin_event(Window *w, XFocusChangeEvent *e) {
+focusin_event(Window *w, void *aux, XFocusChangeEvent *e) {
         if(e->mode == NotifyGrab)
                 disp.hasgrab = &c_root;
 }
 
 static void
-mapreq_event(Window *w, XMapRequestEvent *e) {
+mapreq_event(Window *w, void *aux, XMapRequestEvent *e) {
         XWindowAttributes wa;
 
         if(!XGetWindowAttributes(display, e->window, &wa))
@@ -62,7 +62,7 @@
 }
 
 static void
-motion_event(Window *w, XMotionEvent *e) {
+motion_event(Window *w, void *aux, XMotionEvent *e) {
         Rectangle r, r2;
 
         r = rectsetorigin(Rect(0, 0, 1, 1), Pt(e->x_root, e->y_root));
@@ -72,7 +72,7 @@
 }
 
 static void
-kdown_event(Window *w, XKeyEvent *e) {
+kdown_event(Window *w, void *aux, XKeyEvent *e) {
 
         e->state &= valid_mask;
         kpress(w->xid, e->state, (KeyCode)e->keycode);
diff -r 4d765bd540b8 -r 91080b00b924 cmd/wmii/xdnd.c
--- a/cmd/wmii/xdnd.c Wed May 26 09:20:14 2010 -0400
+++ b/cmd/wmii/xdnd.c Thu May 27 03:58:02 2010 -0400
@@ -71,7 +71,7 @@
                         Dprint(DDnd, "\tp: %P\n", p);
                         if(eqrect(dnd->r, ZR) || !rect_haspoint_p(p, dnd->r))
                                 if(w->handler->dndmotion)
- dnd->r = w->handler->dndmotion(w, p);
+ dnd->r = w->handler->dndmotion(w, w->aux, p);
                         r = dnd->r;
                         if(!eqrect(r, ZR))
                                 r = rectaddpt(r, w->r.min);
diff -r 4d765bd540b8 -r 91080b00b924 config.mk
--- a/config.mk Wed May 26 09:20:14 2010 -0400
+++ b/config.mk Thu May 27 03:58:02 2010 -0400
@@ -26,7 +26,7 @@
 # Archiver
 AR = ar crs
 
-X11PACKAGES = x11 xinerama xrender
+X11PACKAGES = x11 xinerama xrender xrandr
 INCX11 = $$(pkg-config --cflags $(X11PACKAGES))
 LIBIXP = $(LIBDIR)/libixp.a
 
diff -r 4d765bd540b8 -r 91080b00b924 include/debug.h
--- a/include/debug.h Wed May 26 09:20:14 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#include <stdbool.h>
-
-#define Debug(x) if(((debugflag|debugfile)&(x)) && setdebug(x))
-#define Dprint(x, ...) BLOCK( if((debugflag|debugfile)&(x)) debug(x, __VA_ARGS__) )
-
-void debug(int, const char*, ...);
-void dprint(const char*, ...);
-void dwrite(int, void*, int, bool);
-bool setdebug(int);
-void vdebug(int, const char*, va_list);
-
-int debugflag;
-int debugfile;
diff -r 4d765bd540b8 -r 91080b00b924 include/stuff/base.h
--- a/include/stuff/base.h Wed May 26 09:20:14 2010 -0400
+++ b/include/stuff/base.h Thu May 27 03:58:02 2010 -0400
@@ -1,18 +1,25 @@
 #pragma once
 #define _XOPEN_SOURCE 600
 
+#include <sys/types.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdint.h>
 
 #ifndef nil
-#define nil ((void*)0)
+# define nil ((void*)0)
 #endif
 
 #ifndef nelem
-#define nelem(ary) (sizeof(ary) / sizeof(*ary))
+# define nelem(ary) (sizeof(ary) / sizeof(*ary))
 #endif
 
+#ifndef offsetof
+# define offsetof(type, member) ((size_t)&((type*)0)->member)
+#endif
+#define structmember(ptr, type, offset) \
+ (*(type*)((char*)(ptr) + (offset)))
+
 #undef uchar
 #undef ushort
 #undef uint
diff -r 4d765bd540b8 -r 91080b00b924 include/stuff/util.h
--- a/include/stuff/util.h Wed May 26 09:20:14 2010 -0400
+++ b/include/stuff/util.h Thu May 27 03:58:02 2010 -0400
@@ -22,16 +22,7 @@
         CCenter = 1<<1,
         CRight = 1<<2,
 };
-enum DebugOpt {
- D9p = 1<<0,
- DDnd = 1<<1,
- DEvent = 1<<2,
- DEwmh = 1<<3,
- DFocus = 1<<4,
- DGeneric= 1<<5,
- DStack = 1<<6,
- NDebugOpt = 7,
-};
+
 enum {
         GInvert = 1<<0,
 };
diff -r 4d765bd540b8 -r 91080b00b924 include/stuff/x.h
--- a/include/stuff/x.h Wed May 26 09:20:14 2010 -0400
+++ b/include/stuff/x.h Thu May 27 03:58:02 2010 -0400
@@ -16,11 +16,21 @@
 void xext_init(void);
 Rectangle* xinerama_screens(int*);
 
+#define event_handle(w, fn, ev) \
+ _event_handle(w, offsetof(Handlers, fn), (XEvent*)ev)
+
+void _event_handle(Window*, ulong, XEvent*);
+
 void event_check(void);
 void event_dispatch(XEvent*);
 uint event_flush(long, bool dispatch);
 uint event_flushenter(void);
 void event_loop(void);
+#ifdef IXP_API /* Evil. */
+void event_fdclosed(IxpConn*);
+void event_fdready(IxpConn*);
+void event_preselect(IxpServer*);
+#endif
 void event_updatextime(void);
 
 void event_buttonpress(XButtonPressedEvent*);
@@ -36,10 +46,14 @@
 void event_keypress(XKeyEvent*);
 void event_leavenotify(XCrossingEvent*);
 void event_mapnotify(XMapEvent*);
+void event_mappingnotify(XMappingEvent*);
 void event_maprequest(XMapRequestEvent*);
-void event_mappingnotify(XMappingEvent*);
 void event_motionnotify(XMotionEvent*);
 void event_propertynotify(XPropertyEvent*);
+void event_reparentnotify(XReparentEvent *ev);
+void event_selection(XSelectionEvent*);
+void event_selectionclear(XSelectionClearEvent*);
+void event_selectionrequest(XSelectionRequestEvent*);
 void event_unmapnotify(XUnmapEvent*);
 
 extern long event_xtime;
diff -r 4d765bd540b8 -r 91080b00b924 include/stuff/x11.h
--- a/include/stuff/x11.h Wed May 26 09:20:14 2010 -0400
+++ b/include/stuff/x11.h Thu May 27 03:58:02 2010 -0400
@@ -33,12 +33,14 @@
 
 typedef XSetWindowAttributes WinAttr;
 
+typedef union ClientMessageData ClientMessageData;
 typedef struct Color Color;
 typedef struct CTuple CTuple;
 typedef struct ErrorCode ErrorCode;
 typedef struct Ewmh Ewmh;
 typedef struct Font Font;
 typedef struct Handlers Handlers;
+typedef struct HandlersLink HandlersLink;
 typedef struct Screen Screen;
 typedef struct WinHints WinHints;
 typedef struct Window Image;
@@ -48,6 +50,12 @@
 typedef void XftDraw;
 typedef struct XftFont XftFont;
 
+union ClientMessageData {
+ char b[20];
+ short s[10];
+ long l[5];
+};
+
 struct Color {
         ulong pixel;
         XRenderColor render;
@@ -86,24 +94,35 @@
 };
 
 struct Handlers {
- Rectangle (*dndmotion)(Window*, Point);
- void (*bdown)(Window*, XButtonEvent*);
- void (*bup)(Window*, XButtonEvent*);
- void (*config)(Window*, XConfigureEvent*);
- void (*configreq)(Window*, XConfigureRequestEvent*);
- void (*destroy)(Window*, XDestroyWindowEvent*);
- void (*enter)(Window*, XCrossingEvent*);
- void (*expose)(Window*, XExposeEvent*);
- void (*focusin)(Window*, XFocusChangeEvent*);
- void (*focusout)(Window*, XFocusChangeEvent*);
- void (*kdown)(Window*, XKeyEvent*);
- void (*kup)(Window*, XKeyEvent*);
- void (*leave)(Window*, XCrossingEvent*);
- void (*map)(Window*, XMapEvent*);
- void (*mapreq)(Window*, XMapRequestEvent*);
- void (*motion)(Window*, XMotionEvent*);
- void (*property)(Window*, XPropertyEvent*);
- void (*unmap)(Window*, XUnmapEvent*);
+ Rectangle (*dndmotion)(Window*, void*, Point);
+ void (*bdown)(Window*, void*, XButtonEvent*);
+ void (*bup)(Window*, void*, XButtonEvent*);
+ void (*config)(Window*, void*, XConfigureEvent*);
+ void (*configreq)(Window*, void*, XConfigureRequestEvent*);
+ void (*destroy)(Window*, void*, XDestroyWindowEvent*);
+ void (*enter)(Window*, void*, XCrossingEvent*);
+ void (*expose)(Window*, void*, XExposeEvent*);
+ void (*focusin)(Window*, void*, XFocusChangeEvent*);
+ void (*focusout)(Window*, void*, XFocusChangeEvent*);
+ void (*kdown)(Window*, void*, XKeyEvent*);
+ void (*kup)(Window*, void*, XKeyEvent*);
+ void (*leave)(Window*, void*, XCrossingEvent*);
+ void (*map)(Window*, void*, XMapEvent*);
+ void (*mapreq)(Window*, void*, XMapRequestEvent*);
+ void (*message)(Window*, void*, XClientMessageEvent*);
+ void (*motion)(Window*, void*, XMotionEvent*);
+ void (*property)(Window*, void*, XPropertyEvent*);
+ void (*reparent)(Window*, void*, XReparentEvent*);
+ void (*selection)(Window*, void*, XSelectionEvent*);
+ void (*selectionclear)(Window*, void*, XSelectionClearEvent*);
+ void (*selectionrequest)(Window*, void*, XSelectionRequestEvent*);
+ void (*unmap)(Window*, void*, XUnmapEvent*);
+};
+
+struct HandlersLink {
+ HandlersLink* next;
+ void* aux;
+ Handlers* handler;
 };
 
 struct WinHints {
@@ -132,8 +151,10 @@
         Window* next;
         Window* prev;
         Handlers* handler;
+ HandlersLink* handler_link;
         WinHints* hints;
         Ewmh ewmh;
+ long eventmask;
         void* dnd;
         void* aux;
         bool mapped;
@@ -193,6 +214,7 @@
 extern struct Map atommap;
 extern const Point ZP;
 extern const Rectangle ZR;
+extern const WinHints ZWinHints;
 extern Window* pointerwin;
 extern Xft* xft;
 
@@ -204,6 +226,7 @@
                 (uchar*)(data), n)
 
 /* x11.c */
+XRectangle XRect(Rectangle);
 Image* allocimage(int w, int h, int depth);
 void border(Image *dst, Rectangle, int w, Color);
 void changeprop_char(Window*, char*, char*, char[], int);
@@ -213,9 +236,10 @@
 void changeprop_textlist(Window*, char*, char*, char*[]);
 void changeprop_ulong(Window*, char*, char*, ulong[], int);
 void changeproperty(Window*, char*, char*, int width, uchar*, int);
+void clientmessage(Window*, char*, long, int, ClientMessageData);
 void copyimage(Image*, Rectangle, Image*, Point);
 Window* createwindow(Window*, Rectangle, int depth, uint class, WinAttr*, int valuemask);
-Window* createwindow_visual(Window*, Rectangle, int depth, Visual*, uint class, WinAttr*, int);
+Window* createwindow_visual(Window*, Rectangle, int depth, Visual*, uint class, WinAttr*, int);
 void delproperty(Window*, char*);
 void destroywindow(Window*);
 void drawline(Image*, Point, Point, int cap, int w, Color);
@@ -228,11 +252,13 @@
 void freeimage(Image *);
 void freestringlist(char**);
 XWindow getfocus(void);
+void gethints(Window*);
 ulong getprop_long(Window*, char*, char*, ulong, long**, ulong);
 char* getprop_string(Window*, char*);
 int getprop_textlist(Window *w, char *name, char **ret[]);
 ulong getprop_ulong(Window*, char*, char*, ulong, ulong**, ulong);
 ulong getproperty(Window*, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length);
+Rectangle getwinrect(Window*);
 int grabkeyboard(Window*);
 int grabpointer(Window*, Window *confine, Cursor, int mask);
 bool havexft(void);
@@ -247,24 +273,29 @@
 bool namedcolor(char *name, Color*);
 bool parsekey(char*, int*, char**);
 int pointerscreen(void);
+bool pophandler(Window*, Handlers*);
+void pushhandler(Window*, Handlers*, void*);
 Point querypointer(Window*);
 void raisewin(Window*);
 void reparentwindow(Window*, Window*, Point);
 void reshapewin(Window*, Rectangle);
 void selectinput(Window*, long);
-void sendevent(Window*, bool propagate, long mask, XEvent*);
+void sendevent(Window*, bool propagate, long mask, void*);
+void sendmessage(Window*, char*, long, long, long, long, long);
 void setborder(Window*, int, Color);
 void setfocus(Window*, int mode);
-void sethints(Window*);
+Handlers* sethandler(Window*, Handlers*);
+void sethints(Window*, WinHints*);
 void setshapemask(Window *dst, Image *src, Point);
 void setwinattr(Window*, WinAttr*, int valmask);
+Rectangle sizehint(WinHints*, Rectangle);
 char** strlistdup(char**);
 void sync(void);
+Rectangle textextents_l(Font*, char*, uint, int*);
 uint textwidth(Font*, char*);
 uint textwidth_l(Font*, char*, uint len);
-Rectangle textextents_l(Font*, char*, uint, int*);
+Point translate(Window*, Window*, Point);
 int traperrors(bool);
-Point translate(Window*, Window*, Point);
 void ungrabkeyboard(void);
 void ungrabpointer(void);
 int unmapwin(Window*);
@@ -273,9 +304,4 @@
 char* windowname(Window*);
 long winprotocols(Window*);
 Atom xatom(char*);
-void sendmessage(Window*, char*, long, long, long, long, long);
-XRectangle XRect(Rectangle);
-Rectangle getwinrect(Window*);
-Handlers* sethandler(Window*, Handlers*);
-Rectangle sizehint(WinHints*, Rectangle);
 
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/Makefile
--- a/lib/libstuff/Makefile Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/Makefile Thu May 27 03:58:02 2010 -0400
@@ -19,6 +19,7 @@
         event/expose \
         event/focusin \
         event/focusout \
+ event/ixp \
         event/keypress \
         event/leavenotify \
         event/mapnotify \
@@ -26,6 +27,10 @@
         event/mappingnotify \
         event/motionnotify \
         event/propertynotify \
+ event/reparentnotify \
+ event/selection \
+ event/selectionclear \
+ event/selectionrequest \
         event/unmapnotify \
         event/xtime \
         geom/get_sticky \
@@ -38,7 +43,6 @@
         map \
         printevent \
         util/_die \
- util/backtrace \
         util/closeexec \
         util/comm \
         util/doublefork \
@@ -114,6 +118,7 @@
         x11/images/freeimage \
         x11/images/xftdrawable \
         x11/insanity/gravitate \
+ x11/insanity/gethints \
         x11/insanity/sethints \
         x11/insanity/sizehint \
         x11/keyboard/grabkeyboard \
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/clientutil.c
--- a/lib/libstuff/clientutil.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/clientutil.c Thu May 27 03:58:02 2010 -0400
@@ -1,6 +1,7 @@
 #define IXP_NO_P9_
 #define IXP_P9_STRUCTS
 #define CLIENTEXTERN
+#include <stdlib.h>
 #include <string.h>
 #include <ixp.h>
 #include <stuff/clientutil.h>
@@ -40,11 +41,13 @@
 
 void
 client_init(char* address) {
+ if(address == nil)
+ address = getenv("WMII_ADDRESS");
         if(address && *address)
                 client = ixp_mount(address);
         else
                 client = ixp_nsmount("wmii");
         if(client == nil)
- fatal("can't mount: %r\n");
+ fatal("can't mount wmii filesystem: %r\n");
 }
 
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/buttonpress.c
--- a/lib/libstuff/event/buttonpress.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/buttonpress.c Thu May 27 03:58:02 2010 -0400
@@ -8,7 +8,7 @@
         Window *w;
 
         if((w = findwin(ev->window)))
- handle(w, bdown, ev);
+ event_handle(w, bdown, ev);
         else
                 XAllowEvents(display, ReplayPointer, ev->time);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/buttonrelease.c
--- a/lib/libstuff/event/buttonrelease.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/buttonrelease.c Thu May 27 03:58:02 2010 -0400
@@ -8,5 +8,5 @@
         Window *w;
 
         if((w = findwin(ev->window)))
- handle(w, bup, ev);
+ event_handle(w, bup, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/clientmessage.c
--- a/lib/libstuff/event/clientmessage.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/clientmessage.c Thu May 27 03:58:02 2010 -0400
@@ -5,6 +5,8 @@
 
 void
 event_clientmessage(XClientMessageEvent *ev) {
+ Window *w;
 
- USED(ev);
+ if((w = findwin(ev->window)))
+ event_handle(w, message, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/configurenotify.c
--- a/lib/libstuff/event/configurenotify.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/configurenotify.c Thu May 27 03:58:02 2010 -0400
@@ -8,5 +8,5 @@
         Window *w;
 
         if((w = findwin(ev->window)))
- handle(w, config, ev);
+ event_handle(w, config, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/configurerequest.c
--- a/lib/libstuff/event/configurerequest.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/configurerequest.c Thu May 27 03:58:02 2010 -0400
@@ -9,7 +9,7 @@
         Window *w;
 
         if((w = findwin(ev->window)))
- handle(w, configreq, ev);
+ event_handle(w, configreq, ev);
         else{
                 wc.x = ev->x;
                 wc.y = ev->y;
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/destroynotify.c
--- a/lib/libstuff/event/destroynotify.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/destroynotify.c Thu May 27 03:58:02 2010 -0400
@@ -8,5 +8,5 @@
         Window *w;
 
         if((w = findwin(ev->window)))
- handle(w, destroy, ev);
+ event_handle(w, destroy, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/enternotify.c
--- a/lib/libstuff/event/enternotify.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/enternotify.c Thu May 27 03:58:02 2010 -0400
@@ -7,10 +7,11 @@
 event_enternotify(XCrossingEvent *ev) {
         Window *w;
 
- event_xtime = ev->time;
+ if(!ev->send_event)
+ event_xtime = ev->time;
         if(ev->mode != NotifyNormal)
                 return;
 
         if((w = findwin(ev->window)))
- handle(w, enter, ev);
+ event_handle(w, enter, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/event.c
--- a/lib/libstuff/event/event.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/event.c Thu May 27 03:58:02 2010 -0400
@@ -3,6 +3,7 @@
  */
 #include "event.h"
 
+typedef void (*Handler)(Window*, void*, XEvent*);
 void (*event_debug)(XEvent*);
 long event_xtime;
 bool event_looprunning;
@@ -25,10 +26,30 @@
         [MappingNotify] = (EventHandler)event_mappingnotify,
         [MotionNotify] = (EventHandler)event_motionnotify,
         [PropertyNotify] = (EventHandler)event_propertynotify,
+ [ReparentNotify] = (EventHandler)event_reparentnotify,
+ [SelectionClear] = (EventHandler)event_selectionclear,
+ [SelectionNotify] = (EventHandler)event_selection,
         [UnmapNotify] = (EventHandler)event_unmapnotify,
 };
 
 void
+_event_handle(Window *w, ulong offset, XEvent *event) {
+ Handler f;
+ HandlersLink *l;
+
+ if(w->handler && (f = structmember(w->handler, Handler, offset))) {
+ f(w, w->aux, event);
+ return;
+ }
+ for(l=w->handler_link; l; l=l->next) {
+ if(f = structmember(l->handler, Handler, offset)) {
+ f(w, l->aux, event);
+ return;
+ }
+ }
+}
+
+void
 event_dispatch(XEvent *e) {
         if(event_debug)
                 event_debug(e);
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/expose.c
--- a/lib/libstuff/event/expose.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/expose.c Thu May 27 03:58:02 2010 -0400
@@ -8,5 +8,5 @@
         Window *w;
 
         if(ev->count == 0 && (w = findwin(ev->window)))
- handle(w, expose, ev);
+ event_handle(w, expose, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/focusin.c
--- a/lib/libstuff/event/focusin.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/focusin.c Thu May 27 03:58:02 2010 -0400
@@ -23,5 +23,5 @@
                 return;
 
         if((w = findwin(ev->window)))
- handle(w, focusin, ev);
+ event_handle(w, focusin, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/focusout.c
--- a/lib/libstuff/event/focusout.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/focusout.c Thu May 27 03:58:02 2010 -0400
@@ -15,5 +15,5 @@
                 return;
 
         if((w = findwin(ev->window)))
- handle(w, focusout, ev);
+ event_handle(w, focusout, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/ixp.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libstuff/event/ixp.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,23 @@
+/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include <ixp.h>
+#include "event.h"
+
+void
+event_preselect(IxpServer *s) {
+ USED(s);
+ event_check();
+}
+
+void
+event_fdready(IxpConn *c) {
+ USED(c);
+ event_check();
+}
+
+void
+event_fdclosed(IxpConn *c) {
+
+ c->srv->running = false;
+}
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/keypress.c
--- a/lib/libstuff/event/keypress.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/keypress.c Thu May 27 03:58:02 2010 -0400
@@ -7,7 +7,8 @@
 event_keypress(XKeyEvent *ev) {
         Window *w;
 
- event_xtime = ev->time;
+ if(!ev->send_event)
+ event_xtime = ev->time;
         if((w = findwin(ev->window)))
- handle(w, kdown, ev);
+ event_handle(w, kdown, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/leavenotify.c
--- a/lib/libstuff/event/leavenotify.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/leavenotify.c Thu May 27 03:58:02 2010 -0400
@@ -7,7 +7,8 @@
 event_leavenotify(XCrossingEvent *ev) {
         Window *w;
 
- event_xtime = ev->time;
+ if(!ev->send_event)
+ event_xtime = ev->time;
         if((w = findwin(ev->window)))
- handle(w, leave, ev);
+ event_handle(w, leave, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/mapnotify.c
--- a/lib/libstuff/event/mapnotify.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/mapnotify.c Thu May 27 03:58:02 2010 -0400
@@ -8,5 +8,5 @@
         Window *w;
 
         if((w = findwin(ev->window)))
- handle(w, map, ev);
+ event_handle(w, map, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/maprequest.c
--- a/lib/libstuff/event/maprequest.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/maprequest.c Thu May 27 03:58:02 2010 -0400
@@ -8,5 +8,5 @@
         Window *w;
 
         if((w = findwin(ev->parent)))
- handle(w, mapreq, ev);
+ event_handle(w, mapreq, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/motionnotify.c
--- a/lib/libstuff/event/motionnotify.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/motionnotify.c Thu May 27 03:58:02 2010 -0400
@@ -7,7 +7,8 @@
 event_motionnotify(XMotionEvent *ev) {
         Window *w;
 
- event_xtime = ev->time;
+ if(!ev->send_event)
+ event_xtime = ev->time;
         if((w = findwin(ev->window)))
- handle(w, motion, ev);
+ event_handle(w, motion, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/propertynotify.c
--- a/lib/libstuff/event/propertynotify.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/propertynotify.c Thu May 27 03:58:02 2010 -0400
@@ -7,7 +7,8 @@
 event_propertynotify(XPropertyEvent *ev) {
         Window *w;
 
- event_xtime = ev->time;
+ if(!ev->send_event)
+ event_xtime = ev->time;
         if((w = findwin(ev->window)))
- handle(w, property, ev);
+ event_handle(w, property, ev);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/reparentnotify.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libstuff/event/reparentnotify.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,12 @@
+/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "event.h"
+
+void
+event_reparentnotify(XReparentEvent *ev) {
+ Window *w;
+
+ if((w = findwin(ev->window)))
+ event_handle(w, reparent, ev);
+}
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/selection.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libstuff/event/selection.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,15 @@
+/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "event.h"
+
+void
+event_selection(XSelectionEvent *ev) {
+ Window *w;
+
+ if(!ev->send_event)
+ event_xtime = ev->time;
+ if((w = findwin(ev->requestor)))
+ event_handle(w, selection, ev);
+}
+
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/selectionclear.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libstuff/event/selectionclear.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,14 @@
+/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "event.h"
+
+void
+event_selectionclear(XSelectionClearEvent *ev) {
+ Window *w;
+
+ if(!ev->send_event)
+ event_xtime = ev->time;
+ if((w = findwin(ev->window)))
+ event_handle(w, selectionclear, ev);
+}
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/selectionrequest.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libstuff/event/selectionrequest.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,15 @@
+/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "event.h"
+
+void
+event_selectionrequest(XSelectionRequestEvent *ev) {
+ Window *w;
+
+ if(!ev->send_event)
+ event_xtime = ev->time;
+ if((w = findwin(ev->owner)))
+ event_handle(w, selectionrequest, ev);
+}
+
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/event/unmapnotify.c
--- a/lib/libstuff/event/unmapnotify.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/event/unmapnotify.c Thu May 27 03:58:02 2010 -0400
@@ -10,6 +10,6 @@
         if((w = findwin(ev->window)) && (ev->event == w->parent->xid)) {
                 w->mapped = false;
                 if(w->parent && (ev->send_event || w->unmapped-- == 0))
- handle(w, unmap, ev);
+ event_handle(w, unmap, ev);
         }
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/util/backtrace.c
--- a/lib/libstuff/util/backtrace.c Wed May 26 09:20:14 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
- * See LICENSE file for license details.
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <signal.h>
-
-#include <bio.h>
-#include <plan9.h>
-#undef nelem
-#include <debug.h>
-#include "util.h"
-
-#ifdef __linux__
-# define PROGTXT "exe"
-#else
-# define PROGTXT "file"
-#endif
-
-static void
-_backtrace(int pid, char *btarg) {
- char *proc, *spid, *gdbcmd;
- int fd[3], p[2];
- int status, cmdfd;
-
- gdbcmd = estrdup("/tmp/gdbcmd.XXXXXX");
- if(pipe(p) < 0)
- goto done;
- closeexec(p[0]);
-
- cmdfd = mkstemp(gdbcmd);
- if(cmdfd < 0)
- goto done;
-
- fprint(cmdfd, "bt %s\n", btarg);
- fprint(cmdfd, "detach\n");
- close(cmdfd);
-
- fd[0] = open("/dev/null", O_RDONLY);
- fd[1] = p[1];
- fd[2] = dup(2);
-
- proc = sxprint("/proc/%d/" PROGTXT, pid);
- spid = sxprint("%d", pid);
- if(spawn3l(fd, "gdb", "gdb", "-batch", "-x", gdbcmd, proc, spid, nil) < 0) {
- unlink(gdbcmd);
- goto done;
- }
-
- Biobuf bp;
- char *s;
-
- Binit(&bp, p[0], OREAD);
- while((s = Brdstr(&bp, '\n', 1))) {
- Dprint(DStack, "%s\n", s);
- free(s);
- }
- unlink(gdbcmd);
-
-done:
- free(gdbcmd);
- kill(pid, SIGKILL);
- waitpid(pid, &status, 0);
-}
-
-void
-backtrace(char *btarg) {
- int pid;
-
- /* Fork so we can backtrace the child. Keep this stack
- * frame minimal, so the trace is fairly clean.
- */
- Debug(DStack)
- switch(pid = fork()) {
- case -1:
- return;
- case 0:
- kill(getpid(), SIGSTOP);
- _exit(0);
- default:
- _backtrace(pid, btarg);
- break;
- }
-
-}
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/errors.c
--- a/lib/libstuff/x11/errors.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/errors.c Thu May 27 03:58:02 2010 -0400
@@ -13,8 +13,10 @@
 
         USED(dpy);
 
- if(_trap_errors)
+ if(_trap_errors) {
                 nerrors++;
+ return 0;
+ }
 
         e = ignored_xerrors;
         if(e)
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/initdisplay.c
--- a/lib/libstuff/x11/initdisplay.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/initdisplay.c Thu May 27 03:58:02 2010 -0400
@@ -44,6 +44,8 @@
         Window *w;
 
         w = va_arg(f->args, Window*);
+ if(w == nil)
+ return fmtstrcpy(f, "<nil>");
         return fmtprint(f, "0x%ulx", w->xid);
 }
 
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/insanity/gethints.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libstuff/x11/insanity/gethints.c Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,97 @@
+/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include <string.h>
+#include "../x11.h"
+
+void
+gethints(Window *w) {
+ XSizeHints xs;
+ XWMHints *wmh;
+ WinHints *h;
+ Point p;
+ long size;
+
+ if(w->hints == nil)
+ w->hints = emalloc(sizeof *h);
+
+ h = w->hints;
+ *h = ZWinHints;
+
+ wmh = XGetWMHints(display, w->xid);
+ if(wmh) {
+ if(wmh->flags & WindowGroupHint)
+ h->group = wmh->window_group;
+ free(wmh);
+ }
+
+ if(!XGetWMNormalHints(display, w->xid, &xs, &size))
+ return;
+
+ if(xs.flags & PMinSize) {
+ h->min.x = xs.min_width;
+ h->min.y = xs.min_height;
+ }
+ if(xs.flags & PMaxSize) {
+ h->max.x = xs.max_width;
+ h->max.y = xs.max_height;
+ }
+
+ /* Goddamn buggy clients. */
+ if(h->max.x < h->min.x)
+ h->max.x = h->min.x;
+ if(h->max.y < h->min.y)
+ h->max.y = h->min.y;
+
+ h->base = h->min;
+ if(xs.flags & PBaseSize) {
+ p.x = xs.base_width;
+ p.y = xs.base_height;
+ h->base = p;
+ h->baspect = p;
+ }
+
+ if(xs.flags & PResizeInc) {
+ h->inc.x = max(xs.width_inc, 1);
+ h->inc.y = max(xs.height_inc, 1);
+ }
+
+ if(xs.flags & PAspect) {
+ h->aspect.min.x = xs.min_aspect.x;
+ h->aspect.min.y = xs.min_aspect.y;
+ h->aspect.max.x = xs.max_aspect.x;
+ h->aspect.max.y = xs.max_aspect.y;
+ }
+
+ h->position = (xs.flags & (USPosition|PPosition)) != 0;
+
+ if(!(xs.flags & PWinGravity))
+ xs.win_gravity = NorthWestGravity;
+ p = ZP;
+ switch (xs.win_gravity) {
+ case EastGravity:
+ case CenterGravity:
+ case WestGravity:
+ p.y = 1;
+ break;
+ case SouthEastGravity:
+ case SouthGravity:
+ case SouthWestGravity:
+ p.y = 2;
+ break;
+ }
+ switch (xs.win_gravity) {
+ case NorthGravity:
+ case CenterGravity:
+ case SouthGravity:
+ p.x = 1;
+ break;
+ case NorthEastGravity:
+ case EastGravity:
+ case SouthEastGravity:
+ p.x = 2;
+ break;
+ }
+ h->grav = p;
+ h->gravstatic = (xs.win_gravity == StaticGravity);
+}
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/insanity/sethints.c
--- a/lib/libstuff/x11/insanity/sethints.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/insanity/sethints.c Thu May 27 03:58:02 2010 -0400
@@ -1,100 +1,97 @@
 /* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
  * See LICENSE file for license details.
  */
+#include "../x11.h"
 #include <string.h>
-#include "../x11.h"
+
+const WinHints ZWinHints = {
+ .inc = {1, 1},
+ .max = {INT_MAX, INT_MAX},
+};
+
+typedef struct GravityMap GravityMap;
+
+struct GravityMap {
+ Point point;
+ int gravity;
+};
+
+static GravityMap gravity_map[] = {
+ { {0, 0}, NorthWestGravity },
+ { {0, 1}, WestGravity },
+ { {0, 2}, SouthWestGravity },
+
+ { {1, 0}, NorthGravity },
+ { {1, 1}, CenterGravity },
+ { {1, 2}, SouthGravity },
+
+ { {2, 0}, NorthEastGravity },
+ { {2, 1}, EastGravity },
+ { {2, 2}, SouthEastGravity },
+};
 
 void
-sethints(Window *w) {
- XSizeHints xs;
- XWMHints *wmh;
- WinHints *h;
- Point p;
- long size;
+sethints(Window *w, WinHints *h) {
+ XSizeHints xhints = { 0, };
+ int i;
+
+ /* TODO: Group hint */
 
         if(w->hints == nil)
                 w->hints = emalloc(sizeof *h);
 
- h = w->hints;
- memset(h, 0, sizeof *h);
+ *w->hints = *h;
 
- h->max = Pt(INT_MAX, INT_MAX);
- h->inc = Pt(1,1);
-
- wmh = XGetWMHints(display, w->xid);
- if(wmh) {
- if(wmh->flags & WindowGroupHint)
- h->group = wmh->window_group;
- free(wmh);
+ if(!eqpt(h->min, ZP)) {
+ xhints.flags |= PMinSize;
+ xhints.min_width = h->min.x;
+ xhints.min_height = h->min.y;
+ }
+ if(!eqpt(h->max, Pt(INT_MAX, INT_MAX))) {
+ xhints.flags |= PMaxSize;
+ xhints.max_width = h->max.x;
+ xhints.max_height = h->max.y;
         }
 
- if(!XGetWMNormalHints(display, w->xid, &xs, &size))
- return;
-
- if(xs.flags & PMinSize) {
- h->min.x = xs.min_width;
- h->min.y = xs.min_height;
- }
- if(xs.flags & PMaxSize) {
- h->max.x = xs.max_width;
- h->max.y = xs.max_height;
+ if(!eqpt(h->base, ZP)) {
+ xhints.flags |= PBaseSize;
+ xhints.base_width = h->baspect.x;
+ xhints.base_height = h->baspect.y;
         }
 
- /* Goddamn buggy clients. */
- if(h->max.x < h->min.x)
- h->max.x = h->min.x;
- if(h->max.y < h->min.y)
- h->max.y = h->min.y;
+ if(!eqrect(h->aspect, ZR)) {
+ xhints.flags |= PAspect;
 
- h->base = h->min;
- if(xs.flags & PBaseSize) {
- p.x = xs.base_width;
- p.y = xs.base_height;
- h->base = p;
- h->baspect = p;
+ xhints.base_width = h->baspect.x;
+ xhints.base_height = h->baspect.y;
+
+ xhints.min_aspect.x = h->aspect.min.x;
+ xhints.min_aspect.y = h->aspect.min.y;
+
+ xhints.max_aspect.x = h->aspect.max.x;
+ xhints.max_aspect.y = h->aspect.max.y;
         }
 
- if(xs.flags & PResizeInc) {
- h->inc.x = max(xs.width_inc, 1);
- h->inc.y = max(xs.height_inc, 1);
+ if(!eqpt(h->inc, Pt(1, 1))) {
+ xhints.flags |= PResizeInc;
+ xhints.width_inc = h->inc.x;
+ xhints.height_inc = h->inc.y;
         }
 
- if(xs.flags & PAspect) {
- h->aspect.min.x = xs.min_aspect.x;
- h->aspect.min.y = xs.min_aspect.y;
- h->aspect.max.x = xs.max_aspect.x;
- h->aspect.max.y = xs.max_aspect.y;
- }
+ /* USPosition is probably an evil assumption, but it holds in our use cases. */
+ if(h->position)
+ xhints.flags |= USPosition | PPosition;
 
- h->position = (xs.flags & (USPosition|PPosition)) != 0;
+ xhints.flags |= PWinGravity;
+ if(h->gravstatic)
+ xhints.win_gravity = StaticGravity;
+ else
+ for(i=0; i < nelem(gravity_map); i++)
+ if(h->grav.x == gravity_map[i].point.x &&
+ h->grav.y == gravity_map[i].point.y) {
+ xhints.win_gravity = gravity_map[i].gravity;
+ break;
+ }
 
- if(!(xs.flags & PWinGravity))
- xs.win_gravity = NorthWestGravity;
- p = ZP;
- switch (xs.win_gravity) {
- case EastGravity:
- case CenterGravity:
- case WestGravity:
- p.y = 1;
- break;
- case SouthEastGravity:
- case SouthGravity:
- case SouthWestGravity:
- p.y = 2;
- break;
- }
- switch (xs.win_gravity) {
- case NorthGravity:
- case CenterGravity:
- case SouthGravity:
- p.x = 1;
- break;
- case NorthEastGravity:
- case EastGravity:
- case SouthEastGravity:
- p.x = 2;
- break;
- }
- h->grav = p;
- h->gravstatic = (xs.win_gravity == StaticGravity);
+ XSetWMNormalHints(display, w->xid, &xhints);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/properties/changeprop_textlist.c
--- a/lib/libstuff/x11/properties/changeprop_textlist.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/properties/changeprop_textlist.c Thu May 27 03:58:02 2010 -0400
@@ -19,6 +19,6 @@
                 memcpy(t, *p, n);
                 t += n;
         }
- changeprop_char(w, prop, type, s, len);
+ changeprop_char(w, prop, type, s, len - 1);
         free(s);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/sendevent.c
--- a/lib/libstuff/x11/sendevent.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/sendevent.c Thu May 27 03:58:02 2010 -0400
@@ -4,6 +4,7 @@
 #include "x11.h"
 
 void
-sendevent(Window *w, bool propegate, long mask, XEvent *e) {
+sendevent(Window *w, bool propegate, long mask, void *e) {
         XSendEvent(display, w->xid, propegate, mask, e);
 }
+
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/sendmessage.c
--- a/lib/libstuff/x11/sendmessage.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/sendmessage.c Thu May 27 03:58:02 2010 -0400
@@ -2,19 +2,23 @@
  * See LICENSE file for license details.
  */
 #include "x11.h"
+#include <string.h>
 
 void
 sendmessage(Window *w, char *name, long l0, long l1, long l2, long l3, long l4) {
+
+ clientmessage(w, name, NoEventMask, 32, (ClientMessageData){ .l = { l0, l1, l2, l3, l4 } });
+}
+
+void
+clientmessage(Window *w, char *name, long mask, int format, ClientMessageData data) {
         XClientMessageEvent e;
 
         e.type = ClientMessage;
         e.window = w->xid;
         e.message_type = xatom(name);
- e.format = 32;
- e.data.l[0] = l0;
- e.data.l[1] = l1;
- e.data.l[2] = l2;
- e.data.l[3] = l3;
- e.data.l[4] = l4;
- sendevent(w, false, NoEventMask, (XEvent*)&e);
+ e.format = format;
+ bcopy(&data, &e.data, sizeof(data));
+ sendevent(w, false, mask, (XEvent*)&e);
 }
+
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/windows/createwindow_visual.c
--- a/lib/libstuff/x11/windows/createwindow_visual.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/windows/createwindow_visual.c Thu May 27 03:58:02 2010 -0400
@@ -2,6 +2,10 @@
  * See LICENSE file for license details.
  */
 #include "../x11.h"
+#include <string.h>
+#include <unistd.h>
+
+static char hostname[HOST_NAME_MAX + 1];
 
 Window*
 createwindow_visual(Window *parent, Rectangle r,
@@ -21,6 +25,8 @@
         w->parent = parent;
         if(valmask & CWColormap)
                 w->colormap = wa->colormap;
+ if(valmask & CWEventMask)
+ w->eventmask = wa->event_mask;
 
         w->xid = XCreateWindow(display, parent->xid, r.min.x, r.min.y, Dx(r), Dy(r),
                                 0 /* border */, depth, class, vis, valmask, wa);
@@ -31,6 +37,12 @@
         if(class != InputOnly)
                 w->gc = XCreateGC(display, w->xid, 0, nil);
 
+ changeprop_ulong(w, "_NET_WM_PID", "CARDINAL", (ulong[1]){ getpid() }, 1);
+ if(!hostname[0])
+ gethostname(hostname, sizeof(hostname) - 1);
+ if(hostname[0])
+ changeprop_char(w, "WM_CLIENT_MACHINE", "STRING", hostname, strlen(hostname));
+
         w->r = r;
         w->depth = depth;
         return w;
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/windows/destroywindow.c
--- a/lib/libstuff/x11/windows/destroywindow.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/windows/destroywindow.c Thu May 27 03:58:02 2010 -0400
@@ -7,6 +7,8 @@
 destroywindow(Window *w) {
         assert(w->type == WWindow);
         sethandler(w, nil);
+ while(w->handler_link)
+ pophandler(w, w->handler_link->handler);
         if(w->xft)
                 xft->drawdestroy(w->xft);
         if(w->gc)
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/windows/selectinput.c
--- a/lib/libstuff/x11/windows/selectinput.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/windows/selectinput.c Thu May 27 03:58:02 2010 -0400
@@ -5,5 +5,6 @@
 
 void
 selectinput(Window *w, long mask) {
+ w->eventmask = mask;
         XSelectInput(display, w->xid, mask);
 }
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/x11/windows/sethandler.c
--- a/lib/libstuff/x11/windows/sethandler.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/x11/windows/sethandler.c Thu May 27 03:58:02 2010 -0400
@@ -3,21 +3,72 @@
  */
 #include "../x11.h"
 
-Handlers*
-sethandler(Window *w, Handlers *new) {
- Handlers *old;
+static void
+updatemap(Window *w) {
         void **e;
 
         assert(w->type == WWindow);
         assert((w->prev != nil && w->next != nil) || w->next == w->prev);
 
- if(new == nil)
+ if(w->handler == nil && w->handler_link == nil)
                 map_rm(&windowmap, (ulong)w->xid);
         else {
                 e = map_get(&windowmap, (ulong)w->xid, true);
                 *e = w;
         }
+}
+
+Handlers*
+sethandler(Window *w, Handlers *new) {
+ Handlers *old;
+
         old = w->handler;
         w->handler = new;
+
+ updatemap(w);
         return old;
 }
+
+static HandlersLink* free_link;
+
+void
+pushhandler(Window *w, Handlers *new, void *aux) {
+ HandlersLink *l;
+ int i;
+
+ if(free_link == nil) {
+ l = emalloc(16 * sizeof *l);
+ for(i=0; i < 16; i++) {
+ l[i].next = free_link;
+ free_link = l;
+ }
+ }
+ l = free_link;
+ free_link = l->next;
+
+ /* TODO: Maybe: pophandler(w, new); */
+
+ l->next = w->handler_link;
+ l->handler = new;
+ l->aux = aux;
+ w->handler_link = l;
+
+ updatemap(w);
+}
+
+bool
+pophandler(Window *w, Handlers *old) {
+ HandlersLink **lp;
+ HandlersLink *l;
+
+ for(lp=&w->handler_link; (l=*lp); lp=&l->next)
+ if(l->handler == old) {
+ *lp = l->next;
+ l->next = free_link;
+ free_link = l;
+ updatemap(w);
+ return true;
+ }
+ return false;
+}
+
diff -r 4d765bd540b8 -r 91080b00b924 lib/libstuff/xext.c
--- a/lib/libstuff/xext.c Wed May 26 09:20:14 2010 -0400
+++ b/lib/libstuff/xext.c Thu May 27 03:58:02 2010 -0400
@@ -4,6 +4,7 @@
 #define _X11_VISIBLE
 #include <stuff/x.h>
 #include <stuff/util.h>
+#include <X11/extensions/Xrandr.h>
 #include <X11/extensions/Xrender.h>
 #include <X11/extensions/Xinerama.h>
 
diff -r 4d765bd540b8 -r 91080b00b924 man/Makefile
--- a/man/Makefile Wed May 26 09:20:14 2010 -0400
+++ b/man/Makefile Thu May 27 03:58:02 2010 -0400
@@ -7,7 +7,8 @@
         wmii9menu.1\
         wihack.1 \
         wimenu.1 \
- wistrut.1
+ wistrut.1 \
+ witray.1
 
 $(TARG): Makefile $(ROOT)/mk/wmii.mk header.t2t
 
diff -r 4d765bd540b8 -r 91080b00b924 man/wimenu.1
--- a/man/wimenu.1 Wed May 26 09:20:14 2010 -0400
+++ b/man/wimenu.1 Thu May 27 03:58:02 2010 -0400
@@ -193,7 +193,7 @@
 
 .SH SEE ALSO
 .P
-wmii(1), wmiir(1), wmii9menu(1), dmenu(1)
+wmii(1), wmiir(1), wistrug(1), wmii9menu(1), dmenu(1)
 
 .P
 \fI[1]\fR http://www.suckless.org/wiki/wmii/tips/9p_tips
diff -r 4d765bd540b8 -r 91080b00b924 man/wimenu.man1
--- a/man/wimenu.man1 Wed May 26 09:20:14 2010 -0400
+++ b/man/wimenu.man1 Thu May 27 03:58:02 2010 -0400
@@ -168,7 +168,7 @@
         provided.
 :
 = SEE ALSO =
-wmii(1), wmiir(1), wmii9menu(1), dmenu(1)
+wmii(1), wmiir(1), wistrug(1), wmii9menu(1), dmenu(1)
 
 [1] http://www.suckless.org/wiki/wmii/tips/9p_tips
 
diff -r 4d765bd540b8 -r 91080b00b924 man/wistrut.1
--- a/man/wistrut.1 Wed May 26 09:20:14 2010 -0400
+++ b/man/wistrut.1 Thu May 27 03:58:02 2010 -0400
@@ -1,4 +1,4 @@
-.TH "WIMENU" 1 "May, 2010" "wmii-_AT_VERSION@"
+.TH "WISTRUT" 1 "May, 2010" "wmii-_AT_VERSION@"
 
 .SH NAME
 .P
diff -r 4d765bd540b8 -r 91080b00b924 man/wistrut.man1
--- a/man/wistrut.man1 Wed May 26 09:20:14 2010 -0400
+++ b/man/wistrut.man1 Thu May 27 03:58:02 2010 -0400
@@ -1,4 +1,4 @@
-WIMENU
+WISTRUT
 wmii-_AT_VERSION@
 May, 2010
 
diff -r 4d765bd540b8 -r 91080b00b924 man/witray.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/witray.1 Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,85 @@
+.TH "WITRAY" 1 "May, 2010" "wmii-_AT_VERSION@"
+
+.SH NAME
+.P
+witray \- The wmii system tray
+
+.SH SYNOPSIS
+.P
+witray \fI[\-a \fI<address>\fR]\fR \fI[\-NESW]\fR \fI[\-HV]\fR \fI[\-p \fI<padding>\fR]\fR \fI[\-s \fI<iconsize>\fR]\fR \-t (tags)
+.P
+witray \-v
+
+.SH DESCRIPTION
+.P
+\fBwitray\fR is a simple system tray program meant to be used with wmii.
+It supports the Freedesktop System Tray Protocol Specification
+common among all newer applications and desktop environments. The
+tray is only visible when applications require it. While there are
+many standalone system tray applications, this one is explicitly
+tailored to wmii. It's simple, stays out of the user's way, is easy
+to configure, and generally Just Works.
+
+.SH ARGUMENTS
+.TP
+\-a
+The address at which to connect to \fBwmii\fR.
+.TP
+\-N \-E \-S \-W
+
+.RS
+Sets the screen edge where \fBwitray\fR is to appear to the
+\fINorth\fR, \fISouth\fR, \fIEast\fR, or \fIWest\fR edge, respectively.
+Options may be combined, for instance *\-NE* gives the _North
+East_ corner of the screen. If no options are given,
+\fBwitray\fR opens to the West of whichever part of the screen
+the wmii bar occupies.
+.RE
+.TP
+\-H \-V
+
+.RS
+Specifies whether icons are to be aligned horizontally or
+vertically, respectively. Also determines from which edge of
+the screen windows are shunted to make room for the tray.
+.RE
+.TP
+\-p \fI<padding>\fR
+
+.RS
+Sets the padding between icons and around the edge of the
+tray. In pixels.
+.RE
+.TP
+\-s \fI<iconsize>\fR
+
+.RS
+Sets the size of the icons, in pixels. If not provided,
+icons are sized so that the tray is the same height as the
+\fBwmii\fR bar.
+.RE
+.TP
+\-t \fI<tags>\fR
+
+.RS
+The tags on which to open. Default: \fI/./\fR
+.RE
+.TP
+\-v
+
+.RS
+Display version information.
+.RE
+
+.SH CAVEATS
+.P
+\fBwitray\fR is not XRandR aware.
+
+.SH SEE ALSO
+.P
+wmii(1), wimenu(1)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- witray.man1
+
diff -r 4d765bd540b8 -r 91080b00b924 man/witray.man1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/witray.man1 Thu May 27 03:58:02 2010 -0400
@@ -0,0 +1,60 @@
+WITRAY
+wmii-_AT_VERSION@
+May, 2010
+
+%!includeconf: header.t2t
+
+= NAME =
+
+witray - The wmii system tray
+
+= SYNOPSIS =
+
+witray [-a <address>] [-NESW] [-HV] [-p <padding>] [-s <iconsize>] [-t tags] +
+witray -v
+
+= DESCRIPTION =
+
+`witray` is a simple system tray program meant to be used with wmii.
+It supports the Freedesktop System Tray Protocol Specification
+common among all newer applications and desktop environments. The
+tray is only visible when applications require it. While there are
+many standalone system tray applications, this one is explicitly
+tailored to wmii. It's simple, stays out of the user's way, is easy
+to configure, and generally Just Works.
+
+= ARGUMENTS =
+
+: -a
+ The address at which to connect to `wmii`.
+: -N -E -S -W
+ Sets the screen edge where `witray` is to appear to the
+ _North_, _South_, _East_, or _West_ edge, respectively.
+ Options may be combined, for instance *-NE* gives the _North
+ East_ corner of the screen. If no options are given,
+ `witray` opens to the West of whichever part of the screen
+ the wmii bar occupies.
+: -H -V
+ Specifies whether icons are to be aligned horizontally or
+ vertically, respectively. Also determines from which edge of
+ the screen windows are shunted to make room for the tray.
+: -p <padding>
+ Sets the padding between icons and around the edge of the
+ tray. In pixels.
+: -s <iconsize>
+ Sets the size of the icons, in pixels. If not provided,
+ icons are sized so that the tray is the same height as the
+ `wmii` bar.
+: -t <tags>
+ The tags on which to open. Default: _/./_
+: -v
+ Display version information.
+
+= CAVEATS =
+
+`witray` is not XRandR aware.
+
+= SEE ALSO =
+
+wmii(1), wimenu(1)
+
diff -r 4d765bd540b8 -r 91080b00b924 util/compile
--- a/util/compile Wed May 26 09:20:14 2010 -0400
+++ b/util/compile Thu May 27 03:58:02 2010 -0400
@@ -14,7 +14,7 @@
 [ -n "$noisycc" ] && echo $CC -o $outfile $CFLAGS $@
 eval '$CC -o $outfile '"$CFLAGS"' $@ >$xtmp 2>&1'
 status=$?
-[ $? -eq 0 ] || echo $CC -o $outfile $CFLAGS $@ >&2
+[ $status -eq 0 ] || echo $CC -o $outfile $CFLAGS $@ >&2
 
 base=$(echo $BASE | sed 's/,/\\,/g')
 re='\([^[:space:]/][^[:space:]]*\..:[0-9]\)'
Received on Thu May 27 2010 - 07:58:20 UTC

This archive was generated by hypermail 2.2.0 : Thu May 27 2010 - 08:00:09 UTC