wmii/cmd/tray/client.c
2010-06-20 14:24:04 -04:00

207 lines
4.0 KiB
C

/* 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 = pixelvalue(&scr.root, &tray.selcolors.bg);
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;
}
cleanupwindow(&c->w);
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 bool
config_event(Window *w, void *aux, XConfigureEvent *e) {
Client *c;
c = aux;
if(false)
movewin(c->indicator, addpt(w->r.min, Pt(1, 1)));
return false;
}
static bool
configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) {
Dprint("configreq_event(%W)\n", w);
/* This seems, sadly, to be necessary. */
tray_update();
return false;
}
static bool
map_event(Window *w, void *aux, XMapEvent *e) {
Dprint("client map_event(%W)\n", w);
w->mapped = true;
tray_update();
return false;
}
static bool
unmap_event(Window *w, void *aux, XUnmapEvent *e) {
Dprint("client map_event(%W)\n", w);
tray_update();
return false;
}
static bool
reparent_event(Window *w, void *aux, XReparentEvent *e) {
Dprint("client reparent_event(%W)\n", w);
return false;
}
static Handlers handlers = {
.config = config_event,
.configreq = configreq_event,
.map = map_event,
.unmap = unmap_event,
.reparent = reparent_event,
};