diff --git a/PKGBUILD b/PKGBUILD index de8a31c1..ba2d13c9 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -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 @@ provides=("wmii") 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 @@ build() 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 --git a/cmd/Makefile b/cmd/Makefile index 358a2148..b9606b68 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -6,7 +6,8 @@ wmiir.c: $(ROOT)/mk/wmii.mk DIRS = wmii \ menu \ - strut + strut \ + tray TARG = wihack \ wmii.rc \ wmii.sh \ diff --git a/cmd/menu/Makefile b/cmd/menu/Makefile index e284d301..854f25cb 100644 --- a/cmd/menu/Makefile +++ b/cmd/menu/Makefile @@ -12,7 +12,7 @@ bindings.c: keys.txt Makefile TARG = wimenu HFILES= dat.h fns.h -PACKAGES += $(X11PACKAGES) xext xrandr xrender xinerama +PACKAGES += $(X11PACKAGES) LIBS += -lm $(LIBS9) $(LIBIXP) CFLAGS += -DIXP_NEEDAPI=86 diff --git a/cmd/menu/dat.h b/cmd/menu/dat.h index 533568c9..0c3efd97 100644 --- a/cmd/menu/dat.h +++ b/cmd/menu/dat.h @@ -7,9 +7,9 @@ #include #include #include +#include #include #include -#include #define BLOCK(x) do { x; }while(0) diff --git a/cmd/menu/main.c b/cmd/menu/main.c index 0d56304d..0b114526 100644 --- a/cmd/menu/main.c +++ b/cmd/menu/main.c @@ -171,20 +171,6 @@ update_filter(bool print) { 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 @@ main(int argc, char *argv[]) { quotefmtinstall(); fmtinstall('r', errfmt); - address = getenv("WMII_ADDRESS"); screen_hint = PointerScreen; find = strstr; @@ -283,17 +268,18 @@ main(int argc, char *argv[]) { 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 --git a/cmd/menu/menu.c b/cmd/menu/menu.c index c947ec4b..12f0d42e 100644 --- a/cmd/menu/menu.c +++ b/cmd/menu/menu.c @@ -255,7 +255,7 @@ menu_show(void) { } 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 @@ kdown_event(Window *w, XKeyEvent *e) { } static void -expose_event(Window *w, XExposeEvent *e) { +expose_event(Window *w, void *aux, XExposeEvent *e) { USED(w); menu_draw(); diff --git a/cmd/strut/Makefile b/cmd/strut/Makefile index 6e1cbf35..30b193ac 100644 --- a/cmd/strut/Makefile +++ b/cmd/strut/Makefile @@ -7,9 +7,8 @@ main.c: $(ROOT)/mk/wmii.mk 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 --git a/cmd/strut/dat.h b/cmd/strut/dat.h index 826f9971..50b539d3 100644 --- a/cmd/strut/dat.h +++ b/cmd/strut/dat.h @@ -5,7 +5,6 @@ #include #include #include -#include #ifndef EXTERN # define EXTERN extern diff --git a/cmd/strut/fns.h b/cmd/strut/fns.h index 9e3a30e5..8b70f3fc 100644 --- a/cmd/strut/fns.h +++ b/cmd/strut/fns.h @@ -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 --git a/cmd/strut/main.c b/cmd/strut/main.c index 6e20d263..2c55f628 100644 --- a/cmd/strut/main.c +++ b/cmd/strut/main.c @@ -21,11 +21,6 @@ usage(void) { fatal("usage: %s [-HV] ...\n", argv0); } -static int -errfmt(Fmt *f) { - return fmtstrcpy(f, ixp_errbuf()); -} - static void search_wins(char *pattern) { ulong *wins; @@ -135,7 +130,6 @@ main(int argc, char *argv[]) { ulong win; char *s; - fmtinstall('r', errfmt); fmtinstall('E', fmtevent); ARGBEGIN{ diff --git a/cmd/strut/win.c b/cmd/strut/win.c index 071824e3..8e85894e 100644 --- a/cmd/strut/win.c +++ b/cmd/strut/win.c @@ -80,22 +80,23 @@ restrut(Window *frame) { } 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 --git a/cmd/tray/Makefile b/cmd/tray/Makefile new file mode 100644 index 00000000..3ecba941 --- /dev/null +++ b/cmd/tray/Makefile @@ -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 --git a/cmd/tray/client.c b/cmd/tray/client.c new file mode 100644 index 00000000..29b5a11f --- /dev/null +++ b/cmd/tray/client.c @@ -0,0 +1,190 @@ +/* Copyright ©2010 Kris Maglione + * See LICENSE file for license details. + */ +#include "dat.h" +#include "fns.h" +#include + +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 --git a/cmd/tray/dat.h b/cmd/tray/dat.h new file mode 100644 index 00000000..6579ad9e --- /dev/null +++ b/cmd/tray/dat.h @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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 --git a/cmd/tray/ewmh.c b/cmd/tray/ewmh.c new file mode 100644 index 00000000..1bded020 --- /dev/null +++ b/cmd/tray/ewmh.c @@ -0,0 +1,45 @@ +/* Copyright ©2007-2010 Kris Maglione + * See LICENSE file for license details. + */ +#include "dat.h" +#include +#include +#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 + * See LICENSE file for license details. + */ +#define EXTERN +#include "dat.h" +#include +#include +#include +#include +#include +#include +#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
] [-NESW] [-HV] [-p ] [-s ] [-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 --git a/cmd/tray/selection.c b/cmd/tray/selection.c new file mode 100644 index 00000000..a5e71ead --- /dev/null +++ b/cmd/tray/selection.c @@ -0,0 +1,144 @@ +/* Copyright ©2010 Kris Maglione + * 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 +#include + +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, ¬ify); +} + +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 --git a/cmd/tray/tray.c b/cmd/tray/tray.c new file mode 100644 index 00000000..ad907248 --- /dev/null +++ b/cmd/tray/tray.c @@ -0,0 +1,257 @@ +/* Copyright ©2008-2010 Kris Maglione + * See LICENSE file for license details. + */ +#include "dat.h" +#include +#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 --git a/cmd/tray/xembed.c b/cmd/tray/xembed.c new file mode 100644 index 00000000..ff72611e --- /dev/null +++ b/cmd/tray/xembed.c @@ -0,0 +1,128 @@ +/* Copyright ©2010 Kris Maglione + * 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 --git a/cmd/wmii/Makefile b/cmd/wmii/Makefile index 10e9efe0..05a494f5 100644 --- a/cmd/wmii/Makefile +++ b/cmd/wmii/Makefile @@ -15,6 +15,7 @@ LIBS += -lm $(LIBS9) CFLAGS += $(INCICONV) -DIXP_NEEDAPI=97 OBJ = area \ bar \ + backtrace \ client \ column \ div \ diff --git a/lib/libstuff/util/backtrace.c b/cmd/wmii/backtrace.c similarity index 97% rename from lib/libstuff/util/backtrace.c rename to cmd/wmii/backtrace.c index 8c86bbfb..d459c489 100644 --- a/lib/libstuff/util/backtrace.c +++ b/cmd/wmii/backtrace.c @@ -10,8 +10,8 @@ #include #include #undef nelem -#include -#include "util.h" +#include +#include "debug.h" #ifdef __linux__ # define PROGTXT "exe" diff --git a/cmd/wmii/bar.c b/cmd/wmii/bar.c index fd4ba26c..3c3c126f 100644 --- a/cmd/wmii/bar.c +++ b/cmd/wmii/bar.c @@ -246,7 +246,7 @@ findbar(WMScreen *s, Point p) { } static void -bdown_event(Window *w, XButtonPressedEvent *e) { +bdown_event(Window *w, void *aux, XButtonPressedEvent *e) { WMScreen *s; Bar *b; @@ -254,29 +254,29 @@ bdown_event(Window *w, XButtonPressedEvent *e) { 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 @@ dndmotion_event(Window *w, Point p) { } 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 --git a/cmd/wmii/client.c b/cmd/wmii/client.c index 26c6df15..bc1129a7 100644 --- a/cmd/wmii/client.c +++ b/cmd/wmii/client.c @@ -101,9 +101,8 @@ client_create(XWindow w, XWindowAttributes *wa) { 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 @@ client_create(XWindow w, XWindowAttributes *wa) { c->ibuf = &ibuf; if(render_argb_p(wa->visual)) { depth = 32; - vis = render_visual; + vis = scr.visual32; c->ibuf = &ibuf32; } @@ -589,7 +588,7 @@ client_configure(Client *c) { 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 @@ client_prop(Client *c, Atom a) { 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 @@ client_prop(Client *c, Atom a) { /* 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 @@ configreq_event(Window *w, XConfigureRequestEvent *e) { } 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 @@ enter_event(Window *w, XCrossingEvent *e) { } 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 @@ focusin_event(Window *w, XFocusChangeEvent *e) { } 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 @@ focusout_event(Window *w, XFocusChangeEvent *e) { } 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 @@ client_setviews(Client *c, char **tags) { 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 --git a/cmd/wmii/dat.h b/cmd/wmii/dat.h index 2308ea00..bc01d9a9 100644 --- a/cmd/wmii/dat.h +++ b/cmd/wmii/dat.h @@ -12,10 +12,10 @@ #include #include #include +#include #include #include -#include -#include +#include "debug.h" #define FONT "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*" #define FOCUSCOLORS "#ffffff #335577 #447799" diff --git a/include/debug.h b/cmd/wmii/debug.h similarity index 71% rename from include/debug.h rename to cmd/wmii/debug.h index 03be1475..afcfa830 100644 --- a/include/debug.h +++ b/cmd/wmii/debug.h @@ -1,5 +1,16 @@ #include +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__) ) diff --git a/cmd/wmii/div.c b/cmd/wmii/div.c index 986d6a28..fe48b159 100644 --- a/cmd/wmii/div.c +++ b/cmd/wmii/div.c @@ -164,22 +164,22 @@ div_update_all(void) { /* 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 --git a/cmd/wmii/event.c b/cmd/wmii/event.c index 2eb6da37..8ffd338b 100644 --- a/cmd/wmii/event.c +++ b/cmd/wmii/event.c @@ -10,15 +10,12 @@ debug_event(XEvent *e) { 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 @@ event_configurenotify(XConfigureEvent *ev) { ignoreenter = ev->serial; if((w = findwin(ev->window))) - handle(w, config, ev); + event_handle(w, config, ev); } void @@ -47,7 +44,7 @@ event_destroynotify(XDestroyWindowEvent *ev) { 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 @@ event_focusin(XFocusChangeEvent *ev) { 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 @@ event_focusout(XFocusChangeEvent *ev) { && 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 @@ event_mapnotify(XMapEvent *ev) { ignoreenter = ev->serial; if((w = findwin(ev->window))) - handle(w, map, ev); + event_handle(w, map, ev); } void @@ -137,7 +134,7 @@ event_unmapnotify(XUnmapEvent *ev) { 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 --git a/cmd/wmii/frame.c b/cmd/wmii/frame.c index 1c6f4a87..8656360f 100644 --- a/cmd/wmii/frame.c +++ b/cmd/wmii/frame.c @@ -29,6 +29,9 @@ frame_create(Client *c, View *v) { 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 @@ frame_restack(Frame *f, Frame *above) { /* 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 @@ bdown_event(Window *w, XButtonEvent *e) { } 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 @@ enter_event(Window *w, XCrossingEvent *e) { } 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 @@ expose_event(Window *w, XExposeEvent *e) { } 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 --git a/cmd/wmii/layout.c b/cmd/wmii/layout.c index a089e0a6..5fb70c07 100644 --- a/cmd/wmii/layout.c +++ b/cmd/wmii/layout.c @@ -99,7 +99,7 @@ framedestroy(Framewin *f) { } 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 @@ expose_event(Window *w, XExposeEvent *e) { USED(e); - f = w->aux; + f = aux; c = &def.focuscolor; buf = disp.ibuf; diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c index cec4edc4..3761199c 100644 --- a/cmd/wmii/main.c +++ b/cmd/wmii/main.c @@ -317,13 +317,6 @@ spawn_command(const char *cmd) { } } -static void -check_preselect(IxpServer *s) { - USED(s); - - event_check(); -} - static void closedisplay(IxpConn *c) { USED(c); @@ -412,9 +405,9 @@ extern int fmtevent(Fmt*); 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 --git a/cmd/wmii/mouse.c b/cmd/wmii/mouse.c index 47a0a34c..44195505 100644 --- a/cmd/wmii/mouse.c +++ b/cmd/wmii/mouse.c @@ -29,7 +29,7 @@ quad_cursor(Align align) { } 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 --git a/cmd/wmii/root.c b/cmd/wmii/root.c index e3e53e77..f35742dc 100644 --- a/cmd/wmii/root.c +++ b/cmd/wmii/root.c @@ -24,13 +24,13 @@ root_init(void) { } 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 @@ leave_event(Window *w, XCrossingEvent *e) { } 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 @@ mapreq_event(Window *w, XMapRequestEvent *e) { } 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 @@ motion_event(Window *w, XMotionEvent *e) { } 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 --git a/cmd/wmii/xdnd.c b/cmd/wmii/xdnd.c index abb36129..92969e10 100644 --- a/cmd/wmii/xdnd.c +++ b/cmd/wmii/xdnd.c @@ -71,7 +71,7 @@ xdnd_clientmessage(XClientMessageEvent *e) { 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 --git a/config.mk b/config.mk index 60499a89..79dc4f26 100644 --- a/config.mk +++ b/config.mk @@ -26,7 +26,7 @@ LD = cc # Archiver AR = ar crs -X11PACKAGES = x11 xinerama xrender +X11PACKAGES = x11 xinerama xrender xrandr INCX11 = $$(pkg-config --cflags $(X11PACKAGES)) LIBIXP = $(LIBDIR)/libixp.a diff --git a/include/stuff/base.h b/include/stuff/base.h index e9d2d577..2d4ad773 100644 --- a/include/stuff/base.h +++ b/include/stuff/base.h @@ -1,18 +1,25 @@ #pragma once #define _XOPEN_SOURCE 600 +#include #include #include #include #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 --git a/include/stuff/util.h b/include/stuff/util.h index a8367872..aed909b8 100644 --- a/include/stuff/util.h +++ b/include/stuff/util.h @@ -22,16 +22,7 @@ enum { 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 --git a/include/stuff/x.h b/include/stuff/x.h index 2786ebd2..a8fa376a 100644 --- a/include/stuff/x.h +++ b/include/stuff/x.h @@ -16,11 +16,21 @@ void xext_event(XEvent*); 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_focusout(XFocusChangeEvent*); void event_keypress(XKeyEvent*); void event_leavenotify(XCrossingEvent*); void event_mapnotify(XMapEvent*); -void event_maprequest(XMapRequestEvent*); void event_mappingnotify(XMappingEvent*); +void event_maprequest(XMapRequestEvent*); 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 --git a/include/stuff/x11.h b/include/stuff/x11.h index fc12903d..f2b5ddc0 100644 --- a/include/stuff/x11.h +++ b/include/stuff/x11.h @@ -33,12 +33,14 @@ typedef enum WindowType WindowType; 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 struct XftColor XftColor; 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 Font { }; 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 @@ struct Window { 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 windowmap; 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 @@ XRectangle XRect(Rectangle r); (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_string(Window*, char*, char*); 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 freefont(Font*); 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 @@ void movewin(Window*, Point); 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*); -int traperrors(bool); Point translate(Window*, Window*, Point); +int traperrors(bool); void ungrabkeyboard(void); void ungrabpointer(void); int unmapwin(Window*); @@ -273,9 +304,4 @@ Window* window(XWindow); 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 --git a/lib/libstuff/Makefile b/lib/libstuff/Makefile index f24fb2d7..42d38c60 100644 --- a/lib/libstuff/Makefile +++ b/lib/libstuff/Makefile @@ -19,6 +19,7 @@ OBJ=\ event/expose \ event/focusin \ event/focusout \ + event/ixp \ event/keypress \ event/leavenotify \ event/mapnotify \ @@ -26,6 +27,10 @@ OBJ=\ 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 @@ OBJ=\ map \ printevent \ util/_die \ - util/backtrace \ util/closeexec \ util/comm \ util/doublefork \ @@ -114,6 +118,7 @@ OBJ=\ x11/images/freeimage \ x11/images/xftdrawable \ x11/insanity/gravitate \ + x11/insanity/gethints \ x11/insanity/sethints \ x11/insanity/sizehint \ x11/keyboard/grabkeyboard \ diff --git a/lib/libstuff/clientutil.c b/lib/libstuff/clientutil.c index 8d7f3006..13413967 100644 --- a/lib/libstuff/clientutil.c +++ b/lib/libstuff/clientutil.c @@ -1,6 +1,7 @@ #define IXP_NO_P9_ #define IXP_P9_STRUCTS #define CLIENTEXTERN +#include #include #include #include @@ -40,11 +41,13 @@ readctl(char *key) { 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 --git a/lib/libstuff/event/buttonpress.c b/lib/libstuff/event/buttonpress.c index d43cd7d7..30342038 100644 --- a/lib/libstuff/event/buttonpress.c +++ b/lib/libstuff/event/buttonpress.c @@ -8,7 +8,7 @@ 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); } diff --git a/lib/libstuff/event/buttonrelease.c b/lib/libstuff/event/buttonrelease.c index 4848d559..9a7fb49b 100644 --- a/lib/libstuff/event/buttonrelease.c +++ b/lib/libstuff/event/buttonrelease.c @@ -8,5 +8,5 @@ event_buttonrelease(XButtonPressedEvent *ev) { Window *w; if((w = findwin(ev->window))) - handle(w, bup, ev); + event_handle(w, bup, ev); } diff --git a/lib/libstuff/event/clientmessage.c b/lib/libstuff/event/clientmessage.c index 11be5323..2ad8aeb7 100644 --- a/lib/libstuff/event/clientmessage.c +++ b/lib/libstuff/event/clientmessage.c @@ -5,6 +5,8 @@ void event_clientmessage(XClientMessageEvent *ev) { + Window *w; - USED(ev); + if((w = findwin(ev->window))) + event_handle(w, message, ev); } diff --git a/lib/libstuff/event/configurenotify.c b/lib/libstuff/event/configurenotify.c index a008a3ff..55353555 100644 --- a/lib/libstuff/event/configurenotify.c +++ b/lib/libstuff/event/configurenotify.c @@ -8,5 +8,5 @@ event_configurenotify(XConfigureEvent *ev) { Window *w; if((w = findwin(ev->window))) - handle(w, config, ev); + event_handle(w, config, ev); } diff --git a/lib/libstuff/event/configurerequest.c b/lib/libstuff/event/configurerequest.c index e080ef79..739d2b89 100644 --- a/lib/libstuff/event/configurerequest.c +++ b/lib/libstuff/event/configurerequest.c @@ -9,7 +9,7 @@ event_configurerequest(XConfigureRequestEvent *ev) { 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 --git a/lib/libstuff/event/destroynotify.c b/lib/libstuff/event/destroynotify.c index d89f5bae..36effdf3 100644 --- a/lib/libstuff/event/destroynotify.c +++ b/lib/libstuff/event/destroynotify.c @@ -8,5 +8,5 @@ event_destroynotify(XDestroyWindowEvent *ev) { Window *w; if((w = findwin(ev->window))) - handle(w, destroy, ev); + event_handle(w, destroy, ev); } diff --git a/lib/libstuff/event/enternotify.c b/lib/libstuff/event/enternotify.c index d838c7f3..07ff1650 100644 --- a/lib/libstuff/event/enternotify.c +++ b/lib/libstuff/event/enternotify.c @@ -7,10 +7,11 @@ void 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 --git a/lib/libstuff/event/event.c b/lib/libstuff/event/event.c index 4e9f941c..79f9b119 100644 --- a/lib/libstuff/event/event.c +++ b/lib/libstuff/event/event.c @@ -3,6 +3,7 @@ */ #include "event.h" +typedef void (*Handler)(Window*, void*, XEvent*); void (*event_debug)(XEvent*); long event_xtime; bool event_looprunning; @@ -25,9 +26,29 @@ EventHandler event_handler[LASTEvent] = { [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) diff --git a/lib/libstuff/event/expose.c b/lib/libstuff/event/expose.c index 4e098840..2e3e5689 100644 --- a/lib/libstuff/event/expose.c +++ b/lib/libstuff/event/expose.c @@ -8,5 +8,5 @@ event_expose(XExposeEvent *ev) { Window *w; if(ev->count == 0 && (w = findwin(ev->window))) - handle(w, expose, ev); + event_handle(w, expose, ev); } diff --git a/lib/libstuff/event/focusin.c b/lib/libstuff/event/focusin.c index be6c8bf6..3c3b2b88 100644 --- a/lib/libstuff/event/focusin.c +++ b/lib/libstuff/event/focusin.c @@ -23,5 +23,5 @@ event_focusin(XFocusChangeEvent *ev) { return; if((w = findwin(ev->window))) - handle(w, focusin, ev); + event_handle(w, focusin, ev); } diff --git a/lib/libstuff/event/focusout.c b/lib/libstuff/event/focusout.c index 61d98ed3..ade1362c 100644 --- a/lib/libstuff/event/focusout.c +++ b/lib/libstuff/event/focusout.c @@ -15,5 +15,5 @@ event_focusout(XFocusChangeEvent *ev) { return; if((w = findwin(ev->window))) - handle(w, focusout, ev); + event_handle(w, focusout, ev); } diff --git a/lib/libstuff/event/ixp.c b/lib/libstuff/event/ixp.c new file mode 100644 index 00000000..0f85add0 --- /dev/null +++ b/lib/libstuff/event/ixp.c @@ -0,0 +1,23 @@ +/* Copyright ©2010 Kris Maglione + * See LICENSE file for license details. + */ +#include +#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 --git a/lib/libstuff/event/keypress.c b/lib/libstuff/event/keypress.c index 7b1d72b7..c4526d56 100644 --- a/lib/libstuff/event/keypress.c +++ b/lib/libstuff/event/keypress.c @@ -7,7 +7,8 @@ void 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 --git a/lib/libstuff/event/leavenotify.c b/lib/libstuff/event/leavenotify.c index 612183ac..81b7fc12 100644 --- a/lib/libstuff/event/leavenotify.c +++ b/lib/libstuff/event/leavenotify.c @@ -7,7 +7,8 @@ void 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 --git a/lib/libstuff/event/mapnotify.c b/lib/libstuff/event/mapnotify.c index 0a51b5d1..7d9c13c4 100644 --- a/lib/libstuff/event/mapnotify.c +++ b/lib/libstuff/event/mapnotify.c @@ -8,5 +8,5 @@ event_mapnotify(XMapEvent *ev) { Window *w; if((w = findwin(ev->window))) - handle(w, map, ev); + event_handle(w, map, ev); } diff --git a/lib/libstuff/event/maprequest.c b/lib/libstuff/event/maprequest.c index c945d3da..09b47711 100644 --- a/lib/libstuff/event/maprequest.c +++ b/lib/libstuff/event/maprequest.c @@ -8,5 +8,5 @@ event_maprequest(XMapRequestEvent *ev) { Window *w; if((w = findwin(ev->parent))) - handle(w, mapreq, ev); + event_handle(w, mapreq, ev); } diff --git a/lib/libstuff/event/motionnotify.c b/lib/libstuff/event/motionnotify.c index df339dfb..6713bceb 100644 --- a/lib/libstuff/event/motionnotify.c +++ b/lib/libstuff/event/motionnotify.c @@ -7,7 +7,8 @@ void 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 --git a/lib/libstuff/event/propertynotify.c b/lib/libstuff/event/propertynotify.c index 08536b5f..2e05621e 100644 --- a/lib/libstuff/event/propertynotify.c +++ b/lib/libstuff/event/propertynotify.c @@ -7,7 +7,8 @@ void 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 --git a/lib/libstuff/event/reparentnotify.c b/lib/libstuff/event/reparentnotify.c new file mode 100644 index 00000000..5ca4dd03 --- /dev/null +++ b/lib/libstuff/event/reparentnotify.c @@ -0,0 +1,12 @@ +/* Copyright ©2006-2010 Kris Maglione + * 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 --git a/lib/libstuff/event/selection.c b/lib/libstuff/event/selection.c new file mode 100644 index 00000000..992b31c6 --- /dev/null +++ b/lib/libstuff/event/selection.c @@ -0,0 +1,15 @@ +/* Copyright ©2010 Kris Maglione + * 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 --git a/lib/libstuff/event/selectionclear.c b/lib/libstuff/event/selectionclear.c new file mode 100644 index 00000000..5a8848af --- /dev/null +++ b/lib/libstuff/event/selectionclear.c @@ -0,0 +1,14 @@ +/* Copyright ©2010 Kris Maglione + * 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 --git a/lib/libstuff/event/selectionrequest.c b/lib/libstuff/event/selectionrequest.c new file mode 100644 index 00000000..c91ee1d7 --- /dev/null +++ b/lib/libstuff/event/selectionrequest.c @@ -0,0 +1,15 @@ +/* Copyright ©2010 Kris Maglione + * 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 --git a/lib/libstuff/event/unmapnotify.c b/lib/libstuff/event/unmapnotify.c index 797de34c..f560976a 100644 --- a/lib/libstuff/event/unmapnotify.c +++ b/lib/libstuff/event/unmapnotify.c @@ -10,6 +10,6 @@ event_unmapnotify(XUnmapEvent *ev) { 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 --git a/lib/libstuff/x11/errors.c b/lib/libstuff/x11/errors.c index 6bfb09df..3d0621ba 100644 --- a/lib/libstuff/x11/errors.c +++ b/lib/libstuff/x11/errors.c @@ -13,8 +13,10 @@ errorhandler(Display *dpy, XErrorEvent *error) { USED(dpy); - if(_trap_errors) + if(_trap_errors) { nerrors++; + return 0; + } e = ignored_xerrors; if(e) diff --git a/lib/libstuff/x11/initdisplay.c b/lib/libstuff/x11/initdisplay.c index 9cf9c03b..51a397b4 100644 --- a/lib/libstuff/x11/initdisplay.c +++ b/lib/libstuff/x11/initdisplay.c @@ -44,6 +44,8 @@ Wfmt(Fmt *f) { Window *w; w = va_arg(f->args, Window*); + if(w == nil) + return fmtstrcpy(f, ""); return fmtprint(f, "0x%ulx", w->xid); } diff --git a/lib/libstuff/x11/insanity/gethints.c b/lib/libstuff/x11/insanity/gethints.c new file mode 100644 index 00000000..0c141984 --- /dev/null +++ b/lib/libstuff/x11/insanity/gethints.c @@ -0,0 +1,97 @@ +/* Copyright ©2007-2010 Kris Maglione + * See LICENSE file for license details. + */ +#include +#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 --git a/lib/libstuff/x11/insanity/sethints.c b/lib/libstuff/x11/insanity/sethints.c index fe788b16..53cfedb8 100644 --- a/lib/libstuff/x11/insanity/sethints.c +++ b/lib/libstuff/x11/insanity/sethints.c @@ -1,100 +1,97 @@ /* Copyright ©2007-2010 Kris Maglione * See LICENSE file for license details. */ -#include #include "../x11.h" +#include + +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 --git a/lib/libstuff/x11/properties/changeprop_textlist.c b/lib/libstuff/x11/properties/changeprop_textlist.c index 68138caa..de15ef7b 100644 --- a/lib/libstuff/x11/properties/changeprop_textlist.c +++ b/lib/libstuff/x11/properties/changeprop_textlist.c @@ -19,6 +19,6 @@ changeprop_textlist(Window *w, char *prop, char *type, char *data[]) { memcpy(t, *p, n); t += n; } - changeprop_char(w, prop, type, s, len); + changeprop_char(w, prop, type, s, len - 1); free(s); } diff --git a/lib/libstuff/x11/sendevent.c b/lib/libstuff/x11/sendevent.c index 239f4f14..a4c7b40f 100644 --- a/lib/libstuff/x11/sendevent.c +++ b/lib/libstuff/x11/sendevent.c @@ -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 --git a/lib/libstuff/x11/sendmessage.c b/lib/libstuff/x11/sendmessage.c index f95b2e1e..37641022 100644 --- a/lib/libstuff/x11/sendmessage.c +++ b/lib/libstuff/x11/sendmessage.c @@ -2,19 +2,23 @@ * See LICENSE file for license details. */ #include "x11.h" +#include 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 --git a/lib/libstuff/x11/windows/createwindow_visual.c b/lib/libstuff/x11/windows/createwindow_visual.c index 4b7eea97..6122724c 100644 --- a/lib/libstuff/x11/windows/createwindow_visual.c +++ b/lib/libstuff/x11/windows/createwindow_visual.c @@ -2,6 +2,10 @@ * See LICENSE file for license details. */ #include "../x11.h" +#include +#include + +static char hostname[HOST_NAME_MAX + 1]; Window* createwindow_visual(Window *parent, Rectangle r, @@ -21,6 +25,8 @@ createwindow_visual(Window *parent, Rectangle r, 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 @@ createwindow_visual(Window *parent, Rectangle r, 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 --git a/lib/libstuff/x11/windows/destroywindow.c b/lib/libstuff/x11/windows/destroywindow.c index c12ac46a..2420d01f 100644 --- a/lib/libstuff/x11/windows/destroywindow.c +++ b/lib/libstuff/x11/windows/destroywindow.c @@ -7,6 +7,8 @@ void 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 --git a/lib/libstuff/x11/windows/selectinput.c b/lib/libstuff/x11/windows/selectinput.c index 330a2518..fa007e23 100644 --- a/lib/libstuff/x11/windows/selectinput.c +++ b/lib/libstuff/x11/windows/selectinput.c @@ -5,5 +5,6 @@ void selectinput(Window *w, long mask) { + w->eventmask = mask; XSelectInput(display, w->xid, mask); } diff --git a/lib/libstuff/x11/windows/sethandler.c b/lib/libstuff/x11/windows/sethandler.c index 5fdd5ea7..1aa8c368 100644 --- a/lib/libstuff/x11/windows/sethandler.c +++ b/lib/libstuff/x11/windows/sethandler.c @@ -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 --git a/lib/libstuff/xext.c b/lib/libstuff/xext.c index abece4a8..65b3b48a 100644 --- a/lib/libstuff/xext.c +++ b/lib/libstuff/xext.c @@ -4,6 +4,7 @@ #define _X11_VISIBLE #include #include +#include #include #include diff --git a/man/Makefile b/man/Makefile index 2644046b..9067bfad 100644 --- a/man/Makefile +++ b/man/Makefile @@ -7,7 +7,8 @@ TARG = wmii.1 \ wmii9menu.1\ wihack.1 \ wimenu.1 \ - wistrut.1 + wistrut.1 \ + witray.1 $(TARG): Makefile $(ROOT)/mk/wmii.mk header.t2t diff --git a/man/wimenu.1 b/man/wimenu.1 index d4e62d2c..6be0268e 100644 --- a/man/wimenu.1 +++ b/man/wimenu.1 @@ -193,7 +193,7 @@ provided. .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 --git a/man/wimenu.man1 b/man/wimenu.man1 index ce1c7479..afe43b08 100644 --- a/man/wimenu.man1 +++ b/man/wimenu.man1 @@ -168,7 +168,7 @@ most shells. 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 --git a/man/wistrut.1 b/man/wistrut.1 index 1a048a44..f86a195b 100644 --- a/man/wistrut.1 +++ b/man/wistrut.1 @@ -1,4 +1,4 @@ -.TH "WIMENU" 1 "May, 2010" "wmii-@VERSION@" +.TH "WISTRUT" 1 "May, 2010" "wmii-@VERSION@" .SH NAME .P diff --git a/man/wistrut.man1 b/man/wistrut.man1 index 2ceadd7a..e54ec824 100644 --- a/man/wistrut.man1 +++ b/man/wistrut.man1 @@ -1,4 +1,4 @@ -WIMENU +WISTRUT wmii-@VERSION@ May, 2010 diff --git a/man/witray.1 b/man/witray.1 new file mode 100644 index 00000000..4d20161d --- /dev/null +++ b/man/witray.1 @@ -0,0 +1,85 @@ +.TH "WITRAY" 1 "May, 2010" "wmii-@VERSION@" + +.SH NAME +.P +witray \- The wmii system tray + +.SH SYNOPSIS +.P +witray \fI[\-a \fI
\fR]\fR \fI[\-NESW]\fR \fI[\-HV]\fR \fI[\-p \fI\fR]\fR \fI[\-s \fI\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\fR + +.RS +Sets the padding between icons and around the edge of the +tray. In pixels. +.RE +.TP +\-s \fI\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\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 --git a/man/witray.man1 b/man/witray.man1 new file mode 100644 index 00000000..351f3472 --- /dev/null +++ b/man/witray.man1 @@ -0,0 +1,60 @@ +WITRAY +wmii-@VERSION@ +May, 2010 + +%!includeconf: header.t2t + += NAME = + +witray - The wmii system tray + += SYNOPSIS = + +witray [-a
] [-NESW] [-HV] [-p ] [-s ] [-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 + Sets the padding between icons and around the edge of the + tray. In pixels. +: -s + 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 + The tags on which to open. Default: _/./_ +: -v + Display version information. + += CAVEATS = + +`witray` is not XRandR aware. + += SEE ALSO = + +wmii(1), wimenu(1) + diff --git a/util/compile b/util/compile index f8ba628e..f25137e7 100755 --- a/util/compile +++ b/util/compile @@ -14,7 +14,7 @@ echo CC $($bin/cleanname ${BASE}$outfile) [ -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]\)'