(3)

NAME
XfwfPager

DESCRIPTION
The Pager widget displays one page from a long text. A dog's ear in the corner allows flipping pages. This is an alternative to scrolled texts, meant for material that are preferrably read a page at a time. The Pager can operate in two modes, depending on the setting of the lines resource. If lines is 0, as many lines are displayed as will fit in the widget. If lines is positive, that many lines will be displayed. In the latter case, the widget will also try to scale the font (provided the font is scalable).

  Public variables
XfwfPager
Name | Class | Type | Default
XtNtext | XtCText | String | NULL
XtNfontFamily | XtCFontFamily | String | NULL
XtNroman | XtCRoman | FontStruct | guess_roman
XtNitalic | XtCItalic | FontStruct | guess_italic
XtNbold | XtCBold | FontStruct | guess_bold
XtNlines | XtCLines | Int | 0
XtNwrap | XtCWrap | Boolean | False
XtNbaseline | XtCBaseline | Float | "1.2"
XtNmargin | XtCMargin | Int | 5
XtNforeground | XtCForeground | Pixel | "black"

XtNtext
    The text that is displayed can either be given directly as a resource, or it can be input from a file or a pipe. The text can include newlines and in the future probably also escape sequences to switch between roman, italic and bold text. Form-feed characters can be used to force the start of a new page. If the text starts with an atsign (@@) the rest of the text is interpreted as a file name. The file will only be read only once and the contents are held in memory. The file is searched in the current directory first and, if that fails, with a call to XtResolvePathname(). If the text starts with an inverted quote (`), the rest of the text is considered a command that will be passed to popen(). The output of the command is stored in memory and used as the text to display.

    String  text = NULL

XtNfontFamily
    The widget can infer roman, italic and bold variants from the font string that is given for the fontFamily resource. It is also possible to set the roman, italic and bold fonts directly. The fontFamily should be a pattern like "*-cg times-*-*". Especially the two entries after the family name should not be filled in, since they will be used by the automatic font selection.

    String  fontFamily = NULL

XtNroman
    The font that is used for roman text can be inferred from the fontFamily resource or it can be set explicitly. Note that, if the font is scalable (recommended) and the lines resources is positive, the actual point size used will depend on the size of the widget.

    <FontStruct> XFontStruct * roman = <CallProc>guess_roman

XtNitalic
    If the italic resource is not set, the italic font will be inferrred from the fontFamily string, or if that is empty, it will be copied from the roman font. In the current implementation, there is no support yet for italicized text.

    <FontStruct> XFontStruct * italic = <CallProc>guess_italic

XtNbold
    The bold font will by default be inferred from the fontFamily resource or if thatis empty, it will be the same as the roman font. In the current implementation, there is no support yet for bold text.

    <FontStruct> XFontStruct * bold = <CallProc>guess_bold

XtNlines
    The lines resource can be set to a positive value, to force the widget to display a fixed number of lines, whatever its size. This can give strange results when the font is not scalable. If lines <= 0, as many lines are displayed as will fit.

    int  lines = 0

XtNwrap
    Someday, the widget might support yet another mode of display, namely wrapping text. In this mode, lines are broken between words if they don't fit on one line. Newlines are ignored, unless there are two in a row.

    Boolean  wrap = False

XtNbaseline
    The interline spacing depends on the font. The baseline resource specifies how much the normal baseline is stretched (or shrunk). A value of 1 corresponds to a baseline equal to the font's ascent plus the font's descent. Note that setting lines to a positive value without also using a scalable font, will mess up the baselines, because the widget will still try to draw the requested number of lines.

    float  baseline = <String>"1.2"

XtNmargin
    The margin resource gives the number of pixels that must be left blank above and to the left of the text.

    int  margin = 5

XtNforeground
    The foreground color is the color the text is drawn in. By default, this widget uses black letters on a white background.

    Pixel  foreground = <String>"black"

XtNbackground_pixel
    The background resource is therefore given the default "white", instead of the usual XtDefaultBackground, since that is not guaranteed to produce white.

     background_pixel = <String>"white"

XtNframeType
    The frame type is by default set to sunken.

     frameType = XfwfSunken
    XfwfBoard
    Name | Class | Type | Default
    XtNabs_x | XtCAbs_x | Int | 0
    XtNrel_x | XtCRel_x | Float | "0.0"
    XtNabs_y | XtCAbs_y | Int | 0
    XtNrel_y | XtCRel_y | Float | "0.0"
    XtNabs_width | XtCAbs_width | Int | 0
    XtNrel_width | XtCRel_width | Float | "1.0"
    XtNabs_height | XtCAbs_height | Int | 0
    XtNrel_height | XtCRel_height | Float | "1.0"
    XtNhunit | XtCHunit | Float | "1.0"
    XtNvunit | XtCVunit | Float | "1.0"
    XtNlocation | XtCLocation | String | NULL
    XfwfFrame
    Name | Class | Type | Default
    XtNcursor | XtCCursor | Cursor | None
    XtNframeType | XtCFrameType | FrameType | XfwfRaised
    XtNframeWidth | XtCFrameWidth | Dimension | 0
    XtNframeOffset | XtCFrameOffset | Dimension | 0
    XtNshadowScheme | XtCShadowScheme | ShadowScheme | XfwfAuto
    XtNlightColor | XtCLightColor | Pixel | XtDefaultBackground
    XtNdarkColor | XtCDarkColor | Pixel | XtDefaultForeground
    XtNlightStipple | XtCLightStipple | Bitmap | NULL
    XtNdarkStipple | XtCDarkStipple | Bitmap | NULL
    XfwfCommon
    Name | Class | Type | Default
    XtNtraversalOn | XtCTraversalOn | Boolean | True
    XtNhighlightThickness | XtCHighlightThickness | Dimension | 2
    XtNhighlightColor | XtCHighlightColor | Pixel | XtDefaultForeground
    XtNhighlightPixmap | XtCHighlightPixmap | Pixmap | None
    XtNnextTop | XtCNextTop | Callback | NULL
    XtNuserData | XtCUserData | Pointer | NULL
    Composite
    Name | Class | Type | Default
    XtNchildren | XtCChildren | WidgetList | NULL
    insertPosition | XtCInsertPosition | XTOrderProc | NULL
    numChildren | XtCNumChildren | Cardinal | 0
    Core
    Name | Class | Type | Default
    XtNx | XtCX | Position | 0
    XtNy | XtCY | Position | 0
    XtNwidth | XtCWidth | Dimension | 0
    XtNheight | XtCHeight | Dimension | 0
    borderWidth | XtCBorderWidth | Dimension | 0
    XtNcolormap | XtCColormap | Colormap | NULL
    XtNdepth | XtCDepth | Int | 0
    destroyCallback | XtCDestroyCallback | XTCallbackList | NULL
    XtNsensitive | XtCSensitive | Boolean | True
    XtNtranslations | XtCTranslations | XTTranslations | NULL
    ancestorSensitive | XtCAncestorSensitive | Boolean | False
    accelerators | XtCAccelerators | XTTranslations | NULL
    borderColor | XtCBorderColor | Pixel | 0
    borderPixmap | XtCBorderPixmap | Pixmap | NULL
    background | XtCBackground | Pixel | 0
    backgroundPixmap | XtCBackgroundPixmap | Pixmap | NULL
    mappedWhenManaged | XtCMappedWhenManaged | Boolean | True
    XtNscreen | XtCScreen | Screen * | NULL

  Translations
<Key>Prior: previous_page()
<Key>BackSpace: previous_page()
<Key>Next: next_page()
<Key>space: next_page()

  Actions

previous_page
    void previous_page($, XEvent* event, String* params, Cardinal* num_params)
    {
        backwards_CB($, $, NULL);
    }

next_page
    void next_page($, XEvent* event, String* params, Cardinal* num_params)
    {
        forward_CB($, $, NULL);
    }

Importss
incl
 "flip_back.xpm"
incl
 "flip_forward.xpm"
incl
 <Xfwf/Icon.h>
incl
 <stdlib.h>
incl
 <fcntl.h>
incl
 <stdio.h>

  Private variables
The text to display may have been passed in the text resource, or it may have been read from file. In the latter case the text resource will hold the file name instead of the text. The private variable fulltext will hold the real text, whether stored in the text resource or read from file.

String  fulltext
page is a list of indexes into fulltext that points to the start of each page. It is updated whenever the size of a page changes. page[0] is unused, since the first page will be numbered `1'. The end of the text is marked with page[i] == -1

int * page
The current page number is held in pageno. Asnoted above, pages are numbered from 1.

int  pageno
The dog's ear in the lower right corner actually consists of two icons.

Widget  flip_back
Widget  flip_forward
The full font names of the three fonts (if known) are stored in private variables, so they can be changed by the scale_fonts function, in search of scaled versions of the fonts.

String  roman_name
String  italic_name
String  bold_name
Three GCs are used to draw the text in three different fonts.

GC  romangc
GC  italicgc
GC  boldgc
The baseline distance in pixels is computed from the font's height times the value of baseline.

int  baselineskip
The two icons that make up the dog's ear.

Icon  f_back
Icon  f_forward

  Methods
The initialize method uses a utility function init_text to set the private variables. The same function is also used by set_values. Another utility function is used to try to change the font size when lines is set to a positive value. The dog's ear is implemented as a pair of icons. Callbacks will be attached to the icons.
initialize(Widget  request, $, ArgList  args, Cardinal * num_args)
{
    int status;
    $f_back.attributes.valuemask = XpmSize;
    status = XpmCreatePixmapFromData
	(XtDisplay($), DefaultRootWindow(XtDisplay($)), flip_back,
	 $f_back.pixmap, $f_back.mask, $f_back.attributes);
    switch (status) {
    case XpmNoMemory: XtError("Out of memory");
    case XpmColorFailed: XtError("Failed to allocate color for pixmap");
    case XpmColorError: XtWarning("Not all pixmap colors found");
    default: ; /* skip */
    }
    $flip_back = XtVaCreateManagedWidget
	("_flip_back", xfwfIconWidgetClass, $,
	 XtNlocation, "1.0-50 1.0-50 50 50", XtNimage, $f_back,
	 XtNhighlightThickness, 0, XtNtraversalOn, False, NULL);
    XtAddCallback($flip_back, XtNactivate, backwards_CB, $);
    $f_forward.attributes.valuemask = XpmSize;
    status = XpmCreatePixmapFromData
	(XtDisplay($), DefaultRootWindow(XtDisplay($)), flip_forward,
	 $f_forward.pixmap, $f_forward.mask, $f_forward.attributes);
    switch (status) {
    case XpmNoMemory: XtError("Out of memory");
    case XpmColorFailed: XtError("Failed to allocate color for pixmap");
    case XpmColorError: XtWarning("Not all pixmap colors found");
    default: ; /* skip */
    }
    $flip_forward = XtVaCreateManagedWidget
	("_flip_forward", xfwfIconWidgetClass, $,
	 XtNlocation, "1.0-50 1.0-50 50 50", XtNimage, $f_forward,
	 XtNhighlightThickness, 0, XtNtraversalOn, False, NULL);
    XtAddCallback($flip_forward, XtNactivate, forward_CB, $);
    create_romangc($);
    create_italicgc($);
    create_boldgc($);
    $baselineskip = 0.5 + $baseline * ($roman->ascent + $roman->descent);
    $fulltext = NULL;
    $page = NULL;
    init_text($);
    split_text($);
    if ($lines > 0) scale_fonts($);
}
The set_values method calls init_text for most changes. After that, the widget will have to be drawn again. All string resources are copied to newly allocated space on the heap, so the caller can use local variables as arguments to XtVaSetValues.
Boolean  set_values(Widget  old, Widget  request, $, ArgList  args, Cardinal * num_args)
{
    Boolean need_redisplay = False;
    if ($old$fontFamily != $fontFamily) {
	XtFree($old$fontFamily);
	$fontFamily = XtNewString($fontFamily);
	XFreeFont(XtDisplay($), $roman);
	XFreeFont(XtDisplay($), $italic);
	XFreeFont(XtDisplay($), $bold);
	(void) infer_roman($);
	(void) infer_italic($);
	(void) infer_bold($);
    }
    if ($old$text != $text) {
	XtFree($old$text);
	$text = XtNewString($text);
	init_text($);
	split_text($);
	need_redisplay = True;
    }
    if ($old$roman != $roman
	|| $old$italic != $italic
	|| $old$bold != $bold
	|| $old$lines != $lines
	|| $old$wrap != $wrap
	|| $old$baseline != $baseline
	|| ($old$width != $width  $lines == 0)
	|| ($old$height != $height  $lines == 0)) {
	split_text($);
	need_redisplay = True;
    }
    if ($old$height != $height  $lines > 0) {
	scale_fonts($);
	need_redisplay = True;
    }
    return need_redisplay;
}
When the widget changes size, the font may change, in the case that lines is positive.
resize($)
{
    #resize($);
    if ($lines > 0) scale_fonts($); else split_text($);
}
The expose method draws the text of the current page into the widget. It can operate in two modes, depending on the setting of the wrap resource. If wrap is False, the lines are broken only at newline characters, even if that would mean that a part of the line disappears off the right edge of the window. On the other hand, if wrap is True, single newline characters are treated as spaces and only double newlines will force a line break. In this mode, the function will try to find line breaks at spaces in the text. The expose method also adds the current page number at the bottom of the window. Note that the expose method does not have to look at the lines resource to limit the number of lines on the page, since presumably the baseline and the font size have already been set to such values that exactly the right amount of lines will fit on the page. Drawing text will stop at 50 pixels from the bottom, to leave room for the dog's ear and the page number.

expose($, XEvent * event, Region  region)
{
    Region reg;
    XRectangle rect;
    Position y;
    char *p, *q, h[20];
    Display *dpy = XtDisplay($);
    Window win = XtWindow($);
    if (! XtIsRealized($)) return;
    if (! $fulltext) { #expose($, event, region); return; }
    $compute_inside($, rect.x, rect.y, rect.width, rect.height);
    reg = XCreateRegion();
    XUnionRectWithRegion(rect, reg, reg);
    if (region) XIntersectRegion(reg, region, reg);
    XSetRegion(dpy, $romangc, reg);
    /* XSetRegion(dpy, $italicgc, reg); */
    /* XSetRegion(dpy, $boldgc, reg); */
    y = $margin + $baselineskip - $roman->descent;
    if ($wrap) {
        /* wrapping mode not implemented yet */
    } else {
        p = $fulltext + $page[$pageno];
        while (True) {
            if (y + $roman->descent >= rect.y + rect.height - 50) break;
            for (q = p; *q != '\0'  *q != '\n'  *q != '\f'; q++) ;
            XDrawImageString(dpy, win, $romangc, rect.x+$margin, y, p, q-p);
            if (*q == '\0' || *q == '\f') break;
            y += $baselineskip;
            p = q + 1;
        }
    }
    /* Draw page number */
    sprintf(h, "%d", $pageno);
    XDrawImageString(dpy, win, $romangc, rect.x + rect.width/2, rect.y +
		     rect.height - $roman->descent, h, strlen(h));
    XSetClipMask(dpy, $romangc, None);
    /* XSetClipMask(dpy, $italicgc, None); */
    /* XSetClipMask(dpy, $boldgc, None); */
    #expose($, event, region);
}

Utilities
read_from_file opens a file and reads its contents into $fulltext, which is dynamically allocated. def INCREMENT = 2048 def mrealloc(ptr, size) = (void *)XtRealloc ((char *)ptr ,size )
read_from_file($, String  filename)
{
    int fd, len = 0, nbytes;
    if ((fd = open(filename, O_RDONLY)) < 0) {
	perror(filename);
	return;
    }
    do {
	$fulltext = mrealloc($fulltext, len + INCREMENT + 1);
	nbytes = read(fd, $fulltext + len, INCREMENT);
	if (nbytes < 0) perror(filename); else len += nbytes;
    } while (nbytes > 0);
    $fulltext[len] = '\0';
    (void) close(fd);
}
read_from_pipe works almost like read_from_file, except that it read from a pipe instead of a file.
read_from_pipe($, String  cmd)
{
    int len = 0, nbytes;
    FILE *stream;
    if ((stream = popen(cmd, "r")) == NULL) {
	perror(cmd);
	return;
    }
    do {
	$fulltext = mrealloc($fulltext, sizeof(char) * (len + INCREMENT + 1));
	nbytes = fread($fulltext + len, sizeof(char), INCREMENT, stream);
	if (nbytes < 0) perror(cmd); else len += nbytes;
    } while (nbytes > 0);
    $fulltext[len] = '\0';
    (void) pclose(stream);
}
init_text initializes the private variables after a change to one of the resources. It starts by freeing previously allocated memory. Then it initializes fulltext.
init_text($)
{
    XtFree($fulltext); $fulltext = NULL;
    XtFree((char*) $page); $page = NULL;
    if ($text == NULL) return;
    /*
     * Initialize $fulltext
     */
    switch ($text[0]) {
    case '@': read_from_file($, $text + 1); break;
    case '`': read_from_pipe($, $text + 1); break;
    default: $fulltext = XtNewString($text);
    }
}
split_text splits fulltext into pages, by setting the indices of each page in page. The way in which that is done, depends on the setting of the wrap and lines resources. Currently, wrapping is not supported.
split_text($)
{
    int i, j, n, h;
    Position x, y;
    Dimension wd, ht;
    char prev = '\0';
    $page = mrealloc($page, 3 * sizeof($page[0]));
    $page[1] = 0;
    j = 2;
    /* Wrapping is not implemented yet */
    if ($lines > 0  $fulltext != NULL) {
	/* Count lines until n == $lines */
	n = 0;
	for (i = 0; $fulltext[i]; prev = $fulltext[i], i++) {
	    if (prev == '\n') {
		n++;
		if (n == $lines) {
		    $page = mrealloc($page, (j+2) * sizeof($page[0]));
		    $page[j++] = i;
		    n = 0;
		}
	    }
	}
    } else if ($fulltext != NULL) {
	/* Determine page length with actual height of the text */
	$compute_inside($, x, y, wd, ht);
	h = y + $margin + $baselineskip;
	ht = y + ht - 50;
	for (i = 0; $fulltext[i]; prev = $fulltext[i], i++) {
	    if (prev == '\n') {
		h += $baselineskip;
		if (h + $roman->descent >= ht) {
		    $page[j++] = i;
		    h = y + $margin + $baselineskip;
		}
	    }
	}
    }
    $page[j] = -1;
    $pageno = 1;
}
When the widget's size changes while lines is set, or when lines itself changes, the widget tries to shrink or enlarge the fonts to still be able to display the same number of lines. If the fonts cannot change (because they are not scalable), the baseline will be changed instead. This may produce strange results, even to the extent of overlapping lines of text.
scale_fonts($)
{
    Position x, y;
    Dimension w, h;
    int pixels;
    char s[250], *p;
    XFontStruct *fs;
    $compute_inside($, x, y, w, h);
    $baselineskip = (h - 50 - $margin) / $lines;
    if ($roman_name == NULL) { /* Font name is unknown */
        $baseline = $baselineskip / (float) ($roman->ascent + $roman->descent);
        return;
    }
    p = strstr($roman_name, "-0-0-0-0-");
    if (p == NULL) { /* Font is not scalable */
        $baseline = $baselineskip / (float) ($roman->ascent + $roman->descent);
        return;
    }
    pixels = $baselineskip/$baseline;
    *p = '\0';
    (void) sprintf(s, "%s-%d-*-*-*-%s", $roman_name, pixels, p + 9);
    *p = '-';
    /* (void) fprintf(stderr, "scaled roman = %s\n", s); */
    if ((fs = XLoadQueryFont(XtDisplay($), s)) != NULL) {
        XFreeFont(XtDisplay($), $roman);
        $roman = fs;
        create_romangc($);
    }
    if ($italic_name != NULL) {
        p = strstr($italic_name, "-0-0-0-0-");
        if (p != NULL) {
            *p = '\0';
            (void) sprintf(s, "%s-%d-*-*-*-%s", $italic_name, pixels, p + 9);
            *p = '-';
	    /* (void) fprintf(stderr, "scaled italic = %s\n", s); */
            if ((fs = XLoadQueryFont(XtDisplay($), s)) != NULL) {
                XFreeFont(XtDisplay($), $italic);
                $italic = fs;
                create_italicgc($);
            }
        }
    }
    if ($bold_name != NULL) {
        p = strstr($bold_name, "-0-0-0-0-");
        if (p != NULL) {
            *p = '\0';
            (void) sprintf(s, "%s-%d-*-*-*-%s", $bold_name, pixels, p + 9);
            *p = '-';
	    /* (void) fprintf(stderr, "scaled bold = %s\n", s); */
            if ((fs = XLoadQueryFont(XtDisplay($), s)) != NULL) {
                XFreeFont(XtDisplay($), $bold);
                $bold = fs;
                create_boldgc($);
            }
        }
    }
}
create_romangc($)
{
    XGCValues val;
    XtGCMask mask = GCForeground | GCBackground | GCFont;
    if ($romangc != NULL) XtReleaseGC($, $romangc);
    val.foreground = $foreground;
    val.background = $background_pixel;
    val.font = $roman->fid;
    $romangc = XtGetGC($, mask, val);
}
create_italicgc($)
{
    XGCValues val;
    XtGCMask mask = GCForeground | GCBackground | GCFont;
    if ($italicgc != NULL) XtReleaseGC($, $italicgc);
    val.foreground = $foreground;
    val.background = $background_pixel;
    val.font = $italic->fid;
    $italicgc = XtGetGC($, mask, val);
}
create_boldgc($)
{
    XGCValues val;
    XtGCMask mask = GCForeground | GCBackground | GCFont;
    if ($boldgc != NULL) XtReleaseGC($, $boldgc);
    val.foreground = $foreground;
    val.background = $background_pixel;
    val.font = $bold->fid;
    $boldgc = XtGetGC($, mask, val);
}
The forward_CB callback is attached to the `flip_forward' icon. The callback increments the page number and causes the corresponding page to be displayed, provided the current page isn't already the last one.
forward_CB(Widget  w, XtPointer  client_data, XtPointer  call_data)
{
    Widget $ = (Widget) client_data;
    if ($page[$pageno+1] >= 0) {
	$pageno++;
	XClearWindow(XtDisplay($), XtWindow($));
	$expose($, NULL, NULL);
    }
}
The `flip_back' icon has gotten the backwards_CB callback. The callback decrements the page number and causes the corresponding page to be displayed, provided the page number isn't already 1.
backwards_CB(Widget  w, XtPointer  client_data, XtPointer  call_data)
{
    Widget $ = (Widget) client_data;
    if ($pageno > 1) {
	$pageno--;
	XClearWindow(XtDisplay($), XtWindow($));
	$expose($, NULL, NULL);
    }
}
To construct the roman font from the fontFamily string, the string is passed to XListFonts. The returned list is scanned for a font that is `medium' or `normal' and `r' (i.e., roman). If none is found, the list is scanned again for one that is `r' of any weight. If that still doesn't produce a font, the first font from the list is taken. If there is no fontFamily resource, or XListFonts returns no matching fonts, the function returns False.
Boolean  infer_roman($)
{
    char **fonts;
    int n, i;
    XtFree($roman_name); $roman_name = NULL;
    if ($fontFamily == NULL) return False;
    fonts = XListFonts(XtDisplay($), $fontFamily, 1000, n);
    if (n == 0) return False;
    for (i = 0; i < n; i++)
	if (strstr(fonts[i], "normal-r") || strstr(fonts[i], "medium-r")) {
	    $roman_name = XtNewString(fonts[i]);
	    break;
	}
    if ($roman_name == NULL)
	for (i = 0; i < n; i++)
	    if (strstr(fonts[i], "-r-")) {
		$roman_name = XtNewString(fonts[i]);
		break;
	    }
    if ($roman_name == NULL)
	$roman_name = XtNewString(fonts[0]);
    $roman = XLoadQueryFont(XtDisplay($), $roman_name);
    XFreeFontNames(fonts);
    /* (void) fprintf(stderr, "roman name = %s\n", $roman_name); */
    return True;
}
To construct the italic font from the fontFamily string, the string is passed to XListFonts. The returned list is scanned for a font that is `medium' or `normal' and `i' (i.e., italic) or `o' (i.e., oblique). If none is found, the list is scanned again for one that is `i' or `o' of any weight. If that still doesn't produce a font, the first font from the list is taken. If there is no fontFamily resource, or XListFonts returns no matching fonts, the function returns False.
Boolean  infer_italic($)
{
    char **fonts;
    int n, i;
    XtFree($italic_name); $italic_name = NULL;
    if ($fontFamily == NULL) return False;
    fonts = XListFonts(XtDisplay($), $fontFamily, 1000, n);
    if (n == 0) return False;
    for (i = 0; i < n; i++)
	if (strstr(fonts[i], "normal-i") || strstr(fonts[i], "medium-i")
	    || strstr(fonts[i], "normal-o") || strstr(fonts[i], "medium-o")) {
	    $italic_name = XtNewString(fonts[i]);
	    break;
	}
    if ($italic_name == NULL)
	for (i = 0; i < n; i++)
	    if (strstr(fonts[i], "-r-") || strstr(fonts[i], "-o-")) {
		$italic_name = XtNewString(fonts[i]);
		break;
	    }
    if ($italic_name == NULL)
	$italic_name = XtNewString(fonts[0]);
    $italic = XLoadQueryFont(XtDisplay($), $italic_name);
    XFreeFontNames(fonts);
    /* (void) fprintf(stderr, "italic name = %s\n", $italic_name); */
    return True;
}
To construct the bold font from the fontFamily string, the string is passed to XListFonts. The returned list is scanned for a font that is `bold' and `r' (i.e., roman). If none is found, the list is scanned again for one that is `bold' of any style. If that still doesn't produce a font, the first font from the list is taken. If there is no fontFamily resource, or XListFonts returns no matching fonts, the function returns False.
Boolean  infer_bold($)
{
    char **fonts;
    int n, i;
    XtFree($bold_name); $bold_name = NULL;
    if ($fontFamily == NULL) return False;
    fonts = XListFonts(XtDisplay($), $fontFamily, 1000, n);
    if (n == 0) return False;
    for (i = 0; i < n; i++)
	if (strstr(fonts[i], "-bold-r-")) {
	    $bold_name = XtNewString(fonts[i]);
	    break;
	}
    if ($bold_name == NULL)
	for (i = 0; i < n; i++)
	    if (strstr(fonts[i], "-bold-")) {
		$bold_name = XtNewString(fonts[i]);
		break;
	    }
    if ($bold_name == NULL)
	$bold_name = XtNewString(fonts[0]);
    $bold = XLoadQueryFont(XtDisplay($), $bold_name);
    XFreeFontNames(fonts);
    /* (void) fprintf(stderr, "bold name = %s\n", $bold_name); */
    return True;
}
guess_bold is a resource default procedure that tries to infer the bold variant of the family indicated by fontFamily, or if that fails, copies the roman resource.
guess_bold($, int  offset, XrmValue * value)
{
    $bold_name = NULL;
    if (infer_bold($))
	value->addr = (XtPointer) $bold;
    else
	value->addr = (XtPointer) $roman;
}
guess_italic($, int  offset, XrmValue * value)
{
    $italic_name = NULL;
    if (infer_italic($))
	value->addr = (XtPointer) $italic;
    else
	value->addr = (XtPointer) $roman;
}
The guess_roman routine first tries to construct the roman font from the fontFamily resource and if that fails it loads the `fixed' font, which should always be available.
guess_roman($, int  offset, XrmValue * value)
{
    static XFontStruct *fixed;
    $roman_name = NULL;
    if (infer_roman($))
	value->addr = (XtPointer) $roman;
    else {
	fixed = XLoadQueryFont(XtDisplay($), "fixed");
	value->addr = (XtPointer) fixed;
    }
}