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
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 ---------------------- */
44 #include <X11/Xutil.h>
45 #include <X11/Xatom.h>
50 #include "ColorUtils.h"
53 #include "PictureBase.h"
55 #include "FlocaleCharset.h"
57 #include "FftInterface.h"
60 #include "CombineChars.h"
62 /* ---------------------------- local definitions -------------------------- */
64 /* ---------------------------- local macros ------------------------------- */
66 #define FSwitchDrawString(use_16, dpy, d, gc, x, y, s8, s16, l) \
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) \
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
104 void FlocaleParseShadow(char *str
, int *shadow_size
, int *shadow_offset
,
105 int *direction
, char * fontname
, char *module
)
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) ||
118 fprintf(stderr
,"[%s][FlocaleParseShadow]: WARNING -- bad "
119 "shadow size in font name:\n\t'%s'\n",
120 (module
)? module
: "fvwm", fontname
);
123 if (*shadow_size
== 0)
128 if (dir_str
&& *dir_str
&&
129 (GetIntegerArguments(dir_str
, NULL
, shadow_offset
, 1) == 1))
131 if (*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"
148 (module
)? module
: "fvwmlibs", fontname
);
149 PeekToken(dir_str
, &dir_str
); /* skip it */
156 if (*direction
== MULTI_DIR_NONE
)
157 *direction
= MULTI_DIR_SE
;
161 * some simple converters
165 int FlocaleChar2bOneCharToUtf8(XChar2b c
, char *buf
)
168 char byte1
= c
.byte1
;
169 char byte2
= c
.byte2
;
170 unsigned short ucs2
= ((unsigned short)byte1
<< 8) + byte2
;
178 else if(ucs2
<= 0x7ff)
181 buf
[0] = (ucs2
>> 6) | 0xc0;
182 buf
[1] = (ucs2
& 0x3f) | 0x80;
188 buf
[0] = (ucs2
>> 12) | 0xe0;
189 buf
[1] = ((ucs2
& 0xfff) >> 6) | 0x80;
190 buf
[2] = (ucs2
& 0x3f) | 0x80;
196 /* return number of bytes of character at current position
197 (pointed to by str) */
198 int FlocaleStringNumberOfBytes(FlocaleFont
*flf
, const char *str
)
201 if(FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
204 if ((str
[0] & 0x80) == 0)
208 else if((str
[0] & ~0xdf) == 0)
214 /* this handles only 16-bit Unicode */
218 else if(flf
->flags
.is_mb
)
220 /* non-UTF-8 multibyte encoding */
221 if ((str
[0] & 0x80) == 0)
232 /* we must be using an "ordinary" 8-bit encoding */
238 /* given a string, font specifying its locale and a byte offset gives
240 int FlocaleStringByteToCharOffset(FlocaleFont
*flf
, const char *str
,
243 const char *curr_ptr
= str
;
245 int len
= strlen(str
);
250 i
< offset
&& i
< len
;
251 i
+= curr_len
, curr_ptr
+= curr_len
, coffset
++)
253 curr_len
= FlocaleStringNumberOfBytes(flf
, curr_ptr
);
258 /* like above but reversed, ie. return byte offset corresponding to given
260 int FlocaleStringCharToByteOffset(FlocaleFont
*flf
, const char *str
,
263 const char *curr_ptr
= str
;
265 int len
= strlen(str
);
270 i
< coffset
&& i
< len
;
271 offset
+= curr_len
, curr_ptr
+= curr_len
, i
++)
273 curr_len
= FlocaleStringNumberOfBytes(flf
, curr_ptr
);
278 /* return length of string in characters */
279 int FlocaleStringCharLength(FlocaleFont
*flf
, const char *str
)
282 int str_len
= strlen(str
);
283 for(i
= 0, len
= 0 ; i
< str_len
;
284 i
+= FlocaleStringNumberOfBytes(flf
, str
+i
), len
++);
289 XChar2b
*FlocaleUtf8ToUnicodeStr2b(char *str
, int len
, int *nl
)
291 XChar2b
*str2b
= NULL
;
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
];
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);
311 t
= ((str
[i
] & 0x0f) << 12) + ((str
[i
+1] & 0x3f) << 6)+
313 str2b
[j
].byte2
= (unsigned char)(t
& 0xff);
314 str2b
[j
].byte1
= (unsigned char)(t
>> 8);
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- */
331 XChar2b
*FlocaleStringToString2b(
332 Display
*dpy
, FlocaleFont
*flf
, char *str
, int len
, int *nl
)
334 XChar2b
*str2b
= NULL
;
336 Bool free_str
= False
;
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
,
353 else if (flf
->fc
&& StrEquals(flf
->fc
->x
,"big5-0"))
357 str2b
= (XChar2b
*)safemalloc((len
+1)*sizeof(XChar2b
));
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
368 str2b
[j
].byte1
= 0x23; /* magic number! */
369 str2b
[j
].byte2
= str
[i
++];
373 /* mb gl (for gr replace & 0x7f by | 0x80 ...)
375 str2b
[j
].byte1
= str
[i
++] & 0x7f;
376 str2b
[j
].byte2
= str
[i
++] & 0x7f;
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 */
395 str2b
[j
].byte1
= 0xa2; /* magic number! */
396 str2b
[j
].byte2
= str
[i
++];
398 /* a blanck char ... */
399 str2b
[j
].byte1
= 0x21;
400 str2b
[j
].byte2
= 0x21;
404 str2b
[j
].byte1
= str
[i
++];
405 str2b
[j
].byte2
= str
[i
++];
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
,
428 char *str1
, *str2
, *str3
;
432 Bool do_iconv
= True
;
433 const char *bidi_charset
;
441 if (flf
->str_fc
== NULL
|| flf
->fc
== NULL
||
442 flf
->fc
== flf
->str_fc
)
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 */
459 len
= CombineChars((unsigned char *)tmp_str
,
460 strlen(tmp_str
), comb_chars
,
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
);
472 *nl
= len
= strlen(str1
);
477 /* convert back to current charset fail */
484 if (FiconvSupport
&& do_iconv
)
486 str2
= FiconvCharsetToCharset(
487 dpy
, flf
->str_fc
, flf
->fc
, (const char *)str1
, len
);
490 /* fail to convert */
495 if (*do_free
&& str1
)
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
++)
530 if (FlocaleGetBidiCharset(dpy
, flf
->str_fc
) != NULL
&&
531 (bidi_charset
= FlocaleGetBidiCharset(dpy
, flf
->fc
)) != NULL
)
533 str3
= FBidiConvert(str2
, bidi_charset
, len1
,
535 comb_chars
!= NULL
? *comb_chars
: NULL
,
536 l_to_v
!= NULL
? *l_to_v
: NULL
);
537 if (str3
!= NULL
&& str3
!= str2
)
547 /* if we failed to do BIDI convert, return string string from
552 /* we already have the logical to visual mapping
553 from combining phase */
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
)
567 fws
->e_str
= FlocaleEncodeString(
568 dpy
, flf
, fws
->str
, do_free
, *len
, len
, NULL
, comb_chars
,
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
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
,
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
)
609 /* for rotated drawing */
610 FSwitchDrawImageString(
611 is_string16
, dpy
, d
, gc
, x
, y
, fws
->e_str
, fws
->str2b
,
616 FlocaleInitGstpArgs(&gstp_args
, flf
, fws
, x
, y
);
618 if (flf
->shadow_size
!= 0 && has_fg_pixels
== True
)
620 XSetForeground(dpy
, fws
->gc
, fgsh
);
621 while (FlocaleGetShadowTextPosition(
622 &xt
, &yt
, &gstp_args
))
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
;
636 is_string16
, dpy
, d
, gc
, xt
,yt
, fws
->e_str
, fws
->str2b
,
644 * Rotated Text Drawing with a FontStruct or a FontSet
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
;
659 int width
, height
, descent
, min_offset
;
660 XImage
*image
, *rotated_image
;
661 Pixmap canvas_pix
, rotated_pix
;
662 flocale_gstp_args gstp_args
;
665 if (fws
->str
== NULL
|| len
< 1)
669 if (fws
->flags
.text_rotation
== ROTATION_0
)
671 return; /* should not happen */
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
);;
690 /* glyph width and height of the normal text */
695 normal_len
= (normal_w
- 1) / 8 + 1;
697 /* create and clear the canvas */
698 canvas_pix
= XCreatePixmap(dpy
, fws
->win
, width
, height
, 1);
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,
714 fg
, fgsh
, has_fg_pixels
,
717 else if (flf
->fontset
!= None
)
720 dpy
, canvas_pix
, flf
->fontset
, font_gc
, 0,
721 height
- descent
, fws
->e_str
, len
);
724 /* here take care of superimposing chars */
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
732 FlocaleWinString tmp_fws
= *fws
;
733 int offset
= pixel_pos
[comb_chars
[i
].position
];
734 int curr_len
= FlocaleChar2bOneCharToUtf8(
738 char *buf2
= FiconvUtf8ToCharset(
741 (const char *)buf
,curr_len
);
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));
750 tmp_fws
.e_str
= buf2
;
751 tmp_fws
.str2b
= NULL
;
752 if(flf
->fontset
!= None
)
754 XmbDrawString(dpy
, canvas_pix
, flf
->fontset
,
756 height
- descent
, 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;
770 else if (flf
->flags
.is_mb
)
773 FlocaleStringToString2b(
774 dpy
, flf
, tmp_fws
.e_str
,
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
,
790 if(tmp_fws
.str2b
!= NULL
)
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
)
808 image
->byte_order
= image
->bitmap_bit_order
= MSBFirst
;
810 /* extract character from canvas */
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
;
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
)
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
++)
850 if (fws
->flags
.text_rotation
== ROTATION_270
)
853 (normal_w
- j
- 1) / 8
854 ] & (128 >> ((normal_w
- j
- 1) % 8));
856 else if (fws
->flags
.text_rotation
== ROTATION_180
)
858 (normal_h
- j
- 1) * normal_len
+
859 (normal_w
- i
- 1) / 8
860 ] & (128 >> ((normal_w
- i
- 1) % 8));
862 else /* ROTATION_90 */
864 (normal_h
- i
- 1) * normal_len
+
865 j
/ 8] & (128 >> (j
% 8));
868 rotated_data
[j
* rotated_len
+ 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);
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
)
892 xpfg
= fws
->x
- min_offset
;
897 ypfg
= fws
->y
- min_offset
+
898 FLF_SHADOW_BOTTOM_SIZE(flf
);
902 xpfg
= fws
->x
- min_offset
;
908 ypfg
= fws
->y
- min_offset
;
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
);
924 dpy
, fws
->win
, my_gc
, xpsh
, ypsh
, rotated_w
,
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
);
938 * Fonts info and checking
942 char *FlocaleGetFullNameOfFontStruct(Display
*dpy
, XFontStruct
*font
)
944 char *full_name
= NULL
;
947 if (XGetFontProperty(font
, XA_FONT
, &value
))
949 full_name
= XGetAtomName(dpy
, value
);
955 char *FlocaleGetCharsetOfFontStruct(Display
*dpy
, XFontStruct
*font
)
959 char *charset
= NULL
;
962 full_name
= FlocaleGetFullNameOfFontStruct(dpy
, font
);
963 if (full_name
== NULL
)
967 while(full_name
[i
] != '\0' && count
< 13)
969 if (full_name
[i
] == '-')
980 CopyString(&charset
, full_name
+i
);
986 char *FlocaleGetCharsetFromName(char *name
)
993 while(i
>= 0 && name
[i
] != '-')
997 if (i
== 0 || i
== l
-1)
1003 while(i
>= 0 && name
[i
] != '-')
1007 if (i
<= 0 || e
== i
)
1011 CopyString(&charset
, name
+ i
+ 1);
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 */
1019 char *FlocaleFixNameForFontSet(Display
*dpy
, char *name
, char *module
)
1023 XFontStruct
*test_font
= NULL
;
1032 if (strchr(name
, ','))
1034 /* tmp, do not handle "," separated list */
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 */
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
);
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
);
1082 fn
= fft_fallback_font
;
1084 else if (*fn
== '\0')
1087 fn
= fft_fallback_font
;
1089 fftf
= FftGetFont(dpy
, fn
, module
);
1092 if (fn
!= NULL
&& fn
!= fft_fallback_font
)
1098 flf
= (FlocaleFont
*)safemalloc(sizeof(FlocaleFont
));
1099 memset(flf
, '\0', sizeof(FlocaleFont
));
1102 FlocaleCharsetSetFlocaleCharset(dpy
, flf
, hints
, encoding
, module
);
1104 &flf
->fftf
, &flf
->height
, &flf
->ascent
, &flf
->descent
);
1105 FftGetFontWidths(flf
, &flf
->max_char_width
);
1107 if (fn
!= NULL
&& fn
!= fft_fallback_font
)
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
;
1125 XFontSetExtents
*fset_extents
;
1126 char *fn
, *hints
= NULL
, *fn_fixed
= NULL
;
1128 hints
= GetQuotedString(fontname
, &fn
, "/", NULL
, NULL
, NULL
);
1132 fn
= fn_fixed
= mb_fallback_font
;
1134 else if (!(fn_fixed
= FlocaleFixNameForFontSet(dpy
, fn
, module
)))
1136 if (fn
!= NULL
&& fn
!= mb_fallback_font
)
1142 if (!(fontset
= XCreateFontSet(dpy
, fn_fixed
, &ml
, &mc
, &ds
)))
1144 if (fn_fixed
&& fn_fixed
!= fn
)
1148 if (fn
!= NULL
&& fn
!= mb_fallback_font
)
1157 if (mc_errors
<= FLOCALE_NUMBER_MISS_CSET_ERR_MSG
)
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
]);
1168 fprintf(stderr
, ", ");
1170 fprintf(stderr
, "\n");
1171 if (mc_errors
== FLOCALE_NUMBER_MISS_CSET_ERR_MSG
)
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
));
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
)
1197 if (fn
!= NULL
&& fn
!= mb_fallback_font
)
1206 FlocaleFont
*FlocaleGetFont(
1207 Display
*dpy
, char *fontname
, char *encoding
, char *module
)
1209 XFontStruct
*font
= NULL
;
1214 hints
= GetQuotedString(fontname
, &tmp
, "/", NULL
, NULL
, NULL
);
1215 str
= GetQuotedString(tmp
, &fn
, ",", NULL
, NULL
, NULL
);
1223 font
= XLoadQueryFont(dpy
, fn
);
1224 if (fn
!= NULL
&& fn
!= fallback_font
)
1229 if (!font
&& str
&& *str
)
1231 str
= GetQuotedString(str
, &fn
, ",", NULL
, NULL
, NULL
);
1236 if (fn
!= NULL
&& fn
!= fallback_font
)
1247 flf
= (FlocaleFont
*)safemalloc(sizeof(FlocaleFont
));
1248 memset(flf
, '\0', sizeof(FlocaleFont
));
1250 flf
->fontset
= None
;
1251 flf
->fftf
.fftfont
= NULL
;
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
)
1273 FlocaleFont
*FlocaleGetFontOrFontSet(
1274 Display
*dpy
, char *fontname
, char *encoding
, char *fullname
,
1277 FlocaleFont
*flf
= NULL
;
1279 if (fontname
&& strlen(fontname
) > 3 &&
1280 strncasecmp("xft:", fontname
, 4) == 0)
1284 flf
= FlocaleGetFftFont(
1285 dpy
, fontname
+4, encoding
, module
);
1289 CopyString(&flf
->name
, fullname
);
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
;
1313 CopyString(&flf
->name
, fullname
);
1321 * locale local functions
1325 void FlocaleSetlocaleForX(
1326 int category
, const char *locale
, const char *module
)
1328 if ((Flocale
= setlocale(category
, locale
)) == NULL
)
1331 "[%s][%s]: ERROR -- Cannot set locale. Please check"
1332 " your $LC_CTYPE or $LANG.\n",
1333 (module
== NULL
)? "" : module
, "FlocaleSetlocaleForX");
1336 if (!XSupportsLocale())
1339 "[%s][%s]: WARNING -- X does not support locale %s\n",
1340 (module
== NULL
)? "": module
, "FlocaleSetlocaleForX",
1346 /* ---------------------------- interface functions ------------------------ */
1349 * locale initialisation
1353 int category
, const char *locale
, const char *modifiers
,
1357 FlocaleSetlocaleForX(category
, locale
, module
);
1358 if (Flocale
== NULL
)
1361 if (modifiers
!= NULL
&&
1362 (Fmodifiers
= XSetLocaleModifiers(modifiers
)) == NULL
)
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
);
1377 char *prefix_list
[] =
1384 FlocaleFont
*FlocaleLoadFont(Display
*dpy
, char *fontname
, char *module
)
1386 FlocaleFont
*flf
= FlocaleFontList
;
1387 Bool ask_default
= False
;
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
;
1395 /* removing quoting for modules */
1396 if (fontname
&& (t
= strchr("\"'`", *fontname
)))
1400 if (fontname
[strlen(fontname
)-1] == c
)
1401 fontname
[strlen(fontname
)-1] = 0;
1404 if (fontname
== NULL
|| *fontname
== 0)
1407 fontname
= mb_fallback_font
;
1414 for (c1
= fontname
, c2
= flf
->name
; *c1
&& *c2
; ++c1
, ++c2
)
1429 /* not cached load the font as a ";" separated list */
1431 /* But first see if we have a shadow relief and/or an encoding */
1433 while ((i
= GetTokenIndex(str
, prefix_list
, -1, &str
)) > -1)
1435 str
= GetQuotedString(str
, &opt_str
, ":", NULL
, NULL
, NULL
);
1438 case 0: /* shadow= */
1440 opt_str
, &shadow_size
, &shadow_offset
,
1441 &shadow_dir
, fontname
, module
);
1443 case 1: /* encoding= */
1444 if (encoding
!= NULL
)
1449 if (opt_str
&& *opt_str
)
1451 CopyString(&encoding
, opt_str
);
1457 if (opt_str
!= NULL
)
1462 str
= GetQuotedString(str
, &fn
, ";", NULL
, NULL
, NULL
);
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
)
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
)
1491 /* loading failed, try default font */
1494 fprintf(stderr
,"[%s][FlocaleLoadFont]: "
1495 "WARNING -- can't load font '%s',"
1496 " trying default:\n",
1497 (module
)? module
: "fvwmlibs", fontname
);
1501 /* we already tried default fonts: try again? yes */
1503 if (Flocale
!= NULL
)
1507 fprintf(stderr
, "\t%s\n",
1510 if ((flf
= FlocaleGetFontSet(
1511 dpy
, mb_fallback_font
, NULL
,
1514 flf
->name
= mb_fallback_font
;
1521 fprintf(stderr
,"\t%s\n",
1526 dpy
, fallback_font
, NULL
,
1529 flf
->name
= fallback_font
;
1531 else if (!ask_default
)
1534 "[%s][FlocaleLoadFont]:"
1535 " ERROR -- can't load font.\n",
1536 (module
)? module
: "fvwmlibs");
1541 "[%s][FlocaleLoadFont]: ERROR"
1542 " -- can't load default font:\n",
1543 (module
)? module
: "fvwmlibs");
1544 fprintf(stderr
, "\t%s\n",
1546 fprintf(stderr
, "\t%s\n",
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"
1579 (module
)? module
: "fvwmlibs", flf
->name
);
1581 if (flf
->str_fc
== FlocaleCharsetGetUnknownCharset())
1584 FlocaleCharsetGetDefaultCharset(dpy
, module
);
1586 flf
->next
= FlocaleFontList
;
1587 FlocaleFontList
= flf
;
1589 if (encoding
!= NULL
)
1597 void FlocaleUnloadFont(Display
*dpy
, FlocaleFont
*flf
)
1599 FlocaleFont
*list
= FlocaleFontList
;
1606 /* Remove a weight, still too heavy? */
1607 if (--(flf
->count
) > 0)
1612 if (flf
->name
!= NULL
&&
1613 !StrEquals(flf
->name
, mb_fallback_font
) &&
1614 !StrEquals(flf
->name
, fallback_font
))
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
)
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
));
1649 free(flf
->fc
->locale
);
1654 /* Link it out of the list (it might not be there) */
1655 if (flf
== list
) /* in head? simple */
1657 FlocaleFontList
= flf
->next
;
1661 while (list
&& list
->next
!= flf
)
1663 /* fast forward until end or found */
1666 /* not end? means we found it in there, possibly at end */
1669 /* link around it */
1670 list
->next
= flf
->next
;
1677 * Width and Drawing Text
1680 void FlocaleInitGstpArgs(
1681 flocale_gstp_args
*args
, FlocaleFont
*flf
, FlocaleWinString
*fws
,
1682 int start_x
, int start_y
)
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
);
1696 args
->orig_x
= start_x
+ FLF_SHADOW_RIGHT_SIZE(flf
);
1697 args
->orig_y
= start_y
;
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
);
1705 args
->orig_x
= start_x
+ FLF_SHADOW_LEFT_SIZE(flf
);
1706 args
->orig_y
= start_y
;
1709 args
->rot
= fws
->flags
.text_rotation
;
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
) &&
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
)
1732 size
= 2 * (args
->outer_offset
) + 1;
1733 args
->num_inter_steps
= size
* size
;
1737 args
->num_inter_steps
= args
->size
;
1740 if (args
->direction
== MULTI_DIR_NONE
|| args
->size
== 0)
1747 if (args
->direction
== MULTI_DIR_C
)
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
)
1776 (tx
+ args
->outer_offset
) +
1777 (ty
+ args
->outer_offset
) * size
;
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
;
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
);
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
;
1814 void FlocaleDrawString(
1815 Display
*dpy
, FlocaleFont
*flf
, FlocaleWinString
*fws
,
1816 unsigned long flags
)
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
;
1825 int char_len
; /* length in number of chars */
1826 int *pixel_pos
= NULL
;
1833 if (!fws
|| !fws
->str
)
1838 if (flags
& FWS_HAVE_LENGTH
)
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
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) */
1877 i
= 0, curr_pixel_pos
= 0 ;
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
];
1887 pixel_pos
[i
] = curr_pixel_pos
;
1888 /* need to compensate for shadow width (if any) */
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)
1906 if (XGetGCValues(dpy
, fws
->gc
, GCForeground
, &xgcv
) != 0)
1908 fg
= xgcv
.foreground
;
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 */
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
)
1936 dpy
, flf
, fws
, fg
, fgsh
, has_fg_pixels
, len
, flags
);
1938 else if (flf
->fontset
!= None
)
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
))
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
;
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 */
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
1980 FlocaleWinString tmp_fws
= *fws
;
1981 int offset
= pixel_pos
[comb_chars
[i
].position
];
1984 curr_len
= FlocaleChar2bOneCharToUtf8(comb_chars
[i
].c
,
1986 buf2
= FiconvUtf8ToCharset(
1987 dpy
, flf
->str_fc
, (const char *)buf
, curr_len
);
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));
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
;
2002 dpy
, flf
, &tmp_fws
, fg
, fgsh
,
2003 has_fg_pixels
, strlen(buf2
),
2006 else if(flf
->fontset
!= None
)
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
))
2028 XSetForeground(dpy
, fws
->gc
, fg
);
2029 xt
= gstp_args
.orig_x
;
2030 yt
= gstp_args
.orig_y
;
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;
2046 FlocaleUtf8ToUnicodeStr2b(
2048 curr_len, &out_len);*/
2050 else if (flf
->flags
.is_mb
)
2053 FlocaleStringToString2b(
2056 curr_len
, &out_len
);
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
,
2070 if(tmp_fws
.str2b
!= NULL
)
2072 free(tmp_fws
.str2b
);
2080 if (fws
->e_str
!= NULL
)
2087 if (fws
->str2b
!= NULL
)
2093 if(comb_chars
!= NULL
)
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
;
2109 Bool do_free
= True
;
2110 int len
= strlen(fws
->str
);
2115 if (fws
== NULL
|| fws
->str
== NULL
)
2120 /* need to encode the string first to get BIDI and combining chars */
2121 FlocaleEncodeWinString(dpy
, flf
, fws
, &do_free
, &len
, &comb_chars
,
2123 /* we don't need this, only interested in char mapping */
2126 /* now calculate char offset (in bytes) in visual string corresponding
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
) +
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
;
2142 x_s
= fws
->x
+ off1
;
2143 x_e
= fws
->x
+ off2
;
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
)
2155 if(fws
->str2b
!= NULL
)
2165 int FlocaleTextWidth(FlocaleFont
*flf
, char *str
, int sl
)
2170 superimpose_char_t
*comb_chars
= NULL
;
2172 if (!str
|| sl
== 0)
2177 /* a vertical string: nothing to do! */
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) */
2194 tmp_str
= FlocaleEncodeString(
2195 Pdpy
, flf
, str
, &do_free
, sl
, &new_l
, 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
2201 if (strlen(tmp_str
) == 0 && comb_chars
&&
2202 (comb_chars
[0].c
.byte1
!= 0 || comb_chars
[0].c
.byte2
!= 0))
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
)
2229 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
2230 str2b
= FlocaleUtf8ToUnicodeStr2b(
2231 tmp_str
, new_l
, &nl
);
2233 str2b
= FlocaleStringToString2b(
2234 Pdpy
, flf
, tmp_str
, new_l
, &nl
);
2237 result
= XTextWidth16(flf
->font
, str2b
, nl
);
2243 result
= XTextWidth(flf
->font
, tmp_str
, new_l
);
2255 return result
+ ((result
!= 0)? FLF_SHADOW_WIDTH(flf
):0);
2258 int FlocaleGetMinOffset(
2259 FlocaleFont
*flf
, rotation_t rotation
)
2263 #ifdef FFT_BUGGY_FREETYPE
2268 /* better than descent */
2269 min_offset
= (flf
->descent
+ flf
->height
- flf
->ascent
)/2;
2274 /* better than ascent */
2275 min_offset
= (flf
->ascent
+ flf
->height
- flf
->descent
)/2;
2283 /* better than descent */
2284 min_offset
= (flf
->descent
+ flf
->height
- flf
->ascent
)/2;
2289 /* better than ascent */
2290 min_offset
= (flf
->ascent
+ flf
->height
- flf
->descent
)/2;
2297 void FlocaleAllocateWinString(FlocaleWinString
**pfws
)
2299 *pfws
= (FlocaleWinString
*)safemalloc(sizeof(FlocaleWinString
));
2300 memset(*pfws
, '\0', sizeof(FlocaleWinString
));
2306 void FlocaleGetNameProperty(
2307 Status (func
)(Display
*, Window
, XTextProperty
*), Display
*dpy
,
2308 Window w
, FlocaleNameString
*ret_name
)
2312 XTextProperty text_prop
;
2315 if (func(dpy
, w
, &text_prop
) == 0)
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
;
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"
2335 XFree(text_prop
.value
); /* return of XGetWM(Icon)Name() */
2336 ret_name
->name
= *list
;
2337 ret_name
->name_list
= 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
)
2356 XFreeStringList(ptext
->name_list
);
2357 ptext
->name_list
= NULL
;
2359 else if (ptext
->name
!= NULL
)
2368 Bool
FlocaleTextListToTextProperty(
2369 Display
*dpy
, char **list
, int count
, XICCEncodingStyle style
,
2370 XTextProperty
*text_prop_return
)
2374 if (Flocale
!= NULL
)
2376 ret
= XmbTextListToTextProperty(
2377 dpy
, list
, count
, style
, text_prop_return
);
2378 if (ret
== XNoMemory
)
2384 /* ret == Success or the number of unconvertible
2385 * characters. ret should be != XLocaleNotSupported
2386 * because in this case Flocale == NULL */
2392 if (XStringListToTextProperty(
2393 list
, count
, text_prop_return
) == 0)
2409 void FlocalePrintLocaleInfo(Display
*dpy
, int verbose
)
2411 FlocaleFont
*flf
= FlocaleFontList
;
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",
2423 (cs
->iconv_index
>= 0)?
2424 cs
->locale
[cs
->iconv_index
]:"Not defined",
2425 (cs
->bidi
)? "Yes":"No");
2426 FlocaleCharsetPrintXOMInfo();
2432 fprintf(stderr
," Number of loaded font: %i\n", count
);
2436 flf
= FlocaleFontList
;
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: ");
2448 fprintf(stderr
,"FontStruct\n");
2450 else if (flf
->fontset
)
2452 fprintf(stderr
,"FontSet\n");
2456 fprintf(stderr
,"XftFont\n");
2458 fprintf(stderr
, " Charset: X: %s, Iconv: %s, "
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
,
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
);
2473 if (flf
->fftf
.fftfont
!= NULL
)
2478 fprintf(stderr
, " Xft info:\n"
2479 " - Vertical font:");
2480 FftPrintPatternInfo(
2481 fftf
->fftfont
, False
);
2483 "- Rotated font 90:");
2484 if (fftf
->fftfont_rotated_90
)
2485 FftPrintPatternInfo(
2490 fprintf(stderr
, " None\n");
2492 "- Rotated font 270:");
2493 if (fftf
->fftfont_rotated_270
)
2494 FftPrintPatternInfo(
2496 fftfont_rotated_270
,
2499 fprintf(stderr
, " None\n");
2501 "- Rotated font 180:");
2502 if (fftf
->fftfont_rotated_180
)
2503 FftPrintPatternInfo(
2505 fftfont_rotated_180
,
2508 fprintf(stderr
, " None\n");
2510 else if (flf
->font
!= NULL
)
2515 FlocaleGetFullNameOfFontStruct(
2517 fprintf(stderr
, " X info:\n"
2519 (full_name
)? full_name
:"?");
2520 if (full_name
!= NULL
)
2525 else if (flf
->fontset
!= NULL
)
2528 XFontStruct
**font_struct_list
;
2529 char **font_name_list
;
2531 fprintf(stderr
, " X info:\n");
2532 n
= XFontsOfFontSet(
2536 for(i
= 0; i
< n
; i
++)