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