# Responding to Help Requests

This chapter explains how to display different types of help information by setting Help Dialog widget resources.

HRDC.HReq.mkr.2
HRDC.HReq.mkr.3
HRDC.HReq.mkr.5
HRDC.HReq.mkr.6
HRDC.HReq.mkr.7
HRDC.HReq.mkr.8
HRDC.HReq.mkr.9
HRDC.HReq.mkr.11
HRDC.HReq.mkr.12

## Requesting Help

When a user requests help while using your application, it is the application's responsibility to determine what help topic should be displayed.

### Context Sensitivity

Some help requests amount to an explicit request for specific information, such as help on “version” (which usually displays the copyright topic). Other help requests, however, may require some degree of context sensitivity. That is, some processing might be needed to determine the appropriate help topic based on the user's current context within the application.

For instance, your application might test the status of certain modes or settings to determine the appropriate help topic. Or, it might test the value of an input field and provide detailed help if the value is not valid, and general help if the value is valid.

### Entry Points

An entry point is a specific location within a help volume—usually the beginning of a topic—that can be directly accessed by requesting help within the application.

From the author's point of view, entry points are established by assigning IDs at the appropriate places within the help volume. From the programmer's point of view, entry points are created by enabling the user to request help and using the appropriate ID when a particular request is made.

There are four general ways for users to request help:

- Pressing the help key (which is F1 on most keyboards)

- Clicking the Help button in a dialog box

- Choosing a command from the application's Help menu

- Choosing On Item help

## Displaying Help Topics

When a help request is made, the application determines what help topic to display. It then creates (if necessary) and manages a help dialog, and sets the appropriate resources to display a help topic.

Most requests display help topics that are part of the application's help volume, but the Help System's help dialogs are also capable of displaying man pages, text files, and simple text strings.

The Help System's help dialogs are based exclusively on Xt Intrinsics and Motif programming, so you change the values within a help dialog just like any other widget: by setting resources.

The `DtNhelpType` resource determines what type of information is displayed. It can be set to any of these values:

- `DtHELP_TYPE_TOPIC` for displaying normal help topics that are part of a help volume. The volume is specified by setting the `DtNhelpVolume` resource; the topic is specified by setting `DtNLocationId` resource.

- `DtHELP_TYPE_STRING` for displaying a string supplied by the application. Automatic word wrap is disabled, so line breaks are observed as specified in the string. The string is specified by setting the `DtNstringData` resource.

- `DtHELP_TYPE_DYNAMIC_STRING` for displaying a string supplied by the application, using word wrap to format the text. Line breaks within the string are used to separate paragraphs. The string is specified by setting the `DtNstringData` resource.

- `DtHELP_TYPE_FILE` for displaying a text file. The name of the file to be displayed is specified by setting the `DtNhelpFile` resource.

- `DtHELP_TYPE_MAN_PAGE` for displaying a manual reference page (man page) in a help dialog. The man page to be displayed is specified by setting the `DtNmanPage` resource.

These values are defined in the `Help.h` file.

### See Also

- HRDC.CrDia.mkr.1

### To Display a Help Topic

1. Create a help dialog.

2. Set the following resources for the help dialog:

   `DtNhelpType` | Set to `DtHELP_TYPE_TOPIC`.
   `DtNhelpVolume` | Set to the volume name for your application.
   `DtNlocationId` | Set to the topic ID that you want to display.

   You can also set other values for the dialog, such as its size and title.

3. Manage the dialog using `XtManageChild()`.

#### Example

This program segment displays a topic with the ID getting-started in the volume `MyVolume`.

    ac = 0;
    XtSetArg (al[ac], DtNhelpType,   DtHELP_TYPE_TOPIC);  ac++;
    XtSetArg (al[ac], DtNhelpVolume,  “MyVolume”);         ac++;
    XtSetArg (al[ac], DtNlocationId,  “getting-started”);  ac++;
    XtSetArg (al[ac], DtNcolumns,    40);                  ac++;
    XtSetArg (al[ac], DtNrows,       12);                  ac++;
    XtSetValues (helpDialog, al, ac);
    XtManageChild (helpDialog);

If the help volume `MyVolume` is not registered, then a complete path to the `MyVolume.sdl` file is required for the value of `DtNhelpVolume`.

### To Display a String of Text

1. Create a quick help dialog.

   You can use a general help dialog to display string data, but this isn't recommended because most of its features do not apply to string data.

2. Set the following resources for the help dialog:

   `DtNhelpType` | Set to `DtHELP_TYPE_DYNAMIC_STRING` (if you want word wrap enabled) or `DtHELP_TYPE_STRING` (if you want the line breaks within the string to be maintained)
   `DtNstringData` | Set to the string you want to display. A copy of the string is kept internally, so you need not maintain your copy of it.

   You can also set other values for the dialog, such as its size and title.

3. Manage the dialog using `XtManageChild()`.

#### Example

This program segment displays a string stored in the variable descriptionString.

    ac = 0;
    XtSetArg (al[ac], DtNhelpType,   DtHELP_TYPE_DYNAMIC_STRING); ac++;
    XtSetArg (al[ac], DtNstringData, (char *)descriptionString);   ac++;
    XtSetValues (quickHelpDialog, al, ac);
    XtManageChild (quickHelpDialog);

If the string is no longer needed within the application, the memory can be freed, because the help dialog makes its own copy of the data.

    XtFree (descriptionString);

### To Display a Text File

1. Create a quick help dialog or retrieve one from your dialog cache.

   You can use a general help dialog to display a text file, but this isn't recommended because most of its features are useful only for standard help topics.

2. Set the following resources for the help dialog:

   `DtNhelpType` | Set to `DtHELP_TYPE_FILE`.
   `DtNhelpFile` | Set to the file name you want to display. If the file is not in the application's current directory, provide a path to the file.

   You can also set other values for the dialog, such as its size and title. In particular, you might want to set the width to 80 columns, which is the standard width for text files.

3. Manage the dialog using `XtManageChild()`.

#### Example

The following program segment displays a file named `/tmp/printer.list`. It also sets the size of the dialog to better suit a text file.

    ac = 0;
    XtSetArg (al[ac], DtNhelpType, DtHELP_TYPE_FILE);      ac++;
    XtSetArg (al[ac], DtNhelpFile,  “/tmp/printer.list”);  ac++;
    XtSetArg (al[ac], DtNcolumns,  80);                    ac++;
    XtSetArg (al[ac], DtNrows,     20);                    ac++;
    XtSetValues (quickHelpDialog, al, ac);
    XtManageChild (quickHelpDialog);

### To Display a Man Page

1. Create a quick help dialog.

   You can use a general help dialog to display a man page, but this isn't recommended because most of its features are useful only with standard help topics.

2. Set the following resources for the help dialog:

   `DtNhelpType` | Set to `DtHELP_TYPE_MAN_PAGE`.
   `DtNmanPage` | Set to the name of the man page. The value of this resource is passed directly to the system `man` command. So, to specify a particular section of a man page, precede the man page name by a section number, just as you would if you were typing the `man` command conventionally.

   You can also set other values for the dialog, such as its size and title.

3. Manage the dialog using `XtManageChild()`.

#### Example

The following program segment displays the man page for the `grep` command. It also sets the size of the dialog to better suit a man page.

    ac = 0;
    XtSetArg (al[ac], DtNhelpType, DtHELP_TYPE_MAN_PAGE);  ac++;
    XtSetArg (al[ac], DtNmanPage,   “grep”);   ac++;
    XtSetArg (al[ac], DtNcolumns,  80);                          ac++;
    XtSetArg (al[ac], DtNrows,     20);                          ac++;
    XtSetValues (quickHelpDialog, al, ac);
    XtManageChild (quickHelpDialog);

## Enabling the Help Key (F1)

The help key mechanism is a feature built into all Motif manager widgets and primitive widgets. The help key is enabled by adding a help callback to the widget where you want the help key active.

Within your application, you should add a help callback to each widget where you want a unique entry point into help. The help callback mechanism automatically “walks” up the widget hierarchy (up to the shell widget) until it finds a widget with a help callback, then invokes that callback.

If you add a help callback to a manager widget, when the help key is pressed for any of its children, the manager's help callback is invoked (unless the child widget has a help callback of its own).

### To Add a Help Callback

Use the `XtAddCallback()` function as follows:

    XtAddCallback (
          Widget            widget,
          String            DtNhelpCallback,
          XtCallbackProc    HelpRequestCB,
          XtPointer         clientData );

Where:

widget | The widget where you want to activate the help key.
`HelpRequestCB()` | The function in your application that handles the help request when the user presses the help key.
clientData | The data you want passed to the `HelpRequestCB()`function. Typically, this data identifies the topic to be displayed.

When the user presses the help key, the help callback is invoked for the widget with the current keyboard focus. If that widget does not have a help callback, the help callback for its nearest ancestor that does have a help callback is invoked.

If no help callbacks are found, nothing happens. Therefore, it is recommended that you add a help callback to each shell in your application. This ensures that no user requests for help are lost.

Adding a help callback to a dialog shell automatically enables the Help button on the dialog to invoke the help callback.

### Importance of Client Data

Specifying a unique value for clientData in each help callback you add saves you the trouble of writing a separate function to process each help callback. Your application can have a single callback procedure to process all help requests (see HRDC.HReq.mkr.10). Within the callback procedure, use the clientData to identify where the user requested help. That is, each time you add a help callback, you should provide a unique value for clientData.

#### Example

The following example demonstrates one way to associate IDs with entry points. A `HelpEntryIds.h` file is used to define a unique integer for each clientData value for each help callback. Also defined are two ID strings for each widget: one for normal F1 help, the other for item help mode (where the user picks a widget to get a description).

For this example, assume that the application's user interface is just a main window with three input fields: Name, Address, and Telephone Number. Here's what the `HelpEntryIds.h` file would contain:

    #define HELP_volumeName            "MyVolume"
    #define HELP_MainWindow            100
    #define HELP_MainWindow_ID         "basic-tasks"
    #define HELP_MainWindow_ITEM_ID    "main-window-desc"

    #define HELP_NameField             101
    #define HELP_NameField_ID          "specifying-a-name"
    #define HELP_NameField_ITEM_ID     "name-field-desc"

    #define HELP_AddressField          102
    #define HELP_AddressField_ID       "specifying-an-address"
    #define HELP_AddressField_ITEM_ID  "address-field-desc"

    #define HELP_PhoneField            103
    #define HELP_PhoneField_ID         "specifying-a-phone-no"
    #define HELP_PhoneField_ITEM_ID    "phone-field-desc"

Within the part of the application that initially creates the widgets, a help callback is added to each widget as follows:

    XtAddCallback (mainWindow, DtNhelpCallback,
                   HelpRequestCB, HELP_MainWindow);
    XtAddCallback (nameField, DtNhelpCallback,
                   HelpRequestCB, HELP_NameField);
    XtAddCallback (addressField, DtNhelpCallback,
                   HelpRequestCB, HELP_AddressField);
    XtAddCallback (phoneField, DtNhelpCallback,
                   HelpRequestCB, HELP_PhoneField);

Within the `HelpRequestCB()` function, the clientData parameter is used to dispatch the help requests (through a `switch()` statement). Within each case, the value of a global flag `itemHelp` is tested to see if the help callback was invoked by the F1 key (the flag is “false”) or by the user picking the widget in item help mode (the flag is “true”).

    XtCallbackProc HelpRequestCB (
          Widget     w,
          XtPointer  clientData,
          XtPointer  callData)
    {
       char    *topicToDisplay;
       Boolean  useQuickHelpDialog;
       /* Determine the topic ID for the given `clientData.' */
       switch ((int)clientData)
         {
           case HELP_MainWindow:
             useQuickHelpDialog = False;
             if (itemHelpFlag)
               topicToDisplay = HELP_MainWindow_ITEM_ID;
             else
               topicToDisplay = HELP_MainWindow_ID;
             break;       case HELP_NameField:
             useQuickHelpDialog = True;
             if (itemHelpFlag)
               topicToDisplay = HELP_NameField_ITEM_ID;
             else
               topicToDisplay = HELP_NameField_ID;
             break;       case HELP_AddressField:
             useQuickHelpDialog = True;
             if (itemHelpFlag)
               topicToDisplay = HELP_AddressField_ITEM_ID;
             else
               topicToDisplay = HELP_AddressField_ID;
             break;       case HELP_PhoneField:
             useQuickHelpDialog = True;
             if (itemHelpFlag)
               topicToDisplay = HELP_PhoneField_ITEM_ID;
             else
               topicToDisplay = HELP_PhoneField_ID;
             break;       default:
             /* An unknown clientData was received. */
             /* Put your error handling code here. */
             return;
             break;
         }
       /* Display the topic. */
       ac = 0;
       XtSetArg (al[ac], DtNhelpType,   DtHELP_TYPE_TOPIC); ac++;
       XtSetArg (al[ac], DtNhelpVolume, HELP_volumeName);    ac++;
       XtSetArg (al[ac], DtNhelpType,   topicToDisplay);     ac++;
       if (useQuickHelpDialog)
         {
            XtSetValues (mainQuickHelpDialog, al, ac);
            XtManageChild (mainQuickHelpDialog);
         }
       else
         {
            XtSetValues (mainHelpDialog, al, ac);
            XtManageChild (mainHelpDialog);
         }
       /* Clear the `item help' flag. */
       itemHelpFlag = False;
     }

The preceding function assumes that the application uses two help dialogs for all help requests (`mainHelpDialog` and `mainQuickHelpDialog`), and that those dialogs have already been created. It also assumes that `al` and `ac` (used in assembling Xt argument lists) are declared elsewhere.

## Providing a Help Menu

The Style Guide and Certification Checklist recommends that each menu bar include a Help menu. The Help menu may contain a variety of commands that lets the user access different types of online help for your application.

The most important commands include:

- `Introduction` displays the home topic of your application's help, allowing the user to use hyperlinks to navigate to any desired information.

- `Using Help` displays “help” on help. This is information that tells the user how to use the Help System.

- `Version` displays your application's version and copyright information.

Additional commands may display help on special keyboard usage, application tasks, reference, or tutorials. You should design your Help menu to best suit your application, while staying within the guidelines and recommendations of the Style Guide and Certification Checklist.

### See Also

- HRDC.OrgH.mkr.13 describes how authors create the home topic for a help volume.

- HRDC.OrgH.mkr.16 describes how authors create a copyright topic.

- HRDC.H4Hlp.mkr.1describes how help on help is found and how to add it to your application.

## Supporting Item Help Mode

Some applications provide an On Item or Help Mode command in their Help menu. This command temporarily redefines the mouse pointer as a `?` (question mark) to prompt the user to select an item on the screen. When an item is selected, the application is expected to display a description of the item.

The convenience function, `DtHelpReturnSelectedWidgetId()`, changes the pointer to a question mark and waits for the user to pick a widget. The ID of the selected widget is returned. This function is similar to the `XmTrackingLocate()` function except that `DtHelpReturnSelectedWidgetId()` returns NULL if the user presses Escape to cancel the operation.

To display help on the selected item, your application can simply invoke the help callback for the returned widget. This is equivalent to the user pressing F1 while using that widget.

If you want the application to differentiate between item help and F1 help, you can set a flag before calling the widget's help callback. The help callback procedure can then use that flag to determine that the callback was invoked as a result of item help and alter its response accordingly.

### To Add Support for Item Help

1. Write a function that uses the `DtHelpReturnSelectedWidgetId()` function. Within this function, invoke the help callback for the selected widget. In the following steps, this function is called `ProcessOnItemHelp()`, but you can name it whatever you want.

2. Add to your Help menu a command button labeled `On Item`. Add an activate callback that invokes your `ProcessOnItemHelp()` function.

3. Add a help callback to each widget in your application where you want item help to be available.

If the selected widget does not have a help callback, the application should try its parent widget. Similarly, if the parent does not have a help callback, the application should continue to walk up the widget hierarchy until it finds a help callback.

#### Example

The following procedure is a sample `ProcessOnItemHelp()` function that would be invoked by choosing `On Item` from the Help menu.

    void ProcessOnItemHelp(
       Widget widget)
    {
     /* Declare a variable for the selected widget. */
      Widget selWidget=NULL;
      int status=DtHELP_SELECT_ERROR;
      /* Get an application shell widget from our widget hierarchy to
    * pass into DtHelpReturnSelectedWidgetId().   */

      while (!XtIsSubclass(widget, applicationShellWidgetClass))
                       widget = XtParent(widget);
      status = DtHelpReturnSelectedWidgetId(widget, NULL, &selWidget);
      switch ((int)status)
        {
          case DtHELP_SELECT_ERROR:
            printf(“Selection Error, cannot continue\n”);
          break;
          case DtHELP_SELECT_VALID:
             /* We have a valid widget selection, now let's look
            for a registered help callback to invoke.     */

             while (selWidget != NULL)
              {
                if ((XtHasCallbacks(selWidget, XmNhelpCallback)
                                         == XtCallbackHasSome))
                  {
                    /* Found a help callback, so just call it */
                    XtCallCallbacks((Widget)selWidget,
                                    XmNhelpCallback,NULL);
                    break;
                  }
                else
                  /* No help callback on current widget, so try
                  the widget's parent   */
                     selWidget = XtParent(selWidget);
              }
          break;
          case DtHELP_SELECT_ABORT:
            printf("Selection Aborted by user.\n");
          break;
          case DtHELP_SELECT_INVALID:
            printf("You must select a component within your app.\n");
          break;
        }
    }