[ previous ] [ Contents ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ 14 ] [ next ]


Introduction to i18n
Chapter 13 - Examples of I18N


Programmers who have internationalized softwares, have written a patch of L10N, and so on are encouraged to contribute to this chapter.


13.1 TWM -- usage of XFontSet instead of XFontStruct

The author of this section is Tomohiro KUBOTA (kubota@debian.org).


13.1.1 Introduction

TWM is Tabbed (or Tom's) Window Manager, one of the most well-known window managers in the world. It is included in the XFree86 distribution. Since it was not internationalized, I wrote a patch for TWM included in XFree86 version 4.0.1. The patch was adopted in XFree86 version 4.0.1d.

Note: a bug is found for I18N_FetchName() and I18N_GetIconName() of my patch. The bug is fixed since XFree86 version 4.1.0. This document is also fixed.

The contents of the internationalization are:

The following will present these items.


13.1.2 Locale Setting - A Routine Work

At first, I added a small part to call setlocale() at the beginning of main() function.

         loc = setlocale(LC_ALL, "");
         if (!loc || !strcmp(loc, "C") || !strcmp(loc, "POSIX") ||
            !XSupportsLocale()) {
             use_fontset = False;
         } else {
             use_fontset = True;
         }

loc is char *-type auto (local) variable. use_fontset is Bool-type global variable, for which I wrote a declaration in twm.h.

     extern Bool use_fontset;

I also added inclusion of X11/Xlocale.h header file. By including of this header file, locale feature of X11 will be used when compiled in OS without locale features. Otherwise, X11/Xlocale will use locale features of the OS. Thus, you can include X11/Xlocale.h regardless of whether the OS support locale.

Checking of NULL, "C", and "POSIX" locales will enable TWM to work 8bit through when the user does not configure locale properly. Under "C" or "POSIX" locale, or without proper configuration of locale, XFontSet-related functions will work under 7bit ASCII encoding and these functions will regard all 8bit characters as invalid. In such cases, my patch won't use XFontSet-related functions by checking the value of use_fontset. Checking of XSupportLocale() is needed for cases when the OS support the locale while X doesn't support the locale.


13.1.3 Font Preparation

Almost functions related to XFontStruct can be easily substituted by XFontSet-related functions.

Fortunately, TWM used a tailored MyFont type for font handling. Thus the amount of labor was decreased. The original MyFont definition was:

     typedef struct MyFont
     {
         char *name;                 /* name of the font */
         XFontStruct *font;          /* font structure */
         int height;                 /* height of the font */
         int y;                      /* Y coordinate to draw characters */
     } MyFont;

I added a few lines.

     typedef struct MyFont
     {
         char *name;                 /* name of the font */
         XFontStruct *font;          /* font structure */
         XFontSet fontset;           /* fontset structure */
         int height;                 /* height of the font */
         int y;                      /* Y coordinate to draw characters */
         int ascent;
         int descent;
     } MyFont;

Then one of the main part of this patch -- font preparation. The font preparation is done in the GetFont() function in util.c. This function is almost entirely rewritten.

     void
     GetFont(font)
     MyFont *font;
     {
         char *deffontname = "fixed";
         char **missing_charset_list_return;
         int missing_charset_count_return;
         char *def_string_return;
         XFontSetExtents *font_extents;
         XFontStruct **xfonts;
         char **font_names;
         register int i;
         int ascent;
         int descent;
         int fnum;
         char *basename2;
     
         if (use_fontset) {
             if (font->fontset != NULL){
                 XFreeFontSet(dpy, font->fontset);
             }
     
             basename2 = (char *)malloc(strlen(font->name) + 3);
             if (basename2) sprintf(basename2, "%s,*", font->name);
             else basename2 = font->name;
             if( (font->fontset = XCreateFontSet(dpy, basename2,
                                                 &missing_charset_list_return,
                                                 &missing_charset_count_return,
                                                 &def_string_return)) == NULL) {
                 fprintf (stderr, "%s:  unable to open fontset \"%s\"\n",
                              ProgramName, font->name);
                 exit(1);
             }
             if (basename2 != font->name) free(basename2);
             for(i=0; i<missing_charset_count_return; i++){
                 printf("%s: warning: font for charset %s is lacking.\n",
                        ProgramName, missing_charset_list_return[i]);
             }
     
             font_extents = XExtentsOfFontSet(font->fontset);
             fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names);
             for( i = 0, ascent = 0, descent = 0; i<fnum; i++){
                 if (ascent < (*xfonts)->ascent) ascent = (*xfonts)->ascent;
                 if (descent < (*xfonts)->descent) descent = (*xfonts)->descent;
                 xfonts++;
             }
             font->height = font_extents->max_logical_extent.height;
             font->y = ascent;
             font->ascent = ascent;
             font->descent = descent;
             return;
         }
     
         if (font->font != NULL)
             XFreeFont(dpy, font->font);
     
         if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL)
         {
             if (Scr->DefaultFont.name) {
                 deffontname = Scr->DefaultFont.name;
             }
             if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL)
             {
                 fprintf (stderr, "%s:  unable to open fonts \"%s\" or \"%s\"\n",
                          ProgramName, font->name, deffontname);
                 exit(1);
             }
     
         }
         font->height = font->font->ascent + font->font->descent;
         font->y = font->font->ascent;
         font->ascent = font->font->ascent;
         font->descent = font->font->descent;
     }

This function can be divided into two large parts by if (use_fontset). The part inside the if is for internationalized version and other part is for conventional version. Conventional version is used when use_fontset is false, as you can see. This part is almost the same as the original TWM.

Now let's study the internationalized part of GetFont(). It is convenient to compare the internationalized part and conventional part, to study it. The first check and XFreeFontSet() is a replacement of XFreeFont(). The next several lines is the automatic font guessing mechanism (the simplest version), the second item of the whole patch. It only adds ",*" to the font query string. Then the added string is passed into XCreateFontSet(), the key function of font preparation.


13.1.4 Automatic Font Guessing

Let's imagine how this ",*" works. Assume ja_JP.eucJP locale, where EUC-JP encoding is used. In EUC-JP encoding, three fonts of

are used. [28] Again assume that GetFont received a string of "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*" as font->name. This string is a very likely specification of font. Actually, I got the example from the default title font for TWM. Now review the behavior of XLoadQueryFont(). Since it always gets at most one font, it can succeed or fail. However, since XCreateFontSet() may get multiple fonts, it may success only to get a part of the set of requred fonts. The assumed calling of XCreateFontSet() with the font->name in ja_JP.eucJP locale goes into just such a situation. For usual systems, only a font for ISO8859-1 or JISX0201.1976-0 is available. [29] It is easy to solve this situation. Unlike XLoadQueryFont(), XCreateFontSet() can take a list of patterns of fonts with wildcards. XCreateFontSet() chooses necessary fonts from the set of fonts which match the patterns. "*" can match all fonts. This works for character sets for which the given font->name failed to match any fonts.

There were two solutions I imagined.

The first solution may fail because users can rewrite the configuration file. Though it is likely that a user knows necessary character sets for the encoding (s)he uses, the second way is safer. And more, recent window managers are coming to support themes where a set of configuration is packaged and distributed, just as in http://www.themes.org/. It is very unlikely that all developers of these themes know this problem and adds ",*" for every font specifications. Thus, window managers which support themes must take the 2nd solution, though TWM does not support themes.

Which font exactly is choosed for wild cards? It depends on the configuration of X Window System. I imagine that the first font in the list generated by xlsfonts. You may think the choice of the font should be cleverer. It would be adequate to say that ",*" mechanism is not less cleverer; it has entirely no intelligence. It is not clever at all. Yes, though I didn't implement it to TWM, I also wrote a cleverer guessing mechanism. [30]


13.1.5 Font Preparation (continued)

After calling XCreateFontSet(), GetFont() builds a few member variables of MyFont, i.e., font->height, font->y, font->ascent, and font->descent. These parameters are easily get from members of XFontStruct structure and are actually often used in TWM. Thus I had to prepare substitutions for XFontSet version. These variables also build for XFontStruct version so that a united method can be used to get these parameters.


13.1.6 Drawing Text using MyFont

To draw a text, XDrawString() and XDrawImageString() are used for conventional XFontStruct. On the other hand, XmbDrawString()/XwcDrawString() and XmbDrawImageString()/XwcDrawImageString() are used for internationalized XFontSet. The difference between mb and wc versions are whether the text is given in multibyte characters or in wide characters. Since TWM does not perform any text processing, I didn't use wide characters and treat strings as they are (in multibyte characters).

TWM has many calls of these functions. Thus I decided to write wrappers which checks use_fontset and calls proper version of X function. They are MyFont_DrawString() and MyFont_DrawImageString(). Thus all calling of XDrawString() and XDrawImageString() are replaced with the wrappers. Since these two are almost identical, I will explain one of them.

     void
     MyFont_DrawString(dpy, d, font, gc, x, y, string, len)
         Display *dpy;
         Drawable d;
         MyFont *font;
         GC gc;
         int x,y;
         char *string;
         int len;
     {
         if (use_fontset) {
            XmbDrawString(dpy, d, font->fontset, gc, x, y, string, len);
            return;
         }
         XDrawString (dpy, d, gc, x, y, string, len);
     }

Very simple function! However note that the required paramaters are different in these two functions of conventional version and internationalized version. Font is needed for internationalized version.

Then, is GC not used for specifying a font for internationalized version? Right. This causes to increase the labor. The original version of TWM use a macro of FBF to set up the GC. Fortunately, font specification is always performed just before the drawing of the texts. I wrote a function MyFont_ChangeGC() for substitution.

     void
     MyFont_ChangeGC(fix_fore, fix_back, fix_font)
         unsigned long fix_fore, fix_back;
         MyFont *fix_font;
     {
         Gcv.foreground = fix_fore;
         Gcv.background = fix_back;
         if (use_fontset) {
            XChangeGC(dpy, Scr->NormalGC, GCForeground|GCBackground, &Gcv);
            return;
         }
         Gcv.font = fix_font->font->fid;
         XChangeGC(dpy, Scr->NormalGC, GCFont|GCForeground|GCBackground,&Gcv);
     }

You may wonder why this is needed. You may think just do as use_fontset is false and it will work well. No, because fix_font->font is indefinite.

I had to modify one more part related to GC in gc.c.


13.1.7 Geting Size of Texts

TWM calls XTextWidth() many times. It returns the width in pixels for a text. The internationalized version of the function is XmbTextExtent() and XwcTextExtent(), where the difference between mb version and wc version is same as XmbDrawString() and so on.

I wrote a wrapper, as I did for other functions.


13.1.8 Getting Window Titles

General discussions have finished. The following discussions are specific to window managers.

Window managers have to get the names for window titles from X clients. XFetchName() is the function for this purpose.

Window title names are communicated using property mechanism of X. XA_STRING and XA_COMPOUND_TEXT are types to be used for this purpose. XA_STRING means the text data is in ISO8859-1 encoding and XA_COMPOUND_TEXT means the data is in compound text. Compound text is a subset of ISO 2022 and can handle international text data.

Now, XFetchName() can handle XA_STRING type only. Thus we should use XGetWMName(). Since handling of compound text needs several lines of source codes, I wrote a wrapper function.

     /*
      * The following functions are internationalized substitutions
      * for XFetchName and XGetIconName using XGetWMName and
      * XGetWMIconName.  
      *
      * Please note that the third arguments have to be freed using free(), 
      * not XFree().
      */
     Status
     I18N_FetchName(dpy, w, winname)
         Display *dpy;
         Window w;
         char ** winname;
     {
         int    status;
         XTextProperty text_prop;
         char **list;
         int    num;
     
         status = XGetWMName(dpy, w, &text_prop);
         if (!status || !text_prop.value || !text_prop.nitems) return 0;
         status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
         if (status < Success || !num || !*list) return 0;
         XFree(text_prop.value);
         *winname = (char *)strdup(*list);
         XFreeStringList(list);
         return 1;
     }

13.1.9 Getting Icon Names

Window managers need to get not only window titles but also icon names.

TWM used XGetWindowProperty() with XA_STRING to get icon names. However, internationalized function XGetWMIconName() is available for this purpose and I rewrote using this function. Just like XGetWMName(), I wrote a wrapper.

     Status
     I18N_GetIconName(dpy, w, iconname)
         Display *dpy;
         Window w;
         char ** iconname;
     {
         int    status;
         XTextProperty text_prop;
         char **list;
         int    num;
     	
         status = XGetWMIconName(dpy, w, &text_prop);
         if (!status || !text_prop.value || !text_prop.nitems) return 0;
         status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
         if (status < Success || !num || !*list) return 0;
         XFree(text_prop.value);
         *iconname = (char *)strdup(*list);
         XFreeStringList(list);
         return 1;
     }

13.1.10 Configuration File Parser

The parser for configuration file was not 8bit clean. I modified it. It was a very minor change. In parse.c, global variables of buff[], overflowbuff[], stringListSource, and currentString and auto variable of sl in ParseStringList() are changed from char to unsigned char.


13.2 8bit-clean-ize of Minicom

The author of this section is Tomohiro KUBOTA (kubota@debian.org).

I needed a serial communication software to connect to BBS, though I had a MS-DOS version. I tried several softwares and found Minicom but it could not display Japanese characters in kterm. Thus I decided to modify the source of Minicom. Though it was dirty 'quick hacking', I sent the patch to the upstream developer.


13.2.1 8bit-clean-ize

Minicom is written in C.

At first I explore the source code to find the way for characters to be displayed. I found that it implements a 'ncurses'-like functions.

Since Minicom is used for BBS it seemed to have a conversion table so as to IBM-PC graphics characters (I guess) can be displayed correctly. I made an another pass for characters to go without any modification and added a new command option to activate the pass.


13.2.2 Not to break continuity of multibyte characters

The 'ncurses'-like functions in Minicom outputs location code every time a character is outputted. This breaks continuity of multibyte characters.


13.2.3 Catalog in EUC-JP and SHIFT-JIS


13.3 user-ja -- two sets of messages in ASCII and native codeset in the same language

The author of this section is Tomohiro KUBOTA (kubota@debian.or.jp).


13.3.1 Introduction

user-ja is a Debian-specific software which establishes basic settings for Japanese-speaking beginners. user-ja does not automatically establishes the settings. A user who needs Japanese environment has to invoke user-ja-conf.

Since user-ja-conf is a software to establish Japanese environment, the environment where user-ja runs may be poor Japanese environment. For example, user-ja-conf must not assume that Japanese character can be displayed. However, Japanese character should be used in environments where it is possible.

user-ja is a simple example which switches two sets of messages, one is written using ASCII characters and the other Japanese characters. Note that both of them are written in Japanese language. This is beyond what gettext can do.

Though user-ja is a Japanese-specific software, this problem of ability to display non-ASCII character is common to non-ASCII languages.


13.3.2 Strategy

The following environments can display Japanese characters: kon (Kanji Console), kterm, and krxvt (in rxvt-ml package). And more, telnet softwares for Windows and so on may be able to display Japanese characters.

At first, user-ja-conf detects the environment. If it can display Japanese characters, go ahead. If not, try to establish a new environment and invoke itself in it. If detection is failed, display Japanese characters and ask the user whether he/she can read it.


13.3.3 Implementation

user-ja-conf is a perl script. Here shows a function which check whether Japanese native characters can be displayed or not and try to establish an environment where native characters can be displayed, if not.

     sub isNC($$)
     {
             my ($KANJI, $TTY, $TERM, $DISPLAY, $WHICH);
             $TTY = `/usr/bin/tty`;
             $TERM = $ENV{TERM};
             $DISPLAY = $ENV{DISPLAY};
             $WHICH = '/usr/bin/which';
             $THIS = $_[0];
             $OPT = $_[1];
     
             if ($TERM eq 'kon' || $TERM eq 'kterm') {
                     $KANJI=1;
             } elsif ($DISPLAY ne '' && system("$WHICH kterm >/dev/null")==0) {
                     exec("kterm -km euc -e $THIS $OPT");
             } elsif ($DISPLAY ne '' && system("$WHICH krxvt >/dev/null")==0) {
                     exec("krxvt -km euc -e $THIS $OPT");
             } else {
                     print STDERR &sourceset2displayset(
                       "Japanese sentence in Japanese characters 'Can you read this sentence?'\n");
                     print STDERR 
                       "Japanese sentence in ASCII characters 'Can you read the above sentence written in Kanji? [y/N] ";
                     $a = <>;
                     if ($a =~ /y|Y/) {
                             $KANJI=1;
                     } elsif ($TTY =~ m#/dev/tty[0-9]+#) {
                             print STDERR
                               "Japanese sentence in ASCII characters 'Shall I invoke \'KON\'? [Y/n] ";
                             $a = <>;
                             exec("kon -e $THIS $OPT") if ($a !~ /n|N/);
                             $KANJI=0;
                     } else {
                             $KANJI=0;
                     }
             }
             $KANJI;
     }

&sourceset2displayset($) is a function to convert a string from codeset for source code into codeset for display. This is needed because codeset for program source (in this case, perl script) and dotfiles may be different. [31]

The following function is prepared to display messages in appropriate codeset. Don't care 'Lang::' package.

     sub disp ($$) {
             if ($NC) {print STDERR &Lang::sourceset2displayset($_[1]);}
             else {print STDERR $_[0];}
     }

This is an example how the disp function is used.

     sub disp_finish()
     {
             &Sub::disp(<<EOF1,<<EOF2);
     
     [Enter] key WO OSUTO KONO user-ja-conf HA SYUURYOU SHIMASU.
     EOF1
     
     Japanese sentence in Japanese characters 'Push [Enter] key to finish.'
     EOF2
     }

Here the sentence '[Enter] key WO OSUTO...' is the Latin alphabet expression of Japanese.

Thus almost all messages are duplicated using disp function.


13.4 A Quasi-Wrapper to Internationalize Text Output of X Clients

The author of this section is Tomohiro KUBOTA (kubota@debian.or.jp).


13.4.1 Introduction

X11 supplies XFontSet-related internationalized functions for text output. However, many X clients use conventional XFontStruct-related non-internationalized functions and cannot output languages which need multiple fonts (Chinese, Japanese, and Korean).

Now I introduce a wrapper which easily modify non-internationalized X clients to use internationalized X11 functions.


13.4.2 Strategy

Almost XFontStruct-related functions can be replaced easily by XFontSet-related functions.

However, there were several problems.

  1. The font for XDrawString is specified by GC parameter, while XFontSet parameter is used for XmbDrawString.

  1. XFontSet does not have structure members of ascent and descent, while XFontStruct has them and these members are often referred.

  1. Many software specify font name with iso8859-1-specific way. This avoids 'fontset'-related functions work fully and disables non-iso8859-1 languages be displayed.

Though it is possible to solve the first problem, this problem may make the wrapper very complex. Thus, I decided to modify the original source and leave the wrapper simple, instead of writing a complete wrapper. However, if XGCValues.font is set and XCreateGC() is called, it is needed to avoid XCreateGC to fail because of null font specification. Thus I wrote a wrapper of XCreateGC.

To solve the second problem, I wrote a wrapper of XFontSet which has structure members of ascent and descent. Thus all wrapper functions are related to this wrapper structure.

To solve the third problem, I wrote a wrapper of XCreateFontSet(). This part can be used for many X clients which are already internationalized using fontset-related functions, because these softwares have the same problem. Explanation on this problem and solution will be supplied in other section.


13.4.3 Usage of the wrapper

Replace the following structure and functions. You can use replacement faculty of your text editor.

The following two wrapper functions need an additional parameter.


13.4.4 The Header File of the Wrapper

This is the header file of the wrapper.

     /* fontset.h */
     
     #ifndef __fontset__h__
     #define __fontset__h__
     
     #include <X11/Xlocale.h>
     #include <X11/Xlib.h>
     #include <X11/Xatom.h>
     
     typedef struct {
       Font     fid;  /* dummy */
       XFontSet fs;
       int      ascent, descent;
     } QuasiXFontStruct;
     
     #define FONT_ELEMENT_SIZE 50
     
     QuasiXFontStruct *QuasiXLoadQueryFont(Display *d, const char *fontset_name);
     void QuasiXFreeFont(Display *d, QuasiXFontStruct *qxfs);
     void QuasiXDrawString(Display *d, Window w,
     		      QuasiXFontStruct *qxfs, GC gc,
     		      int x, int y, const char* s, int l);
     void QuasiXDrawImageString(Display *d, Window w,
     			   QuasiXFontStruct *qxfs, GC gc,
     			   int x, int y, char* s, int l);
     void QuasiXTextExtents(QuasiXFontStruct *qxfs, char *string, int nchars,
     		       int *direction_return, int *font_ascent_return,
     		       int *font_descent_return, XCharStruct *overall_return);
     int QuasiXTextWidth(QuasiXFontStruct *qxfs, const char *s, int cnt);
     
     Status QuasiXGetWMIconName(Display *d, Window w,
     			   XTextProperty *text_prop_return);
     Status QuasiXGetWMName(Display *d, Window w,
     		       XTextProperty *text_prop_return);
     Status QuasiXFetchName(Display *d, Window w, char **winname);
     Status QuasiXGetIconName(Display *d, Window w,char **iconname);
     GC QuasiXCreateGC(Display *d, Drawable dr, unsigned long mask, XGCValues *xgc);
     int QuasiXChangeGC(Display *d, GC gc, unsigned long mask, XGCValues * xgc);
     
     #else /* !FONTSET */
     
     #define QuasiXFontStruct    XFontStruct
     #define QuasiXLoadQueryFont XLoadQueryFont
     #define QuasiXFreeFont      XFreeFont
     #define QuasiXTextExtents   XTextExtents
     #define QuasiXTextWidth     XTextWidth
     #define QuasiXGetWMIconName XGetWMIconName
     #define QuasiXGetWMName     XGetWMName
     #define QuasiXFetchName     XFetchName
     #define QuasiXGetIconName   XGetIconName
     #define QuasiXChangeGC      XChangeGC
     #define QuasiXCreateGC      XCreateGC
     #define QuasiXDrawString(d, w, qxfs, gc, x, y, s, l) \
             XDrawString(d, w, gc, x, y, s, l)
     #define QuasiXDrawImageString(d, w, qxfs, gc, x, y, s, l) \
             XDrawImageString(d, w, gc, x, y, s, l)
     
     #endif /* __fontset__h__ */

13.4.5 The Source File of the Wrapper

This is the source file of the wrapper.

     /* fontset.c */
     
     #include <X11/Xlib.h>
     #include <X11/Xutil.h>
     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     #include <stdarg.h>
     #include <ctype.h>
     #include "fontset.h"
     
     
     static const char * i_strstr(const char *str, const char *ptn)
     {
       const char *s2, *p2;
       for( ; *str; str++) {
         for(s2=str,p2=ptn; ; s2++,p2++) {
           if (!*p2) return str;
           if (toupper(*s2) != toupper(*p2)) break;
         }
       }
       return NULL;
     }
     
     static const char * Font_GetElement(const char *pattern, char *buf, int bufsiz, ...)
     {
       const char *p, *v;
       char *p2;
       va_list va;
     
       va_start(va, bufsiz);
       buf[bufsiz-1] = 0;
       buf[bufsiz-2] = '*';
       while((v = va_arg(va, char *)) != NULL) {
         p = i_strstr(pattern, v);
         if (p) {
           strncpy(buf, p+1, bufsiz-2);
           p2 = strchr(buf, '-');
           if (p2) *p2=0;
           va_end(va);
           return p;
         }
       }
       va_end(va);
       strncpy(buf, "*", bufsiz);
       return NULL;
     }
     
     static const char * Font_GetSize(const char *pattern, int *size)
     {
       const char *p;
       const char *p2=NULL;
       int n=0;
     
       for (p=pattern; 1; p++) {
         if (!*p) {
           if (p2!=NULL && n>1 && n<72) {
     	*size = n; return p2+1;
           } else {
     	*size = 16; return NULL;
           }
         } else if (*p=='-') {
           if (n>1 && n<72 && p2!=NULL) {
     	*size = n;
     	return p2+1;
           }
           p2=p; n=0;
         } else if (*p>='0' && *p<='9' && p2!=NULL) {
           n *= 10;
           n += *p-'0';
         } else {
           p2=NULL; n=0;
         }
       }
     }
     
     static XFontSet XCreateFontSetWithGuess(Display *d, const char *pattern, char ***miss, int *n_miss, char **def)
     {
       XFontSet fs;
       char *pattern2;
       int pixel_size, bufsiz;
       char weight[FONT_ELEMENT_SIZE], slant[FONT_ELEMENT_SIZE];
     
       /* No problem?  or 'fs' for pattern analysis */
       fs = XCreateFontSet(d, pattern, miss, n_miss, def);
       if (fs && !*n_miss) return fs; /* no need for font guessing */
     
       /* for non-iso8859-1 language and iso8859-1 specification */
       /* This 'fs' is only for pattern analysis. */
       if (!fs) {
         if (*n_miss) XFreeStringList(*miss);
         setlocale(LC_CTYPE, "C");
         fs = XCreateFontSet(d, pattern, miss, n_miss, def);
         setlocale(LC_CTYPE, "");
       }
     
       /* make XLFD font name for pattern analysis */
       if (fs) {
         XFontStruct **fontstructs;
         char **fontnames;
         XFontsOfFontSet(fs, &fontstructs, &fontnames);
         pattern = fontnames[0];
       }
     
       /* read elements of font name */
       Font_GetElement(pattern, weight, FONT_ELEMENT_SIZE, 
     		  "-medium-", "-bold-", "-demibold-", "-regular-", NULL);
       Font_GetElement(pattern, slant, FONT_ELEMENT_SIZE, 
     		  "-r-", "-i-", "-o-", "-ri-", "-ro-", NULL);
       Font_GetSize(pattern, &pixel_size);
     
       /* modify elements of font name to fit usual font names */
       if (!strcmp(weight, "*")) strncpy(weight, "medium", FONT_ELEMENT_SIZE);
       if (!strcmp(slant,  "*")) strncpy(slant,  "r",      FONT_ELEMENT_SIZE);
       if (pixel_size<3) pixel_size=3; else if (pixel_size>97) pixel_size=97;
     
       /* build font pattern for better matching for various charsets */
       bufsiz = strlen(pattern) + FONT_ELEMENT_SIZE*2 + 2*2 + 58;
       pattern2 = (char *)malloc(bufsiz);
       if (pattern2) {
         snprintf(pattern2, bufsiz-1, "%s,"
     	     "-*-*-%s-%s-*-*-%d-*-*-*-*-*-*-*,"
     	     "-*-*-*-*-*-*-%d-*-*-*-*-*-*-*,*",
     	     pattern,
     	     weight, slant, pixel_size,
     	     pixel_size);
         pattern = pattern2;
       }
       if (*n_miss) XFreeStringList(*miss);
       if (fs) XFreeFontSet(d, fs);
     
       /* create fontset */
       fs = XCreateFontSet(d, pattern, miss, n_miss, def);
       if (pattern2) free(pattern2);
       return fs;
     }
     
     QuasiXFontStruct *QuasiXLoadQueryFont(Display *d, const char *fontset_name)
     {
       char **miss, *def, *pattern;
       int n_miss;
       XFontSet fontset;
       QuasiXFontStruct *wxfs;
       int pixel_size=16, bufsiz;
       char family[FONT_ELEMENT_SIZE], weight[FONT_ELEMENT_SIZE], 
            slant[FONT_ELEMENT_SIZE];
     
       wxfs = (QuasiXFontStruct *)malloc(sizeof(QuasiXFontStruct));
       if (!wxfs) return NULL;
     
       /* create fontset */
       fontset = XCreateFontSetWithGuess(d, fontset_name, &miss, &n_miss, &def);
       if (!fontset) {free(wxfs); return NULL;}
     
       if (n_miss) {
         int j;
         fprintf(stderr, 
          "QuasiXLoadQueryFont: lacks the font(s) for the following charset(s)\n");
         for (j=0; j<n_miss; j++) {
           fprintf(stderr, "  %s\n", miss[j]);
         }
         XFreeStringList(miss);
       }
       /* emulating XFontStruct */
       wxfs->fs      = fontset;
       wxfs->ascent  =-XExtentsOfFontSet(fontset)->max_logical_extent.y;
       wxfs->descent = XExtentsOfFontSet(fontset)->max_logical_extent.height
                      +XExtentsOfFontSet(fontset)->max_logical_extent.y;
       return wxfs;
     }
     
     void QuasiXFreeFont(Display *d, QuasiXFontStruct *wxfs)
     {
       if (!wxfs) return;
       XFreeFontSet(d, wxfs->fs);
       free(wxfs);
     }
     
     void QuasiXDrawString(Display *d, Window w, QuasiXFontStruct *qxfs, GC gc, 
     		     int x, int y, const char* s, int l)
     {
       XmbDrawString(d, w, qxfs->fs, gc, x, y, s, l);
     }
     
     void QuasiXDrawImageString(Display *d, Window w, QuasiXFontStruct *qxfs, GC gc,
     			   int x, int y, char* s, int l)
     {
       XmbDrawImageString(d, w, qxfs->fs, gc, x, y, s, l);
     }
     
     void QuasiXTextExtents(QuasiXFontStruct *qxfs, char *string, int nchars,
     		       int *direction_return, int *font_ascent_return,
     		       int *font_descent_return, XCharStruct *overall_return)
     {
       XRectangle overall_ink_return;
       XRectangle overall_logical_return;
       
       XmbTextExtents(qxfs->fs, string, nchars,
     		 &overall_ink_return, &overall_logical_return );
       
       *font_ascent_return  = -overall_logical_return.y;
       *font_descent_return =  overall_logical_return.height
                              +overall_logical_return.y;
       *direction_return    = FontLeftToRight; /* unsupported */
       *overall_return; /* unsupported */
     }
     
     int QuasiXTextWidth(QuasiXFontStruct *wxfs, const char *s, int cnt)
     {
       return XmbTextEscapement(wxfs->fs, s, cnt);
     }
     
     Status QuasiXGetWMName(Display *d, Window w, XTextProperty *text_prop_return)
     {
       int status;
       char **list;
       int num;
     
       status = XGetWMName(d, w, text_prop_return);
     
       if (!status || !text_prop_return->value || text_prop_return->nitems <= 0) {
         return 0; /* failure */
       }
       if (text_prop_return->encoding == XA_STRING) return 1;
       text_prop_return->nitems = strlen((char *)text_prop_return->value);
       status = XmbTextPropertyToTextList(d, text_prop_return,
     				     &list, &num);
       if (status >= Success && num > 0 && *list) {
         XFree(text_prop_return->value);
         text_prop_return->value  = (unsigned char*)strdup(*list);
         text_prop_return->nitems = strlen(*list);
         XFreeStringList(list);
         return 1; /* success */
       }
       return 0;
     }
     
     Status QuasiXGetWMIconName(Display *d, Window w, 
     			   XTextProperty *text_prop_return)
     {
       int status;
       char **list;
       int num;
     
       status = XGetWMIconName(d, w, text_prop_return);
     
       if (!status || !text_prop_return->value || text_prop_return->nitems <= 0) {
         return 0;
       }
       if (text_prop_return->encoding == XA_STRING) return 1;
       text_prop_return->nitems = strlen((char *)text_prop_return->value);
       status = XmbTextPropertyToTextList(d, text_prop_return,
     				     &list, &num);
       if (status >= Success && num > 0 && *list) {
         XFree(text_prop_return->value);
         text_prop_return->value  = (unsigned char*)strdup(*list);
         text_prop_return->nitems = strlen(*list);
         XFreeStringList(list);
         return 1;
       }
       return 0;
     }
     
     Status QuasiXGetIconName(Display *d, Window w, char **iconname)
     {
       XTextProperty text_prop;
       char **list;
       int num;
       
       if (QuasiXGetWMIconName(d, w, &text_prop) != 0) {
         if (text_prop.value && text_prop.nitems) {
           *iconname = (char *)text_prop.value;
           return 1;
         }
       }
       *iconname = NULL;
       return 0;
     }
     
     Status QuasiXFetchName(Display *d, Window w, char ** winname)
     {
       XTextProperty text_prop;
       char **list;
       int num;
       
       if (QuasiXGetWMName(d, w, &text_prop) != 0) {
         if (text_prop.value && text_prop.nitems > 0) {
           *winname = (char *)text_prop.value;
           return 1;
         }
       }
       *winname = NULL;
       return 0;  
     }
     
     GC QuasiXCreateGC(Display *d, Drawable dr, unsigned long mask, XGCValues *xgc)
     {
       return XCreateGC(d, dr, mask & ~GCFont, xgc);
     }
     
     int QuasiXChangeGC(Display *d, GC gc, unsigned long mask, XGCValues * xgc)
     {
       return XChangeGC(d, gc, mask & ~GCFont, xgc);
     }

[ previous ] [ Contents ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ 14 ] [ next ]


Introduction to i18n

22 December 2014

Tomohiro KUBOTA debian at tmail dot plala dot or dot jp (retired DD)