Refactor counting of windows with IndexedWindowName, and IndexedIconName
[fvwm.git] / libs / Flocale.c
blobb30a18c335b3346972c6d0320a1524ed5f6b7d61
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 if (is_rtl != NULL)
437 *is_rtl = False;
438 *do_free = False;
439 *nl = len;
441 if (flf->str_fc == NULL || flf->fc == NULL ||
442 flf->fc == flf->str_fc)
444 do_iconv = False;
447 str1 = str;
448 if (FiconvSupport)
450 char *tmp_str;
452 /* first process combining characters */
453 tmp_str = FiconvCharsetToUtf8(
454 dpy, flf->str_fc, (const char *)str,len);
455 /* if conversion to UTF-8 failed str1 will be NULL */
456 if(tmp_str != NULL)
458 /* do combining */
459 len = CombineChars((unsigned char *)tmp_str,
460 strlen(tmp_str), comb_chars,
461 l_to_v);
462 /* returns the length of the resulting UTF-8 string */
463 /* convert back to current charset */
464 str1 = FiconvUtf8ToCharset(
465 dpy, flf->str_fc, (const char *)tmp_str,len);
466 if (tmp_str != str1)
468 free(tmp_str);
470 if (str1)
472 *nl = len = strlen(str1);
473 *do_free = True;
475 else
477 /* convert back to current charset fail */
478 len = strlen(str);
479 str1 = str;
484 if (FiconvSupport && do_iconv)
486 str2 = FiconvCharsetToCharset(
487 dpy, flf->str_fc, flf->fc, (const char *)str1, len);
488 if (str2 == NULL)
490 /* fail to convert */
491 return str1;
493 if (str2 != str1)
495 if (*do_free && str1)
497 free(str1);
498 str1 = str2;
500 *do_free = True;
501 len1 = strlen(str2);
504 else
506 str2 = str1;
507 len1 = len;
508 /* initialise array with composing characters (empty) */
509 if(comb_chars != NULL && *comb_chars == NULL)
511 *comb_chars = (superimpose_char_t *)
512 safemalloc(sizeof(superimpose_char_t));
513 (*comb_chars)[0].position = -1;
514 (*comb_chars)[0].c.byte1 = 0;
515 (*comb_chars)[0].c.byte2 = 0;
518 /* initialise logic to visual mapping here if that is demanded
519 (this is default when no combining has been done (1-to-1))
521 if(l_to_v != NULL && *l_to_v == NULL)
523 *l_to_v = (int*)safemalloc((len + 1) * sizeof(int));
524 for(i = 0 ; i < len ; i++)
525 (*l_to_v)[i] = i;
526 (*l_to_v)[len] = -1;
530 if (FlocaleGetBidiCharset(dpy, flf->str_fc) != NULL &&
531 (bidi_charset = FlocaleGetBidiCharset(dpy, flf->fc)) != NULL)
533 str3 = FBidiConvert(str2, bidi_charset, len1,
534 is_rtl, &len2,
535 comb_chars != NULL ? *comb_chars : NULL,
536 l_to_v != NULL ? *l_to_v : NULL);
537 if (str3 != NULL && str3 != str2)
539 if (*do_free)
541 free(str2);
543 *do_free = True;
544 len1 = len2;
545 str1 = str3;
547 /* if we failed to do BIDI convert, return string string from
548 combining phase */
549 else
551 str1 = str2;
552 /* we already have the logical to visual mapping
553 from combining phase */
557 *nl = len1;
558 return str1;
561 static
562 void FlocaleEncodeWinString(
563 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, int *do_free,
564 int *len, superimpose_char_t **comb_chars, int **l_to_v)
566 int len2b;
567 fws->e_str = FlocaleEncodeString(
568 dpy, flf, fws->str, do_free, *len, len, NULL, comb_chars,
569 l_to_v);
570 fws->str2b = NULL;
572 if (flf->font != None)
574 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
576 fws->str2b = FlocaleUtf8ToUnicodeStr2b(
577 fws->e_str, *len, &len2b);
579 else if (flf->flags.is_mb)
581 fws->str2b = FlocaleStringToString2b(
582 dpy, flf, fws->e_str, *len, &len2b);
588 * Text Drawing with a FontStruct
591 static
592 void FlocaleFontStructDrawString(
593 Display *dpy, FlocaleFont *flf, Drawable d, GC gc, int x, int y,
594 Pixel fg, Pixel fgsh, Bool has_fg_pixels, FlocaleWinString *fws,
595 int len, Bool image)
597 int xt = x;
598 int yt = y;
599 int is_string16;
600 flocale_gstp_args gstp_args;
602 is_string16 = (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb);
603 if (is_string16 && fws->str2b == NULL)
605 return;
607 if (image)
609 /* for rotated drawing */
610 FSwitchDrawImageString(
611 is_string16, dpy, d, gc, x, y, fws->e_str, fws->str2b,
612 len);
614 else
616 FlocaleInitGstpArgs(&gstp_args, flf, fws, x, y);
617 /* normal drawing */
618 if (flf->shadow_size != 0 && has_fg_pixels == True)
620 XSetForeground(dpy, fws->gc, fgsh);
621 while (FlocaleGetShadowTextPosition(
622 &xt, &yt, &gstp_args))
624 FSwitchDrawString(
625 is_string16, dpy, d, gc, xt, yt,
626 fws->e_str, fws->str2b, len);
629 if (has_fg_pixels == True)
631 XSetForeground(dpy, gc, fg);
633 xt = gstp_args.orig_x;
634 yt = gstp_args.orig_y;
635 FSwitchDrawString(
636 is_string16, dpy, d, gc, xt,yt, fws->e_str, fws->str2b,
637 len);
640 return;
644 * Rotated Text Drawing with a FontStruct or a FontSet
646 static
647 void FlocaleRotateDrawString(
648 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, Pixel fg,
649 Pixel fgsh, Bool has_fg_pixels, int len,
650 superimpose_char_t *comb_chars, int *pixel_pos)
652 static GC my_gc = None;
653 static GC font_gc = None;
654 int j, i, xpfg, ypfg, xpsh, ypsh;
655 unsigned char *normal_data, *rotated_data;
656 unsigned int normal_w, normal_h, normal_len;
657 unsigned int rotated_w, rotated_h, rotated_len;
658 char val;
659 int width, height, descent, min_offset;
660 XImage *image, *rotated_image;
661 Pixmap canvas_pix, rotated_pix;
662 flocale_gstp_args gstp_args;
663 char buf[4];
665 if (fws->str == NULL || len < 1)
667 return;
669 if (fws->flags.text_rotation == ROTATION_0)
671 return; /* should not happen */
674 if (my_gc == None)
676 my_gc = fvwmlib_XCreateGC(dpy, fws->win, 0, NULL);
678 XCopyGC(dpy, fws->gc, GCForeground|GCBackground, my_gc);
680 /* width and height (no shadow!) */
681 width = FlocaleTextWidth(flf, fws->str, len) - FLF_SHADOW_WIDTH(flf);
682 height = flf->height - FLF_SHADOW_HEIGHT(flf);
683 descent = flf->descent - FLF_SHADOW_DESCENT(flf);;
685 if (width < 1)
686 width = 1;
687 if (height < 1)
688 height = 1;
690 /* glyph width and height of the normal text */
691 normal_w = width;
692 normal_h = height;
694 /* width in bytes */
695 normal_len = (normal_w - 1) / 8 + 1;
697 /* create and clear the canvas */
698 canvas_pix = XCreatePixmap(dpy, fws->win, width, height, 1);
699 if (font_gc == None)
701 font_gc = fvwmlib_XCreateGC(dpy, canvas_pix, 0, NULL);
703 XSetBackground(dpy, font_gc, 0);
704 XSetForeground(dpy, font_gc, 0);
705 XFillRectangle(dpy, canvas_pix, font_gc, 0, 0, width, height);
707 /* draw the character center top right on canvas */
708 XSetForeground(dpy, font_gc, 1);
709 if (flf->font != NULL)
711 XSetFont(dpy, font_gc, flf->font->fid);
712 FlocaleFontStructDrawString(dpy, flf, canvas_pix, font_gc, 0,
713 height - descent,
714 fg, fgsh, has_fg_pixels,
715 fws, len, True);
717 else if (flf->fontset != None)
719 XmbDrawString(
720 dpy, canvas_pix, flf->fontset, font_gc, 0,
721 height - descent, fws->e_str, len);
724 /* here take care of superimposing chars */
725 i = 0;
726 if(comb_chars != NULL)
728 while(comb_chars[i].c.byte1 != 0 && comb_chars[i].c.byte2 != 0)
730 /* draw composing character on top of corresponding
731 "real" character */
732 FlocaleWinString tmp_fws = *fws;
733 int offset = pixel_pos[comb_chars[i].position];
734 int curr_len = FlocaleChar2bOneCharToUtf8(
735 comb_chars[i].c,
736 buf);
737 int out_len;
738 char *buf2 = FiconvUtf8ToCharset(
739 dpy,
740 flf->str_fc,
741 (const char *)buf,curr_len);
742 if(buf2 == NULL)
744 /* if conversion failed, combinational char
745 is not representable in current charset */
746 /* just replace with empty string */
747 buf2 = (char *)safemalloc(sizeof(char));
748 buf2[0] = 0;
750 tmp_fws.e_str = buf2;
751 tmp_fws.str2b = NULL;
752 if(flf->fontset != None)
754 XmbDrawString(dpy, canvas_pix, flf->fontset,
755 fws->gc, offset,
756 height - descent, buf2,
757 strlen(buf2));
759 else if(flf->font != None)
761 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
763 tmp_fws.str2b = (XChar2b *)
764 safemalloc(2 * sizeof(XChar2b));
765 tmp_fws.str2b[0] = comb_chars[i].c;
766 tmp_fws.str2b[1].byte1 = 0;
767 tmp_fws.str2b[1].byte2 = 0;
768 out_len = 1;
770 else if (flf->flags.is_mb)
772 tmp_fws.str2b =
773 FlocaleStringToString2b(
774 dpy, flf, tmp_fws.e_str,
775 curr_len, &out_len);
777 else
779 out_len = strlen(buf2);
781 XSetFont(dpy, font_gc, flf->font->fid);
782 FlocaleFontStructDrawString(
783 dpy, flf, canvas_pix, font_gc,
784 offset, height - descent,
785 fg, fgsh, has_fg_pixels, &tmp_fws,
786 out_len, True);
789 free(buf2);
790 if(tmp_fws.str2b != NULL)
792 free(tmp_fws.str2b);
794 i++;
798 /* reserve memory for the first XImage */
799 normal_data = (unsigned char *)safemalloc(normal_len * normal_h);
801 /* create depth 1 XImage */
802 if ((image = XCreateImage(
803 dpy, Pvisual, 1, XYBitmap, 0, (char *)normal_data,
804 normal_w, normal_h, 8, 0)) == NULL)
806 return;
808 image->byte_order = image->bitmap_bit_order = MSBFirst;
810 /* extract character from canvas */
811 XGetSubImage(
812 dpy, canvas_pix, 0, 0, normal_w, normal_h,
813 1, XYPixmap, image, 0, 0);
814 image->format = XYBitmap;
816 /* width, height of the rotated text */
817 if (fws->flags.text_rotation == ROTATION_180)
819 rotated_w = normal_w;
820 rotated_h = normal_h;
822 else /* vertical text */
824 rotated_w = normal_h;
825 rotated_h = normal_w;
828 /* width in bytes */
829 rotated_len = (rotated_w - 1) / 8 + 1;
831 /* reserve memory for the rotated image */
832 rotated_data = (unsigned char *)safecalloc(rotated_h * rotated_len, 1);
834 /* create the rotated X image */
835 if ((rotated_image = XCreateImage(
836 dpy, Pvisual, 1, XYBitmap, 0, (char *)rotated_data,
837 rotated_w, rotated_h, 8, 0)) == NULL)
839 return;
842 rotated_image->byte_order = rotated_image->bitmap_bit_order = MSBFirst;
844 /* map normal text data to rotated text data */
845 for (j = 0; j < rotated_h; j++)
847 for (i = 0; i < rotated_w; i++)
849 /* map bits ... */
850 if (fws->flags.text_rotation == ROTATION_270)
851 val = normal_data[
852 i * normal_len +
853 (normal_w - j - 1) / 8
854 ] & (128 >> ((normal_w - j - 1) % 8));
856 else if (fws->flags.text_rotation == ROTATION_180)
857 val = normal_data[
858 (normal_h - j - 1) * normal_len +
859 (normal_w - i - 1) / 8
860 ] & (128 >> ((normal_w - i - 1) % 8));
862 else /* ROTATION_90 */
863 val = normal_data[
864 (normal_h - i - 1) * normal_len +
865 j / 8] & (128 >> (j % 8));
867 if (val)
868 rotated_data[j * rotated_len + i / 8] |=
869 (128 >> (i % 8));
873 /* create the character's bitmap and put the image on it */
874 rotated_pix = XCreatePixmap(dpy, fws->win, rotated_w, rotated_h, 1);
875 XPutImage(
876 dpy, rotated_pix, font_gc, rotated_image, 0, 0, 0, 0,
877 rotated_w, rotated_h);
879 /* free the image and data */
880 XDestroyImage(image);
881 XDestroyImage(rotated_image);
883 /* free pixmap and GC */
884 XFreePixmap(dpy, canvas_pix);
886 /* x and y corrections: we fill a rectangle! */
887 min_offset = FlocaleGetMinOffset(flf, fws->flags.text_rotation);
888 switch (fws->flags.text_rotation)
890 case ROTATION_90:
891 /* CW */
892 xpfg = fws->x - min_offset;
893 ypfg = fws->y;
894 break;
895 case ROTATION_180:
896 xpfg = fws->x;
897 ypfg = fws->y - min_offset +
898 FLF_SHADOW_BOTTOM_SIZE(flf);
899 break;
900 case ROTATION_270:
901 /* CCW */
902 xpfg = fws->x - min_offset;
903 ypfg = fws->y;
904 break;
905 case ROTATION_0:
906 default:
907 xpfg = fws->x;
908 ypfg = fws->y - min_offset;
909 break;
911 xpsh = xpfg;
912 ypsh = ypfg;
913 /* write the image on the window */
914 XSetFillStyle(dpy, my_gc, FillStippled);
915 XSetStipple(dpy, my_gc, rotated_pix);
916 FlocaleInitGstpArgs(&gstp_args, flf, fws, xpfg, ypfg);
917 if (flf->shadow_size != 0 && has_fg_pixels == True)
919 XSetForeground(dpy, my_gc, fgsh);
920 while (FlocaleGetShadowTextPosition(&xpsh, &ypsh, &gstp_args))
922 XSetTSOrigin(dpy, my_gc, xpsh, ypsh);
923 XFillRectangle(
924 dpy, fws->win, my_gc, xpsh, ypsh, rotated_w,
925 rotated_h);
928 xpsh = gstp_args.orig_x;
929 ypsh = gstp_args.orig_y;
930 XSetTSOrigin(dpy, my_gc, xpsh, ypsh);
931 XFillRectangle(dpy, fws->win, my_gc, xpsh, ypsh, rotated_w, rotated_h);
932 XFreePixmap(dpy, rotated_pix);
934 return;
938 * Fonts info and checking
941 static
942 char *FlocaleGetFullNameOfFontStruct(Display *dpy, XFontStruct *font)
944 char *full_name = NULL;
945 unsigned long value;
947 if (XGetFontProperty(font, XA_FONT, &value))
949 full_name = XGetAtomName(dpy, value);
951 return full_name;
954 static
955 char *FlocaleGetCharsetOfFontStruct(Display *dpy, XFontStruct *font)
957 int i = 0;
958 int count = 0;
959 char *charset = NULL;
960 char *full_name;
962 full_name = FlocaleGetFullNameOfFontStruct(dpy, font);
963 if (full_name == NULL)
965 return NULL;
967 while(full_name[i] != '\0' && count < 13)
969 if (full_name[i] == '-')
971 count++;
973 i++;
976 if (count != 13)
978 return NULL;
980 CopyString(&charset, full_name+i);
981 XFree(full_name);
982 return charset;
985 static
986 char *FlocaleGetCharsetFromName(char *name)
988 int l,i,e;
989 char *charset;
991 l = strlen(name);
992 i = l-1;
993 while(i >= 0 && name[i] != '-')
995 i--;
997 if (i == 0 || i == l-1)
999 return NULL;
1001 i--;
1002 e = i;
1003 while(i >= 0 && name[i] != '-')
1005 i--;
1007 if (i <= 0 || e == i)
1009 return NULL;
1011 CopyString(&charset, name + i + 1);
1012 return charset;
1015 /* return NULL if it is not reasonable to load a FontSet.
1016 * Currently return name if it is reasonable to load a FontSet, but in the
1017 * future we may want to transform name for faster FontSet loading */
1018 static
1019 char *FlocaleFixNameForFontSet(Display *dpy, char *name, char *module)
1021 char *new_name;
1022 char *charset;
1023 XFontStruct *test_font = NULL;
1025 if (!name)
1027 return NULL;
1030 new_name = name;
1032 if (strchr(name, ','))
1034 /* tmp, do not handle "," separated list */
1035 return name;
1037 charset = FlocaleGetCharsetFromName(name);
1038 if (charset == NULL && !strchr(name, '*') && !strchr(name, '?'))
1040 /* probably a font alias! */
1041 if ((test_font = XLoadQueryFont(dpy, name)))
1043 charset = FlocaleGetCharsetOfFontStruct(dpy, test_font);
1044 XFreeFont(dpy, test_font);
1047 if (charset != NULL)
1049 if (!strchr(charset, '*') && !strchr(charset, '?') &&
1050 !FlocaleCharsetIsCharsetXLocale(dpy, charset, module))
1052 /* if the charset is fully specified and do not match
1053 * one of the X locale charset */
1054 new_name = NULL;
1055 #if 0
1056 fprintf(stderr,"[%s][FlocaleGetFontSet]: WARNING -- "
1057 "Use of a non X locale charset '%s' when "
1058 "loading font: %s\n",
1059 (module)? module:"fvwmlibs", charset, name);
1060 #endif
1062 free(charset);
1064 return new_name;
1068 * Fonts loading
1071 static
1072 FlocaleFont *FlocaleGetFftFont(
1073 Display *dpy, char *fontname, char *encoding, char *module)
1075 FftFontType *fftf = NULL;
1076 FlocaleFont *flf = NULL;
1077 char *fn, *hints = NULL;
1079 hints = GetQuotedString(fontname, &fn, "/", NULL, NULL, NULL);
1080 if (fn == NULL)
1082 fn = fft_fallback_font;
1084 else if (*fn == '\0')
1086 free(fn);
1087 fn = fft_fallback_font;
1089 fftf = FftGetFont(dpy, fn, module);
1090 if (fftf == NULL)
1092 if (fn != NULL && fn != fft_fallback_font)
1094 free(fn);
1096 return NULL;
1098 flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
1099 memset(flf, '\0', sizeof(FlocaleFont));
1100 flf->count = 1;
1101 flf->fftf = *fftf;
1102 FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
1103 FftGetFontHeights(
1104 &flf->fftf, &flf->height, &flf->ascent, &flf->descent);
1105 FftGetFontWidths(flf, &flf->max_char_width);
1106 free(fftf);
1107 if (fn != NULL && fn != fft_fallback_font)
1109 free(fn);
1112 return flf;
1115 static
1116 FlocaleFont *FlocaleGetFontSet(
1117 Display *dpy, char *fontname, char *encoding, char *module)
1119 static int mc_errors = 0;
1120 FlocaleFont *flf = NULL;
1121 XFontSet fontset = NULL;
1122 char **ml;
1123 int mc,i;
1124 char *ds;
1125 XFontSetExtents *fset_extents;
1126 char *fn, *hints = NULL, *fn_fixed = NULL;
1128 hints = GetQuotedString(fontname, &fn, "/", NULL, NULL, NULL);
1129 if (*fn == '\0')
1131 free(fn);
1132 fn = fn_fixed = mb_fallback_font;
1134 else if (!(fn_fixed = FlocaleFixNameForFontSet(dpy, fn, module)))
1136 if (fn != NULL && fn != mb_fallback_font)
1138 free(fn);
1140 return NULL;
1142 if (!(fontset = XCreateFontSet(dpy, fn_fixed, &ml, &mc, &ds)))
1144 if (fn_fixed && fn_fixed != fn)
1146 free(fn_fixed);
1148 if (fn != NULL && fn != mb_fallback_font)
1150 free(fn);
1152 return NULL;
1155 if (mc > 0)
1157 if (mc_errors <= FLOCALE_NUMBER_MISS_CSET_ERR_MSG)
1159 mc_errors++;
1160 fprintf(stderr,
1161 "[%s][FlocaleGetFontSet]: (%s)"
1162 " Missing font charsets:\n",
1163 (module)? module: "fvwmlibs", fontname);
1164 for (i = 0; i < mc; i++)
1166 fprintf(stderr, "%s", ml[i]);
1167 if (i < mc - 1)
1168 fprintf(stderr, ", ");
1170 fprintf(stderr, "\n");
1171 if (mc_errors == FLOCALE_NUMBER_MISS_CSET_ERR_MSG)
1173 fprintf(stderr,
1174 "[%s][FlocaleGetFontSet]: No more"
1175 " missing charset reportings\n",
1176 (module)? module: "fvwmlibs");
1179 XFreeStringList(ml);
1182 flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
1183 memset(flf, '\0', sizeof(FlocaleFont));
1184 flf->count = 1;
1185 flf->fontset = fontset;
1186 FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
1187 fset_extents = XExtentsOfFontSet(fontset);
1188 flf->height = fset_extents->max_ink_extent.height;
1189 flf->ascent = - fset_extents->max_ink_extent.y;
1190 flf->descent = fset_extents->max_ink_extent.height +
1191 fset_extents->max_ink_extent.y;
1192 flf->max_char_width = fset_extents->max_ink_extent.width;
1193 if (fn_fixed && fn_fixed != fn)
1195 free(fn_fixed);
1197 if (fn != NULL && fn != mb_fallback_font)
1199 free(fn);
1202 return flf;
1205 static
1206 FlocaleFont *FlocaleGetFont(
1207 Display *dpy, char *fontname, char *encoding, char *module)
1209 XFontStruct *font = NULL;
1210 FlocaleFont *flf;
1211 char *str,*fn,*tmp;
1212 char *hints = NULL;
1214 hints = GetQuotedString(fontname, &tmp, "/", NULL, NULL, NULL);
1215 str = GetQuotedString(tmp, &fn, ",", NULL, NULL, NULL);
1216 while (!font && fn)
1218 if (*fn == '\0')
1220 free(fn);
1221 fn = fallback_font;
1223 font = XLoadQueryFont(dpy, fn);
1224 if (fn != NULL && fn != fallback_font)
1226 free(fn);
1227 fn = NULL;
1229 if (!font && str && *str)
1231 str = GetQuotedString(str, &fn, ",", NULL, NULL, NULL);
1234 if (font == NULL)
1236 if (fn != NULL && fn != fallback_font)
1238 free(fn);
1240 if (tmp != NULL)
1242 free(tmp);
1244 return NULL;
1247 flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
1248 memset(flf, '\0', sizeof(FlocaleFont));
1249 flf->count = 1;
1250 flf->fontset = None;
1251 flf->fftf.fftfont = NULL;
1252 flf->font = font;
1253 FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
1254 flf->height = font->max_bounds.ascent + font->max_bounds.descent;
1255 flf->ascent = font->max_bounds.ascent;
1256 flf->descent = font->max_bounds.descent;
1257 flf->max_char_width = font->max_bounds.width;
1258 if (flf->font->max_byte1 > 0)
1259 flf->flags.is_mb = True;
1260 if (fn != NULL && fn != fallback_font)
1262 free(fn);
1264 if (tmp != NULL)
1266 free(tmp);
1269 return flf;
1272 static
1273 FlocaleFont *FlocaleGetFontOrFontSet(
1274 Display *dpy, char *fontname, char *encoding, char *fullname,
1275 char *module)
1277 FlocaleFont *flf = NULL;
1279 if (fontname && strlen(fontname) > 3 &&
1280 strncasecmp("xft:", fontname, 4) == 0)
1282 if (FftSupport)
1284 flf = FlocaleGetFftFont(
1285 dpy, fontname+4, encoding, module);
1287 if (flf)
1289 CopyString(&flf->name, fullname);
1291 return flf;
1293 if (flf == NULL && Flocale != NULL && fontname)
1295 flf = FlocaleGetFontSet(dpy, fontname, encoding, module);
1297 if (flf == NULL && fontname)
1299 flf = FlocaleGetFont(dpy, fontname, encoding, module);
1301 if (flf && fontname)
1303 if (StrEquals(fullname, mb_fallback_font))
1305 flf->name = mb_fallback_font;
1307 else if (StrEquals(fullname, fallback_font))
1309 flf->name = fallback_font;
1311 else
1313 CopyString(&flf->name, fullname);
1315 return flf;
1317 return NULL;
1321 * locale local functions
1324 static
1325 void FlocaleSetlocaleForX(
1326 int category, const char *locale, const char *module)
1328 if ((Flocale = setlocale(category, locale)) == NULL)
1330 fprintf(stderr,
1331 "[%s][%s]: ERROR -- Cannot set locale. Please check"
1332 " your $LC_CTYPE or $LANG.\n",
1333 (module == NULL)? "" : module, "FlocaleSetlocaleForX");
1334 return;
1336 if (!XSupportsLocale())
1338 fprintf(stderr,
1339 "[%s][%s]: WARNING -- X does not support locale %s\n",
1340 (module == NULL)? "": module, "FlocaleSetlocaleForX",
1341 Flocale);
1342 Flocale = NULL;
1346 /* ---------------------------- interface functions ------------------------ */
1349 * locale initialisation
1352 void FlocaleInit(
1353 int category, const char *locale, const char *modifiers,
1354 const char *module)
1357 FlocaleSetlocaleForX(category, locale, module);
1358 if (Flocale == NULL)
1359 return;
1361 if (modifiers != NULL &&
1362 (Fmodifiers = XSetLocaleModifiers(modifiers)) == NULL)
1364 fprintf(stderr,
1365 "[%s][%s]: WARNING -- Cannot set locale modifiers\n",
1366 (module == NULL)? "": module, "FlocaleInit");
1368 #if FLOCALE_DEBUG_SETLOCALE
1369 fprintf(stderr,"[%s][FlocaleInit] locale: %s, modifier: %s\n",
1370 module, Flocale, Fmodifiers);
1371 #endif
1375 * fonts loading
1377 char *prefix_list[] =
1379 "Shadow=",
1380 "StringEncoding=",
1381 NULL
1384 FlocaleFont *FlocaleLoadFont(Display *dpy, char *fontname, char *module)
1386 FlocaleFont *flf = FlocaleFontList;
1387 Bool ask_default = False;
1388 char *t;
1389 char *str, *opt_str, *encoding= NULL, *fn = NULL;
1390 int shadow_size = 0;
1391 int shadow_offset = 0;
1392 int shadow_dir = MULTI_DIR_SE;
1393 int i;
1395 /* removing quoting for modules */
1396 if (fontname && (t = strchr("\"'`", *fontname)))
1398 char c = *t;
1399 fontname++;
1400 if (fontname[strlen(fontname)-1] == c)
1401 fontname[strlen(fontname)-1] = 0;
1404 if (fontname == NULL || *fontname == 0)
1406 ask_default = True;
1407 fontname = mb_fallback_font;
1410 while (flf)
1412 char *c1, *c2;
1414 for (c1 = fontname, c2 = flf->name; *c1 && *c2; ++c1, ++c2)
1416 if (*c1 != *c2)
1418 break;
1421 if (!*c1 && !*c2)
1423 flf->count++;
1424 return flf;
1426 flf = flf->next;
1429 /* not cached load the font as a ";" separated list */
1431 /* But first see if we have a shadow relief and/or an encoding */
1432 str = fontname;
1433 while ((i = GetTokenIndex(str, prefix_list, -1, &str)) > -1)
1435 str = GetQuotedString(str, &opt_str, ":", NULL, NULL, NULL);
1436 switch(i)
1438 case 0: /* shadow= */
1439 FlocaleParseShadow(
1440 opt_str, &shadow_size, &shadow_offset,
1441 &shadow_dir, fontname, module);
1442 break;
1443 case 1: /* encoding= */
1444 if (encoding != NULL)
1446 free(encoding);
1447 encoding = NULL;
1449 if (opt_str && *opt_str)
1451 CopyString(&encoding, opt_str);
1453 break;
1454 default:
1455 break;
1457 if (opt_str != NULL)
1458 free(opt_str);
1460 if (str && *str)
1462 str = GetQuotedString(str, &fn, ";", NULL, NULL, NULL);
1464 else
1466 fn = mb_fallback_font;
1468 while (!flf && (fn && *fn))
1470 flf = FlocaleGetFontOrFontSet(
1471 dpy, fn, encoding, fontname, module);
1472 if (fn != NULL && fn != mb_fallback_font &&
1473 fn != fallback_font)
1475 free(fn);
1476 fn = NULL;
1478 if (!flf && str && *str)
1480 str = GetQuotedString(str, &fn, ";", NULL, NULL, NULL);
1483 if (fn != NULL && fn != mb_fallback_font &&
1484 fn != fallback_font)
1486 free(fn);
1489 if (flf == NULL)
1491 /* loading failed, try default font */
1492 if (!ask_default)
1494 fprintf(stderr,"[%s][FlocaleLoadFont]: "
1495 "WARNING -- can't load font '%s',"
1496 " trying default:\n",
1497 (module)? module: "fvwmlibs", fontname);
1499 else
1501 /* we already tried default fonts: try again? yes */
1503 if (Flocale != NULL)
1505 if (!ask_default)
1507 fprintf(stderr, "\t%s\n",
1508 mb_fallback_font);
1510 if ((flf = FlocaleGetFontSet(
1511 dpy, mb_fallback_font, NULL,
1512 module)) != NULL)
1514 flf->name = mb_fallback_font;
1517 if (flf == NULL)
1519 if (!ask_default)
1521 fprintf(stderr,"\t%s\n",
1522 fallback_font);
1524 if ((flf =
1525 FlocaleGetFont(
1526 dpy, fallback_font, NULL,
1527 module)) != NULL)
1529 flf->name = fallback_font;
1531 else if (!ask_default)
1533 fprintf(stderr,
1534 "[%s][FlocaleLoadFont]:"
1535 " ERROR -- can't load font.\n",
1536 (module)? module: "fvwmlibs");
1538 else
1540 fprintf(stderr,
1541 "[%s][FlocaleLoadFont]: ERROR"
1542 " -- can't load default font:\n",
1543 (module)? module: "fvwmlibs");
1544 fprintf(stderr, "\t%s\n",
1545 mb_fallback_font);
1546 fprintf(stderr, "\t%s\n",
1547 fallback_font);
1552 if (flf != NULL)
1554 if (shadow_size > 0)
1556 flf->shadow_size = shadow_size;
1557 flf->flags.shadow_dir = shadow_dir;
1558 flf->shadow_offset = shadow_offset;
1559 flf->descent += FLF_SHADOW_DESCENT(flf);
1560 flf->ascent += FLF_SHADOW_ASCENT(flf);
1561 flf->height += FLF_SHADOW_HEIGHT(flf);
1562 flf->max_char_width += FLF_SHADOW_WIDTH(flf);
1564 if (flf->fc == FlocaleCharsetGetUnknownCharset())
1566 fprintf(stderr,"[%s][FlocaleLoadFont]: "
1567 "WARNING -- Unknown charset for font\n\t'%s'\n",
1568 (module)? module: "fvwmlibs", flf->name);
1569 flf->fc = FlocaleCharsetGetDefaultCharset(dpy, module);
1571 else if (flf->str_fc == FlocaleCharsetGetUnknownCharset() &&
1572 (encoding != NULL ||
1573 (FftSupport && flf->fftf.fftfont != NULL &&
1574 flf->fftf.str_encoding != NULL)))
1576 fprintf(stderr,"[%s][FlocaleLoadFont]: "
1577 "WARNING -- Unknown string encoding for font\n"
1578 "\t'%s'\n",
1579 (module)? module: "fvwmlibs", flf->name);
1581 if (flf->str_fc == FlocaleCharsetGetUnknownCharset())
1583 flf->str_fc =
1584 FlocaleCharsetGetDefaultCharset(dpy, module);
1586 flf->next = FlocaleFontList;
1587 FlocaleFontList = flf;
1589 if (encoding != NULL)
1591 free(encoding);
1594 return flf;
1597 void FlocaleUnloadFont(Display *dpy, FlocaleFont *flf)
1599 FlocaleFont *list = FlocaleFontList;
1600 int i = 0;
1602 if (!flf)
1604 return;
1606 /* Remove a weight, still too heavy? */
1607 if (--(flf->count) > 0)
1609 return;
1612 if (flf->name != NULL &&
1613 !StrEquals(flf->name, mb_fallback_font) &&
1614 !StrEquals(flf->name, fallback_font))
1616 free(flf->name);
1618 if (FftSupport && flf->fftf.fftfont != NULL)
1620 FftFontClose(dpy, flf->fftf.fftfont);
1621 if (flf->fftf.fftfont_rotated_90 != NULL)
1622 FftFontClose(dpy, flf->fftf.fftfont_rotated_90);
1623 if (flf->fftf.fftfont_rotated_180 != NULL)
1624 FftFontClose(dpy, flf->fftf.fftfont_rotated_180);
1625 if (flf->fftf.fftfont_rotated_270 != NULL)
1626 FftFontClose(dpy, flf->fftf.fftfont_rotated_270);
1628 if (flf->fontset != NULL)
1630 XFreeFontSet(dpy, flf->fontset);
1632 if (flf->font != NULL)
1634 XFreeFont(dpy, flf->font);
1636 if (flf->flags.must_free_fc)
1638 if (flf->fc->x)
1639 free(flf->fc->x);
1640 if (flf->fc->bidi)
1641 free(flf->fc->bidi);
1642 if (flf->fc->locale != NULL)
1644 while (FLC_GET_LOCALE_CHARSET(flf->fc,i) != NULL)
1646 free(FLC_GET_LOCALE_CHARSET(flf->fc,i));
1647 i++;
1649 free(flf->fc->locale);
1651 free(flf->fc);
1654 /* Link it out of the list (it might not be there) */
1655 if (flf == list) /* in head? simple */
1657 FlocaleFontList = flf->next;
1659 else
1661 while (list && list->next != flf)
1663 /* fast forward until end or found */
1664 list = list->next;
1666 /* not end? means we found it in there, possibly at end */
1667 if (list)
1669 /* link around it */
1670 list->next = flf->next;
1673 free(flf);
1677 * Width and Drawing Text
1680 void FlocaleInitGstpArgs(
1681 flocale_gstp_args *args, FlocaleFont *flf, FlocaleWinString *fws,
1682 int start_x, int start_y)
1684 args->step = 0;
1685 args->offset = flf->shadow_offset + 1;
1686 args->outer_offset = flf->shadow_offset + flf->shadow_size;
1687 args->size = flf->shadow_size;
1688 args->sdir = flf->flags.shadow_dir;
1689 switch (fws->flags.text_rotation)
1691 case ROTATION_270: /* CCW */
1692 args->orig_x = start_x + FLF_SHADOW_UPPER_SIZE(flf);
1693 args->orig_y = start_y + FLF_SHADOW_RIGHT_SIZE(flf);
1694 break;
1695 case ROTATION_180:
1696 args->orig_x = start_x + FLF_SHADOW_RIGHT_SIZE(flf);
1697 args->orig_y = start_y;
1698 break;
1699 case ROTATION_90: /* CW */
1700 args->orig_x = start_x + FLF_SHADOW_BOTTOM_SIZE(flf);
1701 args->orig_y = start_y + FLF_SHADOW_LEFT_SIZE(flf);
1702 break;
1703 case ROTATION_0:
1704 default:
1705 args->orig_x = start_x + FLF_SHADOW_LEFT_SIZE(flf);
1706 args->orig_y = start_y;
1707 break;
1709 args->rot = fws->flags.text_rotation;
1711 return;
1714 Bool FlocaleGetShadowTextPosition(
1715 int *x, int *y, flocale_gstp_args *args)
1717 if (args->step == 0)
1719 args->direction = MULTI_DIR_NONE;
1720 args->inter_step = 0;
1722 if ((args->step == 0 || args->inter_step >= args->num_inter_steps) &&
1723 args->size != 0)
1725 /* setup a new direction */
1726 args->inter_step = 0;
1727 gravity_get_next_multi_dir(args->sdir, &args->direction);
1728 if (args->direction == MULTI_DIR_C)
1730 int size;
1732 size = 2 * (args->outer_offset) + 1;
1733 args->num_inter_steps = size * size;
1735 else
1737 args->num_inter_steps = args->size;
1740 if (args->direction == MULTI_DIR_NONE || args->size == 0)
1742 *x = args->orig_x;
1743 *y = args->orig_y;
1745 return False;
1747 if (args->direction == MULTI_DIR_C)
1749 int tx;
1750 int ty;
1751 int size;
1752 int is_finished;
1754 size = 2 * (args->outer_offset) + 1;
1755 tx = args->inter_step % size - args->outer_offset;
1756 ty = args->inter_step / size - args->outer_offset;
1757 for (is_finished = 0; ty <= args->outer_offset;
1758 ty++, tx = -args->outer_offset)
1760 for (; tx <= args->outer_offset; tx++)
1762 if (tx <= -args->offset ||
1763 tx >= args->offset ||
1764 ty <= -args->offset || ty >= args->offset)
1766 is_finished = 1;
1767 break;
1770 if (is_finished)
1772 break;
1775 args->inter_step =
1776 (tx + args->outer_offset) +
1777 (ty + args->outer_offset) * size;
1778 if (!is_finished)
1780 tx = 0;
1781 ty = 0;
1783 *x = args->orig_x + tx;
1784 *y = args->orig_y + ty;
1786 else if (args->inter_step > 0)
1788 /* into a directional drawing */
1789 (*x) += args->x_sign;
1790 (*y) += args->y_sign;
1792 else
1794 direction_t dir;
1795 direction_t dir_x;
1796 direction_t dir_y;
1798 dir = gravity_multi_dir_to_dir(args->direction);
1799 gravity_split_xy_dir(&dir_x, &dir_y, dir);
1800 args->x_sign = gravity_dir_to_sign_one_axis(dir_x);
1801 args->y_sign = gravity_dir_to_sign_one_axis(dir_y);
1802 gravity_rotate_xy(
1803 args->rot, args->x_sign, args->y_sign,
1804 &args->x_sign, &args->y_sign);
1805 *x = args->orig_x + args->x_sign * args->offset;
1806 *y = args->orig_y + args->y_sign * args->offset;
1808 args->inter_step++;
1809 args->step++;
1811 return True;
1814 void FlocaleDrawString(
1815 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws,
1816 unsigned long flags)
1818 int len;
1819 Bool do_free = False;
1820 Pixel fg = 0, fgsh = 0;
1821 Bool has_fg_pixels = False;
1822 flocale_gstp_args gstp_args;
1823 superimpose_char_t *comb_chars = NULL;
1824 char *curr_str;
1825 int char_len; /* length in number of chars */
1826 int *pixel_pos = NULL;
1827 int i;
1828 int j;
1829 char buf[4];
1830 int curr_pixel_pos;
1831 int curr_len;
1833 if (!fws || !fws->str)
1835 return;
1838 if (flags & FWS_HAVE_LENGTH)
1840 len = fws->len;
1842 else
1844 len = strlen(fws->str);
1847 /* encode the string */
1848 FlocaleEncodeWinString(
1849 dpy, flf, fws, &do_free, &len, &comb_chars, NULL);
1850 curr_str = fws->e_str;
1851 for(char_len = 0, i = 0 ;
1852 i < len && curr_str[i] != 0 ;
1853 char_len++, i += curr_len)
1855 curr_len = FlocaleStringNumberOfBytes(flf, curr_str + i);
1858 /* for superimposition calculate the character positions in pixels */
1859 if (comb_chars != NULL && (
1860 comb_chars[0].c.byte1 != 0 || comb_chars[0].c.byte2 != 0))
1862 /* the second condition is actually redundant,
1863 but there for clarity,
1864 ending at 0 is what's expected in a correct
1865 string */
1866 pixel_pos = (int *)safemalloc(
1867 (char_len != 0 ? char_len : 1) * sizeof(int));
1869 /* if there is 0 bytes in the encoded string, there might
1870 still be combining character to draw (at position 0) */
1871 if(char_len == 0)
1873 pixel_pos[0] = 0;
1876 for(
1877 i = 0, curr_pixel_pos = 0 ;
1878 i < char_len ;
1879 i++, curr_str += curr_len)
1881 curr_len = FlocaleStringNumberOfBytes(flf, curr_str);
1882 for (j = 0 ; j < curr_len ; j++)
1884 buf[j] = curr_str[j];
1886 buf[j] = 0;
1887 pixel_pos[i] = curr_pixel_pos;
1888 /* need to compensate for shadow width (if any) */
1889 curr_pixel_pos +=
1890 FlocaleTextWidth(flf, buf, curr_len) -
1891 FLF_SHADOW_WIDTH(flf);
1895 /* get the pixels */
1896 if (fws->flags.has_colorset)
1898 fg = fws->colorset->fg;
1899 fgsh = fws->colorset->fgsh;
1900 has_fg_pixels = True;
1902 else if (flf->shadow_size != 0)
1904 XGCValues xgcv;
1906 if (XGetGCValues(dpy, fws->gc, GCForeground, &xgcv) != 0)
1908 fg = xgcv.foreground;
1910 else
1912 fg = PictureBlackPixel();
1914 fgsh = GetShadow(fg);
1915 has_fg_pixels = True;
1918 if(flf->font != None &&
1919 (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb))
1921 /* in this case, length is number of 2-byte chars */
1922 len = char_len;
1925 if (fws->flags.text_rotation != ROTATION_0 &&
1926 flf->fftf.fftfont == NULL)
1928 /* pass in information to perform superimposition */
1929 FlocaleRotateDrawString(
1930 dpy, flf, fws, fg, fgsh, has_fg_pixels, len,
1931 comb_chars, pixel_pos);
1933 else if (FftSupport && flf->fftf.fftfont != NULL)
1935 FftDrawString(
1936 dpy, flf, fws, fg, fgsh, has_fg_pixels, len, flags);
1938 else if (flf->fontset != None)
1940 int xt = fws->x;
1941 int yt = fws->y;
1943 FlocaleInitGstpArgs(&gstp_args, flf, fws, fws->x, fws->y);
1944 if (flf->shadow_size != 0)
1946 XSetForeground(dpy, fws->gc, fgsh);
1947 while (FlocaleGetShadowTextPosition(
1948 &xt, &yt, &gstp_args))
1950 XmbDrawString(
1951 dpy, fws->win, flf->fontset, fws->gc,
1952 xt, yt, fws->e_str, len);
1955 if (has_fg_pixels == True)
1957 XSetForeground(dpy, fws->gc, fg);
1959 xt = gstp_args.orig_x;
1960 yt = gstp_args.orig_y;
1961 XmbDrawString(
1962 dpy, fws->win, flf->fontset, fws->gc,
1963 xt, yt, fws->e_str, len);
1965 else if (flf->font != None)
1967 FlocaleFontStructDrawString(
1968 dpy, flf, fws->win, fws->gc, fws->x, fws->y,
1969 fg, fgsh, has_fg_pixels, fws, len, False);
1972 /* here take care of superimposing chars */
1973 i = 0;
1974 if (comb_chars != NULL)
1976 while(comb_chars[i].c.byte1 != 0 && comb_chars[i].c.byte2 != 0)
1978 /* draw composing character on top of corresponding
1979 "real" character */
1980 FlocaleWinString tmp_fws = *fws;
1981 int offset = pixel_pos[comb_chars[i].position];
1982 char *buf2;
1983 int out_len;
1984 curr_len = FlocaleChar2bOneCharToUtf8(comb_chars[i].c,
1985 buf);
1986 buf2 = FiconvUtf8ToCharset(
1987 dpy, flf->str_fc, (const char *)buf, curr_len);
1988 if(buf2 == NULL)
1990 /* if conversion failed, combinational char
1991 is not representable in current charset */
1992 /* just replace with empty string */
1993 buf2 = (char *)safemalloc(sizeof(char));
1994 buf2[0] = 0;
1996 tmp_fws.e_str = buf2;
1997 tmp_fws.str2b = NULL;
1998 if(FftSupport && flf->fftf.fftfont != NULL)
2000 tmp_fws.x = fws->x + offset;
2001 FftDrawString(
2002 dpy, flf, &tmp_fws, fg, fgsh,
2003 has_fg_pixels, strlen(buf2),
2004 flags);
2006 else if(flf->fontset != None)
2008 int xt = fws->x;
2009 int yt = fws->y;
2011 FlocaleInitGstpArgs(
2012 &gstp_args, flf, fws, fws->x, fws->y);
2013 if (flf->shadow_size != 0)
2015 XSetForeground(dpy, fws->gc, fgsh);
2016 while (FlocaleGetShadowTextPosition(
2017 &xt, &yt, &gstp_args))
2019 XmbDrawString(
2020 dpy, fws->win,
2021 flf->fontset,
2022 fws->gc,
2023 xt, yt,
2024 buf2,
2025 strlen(buf2));
2028 XSetForeground(dpy, fws->gc, fg);
2029 xt = gstp_args.orig_x;
2030 yt = gstp_args.orig_y;
2031 XmbDrawString(
2032 dpy, fws->win, flf->fontset, fws->gc,
2033 xt + offset, yt, buf2, strlen(buf2));
2035 else if (flf->font != None)
2037 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
2039 tmp_fws.str2b = (XChar2b *)
2040 safemalloc(2 * sizeof(XChar2b));
2041 tmp_fws.str2b[0] = comb_chars[i].c;
2042 tmp_fws.str2b[1].byte1 = 0;
2043 tmp_fws.str2b[1].byte2 = 0;
2044 out_len = 1;
2045 /*tmp_fws.str2b =
2046 FlocaleUtf8ToUnicodeStr2b(
2047 tmp_fws.e_str,
2048 curr_len, &out_len);*/
2050 else if (flf->flags.is_mb)
2052 tmp_fws.str2b =
2053 FlocaleStringToString2b(
2054 dpy, flf,
2055 tmp_fws.e_str,
2056 curr_len, &out_len);
2058 else
2060 out_len = strlen(buf2);
2062 FlocaleFontStructDrawString(
2063 dpy, flf, fws->win, fws->gc,
2064 fws->x + offset, fws->y, fg, fgsh,
2065 has_fg_pixels, &tmp_fws, out_len,
2066 False);
2069 free(buf2);
2070 if(tmp_fws.str2b != NULL)
2072 free(tmp_fws.str2b);
2074 i++;
2078 if (do_free)
2080 if (fws->e_str != NULL)
2082 free(fws->e_str);
2083 fws->e_str = NULL;
2087 if (fws->str2b != NULL)
2089 free(fws->str2b);
2090 fws->str2b = NULL;
2093 if(comb_chars != NULL)
2095 free(comb_chars);
2096 if(pixel_pos)
2097 free(pixel_pos);
2100 return;
2103 void FlocaleDrawUnderline(
2104 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, int offset)
2106 int off1, off2, y, x_s, x_e;
2107 superimpose_char_t *comb_chars = NULL;
2108 int *l_to_v = NULL;
2109 Bool do_free = True;
2110 int len = strlen(fws->str);
2111 int l_coffset;
2112 int v_coffset;
2113 int voffset;
2115 if (fws == NULL || fws->str == NULL)
2117 return;
2120 /* need to encode the string first to get BIDI and combining chars */
2121 FlocaleEncodeWinString(dpy, flf, fws, &do_free, &len, &comb_chars,
2122 &l_to_v);
2123 /* we don't need this, only interested in char mapping */
2124 free(comb_chars);
2126 /* now calculate char offset (in bytes) in visual string corresponding
2127 to coffset */
2128 /* calculate absolute position in string (in characters) */
2129 l_coffset = FlocaleStringByteToCharOffset(flf, fws->str, offset);
2130 /* map to an offset in the visual string */
2131 v_coffset = l_to_v[l_coffset];
2132 /* calculate byte offset into visual string */
2133 voffset = FlocaleStringCharToByteOffset(flf, fws->e_str, v_coffset);
2135 off1 = FlocaleTextWidth(flf, fws->e_str, voffset) +
2136 ((voffset == 0)?
2137 FLF_SHADOW_LEFT_SIZE(flf) : - FLF_SHADOW_RIGHT_SIZE(flf) );
2138 off2 = FlocaleTextWidth(flf, fws->e_str + voffset,
2139 FlocaleStringNumberOfBytes(flf, fws->e_str + voffset)) -
2140 FLF_SHADOW_WIDTH(flf) - 1 + off1;
2141 y = fws->y + 2;
2142 x_s = fws->x + off1;
2143 x_e = fws->x + off2;
2145 /* No shadow */
2146 XDrawLine(dpy, fws->win, fws->gc, x_s, y, x_e, y);
2148 /* free encoded string if it isn't the same as input string */
2149 if(fws->e_str != fws->str)
2151 free(fws->e_str);
2152 fws->e_str = NULL;
2155 if(fws->str2b != NULL)
2157 free(fws->str2b);
2158 fws->str2b = NULL;
2160 free(l_to_v);
2162 return;
2165 int FlocaleTextWidth(FlocaleFont *flf, char *str, int sl)
2167 int result = 0;
2168 char *tmp_str;
2169 int new_l,do_free;
2170 superimpose_char_t *comb_chars = NULL;
2172 if (!str || sl == 0)
2173 return 0;
2175 if (sl < 0)
2177 /* a vertical string: nothing to do! */
2178 sl = -sl;
2181 /* FIXME */
2182 /* to avoid eccesive calls iconv (slow in Solaris 8)
2183 don't bother to encode if string is one byte
2184 when drawing a string this function is used to calculate
2185 position of each character (for superimposition) */
2186 if(sl == 1)
2188 tmp_str = str;
2189 new_l = sl;
2190 do_free = False;
2192 else
2194 tmp_str = FlocaleEncodeString(
2195 Pdpy, flf, str, &do_free, sl, &new_l, NULL,
2196 &comb_chars, NULL);
2198 /* if we get zero-length, check to to see if there if there's any
2199 combining chars, if so use an imagninary space as a
2200 "base character" */
2201 if (strlen(tmp_str) == 0 && comb_chars &&
2202 (comb_chars[0].c.byte1 != 0 || comb_chars[0].c.byte2 != 0))
2204 if(do_free)
2206 free(tmp_str);
2208 if(comb_chars)
2210 free(comb_chars);
2212 return FlocaleTextWidth(flf, " ", 1);
2214 else if (FftSupport && flf->fftf.fftfont != NULL)
2216 result = FftTextWidth(flf, tmp_str, new_l);
2218 else if (flf->fontset != None)
2220 result = XmbTextEscapement(flf->fontset, tmp_str, new_l);
2222 else if (flf->font != None)
2224 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb)
2226 XChar2b *str2b;
2227 int nl;
2229 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
2230 str2b = FlocaleUtf8ToUnicodeStr2b(
2231 tmp_str, new_l, &nl);
2232 else
2233 str2b = FlocaleStringToString2b(
2234 Pdpy, flf, tmp_str, new_l, &nl);
2235 if (str2b != NULL)
2237 result = XTextWidth16(flf->font, str2b, nl);
2238 free(str2b);
2241 else
2243 result = XTextWidth(flf->font, tmp_str, new_l);
2246 if (do_free)
2248 free(tmp_str);
2250 if (comb_chars)
2252 free(comb_chars);
2255 return result + ((result != 0)? FLF_SHADOW_WIDTH(flf):0);
2258 int FlocaleGetMinOffset(
2259 FlocaleFont *flf, rotation_t rotation)
2261 int min_offset;
2263 #ifdef FFT_BUGGY_FREETYPE
2264 switch(rotation)
2266 case ROTATION_270:
2267 case ROTATION_180:
2268 /* better than descent */
2269 min_offset = (flf->descent + flf->height - flf->ascent)/2;
2270 break;
2271 case ROTATION_0:
2272 case ROTATION_90:
2273 default:
2274 /* better than ascent */
2275 min_offset = (flf->ascent + flf->height - flf->descent)/2;
2276 break;
2278 #else
2279 switch(rotation)
2281 case ROTATION_180:
2282 case ROTATION_90:
2283 /* better than descent */
2284 min_offset = (flf->descent + flf->height - flf->ascent)/2;
2285 break;
2286 case ROTATION_270:
2287 case ROTATION_0:
2288 default:
2289 /* better than ascent */
2290 min_offset = (flf->ascent + flf->height - flf->descent)/2;
2291 break;
2293 #endif
2294 return min_offset;
2297 void FlocaleAllocateWinString(FlocaleWinString **pfws)
2299 *pfws = (FlocaleWinString *)safemalloc(sizeof(FlocaleWinString));
2300 memset(*pfws, '\0', sizeof(FlocaleWinString));
2304 * Text properties
2306 void FlocaleGetNameProperty(
2307 Status (func)(Display *, Window, XTextProperty *), Display *dpy,
2308 Window w, FlocaleNameString *ret_name)
2310 char **list;
2311 int num;
2312 XTextProperty text_prop;
2314 list = NULL;
2315 if (func(dpy, w, &text_prop) == 0)
2317 return;
2319 if (text_prop.encoding == XA_STRING)
2321 /* STRING encoding, use this as it is */
2322 ret_name->name = (char *)text_prop.value;
2323 ret_name->name_list = NULL;
2324 return;
2326 /* not STRING encoding, try to convert XA_COMPOUND_TEXT */
2327 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success
2328 && num > 0 && *list)
2330 /* Does not consider the conversion is REALLY succeeded:
2331 * XmbTextPropertyToTextList return 0 (== Success) on success,
2332 * a negative int if it fails (and in this case we are not
2333 * here), the number of unconvertible char on "partial"
2334 * success*/
2335 XFree(text_prop.value); /* return of XGetWM(Icon)Name() */
2336 ret_name->name = *list;
2337 ret_name->name_list = list;
2339 else
2341 if (list)
2343 XFreeStringList(list);
2345 ret_name->name = (char *)text_prop.value;
2346 ret_name->name_list = NULL;
2350 void FlocaleFreeNameProperty(FlocaleNameString *ptext)
2352 if (ptext->name_list != NULL)
2354 if (ptext->name != NULL && ptext->name != *ptext->name_list)
2355 XFree(ptext->name);
2356 XFreeStringList(ptext->name_list);
2357 ptext->name_list = NULL;
2359 else if (ptext->name != NULL)
2361 XFree(ptext->name);
2363 ptext->name = NULL;
2365 return;
2368 Bool FlocaleTextListToTextProperty(
2369 Display *dpy, char **list, int count, XICCEncodingStyle style,
2370 XTextProperty *text_prop_return)
2372 int ret = False;
2374 if (Flocale != NULL)
2376 ret = XmbTextListToTextProperty(
2377 dpy, list, count, style, text_prop_return);
2378 if (ret == XNoMemory)
2380 ret = False;
2382 else
2384 /* ret == Success or the number of unconvertible
2385 * characters. ret should be != XLocaleNotSupported
2386 * because in this case Flocale == NULL */
2387 ret = True;
2390 if (!ret)
2392 if (XStringListToTextProperty(
2393 list, count, text_prop_return) == 0)
2395 ret = False;
2397 else
2399 ret = True;
2403 return ret;
2407 * Info
2409 void FlocalePrintLocaleInfo(Display *dpy, int verbose)
2411 FlocaleFont *flf = FlocaleFontList;
2412 int count = 0;
2413 FlocaleCharset *cs;
2415 fflush(stderr);
2416 fflush(stdout);
2417 fprintf(stderr,"fvwm info on locale:\n");
2418 fprintf(stderr," locale: %s, Modifier: %s\n",
2419 (Flocale)? Flocale:"", (Fmodifiers)? Fmodifiers:"");
2420 cs = FlocaleCharsetGetDefaultCharset(dpy, NULL);
2421 fprintf(stderr," Default Charset: X: %s, Iconv: %s, Bidi: %s\n",
2422 cs->x,
2423 (cs->iconv_index >= 0)?
2424 cs->locale[cs->iconv_index]:"Not defined",
2425 (cs->bidi)? "Yes":"No");
2426 FlocaleCharsetPrintXOMInfo();
2427 while (flf)
2429 count++;
2430 flf = flf->next;
2432 fprintf(stderr," Number of loaded font: %i\n", count);
2433 if (verbose)
2435 count = 0;
2436 flf = FlocaleFontList;
2437 while(flf)
2439 cs = flf->fc;
2440 fprintf(stderr," * Font number %i\n", count);
2441 fprintf(stderr," fvwm info:\n");
2442 fprintf(stderr," Name: %s\n",
2443 (flf->name)? flf->name:"");
2444 fprintf(stderr," Cache count: %i\n", flf->count);
2445 fprintf(stderr," Type: ");
2446 if (flf->font)
2448 fprintf(stderr,"FontStruct\n");
2450 else if (flf->fontset)
2452 fprintf(stderr,"FontSet\n");
2454 else
2456 fprintf(stderr,"XftFont\n");
2458 fprintf(stderr, " Charset: X: %s, Iconv: %s, "
2459 "Bidi: %s\n",
2460 cs->x,
2461 (cs->iconv_index >= 0)?
2462 cs->locale[cs->iconv_index]:"Not defined",
2463 (cs->bidi)? "Yes":"No");
2464 fprintf(stderr," height: %i, ascent: %i, "
2465 "descent: %i\n", flf->height, flf->ascent,
2466 flf->descent);
2467 fprintf(stderr," shadow size: %i, "
2468 "shadow offset: %i, shadow direction:%i\n",
2469 flf->shadow_size, flf->shadow_offset,
2470 flf->flags.shadow_dir);
2471 if (verbose >= 2)
2473 if (flf->fftf.fftfont != NULL)
2475 FftFontType *fftf;
2477 fftf = &flf->fftf;
2478 fprintf(stderr, " Xft info:\n"
2479 " - Vertical font:");
2480 FftPrintPatternInfo(
2481 fftf->fftfont, False);
2482 fprintf(stderr, " "
2483 "- Rotated font 90:");
2484 if (fftf->fftfont_rotated_90)
2485 FftPrintPatternInfo(
2486 fftf->
2487 fftfont_rotated_90,
2488 True);
2489 else
2490 fprintf(stderr, " None\n");
2491 fprintf(stderr, " "
2492 "- Rotated font 270:");
2493 if (fftf->fftfont_rotated_270)
2494 FftPrintPatternInfo(
2495 fftf->
2496 fftfont_rotated_270,
2497 True);
2498 else
2499 fprintf(stderr, " None\n");
2500 fprintf(stderr, " "
2501 "- Rotated font 180:");
2502 if (fftf->fftfont_rotated_180)
2503 FftPrintPatternInfo(
2504 fftf->
2505 fftfont_rotated_180,
2506 True);
2507 else
2508 fprintf(stderr, " None\n");
2510 else if (flf->font != NULL)
2512 char *full_name;
2514 full_name =
2515 FlocaleGetFullNameOfFontStruct(
2516 dpy, flf->font);
2517 fprintf(stderr, " X info:\n"
2518 " %s\n",
2519 (full_name)? full_name:"?");
2520 if (full_name != NULL)
2522 XFree(full_name);
2525 else if (flf->fontset != NULL)
2527 int n,i;
2528 XFontStruct **font_struct_list;
2529 char **font_name_list;
2531 fprintf(stderr, " X info:\n");
2532 n = XFontsOfFontSet(
2533 flf->fontset,
2534 &font_struct_list,
2535 &font_name_list);
2536 for(i = 0; i < n; i++)
2538 fprintf(stderr,
2539 " %s\n",
2540 font_name_list[i]);
2544 count++;
2545 flf = flf->next;