🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: bit.software.international
Article #287

CA: Motif 1.2 and X11R5 for I18N

#287
From: Bowyer Jeff
Date: Fri, 12 Nov 1993 17:51
444 lines
14997 bytes
Here are the consolidated answers to the original question from
Dilip Angal (dilip@informix.com):

     I Would like to know if any one has used Motif 1.2 (Not 1.1!)  and X11R5
     I18N features and successfully impemented them for truely I18Ned
     software.  Is there any good book (Motif Programmer's reference is not
     good enough!)  Also Mastering Motif Widgets (Even 1.2 version) does not
     have any example of how to use the New APIs for I18N.

     I am perticularly interested in an example of creating and drawing
     Compound string with mixed languages.  The drawing of string should be
     dependant only on the LANG env.  variable or LC_ALL.  Also if there any
     examples on how to use XIM etc.


Jeff
INSOFT-L List Manager

*========================================================================*
 Jeff Bowyer                         EMail:
 Computing Center		     jbowyer@cis.vutbr.cz
 Technical University of Brno
 Udolni 19, 602 00 BRNO
 Czech Republic
*========================================================================*


Sender: Eric Johnson <johnsone@johnsone.camax.com>
        CAMAX Systems, Inc.

I'm not sure how true our software is, but we're using Motif
to create international applications.

The real tough part about the existing Motif documentation is that
it's really hard to decide exactly what you need to do. The documentation
always seems to get bogged down into really low-level details that
you may be able to avoid. In addition, far too much is left to
the system implementors, such as the values of the VendorShell
XmNpreeditType resource. Please, vendors, standardize on these values!

For simple applications, all you have to do is call XtSetLanguageProc
(with three NULL parameters) before calling XtAppInitialize.
XtSetLanguageProc is new in X11R5.

With this, your application will be placed in the proper locale
(based on the LANG environment variable and the XmNxnlLanguage
resource). Xt will call setlocale for you.

Once done, all strings are assumed to be in the locale's encoding
(multibyte characters by default). If your application *can* be written
such that it doesn't pay attention to the text encoding, you don't
have a lot more to do. Unfortunately, I've never had that simple a case.

You'll find more on this in the Decemeber 1993 issue of UNIX REVIEW
magazine (in the Cross Thoughts column by Kevin Reichard and yours
truly) and in the upcoming second edition of Power Programming Motif
(Johnson and Reichard, MIS: Press--it's at the printers now). We don't
cover the XIM calls, though.


Sender: Tom McFarland <tommc@hpcvusc.cv.hp.com>
        Hewlett-Packard, Co.
        Workstation Technology Division
        GUI Lab - I18N

The Motif 1.2 Programmer's Guide provides some useful information on
developing I18N'ed applications with Motif.  Other than that, I don't
believe there is much specifically in print on the subject.

I did a lot of the I18N implementation for OSF in 1.2 and have given
several tutorials on using 1.2 (and R5) to developer internationalized
applications.  I would be glad to send you copies of my slides and
any example programs I have.

Additionally, if you can live with somewhat long turn around times,
send me e-mail with your questions.  I'll do what I can to answer
them as time allows.

>  I am perticularly interested in an example of creating and drawing
>  Compound string with mixed languages. The drawing of string
>  should be dependant only on the LANG env. variable or LC_ALL.
>  Also if there any examples on how to use XIM etc.

This really can't be used witht the I18N capabilities of Motif 1.2.
The I18N model in Motif is based on the ANSI/ISO setlocale model.
The purpose is to allow a single binary executable to be run in different
languages (locales) at different times.  Language choice is determined
at program start up.

Unfortunately, this model does not well facilitate developing multi-lingual
applications.  The model *can* handle entry/display/processing of all
characters in a particular encoding (e.g. Japanese EUC, or ISO 8859.2,
or Chinese Big5)... but if mixing codesets is what you need, the current
Motif 1.2 doesn't well address your problem.

P.S. Attached is a simple program showing use of XIM.  It is simplistic,
but illustrative and functional.

-------------------

#include <stdio.h>
#include <malloc.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <locale.h>
#include <limits.h>

int INIT_X = 10;
int INIT_Y = 50;

typedef struct {
	XFontSet fontset;
	char *foo;
} ApplicationData, *ApplicationDataPtr;

#ifndef NO_XT  /* pardon the double negative... means "If using Xt..." */
static XtResource my_resources[] = {
	{ XtNfontSet, XtCFontSet, XtRFontSet, sizeof (XFontSet),
	  XtOffset(ApplicationDataPtr, fontset), XtRString, "*-18-*"}
};
#endif /* NO_XT */

XIMStyle ChooseBetterStyle(style1,style2)
	XIMStyle style1, style2;
{
   XIMStyle s,t;
   XIMStyle preedit = XIMPreeditArea| XIMPreeditCallbacks | XIMPreeditPosition
		      | XIMPreeditNothing | XIMPreeditNone;
   XIMStyle status = XIMStatusArea | XIMStatusCallbacks | XIMStatusNothing
		      | XIMStatusNone;

   if (style1 == 0) return style2;
   if (style2 == 0) return style1;
   if ((style1 & (preedit | status)) == (style2 & (preedit | status)))
      return style2;

   s = style1 & preedit;
   t = style2 & preedit;
   if (s != t) {
      if (s | t | XIMPreeditCallbacks)
	 return (s == XIMPreeditCallbacks)?style1:style2;
      else if (s | t | XIMPreeditPosition)
	 return (s == XIMPreeditPosition)?style1:style2;
      else if (s | t | XIMPreeditArea)
	 return (s == XIMPreeditArea)?style1:style2;
      else if (s | t | XIMPreeditNothing)
	 return (s == XIMPreeditNothing)?style1:style2;
   } else {
      s = style1 & status;
      t = style2 & status;
      if (s | t | XIMStatusCallbacks)
	 return (s == XIMStatusCallbacks)?style1:style2;
      else if (s | t | XIMStatusArea)
	 return (s == XIMStatusArea)?style1:style2;
      else if (s | t | XIMStatusNothing)
	 return (s == XIMStatusNothing)?style1:style2;
   }
}

void GetPreferredGeometry(ic, name, area)
	XIC ic;
	char *name;
	XRectangle *area;
{
   XVaNestedList list;

   list = XVaCreateNestedList(0, XNAreaNeeded, area, NULL);

   XSetICValues(ic, name, list, NULL);
   XGetICValues(ic, name, list, NULL);
   XFree(list);
}

void SetGeometry(ic, name, area)
	XIC ic;
	char *name;
	XRectangle *area;
{
   XVaNestedList list;

   list = XVaCreateNestedList(0, XNArea, area, NULL);
   XSetICValues(ic, name, list, NULL);
   XFree(list);
}

void SetSpotLocation(fontset, ic, wc_string, str_len)
	XFontSet fontset;
	XIC ic;
	wchar_t *wc_string;
	int str_len;
{
   XPoint spot_loc;
   XVaNestedList list;

   spot_loc.y = INIT_Y;
   spot_loc.x = INIT_X + XwcTextEscapement(fontset, wc_string, str_len);
   list = XVaCreateNestedList(0, XNSpotLocation, &spot_loc, NULL);
   XSetICValues(ic, XNPreeditAttributes, list, NULL);
   XFree(list);
}

main(argc, argv)
	int argc;
	char*argv[];
{
   Display *dpy;
   int screen;
   Window win;
   GC gc;
   XGCValues gcv;
   XEvent event;
   XFontSet fontset;
   XIM im;
   XIC ic;
   XIMStyles *im_supported_styles;
   XIMStyle app_supported_styles;
   XIMStyle style, best_style;
   XVaNestedList pre_ed_list, status_list;
   long im_event_mask;
   XRectangle preedit_area;
   XRectangle status_area;
   char *program_name = argv[0];
   char **missing_charsets;
   int num_missing_charsets = 0;
   char *default_string;
   wchar_t wc_string[200];
   int str_len = 0;
   int i;
   int buf_len = 10;
   char *mb_buffer = malloc(buf_len * MB_LEN_MAX);
   wchar_t *buffer = (wchar_t *)malloc(buf_len * sizeof(wchar_t));
   ApplicationData data;
   XPoint spot;

#ifndef NO_XT  /* pardon the double negative... means "If using Xt..." */
   Widget toplevel;
#endif

#ifdef NO_XT
   (void)setlocale(LC_ALL, "");
#else
   (void)XtSetLanguageProc(NULL, NULL, NULL);
#endif /* NO_XT */

#ifdef NO_XT
   if ((dpy = XOpenDisplay(NULL)) == NULL) {
      (void) fprintf(stderr, "%s: cannot open Display.\n", program_name);
      exit(1);
   }
#else
   toplevel = XtInitialize(argv[0], "XIMtest", 0, 0, &argc, argv);
   dpy = XtDisplay(toplevel);
#endif /* NO_XT */

   if (!XSupportsLocale()){
      (void) fprintf(stderr, "%s: X does not support locale %s.\n",
		     program_name, setlocale(LC_ALL, NULL));
      exit(1);
   }

   if (XSetLocaleModifiers("") == NULL) {
      (void) fprintf(stderr, "%s: Warning: cannot set locale modifiers.\n",
		     argv[0]);
   }


#ifdef NO_XT
   fontset = XCreateFontSet(dpy, "*-18-*", &missing_charsets,
			    &num_missing_charsets, &default_string);
#else
   XtGetApplicationResources(toplevel, &data, my_resources,
			     XtNumber(my_resources), NULL, 0);
   fontset = data.fontset;
#endif /* NO_XT */

   if (num_missing_charsets > 0) {
      (void) fprintf(stderr, "%s: missing charsets.\n", program_name);
      XFreeStringList(missing_charsets);
   }

   screen = DefaultScreen(dpy);
   win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), 0, 0, 400, 100,
			     2, WhitePixel(dpy,screen), BlackPixel(dpy,screen));
   gc = XCreateGC(dpy, win,0,&gcv);
   XSetForeground(dpy, gc, WhitePixel(dpy,screen));
   XSetBackground(dpy, gc, BlackPixel(dpy,screen));

   if ((im = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) {
      (void) fprintf(stderr, "Couldn't open IM\n");
      exit(1);
   }

   app_supported_styles = XIMPreeditNone | XIMPreeditNothing | XIMPreeditArea
			  | XIMPreeditPosition;
   app_supported_styles |= XIMStatusNone | XIMStatusNothing | XIMStatusArea;

   XGetIMValues(im, XNQueryInputStyle, &im_supported_styles, NULL);
   best_style = 0;
   for(i=0; i < im_supported_styles->count_styles; i++){
      style = im_supported_styles->supported_styles[i];
      if ((style & app_supported_styles) == style)
	 best_style = ChooseBetterStyle(style, best_style);
   }

   if (best_style == 0) {
      (void)fprintf(stderr, "No common style\n");
      exit(1);
   }

   XFree(im_supported_styles);

   status_list = XVaCreateNestedList(0, XNFontSet,fontset,
				 XNForeground, WhitePixel(dpy,screen),
				 XNBackground, BlackPixel(dpy,screen),
				 NULL);

  /* initialize spot location */
   spot.x = INIT_X;
   spot.y = INIT_Y;

   pre_ed_list = XVaCreateNestedList(0, XNFontSet,fontset,
				 XNSpotLocation, &spot,
				 XNForeground, WhitePixel(dpy,screen),
				 XNBackground, BlackPixel(dpy,screen),
				 NULL);

   ic = XCreateIC(im,
		  XNInputStyle, best_style,
		  XNFocusWindow, win,
		  XNClientWindow, win,
		  XNPreeditAttributes, pre_ed_list,
		  XNStatusAttributes, status_list,
		  NULL);
   XFree(pre_ed_list);
   XFree(status_list);
   if (ic == NULL) {
      (void)fprintf(stderr, "Cannot create input context.\n");
      exit(1);
   }

   XGetICValues(ic, XNFilterEvents, &im_event_mask, NULL);
   XSelectInput(dpy,win, ExposureMask | FocusChangeMask | KeyPressMask |
		StructureNotifyMask | im_event_mask);
   XSetICFocus(ic);

   XMapWindow(dpy,win);

   while(1) {
      int len;
      KeySym keysym;
      Status status;
      Bool redraw = False;

      XNextEvent(dpy, &event);
      if (XFilterEvent(&event, None))
	 continue;

   switch (event.type) {
      case Expose:
	 if (event.xexpose.count == 0)
	    XwcDrawString(dpy, win, fontset, gc, INIT_X, INIT_Y, wc_string,
			  str_len);
         break;
      case FocusIn:
	 if (best_style & XIMPreeditPosition)
	    SetSpotLocation(fontset, ic, wc_string, str_len);
         XSetICFocus(ic);
         break;
      case FocusOut:
         XUnsetICFocus(ic);
         break;
      case KeyPress:
	 len = XmbLookupString(ic, &event, mb_buffer, buf_len, &keysym, &status);
	 if (len)
	    len = mbstowcs(buffer, mb_buffer, buf_len);
	 /*
	 len = XwcLookupString(ic, &event, buffer, buf_len, &keysym, &status);
	 */
	 if (status == XBufferOverflow){
	    buf_len = len;
	    buffer = (wchar_t *)realloc((char*)buffer,
					buf_len *sizeof(wchar_t));
            len = XwcLookupString(ic, &event, buffer, buf_len, &keysym,
				  &status);
         }

	 redraw = False;

	 switch (status) {
	    case XLookupNone:
	       break;
            case XLookupKeySym:
	    case XLookupBoth:
	       if ((keysym == XK_Delete) || (keysym == XK_BackSpace)){
		  if (str_len > 0) str_len --;
		  redraw = True;
		  break;
	       }
	       if (keysym == XK_Return) exit(0);
	       if (status == XLookupKeySym) break;
            case XLookupChars:
	       for (i=0;i < len; i++)
		  wc_string[str_len++] = buffer[i];
               redraw = True;
	       break;
         }
	 if (redraw) {
	    XClearWindow(dpy, win);
	    XwcDrawString(dpy, win, fontset, gc, INIT_X, INIT_Y, wc_string,
			  str_len);
         }
	 if (best_style & XIMPreeditPosition)
	    SetSpotLocation(fontset, ic, wc_string, str_len);
	 break;
      case ConfigureNotify:
	 if (best_style & XIMPreeditArea) {
	    preedit_area.width = event.xconfigure.width * 4/5;
	    preedit_area.height = 0;
	    GetPreferredGeometry(ic, XNPreeditAttributes, &preedit_area);
	    preedit_area.x = event.xconfigure.width - preedit_area.width;
	    preedit_area.y = event.xconfigure.height - preedit_area.height;
	    SetGeometry(ic, XNPreeditAttributes, &preedit_area);
         }
	 if (best_style & XIMStatusArea) {
	    status_area.width = event.xconfigure.width * 4/5;
	    status_area.height = 0;
	    GetPreferredGeometry(ic, XNStatusAttributes, &status_area);
	    status_area.x = event.xconfigure.width - status_area.width;
	    status_area.y = event.xconfigure.height - status_area.height;
	    SetGeometry(ic, XNStatusAttributes, &status_area);
         }
	 break;
      }
   }
}


Sender: Walter Gillette (walter@MathWorks.COM)

I haven't done this, but can recommend the O'Reilly series of books on X as a
useful reference (published by O'Reilly & Assoc).  Vol 1 has a discussion of
i18n.
Technical Details
Message-ID: <2c0ie9$1k9@rhino.cis.vutbr.cz>
Path: arc1-ca.pugleaf.net!gmd.de!xlink.net!howland.reston.ans.net!paladin.american.edu!news.univie.ac.at!aci.cvut.cz!rhino.cis.vutbr.cz!gateway

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: 110cdc,d2c574a920b91741,start
X-Google-Attributes: gid110cdc,public
X-Google-ArrivalTime: 1993-11-12 09:51:05 PST
Path: arc1-ca.pugleaf.net!gmd.de!xlink.net!howland.reston.ans.net!paladin.american.edu!news.univie.ac.at!aci.cvut.cz!rhino.cis.vutbr.cz!gateway
From: jbowyer@cis.vutbr.cz (Bowyer Jeff)
Newsgroups: bit.software.international
Subject: CA: Motif 1.2 and X11R5 for I18N
Date: 12 Nov 1993 18:51:05 +0100
Organization: Technical University of Brno, Czech Republic
Lines: 445
Sender: root@rhino.cis.vutbr.cz
Approved: insoft-l-moderator@cis.vutbr.cz
Message-ID: <2c0ie9$1k9@rhino.cis.vutbr.cz>
Reply-To: <insoft-l@cis.vutbr.cz>