/*-------------------------------------------------------------*/
/*  File: browse.c
 *
 *  A program for browsing text files. Instead of using a
 *  Text widget, this program reads a text file and displays
 *  the contents in a Stub widget. The idea is to illustrate
 *  the Xlib text drawing functions and show how to handle
 *  different fonts. 
 *
 */
/*-------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>            /* ANSI standard string library */
#include <varargs.h>     /* UNIX-style variable argument macros */
#include <errno.h>

#include <X11/Xlib.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <Xol/OpenLook.h>

#include <Xol/FooterPane.h>
#include <Xol/ControlAre.h>
#include <Xol/ScrolledWi.h>
#include <Xol/Scrollbar.h>
#include <Xol/MenuButton.h>
#include <Xol/Stub.h>
#include <Xol/Form.h>
#include <Xol/StaticText.h>

#include <Xol/PopupWindo.h>
#include <Xol/Caption.h>
#include <Xol/TextField.h>
#include <Xol/OblongButt.h>

#include <Xol/Exclusives.h>
#include <Xol/RectButton.h>

#define WIDTH         200
#define HEIGHT        300


#define LEFT_MARGIN    4    /* Leave a 4-pixel margin */

#define SCROLL_UP    0
#define SCROLL_DOWN  1

#define MAXCHARS   512     /* Maximum length of a line    */

/* Data structure for command window that prompts for
 * a file name.
 */
typedef struct COMMAND_WINDOW
{
    Widget popup_shell;    /* ID of PopupWindowShell      */
    Widget dir_prompt;     /* "Directory:" TextField      */
    Widget file_prompt;    /* "File:" TextField           */
    Widget load_button;    /* "Load" OblongButton         */
    Widget message_area;   /* StaticText for messages     */
    int    ok_to_pop_down; /* True = OK to pop down shell */
} COMMAND_WINDOW;

static COMMAND_WINDOW fname_cmd = 
{ (Widget)0, (Widget)0, (Widget)0, (Widget)0, 
  (Widget)0, True
};

/* Structure with information about a property window */
typedef struct PROPERTY_WINDOW
{
    Widget popup_shell;    /* ID of PopupWindowShell      */
    Widget apply_button;   /* "Apply" OblongButton        */
    Widget reset_button;   /* "Reset" OblongButton        */
    Widget message_area;   /* StaticText for messages     */
    int    ok_to_pop_down; /* True = OK to pop down shell */
} PROPERTY_WINDOW;

static PROPERTY_WINDOW font_prop =
{
    (Widget)0, (Widget)0, (Widget)0, (Widget)0, True
};

/* Data structures for loading lines from text file into 
 * memory.
 */
typedef struct D_LINE      /* Holds info on each line     */
{
    struct D_LINE *prev;   /* Pointer to previous line    */
    struct D_LINE *next;   /* Pointer to next line        */
    char          *line;   /* Null-terminated line        */
    short         length;  /* Number of characters in line*/
    short         lbearing;/* Left and right edges of     */
    short         rbearing;/* rectangle covered by line   */
    short         height;  /* Height of text string       */
    short         width;   /* Width of text string        */
} D_LINE;

typedef struct D_LBUF      /* Info on entire buffer       */
{
    D_LINE        *lines;  /* First line in buffer        */
    D_LINE        *lstart; /* First line in window        */
    GC            gc;      /* GC used to display text     */
    XFontStruct   *fstruct;/* Info on current font        */
    int           font;    /* Currently selected font     */
    int           weight;  /* weight and                  */
    int           size;    /* size                        */
    int           o_font;  /* The last applied font       */
    int           o_weight;/* weight and                  */
    int           o_size;  /* size                        */
    Dimension     dwidth;  /* Width of text display area  */
    Dimension     dheight; /* Height of text display area */
    long          count;   /* How many lines in buffer    */
} D_LBUF;

static D_LBUF fbuf = { NULL,NULL, None, None, 0, 0, 0,
                       0, 0, 0, 0, 0, 0};

static int zero=0, one=1, two=2, three=3, four=4;

static  GC     theGC;   /* GC used for text output */

/* Information necessary to construct font names   */
static char *fontname[] =
{
  "courier", "helvetica", "new century schoolbook", "times"
};
static char *weight[] = { "medium", "bold" };
static char *size[] = {"100", "120", "140", "180", "240"};

/* File to be opened */
char *file_name = NULL;

/* Window id of text area */
static Window  dWin;

/* Name of application */
static char *theAppName;

static int file_not_loaded = True;


/* Callbacks and other functions used in the application */

static void handle_expose();
static void quit_action();
static void font_select();
static void wt_select();
static void size_select();

static void open_file();

static void fs_load();

static void load_file();
static void apply_font();
static void reset_font();
static void display_lines();

static void popdown_ok();

static void disp_propwin();

/* This function, defined in file ol_util.c, prepares menus */
Widget MakeMenuButton();

/* This funtion, defined later, builds an Exclusives widget
 * filled with RectButtons.
 */
Widget MakeExclusives();

/* Message area of the application's base window */
static Widget message_area;

/* Text display area--the Stub widget */
static Widget text_area;
/*-------------------------------------------------------------*/
void main(argc, argv)
int  argc;
char **argv;
{
    Widget    top_level, footer_panel, form, menu_bar, 
              scroll_win, new_menu;


    Pixel     fg, bg;
    XGCValues xgcv;

/* Create the top-level shell widget and initialize the toolkit*/       
    top_level = OlInitialize(argv[0], "Browse", NULL,
                               0, &argc, argv);

    theAppName = argv[0];


    footer_panel = XtVaCreateManagedWidget("footer",
                            footerPanelWidgetClass, top_level,
                            NULL);

    form = XtVaCreateManagedWidget("form",
                            formWidgetClass, footer_panel,
                            NULL);

/* Footer area for status and error messages */

    message_area = XtVaCreateManagedWidget("messages",
                            staticTextWidgetClass, footer_panel,
                            XtNstring,      "Initializing...",
                            XtNgravity,     WestGravity,
                            NULL);

    menu_bar = XtVaCreateManagedWidget("menubar",
                            controlAreaWidgetClass, form,
                            NULL);

/* Add the menu buttons to the menu bar */
/* Create the "File" menu -------------------------------------*/
    new_menu = MakeMenuButton("File", menu_bar, OL_OUT,
                        "Load...", open_file, (caddr_t)top_level,
                        "Quit", quit_action, NULL,
                         NULL);

/* Create the "Font Properties" menu --------------------------*/
    new_menu = MakeMenuButton("Properties", menu_bar, OL_OUT,
                  "Font",   disp_propwin,   NULL,
                  NULL);

/* Add a scrolled window and the text display area within it */
    scroll_win =  XtVaCreateManagedWidget("scrollwin",
                        scrolledWindowWidgetClass, form,
                        XtNhStepSize,           8,
                        XtNvStepSize,           8,
                        XtNyRefWidget,          menu_bar,
                        XtNyAddHeight,          True,
                        XtNxResizable,          True,
                        XtNyResizable,          True,
                        XtNyAttachBottom,       True,
                        XtNxAttachRight,        True,
                        NULL);

/* Create the Stub widget where we will display the text */
    text_area = XtVaCreateManagedWidget("stub",
                            stubWidgetClass, scroll_win,
                            XtNheight,       WIDTH,
                            XtNwidth,        HEIGHT,
                            XtNexpose,       handle_expose,
                            NULL);

/* Set up a GC to display text. First retrieve the background 
 * color from the Stub widget's resources. 
 */
    XtVaGetValues(text_area, XtNbackground, &bg,
                  NULL);

/* Assume a black foreground color */
    fg = BlackPixelOfScreen(XtScreen(text_area));

/* If the foreground and background colors are the same,
 * reset foreground to "black" and background to "white"
 */
    if(fg == bg)
    {
        bg = WhitePixelOfScreen(XtScreen(text_area));
        XtVaSetValues(text_area, XtNbackground, &bg,
                      NULL);
    }
    
/* Define a GC with these colors */
    xgcv.foreground = fg;
    xgcv.background = bg;
    fbuf.gc = XtGetGC(text_area, GCForeground | GCBackground,
                      &xgcv);
/* Realize all widgets */
    XtRealizeWidget(top_level);

/* dWin is a global variable that holds the Window id of
 * the text display area
 */
    dWin = XtWindow(text_area);

/* Event handling loop--keep processing events until done */
    XtMainLoop();
}
/*-------------------------------------------------------------*/
/*  h a n d l e _ e x p o s e
 *
 *  Expose event-handler for the text display area 
 */
static void handle_expose(w, p_event, r)
Widget w;
XEvent *p_event;
Region r;
{

/* Do nothing, if no file has been loaded */
    if(file_not_loaded) return;

/* Handle the expose event only if 'count' is 0 */
    if(p_event->xexpose.count == 0) display_lines(w);
}
/*-------------------------------------------------------------*/
/*  q u i t _ a c t i o n
 *
 *  This routine is called when the "Quit" item is selected from
 *  the "File" menu.
 */
static void quit_action(w, client_data, call_data)
Widget    w;
XtPointer client_data, call_data;
{
    XtCloseDisplay(XtDisplay(w));
    exit(0);
}
/*-------------------------------------------------------------*/
/*  l o a d _ f i l e
 *
 *  Read in file to be displayed.
 *
 */
static void load_file(filename, cw)
char           *filename;
COMMAND_WINDOW *cw;
{
    FILE        *fp;
    D_LINE      *p_l = NULL, *p_l_prev = NULL, *p_l_next;
    char        buf[MAXCHARS];
    extern char *sys_errlist[];
    
/* If a file was already loaded, first release all memory */
    if(fbuf.lines != NULL)
    {
        p_l = fbuf.lines; 
        while (p_l != NULL) 
        {
            XtFree(p_l->line);
            XtFree(p_l);
            p_l_next = p_l->next;
            p_l = p_l_next;
        }
        fbuf.count = 0;
        fbuf.lines = NULL;
        fbuf.lstart = NULL;
        file_not_loaded = True;
    }
    
/* Open the file */
    if((fp = fopen(filename, "r")) == NULL)
    {
/* In case of failure, display message */
        char emsg[80];
        sprintf(emsg, "error: %s", sys_errlist[errno]);
        XtVaSetValues(cw->message_area, 
                      XtNstring, emsg, NULL);
        cw->ok_to_pop_down = False;
        return;
    }

/* Read each line and store in linked list of D_LINE structs  */
    while((fgets(buf, MAXCHARS, fp)) != NULL)
    {
        if((p_l = (D_LINE *) XtCalloc(1, sizeof(D_LINE))) 
                                                      != NULL)
        {
            if(fbuf.lines == NULL)
            {
                fbuf.lines = p_l;
            }
            else
            {
                p_l_prev->next = p_l;
                p_l->prev = p_l_prev;
            }
        }
        else
        {
/* Allocation failed...*/
            fprintf(stderr, "Failed to allocate memory for\
line data structure...\n");
            exit(1);
        }
        p_l->length = strlen(buf) - 1; /* Exclude newline */
        buf[p_l->length] = '\0';
        if((p_l->line = XtMalloc(p_l->length+1)) == NULL)
        {
            fprintf(stderr, "Failed to allocate memory for\
line:\n%s\n", buf);
            exit(1);
        }
        strcpy(p_l->line, buf);
        p_l_prev = p_l;
        fbuf.count++;
    }

/* Display a message to tell user how many lines were loaded */
    sprintf(buf, "%d lines loaded from %s\n", fbuf.count, 
            filename);
    XtVaSetValues(message_area, XtNstring, buf, NULL);

    file_not_loaded = False;
    
/* Close the file */
    fclose(fp);

    cw->ok_to_pop_down = True;
}
/*-------------------------------------------------------------*/
/*  d i s p l a y _ l i n e s
 *
 *  Displays the lines in the text window
 */
static void display_lines(w)
Widget w;
{
    int    xpos, ypos = 0, ystart = 0, yend = fbuf.dheight;
    D_LINE *p_l;    
    XWindowAttributes xwa;
    Dimension pheight;

    
/* Draw as many lines of text as necessary */
    if(XGetWindowAttributes(XtDisplay(w), XtWindow(w), &xwa))
    {
        ystart = - xwa.y;
    }
    XtVaGetValues(XtParent(w), XtNheight, &pheight, NULL);
    yend = ystart + pheight;


    for(p_l = fbuf.lstart; p_l != NULL && ypos < yend;
        p_l = p_l->next)
    {
        xpos = LEFT_MARGIN - p_l->lbearing;
        ypos += p_l->height;
        if(ypos >= ystart)
            XDrawImageString(XtDisplay(w), dWin, fbuf.gc,
                         xpos, ypos, p_l->line, p_l->length);
    }
}
/*-------------------------------------------------------------*/
/*  o p e n _ f i l e
 *
 *  Display a "Load File" command window and let user enter the 
 *  name of the file to be loaded for browsing.
 */
static void open_file(w, client_data, call_data)
Widget    w;
XtPointer client_data, call_data;
{
    Widget upper, lower, footer, caption;
        
/* Indicate that it is ok to pop down the command widget */
    fname_cmd.ok_to_pop_down = True;

    if(fname_cmd.popup_shell == (Widget)0)
    {
/* Create the pop-up widget */
        fname_cmd.popup_shell = XtVaCreatePopupShell(
                      "PopupCommand", 
                      popupWindowShellWidgetClass, w,
                      XtNtitle,       "Load File",
                      NULL);

/* Set up callback to be called before the window pops down */
        XtAddCallback(fname_cmd.popup_shell,
                      XtNverify, popdown_ok, &fname_cmd);

/* Get the ID of the child widgets of the pop-up shell widget */
        XtVaGetValues(fname_cmd.popup_shell,
            XtNupperControlArea, &upper,
            XtNlowerControlArea, &lower,
            XtNfooterPanel,      &footer,
            NULL);

/* Create component widgets to complete the command window
 * Start with the text fields that prompt for directory and
 * file names.
 */
        caption = XtVaCreateManagedWidget("Directory",
                      captionWidgetClass, upper,
                      XtNlabel,       "Directory:",
                      NULL);

        fname_cmd.dir_prompt = XtVaCreateManagedWidget(
                    "dir_field",
                    textFieldWidgetClass, caption,
                    XtNwidth,       150,
                    XtNtraversalOn, True,
                    NULL);

        caption = XtVaCreateManagedWidget("File",
                      captionWidgetClass, upper,
                      XtNlabel,       "File:",
                      NULL);

        fname_cmd.file_prompt = XtVaCreateManagedWidget(
                    "file_field",
                    textFieldWidgetClass, caption,
                    XtNwidth,       150,
                    XtNtraversalOn, True,
                    NULL);

/* Create the Load button */
        fname_cmd.load_button = XtVaCreateManagedWidget(
                "load_button",
                oblongButtonWidgetClass, lower,
                XtNlabel,      "Load",
                XtNdefault,    True,
                NULL);

/* Add callback for the Load button */
        XtAddCallback(fname_cmd.load_button,
                 XtNselect, fs_load, &fname_cmd);

/* Create a StaticText widget to display messages */
        fname_cmd.message_area = XtVaCreateManagedWidget(
                      "message_area", 
                      staticTextWidgetClass, footer,
                      XtNalignment, OL_LEFT,
                      XtNgravity,   SouthWestGravity,
                      XtNstring,    "Waiting for file name",
                      NULL);
    }

/* Pop up the command window */
    XtPopup(fname_cmd.popup_shell, XtGrabNone);
}
/*-------------------------------------------------------------*/
/*  p o p d o w n _ o k
 *
 *  Callback for verifying if it is ok to pop down the 
 *  command window.
 */
static void popdown_ok(w, client_data, call_data)
Widget    w;
XtPointer client_data, call_data;
{
    Boolean *ok_flag = (Boolean *)call_data;
    COMMAND_WINDOW *cw = (COMMAND_WINDOW *)client_data;

/* Indicate if it's ok to pop down the command window */
    if(*ok_flag) *ok_flag = cw->ok_to_pop_down;
}
/*-------------------------------------------------------------*/
/*  f s _ l o a d
 *
 *  Callback for the "Load" button in the Load command window.
 */
static void fs_load(w, client_data, call_data)
Widget    w;
XtPointer client_data, call_data;
{
    char           *dir, *file, *file_name;
    COMMAND_WINDOW *cw = (COMMAND_WINDOW *)client_data;

/* Clear message area */
    XtVaSetValues(cw->message_area, XtNstring, " ", NULL);
    
/* Get file name from user's selection */
    XtVaGetValues(cw->dir_prompt, XtNstring, &dir, NULL);
    XtVaGetValues(cw->file_prompt, XtNstring, &file, NULL);

/* Append file name to directory name to construct 
 * full path name 
 */
    if((file_name = XtMalloc(strlen(dir) + strlen(file) + 2))
       != NULL)
    {
/* Construct file name */
        strcpy(file_name, dir);
        if(strlen(dir) > 0) strcat(file_name, "/");
        strcat(file_name, file);
        printf("File selected: %s\n", file_name);
/* Load the file */
        load_file(file_name, cw);
        if(cw->ok_to_pop_down)
        {
            fbuf.lstart = fbuf.lines;
            apply_font(text_area, NULL, NULL);

/* Clear the display window so that text is displayed again */
            XClearArea(XtDisplay(w), dWin, 0, 0, 0, 0, True);
        }
        XtFree(file_name);
    }
    else
    {
        printf("Nothing selected\n");
    }
}
/*-------------------------------------------------------------*/
/*  d i s p _ p r o p w i n
 *
 *  Display a "Font" property window and let user change the
 *  font used to display the text in the window.
 */
static void disp_propwin(w, client_data, call_data)
Widget    w;
XtPointer client_data, call_data;
{
    static XtCallbackRec apply_callback[] =
    {
        {(XtCallbackProc)apply_font, NULL},
        { NULL, NULL}
    };
    
    static XtCallbackRec reset_callback[] =
    {
        {(XtCallbackProc)reset_font, NULL},
        { NULL, NULL}
    };
    
    Widget upper, lower, footer, caption, excl;
    

/* Beep and return, if nothing is being displayed */

    if(file_not_loaded)
    {
        XBell(XtDisplay(w), 100);
        return;
    }
    
/* Indicate that it is ok to pop down the property window */
    font_prop.ok_to_pop_down = True;

    if(font_prop.popup_shell == (Widget)0)
    {
/* Create the pop-up widget */
        font_prop.popup_shell = XtVaCreatePopupShell(
                      "PopupCommand", 
                      popupWindowShellWidgetClass, w,
                      XtNtitle,    "browse: Font Properties",
                      XtNapply,    apply_callback,
                      XtNreset,    reset_callback,
                      NULL);

/* Get the ID of the child widgets of the pop-up shell widget */
        XtVaGetValues(font_prop.popup_shell,
                      XtNupperControlArea, &upper,
                      XtNlowerControlArea, &lower,
                      XtNfooterPanel,      &footer,
                      NULL);

/* Create component widgets to complete the property window
 * Start with the text fields that prompt for directory and
 * file names.
 */
        caption = XtVaCreateManagedWidget("Font",
                      captionWidgetClass, upper,
                      XtNlabel,       "Font:",
                      NULL);

        excl = MakeExclusives("font_face", caption,
                  "Courier",     font_select, (caddr_t)&zero,
                  "Helvetica",   font_select, (caddr_t)&one,
                  "New Century Schoolbook", 
                                 font_select, (caddr_t)&two,
                  "Times",       font_select, (caddr_t)&three,
                  NULL);


        caption = XtVaCreateManagedWidget("Size",
                      captionWidgetClass, upper,
                      XtNlabel,       "Size:",
                      NULL);

        excl = MakeExclusives("font_size", caption,
                  " 10pt",       size_select, (caddr_t)&zero,
                  " 12pt",       size_select, (caddr_t)&one,
                  " 14pt",       size_select, (caddr_t)&two,
                  " 18pt",       size_select, (caddr_t)&three,
                  " 24pt",       size_select, (caddr_t)&four,
                  NULL);


        caption = XtVaCreateManagedWidget("Weight",
                      captionWidgetClass, upper,
                      XtNlabel,       "Weight:",
                      NULL);

        excl = MakeExclusives("font_weight", caption,
                  "Medium",  wt_select, (caddr_t)&zero,
                  "Bold",    wt_select, (caddr_t)&one,
                  NULL);
    

/* Create a StaticText widget to display messages */
        font_prop.message_area = XtVaCreateManagedWidget(
                      "message_area", 
                      staticTextWidgetClass, footer,
                      XtNalignment, OL_LEFT,
                      XtNgravity,   SouthWestGravity,
                      XtNstring,    "Select font",
                      NULL);
    }

/* Pop up the property window */
    XtPopup(font_prop.popup_shell, XtGrabNone);
}
/*-------------------------------------------------------------*/
/*  M a k e E x c l u s i v e s
 *
 *  Create an exclusives widget and add RectButtons to it.
 *  Uses variable number of arguments.
 *  Each argument is a pair of the form: label, action_proc
 *  A NULL marks the end.
 */
Widget MakeExclusives(name, parent, va_alist)
char   *name;
Widget parent;
va_dcl
{

typedef void   (*P_FUNC)();
typedef char   *P_CHAR;

    va_list  argp;         /* Used to access arguments */
    Widget   w, menu, b;
    char     *item_label;
    Widget   button;
    P_FUNC   item_action;
    caddr_t  action_args;
    int      bcount = 0;

/* Create the Exclusives widget */    
    w = XtVaCreateManagedWidget(name,
                      exclusivesWidgetClass, parent,
                      XtNlabel,         name,
                      XtNtitle,         name,
                      NULL);

/* Add entries (RectButtons) to the Exclusives widget */
/* Get the first optional parameter using "va_start"  */
    va_start(argp);

/* Get items one by one and prepare the menu items */
    while((item_label = va_arg(argp, P_CHAR)) != NULL)
    {
        b = XtVaCreateManagedWidget(item_label,
                    rectButtonWidgetClass, w,
                    XtNlabel,   item_label,
                    NULL);

/* Make the first menu item the default */
        if(bcount == 0) 
            XtVaSetValues(b, XtNdefault, True, NULL);
        bcount++;

/* Register callback for this menu button */

        item_action = va_arg(argp, P_FUNC);
        action_args = va_arg(argp, caddr_t);
                      
        XtAddCallback(b, XtNselect,
                      item_action, action_args);
    }
    va_end(argp);

    return w;
}
/*-------------------------------------------------------------*/
/*  f o n t _ s e l e c t
 *
 *  Handle font selection
 *
 */
static void font_select(w, client_data, call_data)
Widget    w;
XtPointer client_data, call_data;
{
    int font = *((int *)client_data);

    if(font != fbuf.font)
    {
        fbuf.o_font = fbuf.font;
        fbuf.font = font;
    }
}
/*-------------------------------------------------------------*/
/*  w t _ s e l e c t
 *
 *  Font weight changed.
 *
 */
static void wt_select(w, client_data, call_data)
Widget    w;
XtPointer client_data, call_data;
{
    int weight = *((int *)client_data);

    if(weight != fbuf.weight)
    {
        fbuf.o_weight = fbuf.weight;
        fbuf.weight = weight;
    }
}
/*-------------------------------------------------------------*/
/*  s i z e _ s e l e c t
 *
 *  New size font selected
 *
 */
static void size_select(w, client_data, call_data)
Widget    w;
XtPointer client_data, call_data;
{
    int size = *((int *)client_data);

    if(size != fbuf.size)
    {
        fbuf.o_size = fbuf.size;
        fbuf.size = size;
    }
}
/*-------------------------------------------------------------*/
/*  r e s e t _ f o n t
 *
 *  Revert back to previous font
 *
 */
static void reset_font(w, client_data, call_data)
Widget    w;
XtPointer client_data, call_data;
{
    fbuf.font = fbuf.o_font;
    fbuf.weight = fbuf.o_weight;
    fbuf.size = fbuf.o_size;
    apply_font(w, client_data, call_data);
}
/*-------------------------------------------------------------*/
/*  a p p l y _ f o n t
 *
 *  Set up a new font for use. Also compute screen areas 
 *  occupied by each line.
 */
static void apply_font(wid, client_data, call_data)
Widget    wid;
XtPointer client_data, call_data;
{
    Widget      w = text_area;
    D_LINE      *p_l;
    int         dir, ascent, descent;
    static char fname[120];      /* Room for font's name */
    XCharStruct cinfo;
    int         font = fbuf.font, 
                wt = fbuf.weight,
                sz = fbuf.size;

/* Do nothing if no file is loaded */
    if(file_not_loaded) return;

    fbuf.dwidth = 1;
    fbuf.dheight = 1;
    
/* Construct font's name */
    sprintf(fname, "*adobe-%s-%s-r*%s*", fontname[font], 
            weight[wt], size[sz]);

/* Display it in the property window's message area */
    if(font_prop.popup_shell != (Widget)0)
        XtVaSetValues(font_prop.message_area, 
                      XtNstring, fname, NULL);

/* Free the font, if necessary */
    if(fbuf.fstruct != NULL)
        XFreeFont(XtDisplay(w), fbuf.fstruct);
    
/* Load the new font */             
    if ((fbuf.fstruct = XLoadQueryFont(XtDisplay(w), fname)) 
        == NULL)
    {
        fprintf(stderr, "%s: display %s cannot load font: %s\n",
            theAppName, DisplayString(XtDisplay(w)), fname);

/* Set fbuf.fstruct to the "fixed" font */
        if ((fbuf.fstruct = XLoadQueryFont(XtDisplay(w), 
                                           "fixed")) == NULL) 
        {
            fprintf(stderr, "%s: display %s cannot load \
\"fixed\" font\n", theAppName, DisplayString(XtDisplay(w)));
            exit(1);
        }
    }

/* Compute bounding box of each line in the buffer */
    for(p_l = fbuf.lines; p_l != NULL; p_l = p_l->next)
    {
       XTextExtents(fbuf.fstruct, p_l->line, p_l->length,
           &dir, &ascent, &descent, &cinfo);
       p_l->lbearing = cinfo.lbearing;
       p_l->rbearing = cinfo.rbearing;
       p_l->height = ascent + descent;
       p_l->width = cinfo.width;
       fbuf.dheight += p_l->height;
       if(fbuf.dwidth < p_l->width + LEFT_MARGIN)
               fbuf.dwidth = p_l->width + LEFT_MARGIN;
    }

/* Set size of the text area widget */
    XtVaSetValues(text_area, XtNwidth,  fbuf.dwidth,
                             XtNheight, fbuf.dheight,
                             NULL);

/* Set the font in the GC */
    XSetFont(XtDisplay(w), fbuf.gc, fbuf.fstruct->fid);

/* Clear the display window so that text is displayed again */
    XClearArea(XtDisplay(w), dWin, 0, 0, 0, 0, True);
}

