1 
2 /*
3 * (C)opyright 2007-2009 Robert Manea <rob dot manea at gmail dot com>
4 * See LICENSE file for license details.
5 *
6 */
7 
8 #include "dzen.h"
9 #include "action.h"
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #ifdef DZEN_XPM
15 #include <X11/xpm.h>
16 #endif
17 
18 #define ARGLEN 256
19 #define MAX_ICON_CACHE 32
20 
21 #define MAX(a,b) ((a)>(b)?(a):(b))
22 #define LNR2WINDOW(lnr) lnr==-1?0:1
23 
24 typedef struct ICON_C {
25 	char name[ARGLEN];
26 	Pixmap p;
27 
28 	int w, h;
29 } icon_c;
30 
31 icon_c icons[MAX_ICON_CACHE];
32 int icon_cnt;
33 int otx;
34 
35 int xorig[2];
36 sens_w window_sens[2];
37 
38 /* command types for the in-text parser */
39 enum ctype  {bg, fg, icon, rect, recto, circle, circleo, pos, abspos, titlewin, ibg, fn, fixpos, ca, ba};
40 
41 struct command_lookup {
42 	const char *name;
43 	int id;
44 	int off;
45 };
46 
47 struct command_lookup cmd_lookup_table[] = {
48 	{ "fg(",        fg,			3},
49 	{ "bg(",        bg,			3},
50 	{ "i(",			icon,		2},
51 	{ "r(",	        rect,		2},
52 	{ "ro(",        recto,		3},
53 	{ "c(",	        circle,		2},
54 	{ "co(",        circleo,	3},
55 	{ "p(",	        pos,		2},
56 	{ "pa(",        abspos,		3},
57 	{ "tw(",        titlewin,	3},
58 	{ "ib(",        ibg,		3},
59 	{ "fn(",        fn,			3},
60 	{ "ca(",        ca,			3},
61 	{ "ba(",		ba,			3},
62 	{ 0,			0,			0}
63 };
64 
65 
66 /* positioning helpers */
67 enum sctype {LOCK_X, UNLOCK_X, TOP, BOTTOM, CENTER, LEFT, RIGHT};
68 
69 int get_tokval(const char* line, char **retdata);
70 int get_token(const char*  line, int * t, char **tval);
71 
72 static unsigned int
textnw(Fnt * font,const char * text,unsigned int len)73 textnw(Fnt *font, const char *text, unsigned int len) {
74 #ifndef DZEN_XFT
75 	XRectangle r;
76 
77 	if(font->set) {
78 		XmbTextExtents(font->set, text, len, NULL, &r);
79 		return r.width;
80 	}
81 	return XTextWidth(font->xfont, text, len);
82 #else
83 	XftTextExtentsUtf8(dzen.dpy, dzen.font.xftfont, (unsigned const char *) text, strlen(text), dzen.font.extents);
84 	if(dzen.font.extents->height > dzen.font.height)
85 		dzen.font.height = dzen.font.extents->height;
86 	return dzen.font.extents->xOff;
87 #endif
88 }
89 
90 
91 void
drawtext(const char * text,int reverse,int line,int align)92 drawtext(const char *text, int reverse, int line, int align) {
93 	if(!reverse) {
94 		XSetForeground(dzen.dpy, dzen.gc, dzen.norm[ColBG]);
95 		XFillRectangle(dzen.dpy, dzen.slave_win.drawable[line], dzen.gc, 0, 0, dzen.w, dzen.h);
96 		XSetForeground(dzen.dpy, dzen.gc, dzen.norm[ColFG]);
97 	}
98 	else {
99 		XSetForeground(dzen.dpy, dzen.rgc, dzen.norm[ColFG]);
100 		XFillRectangle(dzen.dpy, dzen.slave_win.drawable[line], dzen.rgc, 0, 0, dzen.w, dzen.h);
101 		XSetForeground(dzen.dpy, dzen.rgc, dzen.norm[ColBG]);
102 	}
103 
104 	parse_line(text, line, align, reverse, 0);
105 }
106 
107 long
getcolor(const char * colstr)108 getcolor(const char *colstr) {
109 	Colormap cmap = DefaultColormap(dzen.dpy, dzen.screen);
110 	XColor color;
111 
112 	if(!XAllocNamedColor(dzen.dpy, cmap, colstr, &color, &color))
113 		return -1;
114 
115 	return color.pixel;
116 }
117 
118 void
setfont(const char * fontstr)119 setfont(const char *fontstr) {
120 #ifndef DZEN_XFT
121 	char *def, **missing;
122 	int i, n;
123 
124 	missing = NULL;
125 	if(dzen.font.set)
126 		XFreeFontSet(dzen.dpy, dzen.font.set);
127 
128 	dzen.font.set = XCreateFontSet(dzen.dpy, fontstr, &missing, &n, &def);
129 	if(missing)
130 		XFreeStringList(missing);
131 
132 	if(dzen.font.set) {
133 		XFontSetExtents *font_extents;
134 		XFontStruct **xfonts;
135 		char **font_names;
136 		dzen.font.ascent = dzen.font.descent = 0;
137 		font_extents = XExtentsOfFontSet(dzen.font.set);
138 		n = XFontsOfFontSet(dzen.font.set, &xfonts, &font_names);
139 		for(i = 0, dzen.font.ascent = 0, dzen.font.descent = 0; i < n; i++) {
140 			if(dzen.font.ascent < (*xfonts)->ascent)
141 				dzen.font.ascent = (*xfonts)->ascent;
142 			if(dzen.font.descent < (*xfonts)->descent)
143 				dzen.font.descent = (*xfonts)->descent;
144 			xfonts++;
145 		}
146 	}
147 	else {
148 		if(dzen.font.xfont)
149 			XFreeFont(dzen.dpy, dzen.font.xfont);
150 		dzen.font.xfont = NULL;
151 		if(!(dzen.font.xfont = XLoadQueryFont(dzen.dpy, fontstr)))
152 			eprint("dzen: error, cannot load font: '%s'\n", fontstr);
153 		dzen.font.ascent = dzen.font.xfont->ascent;
154 		dzen.font.descent = dzen.font.xfont->descent;
155 	}
156 	dzen.font.height = dzen.font.ascent + dzen.font.descent;
157 #else
158         if(dzen.font.xftfont)
159            XftFontClose(dzen.dpy, dzen.font.xftfont);
160 	dzen.font.xftfont = XftFontOpenXlfd(dzen.dpy, dzen.screen, fontstr);
161 	if(!dzen.font.xftfont)
162 	   dzen.font.xftfont = XftFontOpenName(dzen.dpy, dzen.screen, fontstr);
163 	if(!dzen.font.xftfont)
164 	   eprint("error, cannot load font: '%s'\n", fontstr);
165 	dzen.font.extents = malloc(sizeof(XGlyphInfo));
166 	XftTextExtentsUtf8(dzen.dpy, dzen.font.xftfont, (unsigned const char *) fontstr, strlen(fontstr), dzen.font.extents);
167 	dzen.font.height = dzen.font.xftfont->ascent + dzen.font.xftfont->descent;
168 	dzen.font.width = (dzen.font.extents->width)/strlen(fontstr);
169 #endif
170 }
171 
172 
173 int
get_tokval(const char * line,char ** retdata)174 get_tokval(const char* line, char **retdata) {
175 	int i;
176 	char tokval[ARGLEN];
177 
178 	for(i=0; i < ARGLEN && (*(line+i) != ')'); i++)
179 		tokval[i] = *(line+i);
180 
181 	tokval[i] = '\0';
182 	*retdata = strdup(tokval);
183 
184 	return i+1;
185 }
186 
187 int
get_token(const char * line,int * t,char ** tval)188 get_token(const char *line, int * t, char **tval) {
189 	int off=0, next_pos=0, i;
190 	char *tokval = NULL;
191 
192 	if(*(line+1) == ESC_CHAR)
193 		return 0;
194 	line++;
195 
196 	for(i=0; cmd_lookup_table[i].name; ++i) {
197 		if( off=cmd_lookup_table[i].off,
198 				!strncmp(line, cmd_lookup_table[i].name, off) ) {
199 			next_pos = get_tokval(line+off, &tokval);
200 			*t = cmd_lookup_table[i].id;
201 			break;
202 		}
203 	}
204 
205 
206 	*tval = tokval;
207 	return next_pos+off;
208 }
209 
210 static void
setcolor(Drawable * pm,int x,int width,long tfg,long tbg,int reverse,int nobg)211 setcolor(Drawable *pm, int x, int width, long tfg, long tbg, int reverse, int nobg) {
212 
213 	if(nobg)
214 		return;
215 
216 	XSetForeground(dzen.dpy, dzen.tgc, reverse ? tfg : tbg);
217 	XFillRectangle(dzen.dpy, *pm, dzen.tgc, x, 0, width, dzen.line_height);
218 
219 	XSetForeground(dzen.dpy, dzen.tgc, reverse ? tbg : tfg);
220 	XSetBackground(dzen.dpy, dzen.tgc, reverse ? tfg : tbg);
221 }
222 
223 int
get_sens_area(char * s,int * b,char * cmd)224 get_sens_area(char *s, int *b, char *cmd) {
225 	memset(cmd, 0, 1024);
226     sscanf(s, "%5d", b);
227     char *comma = strchr(s, ',');
228     if (comma != NULL)
229         strncpy(cmd, comma+1, 1024);
230 
231 	return 0;
232 }
233 
234 static int
get_rect_vals(char * s,int * w,int * h,int * x,int * y)235 get_rect_vals(char *s, int *w, int *h, int *x, int *y) {
236 	*w=*h=*x=*y=0;
237 
238 	return sscanf(s, "%5dx%5d%5d%5d", w, h, x, y);
239 }
240 
241 static int
get_circle_vals(char * s,int * d,int * a)242 get_circle_vals(char *s, int *d, int *a) {
243 	int ret;
244 	*d=*a=ret=0;
245 
246 	return  sscanf(s, "%5d%5d", d, a);
247 }
248 
249 static int
get_pos_vals(char * s,int * d,int * a)250 get_pos_vals(char *s, int *d, int *a) {
251 	int i=0, ret=3, onlyx=1;
252 	char buf[128];
253 	*d=*a=0;
254 
255 	if(s[0] == '_') {
256 		if(!strncmp(s, "_LOCK_X", 7)) {
257 			*d = LOCK_X;
258 		}
259 		if(!strncmp(s, "_UNLOCK_X", 8)) {
260 			*d = UNLOCK_X;
261 		}
262 		if(!strncmp(s, "_LEFT", 5)) {
263 			*d = LEFT;
264 		}
265 		if(!strncmp(s, "_RIGHT", 6)) {
266 			*d = RIGHT;
267 		}
268 		if(!strncmp(s, "_CENTER", 7)) {
269 			*d = CENTER;
270 		}
271 		if(!strncmp(s, "_BOTTOM", 7)) {
272 			*d = BOTTOM;
273 		}
274 		if(!strncmp(s, "_TOP", 4)) {
275 			*d = TOP;
276 		}
277 
278 		return 5;
279 	} else {
280 		for(i=0; s[i] && i<128; i++) {
281 			if(s[i] == ';') {
282 				onlyx=0;
283 				break;
284 			} else
285 				buf[i]=s[i];
286 		}
287 
288 		if(i) {
289 			buf[i]='\0';
290 			*d=atoi(buf);
291 		} else
292 			ret=2;
293 
294 		if(s[++i]) {
295 			*a=atoi(s+i);
296 		} else
297 			ret = 1;
298 
299 		if(onlyx) ret=1;
300 
301 		return ret;
302 	}
303 }
304 
305 static int
get_block_align_vals(char * s,int * a,int * w)306 get_block_align_vals(char *s, int *a, int *w)
307 {
308 	char buf[32];
309 	int r;
310 	*w = -1;
311 	r = sscanf(s, "%d,%31s", w, buf);
312 	if(!strcmp(buf, "_LEFT"))
313 		*a = ALIGNLEFT;
314 	else if(!strcmp(buf, "_RIGHT"))
315 		*a = ALIGNRIGHT;
316 	else if(!strcmp(buf, "_CENTER"))
317 		*a = ALIGNCENTER;
318 	else
319 		*a = -1;
320 
321 	return r;
322 }
323 
324 
325 static int
search_icon_cache(const char * name)326 search_icon_cache(const char* name) {
327 	int i;
328 
329 	for(i=0; i < MAX_ICON_CACHE; i++)
330 		if(!strncmp(icons[i].name, name, ARGLEN))
331 			return i;
332 
333 	return -1;
334 }
335 
336 #ifdef DZEN_XPM
337 static void
cache_icon(const char * name,Pixmap pm,int w,int h)338 cache_icon(const char* name, Pixmap pm, int w, int h) {
339 	if(icon_cnt >= MAX_ICON_CACHE)
340 		icon_cnt = 0;
341 
342 	if(icons[icon_cnt].p)
343 		XFreePixmap(dzen.dpy, icons[icon_cnt].p);
344 
345 	strncpy(icons[icon_cnt].name, name, ARGLEN);
346 	icons[icon_cnt].w = w;
347 	icons[icon_cnt].h = h;
348 	icons[icon_cnt].p = pm;
349 	icon_cnt++;
350 }
351 #endif
352 
353 
354 char *
parse_line(const char * line,int lnr,int align,int reverse,int nodraw)355 parse_line(const char *line, int lnr, int align, int reverse, int nodraw) {
356 	/* bitmaps */
357 	unsigned int bm_w, bm_h;
358 	int bm_xh, bm_yh;
359 	/* rectangles, cirlcles*/
360 	int rectw, recth, rectx, recty;
361 	/* positioning */
362 	int n_posx, n_posy, set_posy=0;
363 	int px=0, py=0, opx=0;
364 	int i, next_pos=0, j=0, h=0, tw=0;
365 	/* buffer pos */
366 	const char *linep=NULL;
367 	/* fonts */
368 	int font_was_set=0;
369 	/* position */
370 	int pos_is_fixed = 0;
371 	/* block alignment */
372 	int block_align = -1;
373 	int block_width = -1;
374 	/* clickable area y tracking */
375 	int max_y=-1;
376 
377 	/* temp buffers */
378 	char lbuf[MAX_LINE_LEN], *rbuf = NULL;
379 
380 	/* parser state */
381 	int t=-1, nobg=0;
382 	char *tval=NULL;
383 
384 	/* X stuff */
385 	long lastfg = dzen.norm[ColFG], lastbg = dzen.norm[ColBG];
386 	Fnt *cur_fnt = NULL;
387 #ifndef DZEN_XFT
388 	XGCValues gcv;
389 #endif
390 	Drawable pm=0, bm;
391 #ifdef DZEN_XPM
392 	int free_xpm_attrib = 0;
393 	Pixmap xpm_pm;
394 	XpmAttributes xpma;
395 	XpmColorSymbol xpms;
396 #endif
397 
398 	/* icon cache */
399 	int ip;
400 
401 #ifdef DZEN_XFT
402 	XftDraw *xftd=NULL;
403 	XftColor xftc;
404 	char *xftcs;
405 	char *xftcs_bg;
406 
407 	/* set default fg/bg for XFT */
408 	xftcs = estrdup(dzen.fg);
409 	xftcs_bg = estrdup(dzen.bg);
410 #endif
411 
412 	/* parse line and return the text without control commands */
413 	if(nodraw) {
414 		rbuf = emalloc(MAX_LINE_LEN);
415 		rbuf[0] = '\0';
416 		if( (lnr + dzen.slave_win.first_line_vis) >= dzen.slave_win.tcnt)
417 			line = NULL;
418 		else
419 			line = dzen.slave_win.tbuf[dzen.slave_win.first_line_vis+lnr];
420 
421 	}
422 	/* parse line and render text */
423 	else {
424 		h = dzen.font.height;
425 		py = (dzen.line_height - h) / 2;
426 		xorig[LNR2WINDOW(lnr)] = 0;
427 
428 		if(lnr != -1) {
429 			pm = XCreatePixmap(dzen.dpy, RootWindow(dzen.dpy, DefaultScreen(dzen.dpy)), dzen.slave_win.width,
430 					dzen.line_height, DefaultDepth(dzen.dpy, dzen.screen));
431 		}
432 		else {
433 			pm = XCreatePixmap(dzen.dpy, RootWindow(dzen.dpy, DefaultScreen(dzen.dpy)), dzen.title_win.width,
434 					dzen.line_height, DefaultDepth(dzen.dpy, dzen.screen));
435 		}
436 
437 #ifdef DZEN_XFT
438 		xftd = XftDrawCreate(dzen.dpy, pm, DefaultVisual(dzen.dpy, dzen.screen),
439 				DefaultColormap(dzen.dpy, dzen.screen));
440 #endif
441 
442 		if(!reverse) {
443 			XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColBG]);
444 #ifdef DZEN_XPM
445 			xpms.pixel = dzen.norm[ColBG];
446 #endif
447 #ifdef DZEN_XFT
448 			xftcs_bg = estrdup(dzen.bg);
449 #endif
450 		}
451 		else {
452 			XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColFG]);
453 #ifdef DZEN_XPM
454 			xpms.pixel = dzen.norm[ColFG];
455 #endif
456 		}
457 		XFillRectangle(dzen.dpy, pm, dzen.tgc, 0, 0, dzen.w, dzen.h);
458 
459 		if(!reverse) {
460 			XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColFG]);
461 		}
462 		else {
463 			XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColBG]);
464 		}
465 
466 #ifdef DZEN_XPM
467 		xpms.name = NULL;
468 		xpms.value = (char *)"none";
469 
470 		xpma.colormap = DefaultColormap(dzen.dpy, dzen.screen);
471 		xpma.depth = DefaultDepth(dzen.dpy, dzen.screen);
472 		xpma.visual = DefaultVisual(dzen.dpy, dzen.screen);
473 		xpma.colorsymbols = &xpms;
474 		xpma.numsymbols = 1;
475 		xpma.valuemask = XpmColormap|XpmDepth|XpmVisual|XpmColorSymbols;
476 #endif
477 
478 #ifndef DZEN_XFT
479 		if(!dzen.font.set){
480 			gcv.font = dzen.font.xfont->fid;
481 			XChangeGC(dzen.dpy, dzen.tgc, GCFont, &gcv);
482 		}
483 #endif
484 		cur_fnt = &dzen.font;
485 
486 		if( lnr != -1 && (lnr + dzen.slave_win.first_line_vis >= dzen.slave_win.tcnt)) {
487 			XCopyArea(dzen.dpy, pm, dzen.slave_win.drawable[lnr], dzen.gc,
488 					0, 0, px, dzen.line_height, xorig[LNR2WINDOW(lnr)], 0);
489 			XFreePixmap(dzen.dpy, pm);
490 			return NULL;
491 		}
492 	}
493 
494 	linep = line;
495 	while(1) {
496 		if(*linep == ESC_CHAR || *linep == '\0') {
497 			lbuf[j] = '\0';
498 
499 			/* clear _lock_x at EOL so final width is correct */
500 			if(*linep=='\0')
501 				pos_is_fixed=0;
502 
503 			if(nodraw) {
504 				strcat(rbuf, lbuf);
505 			}
506 			else {
507 				if(t != -1 && tval) {
508 					switch(t) {
509 						case icon:
510 							if(MAX_ICON_CACHE && (ip=search_icon_cache(tval)) != -1) {
511 								int y;
512 								XCopyArea(dzen.dpy, icons[ip].p, pm, dzen.tgc,
513 										0, 0, icons[ip].w, icons[ip].h, px, y=(set_posy ? py :
514 										(dzen.line_height >= (signed)icons[ip].h ?
515 										(dzen.line_height - icons[ip].h)/2 : 0)));
516 								px += !pos_is_fixed ? icons[ip].w : 0;
517 								max_y = MAX(max_y, y+icons[ip].h);
518 							} else {
519 								int y;
520 								if(XReadBitmapFile(dzen.dpy, pm, tval, &bm_w,
521 											&bm_h, &bm, &bm_xh, &bm_yh) == BitmapSuccess
522 										&& (h/2 + px + (signed)bm_w < dzen.w)) {
523 									setcolor(&pm, px, bm_w, lastfg, lastbg, reverse, nobg);
524 
525 									XCopyPlane(dzen.dpy, bm, pm, dzen.tgc,
526 											0, 0, bm_w, bm_h, px, y=(set_posy ? py :
527 											(dzen.line_height >= (int)bm_h ?
528 												(dzen.line_height - (int)bm_h)/2 : 0)), 1);
529 									XFreePixmap(dzen.dpy, bm);
530 									px += !pos_is_fixed ? bm_w : 0;
531 									max_y = MAX(max_y, y+bm_h);
532 								}
533 #ifdef DZEN_XPM
534 								else if(XpmReadFileToPixmap(dzen.dpy, dzen.title_win.win, tval, &xpm_pm, NULL, &xpma) == XpmSuccess) {
535 									setcolor(&pm, px, xpma.width, lastfg, lastbg, reverse, nobg);
536 
537 									if(MAX_ICON_CACHE)
538 										cache_icon(tval, xpm_pm, xpma.width, xpma.height);
539 
540 									XCopyArea(dzen.dpy, xpm_pm, pm, dzen.tgc,
541 											0, 0, xpma.width, xpma.height, px, y=(set_posy ? py :
542 											(dzen.line_height >= (int)xpma.height ?
543 												(dzen.line_height - (int)xpma.height)/2 : 0)));
544 									px += !pos_is_fixed ? xpma.width : 0;
545 									max_y = MAX(max_y, y+xpma.height);
546 
547 									/* freed by cache_icon() */
548 									//XFreePixmap(dzen.dpy, xpm_pm);
549 									free_xpm_attrib = 1;
550 								}
551 #endif
552 							}
553 							break;
554 
555 
556 						case rect:
557 							get_rect_vals(tval, &rectw, &recth, &rectx, &recty);
558 							recth = recth > dzen.line_height ? dzen.line_height : recth;
559 							if(set_posy)
560 								py += recty;
561 							recty =	recty == 0 ? (dzen.line_height - recth)/2 :
562 								(dzen.line_height - recth)/2 + recty;
563 							px += !pos_is_fixed ? rectx : 0;
564 							setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
565 
566 							XFillRectangle(dzen.dpy, pm, dzen.tgc, px,
567 									set_posy ? py :
568 									((int)recty < 0 ? dzen.line_height + recty : recty),
569 									rectw, recth);
570 
571 							px += !pos_is_fixed ? rectw : 0;
572 							break;
573 
574 						case recto:
575 							get_rect_vals(tval, &rectw, &recth, &rectx, &recty);
576 							if (!rectw) break;
577 
578 							recth = recth > dzen.line_height ? dzen.line_height-2 : recth-1;
579 							if(set_posy)
580 								py += recty;
581 							recty =	recty == 0 ? (dzen.line_height - recth)/2 :
582 								(dzen.line_height - recth)/2 + recty;
583 							px = (rectx == 0) ? px : rectx+px;
584 							/* prevent from stairs effect when rounding recty */
585 							if (!((dzen.line_height - recth) % 2)) recty--;
586 							setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
587 							XDrawRectangle(dzen.dpy, pm, dzen.tgc, px,
588 									set_posy ? py :
589 									((int)recty<0 ? dzen.line_height + recty : recty), rectw-1, recth);
590 							px += !pos_is_fixed ? rectw : 0;
591 							break;
592 
593 						case circle:
594 							rectx = get_circle_vals(tval, &rectw, &recth);
595 							setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
596 							XFillArc(dzen.dpy, pm, dzen.tgc, px, set_posy ? py :(dzen.line_height - rectw)/2,
597 									rectw, rectw, 90*64, rectx>1?recth*64:64*360);
598 							px += !pos_is_fixed ? rectw : 0;
599 							break;
600 
601 						case circleo:
602 							rectx = get_circle_vals(tval, &rectw, &recth);
603 							setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
604 							XDrawArc(dzen.dpy, pm, dzen.tgc, px, set_posy ? py : (dzen.line_height - rectw)/2,
605 									rectw, rectw, 90*64, rectx>1?recth*64:64*360);
606 							px += !pos_is_fixed ? rectw : 0;
607 							break;
608 
609 						case pos:
610 							if(tval[0]) {
611 								int r=0;
612 								r = get_pos_vals(tval, &n_posx, &n_posy);
613 								if( (r == 1 && !set_posy))
614 									set_posy=0;
615 								else if (r == 5) {
616 									switch(n_posx) {
617 										case LOCK_X:
618 											pos_is_fixed = 1;
619 											break;
620 										case UNLOCK_X:
621 											pos_is_fixed = 0;
622 											break;
623 										case LEFT:
624 											px = 0;
625 											break;
626 										case RIGHT:
627 											px = dzen.w;
628 											break;
629 										case CENTER:
630 											px = dzen.w/2;
631 											break;
632 										case BOTTOM:
633 											set_posy = 1;
634 											py = dzen.line_height;
635 											break;
636 										case TOP:
637 											set_posy = 1;
638 											py = 0;
639 											break;
640 									}
641 								} else
642 									set_posy=1;
643 
644 								if(r != 2)
645 									px = px+n_posx<0? 0 : px + n_posx;
646 								if(r != 1)
647 									py += n_posy;
648 							} else {
649 								set_posy = 0;
650 								py = (dzen.line_height - dzen.font.height) / 2;
651 							}
652 							break;
653 
654 						case abspos:
655 							if(tval[0]) {
656 								int r=0;
657 								if( (r=get_pos_vals(tval, &n_posx, &n_posy)) == 1 && !set_posy)
658 									set_posy=0;
659 								else
660 									set_posy=1;
661 
662 								n_posx = n_posx < 0 ? n_posx*-1 : n_posx;
663 								if(r != 2)
664 									px = n_posx;
665 								if(r != 1)
666 									py = n_posy;
667 							} else {
668 								set_posy = 0;
669 								py = (dzen.line_height - dzen.font.height) / 2;
670 							}
671 							break;
672 
673 						case ibg:
674 							nobg = atoi(tval);
675 							break;
676 
677 						case bg:
678 							lastbg = tval[0] ? (unsigned)getcolor(tval) : dzen.norm[ColBG];
679 #ifdef DZEN_XFT
680 							if(xftcs_bg) free(xftcs_bg);
681 							xftcs_bg = estrdup(tval[0] ? tval : dzen.bg);
682 #endif
683 
684 							break;
685 
686 						case fg:
687 							lastfg = tval[0] ? (unsigned)getcolor(tval) : dzen.norm[ColFG];
688 							XSetForeground(dzen.dpy, dzen.tgc, lastfg);
689 #ifdef DZEN_XFT
690 							if (xftcs) free(xftcs);
691 							xftcs = estrdup(tval[0] ? tval : dzen.fg);
692 #endif
693 							break;
694 
695 						case fn:
696 							if(tval[0]) {
697 #ifndef DZEN_XFT
698 								if(!strncmp(tval, "dfnt", 4)) {
699 									cur_fnt = &(dzen.fnpl[atoi(tval+4)]);
700 
701 									if(!cur_fnt->set) {
702 										gcv.font = cur_fnt->xfont->fid;
703 										XChangeGC(dzen.dpy, dzen.tgc, GCFont, &gcv);
704 									}
705 								}
706 								else
707 #endif
708 									setfont(tval);
709 							}
710 							else {
711 								cur_fnt = &dzen.font;
712 #ifndef DZEN_XFT
713 								if(!cur_fnt->set){
714 									gcv.font = cur_fnt->xfont->fid;
715 									XChangeGC(dzen.dpy, dzen.tgc, GCFont, &gcv);
716 								}
717 #else
718 							setfont(dzen.fnt ? dzen.fnt : FONT);
719 #endif
720 							}
721 							py = set_posy ? py : (dzen.line_height - cur_fnt->height) / 2;
722 							font_was_set = 1;
723 							break;
724 						case ca:
725 							; //nop to keep gcc happy
726 							sens_w *w = &window_sens[LNR2WINDOW(lnr)];
727 
728 							if(tval[0]) {
729 								click_a *area = &((*w).sens_areas[(*w).sens_areas_cnt]);
730 								if((*w).sens_areas_cnt < MAX_CLICKABLE_AREAS) {
731 									get_sens_area(tval,
732 											&(*area).button,
733 											(*area).cmd);
734 									(*area).start_x = px;
735 									(*area).start_y = py;
736 									(*area).end_y = py;
737 									max_y = py;
738 									(*area).active = 0;
739 									if(lnr == -1) {
740 										(*area).win = dzen.title_win.win;
741 									} else {
742 										(*area).win = dzen.slave_win.line[lnr];
743 									}
744 									(*w).sens_areas_cnt++;
745 								}
746 							} else {
747 									//find most recent unclosed area
748 									for(i = (*w).sens_areas_cnt - 1; i >= 0; i--)
749 										if(!(*w).sens_areas[i].active)
750 											break;
751 									if(i >= 0 && i < MAX_CLICKABLE_AREAS) {
752 										(*w).sens_areas[i].end_x = px;
753 										(*w).sens_areas[i].end_y = max_y;
754 										(*w).sens_areas[i].active = 1;
755 								}
756 							}
757 							break;
758 						case ba:
759 							if(tval[0])
760 								get_block_align_vals(tval, &block_align, &block_width);
761 							else
762 								block_align=block_width=-1;
763 							break;
764 					}
765 					free(tval);
766 				}
767 
768 				/* check if text is longer than window's width */
769 				tw = textnw(cur_fnt, lbuf, strlen(lbuf));
770 				while((((tw + px) > (dzen.w)) || (block_align!=-1 && tw>block_width)) && j>=0) {
771 					lbuf[--j] = '\0';
772 					tw = textnw(cur_fnt, lbuf, strlen(lbuf));
773 				}
774 
775 				opx = px;
776 
777 				/* draw background for block */
778 				if(block_align!=-1 && !nobg) {
779 					setcolor(&pm, px, rectw, lastbg, lastbg, 0, nobg);
780 					XFillRectangle(dzen.dpy, pm, dzen.tgc, px, 0, block_width, dzen.line_height);
781 				}
782 
783 				if(block_align==ALIGNRIGHT)
784 					px += (block_width - tw);
785 				else if(block_align==ALIGNCENTER)
786 					px += (block_width/2) - (tw/2);
787 
788 				if(!nobg)
789 					setcolor(&pm, px, tw, lastfg, lastbg, reverse, nobg);
790 
791 #ifndef DZEN_XFT
792 				if(cur_fnt->set)
793 					XmbDrawString(dzen.dpy, pm, cur_fnt->set,
794 							dzen.tgc, px, py + cur_fnt->ascent, lbuf, strlen(lbuf));
795 				else
796 					XDrawString(dzen.dpy, pm, dzen.tgc, px, py+dzen.font.ascent, lbuf, strlen(lbuf));
797 #else
798 				if(reverse) {
799 				XftColorAllocName(dzen.dpy, DefaultVisual(dzen.dpy, dzen.screen),
800 						DefaultColormap(dzen.dpy, dzen.screen),  xftcs_bg,  &xftc);
801 				} else {
802 				XftColorAllocName(dzen.dpy, DefaultVisual(dzen.dpy, dzen.screen),
803 						DefaultColormap(dzen.dpy, dzen.screen),  xftcs,  &xftc);
804 				}
805 
806 				XftDrawStringUtf8(xftd, &xftc,
807 						cur_fnt->xftfont, px, py + dzen.font.xftfont->ascent, (const FcChar8 *)lbuf, strlen(lbuf));
808 #endif
809 
810 				max_y = MAX(max_y, py+dzen.font.height);
811 
812 				if(block_align==-1) {
813 					if(!pos_is_fixed || *linep =='\0')
814 						px += tw;
815 				} else {
816 					if(pos_is_fixed)
817 						px = opx;
818 					else
819 						px = opx+block_width;
820 				}
821 
822 				block_align=block_width=-1;
823 			}
824 
825 			if(*linep=='\0')
826 				break;
827 
828 			j=0; t=-1; tval=NULL;
829 			next_pos = get_token(linep, &t, &tval);
830 			linep += next_pos;
831 
832 			/* ^^ escapes */
833 			if(next_pos == 0)
834 				lbuf[j++] = *linep++;
835 		}
836 		else
837 			lbuf[j++] = *linep;
838 
839 		linep++;
840 	}
841 
842 	if(!nodraw) {
843 		/* expand/shrink dynamically */
844 		if(dzen.title_win.expand && lnr == -1){
845 			i = px;
846 			switch(dzen.title_win.expand) {
847 				case left:
848 					/* grow left end */
849 					otx = dzen.title_win.x_right_corner - i > dzen.title_win.x ?
850 						dzen.title_win.x_right_corner - i : dzen.title_win.x;
851 					XMoveResizeWindow(dzen.dpy, dzen.title_win.win, otx, dzen.title_win.y, px, dzen.line_height);
852 					break;
853 				case right:
854 					XResizeWindow(dzen.dpy, dzen.title_win.win, px, dzen.line_height);
855 					break;
856 			}
857 
858 		} else {
859 			if(align == ALIGNLEFT)
860 				xorig[LNR2WINDOW(lnr)] = 0;
861 			if(align == ALIGNCENTER) {
862 				xorig[LNR2WINDOW(lnr)] = (lnr != -1) ?
863 					(dzen.slave_win.width - px)/2 :
864 					(dzen.title_win.width - px)/2;
865 			}
866 			else if(align == ALIGNRIGHT) {
867 				xorig[LNR2WINDOW(lnr)] = (lnr != -1) ?
868 					(dzen.slave_win.width - px) :
869 					(dzen.title_win.width - px);
870 			}
871 		}
872 
873 
874 		if(lnr != -1) {
875 			XCopyArea(dzen.dpy, pm, dzen.slave_win.drawable[lnr], dzen.gc,
876                     0, 0, dzen.w, dzen.line_height, xorig[LNR2WINDOW(lnr)], 0);
877 		}
878 		else {
879 			XCopyArea(dzen.dpy, pm, dzen.title_win.drawable, dzen.gc,
880 					0, 0, dzen.w, dzen.line_height, xorig[LNR2WINDOW(lnr)], 0);
881 		}
882 		XFreePixmap(dzen.dpy, pm);
883 
884 		/* reset font to default */
885 		if(font_was_set)
886 			setfont(dzen.fnt ? dzen.fnt : FONT);
887 
888 #ifdef DZEN_XPM
889 		if(free_xpm_attrib) {
890 			XFreeColors(dzen.dpy, xpma.colormap, xpma.pixels, xpma.npixels, xpma.depth);
891 			XpmFreeAttributes(&xpma);
892 		}
893 #endif
894 
895 #ifdef DZEN_XFT
896 		XftDrawDestroy(xftd);
897 #endif
898 	}
899 
900 #ifdef DZEN_XFT
901 	if(xftcs) free(xftcs);
902 	if(xftcs_bg) free(xftcs_bg);
903 #endif
904 
905 	return nodraw ? rbuf : NULL;
906 }
907 
908 int
parse_non_drawing_commands(char * text)909 parse_non_drawing_commands(char * text) {
910 
911 	if(!text)
912 		return 1;
913 
914 	if(!strncmp(text, "^togglecollapse()", strlen("^togglecollapse()"))) {
915 		a_togglecollapse(NULL);
916 		return 0;
917 	}
918 	if(!strncmp(text, "^collapse()", strlen("^collapse()"))) {
919 		a_collapse(NULL);
920 		return 0;
921 	}
922 	if(!strncmp(text, "^uncollapse()", strlen("^uncollapse()"))) {
923 		a_uncollapse(NULL);
924 		return 0;
925 	}
926 
927 	if(!strncmp(text, "^togglestick()", strlen("^togglestick()"))) {
928 		a_togglestick(NULL);
929 		return 0;
930 	}
931 	if(!strncmp(text, "^stick()", strlen("^stick()"))) {
932 		a_stick(NULL);
933 		return 0;
934 	}
935 	if(!strncmp(text, "^unstick()", strlen("^unstick()"))) {
936 		a_unstick(NULL);
937 		return 0;
938 	}
939 
940 	if(!strncmp(text, "^togglehide()", strlen("^togglehide()"))) {
941 		a_togglehide(NULL);
942 		return 0;
943 	}
944 	if(!strncmp(text, "^hide()", strlen("^hide()"))) {
945 		a_hide(NULL);
946 		return 0;
947 	}
948 	if(!strncmp(text, "^unhide()", strlen("^unhide()"))) {
949 		a_unhide(NULL);
950 		return 0;
951 	}
952 
953 	if(!strncmp(text, "^raise()", strlen("^raise()"))) {
954 		a_raise(NULL);
955 		return 0;
956 	}
957 
958 	if(!strncmp(text, "^lower()", strlen("^lower()"))) {
959 		a_lower(NULL);
960 		return 0;
961 	}
962 
963 	if(!strncmp(text, "^scrollhome()", strlen("^scrollhome()"))) {
964 		a_scrollhome(NULL);
965 		return 0;
966 	}
967 
968 	if(!strncmp(text, "^scrollend()", strlen("^scrollend()"))) {
969 		a_scrollend(NULL);
970 		return 0;
971 	}
972 
973 	if(!strncmp(text, "^exit()", strlen("^exit()"))) {
974 		a_exit(NULL);
975 		return 0;
976 	}
977 
978 	return 1;
979 }
980 
981 
982 void
drawheader(const char * text)983 drawheader(const char * text) {
984 	if(parse_non_drawing_commands((char *)text)) {
985 		if (text){
986 			dzen.w = dzen.title_win.width;
987 			dzen.h = dzen.line_height;
988 
989 			window_sens[TOPWINDOW].sens_areas_cnt = 0;
990 
991 			XFillRectangle(dzen.dpy, dzen.title_win.drawable, dzen.rgc, 0, 0, dzen.w, dzen.h);
992 			parse_line(text, -1, dzen.title_win.alignment, 0, 0);
993 		}
994 	} else {
995 		dzen.slave_win.tcnt = -1;
996 		dzen.cur_line = 0;
997 	}
998 
999 	XCopyArea(dzen.dpy, dzen.title_win.drawable, dzen.title_win.win,
1000 			dzen.gc, 0, 0, dzen.title_win.width, dzen.line_height, 0, 0);
1001 }
1002 
1003 void
drawbody(char * text)1004 drawbody(char * text) {
1005 	char *ec;
1006 	int i, write_buffer=1;
1007 
1008 
1009 	if(dzen.slave_win.tcnt == -1) {
1010 		dzen.slave_win.tcnt = 0;
1011 		drawheader(text);
1012 		return;
1013 	}
1014 
1015 
1016 	if((ec = strstr(text, "^tw()")) && (*(ec-1) != '^')) {
1017 		drawheader(ec+5);
1018 		return;
1019 	}
1020 
1021 	if(dzen.slave_win.tcnt == dzen.slave_win.tsize)
1022 		free_buffer();
1023 
1024 	write_buffer = parse_non_drawing_commands(text);
1025 
1026 
1027 	if(text[0] == '^' && text[1] == 'c' && text[2] == 's') {
1028 		free_buffer();
1029 
1030 		for(i=0; i < dzen.slave_win.max_lines; i++)
1031 			XFillRectangle(dzen.dpy, dzen.slave_win.drawable[i], dzen.rgc, 0, 0, dzen.slave_win.width, dzen.line_height);
1032 		x_draw_body();
1033 		return;
1034 	}
1035 
1036 	if( write_buffer && (dzen.slave_win.tcnt < dzen.slave_win.tsize) ) {
1037 		dzen.slave_win.tbuf[dzen.slave_win.tcnt] = estrdup(text);
1038 		dzen.slave_win.tcnt++;
1039 	}
1040 }
1041