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"
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
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,6 @@
#include <unistd.h>
#include <stuff/x.h>
#include <stuff/util.h>
#include <ixp.h>
#ifndef 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 ewmh_getstrut(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);
}
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{

View File

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

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
OBJ = area \
bar \
backtrace \
client \
column \
div \

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,16 @@
#include <stdbool.h>
enum DebugOpt {
D9p = 1<<0,
DDnd = 1<<1,
DEvent = 1<<2,
DEwmh = 1<<3,
DFocus = 1<<4,
DGeneric= 1<<5,
DStack = 1<<6,
NDebugOpt = 7,
};
#define Debug(x) if(((debugflag|debugfile)&(x)) && setdebug(x))
#define Dprint(x, ...) BLOCK( if((debugflag|debugfile)&(x)) debug(x, __VA_ARGS__) )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,18 +1,25 @@
#pragma once
#define _XOPEN_SOURCE 600
#include <sys/types.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#ifndef nil
#define nil ((void*)0)
# define nil ((void*)0)
#endif
#ifndef nelem
#define nelem(ary) (sizeof(ary) / sizeof(*ary))
# define nelem(ary) (sizeof(ary) / sizeof(*ary))
#endif
#ifndef offsetof
# define offsetof(type, member) ((size_t)&((type*)0)->member)
#endif
#define structmember(ptr, type, offset) \
(*(type*)((char*)(ptr) + (offset)))
#undef uchar
#undef ushort
#undef uint

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
#define IXP_NO_P9_
#define IXP_P9_STRUCTS
#define CLIENTEXTERN
#include <stdlib.h>
#include <string.h>
#include <ixp.h>
#include <stuff/clientutil.h>
@ -40,11 +41,13 @@ 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");
}

View File

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

View File

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

View File

@ -5,6 +5,8 @@
void
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;
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;
if((w = findwin(ev->window)))
handle(w, configreq, ev);
event_handle(w, configreq, ev);
else{
wc.x = ev->x;
wc.y = ev->y;

View File

@ -8,5 +8,5 @@ event_destroynotify(XDestroyWindowEvent *ev) {
Window *w;
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) {
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);
}

View File

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

View File

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

View File

@ -23,5 +23,5 @@ event_focusin(XFocusChangeEvent *ev) {
return;
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;
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) {
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);
}

View File

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

View File

@ -8,5 +8,5 @@ event_mapnotify(XMapEvent *ev) {
Window *w;
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;
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) {
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);
}

View File

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

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)) {
w->mapped = false;
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);
if(_trap_errors)
if(_trap_errors) {
nerrors++;
return 0;
}
e = ignored_xerrors;
if(e)

View File

@ -44,6 +44,8 @@ Wfmt(Fmt *f) {
Window *w;
w = va_arg(f->args, Window*);
if(w == nil)
return fmtstrcpy(f, "<nil>");
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>
* See LICENSE file for license details.
*/
#include <string.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
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);
}

View File

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

View File

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

View File

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

View File

@ -2,6 +2,10 @@
* See LICENSE file for license details.
*/
#include "../x11.h"
#include <string.h>
#include <unistd.h>
static char hostname[HOST_NAME_MAX + 1];
Window*
createwindow_visual(Window *parent, Rectangle r,
@ -21,6 +25,8 @@ 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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
WIMENU
WISTRUT
wmii-@VERSION@
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 $@
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]\)'