2013-04-17 20:21:47 +01:00
/* See LICENSE file for copyright and license details. */
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <X11/Xlib.h>
2015-03-06 04:26:11 +00:00
# include <X11/Xft/Xft.h>
2013-04-17 20:21:47 +01:00
# include "drw.h"
# include "util.h"
2015-03-06 04:26:11 +00:00
# define UTF_INVALID 0xFFFD
2015-10-20 22:34:49 +01:00
# define UTF_SIZ 4
2015-03-06 04:26:11 +00:00
static const unsigned char utfbyte [ UTF_SIZ + 1 ] = { 0x80 , 0 , 0xC0 , 0xE0 , 0xF0 } ;
static const unsigned char utfmask [ UTF_SIZ + 1 ] = { 0xC0 , 0x80 , 0xE0 , 0xF0 , 0xF8 } ;
static const long utfmin [ UTF_SIZ + 1 ] = { 0 , 0 , 0x80 , 0x800 , 0x10000 } ;
static const long utfmax [ UTF_SIZ + 1 ] = { 0x10FFFF , 0x7F , 0x7FF , 0xFFFF , 0x10FFFF } ;
static long
2015-10-20 22:34:49 +01:00
utf8decodebyte ( const char c , size_t * i )
{
for ( * i = 0 ; * i < ( UTF_SIZ + 1 ) ; + + ( * i ) )
if ( ( ( unsigned char ) c & utfmask [ * i ] ) = = utfbyte [ * i ] )
2015-03-06 04:26:11 +00:00
return ( unsigned char ) c & ~ utfmask [ * i ] ;
return 0 ;
}
static size_t
2015-10-20 22:34:49 +01:00
utf8validate ( long * u , size_t i )
{
if ( ! BETWEEN ( * u , utfmin [ i ] , utfmax [ i ] ) | | BETWEEN ( * u , 0xD800 , 0xDFFF ) )
2015-03-06 04:26:11 +00:00
* u = UTF_INVALID ;
2015-10-20 22:34:49 +01:00
for ( i = 1 ; * u > utfmax [ i ] ; + + i )
2015-03-06 04:26:11 +00:00
;
return i ;
}
static size_t
2015-10-20 22:34:49 +01:00
utf8decode ( const char * c , long * u , size_t clen )
{
2015-03-06 04:26:11 +00:00
size_t i , j , len , type ;
long udecoded ;
* u = UTF_INVALID ;
2015-10-20 22:34:49 +01:00
if ( ! clen )
2015-03-06 04:26:11 +00:00
return 0 ;
udecoded = utf8decodebyte ( c [ 0 ] , & len ) ;
2015-10-20 22:34:49 +01:00
if ( ! BETWEEN ( len , 1 , UTF_SIZ ) )
2015-03-06 04:26:11 +00:00
return 1 ;
2015-10-20 22:34:49 +01:00
for ( i = 1 , j = 1 ; i < clen & & j < len ; + + i , + + j ) {
2015-03-06 04:26:11 +00:00
udecoded = ( udecoded < < 6 ) | utf8decodebyte ( c [ i ] , & type ) ;
2015-10-20 22:34:49 +01:00
if ( type )
2015-03-06 04:26:11 +00:00
return j ;
}
2015-10-20 22:34:49 +01:00
if ( j < len )
2015-03-06 04:26:11 +00:00
return 0 ;
* u = udecoded ;
utf8validate ( u , len ) ;
2015-10-20 22:34:49 +01:00
2015-03-06 04:26:11 +00:00
return len ;
}
2013-04-17 20:21:47 +01:00
Drw *
2015-10-20 22:34:49 +01:00
drw_create ( Display * dpy , int screen , Window root , unsigned int w , unsigned int h )
{
2016-05-22 21:33:56 +01:00
Drw * drw = ecalloc ( 1 , sizeof ( Drw ) ) ;
2015-10-20 22:34:49 +01:00
2013-04-17 20:21:47 +01:00
drw - > dpy = dpy ;
drw - > screen = screen ;
2013-06-16 14:20:29 +01:00
drw - > root = root ;
2013-04-17 20:21:47 +01:00
drw - > w = w ;
drw - > h = h ;
2013-06-16 14:20:29 +01:00
drw - > drawable = XCreatePixmap ( dpy , root , w , h , DefaultDepth ( dpy , screen ) ) ;
drw - > gc = XCreateGC ( dpy , root , 0 , NULL ) ;
2013-04-17 20:21:47 +01:00
XSetLineAttributes ( dpy , drw - > gc , 1 , LineSolid , CapButt , JoinMiter ) ;
2015-10-20 22:34:49 +01:00
2013-04-17 20:21:47 +01:00
return drw ;
}
void
2015-10-20 22:34:49 +01:00
drw_resize ( Drw * drw , unsigned int w , unsigned int h )
{
2016-05-22 21:33:56 +01:00
if ( ! drw )
return ;
2013-04-17 20:21:47 +01:00
drw - > w = w ;
drw - > h = h ;
2015-10-20 22:34:49 +01:00
if ( drw - > drawable )
2013-06-16 14:20:29 +01:00
XFreePixmap ( drw - > dpy , drw - > drawable ) ;
drw - > drawable = XCreatePixmap ( drw - > dpy , drw - > root , w , h , DefaultDepth ( drw - > dpy , drw - > screen ) ) ;
2013-04-17 20:21:47 +01:00
}
void
2015-10-20 22:34:49 +01:00
drw_free ( Drw * drw )
{
2013-06-16 14:20:29 +01:00
XFreePixmap ( drw - > dpy , drw - > drawable ) ;
2013-04-17 20:21:47 +01:00
XFreeGC ( drw - > dpy , drw - > gc ) ;
2020-06-11 14:28:32 +01:00
drw_fontset_free ( drw - > fonts ) ;
2013-04-17 20:21:47 +01:00
free ( drw ) ;
}
2015-03-06 04:26:11 +00:00
/* This function is an implementation detail. Library users should use
2016-05-22 21:33:56 +01:00
* drw_fontset_create instead .
2015-03-06 04:26:11 +00:00
*/
static Fnt *
2016-05-22 21:33:56 +01:00
xfont_create ( Drw * drw , const char * fontname , FcPattern * fontpattern )
2015-10-20 22:34:49 +01:00
{
2013-04-17 20:21:47 +01:00
Fnt * font ;
2015-10-20 22:34:49 +01:00
XftFont * xfont = NULL ;
FcPattern * pattern = NULL ;
2015-03-06 04:26:11 +00:00
if ( fontname ) {
2016-05-22 21:33:56 +01:00
/* Using the pattern found at font->xfont->pattern does not yield the
* same substitution results as using the pattern returned by
2015-03-06 04:26:11 +00:00
* FcNameParse ; using the latter results in the desired fallback
2016-05-22 21:33:56 +01:00
* behaviour whereas the former just results in missing - character
* rectangles being drawn , at least with some fonts . */
2015-10-20 22:34:49 +01:00
if ( ! ( xfont = XftFontOpenName ( drw - > dpy , drw - > screen , fontname ) ) ) {
2016-05-22 21:33:56 +01:00
fprintf ( stderr , " error, cannot load font from name: '%s' \n " , fontname ) ;
2015-10-20 22:34:49 +01:00
return NULL ;
}
if ( ! ( pattern = FcNameParse ( ( FcChar8 * ) fontname ) ) ) {
2016-05-22 21:33:56 +01:00
fprintf ( stderr , " error, cannot parse font name to pattern: '%s' \n " , fontname ) ;
2015-10-20 22:34:49 +01:00
XftFontClose ( drw - > dpy , xfont ) ;
return NULL ;
2015-03-06 04:26:11 +00:00
}
} else if ( fontpattern ) {
2015-10-20 22:34:49 +01:00
if ( ! ( xfont = XftFontOpenPattern ( drw - > dpy , fontpattern ) ) ) {
2016-05-22 21:33:56 +01:00
fprintf ( stderr , " error, cannot load font from pattern. \n " ) ;
2015-10-20 22:34:49 +01:00
return NULL ;
2013-04-17 20:21:47 +01:00
}
2015-10-20 22:34:49 +01:00
} else {
2016-08-12 13:35:25 +01:00
die ( " no font specified. " ) ;
2013-04-17 20:21:47 +01:00
}
2015-03-06 04:26:11 +00:00
2015-10-20 22:34:49 +01:00
font = ecalloc ( 1 , sizeof ( Fnt ) ) ;
font - > xfont = xfont ;
font - > pattern = pattern ;
2016-05-22 21:33:56 +01:00
font - > h = xfont - > ascent + xfont - > descent ;
2015-03-06 04:26:11 +00:00
font - > dpy = drw - > dpy ;
2015-10-20 22:34:49 +01:00
2013-04-17 20:21:47 +01:00
return font ;
}
2016-05-22 21:33:56 +01:00
static void
xfont_free ( Fnt * font )
2015-10-20 22:34:49 +01:00
{
2016-05-22 21:33:56 +01:00
if ( ! font )
return ;
if ( font - > pattern )
FcPatternDestroy ( font - > pattern ) ;
XftFontClose ( font - > dpy , font - > xfont ) ;
free ( font ) ;
2015-03-06 04:26:11 +00:00
}
2016-05-22 21:33:56 +01:00
Fnt *
drw_fontset_create ( Drw * drw , const char * fonts [ ] , size_t fontcount )
2015-10-20 22:34:49 +01:00
{
2016-05-22 21:33:56 +01:00
Fnt * cur , * ret = NULL ;
2015-03-06 04:26:11 +00:00
size_t i ;
2015-10-20 22:34:49 +01:00
2016-05-22 21:33:56 +01:00
if ( ! drw | | ! fonts )
return NULL ;
for ( i = 1 ; i < = fontcount ; i + + ) {
if ( ( cur = xfont_create ( drw , fonts [ fontcount - i ] , NULL ) ) ) {
cur - > next = ret ;
ret = cur ;
2015-03-06 04:26:11 +00:00
}
}
2016-05-22 21:33:56 +01:00
return ( drw - > fonts = ret ) ;
2015-03-06 04:26:11 +00:00
}
2013-04-17 20:21:47 +01:00
void
2016-05-22 21:33:56 +01:00
drw_fontset_free ( Fnt * font )
2015-10-20 22:34:49 +01:00
{
2016-05-22 21:33:56 +01:00
if ( font ) {
drw_fontset_free ( font - > next ) ;
xfont_free ( font ) ;
}
2013-04-17 20:21:47 +01:00
}
2016-05-22 21:33:56 +01:00
void
2017-11-03 20:20:48 +00:00
drw_clr_create ( Drw * drw , Clr * dest , const char * clrname )
2015-10-20 22:34:49 +01:00
{
2016-05-22 21:33:56 +01:00
if ( ! drw | | ! dest | | ! clrname )
return ;
2015-10-20 22:34:49 +01:00
if ( ! XftColorAllocName ( drw - > dpy , DefaultVisual ( drw - > dpy , drw - > screen ) ,
DefaultColormap ( drw - > dpy , drw - > screen ) ,
2016-05-22 21:33:56 +01:00
clrname , dest ) )
2016-08-12 13:35:25 +01:00
die ( " error, cannot allocate color '%s' " , clrname ) ;
2016-05-22 21:33:56 +01:00
}
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it . */
2017-11-03 20:20:48 +00:00
Clr *
2016-05-22 21:33:56 +01:00
drw_scm_create ( Drw * drw , const char * clrnames [ ] , size_t clrcount )
{
size_t i ;
2017-11-03 20:20:48 +00:00
Clr * ret ;
2016-05-22 21:33:56 +01:00
/* need at least two colors for a scheme */
2019-02-02 12:50:42 +00:00
if ( ! drw | | ! clrnames | | clrcount < 2 | | ! ( ret = ecalloc ( clrcount , sizeof ( XftColor ) ) ) )
2016-05-22 21:33:56 +01:00
return NULL ;
2015-10-20 22:34:49 +01:00
2016-05-22 21:33:56 +01:00
for ( i = 0 ; i < clrcount ; i + + )
drw_clr_create ( drw , & ret [ i ] , clrnames [ i ] ) ;
return ret ;
2013-04-17 20:21:47 +01:00
}
void
2016-05-22 21:33:56 +01:00
drw_setfontset ( Drw * drw , Fnt * set )
2015-10-20 22:34:49 +01:00
{
2016-05-22 21:33:56 +01:00
if ( drw )
drw - > fonts = set ;
2013-04-17 20:21:47 +01:00
}
void
2017-11-03 20:20:48 +00:00
drw_setscheme ( Drw * drw , Clr * scm )
2015-10-20 22:34:49 +01:00
{
2016-05-22 21:33:56 +01:00
if ( drw )
drw - > scheme = scm ;
2013-04-17 20:21:47 +01:00
}
void
2016-05-22 21:33:56 +01:00
drw_rect ( Drw * drw , int x , int y , unsigned int w , unsigned int h , int filled , int invert )
2015-10-20 22:34:49 +01:00
{
2016-05-22 21:33:56 +01:00
if ( ! drw | | ! drw - > scheme )
2013-04-17 20:21:47 +01:00
return ;
2016-05-22 21:33:56 +01:00
XSetForeground ( drw - > dpy , drw - > gc , invert ? drw - > scheme [ ColBg ] . pixel : drw - > scheme [ ColFg ] . pixel ) ;
2015-10-20 22:34:49 +01:00
if ( filled )
2016-05-22 21:33:56 +01:00
XFillRectangle ( drw - > dpy , drw - > drawable , drw - > gc , x , y , w , h ) ;
else
XDrawRectangle ( drw - > dpy , drw - > drawable , drw - > gc , x , y , w - 1 , h - 1 ) ;
2013-04-17 20:21:47 +01:00
}
2023-02-18 18:21:40 +00:00
void
drw_polygon ( Drw * drw , int x , int y , int ow , int oh , int sw , int sh , const XPoint * points , int npoints , int shape , int filled ) /* wrapper function to scale and draw a polygon with X11 */
{
if ( ! drw | | ! drw - > scheme )
return ;
XSetForeground ( drw - > dpy , drw - > gc , drw - > scheme [ ColFg ] . pixel ) ;
if ( ! filled ) { /* reduces the scaled width and height by 1 when drawing the outline to compensate for X11 drawing the line 1 pixel over */
sw - = 1 ;
sh - = 1 ;
}
XPoint scaledpoints [ npoints ] ;
memcpy ( scaledpoints , points , npoints ) ;
for ( int v = 0 ; v < npoints ; v + + )
scaledpoints [ v ] = ( XPoint ) { . x = points [ v ] . x * sw / ow + x , . y = points [ v ] . y * sh / oh + y } ;
if ( filled )
XFillPolygon ( drw - > dpy , drw - > drawable , drw - > gc , scaledpoints , npoints , shape , CoordModeOrigin ) ; /* Change shape to 'Convex' or 'Complex' in dwm.c if the shape is not 'Nonconvex' */
else
XDrawLines ( drw - > dpy , drw - > drawable , drw - > gc , scaledpoints , npoints , CoordModeOrigin ) ;
}
2015-03-06 04:26:11 +00:00
int
2016-05-22 21:33:56 +01:00
drw_text ( Drw * drw , int x , int y , unsigned int w , unsigned int h , unsigned int lpad , const char * text , int invert )
2015-10-20 22:34:49 +01:00
{
2022-05-10 18:07:56 +01:00
int i , ty , ellipsis_x = 0 ;
unsigned int tmpw , ew , ellipsis_w = 0 , ellipsis_len ;
2015-10-20 22:34:49 +01:00
XftDraw * d = NULL ;
2016-05-22 21:33:56 +01:00
Fnt * usedfont , * curfont , * nextfont ;
int utf8strlen , utf8charlen , render = x | | y | | w | | h ;
2015-03-06 04:26:11 +00:00
long utf8codepoint = 0 ;
const char * utf8str ;
FcCharSet * fccharset ;
FcPattern * fcpattern ;
FcPattern * match ;
XftResult result ;
2022-05-10 18:07:56 +01:00
int charexists = 0 , overflow = 0 ;
/* keep track of a couple codepoints for which we have no match. */
enum { nomatches_len = 64 } ;
static struct { long codepoint [ nomatches_len ] ; unsigned int idx ; } nomatches ;
static unsigned int ellipsis_width = 0 ;
2013-04-17 20:21:47 +01:00
2022-05-10 18:07:56 +01:00
if ( ! drw | | ( render & & ( ! drw - > scheme | | ! w ) ) | | ! text | | ! drw - > fonts )
2015-10-20 22:34:49 +01:00
return 0 ;
2016-05-22 21:33:56 +01:00
if ( ! render ) {
2022-05-10 18:07:56 +01:00
w = invert ? invert : ~ invert ;
2015-10-20 22:34:49 +01:00
} else {
2016-05-22 21:33:56 +01:00
XSetForeground ( drw - > dpy , drw - > gc , drw - > scheme [ invert ? ColFg : ColBg ] . pixel ) ;
2015-03-06 04:26:11 +00:00
XFillRectangle ( drw - > dpy , drw - > drawable , drw - > gc , x , y , w , h ) ;
2015-10-20 22:34:49 +01:00
d = XftDrawCreate ( drw - > dpy , drw - > drawable ,
DefaultVisual ( drw - > dpy , drw - > screen ) ,
DefaultColormap ( drw - > dpy , drw - > screen ) ) ;
2016-05-22 21:33:56 +01:00
x + = lpad ;
w - = lpad ;
2015-03-06 04:26:11 +00:00
}
2016-05-22 21:33:56 +01:00
usedfont = drw - > fonts ;
2022-05-10 18:07:56 +01:00
if ( ! ellipsis_width & & render )
ellipsis_width = drw_fontset_getwidth ( drw , " ... " ) ;
2015-03-06 04:26:11 +00:00
while ( 1 ) {
2022-05-10 18:07:56 +01:00
ew = ellipsis_len = utf8strlen = 0 ;
2015-03-06 04:26:11 +00:00
utf8str = text ;
nextfont = NULL ;
while ( * text ) {
utf8charlen = utf8decode ( text , & utf8codepoint , UTF_SIZ ) ;
2016-05-22 21:33:56 +01:00
for ( curfont = drw - > fonts ; curfont ; curfont = curfont - > next ) {
charexists = charexists | | XftCharExists ( drw - > dpy , curfont - > xfont , utf8codepoint ) ;
2015-03-06 04:26:11 +00:00
if ( charexists ) {
2022-05-10 18:07:56 +01:00
drw_font_getexts ( curfont , text , utf8charlen , & tmpw , NULL ) ;
if ( ew + ellipsis_width < = w ) {
/* keep track where the ellipsis still fits */
ellipsis_x = x + ew ;
ellipsis_w = w - ew ;
ellipsis_len = utf8strlen ;
}
if ( ew + tmpw > w ) {
overflow = 1 ;
/* called from drw_fontset_getwidth_clamp():
* it wants the width AFTER the overflow
*/
if ( ! render )
x + = tmpw ;
else
utf8strlen = ellipsis_len ;
} else if ( curfont = = usedfont ) {
2015-03-06 04:26:11 +00:00
utf8strlen + = utf8charlen ;
text + = utf8charlen ;
2022-05-10 18:07:56 +01:00
ew + = tmpw ;
2015-03-06 04:26:11 +00:00
} else {
2016-05-22 21:33:56 +01:00
nextfont = curfont ;
2015-03-06 04:26:11 +00:00
}
break ;
}
}
2022-05-10 18:07:56 +01:00
if ( overflow | | ! charexists | | nextfont )
2015-03-06 04:26:11 +00:00
break ;
2015-10-20 22:34:49 +01:00
else
2015-03-06 04:26:11 +00:00
charexists = 0 ;
}
if ( utf8strlen ) {
2022-05-10 18:07:56 +01:00
if ( render ) {
ty = y + ( h - usedfont - > h ) / 2 + usedfont - > xfont - > ascent ;
XftDrawStringUtf8 ( d , & drw - > scheme [ invert ? ColBg : ColFg ] ,
usedfont - > xfont , x , ty , ( XftChar8 * ) utf8str , utf8strlen ) ;
2015-03-06 04:26:11 +00:00
}
2022-05-10 18:07:56 +01:00
x + = ew ;
w - = ew ;
2015-03-06 04:26:11 +00:00
}
2022-05-10 18:07:56 +01:00
if ( render & & overflow )
drw_text ( drw , ellipsis_x , y , ellipsis_w , h , 0 , " ... " , invert ) ;
2015-03-06 04:26:11 +00:00
2022-05-10 18:07:56 +01:00
if ( ! * text | | overflow ) {
2015-03-06 04:26:11 +00:00
break ;
} else if ( nextfont ) {
charexists = 0 ;
2016-05-22 21:33:56 +01:00
usedfont = nextfont ;
2015-03-06 04:26:11 +00:00
} else {
/* Regardless of whether or not a fallback font is found, the
2016-05-22 21:33:56 +01:00
* character must be drawn . */
2015-03-06 04:26:11 +00:00
charexists = 1 ;
2022-05-10 18:07:56 +01:00
for ( i = 0 ; i < nomatches_len ; + + i ) {
/* avoid calling XftFontMatch if we know we won't find a match */
if ( utf8codepoint = = nomatches . codepoint [ i ] )
goto no_match ;
}
2015-03-06 04:26:11 +00:00
fccharset = FcCharSetCreate ( ) ;
FcCharSetAddChar ( fccharset , utf8codepoint ) ;
2016-05-22 21:33:56 +01:00
if ( ! drw - > fonts - > pattern ) {
/* Refer to the comment in xfont_create for more information. */
2016-08-12 13:35:25 +01:00
die ( " the first font in the cache must be loaded from a font string. " ) ;
2015-03-06 04:26:11 +00:00
}
2016-05-22 21:33:56 +01:00
fcpattern = FcPatternDuplicate ( drw - > fonts - > pattern ) ;
2015-03-06 04:26:11 +00:00
FcPatternAddCharSet ( fcpattern , FC_CHARSET , fccharset ) ;
FcPatternAddBool ( fcpattern , FC_SCALABLE , FcTrue ) ;
FcConfigSubstitute ( NULL , fcpattern , FcMatchPattern ) ;
FcDefaultSubstitute ( fcpattern ) ;
match = XftFontMatch ( drw - > dpy , drw - > screen , fcpattern , & result ) ;
FcCharSetDestroy ( fccharset ) ;
FcPatternDestroy ( fcpattern ) ;
if ( match ) {
2016-05-22 21:33:56 +01:00
usedfont = xfont_create ( drw , NULL , match ) ;
if ( usedfont & & XftCharExists ( drw - > dpy , usedfont - > xfont , utf8codepoint ) ) {
for ( curfont = drw - > fonts ; curfont - > next ; curfont = curfont - > next )
; /* NOP */
curfont - > next = usedfont ;
2015-03-06 04:26:11 +00:00
} else {
2016-05-22 21:33:56 +01:00
xfont_free ( usedfont ) ;
2022-05-10 18:07:56 +01:00
nomatches . codepoint [ + + nomatches . idx % nomatches_len ] = utf8codepoint ;
no_match :
2016-05-22 21:33:56 +01:00
usedfont = drw - > fonts ;
2015-03-06 04:26:11 +00:00
}
}
}
}
2015-10-20 22:34:49 +01:00
if ( d )
2015-03-06 04:26:11 +00:00
XftDrawDestroy ( d ) ;
2016-05-22 21:33:56 +01:00
return x + ( render ? w : 0 ) ;
2013-04-17 20:21:47 +01:00
}
void
2015-10-20 22:34:49 +01:00
drw_map ( Drw * drw , Window win , int x , int y , unsigned int w , unsigned int h )
{
2016-05-22 21:33:56 +01:00
if ( ! drw )
return ;
2013-06-16 14:20:29 +01:00
XCopyArea ( drw - > dpy , drw - > drawable , win , drw - > gc , x , y , w , h , x , y ) ;
2013-04-17 20:21:47 +01:00
XSync ( drw - > dpy , False ) ;
}
2016-05-22 21:33:56 +01:00
unsigned int
drw_fontset_getwidth ( Drw * drw , const char * text )
2015-10-20 22:34:49 +01:00
{
2016-05-22 21:33:56 +01:00
if ( ! drw | | ! drw - > fonts | | ! text )
return 0 ;
return drw_text ( drw , 0 , 0 , 0 , 0 , 0 , text , 0 ) ;
2013-04-17 20:21:47 +01:00
}
2013-06-16 14:20:29 +01:00
2022-05-10 18:07:56 +01:00
unsigned int
drw_fontset_getwidth_clamp ( Drw * drw , const char * text , unsigned int n )
{
unsigned int tmp = 0 ;
if ( drw & & drw - > fonts & & text & & n )
tmp = drw_text ( drw , 0 , 0 , 0 , 0 , 0 , text , n ) ;
return MIN ( n , tmp ) ;
}
2016-05-22 21:33:56 +01:00
void
drw_font_getexts ( Fnt * font , const char * text , unsigned int len , unsigned int * w , unsigned int * h )
2015-10-20 22:34:49 +01:00
{
2016-05-22 21:33:56 +01:00
XGlyphInfo ext ;
2013-06-16 14:20:29 +01:00
2016-05-22 21:33:56 +01:00
if ( ! font | | ! text )
return ;
2015-10-20 22:34:49 +01:00
2016-05-22 21:33:56 +01:00
XftTextExtentsUtf8 ( font - > dpy , font - > xfont , ( XftChar8 * ) text , len , & ext ) ;
if ( w )
* w = ext . xOff ;
if ( h )
* h = font - > h ;
2013-06-16 14:20:29 +01:00
}
Cur *
2015-10-20 22:34:49 +01:00
drw_cur_create ( Drw * drw , int shape )
{
Cur * cur ;
2013-06-16 14:20:29 +01:00
2016-05-22 21:33:56 +01:00
if ( ! drw | | ! ( cur = ecalloc ( 1 , sizeof ( Cur ) ) ) )
return NULL ;
2013-06-16 14:20:29 +01:00
cur - > cursor = XCreateFontCursor ( drw - > dpy , shape ) ;
2015-10-20 22:34:49 +01:00
2013-06-16 14:20:29 +01:00
return cur ;
}
void
2015-10-20 22:34:49 +01:00
drw_cur_free ( Drw * drw , Cur * cursor )
{
if ( ! cursor )
2013-06-16 14:20:29 +01:00
return ;
2016-05-22 21:33:56 +01:00
2013-06-16 14:20:29 +01:00
XFreeCursor ( drw - > dpy , cursor - > cursor ) ;
free ( cursor ) ;
}