* Fixed UTF8 crash.
[fvwm.git] / libs / Flocale.c
blob3b5eeb011664af71f2706e8cefc14fe1092acecf
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 /* ---------------------------- exported variables (globals) --------------- */
91 /* ---------------------------- local functions ---------------------------- */
94 * shadow local functions
97 static
98 void FlocaleParseShadow(char *str, int *shadow_size, int *shadow_offset,
99 int *direction, char * fontname, char *module)
101 char *dir_str;
102 char *token;
103 multi_direction_t dir;
105 *direction = MULTI_DIR_NONE;
106 token = PeekToken(str, &dir_str);
107 if (token == NULL || *token == 0 ||
108 (GetIntegerArguments(token, NULL, shadow_size, 1) != 1) ||
109 *shadow_size < 0)
111 *shadow_size = 0;
112 fprintf(stderr,"[%s][FlocaleParseShadow]: WARNING -- bad "
113 "shadow size in font name:\n\t'%s'\n",
114 (module)? module: "FVWM", fontname);
115 return;
117 if (*shadow_size == 0)
119 return;
121 /* some offset ? */
122 if (dir_str && *dir_str &&
123 (GetIntegerArguments(dir_str, NULL, shadow_offset, 1) == 1))
125 if (*shadow_offset < 0)
127 *shadow_offset = 0;
128 fprintf(stderr,"[%s][FlocaleParseShadow]: WARNING -- "
129 "bad shadow offset in font name:\n\t'%s'\n",
130 (module)? module: "FVWMlibs", fontname);
132 PeekToken(dir_str, &dir_str);
134 while (dir_str && *dir_str && *dir_str != '\n')
136 dir = gravity_parse_multi_dir_argument(dir_str, &dir_str);
137 if (dir == MULTI_DIR_NONE)
139 fprintf(stderr,"[%s][FlocaleParseShadow]: WARNING -- "
140 "bad shadow direction in font description:\n"
141 "\t%s\n",
142 (module)? module: "FVWMlibs", fontname);
143 PeekToken(dir_str, &dir_str); /* skip it */
145 else
147 *direction |= dir;
150 if (*direction == MULTI_DIR_NONE)
151 *direction = MULTI_DIR_SE;
155 * some simple converters
158 static
159 int FlocaleChar2bOneCharToUtf8(XChar2b c, char *buf)
161 int len;
162 char byte1 = c.byte1;
163 char byte2 = c.byte2;
164 unsigned short ucs2 = ((unsigned short)byte1 << 8) + byte2;
166 if(ucs2 <= 0x7f)
168 len = 1;
169 buf[0] = (char)ucs2;
170 buf[1] = 0;
172 else if(ucs2 <= 0x7ff)
174 len = 2;
175 buf[0] = (ucs2 >> 6) | 0xc0;
176 buf[1] = (ucs2 & 0x3f) | 0x80;
177 buf[2] = 0;
179 else
181 len = 3;
182 buf[0] = (ucs2 >> 12) | 0xe0;
183 buf[1] = ((ucs2 & 0xfff) >> 6) | 0x80;
184 buf[2] = (ucs2 & 0x3f) | 0x80;
185 buf[3] = 0;
187 return len;
190 /* return number of bytes of character at current position
191 (pointed to by str) */
192 int FlocaleStringNumberOfBytes(FlocaleFont *flf, const char *str)
194 int bytes = 0;
195 if(FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
197 /* handle UTF-8 */
198 if ((str[0] & 0x80) == 0)
200 bytes = 1;
202 else if((str[0] & ~0xdf) == 0)
204 bytes = 2;
206 else
208 /* this handles only 16-bit Unicode */
209 bytes = 3;
212 else if(flf->flags.is_mb)
214 /* non-UTF-8 multibyte encoding */
215 if ((str[0] & 0x80) == 0)
217 bytes = 1;
219 else
221 bytes = 2;
224 else
226 /* we must be using an "ordinary" 8-bit encoding */
227 bytes = 1;
229 return bytes;
232 /* given a string, font specifying its locale and a byte offset gives
233 character offset */
234 int FlocaleStringByteToCharOffset(FlocaleFont *flf, const char *str,
235 int offset)
237 const char *curr_ptr = str;
238 int i = 0;
239 int len = strlen(str);
240 int coffset = 0;
241 int curr_len;
243 for(i = 0 ;
244 i < offset && i < len ;
245 i += curr_len, curr_ptr += curr_len, coffset++)
247 curr_len = FlocaleStringNumberOfBytes(flf, curr_ptr);
249 return coffset;
252 /* like above but reversed, ie. return byte offset corresponding to given
253 charater offset */
254 int FlocaleStringCharToByteOffset(FlocaleFont *flf, const char *str,
255 int coffset)
257 const char *curr_ptr = str;
258 int i;
259 int len = strlen(str);
260 int offset = 0;
261 int curr_len;
263 for(i = 0 ;
264 i < coffset && i < len ;
265 offset += curr_len, curr_ptr += curr_len, i++)
267 curr_len = FlocaleStringNumberOfBytes(flf, curr_ptr);
269 return offset;
272 /* return length of string in characters */
273 int FlocaleStringCharLength(FlocaleFont *flf, const char *str)
275 int i, len;
276 int str_len = strlen(str);
277 for(i = 0, len = 0 ; i < str_len ;
278 i += FlocaleStringNumberOfBytes(flf, str+i), len++);
279 return len;
282 static
283 XChar2b *FlocaleUtf8ToUnicodeStr2b(char *str, int len, int *nl)
285 XChar2b *str2b = NULL;
286 int i = 0, j = 0, t;
288 str2b = (XChar2b *)safemalloc((len+1)*sizeof(XChar2b));
289 while (i < len && str[i] != 0)
291 if ((str[i] & 0x80) == 0)
293 str2b[j].byte2 = str[i];
294 str2b[j].byte1 = 0;
296 else if ((str[i] & ~0xdf) == 0 && i+1 < len)
298 t = ((str[i] & 0x1f) << 6) + (str[i+1] & 0x3f);
299 str2b[j].byte2 = (unsigned char)(t & 0xff);
300 str2b[j].byte1 = (unsigned char)(t >> 8);
301 i++;
303 else if (i+2 <len)
305 t = ((str[i] & 0x0f) << 12) + ((str[i+1] & 0x3f) << 6)+
306 (str[i+2] & 0x3f);
307 str2b[j].byte2 = (unsigned char)(t & 0xff);
308 str2b[j].byte1 = (unsigned char)(t >> 8);
309 i += 2;
311 i++; j++;
313 *nl = j;
314 return str2b;
317 /* Note: this function is not expected to work; good mb rendering
318 * should be (and is) done using Xmb functions and not XDrawString16
319 * (or with iso10646-1 fonts and setting the encoding).
320 * This function is used when the locale does not correspond to the font.
321 * It works with "EUC fonts": ksc5601.1987-0, gb2312 and maybe also
322 * cns11643-*. It works patially with jisx* and big5-0. Should try gbk-0,
323 * big5hkscs-0, and cns-11643- */
324 static
325 XChar2b *FlocaleStringToString2b(
326 Display *dpy, FlocaleFont *flf, char *str, int len, int *nl)
328 XChar2b *str2b = NULL;
329 char *tmp = NULL;
330 Bool free_str = False;
331 int i = 0, j = 0;
332 Bool euc = True; /* KSC5601 (EUC-KR), GB2312 (EUC-CN), CNS11643-1986-1
333 * (EUC-TW) and converted jisx (EUC-JP) */
335 if (flf->fc && StrEquals(flf->fc->x,"jisx0208.1983-0"))
337 tmp = FiconvCharsetToCharset(
338 dpy, flf->fc, FlocaleCharsetGetEUCJPCharset(), str,
339 len);
340 if (tmp != NULL)
342 free_str = True;
343 str = tmp;
344 len = strlen(tmp);
347 else if (flf->fc && StrEquals(flf->fc->x,"big5-0"))
349 euc = False;
351 str2b = (XChar2b *)safemalloc((len+1)*sizeof(XChar2b));
352 if (euc)
354 while (i < len && str[i] != 0)
356 if ((str[i] & 0x80) == 0)
358 /* seems ok with KSC5601 and GB2312 as we get
359 * almost the ascii. I do no try
360 * CNS11643-1986-1. Should convert to ascii
361 * with jisx */
362 str2b[j].byte1 = 0x23; /* magic number! */
363 str2b[j].byte2 = str[i++];
365 else if (i+1 < len)
367 /* mb gl (for gr replace & 0x7f by | 0x80 ...)
369 str2b[j].byte1 = str[i++] & 0x7f;
370 str2b[j].byte2 = str[i++] & 0x7f;
372 else
374 str2b[j].byte1 = 0;
375 str2b[j].byte2 = 0;
376 i++;
378 j++;
381 else /* big5 and others not yet tested */
383 while (i < len && str[i] != 0)
385 if ((str[i] & 0x80) == 0)
387 /* we should convert to ascii */
388 #if 0
389 str2b[j].byte1 = 0xa2; /* magic number! */
390 str2b[j].byte2 = str[i++];
391 #endif
392 /* a blanck char ... */
393 str2b[j].byte1 = 0x21;
394 str2b[j].byte2 = 0x21;
396 else if (i+1 < len)
398 str2b[j].byte1 = str[i++];
399 str2b[j].byte2 = str[i++];
401 else
403 str2b[j].byte1 = 0;
404 str2b[j].byte2 = 0;
405 i++;
407 j++;
410 *nl = j;
411 if (free_str)
412 free(str);
413 return str2b;
416 static
417 char *FlocaleEncodeString(
418 Display *dpy, FlocaleFont *flf, char *str, int *do_free, int len,
419 int *nl, int *is_rtl, superimpose_char_t **comb_chars,
420 int **l_to_v)
422 char *str1, *str2, *str3;
423 int len1 = len, len2;
424 int i;
425 Bool do_iconv = True;
426 const char *bidi_charset;
428 if (is_rtl != NULL)
429 *is_rtl = False;
430 *do_free = False;
431 *nl = len;
433 if (flf->str_fc == NULL || flf->fc == NULL ||
434 flf->fc == flf->str_fc)
436 do_iconv = False;
439 str1 = str;
440 if (FiconvSupport)
442 char *tmp_str;
444 /* first process combining characters */
445 tmp_str = FiconvCharsetToUtf8(
446 dpy, flf->str_fc, (const char *)str,len);
447 /* if conversion to UTF-8 failed str1 will be NULL */
448 if(tmp_str != NULL)
450 /* do combining */
451 len = CombineChars((unsigned char *)tmp_str,
452 strlen(tmp_str), comb_chars,
453 l_to_v);
454 /* returns the length of the resulting UTF-8 string */
455 /* convert back to current charset */
456 str1 = FiconvUtf8ToCharset(
457 dpy, flf->str_fc, (const char *)tmp_str,len);
458 if (tmp_str != str1)
460 free(tmp_str);
462 if (str1)
464 *nl = len = strlen(str1);
465 *do_free = True;
467 else
469 /* convert back to current charset fail */
470 len = strlen(str);
471 str1 = str;
476 if (FiconvSupport && do_iconv)
478 str2 = FiconvCharsetToCharset(
479 dpy, flf->str_fc, flf->fc, (const char *)str1, len);
480 if (str2 == NULL)
482 /* fail to convert */
483 return str1;
485 if (str2 != str1)
487 if (*do_free && str1)
489 free(str1);
490 str1 = str2;
492 *do_free = True;
493 len1 = strlen(str2);
496 else
498 str2 = str1;
499 len1 = len;
500 /* initialise array with composing characters (empty) */
501 if(comb_chars != NULL && *comb_chars == NULL)
503 *comb_chars = (superimpose_char_t *)
504 safemalloc(sizeof(superimpose_char_t));
505 (*comb_chars)[0].position = -1;
506 (*comb_chars)[0].c.byte1 = 0;
507 (*comb_chars)[0].c.byte2 = 0;
510 /* initialise logic to visual mapping here if that is demanded
511 (this is default when no combining has been done (1-to-1))
513 if(l_to_v != NULL && *l_to_v == NULL)
515 *l_to_v = (int*)safemalloc((len + 1) * sizeof(int));
516 for(i = 0 ; i < len ; i++)
517 (*l_to_v)[i] = i;
518 (*l_to_v)[len] = -1;
522 if (FlocaleGetBidiCharset(dpy, flf->str_fc) != NULL &&
523 (bidi_charset = FlocaleGetBidiCharset(dpy, flf->fc)) != NULL)
525 str3 = FBidiConvert(str2, bidi_charset, len1,
526 is_rtl, &len2,
527 comb_chars != NULL ? *comb_chars : NULL,
528 l_to_v != NULL ? *l_to_v : NULL);
529 if (str3 != NULL && str3 != str2)
531 if (*do_free)
533 free(str2);
535 *do_free = True;
536 len1 = len2;
537 str1 = str3;
539 /* if we failed to do BIDI convert, return string string from
540 combining phase */
541 else
543 str1 = str2;
544 /* we already have the logical to visual mapping
545 from combining phase */
549 *nl = len1;
550 return str1;
553 static
554 void FlocaleEncodeWinString(
555 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, int *do_free,
556 int *len, superimpose_char_t **comb_chars, int **l_to_v)
558 int len2b;
559 fws->e_str = FlocaleEncodeString(
560 dpy, flf, fws->str, do_free, *len, len, NULL, comb_chars,
561 l_to_v);
562 fws->str2b = NULL;
564 if (flf->font != None)
566 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
568 fws->str2b = FlocaleUtf8ToUnicodeStr2b(
569 fws->e_str, *len, &len2b);
571 else if (flf->flags.is_mb)
573 fws->str2b = FlocaleStringToString2b(
574 dpy, flf, fws->e_str, *len, &len2b);
580 * Text Drawing with a FontStruct
583 static
584 void FlocaleFontStructDrawString(
585 Display *dpy, FlocaleFont *flf, Drawable d, GC gc, int x, int y,
586 Pixel fg, Pixel fgsh, Bool has_fg_pixels, FlocaleWinString *fws,
587 int len, Bool image)
589 int xt = x;
590 int yt = y;
591 int is_string16;
592 flocale_gstp_args gstp_args;
594 is_string16 = (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb);
595 if (is_string16 && fws->str2b == NULL)
597 return;
599 if (image)
601 /* for rotated drawing */
602 FSwitchDrawImageString(
603 is_string16, dpy, d, gc, x, y, fws->e_str, fws->str2b,
604 len);
606 else
608 FlocaleInitGstpArgs(&gstp_args, flf, fws, x, y);
609 /* normal drawing */
610 if (flf->shadow_size != 0 && has_fg_pixels == True)
612 XSetForeground(dpy, fws->gc, fgsh);
613 while (FlocaleGetShadowTextPosition(
614 &xt, &yt, &gstp_args))
616 FSwitchDrawString(
617 is_string16, dpy, d, gc, xt, yt,
618 fws->e_str, fws->str2b, len);
621 if (has_fg_pixels == True)
623 XSetForeground(dpy, gc, fg);
625 xt = gstp_args.orig_x;
626 yt = gstp_args.orig_y;
627 FSwitchDrawString(
628 is_string16, dpy, d, gc, xt,yt, fws->e_str, fws->str2b,
629 len);
632 return;
636 * Rotated Text Drawing with a FontStruct or a FontSet
638 static
639 void FlocaleRotateDrawString(
640 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, Pixel fg,
641 Pixel fgsh, Bool has_fg_pixels, int len,
642 superimpose_char_t *comb_chars, int *pixel_pos)
644 static GC my_gc = None;
645 static GC font_gc = None;
646 int j, i, xpfg, ypfg, xpsh, ypsh;
647 unsigned char *normal_data, *rotated_data;
648 unsigned int normal_w, normal_h, normal_len;
649 unsigned int rotated_w, rotated_h, rotated_len;
650 char val;
651 int width, height, descent, min_offset;
652 XImage *image, *rotated_image;
653 Pixmap canvas_pix, rotated_pix;
654 flocale_gstp_args gstp_args;
655 char buf[4];
657 if (fws->str == NULL || len < 1)
659 return;
661 if (fws->flags.text_rotation == ROTATION_0)
663 return; /* should not happen */
666 if (my_gc == None)
668 my_gc = fvwmlib_XCreateGC(dpy, fws->win, 0, NULL);
670 XCopyGC(dpy, fws->gc, GCForeground|GCBackground, my_gc);
672 /* width and height (no shadow!) */
673 width = FlocaleTextWidth(flf, fws->str, len) - FLF_SHADOW_WIDTH(flf);
674 height = flf->height - FLF_SHADOW_HEIGHT(flf);
675 descent = flf->descent - FLF_SHADOW_DESCENT(flf);;
677 if (width < 1)
678 width = 1;
679 if (height < 1)
680 height = 1;
682 /* glyph width and height of the normal text */
683 normal_w = width;
684 normal_h = height;
686 /* width in bytes */
687 normal_len = (normal_w - 1) / 8 + 1;
689 /* create and clear the canvas */
690 canvas_pix = XCreatePixmap(dpy, fws->win, width, height, 1);
691 if (font_gc == None)
693 font_gc = fvwmlib_XCreateGC(dpy, canvas_pix, 0, NULL);
695 XSetBackground(dpy, font_gc, 0);
696 XSetForeground(dpy, font_gc, 0);
697 XFillRectangle(dpy, canvas_pix, font_gc, 0, 0, width, height);
699 /* draw the character center top right on canvas */
700 XSetForeground(dpy, font_gc, 1);
701 if (flf->font != NULL)
703 XSetFont(dpy, font_gc, flf->font->fid);
704 FlocaleFontStructDrawString(dpy, flf, canvas_pix, font_gc, 0,
705 height - descent,
706 fg, fgsh, has_fg_pixels,
707 fws, len, True);
709 else if (flf->fontset != None)
711 XmbDrawString(
712 dpy, canvas_pix, flf->fontset, font_gc, 0,
713 height - descent, fws->e_str, len);
716 /* here take care of superimposing chars */
717 i = 0;
718 if(comb_chars != NULL)
720 while(comb_chars[i].c.byte1 != 0 && comb_chars[i].c.byte2 != 0)
722 /* draw composing character on top of corresponding
723 "real" character */
724 FlocaleWinString tmp_fws = *fws;
725 int offset = pixel_pos[comb_chars[i].position];
726 int curr_len = FlocaleChar2bOneCharToUtf8(
727 comb_chars[i].c,
728 buf);
729 int out_len;
730 char *buf2 = FiconvUtf8ToCharset(
731 dpy,
732 flf->str_fc,
733 (const char *)buf,curr_len);
734 if(buf2 == NULL)
736 /* if conversion failed, combinational char
737 is not representable in current charset */
738 /* just replace with empty string */
739 buf2 = (char *)safemalloc(sizeof(char));
740 buf2[0] = 0;
742 tmp_fws.e_str = buf2;
743 tmp_fws.str2b = NULL;
744 if(flf->fontset != None)
746 XmbDrawString(dpy, canvas_pix, flf->fontset,
747 fws->gc, offset,
748 height - descent, buf2,
749 strlen(buf2));
751 else if(flf->font != None)
753 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
755 tmp_fws.str2b = (XChar2b *)
756 safemalloc(2 * sizeof(XChar2b));
757 tmp_fws.str2b[0] = comb_chars[i].c;
758 tmp_fws.str2b[1].byte1 = 0;
759 tmp_fws.str2b[1].byte2 = 0;
760 out_len = 1;
762 else if (flf->flags.is_mb)
764 tmp_fws.str2b =
765 FlocaleStringToString2b(
766 dpy, flf, tmp_fws.e_str,
767 curr_len, &out_len);
769 else
771 out_len = strlen(buf2);
773 XSetFont(dpy, font_gc, flf->font->fid);
774 FlocaleFontStructDrawString(
775 dpy, flf, canvas_pix, font_gc,
776 offset, height - descent,
777 fg, fgsh, has_fg_pixels, &tmp_fws,
778 out_len, True);
781 free(buf2);
782 if(tmp_fws.str2b != NULL)
784 free(tmp_fws.str2b);
786 i++;
790 /* reserve memory for the first XImage */
791 normal_data = (unsigned char *)safemalloc(normal_len * normal_h);
793 /* create depth 1 XImage */
794 if ((image = XCreateImage(
795 dpy, Pvisual, 1, XYBitmap, 0, (char *)normal_data,
796 normal_w, normal_h, 8, 0)) == NULL)
798 return;
800 image->byte_order = image->bitmap_bit_order = MSBFirst;
802 /* extract character from canvas */
803 XGetSubImage(
804 dpy, canvas_pix, 0, 0, normal_w, normal_h,
805 1, XYPixmap, image, 0, 0);
806 image->format = XYBitmap;
808 /* width, height of the rotated text */
809 if (fws->flags.text_rotation == ROTATION_180)
811 rotated_w = normal_w;
812 rotated_h = normal_h;
814 else /* vertical text */
816 rotated_w = normal_h;
817 rotated_h = normal_w;
820 /* width in bytes */
821 rotated_len = (rotated_w - 1) / 8 + 1;
823 /* reserve memory for the rotated image */
824 rotated_data = (unsigned char *)safecalloc(rotated_h * rotated_len, 1);
826 /* create the rotated X image */
827 if ((rotated_image = XCreateImage(
828 dpy, Pvisual, 1, XYBitmap, 0, (char *)rotated_data,
829 rotated_w, rotated_h, 8, 0)) == NULL)
831 return;
834 rotated_image->byte_order = rotated_image->bitmap_bit_order = MSBFirst;
836 /* map normal text data to rotated text data */
837 for (j = 0; j < rotated_h; j++)
839 for (i = 0; i < rotated_w; i++)
841 /* map bits ... */
842 if (fws->flags.text_rotation == ROTATION_270)
843 val = normal_data[
844 i * normal_len +
845 (normal_w - j - 1) / 8
846 ] & (128 >> ((normal_w - j - 1) % 8));
848 else if (fws->flags.text_rotation == ROTATION_180)
849 val = normal_data[
850 (normal_h - j - 1) * normal_len +
851 (normal_w - i - 1) / 8
852 ] & (128 >> ((normal_w - i - 1) % 8));
854 else /* ROTATION_90 */
855 val = normal_data[
856 (normal_h - i - 1) * normal_len +
857 j / 8] & (128 >> (j % 8));
859 if (val)
860 rotated_data[j * rotated_len + i / 8] |=
861 (128 >> (i % 8));
865 /* create the character's bitmap and put the image on it */
866 rotated_pix = XCreatePixmap(dpy, fws->win, rotated_w, rotated_h, 1);
867 XPutImage(
868 dpy, rotated_pix, font_gc, rotated_image, 0, 0, 0, 0,
869 rotated_w, rotated_h);
871 /* free the image and data */
872 XDestroyImage(image);
873 XDestroyImage(rotated_image);
875 /* free pixmap and GC */
876 XFreePixmap(dpy, canvas_pix);
878 /* x and y corrections: we fill a rectangle! */
879 min_offset = FlocaleGetMinOffset(flf, fws->flags.text_rotation);
880 switch (fws->flags.text_rotation)
882 case ROTATION_90:
883 /* CW */
884 xpfg = fws->x - min_offset;
885 ypfg = fws->y;
886 break;
887 case ROTATION_180:
888 xpfg = fws->x;
889 ypfg = fws->y - min_offset +
890 FLF_SHADOW_BOTTOM_SIZE(flf);
891 break;
892 case ROTATION_270:
893 /* CCW */
894 xpfg = fws->x - min_offset;
895 ypfg = fws->y;
896 break;
897 case ROTATION_0:
898 default:
899 xpfg = fws->x;
900 ypfg = fws->y - min_offset;
901 break;
903 xpsh = xpfg;
904 ypsh = ypfg;
905 /* write the image on the window */
906 XSetFillStyle(dpy, my_gc, FillStippled);
907 XSetStipple(dpy, my_gc, rotated_pix);
908 FlocaleInitGstpArgs(&gstp_args, flf, fws, xpfg, ypfg);
909 if (flf->shadow_size != 0 && has_fg_pixels == True)
911 XSetForeground(dpy, my_gc, fgsh);
912 while (FlocaleGetShadowTextPosition(&xpsh, &ypsh, &gstp_args))
914 XSetTSOrigin(dpy, my_gc, xpsh, ypsh);
915 XFillRectangle(
916 dpy, fws->win, my_gc, xpsh, ypsh, rotated_w,
917 rotated_h);
920 xpsh = gstp_args.orig_x;
921 ypsh = gstp_args.orig_y;
922 XSetTSOrigin(dpy, my_gc, xpsh, ypsh);
923 XFillRectangle(dpy, fws->win, my_gc, xpsh, ypsh, rotated_w, rotated_h);
924 XFreePixmap(dpy, rotated_pix);
926 return;
930 * Fonts info and checking
933 static
934 char *FlocaleGetFullNameOfFontStruct(Display *dpy, XFontStruct *font)
936 char *full_name = NULL;
937 unsigned long value;
939 if (XGetFontProperty(font, XA_FONT, &value))
941 full_name = XGetAtomName(dpy, value);
943 return full_name;
946 static
947 char *FlocaleGetCharsetOfFontStruct(Display *dpy, XFontStruct *font)
949 int i = 0;
950 int count = 0;
951 char *charset = NULL;
952 char *full_name;
954 full_name = FlocaleGetFullNameOfFontStruct(dpy, font);
955 if (full_name == NULL)
957 return NULL;
959 while(full_name[i] != '\0' && count < 13)
961 if (full_name[i] == '-')
963 count++;
965 i++;
968 if (count != 13)
970 return NULL;
972 CopyString(&charset, full_name+i);
973 XFree(full_name);
974 return charset;
977 static
978 char *FlocaleGetCharsetFromName(char *name)
980 int l,i,e;
981 char *charset;
983 l = strlen(name);
984 i = l-1;
985 while(i >= 0 && name[i] != '-')
987 i--;
989 if (i == 0 || i == l-1)
991 return NULL;
993 i--;
994 e = i;
995 while(i >= 0 && name[i] != '-')
997 i--;
999 if (i <= 0 || e == i)
1001 return NULL;
1003 CopyString(&charset, name + i + 1);
1004 return charset;
1007 /* return NULL if it is not reasonable to load a FontSet.
1008 * Currently return name if it is reasonable to load a FontSet, but in the
1009 * future we may want to transform name for faster FontSet loading */
1010 static
1011 char *FlocaleFixNameForFontSet(Display *dpy, char *name, char *module)
1013 char *new_name;
1014 char *charset;
1015 XFontStruct *test_font = NULL;
1017 if (!name)
1019 return NULL;
1022 new_name = name;
1024 if (strchr(name, ','))
1026 /* tmp, do not handle "," separated list */
1027 return name;
1029 charset = FlocaleGetCharsetFromName(name);
1030 if (charset == NULL && !strchr(name, '*') && !strchr(name, '?'))
1032 /* probably a font alias! */
1033 if ((test_font = XLoadQueryFont(dpy, name)))
1035 charset = FlocaleGetCharsetOfFontStruct(dpy, test_font);
1036 XFreeFont(dpy, test_font);
1039 if (charset != NULL)
1041 if (!strchr(charset, '*') && !strchr(charset, '?') &&
1042 !FlocaleCharsetIsCharsetXLocale(dpy, charset, module))
1044 /* if the charset is fully specified and do not match
1045 * one of the X locale charset */
1046 new_name = NULL;
1047 #if 0
1048 fprintf(stderr,"[%s][FlocaleGetFontSet]: WARNING -- "
1049 "Use of a non X locale charset '%s' when "
1050 "loading font: %s\n",
1051 (module)? module:"fvwmlibs", charset, name);
1052 #endif
1054 free(charset);
1056 return new_name;
1060 * Fonts loading
1063 static
1064 FlocaleFont *FlocaleGetFftFont(
1065 Display *dpy, char *fontname, char *encoding, char *module)
1067 FftFontType *fftf = NULL;
1068 FlocaleFont *flf = NULL;
1069 char *fn, *hints = NULL;
1071 hints = GetQuotedString(fontname, &fn, "/", NULL, NULL, NULL);
1072 if (fn == NULL)
1074 fn = FLOCALE_FFT_FALLBACK_FONT;
1076 else if (*fn == '\0')
1078 free(fn);
1079 fn = FLOCALE_FFT_FALLBACK_FONT;
1081 fftf = FftGetFont(dpy, fn, module);
1082 if (fftf == NULL)
1084 if (fn != NULL && fn != FLOCALE_FFT_FALLBACK_FONT)
1086 free(fn);
1088 return NULL;
1090 flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
1091 memset(flf, '\0', sizeof(FlocaleFont));
1092 flf->count = 1;
1093 flf->fftf = *fftf;
1094 FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
1095 FftGetFontHeights(
1096 &flf->fftf, &flf->height, &flf->ascent, &flf->descent);
1097 FftGetFontWidths(flf, &flf->max_char_width);
1098 free(fftf);
1099 if (fn != NULL && fn != FLOCALE_FFT_FALLBACK_FONT)
1101 free(fn);
1104 return flf;
1107 static
1108 FlocaleFont *FlocaleGetFontSet(
1109 Display *dpy, char *fontname, char *encoding, char *module)
1111 static int mc_errors = 0;
1112 FlocaleFont *flf = NULL;
1113 XFontSet fontset = NULL;
1114 char **ml;
1115 int mc,i;
1116 char *ds;
1117 XFontSetExtents *fset_extents;
1118 char *fn, *hints = NULL, *fn_fixed = NULL;
1120 hints = GetQuotedString(fontname, &fn, "/", NULL, NULL, NULL);
1121 if (*fn == '\0')
1123 free(fn);
1124 fn = fn_fixed = FLOCALE_MB_FALLBACK_FONT;
1126 else if (!(fn_fixed = FlocaleFixNameForFontSet(dpy, fn, module)))
1128 if (fn != NULL && fn != FLOCALE_MB_FALLBACK_FONT)
1130 free(fn);
1132 return NULL;
1134 if (!(fontset = XCreateFontSet(dpy, fn_fixed, &ml, &mc, &ds)))
1136 if (fn_fixed && fn_fixed != fn)
1138 free(fn_fixed);
1140 if (fn != NULL && fn != FLOCALE_MB_FALLBACK_FONT)
1142 free(fn);
1144 return NULL;
1147 if (mc > 0)
1149 if (mc_errors <= FLOCALE_NUMBER_MISS_CSET_ERR_MSG)
1151 mc_errors++;
1152 fprintf(stderr,
1153 "[%s][FlocaleGetFontSet]: (%s)"
1154 " Missing font charsets:\n",
1155 (module)? module: "FVWMlibs", fontname);
1156 for (i = 0; i < mc; i++)
1158 fprintf(stderr, "%s", ml[i]);
1159 if (i < mc - 1)
1160 fprintf(stderr, ", ");
1162 fprintf(stderr, "\n");
1163 if (mc_errors == FLOCALE_NUMBER_MISS_CSET_ERR_MSG)
1165 fprintf(stderr,
1166 "[%s][FlocaleGetFontSet]: No more"
1167 " missing charset reportings\n",
1168 (module)? module: "FVWMlibs");
1171 XFreeStringList(ml);
1174 flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
1175 memset(flf, '\0', sizeof(FlocaleFont));
1176 flf->count = 1;
1177 flf->fontset = fontset;
1178 FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
1179 fset_extents = XExtentsOfFontSet(fontset);
1180 flf->height = fset_extents->max_ink_extent.height;
1181 flf->ascent = - fset_extents->max_ink_extent.y;
1182 flf->descent = fset_extents->max_ink_extent.height +
1183 fset_extents->max_ink_extent.y;
1184 flf->max_char_width = fset_extents->max_ink_extent.width;
1185 if (fn_fixed && fn_fixed != fn)
1187 free(fn_fixed);
1189 if (fn != NULL && fn != FLOCALE_MB_FALLBACK_FONT)
1191 free(fn);
1194 return flf;
1197 static
1198 FlocaleFont *FlocaleGetFont(
1199 Display *dpy, char *fontname, char *encoding, char *module)
1201 XFontStruct *font = NULL;
1202 FlocaleFont *flf;
1203 char *str,*fn,*tmp;
1204 char *hints = NULL;
1206 hints = GetQuotedString(fontname, &tmp, "/", NULL, NULL, NULL);
1207 str = GetQuotedString(tmp, &fn, ",", NULL, NULL, NULL);
1208 while (!font && fn)
1210 if (*fn == '\0')
1212 free(fn);
1213 fn = FLOCALE_FALLBACK_FONT;
1215 font = XLoadQueryFont(dpy, fn);
1216 if (fn != NULL && fn != FLOCALE_FALLBACK_FONT)
1218 free(fn);
1219 fn = NULL;
1221 if (!font && str && *str)
1223 str = GetQuotedString(str, &fn, ",", NULL, NULL, NULL);
1226 if (font == NULL)
1228 if (fn != NULL && fn != FLOCALE_FALLBACK_FONT)
1230 free(fn);
1232 if (tmp != NULL)
1234 free(tmp);
1236 return NULL;
1239 flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
1240 memset(flf, '\0', sizeof(FlocaleFont));
1241 flf->count = 1;
1242 flf->fontset = None;
1243 flf->fftf.fftfont = NULL;
1244 flf->font = font;
1245 FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
1246 flf->height = font->max_bounds.ascent + font->max_bounds.descent;
1247 flf->ascent = font->max_bounds.ascent;
1248 flf->descent = font->max_bounds.descent;
1249 flf->max_char_width = font->max_bounds.width;
1250 if (flf->font->max_byte1 > 0)
1251 flf->flags.is_mb = True;
1252 if (fn != NULL && fn != FLOCALE_FALLBACK_FONT)
1254 free(fn);
1256 if (tmp != NULL)
1258 free(tmp);
1261 return flf;
1264 static
1265 FlocaleFont *FlocaleGetFontOrFontSet(
1266 Display *dpy, char *fontname, char *encoding, char *fullname,
1267 char *module)
1269 FlocaleFont *flf = NULL;
1271 if (fontname && strlen(fontname) > 3 &&
1272 strncasecmp("xft:", fontname, 4) == 0)
1274 if (FftSupport)
1276 flf = FlocaleGetFftFont(
1277 dpy, fontname+4, encoding, module);
1279 if (flf)
1281 CopyString(&flf->name, fullname);
1283 return flf;
1285 if (flf == NULL && Flocale != NULL && fontname)
1287 flf = FlocaleGetFontSet(dpy, fontname, encoding, module);
1289 if (flf == NULL && fontname)
1291 flf = FlocaleGetFont(dpy, fontname, encoding, module);
1293 if (flf && fontname)
1295 if (StrEquals(fullname, FLOCALE_MB_FALLBACK_FONT))
1297 flf->name = FLOCALE_MB_FALLBACK_FONT;
1299 else if (StrEquals(fullname, FLOCALE_FALLBACK_FONT))
1301 flf->name = FLOCALE_FALLBACK_FONT;
1303 else
1305 CopyString(&flf->name, fullname);
1307 return flf;
1309 return NULL;
1313 * locale local functions
1316 static
1317 void FlocaleSetlocaleForX(
1318 int category, const char *locale, const char *module)
1320 if ((Flocale = setlocale(category, locale)) == NULL)
1322 fprintf(stderr,
1323 "[%s][%s]: ERROR -- Cannot set locale. Please check"
1324 " your $LC_CTYPE or $LANG.\n",
1325 (module == NULL)? "" : module, "FlocaleSetlocaleForX");
1326 return;
1328 if (!XSupportsLocale())
1330 fprintf(stderr,
1331 "[%s][%s]: WARNING -- X does not support locale %s\n",
1332 (module == NULL)? "": module, "FlocaleSetlocaleForX",
1333 Flocale);
1334 Flocale = NULL;
1338 /* ---------------------------- interface functions ------------------------ */
1341 * locale initialisation
1344 void FlocaleInit(
1345 int category, const char *locale, const char *modifiers,
1346 const char *module)
1349 FlocaleSetlocaleForX(category, locale, module);
1350 if (Flocale == NULL)
1351 return;
1353 if (modifiers != NULL &&
1354 (Fmodifiers = XSetLocaleModifiers(modifiers)) == NULL)
1356 fprintf(stderr,
1357 "[%s][%s]: WARNING -- Cannot set locale modifiers\n",
1358 (module == NULL)? "": module, "FlocaleInit");
1360 #if FLOCALE_DEBUG_SETLOCALE
1361 fprintf(stderr,"[%s][FlocaleInit] locale: %s, modifier: %s\n",
1362 module, Flocale, Fmodifiers);
1363 #endif
1367 * fonts loading
1369 char *prefix_list[] =
1371 "Shadow=",
1372 "StringEncoding=",
1373 NULL
1376 FlocaleFont *FlocaleLoadFont(Display *dpy, char *fontname, char *module)
1378 FlocaleFont *flf = FlocaleFontList;
1379 Bool ask_default = False;
1380 char *t;
1381 char *str, *opt_str, *encoding= NULL, *fn = NULL;
1382 int shadow_size = 0;
1383 int shadow_offset = 0;
1384 int shadow_dir = MULTI_DIR_SE;
1385 int i;
1387 /* removing quoting for modules */
1388 if (fontname && (t = strchr("\"'`", *fontname)))
1390 char c = *t;
1391 fontname++;
1392 if (fontname[strlen(fontname)-1] == c)
1393 fontname[strlen(fontname)-1] = 0;
1396 if (fontname == NULL || *fontname == 0)
1398 ask_default = True;
1399 fontname = FLOCALE_MB_FALLBACK_FONT;
1402 while (flf)
1404 char *c1, *c2;
1406 for (c1 = fontname, c2 = flf->name; *c1 && *c2; ++c1, ++c2)
1408 if (*c1 != *c2)
1410 break;
1413 if (!*c1 && !*c2)
1415 flf->count++;
1416 return flf;
1418 flf = flf->next;
1421 /* not cached load the font as a ";" separated list */
1423 /* But first see if we have a shadow relief and/or an encoding */
1424 str = fontname;
1425 while ((i = GetTokenIndex(str, prefix_list, -1, &str)) > -1)
1427 str = GetQuotedString(str, &opt_str, ":", NULL, NULL, NULL);
1428 switch(i)
1430 case 0: /* shadow= */
1431 FlocaleParseShadow(
1432 opt_str, &shadow_size, &shadow_offset,
1433 &shadow_dir, fontname, module);
1434 break;
1435 case 1: /* encoding= */
1436 if (encoding != NULL)
1438 free(encoding);
1439 encoding = NULL;
1441 if (opt_str && *opt_str)
1443 CopyString(&encoding, opt_str);
1445 break;
1446 default:
1447 break;
1449 if (opt_str != NULL)
1450 free(opt_str);
1452 if (str && *str)
1454 str = GetQuotedString(str, &fn, ";", NULL, NULL, NULL);
1456 else
1458 fn = FLOCALE_MB_FALLBACK_FONT;
1460 while (!flf && (fn && *fn))
1462 flf = FlocaleGetFontOrFontSet(
1463 dpy, fn, encoding, fontname, module);
1464 if (fn != NULL && fn != FLOCALE_MB_FALLBACK_FONT &&
1465 fn != FLOCALE_FALLBACK_FONT)
1467 free(fn);
1468 fn = NULL;
1470 if (!flf && str && *str)
1472 str = GetQuotedString(str, &fn, ";", NULL, NULL, NULL);
1475 if (fn != NULL && fn != FLOCALE_MB_FALLBACK_FONT &&
1476 fn != FLOCALE_FALLBACK_FONT)
1478 free(fn);
1481 if (flf == NULL)
1483 /* loading failed, try default font */
1484 if (!ask_default)
1486 fprintf(stderr,"[%s][FlocaleLoadFont]: "
1487 "WARNING -- can't load font '%s',"
1488 " trying default:\n",
1489 (module)? module: "FVWMlibs", fontname);
1491 else
1493 /* we already tried default fonts: try again? yes */
1495 if (Flocale != NULL)
1497 if (!ask_default)
1499 fprintf(stderr, "\t%s\n",
1500 FLOCALE_MB_FALLBACK_FONT);
1502 if ((flf = FlocaleGetFontSet(
1503 dpy, FLOCALE_MB_FALLBACK_FONT, NULL,
1504 module)) != NULL)
1506 flf->name = FLOCALE_MB_FALLBACK_FONT;
1509 if (flf == NULL)
1511 if (!ask_default)
1513 fprintf(stderr,"\t%s\n",
1514 FLOCALE_FALLBACK_FONT);
1516 if ((flf =
1517 FlocaleGetFont(
1518 dpy, FLOCALE_FALLBACK_FONT, NULL,
1519 module)) != NULL)
1521 flf->name = FLOCALE_FALLBACK_FONT;
1523 else if (!ask_default)
1525 fprintf(stderr,
1526 "[%s][FlocaleLoadFont]:"
1527 " ERROR -- can't load font.\n",
1528 (module)? module: "FVWMlibs");
1530 else
1532 fprintf(stderr,
1533 "[%s][FlocaleLoadFont]: ERROR"
1534 " -- can't load default font:\n",
1535 (module)? module: "FVWMlibs");
1536 fprintf(stderr, "\t%s\n",
1537 FLOCALE_MB_FALLBACK_FONT);
1538 fprintf(stderr, "\t%s\n",
1539 FLOCALE_FALLBACK_FONT);
1544 if (flf != NULL)
1546 if (shadow_size > 0)
1548 flf->shadow_size = shadow_size;
1549 flf->flags.shadow_dir = shadow_dir;
1550 flf->shadow_offset = shadow_offset;
1551 flf->descent += FLF_SHADOW_DESCENT(flf);
1552 flf->ascent += FLF_SHADOW_ASCENT(flf);
1553 flf->height += FLF_SHADOW_HEIGHT(flf);
1554 flf->max_char_width += FLF_SHADOW_WIDTH(flf);
1556 if (flf->fc == FlocaleCharsetGetUnknownCharset())
1558 fprintf(stderr,"[%s][FlocaleLoadFont]: "
1559 "WARNING -- Unknown charset for font\n\t'%s'\n",
1560 (module)? module: "FVWMlibs", flf->name);
1561 flf->fc = FlocaleCharsetGetDefaultCharset(dpy, module);
1563 else if (flf->str_fc == FlocaleCharsetGetUnknownCharset() &&
1564 (encoding != NULL ||
1565 (FftSupport && flf->fftf.fftfont != NULL &&
1566 flf->fftf.str_encoding != NULL)))
1568 fprintf(stderr,"[%s][FlocaleLoadFont]: "
1569 "WARNING -- Unknown string encoding for font\n"
1570 "\t'%s'\n",
1571 (module)? module: "FVWMlibs", flf->name);
1573 if (flf->str_fc == FlocaleCharsetGetUnknownCharset())
1575 flf->str_fc =
1576 FlocaleCharsetGetDefaultCharset(dpy, module);
1578 flf->next = FlocaleFontList;
1579 FlocaleFontList = flf;
1581 if (encoding != NULL)
1583 free(encoding);
1586 return flf;
1589 void FlocaleUnloadFont(Display *dpy, FlocaleFont *flf)
1591 FlocaleFont *list = FlocaleFontList;
1592 int i = 0;
1594 if (!flf)
1596 return;
1598 /* Remove a weight, still too heavy? */
1599 if (--(flf->count) > 0)
1601 return;
1604 if (flf->name != NULL &&
1605 !StrEquals(flf->name, FLOCALE_MB_FALLBACK_FONT) &&
1606 !StrEquals(flf->name, FLOCALE_FALLBACK_FONT))
1608 free(flf->name);
1610 if (FftSupport && flf->fftf.fftfont != NULL)
1612 FftFontClose(dpy, flf->fftf.fftfont);
1613 if (flf->fftf.fftfont_rotated_90 != NULL)
1614 FftFontClose(dpy, flf->fftf.fftfont_rotated_90);
1615 if (flf->fftf.fftfont_rotated_180 != NULL)
1616 FftFontClose(dpy, flf->fftf.fftfont_rotated_180);
1617 if (flf->fftf.fftfont_rotated_270 != NULL)
1618 FftFontClose(dpy, flf->fftf.fftfont_rotated_270);
1620 if (flf->fontset != NULL)
1622 XFreeFontSet(dpy, flf->fontset);
1624 if (flf->font != NULL)
1626 XFreeFont(dpy, flf->font);
1628 if (flf->flags.must_free_fc)
1630 if (flf->fc->x)
1631 free(flf->fc->x);
1632 if (flf->fc->bidi)
1633 free(flf->fc->bidi);
1634 if (flf->fc->locale != NULL)
1636 while (FLC_GET_LOCALE_CHARSET(flf->fc,i) != NULL)
1638 free(FLC_GET_LOCALE_CHARSET(flf->fc,i));
1639 i++;
1641 free(flf->fc->locale);
1643 free(flf->fc);
1646 /* Link it out of the list (it might not be there) */
1647 if (flf == list) /* in head? simple */
1649 FlocaleFontList = flf->next;
1651 else
1653 while (list && list->next != flf)
1655 /* fast forward until end or found */
1656 list = list->next;
1658 /* not end? means we found it in there, possibly at end */
1659 if (list)
1661 /* link around it */
1662 list->next = flf->next;
1665 free(flf);
1669 * Width and Drawing Text
1672 void FlocaleInitGstpArgs(
1673 flocale_gstp_args *args, FlocaleFont *flf, FlocaleWinString *fws,
1674 int start_x, int start_y)
1676 args->step = 0;
1677 args->offset = flf->shadow_offset + 1;
1678 args->outer_offset = flf->shadow_offset + flf->shadow_size;
1679 args->size = flf->shadow_size;
1680 args->sdir = flf->flags.shadow_dir;
1681 switch (fws->flags.text_rotation)
1683 case ROTATION_270: /* CCW */
1684 args->orig_x = start_x + FLF_SHADOW_UPPER_SIZE(flf);
1685 args->orig_y = start_y + FLF_SHADOW_RIGHT_SIZE(flf);
1686 break;
1687 case ROTATION_180:
1688 args->orig_x = start_x + FLF_SHADOW_RIGHT_SIZE(flf);
1689 args->orig_y = start_y;
1690 break;
1691 case ROTATION_90: /* CW */
1692 args->orig_x = start_x + FLF_SHADOW_BOTTOM_SIZE(flf);
1693 args->orig_y = start_y + FLF_SHADOW_LEFT_SIZE(flf);
1694 break;
1695 case ROTATION_0:
1696 default:
1697 args->orig_x = start_x + FLF_SHADOW_LEFT_SIZE(flf);
1698 args->orig_y = start_y;
1699 break;
1701 args->rot = fws->flags.text_rotation;
1703 return;
1706 Bool FlocaleGetShadowTextPosition(
1707 int *x, int *y, flocale_gstp_args *args)
1709 if (args->step == 0)
1711 args->direction = MULTI_DIR_NONE;
1712 args->inter_step = 0;
1714 if ((args->step == 0 || args->inter_step >= args->num_inter_steps) &&
1715 args->size != 0)
1717 /* setup a new direction */
1718 args->inter_step = 0;
1719 gravity_get_next_multi_dir(args->sdir, &args->direction);
1720 if (args->direction == MULTI_DIR_C)
1722 int size;
1724 size = 2 * (args->outer_offset) + 1;
1725 args->num_inter_steps = size * size;
1727 else
1729 args->num_inter_steps = args->size;
1732 if (args->direction == MULTI_DIR_NONE || args->size == 0)
1734 *x = args->orig_x;
1735 *y = args->orig_y;
1737 return False;
1739 if (args->direction == MULTI_DIR_C)
1741 int tx;
1742 int ty;
1743 int size;
1744 int is_finished;
1746 size = 2 * (args->outer_offset) + 1;
1747 tx = args->inter_step % size - args->outer_offset;
1748 ty = args->inter_step / size - args->outer_offset;
1749 for (is_finished = 0; ty <= args->outer_offset;
1750 ty++, tx = -args->outer_offset)
1752 for (; tx <= args->outer_offset; tx++)
1754 if (tx <= -args->offset ||
1755 tx >= args->offset ||
1756 ty <= -args->offset || ty >= args->offset)
1758 is_finished = 1;
1759 break;
1762 if (is_finished)
1764 break;
1767 args->inter_step =
1768 (tx + args->outer_offset) +
1769 (ty + args->outer_offset) * size;
1770 if (!is_finished)
1772 tx = 0;
1773 ty = 0;
1775 *x = args->orig_x + tx;
1776 *y = args->orig_y + ty;
1778 else if (args->inter_step > 0)
1780 /* into a directional drawing */
1781 (*x) += args->x_sign;
1782 (*y) += args->y_sign;
1784 else
1786 direction_t dir;
1787 direction_t dir_x;
1788 direction_t dir_y;
1790 dir = gravity_multi_dir_to_dir(args->direction);
1791 gravity_split_xy_dir(&dir_x, &dir_y, dir);
1792 args->x_sign = gravity_dir_to_sign_one_axis(dir_x);
1793 args->y_sign = gravity_dir_to_sign_one_axis(dir_y);
1794 gravity_rotate_xy(
1795 args->rot, args->x_sign, args->y_sign,
1796 &args->x_sign, &args->y_sign);
1797 *x = args->orig_x + args->x_sign * args->offset;
1798 *y = args->orig_y + args->y_sign * args->offset;
1800 args->inter_step++;
1801 args->step++;
1803 return True;
1806 void FlocaleDrawString(
1807 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws,
1808 unsigned long flags)
1810 int len;
1811 Bool do_free = False;
1812 Pixel fg = 0, fgsh = 0;
1813 Bool has_fg_pixels = False;
1814 flocale_gstp_args gstp_args;
1815 superimpose_char_t *comb_chars = NULL;
1816 char *curr_str;
1817 int char_len; /* length in number of chars */
1818 int *pixel_pos = NULL;
1819 int i;
1820 int j;
1821 char buf[4];
1822 int curr_pixel_pos;
1823 int curr_len;
1825 if (!fws || !fws->str)
1827 return;
1830 if (flags & FWS_HAVE_LENGTH)
1832 len = fws->len;
1834 else
1836 len = strlen(fws->str);
1839 /* encode the string */
1840 FlocaleEncodeWinString(
1841 dpy, flf, fws, &do_free, &len, &comb_chars, NULL);
1842 curr_str = fws->e_str;
1843 for(char_len = 0, i = 0 ;
1844 i < len && curr_str[i] != 0 ;
1845 char_len++, i += curr_len)
1847 curr_len = FlocaleStringNumberOfBytes(flf, curr_str + i);
1850 /* for superimposition calculate the character positions in pixels */
1851 if (comb_chars != NULL && (
1852 comb_chars[0].c.byte1 != 0 || comb_chars[0].c.byte2 != 0))
1854 /* the second condition is actually redundant,
1855 but there for clarity,
1856 ending at 0 is what's expected in a correct
1857 string */
1858 pixel_pos = (int *)safemalloc(
1859 (char_len != 0 ? char_len : 1) * sizeof(int));
1861 /* if there is 0 bytes in the encoded string, there might
1862 still be combining character to draw (at position 0) */
1863 if(char_len == 0)
1865 pixel_pos[0] = 0;
1868 for(
1869 i = 0, curr_pixel_pos = 0 ;
1870 i < char_len ;
1871 i++, curr_str += curr_len)
1873 curr_len = FlocaleStringNumberOfBytes(flf, curr_str);
1874 for (j = 0 ; j < curr_len ; j++)
1876 buf[j] = curr_str[j];
1878 buf[j] = 0;
1879 pixel_pos[i] = curr_pixel_pos;
1880 /* need to compensate for shadow width (if any) */
1881 curr_pixel_pos +=
1882 FlocaleTextWidth(flf, buf, curr_len) -
1883 FLF_SHADOW_WIDTH(flf);
1887 /* get the pixels */
1888 if (fws->flags.has_colorset)
1890 fg = fws->colorset->fg;
1891 fgsh = fws->colorset->fgsh;
1892 has_fg_pixels = True;
1894 else if (flf->shadow_size != 0)
1896 XGCValues xgcv;
1898 if (XGetGCValues(dpy, fws->gc, GCForeground, &xgcv) != 0)
1900 fg = xgcv.foreground;
1902 else
1904 fg = PictureBlackPixel();
1906 fgsh = GetShadow(fg);
1907 has_fg_pixels = True;
1910 if(flf->font != None &&
1911 (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb))
1913 /* in this case, length is number of 2-byte chars */
1914 len = char_len;
1917 if (fws->flags.text_rotation != ROTATION_0 &&
1918 flf->fftf.fftfont == NULL)
1920 /* pass in information to perform superimposition */
1921 FlocaleRotateDrawString(
1922 dpy, flf, fws, fg, fgsh, has_fg_pixels, len,
1923 comb_chars, pixel_pos);
1925 else if (FftSupport && flf->fftf.fftfont != NULL)
1927 FftDrawString(
1928 dpy, flf, fws, fg, fgsh, has_fg_pixels, len, flags);
1930 else if (flf->fontset != None)
1932 int xt = fws->x;
1933 int yt = fws->y;
1935 FlocaleInitGstpArgs(&gstp_args, flf, fws, fws->x, fws->y);
1936 if (flf->shadow_size != 0)
1938 XSetForeground(dpy, fws->gc, fgsh);
1939 while (FlocaleGetShadowTextPosition(
1940 &xt, &yt, &gstp_args))
1942 XmbDrawString(
1943 dpy, fws->win, flf->fontset, fws->gc,
1944 xt, yt, fws->e_str, len);
1947 if (has_fg_pixels == True)
1949 XSetForeground(dpy, fws->gc, fg);
1951 xt = gstp_args.orig_x;
1952 yt = gstp_args.orig_y;
1953 XmbDrawString(
1954 dpy, fws->win, flf->fontset, fws->gc,
1955 xt, yt, fws->e_str, len);
1957 else if (flf->font != None)
1959 FlocaleFontStructDrawString(
1960 dpy, flf, fws->win, fws->gc, fws->x, fws->y,
1961 fg, fgsh, has_fg_pixels, fws, len, False);
1964 /* here take care of superimposing chars */
1965 i = 0;
1966 if (comb_chars != NULL)
1968 while(comb_chars[i].c.byte1 != 0 && comb_chars[i].c.byte2 != 0)
1970 /* draw composing character on top of corresponding
1971 "real" character */
1972 FlocaleWinString tmp_fws = *fws;
1973 int offset = pixel_pos[comb_chars[i].position];
1974 char *buf2;
1975 int out_len;
1976 curr_len = FlocaleChar2bOneCharToUtf8(comb_chars[i].c,
1977 buf);
1978 buf2 = FiconvUtf8ToCharset(
1979 dpy, flf->str_fc, (const char *)buf, curr_len);
1980 if(buf2 == NULL)
1982 /* if conversion failed, combinational char
1983 is not representable in current charset */
1984 /* just replace with empty string */
1985 buf2 = (char *)safemalloc(sizeof(char));
1986 buf2[0] = 0;
1988 tmp_fws.e_str = buf2;
1989 tmp_fws.str2b = NULL;
1990 if(FftSupport && flf->fftf.fftfont != NULL)
1992 tmp_fws.x = fws->x + offset;
1993 FftDrawString(
1994 dpy, flf, &tmp_fws, fg, fgsh,
1995 has_fg_pixels, strlen(buf2),
1996 flags);
1998 else if(flf->fontset != None)
2000 int xt = fws->x;
2001 int yt = fws->y;
2003 FlocaleInitGstpArgs(
2004 &gstp_args, flf, fws, fws->x, fws->y);
2005 if (flf->shadow_size != 0)
2007 XSetForeground(dpy, fws->gc, fgsh);
2008 while (FlocaleGetShadowTextPosition(
2009 &xt, &yt, &gstp_args))
2011 XmbDrawString(
2012 dpy, fws->win,
2013 flf->fontset,
2014 fws->gc,
2015 xt, yt,
2016 buf2,
2017 strlen(buf2));
2020 XSetForeground(dpy, fws->gc, fg);
2021 xt = gstp_args.orig_x;
2022 yt = gstp_args.orig_y;
2023 XmbDrawString(
2024 dpy, fws->win, flf->fontset, fws->gc,
2025 xt + offset, yt, buf2, strlen(buf2));
2027 else if (flf->font != None)
2029 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
2031 tmp_fws.str2b = (XChar2b *)
2032 safemalloc(2 * sizeof(XChar2b));
2033 tmp_fws.str2b[0] = comb_chars[i].c;
2034 tmp_fws.str2b[1].byte1 = 0;
2035 tmp_fws.str2b[1].byte2 = 0;
2036 out_len = 1;
2037 /*tmp_fws.str2b =
2038 FlocaleUtf8ToUnicodeStr2b(
2039 tmp_fws.e_str,
2040 curr_len, &out_len);*/
2042 else if (flf->flags.is_mb)
2044 tmp_fws.str2b =
2045 FlocaleStringToString2b(
2046 dpy, flf,
2047 tmp_fws.e_str,
2048 curr_len, &out_len);
2050 else
2052 out_len = strlen(buf2);
2054 FlocaleFontStructDrawString(
2055 dpy, flf, fws->win, fws->gc,
2056 fws->x + offset, fws->y, fg, fgsh,
2057 has_fg_pixels, &tmp_fws, out_len,
2058 False);
2061 free(buf2);
2062 if(tmp_fws.str2b != NULL)
2064 free(tmp_fws.str2b);
2066 i++;
2070 if (do_free)
2072 if (fws->e_str != NULL)
2074 free(fws->e_str);
2075 fws->e_str = NULL;
2079 if (fws->str2b != NULL)
2081 free(fws->str2b);
2082 fws->str2b = NULL;
2085 if(comb_chars != NULL)
2087 free(comb_chars);
2088 if(pixel_pos)
2089 free(pixel_pos);
2092 return;
2095 void FlocaleDrawUnderline(
2096 Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, int offset)
2098 int off1, off2, y, x_s, x_e;
2099 superimpose_char_t *comb_chars = NULL;
2100 int *l_to_v = NULL;
2101 Bool do_free = True;
2102 int len = strlen(fws->str);
2103 int l_coffset;
2104 int v_coffset;
2105 int voffset;
2107 if (fws == NULL || fws->str == NULL)
2109 return;
2112 /* need to encode the string first to get BIDI and combining chars */
2113 FlocaleEncodeWinString(dpy, flf, fws, &do_free, &len, &comb_chars,
2114 &l_to_v);
2115 /* we don't need this, only interested in char mapping */
2116 free(comb_chars);
2118 /* now calculate char offset (in bytes) in visual string corresponding
2119 to coffset */
2120 /* calculate absolute position in string (in characters) */
2121 l_coffset = FlocaleStringByteToCharOffset(flf, fws->str, offset);
2122 /* map to an offset in the visual string */
2123 v_coffset = l_to_v[l_coffset];
2124 /* calculate byte offset into visual string */
2125 voffset = FlocaleStringCharToByteOffset(flf, fws->e_str, v_coffset);
2127 off1 = FlocaleTextWidth(flf, fws->e_str, voffset) +
2128 ((voffset == 0)?
2129 FLF_SHADOW_LEFT_SIZE(flf) : - FLF_SHADOW_RIGHT_SIZE(flf) );
2130 off2 = FlocaleTextWidth(flf, fws->e_str + voffset,
2131 FlocaleStringNumberOfBytes(flf, fws->e_str + voffset)) -
2132 FLF_SHADOW_WIDTH(flf) - 1 + off1;
2133 y = fws->y + 2;
2134 x_s = fws->x + off1;
2135 x_e = fws->x + off2;
2137 /* No shadow */
2138 XDrawLine(dpy, fws->win, fws->gc, x_s, y, x_e, y);
2140 /* free encoded string if it isn't the same as input string */
2141 if(fws->e_str != fws->str)
2143 free(fws->e_str);
2144 fws->e_str = NULL;
2147 if(fws->str2b != NULL)
2149 free(fws->str2b);
2150 fws->str2b = NULL;
2152 free(l_to_v);
2154 return;
2157 int FlocaleTextWidth(FlocaleFont *flf, char *str, int sl)
2159 int result = 0;
2160 char *tmp_str;
2161 int new_l,do_free;
2162 superimpose_char_t *comb_chars = NULL;
2164 if (!str || sl == 0)
2165 return 0;
2167 if (sl < 0)
2169 /* a vertical string: nothing to do! */
2170 sl = -sl;
2173 /* FIXME */
2174 /* to avoid eccesive calls iconv (slow in Solaris 8)
2175 don't bother to encode if string is one byte
2176 when drawing a string this function is used to calculate
2177 position of each character (for superimposition) */
2178 if(sl == 1)
2180 tmp_str = str;
2181 new_l = sl;
2182 do_free = False;
2184 else
2186 tmp_str = FlocaleEncodeString(
2187 Pdpy, flf, str, &do_free, sl, &new_l, NULL,
2188 &comb_chars, NULL);
2190 /* if we get zero-length, check to to see if there if there's any
2191 combining chars, if so use an imagninary space as a
2192 "base character" */
2193 if (strlen(tmp_str) == 0 && comb_chars &&
2194 (comb_chars[0].c.byte1 != 0 || comb_chars[0].c.byte2 != 0))
2196 if(do_free)
2198 free(tmp_str);
2200 if(comb_chars)
2202 free(comb_chars);
2204 return FlocaleTextWidth(flf, " ", 1);
2206 else if (FftSupport && flf->fftf.fftfont != NULL)
2208 result = FftTextWidth(flf, tmp_str, new_l);
2210 else if (flf->fontset != None)
2212 result = XmbTextEscapement(flf->fontset, tmp_str, new_l);
2214 else if (flf->font != None)
2216 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb)
2218 XChar2b *str2b;
2219 int nl;
2221 if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
2222 str2b = FlocaleUtf8ToUnicodeStr2b(
2223 tmp_str, new_l, &nl);
2224 else
2225 str2b = FlocaleStringToString2b(
2226 Pdpy, flf, tmp_str, new_l, &nl);
2227 if (str2b != NULL)
2229 result = XTextWidth16(flf->font, str2b, nl);
2230 free(str2b);
2233 else
2235 result = XTextWidth(flf->font, tmp_str, new_l);
2238 if (do_free)
2240 free(tmp_str);
2242 if (comb_chars)
2244 free(comb_chars);
2247 return result + ((result != 0)? FLF_SHADOW_WIDTH(flf):0);
2250 int FlocaleGetMinOffset(
2251 FlocaleFont *flf, rotation_t rotation)
2253 int min_offset;
2255 #ifdef FFT_BUGGY_FREETYPE
2256 switch(rotation)
2258 case ROTATION_270:
2259 case ROTATION_180:
2260 /* better than descent */
2261 min_offset = (flf->descent + flf->height - flf->ascent)/2;
2262 break;
2263 case ROTATION_0:
2264 case ROTATION_90:
2265 default:
2266 /* better than ascent */
2267 min_offset = (flf->ascent + flf->height - flf->descent)/2;
2268 break;
2270 #else
2271 switch(rotation)
2273 case ROTATION_180:
2274 case ROTATION_90:
2275 /* better than descent */
2276 min_offset = (flf->descent + flf->height - flf->ascent)/2;
2277 break;
2278 case ROTATION_270:
2279 case ROTATION_0:
2280 default:
2281 /* better than ascent */
2282 min_offset = (flf->ascent + flf->height - flf->descent)/2;
2283 break;
2285 #endif
2286 return min_offset;
2289 void FlocaleAllocateWinString(FlocaleWinString **pfws)
2291 *pfws = (FlocaleWinString *)safemalloc(sizeof(FlocaleWinString));
2292 memset(*pfws, '\0', sizeof(FlocaleWinString));
2296 * Text properties
2298 void FlocaleGetNameProperty(
2299 Status (func)(Display *, Window, XTextProperty *), Display *dpy,
2300 Window w, FlocaleNameString *ret_name)
2302 char **list;
2303 int num;
2304 XTextProperty text_prop;
2306 list = NULL;
2307 if (func(dpy, w, &text_prop) == 0)
2309 return;
2311 if (text_prop.encoding == XA_STRING)
2313 /* STRING encoding, use this as it is */
2314 ret_name->name = (char *)text_prop.value;
2315 ret_name->name_list = NULL;
2316 return;
2318 /* not STRING encoding, try to convert XA_COMPOUND_TEXT */
2319 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success
2320 && num > 0 && *list)
2322 /* Does not consider the conversion is REALLY succeeded:
2323 * XmbTextPropertyToTextList return 0 (== Success) on success,
2324 * a negative int if it fails (and in this case we are not
2325 * here), the number of unconvertible char on "partial"
2326 * success*/
2327 XFree(text_prop.value); /* return of XGetWM(Icon)Name() */
2328 ret_name->name = *list;
2329 ret_name->name_list = list;
2331 else
2333 if (list)
2335 XFreeStringList(list);
2337 ret_name->name = (char *)text_prop.value;
2338 ret_name->name_list = NULL;
2342 void FlocaleFreeNameProperty(FlocaleNameString *ptext)
2344 if (ptext->name_list != NULL)
2346 if (ptext->name != NULL && ptext->name != *ptext->name_list)
2347 XFree(ptext->name);
2348 XFreeStringList(ptext->name_list);
2349 ptext->name_list = NULL;
2351 else if (ptext->name != NULL)
2353 XFree(ptext->name);
2355 ptext->name = NULL;
2357 return;
2360 Bool FlocaleTextListToTextProperty(
2361 Display *dpy, char **list, int count, XICCEncodingStyle style,
2362 XTextProperty *text_prop_return)
2364 int ret = False;
2366 if (Flocale != NULL)
2368 ret = XmbTextListToTextProperty(
2369 dpy, list, count, style, text_prop_return);
2370 if (ret == XNoMemory)
2372 ret = False;
2374 else
2376 /* ret == Success or the number of unconvertible
2377 * characters. ret should be != XLocaleNotSupported
2378 * because in this case Flocale == NULL */
2379 ret = True;
2382 if (!ret)
2384 if (XStringListToTextProperty(
2385 list, count, text_prop_return) == 0)
2387 ret = False;
2389 else
2391 ret = True;
2395 return ret;
2399 * Info
2401 void FlocalePrintLocaleInfo(Display *dpy, int verbose)
2403 FlocaleFont *flf = FlocaleFontList;
2404 int count = 0;
2405 FlocaleCharset *cs;
2407 fflush(stderr);
2408 fflush(stdout);
2409 fprintf(stderr,"FVWM info on locale:\n");
2410 fprintf(stderr," locale: %s, Modifier: %s\n",
2411 (Flocale)? Flocale:"", (Fmodifiers)? Fmodifiers:"");
2412 cs = FlocaleCharsetGetDefaultCharset(dpy, NULL);
2413 fprintf(stderr," Default Charset: X: %s, Iconv: %s, Bidi: %s\n",
2414 cs->x,
2415 (cs->iconv_index >= 0)?
2416 cs->locale[cs->iconv_index]:"Not defined",
2417 (cs->bidi)? "Yes":"No");
2418 FlocaleCharsetPrintXOMInfo();
2419 while (flf)
2421 count++;
2422 flf = flf->next;
2424 fprintf(stderr," Number of loaded font: %i\n", count);
2425 if (verbose)
2427 count = 0;
2428 flf = FlocaleFontList;
2429 while(flf)
2431 cs = flf->fc;
2432 fprintf(stderr," * Font number %i\n", count);
2433 fprintf(stderr," fvwm info:\n");
2434 fprintf(stderr," Name: %s\n",
2435 (flf->name)? flf->name:"");
2436 fprintf(stderr," Cache count: %i\n", flf->count);
2437 fprintf(stderr," Type: ");
2438 if (flf->font)
2440 fprintf(stderr,"FontStruct\n");
2442 else if (flf->fontset)
2444 fprintf(stderr,"FontSet\n");
2446 else
2448 fprintf(stderr,"XftFont\n");
2450 fprintf(stderr, " Charset: X: %s, Iconv: %s, "
2451 "Bidi: %s\n",
2452 cs->x,
2453 (cs->iconv_index >= 0)?
2454 cs->locale[cs->iconv_index]:"Not defined",
2455 (cs->bidi)? "Yes":"No");
2456 fprintf(stderr," height: %i, ascent: %i, "
2457 "descent: %i\n", flf->height, flf->ascent,
2458 flf->descent);
2459 fprintf(stderr," shadow size: %i, "
2460 "shadow offset: %i, shadow direction:%i\n",
2461 flf->shadow_size, flf->shadow_offset,
2462 flf->flags.shadow_dir);
2463 if (verbose >= 2)
2465 if (flf->fftf.fftfont != NULL)
2467 FftFontType *fftf;
2469 fftf = &flf->fftf;
2470 fprintf(stderr, " Xft info:\n"
2471 " - Vertical font:");
2472 FftPrintPatternInfo(
2473 fftf->fftfont, False);
2474 fprintf(stderr, " "
2475 "- Rotated font 90:");
2476 if (fftf->fftfont_rotated_90)
2477 FftPrintPatternInfo(
2478 fftf->
2479 fftfont_rotated_90,
2480 True);
2481 else
2482 fprintf(stderr, " None\n");
2483 fprintf(stderr, " "
2484 "- Rotated font 270:");
2485 if (fftf->fftfont_rotated_270)
2486 FftPrintPatternInfo(
2487 fftf->
2488 fftfont_rotated_270,
2489 True);
2490 else
2491 fprintf(stderr, " None\n");
2492 fprintf(stderr, " "
2493 "- Rotated font 180:");
2494 if (fftf->fftfont_rotated_180)
2495 FftPrintPatternInfo(
2496 fftf->
2497 fftfont_rotated_180,
2498 True);
2499 else
2500 fprintf(stderr, " None\n");
2502 else if (flf->font != NULL)
2504 char *full_name;
2506 full_name =
2507 FlocaleGetFullNameOfFontStruct(
2508 dpy, flf->font);
2509 fprintf(stderr, " X info:\n"
2510 " %s\n",
2511 (full_name)? full_name:"?");
2512 if (full_name != NULL)
2514 XFree(full_name);
2517 else if (flf->fontset != NULL)
2519 int n,i;
2520 XFontStruct **font_struct_list;
2521 char **font_name_list;
2523 fprintf(stderr, " X info:\n");
2524 n = XFontsOfFontSet(
2525 flf->fontset,
2526 &font_struct_list,
2527 &font_name_list);
2528 for(i = 0; i < n; i++)
2530 fprintf(stderr,
2531 " %s\n",
2532 font_name_list[i]);
2536 count++;
2537 flf = flf->next;