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 /* ---------------------------- exported variables (globals) --------------- */
91 /* ---------------------------- local functions ---------------------------- */
94 * shadow local functions
98 void FlocaleParseShadow(char *str
, int *shadow_size
, int *shadow_offset
,
99 int *direction
, char * fontname
, char *module
)
103 multi_direction_t dir
;
105 *direction
= MULTI_DIR_NONE
;
106 token
= PeekToken(str
, &dir_str
);
107 if (token
== NULL
|| *token
== 0 ||
108 (GetIntegerArguments(token
, NULL
, shadow_size
, 1) != 1) ||
112 fprintf(stderr
,"[%s][FlocaleParseShadow]: WARNING -- bad "
113 "shadow size in font name:\n\t'%s'\n",
114 (module
)? module
: "FVWM", fontname
);
117 if (*shadow_size
== 0)
122 if (dir_str
&& *dir_str
&&
123 (GetIntegerArguments(dir_str
, NULL
, shadow_offset
, 1) == 1))
125 if (*shadow_offset
< 0)
128 fprintf(stderr
,"[%s][FlocaleParseShadow]: WARNING -- "
129 "bad shadow offset in font name:\n\t'%s'\n",
130 (module
)? module
: "FVWMlibs", fontname
);
132 PeekToken(dir_str
, &dir_str
);
134 while (dir_str
&& *dir_str
&& *dir_str
!= '\n')
136 dir
= gravity_parse_multi_dir_argument(dir_str
, &dir_str
);
137 if (dir
== MULTI_DIR_NONE
)
139 fprintf(stderr
,"[%s][FlocaleParseShadow]: WARNING -- "
140 "bad shadow direction in font description:\n"
142 (module
)? module
: "FVWMlibs", fontname
);
143 PeekToken(dir_str
, &dir_str
); /* skip it */
150 if (*direction
== MULTI_DIR_NONE
)
151 *direction
= MULTI_DIR_SE
;
155 * some simple converters
159 int FlocaleChar2bOneCharToUtf8(XChar2b c
, char *buf
)
162 char byte1
= c
.byte1
;
163 char byte2
= c
.byte2
;
164 unsigned short ucs2
= ((unsigned short)byte1
<< 8) + byte2
;
172 else if(ucs2
<= 0x7ff)
175 buf
[0] = (ucs2
>> 6) | 0xc0;
176 buf
[1] = (ucs2
& 0x3f) | 0x80;
182 buf
[0] = (ucs2
>> 12) | 0xe0;
183 buf
[1] = ((ucs2
& 0xfff) >> 6) | 0x80;
184 buf
[2] = (ucs2
& 0x3f) | 0x80;
190 /* return number of bytes of character at current position
191 (pointed to by str) */
192 int FlocaleStringNumberOfBytes(FlocaleFont
*flf
, const char *str
)
195 if(FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
198 if ((str
[0] & 0x80) == 0)
202 else if((str
[0] & ~0xdf) == 0)
208 /* this handles only 16-bit Unicode */
212 else if(flf
->flags
.is_mb
)
214 /* non-UTF-8 multibyte encoding */
215 if ((str
[0] & 0x80) == 0)
226 /* we must be using an "ordinary" 8-bit encoding */
232 /* given a string, font specifying its locale and a byte offset gives
234 int FlocaleStringByteToCharOffset(FlocaleFont
*flf
, const char *str
,
237 const char *curr_ptr
= str
;
239 int len
= strlen(str
);
244 i
< offset
&& i
< len
;
245 i
+= curr_len
, curr_ptr
+= curr_len
, coffset
++)
247 curr_len
= FlocaleStringNumberOfBytes(flf
, curr_ptr
);
252 /* like above but reversed, ie. return byte offset corresponding to given
254 int FlocaleStringCharToByteOffset(FlocaleFont
*flf
, const char *str
,
257 const char *curr_ptr
= str
;
259 int len
= strlen(str
);
264 i
< coffset
&& i
< len
;
265 offset
+= curr_len
, curr_ptr
+= curr_len
, i
++)
267 curr_len
= FlocaleStringNumberOfBytes(flf
, curr_ptr
);
272 /* return length of string in characters */
273 int FlocaleStringCharLength(FlocaleFont
*flf
, const char *str
)
276 int str_len
= strlen(str
);
277 for(i
= 0, len
= 0 ; i
< str_len
;
278 i
+= FlocaleStringNumberOfBytes(flf
, str
+i
), len
++);
283 XChar2b
*FlocaleUtf8ToUnicodeStr2b(char *str
, int len
, int *nl
)
285 XChar2b
*str2b
= NULL
;
288 str2b
= (XChar2b
*)safemalloc((len
+1)*sizeof(XChar2b
));
289 while (i
< len
&& str
[i
] != 0)
291 if ((str
[i
] & 0x80) == 0)
293 str2b
[j
].byte2
= str
[i
];
296 else if ((str
[i
] & ~0xdf) == 0 && i
+1 < len
)
298 t
= ((str
[i
] & 0x1f) << 6) + (str
[i
+1] & 0x3f);
299 str2b
[j
].byte2
= (unsigned char)(t
& 0xff);
300 str2b
[j
].byte1
= (unsigned char)(t
>> 8);
305 t
= ((str
[i
] & 0x0f) << 12) + ((str
[i
+1] & 0x3f) << 6)+
307 str2b
[j
].byte2
= (unsigned char)(t
& 0xff);
308 str2b
[j
].byte1
= (unsigned char)(t
>> 8);
317 /* Note: this function is not expected to work; good mb rendering
318 * should be (and is) done using Xmb functions and not XDrawString16
319 * (or with iso10646-1 fonts and setting the encoding).
320 * This function is used when the locale does not correspond to the font.
321 * It works with "EUC fonts": ksc5601.1987-0, gb2312 and maybe also
322 * cns11643-*. It works patially with jisx* and big5-0. Should try gbk-0,
323 * big5hkscs-0, and cns-11643- */
325 XChar2b
*FlocaleStringToString2b(
326 Display
*dpy
, FlocaleFont
*flf
, char *str
, int len
, int *nl
)
328 XChar2b
*str2b
= NULL
;
330 Bool free_str
= False
;
332 Bool euc
= True
; /* KSC5601 (EUC-KR), GB2312 (EUC-CN), CNS11643-1986-1
333 * (EUC-TW) and converted jisx (EUC-JP) */
335 if (flf
->fc
&& StrEquals(flf
->fc
->x
,"jisx0208.1983-0"))
337 tmp
= FiconvCharsetToCharset(
338 dpy
, flf
->fc
, FlocaleCharsetGetEUCJPCharset(), str
,
347 else if (flf
->fc
&& StrEquals(flf
->fc
->x
,"big5-0"))
351 str2b
= (XChar2b
*)safemalloc((len
+1)*sizeof(XChar2b
));
354 while (i
< len
&& str
[i
] != 0)
356 if ((str
[i
] & 0x80) == 0)
358 /* seems ok with KSC5601 and GB2312 as we get
359 * almost the ascii. I do no try
360 * CNS11643-1986-1. Should convert to ascii
362 str2b
[j
].byte1
= 0x23; /* magic number! */
363 str2b
[j
].byte2
= str
[i
++];
367 /* mb gl (for gr replace & 0x7f by | 0x80 ...)
369 str2b
[j
].byte1
= str
[i
++] & 0x7f;
370 str2b
[j
].byte2
= str
[i
++] & 0x7f;
381 else /* big5 and others not yet tested */
383 while (i
< len
&& str
[i
] != 0)
385 if ((str
[i
] & 0x80) == 0)
387 /* we should convert to ascii */
389 str2b
[j
].byte1
= 0xa2; /* magic number! */
390 str2b
[j
].byte2
= str
[i
++];
392 /* a blanck char ... */
393 str2b
[j
].byte1
= 0x21;
394 str2b
[j
].byte2
= 0x21;
398 str2b
[j
].byte1
= str
[i
++];
399 str2b
[j
].byte2
= str
[i
++];
417 char *FlocaleEncodeString(
418 Display
*dpy
, FlocaleFont
*flf
, char *str
, int *do_free
, int len
,
419 int *nl
, int *is_rtl
, superimpose_char_t
**comb_chars
,
422 char *str1
, *str2
, *str3
;
423 int len1
= len
, len2
;
425 Bool do_iconv
= True
;
426 const char *bidi_charset
;
433 if (flf
->str_fc
== NULL
|| flf
->fc
== NULL
||
434 flf
->fc
== flf
->str_fc
)
444 /* first process combining characters */
445 tmp_str
= FiconvCharsetToUtf8(
446 dpy
, flf
->str_fc
, (const char *)str
,len
);
447 /* if conversion to UTF-8 failed str1 will be NULL */
451 len
= CombineChars((unsigned char *)tmp_str
,
452 strlen(tmp_str
), comb_chars
,
454 /* returns the length of the resulting UTF-8 string */
455 /* convert back to current charset */
456 str1
= FiconvUtf8ToCharset(
457 dpy
, flf
->str_fc
, (const char *)tmp_str
,len
);
464 *nl
= len
= strlen(str1
);
469 /* convert back to current charset fail */
476 if (FiconvSupport
&& do_iconv
)
478 str2
= FiconvCharsetToCharset(
479 dpy
, flf
->str_fc
, flf
->fc
, (const char *)str1
, len
);
482 /* fail to convert */
487 if (*do_free
&& str1
)
500 /* initialise array with composing characters (empty) */
501 if(comb_chars
!= NULL
&& *comb_chars
== NULL
)
503 *comb_chars
= (superimpose_char_t
*)
504 safemalloc(sizeof(superimpose_char_t
));
505 (*comb_chars
)[0].position
= -1;
506 (*comb_chars
)[0].c
.byte1
= 0;
507 (*comb_chars
)[0].c
.byte2
= 0;
510 /* initialise logic to visual mapping here if that is demanded
511 (this is default when no combining has been done (1-to-1))
513 if(l_to_v
!= NULL
&& *l_to_v
== NULL
)
515 *l_to_v
= (int*)safemalloc((len
+ 1) * sizeof(int));
516 for(i
= 0 ; i
< len
; i
++)
522 if (FlocaleGetBidiCharset(dpy
, flf
->str_fc
) != NULL
&&
523 (bidi_charset
= FlocaleGetBidiCharset(dpy
, flf
->fc
)) != NULL
)
525 str3
= FBidiConvert(str2
, bidi_charset
, len1
,
527 comb_chars
!= NULL
? *comb_chars
: NULL
,
528 l_to_v
!= NULL
? *l_to_v
: NULL
);
529 if (str3
!= NULL
&& str3
!= str2
)
539 /* if we failed to do BIDI convert, return string string from
544 /* we already have the logical to visual mapping
545 from combining phase */
554 void FlocaleEncodeWinString(
555 Display
*dpy
, FlocaleFont
*flf
, FlocaleWinString
*fws
, int *do_free
,
556 int *len
, superimpose_char_t
**comb_chars
, int **l_to_v
)
559 fws
->e_str
= FlocaleEncodeString(
560 dpy
, flf
, fws
->str
, do_free
, *len
, len
, NULL
, comb_chars
,
564 if (flf
->font
!= None
)
566 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
568 fws
->str2b
= FlocaleUtf8ToUnicodeStr2b(
569 fws
->e_str
, *len
, &len2b
);
571 else if (flf
->flags
.is_mb
)
573 fws
->str2b
= FlocaleStringToString2b(
574 dpy
, flf
, fws
->e_str
, *len
, &len2b
);
580 * Text Drawing with a FontStruct
584 void FlocaleFontStructDrawString(
585 Display
*dpy
, FlocaleFont
*flf
, Drawable d
, GC gc
, int x
, int y
,
586 Pixel fg
, Pixel fgsh
, Bool has_fg_pixels
, FlocaleWinString
*fws
,
592 flocale_gstp_args gstp_args
;
594 is_string16
= (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
) || flf
->flags
.is_mb
);
595 if (is_string16
&& fws
->str2b
== NULL
)
601 /* for rotated drawing */
602 FSwitchDrawImageString(
603 is_string16
, dpy
, d
, gc
, x
, y
, fws
->e_str
, fws
->str2b
,
608 FlocaleInitGstpArgs(&gstp_args
, flf
, fws
, x
, y
);
610 if (flf
->shadow_size
!= 0 && has_fg_pixels
== True
)
612 XSetForeground(dpy
, fws
->gc
, fgsh
);
613 while (FlocaleGetShadowTextPosition(
614 &xt
, &yt
, &gstp_args
))
617 is_string16
, dpy
, d
, gc
, xt
, yt
,
618 fws
->e_str
, fws
->str2b
, len
);
621 if (has_fg_pixels
== True
)
623 XSetForeground(dpy
, gc
, fg
);
625 xt
= gstp_args
.orig_x
;
626 yt
= gstp_args
.orig_y
;
628 is_string16
, dpy
, d
, gc
, xt
,yt
, fws
->e_str
, fws
->str2b
,
636 * Rotated Text Drawing with a FontStruct or a FontSet
639 void FlocaleRotateDrawString(
640 Display
*dpy
, FlocaleFont
*flf
, FlocaleWinString
*fws
, Pixel fg
,
641 Pixel fgsh
, Bool has_fg_pixels
, int len
,
642 superimpose_char_t
*comb_chars
, int *pixel_pos
)
644 static GC my_gc
= None
;
645 static GC font_gc
= None
;
646 int j
, i
, xpfg
, ypfg
, xpsh
, ypsh
;
647 unsigned char *normal_data
, *rotated_data
;
648 unsigned int normal_w
, normal_h
, normal_len
;
649 unsigned int rotated_w
, rotated_h
, rotated_len
;
651 int width
, height
, descent
, min_offset
;
652 XImage
*image
, *rotated_image
;
653 Pixmap canvas_pix
, rotated_pix
;
654 flocale_gstp_args gstp_args
;
657 if (fws
->str
== NULL
|| len
< 1)
661 if (fws
->flags
.text_rotation
== ROTATION_0
)
663 return; /* should not happen */
668 my_gc
= fvwmlib_XCreateGC(dpy
, fws
->win
, 0, NULL
);
670 XCopyGC(dpy
, fws
->gc
, GCForeground
|GCBackground
, my_gc
);
672 /* width and height (no shadow!) */
673 width
= FlocaleTextWidth(flf
, fws
->str
, len
) - FLF_SHADOW_WIDTH(flf
);
674 height
= flf
->height
- FLF_SHADOW_HEIGHT(flf
);
675 descent
= flf
->descent
- FLF_SHADOW_DESCENT(flf
);;
682 /* glyph width and height of the normal text */
687 normal_len
= (normal_w
- 1) / 8 + 1;
689 /* create and clear the canvas */
690 canvas_pix
= XCreatePixmap(dpy
, fws
->win
, width
, height
, 1);
693 font_gc
= fvwmlib_XCreateGC(dpy
, canvas_pix
, 0, NULL
);
695 XSetBackground(dpy
, font_gc
, 0);
696 XSetForeground(dpy
, font_gc
, 0);
697 XFillRectangle(dpy
, canvas_pix
, font_gc
, 0, 0, width
, height
);
699 /* draw the character center top right on canvas */
700 XSetForeground(dpy
, font_gc
, 1);
701 if (flf
->font
!= NULL
)
703 XSetFont(dpy
, font_gc
, flf
->font
->fid
);
704 FlocaleFontStructDrawString(dpy
, flf
, canvas_pix
, font_gc
, 0,
706 fg
, fgsh
, has_fg_pixels
,
709 else if (flf
->fontset
!= None
)
712 dpy
, canvas_pix
, flf
->fontset
, font_gc
, 0,
713 height
- descent
, fws
->e_str
, len
);
716 /* here take care of superimposing chars */
718 if(comb_chars
!= NULL
)
720 while(comb_chars
[i
].c
.byte1
!= 0 && comb_chars
[i
].c
.byte2
!= 0)
722 /* draw composing character on top of corresponding
724 FlocaleWinString tmp_fws
= *fws
;
725 int offset
= pixel_pos
[comb_chars
[i
].position
];
726 int curr_len
= FlocaleChar2bOneCharToUtf8(
730 char *buf2
= FiconvUtf8ToCharset(
733 (const char *)buf
,curr_len
);
736 /* if conversion failed, combinational char
737 is not representable in current charset */
738 /* just replace with empty string */
739 buf2
= (char *)safemalloc(sizeof(char));
742 tmp_fws
.e_str
= buf2
;
743 tmp_fws
.str2b
= NULL
;
744 if(flf
->fontset
!= None
)
746 XmbDrawString(dpy
, canvas_pix
, flf
->fontset
,
748 height
- descent
, buf2
,
751 else if(flf
->font
!= None
)
753 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
755 tmp_fws
.str2b
= (XChar2b
*)
756 safemalloc(2 * sizeof(XChar2b
));
757 tmp_fws
.str2b
[0] = comb_chars
[i
].c
;
758 tmp_fws
.str2b
[1].byte1
= 0;
759 tmp_fws
.str2b
[1].byte2
= 0;
762 else if (flf
->flags
.is_mb
)
765 FlocaleStringToString2b(
766 dpy
, flf
, tmp_fws
.e_str
,
771 out_len
= strlen(buf2
);
773 XSetFont(dpy
, font_gc
, flf
->font
->fid
);
774 FlocaleFontStructDrawString(
775 dpy
, flf
, canvas_pix
, font_gc
,
776 offset
, height
- descent
,
777 fg
, fgsh
, has_fg_pixels
, &tmp_fws
,
782 if(tmp_fws
.str2b
!= NULL
)
790 /* reserve memory for the first XImage */
791 normal_data
= (unsigned char *)safemalloc(normal_len
* normal_h
);
793 /* create depth 1 XImage */
794 if ((image
= XCreateImage(
795 dpy
, Pvisual
, 1, XYBitmap
, 0, (char *)normal_data
,
796 normal_w
, normal_h
, 8, 0)) == NULL
)
800 image
->byte_order
= image
->bitmap_bit_order
= MSBFirst
;
802 /* extract character from canvas */
804 dpy
, canvas_pix
, 0, 0, normal_w
, normal_h
,
805 1, XYPixmap
, image
, 0, 0);
806 image
->format
= XYBitmap
;
808 /* width, height of the rotated text */
809 if (fws
->flags
.text_rotation
== ROTATION_180
)
811 rotated_w
= normal_w
;
812 rotated_h
= normal_h
;
814 else /* vertical text */
816 rotated_w
= normal_h
;
817 rotated_h
= normal_w
;
821 rotated_len
= (rotated_w
- 1) / 8 + 1;
823 /* reserve memory for the rotated image */
824 rotated_data
= (unsigned char *)safecalloc(rotated_h
* rotated_len
, 1);
826 /* create the rotated X image */
827 if ((rotated_image
= XCreateImage(
828 dpy
, Pvisual
, 1, XYBitmap
, 0, (char *)rotated_data
,
829 rotated_w
, rotated_h
, 8, 0)) == NULL
)
834 rotated_image
->byte_order
= rotated_image
->bitmap_bit_order
= MSBFirst
;
836 /* map normal text data to rotated text data */
837 for (j
= 0; j
< rotated_h
; j
++)
839 for (i
= 0; i
< rotated_w
; i
++)
842 if (fws
->flags
.text_rotation
== ROTATION_270
)
845 (normal_w
- j
- 1) / 8
846 ] & (128 >> ((normal_w
- j
- 1) % 8));
848 else if (fws
->flags
.text_rotation
== ROTATION_180
)
850 (normal_h
- j
- 1) * normal_len
+
851 (normal_w
- i
- 1) / 8
852 ] & (128 >> ((normal_w
- i
- 1) % 8));
854 else /* ROTATION_90 */
856 (normal_h
- i
- 1) * normal_len
+
857 j
/ 8] & (128 >> (j
% 8));
860 rotated_data
[j
* rotated_len
+ i
/ 8] |=
865 /* create the character's bitmap and put the image on it */
866 rotated_pix
= XCreatePixmap(dpy
, fws
->win
, rotated_w
, rotated_h
, 1);
868 dpy
, rotated_pix
, font_gc
, rotated_image
, 0, 0, 0, 0,
869 rotated_w
, rotated_h
);
871 /* free the image and data */
872 XDestroyImage(image
);
873 XDestroyImage(rotated_image
);
875 /* free pixmap and GC */
876 XFreePixmap(dpy
, canvas_pix
);
878 /* x and y corrections: we fill a rectangle! */
879 min_offset
= FlocaleGetMinOffset(flf
, fws
->flags
.text_rotation
);
880 switch (fws
->flags
.text_rotation
)
884 xpfg
= fws
->x
- min_offset
;
889 ypfg
= fws
->y
- min_offset
+
890 FLF_SHADOW_BOTTOM_SIZE(flf
);
894 xpfg
= fws
->x
- min_offset
;
900 ypfg
= fws
->y
- min_offset
;
905 /* write the image on the window */
906 XSetFillStyle(dpy
, my_gc
, FillStippled
);
907 XSetStipple(dpy
, my_gc
, rotated_pix
);
908 FlocaleInitGstpArgs(&gstp_args
, flf
, fws
, xpfg
, ypfg
);
909 if (flf
->shadow_size
!= 0 && has_fg_pixels
== True
)
911 XSetForeground(dpy
, my_gc
, fgsh
);
912 while (FlocaleGetShadowTextPosition(&xpsh
, &ypsh
, &gstp_args
))
914 XSetTSOrigin(dpy
, my_gc
, xpsh
, ypsh
);
916 dpy
, fws
->win
, my_gc
, xpsh
, ypsh
, rotated_w
,
920 xpsh
= gstp_args
.orig_x
;
921 ypsh
= gstp_args
.orig_y
;
922 XSetTSOrigin(dpy
, my_gc
, xpsh
, ypsh
);
923 XFillRectangle(dpy
, fws
->win
, my_gc
, xpsh
, ypsh
, rotated_w
, rotated_h
);
924 XFreePixmap(dpy
, rotated_pix
);
930 * Fonts info and checking
934 char *FlocaleGetFullNameOfFontStruct(Display
*dpy
, XFontStruct
*font
)
936 char *full_name
= NULL
;
939 if (XGetFontProperty(font
, XA_FONT
, &value
))
941 full_name
= XGetAtomName(dpy
, value
);
947 char *FlocaleGetCharsetOfFontStruct(Display
*dpy
, XFontStruct
*font
)
951 char *charset
= NULL
;
954 full_name
= FlocaleGetFullNameOfFontStruct(dpy
, font
);
955 if (full_name
== NULL
)
959 while(full_name
[i
] != '\0' && count
< 13)
961 if (full_name
[i
] == '-')
972 CopyString(&charset
, full_name
+i
);
978 char *FlocaleGetCharsetFromName(char *name
)
985 while(i
>= 0 && name
[i
] != '-')
989 if (i
== 0 || i
== l
-1)
995 while(i
>= 0 && name
[i
] != '-')
999 if (i
<= 0 || e
== i
)
1003 CopyString(&charset
, name
+ i
+ 1);
1007 /* return NULL if it is not reasonable to load a FontSet.
1008 * Currently return name if it is reasonable to load a FontSet, but in the
1009 * future we may want to transform name for faster FontSet loading */
1011 char *FlocaleFixNameForFontSet(Display
*dpy
, char *name
, char *module
)
1015 XFontStruct
*test_font
= NULL
;
1024 if (strchr(name
, ','))
1026 /* tmp, do not handle "," separated list */
1029 charset
= FlocaleGetCharsetFromName(name
);
1030 if (charset
== NULL
&& !strchr(name
, '*') && !strchr(name
, '?'))
1032 /* probably a font alias! */
1033 if ((test_font
= XLoadQueryFont(dpy
, name
)))
1035 charset
= FlocaleGetCharsetOfFontStruct(dpy
, test_font
);
1036 XFreeFont(dpy
, test_font
);
1039 if (charset
!= NULL
)
1041 if (!strchr(charset
, '*') && !strchr(charset
, '?') &&
1042 !FlocaleCharsetIsCharsetXLocale(dpy
, charset
, module
))
1044 /* if the charset is fully specified and do not match
1045 * one of the X locale charset */
1048 fprintf(stderr
,"[%s][FlocaleGetFontSet]: WARNING -- "
1049 "Use of a non X locale charset '%s' when "
1050 "loading font: %s\n",
1051 (module
)? module
:"fvwmlibs", charset
, name
);
1064 FlocaleFont
*FlocaleGetFftFont(
1065 Display
*dpy
, char *fontname
, char *encoding
, char *module
)
1067 FftFontType
*fftf
= NULL
;
1068 FlocaleFont
*flf
= NULL
;
1069 char *fn
, *hints
= NULL
;
1071 hints
= GetQuotedString(fontname
, &fn
, "/", NULL
, NULL
, NULL
);
1074 fn
= FLOCALE_FFT_FALLBACK_FONT
;
1076 else if (*fn
== '\0')
1079 fn
= FLOCALE_FFT_FALLBACK_FONT
;
1081 fftf
= FftGetFont(dpy
, fn
, module
);
1084 if (fn
!= NULL
&& fn
!= FLOCALE_FFT_FALLBACK_FONT
)
1090 flf
= (FlocaleFont
*)safemalloc(sizeof(FlocaleFont
));
1091 memset(flf
, '\0', sizeof(FlocaleFont
));
1094 FlocaleCharsetSetFlocaleCharset(dpy
, flf
, hints
, encoding
, module
);
1096 &flf
->fftf
, &flf
->height
, &flf
->ascent
, &flf
->descent
);
1097 FftGetFontWidths(flf
, &flf
->max_char_width
);
1099 if (fn
!= NULL
&& fn
!= FLOCALE_FFT_FALLBACK_FONT
)
1108 FlocaleFont
*FlocaleGetFontSet(
1109 Display
*dpy
, char *fontname
, char *encoding
, char *module
)
1111 static int mc_errors
= 0;
1112 FlocaleFont
*flf
= NULL
;
1113 XFontSet fontset
= NULL
;
1117 XFontSetExtents
*fset_extents
;
1118 char *fn
, *hints
= NULL
, *fn_fixed
= NULL
;
1120 hints
= GetQuotedString(fontname
, &fn
, "/", NULL
, NULL
, NULL
);
1124 fn
= fn_fixed
= FLOCALE_MB_FALLBACK_FONT
;
1126 else if (!(fn_fixed
= FlocaleFixNameForFontSet(dpy
, fn
, module
)))
1128 if (fn
!= NULL
&& fn
!= FLOCALE_MB_FALLBACK_FONT
)
1134 if (!(fontset
= XCreateFontSet(dpy
, fn_fixed
, &ml
, &mc
, &ds
)))
1136 if (fn_fixed
&& fn_fixed
!= fn
)
1140 if (fn
!= NULL
&& fn
!= FLOCALE_MB_FALLBACK_FONT
)
1149 if (mc_errors
<= FLOCALE_NUMBER_MISS_CSET_ERR_MSG
)
1153 "[%s][FlocaleGetFontSet]: (%s)"
1154 " Missing font charsets:\n",
1155 (module
)? module
: "FVWMlibs", fontname
);
1156 for (i
= 0; i
< mc
; i
++)
1158 fprintf(stderr
, "%s", ml
[i
]);
1160 fprintf(stderr
, ", ");
1162 fprintf(stderr
, "\n");
1163 if (mc_errors
== FLOCALE_NUMBER_MISS_CSET_ERR_MSG
)
1166 "[%s][FlocaleGetFontSet]: No more"
1167 " missing charset reportings\n",
1168 (module
)? module
: "FVWMlibs");
1171 XFreeStringList(ml
);
1174 flf
= (FlocaleFont
*)safemalloc(sizeof(FlocaleFont
));
1175 memset(flf
, '\0', sizeof(FlocaleFont
));
1177 flf
->fontset
= fontset
;
1178 FlocaleCharsetSetFlocaleCharset(dpy
, flf
, hints
, encoding
, module
);
1179 fset_extents
= XExtentsOfFontSet(fontset
);
1180 flf
->height
= fset_extents
->max_ink_extent
.height
;
1181 flf
->ascent
= - fset_extents
->max_ink_extent
.y
;
1182 flf
->descent
= fset_extents
->max_ink_extent
.height
+
1183 fset_extents
->max_ink_extent
.y
;
1184 flf
->max_char_width
= fset_extents
->max_ink_extent
.width
;
1185 if (fn_fixed
&& fn_fixed
!= fn
)
1189 if (fn
!= NULL
&& fn
!= FLOCALE_MB_FALLBACK_FONT
)
1198 FlocaleFont
*FlocaleGetFont(
1199 Display
*dpy
, char *fontname
, char *encoding
, char *module
)
1201 XFontStruct
*font
= NULL
;
1206 hints
= GetQuotedString(fontname
, &tmp
, "/", NULL
, NULL
, NULL
);
1207 str
= GetQuotedString(tmp
, &fn
, ",", NULL
, NULL
, NULL
);
1213 fn
= FLOCALE_FALLBACK_FONT
;
1215 font
= XLoadQueryFont(dpy
, fn
);
1216 if (fn
!= NULL
&& fn
!= FLOCALE_FALLBACK_FONT
)
1221 if (!font
&& str
&& *str
)
1223 str
= GetQuotedString(str
, &fn
, ",", NULL
, NULL
, NULL
);
1228 if (fn
!= NULL
&& fn
!= FLOCALE_FALLBACK_FONT
)
1239 flf
= (FlocaleFont
*)safemalloc(sizeof(FlocaleFont
));
1240 memset(flf
, '\0', sizeof(FlocaleFont
));
1242 flf
->fontset
= None
;
1243 flf
->fftf
.fftfont
= NULL
;
1245 FlocaleCharsetSetFlocaleCharset(dpy
, flf
, hints
, encoding
, module
);
1246 flf
->height
= font
->max_bounds
.ascent
+ font
->max_bounds
.descent
;
1247 flf
->ascent
= font
->max_bounds
.ascent
;
1248 flf
->descent
= font
->max_bounds
.descent
;
1249 flf
->max_char_width
= font
->max_bounds
.width
;
1250 if (flf
->font
->max_byte1
> 0)
1251 flf
->flags
.is_mb
= True
;
1252 if (fn
!= NULL
&& fn
!= FLOCALE_FALLBACK_FONT
)
1265 FlocaleFont
*FlocaleGetFontOrFontSet(
1266 Display
*dpy
, char *fontname
, char *encoding
, char *fullname
,
1269 FlocaleFont
*flf
= NULL
;
1271 if (fontname
&& strlen(fontname
) > 3 &&
1272 strncasecmp("xft:", fontname
, 4) == 0)
1276 flf
= FlocaleGetFftFont(
1277 dpy
, fontname
+4, encoding
, module
);
1281 CopyString(&flf
->name
, fullname
);
1285 if (flf
== NULL
&& Flocale
!= NULL
&& fontname
)
1287 flf
= FlocaleGetFontSet(dpy
, fontname
, encoding
, module
);
1289 if (flf
== NULL
&& fontname
)
1291 flf
= FlocaleGetFont(dpy
, fontname
, encoding
, module
);
1293 if (flf
&& fontname
)
1295 if (StrEquals(fullname
, FLOCALE_MB_FALLBACK_FONT
))
1297 flf
->name
= FLOCALE_MB_FALLBACK_FONT
;
1299 else if (StrEquals(fullname
, FLOCALE_FALLBACK_FONT
))
1301 flf
->name
= FLOCALE_FALLBACK_FONT
;
1305 CopyString(&flf
->name
, fullname
);
1313 * locale local functions
1317 void FlocaleSetlocaleForX(
1318 int category
, const char *locale
, const char *module
)
1320 if ((Flocale
= setlocale(category
, locale
)) == NULL
)
1323 "[%s][%s]: ERROR -- Cannot set locale. Please check"
1324 " your $LC_CTYPE or $LANG.\n",
1325 (module
== NULL
)? "" : module
, "FlocaleSetlocaleForX");
1328 if (!XSupportsLocale())
1331 "[%s][%s]: WARNING -- X does not support locale %s\n",
1332 (module
== NULL
)? "": module
, "FlocaleSetlocaleForX",
1338 /* ---------------------------- interface functions ------------------------ */
1341 * locale initialisation
1345 int category
, const char *locale
, const char *modifiers
,
1349 FlocaleSetlocaleForX(category
, locale
, module
);
1350 if (Flocale
== NULL
)
1353 if (modifiers
!= NULL
&&
1354 (Fmodifiers
= XSetLocaleModifiers(modifiers
)) == NULL
)
1357 "[%s][%s]: WARNING -- Cannot set locale modifiers\n",
1358 (module
== NULL
)? "": module
, "FlocaleInit");
1360 #if FLOCALE_DEBUG_SETLOCALE
1361 fprintf(stderr
,"[%s][FlocaleInit] locale: %s, modifier: %s\n",
1362 module
, Flocale
, Fmodifiers
);
1369 char *prefix_list
[] =
1376 FlocaleFont
*FlocaleLoadFont(Display
*dpy
, char *fontname
, char *module
)
1378 FlocaleFont
*flf
= FlocaleFontList
;
1379 Bool ask_default
= False
;
1381 char *str
, *opt_str
, *encoding
= NULL
, *fn
= NULL
;
1382 int shadow_size
= 0;
1383 int shadow_offset
= 0;
1384 int shadow_dir
= MULTI_DIR_SE
;
1387 /* removing quoting for modules */
1388 if (fontname
&& (t
= strchr("\"'`", *fontname
)))
1392 if (fontname
[strlen(fontname
)-1] == c
)
1393 fontname
[strlen(fontname
)-1] = 0;
1396 if (fontname
== NULL
|| *fontname
== 0)
1399 fontname
= FLOCALE_MB_FALLBACK_FONT
;
1406 for (c1
= fontname
, c2
= flf
->name
; *c1
&& *c2
; ++c1
, ++c2
)
1421 /* not cached load the font as a ";" separated list */
1423 /* But first see if we have a shadow relief and/or an encoding */
1425 while ((i
= GetTokenIndex(str
, prefix_list
, -1, &str
)) > -1)
1427 str
= GetQuotedString(str
, &opt_str
, ":", NULL
, NULL
, NULL
);
1430 case 0: /* shadow= */
1432 opt_str
, &shadow_size
, &shadow_offset
,
1433 &shadow_dir
, fontname
, module
);
1435 case 1: /* encoding= */
1436 if (encoding
!= NULL
)
1441 if (opt_str
&& *opt_str
)
1443 CopyString(&encoding
, opt_str
);
1449 if (opt_str
!= NULL
)
1454 str
= GetQuotedString(str
, &fn
, ";", NULL
, NULL
, NULL
);
1458 fn
= FLOCALE_MB_FALLBACK_FONT
;
1460 while (!flf
&& (fn
&& *fn
))
1462 flf
= FlocaleGetFontOrFontSet(
1463 dpy
, fn
, encoding
, fontname
, module
);
1464 if (fn
!= NULL
&& fn
!= FLOCALE_MB_FALLBACK_FONT
&&
1465 fn
!= FLOCALE_FALLBACK_FONT
)
1470 if (!flf
&& str
&& *str
)
1472 str
= GetQuotedString(str
, &fn
, ";", NULL
, NULL
, NULL
);
1475 if (fn
!= NULL
&& fn
!= FLOCALE_MB_FALLBACK_FONT
&&
1476 fn
!= FLOCALE_FALLBACK_FONT
)
1483 /* loading failed, try default font */
1486 fprintf(stderr
,"[%s][FlocaleLoadFont]: "
1487 "WARNING -- can't load font '%s',"
1488 " trying default:\n",
1489 (module
)? module
: "FVWMlibs", fontname
);
1493 /* we already tried default fonts: try again? yes */
1495 if (Flocale
!= NULL
)
1499 fprintf(stderr
, "\t%s\n",
1500 FLOCALE_MB_FALLBACK_FONT
);
1502 if ((flf
= FlocaleGetFontSet(
1503 dpy
, FLOCALE_MB_FALLBACK_FONT
, NULL
,
1506 flf
->name
= FLOCALE_MB_FALLBACK_FONT
;
1513 fprintf(stderr
,"\t%s\n",
1514 FLOCALE_FALLBACK_FONT
);
1518 dpy
, FLOCALE_FALLBACK_FONT
, NULL
,
1521 flf
->name
= FLOCALE_FALLBACK_FONT
;
1523 else if (!ask_default
)
1526 "[%s][FlocaleLoadFont]:"
1527 " ERROR -- can't load font.\n",
1528 (module
)? module
: "FVWMlibs");
1533 "[%s][FlocaleLoadFont]: ERROR"
1534 " -- can't load default font:\n",
1535 (module
)? module
: "FVWMlibs");
1536 fprintf(stderr
, "\t%s\n",
1537 FLOCALE_MB_FALLBACK_FONT
);
1538 fprintf(stderr
, "\t%s\n",
1539 FLOCALE_FALLBACK_FONT
);
1546 if (shadow_size
> 0)
1548 flf
->shadow_size
= shadow_size
;
1549 flf
->flags
.shadow_dir
= shadow_dir
;
1550 flf
->shadow_offset
= shadow_offset
;
1551 flf
->descent
+= FLF_SHADOW_DESCENT(flf
);
1552 flf
->ascent
+= FLF_SHADOW_ASCENT(flf
);
1553 flf
->height
+= FLF_SHADOW_HEIGHT(flf
);
1554 flf
->max_char_width
+= FLF_SHADOW_WIDTH(flf
);
1556 if (flf
->fc
== FlocaleCharsetGetUnknownCharset())
1558 fprintf(stderr
,"[%s][FlocaleLoadFont]: "
1559 "WARNING -- Unknown charset for font\n\t'%s'\n",
1560 (module
)? module
: "FVWMlibs", flf
->name
);
1561 flf
->fc
= FlocaleCharsetGetDefaultCharset(dpy
, module
);
1563 else if (flf
->str_fc
== FlocaleCharsetGetUnknownCharset() &&
1564 (encoding
!= NULL
||
1565 (FftSupport
&& flf
->fftf
.fftfont
!= NULL
&&
1566 flf
->fftf
.str_encoding
!= NULL
)))
1568 fprintf(stderr
,"[%s][FlocaleLoadFont]: "
1569 "WARNING -- Unknown string encoding for font\n"
1571 (module
)? module
: "FVWMlibs", flf
->name
);
1573 if (flf
->str_fc
== FlocaleCharsetGetUnknownCharset())
1576 FlocaleCharsetGetDefaultCharset(dpy
, module
);
1578 flf
->next
= FlocaleFontList
;
1579 FlocaleFontList
= flf
;
1581 if (encoding
!= NULL
)
1589 void FlocaleUnloadFont(Display
*dpy
, FlocaleFont
*flf
)
1591 FlocaleFont
*list
= FlocaleFontList
;
1598 /* Remove a weight, still too heavy? */
1599 if (--(flf
->count
) > 0)
1604 if (flf
->name
!= NULL
&&
1605 !StrEquals(flf
->name
, FLOCALE_MB_FALLBACK_FONT
) &&
1606 !StrEquals(flf
->name
, FLOCALE_FALLBACK_FONT
))
1610 if (FftSupport
&& flf
->fftf
.fftfont
!= NULL
)
1612 FftFontClose(dpy
, flf
->fftf
.fftfont
);
1613 if (flf
->fftf
.fftfont_rotated_90
!= NULL
)
1614 FftFontClose(dpy
, flf
->fftf
.fftfont_rotated_90
);
1615 if (flf
->fftf
.fftfont_rotated_180
!= NULL
)
1616 FftFontClose(dpy
, flf
->fftf
.fftfont_rotated_180
);
1617 if (flf
->fftf
.fftfont_rotated_270
!= NULL
)
1618 FftFontClose(dpy
, flf
->fftf
.fftfont_rotated_270
);
1620 if (flf
->fontset
!= NULL
)
1622 XFreeFontSet(dpy
, flf
->fontset
);
1624 if (flf
->font
!= NULL
)
1626 XFreeFont(dpy
, flf
->font
);
1628 if (flf
->flags
.must_free_fc
)
1633 free(flf
->fc
->bidi
);
1634 if (flf
->fc
->locale
!= NULL
)
1636 while (FLC_GET_LOCALE_CHARSET(flf
->fc
,i
) != NULL
)
1638 free(FLC_GET_LOCALE_CHARSET(flf
->fc
,i
));
1641 free(flf
->fc
->locale
);
1646 /* Link it out of the list (it might not be there) */
1647 if (flf
== list
) /* in head? simple */
1649 FlocaleFontList
= flf
->next
;
1653 while (list
&& list
->next
!= flf
)
1655 /* fast forward until end or found */
1658 /* not end? means we found it in there, possibly at end */
1661 /* link around it */
1662 list
->next
= flf
->next
;
1669 * Width and Drawing Text
1672 void FlocaleInitGstpArgs(
1673 flocale_gstp_args
*args
, FlocaleFont
*flf
, FlocaleWinString
*fws
,
1674 int start_x
, int start_y
)
1677 args
->offset
= flf
->shadow_offset
+ 1;
1678 args
->outer_offset
= flf
->shadow_offset
+ flf
->shadow_size
;
1679 args
->size
= flf
->shadow_size
;
1680 args
->sdir
= flf
->flags
.shadow_dir
;
1681 switch (fws
->flags
.text_rotation
)
1683 case ROTATION_270
: /* CCW */
1684 args
->orig_x
= start_x
+ FLF_SHADOW_UPPER_SIZE(flf
);
1685 args
->orig_y
= start_y
+ FLF_SHADOW_RIGHT_SIZE(flf
);
1688 args
->orig_x
= start_x
+ FLF_SHADOW_RIGHT_SIZE(flf
);
1689 args
->orig_y
= start_y
;
1691 case ROTATION_90
: /* CW */
1692 args
->orig_x
= start_x
+ FLF_SHADOW_BOTTOM_SIZE(flf
);
1693 args
->orig_y
= start_y
+ FLF_SHADOW_LEFT_SIZE(flf
);
1697 args
->orig_x
= start_x
+ FLF_SHADOW_LEFT_SIZE(flf
);
1698 args
->orig_y
= start_y
;
1701 args
->rot
= fws
->flags
.text_rotation
;
1706 Bool
FlocaleGetShadowTextPosition(
1707 int *x
, int *y
, flocale_gstp_args
*args
)
1709 if (args
->step
== 0)
1711 args
->direction
= MULTI_DIR_NONE
;
1712 args
->inter_step
= 0;
1714 if ((args
->step
== 0 || args
->inter_step
>= args
->num_inter_steps
) &&
1717 /* setup a new direction */
1718 args
->inter_step
= 0;
1719 gravity_get_next_multi_dir(args
->sdir
, &args
->direction
);
1720 if (args
->direction
== MULTI_DIR_C
)
1724 size
= 2 * (args
->outer_offset
) + 1;
1725 args
->num_inter_steps
= size
* size
;
1729 args
->num_inter_steps
= args
->size
;
1732 if (args
->direction
== MULTI_DIR_NONE
|| args
->size
== 0)
1739 if (args
->direction
== MULTI_DIR_C
)
1746 size
= 2 * (args
->outer_offset
) + 1;
1747 tx
= args
->inter_step
% size
- args
->outer_offset
;
1748 ty
= args
->inter_step
/ size
- args
->outer_offset
;
1749 for (is_finished
= 0; ty
<= args
->outer_offset
;
1750 ty
++, tx
= -args
->outer_offset
)
1752 for (; tx
<= args
->outer_offset
; tx
++)
1754 if (tx
<= -args
->offset
||
1755 tx
>= args
->offset
||
1756 ty
<= -args
->offset
|| ty
>= args
->offset
)
1768 (tx
+ args
->outer_offset
) +
1769 (ty
+ args
->outer_offset
) * size
;
1775 *x
= args
->orig_x
+ tx
;
1776 *y
= args
->orig_y
+ ty
;
1778 else if (args
->inter_step
> 0)
1780 /* into a directional drawing */
1781 (*x
) += args
->x_sign
;
1782 (*y
) += args
->y_sign
;
1790 dir
= gravity_multi_dir_to_dir(args
->direction
);
1791 gravity_split_xy_dir(&dir_x
, &dir_y
, dir
);
1792 args
->x_sign
= gravity_dir_to_sign_one_axis(dir_x
);
1793 args
->y_sign
= gravity_dir_to_sign_one_axis(dir_y
);
1795 args
->rot
, args
->x_sign
, args
->y_sign
,
1796 &args
->x_sign
, &args
->y_sign
);
1797 *x
= args
->orig_x
+ args
->x_sign
* args
->offset
;
1798 *y
= args
->orig_y
+ args
->y_sign
* args
->offset
;
1806 void FlocaleDrawString(
1807 Display
*dpy
, FlocaleFont
*flf
, FlocaleWinString
*fws
,
1808 unsigned long flags
)
1811 Bool do_free
= False
;
1812 Pixel fg
= 0, fgsh
= 0;
1813 Bool has_fg_pixels
= False
;
1814 flocale_gstp_args gstp_args
;
1815 superimpose_char_t
*comb_chars
= NULL
;
1817 int char_len
; /* length in number of chars */
1818 int *pixel_pos
= NULL
;
1825 if (!fws
|| !fws
->str
)
1830 if (flags
& FWS_HAVE_LENGTH
)
1836 len
= strlen(fws
->str
);
1839 /* encode the string */
1840 FlocaleEncodeWinString(
1841 dpy
, flf
, fws
, &do_free
, &len
, &comb_chars
, NULL
);
1842 curr_str
= fws
->e_str
;
1843 for(char_len
= 0, i
= 0 ;
1844 i
< len
&& curr_str
[i
] != 0 ;
1845 char_len
++, i
+= curr_len
)
1847 curr_len
= FlocaleStringNumberOfBytes(flf
, curr_str
+ i
);
1850 /* for superimposition calculate the character positions in pixels */
1851 if (comb_chars
!= NULL
&& (
1852 comb_chars
[0].c
.byte1
!= 0 || comb_chars
[0].c
.byte2
!= 0))
1854 /* the second condition is actually redundant,
1855 but there for clarity,
1856 ending at 0 is what's expected in a correct
1858 pixel_pos
= (int *)safemalloc(
1859 (char_len
!= 0 ? char_len
: 1) * sizeof(int));
1861 /* if there is 0 bytes in the encoded string, there might
1862 still be combining character to draw (at position 0) */
1869 i
= 0, curr_pixel_pos
= 0 ;
1871 i
++, curr_str
+= curr_len
)
1873 curr_len
= FlocaleStringNumberOfBytes(flf
, curr_str
);
1874 for (j
= 0 ; j
< curr_len
; j
++)
1876 buf
[j
] = curr_str
[j
];
1879 pixel_pos
[i
] = curr_pixel_pos
;
1880 /* need to compensate for shadow width (if any) */
1882 FlocaleTextWidth(flf
, buf
, curr_len
) -
1883 FLF_SHADOW_WIDTH(flf
);
1887 /* get the pixels */
1888 if (fws
->flags
.has_colorset
)
1890 fg
= fws
->colorset
->fg
;
1891 fgsh
= fws
->colorset
->fgsh
;
1892 has_fg_pixels
= True
;
1894 else if (flf
->shadow_size
!= 0)
1898 if (XGetGCValues(dpy
, fws
->gc
, GCForeground
, &xgcv
) != 0)
1900 fg
= xgcv
.foreground
;
1904 fg
= PictureBlackPixel();
1906 fgsh
= GetShadow(fg
);
1907 has_fg_pixels
= True
;
1910 if(flf
->font
!= None
&&
1911 (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
) || flf
->flags
.is_mb
))
1913 /* in this case, length is number of 2-byte chars */
1917 if (fws
->flags
.text_rotation
!= ROTATION_0
&&
1918 flf
->fftf
.fftfont
== NULL
)
1920 /* pass in information to perform superimposition */
1921 FlocaleRotateDrawString(
1922 dpy
, flf
, fws
, fg
, fgsh
, has_fg_pixels
, len
,
1923 comb_chars
, pixel_pos
);
1925 else if (FftSupport
&& flf
->fftf
.fftfont
!= NULL
)
1928 dpy
, flf
, fws
, fg
, fgsh
, has_fg_pixels
, len
, flags
);
1930 else if (flf
->fontset
!= None
)
1935 FlocaleInitGstpArgs(&gstp_args
, flf
, fws
, fws
->x
, fws
->y
);
1936 if (flf
->shadow_size
!= 0)
1938 XSetForeground(dpy
, fws
->gc
, fgsh
);
1939 while (FlocaleGetShadowTextPosition(
1940 &xt
, &yt
, &gstp_args
))
1943 dpy
, fws
->win
, flf
->fontset
, fws
->gc
,
1944 xt
, yt
, fws
->e_str
, len
);
1947 if (has_fg_pixels
== True
)
1949 XSetForeground(dpy
, fws
->gc
, fg
);
1951 xt
= gstp_args
.orig_x
;
1952 yt
= gstp_args
.orig_y
;
1954 dpy
, fws
->win
, flf
->fontset
, fws
->gc
,
1955 xt
, yt
, fws
->e_str
, len
);
1957 else if (flf
->font
!= None
)
1959 FlocaleFontStructDrawString(
1960 dpy
, flf
, fws
->win
, fws
->gc
, fws
->x
, fws
->y
,
1961 fg
, fgsh
, has_fg_pixels
, fws
, len
, False
);
1964 /* here take care of superimposing chars */
1966 if (comb_chars
!= NULL
)
1968 while(comb_chars
[i
].c
.byte1
!= 0 && comb_chars
[i
].c
.byte2
!= 0)
1970 /* draw composing character on top of corresponding
1972 FlocaleWinString tmp_fws
= *fws
;
1973 int offset
= pixel_pos
[comb_chars
[i
].position
];
1976 curr_len
= FlocaleChar2bOneCharToUtf8(comb_chars
[i
].c
,
1978 buf2
= FiconvUtf8ToCharset(
1979 dpy
, flf
->str_fc
, (const char *)buf
, curr_len
);
1982 /* if conversion failed, combinational char
1983 is not representable in current charset */
1984 /* just replace with empty string */
1985 buf2
= (char *)safemalloc(sizeof(char));
1988 tmp_fws
.e_str
= buf2
;
1989 tmp_fws
.str2b
= NULL
;
1990 if(FftSupport
&& flf
->fftf
.fftfont
!= NULL
)
1992 tmp_fws
.x
= fws
->x
+ offset
;
1994 dpy
, flf
, &tmp_fws
, fg
, fgsh
,
1995 has_fg_pixels
, strlen(buf2
),
1998 else if(flf
->fontset
!= None
)
2003 FlocaleInitGstpArgs(
2004 &gstp_args
, flf
, fws
, fws
->x
, fws
->y
);
2005 if (flf
->shadow_size
!= 0)
2007 XSetForeground(dpy
, fws
->gc
, fgsh
);
2008 while (FlocaleGetShadowTextPosition(
2009 &xt
, &yt
, &gstp_args
))
2020 XSetForeground(dpy
, fws
->gc
, fg
);
2021 xt
= gstp_args
.orig_x
;
2022 yt
= gstp_args
.orig_y
;
2024 dpy
, fws
->win
, flf
->fontset
, fws
->gc
,
2025 xt
+ offset
, yt
, buf2
, strlen(buf2
));
2027 else if (flf
->font
!= None
)
2029 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
2031 tmp_fws
.str2b
= (XChar2b
*)
2032 safemalloc(2 * sizeof(XChar2b
));
2033 tmp_fws
.str2b
[0] = comb_chars
[i
].c
;
2034 tmp_fws
.str2b
[1].byte1
= 0;
2035 tmp_fws
.str2b
[1].byte2
= 0;
2038 FlocaleUtf8ToUnicodeStr2b(
2040 curr_len, &out_len);*/
2042 else if (flf
->flags
.is_mb
)
2045 FlocaleStringToString2b(
2048 curr_len
, &out_len
);
2052 out_len
= strlen(buf2
);
2054 FlocaleFontStructDrawString(
2055 dpy
, flf
, fws
->win
, fws
->gc
,
2056 fws
->x
+ offset
, fws
->y
, fg
, fgsh
,
2057 has_fg_pixels
, &tmp_fws
, out_len
,
2062 if(tmp_fws
.str2b
!= NULL
)
2064 free(tmp_fws
.str2b
);
2072 if (fws
->e_str
!= NULL
)
2079 if (fws
->str2b
!= NULL
)
2085 if(comb_chars
!= NULL
)
2095 void FlocaleDrawUnderline(
2096 Display
*dpy
, FlocaleFont
*flf
, FlocaleWinString
*fws
, int offset
)
2098 int off1
, off2
, y
, x_s
, x_e
;
2099 superimpose_char_t
*comb_chars
= NULL
;
2101 Bool do_free
= True
;
2102 int len
= strlen(fws
->str
);
2107 if (fws
== NULL
|| fws
->str
== NULL
)
2112 /* need to encode the string first to get BIDI and combining chars */
2113 FlocaleEncodeWinString(dpy
, flf
, fws
, &do_free
, &len
, &comb_chars
,
2115 /* we don't need this, only interested in char mapping */
2118 /* now calculate char offset (in bytes) in visual string corresponding
2120 /* calculate absolute position in string (in characters) */
2121 l_coffset
= FlocaleStringByteToCharOffset(flf
, fws
->str
, offset
);
2122 /* map to an offset in the visual string */
2123 v_coffset
= l_to_v
[l_coffset
];
2124 /* calculate byte offset into visual string */
2125 voffset
= FlocaleStringCharToByteOffset(flf
, fws
->e_str
, v_coffset
);
2127 off1
= FlocaleTextWidth(flf
, fws
->e_str
, voffset
) +
2129 FLF_SHADOW_LEFT_SIZE(flf
) : - FLF_SHADOW_RIGHT_SIZE(flf
) );
2130 off2
= FlocaleTextWidth(flf
, fws
->e_str
+ voffset
,
2131 FlocaleStringNumberOfBytes(flf
, fws
->e_str
+ voffset
)) -
2132 FLF_SHADOW_WIDTH(flf
) - 1 + off1
;
2134 x_s
= fws
->x
+ off1
;
2135 x_e
= fws
->x
+ off2
;
2138 XDrawLine(dpy
, fws
->win
, fws
->gc
, x_s
, y
, x_e
, y
);
2140 /* free encoded string if it isn't the same as input string */
2141 if(fws
->e_str
!= fws
->str
)
2147 if(fws
->str2b
!= NULL
)
2157 int FlocaleTextWidth(FlocaleFont
*flf
, char *str
, int sl
)
2162 superimpose_char_t
*comb_chars
= NULL
;
2164 if (!str
|| sl
== 0)
2169 /* a vertical string: nothing to do! */
2174 /* to avoid eccesive calls iconv (slow in Solaris 8)
2175 don't bother to encode if string is one byte
2176 when drawing a string this function is used to calculate
2177 position of each character (for superimposition) */
2186 tmp_str
= FlocaleEncodeString(
2187 Pdpy
, flf
, str
, &do_free
, sl
, &new_l
, NULL
,
2190 /* if we get zero-length, check to to see if there if there's any
2191 combining chars, if so use an imagninary space as a
2193 if (strlen(tmp_str
) == 0 && comb_chars
&&
2194 (comb_chars
[0].c
.byte1
!= 0 || comb_chars
[0].c
.byte2
!= 0))
2204 return FlocaleTextWidth(flf
, " ", 1);
2206 else if (FftSupport
&& flf
->fftf
.fftfont
!= NULL
)
2208 result
= FftTextWidth(flf
, tmp_str
, new_l
);
2210 else if (flf
->fontset
!= None
)
2212 result
= XmbTextEscapement(flf
->fontset
, tmp_str
, new_l
);
2214 else if (flf
->font
!= None
)
2216 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
) || flf
->flags
.is_mb
)
2221 if (FLC_ENCODING_TYPE_IS_UTF_8(flf
->fc
))
2222 str2b
= FlocaleUtf8ToUnicodeStr2b(
2223 tmp_str
, new_l
, &nl
);
2225 str2b
= FlocaleStringToString2b(
2226 Pdpy
, flf
, tmp_str
, new_l
, &nl
);
2229 result
= XTextWidth16(flf
->font
, str2b
, nl
);
2235 result
= XTextWidth(flf
->font
, tmp_str
, new_l
);
2247 return result
+ ((result
!= 0)? FLF_SHADOW_WIDTH(flf
):0);
2250 int FlocaleGetMinOffset(
2251 FlocaleFont
*flf
, rotation_t rotation
)
2255 #ifdef FFT_BUGGY_FREETYPE
2260 /* better than descent */
2261 min_offset
= (flf
->descent
+ flf
->height
- flf
->ascent
)/2;
2266 /* better than ascent */
2267 min_offset
= (flf
->ascent
+ flf
->height
- flf
->descent
)/2;
2275 /* better than descent */
2276 min_offset
= (flf
->descent
+ flf
->height
- flf
->ascent
)/2;
2281 /* better than ascent */
2282 min_offset
= (flf
->ascent
+ flf
->height
- flf
->descent
)/2;
2289 void FlocaleAllocateWinString(FlocaleWinString
**pfws
)
2291 *pfws
= (FlocaleWinString
*)safemalloc(sizeof(FlocaleWinString
));
2292 memset(*pfws
, '\0', sizeof(FlocaleWinString
));
2298 void FlocaleGetNameProperty(
2299 Status (func
)(Display
*, Window
, XTextProperty
*), Display
*dpy
,
2300 Window w
, FlocaleNameString
*ret_name
)
2304 XTextProperty text_prop
;
2307 if (func(dpy
, w
, &text_prop
) == 0)
2311 if (text_prop
.encoding
== XA_STRING
)
2313 /* STRING encoding, use this as it is */
2314 ret_name
->name
= (char *)text_prop
.value
;
2315 ret_name
->name_list
= NULL
;
2318 /* not STRING encoding, try to convert XA_COMPOUND_TEXT */
2319 if (XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >= Success
2320 && num
> 0 && *list
)
2322 /* Does not consider the conversion is REALLY succeeded:
2323 * XmbTextPropertyToTextList return 0 (== Success) on success,
2324 * a negative int if it fails (and in this case we are not
2325 * here), the number of unconvertible char on "partial"
2327 XFree(text_prop
.value
); /* return of XGetWM(Icon)Name() */
2328 ret_name
->name
= *list
;
2329 ret_name
->name_list
= list
;
2335 XFreeStringList(list
);
2337 ret_name
->name
= (char *)text_prop
.value
;
2338 ret_name
->name_list
= NULL
;
2342 void FlocaleFreeNameProperty(FlocaleNameString
*ptext
)
2344 if (ptext
->name_list
!= NULL
)
2346 if (ptext
->name
!= NULL
&& ptext
->name
!= *ptext
->name_list
)
2348 XFreeStringList(ptext
->name_list
);
2349 ptext
->name_list
= NULL
;
2351 else if (ptext
->name
!= NULL
)
2360 Bool
FlocaleTextListToTextProperty(
2361 Display
*dpy
, char **list
, int count
, XICCEncodingStyle style
,
2362 XTextProperty
*text_prop_return
)
2366 if (Flocale
!= NULL
)
2368 ret
= XmbTextListToTextProperty(
2369 dpy
, list
, count
, style
, text_prop_return
);
2370 if (ret
== XNoMemory
)
2376 /* ret == Success or the number of unconvertible
2377 * characters. ret should be != XLocaleNotSupported
2378 * because in this case Flocale == NULL */
2384 if (XStringListToTextProperty(
2385 list
, count
, text_prop_return
) == 0)
2401 void FlocalePrintLocaleInfo(Display
*dpy
, int verbose
)
2403 FlocaleFont
*flf
= FlocaleFontList
;
2409 fprintf(stderr
,"FVWM info on locale:\n");
2410 fprintf(stderr
," locale: %s, Modifier: %s\n",
2411 (Flocale
)? Flocale
:"", (Fmodifiers
)? Fmodifiers
:"");
2412 cs
= FlocaleCharsetGetDefaultCharset(dpy
, NULL
);
2413 fprintf(stderr
," Default Charset: X: %s, Iconv: %s, Bidi: %s\n",
2415 (cs
->iconv_index
>= 0)?
2416 cs
->locale
[cs
->iconv_index
]:"Not defined",
2417 (cs
->bidi
)? "Yes":"No");
2418 FlocaleCharsetPrintXOMInfo();
2424 fprintf(stderr
," Number of loaded font: %i\n", count
);
2428 flf
= FlocaleFontList
;
2432 fprintf(stderr
," * Font number %i\n", count
);
2433 fprintf(stderr
," fvwm info:\n");
2434 fprintf(stderr
," Name: %s\n",
2435 (flf
->name
)? flf
->name
:"");
2436 fprintf(stderr
," Cache count: %i\n", flf
->count
);
2437 fprintf(stderr
," Type: ");
2440 fprintf(stderr
,"FontStruct\n");
2442 else if (flf
->fontset
)
2444 fprintf(stderr
,"FontSet\n");
2448 fprintf(stderr
,"XftFont\n");
2450 fprintf(stderr
, " Charset: X: %s, Iconv: %s, "
2453 (cs
->iconv_index
>= 0)?
2454 cs
->locale
[cs
->iconv_index
]:"Not defined",
2455 (cs
->bidi
)? "Yes":"No");
2456 fprintf(stderr
," height: %i, ascent: %i, "
2457 "descent: %i\n", flf
->height
, flf
->ascent
,
2459 fprintf(stderr
," shadow size: %i, "
2460 "shadow offset: %i, shadow direction:%i\n",
2461 flf
->shadow_size
, flf
->shadow_offset
,
2462 flf
->flags
.shadow_dir
);
2465 if (flf
->fftf
.fftfont
!= NULL
)
2470 fprintf(stderr
, " Xft info:\n"
2471 " - Vertical font:");
2472 FftPrintPatternInfo(
2473 fftf
->fftfont
, False
);
2475 "- Rotated font 90:");
2476 if (fftf
->fftfont_rotated_90
)
2477 FftPrintPatternInfo(
2482 fprintf(stderr
, " None\n");
2484 "- Rotated font 270:");
2485 if (fftf
->fftfont_rotated_270
)
2486 FftPrintPatternInfo(
2488 fftfont_rotated_270
,
2491 fprintf(stderr
, " None\n");
2493 "- Rotated font 180:");
2494 if (fftf
->fftfont_rotated_180
)
2495 FftPrintPatternInfo(
2497 fftfont_rotated_180
,
2500 fprintf(stderr
, " None\n");
2502 else if (flf
->font
!= NULL
)
2507 FlocaleGetFullNameOfFontStruct(
2509 fprintf(stderr
, " X info:\n"
2511 (full_name
)? full_name
:"?");
2512 if (full_name
!= NULL
)
2517 else if (flf
->fontset
!= NULL
)
2520 XFontStruct
**font_struct_list
;
2521 char **font_name_list
;
2523 fprintf(stderr
, " X info:\n");
2524 n
= XFontsOfFontSet(
2528 for(i
= 0; i
< n
; i
++)