HOW TO RENDER XmStrings
 
 
Rendering XmStrings into a DrawingArea widget (for example) is a somewhat tough task, if you don't have good information at hand. "Good information", that is: third party books - not the ones from the OSF... 

The OSF's documentation on XmStringDraw() is (expressed carefully) inaccurate. There are a few things to note: 

  • The Graphics Context specified in the call to XmStringDraw() must have a valid font or XmStringDraw() will crash. That's because the function saves the font originaly associated with the gc then changes the font member during drawing and later restores the font member.
  • Better forget the clipping rectangle! XmStringDraw() seems to ignore it completely or even remove any clipping rectangle. Better set any clipping you need before you draw the string and then specify a NULL clipping rectangle in the call to XmStringDraw().
Conclusion: you'll need a Graphics Context with a valid font member, but how to achieve this? Here's my way of doing this. There's also another short cut to get a fontlist, but that method uses an undocumented function call, so I decided not to publish that one. The solution below uses only documented function calls and can be used either with Motif 1.1 or 1.2. 

...first some definitions... 

 XmFontList DrawingFontList;
 XGCValues gcvalues;
 XFontStruct *font, **FontList;
 XtPointer FontPtr;
#if (XmREVISION <= 1)
 XmStringCharSet CharSet;
 XmFontContext FontContext;
#else
 XmFontType FontType;
#endif
 int NrOfFonts;

 char **FontNameList;
...some other things to do... 
#if (XmREVISION <= 1)
 XmFontListInitFontContext(&FontContext, DrawingFontList);
 XmFontListGetNextFont(FontContext, &CharSet, &font);
 gcvalues.font = font->fid;
 XtFree(CharSet);
 XmFontListFreeFontContext(FontContext);
#else
 FontPtr = XmFontListEntryGetFont(DrawingFontList, &FontType);
 if ( FontType == XmFONT_IS_FONT )
     font = (XFontStruct *) FontPtr;
 else {
     NrOfFonts = XFontsOfFontSet((XFontSet) FontPtr,
                                 &FontList, &FontNameList);
     font = FontList[0];
 }
 gcvalues.font = font->fid;
#endif
Now gcvalues.font contains a valid font id derived from the font list specified in DrawingFontList. You can get a font list by either querying some other widget or by using an undocumented function call (intended for widget writers only). Did I said I don't use any undocumented call...? Depending on your employer, please follow these guidelines: OSF: forget what I said - other companies: because that undocumented call is documented here, it can't be an undocumented call, alright?! 
 DrawingFontList =
 _XmGetDefaultFontList(DrawingArea, XmLABEL_FONTLIST);
Rendering a XmString is now an easy task. One example might be: 
 XmStringDraw(XtDisplay(DrawingArea), XtWindow(DrawingArea),
              DrawingFontList, Message, DrawingGC,
              2, 2,
              500 - 4,
              XmALIGNMENT_BEGINNING,
              XmSTRING_DIRECTION_L_TO_R, NULL);
Remember to do this only in response to Expose events. 

I'm using the code above as part of another software project, so it has been proven to work with either Motif 1.1 or 1.2. In the links below you'll find the source of a complete working sample based on the code presented here in my Motif Programming Corner. This example code creates a DrawingArea and then draws a message into it in response to expose events. 

The final question (as usual): Why did the OSF not include such usefull examples with the huge documentation they are selling to people? But this will continue to be one of great questions in the history of men. 


Here you can download the source of the example. 
Next page (How to specify a font list for rendering XmStrings) 
Back to the Tips page 

Contents: Harald Albrecht (albrecht@igpm.rwth-aachen.de) 
Layout: Harald Albrecht 
Last Change: 97/08/10 (ab)