if (!XmStringInitContext (&context, str)) {
/* compound strings from GetValues still need to be freed! */
XmStringFree (str);
XtWarning ("Can't convert compound string.");
return;
}
/* p keeps a running pointer thru buf as text is read */
p = buf;
while (XmStringGetNextSegment (context, &text, &tag,
&direction, &separator)) {
/* copy text into p and advance to the end of the string */
p += (strlen (strcpy (p, text)));
if (separator == True) { /* if there's a separator ... */
*p++ = '0;
*p = 0; /* add newline and null−terminate */
}
XtFree (text); /* we're done with the text; free it */
}
XmStringFreeContext (context);
XmStringFree (str);
printf ("Compound string:0s0, buf);
}
20.4 Working With Font Lists
As we have demonstrated, font lists can be set in a resource file. If your application is robust enough to handle any
particular font that the user may specify, you are encouraged to use fallback resources and the application defaults
files for all font list specifications. This technique simplifies maintenance for your application, as you do not have to
open fonts, maintain handles to them, and free them. If you are writing an internationalized application, you should
only specify font lists in resource files so that you can specify different fonts and/or font sets in the resource files for
different locales.
However, if you specifically don't want the user to override your font specifications, you can hard−code fonts within
the application using various Motif routines to create a font list. In this case, you are taking on the responsibility of
creating, maintaining, and destroying fonts as necessary. Motif also provides routines that allow you to retrieve
information about a font list.
20.4.1 Creating Font Lists
All of the font list creation functions deal with a font list object of type XmFontList. This type is intended to be
opaque, so you should not attempt to access the internal fields of the data structure. If you need information about the
fonts in a font list, you can use the routines for querying a font list that we are going to describe.
The Motif API for font lists has changed significantly in Motif 1.2 to support the new XFontSet abstraction. The
Motif 1.1 routines exist for backwards compatibility, but they are now obsolete. In Motif 1.2, each item in a font list
specifies an XmFontListEntry and an associated tag, while in Motif 1.1 each item specifies a font and a character
set tag. The XmFontListEntry type is an opaque type that can specify either a font or a font set.
The process for creating a font list involves creating individual font list entries and then appending these entries to a
font list. the source code shows a program that produces the same output as the source code but now the font list is
20 Compound Strings 20.4 Working With Font Lists
579
hard−coded in the program. XtSetLanguageProc() is only available in X11R5; there is no corresponding
function in X11R4. XmFontListEntryCreate() is only available in Motif 1.2; there is no corresponding
function in Motif 1.1. XmFontListAppendEntry() is only available in Motif 1.2; XmFontListCreate()
and XmFontListAdd() are the corresponding functions in Motif 1.1.
/* fontlist.c −− demonstrate how to create, add to, and destroy
* font lists. The fonts and text displayed are hardcoded in
* this program and cannot be overriden by user resources.
*/
#include <Xm/Label.h>
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel;
XtAppContext app;
XmString s1, s2, s3, text, tmp;
XmFontListEntry entry1, entry2, entry3;
XmFontList fontlist;
String string1 = "This is a string ",
string2 = "that contains three ",
string3 = "separate fonts.";
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0,
&argc, argv, NULL, NULL);
entry1 = XmFontListEntryLoad (XtDisplay (toplevel),
"−*−courier−*−r−*−−*−120−*", XmFONT_IS_FONT, "TAG1");
entry2 = XmFontListEntryLoad (XtDisplay (toplevel),
"−*−courier−bold−o−*−−*−140−*", XmFONT_IS_FONT, "TAG2");
entry3 = XmFontListEntryLoad (XtDisplay (toplevel),
"−*−courier−medium−r−*−−*−180−*", XmFONT_IS_FONT, "TAG3");
fontlist = XmFontListAppendEntry (NULL, entry1);
fontlist = XmFontListAppendEntry (fontlist, entry2);
fontlist = XmFontListAppendEntry (fontlist, entry3);
XmFontListEntryFree (&entry1);
XmFontListEntryFree (&entry2);
XmFontListEntryFree (&entry3);
s1 = XmStringCreate (string1, "TAG1");
s2 = XmStringCreate (string2, "TAG2");
s3 = XmStringCreate (string3, "TAG3");
/* concatenate the 3 strings on top of each other, but we can only
* do two at a time. So do s1 and s2 onto tmp and then do s3.
*/
tmp = XmStringConcat (s1, s2);
text = XmStringConcat (tmp, s3);
XtVaCreateManagedWidget ("label", xmLabelWidgetClass, toplevel,
XmNlabelString, text,
XmNfontList, fontlist,
NULL);
XmStringFree (s1);
XmStringFree (s2);
XmStringFree (s3);
20 Compound Strings 20.4 Working With Font Lists
580
XmStringFree (tmp);
XmStringFree (text);
XmFontListFree (fontlist);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
This program creates font list entries for three fonts, appends the entries to a font list, and uses the resulting font list to
specify the XmNfontList resource of a Label widget. The compound strings are created using the same tags as the
font list entries, so they are displayed in the appropriate fonts.
In the source code we create the font list entries using XmFontListEntryLoad(), which takes the following
form:
XmFontListEntry
XmFontListEntryLoad(display, font_name, type, tag)
Display *display;
char *font_name;
XmFontType type;
char *tag;
This routine loads the font or creates the font set specified by font_name. The function uses Xt resource converters
to convert the string name of the font to the appropriate type. The type parameter specifies whether the font name is
a font or a font set; it can have the value XmFONT_IS_FONT or XmFONT_IS_FONT_SET. The tag is associated
with the font list entry. If the routine can load or create the specified font, it allocates and returns an
XmFontListEntry, which the application must free using XmFontListEntryFree(). If the routine cannot
find the specified font, it returns NULL.
Once we have created the font list entries, we can use them to make a font list. XmFontListAppendEntry()
appends a font list entry to a font list. We call this routine three times to add the three entries.
XmFontListAppendEntry() takes the following form:
XmFontList
XmFontListAppendEntry(oldlist, entry)
XmFontList oldlist;
XmFontListEntry entry;
The routine adds the specified entry to the old font list and returns a new font list. If oldlist is NULL, the routine
simply creates a font list using the font list entry. Motif caches font lists, so when we add a font list entry to a font list,
the routine searches the cache for a font list that matches the new font list. If the routine finds a matching font list, it
returns that font list and increments its reference count. Otherwise, XmFontListAppendEntry() allocates space
for the new font list and caches it. The routine deallocates the storage for the old font list, but the application is
responsible for freeing the storage for the new font list using XmFontListFree().
After we add the font list entries to the font list, we don't need the individual entries, so we free them using
XmFontListEntryFree(). Notice that this routine takes an address of a font list entry, not the actual font list
entry. When Motif creates a font list entry, it does not copy the XFontStruct or XFontSet, so these items must
not be freed. If you pass a font list entry, instead of its address, to XmFontListEntryFree(), you end up freeing
the font or font set, which results in an X protocol error.
The fontlist.c program creates compound strings just like our previous examples. The strings are associated with the
same tags as the font list entries, so the strings are rendered using the appropriate fonts. The program sets the
XmNfontList resource of the Label widget, so the fonts are hard−coded in the application and cannot be modified
20 Compound Strings 20.4 Working With Font Lists
581
using a resource file. When a font list is assigned to a widget, the widget copies the list using XmFontListCopy().
After the resource has been specified, the program no longer needs the font list, so it frees it using
XmFontListFree().
We used XmFontListEntryLoad() to both load the font and create a font list entry. Alternatively, we could have
loaded the fonts using a routine like XLoadQueryFont() and then called XmFontListEntryCreate() to
create the font list entries. This routine takes the following form:
XmFontListEntry
XmFontListEntryCreate(tag, type, font)
char *tag
XmFontType type;
XtPointer font;
The type parameter specifies whether the specified font is an XFontStruct or an XFontSet. You can load a
font using XLoadQueryFont(). Use XCreateFontSet() to create a font set. (See Volume One, Xlib
Programming Manual, for more information on these routines.) XmFontListEntryCreate() allocates and
returns a font list entry; the application is responsible for freeing this entry using XmFontListEntryFree().
It is purely a matter of preference whether you use XmFontListEntryCreate() or
XmFontListEntryLoad(). In the source code we could replace our calls to XmFontListEntryLoad() with
the following code:
XFontStruct *font1, *font2, *font3;
XmFontListEntry entry1, entry2, entry3;
font1 = XLoadQueryFont (XtDisplay (toplevel),
"−*−courier−*−r−*−−*−120−*");
font2 = XLoadQueryFont (XtDisplay (toplevel),
"−*−courier−bold−o−*−−*−140−*");
font3 = XLoadQueryFont (XtDisplay (toplevel),
"−*−courier−medium−r−*−−*−180−*");
entry1 = XmFontListEntryCreate ("TAG1", XmFONT_IS_FONT, font1);
entry2 = XmFontListEntryCreate ("TAG2", XmFONT_IS_FONT, font2);
entry3 = XmFontListEntryCreate ("TAG3", XmFONT_IS_FONT, font3);
The functionality of the program is the same in either case, so which method you use really depends on whether you
want to load the fonts yourself or let the routine handle it for you.
In Motif 1.1, there are two routines for dealing with font lists. XmFontListCreate() creates a new font list with
one entry, while XmFontListAdd() adds a font to an existing font list. These routines take the following form:
XmFontList
XmFontListCreate(font, charset)
XFontStruct *font;
XmStringCharSet charset;
XmFontList
XmFontListAdd(oldlist, font, charset);
XmFontList oldlist;
XFontStruct *font;
XmStringCharSet charset;
The routines both take an XFontStruct, so you have to load the font yourself using XLoadQueryFont(). The
20 Compound Strings 20.4 Working With Font Lists
582
Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.