wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

client.c (4048B)


      1 /* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
      2  * See LICENSE file for license details.
      3  */
      4 #include "dat.h"
      5 #include "fns.h"
      6 #include <string.h>
      7 
      8 static Handlers	handlers;
      9 
     10 static void client_cleanup(XEmbed*);
     11 
     12 void
     13 client_manage(XWindow w) {
     14 	Client **cp;
     15 	Client *c;
     16 	WinAttr wa;
     17 	int size;
     18 
     19 	c = emallocz(sizeof *c);
     20 	c->w.type = WWindow;
     21 	c->w.xid = w;
     22 	c->w.aux = c;
     23 
     24 	Dprint("client_manage(%W)\n", &c->w);
     25 
     26 	traperrors(true);
     27 	XAddToSaveSet(display, w);
     28 	c->xembed = xembed_swallow(tray.win, &c->w, client_cleanup);
     29 	if(traperrors(false)) {
     30 		fprint(2, "client_manage(0x%ulx): Caught error.\n", w);
     31 		if(c->xembed)
     32 			xembed_disown(c->xembed);
     33 		return;
     34 	}
     35 
     36 	wa.background_pixel = pixelvalue(&scr.root, &tray.selcolors.bg);
     37 	size = max(tray.iconsize / 4, 4);
     38 
     39 	c->indicator = createwindow(tray.win, Rect(0, 0, size, size), scr.depth,
     40 				    InputOutput, &wa, CWBackPixel);
     41 	setborder(c->indicator, 1, &tray.selcolors.border);
     42 
     43 	sethandler(&c->w, &handlers);
     44 
     45 	for(cp=&tray.clients; *cp; cp=&(*cp)->next)
     46 		;
     47 	*cp = c;
     48 
     49 	tray_update();
     50 }
     51 
     52 void
     53 client_disown(Client *c) {
     54 
     55 	Dprint("client_disown(%W)\n", &c->w);
     56 	xembed_disown(c->xembed);
     57 }
     58 
     59 static void
     60 client_cleanup(XEmbed *e) {
     61 	Client **cp;
     62 	Client *c;
     63 
     64 	c = e->w->aux;
     65 	destroywindow(c->indicator);
     66 
     67 	for(cp=&tray.clients; *cp; cp=&(*cp)->next)
     68 		if(*cp == c) {
     69 			*cp = c->next;
     70 			break;
     71 		}
     72 	cleanupwindow(&c->w);
     73 	free(c);
     74 	tray_update();
     75 }
     76 
     77 Client*
     78 client_find(Window *w) {
     79 	Client *c;
     80 
     81 	for(c=tray.clients; c; c=c->next)
     82 		if(&c->w == w)
     83 			return c;
     84 	return nil;
     85 }
     86 
     87 void
     88 message_cancel(Client *c, long id) {
     89 	Message *m, **mp;
     90 
     91 	for(mp=&c->message; (m = *mp) && m->id != id; mp=&m->next)
     92 		;
     93 
     94 	if(m) {
     95 		*mp = m->next;
     96 		free(m->msg.data);
     97 		free(m);
     98 	}
     99 }
    100 
    101 bool
    102 client_hasmessage(Client *c) {
    103 	Message *m;
    104 
    105 	for(m=c->message; m; m=m->next)
    106 		if(m->msg.pos == m->msg.end)
    107 			return true;
    108 	return false;
    109 }
    110 
    111 void
    112 client_opcode(Client *c, long message, long l1, long l2, long l3) {
    113 	Message *m, **mp;
    114 
    115 	Dprint("client_opcode(%p, %s, %ulx, %ulx, %ulx)\n",
    116 	       c,
    117 	       message == TrayRequestDock   ? "TrayRequestDock" :
    118 	       message == TrayBeginMessage  ? "TrayBeginMessage" :
    119 	       message == TrayCancelMessage ? "TrayCancelMessage" :
    120 	       sxprint("%lx", message),
    121 	       l1, l2, l3);
    122 
    123 	if(message == TrayBeginMessage)
    124 		message_cancel(c, l1);
    125 	else if(message == TrayBeginMessage) {
    126 		if(l2 > 5 * 1024) /* Don't bother with absurdly large messages. */
    127 			return;
    128 
    129 		m = emallocz(sizeof *m);
    130 		m->timeout = l1;
    131 		m->msg     = ixp_message(emallocz(l2), l2, MsgPack);
    132 		m->id      = l3;
    133 
    134 		/* Add the message to the end of the queue. */
    135 		for(mp=&c->message; *mp; mp=&(*mp)->next)
    136 			;
    137 		*mp = m;
    138 	}
    139 }
    140 
    141 void
    142 client_message(Client *c, long type, int format, ClientMessageData* data) {
    143 	Message *m;
    144 
    145 	if(format == 8 && type == NET("SYSTEM_TRAY_MESSAGE_DATA")) {
    146 		/* Append the data to the last incomplete message. */
    147 		for(m = c->message; m && m->msg.pos >= m->msg.end; m++)
    148 			;
    149 		if(m) {
    150 			memcpy(m->msg.pos, data, min(20, m->msg.end - m->msg.pos));
    151 			m->msg.pos += min(20, m->msg.end - m->msg.pos);
    152 		}
    153 	}
    154 }
    155 
    156 static bool
    157 config_event(Window *w, void *aux, XConfigureEvent *e) {
    158 	Client *c;
    159 
    160 	c = aux;
    161 	if(false)
    162 		movewin(c->indicator, addpt(w->r.min, Pt(1, 1)));
    163 	return false;
    164 }
    165 
    166 static bool
    167 configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) {
    168 
    169 	Dprint("configreq_event(%W)\n", w);
    170 	/* This seems, sadly, to be necessary. */
    171 	tray_update();
    172 	return false;
    173 }
    174 
    175 static bool
    176 map_event(Window *w, void *aux, XMapEvent *e) {
    177 
    178 	Dprint("client map_event(%W)\n", w);
    179 	w->mapped = true;
    180 	tray_update();
    181 	return false;
    182 }
    183 
    184 static bool
    185 unmap_event(Window *w, void *aux, XUnmapEvent *e) {
    186 
    187 	Dprint("client map_event(%W)\n", w);
    188 	tray_update();
    189 	return false;
    190 }
    191 
    192 static bool
    193 reparent_event(Window *w, void *aux, XReparentEvent *e) {
    194 
    195 	Dprint("client reparent_event(%W)\n", w);
    196 	return false;
    197 }
    198 
    199 static Handlers handlers = {
    200 	.config = config_event,
    201 	.configreq = configreq_event,
    202 	.map = map_event,
    203 	.unmap = unmap_event,
    204 	.reparent = reparent_event,
    205 };
    206