Pre-initialise "len2" to zero, to avoid GCC warning during compilation.
[fvwm.git] / libs / Flocale.c
blob058dc49dfaea462d2a55c2a981902909283f0612
1 /* -*-c-*- */
2 /* Copyright (C) 2002 Olivier Chapuis */
3 /* This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 /* FlocaleRotateDrawString is strongly inspired by some part of xvertext
18 * taken from wmx */
19 /* Here the copyright for this function: */
20 /* xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma)
22 * Permission to use, copy, modify, and distribute this software and its
23 * documentation for any purpose and without fee is hereby granted, provided
24 * that the above copyright notice appear in all copies and that both the
25 * copyright notice and this permission notice appear in supporting
26 * documentation. All work developed as a consequence of the use of
27 * this program should duly acknowledge such use. No representations are
28 * made about the suitability of this software for any purpose. It is
29 * provided "as is" without express or implied warranty.
31 * Minor modifications by Chris Cannam for wm2/wmx
32 * Major modifications by Kazushi (Jam) Marukawa for wm2/wmx i18n patch
33 * Simplification and complications by olicha for use with fvwm
36 /* ---------------------------- included header files ---------------------- */
38 #include "config.h"
40 #include <stdio.h>
41 #include <unistd.h>
43 #include <X11/Xlib.h>
44 #include <X11/Xutil.h>
45 #include <X11/Xatom.h>
47 #include "defaults.h"
48 #include "fvwmlib.h"
49 #include "Graphics.h"
50 #include "ColorUtils.h"
51 #include "Strings.h"
52 #include "Parse.h"
53 #include "PictureBase.h"
54 #include "Flocale.h"
55 #include "FlocaleCharset.h"
56 #include "FBidi.h"
57 #include "FftInterface.h"
58 #include "Colorset.h"
59 #include "Ficonv.h"
60 #include "CombineChars.h"
62 /* ---------------------------- local definitions -------------------------- */
64 /* ---------------------------- local macros ------------------------------- */
66 #define FSwitchDrawString(use_16, dpy, d, gc, x, y, s8, s16, l) \
67 (use_16) ? \
68 XDrawString16(dpy, d, gc, x, y, s16, l) : \
69 XDrawString(dpy, d, gc, x, y, s8, l)
70 #define FSwitchDrawImageString(use_16, dpy, d, gc, x, y, s8, s16, l) \
71 (use_16) ? \
72 XDrawImageString16(dpy, d, gc, x, y, s16, l) : \
73 XDrawImageString(dpy, d, gc, x, y, s8, l)
75 /* ---------------------------- imports ------------------------------------ */
77 /* ---------------------------- included code files ------------------------ */
79 /* ---------------------------- local types -------------------------------- */
81 /* ---------------------------- forward declarations ----------------------- */
83 /* ---------------------------- local variables ---------------------------- */
85 static FlocaleFont *FlocaleFontList = NULL;
86 static char *Flocale = NULL;
87 static char *Fmodifiers = NULL;
89 /* TODO: make these (static const char *) */
90 static char *fft_fallback_font = FLOCALE_FFT_FALLBACK_FONT;
91 static char *mb_fallback_font = FLOCALE_MB_FALLBACK_FONT;
92 static char *fallback_font = FLOCALE_FALLBACK_FONT;
95 /* ---------------------------- exported variables (globals) --------------- */
97 /* ---------------------------- local functions ---------------------------- */
100 * shadow local functions
103 static
104 void FlocaleParseShadow(char *str, int *shadow_size, int *shadow_offset,
105 int *direction, char * fontname, char *module)
107 char *dir_str;
108 char *token;
109 multi_direction_t dir;
111 *direction = MULTI_DIR_NONE;
112 token = PeekToken(str, &dir_str);
113 if (token == NULL || *token == 0 ||
114 (GetIntegerArguments(token, NULL, shadow_size, 1) != 1) ||
115 *shadow_size < 0)
117 *shadow_size = 0;
118 fprintf(stderr,"[%s][FlocaleParseShadow]: WARNING -- bad "
119 "shadow size in font name:\n\t'%s'\n",
120 (module)? module: "fvwm", fontname);
121 return;
123 if (*shadow_size == 0)
125 return;
127 /* some offset ? */
128 if (dir_str && *dir_str &&
129 (GetIntegerArguments(dir_str, NULL, shadow_offset, 1) == 1))
131 if (*shadow_offset < 0)
133 *shadow_offset = 0;
134 fprintf(stderr,"[%s][FlocaleParseShadow]: WARNING -- "
135 "bad shadow offset in font name:\n\t'%s'\n",
136 (module)? module: "fvwmlibs", fontname);
138 PeekToken(dir_str, &dir_str);
140 while (dir_str && *dir_str && *dir_str != '\n')
142 dir = gravity_parse_multi_dir_argument(dir_str, &dir_str);
143 if (dir == MULTI_DIR_NONE)
145 fprintf(stderr,"[%s][FlocaleParseShadow]: WARNING -- "
146 "bad shadow direction in font description:\n"
147 "\t%s\n",
148 (module)? module: "fvwmlibs", fontname);
149 PeekToken(dir_str, &dir_str); /* skip it */
151 else
153 *direction |= dir;
156 if (*direction == MULTI_DIR_NONE)
157 *direction = MULTI_DIR_SE;
161 * some simple converters
164 static
165 int FlocaleChar2bOneCharToUtf8(XChar2b c, char *buf)
167 int len;
168 char byte1 = c.byte1;
169 char byte2 = c.byte2;
170 unsigned short ucs2 = ((unsigned short)byte1 << 8) + byte2;
172 if(ucs2 <= 0x7f)
174 len = 1;
175 buf[0] = (char)ucs2;
176 buf[1] = 0;
178 else if(ucs2 <= 0x7ff)
180 len = 2;
181 buf[0] = (ucs2 >> 6) | 0xc0;
182 buf[1] = (ucs2 & 0x3f) | 0x80;
183 buf[2] = 0;
185 else
187 len = 3;
188 buf[0] = (ucs2 >> 12) | 0xe0;
189 buf[1] = ((ucs2 & 0xfff) >> 6) | 0x80;
190 buf[2] = (ucs2 & 0x3f) | 0x80;
191 buf[3] = 0;
193 return len;
196 /* return number of bytes of character at current position
197 (pointed to by str) */
198 int FlocaleStringNumberOfBytes(FlocaleFont *flf, const char *str)
200 int bytes = 0;
201 if(FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
203 /* handle UTF-8 */
204 if ((str[0] & 0x80) == 0)
206 bytes = 1;
208 else if((str[0] & ~0xdf) == 0)
210 bytes = 2;
212 else
214 /* this handles only 16-bit Unicode */
215 bytes = 3;
218 else if(flf->flags.is_mb)
220 /* non-UTF-8 multibyte encoding */
221 if ((str[0] & 0x80) == 0)
223 bytes = 1;
225 else
227 bytes = 2;
230 else
232 /* we must be using an "ordinary" 8-bit encoding */
233 bytes = 1;
235 return bytes;
238 /* given a string, font specifying its locale and a byte offset gives
239 character offset */
240 int FlocaleStringByteToCharOffset(FlocaleFont *flf, const char *str,
241 int offset)
243 const char *curr_ptr = str;
244 int i = 0;
245 int len = strlen(str);
246 int coffset = 0;
247 int curr_len;
249 for(i = 0 ;
250 i < offset && i < len ;
251 i += curr_len, curr_ptr += curr_len, coffset++)
253 curr_len = FlocaleStringNumberOfBytes(flf, curr_ptr);
255 return coffset;
258 /* like above but reversed, ie. return byte offset corresponding to given
259 charater offset */
260 int FlocaleStringCharToByteOffset(FlocaleFont *flf, const char *str,
261 int coffset)
263 const char *curr_ptr = str;
264 int i;
265 int len = strlen(str);
266 int offset = 0;
267 int curr_len;
269 for(i = 0 ;
270 i < coffset && i < len ;
271 offset += curr_len, curr_ptr += curr_len, i++)
273 curr_len = FlocaleStringNumberOfBytes(flf, curr_ptr);
275 return offset;
278 /* return length of string in characters */
279 int FlocaleStringCharLength(FlocaleFont *flf, const char *str)
281 int i, len;
282 int str_len = strlen(str);
283 for(i = 0, len = 0 ; i < str_len ;
284 i += FlocaleStringNumberOfBytes(flf, str+i), len++);
285 return len;
288 static
289 XChar2b *FlocaleUtf8ToUnicodeStr2b(char *str, int len, int *nl)
291 XChar2b *str2b = NULL;
292 int i = 0, j = 0, t;
294 str2b = (XChar2b *)safemalloc((len+1)*sizeof(XChar2b));
295 while (i < len && str[i] != 0)
297 if ((str[i] & 0x80) == 0)
299 str2b[j].byte2 = str[i];
300 str2b[j].byte1 = 0;
302 else if ((str[i] & ~0xdf) == 0 && i+1 < len)
304 t = ((str[i] & 0x1f) << 6) + (str[i+1] & 0x3f);
305 str2b[j].byte2 = (unsigned char)(t & 0xff);
306 str2b[j].byte1 = (unsigned char)(t >> 8);
307 i++;
309 else if (i+2 <len)
311 t = ((str[i] & 0x0f) << 12) + ((str[i+1] & 0x3f) << 6)+
312 (str[i+2] & 0x3f);
313 str2b[j].byte2 = (unsigned char)(t & 0xff);
314 str2b[j].byte1 = (unsigned char)(t >> 8);
315 i += 2;
317 i++; j++;
319 *nl = j;
320 return str2b;
323 /* Note: this function is not expected to work; good mb rendering
324 * should be (and is) done using Xmb functions and not XDrawString16
325 * (or with iso10646-1 fonts and setting the encoding).
326 * This function is used when the locale does not correspond to the font.
327 * It works with "EUC fonts": ksc5601.1987-0, gb2312 and maybe also
328 * cns11643-*. It works patially with jisx* and big5-0. Should try gbk-0,
329 * big5hkscs-0, and cns-11643- */
330 static
331 XChar2b *FlocaleStringToString2b(
332 Display *dpy, FlocaleFont *flf, char *str, int len, int *nl)
334 XChar2b *str2b = NULL;
335 char *tmp = NULL;
336 Bool free_str = False;
337 int i = 0, j = 0;
338 Bool euc = True; /* KSC5601 (EUC-KR), GB2312 (EUC-CN), CNS11643-1986-1
339 * (EUC-TW) and converted jisx (EUC-JP) */
341 if (flf->fc && StrEquals(flf->fc->x,"jisx0208.1983-0"))
343 tmp = FiconvCharsetToCharset(
344 dpy, flf->fc, FlocaleCharsetGetEUCJPCharset(), str,
345 len);
346 if (tmp != NULL)
348 free_str = True;
349 str = tmp;
350 len = strlen(tmp);
353 else if (flf->fc && StrEquals(flf->fc->x,"big5-0"))
355 euc = False;
357 str2b = (XChar2b *)safemalloc((len+1)*sizeof(XChar2b));
358 if (euc)
360 while (i < len && str[i] != 0)
362 if ((str[i] & 0x80) == 0)
364 /* seems ok with KSC5601 and GB2312 as we get
365 * almost the ascii. I do no try
366 * CNS11643-1986-1. Should convert to ascii
367 * with jisx */
368 str2b[j].byte1 = 0x23; /* magic number! */
369 str2b[j].byte2 = str[i++];
371 else if (i+1 < len)
373 /* mb gl (for gr replace & 0x7f by | 0x80 ...)
375 str2b[j].byte1 = str[i++] & 0x7f;
376 str2b[j].byte2 = str[i++] & 0x7f;
378 else
380 str2b[j].byte1 = 0;
381 str2b[j].byte2 = 0;
382 i++;
384 j++;
387 else /* big5 and others not yet tested */
389 while (i < len && str[i] != 0)
391 if ((str[i] & 0x80) == 0)
393 /* we should convert to ascii */
394 #if 0
395 str2b[j].byte1 = 0xa2; /* magic number! */
396 str2b[j].byte2 = str[i++];
397 #endif
398 /* a blanck char ... */
399 str2b[j].byte1 = 0x21;
400 str2b[j].byte2 = 0x21;
402 else if (i+1 < len)
404 str2b[j].byte1 = str[i++];
405 str2b[j].byte2 = str[i++];
407 else
409 str2b[j].byte1 = 0;
410 str2b[j].byte2 = 0;
411 i++;
413 j++;
416 *nl = j;
417 if (free_str)
418 free(str);
419 return str2b;
422 static
423 char *FlocaleEncodeString(
424 Display *dpy, FlocaleFont *flf, char *str, int *do_free, int len,
425 int *nl, int *is_rtl, superimpose_char_t **comb_chars,
426 int **l_to_v)
428 char *str1, *str2, *str3;
429 int len1;
430 int len2;
431 int i;
432 Bool do_iconv = True;
433 const char *bidi_charset;
435 len1 = len;
436 len2 = 0;
438 if (is_rtl != NULL)
439 *is_rtl = False;
440 *do_free = False;
441 *nl = len;
443 if (flf->str_fc == NULL || flf->fc == NULL ||
444 flf->fc == flf->str_fc)
446 do_iconv = False;
449 str1 = str;
450 if (FiconvSupport)
452 char *tmp_str;
454 /* first process combining characters */
455 tmp_str = FiconvCharsetToUtf8(
456 dpy, flf->str_fc, (const char *)str,len);
457 /* if conversion to UTF-8 failed str1 will be NULL */
458 if(tmp_str != NULL)
460 /* do combining */
461 len = CombineChars((unsigned char *)tmp_str,
462 strlen(tmp_str), comb_chars,
463 l_to_v);
464 /* returns the length of the resulting UTF-8 string */
465 /* convert back to current charset */
466 str1 = FiconvUtf8ToCharset(
467 dpy, flf->str_fc, (const char *)tmp_str,len);
468 if (tmp_str != str1)
470 free(tmp_str);
472 if (str1)
474 *nl = len = strlen(str1);
475 *do_free = True;
477 else
479 /* convert back to current charset fail */
480 len = strlen(str);
481 str1 = str;
486 if (FiconvSupport && do_iconv)
488 str2 = FiconvCharsetToCharset(
489 dpy, flf->str_fc, flf->fc, (const char *)str1, len);
490 if (str2 == NULL)
492 /* fail to convert */
493 return str1;
495 if (str2 != str1)
497 if (*do_free && str1)
499 free(str1);
500 str1 = str2;
502 *do_free = True;
503 len1 = strlen(str2);
506 else
508 str2 = str1;
509 len1 = len;
510 /* initialise array with composing characters (empty) */
511 if(comb_chars != NULL && *comb_chars == NULL)
513 *comb_chars = (superimpose_char_t *)
514 safemalloc(sizeof(superimpose_char_t));
515 (*comb_chars)[0].position = -1;
516 (*comb_chars)[0].c.byte1 = 0;
517 (*comb_chars)[0].c.byte2 = 0;
520 /* initialise logic to visual mapping here if that is demanded
521 (this is default when no combining has been done (1-to-1))
523 if(l_to_v != NULL && *l_to_v == NULL)
525 *l_to_v = (int*)safemalloc((len + 1) * sizeof(int));
526 for(i = 0 ; i < len ; i++)
527 (*l_to_v)[i] = i;
528 (*l_to_v)[len] = -1;
532 if (FlocaleGetBidiCharset(dpy, flf->str_fc) != NULL &&
533 (bidi_charset = FlocaleGetBidiCharset(dpy, flf->fc)) != NULL)
535 str3 = FBidiConvert(str2, bidi_charset, len1,
536 is_rtl, &len2,
537 comb_chars != NULL ? *comb_chars : NULL,
538 l_to_v != NULL ? *l_to_v : NULL);
539 if (str3 != NULL && str3 != str2)
541 if (*do_free)
543 free(str2);
545 *do_free = True;
546 len1 = len2;
547 str1 = str3;
549 /* if we failed to do BIDI convert, return string string from
550 combining phase */
551 else
553 str1 = str2;
554 /* we already have the logical to visual mapping
555 from combining phase */
559 *nl = len1;
560 return str1;
563 static
564 void FlocaleEncodeWinString(
565 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, int *do_free,
566 int *len, superimpose_char_t **comb_chars, int **l_to_v)
568 int len2b;
569 fws->e_str = FlocaleEncodeString(
570 dpy, flf, fws->str, do_free, *len, len, NULL, comb_chars,
571 l_to_v);
572 fws->str2b = NULL;
574 if (flf->font != None)
576 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
578 fws->str2b = FlocaleUtf8ToUnicodeStr2b(
579 fws->e_str, *len, &len2b);
581 else if (flf->flags.is_mb)
583 fws->str2b = FlocaleStringToString2b(
584 dpy, flf, fws->e_str, *len, &len2b);
590 * Text Drawing with a FontStruct
593 static
594 void FlocaleFontStructDrawString(
595 Display *dpy, FlocaleFont *flf, Drawable d, GC gc, int x, int y,
596 Pixel fg, Pixel fgsh, Bool has_fg_pixels, FlocaleWinString *fws,
597 int len, Bool image)
599 int xt = x;
600 int yt = y;
601 int is_string16;
602 flocale_gstp_args gstp_args;
604 is_string16 = (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb);
605 if (is_string16 && fws->str2b == NULL)
607 return;
609 if (image)
611 /* for rotated drawing */
612 FSwitchDrawImageString(
613 is_string16, dpy, d, gc, x, y, fws->e_str, fws->str2b,
614 len);
616 else
618 FlocaleInitGstpArgs(&gstp_args, flf, fws, x, y);
619 /* normal drawing */
620 if (flf->shadow_size != 0 && has_fg_pixels == True)
622 XSetForeground(dpy, fws->gc, fgsh);
623 while (FlocaleGetShadowTextPosition(
624 &xt, &yt, &gstp_args))
626 FSwitchDrawString(
627 is_string16, dpy, d, gc, xt, yt,
628 fws->e_str, fws->str2b, len);
631 if (has_fg_pixels == True)
633 XSetForeground(dpy, gc, fg);
635 xt = gstp_args.orig_x;
636 yt = gstp_args.orig_y;
637 FSwitchDrawString(
638 is_string16, dpy, d, gc, xt,yt, fws->e_str, fws->str2b,
639 len);
642 return;
646 * Rotated Text Drawing with a FontStruct or a FontSet
648 static
649 void FlocaleRotateDrawString(
650 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, Pixel fg,
651 Pixel fgsh, Bool has_fg_pixels, int len,
652 superimpose_char_t *comb_chars, int *pixel_pos)
654 static GC my_gc = None;
655 static GC font_gc = None;
656 int j, i, xpfg, ypfg, xpsh, ypsh;
657 unsigned char *normal_data, *rotated_data;
658 unsigned int normal_w, normal_h, normal_len;
659 unsigned int rotated_w, rotated_h, rotated_len;
660 char val;
661 int width, height, descent, min_offset;
662 XImage *image, *rotated_image;
663 Pixmap canvas_pix, rotated_pix;
664 flocale_gstp_args gstp_args;
665 char buf[4];
667 if (fws->str == NULL || len < 1)
669 return;
671 if (fws->flags.text_rotation == ROTATION_0)
673 return; /* should not happen */
676 if (my_gc == None)
678 my_gc = fvwmlib_XCreateGC(dpy, fws->win, 0, NULL);
680 XCopyGC(dpy, fws->gc, GCForeground|GCBackground, my_gc);
682 /* width and height (no shadow!) */
683 width = FlocaleTextWidth(flf, fws->str, len) - FLF_SHADOW_WIDTH(flf);
684 height = flf->height - FLF_SHADOW_HEIGHT(flf);
685 descent = flf->descent - FLF_SHADOW_DESCENT(flf);;
687 if (width < 1)
688 width = 1;
689 if (height < 1)
690 height = 1;
692 /* glyph width and height of the normal text */
693 normal_w = width;
694 normal_h = height;
696 /* width in bytes */
697 normal_len = (normal_w - 1) / 8 + 1;
699 /* create and clear the canvas */
700 canvas_pix = XCreatePixmap(dpy, fws->win, width, height, 1);
701 if (font_gc == None)
703 font_gc = fvwmlib_XCreateGC(dpy, canvas_pix, 0, NULL);
705 XSetBackground(dpy, font_gc, 0);
706 XSetForeground(dpy, font_gc, 0);
707 XFillRectangle(dpy, canvas_pix, font_gc, 0, 0, width, height);
709 /* draw the character center top right on canvas */
710 XSetForeground(dpy, font_gc, 1);
711 if (flf->font != NULL)
713 XSetFont(dpy, font_gc, flf->font->fid);
714 FlocaleFontStructDrawString(dpy, flf, canvas_pix, font_gc, 0,
715 height - descent,
716 fg, fgsh, has_fg_pixels,
717 fws, len, True);
719 else if (flf->fontset != None)
721 XmbDrawString(
722 dpy, canvas_pix, flf->fontset, font_gc, 0,
723 height - descent, fws->e_str, len);
726 /* here take care of superimposing chars */
727 i = 0;
728 if(comb_chars != NULL)
730 while(comb_chars[i].c.byte1 != 0 && comb_chars[i].c.byte2 != 0)
732 /* draw composing character on top of corresponding
733 "real" character */
734 FlocaleWinString tmp_fws = *fws;
735 int offset = pixel_pos[comb_chars[i].position];
736 int curr_len = FlocaleChar2bOneCharToUtf8(
737 comb_chars[i].c,
738 buf);
739 int out_len;
740 char *buf2 = FiconvUtf8ToCharset(
741 dpy,
742 flf->str_fc,
743 (const char *)buf,curr_len);
744 if(buf2 == NULL)
746 /* if conversion failed, combinational char
747 is not representable in current charset */
748 /* just replace with empty string */
749 buf2 = (char *)safemalloc(sizeof(char));
750 buf2[0] = 0;
752 tmp_fws.e_str = buf2;
753 tmp_fws.str2b = NULL;
754 if(flf->fontset != None)
756 XmbDrawString(dpy, canvas_pix, flf->fontset,
757 fws->gc, offset,
758 height - descent, buf2,
759 strlen(buf2));
761 else if(flf->font != None)
763 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
765 tmp_fws.str2b = (XChar2b *)
766 safemalloc(2 * sizeof(XChar2b));
767 tmp_fws.str2b[0] = comb_chars[i].c;
768 tmp_fws.str2b[1].byte1 = 0;
769 tmp_fws.str2b[1].byte2 = 0;
770 out_len = 1;
772 else if (flf->flags.is_mb)
774 tmp_fws.str2b =
775 FlocaleStringToString2b(
776 dpy, flf, tmp_fws.e_str,
777 curr_len, &out_len);
779 else
781 out_len = strlen(buf2);
783 XSetFont(dpy, font_gc, flf->font->fid);
784 FlocaleFontStructDrawString(
785 dpy, flf, canvas_pix, font_gc,
786 offset, height - descent,
787 fg, fgsh, has_fg_pixels, &tmp_fws,
788 out_len, True);
791 free(buf2);
792 if(tmp_fws.str2b != NULL)
794 free(tmp_fws.str2b);
796 i++;
800 /* reserve memory for the first XImage */
801 normal_data = (unsigned char *)safemalloc(normal_len * normal_h);
803 /* create depth 1 XImage */
804 if ((image = XCreateImage(
805 dpy, Pvisual, 1, XYBitmap, 0, (char *)normal_data,
806 normal_w, normal_h, 8, 0)) == NULL)
808 return;
810 image->byte_order = image->bitmap_bit_order = MSBFirst;
812 /* extract character from canvas */
813 XGetSubImage(
814 dpy, canvas_pix, 0, 0, normal_w, normal_h,
815 1, XYPixmap, image, 0, 0);
816 image->format = XYBitmap;
818 /* width, height of the rotated text */
819 if (fws->flags.text_rotation == ROTATION_180)
821 rotated_w = normal_w;
822 rotated_h = normal_h;
824 else /* vertical text */
826 rotated_w = normal_h;
827 rotated_h = normal_w;
830 /* width in bytes */
831 rotated_len = (rotated_w - 1) / 8 + 1;
833 /* reserve memory for the rotated image */
834 rotated_data = (unsigned char *)safecalloc(rotated_h * rotated_len, 1);
836 /* create the rotated X image */
837 if ((rotated_image = XCreateImage(
838 dpy, Pvisual, 1, XYBitmap, 0, (char *)rotated_data,
839 rotated_w, rotated_h, 8, 0)) == NULL)
841 return;
844 rotated_image->byte_order = rotated_image->bitmap_bit_order = MSBFirst;
846 /* map normal text data to rotated text data */
847 for (j = 0; j < rotated_h; j++)
849 for (i = 0; i < rotated_w; i++)
851 /* map bits ... */
852 if (fws->flags.text_rotation == ROTATION_270)
853 val = normal_data[
854 i * normal_len +
855 (normal_w - j - 1) / 8
856 ] & (128 >> ((normal_w - j - 1) % 8));
858 else if (fws->flags.text_rotation == ROTATION_180)
859 val = normal_data[
860 (normal_h - j - 1) * normal_len +
861 (normal_w - i - 1) / 8
862 ] & (128 >> ((normal_w - i - 1) % 8));
864 else /* ROTATION_90 */
865 val = normal_data[
866 (normal_h - i - 1) * normal_len +
867 j / 8] & (128 >> (j % 8));
869 if (val)
870 rotated_data[j * rotated_len + i / 8] |=
871 (128 >> (i % 8));
875 /* create the character's bitmap and put the image on it */
876 rotated_pix = XCreatePixmap(dpy, fws->win, rotated_w, rotated_h, 1);
877 XPutImage(
878 dpy, rotated_pix, font_gc, rotated_image, 0, 0, 0, 0,
879 rotated_w, rotated_h);
881 /* free the image and data */
882 XDestroyImage(image);
883 XDestroyImage(rotated_image);
885 /* free pixmap and GC */
886 XFreePixmap(dpy, canvas_pix);
888 /* x and y corrections: we fill a rectangle! */
889 min_offset = FlocaleGetMinOffset(flf, fws->flags.text_rotation);
890 switch (fws->flags.text_rotation)
892 case ROTATION_90:
893 /* CW */
894 xpfg = fws->x - min_offset;
895 ypfg = fws->y;
896 break;
897 case ROTATION_180:
898 xpfg = fws->x;
899 ypfg = fws->y - min_offset +
900 FLF_SHADOW_BOTTOM_SIZE(flf);
901 break;
902 case ROTATION_270:
903 /* CCW */
904 xpfg = fws->x - min_offset;
905 ypfg = fws->y;
906 break;
907 case ROTATION_0:
908 default:
909 xpfg = fws->x;
910 ypfg = fws->y - min_offset;
911 break;
913 xpsh = xpfg;
914 ypsh = ypfg;
915 /* write the image on the window */
916 XSetFillStyle(dpy, my_gc, FillStippled);
917 XSetStipple(dpy, my_gc, rotated_pix);
918 FlocaleInitGstpArgs(&gstp_args, flf, fws, xpfg, ypfg);
919 if (flf->shadow_size != 0 && has_fg_pixels == True)
921 XSetForeground(dpy, my_gc, fgsh);
922 while (FlocaleGetShadowTextPosition(&xpsh, &ypsh, &gstp_args))
924 XSetTSOrigin(dpy, my_gc, xpsh, ypsh);
925 XFillRectangle(
926 dpy, fws->win, my_gc, xpsh, ypsh, rotated_w,
927 rotated_h);
930 xpsh = gstp_args.orig_x;
931 ypsh = gstp_args.orig_y;
932 XSetTSOrigin(dpy, my_gc, xpsh, ypsh);
933 XFillRectangle(dpy, fws->win, my_gc, xpsh, ypsh, rotated_w, rotated_h);
934 XFreePixmap(dpy, rotated_pix);
936 return;
940 * Fonts info and checking
943 static
944 char *FlocaleGetFullNameOfFontStruct(Display *dpy, XFontStruct *font)
946 char *full_name = NULL;
947 unsigned long value;
949 if (XGetFontProperty(font, XA_FONT, &value))
951 full_name = XGetAtomName(dpy, value);
953 return full_name;
956 static
957 char *FlocaleGetCharsetOfFontStruct(Display *dpy, XFontStruct *font)
959 int i = 0;
960 int count = 0;
961 char *charset = NULL;
962 char *full_name;
964 full_name = FlocaleGetFullNameOfFontStruct(dpy, font);
965 if (full_name == NULL)
967 return NULL;
969 while(full_name[i] != '\0' && count < 13)
971 if (full_name[i] == '-')
973 count++;
975 i++;
978 if (count != 13)
980 return NULL;
982 CopyString(&charset, full_name+i);
983 XFree(full_name);
984 return charset;
987 static
988 char *FlocaleGetCharsetFromName(char *name)
990 int l,i,e;
991 char *charset;
993 l = strlen(name);
994 i = l-1;
995 while(i >= 0 && name[i] != '-')
997 i--;
999 if (i == 0 || i == l-1)
1001 return NULL;
1003 i--;
1004 e = i;
1005 while(i >= 0 && name[i] != '-')
1007 i--;
1009 if (i <= 0 || e == i)
1011 return NULL;
1013 CopyString(&charset, name + i + 1);
1014 return charset;
1017 /* return NULL if it is not reasonable to load a FontSet.
1018 * Currently return name if it is reasonable to load a FontSet, but in the
1019 * future we may want to transform name for faster FontSet loading */
1020 static
1021 char *FlocaleFixNameForFontSet(Display *dpy, char *name, char *module)
1023 char *new_name;
1024 char *charset;
1025 XFontStruct *test_font = NULL;
1027 if (!name)
1029 return NULL;
1032 new_name = name;
1034 if (strchr(name, ','))
1036 /* tmp, do not handle "," separated list */
1037 return name;
1039 charset = FlocaleGetCharsetFromName(name);
1040 if (charset == NULL && !strchr(name, '*') && !strchr(name, '?'))
1042 /* probably a font alias! */
1043 if ((test_font = XLoadQueryFont(dpy, name)))
1045 charset = FlocaleGetCharsetOfFontStruct(dpy, test_font);
1046 XFreeFont(dpy, test_font);
1049 if (charset != NULL)
1051 if (!strchr(charset, '*') && !strchr(charset, '?') &&
1052 !FlocaleCharsetIsCharsetXLocale(dpy, charset, module))
1054 /* if the charset is fully specified and do not match
1055 * one of the X locale charset */
1056 new_name = NULL;
1057 #if 0
1058 fprintf(stderr,"[%s][FlocaleGetFontSet]: WARNING -- "
1059 "Use of a non X locale charset '%s' when "
1060 "loading font: %s\n",
1061 (module)? module:"fvwmlibs", charset, name);
1062 #endif
1064 free(charset);
1066 return new_name;
1070 * Fonts loading
1073 static
1074 FlocaleFont *FlocaleGetFftFont(
1075 Display *dpy, char *fontname, char *encoding, char *module)
1077 FftFontType *fftf = NULL;
1078 FlocaleFont *flf = NULL;
1079 char *fn, *hints = NULL;
1081 hints = GetQuotedString(fontname, &fn, "/", NULL, NULL, NULL);
1082 if (fn == NULL)
1084 fn = fft_fallback_font;
1086 else if (*fn == '\0')
1088 free(fn);
1089 fn = fft_fallback_font;
1091 fftf = FftGetFont(dpy, fn, module);
1092 if (fftf == NULL)
1094 if (fn != NULL && fn != fft_fallback_font)
1096 free(fn);
1098 return NULL;
1100 flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
1101 memset(flf, '\0', sizeof(FlocaleFont));
1102 flf->count = 1;
1103 flf->fftf = *fftf;
1104 FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
1105 FftGetFontHeights(
1106 &flf->fftf, &flf->height, &flf->ascent, &flf->descent);
1107 FftGetFontWidths(flf, &flf->max_char_width);
1108 free(fftf);
1109 if (fn != NULL && fn != fft_fallback_font)
1111 free(fn);
1114 return flf;
1117 static
1118 FlocaleFont *FlocaleGetFontSet(
1119 Display *dpy, char *fontname, char *encoding, char *module)
1121 static int mc_errors = 0;
1122 FlocaleFont *flf = NULL;
1123 XFontSet fontset = NULL;
1124 char **ml;
1125 int mc,i;
1126 char *ds;
1127 XFontSetExtents *fset_extents;
1128 char *fn, *hints = NULL, *fn_fixed = NULL;
1130 hints = GetQuotedString(fontname, &fn, "/", NULL, NULL, NULL);
1131 if (*fn == '\0')
1133 free(fn);
1134 fn = fn_fixed = mb_fallback_font;
1136 else if (!(fn_fixed = FlocaleFixNameForFontSet(dpy, fn, module)))
1138 if (fn != NULL && fn != mb_fallback_font)
1140 free(fn);
1142 return NULL;
1144 if (!(fontset = XCreateFontSet(dpy, fn_fixed, &ml, &mc, &ds)))
1146 if (fn_fixed && fn_fixed != fn)
1148 free(fn_fixed);
1150 if (fn != NULL && fn != mb_fallback_font)
1152 free(fn);
1154 return NULL;
1157 if (mc > 0)
1159 if (mc_errors <= FLOCALE_NUMBER_MISS_CSET_ERR_MSG)
1161 mc_errors++;
1162 fprintf(stderr,
1163 "[%s][FlocaleGetFontSet]: (%s)"
1164 " Missing font charsets:\n",
1165 (module)? module: "fvwmlibs", fontname);
1166 for (i = 0; i < mc; i++)
1168 fprintf(stderr, "%s", ml[i]);
1169 if (i < mc - 1)
1170 fprintf(stderr, ", ");
1172 fprintf(stderr, "\n");
1173 if (mc_errors == FLOCALE_NUMBER_MISS_CSET_ERR_MSG)
1175 fprintf(stderr,
1176 "[%s][FlocaleGetFontSet]: No more"
1177 " missing charset reportings\n",
1178 (module)? module: "fvwmlibs");
1181 XFreeStringList(ml);
1184 flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
1185 memset(flf, '\0', sizeof(FlocaleFont));
1186 flf->count = 1;
1187 flf->fontset = fontset;
1188 FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
1189 fset_extents = XExtentsOfFontSet(fontset);
1190 flf->height = fset_extents->max_ink_extent.height;
1191 flf->ascent = - fset_extents->max_ink_extent.y;
1192 flf->descent = fset_extents->max_ink_extent.height +
1193 fset_extents->max_ink_extent.y;
1194 flf->max_char_width = fset_extents->max_ink_extent.width;
1195 if (fn_fixed && fn_fixed != fn)
1197 free(fn_fixed);
1199 if (fn != NULL && fn != mb_fallback_font)
1201 free(fn);
1204 return flf;
1207 static
1208 FlocaleFont *FlocaleGetFont(
1209 Display *dpy, char *fontname, char *encoding, char *module)
1211 XFontStruct *font = NULL;
1212 FlocaleFont *flf;
1213 char *str,*fn,*tmp;
1214 char *hints = NULL;
1216 hints = GetQuotedString(fontname, &tmp, "/", NULL, NULL, NULL);
1217 str = GetQuotedString(tmp, &fn, ",", NULL, NULL, NULL);
1218 while (!font && fn)
1220 if (*fn == '\0')
1222 free(fn);
1223 fn = fallback_font;
1225 font = XLoadQueryFont(dpy, fn);
1226 if (fn != NULL && fn != fallback_font)
1228 free(fn);
1229 fn = NULL;
1231 if (!font && str && *str)
1233 str = GetQuotedString(str, &fn, ",", NULL, NULL, NULL);
1236 if (font == NULL)
1238 if (fn != NULL && fn != fallback_font)
1240 free(fn);
1242 if (tmp != NULL)
1244 free(tmp);
1246 return NULL;
1249 flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
1250 memset(flf, '\0', sizeof(FlocaleFont));
1251 flf->count = 1;
1252 flf->fontset = None;
1253 flf->fftf.fftfont = NULL;
1254 flf->font = font;
1255 FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
1256 flf->height = font->max_bounds.ascent + font->max_bounds.descent;
1257 flf->ascent = font->max_bounds.ascent;
1258 flf->descent = font->max_bounds.descent;
1259 flf->max_char_width = font->max_bounds.width;
1260 if (flf->font->max_byte1 > 0)
1261 flf->flags.is_mb = True;
1262 if (fn != NULL && fn != fallback_font)
1264 free(fn);
1266 if (tmp != NULL)
1268 free(tmp);
1271 return flf;
1274 static
1275 FlocaleFont *FlocaleGetFontOrFontSet(
1276 Display *dpy, char *fontname, char *encoding, char *fullname,
1277 char *module)
1279 FlocaleFont *flf = NULL;
1281 if (fontname && strlen(fontname) > 3 &&
1282 strncasecmp("xft:", fontname, 4) == 0)
1284 if (FftSupport)
1286 flf = FlocaleGetFftFont(
1287 dpy, fontname+4, encoding, module);
1289 if (flf)
1291 CopyString(&flf->name, fullname);
1293 return flf;
1295 if (flf == NULL && Flocale != NULL && fontname)
1297 flf = FlocaleGetFontSet(dpy, fontname, encoding, module);
1299 if (flf == NULL && fontname)
1301 flf = FlocaleGetFont(dpy, fontname, encoding, module);
1303 if (flf && fontname)
1305 if (StrEquals(fullname, mb_fallback_font))
1307 flf->name = mb_fallback_font;
1309 else if (StrEquals(fullname, fallback_font))
1311 flf->name = fallback_font;
1313 else
1315 CopyString(&flf->name, fullname);
1317 return flf;
1319 return NULL;
1323 * locale local functions
1326 static
1327 void FlocaleSetlocaleForX(
1328 int category, const char *locale, const char *module)
1330 if ((Flocale = setlocale(category, locale)) == NULL)
1332 fprintf(stderr,
1333 "[%s][%s]: ERROR -- Cannot set locale. Please check"
1334 " your $LC_CTYPE or $LANG.\n",
1335 (module == NULL)? "" : module, "FlocaleSetlocaleForX");
1336 return;
1338 if (!XSupportsLocale())
1340 fprintf(stderr,
1341 "[%s][%s]: WARNING -- X does not support locale %s\n",
1342 (module == NULL)? "": module, "FlocaleSetlocaleForX",
1343 Flocale);
1344 Flocale = NULL;
1348 /* ---------------------------- interface functions ------------------------ */
1351 * locale initialisation
1354 void FlocaleInit(
1355 int category, const char *locale, const char *modifiers,
1356 const char *module)
1359 FlocaleSetlocaleForX(category, locale, module);
1360 if (Flocale == NULL)
1361 return;
1363 if (modifiers != NULL &&
1364 (Fmodifiers = XSetLocaleModifiers(modifiers)) == NULL)
1366 fprintf(stderr,
1367 "[%s][%s]: WARNING -- Cannot set locale modifiers\n",
1368 (module == NULL)? "": module, "FlocaleInit");
1370 #if FLOCALE_DEBUG_SETLOCALE
1371 fprintf(stderr,"[%s][FlocaleInit] locale: %s, modifier: %s\n",
1372 module, Flocale, Fmodifiers);
1373 #endif
1377 * fonts loading
1379 char *prefix_list[] =
1381 "Shadow=",
1382 "StringEncoding=",
1383 NULL
1386 FlocaleFont *FlocaleLoadFont(Display *dpy, char *fontname, char *module)
1388 FlocaleFont *flf = FlocaleFontList;
1389 Bool ask_default = False;
1390 char *t;
1391 char *str, *opt_str, *encoding= NULL, *fn = NULL;
1392 int shadow_size = 0;
1393 int shadow_offset = 0;
1394 int shadow_dir = MULTI_DIR_SE;
1395 int i;
1397 /* removing quoting for modules */
1398 if (fontname && (t = strchr("\"'`", *fontname)))
1400 char c = *t;
1401 fontname++;
1402 if (fontname[strlen(fontname)-1] == c)
1403 fontname[strlen(fontname)-1] = 0;
1406 if (fontname == NULL || *fontname == 0)
1408 ask_default = True;
1409 fontname = mb_fallback_font;
1412 while (flf)
1414 char *c1, *c2;
1416 for (c1 = fontname, c2 = flf->name; *c1 && *c2; ++c1, ++c2)
1418 if (*c1 != *c2)
1420 break;
1423 if (!*c1 && !*c2)
1425 flf->count++;
1426 return flf;
1428 flf = flf->next;
1431 /* not cached load the font as a ";" separated list */
1433 /* But first see if we have a shadow relief and/or an encoding */
1434 str = fontname;
1435 while ((i = GetTokenIndex(str, prefix_list, -1, &str)) > -1)
1437 str = GetQuotedString(str, &opt_str, ":", NULL, NULL, NULL);
1438 switch(i)
1440 case 0: /* shadow= */
1441 FlocaleParseShadow(
1442 opt_str, &shadow_size, &shadow_offset,
1443 &shadow_dir, fontname, module);
1444 break;
1445 case 1: /* encoding= */
1446 if (encoding != NULL)
1448 free(encoding);
1449 encoding = NULL;
1451 if (opt_str && *opt_str)
1453 CopyString(&encoding, opt_str);
1455 break;
1456 default:
1457 break;
1459 if (opt_str != NULL)
1460 free(opt_str);
1462 if (str && *str)
1464 str = GetQuotedString(str, &fn, ";", NULL, NULL, NULL);
1466 else
1468 fn = mb_fallback_font;
1470 while (!flf && (fn && *fn))
1472 flf = FlocaleGetFontOrFontSet(
1473 dpy, fn, encoding, fontname, module);
1474 if (fn != NULL && fn != mb_fallback_font &&
1475 fn != fallback_font)
1477 free(fn);
1478 fn = NULL;
1480 if (!flf && str && *str)
1482 str = GetQuotedString(str, &fn, ";", NULL, NULL, NULL);
1485 if (fn != NULL && fn != mb_fallback_font &&
1486 fn != fallback_font)
1488 free(fn);
1491 if (flf == NULL)
1493 /* loading failed, try default font */
1494 if (!ask_default)
1496 fprintf(stderr,"[%s][FlocaleLoadFont]: "
1497 "WARNING -- can't load font '%s',"
1498 " trying default:\n",
1499 (module)? module: "fvwmlibs", fontname);
1501 else
1503 /* we already tried default fonts: try again? yes */
1505 if (Flocale != NULL)
1507 if (!ask_default)
1509 fprintf(stderr, "\t%s\n",
1510 mb_fallback_font);
1512 if ((flf = FlocaleGetFontSet(
1513 dpy, mb_fallback_font, NULL,
1514 module)) != NULL)
1516 flf->name = mb_fallback_font;
1519 if (flf == NULL)
1521 if (!ask_default)
1523 fprintf(stderr,"\t%s\n",
1524 fallback_font);
1526 if ((flf =
1527 FlocaleGetFont(
1528 dpy, fallback_font, NULL,
1529 module)) != NULL)
1531 flf->name = fallback_font;
1533 else if (!ask_default)
1535 fprintf(stderr,
1536 "[%s][FlocaleLoadFont]:"
1537 " ERROR -- can't load font.\n",
1538 (module)? module: "fvwmlibs");
1540 else
1542 fprintf(stderr,
1543 "[%s][FlocaleLoadFont]: ERROR"
1544 " -- can't load default font:\n",
1545 (module)? module: "fvwmlibs");
1546 fprintf(stderr, "\t%s\n",
1547 mb_fallback_font);
1548 fprintf(stderr, "\t%s\n",
1549 fallback_font);
1554 if (flf != NULL)
1556 if (shadow_size > 0)
1558 flf->shadow_size = shadow_size;
1559 flf->flags.shadow_dir = shadow_dir;
1560 flf->shadow_offset = shadow_offset;
1561 flf->descent += FLF_SHADOW_DESCENT(flf);
1562 flf->ascent += FLF_SHADOW_ASCENT(flf);
1563 flf->height += FLF_SHADOW_HEIGHT(flf);
1564 flf->max_char_width += FLF_SHADOW_WIDTH(flf);
1566 if (flf->fc == FlocaleCharsetGetUnknownCharset())
1568 fprintf(stderr,"[%s][FlocaleLoadFont]: "
1569 "WARNING -- Unknown charset for font\n\t'%s'\n",
1570 (module)? module: "fvwmlibs", flf->name);
1571 flf->fc = FlocaleCharsetGetDefaultCharset(dpy, module);
1573 else if (flf->str_fc == FlocaleCharsetGetUnknownCharset() &&
1574 (encoding != NULL ||
1575 (FftSupport && flf->fftf.fftfont != NULL &&
1576 flf->fftf.str_encoding != NULL)))
1578 fprintf(stderr,"[%s][FlocaleLoadFont]: "
1579 "WARNING -- Unknown string encoding for font\n"
1580 "\t'%s'\n",
1581 (module)? module: "fvwmlibs", flf->name);
1583 if (flf->str_fc == FlocaleCharsetGetUnknownCharset())
1585 flf->str_fc =
1586 FlocaleCharsetGetDefaultCharset(dpy, module);
1588 flf->next = FlocaleFontList;
1589 FlocaleFontList = flf;
1591 if (encoding != NULL)
1593 free(encoding);
1596 return flf;
1599 void FlocaleUnloadFont(Display *dpy, FlocaleFont *flf)
1601 FlocaleFont *list = FlocaleFontList;
1602 int i = 0;
1604 if (!flf)
1606 return;
1608 /* Remove a weight, still too heavy? */
1609 if (--(flf->count) > 0)
1611 return;
1614 if (flf->name != NULL &&
1615 !StrEquals(flf->name, mb_fallback_font) &&
1616 !StrEquals(flf->name, fallback_font))
1618 free(flf->name);
1620 if (FftSupport && flf->fftf.fftfont != NULL)
1622 FftFontClose(dpy, flf->fftf.fftfont);
1623 if (flf->fftf.fftfont_rotated_90 != NULL)
1624 FftFontClose(dpy, flf->fftf.fftfont_rotated_90);
1625 if (flf->fftf.fftfont_rotated_180 != NULL)
1626 FftFontClose(dpy, flf->fftf.fftfont_rotated_180);
1627 if (flf->fftf.fftfont_rotated_270 != NULL)
1628 FftFontClose(dpy, flf->fftf.fftfont_rotated_270);
1630 if (flf->fontset != NULL)
1632 XFreeFontSet(dpy, flf->fontset);
1634 if (flf->font != NULL)
1636 XFreeFont(dpy, flf->font);
1638 if (flf->flags.must_free_fc)
1640 if (flf->fc->x)
1641 free(flf->fc->x);
1642 if (flf->fc->bidi)
1643 free(flf->fc->bidi);
1644 if (flf->fc->locale != NULL)
1646 while (FLC_GET_LOCALE_CHARSET(flf->fc,i) != NULL)
1648 free(FLC_GET_LOCALE_CHARSET(flf->fc,i));
1649 i++;
1651 free(flf->fc->locale);
1653 free(flf->fc);
1656 /* Link it out of the list (it might not be there) */
1657 if (flf == list) /* in head? simple */
1659 FlocaleFontList = flf->next;
1661 else
1663 while (list && list->next != flf)
1665 /* fast forward until end or found */
1666 list = list->next;
1668 /* not end? means we found it in there, possibly at end */
1669 if (list)
1671 /* link around it */
1672 list->next = flf->next;
1675 free(flf);
1679 * Width and Drawing Text
1682 void FlocaleInitGstpArgs(
1683 flocale_gstp_args *args, FlocaleFont *flf, FlocaleWinString *fws,
1684 int start_x, int start_y)
1686 args->step = 0;
1687 args->offset = flf->shadow_offset + 1;
1688 args->outer_offset = flf->shadow_offset + flf->shadow_size;
1689 args->size = flf->shadow_size;
1690 args->sdir = flf->flags.shadow_dir;
1691 switch (fws->flags.text_rotation)
1693 case ROTATION_270: /* CCW */
1694 args->orig_x = start_x + FLF_SHADOW_UPPER_SIZE(flf);
1695 args->orig_y = start_y + FLF_SHADOW_RIGHT_SIZE(flf);
1696 break;
1697 case ROTATION_180:
1698 args->orig_x = start_x + FLF_SHADOW_RIGHT_SIZE(flf);
1699 args->orig_y = start_y;
1700 break;
1701 case ROTATION_90: /* CW */
1702 args->orig_x = start_x + FLF_SHADOW_BOTTOM_SIZE(flf);
1703 args->orig_y = start_y + FLF_SHADOW_LEFT_SIZE(flf);
1704 break;
1705 case ROTATION_0:
1706 default:
1707 args->orig_x = start_x + FLF_SHADOW_LEFT_SIZE(flf);
1708 args->orig_y = start_y;
1709 break;
1711 args->rot = fws->flags.text_rotation;
1713 return;
1716 Bool FlocaleGetShadowTextPosition(
1717 int *x, int *y, flocale_gstp_args *args)
1719 if (args->step == 0)
1721 args->direction = MULTI_DIR_NONE;
1722 args->inter_step = 0;
1724 if ((args->step == 0 || args->inter_step >= args->num_inter_steps) &&
1725 args->size != 0)
1727 /* setup a new direction */
1728 args->inter_step = 0;
1729 gravity_get_next_multi_dir(args->sdir, &args->direction);
1730 if (args->direction == MULTI_DIR_C)
1732 int size;
1734 size = 2 * (args->outer_offset) + 1;
1735 args->num_inter_steps = size * size;
1737 else
1739 args->num_inter_steps = args->size;
1742 if (args->direction == MULTI_DIR_NONE || args->size == 0)
1744 *x = args->orig_x;
1745 *y = args->orig_y;
1747 return False;
1749 if (args->direction == MULTI_DIR_C)
1751 int tx;
1752 int ty;
1753 int size;
1754 int is_finished;
1756 size = 2 * (args->outer_offset) + 1;
1757 tx = args->inter_step % size - args->outer_offset;
1758 ty = args->inter_step / size - args->outer_offset;
1759 for (is_finished = 0; ty <= args->outer_offset;
1760 ty++, tx = -args->outer_offset)
1762 for (; tx <= args->outer_offset; tx++)
1764 if (tx <= -args->offset ||
1765 tx >= args->offset ||
1766 ty <= -args->offset || ty >= args->offset)
1768 is_finished = 1;
1769 break;
1772 if (is_finished)
1774 break;
1777 args->inter_step =
1778 (tx + args->outer_offset) +
1779 (ty + args->outer_offset) * size;
1780 if (!is_finished)
1782 tx = 0;
1783 ty = 0;
1785 *x = args->orig_x + tx;
1786 *y = args->orig_y + ty;
1788 else if (args->inter_step > 0)
1790 /* into a directional drawing */
1791 (*x) += args->x_sign;
1792 (*y) += args->y_sign;
1794 else
1796 direction_t dir;
1797 direction_t dir_x;
1798 direction_t dir_y;
1800 dir = gravity_multi_dir_to_dir(args->direction);
1801 gravity_split_xy_dir(&dir_x, &dir_y, dir);
1802 args->x_sign = gravity_dir_to_sign_one_axis(dir_x);
1803 args->y_sign = gravity_dir_to_sign_one_axis(dir_y);
1804 gravity_rotate_xy(
1805 args->rot, args->x_sign, args->y_sign,
1806 &args->x_sign, &args->y_sign);
1807 *x = args->orig_x + args->x_sign * args->offset;
1808 *y = args->orig_y + args->y_sign * args->offset;
1810 args->inter_step++;
1811 args->step++;
1813 return True;
1816 void FlocaleDrawString(
1817 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws,
1818 unsigned long flags)
1820 int len;
1821 Bool do_free = False;
1822 Pixel fg = 0, fgsh = 0;
1823 Bool has_fg_pixels = False;
1824 flocale_gstp_args gstp_args;
1825 superimpose_char_t *comb_chars = NULL;
1826 char *curr_str;
1827 int char_len; /* length in number of chars */
1828 int *pixel_pos = NULL;
1829 int i;
1830 int j;
1831 char buf[4];
1832 int curr_pixel_pos;
1833 int curr_len;
1835 if (!fws || !fws->str)
1837 return;
1840 if (flags & FWS_HAVE_LENGTH)
1842 len = fws->len;
1844 else
1846 len = strlen(fws->str);
1849 /* encode the string */
1850 FlocaleEncodeWinString(
1851 dpy, flf, fws, &do_free, &len, &comb_chars, NULL);
1852 curr_str = fws->e_str;
1853 for(char_len = 0, i = 0 ;
1854 i < len && curr_str[i] != 0 ;
1855 char_len++, i += curr_len)
1857 curr_len = FlocaleStringNumberOfBytes(flf, curr_str + i);
1860 /* for superimposition calculate the character positions in pixels */
1861 if (comb_chars != NULL && (
1862 comb_chars[0].c.byte1 != 0 || comb_chars[0].c.byte2 != 0))
1864 /* the second condition is actually redundant,
1865 but there for clarity,
1866 ending at 0 is what's expected in a correct
1867 string */
1868 pixel_pos = (int *)safemalloc(
1869 (char_len != 0 ? char_len : 1) * sizeof(int));
1871 /* if there is 0 bytes in the encoded string, there might
1872 still be combining character to draw (at position 0) */
1873 if(char_len == 0)
1875 pixel_pos[0] = 0;
1878 for(
1879 i = 0, curr_pixel_pos = 0 ;
1880 i < char_len ;
1881 i++, curr_str += curr_len)
1883 curr_len = FlocaleStringNumberOfBytes(flf, curr_str);
1884 for (j = 0 ; j < curr_len ; j++)
1886 buf[j] = curr_str[j];
1888 buf[j] = 0;
1889 pixel_pos[i] = curr_pixel_pos;
1890 /* need to compensate for shadow width (if any) */
1891 curr_pixel_pos +=
1892 FlocaleTextWidth(flf, buf, curr_len) -
1893 FLF_SHADOW_WIDTH(flf);
1897 /* get the pixels */
1898 if (fws->flags.has_colorset)
1900 fg = fws->colorset->fg;
1901 fgsh = fws->colorset->fgsh;
1902 has_fg_pixels = True;
1904 else if (flf->shadow_size != 0)
1906 XGCValues xgcv;
1908 if (XGetGCValues(dpy, fws->gc, GCForeground, &xgcv) != 0)
1910 fg = xgcv.foreground;
1912 else
1914 fg = PictureBlackPixel();
1916 fgsh = GetShadow(fg);
1917 has_fg_pixels = True;
1920 if(flf->font != None &&
1921 (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb))
1923 /* in this case, length is number of 2-byte chars */
1924 len = char_len;
1927 if (fws->flags.text_rotation != ROTATION_0 &&
1928 flf->fftf.fftfont == NULL)
1930 /* pass in information to perform superimposition */
1931 FlocaleRotateDrawString(
1932 dpy, flf, fws, fg, fgsh, has_fg_pixels, len,
1933 comb_chars, pixel_pos);
1935 else if (FftSupport && flf->fftf.fftfont != NULL)
1937 FftDrawString(
1938 dpy, flf, fws, fg, fgsh, has_fg_pixels, len, flags);
1940 else if (flf->fontset != None)
1942 int xt = fws->x;
1943 int yt = fws->y;
1945 FlocaleInitGstpArgs(&gstp_args, flf, fws, fws->x, fws->y);
1946 if (flf->shadow_size != 0)
1948 XSetForeground(dpy, fws->gc, fgsh);
1949 while (FlocaleGetShadowTextPosition(
1950 &xt, &yt, &gstp_args))
1952 XmbDrawString(
1953 dpy, fws->win, flf->fontset, fws->gc,
1954 xt, yt, fws->e_str, len);
1957 if (has_fg_pixels == True)
1959 XSetForeground(dpy, fws->gc, fg);
1961 xt = gstp_args.orig_x;
1962 yt = gstp_args.orig_y;
1963 XmbDrawString(
1964 dpy, fws->win, flf->fontset, fws->gc,
1965 xt, yt, fws->e_str, len);
1967 else if (flf->font != None)
1969 FlocaleFontStructDrawString(
1970 dpy, flf, fws->win, fws->gc, fws->x, fws->y,
1971 fg, fgsh, has_fg_pixels, fws, len, False);
1974 /* here take care of superimposing chars */
1975 i = 0;
1976 if (comb_chars != NULL)
1978 while(comb_chars[i].c.byte1 != 0 && comb_chars[i].c.byte2 != 0)
1980 /* draw composing character on top of corresponding
1981 "real" character */
1982 FlocaleWinString tmp_fws = *fws;
1983 int offset = pixel_pos[comb_chars[i].position];
1984 char *buf2;
1985 int out_len;
1986 curr_len = FlocaleChar2bOneCharToUtf8(comb_chars[i].c,
1987 buf);
1988 buf2 = FiconvUtf8ToCharset(
1989 dpy, flf->str_fc, (const char *)buf, curr_len);
1990 if(buf2 == NULL)
1992 /* if conversion failed, combinational char
1993 is not representable in current charset */
1994 /* just replace with empty string */
1995 buf2 = (char *)safemalloc(sizeof(char));
1996 buf2[0] = 0;
1998 tmp_fws.e_str = buf2;
1999 tmp_fws.str2b = NULL;
2000 if(FftSupport && flf->fftf.fftfont != NULL)
2002 tmp_fws.x = fws->x + offset;
2003 FftDrawString(
2004 dpy, flf, &tmp_fws, fg, fgsh,
2005 has_fg_pixels, strlen(buf2),
2006 flags);
2008 else if(flf->fontset != None)
2010 int xt = fws->x;
2011 int yt = fws->y;
2013 FlocaleInitGstpArgs(
2014 &gstp_args, flf, fws, fws->x, fws->y);
2015 if (flf->shadow_size != 0)
2017 XSetForeground(dpy, fws->gc, fgsh);
2018 while (FlocaleGetShadowTextPosition(
2019 &xt, &yt, &gstp_args))
2021 XmbDrawString(
2022 dpy, fws->win,
2023 flf->fontset,
2024 fws->gc,
2025 xt, yt,
2026 buf2,
2027 strlen(buf2));
2030 XSetForeground(dpy, fws->gc, fg);
2031 xt = gstp_args.orig_x;
2032 yt = gstp_args.orig_y;
2033 XmbDrawString(
2034 dpy, fws->win, flf->fontset, fws->gc,
2035 xt + offset, yt, buf2, strlen(buf2));
2037 else if (flf->font != None)
2039 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
2041 tmp_fws.str2b = (XChar2b *)
2042 safemalloc(2 * sizeof(XChar2b));
2043 tmp_fws.str2b[0] = comb_chars[i].c;
2044 tmp_fws.str2b[1].byte1 = 0;
2045 tmp_fws.str2b[1].byte2 = 0;
2046 out_len = 1;
2047 /*tmp_fws.str2b =
2048 FlocaleUtf8ToUnicodeStr2b(
2049 tmp_fws.e_str,
2050 curr_len, &out_len);*/
2052 else if (flf->flags.is_mb)
2054 tmp_fws.str2b =
2055 FlocaleStringToString2b(
2056 dpy, flf,
2057 tmp_fws.e_str,
2058 curr_len, &out_len);
2060 else
2062 out_len = strlen(buf2);
2064 FlocaleFontStructDrawString(
2065 dpy, flf, fws->win, fws->gc,
2066 fws->x + offset, fws->y, fg, fgsh,
2067 has_fg_pixels, &tmp_fws, out_len,
2068 False);
2071 free(buf2);
2072 if(tmp_fws.str2b != NULL)
2074 free(tmp_fws.str2b);
2076 i++;
2080 if (do_free)
2082 if (fws->e_str != NULL)
2084 free(fws->e_str);
2085 fws->e_str = NULL;
2089 if (fws->str2b != NULL)
2091 free(fws->str2b);
2092 fws->str2b = NULL;
2095 if(comb_chars != NULL)
2097 free(comb_chars);
2098 if(pixel_pos)
2099 free(pixel_pos);
2102 return;
2105 void FlocaleDrawUnderline(
2106 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, int offset)
2108 int off1, off2, y, x_s, x_e;
2109 superimpose_char_t *comb_chars = NULL;
2110 int *l_to_v = NULL;
2111 Bool do_free = True;
2112 int len = strlen(fws->str);
2113 int l_coffset;
2114 int v_coffset;
2115 int voffset;
2117 if (fws == NULL || fws->str == NULL)
2119 return;
2122 /* need to encode the string first to get BIDI and combining chars */
2123 FlocaleEncodeWinString(dpy, flf, fws, &do_free, &len, &comb_chars,
2124 &l_to_v);
2125 /* we don't need this, only interested in char mapping */
2126 free(comb_chars);
2128 /* now calculate char offset (in bytes) in visual string corresponding
2129 to coffset */
2130 /* calculate absolute position in string (in characters) */
2131 l_coffset = FlocaleStringByteToCharOffset(flf, fws->str, offset);
2132 /* map to an offset in the visual string */
2133 v_coffset = l_to_v[l_coffset];
2134 /* calculate byte offset into visual string */
2135 voffset = FlocaleStringCharToByteOffset(flf, fws->e_str, v_coffset);
2137 off1 = FlocaleTextWidth(flf, fws->e_str, voffset) +
2138 ((voffset == 0)?
2139 FLF_SHADOW_LEFT_SIZE(flf) : - FLF_SHADOW_RIGHT_SIZE(flf) );
2140 off2 = FlocaleTextWidth(flf, fws->e_str + voffset,
2141 FlocaleStringNumberOfBytes(flf, fws->e_str + voffset)) -
2142 FLF_SHADOW_WIDTH(flf) - 1 + off1;
2143 y = fws->y + 2;
2144 x_s = fws->x + off1;
2145 x_e = fws->x + off2;
2147 /* No shadow */
2148 XDrawLine(dpy, fws->win, fws->gc, x_s, y, x_e, y);
2150 /* free encoded string if it isn't the same as input string */
2151 if(fws->e_str != fws->str)
2153 free(fws->e_str);
2154 fws->e_str = NULL;
2157 if(fws->str2b != NULL)
2159 free(fws->str2b);
2160 fws->str2b = NULL;
2162 free(l_to_v);
2164 return;
2167 int FlocaleTextWidth(FlocaleFont *flf, char *str, int sl)
2169 int result = 0;
2170 char *tmp_str;
2171 int new_l,do_free;
2172 superimpose_char_t *comb_chars = NULL;
2174 if (!str || sl == 0)
2175 return 0;
2177 if (sl < 0)
2179 /* a vertical string: nothing to do! */
2180 sl = -sl;
2183 /* FIXME */
2184 /* to avoid eccesive calls iconv (slow in Solaris 8)
2185 don't bother to encode if string is one byte
2186 when drawing a string this function is used to calculate
2187 position of each character (for superimposition) */
2188 if(sl == 1)
2190 tmp_str = str;
2191 new_l = sl;
2192 do_free = False;
2194 else
2196 tmp_str = FlocaleEncodeString(
2197 Pdpy, flf, str, &do_free, sl, &new_l, NULL,
2198 &comb_chars, NULL);
2200 /* if we get zero-length, check to to see if there if there's any
2201 combining chars, if so use an imagninary space as a
2202 "base character" */
2203 if (strlen(tmp_str) == 0 && comb_chars &&
2204 (comb_chars[0].c.byte1 != 0 || comb_chars[0].c.byte2 != 0))
2206 if(do_free)
2208 free(tmp_str);
2210 if(comb_chars)
2212 free(comb_chars);
2214 return FlocaleTextWidth(flf, " ", 1);
2216 else if (FftSupport && flf->fftf.fftfont != NULL)
2218 result = FftTextWidth(flf, tmp_str, new_l);
2220 else if (flf->fontset != None)
2222 result = XmbTextEscapement(flf->fontset, tmp_str, new_l);
2224 else if (flf->font != None)
2226 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb)
2228 XChar2b *str2b;
2229 int nl;
2231 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
2232 str2b = FlocaleUtf8ToUnicodeStr2b(
2233 tmp_str, new_l, &nl);
2234 else
2235 str2b = FlocaleStringToString2b(
2236 Pdpy, flf, tmp_str, new_l, &nl);
2237 if (str2b != NULL)
2239 result = XTextWidth16(flf->font, str2b, nl);
2240 free(str2b);
2243 else
2245 result = XTextWidth(flf->font, tmp_str, new_l);
2248 if (do_free)
2250 free(tmp_str);
2252 if (comb_chars)
2254 free(comb_chars);
2257 return result + ((result != 0)? FLF_SHADOW_WIDTH(flf):0);
2260 int FlocaleGetMinOffset(
2261 FlocaleFont *flf, rotation_t rotation)
2263 int min_offset;
2265 #ifdef FFT_BUGGY_FREETYPE
2266 switch(rotation)
2268 case ROTATION_270:
2269 case ROTATION_180:
2270 /* better than descent */
2271 min_offset = (flf->descent + flf->height - flf->ascent)/2;
2272 break;
2273 case ROTATION_0:
2274 case ROTATION_90:
2275 default:
2276 /* better than ascent */
2277 min_offset = (flf->ascent + flf->height - flf->descent)/2;
2278 break;
2280 #else
2281 switch(rotation)
2283 case ROTATION_180:
2284 case ROTATION_90:
2285 /* better than descent */
2286 min_offset = (flf->descent + flf->height - flf->ascent)/2;
2287 break;
2288 case ROTATION_270:
2289 case ROTATION_0:
2290 default:
2291 /* better than ascent */
2292 min_offset = (flf->ascent + flf->height - flf->descent)/2;
2293 break;
2295 #endif
2296 return min_offset;
2299 void FlocaleAllocateWinString(FlocaleWinString **pfws)
2301 *pfws = (FlocaleWinString *)safemalloc(sizeof(FlocaleWinString));
2302 memset(*pfws, '\0', sizeof(FlocaleWinString));
2306 * Text properties
2308 void FlocaleGetNameProperty(
2309 Status (func)(Display *, Window, XTextProperty *), Display *dpy,
2310 Window w, FlocaleNameString *ret_name)
2312 char **list;
2313 int num;
2314 XTextProperty text_prop;
2316 list = NULL;
2317 if (func(dpy, w, &text_prop) == 0)
2319 return;
2321 if (text_prop.encoding == XA_STRING)
2323 /* STRING encoding, use this as it is */
2324 ret_name->name = (char *)text_prop.value;
2325 ret_name->name_list = NULL;
2326 return;
2328 /* not STRING encoding, try to convert XA_COMPOUND_TEXT */
2329 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success
2330 && num > 0 && *list)
2332 /* Does not consider the conversion is REALLY succeeded:
2333 * XmbTextPropertyToTextList return 0 (== Success) on success,
2334 * a negative int if it fails (and in this case we are not
2335 * here), the number of unconvertible char on "partial"
2336 * success*/
2337 XFree(text_prop.value); /* return of XGetWM(Icon)Name() */
2338 ret_name->name = *list;
2339 ret_name->name_list = list;
2341 else
2343 if (list)
2345 XFreeStringList(list);
2347 ret_name->name = (char *)text_prop.value;
2348 ret_name->name_list = NULL;
2352 void FlocaleFreeNameProperty(FlocaleNameString *ptext)
2354 if (ptext->name_list != NULL)
2356 if (ptext->name != NULL && ptext->name != *ptext->name_list)
2357 XFree(ptext->name);
2358 XFreeStringList(ptext->name_list);
2359 ptext->name_list = NULL;
2361 else if (ptext->name != NULL)
2363 XFree(ptext->name);
2365 ptext->name = NULL;
2367 return;
2370 Bool FlocaleTextListToTextProperty(
2371 Display *dpy, char **list, int count, XICCEncodingStyle style,
2372 XTextProperty *text_prop_return)
2374 int ret = False;
2376 if (Flocale != NULL)
2378 ret = XmbTextListToTextProperty(
2379 dpy, list, count, style, text_prop_return);
2380 if (ret == XNoMemory)
2382 ret = False;
2384 else
2386 /* ret == Success or the number of unconvertible
2387 * characters. ret should be != XLocaleNotSupported
2388 * because in this case Flocale == NULL */
2389 ret = True;
2392 if (!ret)
2394 if (XStringListToTextProperty(
2395 list, count, text_prop_return) == 0)
2397 ret = False;
2399 else
2401 ret = True;
2405 return ret;
2409 * Info
2411 void FlocalePrintLocaleInfo(Display *dpy, int verbose)
2413 FlocaleFont *flf = FlocaleFontList;
2414 int count = 0;
2415 FlocaleCharset *cs;
2417 fflush(stderr);
2418 fflush(stdout);
2419 fprintf(stderr,"fvwm info on locale:\n");
2420 fprintf(stderr," locale: %s, Modifier: %s\n",
2421 (Flocale)? Flocale:"", (Fmodifiers)? Fmodifiers:"");
2422 cs = FlocaleCharsetGetDefaultCharset(dpy, NULL);
2423 fprintf(stderr," Default Charset: X: %s, Iconv: %s, Bidi: %s\n",
2424 cs->x,
2425 (cs->iconv_index >= 0)?
2426 cs->locale[cs->iconv_index]:"Not defined",
2427 (cs->bidi)? "Yes":"No");
2428 FlocaleCharsetPrintXOMInfo();
2429 while (flf)
2431 count++;
2432 flf = flf->next;
2434 fprintf(stderr," Number of loaded font: %i\n", count);
2435 if (verbose)
2437 count = 0;
2438 flf = FlocaleFontList;
2439 while(flf)
2441 cs = flf->fc;
2442 fprintf(stderr," * Font number %i\n", count);
2443 fprintf(stderr," fvwm info:\n");
2444 fprintf(stderr," Name: %s\n",
2445 (flf->name)? flf->name:"");
2446 fprintf(stderr," Cache count: %i\n", flf->count);
2447 fprintf(stderr," Type: ");
2448 if (flf->font)
2450 fprintf(stderr,"FontStruct\n");
2452 else if (flf->fontset)
2454 fprintf(stderr,"FontSet\n");
2456 else
2458 fprintf(stderr,"XftFont\n");
2460 fprintf(stderr, " Charset: X: %s, Iconv: %s, "
2461 "Bidi: %s\n",
2462 cs->x,
2463 (cs->iconv_index >= 0)?
2464 cs->locale[cs->iconv_index]:"Not defined",
2465 (cs->bidi)? "Yes":"No");
2466 fprintf(stderr," height: %i, ascent: %i, "
2467 "descent: %i\n", flf->height, flf->ascent,
2468 flf->descent);
2469 fprintf(stderr," shadow size: %i, "
2470 "shadow offset: %i, shadow direction:%i\n",
2471 flf->shadow_size, flf->shadow_offset,
2472 flf->flags.shadow_dir);
2473 if (verbose >= 2)
2475 if (flf->fftf.fftfont != NULL)
2477 FftFontType *fftf;
2479 fftf = &flf->fftf;
2480 fprintf(stderr, " Xft info:\n"
2481 " - Vertical font:");
2482 FftPrintPatternInfo(
2483 fftf->fftfont, False);
2484 fprintf(stderr, " "
2485 "- Rotated font 90:");
2486 if (fftf->fftfont_rotated_90)
2487 FftPrintPatternInfo(
2488 fftf->
2489 fftfont_rotated_90,
2490 True);
2491 else
2492 fprintf(stderr, " None\n");
2493 fprintf(stderr, " "
2494 "- Rotated font 270:");
2495 if (fftf->fftfont_rotated_270)
2496 FftPrintPatternInfo(
2497 fftf->
2498 fftfont_rotated_270,
2499 True);
2500 else
2501 fprintf(stderr, " None\n");
2502 fprintf(stderr, " "
2503 "- Rotated font 180:");
2504 if (fftf->fftfont_rotated_180)
2505 FftPrintPatternInfo(
2506 fftf->
2507 fftfont_rotated_180,
2508 True);
2509 else
2510 fprintf(stderr, " None\n");
2512 else if (flf->font != NULL)
2514 char *full_name;
2516 full_name =
2517 FlocaleGetFullNameOfFontStruct(
2518 dpy, flf->font);
2519 fprintf(stderr, " X info:\n"
2520 " %s\n",
2521 (full_name)? full_name:"?");
2522 if (full_name != NULL)
2524 XFree(full_name);
2527 else if (flf->fontset != NULL)
2529 int n,i;
2530 XFontStruct **font_struct_list;
2531 char **font_name_list;
2533 fprintf(stderr, " X info:\n");
2534 n = XFontsOfFontSet(
2535 flf->fontset,
2536 &font_struct_list,
2537 &font_name_list);
2538 for(i = 0; i < n; i++)
2540 fprintf(stderr,
2541 " %s\n",
2542 font_name_list[i]);
2546 count++;
2547 flf = flf->next;