/* -*-c-*- */
/* Copyright (C) 2002 Olivier Chapuis */
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* FlocaleRotateDrawString is strongly inspired by some part of xvertext
* taken from wmx */
/* Here the copyright for this function: */
/* xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma)
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both the
* copyright notice and this permission notice appear in supporting
* documentation. All work developed as a consequence of the use of
* this program should duly acknowledge such use. No representations are
* made about the suitability of this software for any purpose. It is
* provided "as is" without express or implied warranty.
*
* Minor modifications by Chris Cannam for wm2/wmx
* Major modifications by Kazushi (Jam) Marukawa for wm2/wmx i18n patch
* Simplification and complications by olicha for use with fvwm
*/
/* ---------------------------- included header files ---------------------- */
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include "defaults.h"
#include "fvwmlib.h"
#include "Graphics.h"
#include "ColorUtils.h"
#include "Strings.h"
#include "Parse.h"
#include "PictureBase.h"
#include "Flocale.h"
#include "FlocaleCharset.h"
#include "FBidi.h"
#include "FftInterface.h"
#include "Colorset.h"
#include "Ficonv.h"
#include "CombineChars.h"
/* ---------------------------- local definitions -------------------------- */
/* ---------------------------- local macros ------------------------------- */
#define FSwitchDrawString(use_16, dpy, d, gc, x, y, s8, s16, l) \
(use_16) ? \
XDrawString16(dpy, d, gc, x, y, s16, l) : \
XDrawString(dpy, d, gc, x, y, s8, l)
#define FSwitchDrawImageString(use_16, dpy, d, gc, x, y, s8, s16, l) \
(use_16) ? \
XDrawImageString16(dpy, d, gc, x, y, s16, l) : \
XDrawImageString(dpy, d, gc, x, y, s8, l)
/* ---------------------------- imports ------------------------------------ */
/* ---------------------------- included code files ------------------------ */
/* ---------------------------- local types -------------------------------- */
/* ---------------------------- forward declarations ----------------------- */
/* ---------------------------- local variables ---------------------------- */
static FlocaleFont *FlocaleFontList = NULL;
static char *Flocale = NULL;
static char *Fmodifiers = NULL;
/* TODO: make these (static const char *) */
static char *fft_fallback_font = FLOCALE_FFT_FALLBACK_FONT;
static char *mb_fallback_font = FLOCALE_MB_FALLBACK_FONT;
static char *fallback_font = FLOCALE_FALLBACK_FONT;
/* ---------------------------- exported variables (globals) --------------- */
/* ---------------------------- local functions ---------------------------- */
/*
* shadow local functions
*/
static
void FlocaleParseShadow(char *str, int *shadow_size, int *shadow_offset,
int *direction, char * fontname, char *module)
{
char *dir_str;
char *token;
multi_direction_t dir;
*direction = MULTI_DIR_NONE;
token = PeekToken(str, &dir_str);
if (token == NULL || *token == 0 ||
(GetIntegerArguments(token, NULL, shadow_size, 1) != 1) ||
*shadow_size < 0)
{
*shadow_size = 0;
fprintf(stderr,"[%s][FlocaleParseShadow]: WARNING -- bad "
"shadow size in font name:\n\t'%s'\n",
(module)? module: "fvwm", fontname);
return;
}
if (*shadow_size == 0)
{
return;
}
/* some offset ? */
if (dir_str && *dir_str &&
(GetIntegerArguments(dir_str, NULL, shadow_offset, 1) == 1))
{
if (*shadow_offset < 0)
{
*shadow_offset = 0;
fprintf(stderr,"[%s][FlocaleParseShadow]: WARNING -- "
"bad shadow offset in font name:\n\t'%s'\n",
(module)? module: "fvwmlibs", fontname);
}
PeekToken(dir_str, &dir_str);
}
while (dir_str && *dir_str && *dir_str != '\n')
{
dir = gravity_parse_multi_dir_argument(dir_str, &dir_str);
if (dir == MULTI_DIR_NONE)
{
fprintf(stderr,"[%s][FlocaleParseShadow]: WARNING -- "
"bad shadow direction in font description:\n"
"\t%s\n",
(module)? module: "fvwmlibs", fontname);
PeekToken(dir_str, &dir_str); /* skip it */
}
else
{
*direction |= dir;
}
}
if (*direction == MULTI_DIR_NONE)
*direction = MULTI_DIR_SE;
}
/*
* some simple converters
*/
static
int FlocaleChar2bOneCharToUtf8(XChar2b c, char *buf)
{
int len;
char byte1 = c.byte1;
char byte2 = c.byte2;
unsigned short ucs2 = ((unsigned short)byte1 << 8) + byte2;
if(ucs2 <= 0x7f)
{
len = 1;
buf[0] = (char)ucs2;
buf[1] = 0;
}
else if(ucs2 <= 0x7ff)
{
len = 2;
buf[0] = (ucs2 >> 6) | 0xc0;
buf[1] = (ucs2 & 0x3f) | 0x80;
buf[2] = 0;
}
else
{
len = 3;
buf[0] = (ucs2 >> 12) | 0xe0;
buf[1] = ((ucs2 & 0xfff) >> 6) | 0x80;
buf[2] = (ucs2 & 0x3f) | 0x80;
buf[3] = 0;
}
return len;
}
/* return number of bytes of character at current position
(pointed to by str) */
int FlocaleStringNumberOfBytes(FlocaleFont *flf, const char *str)
{
int bytes = 0;
if(FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
{
/* handle UTF-8 */
if ((str[0] & 0x80) == 0)
{
bytes = 1;
}
else if((str[0] & ~0xdf) == 0)
{
bytes = 2;
}
else
{
/* this handles only 16-bit Unicode */
bytes = 3;
}
}
else if(flf->flags.is_mb)
{
/* non-UTF-8 multibyte encoding */
if ((str[0] & 0x80) == 0)
{
bytes = 1;
}
else
{
bytes = 2;
}
}
else
{
/* we must be using an "ordinary" 8-bit encoding */
bytes = 1;
}
return bytes;
}
/* given a string, font specifying its locale and a byte offset gives
character offset */
int FlocaleStringByteToCharOffset(FlocaleFont *flf, const char *str,
int offset)
{
const char *curr_ptr = str;
int i = 0;
int len = strlen(str);
int coffset = 0;
int curr_len;
for(i = 0 ;
i < offset && i < len ;
i += curr_len, curr_ptr += curr_len, coffset++)
{
curr_len = FlocaleStringNumberOfBytes(flf, curr_ptr);
}
return coffset;
}
/* like above but reversed, ie. return byte offset corresponding to given
charater offset */
int FlocaleStringCharToByteOffset(FlocaleFont *flf, const char *str,
int coffset)
{
const char *curr_ptr = str;
int i;
int len = strlen(str);
int offset = 0;
int curr_len;
for(i = 0 ;
i < coffset && i < len ;
offset += curr_len, curr_ptr += curr_len, i++)
{
curr_len = FlocaleStringNumberOfBytes(flf, curr_ptr);
}
return offset;
}
/* return length of string in characters */
int FlocaleStringCharLength(FlocaleFont *flf, const char *str)
{
int i, len;
int str_len = strlen(str);
for(i = 0, len = 0 ; i < str_len ;
i += FlocaleStringNumberOfBytes(flf, str+i), len++);
return len;
}
static
XChar2b *FlocaleUtf8ToUnicodeStr2b(char *str, int len, int *nl)
{
XChar2b *str2b = NULL;
int i = 0, j = 0, t;
str2b = (XChar2b *)safemalloc((len+1)*sizeof(XChar2b));
while (i < len && str[i] != 0)
{
if ((str[i] & 0x80) == 0)
{
str2b[j].byte2 = str[i];
str2b[j].byte1 = 0;
}
else if ((str[i] & ~0xdf) == 0 && i+1 < len)
{
t = ((str[i] & 0x1f) << 6) + (str[i+1] & 0x3f);
str2b[j].byte2 = (unsigned char)(t & 0xff);
str2b[j].byte1 = (unsigned char)(t >> 8);
i++;
}
else if (i+2 <len)
{
t = ((str[i] & 0x0f) << 12) + ((str[i+1] & 0x3f) << 6)+
(str[i+2] & 0x3f);
str2b[j].byte2 = (unsigned char)(t & 0xff);
str2b[j].byte1 = (unsigned char)(t >> 8);
i += 2;
}
i++; j++;
}
*nl = j;
return str2b;
}
/* Note: this function is not expected to work; good mb rendering
* should be (and is) done using Xmb functions and not XDrawString16
* (or with iso10646-1 fonts and setting the encoding).
* This function is used when the locale does not correspond to the font.
* It works with "EUC fonts": ksc5601.1987-0, gb2312 and maybe also
* cns11643-*. It works patially with jisx* and big5-0. Should try gbk-0,
* big5hkscs-0, and cns-11643- */
static
XChar2b *FlocaleStringToString2b(
Display *dpy, FlocaleFont *flf, char *str, int len, int *nl)
{
XChar2b *str2b = NULL;
char *tmp = NULL;
Bool free_str = False;
int i = 0, j = 0;
Bool euc = True; /* KSC5601 (EUC-KR), GB2312 (EUC-CN), CNS11643-1986-1
* (EUC-TW) and converted jisx (EUC-JP) */
if (flf->fc && StrEquals(flf->fc->x,"jisx0208.1983-0"))
{
tmp = FiconvCharsetToCharset(
dpy, flf->fc, FlocaleCharsetGetEUCJPCharset(), str,
len);
if (tmp != NULL)
{
free_str = True;
str = tmp;
len = strlen(tmp);
}
}
else if (flf->fc && StrEquals(flf->fc->x,"big5-0"))
{
euc = False;
}
str2b = (XChar2b *)safemalloc((len+1)*sizeof(XChar2b));
if (euc)
{
while (i < len && str[i] != 0)
{
if ((str[i] & 0x80) == 0)
{
/* seems ok with KSC5601 and GB2312 as we get
* almost the ascii. I do no try
* CNS11643-1986-1. Should convert to ascii
* with jisx */
str2b[j].byte1 = 0x23; /* magic number! */
str2b[j].byte2 = str[i++];
}
else if (i+1 < len)
{
/* mb gl (for gr replace & 0x7f by | 0x80 ...)
*/
str2b[j].byte1 = str[i++] & 0x7f;
str2b[j].byte2 = str[i++] & 0x7f;
}
else
{
str2b[j].byte1 = 0;
str2b[j].byte2 = 0;
i++;
}
j++;
}
}
else /* big5 and others not yet tested */
{
while (i < len && str[i] != 0)
{
if ((str[i] & 0x80) == 0)
{
/* we should convert to ascii */
#if 0
str2b[j].byte1 = 0xa2; /* magic number! */
str2b[j].byte2 = str[i++];
#endif
/* a blanck char ... */
str2b[j].byte1 = 0x21;
str2b[j].byte2 = 0x21;
}
else if (i+1 < len)
{
str2b[j].byte1 = str[i++];
str2b[j].byte2 = str[i++];
}
else
{
str2b[j].byte1 = 0;
str2b[j].byte2 = 0;
i++;
}
j++;
}
}
*nl = j;
if (free_str)
free(str);
return str2b;
}
static
char *FlocaleEncodeString(
Display *dpy, FlocaleFont *flf, char *str, int *do_free, int len,
int *nl, int *is_rtl, superimpose_char_t **comb_chars,
int **l_to_v)
{
char *str1, *str2, *str3;
int len1;
int len2;
int i;
Bool do_iconv = True;
const char *bidi_charset;
len1 = len;
if (is_rtl != NULL)
*is_rtl = False;
*do_free = False;
*nl = len;
if (flf->str_fc == NULL || flf->fc == NULL ||
flf->fc == flf->str_fc)
{
do_iconv = False;
}
str1 = str;
if (FiconvSupport)
{
char *tmp_str;
/* first process combining characters */
tmp_str = FiconvCharsetToUtf8(
dpy, flf->str_fc, (const char *)str,len);
/* if conversion to UTF-8 failed str1 will be NULL */
if(tmp_str != NULL)
{
/* do combining */
len = CombineChars((unsigned char *)tmp_str,
strlen(tmp_str), comb_chars,
l_to_v);
/* returns the length of the resulting UTF-8 string */
/* convert back to current charset */
str1 = FiconvUtf8ToCharset(
dpy, flf->str_fc, (const char *)tmp_str,len);
if (tmp_str != str1)
{
free(tmp_str);
}
if (str1)
{
*nl = len = strlen(str1);
*do_free = True;
}
else
{
/* convert back to current charset fail */
len = strlen(str);
str1 = str;
}
}
}
if (FiconvSupport && do_iconv)
{
str2 = FiconvCharsetToCharset(
dpy, flf->str_fc, flf->fc, (const char *)str1, len);
if (str2 == NULL)
{
/* fail to convert */
return str1;
}
if (str2 != str1)
{
if (*do_free && str1)
{
free(str1);
str1 = str2;
}
*do_free = True;
len1 = strlen(str2);
}
}
else
{
str2 = str1;
len1 = len;
/* initialise array with composing characters (empty) */
if(comb_chars != NULL && *comb_chars == NULL)
{
*comb_chars = (superimpose_char_t *)
safemalloc(sizeof(superimpose_char_t));
(*comb_chars)[0].position = -1;
(*comb_chars)[0].c.byte1 = 0;
(*comb_chars)[0].c.byte2 = 0;
}
/* initialise logic to visual mapping here if that is demanded
(this is default when no combining has been done (1-to-1))
*/
if(l_to_v != NULL && *l_to_v == NULL)
{
*l_to_v = (int*)safemalloc((len + 1) * sizeof(int));
for(i = 0 ; i < len ; i++)
(*l_to_v)[i] = i;
(*l_to_v)[len] = -1;
}
}
if (FlocaleGetBidiCharset(dpy, flf->str_fc) != NULL &&
(bidi_charset = FlocaleGetBidiCharset(dpy, flf->fc)) != NULL)
{
str3 = FBidiConvert(str2, bidi_charset, len1,
is_rtl, &len2,
comb_chars != NULL ? *comb_chars : NULL,
l_to_v != NULL ? *l_to_v : NULL);
if (str3 != NULL && str3 != str2)
{
if (*do_free)
{
free(str2);
}
*do_free = True;
len1 = len2;
str1 = str3;
}
/* if we failed to do BIDI convert, return string string from
combining phase */
else
{
str1 = str2;
/* we already have the logical to visual mapping
from combining phase */
}
}
*nl = len1;
return str1;
}
static
void FlocaleEncodeWinString(
Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, int *do_free,
int *len, superimpose_char_t **comb_chars, int **l_to_v)
{
int len2b;
fws->e_str = FlocaleEncodeString(
dpy, flf, fws->str, do_free, *len, len, NULL, comb_chars,
l_to_v);
fws->str2b = NULL;
if (flf->font != None)
{
if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
{
fws->str2b = FlocaleUtf8ToUnicodeStr2b(
fws->e_str, *len, &len2b);
}
else if (flf->flags.is_mb)
{
fws->str2b = FlocaleStringToString2b(
dpy, flf, fws->e_str, *len, &len2b);
}
}
}
/*
* Text Drawing with a FontStruct
*/
static
void FlocaleFontStructDrawString(
Display *dpy, FlocaleFont *flf, Drawable d, GC gc, int x, int y,
Pixel fg, Pixel fgsh, Bool has_fg_pixels, FlocaleWinString *fws,
int len, Bool image)
{
int xt = x;
int yt = y;
int is_string16;
flocale_gstp_args gstp_args;
is_string16 = (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb);
if (is_string16 && fws->str2b == NULL)
{
return;
}
if (image)
{
/* for rotated drawing */
FSwitchDrawImageString(
is_string16, dpy, d, gc, x, y, fws->e_str, fws->str2b,
len);
}
else
{
FlocaleInitGstpArgs(&gstp_args, flf, fws, x, y);
/* normal drawing */
if (flf->shadow_size != 0 && has_fg_pixels == True)
{
XSetForeground(dpy, fws->gc, fgsh);
while (FlocaleGetShadowTextPosition(
&xt, &yt, &gstp_args))
{
FSwitchDrawString(
is_string16, dpy, d, gc, xt, yt,
fws->e_str, fws->str2b, len);
}
}
if (has_fg_pixels == True)
{
XSetForeground(dpy, gc, fg);
}
xt = gstp_args.orig_x;
yt = gstp_args.orig_y;
FSwitchDrawString(
is_string16, dpy, d, gc, xt,yt, fws->e_str, fws->str2b,
len);
}
return;
}
/*
* Rotated Text Drawing with a FontStruct or a FontSet
*/
static
void FlocaleRotateDrawString(
Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, Pixel fg,
Pixel fgsh, Bool has_fg_pixels, int len,
superimpose_char_t *comb_chars, int *pixel_pos)
{
static GC my_gc = None;
static GC font_gc = None;
int j, i, xpfg, ypfg, xpsh, ypsh;
unsigned char *normal_data, *rotated_data;
unsigned int normal_w, normal_h, normal_len;
unsigned int rotated_w, rotated_h, rotated_len;
char val;
int width, height, descent, min_offset;
XImage *image, *rotated_image;
Pixmap canvas_pix, rotated_pix;
flocale_gstp_args gstp_args;
char buf[4];
if (fws->str == NULL || len < 1)
{
return;
}
if (fws->flags.text_rotation == ROTATION_0)
{
return; /* should not happen */
}
if (my_gc == None)
{
my_gc = fvwmlib_XCreateGC(dpy, fws->win, 0, NULL);
}
XCopyGC(dpy, fws->gc, GCForeground|GCBackground, my_gc);
/* width and height (no shadow!) */
width = FlocaleTextWidth(flf, fws->str, len) - FLF_SHADOW_WIDTH(flf);
height = flf->height - FLF_SHADOW_HEIGHT(flf);
descent = flf->descent - FLF_SHADOW_DESCENT(flf);;
if (width < 1)
width = 1;
if (height < 1)
height = 1;
/* glyph width and height of the normal text */
normal_w = width;
normal_h = height;
/* width in bytes */
normal_len = (normal_w - 1) / 8 + 1;
/* create and clear the canvas */
canvas_pix = XCreatePixmap(dpy, fws->win, width, height, 1);
if (font_gc == None)
{
font_gc = fvwmlib_XCreateGC(dpy, canvas_pix, 0, NULL);
}
XSetBackground(dpy, font_gc, 0);
XSetForeground(dpy, font_gc, 0);
XFillRectangle(dpy, canvas_pix, font_gc, 0, 0, width, height);
/* draw the character center top right on canvas */
XSetForeground(dpy, font_gc, 1);
if (flf->font != NULL)
{
XSetFont(dpy, font_gc, flf->font->fid);
FlocaleFontStructDrawString(dpy, flf, canvas_pix, font_gc, 0,
height - descent,
fg, fgsh, has_fg_pixels,
fws, len, True);
}
else if (flf->fontset != None)
{
XmbDrawString(
dpy, canvas_pix, flf->fontset, font_gc, 0,
height - descent, fws->e_str, len);
}
/* here take care of superimposing chars */
i = 0;
if(comb_chars != NULL)
{
while(comb_chars[i].c.byte1 != 0 && comb_chars[i].c.byte2 != 0)
{
/* draw composing character on top of corresponding
"real" character */
FlocaleWinString tmp_fws = *fws;
int offset = pixel_pos[comb_chars[i].position];
int curr_len = FlocaleChar2bOneCharToUtf8(
comb_chars[i].c,
buf);
int out_len;
char *buf2 = FiconvUtf8ToCharset(
dpy,
flf->str_fc,
(const char *)buf,curr_len);
if(buf2 == NULL)
{
/* if conversion failed, combinational char
is not representable in current charset */
/* just replace with empty string */
buf2 = (char *)safemalloc(sizeof(char));
buf2[0] = 0;
}
tmp_fws.e_str = buf2;
tmp_fws.str2b = NULL;
if(flf->fontset != None)
{
XmbDrawString(dpy, canvas_pix, flf->fontset,
fws->gc, offset,
height - descent, buf2,
strlen(buf2));
}
else if(flf->font != None)
{
if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
{
tmp_fws.str2b = (XChar2b *)
safemalloc(2 * sizeof(XChar2b));
tmp_fws.str2b[0] = comb_chars[i].c;
tmp_fws.str2b[1].byte1 = 0;
tmp_fws.str2b[1].byte2 = 0;
out_len = 1;
}
else if (flf->flags.is_mb)
{
tmp_fws.str2b =
FlocaleStringToString2b(
dpy, flf, tmp_fws.e_str,
curr_len, &out_len);
}
else
{
out_len = strlen(buf2);
}
XSetFont(dpy, font_gc, flf->font->fid);
FlocaleFontStructDrawString(
dpy, flf, canvas_pix, font_gc,
offset, height - descent,
fg, fgsh, has_fg_pixels, &tmp_fws,
out_len, True);
}
free(buf2);
if(tmp_fws.str2b != NULL)
{
free(tmp_fws.str2b);
}
i++;
}
}
/* reserve memory for the first XImage */
normal_data = (unsigned char *)safemalloc(normal_len * normal_h);
/* create depth 1 XImage */
if ((image = XCreateImage(
dpy, Pvisual, 1, XYBitmap, 0, (char *)normal_data,
normal_w, normal_h, 8, 0)) == NULL)
{
return;
}
image->byte_order = image->bitmap_bit_order = MSBFirst;
/* extract character from canvas */
XGetSubImage(
dpy, canvas_pix, 0, 0, normal_w, normal_h,
1, XYPixmap, image, 0, 0);
image->format = XYBitmap;
/* width, height of the rotated text */
if (fws->flags.text_rotation == ROTATION_180)
{
rotated_w = normal_w;
rotated_h = normal_h;
}
else /* vertical text */
{
rotated_w = normal_h;
rotated_h = normal_w;
}
/* width in bytes */
rotated_len = (rotated_w - 1) / 8 + 1;
/* reserve memory for the rotated image */
rotated_data = (unsigned char *)safecalloc(rotated_h * rotated_len, 1);
/* create the rotated X image */
if ((rotated_image = XCreateImage(
dpy, Pvisual, 1, XYBitmap, 0, (char *)rotated_data,
rotated_w, rotated_h, 8, 0)) == NULL)
{
return;
}
rotated_image->byte_order = rotated_image->bitmap_bit_order = MSBFirst;
/* map normal text data to rotated text data */
for (j = 0; j < rotated_h; j++)
{
for (i = 0; i < rotated_w; i++)
{
/* map bits ... */
if (fws->flags.text_rotation == ROTATION_270)
val = normal_data[
i * normal_len +
(normal_w - j - 1) / 8
] & (128 >> ((normal_w - j - 1) % 8));
else if (fws->flags.text_rotation == ROTATION_180)
val = normal_data[
(normal_h - j - 1) * normal_len +
(normal_w - i - 1) / 8
] & (128 >> ((normal_w - i - 1) % 8));
else /* ROTATION_90 */
val = normal_data[
(normal_h - i - 1) * normal_len +
j / 8] & (128 >> (j % 8));
if (val)
rotated_data[j * rotated_len + i / 8] |=
(128 >> (i % 8));
}
}
/* create the character's bitmap and put the image on it */
rotated_pix = XCreatePixmap(dpy, fws->win, rotated_w, rotated_h, 1);
XPutImage(
dpy, rotated_pix, font_gc, rotated_image, 0, 0, 0, 0,
rotated_w, rotated_h);
/* free the image and data */
XDestroyImage(image);
XDestroyImage(rotated_image);
/* free pixmap and GC */
XFreePixmap(dpy, canvas_pix);
/* x and y corrections: we fill a rectangle! */
min_offset = FlocaleGetMinOffset(flf, fws->flags.text_rotation);
switch (fws->flags.text_rotation)
{
case ROTATION_90:
/* CW */
xpfg = fws->x - min_offset;
ypfg = fws->y;
break;
case ROTATION_180:
xpfg = fws->x;
ypfg = fws->y - min_offset +
FLF_SHADOW_BOTTOM_SIZE(flf);
break;
case ROTATION_270:
/* CCW */
xpfg = fws->x - min_offset;
ypfg = fws->y;
break;
case ROTATION_0:
default:
xpfg = fws->x;
ypfg = fws->y - min_offset;
break;
}
xpsh = xpfg;
ypsh = ypfg;
/* write the image on the window */
XSetFillStyle(dpy, my_gc, FillStippled);
XSetStipple(dpy, my_gc, rotated_pix);
FlocaleInitGstpArgs(&gstp_args, flf, fws, xpfg, ypfg);
if (flf->shadow_size != 0 && has_fg_pixels == True)
{
XSetForeground(dpy, my_gc, fgsh);
while (FlocaleGetShadowTextPosition(&xpsh, &ypsh, &gstp_args))
{
XSetTSOrigin(dpy, my_gc, xpsh, ypsh);
XFillRectangle(
dpy, fws->win, my_gc, xpsh, ypsh, rotated_w,
rotated_h);
}
}
xpsh = gstp_args.orig_x;
ypsh = gstp_args.orig_y;
XSetTSOrigin(dpy, my_gc, xpsh, ypsh);
XFillRectangle(dpy, fws->win, my_gc, xpsh, ypsh, rotated_w, rotated_h);
XFreePixmap(dpy, rotated_pix);
return;
}
/*
* Fonts info and checking
*/
static
char *FlocaleGetFullNameOfFontStruct(Display *dpy, XFontStruct *font)
{
char *full_name = NULL;
unsigned long value;
if (XGetFontProperty(font, XA_FONT, &value))
{
full_name = XGetAtomName(dpy, value);
}
return full_name;
}
static
char *FlocaleGetCharsetOfFontStruct(Display *dpy, XFontStruct *font)
{
int i = 0;
int count = 0;
char *charset = NULL;
char *full_name;
full_name = FlocaleGetFullNameOfFontStruct(dpy, font);
if (full_name == NULL)
{
return NULL;
}
while(full_name[i] != '\0' && count < 13)
{
if (full_name[i] == '-')
{
count++;
}
i++;
}
if (count != 13)
{
return NULL;
}
CopyString(&charset, full_name+i);
XFree(full_name);
return charset;
}
static
char *FlocaleGetCharsetFromName(char *name)
{
int l,i,e;
char *charset;
l = strlen(name);
i = l-1;
while(i >= 0 && name[i] != '-')
{
i--;
}
if (i == 0 || i == l-1)
{
return NULL;
}
i--;
e = i;
while(i >= 0 && name[i] != '-')
{
i--;
}
if (i <= 0 || e == i)
{
return NULL;
}
CopyString(&charset, name + i + 1);
return charset;
}
/* return NULL if it is not reasonable to load a FontSet.
* Currently return name if it is reasonable to load a FontSet, but in the
* future we may want to transform name for faster FontSet loading */
static
char *FlocaleFixNameForFontSet(Display *dpy, char *name, char *module)
{
char *new_name;
char *charset;
XFontStruct *test_font = NULL;
if (!name)
{
return NULL;
}
new_name = name;
if (strchr(name, ','))
{
/* tmp, do not handle "," separated list */
return name;
}
charset = FlocaleGetCharsetFromName(name);
if (charset == NULL && !strchr(name, '*') && !strchr(name, '?'))
{
/* probably a font alias! */
if ((test_font = XLoadQueryFont(dpy, name)))
{
charset = FlocaleGetCharsetOfFontStruct(dpy, test_font);
XFreeFont(dpy, test_font);
}
}
if (charset != NULL)
{
if (!strchr(charset, '*') && !strchr(charset, '?') &&
!FlocaleCharsetIsCharsetXLocale(dpy, charset, module))
{
/* if the charset is fully specified and do not match
* one of the X locale charset */
new_name = NULL;
#if 0
fprintf(stderr,"[%s][FlocaleGetFontSet]: WARNING -- "
"Use of a non X locale charset '%s' when "
"loading font: %s\n",
(module)? module:"fvwmlibs", charset, name);
#endif
}
free(charset);
}
return new_name;
}
/*
* Fonts loading
*/
static
FlocaleFont *FlocaleGetFftFont(
Display *dpy, char *fontname, char *encoding, char *module)
{
FftFontType *fftf = NULL;
FlocaleFont *flf = NULL;
char *fn, *hints = NULL;
hints = GetQuotedString(fontname, &fn, "/", NULL, NULL, NULL);
if (fn == NULL)
{
fn = fft_fallback_font;
}
else if (*fn == '\0')
{
free(fn);
fn = fft_fallback_font;
}
fftf = FftGetFont(dpy, fn, module);
if (fftf == NULL)
{
if (fn != NULL && fn != fft_fallback_font)
{
free(fn);
}
return NULL;
}
flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
memset(flf, '\0', sizeof(FlocaleFont));
flf->count = 1;
flf->fftf = *fftf;
FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
FftGetFontHeights(
&flf->fftf, &flf->height, &flf->ascent, &flf->descent);
FftGetFontWidths(flf, &flf->max_char_width);
free(fftf);
if (fn != NULL && fn != fft_fallback_font)
{
free(fn);
}
return flf;
}
static
FlocaleFont *FlocaleGetFontSet(
Display *dpy, char *fontname, char *encoding, char *module)
{
static int mc_errors = 0;
FlocaleFont *flf = NULL;
XFontSet fontset = NULL;
char **ml;
int mc,i;
char *ds;
XFontSetExtents *fset_extents;
char *fn, *hints = NULL, *fn_fixed = NULL;
hints = GetQuotedString(fontname, &fn, "/", NULL, NULL, NULL);
if (*fn == '\0')
{
free(fn);
fn = fn_fixed = mb_fallback_font;
}
else if (!(fn_fixed = FlocaleFixNameForFontSet(dpy, fn, module)))
{
if (fn != NULL && fn != mb_fallback_font)
{
free(fn);
}
return NULL;
}
if (!(fontset = XCreateFontSet(dpy, fn_fixed, &ml, &mc, &ds)))
{
if (fn_fixed && fn_fixed != fn)
{
free(fn_fixed);
}
if (fn != NULL && fn != mb_fallback_font)
{
free(fn);
}
return NULL;
}
if (mc > 0)
{
if (mc_errors <= FLOCALE_NUMBER_MISS_CSET_ERR_MSG)
{
mc_errors++;
fprintf(stderr,
"[%s][FlocaleGetFontSet]: (%s)"
" Missing font charsets:\n",
(module)? module: "fvwmlibs", fontname);
for (i = 0; i < mc; i++)
{
fprintf(stderr, "%s", ml[i]);
if (i < mc - 1)
fprintf(stderr, ", ");
}
fprintf(stderr, "\n");
if (mc_errors == FLOCALE_NUMBER_MISS_CSET_ERR_MSG)
{
fprintf(stderr,
"[%s][FlocaleGetFontSet]: No more"
" missing charset reportings\n",
(module)? module: "fvwmlibs");
}
}
XFreeStringList(ml);
}
flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
memset(flf, '\0', sizeof(FlocaleFont));
flf->count = 1;
flf->fontset = fontset;
FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
fset_extents = XExtentsOfFontSet(fontset);
flf->height = fset_extents->max_ink_extent.height;
flf->ascent = - fset_extents->max_ink_extent.y;
flf->descent = fset_extents->max_ink_extent.height +
fset_extents->max_ink_extent.y;
flf->max_char_width = fset_extents->max_ink_extent.width;
if (fn_fixed && fn_fixed != fn)
{
free(fn_fixed);
}
if (fn != NULL && fn != mb_fallback_font)
{
free(fn);
}
return flf;
}
static
FlocaleFont *FlocaleGetFont(
Display *dpy, char *fontname, char *encoding, char *module)
{
XFontStruct *font = NULL;
FlocaleFont *flf;
char *str,*fn,*tmp;
char *hints = NULL;
hints = GetQuotedString(fontname, &tmp, "/", NULL, NULL, NULL);
str = GetQuotedString(tmp, &fn, ",", NULL, NULL, NULL);
while (!font && fn)
{
if (*fn == '\0')
{
free(fn);
fn = fallback_font;
}
font = XLoadQueryFont(dpy, fn);
if (fn != NULL && fn != fallback_font)
{
free(fn);
fn = NULL;
}
if (!font && str && *str)
{
str = GetQuotedString(str, &fn, ",", NULL, NULL, NULL);
}
}
if (font == NULL)
{
if (fn != NULL && fn != fallback_font)
{
free(fn);
}
if (tmp != NULL)
{
free(tmp);
}
return NULL;
}
flf = (FlocaleFont *)safemalloc(sizeof(FlocaleFont));
memset(flf, '\0', sizeof(FlocaleFont));
flf->count = 1;
flf->fontset = None;
flf->fftf.fftfont = NULL;
flf->font = font;
FlocaleCharsetSetFlocaleCharset(dpy, flf, hints, encoding, module);
flf->height = font->max_bounds.ascent + font->max_bounds.descent;
flf->ascent = font->max_bounds.ascent;
flf->descent = font->max_bounds.descent;
flf->max_char_width = font->max_bounds.width;
if (flf->font->max_byte1 > 0)
flf->flags.is_mb = True;
if (fn != NULL && fn != fallback_font)
{
free(fn);
}
if (tmp != NULL)
{
free(tmp);
}
return flf;
}
static
FlocaleFont *FlocaleGetFontOrFontSet(
Display *dpy, char *fontname, char *encoding, char *fullname,
char *module)
{
FlocaleFont *flf = NULL;
if (fontname && strlen(fontname) > 3 &&
strncasecmp("xft:", fontname, 4) == 0)
{
if (FftSupport)
{
flf = FlocaleGetFftFont(
dpy, fontname+4, encoding, module);
}
if (flf)
{
CopyString(&flf->name, fullname);
}
return flf;
}
if (flf == NULL && Flocale != NULL && fontname)
{
flf = FlocaleGetFontSet(dpy, fontname, encoding, module);
}
if (flf == NULL && fontname)
{
flf = FlocaleGetFont(dpy, fontname, encoding, module);
}
if (flf && fontname)
{
if (StrEquals(fullname, mb_fallback_font))
{
flf->name = mb_fallback_font;
}
else if (StrEquals(fullname, fallback_font))
{
flf->name = fallback_font;
}
else
{
CopyString(&flf->name, fullname);
}
return flf;
}
return NULL;
}
/*
* locale local functions
*/
static
void FlocaleSetlocaleForX(
int category, const char *locale, const char *module)
{
if ((Flocale = setlocale(category, locale)) == NULL)
{
fprintf(stderr,
"[%s][%s]: ERROR -- Cannot set locale. Please check"
" your $LC_CTYPE or $LANG.\n",
(module == NULL)? "" : module, "FlocaleSetlocaleForX");
return;
}
if (!XSupportsLocale())
{
fprintf(stderr,
"[%s][%s]: WARNING -- X does not support locale %s\n",
(module == NULL)? "": module, "FlocaleSetlocaleForX",
Flocale);
Flocale = NULL;
}
}
/* ---------------------------- interface functions ------------------------ */
/*
* locale initialisation
*/
void FlocaleInit(
int category, const char *locale, const char *modifiers,
const char *module)
{
FlocaleSetlocaleForX(category, locale, module);
if (Flocale == NULL)
return;
if (modifiers != NULL &&
(Fmodifiers = XSetLocaleModifiers(modifiers)) == NULL)
{
fprintf(stderr,
"[%s][%s]: WARNING -- Cannot set locale modifiers\n",
(module == NULL)? "": module, "FlocaleInit");
}
#if FLOCALE_DEBUG_SETLOCALE
fprintf(stderr,"[%s][FlocaleInit] locale: %s, modifier: %s\n",
module, Flocale, Fmodifiers);
#endif
}
/*
* fonts loading
*/
char *prefix_list[] =
{
"Shadow=",
"StringEncoding=",
NULL
};
FlocaleFont *FlocaleLoadFont(Display *dpy, char *fontname, char *module)
{
FlocaleFont *flf = FlocaleFontList;
Bool ask_default = False;
char *t;
char *str, *opt_str, *encoding= NULL, *fn = NULL;
int shadow_size = 0;
int shadow_offset = 0;
int shadow_dir = MULTI_DIR_SE;
int i;
/* removing quoting for modules */
if (fontname && (t = strchr("\"'`", *fontname)))
{
char c = *t;
fontname++;
if (fontname[strlen(fontname)-1] == c)
fontname[strlen(fontname)-1] = 0;
}
if (fontname == NULL || *fontname == 0)
{
ask_default = True;
fontname = mb_fallback_font;
}
while (flf)
{
char *c1, *c2;
for (c1 = fontname, c2 = flf->name; *c1 && *c2; ++c1, ++c2)
{
if (*c1 != *c2)
{
break;
}
}
if (!*c1 && !*c2)
{
flf->count++;
return flf;
}
flf = flf->next;
}
/* not cached load the font as a ";" separated list */
/* But first see if we have a shadow relief and/or an encoding */
str = fontname;
while ((i = GetTokenIndex(str, prefix_list, -1, &str)) > -1)
{
str = GetQuotedString(str, &opt_str, ":", NULL, NULL, NULL);
switch(i)
{
case 0: /* shadow= */
FlocaleParseShadow(
opt_str, &shadow_size, &shadow_offset,
&shadow_dir, fontname, module);
break;
case 1: /* encoding= */
if (encoding != NULL)
{
free(encoding);
encoding = NULL;
}
if (opt_str && *opt_str)
{
CopyString(&encoding, opt_str);
}
break;
default:
break;
}
if (opt_str != NULL)
free(opt_str);
}
if (str && *str)
{
str = GetQuotedString(str, &fn, ";", NULL, NULL, NULL);
}
else
{
fn = mb_fallback_font;
}
while (!flf && (fn && *fn))
{
flf = FlocaleGetFontOrFontSet(
dpy, fn, encoding, fontname, module);
if (fn != NULL && fn != mb_fallback_font &&
fn != fallback_font)
{
free(fn);
fn = NULL;
}
if (!flf && str && *str)
{
str = GetQuotedString(str, &fn, ";", NULL, NULL, NULL);
}
}
if (fn != NULL && fn != mb_fallback_font &&
fn != fallback_font)
{
free(fn);
}
if (flf == NULL)
{
/* loading failed, try default font */
if (!ask_default)
{
fprintf(stderr,"[%s][FlocaleLoadFont]: "
"WARNING -- can't load font '%s',"
" trying default:\n",
(module)? module: "fvwmlibs", fontname);
}
else
{
/* we already tried default fonts: try again? yes */
}
if (Flocale != NULL)
{
if (!ask_default)
{
fprintf(stderr, "\t%s\n",
mb_fallback_font);
}
if ((flf = FlocaleGetFontSet(
dpy, mb_fallback_font, NULL,
module)) != NULL)
{
flf->name = mb_fallback_font;
}
}
if (flf == NULL)
{
if (!ask_default)
{
fprintf(stderr,"\t%s\n",
fallback_font);
}
if ((flf =
FlocaleGetFont(
dpy, fallback_font, NULL,
module)) != NULL)
{
flf->name = fallback_font;
}
else if (!ask_default)
{
fprintf(stderr,
"[%s][FlocaleLoadFont]:"
" ERROR -- can't load font.\n",
(module)? module: "fvwmlibs");
}
else
{
fprintf(stderr,
"[%s][FlocaleLoadFont]: ERROR"
" -- can't load default font:\n",
(module)? module: "fvwmlibs");
fprintf(stderr, "\t%s\n",
mb_fallback_font);
fprintf(stderr, "\t%s\n",
fallback_font);
}
}
}
if (flf != NULL)
{
if (shadow_size > 0)
{
flf->shadow_size = shadow_size;
flf->flags.shadow_dir = shadow_dir;
flf->shadow_offset = shadow_offset;
flf->descent += FLF_SHADOW_DESCENT(flf);
flf->ascent += FLF_SHADOW_ASCENT(flf);
flf->height += FLF_SHADOW_HEIGHT(flf);
flf->max_char_width += FLF_SHADOW_WIDTH(flf);
}
if (flf->fc == FlocaleCharsetGetUnknownCharset())
{
fprintf(stderr,"[%s][FlocaleLoadFont]: "
"WARNING -- Unknown charset for font\n\t'%s'\n",
(module)? module: "fvwmlibs", flf->name);
flf->fc = FlocaleCharsetGetDefaultCharset(dpy, module);
}
else if (flf->str_fc == FlocaleCharsetGetUnknownCharset() &&
(encoding != NULL ||
(FftSupport && flf->fftf.fftfont != NULL &&
flf->fftf.str_encoding != NULL)))
{
fprintf(stderr,"[%s][FlocaleLoadFont]: "
"WARNING -- Unknown string encoding for font\n"
"\t'%s'\n",
(module)? module: "fvwmlibs", flf->name);
}
if (flf->str_fc == FlocaleCharsetGetUnknownCharset())
{
flf->str_fc =
FlocaleCharsetGetDefaultCharset(dpy, module);
}
flf->next = FlocaleFontList;
FlocaleFontList = flf;
}
if (encoding != NULL)
{
free(encoding);
}
return flf;
}
void FlocaleUnloadFont(Display *dpy, FlocaleFont *flf)
{
FlocaleFont *list = FlocaleFontList;
int i = 0;
if (!flf)
{
return;
}
/* Remove a weight, still too heavy? */
if (--(flf->count) > 0)
{
return;
}
if (flf->name != NULL &&
!StrEquals(flf->name, mb_fallback_font) &&
!StrEquals(flf->name, fallback_font))
{
free(flf->name);
}
if (FftSupport && flf->fftf.fftfont != NULL)
{
FftFontClose(dpy, flf->fftf.fftfont);
if (flf->fftf.fftfont_rotated_90 != NULL)
FftFontClose(dpy, flf->fftf.fftfont_rotated_90);
if (flf->fftf.fftfont_rotated_180 != NULL)
FftFontClose(dpy, flf->fftf.fftfont_rotated_180);
if (flf->fftf.fftfont_rotated_270 != NULL)
FftFontClose(dpy, flf->fftf.fftfont_rotated_270);
}
if (flf->fontset != NULL)
{
XFreeFontSet(dpy, flf->fontset);
}
if (flf->font != NULL)
{
XFreeFont(dpy, flf->font);
}
if (flf->flags.must_free_fc)
{
if (flf->fc->x)
free(flf->fc->x);
if (flf->fc->bidi)
free(flf->fc->bidi);
if (flf->fc->locale != NULL)
{
while (FLC_GET_LOCALE_CHARSET(flf->fc,i) != NULL)
{
free(FLC_GET_LOCALE_CHARSET(flf->fc,i));
i++;
}
free(flf->fc->locale);
}
free(flf->fc);
}
/* Link it out of the list (it might not be there) */
if (flf == list) /* in head? simple */
{
FlocaleFontList = flf->next;
}
else
{
while (list && list->next != flf)
{
/* fast forward until end or found */
list = list->next;
}
/* not end? means we found it in there, possibly at end */
if (list)
{
/* link around it */
list->next = flf->next;
}
}
free(flf);
}
/*
* Width and Drawing Text
*/
void FlocaleInitGstpArgs(
flocale_gstp_args *args, FlocaleFont *flf, FlocaleWinString *fws,
int start_x, int start_y)
{
args->step = 0;
args->offset = flf->shadow_offset + 1;
args->outer_offset = flf->shadow_offset + flf->shadow_size;
args->size = flf->shadow_size;
args->sdir = flf->flags.shadow_dir;
switch (fws->flags.text_rotation)
{
case ROTATION_270: /* CCW */
args->orig_x = start_x + FLF_SHADOW_UPPER_SIZE(flf);
args->orig_y = start_y + FLF_SHADOW_RIGHT_SIZE(flf);
break;
case ROTATION_180:
args->orig_x = start_x + FLF_SHADOW_RIGHT_SIZE(flf);
args->orig_y = start_y;
break;
case ROTATION_90: /* CW */
args->orig_x = start_x + FLF_SHADOW_BOTTOM_SIZE(flf);
args->orig_y = start_y + FLF_SHADOW_LEFT_SIZE(flf);
break;
case ROTATION_0:
default:
args->orig_x = start_x + FLF_SHADOW_LEFT_SIZE(flf);
args->orig_y = start_y;
break;
}
args->rot = fws->flags.text_rotation;
return;
}
Bool FlocaleGetShadowTextPosition(
int *x, int *y, flocale_gstp_args *args)
{
if (args->step == 0)
{
args->direction = MULTI_DIR_NONE;
args->inter_step = 0;
}
if ((args->step == 0 || args->inter_step >= args->num_inter_steps) &&
args->size != 0)
{
/* setup a new direction */
args->inter_step = 0;
gravity_get_next_multi_dir(args->sdir, &args->direction);
if (args->direction == MULTI_DIR_C)
{
int size;
size = 2 * (args->outer_offset) + 1;
args->num_inter_steps = size * size;
}
else
{
args->num_inter_steps = args->size;
}
}
if (args->direction == MULTI_DIR_NONE || args->size == 0)
{
*x = args->orig_x;
*y = args->orig_y;
return False;
}
if (args->direction == MULTI_DIR_C)
{
int tx;
int ty;
int size;
int is_finished;
size = 2 * (args->outer_offset) + 1;
tx = args->inter_step % size - args->outer_offset;
ty = args->inter_step / size - args->outer_offset;
for (is_finished = 0; ty <= args->outer_offset;
ty++, tx = -args->outer_offset)
{
for (; tx <= args->outer_offset; tx++)
{
if (tx <= -args->offset ||
tx >= args->offset ||
ty <= -args->offset || ty >= args->offset)
{
is_finished = 1;
break;
}
}
if (is_finished)
{
break;
}
}
args->inter_step =
(tx + args->outer_offset) +
(ty + args->outer_offset) * size;
if (!is_finished)
{
tx = 0;
ty = 0;
}
*x = args->orig_x + tx;
*y = args->orig_y + ty;
}
else if (args->inter_step > 0)
{
/* into a directional drawing */
(*x) += args->x_sign;
(*y) += args->y_sign;
}
else
{
direction_t dir;
direction_t dir_x;
direction_t dir_y;
dir = gravity_multi_dir_to_dir(args->direction);
gravity_split_xy_dir(&dir_x, &dir_y, dir);
args->x_sign = gravity_dir_to_sign_one_axis(dir_x);
args->y_sign = gravity_dir_to_sign_one_axis(dir_y);
gravity_rotate_xy(
args->rot, args->x_sign, args->y_sign,
&args->x_sign, &args->y_sign);
*x = args->orig_x + args->x_sign * args->offset;
*y = args->orig_y + args->y_sign * args->offset;
}
args->inter_step++;
args->step++;
return True;
}
void FlocaleDrawString(
Display *dpy, FlocaleFont *flf, FlocaleWinString *fws,
unsigned long flags)
{
int len;
Bool do_free = False;
Pixel fg = 0, fgsh = 0;
Bool has_fg_pixels = False;
flocale_gstp_args gstp_args;
superimpose_char_t *comb_chars = NULL;
char *curr_str;
int char_len; /* length in number of chars */
int *pixel_pos = NULL;
int i;
int j;
char buf[4];
int curr_pixel_pos;
int curr_len;
if (!fws || !fws->str)
{
return;
}
if (flags & FWS_HAVE_LENGTH)
{
len = fws->len;
}
else
{
len = strlen(fws->str);
}
/* encode the string */
FlocaleEncodeWinString(
dpy, flf, fws, &do_free, &len, &comb_chars, NULL);
curr_str = fws->e_str;
for(char_len = 0, i = 0 ;
i < len && curr_str[i] != 0 ;
char_len++, i += curr_len)
{
curr_len = FlocaleStringNumberOfBytes(flf, curr_str + i);
}
/* for superimposition calculate the character positions in pixels */
if (comb_chars != NULL && (
comb_chars[0].c.byte1 != 0 || comb_chars[0].c.byte2 != 0))
{
/* the second condition is actually redundant,
but there for clarity,
ending at 0 is what's expected in a correct
string */
pixel_pos = (int *)safemalloc(
(char_len != 0 ? char_len : 1) * sizeof(int));
/* if there is 0 bytes in the encoded string, there might
still be combining character to draw (at position 0) */
if(char_len == 0)
{
pixel_pos[0] = 0;
}
for(
i = 0, curr_pixel_pos = 0 ;
i < char_len ;
i++, curr_str += curr_len)
{
curr_len = FlocaleStringNumberOfBytes(flf, curr_str);
for (j = 0 ; j < curr_len ; j++)
{
buf[j] = curr_str[j];
}
buf[j] = 0;
pixel_pos[i] = curr_pixel_pos;
/* need to compensate for shadow width (if any) */
curr_pixel_pos +=
FlocaleTextWidth(flf, buf, curr_len) -
FLF_SHADOW_WIDTH(flf);
}
}
/* get the pixels */
if (fws->flags.has_colorset)
{
fg = fws->colorset->fg;
fgsh = fws->colorset->fgsh;
has_fg_pixels = True;
}
else if (flf->shadow_size != 0)
{
XGCValues xgcv;
if (XGetGCValues(dpy, fws->gc, GCForeground, &xgcv) != 0)
{
fg = xgcv.foreground;
}
else
{
fg = PictureBlackPixel();
}
fgsh = GetShadow(fg);
has_fg_pixels = True;
}
if(flf->font != None &&
(FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb))
{
/* in this case, length is number of 2-byte chars */
len = char_len;
}
if (fws->flags.text_rotation != ROTATION_0 &&
flf->fftf.fftfont == NULL)
{
/* pass in information to perform superimposition */
FlocaleRotateDrawString(
dpy, flf, fws, fg, fgsh, has_fg_pixels, len,
comb_chars, pixel_pos);
}
else if (FftSupport && flf->fftf.fftfont != NULL)
{
FftDrawString(
dpy, flf, fws, fg, fgsh, has_fg_pixels, len, flags);
}
else if (flf->fontset != None)
{
int xt = fws->x;
int yt = fws->y;
FlocaleInitGstpArgs(&gstp_args, flf, fws, fws->x, fws->y);
if (flf->shadow_size != 0)
{
XSetForeground(dpy, fws->gc, fgsh);
while (FlocaleGetShadowTextPosition(
&xt, &yt, &gstp_args))
{
XmbDrawString(
dpy, fws->win, flf->fontset, fws->gc,
xt, yt, fws->e_str, len);
}
}
if (has_fg_pixels == True)
{
XSetForeground(dpy, fws->gc, fg);
}
xt = gstp_args.orig_x;
yt = gstp_args.orig_y;
XmbDrawString(
dpy, fws->win, flf->fontset, fws->gc,
xt, yt, fws->e_str, len);
}
else if (flf->font != None)
{
FlocaleFontStructDrawString(
dpy, flf, fws->win, fws->gc, fws->x, fws->y,
fg, fgsh, has_fg_pixels, fws, len, False);
}
/* here take care of superimposing chars */
i = 0;
if (comb_chars != NULL)
{
while(comb_chars[i].c.byte1 != 0 && comb_chars[i].c.byte2 != 0)
{
/* draw composing character on top of corresponding
"real" character */
FlocaleWinString tmp_fws = *fws;
int offset = pixel_pos[comb_chars[i].position];
char *buf2;
int out_len;
curr_len = FlocaleChar2bOneCharToUtf8(comb_chars[i].c,
buf);
buf2 = FiconvUtf8ToCharset(
dpy, flf->str_fc, (const char *)buf, curr_len);
if(buf2 == NULL)
{
/* if conversion failed, combinational char
is not representable in current charset */
/* just replace with empty string */
buf2 = (char *)safemalloc(sizeof(char));
buf2[0] = 0;
}
tmp_fws.e_str = buf2;
tmp_fws.str2b = NULL;
if(FftSupport && flf->fftf.fftfont != NULL)
{
tmp_fws.x = fws->x + offset;
FftDrawString(
dpy, flf, &tmp_fws, fg, fgsh,
has_fg_pixels, strlen(buf2),
flags);
}
else if(flf->fontset != None)
{
int xt = fws->x;
int yt = fws->y;
FlocaleInitGstpArgs(
&gstp_args, flf, fws, fws->x, fws->y);
if (flf->shadow_size != 0)
{
XSetForeground(dpy, fws->gc, fgsh);
while (FlocaleGetShadowTextPosition(
&xt, &yt, &gstp_args))
{
XmbDrawString(
dpy, fws->win,
flf->fontset,
fws->gc,
xt, yt,
buf2,
strlen(buf2));
}
}
XSetForeground(dpy, fws->gc, fg);
xt = gstp_args.orig_x;
yt = gstp_args.orig_y;
XmbDrawString(
dpy, fws->win, flf->fontset, fws->gc,
xt + offset, yt, buf2, strlen(buf2));
}
else if (flf->font != None)
{
if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
{
tmp_fws.str2b = (XChar2b *)
safemalloc(2 * sizeof(XChar2b));
tmp_fws.str2b[0] = comb_chars[i].c;
tmp_fws.str2b[1].byte1 = 0;
tmp_fws.str2b[1].byte2 = 0;
out_len = 1;
/*tmp_fws.str2b =
FlocaleUtf8ToUnicodeStr2b(
tmp_fws.e_str,
curr_len, &out_len);*/
}
else if (flf->flags.is_mb)
{
tmp_fws.str2b =
FlocaleStringToString2b(
dpy, flf,
tmp_fws.e_str,
curr_len, &out_len);
}
else
{
out_len = strlen(buf2);
}
FlocaleFontStructDrawString(
dpy, flf, fws->win, fws->gc,
fws->x + offset, fws->y, fg, fgsh,
has_fg_pixels, &tmp_fws, out_len,
False);
}
free(buf2);
if(tmp_fws.str2b != NULL)
{
free(tmp_fws.str2b);
}
i++;
}
}
if (do_free)
{
if (fws->e_str != NULL)
{
free(fws->e_str);
fws->e_str = NULL;
}
}
if (fws->str2b != NULL)
{
free(fws->str2b);
fws->str2b = NULL;
}
if(comb_chars != NULL)
{
free(comb_chars);
if(pixel_pos)
free(pixel_pos);
}
return;
}
void FlocaleDrawUnderline(
Display *dpy, FlocaleFont *flf, FlocaleWinString *fws, int offset)
{
int off1, off2, y, x_s, x_e;
superimpose_char_t *comb_chars = NULL;
int *l_to_v = NULL;
Bool do_free = True;
int len = strlen(fws->str);
int l_coffset;
int v_coffset;
int voffset;
if (fws == NULL || fws->str == NULL)
{
return;
}
/* need to encode the string first to get BIDI and combining chars */
FlocaleEncodeWinString(dpy, flf, fws, &do_free, &len, &comb_chars,
&l_to_v);
/* we don't need this, only interested in char mapping */
free(comb_chars);
/* now calculate char offset (in bytes) in visual string corresponding
to coffset */
/* calculate absolute position in string (in characters) */
l_coffset = FlocaleStringByteToCharOffset(flf, fws->str, offset);
/* map to an offset in the visual string */
v_coffset = l_to_v[l_coffset];
/* calculate byte offset into visual string */
voffset = FlocaleStringCharToByteOffset(flf, fws->e_str, v_coffset);
off1 = FlocaleTextWidth(flf, fws->e_str, voffset) +
((voffset == 0)?
FLF_SHADOW_LEFT_SIZE(flf) : - FLF_SHADOW_RIGHT_SIZE(flf) );
off2 = FlocaleTextWidth(flf, fws->e_str + voffset,
FlocaleStringNumberOfBytes(flf, fws->e_str + voffset)) -
FLF_SHADOW_WIDTH(flf) - 1 + off1;
y = fws->y + 2;
x_s = fws->x + off1;
x_e = fws->x + off2;
/* No shadow */
XDrawLine(dpy, fws->win, fws->gc, x_s, y, x_e, y);
/* free encoded string if it isn't the same as input string */
if(fws->e_str != fws->str)
{
free(fws->e_str);
fws->e_str = NULL;
}
if(fws->str2b != NULL)
{
free(fws->str2b);
fws->str2b = NULL;
}
free(l_to_v);
return;
}
int FlocaleTextWidth(FlocaleFont *flf, char *str, int sl)
{
int result = 0;
char *tmp_str;
int new_l,do_free;
superimpose_char_t *comb_chars = NULL;
if (!str || sl == 0)
return 0;
if (sl < 0)
{
/* a vertical string: nothing to do! */
sl = -sl;
}
/* FIXME */
/* to avoid eccesive calls iconv (slow in Solaris 8)
don't bother to encode if string is one byte
when drawing a string this function is used to calculate
position of each character (for superimposition) */
if(sl == 1)
{
tmp_str = str;
new_l = sl;
do_free = False;
}
else
{
tmp_str = FlocaleEncodeString(
Pdpy, flf, str, &do_free, sl, &new_l, NULL,
&comb_chars, NULL);
}
/* if we get zero-length, check to to see if there if there's any
combining chars, if so use an imagninary space as a
"base character" */
if (strlen(tmp_str) == 0 && comb_chars &&
(comb_chars[0].c.byte1 != 0 || comb_chars[0].c.byte2 != 0))
{
if(do_free)
{
free(tmp_str);
}
if(comb_chars)
{
free(comb_chars);
}
return FlocaleTextWidth(flf, " ", 1);
}
else if (FftSupport && flf->fftf.fftfont != NULL)
{
result = FftTextWidth(flf, tmp_str, new_l);
}
else if (flf->fontset != None)
{
result = XmbTextEscapement(flf->fontset, tmp_str, new_l);
}
else if (flf->font != None)
{
if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc) || flf->flags.is_mb)
{
XChar2b *str2b;
int nl;
if (FLC_ENCODING_TYPE_IS_UTF_8(flf->fc))
str2b = FlocaleUtf8ToUnicodeStr2b(
tmp_str, new_l, &nl);
else
str2b = FlocaleStringToString2b(
Pdpy, flf, tmp_str, new_l, &nl);
if (str2b != NULL)
{
result = XTextWidth16(flf->font, str2b, nl);
free(str2b);
}
}
else
{
result = XTextWidth(flf->font, tmp_str, new_l);
}
}
if (do_free)
{
free(tmp_str);
}
if (comb_chars)
{
free(comb_chars);
}
return result + ((result != 0)? FLF_SHADOW_WIDTH(flf):0);
}
int FlocaleGetMinOffset(
FlocaleFont *flf, rotation_t rotation)
{
int min_offset;
#ifdef FFT_BUGGY_FREETYPE
switch(rotation)
{
case ROTATION_270:
case ROTATION_180:
/* better than descent */
min_offset = (flf->descent + flf->height - flf->ascent)/2;
break;
case ROTATION_0:
case ROTATION_90:
default:
/* better than ascent */
min_offset = (flf->ascent + flf->height - flf->descent)/2;
break;
}
#else
switch(rotation)
{
case ROTATION_180:
case ROTATION_90:
/* better than descent */
min_offset = (flf->descent + flf->height - flf->ascent)/2;
break;
case ROTATION_270:
case ROTATION_0:
default:
/* better than ascent */
min_offset = (flf->ascent + flf->height - flf->descent)/2;
break;
}
#endif
return min_offset;
}
void FlocaleAllocateWinString(FlocaleWinString **pfws)
{
*pfws = (FlocaleWinString *)safemalloc(sizeof(FlocaleWinString));
memset(*pfws, '\0', sizeof(FlocaleWinString));
}
/*
* Text properties
*/
void FlocaleGetNameProperty(
Status (func)(Display *, Window, XTextProperty *), Display *dpy,
Window w, FlocaleNameString *ret_name)
{
char **list;
int num;
XTextProperty text_prop;
list = NULL;
if (func(dpy, w, &text_prop) == 0)
{
return;
}
if (text_prop.encoding == XA_STRING)
{
/* STRING encoding, use this as it is */
ret_name->name = (char *)text_prop.value;
ret_name->name_list = NULL;
return;
}
/* not STRING encoding, try to convert XA_COMPOUND_TEXT */
if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success
&& num > 0 && *list)
{
/* Does not consider the conversion is REALLY succeeded:
* XmbTextPropertyToTextList return 0 (== Success) on success,
* a negative int if it fails (and in this case we are not
* here), the number of unconvertible char on "partial"
* success*/
XFree(text_prop.value); /* return of XGetWM(Icon)Name() */
ret_name->name = *list;
ret_name->name_list = list;
}
else
{
if (list)
{
XFreeStringList(list);
}
ret_name->name = (char *)text_prop.value;
ret_name->name_list = NULL;
}
}
void FlocaleFreeNameProperty(FlocaleNameString *ptext)
{
if (ptext->name_list != NULL)
{
if (ptext->name != NULL && ptext->name != *ptext->name_list)
XFree(ptext->name);
XFreeStringList(ptext->name_list);
ptext->name_list = NULL;
}
else if (ptext->name != NULL)
{
XFree(ptext->name);
}
ptext->name = NULL;
return;
}
Bool FlocaleTextListToTextProperty(
Display *dpy, char **list, int count, XICCEncodingStyle style,
XTextProperty *text_prop_return)
{
int ret = False;
if (Flocale != NULL)
{
ret = XmbTextListToTextProperty(
dpy, list, count, style, text_prop_return);
if (ret == XNoMemory)
{
ret = False;
}
else
{
/* ret == Success or the number of unconvertible
* characters. ret should be != XLocaleNotSupported
* because in this case Flocale == NULL */
ret = True;
}
}
if (!ret)
{
if (XStringListToTextProperty(
list, count, text_prop_return) == 0)
{
ret = False;
}
else
{
ret = True;
}
}
return ret;
}
/*
* Info
*/
void FlocalePrintLocaleInfo(Display *dpy, int verbose)
{
FlocaleFont *flf = FlocaleFontList;
int count = 0;
FlocaleCharset *cs;
fflush(stderr);
fflush(stdout);
fprintf(stderr,"fvwm info on locale:\n");
fprintf(stderr," locale: %s, Modifier: %s\n",
(Flocale)? Flocale:"", (Fmodifiers)? Fmodifiers:"");
cs = FlocaleCharsetGetDefaultCharset(dpy, NULL);
fprintf(stderr," Default Charset: X: %s, Iconv: %s, Bidi: %s\n",
cs->x,
(cs->iconv_index >= 0)?
cs->locale[cs->iconv_index]:"Not defined",
(cs->bidi)? "Yes":"No");
FlocaleCharsetPrintXOMInfo();
while (flf)
{
count++;
flf = flf->next;
}
fprintf(stderr," Number of loaded font: %i\n", count);
if (verbose)
{
count = 0;
flf = FlocaleFontList;
while(flf)
{
cs = flf->fc;
fprintf(stderr," * Font number %i\n", count);
fprintf(stderr," fvwm info:\n");
fprintf(stderr," Name: %s\n",
(flf->name)? flf->name:"");
fprintf(stderr," Cache count: %i\n", flf->count);
fprintf(stderr," Type: ");
if (flf->font)
{
fprintf(stderr,"FontStruct\n");
}
else if (flf->fontset)
{
fprintf(stderr,"FontSet\n");
}
else
{
fprintf(stderr,"XftFont\n");
}
fprintf(stderr, " Charset: X: %s, Iconv: %s, "
"Bidi: %s\n",
cs->x,
(cs->iconv_index >= 0)?
cs->locale[cs->iconv_index]:"Not defined",
(cs->bidi)? "Yes":"No");
fprintf(stderr," height: %i, ascent: %i, "
"descent: %i\n", flf->height, flf->ascent,
flf->descent);
fprintf(stderr," shadow size: %i, "
"shadow offset: %i, shadow direction:%i\n",
flf->shadow_size, flf->shadow_offset,
flf->flags.shadow_dir);
if (verbose >= 2)
{
if (flf->fftf.fftfont != NULL)
{
FftFontType *fftf;
fftf = &flf->fftf;
fprintf(stderr, " Xft info:\n"
" - Vertical font:");
FftPrintPatternInfo(
fftf->fftfont, False);
fprintf(stderr, " "
"- Rotated font 90:");
if (fftf->fftfont_rotated_90)
FftPrintPatternInfo(
fftf->
fftfont_rotated_90,
True);
else
fprintf(stderr, " None\n");
fprintf(stderr, " "
"- Rotated font 270:");
if (fftf->fftfont_rotated_270)
FftPrintPatternInfo(
fftf->
fftfont_rotated_270,
True);
else
fprintf(stderr, " None\n");
fprintf(stderr, " "
"- Rotated font 180:");
if (fftf->fftfont_rotated_180)
FftPrintPatternInfo(
fftf->
fftfont_rotated_180,
True);
else
fprintf(stderr, " None\n");
}
else if (flf->font != NULL)
{
char *full_name;
full_name =
FlocaleGetFullNameOfFontStruct(
dpy, flf->font);
fprintf(stderr, " X info:\n"
" %s\n",
(full_name)? full_name:"?");
if (full_name != NULL)
{
XFree(full_name);
}
}
else if (flf->fontset != NULL)
{
int n,i;
XFontStruct **font_struct_list;
char **font_name_list;
fprintf(stderr, " X info:\n");
n = XFontsOfFontSet(
flf->fontset,
&font_struct_list,
&font_name_list);
for(i = 0; i < n; i++)
{
fprintf(stderr,
" %s\n",
font_name_list[i]);
}
}
}
count++;
flf = flf->next;
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1