@ -63,9 +63,8 @@ utf8decode(const char *c, long *u, size_t clen)
Drw *
Drw *
drw_create ( Display * dpy , int screen , Window root , unsigned int w , unsigned int h )
drw_create ( Display * dpy , int screen , Window root , unsigned int w , unsigned int h )
{
{
Drw * drw ;
Drw * drw = ecalloc ( 1 , sizeof ( Drw ) ) ;
drw = ecalloc ( 1 , sizeof ( Drw ) ) ;
drw - > dpy = dpy ;
drw - > dpy = dpy ;
drw - > screen = screen ;
drw - > screen = screen ;
drw - > root = root ;
drw - > root = root ;
@ -73,7 +72,6 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
drw - > h = h ;
drw - > h = h ;
drw - > drawable = XCreatePixmap ( dpy , root , w , h , DefaultDepth ( dpy , screen ) ) ;
drw - > drawable = XCreatePixmap ( dpy , root , w , h , DefaultDepth ( dpy , screen ) ) ;
drw - > gc = XCreateGC ( dpy , root , 0 , NULL ) ;
drw - > gc = XCreateGC ( dpy , root , 0 , NULL ) ;
drw - > fontcount = 0 ;
XSetLineAttributes ( dpy , drw - > gc , 1 , LineSolid , CapButt , JoinMiter ) ;
XSetLineAttributes ( dpy , drw - > gc , 1 , LineSolid , CapButt , JoinMiter ) ;
return drw ;
return drw ;
@ -82,6 +80,9 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
void
void
drw_resize ( Drw * drw , unsigned int w , unsigned int h )
drw_resize ( Drw * drw , unsigned int w , unsigned int h )
{
{
if ( ! drw )
return ;
drw - > w = w ;
drw - > w = w ;
drw - > h = h ;
drw - > h = h ;
if ( drw - > drawable )
if ( drw - > drawable )
@ -92,44 +93,39 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
void
void
drw_free ( Drw * drw )
drw_free ( Drw * drw )
{
{
size_t i ;
for ( i = 0 ; i < drw - > fontcount ; i + + )
drw_font_free ( drw - > fonts [ i ] ) ;
XFreePixmap ( drw - > dpy , drw - > drawable ) ;
XFreePixmap ( drw - > dpy , drw - > drawable ) ;
XFreeGC ( drw - > dpy , drw - > gc ) ;
XFreeGC ( drw - > dpy , drw - > gc ) ;
free ( drw ) ;
free ( drw ) ;
}
}
/* This function is an implementation detail. Library users should use
/* This function is an implementation detail. Library users should use
* drw_font_create instead .
* drw_fontset _create instead .
*/
*/
static Fnt *
static Fnt *
drw_font_x create( Drw * drw , const char * fontname , FcPattern * fontpattern )
xfont_ create( Drw * drw , const char * fontname , FcPattern * fontpattern )
{
{
Fnt * font ;
Fnt * font ;
XftFont * xfont = NULL ;
XftFont * xfont = NULL ;
FcPattern * pattern = NULL ;
FcPattern * pattern = NULL ;
if ( fontname ) {
if ( fontname ) {
/* Using the pattern found at font->xfont->pattern does not yield sam e
/* Using the pattern found at font->xfont->pattern does not yield th e
* the same substitution results as using the pattern returned by
* same substitution results as using the pattern returned by
* FcNameParse ; using the latter results in the desired fallback
* FcNameParse ; using the latter results in the desired fallback
* behaviour whereas the former just results in
* behaviour whereas the former just results in missing - character
* missing - character - rectangles being drawn , at least with some fonts .
* rectangles being drawn , at least with some fonts . */
*/
if ( ! ( xfont = XftFontOpenName ( drw - > dpy , drw - > screen , fontname ) ) ) {
if ( ! ( xfont = XftFontOpenName ( drw - > dpy , drw - > screen , fontname ) ) ) {
fprintf ( stderr , " error, cannot load font: '%s' \n " , fontname ) ;
fprintf ( stderr , " error, cannot load font from name : '%s' \n " , fontname ) ;
return NULL ;
return NULL ;
}
}
if ( ! ( pattern = FcNameParse ( ( FcChar8 * ) fontname ) ) ) {
if ( ! ( pattern = FcNameParse ( ( FcChar8 * ) fontname ) ) ) {
fprintf ( stderr , " error, cannot load font : '%s' \n " , fontname ) ;
fprintf ( stderr , " error, cannot parse font name to pattern : '%s' \n " , fontname ) ;
XftFontClose ( drw - > dpy , xfont ) ;
XftFontClose ( drw - > dpy , xfont ) ;
return NULL ;
return NULL ;
}
}
} else if ( fontpattern ) {
} else if ( fontpattern ) {
if ( ! ( xfont = XftFontOpenPattern ( drw - > dpy , fontpattern ) ) ) {
if ( ! ( xfont = XftFontOpenPattern ( drw - > dpy , fontpattern ) ) ) {
fprintf ( stderr , " error, cannot load font pattern. \n " ) ;
fprintf ( stderr , " error, cannot load font from pattern. \n " ) ;
return NULL ;
return NULL ;
}
}
} else {
} else {
@ -139,95 +135,115 @@ drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern)
font = ecalloc ( 1 , sizeof ( Fnt ) ) ;
font = ecalloc ( 1 , sizeof ( Fnt ) ) ;
font - > xfont = xfont ;
font - > xfont = xfont ;
font - > pattern = pattern ;
font - > pattern = pattern ;
font - > ascent = xfont - > ascent ;
font - > h = xfont - > ascent + xfont - > descent ;
font - > descent = xfont - > descent ;
font - > h = font - > ascent + font - > descent ;
font - > dpy = drw - > dpy ;
font - > dpy = drw - > dpy ;
return font ;
return font ;
}
}
Fnt *
static void
drw_font_create ( Drw * drw , const char * fontname )
xfont_free ( Fnt * font )
{
{
return drw_font_xcreate ( drw , fontname , NULL ) ;
if ( ! font )
return ;
if ( font - > pattern )
FcPatternDestroy ( font - > pattern ) ;
XftFontClose ( font - > dpy , font - > xfont ) ;
free ( font ) ;
}
}
void
Fnt *
drw_load_fonts ( Drw * drw , const char * fonts [ ] , size_t fontcount )
drw_fontset_create ( Drw * drw , const char * fonts [ ] , size_t fontcount )
{
{
Fnt * cur , * ret = NULL ;
size_t i ;
size_t i ;
Fnt * font ;
for ( i = 0 ; i < fontcount ; i + + ) {
if ( ! drw | | ! fonts )
if ( drw - > fontcount > = DRW_FONT_CACHE_SIZE ) {
return NULL ;
die ( " Font cache exhausted. \n " ) ;
} else if ( ( font = drw_font_xcreate ( drw , fonts [ i ] , NULL ) ) ) {
for ( i = 1 ; i < = fontcount ; i + + ) {
drw - > fonts [ drw - > fontcount + + ] = font ;
if ( ( cur = xfont_create ( drw , fonts [ fontcount - i ] , NULL ) ) ) {
cur - > next = ret ;
ret = cur ;
}
}
}
}
return ( drw - > fonts = ret ) ;
}
}
void
void
drw_font_free ( Fnt * font )
drw_fontset _free ( Fnt * font )
{
{
if ( ! font )
if ( font ) {
return ;
drw_fontset_free ( font - > next ) ;
if ( font - > pattern )
xfont_free ( font ) ;
FcPatternDestroy ( font - > pattern ) ;
}
XftFontClose ( font - > dpy , font - > xfont ) ;
free ( font ) ;
}
}
Clr *
void
drw_clr_create ( Drw * drw , const char * clrname )
drw_clr_create ( Drw * drw , Clr * dest , const char * clrname )
{
{
Clr * clr ;
if ( ! drw | | ! dest | | ! clrname )
return ;
clr = ecalloc ( 1 , sizeof ( Clr ) ) ;
if ( ! XftColorAllocName ( drw - > dpy , DefaultVisual ( drw - > dpy , drw - > screen ) ,
if ( ! XftColorAllocName ( drw - > dpy , DefaultVisual ( drw - > dpy , drw - > screen ) ,
DefaultColormap ( drw - > dpy , drw - > screen ) ,
DefaultColormap ( drw - > dpy , drw - > screen ) ,
clrname , & clr - > rgb ) )
clrname , dest ) )
die ( " error, cannot allocate color '%s' \n " , clrname ) ;
die ( " error, cannot allocate color '%s' \n " , clrname ) ;
clr - > pix = clr - > rgb . pixel ;
}
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it . */
Clr *
drw_scm_create ( Drw * drw , const char * clrnames [ ] , size_t clrcount )
{
size_t i ;
Clr * ret ;
/* need at least two colors for a scheme */
if ( ! drw | | ! clrnames | | clrcount < 2 | | ! ( ret = ecalloc ( clrcount , sizeof ( XftColor ) ) ) )
return NULL ;
return clr ;
for ( i = 0 ; i < clrcount ; i + + )
drw_clr_create ( drw , & ret [ i ] , clrnames [ i ] ) ;
return ret ;
}
}
void
void
drw_clr_free ( Clr * clr )
drw_setfontset ( Drw * drw , Fnt * set )
{
{
free ( clr ) ;
if ( drw )
drw - > fonts = set ;
}
}
void
void
drw_setscheme ( Drw * drw , ClrScheme * scheme )
drw_setscheme ( Drw * drw , Clr * scm )
{
{
drw - > scheme = scheme ;
if ( drw )
drw - > scheme = scm ;
}
}
void
void
drw_rect ( Drw * drw , int x , int y , unsigned int w , unsigned int h , int filled , int empty , int invert )
drw_rect ( Drw * drw , int x , int y , unsigned int w , unsigned int h , int filled , int invert )
{
{
if ( ! drw - > scheme )
if ( ! drw | | ! drw - > scheme )
return ;
return ;
XSetForeground ( drw - > dpy , drw - > gc , invert ? drw - > scheme - > bg - > pix : drw - > scheme - > fg - > pix ) ;
XSetForeground ( drw - > dpy , drw - > gc , invert ? drw - > scheme [ ColBg ] . pixel : drw - > scheme [ ColFg ] . pixel ) ;
if ( filled )
if ( filled )
XFillRectangle ( drw - > dpy , drw - > drawable , drw - > gc , x , y , w + 1 , h + 1 ) ;
XFillRectangle ( drw - > dpy , drw - > drawable , drw - > gc , x , y , w , h ) ;
else if ( empty )
else
XDrawRectangle ( drw - > dpy , drw - > drawable , drw - > gc , x , y , w , h ) ;
XDrawRectangle ( drw - > dpy , drw - > drawable , drw - > gc , x , y , w - 1 , h - 1 ) ;
}
}
int
int
drw_text ( Drw * drw , int x , int y , unsigned int w , unsigned int h , const char * text , int invert )
drw_text ( Drw * drw , int x , int y , unsigned int w , unsigned int h , unsigned int lpad , const char * text , int invert )
{
{
char buf [ 1024 ] ;
char buf [ 1024 ] ;
int tx , t y , th ;
int ty ;
Extnts tex ;
unsigned int ew ;
XftDraw * d = NULL ;
XftDraw * d = NULL ;
Fnt * curfont , * nextfont ;
Fnt * usedfont , * curfont , * nextfont ;
size_t i , len ;
size_t i , len ;
int utf8strlen , utf8charlen , render ;
int utf8strlen , utf8charlen , render = x | | y | | w | | h ;
long utf8codepoint = 0 ;
long utf8codepoint = 0 ;
const char * utf8str ;
const char * utf8str ;
FcCharSet * fccharset ;
FcCharSet * fccharset ;
@ -236,66 +252,67 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
XftResult result ;
XftResult result ;
int charexists = 0 ;
int charexists = 0 ;
if ( ! drw - > scheme | | ! drw - > fontcount )
if ( ! drw | | ( render & & ! drw - > scheme ) | | ! text | | ! drw - > fonts )
return 0 ;
return 0 ;
if ( ! ( render = x | | y | | w | | h ) ) {
if ( ! render ) {
w = ~ w ;
w = ~ w ;
} else {
} else {
XSetForeground ( drw - > dpy , drw - > gc , invert ?
XSetForeground ( drw - > dpy , drw - > gc , drw - > scheme [ invert ? ColFg : ColBg ] . pixel ) ;
drw - > scheme - > fg - > pix : drw - > scheme - > bg - > pix ) ;
XFillRectangle ( drw - > dpy , drw - > drawable , drw - > gc , x , y , w , h ) ;
XFillRectangle ( drw - > dpy , drw - > drawable , drw - > gc , x , y , w , h ) ;
d = XftDrawCreate ( drw - > dpy , drw - > drawable ,
d = XftDrawCreate ( drw - > dpy , drw - > drawable ,
DefaultVisual ( drw - > dpy , drw - > screen ) ,
DefaultVisual ( drw - > dpy , drw - > screen ) ,
DefaultColormap ( drw - > dpy , drw - > screen ) ) ;
DefaultColormap ( drw - > dpy , drw - > screen ) ) ;
x + = lpad ;
w - = lpad ;
}
}
cur font = drw - > fonts [ 0 ] ;
used font = drw - > fonts ;
while ( 1 ) {
while ( 1 ) {
utf8strlen = 0 ;
utf8strlen = 0 ;
utf8str = text ;
utf8str = text ;
nextfont = NULL ;
nextfont = NULL ;
while ( * text ) {
while ( * text ) {
utf8charlen = utf8decode ( text , & utf8codepoint , UTF_SIZ ) ;
utf8charlen = utf8decode ( text , & utf8codepoint , UTF_SIZ ) ;
for ( i = 0 ; i < drw - > fontcount ; i + + ) {
for ( curfont = drw - > fonts ; curfont ; curfont = curfont - > next ) {
charexists = charexists | | XftCharExists ( drw - > dpy , drw - > fonts [ i ] - > xfont , utf8codepoint ) ;
charexists = charexists | | XftCharExists ( drw - > dpy , curfont - > xfont , utf8codepoint ) ;
if ( charexists ) {
if ( charexists ) {
if ( drw - > fonts [ i ] = = cur font) {
if ( curfont = = used font) {
utf8strlen + = utf8charlen ;
utf8strlen + = utf8charlen ;
text + = utf8charlen ;
text + = utf8charlen ;
} else {
} else {
nextfont = drw - > fonts [ i ] ;
nextfont = curfont ;
}
}
break ;
break ;
}
}
}
}
if ( ! charexists | | ( nextfont & & nextfont ! = curfont ) )
if ( ! charexists | | nextfont )
break ;
break ;
else
else
charexists = 0 ;
charexists = 0 ;
}
}
if ( utf8strlen ) {
if ( utf8strlen ) {
drw_font_getexts ( cur font, utf8str , utf8strlen , & tex ) ;
drw_font_getexts ( used font, utf8str , utf8strlen , & ew , NULL ) ;
/* shorten text if necessary */
/* shorten text if necessary */
for ( len = MIN ( utf8strlen , ( sizeof buf ) - 1 ) ; len & & ( t ex . w > w - drw - > fonts [ 0 ] - > h | | w < drw - > fonts [ 0 ] - > h ) ; len - - )
for ( len = MIN ( utf8strlen , sizeof ( buf ) - 1 ) ; len & & ew > w ; len - - )
drw_font_getexts ( cur font, utf8str , len , & tex ) ;
drw_font_getexts ( used font, utf8str , len , & ew , NULL ) ;
if ( len ) {
if ( len ) {
memcpy ( buf , utf8str , len ) ;
memcpy ( buf , utf8str , len ) ;
buf [ len ] = ' \0 ' ;
buf [ len ] = ' \0 ' ;
if ( len < utf8strlen )
if ( len < utf8strlen )
for ( i = len ; i & & i > len - 3 ; buf [ - - i ] = ' . ' ) ;
for ( i = len ; i & & i > len - 3 ; buf [ - - i ] = ' . ' )
; /* NOP */
if ( render ) {
if ( render ) {
th = curfont - > ascent + curfont - > descent ;
ty = y + ( h - usedfont - > h ) / 2 + usedfont - > xfont - > ascent ;
ty = y + ( h / 2 ) - ( th / 2 ) + curfont - > ascent ;
XftDrawStringUtf8 ( d , & drw - > scheme [ invert ? ColBg : ColFg ] ,
tx = x + ( h / 2 ) ;
usedfont - > xfont , x , ty , ( XftChar8 * ) buf , len ) ;
XftDrawStringUtf8 ( d , invert ? & drw - > scheme - > bg - > rgb : & drw - > scheme - > fg - > rgb , curfont - > xfont , tx , ty , ( XftChar8 * ) buf , len ) ;
}
}
x + = t ex . w ;
x + = ew ;
w - = t ex . w ;
w - = ew ;
}
}
}
}
@ -303,26 +320,21 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
break ;
break ;
} else if ( nextfont ) {
} else if ( nextfont ) {
charexists = 0 ;
charexists = 0 ;
cur font = nextfont ;
used font = nextfont ;
} else {
} else {
/* Regardless of whether or not a fallback font is found, the
/* Regardless of whether or not a fallback font is found, the
* character must be drawn .
* character must be drawn . */
*/
charexists = 1 ;
charexists = 1 ;
if ( drw - > fontcount > = DRW_FONT_CACHE_SIZE )
continue ;
fccharset = FcCharSetCreate ( ) ;
fccharset = FcCharSetCreate ( ) ;
FcCharSetAddChar ( fccharset , utf8codepoint ) ;
FcCharSetAddChar ( fccharset , utf8codepoint ) ;
if ( ! drw - > fonts [ 0 ] - > pattern ) {
if ( ! drw - > fonts - > pattern ) {
/* Refer to the comment in drw_font_xcreate for more
/* Refer to the comment in xfont_create for more information. */
* information . */
die ( " the first font in the cache must be loaded from a font string. \n " ) ;
die ( " the first font in the cache must be loaded from a font string. \n " ) ;
}
}
fcpattern = FcPatternDuplicate ( drw - > fonts [ 0 ] - > pattern ) ;
fcpattern = FcPatternDuplicate ( drw - > fonts - > pattern ) ;
FcPatternAddCharSet ( fcpattern , FC_CHARSET , fccharset ) ;
FcPatternAddCharSet ( fcpattern , FC_CHARSET , fccharset ) ;
FcPatternAddBool ( fcpattern , FC_SCALABLE , FcTrue ) ;
FcPatternAddBool ( fcpattern , FC_SCALABLE , FcTrue ) ;
@ -334,12 +346,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
FcPatternDestroy ( fcpattern ) ;
FcPatternDestroy ( fcpattern ) ;
if ( match ) {
if ( match ) {
curfont = drw_font_xcreate ( drw , NULL , match ) ;
usedfont = xfont_create ( drw , NULL , match ) ;
if ( curfont & & XftCharExists ( drw - > dpy , curfont - > xfont , utf8codepoint ) ) {
if ( usedfont & & XftCharExists ( drw - > dpy , usedfont - > xfont , utf8codepoint ) ) {
drw - > fonts [ drw - > fontcount + + ] = curfont ;
for ( curfont = drw - > fonts ; curfont - > next ; curfont = curfont - > next )
; /* NOP */
curfont - > next = usedfont ;
} else {
} else {
drw_font_free ( curfont ) ;
xfont_free ( used font) ;
cur font = drw - > fonts [ 0 ] ;
used font = drw - > fonts ;
}
}
}
}
}
}
@ -347,34 +361,40 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
if ( d )
if ( d )
XftDrawDestroy ( d ) ;
XftDrawDestroy ( d ) ;
return x ;
return x + ( render ? w : 0 ) ;
}
}
void
void
drw_map ( Drw * drw , Window win , int x , int y , unsigned int w , unsigned int h )
drw_map ( Drw * drw , Window win , int x , int y , unsigned int w , unsigned int h )
{
{
if ( ! drw )
return ;
XCopyArea ( drw - > dpy , drw - > drawable , win , drw - > gc , x , y , w , h , x , y ) ;
XCopyArea ( drw - > dpy , drw - > drawable , win , drw - > gc , x , y , w , h , x , y ) ;
XSync ( drw - > dpy , False ) ;
XSync ( drw - > dpy , False ) ;
}
}
void
unsigned int
drw_font_getexts ( Fnt * font , const char * text , unsigned int len , Extnts * tex )
drw_fontset_getwidth ( Drw * drw , const char * text )
{
{
XGlyphInfo ext ;
if ( ! drw | | ! drw - > fonts | | ! text )
return 0 ;
XftTextExtentsUtf8 ( font - > dpy , font - > xfont , ( XftChar8 * ) text , len , & ext ) ;
return drw_text ( drw , 0 , 0 , 0 , 0 , 0 , text , 0 ) ;
tex - > h = font - > h ;
tex - > w = ext . xOff ;
}
}
unsigned int
void
drw_font_getexts_width ( Fnt * font , const char * text , unsigned int len )
drw_font_getexts ( Fnt * font , const char * text , unsigned int len , unsigned int * w , unsigned int * h )
{
{
Extnts tex ;
XGlyphInfo ext ;
drw_font_getexts ( font , text , len , & tex ) ;
if ( ! font | | ! text )
return ;
return tex . w ;
XftTextExtentsUtf8 ( font - > dpy , font - > xfont , ( XftChar8 * ) text , len , & ext ) ;
if ( w )
* w = ext . xOff ;
if ( h )
* h = font - > h ;
}
}
Cur *
Cur *
@ -382,7 +402,9 @@ drw_cur_create(Drw *drw, int shape)
{
{
Cur * cur ;
Cur * cur ;
cur = ecalloc ( 1 , sizeof ( Cur ) ) ;
if ( ! drw | | ! ( cur = ecalloc ( 1 , sizeof ( Cur ) ) ) )
return NULL ;
cur - > cursor = XCreateFontCursor ( drw - > dpy , shape ) ;
cur - > cursor = XCreateFontCursor ( drw - > dpy , shape ) ;
return cur ;
return cur ;
@ -393,6 +415,7 @@ drw_cur_free(Drw *drw, Cur *cursor)
{
{
if ( ! cursor )
if ( ! cursor )
return ;
return ;
XFreeCursor ( drw - > dpy , cursor - > cursor ) ;
XFreeCursor ( drw - > dpy , cursor - > cursor ) ;
free ( cursor ) ;
free ( cursor ) ;
}
}