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