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
;
443 if (flf
->str_fc
== NULL
|| flf
->fc
== NULL
||
444 flf
->fc
== flf
->str_fc
)
454 /* first process combining characters */
455 tmp_str
= FiconvCharsetToUtf8(
456 dpy
, flf
->str_fc
, (const char *)str
,len
);
457 /* if conversion to UTF-8 failed str1 will be NULL */
461 len
= CombineChars((unsigned char *)tmp_str
,
462 strlen(tmp_str
), comb_chars
,
464 /* returns the length of the resulting UTF-8 string */
465 /* convert back to current charset */
466 str1
= FiconvUtf8ToCharset(
467 dpy
, flf
->str_fc
, (const char *)tmp_str
,len
);
474 *nl
= len
= strlen(str1
);
479 /* convert back to current charset fail */
486 if (FiconvSupport
&& do_iconv
)
488 str2
= FiconvCharsetToCharset(
489 dpy
, flf
->str_fc
, flf
->fc
, (const char *)str1
, len
);
492 /* fail to convert */
497 if (*do_free
&& str1
)
510 /* initialise array with composing characters (empty) */
511 if(comb_chars
!= NULL
&& *comb_chars
== NULL
)
513 *comb_chars
= (superimpose_char_t
*)
514 safemalloc(sizeof(superimpose_char_t
));
515 (*comb_chars
)[0].position
= -1;
516 (*comb_chars
)[0].c
.byte1
= 0;
517 (*comb_chars
)[0].c
.byte2
= 0;
520 /* initialise logic to visual mapping here if that is demanded
521 (this is default when no combining has been done (1-to-1))
523 if(l_to_v
!= NULL
&& *l_to_v
== NULL
)
525 *l_to_v
= (int*)safemalloc((len
+ 1) * sizeof(int));
526 for(i
= 0 ; i
< len
; i
++)
532 if (FlocaleGetBidiCharset(dpy
, flf
->str_fc
) != NULL
&&
533 (bidi_charset
= FlocaleGetBidiCharset(dpy
, flf
->fc
)) != NULL
)
535 str3
= FBidiConvert(str2
, bidi_charset
, len1
,
537 comb_chars
!= NULL
? *comb_chars
: NULL
,
538 l_to_v
!= NULL
? *l_to_v
: NULL
);
539 if (str3
!= NULL
&& str3
!= str2
)
549 /* if we failed to do BIDI convert, return string string from
554 /* we already have the logical to visual mapping
555 from combining phase */
564 void FlocaleEncodeWinString(
565 Display
*dpy
, FlocaleFont
*flf
, FlocaleWinString
*fws
, int *do_free
,
566 int *len
, superimpose_char_t
**comb_chars
, int **l_to_v
)
569 fws
->e_str
= FlocaleEncodeString(
570 dpy
, flf
, fws
->str
, do_free
, *len
, len
, NULL
, comb_chars
,
574 if (flf
->font
!= None
)
576 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
578 fws
->str2b
= FlocaleUtf8ToUnicodeStr2b(
579 fws
->e_str
, *len
, &len2b
);
581 else if (flf
->flags
.is_mb
)
583 fws
->str2b
= FlocaleStringToString2b(
584 dpy
, flf
, fws
->e_str
, *len
, &len2b
);
590 * Text Drawing with a FontStruct
594 void FlocaleFontStructDrawString(
595 Display
*dpy
, FlocaleFont
*flf
, Drawable d
, GC gc
, int x
, int y
,
596 Pixel fg
, Pixel fgsh
, Bool has_fg_pixels
, FlocaleWinString
*fws
,
602 flocale_gstp_args gstp_args
;
604 is_string16
= (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
) || flf
->flags
.is_mb
);
605 if (is_string16
&& fws
->str2b
== NULL
)
611 /* for rotated drawing */
612 FSwitchDrawImageString(
613 is_string16
, dpy
, d
, gc
, x
, y
, fws
->e_str
, fws
->str2b
,
618 FlocaleInitGstpArgs(&gstp_args
, flf
, fws
, x
, y
);
620 if (flf
->shadow_size
!= 0 && has_fg_pixels
== True
)
622 XSetForeground(dpy
, fws
->gc
, fgsh
);
623 while (FlocaleGetShadowTextPosition(
624 &xt
, &yt
, &gstp_args
))
627 is_string16
, dpy
, d
, gc
, xt
, yt
,
628 fws
->e_str
, fws
->str2b
, len
);
631 if (has_fg_pixels
== True
)
633 XSetForeground(dpy
, gc
, fg
);
635 xt
= gstp_args
.orig_x
;
636 yt
= gstp_args
.orig_y
;
638 is_string16
, dpy
, d
, gc
, xt
,yt
, fws
->e_str
, fws
->str2b
,
646 * Rotated Text Drawing with a FontStruct or a FontSet
649 void FlocaleRotateDrawString(
650 Display
*dpy
, FlocaleFont
*flf
, FlocaleWinString
*fws
, Pixel fg
,
651 Pixel fgsh
, Bool has_fg_pixels
, int len
,
652 superimpose_char_t
*comb_chars
, int *pixel_pos
)
654 static GC my_gc
= None
;
655 static GC font_gc
= None
;
656 int j
, i
, xpfg
, ypfg
, xpsh
, ypsh
;
657 unsigned char *normal_data
, *rotated_data
;
658 unsigned int normal_w
, normal_h
, normal_len
;
659 unsigned int rotated_w
, rotated_h
, rotated_len
;
661 int width
, height
, descent
, min_offset
;
662 XImage
*image
, *rotated_image
;
663 Pixmap canvas_pix
, rotated_pix
;
664 flocale_gstp_args gstp_args
;
667 if (fws
->str
== NULL
|| len
< 1)
671 if (fws
->flags
.text_rotation
== ROTATION_0
)
673 return; /* should not happen */
678 my_gc
= fvwmlib_XCreateGC(dpy
, fws
->win
, 0, NULL
);
680 XCopyGC(dpy
, fws
->gc
, GCForeground
|GCBackground
, my_gc
);
682 /* width and height (no shadow!) */
683 width
= FlocaleTextWidth(flf
, fws
->str
, len
) - FLF_SHADOW_WIDTH(flf
);
684 height
= flf
->height
- FLF_SHADOW_HEIGHT(flf
);
685 descent
= flf
->descent
- FLF_SHADOW_DESCENT(flf
);;
692 /* glyph width and height of the normal text */
697 normal_len
= (normal_w
- 1) / 8 + 1;
699 /* create and clear the canvas */
700 canvas_pix
= XCreatePixmap(dpy
, fws
->win
, width
, height
, 1);
703 font_gc
= fvwmlib_XCreateGC(dpy
, canvas_pix
, 0, NULL
);
705 XSetBackground(dpy
, font_gc
, 0);
706 XSetForeground(dpy
, font_gc
, 0);
707 XFillRectangle(dpy
, canvas_pix
, font_gc
, 0, 0, width
, height
);
709 /* draw the character center top right on canvas */
710 XSetForeground(dpy
, font_gc
, 1);
711 if (flf
->font
!= NULL
)
713 XSetFont(dpy
, font_gc
, flf
->font
->fid
);
714 FlocaleFontStructDrawString(dpy
, flf
, canvas_pix
, font_gc
, 0,
716 fg
, fgsh
, has_fg_pixels
,
719 else if (flf
->fontset
!= None
)
722 dpy
, canvas_pix
, flf
->fontset
, font_gc
, 0,
723 height
- descent
, fws
->e_str
, len
);
726 /* here take care of superimposing chars */
728 if(comb_chars
!= NULL
)
730 while(comb_chars
[i
].c
.byte1
!= 0 && comb_chars
[i
].c
.byte2
!= 0)
732 /* draw composing character on top of corresponding
734 FlocaleWinString tmp_fws
= *fws
;
735 int offset
= pixel_pos
[comb_chars
[i
].position
];
736 int curr_len
= FlocaleChar2bOneCharToUtf8(
740 char *buf2
= FiconvUtf8ToCharset(
743 (const char *)buf
,curr_len
);
746 /* if conversion failed, combinational char
747 is not representable in current charset */
748 /* just replace with empty string */
749 buf2
= (char *)safemalloc(sizeof(char));
752 tmp_fws
.e_str
= buf2
;
753 tmp_fws
.str2b
= NULL
;
754 if(flf
->fontset
!= None
)
756 XmbDrawString(dpy
, canvas_pix
, flf
->fontset
,
758 height
- descent
, buf2
,
761 else if(flf
->font
!= None
)
763 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
765 tmp_fws
.str2b
= (XChar2b
*)
766 safemalloc(2 * sizeof(XChar2b
));
767 tmp_fws
.str2b
[0] = comb_chars
[i
].c
;
768 tmp_fws
.str2b
[1].byte1
= 0;
769 tmp_fws
.str2b
[1].byte2
= 0;
772 else if (flf
->flags
.is_mb
)
775 FlocaleStringToString2b(
776 dpy
, flf
, tmp_fws
.e_str
,
781 out_len
= strlen(buf2
);
783 XSetFont(dpy
, font_gc
, flf
->font
->fid
);
784 FlocaleFontStructDrawString(
785 dpy
, flf
, canvas_pix
, font_gc
,
786 offset
, height
- descent
,
787 fg
, fgsh
, has_fg_pixels
, &tmp_fws
,
792 if(tmp_fws
.str2b
!= NULL
)
800 /* reserve memory for the first XImage */
801 normal_data
= (unsigned char *)safemalloc(normal_len
* normal_h
);
803 /* create depth 1 XImage */
804 if ((image
= XCreateImage(
805 dpy
, Pvisual
, 1, XYBitmap
, 0, (char *)normal_data
,
806 normal_w
, normal_h
, 8, 0)) == NULL
)
810 image
->byte_order
= image
->bitmap_bit_order
= MSBFirst
;
812 /* extract character from canvas */
814 dpy
, canvas_pix
, 0, 0, normal_w
, normal_h
,
815 1, XYPixmap
, image
, 0, 0);
816 image
->format
= XYBitmap
;
818 /* width, height of the rotated text */
819 if (fws
->flags
.text_rotation
== ROTATION_180
)
821 rotated_w
= normal_w
;
822 rotated_h
= normal_h
;
824 else /* vertical text */
826 rotated_w
= normal_h
;
827 rotated_h
= normal_w
;
831 rotated_len
= (rotated_w
- 1) / 8 + 1;
833 /* reserve memory for the rotated image */
834 rotated_data
= (unsigned char *)safecalloc(rotated_h
* rotated_len
, 1);
836 /* create the rotated X image */
837 if ((rotated_image
= XCreateImage(
838 dpy
, Pvisual
, 1, XYBitmap
, 0, (char *)rotated_data
,
839 rotated_w
, rotated_h
, 8, 0)) == NULL
)
844 rotated_image
->byte_order
= rotated_image
->bitmap_bit_order
= MSBFirst
;
846 /* map normal text data to rotated text data */
847 for (j
= 0; j
< rotated_h
; j
++)
849 for (i
= 0; i
< rotated_w
; i
++)
852 if (fws
->flags
.text_rotation
== ROTATION_270
)
855 (normal_w
- j
- 1) / 8
856 ] & (128 >> ((normal_w
- j
- 1) % 8));
858 else if (fws
->flags
.text_rotation
== ROTATION_180
)
860 (normal_h
- j
- 1) * normal_len
+
861 (normal_w
- i
- 1) / 8
862 ] & (128 >> ((normal_w
- i
- 1) % 8));
864 else /* ROTATION_90 */
866 (normal_h
- i
- 1) * normal_len
+
867 j
/ 8] & (128 >> (j
% 8));
870 rotated_data
[j
* rotated_len
+ i
/ 8] |=
875 /* create the character's bitmap and put the image on it */
876 rotated_pix
= XCreatePixmap(dpy
, fws
->win
, rotated_w
, rotated_h
, 1);
878 dpy
, rotated_pix
, font_gc
, rotated_image
, 0, 0, 0, 0,
879 rotated_w
, rotated_h
);
881 /* free the image and data */
882 XDestroyImage(image
);
883 XDestroyImage(rotated_image
);
885 /* free pixmap and GC */
886 XFreePixmap(dpy
, canvas_pix
);
888 /* x and y corrections: we fill a rectangle! */
889 min_offset
= FlocaleGetMinOffset(flf
, fws
->flags
.text_rotation
);
890 switch (fws
->flags
.text_rotation
)
894 xpfg
= fws
->x
- min_offset
;
899 ypfg
= fws
->y
- min_offset
+
900 FLF_SHADOW_BOTTOM_SIZE(flf
);
904 xpfg
= fws
->x
- min_offset
;
910 ypfg
= fws
->y
- min_offset
;
915 /* write the image on the window */
916 XSetFillStyle(dpy
, my_gc
, FillStippled
);
917 XSetStipple(dpy
, my_gc
, rotated_pix
);
918 FlocaleInitGstpArgs(&gstp_args
, flf
, fws
, xpfg
, ypfg
);
919 if (flf
->shadow_size
!= 0 && has_fg_pixels
== True
)
921 XSetForeground(dpy
, my_gc
, fgsh
);
922 while (FlocaleGetShadowTextPosition(&xpsh
, &ypsh
, &gstp_args
))
924 XSetTSOrigin(dpy
, my_gc
, xpsh
, ypsh
);
926 dpy
, fws
->win
, my_gc
, xpsh
, ypsh
, rotated_w
,
930 xpsh
= gstp_args
.orig_x
;
931 ypsh
= gstp_args
.orig_y
;
932 XSetTSOrigin(dpy
, my_gc
, xpsh
, ypsh
);
933 XFillRectangle(dpy
, fws
->win
, my_gc
, xpsh
, ypsh
, rotated_w
, rotated_h
);
934 XFreePixmap(dpy
, rotated_pix
);
940 * Fonts info and checking
944 char *FlocaleGetFullNameOfFontStruct(Display
*dpy
, XFontStruct
*font
)
946 char *full_name
= NULL
;
949 if (XGetFontProperty(font
, XA_FONT
, &value
))
951 full_name
= XGetAtomName(dpy
, value
);
957 char *FlocaleGetCharsetOfFontStruct(Display
*dpy
, XFontStruct
*font
)
961 char *charset
= NULL
;
964 full_name
= FlocaleGetFullNameOfFontStruct(dpy
, font
);
965 if (full_name
== NULL
)
969 while(full_name
[i
] != '\0' && count
< 13)
971 if (full_name
[i
] == '-')
982 CopyString(&charset
, full_name
+i
);
988 char *FlocaleGetCharsetFromName(char *name
)
995 while(i
>= 0 && name
[i
] != '-')
999 if (i
== 0 || i
== l
-1)
1005 while(i
>= 0 && name
[i
] != '-')
1009 if (i
<= 0 || e
== i
)
1013 CopyString(&charset
, name
+ i
+ 1);
1017 /* return NULL if it is not reasonable to load a FontSet.
1018 * Currently return name if it is reasonable to load a FontSet, but in the
1019 * future we may want to transform name for faster FontSet loading */
1021 char *FlocaleFixNameForFontSet(Display
*dpy
, char *name
, char *module
)
1025 XFontStruct
*test_font
= NULL
;
1034 if (strchr(name
, ','))
1036 /* tmp, do not handle "," separated list */
1039 charset
= FlocaleGetCharsetFromName(name
);
1040 if (charset
== NULL
&& !strchr(name
, '*') && !strchr(name
, '?'))
1042 /* probably a font alias! */
1043 if ((test_font
= XLoadQueryFont(dpy
, name
)))
1045 charset
= FlocaleGetCharsetOfFontStruct(dpy
, test_font
);
1046 XFreeFont(dpy
, test_font
);
1049 if (charset
!= NULL
)
1051 if (!strchr(charset
, '*') && !strchr(charset
, '?') &&
1052 !FlocaleCharsetIsCharsetXLocale(dpy
, charset
, module
))
1054 /* if the charset is fully specified and do not match
1055 * one of the X locale charset */
1058 fprintf(stderr
,"[%s][FlocaleGetFontSet]: WARNING -- "
1059 "Use of a non X locale charset '%s' when "
1060 "loading font: %s\n",
1061 (module
)? module
:"fvwmlibs", charset
, name
);
1074 FlocaleFont
*FlocaleGetFftFont(
1075 Display
*dpy
, char *fontname
, char *encoding
, char *module
)
1077 FftFontType
*fftf
= NULL
;
1078 FlocaleFont
*flf
= NULL
;
1079 char *fn
, *hints
= NULL
;
1081 hints
= GetQuotedString(fontname
, &fn
, "/", NULL
, NULL
, NULL
);
1084 fn
= fft_fallback_font
;
1086 else if (*fn
== '\0')
1089 fn
= fft_fallback_font
;
1091 fftf
= FftGetFont(dpy
, fn
, module
);
1094 if (fn
!= NULL
&& fn
!= fft_fallback_font
)
1100 flf
= (FlocaleFont
*)safemalloc(sizeof(FlocaleFont
));
1101 memset(flf
, '\0', sizeof(FlocaleFont
));
1104 FlocaleCharsetSetFlocaleCharset(dpy
, flf
, hints
, encoding
, module
);
1106 &flf
->fftf
, &flf
->height
, &flf
->ascent
, &flf
->descent
);
1107 FftGetFontWidths(flf
, &flf
->max_char_width
);
1109 if (fn
!= NULL
&& fn
!= fft_fallback_font
)
1118 FlocaleFont
*FlocaleGetFontSet(
1119 Display
*dpy
, char *fontname
, char *encoding
, char *module
)
1121 static int mc_errors
= 0;
1122 FlocaleFont
*flf
= NULL
;
1123 XFontSet fontset
= NULL
;
1127 XFontSetExtents
*fset_extents
;
1128 char *fn
, *hints
= NULL
, *fn_fixed
= NULL
;
1130 hints
= GetQuotedString(fontname
, &fn
, "/", NULL
, NULL
, NULL
);
1134 fn
= fn_fixed
= mb_fallback_font
;
1136 else if (!(fn_fixed
= FlocaleFixNameForFontSet(dpy
, fn
, module
)))
1138 if (fn
!= NULL
&& fn
!= mb_fallback_font
)
1144 if (!(fontset
= XCreateFontSet(dpy
, fn_fixed
, &ml
, &mc
, &ds
)))
1146 if (fn_fixed
&& fn_fixed
!= fn
)
1150 if (fn
!= NULL
&& fn
!= mb_fallback_font
)
1159 if (mc_errors
<= FLOCALE_NUMBER_MISS_CSET_ERR_MSG
)
1163 "[%s][FlocaleGetFontSet]: (%s)"
1164 " Missing font charsets:\n",
1165 (module
)? module
: "fvwmlibs", fontname
);
1166 for (i
= 0; i
< mc
; i
++)
1168 fprintf(stderr
, "%s", ml
[i
]);
1170 fprintf(stderr
, ", ");
1172 fprintf(stderr
, "\n");
1173 if (mc_errors
== FLOCALE_NUMBER_MISS_CSET_ERR_MSG
)
1176 "[%s][FlocaleGetFontSet]: No more"
1177 " missing charset reportings\n",
1178 (module
)? module
: "fvwmlibs");
1181 XFreeStringList(ml
);
1184 flf
= (FlocaleFont
*)safemalloc(sizeof(FlocaleFont
));
1185 memset(flf
, '\0', sizeof(FlocaleFont
));
1187 flf
->fontset
= fontset
;
1188 FlocaleCharsetSetFlocaleCharset(dpy
, flf
, hints
, encoding
, module
);
1189 fset_extents
= XExtentsOfFontSet(fontset
);
1190 flf
->height
= fset_extents
->max_ink_extent
.height
;
1191 flf
->ascent
= - fset_extents
->max_ink_extent
.y
;
1192 flf
->descent
= fset_extents
->max_ink_extent
.height
+
1193 fset_extents
->max_ink_extent
.y
;
1194 flf
->max_char_width
= fset_extents
->max_ink_extent
.width
;
1195 if (fn_fixed
&& fn_fixed
!= fn
)
1199 if (fn
!= NULL
&& fn
!= mb_fallback_font
)
1208 FlocaleFont
*FlocaleGetFont(
1209 Display
*dpy
, char *fontname
, char *encoding
, char *module
)
1211 XFontStruct
*font
= NULL
;
1216 hints
= GetQuotedString(fontname
, &tmp
, "/", NULL
, NULL
, NULL
);
1217 str
= GetQuotedString(tmp
, &fn
, ",", NULL
, NULL
, NULL
);
1225 font
= XLoadQueryFont(dpy
, fn
);
1226 if (fn
!= NULL
&& fn
!= fallback_font
)
1231 if (!font
&& str
&& *str
)
1233 str
= GetQuotedString(str
, &fn
, ",", NULL
, NULL
, NULL
);
1238 if (fn
!= NULL
&& fn
!= fallback_font
)
1249 flf
= (FlocaleFont
*)safemalloc(sizeof(FlocaleFont
));
1250 memset(flf
, '\0', sizeof(FlocaleFont
));
1252 flf
->fontset
= None
;
1253 flf
->fftf
.fftfont
= NULL
;
1255 FlocaleCharsetSetFlocaleCharset(dpy
, flf
, hints
, encoding
, module
);
1256 flf
->height
= font
->max_bounds
.ascent
+ font
->max_bounds
.descent
;
1257 flf
->ascent
= font
->max_bounds
.ascent
;
1258 flf
->descent
= font
->max_bounds
.descent
;
1259 flf
->max_char_width
= font
->max_bounds
.width
;
1260 if (flf
->font
->max_byte1
> 0)
1261 flf
->flags
.is_mb
= True
;
1262 if (fn
!= NULL
&& fn
!= fallback_font
)
1275 FlocaleFont
*FlocaleGetFontOrFontSet(
1276 Display
*dpy
, char *fontname
, char *encoding
, char *fullname
,
1279 FlocaleFont
*flf
= NULL
;
1281 if (fontname
&& strlen(fontname
) > 3 &&
1282 strncasecmp("xft:", fontname
, 4) == 0)
1286 flf
= FlocaleGetFftFont(
1287 dpy
, fontname
+4, encoding
, module
);
1291 CopyString(&flf
->name
, fullname
);
1295 if (flf
== NULL
&& Flocale
!= NULL
&& fontname
)
1297 flf
= FlocaleGetFontSet(dpy
, fontname
, encoding
, module
);
1299 if (flf
== NULL
&& fontname
)
1301 flf
= FlocaleGetFont(dpy
, fontname
, encoding
, module
);
1303 if (flf
&& fontname
)
1305 if (StrEquals(fullname
, mb_fallback_font
))
1307 flf
->name
= mb_fallback_font
;
1309 else if (StrEquals(fullname
, fallback_font
))
1311 flf
->name
= fallback_font
;
1315 CopyString(&flf
->name
, fullname
);
1323 * locale local functions
1327 void FlocaleSetlocaleForX(
1328 int category
, const char *locale
, const char *module
)
1330 if ((Flocale
= setlocale(category
, locale
)) == NULL
)
1333 "[%s][%s]: ERROR -- Cannot set locale. Please check"
1334 " your $LC_CTYPE or $LANG.\n",
1335 (module
== NULL
)? "" : module
, "FlocaleSetlocaleForX");
1338 if (!XSupportsLocale())
1341 "[%s][%s]: WARNING -- X does not support locale %s\n",
1342 (module
== NULL
)? "": module
, "FlocaleSetlocaleForX",
1348 /* ---------------------------- interface functions ------------------------ */
1351 * locale initialisation
1355 int category
, const char *locale
, const char *modifiers
,
1359 FlocaleSetlocaleForX(category
, locale
, module
);
1360 if (Flocale
== NULL
)
1363 if (modifiers
!= NULL
&&
1364 (Fmodifiers
= XSetLocaleModifiers(modifiers
)) == NULL
)
1367 "[%s][%s]: WARNING -- Cannot set locale modifiers\n",
1368 (module
== NULL
)? "": module
, "FlocaleInit");
1370 #if FLOCALE_DEBUG_SETLOCALE
1371 fprintf(stderr
,"[%s][FlocaleInit] locale: %s, modifier: %s\n",
1372 module
, Flocale
, Fmodifiers
);
1379 char *prefix_list
[] =
1386 FlocaleFont
*FlocaleLoadFont(Display
*dpy
, char *fontname
, char *module
)
1388 FlocaleFont
*flf
= FlocaleFontList
;
1389 Bool ask_default
= False
;
1391 char *str
, *opt_str
, *encoding
= NULL
, *fn
= NULL
;
1392 int shadow_size
= 0;
1393 int shadow_offset
= 0;
1394 int shadow_dir
= MULTI_DIR_SE
;
1397 /* removing quoting for modules */
1398 if (fontname
&& (t
= strchr("\"'`", *fontname
)))
1402 if (fontname
[strlen(fontname
)-1] == c
)
1403 fontname
[strlen(fontname
)-1] = 0;
1406 if (fontname
== NULL
|| *fontname
== 0)
1409 fontname
= mb_fallback_font
;
1416 for (c1
= fontname
, c2
= flf
->name
; *c1
&& *c2
; ++c1
, ++c2
)
1431 /* not cached load the font as a ";" separated list */
1433 /* But first see if we have a shadow relief and/or an encoding */
1435 while ((i
= GetTokenIndex(str
, prefix_list
, -1, &str
)) > -1)
1437 str
= GetQuotedString(str
, &opt_str
, ":", NULL
, NULL
, NULL
);
1440 case 0: /* shadow= */
1442 opt_str
, &shadow_size
, &shadow_offset
,
1443 &shadow_dir
, fontname
, module
);
1445 case 1: /* encoding= */
1446 if (encoding
!= NULL
)
1451 if (opt_str
&& *opt_str
)
1453 CopyString(&encoding
, opt_str
);
1459 if (opt_str
!= NULL
)
1464 str
= GetQuotedString(str
, &fn
, ";", NULL
, NULL
, NULL
);
1468 fn
= mb_fallback_font
;
1470 while (!flf
&& (fn
&& *fn
))
1472 flf
= FlocaleGetFontOrFontSet(
1473 dpy
, fn
, encoding
, fontname
, module
);
1474 if (fn
!= NULL
&& fn
!= mb_fallback_font
&&
1475 fn
!= fallback_font
)
1480 if (!flf
&& str
&& *str
)
1482 str
= GetQuotedString(str
, &fn
, ";", NULL
, NULL
, NULL
);
1485 if (fn
!= NULL
&& fn
!= mb_fallback_font
&&
1486 fn
!= fallback_font
)
1493 /* loading failed, try default font */
1496 fprintf(stderr
,"[%s][FlocaleLoadFont]: "
1497 "WARNING -- can't load font '%s',"
1498 " trying default:\n",
1499 (module
)? module
: "fvwmlibs", fontname
);
1503 /* we already tried default fonts: try again? yes */
1505 if (Flocale
!= NULL
)
1509 fprintf(stderr
, "\t%s\n",
1512 if ((flf
= FlocaleGetFontSet(
1513 dpy
, mb_fallback_font
, NULL
,
1516 flf
->name
= mb_fallback_font
;
1523 fprintf(stderr
,"\t%s\n",
1528 dpy
, fallback_font
, NULL
,
1531 flf
->name
= fallback_font
;
1533 else if (!ask_default
)
1536 "[%s][FlocaleLoadFont]:"
1537 " ERROR -- can't load font.\n",
1538 (module
)? module
: "fvwmlibs");
1543 "[%s][FlocaleLoadFont]: ERROR"
1544 " -- can't load default font:\n",
1545 (module
)? module
: "fvwmlibs");
1546 fprintf(stderr
, "\t%s\n",
1548 fprintf(stderr
, "\t%s\n",
1556 if (shadow_size
> 0)
1558 flf
->shadow_size
= shadow_size
;
1559 flf
->flags
.shadow_dir
= shadow_dir
;
1560 flf
->shadow_offset
= shadow_offset
;
1561 flf
->descent
+= FLF_SHADOW_DESCENT(flf
);
1562 flf
->ascent
+= FLF_SHADOW_ASCENT(flf
);
1563 flf
->height
+= FLF_SHADOW_HEIGHT(flf
);
1564 flf
->max_char_width
+= FLF_SHADOW_WIDTH(flf
);
1566 if (flf
->fc
== FlocaleCharsetGetUnknownCharset())
1568 fprintf(stderr
,"[%s][FlocaleLoadFont]: "
1569 "WARNING -- Unknown charset for font\n\t'%s'\n",
1570 (module
)? module
: "fvwmlibs", flf
->name
);
1571 flf
->fc
= FlocaleCharsetGetDefaultCharset(dpy
, module
);
1573 else if (flf
->str_fc
== FlocaleCharsetGetUnknownCharset() &&
1574 (encoding
!= NULL
||
1575 (FftSupport
&& flf
->fftf
.fftfont
!= NULL
&&
1576 flf
->fftf
.str_encoding
!= NULL
)))
1578 fprintf(stderr
,"[%s][FlocaleLoadFont]: "
1579 "WARNING -- Unknown string encoding for font\n"
1581 (module
)? module
: "fvwmlibs", flf
->name
);
1583 if (flf
->str_fc
== FlocaleCharsetGetUnknownCharset())
1586 FlocaleCharsetGetDefaultCharset(dpy
, module
);
1588 flf
->next
= FlocaleFontList
;
1589 FlocaleFontList
= flf
;
1591 if (encoding
!= NULL
)
1599 void FlocaleUnloadFont(Display
*dpy
, FlocaleFont
*flf
)
1601 FlocaleFont
*list
= FlocaleFontList
;
1608 /* Remove a weight, still too heavy? */
1609 if (--(flf
->count
) > 0)
1614 if (flf
->name
!= NULL
&&
1615 !StrEquals(flf
->name
, mb_fallback_font
) &&
1616 !StrEquals(flf
->name
, fallback_font
))
1620 if (FftSupport
&& flf
->fftf
.fftfont
!= NULL
)
1622 FftFontClose(dpy
, flf
->fftf
.fftfont
);
1623 if (flf
->fftf
.fftfont_rotated_90
!= NULL
)
1624 FftFontClose(dpy
, flf
->fftf
.fftfont_rotated_90
);
1625 if (flf
->fftf
.fftfont_rotated_180
!= NULL
)
1626 FftFontClose(dpy
, flf
->fftf
.fftfont_rotated_180
);
1627 if (flf
->fftf
.fftfont_rotated_270
!= NULL
)
1628 FftFontClose(dpy
, flf
->fftf
.fftfont_rotated_270
);
1630 if (flf
->fontset
!= NULL
)
1632 XFreeFontSet(dpy
, flf
->fontset
);
1634 if (flf
->font
!= NULL
)
1636 XFreeFont(dpy
, flf
->font
);
1638 if (flf
->flags
.must_free_fc
)
1643 free(flf
->fc
->bidi
);
1644 if (flf
->fc
->locale
!= NULL
)
1646 while (FLC_GET_LOCALE_CHARSET(flf
->fc
,i
) != NULL
)
1648 free(FLC_GET_LOCALE_CHARSET(flf
->fc
,i
));
1651 free(flf
->fc
->locale
);
1656 /* Link it out of the list (it might not be there) */
1657 if (flf
== list
) /* in head? simple */
1659 FlocaleFontList
= flf
->next
;
1663 while (list
&& list
->next
!= flf
)
1665 /* fast forward until end or found */
1668 /* not end? means we found it in there, possibly at end */
1671 /* link around it */
1672 list
->next
= flf
->next
;
1679 * Width and Drawing Text
1682 void FlocaleInitGstpArgs(
1683 flocale_gstp_args
*args
, FlocaleFont
*flf
, FlocaleWinString
*fws
,
1684 int start_x
, int start_y
)
1687 args
->offset
= flf
->shadow_offset
+ 1;
1688 args
->outer_offset
= flf
->shadow_offset
+ flf
->shadow_size
;
1689 args
->size
= flf
->shadow_size
;
1690 args
->sdir
= flf
->flags
.shadow_dir
;
1691 switch (fws
->flags
.text_rotation
)
1693 case ROTATION_270
: /* CCW */
1694 args
->orig_x
= start_x
+ FLF_SHADOW_UPPER_SIZE(flf
);
1695 args
->orig_y
= start_y
+ FLF_SHADOW_RIGHT_SIZE(flf
);
1698 args
->orig_x
= start_x
+ FLF_SHADOW_RIGHT_SIZE(flf
);
1699 args
->orig_y
= start_y
;
1701 case ROTATION_90
: /* CW */
1702 args
->orig_x
= start_x
+ FLF_SHADOW_BOTTOM_SIZE(flf
);
1703 args
->orig_y
= start_y
+ FLF_SHADOW_LEFT_SIZE(flf
);
1707 args
->orig_x
= start_x
+ FLF_SHADOW_LEFT_SIZE(flf
);
1708 args
->orig_y
= start_y
;
1711 args
->rot
= fws
->flags
.text_rotation
;
1716 Bool
FlocaleGetShadowTextPosition(
1717 int *x
, int *y
, flocale_gstp_args
*args
)
1719 if (args
->step
== 0)
1721 args
->direction
= MULTI_DIR_NONE
;
1722 args
->inter_step
= 0;
1724 if ((args
->step
== 0 || args
->inter_step
>= args
->num_inter_steps
) &&
1727 /* setup a new direction */
1728 args
->inter_step
= 0;
1729 gravity_get_next_multi_dir(args
->sdir
, &args
->direction
);
1730 if (args
->direction
== MULTI_DIR_C
)
1734 size
= 2 * (args
->outer_offset
) + 1;
1735 args
->num_inter_steps
= size
* size
;
1739 args
->num_inter_steps
= args
->size
;
1742 if (args
->direction
== MULTI_DIR_NONE
|| args
->size
== 0)
1749 if (args
->direction
== MULTI_DIR_C
)
1756 size
= 2 * (args
->outer_offset
) + 1;
1757 tx
= args
->inter_step
% size
- args
->outer_offset
;
1758 ty
= args
->inter_step
/ size
- args
->outer_offset
;
1759 for (is_finished
= 0; ty
<= args
->outer_offset
;
1760 ty
++, tx
= -args
->outer_offset
)
1762 for (; tx
<= args
->outer_offset
; tx
++)
1764 if (tx
<= -args
->offset
||
1765 tx
>= args
->offset
||
1766 ty
<= -args
->offset
|| ty
>= args
->offset
)
1778 (tx
+ args
->outer_offset
) +
1779 (ty
+ args
->outer_offset
) * size
;
1785 *x
= args
->orig_x
+ tx
;
1786 *y
= args
->orig_y
+ ty
;
1788 else if (args
->inter_step
> 0)
1790 /* into a directional drawing */
1791 (*x
) += args
->x_sign
;
1792 (*y
) += args
->y_sign
;
1800 dir
= gravity_multi_dir_to_dir(args
->direction
);
1801 gravity_split_xy_dir(&dir_x
, &dir_y
, dir
);
1802 args
->x_sign
= gravity_dir_to_sign_one_axis(dir_x
);
1803 args
->y_sign
= gravity_dir_to_sign_one_axis(dir_y
);
1805 args
->rot
, args
->x_sign
, args
->y_sign
,
1806 &args
->x_sign
, &args
->y_sign
);
1807 *x
= args
->orig_x
+ args
->x_sign
* args
->offset
;
1808 *y
= args
->orig_y
+ args
->y_sign
* args
->offset
;
1816 void FlocaleDrawString(
1817 Display
*dpy
, FlocaleFont
*flf
, FlocaleWinString
*fws
,
1818 unsigned long flags
)
1821 Bool do_free
= False
;
1822 Pixel fg
= 0, fgsh
= 0;
1823 Bool has_fg_pixels
= False
;
1824 flocale_gstp_args gstp_args
;
1825 superimpose_char_t
*comb_chars
= NULL
;
1827 int char_len
; /* length in number of chars */
1828 int *pixel_pos
= NULL
;
1835 if (!fws
|| !fws
->str
)
1840 if (flags
& FWS_HAVE_LENGTH
)
1846 len
= strlen(fws
->str
);
1849 /* encode the string */
1850 FlocaleEncodeWinString(
1851 dpy
, flf
, fws
, &do_free
, &len
, &comb_chars
, NULL
);
1852 curr_str
= fws
->e_str
;
1853 for(char_len
= 0, i
= 0 ;
1854 i
< len
&& curr_str
[i
] != 0 ;
1855 char_len
++, i
+= curr_len
)
1857 curr_len
= FlocaleStringNumberOfBytes(flf
, curr_str
+ i
);
1860 /* for superimposition calculate the character positions in pixels */
1861 if (comb_chars
!= NULL
&& (
1862 comb_chars
[0].c
.byte1
!= 0 || comb_chars
[0].c
.byte2
!= 0))
1864 /* the second condition is actually redundant,
1865 but there for clarity,
1866 ending at 0 is what's expected in a correct
1868 pixel_pos
= (int *)safemalloc(
1869 (char_len
!= 0 ? char_len
: 1) * sizeof(int));
1871 /* if there is 0 bytes in the encoded string, there might
1872 still be combining character to draw (at position 0) */
1879 i
= 0, curr_pixel_pos
= 0 ;
1881 i
++, curr_str
+= curr_len
)
1883 curr_len
= FlocaleStringNumberOfBytes(flf
, curr_str
);
1884 for (j
= 0 ; j
< curr_len
; j
++)
1886 buf
[j
] = curr_str
[j
];
1889 pixel_pos
[i
] = curr_pixel_pos
;
1890 /* need to compensate for shadow width (if any) */
1892 FlocaleTextWidth(flf
, buf
, curr_len
) -
1893 FLF_SHADOW_WIDTH(flf
);
1897 /* get the pixels */
1898 if (fws
->flags
.has_colorset
)
1900 fg
= fws
->colorset
->fg
;
1901 fgsh
= fws
->colorset
->fgsh
;
1902 has_fg_pixels
= True
;
1904 else if (flf
->shadow_size
!= 0)
1908 if (XGetGCValues(dpy
, fws
->gc
, GCForeground
, &xgcv
) != 0)
1910 fg
= xgcv
.foreground
;
1914 fg
= PictureBlackPixel();
1916 fgsh
= GetShadow(fg
);
1917 has_fg_pixels
= True
;
1920 if(flf
->font
!= None
&&
1921 (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
) || flf
->flags
.is_mb
))
1923 /* in this case, length is number of 2-byte chars */
1927 if (fws
->flags
.text_rotation
!= ROTATION_0
&&
1928 flf
->fftf
.fftfont
== NULL
)
1930 /* pass in information to perform superimposition */
1931 FlocaleRotateDrawString(
1932 dpy
, flf
, fws
, fg
, fgsh
, has_fg_pixels
, len
,
1933 comb_chars
, pixel_pos
);
1935 else if (FftSupport
&& flf
->fftf
.fftfont
!= NULL
)
1938 dpy
, flf
, fws
, fg
, fgsh
, has_fg_pixels
, len
, flags
);
1940 else if (flf
->fontset
!= None
)
1945 FlocaleInitGstpArgs(&gstp_args
, flf
, fws
, fws
->x
, fws
->y
);
1946 if (flf
->shadow_size
!= 0)
1948 XSetForeground(dpy
, fws
->gc
, fgsh
);
1949 while (FlocaleGetShadowTextPosition(
1950 &xt
, &yt
, &gstp_args
))
1953 dpy
, fws
->win
, flf
->fontset
, fws
->gc
,
1954 xt
, yt
, fws
->e_str
, len
);
1957 if (has_fg_pixels
== True
)
1959 XSetForeground(dpy
, fws
->gc
, fg
);
1961 xt
= gstp_args
.orig_x
;
1962 yt
= gstp_args
.orig_y
;
1964 dpy
, fws
->win
, flf
->fontset
, fws
->gc
,
1965 xt
, yt
, fws
->e_str
, len
);
1967 else if (flf
->font
!= None
)
1969 FlocaleFontStructDrawString(
1970 dpy
, flf
, fws
->win
, fws
->gc
, fws
->x
, fws
->y
,
1971 fg
, fgsh
, has_fg_pixels
, fws
, len
, False
);
1974 /* here take care of superimposing chars */
1976 if (comb_chars
!= NULL
)
1978 while(comb_chars
[i
].c
.byte1
!= 0 && comb_chars
[i
].c
.byte2
!= 0)
1980 /* draw composing character on top of corresponding
1982 FlocaleWinString tmp_fws
= *fws
;
1983 int offset
= pixel_pos
[comb_chars
[i
].position
];
1986 curr_len
= FlocaleChar2bOneCharToUtf8(comb_chars
[i
].c
,
1988 buf2
= FiconvUtf8ToCharset(
1989 dpy
, flf
->str_fc
, (const char *)buf
, curr_len
);
1992 /* if conversion failed, combinational char
1993 is not representable in current charset */
1994 /* just replace with empty string */
1995 buf2
= (char *)safemalloc(sizeof(char));
1998 tmp_fws
.e_str
= buf2
;
1999 tmp_fws
.str2b
= NULL
;
2000 if(FftSupport
&& flf
->fftf
.fftfont
!= NULL
)
2002 tmp_fws
.x
= fws
->x
+ offset
;
2004 dpy
, flf
, &tmp_fws
, fg
, fgsh
,
2005 has_fg_pixels
, strlen(buf2
),
2008 else if(flf
->fontset
!= None
)
2013 FlocaleInitGstpArgs(
2014 &gstp_args
, flf
, fws
, fws
->x
, fws
->y
);
2015 if (flf
->shadow_size
!= 0)
2017 XSetForeground(dpy
, fws
->gc
, fgsh
);
2018 while (FlocaleGetShadowTextPosition(
2019 &xt
, &yt
, &gstp_args
))
2030 XSetForeground(dpy
, fws
->gc
, fg
);
2031 xt
= gstp_args
.orig_x
;
2032 yt
= gstp_args
.orig_y
;
2034 dpy
, fws
->win
, flf
->fontset
, fws
->gc
,
2035 xt
+ offset
, yt
, buf2
, strlen(buf2
));
2037 else if (flf
->font
!= None
)
2039 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
2041 tmp_fws
.str2b
= (XChar2b
*)
2042 safemalloc(2 * sizeof(XChar2b
));
2043 tmp_fws
.str2b
[0] = comb_chars
[i
].c
;
2044 tmp_fws
.str2b
[1].byte1
= 0;
2045 tmp_fws
.str2b
[1].byte2
= 0;
2048 FlocaleUtf8ToUnicodeStr2b(
2050 curr_len, &out_len);*/
2052 else if (flf
->flags
.is_mb
)
2055 FlocaleStringToString2b(
2058 curr_len
, &out_len
);
2062 out_len
= strlen(buf2
);
2064 FlocaleFontStructDrawString(
2065 dpy
, flf
, fws
->win
, fws
->gc
,
2066 fws
->x
+ offset
, fws
->y
, fg
, fgsh
,
2067 has_fg_pixels
, &tmp_fws
, out_len
,
2072 if(tmp_fws
.str2b
!= NULL
)
2074 free(tmp_fws
.str2b
);
2082 if (fws
->e_str
!= NULL
)
2089 if (fws
->str2b
!= NULL
)
2095 if(comb_chars
!= NULL
)
2105 void FlocaleDrawUnderline(
2106 Display
*dpy
, FlocaleFont
*flf
, FlocaleWinString
*fws
, int offset
)
2108 int off1
, off2
, y
, x_s
, x_e
;
2109 superimpose_char_t
*comb_chars
= NULL
;
2111 Bool do_free
= True
;
2112 int len
= strlen(fws
->str
);
2117 if (fws
== NULL
|| fws
->str
== NULL
)
2122 /* need to encode the string first to get BIDI and combining chars */
2123 FlocaleEncodeWinString(dpy
, flf
, fws
, &do_free
, &len
, &comb_chars
,
2125 /* we don't need this, only interested in char mapping */
2128 /* now calculate char offset (in bytes) in visual string corresponding
2130 /* calculate absolute position in string (in characters) */
2131 l_coffset
= FlocaleStringByteToCharOffset(flf
, fws
->str
, offset
);
2132 /* map to an offset in the visual string */
2133 v_coffset
= l_to_v
[l_coffset
];
2134 /* calculate byte offset into visual string */
2135 voffset
= FlocaleStringCharToByteOffset(flf
, fws
->e_str
, v_coffset
);
2137 off1
= FlocaleTextWidth(flf
, fws
->e_str
, voffset
) +
2139 FLF_SHADOW_LEFT_SIZE(flf
) : - FLF_SHADOW_RIGHT_SIZE(flf
) );
2140 off2
= FlocaleTextWidth(flf
, fws
->e_str
+ voffset
,
2141 FlocaleStringNumberOfBytes(flf
, fws
->e_str
+ voffset
)) -
2142 FLF_SHADOW_WIDTH(flf
) - 1 + off1
;
2144 x_s
= fws
->x
+ off1
;
2145 x_e
= fws
->x
+ off2
;
2148 XDrawLine(dpy
, fws
->win
, fws
->gc
, x_s
, y
, x_e
, y
);
2150 /* free encoded string if it isn't the same as input string */
2151 if(fws
->e_str
!= fws
->str
)
2157 if(fws
->str2b
!= NULL
)
2167 int FlocaleTextWidth(FlocaleFont
*flf
, char *str
, int sl
)
2172 superimpose_char_t
*comb_chars
= NULL
;
2174 if (!str
|| sl
== 0)
2179 /* a vertical string: nothing to do! */
2184 /* to avoid eccesive calls iconv (slow in Solaris 8)
2185 don't bother to encode if string is one byte
2186 when drawing a string this function is used to calculate
2187 position of each character (for superimposition) */
2196 tmp_str
= FlocaleEncodeString(
2197 Pdpy
, flf
, str
, &do_free
, sl
, &new_l
, NULL
,
2200 /* if we get zero-length, check to to see if there if there's any
2201 combining chars, if so use an imagninary space as a
2203 if (strlen(tmp_str
) == 0 && comb_chars
&&
2204 (comb_chars
[0].c
.byte1
!= 0 || comb_chars
[0].c
.byte2
!= 0))
2214 return FlocaleTextWidth(flf
, " ", 1);
2216 else if (FftSupport
&& flf
->fftf
.fftfont
!= NULL
)
2218 result
= FftTextWidth(flf
, tmp_str
, new_l
);
2220 else if (flf
->fontset
!= None
)
2222 result
= XmbTextEscapement(flf
->fontset
, tmp_str
, new_l
);
2224 else if (flf
->font
!= None
)
2226 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
) || flf
->flags
.is_mb
)
2231 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
2232 str2b
= FlocaleUtf8ToUnicodeStr2b(
2233 tmp_str
, new_l
, &nl
);
2235 str2b
= FlocaleStringToString2b(
2236 Pdpy
, flf
, tmp_str
, new_l
, &nl
);
2239 result
= XTextWidth16(flf
->font
, str2b
, nl
);
2245 result
= XTextWidth(flf
->font
, tmp_str
, new_l
);
2257 return result
+ ((result
!= 0)? FLF_SHADOW_WIDTH(flf
):0);
2260 int FlocaleGetMinOffset(
2261 FlocaleFont
*flf
, rotation_t rotation
)
2265 #ifdef FFT_BUGGY_FREETYPE
2270 /* better than descent */
2271 min_offset
= (flf
->descent
+ flf
->height
- flf
->ascent
)/2;
2276 /* better than ascent */
2277 min_offset
= (flf
->ascent
+ flf
->height
- flf
->descent
)/2;
2285 /* better than descent */
2286 min_offset
= (flf
->descent
+ flf
->height
- flf
->ascent
)/2;
2291 /* better than ascent */
2292 min_offset
= (flf
->ascent
+ flf
->height
- flf
->descent
)/2;
2299 void FlocaleAllocateWinString(FlocaleWinString
**pfws
)
2301 *pfws
= (FlocaleWinString
*)safemalloc(sizeof(FlocaleWinString
));
2302 memset(*pfws
, '\0', sizeof(FlocaleWinString
));
2308 void FlocaleGetNameProperty(
2309 Status (func
)(Display
*, Window
, XTextProperty
*), Display
*dpy
,
2310 Window w
, FlocaleNameString
*ret_name
)
2314 XTextProperty text_prop
;
2317 if (func(dpy
, w
, &text_prop
) == 0)
2321 if (text_prop
.encoding
== XA_STRING
)
2323 /* STRING encoding, use this as it is */
2324 ret_name
->name
= (char *)text_prop
.value
;
2325 ret_name
->name_list
= NULL
;
2328 /* not STRING encoding, try to convert XA_COMPOUND_TEXT */
2329 if (XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >= Success
2330 && num
> 0 && *list
)
2332 /* Does not consider the conversion is REALLY succeeded:
2333 * XmbTextPropertyToTextList return 0 (== Success) on success,
2334 * a negative int if it fails (and in this case we are not
2335 * here), the number of unconvertible char on "partial"
2337 XFree(text_prop
.value
); /* return of XGetWM(Icon)Name() */
2338 ret_name
->name
= *list
;
2339 ret_name
->name_list
= list
;
2345 XFreeStringList(list
);
2347 ret_name
->name
= (char *)text_prop
.value
;
2348 ret_name
->name_list
= NULL
;
2352 void FlocaleFreeNameProperty(FlocaleNameString
*ptext
)
2354 if (ptext
->name_list
!= NULL
)
2356 if (ptext
->name
!= NULL
&& ptext
->name
!= *ptext
->name_list
)
2358 XFreeStringList(ptext
->name_list
);
2359 ptext
->name_list
= NULL
;
2361 else if (ptext
->name
!= NULL
)
2370 Bool
FlocaleTextListToTextProperty(
2371 Display
*dpy
, char **list
, int count
, XICCEncodingStyle style
,
2372 XTextProperty
*text_prop_return
)
2376 if (Flocale
!= NULL
)
2378 ret
= XmbTextListToTextProperty(
2379 dpy
, list
, count
, style
, text_prop_return
);
2380 if (ret
== XNoMemory
)
2386 /* ret == Success or the number of unconvertible
2387 * characters. ret should be != XLocaleNotSupported
2388 * because in this case Flocale == NULL */
2394 if (XStringListToTextProperty(
2395 list
, count
, text_prop_return
) == 0)
2411 void FlocalePrintLocaleInfo(Display
*dpy
, int verbose
)
2413 FlocaleFont
*flf
= FlocaleFontList
;
2419 fprintf(stderr
,"fvwm info on locale:\n");
2420 fprintf(stderr
," locale: %s, Modifier: %s\n",
2421 (Flocale
)? Flocale
:"", (Fmodifiers
)? Fmodifiers
:"");
2422 cs
= FlocaleCharsetGetDefaultCharset(dpy
, NULL
);
2423 fprintf(stderr
," Default Charset: X: %s, Iconv: %s, Bidi: %s\n",
2425 (cs
->iconv_index
>= 0)?
2426 cs
->locale
[cs
->iconv_index
]:"Not defined",
2427 (cs
->bidi
)? "Yes":"No");
2428 FlocaleCharsetPrintXOMInfo();
2434 fprintf(stderr
," Number of loaded font: %i\n", count
);
2438 flf
= FlocaleFontList
;
2442 fprintf(stderr
," * Font number %i\n", count
);
2443 fprintf(stderr
," fvwm info:\n");
2444 fprintf(stderr
," Name: %s\n",
2445 (flf
->name
)? flf
->name
:"");
2446 fprintf(stderr
," Cache count: %i\n", flf
->count
);
2447 fprintf(stderr
," Type: ");
2450 fprintf(stderr
,"FontStruct\n");
2452 else if (flf
->fontset
)
2454 fprintf(stderr
,"FontSet\n");
2458 fprintf(stderr
,"XftFont\n");
2460 fprintf(stderr
, " Charset: X: %s, Iconv: %s, "
2463 (cs
->iconv_index
>= 0)?
2464 cs
->locale
[cs
->iconv_index
]:"Not defined",
2465 (cs
->bidi
)? "Yes":"No");
2466 fprintf(stderr
," height: %i, ascent: %i, "
2467 "descent: %i\n", flf
->height
, flf
->ascent
,
2469 fprintf(stderr
," shadow size: %i, "
2470 "shadow offset: %i, shadow direction:%i\n",
2471 flf
->shadow_size
, flf
->shadow_offset
,
2472 flf
->flags
.shadow_dir
);
2475 if (flf
->fftf
.fftfont
!= NULL
)
2480 fprintf(stderr
, " Xft info:\n"
2481 " - Vertical font:");
2482 FftPrintPatternInfo(
2483 fftf
->fftfont
, False
);
2485 "- Rotated font 90:");
2486 if (fftf
->fftfont_rotated_90
)
2487 FftPrintPatternInfo(
2492 fprintf(stderr
, " None\n");
2494 "- Rotated font 270:");
2495 if (fftf
->fftfont_rotated_270
)
2496 FftPrintPatternInfo(
2498 fftfont_rotated_270
,
2501 fprintf(stderr
, " None\n");
2503 "- Rotated font 180:");
2504 if (fftf
->fftfont_rotated_180
)
2505 FftPrintPatternInfo(
2507 fftfont_rotated_180
,
2510 fprintf(stderr
, " None\n");
2512 else if (flf
->font
!= NULL
)
2517 FlocaleGetFullNameOfFontStruct(
2519 fprintf(stderr
, " X info:\n"
2521 (full_name
)? full_name
:"?");
2522 if (full_name
!= NULL
)
2527 else if (flf
->fontset
!= NULL
)
2530 XFontStruct
**font_struct_list
;
2531 char **font_name_list
;
2533 fprintf(stderr
, " X info:\n");
2534 n
= XFontsOfFontSet(
2538 for(i
= 0; i
< n
; i
++)