1 /*-----------------------------------*-C-*-------------------------------------*
2  * File		: xftacs.c
3  * Created	: Tue 27 Dec 2005 09:59:55 PM CST
4  * Modified	: Wed 12 Apr 2006 01:33:43 AM CDT
5  * Author	: Gautam Iyer <gi1242@users.sourceforge.net>
6  *-----------------------------------------------------------------------------*
7  *
8  * All portions of code are copyright by their respective author/s.
9  *
10  * 	Copyright 2005-2006   Gautam Iyer <gi1242@users.sourceforge.net>
11  *
12  * This program is free software; you can redistribute it and/or modify it under
13  * the terms of the GNU General Public License as published by the Free Software
14  * Foundation; either version 2 of the License, or (at your option) any later
15  * version.
16  *
17  * This program is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
20  * details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
24  * Ave, Cambridge, MA 02139, USA.
25  *-----------------------------------------------------------------------------*
26  *
27  * DESCRIPTION
28  *
29  * 	Functions to draw VT100 / ACS graphics charecters. Xft functions do not
30  * 	draw text graphic charecters (like XDrawText), so we have to do it
31  * 	ourself. Partly plagurized with thanks from Thomas Dicky's xterm-204:
32  *
33  *		http://invisible-island.net/xterm/xterm.html
34  *
35  *	This file has nothing specific to rxvt. Instead of using XftDrawString,
36  *	use xftDrawACSString. Draws the non-graphics chars using a regular Xft
37  *	function, and graphics chars using XftGlyphs (if available) or line
38  *	segments.
39  *
40  *	Before your first call to xftDrawACSString, call xftInitACS(). After
41  *	your last call to xftDrawACSString, call xftCloseACS().
42  *
43  *	See the comments before each function definition for details.
44  *
45  * BUGS
46  *
47  *	1. Complex chars are drawn using a glyph from the Xft font. Not all
48  *	   fonts have these glyphs. Some have them in a different location than
49  *	   we expect.
50  *
51  *	   The fonts "Andale Mono", "Bitstream Vera Sans Mono" and "Courier New"
52  *	   HAVE the required glyphs at the positions below. The fonts "Courier",
53  *	   "Luxi Mono" and "Nimbus Mono L" DO NOT have the required glyphs.
54  *
55  *----------------------------------------------------------------------------*/
56 
57 #include "../config.h"
58 #include "rxvt.h"
59 
60 #include <xftacs.h>
61 
62 
63 /*
64  * Maximum number of glyphs to be drawn per call to XftDrawGlyphs.
65  */
66 #define MAX_GLYPHS (32)
67 
68 /*
69  * Global variables that need to be inited on startup.
70  */
71 GC	acsGc=0;	/* GC used for all drawing requests */
72 Pixmap	sPmap=0;	/* Stippled pixmap used for tiling */
73 
74 /*
75  * The grid is arbitrary, enough resolution that nothing's lost in
76  * initialization.
77  */
78 #define BOX_HIGH 60
79 #define BOX_WIDE 60
80 
81 #define MID_HIGH (BOX_HIGH/2)
82 #define MID_WIDE (BOX_WIDE/2)
83 
84 #define CHR_WIDE ((9*BOX_WIDE)/10)
85 #define CHR_HIGH ((9*BOX_HIGH)/10)
86 
87 /*
88  * ...since we'll scale the values anyway.
89  */
90 #define SCALE_X(n) n = (n * (font_width-1)) / (BOX_WIDE-1)
91 #define SCALE_Y(n) n = (n * (font_height-1)) / (BOX_HIGH-1)
92 
93 #define SEG(x0,y0,x1,y1) x0,y0, x1,y1
94 
95 /*
96  * XError handler for xftInitACS. This only sets sPmap to 0, and complains.
97  */
98 int
acsXErrorHandler(Display * dpy,XErrorEvent * event)99 acsXErrorHandler( __attribute__((unused)) Display *dpy,
100 	__attribute__((unused)) XErrorEvent *event)
101 {
102 
103     sPmap = 0;
104 
105     rxvt_dbgmsg ((DBG_VERBOSE, DBG_XFTACS, "Could not create pixmap\n"));
106     return 0;
107 }
108 
109 /*
110  * Initialize sPmap. Call this before calling xftDrawACSString(). If d or depth
111  * are 0, then default values are used.
112  *
113  * You will probabaly get a BadMatch error if you try using xftDrawACSString on
114  * a drawable of a different depth.
115  */
116 void
xftInitACS(Display * dpy,Drawable d,unsigned depth)117 xftInitACS( Display *dpy, Drawable d, unsigned depth)
118 {
119     int (*oldXerrorHandler)( Display *, XErrorEvent *);
120 
121     rxvt_dbgmsg ((DBG_DEBUG, DBG_XFTACS, "Initing sPmap\n"));
122 
123     if(d == 0)		d = DefaultRootWindow( dpy);
124     if(depth == 0)	depth=DefaultDepth( dpy, DefaultScreen( dpy));
125 
126 #ifdef DEBUG
127     if( sPmap != 0)
128 	rxvt_dbgmsg ((DBG_DEBUG, DBG_XFTACS, "sPmap not null in xftInitACS"));
129 #endif
130 
131     acsGc = XCreateGC( dpy, d, 0, NULL);
132 
133     oldXerrorHandler = XSetErrorHandler( (XErrorHandler) acsXErrorHandler);
134     sPmap = XCreatePixmap( dpy, d, 2, 2, depth);
135     XSetErrorHandler( oldXerrorHandler);
136 
137     XSetTile( dpy, acsGc, sPmap);
138 }
139 
140 /*
141  * Free sPmap. Call this after your last call to xftDrawACSString, or you WILL
142  * have a memory leak.
143  */
144 void
xftCloseACS(Display * dpy)145 xftCloseACS( Display *dpy)
146 {
147     if( sPmap )
148     {
149 	rxvt_dbgmsg ((DBG_DEBUG, DBG_XFTACS, "freeing sPmap\n"));
150 
151 	XFreePixmap( dpy, sPmap);
152 	sPmap = 0;
153     }
154 #ifdef DEBUG
155     else
156 	rxvt_dbgmsg ((DBG_DEBUG, DBG_XFTACS, "sPmap already null in xftCloseACS"));
157 #endif
158 
159     XFreeGC( dpy, acsGc);
160 }
161 
162 /*
163  * INTERNAL USE ONLY. Draw a ACS graphics character on screen at x,y. Like XFT
164  * functions, we do not clear the background before drawing.
165  *
166  * (x,y) is the bottom left corner of the character to draw.
167  *
168  * WARNING: If any char in *str has ascii value >= 32, then this function will
169  * get stuck in an infinite loop.
170  */
171 void
xftDrawACSChars(Display * dpy,Drawable d,GC gc,XftDraw * draw,const XftColor * color,XftFont * pub,int x,int y,const unsigned char * str,int len)172 xftDrawACSChars(
173 	Display *dpy, Drawable d, GC gc,
174 	XftDraw *draw, const XftColor *color, XftFont *pub,
175 	int x, int y, const unsigned char *str, int len)
176 {
177 
178     /*
179      * Line segments to draw line like chars.
180      */
181     static const short glyph_ht[] = {
182 	SEG(  0,	    0,		  0,	      5*MID_HIGH/6),	/* H */
183 	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
184 	SEG(  0,	  5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
185 	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
186 	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
187 	-1
188     }, glyph_ff[] = {
189 	SEG(  0,	    0,		6*BOX_WIDE/10,	0),		/* F */
190 	SEG(  0,	  5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
191 	SEG(  0,	    0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
192 	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
193 	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
194 	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
195 	-1
196     }, glyph_lf[] = {
197 	SEG(  0,	    0,		  0,	      5*MID_HIGH/6),	/* L */
198 	SEG(  0,	  5*MID_HIGH/6,	6*BOX_WIDE/10,5*MID_HIGH/6),
199 	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
200 	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
201 	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
202 	-1
203     }, glyph_nl[] = {
204 	SEG(  0,	  5*MID_HIGH/6,	  0,		0),		/* N */
205 	SEG(  0,	    0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
206 	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
207 	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
208 	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
209 	-1
210     }, glyph_vt[] = {
211 	SEG(  0,	    0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
212 	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
213 	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
214 	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
215 	-1
216     }, lower_right_corner[] =
217     {
218 	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
219 	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
220 	-1
221     }, upper_right_corner[] =
222     {
223 	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
224 	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
225 	-1
226     }, upper_left_corner[] =
227     {
228 	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
229 	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
230 	-1
231     }, lower_left_corner[] =
232     {
233 	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
234 	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
235 	-1
236     }, cross[] =
237     {
238 	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
239 	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
240 	-1
241     }, left_tee[] =
242     {
243 	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
244 	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
245 	-1
246     }, right_tee[] =
247     {
248 	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
249 	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
250 	-1
251     }, bottom_tee[] =
252     {
253 	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
254 	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
255 	-1
256     }, top_tee[] =
257     {
258 	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
259 	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
260 	-1
261     }, vertical_line[] =
262     {
263 	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
264 	-1
265     };
266 
267     /*
268      * Pointer to line-segment structure.
269      */
270     static const short *lines[] = {
271 	NULL,			/* 00 (unused) */
272 	NULL,			/* 01 diamond */
273 	NULL,			/* 02 box */
274 	glyph_ht,		/* 03 HT */
275 	glyph_ff,		/* 04 FF */
276 	NULL,			/* 05 CR (not drawn) */
277 	glyph_lf,		/* 06 LF */
278 	NULL,			/* 07 degrees (small circle) */
279 	NULL,			/* 08 plus or minus*/
280 	glyph_nl,		/* 09 */
281 	glyph_vt,		/* 0A */
282 	lower_right_corner,	/* 0B */
283 	upper_right_corner,	/* 0C */
284 	upper_left_corner,	/* 0D */
285 	lower_left_corner,	/* 0E */
286 	cross,			/* 0F */
287 	NULL,			/* 10 overline  */
288 	NULL,			/* 11 topline   */
289 	NULL,			/* 12 midline   */
290 	NULL,			/* 13 botline   */
291 	NULL,			/* 14 underline */
292 	left_tee,		/* 15 */
293 	right_tee,		/* 16 */
294 	bottom_tee,		/* 17 */
295 	top_tee,		/* 18 */
296 	vertical_line,		/* 19 */
297 	NULL,			/* 1A leq */
298 	NULL,			/* 1B geq */
299 	NULL,			/* 1C pi */
300 	NULL,			/* 1D neq */
301 	NULL,			/* 1E pound  */
302 	NULL,			/* 1F bullet */
303     };
304 
305     /*
306      * Character number in XftFont (if any).
307      */
308     static const FT_UInt xftCharNo[] = {
309 	0,	/* 00 (unused) */
310 	0,	/* 01 diamond */
311 	0,	/* 02 box */
312 	0,	/* 03 HT */
313 	0,	/* 04 FF */
314 	0x8b,	/* 05 CR (drawn as (c) ) */
315 	0,	/* 06 LF */
316 	0x83,	/* 07 degrees (small circle) */
317 	0x93,	/* 08 plus or minus*/
318 	0,	/* 09 */
319 	0,	/* 0A */
320 	0,	/* 0B */
321 	0,	/* 0C */
322 	0,	/* 0D */
323 	0,	/* 0E */
324 	0,	/* 0F */
325 	0,	/* 10 overline  */
326 	0,	/* 11 topline   */
327 	0,	/* 12 midline   */
328 	0,	/* 13 botline   */
329 	0,	/* 14 underline */
330 	0,	/* 15 */
331 	0,	/* 16 */
332 	0,	/* 17 */
333 	0,	/* 18 */
334 	0,	/* 19 */
335 	0x94,	/* 1A leq */
336 	0x95,	/* 1B geq */
337 	0x9b,	/* 1C pi */
338 	0x8f,	/* 1D neq */
339 	0x85,	/* 1E pound  */
340 	0x87	/* 1F bullet */
341     };
342 
343     unsigned font_width	 = pub->max_advance_width;
344     unsigned font_height = pub->ascent + pub->descent;
345     const short *p;
346     FT_UInt glyphs[MAX_GLYPHS];
347 
348     int ytop = y - pub->ascent; /* (x, ytop) is the top left corner */
349 
350     /*
351      * Update fill styles in acsGc
352      */
353     XSetLineAttributes(dpy, acsGc, (font_height > 16) ? font_height / 16 : 1,
354 	LineSolid, CapProjecting, JoinMiter);
355     XCopyGC( dpy, gc, GCForeground | GCBackground, acsGc);
356 
357     /*
358      * Draw the characters. A few (ones with curves / shading) need to be
359      * treated specially. The rest can be drawn with the segments in lines[n].
360      */
361     while( 1 )
362     {
363 	/*
364 	 * If even one value in str[] is >= 32, this loop will never terminate.
365 	 * This is checked before calling, so no need to recheck here.
366 	 *
367 	 * We use such "contorted" code to optimize for speed. Since this is
368 	 * done several times while refreshing the screen, we don't want to slow
369 	 * things down.
370 	 */
371 	int n;
372 
373 	/*
374 	 * Find max contiguous block of chars which are present in the Xft font,
375 	 * and use XftDrawGlyphs to draw them.
376 	 */
377 	for( n=0; n < len && n < MAX_GLYPHS && (glyphs[n] = xftCharNo[ *str ]);
378 		n++, str++);
379 	if( n )
380 	{
381 	    rxvt_dbgmsg ((DBG_VERBOSE, DBG_XFTACS, "(%d glyphs) ", n));
382 
383 	    XftDrawGlyphs( draw, color, pub, x, y, glyphs, n);
384 
385 	    x += n * font_width;
386 	    if( !(len -= n) ) break; /* !(len -= n) iff (len -= n) <= 0 */
387 	}
388 
389 	/*
390 	 * Draw contiguous stippled box (0x02)
391 	 */
392 	for( n=0; n < len && *str == 2; n++, str++);
393 	if( n )
394 	{
395 	    XGCValues values;
396 
397 	    rxvt_dbgmsg ((DBG_VERBOSE, DBG_XFTACS, "(%d boxes) ", n));
398 
399 	    XGetGCValues( dpy, acsGc, GCForeground | GCBackground, &values);
400 
401 	    XDrawPoint( dpy, sPmap, acsGc, 0, 0);
402 	    XDrawPoint( dpy, sPmap, acsGc, 1, 1);
403 
404 	    XSetForeground( dpy, acsGc, values.background);
405 	    XDrawPoint( dpy, sPmap, acsGc, 0, 1);
406 	    XDrawPoint( dpy, sPmap, acsGc, 1, 0);
407 
408 	    values.fill_style = FillTiled;
409 	    XChangeGC( dpy, acsGc, GCForeground | GCFillStyle, &values);
410 
411 	    XFillRectangle( dpy, d, acsGc, x, ytop, n * font_width, font_height);
412 
413 	    if( !(len -= n) ) break; /* !(len -= n) iff (len -= n) <= 0 */
414 	    x += n * font_width;
415 	}
416 
417 	/*
418 	 * Draw contiguous horizontal lines.
419 	 */
420 	if( *str >= 0x10 && *str <= 0x14)
421 	{
422 	    unsigned char c = *str;
423 	    int xstart = x;
424 	    int ystart = ytop + ((c - 0x10) * (font_height-1)) / 4;
425 
426 	    for( n=0; ++n < len && *(++str) == c; );
427 
428 	    rxvt_dbgmsg ((DBG_VERBOSE, DBG_XFTACS, "(%d hln)", n));
429 	    x += n * font_width;
430 
431 	    XSetFillStyle( dpy, acsGc, FillSolid);
432 	    XDrawLine( dpy, d, acsGc, xstart, ystart, x-1, ystart);
433 
434 	    if( !(len -= n)) break;
435 	}
436 
437 	/*
438 	 * Contiguous drawing not possible for these cases.
439 	 */
440 	if (*str == 1)			/* Filled diamond */
441 	{
442 	    XPoint points[4];
443 	    int npoints = 4, n;
444 
445 	    rxvt_dbgmsg ((DBG_VERBOSE, DBG_XFTACS, "(1 dmd) "));
446 
447 	    points[0].x = CHR_WIDE/2 + (BOX_WIDE - CHR_WIDE) / 2;
448 	    points[0].y = 0;
449 
450 	    points[1].x = (BOX_WIDE - CHR_WIDE) / 2;
451 	    points[1].y = CHR_HIGH/2 + (BOX_HIGH - CHR_HIGH) / 2;
452 
453 	    points[2].x = points[0].x;
454 	    points[2].y = CHR_HIGH + (BOX_HIGH - CHR_HIGH) / 2;
455 
456 	    points[3].x = CHR_WIDE + (BOX_WIDE - CHR_WIDE) / 2;
457 	    points[3].y = points[1].y;
458 
459 	    for (n = 0; n < npoints; n++)
460 	    {
461 		SCALE_X(points[n].x);
462 		SCALE_Y(points[n].y);
463 
464 		points[n].x += x;
465 		points[n].y += ytop;
466 	    }
467 
468 	    XSetFillStyle( dpy, acsGc, FillSolid);
469 	    XFillPolygon( dpy, d, acsGc, points, npoints, Convex, CoordModeOrigin);
470 
471 	    if( ! (--len)) break;
472 	    str++;
473 	    x += font_width;
474 	}
475 	else if( NOT_NULL(p = lines[*str]))
476 	{
477 	    /*
478 	     * Draw character using segments in lines[*str]
479 	     */
480 	    int coord[4];
481 	    int n = 0;
482 
483 	    rxvt_dbgmsg ((DBG_VERBOSE, DBG_XFTACS, "(1 ldc) "));
484 
485 	    XSetFillStyle( dpy, acsGc, FillSolid);
486 	    while (*p >= 0)
487 	    {
488 		coord[n++] = *p++;
489 		if (n == 4)
490 		{
491 		    SCALE_X(coord[0]);
492 		    SCALE_Y(coord[1]);
493 		    SCALE_X(coord[2]);
494 		    SCALE_Y(coord[3]);
495 		    XDrawLine( dpy, d, acsGc,
496 			x + coord[0], ytop + coord[1],
497 			x + coord[2], ytop + coord[3]);
498 		    n = 0;
499 		}
500 	    }
501 
502 	    if( !(--len)) break;
503 	    str++;
504 	    x += font_width;
505 	}
506     }
507 #ifdef DEBUG
508     rxvt_dbgmsg ((DBG_DEBUG, DBG_XFTACS, "\n"));
509 #endif
510 }
511 
512 /*
513  * Draws an XFT string on screen. All characters below 32 are assumed to be ACS
514  * graphics characters and are drawn by hand. Ther rest are passed to
515  * xftdraw_string to be drawn by Xft. xftdraw_string should be XftDrawString8 /
516  * Utf8. Changing this to accept XftDrawString16 etc is not hard, but will bloat
517  * mrxvt (and isn't done here).
518  */
519 void
xftDrawACSString(Display * dpy,Drawable d,GC gc,void (* xftdraw_string)(),XftDraw * draw,const XftColor * color,XftFont * pub,int x,int y,const unsigned char * str,int len)520 xftDrawACSString ( Display *dpy, Drawable d, GC gc,
521 	void (*xftdraw_string)(),
522 	XftDraw *draw, const XftColor *color, XftFont *pub,
523 	int x, int y, const unsigned char *str, int len)
524 {
525     const unsigned char *t = str;
526     int chars;
527 
528     rxvt_dbgmsg ((DBG_VERBOSE, DBG_XFTACS, "Drawing %d(%d) %sACS characters.", len, STRLEN( str), ( xftdraw_string == XftDrawString8) ? "Utf8 " : ""));
529 
530     while(len > 0)
531     {
532 	/*
533 	 * Pass all non graphic chars to xftdraw_string.
534 	 */
535 	for( chars=0; *t >= 32 && chars < len; chars++, t++);
536 	if( chars)
537 	{
538 	    rxvt_dbgmsg ((DBG_VERBOSE, DBG_XFTACS, " [%d chars]", chars));
539 	    xftdraw_string( draw, color, pub, x, y, str, chars);
540 
541 	    x += chars * pub->max_advance_width;
542 	    str = t;
543 	    len -= chars;
544 	}
545 
546 	/*
547 	 * Draw all ACS graphics chars by hand.
548 	 */
549 	for( chars=0; *t < 32 && chars < len; chars++, t++);
550 	if( chars)
551 	{
552 	    rxvt_dbgmsg ((DBG_VERBOSE, DBG_XFTACS, " (%d glyphs)", chars));
553 	    xftDrawACSChars( dpy, d, gc, draw, color, pub, x, y, str, chars);
554 
555 	    x += chars * pub->max_advance_width;
556 	    str = t;
557 	    len -= chars;
558 	}
559     }
560 #ifdef DEBUG
561     rxvt_dbgmsg ((DBG_DEBUG, DBG_XFTACS, "\n"));
562 #endif
563 }
564 /*-------------------------- end-of-file (C source) --------------------------*/
565