/*
* (C)opyright 2007-2009 Robert Manea <rob dot manea at gmail dot com>
* See LICENSE file for license details.
*
*/
#include "dzen.h"
#include "action.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef DZEN_XPM
#include <X11/xpm.h>
#endif
#define ARGLEN 256
#define MAX_ICON_CACHE 32
#define MAX(a,b) ((a)>(b)?(a):(b))
typedef struct ICON_C {
char name[ARGLEN];
Pixmap p;
int w, h;
} icon_c;
icon_c icons[MAX_ICON_CACHE];
int icon_cnt;
int otx;
int xorig=0;
/* command types for the in-text parser */
enum ctype {bg, fg, icon, rect, recto, circle, circleo, pos, abspos, titlewin, ibg, fn, fixpos, ca, ba};
struct command_lookup {
const char *name;
int id;
int off;
};
struct command_lookup cmd_lookup_table[] = {
{ "fg(", fg, 3},
{ "bg(", bg, 3},
{ "i(", icon, 2},
{ "r(", rect, 2},
{ "ro(", recto, 3},
{ "c(", circle, 2},
{ "co(", circleo, 3},
{ "p(", pos, 2},
{ "pa(", abspos, 3},
{ "tw(", titlewin, 3},
{ "ib(", ibg, 3},
{ "fn(", fn, 3},
{ "ca(", ca, 3},
{ "ba(", ba, 3},
{ 0, 0, 0}
};
/* positioning helpers */
enum sctype {LOCK_X, UNLOCK_X, TOP, BOTTOM, CENTER, LEFT, RIGHT};
int get_tokval(const char* line, char **retdata);
int get_token(const char* line, int * t, char **tval);
static unsigned int
textnw(Fnt *font, const char *text, unsigned int len) {
#ifndef DZEN_XFT
XRectangle r;
if(font->set) {
XmbTextExtents(font->set, text, len, NULL, &r);
return r.width;
}
return XTextWidth(font->xfont, text, len);
#else
XftTextExtentsUtf8(dzen.dpy, dzen.font.xftfont, (unsigned const char *) text, strlen(text), dzen.font.extents);
if(dzen.font.extents->height > dzen.font.height)
dzen.font.height = dzen.font.extents->height;
return dzen.font.extents->xOff;
#endif
}
void
drawtext(const char *text, int reverse, int line, int align) {
if(!reverse) {
XSetForeground(dzen.dpy, dzen.gc, dzen.norm[ColBG]);
XFillRectangle(dzen.dpy, dzen.slave_win.drawable[line], dzen.gc, 0, 0, dzen.w, dzen.h);
XSetForeground(dzen.dpy, dzen.gc, dzen.norm[ColFG]);
}
else {
XSetForeground(dzen.dpy, dzen.rgc, dzen.norm[ColFG]);
XFillRectangle(dzen.dpy, dzen.slave_win.drawable[line], dzen.rgc, 0, 0, dzen.w, dzen.h);
XSetForeground(dzen.dpy, dzen.rgc, dzen.norm[ColBG]);
}
parse_line(text, line, align, reverse, 0);
}
long
getcolor(const char *colstr) {
long color;
if ((color = colorcache_get(colstr)) != -1)
return color;
else {
Colormap cmap = DefaultColormap(dzen.dpy, dzen.screen);
XColor color;
if(!XAllocNamedColor(dzen.dpy, cmap, colstr, &color, &color))
return -1;
colorcache_set(colstr, color.pixel);
return color.pixel;
}
}
void
setfont(const char *fontstr) {
#ifndef DZEN_XFT
char *def, **missing;
int i, n;
missing = NULL;
if(dzen.font.set)
XFreeFontSet(dzen.dpy, dzen.font.set);
dzen.font.set = XCreateFontSet(dzen.dpy, fontstr, &missing, &n, &def);
if(missing)
XFreeStringList(missing);
if(dzen.font.set) {
XFontSetExtents *font_extents;
XFontStruct **xfonts;
char **font_names;
dzen.font.ascent = dzen.font.descent = 0;
font_extents = XExtentsOfFontSet(dzen.font.set);
n = XFontsOfFontSet(dzen.font.set, &xfonts, &font_names);
for(i = 0, dzen.font.ascent = 0, dzen.font.descent = 0; i < n; i++) {
if(dzen.font.ascent < (*xfonts)->ascent)
dzen.font.ascent = (*xfonts)->ascent;
if(dzen.font.descent < (*xfonts)->descent)
dzen.font.descent = (*xfonts)->descent;
xfonts++;
}
}
else {
if(dzen.font.xfont)
XFreeFont(dzen.dpy, dzen.font.xfont);
dzen.font.xfont = NULL;
if(!(dzen.font.xfont = XLoadQueryFont(dzen.dpy, fontstr)))
eprint("dzen: error, cannot load font: '%s'\n", fontstr);
dzen.font.ascent = dzen.font.xfont->ascent;
dzen.font.descent = dzen.font.xfont->descent;
}
dzen.font.height = dzen.font.ascent + dzen.font.descent;
#else
dzen.font.xftfont = XftFontOpenXlfd(dzen.dpy, dzen.screen, fontstr);
if(!dzen.font.xftfont)
dzen.font.xftfont = XftFontOpenName(dzen.dpy, dzen.screen, fontstr);
if(!dzen.font.xftfont)
eprint("error, cannot load font: '%s'\n", fontstr);
dzen.font.extents = malloc(sizeof(XGlyphInfo));
XftTextExtentsUtf8(dzen.dpy, dzen.font.xftfont, (unsigned const char *) fontstr, strlen(fontstr), dzen.font.extents);
dzen.font.height = dzen.font.xftfont->ascent + dzen.font.xftfont->descent;
dzen.font.width = (dzen.font.extents->width)/strlen(fontstr);
#endif
}
int
get_tokval(const char* line, char **retdata) {
int i;
char tokval[ARGLEN];
for(i=0; i < ARGLEN && (*(line+i) != ')'); i++)
tokval[i] = *(line+i);
tokval[i] = '\0';
*retdata = strdup(tokval);
return i+1;
}
int
get_token(const char *line, int * t, char **tval) {
int off=0, next_pos=0, i;
char *tokval = NULL;
if(*(line+1) == ESC_CHAR)
return 0;
line++;
for(i=0; cmd_lookup_table[i].name; ++i) {
if( off=cmd_lookup_table[i].off,
!strncmp(line, cmd_lookup_table[i].name, off) ) {
next_pos = get_tokval(line+off, &tokval);
*t = cmd_lookup_table[i].id;
break;
}
}
*tval = tokval;
return next_pos+off;
}
static void
setcolor(Drawable *pm, int x, int width, long tfg, long tbg, int reverse, int nobg) {
if(nobg)
return;
XSetForeground(dzen.dpy, dzen.tgc, reverse ? tfg : tbg);
XFillRectangle(dzen.dpy, *pm, dzen.tgc, x, 0, width, dzen.line_height);
XSetForeground(dzen.dpy, dzen.tgc, reverse ? tbg : tfg);
XSetBackground(dzen.dpy, dzen.tgc, reverse ? tfg : tbg);
}
int
get_sens_area(char *s, int *b, char *cmd) {
memset(cmd, 0, 1024);
sscanf(s, "%5d", b);
char *comma = strchr(s, ',');
if (comma != NULL)
strncpy(cmd, comma+1, 1024);
return 0;
}
static int
get_rect_vals(char *s, int *w, int *h, int *x, int *y) {
*w=*h=*x=*y=0;
return sscanf(s, "%5dx%5d%5d%5d", w, h, x, y);
}
static int
get_circle_vals(char *s, int *d, int *a) {
int ret;
*d=*a=ret=0;
return sscanf(s, "%5d%5d", d, a);
}
static int
get_pos_vals(char *s, int *d, int *a) {
int i=0, ret=3, onlyx=1;
char buf[128];
*d=*a=0;
if(s[0] == '_') {
if(!strncmp(s, "_LOCK_X", 7)) {
*d = LOCK_X;
}
if(!strncmp(s, "_UNLOCK_X", 8)) {
*d = UNLOCK_X;
}
if(!strncmp(s, "_LEFT", 5)) {
*d = LEFT;
}
if(!strncmp(s, "_RIGHT", 6)) {
*d = RIGHT;
}
if(!strncmp(s, "_CENTER", 7)) {
*d = CENTER;
}
if(!strncmp(s, "_BOTTOM", 7)) {
*d = BOTTOM;
}
if(!strncmp(s, "_TOP", 4)) {
*d = TOP;
}
return 5;
} else {
for(i=0; s[i] && i<128; i++) {
if(s[i] == ';') {
onlyx=0;
break;
} else
buf[i]=s[i];
}
if(i) {
buf[i]='\0';
*d=atoi(buf);
} else
ret=2;
if(s[++i]) {
*a=atoi(s+i);
} else
ret = 1;
if(onlyx) ret=1;
return ret;
}
}
static int
get_block_align_vals(char *s, int *a, int *w)
{
char buf[32];
int r;
*w = -1;
r = sscanf(s, "%d,%31s", w, buf);
if(!strcmp(buf, "_LEFT"))
*a = ALIGNLEFT;
else if(!strcmp(buf, "_RIGHT"))
*a = ALIGNRIGHT;
else if(!strcmp(buf, "_CENTER"))
*a = ALIGNCENTER;
else
*a = -1;
return r;
}
static int
search_icon_cache(const char* name) {
int i;
for(i=0; i < MAX_ICON_CACHE; i++)
if(!strncmp(icons[i].name, name, ARGLEN))
return i;
return -1;
}
#ifdef DZEN_XPM
static void
cache_icon(const char* name, Pixmap pm, int w, int h) {
if(icon_cnt >= MAX_ICON_CACHE)
icon_cnt = 0;
if(icons[icon_cnt].p)
XFreePixmap(dzen.dpy, icons[icon_cnt].p);
strncpy(icons[icon_cnt].name, name, ARGLEN);
icons[icon_cnt].w = w;
icons[icon_cnt].h = h;
icons[icon_cnt].p = pm;
icon_cnt++;
}
#endif
char *
parse_line(const char *line, int lnr, int align, int reverse, int nodraw) {
/* bitmaps */
unsigned int bm_w, bm_h;
int bm_xh, bm_yh;
/* rectangles, cirlcles*/
int rectw, recth, rectx, recty;
/* positioning */
int n_posx, n_posy, set_posy=0;
int px=0, py=0, opx=0;
int i, next_pos=0, j=0, h=0, tw=0;
/* buffer pos */
const char *linep=NULL;
/* fonts */
int font_was_set=0;
/* position */
int pos_is_fixed = 0;
/* block alignment */
int block_align = -1;
int block_width = -1;
/* clickable area y tracking */
int max_y=-1;
/* temp buffers */
char lbuf[MAX_LINE_LEN], *rbuf = NULL;
/* parser state */
int t=-1, nobg=0;
char *tval=NULL;
/* X stuff */
long lastfg = dzen.norm[ColFG], lastbg = dzen.norm[ColBG];
Fnt *cur_fnt = NULL;
#ifndef DZEN_XFT
XGCValues gcv;
#endif
Drawable pm=0, bm;
#ifdef DZEN_XPM
int free_xpm_attrib = 0;
Pixmap xpm_pm;
XpmAttributes xpma;
XpmColorSymbol xpms;
#endif
#ifdef DZEN_XFT
XftDraw *xftd=NULL;
XftColor xftc;
char *xftcs;
int xftcs_f=0;
char *xftcs_bg;
int xftcs_bgf=0;
xftcs = (char *)dzen.fg;
xftcs_bg = (char *)dzen.bg;
#endif
/* icon cache */
int ip;
/* parse line and return the text without control commands */
if(nodraw) {
rbuf = emalloc(MAX_LINE_LEN);
rbuf[0] = '\0';
if( (lnr + dzen.slave_win.first_line_vis) >= dzen.slave_win.tcnt)
line = NULL;
else
line = dzen.slave_win.tbuf[dzen.slave_win.first_line_vis+lnr];
}
/* parse line and render text */
else {
h = dzen.font.height;
py = (dzen.line_height - h) / 2;
xorig = 0;
if(lnr != -1) {
pm = XCreatePixmap(dzen.dpy, RootWindow(dzen.dpy, DefaultScreen(dzen.dpy)), dzen.slave_win.width,
dzen.line_height, DefaultDepth(dzen.dpy, dzen.screen));
}
else {
pm = XCreatePixmap(dzen.dpy, RootWindow(dzen.dpy, DefaultScreen(dzen.dpy)), dzen.title_win.width,
dzen.line_height, DefaultDepth(dzen.dpy, dzen.screen));
sens_areas_cnt = 0;
}
#ifdef DZEN_XFT
xftd = XftDrawCreate(dzen.dpy, pm, DefaultVisual(dzen.dpy, dzen.screen),
DefaultColormap(dzen.dpy, dzen.screen));
#endif
if(!reverse) {
XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColBG]);
#ifdef DZEN_XPM
xpms.pixel = dzen.norm[ColBG];
#endif
#ifdef DZEN_XFT
xftcs_bg = (char *)dzen.bg;
xftcs_bgf = 0;
#endif
}
else {
XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColFG]);
#ifdef DZEN_XPM
xpms.pixel = dzen.norm[ColFG];
#endif
}
XFillRectangle(dzen.dpy, pm, dzen.tgc, 0, 0, dzen.w, dzen.h);
if(!reverse) {
XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColFG]);
}
else {
XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColBG]);
}
#ifdef DZEN_XPM
xpms.name = NULL;
xpms.value = (char *)"none";
xpma.colormap = DefaultColormap(dzen.dpy, dzen.screen);
xpma.depth = DefaultDepth(dzen.dpy, dzen.screen);
xpma.visual = DefaultVisual(dzen.dpy, dzen.screen);
xpma.colorsymbols = &xpms;
xpma.numsymbols = 1;
xpma.valuemask = XpmColormap|XpmDepth|XpmVisual|XpmColorSymbols;
#endif
#ifndef DZEN_XFT
if(!dzen.font.set){
gcv.font = dzen.font.xfont->fid;
XChangeGC(dzen.dpy, dzen.tgc, GCFont, &gcv);
}
#endif
cur_fnt = &dzen.font;
if( lnr != -1 && (lnr + dzen.slave_win.first_line_vis >= dzen.slave_win.tcnt)) {
XCopyArea(dzen.dpy, pm, dzen.slave_win.drawable[lnr], dzen.gc,
0, 0, px, dzen.line_height, xorig, 0);
XFreePixmap(dzen.dpy, pm);
return NULL;
}
}
linep = line;
while(1) {
if(*linep == ESC_CHAR || *linep == '\0') {
lbuf[j] = '\0';
/* clear _lock_x at EOL so final width is correct */
if(*linep=='\0')
pos_is_fixed=0;
if(nodraw) {
strcat(rbuf, lbuf);
}
else {
if(t != -1 && tval) {
switch(t) {
case icon:
if(MAX_ICON_CACHE && (ip=search_icon_cache(tval)) != -1) {
int y;
XCopyArea(dzen.dpy, icons[ip].p, pm, dzen.tgc,
0, 0, icons[ip].w, icons[ip].h, px, y=(set_posy ? py :
(dzen.line_height >= (signed)icons[ip].h ?
(dzen.line_height - icons[ip].h)/2 : 0)));
px += !pos_is_fixed ? icons[ip].w : 0;
max_y = MAX(max_y, y+icons[ip].h);
} else {
int y;
if(XReadBitmapFile(dzen.dpy, pm, tval, &bm_w,
&bm_h, &bm, &bm_xh, &bm_yh) == BitmapSuccess
&& (h/2 + px + (signed)bm_w < dzen.w)) {
setcolor(&pm, px, bm_w, lastfg, lastbg, reverse, nobg);
XCopyPlane(dzen.dpy, bm, pm, dzen.tgc,
0, 0, bm_w, bm_h, px, y=(set_posy ? py :
(dzen.line_height >= (int)bm_h ?
(dzen.line_height - (int)bm_h)/2 : 0)), 1);
XFreePixmap(dzen.dpy, bm);
px += !pos_is_fixed ? bm_w : 0;
max_y = MAX(max_y, y+bm_h);
}
#ifdef DZEN_XPM
else if(XpmReadFileToPixmap(dzen.dpy, dzen.title_win.win, tval, &xpm_pm, NULL, &xpma) == XpmSuccess) {
setcolor(&pm, px, xpma.width, lastfg, lastbg, reverse, nobg);
if(MAX_ICON_CACHE)
cache_icon(tval, xpm_pm, xpma.width, xpma.height);
XCopyArea(dzen.dpy, xpm_pm, pm, dzen.tgc,
0, 0, xpma.width, xpma.height, px, y=(set_posy ? py :
(dzen.line_height >= (int)xpma.height ?
(dzen.line_height - (int)xpma.height)/2 : 0)));
px += !pos_is_fixed ? xpma.width : 0;
max_y = MAX(max_y, y+xpma.height);
/* freed by cache_icon() */
//XFreePixmap(dzen.dpy, xpm_pm);
free_xpm_attrib = 1;
}
#endif
}
break;
case rect:
get_rect_vals(tval, &rectw, &recth, &rectx, &recty);
recth = recth > dzen.line_height ? dzen.line_height : recth;
if(set_posy)
py += recty;
recty = recty == 0 ? (dzen.line_height - recth)/2 :
(dzen.line_height - recth)/2 + recty;
px += !pos_is_fixed ? rectx : 0;
setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
XFillRectangle(dzen.dpy, pm, dzen.tgc, px,
set_posy ? py :
((int)recty < 0 ? dzen.line_height + recty : recty),
rectw, recth);
px += !pos_is_fixed ? rectw : 0;
break;
case recto:
get_rect_vals(tval, &rectw, &recth, &rectx, &recty);
if (!rectw) break;
recth = recth > dzen.line_height ? dzen.line_height-2 : recth-1;
if(set_posy)
py += recty;
recty = recty == 0 ? (dzen.line_height - recth)/2 :
(dzen.line_height - recth)/2 + recty;
px = (rectx == 0) ? px : rectx+px;
/* prevent from stairs effect when rounding recty */
if (!((dzen.line_height - recth) % 2)) recty--;
setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
XDrawRectangle(dzen.dpy, pm, dzen.tgc, px,
set_posy ? py :
((int)recty<0 ? dzen.line_height + recty : recty), rectw-1, recth);
px += !pos_is_fixed ? rectw : 0;
break;
case circle:
rectx = get_circle_vals(tval, &rectw, &recth);
setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
XFillArc(dzen.dpy, pm, dzen.tgc, px, set_posy ? py :(dzen.line_height - rectw)/2,
rectw, rectw, 90*64, rectx>1?recth*64:64*360);
px += !pos_is_fixed ? rectw : 0;
break;
case circleo:
rectx = get_circle_vals(tval, &rectw, &recth);
setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
XDrawArc(dzen.dpy, pm, dzen.tgc, px, set_posy ? py : (dzen.line_height - rectw)/2,
rectw, rectw, 90*64, rectx>1?recth*64:64*360);
px += !pos_is_fixed ? rectw : 0;
break;
case pos:
if(tval[0]) {
int r=0;
r = get_pos_vals(tval, &n_posx, &n_posy);
if( (r == 1 && !set_posy))
set_posy=0;
else if (r == 5) {
switch(n_posx) {
case LOCK_X:
pos_is_fixed = 1;
break;
case UNLOCK_X:
pos_is_fixed = 0;
break;
case LEFT:
px = 0;
break;
case RIGHT:
px = dzen.w;
break;
case CENTER:
px = dzen.w/2;
break;
case BOTTOM:
set_posy = 1;
py = dzen.line_height;
break;
case TOP:
set_posy = 1;
py = 0;
break;
}
} else
set_posy=1;
if(r != 2)
px = px+n_posx<0? 0 : px + n_posx;
if(r != 1)
py += n_posy;
} else {
set_posy = 0;
py = (dzen.line_height - dzen.font.height) / 2;
}
break;
case abspos:
if(tval[0]) {
int r=0;
if( (r=get_pos_vals(tval, &n_posx, &n_posy)) == 1 && !set_posy)
set_posy=0;
else
set_posy=1;
n_posx = n_posx < 0 ? n_posx*-1 : n_posx;
if(r != 2)
px = n_posx;
if(r != 1)
py = n_posy;
} else {
set_posy = 0;
py = (dzen.line_height - dzen.font.height) / 2;
}
break;
case ibg:
nobg = atoi(tval);
break;
case bg:
lastbg = tval[0] ? (unsigned)getcolor(tval) : dzen.norm[ColBG];
#ifdef DZEN_XFT
if(xftcs_bgf) free(xftcs_bg);
if(tval[0]) {
xftcs_bg = estrdup(tval);
xftcs_bgf = 1;
} else {
xftcs_bg = (char *)dzen.bg;
xftcs_bgf = 0;
}
#endif
break;
case fg:
lastfg = tval[0] ? (unsigned)getcolor(tval) : dzen.norm[ColFG];
XSetForeground(dzen.dpy, dzen.tgc, lastfg);
#ifdef DZEN_XFT
if(tval[0]) {
xftcs = estrdup(tval);
xftcs_f = 1;
} else {
xftcs = (char *)dzen.fg;
xftcs_f = 0;
}
#endif
break;
case fn:
if(tval[0]) {
#ifndef DZEN_XFT
if(!strncmp(tval, "dfnt", 4)) {
cur_fnt = &(dzen.fnpl[atoi(tval+4)]);
if(!cur_fnt->set) {
gcv.font = cur_fnt->xfont->fid;
XChangeGC(dzen.dpy, dzen.tgc, GCFont, &gcv);
}
}
else
#endif
setfont(tval);
}
else {
cur_fnt = &dzen.font;
#ifndef DZEN_XFT
if(!cur_fnt->set){
gcv.font = cur_fnt->xfont->fid;
XChangeGC(dzen.dpy, dzen.tgc, GCFont, &gcv);
}
#else
setfont(dzen.fnt ? dzen.fnt : FONT);
#endif
}
py = set_posy ? py : (dzen.line_height - cur_fnt->height) / 2;
font_was_set = 1;
break;
case ca:
if(lnr == -1) {
if(tval[0]) {
if(sens_areas_cnt < MAX_CLICKABLE_AREAS) {
get_sens_area(tval,
&sens_areas[sens_areas_cnt].button,
sens_areas[sens_areas_cnt].cmd);
sens_areas[sens_areas_cnt].start_x = px;
sens_areas[sens_areas_cnt].start_y = py;
sens_areas[sens_areas_cnt].end_y = py;
max_y = py;
sens_areas[sens_areas_cnt].active = 0;
sens_areas_cnt++;
}
} else {
/* find most recent unclosed area */
for(i = sens_areas_cnt - 1; i >= 0; i--)
if(!sens_areas[i].active)
break;
if(i >= 0 && i < MAX_CLICKABLE_AREAS) {
sens_areas[i].end_x = px;
sens_areas[i].end_y = max_y;
sens_areas[i].active = 1;
}
}
}
break;
case ba:
if(tval[0])
get_block_align_vals(tval, &block_align, &block_width);
else
block_align=block_width=-1;
break;
}
free(tval);
}
/* check if text is longer than window's width */
tw = textnw(cur_fnt, lbuf, strlen(lbuf));
while((((tw + px) > (dzen.w)) || (block_align!=-1 && tw>block_width)) && j>=0) {
lbuf[--j] = '\0';
tw = textnw(cur_fnt, lbuf, strlen(lbuf));
}
opx = px;
/* draw background for block */
if(block_align!=-1 && !nobg) {
setcolor(&pm, px, rectw, lastbg, lastbg, 0, nobg);
XFillRectangle(dzen.dpy, pm, dzen.tgc, px, 0, block_width, dzen.line_height);
}
if(block_align==ALIGNRIGHT)
px += (block_width - tw);
else if(block_align==ALIGNCENTER)
px += (block_width/2) - (tw/2);
if(!nobg)
setcolor(&pm, px, tw, lastfg, lastbg, reverse, nobg);
#ifndef DZEN_XFT
if(cur_fnt->set)
XmbDrawString(dzen.dpy, pm, cur_fnt->set,
dzen.tgc, px, py + cur_fnt->ascent, lbuf, strlen(lbuf));
else
XDrawString(dzen.dpy, pm, dzen.tgc, px, py+dzen.font.ascent, lbuf, strlen(lbuf));
#else
if(reverse) {
if (!xftcolorcache_get(xftcs_bg, &xftc)) {
XftColorAllocName(dzen.dpy, DefaultVisual(dzen.dpy, dzen.screen),
DefaultColormap(dzen.dpy, dzen.screen), xftcs_bg, &xftc);
xftcolorcache_set(xftcs_bg, &xftc);
}
} else {
if (!xftcolorcache_get(xftcs, &xftc)) {
XftColorAllocName(dzen.dpy, DefaultVisual(dzen.dpy, dzen.screen),
DefaultColormap(dzen.dpy, dzen.screen), xftcs, &xftc);
xftcolorcache_set(xftcs, &xftc);
}
}
XftDrawStringUtf8(xftd, &xftc,
cur_fnt->xftfont, px, py + dzen.font.xftfont->ascent, (const FcChar8 *)lbuf, strlen(lbuf));
if(xftcs_f) {
free(xftcs);
xftcs_f = 0;
}
if(xftcs_bgf) {
free(xftcs_bg);
xftcs_bgf = 0;
}
#endif
max_y = MAX(max_y, py+dzen.font.height);
if(block_align==-1) {
if(!pos_is_fixed || *linep =='\0')
px += tw;
} else {
if(pos_is_fixed)
px = opx;
else
px = opx+block_width;
}
block_align=block_width=-1;
}
if(*linep=='\0')
break;
j=0; t=-1; tval=NULL;
next_pos = get_token(linep, &t, &tval);
linep += next_pos;
/* ^^ escapes */
if(next_pos == 0)
lbuf[j++] = *linep++;
}
else
lbuf[j++] = *linep;
linep++;
}
if(!nodraw) {
/* expand/shrink dynamically */
if(dzen.title_win.expand && lnr == -1){
i = px;
switch(dzen.title_win.expand) {
case left:
/* grow left end */
otx = dzen.title_win.x_right_corner - i > dzen.title_win.x ?
dzen.title_win.x_right_corner - i : dzen.title_win.x;
XMoveResizeWindow(dzen.dpy, dzen.title_win.win, otx, dzen.title_win.y, px, dzen.line_height);
break;
case right:
XResizeWindow(dzen.dpy, dzen.title_win.win, px, dzen.line_height);
break;
}
} else {
if(align == ALIGNLEFT)
xorig = 0;
if(align == ALIGNCENTER) {
xorig = (lnr != -1) ?
(dzen.slave_win.width - px)/2 :
(dzen.title_win.width - px)/2;
}
else if(align == ALIGNRIGHT) {
xorig = (lnr != -1) ?
(dzen.slave_win.width - px) :
(dzen.title_win.width - px);
}
}
if(lnr != -1) {
XCopyArea(dzen.dpy, pm, dzen.slave_win.drawable[lnr], dzen.gc,
0, 0, dzen.w, dzen.line_height, xorig, 0);
}
else {
XCopyArea(dzen.dpy, pm, dzen.title_win.drawable, dzen.gc,
0, 0, dzen.w, dzen.line_height, xorig, 0);
}
XFreePixmap(dzen.dpy, pm);
/* reset font to default */
if(font_was_set)
setfont(dzen.fnt ? dzen.fnt : FONT);
#ifdef DZEN_XPM
if(free_xpm_attrib) {
XFreeColors(dzen.dpy, xpma.colormap, xpma.pixels, xpma.npixels, xpma.depth);
XpmFreeAttributes(&xpma);
}
#endif
#ifdef DZEN_XFT
XftDrawDestroy(xftd);
#endif
}
return nodraw ? rbuf : NULL;
}
int
parse_non_drawing_commands(char * text) {
if(!text)
return 1;
if(!strncmp(text, "^togglecollapse()", strlen("^togglecollapse()"))) {
a_togglecollapse(NULL);
return 0;
}
if(!strncmp(text, "^collapse()", strlen("^collapse()"))) {
a_collapse(NULL);
return 0;
}
if(!strncmp(text, "^uncollapse()", strlen("^uncollapse()"))) {
a_uncollapse(NULL);
return 0;
}
if(!strncmp(text, "^togglestick()", strlen("^togglestick()"))) {
a_togglestick(NULL);
return 0;
}
if(!strncmp(text, "^stick()", strlen("^stick()"))) {
a_stick(NULL);
return 0;
}
if(!strncmp(text, "^unstick()", strlen("^unstick()"))) {
a_unstick(NULL);
return 0;
}
if(!strncmp(text, "^togglehide()", strlen("^togglehide()"))) {
a_togglehide(NULL);
return 0;
}
if(!strncmp(text, "^hide()", strlen("^hide()"))) {
a_hide(NULL);
return 0;
}
if(!strncmp(text, "^unhide()", strlen("^unhide()"))) {
a_unhide(NULL);
return 0;
}
if(!strncmp(text, "^raise()", strlen("^raise()"))) {
a_raise(NULL);
return 0;
}
if(!strncmp(text, "^lower()", strlen("^lower()"))) {
a_lower(NULL);
return 0;
}
if(!strncmp(text, "^scrollhome()", strlen("^scrollhome()"))) {
a_scrollhome(NULL);
return 0;
}
if(!strncmp(text, "^scrollend()", strlen("^scrollend()"))) {
a_scrollend(NULL);
return 0;
}
if(!strncmp(text, "^exit()", strlen("^exit()"))) {
a_exit(NULL);
return 0;
}
return 1;
}
void
drawheader(const char * text) {
if(parse_non_drawing_commands((char *)text)) {
if (text){
dzen.w = dzen.title_win.width;
dzen.h = dzen.line_height;
XFillRectangle(dzen.dpy, dzen.title_win.drawable, dzen.rgc, 0, 0, dzen.w, dzen.h);
parse_line(text, -1, dzen.title_win.alignment, 0, 0);
}
} else {
dzen.slave_win.tcnt = -1;
dzen.cur_line = 0;
}
XCopyArea(dzen.dpy, dzen.title_win.drawable, dzen.title_win.win,
dzen.gc, 0, 0, dzen.title_win.width, dzen.line_height, 0, 0);
}
void
drawbody(char * text) {
char *ec;
int i, write_buffer=1;
if(dzen.slave_win.tcnt == -1) {
dzen.slave_win.tcnt = 0;
drawheader(text);
return;
}
if((ec = strstr(text, "^tw()")) && (*(ec-1) != '^')) {
dzen.w = dzen.title_win.width;
dzen.h = dzen.line_height;
XFillRectangle(dzen.dpy, dzen.title_win.drawable, dzen.rgc, 0, 0, dzen.w, dzen.h);
parse_line(ec+5, -1, dzen.title_win.alignment, 0, 0);
XCopyArea(dzen.dpy, dzen.title_win.drawable, dzen.title_win.win,
dzen.gc, 0, 0, dzen.w, dzen.h, 0, 0);
return;
}
if(dzen.slave_win.tcnt == dzen.slave_win.tsize)
free_buffer();
write_buffer = parse_non_drawing_commands(text);
if(text[0] == '^' && text[1] == 'c' && text[2] == 's') {
free_buffer();
for(i=0; i < dzen.slave_win.max_lines; i++)
XFillRectangle(dzen.dpy, dzen.slave_win.drawable[i], dzen.rgc, 0, 0, dzen.slave_win.width, dzen.line_height);
x_draw_body();
return;
}
if( write_buffer && (dzen.slave_win.tcnt < dzen.slave_win.tsize) ) {
dzen.slave_win.tbuf[dzen.slave_win.tcnt] = estrdup(text);
dzen.slave_win.tcnt++;
}
}