[Previous] [Contents] [Index] [Next]


This chapter describes how to work with fonts in a Photon application.

Font names

It's possible - and common - to hard-code all references to fonts in a Photon application. But there's a more flexible approach where applications can choose the best match from whatever fonts are available. That way, there isn't a problem if a particular font is eventually renamed, removed, or replaced.

To specify a font in the Photon API, you always use a stem name. For example, the following call to PtAskQuestion() uses the stem name helv14 to specify 14-point Helvetica:

PtAskQuestion (base_wgt, NULL, 
               "File has not been saved. Save it?", 
               "helv14", "&Save", "&Discard", 
               "&Cancel", 1);

If you're using QNX 4.25, you'll find the available stem names listed in /qnx4/photon/font/fontdir. If you're using QNX Neutrino 2, look in /nto/photon/font/fontdir.

Alternately, if you have a $HOME/.photon directory, check in $HOME/.photon/font/fontdir. Photon creates this local file only when needed, such as when you run the fontcfg utility to create your own personal font configuration. Until the local file is created, Photon uses the global file.

The above example takes a shortcut by using a hard-coded stem name (helv14).And, like any shortcut, this approach has tradeoffs. First, stem names are subject to change. More importantly, all versions of Photon up to and including 1.13 have only 16 characters available for the stem name. This isn't always enough to give each font a unique stem. Photon 1.14 for QNX Neutrino has 80 characters

To get around these problems, use PfQueryFonts() to provide the information needed to build your stem name. This function queries the Photon Font Server, and protects you from future changes.

Using PfQueryFonts()

Let's start with the parameters to PfQueryFonts() - then we'll look at a code sample that extracts the stem name from the data returned by the function.

The function itself looks like this:

PfQueryFonts (long symbol, 
              unsigned flags, 
              FontDetails list[], 
              int n );

The arguments are:

A key for searching the Photon Font Manager. The function looks for fonts that include this symbol and discards those that don't have it.

For instance, a Unicode space symbol (0x0020) is available in almost any font. Specifying an é symbol (Unicode 0x00c9), on the other hand, narrows down the font choices considerably. And, of course, specifying a Japanese character selects only Japanese fonts.

To include all available fonts, use PHFONT_ALL_SYMBOLS.

Provides another way to narrow down your search. Available values:
An array that the Photon Font Manager fills in for you. You need to declare a FontDetails structure, which is described below.
The number of elements available in the list array.

If PfQueryFonts() is successful, it returns the number of fonts available that matched your selection criteria. Otherwise, it returns -1.

Note: If n is 0 and list is NULL, PfQueryFonts() returns the number of matching fonts but doesn't try to fill in the list. You can use this feature to determine the number of items to allocate for the list.

FontDetails structure

Once you've got the list of fonts, you'll need to tear apart the FontDetails structure for each. That way, you can find both the font you need and the string to use as a stem name.

The FontDetails structure is defined in <photon/Pf.h>, and is defined as:

typedef struct {  
    FontDescription desc;
    FontName        stem;
    short           losize;
    short           hisize;
    unsigned short  flags;
} FontDetails;

For our purposes, the desc and stem elements the most useful, but let's review them all.

The full descriptive name of the font; for example, Helvetica or Charter. Note the use of capitals. Assigned by the foundry that built the font, this name is universal across operating environments (e.g. X, Photon).
The short form. This provides a part of the stem name used by the Photon API calls. For example, helv and char correspond to Helvetica and Charter.
The minimum available point size for the font, say 4.
The largest size the font has available. If both losize and hisize are 0, the font is scalable.
Available values:


Now that we've looked at the pieces involved, it's fairly simple to follow the steps needed to build up the correct stem name for a given font.

Keep these things in mind:

You'll probably want to do this work in the initialization function for your application, or perhaps in the base window setup function. Once you've constructed the stem name, keep the string in a global variable. You can then use it as needed.

Here's a sample application-initialization function:

***   global variables   ***

char GcaCharter14Bold [MAX_FONT_TAG + 1];  
   /* Remember: there's no point in having a larger 
      buffer than the stem name's size (plus 1 to
      allow for a NULL-terminated string */

fcnAppInit( int argc, char *argv[] )

      /* Local variables */
         FontDetails tsFontList [nFONTLIST_SIZE];
         short sCurrFont = 0;
         char caBuff[20];

      /* Get a description of the available fonts */
         if (PfQueryFonts (PHFONT_ALL_SYMBOLS,
               PHFONT_ALL_FONTS, tsFontList,
               nFONTLIST_SIZE) == -1)
               perror ("PfQueryFonts() failed:  ");
               return (Pt_CONTINUE);

      /* Search among them for the font that matches our 
         specifications */
         for (sCurrFont = 0; 
              sCurrFont < nFONTLIST_SIZE; sCurrFont++)
               if ( !strcmp (tsFontList[sCurrFont].desc,
                             "Charter") )
                  break;  /* we've found it */
      /* Overrun check */
         if (sCurrFont == nFONTLIST_SIZE)
               /* check for a partial match */
                  for (sCurrFont = 0;
                       sCurrFont < nFONTLIST_SIZE; 
                        if ( !strncmp (tsFontList[sCurrFont].desc, 
                                       strlen ("Charter") ) )
                           break;  /* found a partial match */
                  if (sCurrFont == nFONTLIST_SIZE)
                        printf ("Charter not in %d fonts checked.\n",
                        return (Pt_CONTINUE);
                     printf ("Using partial match -- 'Charter'.\n");

      /* Does it have bold? */
         if (!(tsFontList[sCurrFont].flags & PHFONT_INFO_BOLD))
               printf ("Charter not available in bold font.\n");
               return (Pt_CONTINUE);

      /* Is 14-point available? */
         if ( !( (tsFontList[sCurrFont].losize == 
                  tsFontList[sCurrFont].hisize == 0) 
                     /* proportional font -- it can be shown in

                 ( (tsFontList[sCurrFont].losize <= 14 )
                   (tsFontList[sCurrFont].hisize >= 14 ) ) ) )
                     /* 14-point fits between smallest and
                        largest available size */
               printf ("Charter not available in 14-point.\n");
               return (Pt_CONTINUE);

      /* Build up the stem name */
         strncpy (GcaCharter14Bold, 
         if (GcaCharter14Bold[0] == '\x0')
               printf ("Charter font stem name was blank.\n");
               return (Pt_CONTINUE);
         strcat (GcaCharter14Bold, itoa (14, caBuff, 10) );
         strcat (GcaCharter14Bold, "b");
         strcat (GcaCharter14Bold, "");  /* note the NULL termination */
      /* You can now use GcaCharter14Bold as an argument to
         PtAskQuestion(), etc. */

    /* Eliminate 'unreferenced' warnings */
          argc = argc, argv = argv;

    return( Pt_CONTINUE );


For the above code to work, you must declare the following information in the application's global header file. To do this, use PhAB's Startup Info/Modules dialog (accessed from the Application menu).

***   user-defined constants   ***
#define nFONTLIST_SIZE 100  /* an arbitrary choice of size */

***   global variables   ***

extern char GcaCharter14Bold [];

Remember to define this header before you start adding callbacks and setup functions -- that way, it will be automatically included as a #define. If you forget, you'll have to go back and add the statement manually.

And last of all, here's a sample callback that uses our stem name string:

fcnbase_btn_showdlg_ActivateCB( PtWidget_t *widget, ApInfo_t *apinfo,
                                PtCallbackInfo_t *cbinfo )

   /* This callback is used to launch a dialog box with the
      intent of exercising the global variable GcaCharter14Bold */
         (ABW_base, "Font Demonstration", 
          "This sentence is in 14-pt. Charter bold",
          GcaCharter14Bold, "OK", NULL, NULL, 1);

    /* Eliminate 'unreferenced' warnings */
          widget = widget, apinfo = apinfo, cbinfo = cbinfo;

    return( Pt_CONTINUE );

[Previous] [Contents] [Index] [Next]