Add witray system tray program.

This commit is contained in:
Kris Maglione 2010-05-27 03:58:02 -04:00
parent 1dad368d9c
commit 88f0721673
84 changed files with 1855 additions and 294 deletions

View File

@ -1,6 +1,6 @@
pkgname="wmii-hg" pkgname="wmii-hg"
pkgver=2637 pkgver=2647
pkgrel=1 pkgrel=1
pkgdesc="The latest hg pull of wmii, a lightweight, dynamic window manager for X11" pkgdesc="The latest hg pull of wmii, a lightweight, dynamic window manager for X11"
url="http://wmii.suckless.org" url="http://wmii.suckless.org"
@ -16,8 +16,6 @@ provides=("wmii")
conflicts=("wmii") conflicts=("wmii")
source=() source=()
test -d src || mkdir src
ln -snf .. src/wmii
FORCE_VER=$(hg tip --template {rev}) FORCE_VER=$(hg tip --template {rev})
#_hgroot="http://hg.suckless.org/" #_hgroot="http://hg.suckless.org/"
#_hgrepo="wmii" #_hgrepo="wmii"
@ -32,7 +30,7 @@ build()
make "${flags[@]}" || return 1 make "${flags[@]}" || return 1
make "${flags[@]}" install || 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 install -m644 -D ./LICENSE $startdir/pkg/usr/share/licenses/wmii/LICENSE
} }

View File

@ -6,7 +6,8 @@ wmiir.c: $(ROOT)/mk/wmii.mk
DIRS = wmii \ DIRS = wmii \
menu \ menu \
strut strut \
tray
TARG = wihack \ TARG = wihack \
wmii.rc \ wmii.rc \
wmii.sh \ wmii.sh \

View File

@ -12,7 +12,7 @@ bindings.c: keys.txt Makefile
TARG = wimenu TARG = wimenu
HFILES= dat.h fns.h HFILES= dat.h fns.h
PACKAGES += $(X11PACKAGES) xext xrandr xrender xinerama PACKAGES += $(X11PACKAGES)
LIBS += -lm $(LIBS9) $(LIBIXP) LIBS += -lm $(LIBS9) $(LIBIXP)
CFLAGS += -DIXP_NEEDAPI=86 CFLAGS += -DIXP_NEEDAPI=86

View File

@ -7,9 +7,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <ixp.h>
#include <stuff/x.h> #include <stuff/x.h>
#include <stuff/util.h> #include <stuff/util.h>
#include <ixp.h>
#define BLOCK(x) do { x; }while(0) #define BLOCK(x) do { x; }while(0)

View File

@ -171,20 +171,6 @@ update_filter(bool print) {
update_input(); update_input();
} }
static void
end(IxpConn *c) {
USED(c);
srv.running = 0;
}
static void
preselect(IxpServer *s) {
USED(s);
event_check();
}
enum { PointerScreen = -1 }; enum { PointerScreen = -1 };
void void
@ -224,7 +210,6 @@ main(int argc, char *argv[]) {
quotefmtinstall(); quotefmtinstall();
fmtinstall('r', errfmt); fmtinstall('r', errfmt);
address = getenv("WMII_ADDRESS");
screen_hint = PointerScreen; screen_hint = PointerScreen;
find = strstr; find = strstr;
@ -283,17 +268,18 @@ main(int argc, char *argv[]) {
client_init(address); client_init(address);
srv.preselect = preselect; srv.preselect = event_preselect;
ixp_listen(&srv, ConnectionNumber(display), nil, (void (*)(IxpConn*))preselect, end); ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, event_fdclosed);
ontop = !strcmp(readctl("bar on "), "top"); ontop = !strcmp(readctl("bar on "), "top");
loadcolor(&cnorm, readctl("normcolors ")); loadcolor(&cnorm, readctl("normcolors "));
loadcolor(&csel, readctl("focuscolors ")); loadcolor(&csel, readctl("focuscolors "));
font = loadfont(readctl("font ")); 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) if(!font)
fatal("Can't load font %q", readctl("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); cmplbuf = Bfdopen(0, OREAD);
items = populate_list(cmplbuf, false); items = populate_list(cmplbuf, false);

View File

@ -255,7 +255,7 @@ menu_show(void) {
} }
static void static void
kdown_event(Window *w, XKeyEvent *e) { kdown_event(Window *w, void *aux, XKeyEvent *e) {
char **action, **p; char **action, **p;
char *key; char *key;
char buf[32]; char buf[32];
@ -331,7 +331,7 @@ kdown_event(Window *w, XKeyEvent *e) {
} }
static void static void
expose_event(Window *w, XExposeEvent *e) { expose_event(Window *w, void *aux, XExposeEvent *e) {
USED(w); USED(w);
menu_draw(); menu_draw();

View File

@ -7,9 +7,8 @@ main.c: $(ROOT)/mk/wmii.mk
TARG = wistrut TARG = wistrut
HFILES= dat.h fns.h HFILES= dat.h fns.h
PACKAGES += $(X11PACKAGES) xext xrandr xinerama PACKAGES += $(X11PACKAGES)
LIB = $(LIBIXP)
LIBS += -lm $(LIBS9) LIBS += -lm $(LIBS9)
CFLAGS += -DIXP_NEEDAPI=86 CFLAGS += -DIXP_NEEDAPI=86
OBJ = main \ OBJ = main \

View File

@ -5,7 +5,6 @@
#include <unistd.h> #include <unistd.h>
#include <stuff/x.h> #include <stuff/x.h>
#include <stuff/util.h> #include <stuff/util.h>
#include <ixp.h>
#ifndef EXTERN #ifndef EXTERN
# define EXTERN extern # define EXTERN extern

View File

@ -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 restrut(Window*);
void ewmh_getstrut(Window*, Rectangle[4]); void ewmh_getstrut(Window*, Rectangle[4]);
void ewmh_setstrut(Window*, Rectangle[4]); void ewmh_setstrut(Window*, Rectangle[4]);
void printevent(XEvent *e);

View File

@ -21,11 +21,6 @@ usage(void) {
fatal("usage: %s [-HV] <window|class>...\n", argv0); fatal("usage: %s [-HV] <window|class>...\n", argv0);
} }
static int
errfmt(Fmt *f) {
return fmtstrcpy(f, ixp_errbuf());
}
static void static void
search_wins(char *pattern) { search_wins(char *pattern) {
ulong *wins; ulong *wins;
@ -135,7 +130,6 @@ main(int argc, char *argv[]) {
ulong win; ulong win;
char *s; char *s;
fmtinstall('r', errfmt);
fmtinstall('E', fmtevent); fmtinstall('E', fmtevent);
ARGBEGIN{ ARGBEGIN{

View File

@ -80,22 +80,23 @@ restrut(Window *frame) {
} }
static void 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), frame->r = rectaddpt(Rect(ev->x, ev->y, ev->width, ev->height),
Pt(ev->x+ev->border_width, ev->y+ev->border_width)); Pt(ev->border_width, ev->border_width));
restrut(frame); restrut(frame);
} }
static void static void
destroy(Window *w, XDestroyWindowEvent *ev) { destroy_event(Window *w, void *aux, XDestroyWindowEvent *ev) {
USED(w, ev);
USED(ev);
sethandler(w, nil); sethandler(w, nil);
event_looprunning = windowmap.nmemb > 0; event_looprunning = windowmap.nmemb > 0;
} }
Handlers handlers = { Handlers handlers = {
.config = config, .config = config_event,
.destroy = destroy, .destroy = destroy_event,
}; };

22
cmd/tray/Makefile Normal file
View File

@ -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

190
cmd/tray/client.c Normal file
View File

@ -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,
};

82
cmd/tray/dat.h Normal file
View File

@ -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;

45
cmd/tray/ewmh.c Normal file
View File

@ -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));
}

34
cmd/tray/fns.h Normal file
View File

@ -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

216
cmd/tray/main.c Normal file
View File

@ -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;
}

144
cmd/tray/selection.c Normal file
View File

@ -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,
};

257
cmd/tray/tray.c Normal file
View File

@ -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,
};

128
cmd/tray/xembed.c Normal file
View File

@ -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,
};

View File

@ -15,6 +15,7 @@ LIBS += -lm $(LIBS9)
CFLAGS += $(INCICONV) -DIXP_NEEDAPI=97 CFLAGS += $(INCICONV) -DIXP_NEEDAPI=97
OBJ = area \ OBJ = area \
bar \ bar \
backtrace \
client \ client \
column \ column \
div \ div \

View File

@ -10,8 +10,8 @@
#include <bio.h> #include <bio.h>
#include <plan9.h> #include <plan9.h>
#undef nelem #undef nelem
#include <debug.h> #include <stuff/util.h>
#include "util.h" #include "debug.h"
#ifdef __linux__ #ifdef __linux__
# define PROGTXT "exe" # define PROGTXT "exe"

View File

@ -246,7 +246,7 @@ findbar(WMScreen *s, Point p) {
} }
static void static void
bdown_event(Window *w, XButtonPressedEvent *e) { bdown_event(Window *w, void *aux, XButtonPressedEvent *e) {
WMScreen *s; WMScreen *s;
Bar *b; Bar *b;
@ -254,29 +254,29 @@ bdown_event(Window *w, XButtonPressedEvent *e) {
XUngrabPointer(display, e->time); XUngrabPointer(display, e->time);
sync(); sync();
s = w->aux; s = aux;
b = findbar(s, Pt(e->x, e->y)); b = findbar(s, Pt(e->x, e->y));
if(b) if(b)
event("%sBarMouseDown %d %s\n", barside[b->bar], e->button, b->name); event("%sBarMouseDown %d %s\n", barside[b->bar], e->button, b->name);
} }
static void static void
bup_event(Window *w, XButtonPressedEvent *e) { bup_event(Window *w, void *aux, XButtonPressedEvent *e) {
WMScreen *s; WMScreen *s;
Bar *b; Bar *b;
s = w->aux; s = aux;
b = findbar(s, Pt(e->x, e->y)); b = findbar(s, Pt(e->x, e->y));
if(b) if(b)
event("%sBarClick %d %s\n", barside[b->bar], e->button, b->name); event("%sBarClick %d %s\n", barside[b->bar], e->button, b->name);
} }
static Rectangle static Rectangle
dndmotion_event(Window *w, Point p) { dndmotion_event(Window *w, void *aux, Point p) {
WMScreen *s; WMScreen *s;
Bar *b; Bar *b;
s = w->aux; s = aux;
b = findbar(s, p); b = findbar(s, p);
if(b) { if(b) {
event("%sBarDND 1 %s\n", barside[b->bar], b->name); event("%sBarDND 1 %s\n", barside[b->bar], b->name);
@ -286,9 +286,9 @@ dndmotion_event(Window *w, Point p) {
} }
static void static void
expose_event(Window *w, XExposeEvent *e) { expose_event(Window *w, void *aux, XExposeEvent *e) {
USED(w, e); USED(w, e);
bar_draw(w->aux); bar_draw(aux);
} }
static Handlers handlers = { static Handlers handlers = {

View File

@ -101,9 +101,8 @@ client_create(XWindow w, XWindowAttributes *wa) {
c->fullscreen = -1; c->fullscreen = -1;
c->border = wa->border_width; c->border = wa->border_width;
c->r.min = Pt(wa->x, wa->y); c->r = rectsetorigin(Rect(0, 0, wa->width, wa->height),
c->r.max = addpt(c->r.min, Pt(wa->x, wa->y));
Pt(wa->width, wa->height));
c->w.type = WWindow; c->w.type = WWindow;
c->w.xid = w; c->w.xid = w;
@ -115,7 +114,7 @@ client_create(XWindow w, XWindowAttributes *wa) {
c->ibuf = &ibuf; c->ibuf = &ibuf;
if(render_argb_p(wa->visual)) { if(render_argb_p(wa->visual)) {
depth = 32; depth = 32;
vis = render_visual; vis = scr.visual32;
c->ibuf = &ibuf32; c->ibuf = &ibuf32;
} }
@ -589,7 +588,7 @@ client_configure(Client *c) {
e.height = Dy(r); e.height = Dy(r);
e.border_width = c->border; e.border_width = c->border;
sendevent(&c->w, false, StructureNotifyMask, (XEvent*)&e); sendevent(&c->w, false, StructureNotifyMask, &e);
} }
void void
@ -809,7 +808,7 @@ client_prop(Client *c, Atom a) {
memset(&h, 0, sizeof h); memset(&h, 0, sizeof h);
if(c->w.hints) if(c->w.hints)
bcopy(c->w.hints, &h, sizeof h); bcopy(c->w.hints, &h, sizeof h);
sethints(&c->w); gethints(&c->w);
if(c->w.hints) if(c->w.hints)
c->fixedsize = eqpt(c->w.hints->min, c->w.hints->max); c->fixedsize = eqpt(c->w.hints->min, c->w.hints->max);
if(memcmp(&h, c->w.hints, sizeof h)) if(memcmp(&h, c->w.hints, sizeof h))
@ -841,11 +840,11 @@ client_prop(Client *c, Atom a) {
/* Handlers */ /* Handlers */
static void static void
configreq_event(Window *w, XConfigureRequestEvent *e) { configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) {
Rectangle r, cr; Rectangle r, cr;
Client *c; Client *c;
c = w->aux; c = aux;
r = client_grav(c, ZR); r = client_grav(c, ZR);
r.max = subpt(r.max, r.min); r.max = subpt(r.max, r.min);
@ -875,17 +874,17 @@ configreq_event(Window *w, XConfigureRequestEvent *e) {
} }
static void static void
destroy_event(Window *w, XDestroyWindowEvent *e) { destroy_event(Window *w, void *aux, XDestroyWindowEvent *e) {
USED(w, e); USED(w, e);
client_destroy(w->aux); client_destroy(aux);
} }
static void static void
enter_event(Window *w, XCrossingEvent *e) { enter_event(Window *w, void *aux, XCrossingEvent *e) {
Client *c; Client *c;
c = w->aux; c = aux;
if(e->detail != NotifyInferior) { if(e->detail != NotifyInferior) {
if(e->detail != NotifyVirtual) if(e->detail != NotifyVirtual)
if(e->serial != ignoreenter && disp.focus != c) { if(e->serial != ignoreenter && disp.focus != c) {
@ -898,10 +897,10 @@ enter_event(Window *w, XCrossingEvent *e) {
} }
static void static void
focusin_event(Window *w, XFocusChangeEvent *e) { focusin_event(Window *w, void *aux, XFocusChangeEvent *e) {
Client *c, *old; Client *c, *old;
c = w->aux; c = aux;
print_focus("focusin_event", c, c->name); print_focus("focusin_event", c, c->name);
@ -918,10 +917,10 @@ focusin_event(Window *w, XFocusChangeEvent *e) {
} }
static void static void
focusout_event(Window *w, XFocusChangeEvent *e) { focusout_event(Window *w, void *aux, XFocusChangeEvent *e) {
Client *c; Client *c;
c = w->aux; c = aux;
if((e->mode == NotifyWhileGrabbed) && (disp.hasgrab != &c_root)) { if((e->mode == NotifyWhileGrabbed) && (disp.hasgrab != &c_root)) {
if(disp.focus) if(disp.focus)
disp.hasgrab = disp.focus; disp.hasgrab = disp.focus;
@ -934,34 +933,34 @@ focusout_event(Window *w, XFocusChangeEvent *e) {
} }
static void static void
unmap_event(Window *w, XUnmapEvent *e) { unmap_event(Window *w, void *aux, XUnmapEvent *e) {
Client *c; Client *c;
c = w->aux; c = aux;
if(!e->send_event) if(!e->send_event)
c->unmapped--; c->unmapped--;
client_destroy(c); client_destroy(c);
} }
static void static void
map_event(Window *w, XMapEvent *e) { map_event(Window *w, void *aux, XMapEvent *e) {
Client *c; Client *c;
USED(e); USED(e);
c = w->aux; c = aux;
if(c == selclient()) if(c == selclient())
client_focus(c); client_focus(c);
} }
static void static void
property_event(Window *w, XPropertyEvent *e) { property_event(Window *w, void *aux, XPropertyEvent *e) {
Client *c; Client *c;
if(e->state == PropertyDelete) /* FIXME */ if(e->state == PropertyDelete) /* FIXME */
return; return;
c = w->aux; c = aux;
client_prop(c, e->atom); client_prop(c, e->atom);
} }
@ -1002,6 +1001,7 @@ client_setviews(Client *c, char **tags) {
if(*tags) { if(*tags) {
if(!*fp || cmp > 0) { if(!*fp || cmp > 0) {
f = frame_create(c, view_create(*tags)); 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) if(f->view == selview || !c->sel)
c->sel = f; c->sel = f;
kludge = c; /* FIXME */ kludge = c; /* FIXME */

View File

@ -12,10 +12,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <utf.h> #include <utf.h>
#include <ixp.h>
#include <stuff/x.h> #include <stuff/x.h>
#include <stuff/util.h> #include <stuff/util.h>
#include <debug.h> #include "debug.h"
#include <ixp.h>
#define FONT "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*" #define FONT "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*"
#define FOCUSCOLORS "#ffffff #335577 #447799" #define FOCUSCOLORS "#ffffff #335577 #447799"

View File

@ -1,5 +1,16 @@
#include <stdbool.h> #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 Debug(x) if(((debugflag|debugfile)&(x)) && setdebug(x))
#define Dprint(x, ...) BLOCK( if((debugflag|debugfile)&(x)) debug(x, __VA_ARGS__) ) #define Dprint(x, ...) BLOCK( if((debugflag|debugfile)&(x)) debug(x, __VA_ARGS__) )

View File

@ -164,22 +164,22 @@ div_update_all(void) {
/* Div Handlers */ /* Div Handlers */
static void static void
bdown_event(Window *w, XButtonEvent *e) { bdown_event(Window *w, void *aux, XButtonEvent *e) {
Divide *d; Divide *d;
USED(e); USED(e);
d = w->aux; d = aux;
mouse_resizecol(d); mouse_resizecol(d);
} }
static void static void
expose_event(Window *w, XExposeEvent *e) { expose_event(Window *w, void *aux, XExposeEvent *e) {
Divide *d; Divide *d;
USED(e); USED(e);
d = w->aux; d = aux;
drawdiv(d); drawdiv(d);
} }

View File

@ -10,15 +10,12 @@ debug_event(XEvent *e) {
Dprint(DEvent, "%E\n", e); Dprint(DEvent, "%E\n", e);
} }
#define handle(w, fn, ev) \
BLOCK(if((w)->handler->fn) (w)->handler->fn((w), ev))
void void
event_buttonpress(XButtonPressedEvent *ev) { event_buttonpress(XButtonPressedEvent *ev) {
Window *w; Window *w;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, bdown, ev); event_handle(w, bdown, ev);
else else
XAllowEvents(display, ReplayPointer, ev->time); XAllowEvents(display, ReplayPointer, ev->time);
} }
@ -29,7 +26,7 @@ event_configurenotify(XConfigureEvent *ev) {
ignoreenter = ev->serial; ignoreenter = ev->serial;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, config, ev); event_handle(w, config, ev);
} }
void void
@ -47,7 +44,7 @@ event_destroynotify(XDestroyWindowEvent *ev) {
Client *c; Client *c;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, destroy, ev); event_handle(w, destroy, ev);
else if((c = win2client(ev->window))) else if((c = win2client(ev->window)))
fprint(2, "Badness: Unhandled DestroyNotify: Client: %p, Window: %W, Name: %s\n", fprint(2, "Badness: Unhandled DestroyNotify: Client: %p, Window: %W, Name: %s\n",
c, &c->w, c->name); c, &c->w, c->name);
@ -87,7 +84,7 @@ event_focusin(XFocusChangeEvent *ev) {
disp.focus = nil; disp.focus = nil;
} }
else if((w = findwin(ev->window))) else if((w = findwin(ev->window)))
handle(w, focusin, ev); event_handle(w, focusin, ev);
else if(ev->mode == NotifyGrab) { else if(ev->mode == NotifyGrab) {
/* Some unmanaged window has grabbed focus */ /* Some unmanaged window has grabbed focus */
if((c = disp.focus)) { if((c = disp.focus)) {
@ -117,7 +114,7 @@ event_focusout(XFocusChangeEvent *ev) {
&& XCheckMaskEvent(display, KeyPressMask, &me)) && XCheckMaskEvent(display, KeyPressMask, &me))
event_dispatch(&me); event_dispatch(&me);
else if((w = findwin(ev->window))) else if((w = findwin(ev->window)))
handle(w, focusout, ev); event_handle(w, focusout, ev);
} }
void void
@ -126,7 +123,7 @@ event_mapnotify(XMapEvent *ev) {
ignoreenter = ev->serial; ignoreenter = ev->serial;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, map, ev); event_handle(w, map, ev);
} }
void void
@ -137,7 +134,7 @@ event_unmapnotify(XUnmapEvent *ev) {
if((w = findwin(ev->window)) && (ev->event == w->parent->xid)) { if((w = findwin(ev->window)) && (ev->event == w->parent->xid)) {
w->mapped = false; w->mapped = false;
if(ev->send_event || w->unmapped-- == 0) if(ev->send_event || w->unmapped-- == 0)
handle(w, unmap, ev); event_handle(w, unmap, ev);
} }
} }

View File

@ -29,6 +29,9 @@ frame_create(Client *c, View *v) {
if(c->sel) { if(c->sel) {
f->floatr = c->sel->floatr; f->floatr = c->sel->floatr;
f->r = c->sel->r; f->r = c->sel->r;
}else if(c->sel) {
f->floatr = c->frame->floatr;
f->r = c->frame->r;
}else { }else {
f->r = client_grav(c, c->r); f->r = client_grav(c, c->r);
f->floatr = f->r; f->floatr = f->r;
@ -140,20 +143,20 @@ frame_restack(Frame *f, Frame *above) {
/* Handlers */ /* Handlers */
static void static void
bup_event(Window *w, XButtonEvent *e) { bup_event(Window *w, void *aux, XButtonEvent *e) {
if((e->state & def.mod) != def.mod) if((e->state & def.mod) != def.mod)
XAllowEvents(display, ReplayPointer, e->time); XAllowEvents(display, ReplayPointer, e->time);
else else
XUngrabPointer(display, e->time); XUngrabPointer(display, e->time);
event("ClientClick %#C %d\n", w->aux, e->button); event("ClientClick %#C %d\n", aux, e->button);
} }
static void static void
bdown_event(Window *w, XButtonEvent *e) { bdown_event(Window *w, void *aux, XButtonEvent *e) {
Frame *f; Frame *f;
Client *c; Client *c;
c = w->aux; c = aux;
f = c->sel; f = c->sel;
if((e->state & def.mod) == def.mod) { if((e->state & def.mod) == def.mod) {
@ -200,17 +203,17 @@ bdown_event(Window *w, XButtonEvent *e) {
} }
static void static void
config_event(Window *w, XConfigureEvent *e) { config_event(Window *w, void *aux, XConfigureEvent *e) {
USED(w, e); USED(w, e);
} }
static void static void
enter_event(Window *w, XCrossingEvent *e) { enter_event(Window *w, void *aux, XCrossingEvent *e) {
Client *c; Client *c;
Frame *f; Frame *f;
c = w->aux; c = aux;
f = c->sel; f = c->sel;
if(disp.focus != c || selclient() != c) { if(disp.focus != c || selclient() != c) {
Dprint(DFocus, "enter_notify(f) => [%#C]%s%s\n", Dprint(DFocus, "enter_notify(f) => [%#C]%s%s\n",
@ -225,12 +228,12 @@ enter_event(Window *w, XCrossingEvent *e) {
} }
static void static void
expose_event(Window *w, XExposeEvent *e) { expose_event(Window *w, void *aux, XExposeEvent *e) {
Client *c; Client *c;
USED(e); USED(e);
c = w->aux; c = aux;
if(c->sel) if(c->sel)
frame_draw(c->sel); frame_draw(c->sel);
else else
@ -239,10 +242,10 @@ expose_event(Window *w, XExposeEvent *e) {
} }
static void static void
motion_event(Window *w, XMotionEvent *e) { motion_event(Window *w, void *aux, XMotionEvent *e) {
Client *c; Client *c;
c = w->aux; c = aux;
mouse_checkresize(c->sel, Pt(e->x, e->y), false); mouse_checkresize(c->sel, Pt(e->x, e->y), false);
} }

View File

@ -99,7 +99,7 @@ framedestroy(Framewin *f) {
} }
static void static void
expose_event(Window *w, XExposeEvent *e) { expose_event(Window *w, void *aux, XExposeEvent *e) {
Rectangle r; Rectangle r;
Framewin *f; Framewin *f;
Image *buf; Image *buf;
@ -107,7 +107,7 @@ expose_event(Window *w, XExposeEvent *e) {
USED(e); USED(e);
f = w->aux; f = aux;
c = &def.focuscolor; c = &def.focuscolor;
buf = disp.ibuf; buf = disp.ibuf;

View File

@ -317,13 +317,6 @@ spawn_command(const char *cmd) {
} }
} }
static void
check_preselect(IxpServer *s) {
USED(s);
event_check();
}
static void static void
closedisplay(IxpConn *c) { closedisplay(IxpConn *c) {
USED(c); USED(c);
@ -412,9 +405,9 @@ extern int fmtevent(Fmt*);
event_debug = debug_event; event_debug = debug_event;
srv.preselect = check_preselect; srv.preselect = event_preselect;
ixp_listen(&srv, sock, &p9srv, serve_9pcon, nil); 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.border = 1;
def.colmode = Colstack; def.colmode = Colstack;

View File

@ -29,7 +29,7 @@ quad_cursor(Align align) {
} }
static void 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, rectsubpt(w->r, w->r.min), def.focuscolor.bg);
fill(w, w->r, def.focuscolor.bg); fill(w, w->r, def.focuscolor.bg);

View File

@ -24,13 +24,13 @@ root_init(void) {
} }
static void static void
enter_event(Window *w, XCrossingEvent *e) { enter_event(Window *w, void *aux, XCrossingEvent *e) {
disp.sel = true; disp.sel = true;
frame_draw_all(); frame_draw_all();
} }
static void static void
leave_event(Window *w, XCrossingEvent *e) { leave_event(Window *w, void *aux, XCrossingEvent *e) {
if(!e->same_screen) { if(!e->same_screen) {
disp.sel = false; disp.sel = false;
frame_draw_all(); frame_draw_all();
@ -38,13 +38,13 @@ leave_event(Window *w, XCrossingEvent *e) {
} }
static void static void
focusin_event(Window *w, XFocusChangeEvent *e) { focusin_event(Window *w, void *aux, XFocusChangeEvent *e) {
if(e->mode == NotifyGrab) if(e->mode == NotifyGrab)
disp.hasgrab = &c_root; disp.hasgrab = &c_root;
} }
static void static void
mapreq_event(Window *w, XMapRequestEvent *e) { mapreq_event(Window *w, void *aux, XMapRequestEvent *e) {
XWindowAttributes wa; XWindowAttributes wa;
if(!XGetWindowAttributes(display, e->window, &wa)) if(!XGetWindowAttributes(display, e->window, &wa))
@ -62,7 +62,7 @@ mapreq_event(Window *w, XMapRequestEvent *e) {
} }
static void static void
motion_event(Window *w, XMotionEvent *e) { motion_event(Window *w, void *aux, XMotionEvent *e) {
Rectangle r, r2; Rectangle r, r2;
r = rectsetorigin(Rect(0, 0, 1, 1), Pt(e->x_root, e->y_root)); 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 static void
kdown_event(Window *w, XKeyEvent *e) { kdown_event(Window *w, void *aux, XKeyEvent *e) {
e->state &= valid_mask; e->state &= valid_mask;
kpress(w->xid, e->state, (KeyCode)e->keycode); kpress(w->xid, e->state, (KeyCode)e->keycode);

View File

@ -71,7 +71,7 @@ xdnd_clientmessage(XClientMessageEvent *e) {
Dprint(DDnd, "\tp: %P\n", p); Dprint(DDnd, "\tp: %P\n", p);
if(eqrect(dnd->r, ZR) || !rect_haspoint_p(p, dnd->r)) if(eqrect(dnd->r, ZR) || !rect_haspoint_p(p, dnd->r))
if(w->handler->dndmotion) if(w->handler->dndmotion)
dnd->r = w->handler->dndmotion(w, p); dnd->r = w->handler->dndmotion(w, w->aux, p);
r = dnd->r; r = dnd->r;
if(!eqrect(r, ZR)) if(!eqrect(r, ZR))
r = rectaddpt(r, w->r.min); r = rectaddpt(r, w->r.min);

View File

@ -26,7 +26,7 @@ LD = cc
# Archiver # Archiver
AR = ar crs AR = ar crs
X11PACKAGES = x11 xinerama xrender X11PACKAGES = x11 xinerama xrender xrandr
INCX11 = $$(pkg-config --cflags $(X11PACKAGES)) INCX11 = $$(pkg-config --cflags $(X11PACKAGES))
LIBIXP = $(LIBDIR)/libixp.a LIBIXP = $(LIBDIR)/libixp.a

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#define _XOPEN_SOURCE 600 #define _XOPEN_SOURCE 600
#include <sys/types.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
@ -13,6 +14,12 @@
# define nelem(ary) (sizeof(ary) / sizeof(*ary)) # define nelem(ary) (sizeof(ary) / sizeof(*ary))
#endif #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 uchar
#undef ushort #undef ushort
#undef uint #undef uint

View File

@ -22,16 +22,7 @@ enum {
CCenter = 1<<1, CCenter = 1<<1,
CRight = 1<<2, 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 { enum {
GInvert = 1<<0, GInvert = 1<<0,
}; };

View File

@ -16,11 +16,21 @@ void xext_event(XEvent*);
void xext_init(void); void xext_init(void);
Rectangle* xinerama_screens(int*); 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_check(void);
void event_dispatch(XEvent*); void event_dispatch(XEvent*);
uint event_flush(long, bool dispatch); uint event_flush(long, bool dispatch);
uint event_flushenter(void); uint event_flushenter(void);
void event_loop(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_updatextime(void);
void event_buttonpress(XButtonPressedEvent*); void event_buttonpress(XButtonPressedEvent*);
@ -36,10 +46,14 @@ void event_focusout(XFocusChangeEvent*);
void event_keypress(XKeyEvent*); void event_keypress(XKeyEvent*);
void event_leavenotify(XCrossingEvent*); void event_leavenotify(XCrossingEvent*);
void event_mapnotify(XMapEvent*); void event_mapnotify(XMapEvent*);
void event_maprequest(XMapRequestEvent*);
void event_mappingnotify(XMappingEvent*); void event_mappingnotify(XMappingEvent*);
void event_maprequest(XMapRequestEvent*);
void event_motionnotify(XMotionEvent*); void event_motionnotify(XMotionEvent*);
void event_propertynotify(XPropertyEvent*); 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*); void event_unmapnotify(XUnmapEvent*);
extern long event_xtime; extern long event_xtime;

View File

@ -33,12 +33,14 @@ typedef enum WindowType WindowType;
typedef XSetWindowAttributes WinAttr; typedef XSetWindowAttributes WinAttr;
typedef union ClientMessageData ClientMessageData;
typedef struct Color Color; typedef struct Color Color;
typedef struct CTuple CTuple; typedef struct CTuple CTuple;
typedef struct ErrorCode ErrorCode; typedef struct ErrorCode ErrorCode;
typedef struct Ewmh Ewmh; typedef struct Ewmh Ewmh;
typedef struct Font Font; typedef struct Font Font;
typedef struct Handlers Handlers; typedef struct Handlers Handlers;
typedef struct HandlersLink HandlersLink;
typedef struct Screen Screen; typedef struct Screen Screen;
typedef struct WinHints WinHints; typedef struct WinHints WinHints;
typedef struct Window Image; typedef struct Window Image;
@ -48,6 +50,12 @@ typedef struct XftColor XftColor;
typedef void XftDraw; typedef void XftDraw;
typedef struct XftFont XftFont; typedef struct XftFont XftFont;
union ClientMessageData {
char b[20];
short s[10];
long l[5];
};
struct Color { struct Color {
ulong pixel; ulong pixel;
XRenderColor render; XRenderColor render;
@ -86,24 +94,35 @@ struct Font {
}; };
struct Handlers { struct Handlers {
Rectangle (*dndmotion)(Window*, Point); Rectangle (*dndmotion)(Window*, void*, Point);
void (*bdown)(Window*, XButtonEvent*); void (*bdown)(Window*, void*, XButtonEvent*);
void (*bup)(Window*, XButtonEvent*); void (*bup)(Window*, void*, XButtonEvent*);
void (*config)(Window*, XConfigureEvent*); void (*config)(Window*, void*, XConfigureEvent*);
void (*configreq)(Window*, XConfigureRequestEvent*); void (*configreq)(Window*, void*, XConfigureRequestEvent*);
void (*destroy)(Window*, XDestroyWindowEvent*); void (*destroy)(Window*, void*, XDestroyWindowEvent*);
void (*enter)(Window*, XCrossingEvent*); void (*enter)(Window*, void*, XCrossingEvent*);
void (*expose)(Window*, XExposeEvent*); void (*expose)(Window*, void*, XExposeEvent*);
void (*focusin)(Window*, XFocusChangeEvent*); void (*focusin)(Window*, void*, XFocusChangeEvent*);
void (*focusout)(Window*, XFocusChangeEvent*); void (*focusout)(Window*, void*, XFocusChangeEvent*);
void (*kdown)(Window*, XKeyEvent*); void (*kdown)(Window*, void*, XKeyEvent*);
void (*kup)(Window*, XKeyEvent*); void (*kup)(Window*, void*, XKeyEvent*);
void (*leave)(Window*, XCrossingEvent*); void (*leave)(Window*, void*, XCrossingEvent*);
void (*map)(Window*, XMapEvent*); void (*map)(Window*, void*, XMapEvent*);
void (*mapreq)(Window*, XMapRequestEvent*); void (*mapreq)(Window*, void*, XMapRequestEvent*);
void (*motion)(Window*, XMotionEvent*); void (*message)(Window*, void*, XClientMessageEvent*);
void (*property)(Window*, XPropertyEvent*); void (*motion)(Window*, void*, XMotionEvent*);
void (*unmap)(Window*, XUnmapEvent*); 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 { struct WinHints {
@ -132,8 +151,10 @@ struct Window {
Window* next; Window* next;
Window* prev; Window* prev;
Handlers* handler; Handlers* handler;
HandlersLink* handler_link;
WinHints* hints; WinHints* hints;
Ewmh ewmh; Ewmh ewmh;
long eventmask;
void* dnd; void* dnd;
void* aux; void* aux;
bool mapped; bool mapped;
@ -193,6 +214,7 @@ extern struct Map windowmap;
extern struct Map atommap; extern struct Map atommap;
extern const Point ZP; extern const Point ZP;
extern const Rectangle ZR; extern const Rectangle ZR;
extern const WinHints ZWinHints;
extern Window* pointerwin; extern Window* pointerwin;
extern Xft* xft; extern Xft* xft;
@ -204,6 +226,7 @@ XRectangle XRect(Rectangle r);
(uchar*)(data), n) (uchar*)(data), n)
/* x11.c */ /* x11.c */
XRectangle XRect(Rectangle);
Image* allocimage(int w, int h, int depth); Image* allocimage(int w, int h, int depth);
void border(Image *dst, Rectangle, int w, Color); void border(Image *dst, Rectangle, int w, Color);
void changeprop_char(Window*, char*, char*, char[], int); void changeprop_char(Window*, char*, char*, char[], int);
@ -213,6 +236,7 @@ void changeprop_string(Window*, char*, char*);
void changeprop_textlist(Window*, char*, char*, char*[]); void changeprop_textlist(Window*, char*, char*, char*[]);
void changeprop_ulong(Window*, char*, char*, ulong[], int); void changeprop_ulong(Window*, char*, char*, ulong[], int);
void changeproperty(Window*, char*, char*, int width, uchar*, int); void changeproperty(Window*, char*, char*, int width, uchar*, int);
void clientmessage(Window*, char*, long, int, ClientMessageData);
void copyimage(Image*, Rectangle, Image*, Point); void copyimage(Image*, Rectangle, Image*, Point);
Window* createwindow(Window*, Rectangle, int depth, uint class, WinAttr*, int valuemask); 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);
@ -228,11 +252,13 @@ void freefont(Font*);
void freeimage(Image *); void freeimage(Image *);
void freestringlist(char**); void freestringlist(char**);
XWindow getfocus(void); XWindow getfocus(void);
void gethints(Window*);
ulong getprop_long(Window*, char*, char*, ulong, long**, ulong); ulong getprop_long(Window*, char*, char*, ulong, long**, ulong);
char* getprop_string(Window*, char*); char* getprop_string(Window*, char*);
int getprop_textlist(Window *w, char *name, char **ret[]); int getprop_textlist(Window *w, char *name, char **ret[]);
ulong getprop_ulong(Window*, char*, char*, ulong, ulong**, ulong); ulong getprop_ulong(Window*, char*, char*, ulong, ulong**, ulong);
ulong getproperty(Window*, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length); ulong getproperty(Window*, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length);
Rectangle getwinrect(Window*);
int grabkeyboard(Window*); int grabkeyboard(Window*);
int grabpointer(Window*, Window *confine, Cursor, int mask); int grabpointer(Window*, Window *confine, Cursor, int mask);
bool havexft(void); bool havexft(void);
@ -247,24 +273,29 @@ void movewin(Window*, Point);
bool namedcolor(char *name, Color*); bool namedcolor(char *name, Color*);
bool parsekey(char*, int*, char**); bool parsekey(char*, int*, char**);
int pointerscreen(void); int pointerscreen(void);
bool pophandler(Window*, Handlers*);
void pushhandler(Window*, Handlers*, void*);
Point querypointer(Window*); Point querypointer(Window*);
void raisewin(Window*); void raisewin(Window*);
void reparentwindow(Window*, Window*, Point); void reparentwindow(Window*, Window*, Point);
void reshapewin(Window*, Rectangle); void reshapewin(Window*, Rectangle);
void selectinput(Window*, long); 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 setborder(Window*, int, Color);
void setfocus(Window*, int mode); void setfocus(Window*, int mode);
void sethints(Window*); Handlers* sethandler(Window*, Handlers*);
void sethints(Window*, WinHints*);
void setshapemask(Window *dst, Image *src, Point); void setshapemask(Window *dst, Image *src, Point);
void setwinattr(Window*, WinAttr*, int valmask); void setwinattr(Window*, WinAttr*, int valmask);
Rectangle sizehint(WinHints*, Rectangle);
char** strlistdup(char**); char** strlistdup(char**);
void sync(void); void sync(void);
Rectangle textextents_l(Font*, char*, uint, int*);
uint textwidth(Font*, char*); uint textwidth(Font*, char*);
uint textwidth_l(Font*, char*, uint len); uint textwidth_l(Font*, char*, uint len);
Rectangle textextents_l(Font*, char*, uint, int*);
int traperrors(bool);
Point translate(Window*, Window*, Point); Point translate(Window*, Window*, Point);
int traperrors(bool);
void ungrabkeyboard(void); void ungrabkeyboard(void);
void ungrabpointer(void); void ungrabpointer(void);
int unmapwin(Window*); int unmapwin(Window*);
@ -273,9 +304,4 @@ Window* window(XWindow);
char* windowname(Window*); char* windowname(Window*);
long winprotocols(Window*); long winprotocols(Window*);
Atom xatom(char*); 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);

View File

@ -19,6 +19,7 @@ OBJ=\
event/expose \ event/expose \
event/focusin \ event/focusin \
event/focusout \ event/focusout \
event/ixp \
event/keypress \ event/keypress \
event/leavenotify \ event/leavenotify \
event/mapnotify \ event/mapnotify \
@ -26,6 +27,10 @@ OBJ=\
event/mappingnotify \ event/mappingnotify \
event/motionnotify \ event/motionnotify \
event/propertynotify \ event/propertynotify \
event/reparentnotify \
event/selection \
event/selectionclear \
event/selectionrequest \
event/unmapnotify \ event/unmapnotify \
event/xtime \ event/xtime \
geom/get_sticky \ geom/get_sticky \
@ -38,7 +43,6 @@ OBJ=\
map \ map \
printevent \ printevent \
util/_die \ util/_die \
util/backtrace \
util/closeexec \ util/closeexec \
util/comm \ util/comm \
util/doublefork \ util/doublefork \
@ -114,6 +118,7 @@ OBJ=\
x11/images/freeimage \ x11/images/freeimage \
x11/images/xftdrawable \ x11/images/xftdrawable \
x11/insanity/gravitate \ x11/insanity/gravitate \
x11/insanity/gethints \
x11/insanity/sethints \ x11/insanity/sethints \
x11/insanity/sizehint \ x11/insanity/sizehint \
x11/keyboard/grabkeyboard \ x11/keyboard/grabkeyboard \

View File

@ -1,6 +1,7 @@
#define IXP_NO_P9_ #define IXP_NO_P9_
#define IXP_P9_STRUCTS #define IXP_P9_STRUCTS
#define CLIENTEXTERN #define CLIENTEXTERN
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <ixp.h> #include <ixp.h>
#include <stuff/clientutil.h> #include <stuff/clientutil.h>
@ -40,11 +41,13 @@ readctl(char *key) {
void void
client_init(char* address) { client_init(char* address) {
if(address == nil)
address = getenv("WMII_ADDRESS");
if(address && *address) if(address && *address)
client = ixp_mount(address); client = ixp_mount(address);
else else
client = ixp_nsmount("wmii"); client = ixp_nsmount("wmii");
if(client == nil) if(client == nil)
fatal("can't mount: %r\n"); fatal("can't mount wmii filesystem: %r\n");
} }

View File

@ -8,7 +8,7 @@ event_buttonpress(XButtonPressedEvent *ev) {
Window *w; Window *w;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, bdown, ev); event_handle(w, bdown, ev);
else else
XAllowEvents(display, ReplayPointer, ev->time); XAllowEvents(display, ReplayPointer, ev->time);
} }

View File

@ -8,5 +8,5 @@ event_buttonrelease(XButtonPressedEvent *ev) {
Window *w; Window *w;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, bup, ev); event_handle(w, bup, ev);
} }

View File

@ -5,6 +5,8 @@
void void
event_clientmessage(XClientMessageEvent *ev) { event_clientmessage(XClientMessageEvent *ev) {
Window *w;
USED(ev); if((w = findwin(ev->window)))
event_handle(w, message, ev);
} }

View File

@ -8,5 +8,5 @@ event_configurenotify(XConfigureEvent *ev) {
Window *w; Window *w;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, config, ev); event_handle(w, config, ev);
} }

View File

@ -9,7 +9,7 @@ event_configurerequest(XConfigureRequestEvent *ev) {
Window *w; Window *w;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, configreq, ev); event_handle(w, configreq, ev);
else{ else{
wc.x = ev->x; wc.x = ev->x;
wc.y = ev->y; wc.y = ev->y;

View File

@ -8,5 +8,5 @@ event_destroynotify(XDestroyWindowEvent *ev) {
Window *w; Window *w;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, destroy, ev); event_handle(w, destroy, ev);
} }

View File

@ -7,10 +7,11 @@ void
event_enternotify(XCrossingEvent *ev) { event_enternotify(XCrossingEvent *ev) {
Window *w; Window *w;
if(!ev->send_event)
event_xtime = ev->time; event_xtime = ev->time;
if(ev->mode != NotifyNormal) if(ev->mode != NotifyNormal)
return; return;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, enter, ev); event_handle(w, enter, ev);
} }

View File

@ -3,6 +3,7 @@
*/ */
#include "event.h" #include "event.h"
typedef void (*Handler)(Window*, void*, XEvent*);
void (*event_debug)(XEvent*); void (*event_debug)(XEvent*);
long event_xtime; long event_xtime;
bool event_looprunning; bool event_looprunning;
@ -25,9 +26,29 @@ EventHandler event_handler[LASTEvent] = {
[MappingNotify] = (EventHandler)event_mappingnotify, [MappingNotify] = (EventHandler)event_mappingnotify,
[MotionNotify] = (EventHandler)event_motionnotify, [MotionNotify] = (EventHandler)event_motionnotify,
[PropertyNotify] = (EventHandler)event_propertynotify, [PropertyNotify] = (EventHandler)event_propertynotify,
[ReparentNotify] = (EventHandler)event_reparentnotify,
[SelectionClear] = (EventHandler)event_selectionclear,
[SelectionNotify] = (EventHandler)event_selection,
[UnmapNotify] = (EventHandler)event_unmapnotify, [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 void
event_dispatch(XEvent *e) { event_dispatch(XEvent *e) {
if(event_debug) if(event_debug)

View File

@ -8,5 +8,5 @@ event_expose(XExposeEvent *ev) {
Window *w; Window *w;
if(ev->count == 0 && (w = findwin(ev->window))) if(ev->count == 0 && (w = findwin(ev->window)))
handle(w, expose, ev); event_handle(w, expose, ev);
} }

View File

@ -23,5 +23,5 @@ event_focusin(XFocusChangeEvent *ev) {
return; return;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, focusin, ev); event_handle(w, focusin, ev);
} }

View File

@ -15,5 +15,5 @@ event_focusout(XFocusChangeEvent *ev) {
return; return;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, focusout, ev); event_handle(w, focusout, ev);
} }

23
lib/libstuff/event/ixp.c Normal file
View File

@ -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;
}

View File

@ -7,7 +7,8 @@ void
event_keypress(XKeyEvent *ev) { event_keypress(XKeyEvent *ev) {
Window *w; Window *w;
if(!ev->send_event)
event_xtime = ev->time; event_xtime = ev->time;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, kdown, ev); event_handle(w, kdown, ev);
} }

View File

@ -7,7 +7,8 @@ void
event_leavenotify(XCrossingEvent *ev) { event_leavenotify(XCrossingEvent *ev) {
Window *w; Window *w;
if(!ev->send_event)
event_xtime = ev->time; event_xtime = ev->time;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, leave, ev); event_handle(w, leave, ev);
} }

View File

@ -8,5 +8,5 @@ event_mapnotify(XMapEvent *ev) {
Window *w; Window *w;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, map, ev); event_handle(w, map, ev);
} }

View File

@ -8,5 +8,5 @@ event_maprequest(XMapRequestEvent *ev) {
Window *w; Window *w;
if((w = findwin(ev->parent))) if((w = findwin(ev->parent)))
handle(w, mapreq, ev); event_handle(w, mapreq, ev);
} }

View File

@ -7,7 +7,8 @@ void
event_motionnotify(XMotionEvent *ev) { event_motionnotify(XMotionEvent *ev) {
Window *w; Window *w;
if(!ev->send_event)
event_xtime = ev->time; event_xtime = ev->time;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, motion, ev); event_handle(w, motion, ev);
} }

View File

@ -7,7 +7,8 @@ void
event_propertynotify(XPropertyEvent *ev) { event_propertynotify(XPropertyEvent *ev) {
Window *w; Window *w;
if(!ev->send_event)
event_xtime = ev->time; event_xtime = ev->time;
if((w = findwin(ev->window))) if((w = findwin(ev->window)))
handle(w, property, ev); event_handle(w, property, ev);
} }

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -10,6 +10,6 @@ event_unmapnotify(XUnmapEvent *ev) {
if((w = findwin(ev->window)) && (ev->event == w->parent->xid)) { if((w = findwin(ev->window)) && (ev->event == w->parent->xid)) {
w->mapped = false; w->mapped = false;
if(w->parent && (ev->send_event || w->unmapped-- == 0)) if(w->parent && (ev->send_event || w->unmapped-- == 0))
handle(w, unmap, ev); event_handle(w, unmap, ev);
} }
} }

View File

@ -13,8 +13,10 @@ errorhandler(Display *dpy, XErrorEvent *error) {
USED(dpy); USED(dpy);
if(_trap_errors) if(_trap_errors) {
nerrors++; nerrors++;
return 0;
}
e = ignored_xerrors; e = ignored_xerrors;
if(e) if(e)

View File

@ -44,6 +44,8 @@ Wfmt(Fmt *f) {
Window *w; Window *w;
w = va_arg(f->args, Window*); w = va_arg(f->args, Window*);
if(w == nil)
return fmtstrcpy(f, "<nil>");
return fmtprint(f, "0x%ulx", w->xid); return fmtprint(f, "0x%ulx", w->xid);
} }

View File

@ -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);
}

View File

@ -1,100 +1,97 @@
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail> /* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include <string.h>
#include "../x11.h" #include "../x11.h"
#include <string.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 void
sethints(Window *w) { sethints(Window *w, WinHints *h) {
XSizeHints xs; XSizeHints xhints = { 0, };
XWMHints *wmh; int i;
WinHints *h;
Point p; /* TODO: Group hint */
long size;
if(w->hints == nil) if(w->hints == nil)
w->hints = emalloc(sizeof *h); w->hints = emalloc(sizeof *h);
h = w->hints; *w->hints = *h;
memset(h, 0, sizeof *h);
h->max = Pt(INT_MAX, INT_MAX); if(!eqpt(h->min, ZP)) {
h->inc = Pt(1,1); xhints.flags |= PMinSize;
xhints.min_width = h->min.x;
wmh = XGetWMHints(display, w->xid); xhints.min_height = h->min.y;
if(wmh) { }
if(wmh->flags & WindowGroupHint) if(!eqpt(h->max, Pt(INT_MAX, INT_MAX))) {
h->group = wmh->window_group; xhints.flags |= PMaxSize;
free(wmh); xhints.max_width = h->max.x;
xhints.max_height = h->max.y;
} }
if(!XGetWMNormalHints(display, w->xid, &xs, &size)) if(!eqpt(h->base, ZP)) {
return; xhints.flags |= PBaseSize;
xhints.base_width = h->baspect.x;
if(xs.flags & PMinSize) { xhints.base_height = h->baspect.y;
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(!eqrect(h->aspect, ZR)) {
if(h->max.x < h->min.x) xhints.flags |= PAspect;
h->max.x = h->min.x;
if(h->max.y < h->min.y)
h->max.y = h->min.y;
h->base = h->min; xhints.base_width = h->baspect.x;
if(xs.flags & PBaseSize) { xhints.base_height = h->baspect.y;
p.x = xs.base_width;
p.y = xs.base_height; xhints.min_aspect.x = h->aspect.min.x;
h->base = p; xhints.min_aspect.y = h->aspect.min.y;
h->baspect = p;
xhints.max_aspect.x = h->aspect.max.x;
xhints.max_aspect.y = h->aspect.max.y;
} }
if(xs.flags & PResizeInc) { if(!eqpt(h->inc, Pt(1, 1))) {
h->inc.x = max(xs.width_inc, 1); xhints.flags |= PResizeInc;
h->inc.y = max(xs.height_inc, 1); xhints.width_inc = h->inc.x;
xhints.height_inc = h->inc.y;
} }
if(xs.flags & PAspect) { /* USPosition is probably an evil assumption, but it holds in our use cases. */
h->aspect.min.x = xs.min_aspect.x; if(h->position)
h->aspect.min.y = xs.min_aspect.y; xhints.flags |= USPosition | PPosition;
h->aspect.max.x = xs.max_aspect.x;
h->aspect.max.y = xs.max_aspect.y;
}
h->position = (xs.flags & (USPosition|PPosition)) != 0; xhints.flags |= PWinGravity;
if(h->gravstatic)
if(!(xs.flags & PWinGravity)) xhints.win_gravity = StaticGravity;
xs.win_gravity = NorthWestGravity; else
p = ZP; for(i=0; i < nelem(gravity_map); i++)
switch (xs.win_gravity) { if(h->grav.x == gravity_map[i].point.x &&
case EastGravity: h->grav.y == gravity_map[i].point.y) {
case CenterGravity: xhints.win_gravity = gravity_map[i].gravity;
case WestGravity:
p.y = 1;
break;
case SouthEastGravity:
case SouthGravity:
case SouthWestGravity:
p.y = 2;
break; break;
} }
switch (xs.win_gravity) {
case NorthGravity: XSetWMNormalHints(display, w->xid, &xhints);
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);
} }

View File

@ -19,6 +19,6 @@ changeprop_textlist(Window *w, char *prop, char *type, char *data[]) {
memcpy(t, *p, n); memcpy(t, *p, n);
t += n; t += n;
} }
changeprop_char(w, prop, type, s, len); changeprop_char(w, prop, type, s, len - 1);
free(s); free(s);
} }

View File

@ -4,6 +4,7 @@
#include "x11.h" #include "x11.h"
void 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); XSendEvent(display, w->xid, propegate, mask, e);
} }

View File

@ -2,19 +2,23 @@
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "x11.h" #include "x11.h"
#include <string.h>
void void
sendmessage(Window *w, char *name, long l0, long l1, long l2, long l3, long l4) { 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; XClientMessageEvent e;
e.type = ClientMessage; e.type = ClientMessage;
e.window = w->xid; e.window = w->xid;
e.message_type = xatom(name); e.message_type = xatom(name);
e.format = 32; e.format = format;
e.data.l[0] = l0; bcopy(&data, &e.data, sizeof(data));
e.data.l[1] = l1; sendevent(w, false, mask, (XEvent*)&e);
e.data.l[2] = l2;
e.data.l[3] = l3;
e.data.l[4] = l4;
sendevent(w, false, NoEventMask, (XEvent*)&e);
} }

View File

@ -2,6 +2,10 @@
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "../x11.h" #include "../x11.h"
#include <string.h>
#include <unistd.h>
static char hostname[HOST_NAME_MAX + 1];
Window* Window*
createwindow_visual(Window *parent, Rectangle r, createwindow_visual(Window *parent, Rectangle r,
@ -21,6 +25,8 @@ createwindow_visual(Window *parent, Rectangle r,
w->parent = parent; w->parent = parent;
if(valmask & CWColormap) if(valmask & CWColormap)
w->colormap = wa->colormap; 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), w->xid = XCreateWindow(display, parent->xid, r.min.x, r.min.y, Dx(r), Dy(r),
0 /* border */, depth, class, vis, valmask, wa); 0 /* border */, depth, class, vis, valmask, wa);
@ -31,6 +37,12 @@ createwindow_visual(Window *parent, Rectangle r,
if(class != InputOnly) if(class != InputOnly)
w->gc = XCreateGC(display, w->xid, 0, nil); 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->r = r;
w->depth = depth; w->depth = depth;
return w; return w;

View File

@ -7,6 +7,8 @@ void
destroywindow(Window *w) { destroywindow(Window *w) {
assert(w->type == WWindow); assert(w->type == WWindow);
sethandler(w, nil); sethandler(w, nil);
while(w->handler_link)
pophandler(w, w->handler_link->handler);
if(w->xft) if(w->xft)
xft->drawdestroy(w->xft); xft->drawdestroy(w->xft);
if(w->gc) if(w->gc)

View File

@ -5,5 +5,6 @@
void void
selectinput(Window *w, long mask) { selectinput(Window *w, long mask) {
w->eventmask = mask;
XSelectInput(display, w->xid, mask); XSelectInput(display, w->xid, mask);
} }

View File

@ -3,21 +3,72 @@
*/ */
#include "../x11.h" #include "../x11.h"
Handlers* static void
sethandler(Window *w, Handlers *new) { updatemap(Window *w) {
Handlers *old;
void **e; void **e;
assert(w->type == WWindow); assert(w->type == WWindow);
assert((w->prev != nil && w->next != nil) || w->next == w->prev); 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); map_rm(&windowmap, (ulong)w->xid);
else { else {
e = map_get(&windowmap, (ulong)w->xid, true); e = map_get(&windowmap, (ulong)w->xid, true);
*e = w; *e = w;
} }
}
Handlers*
sethandler(Window *w, Handlers *new) {
Handlers *old;
old = w->handler; old = w->handler;
w->handler = new; w->handler = new;
updatemap(w);
return old; 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;
}

View File

@ -4,6 +4,7 @@
#define _X11_VISIBLE #define _X11_VISIBLE
#include <stuff/x.h> #include <stuff/x.h>
#include <stuff/util.h> #include <stuff/util.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xrender.h> #include <X11/extensions/Xrender.h>
#include <X11/extensions/Xinerama.h> #include <X11/extensions/Xinerama.h>

View File

@ -7,7 +7,8 @@ TARG = wmii.1 \
wmii9menu.1\ wmii9menu.1\
wihack.1 \ wihack.1 \
wimenu.1 \ wimenu.1 \
wistrut.1 wistrut.1 \
witray.1
$(TARG): Makefile $(ROOT)/mk/wmii.mk header.t2t $(TARG): Makefile $(ROOT)/mk/wmii.mk header.t2t

View File

@ -193,7 +193,7 @@ provided.
.SH SEE ALSO .SH SEE ALSO
.P .P
wmii(1), wmiir(1), wmii9menu(1), dmenu(1) wmii(1), wmiir(1), wistrug(1), wmii9menu(1), dmenu(1)
.P .P
\fI[1]\fR http://www.suckless.org/wiki/wmii/tips/9p_tips \fI[1]\fR http://www.suckless.org/wiki/wmii/tips/9p_tips

View File

@ -168,7 +168,7 @@ most shells.
provided. provided.
: :
= SEE ALSO = = 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 [1] http://www.suckless.org/wiki/wmii/tips/9p_tips

View File

@ -1,4 +1,4 @@
.TH "WIMENU" 1 "May, 2010" "wmii-@VERSION@" .TH "WISTRUT" 1 "May, 2010" "wmii-@VERSION@"
.SH NAME .SH NAME
.P .P

View File

@ -1,4 +1,4 @@
WIMENU WISTRUT
wmii-@VERSION@ wmii-@VERSION@
May, 2010 May, 2010

85
man/witray.1 Normal file
View File

@ -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<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

60
man/witray.man1 Normal file
View File

@ -0,0 +1,60 @@
WITRAY
wmii-@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)

View File

@ -14,7 +14,7 @@ echo CC $($bin/cleanname ${BASE}$outfile)
[ -n "$noisycc" ] && echo $CC -o $outfile $CFLAGS $@ [ -n "$noisycc" ] && echo $CC -o $outfile $CFLAGS $@
eval '$CC -o $outfile '"$CFLAGS"' $@ >$xtmp 2>&1' eval '$CC -o $outfile '"$CFLAGS"' $@ >$xtmp 2>&1'
status=$? status=$?
[ $? -eq 0 ] || echo $CC -o $outfile $CFLAGS $@ >&2 [ $status -eq 0 ] || echo $CC -o $outfile $CFLAGS $@ >&2
base=$(echo $BASE | sed 's/,/\\,/g') base=$(echo $BASE | sed 's/,/\\,/g')
re='\([^[:space:]/][^[:space:]]*\..:[0-9]\)' re='\([^[:space:]/][^[:space:]]*\..:[0-9]\)'