Chapter 3. The ViewKit Application Class

This chapter describes the VkApp class, which handles application-level tasks such as Xt initialization, event handling, window management, cursor control, and application busy states. Figure 3-1 shows the inheritance graph for VkApp and an auxiliary class, VkCursorList.

Figure 3-1. Inheritance Graph for VkApp

Figure 3-1 Inheritance Graph for VkApp

Overview of the VkApp Class

The VkApp class, derived from the VkComponent class, provides facilities required by all ViewKit applications. In all of your ViewKit applications you must create a single instance of VkApp or a class derived from VkApp.

The primary responsibility of VkApp is to handle the initialization and event-handling operations common to all Xt-based applications. When you write a ViewKit application, instead of calling Xt functions such as XtAppInitialize(3Xt) and XtAppMainLoop(3Xt), you simply instantiate and use a VkApp object.

The VkApp class also provides support for other application-level tasks. For example, VkApp provides functions for quitting your application; showing, hiding, iconifying, and opening all of the application's windows; handling application busy states; maintaining product version information; and setting the application's cursor shape.

The VkApp class also stores some essential information that can be accessed throughout an application. This information includes a pointer to the X Display structure associated with the application's connection to the server; the XtAppContext structure required by many Xt functions; the application's name; and the application's class name. This information is maintained in the private portion of the class and is available through public access functions.

VkApp Constructor

In all ViewKit applications you must create a single instance of the VkApp class (or a derived class) before instantiating any other ViewKit objects.The VkApp constructor initializes the Xt Intrinsics and creates a shell, which is never visible, to serve as the parent for all of the application's main windows. ViewKit supports a commonly used multi-shell architecture as described in the book X Window System Toolkit (Asente and Swick, 1990). ViewKit creates all windows (using the VkSimpleWindow and VkWindow classes described in Chapter 4, “ViewKit Windows”) as popup children of the shell created by VkApp.

When you create an instance of the VkApp class, the constructor assigns a pointer to the VkApp object to the global variable theApplication. The <Vk/VkApp.h> header file declares this global variable as follows:

extern VkApp *theApplication;

As a result, the theApplication pointer is available in any file that includes the <Vk/VkApp.h> header file. This provides easy use of VkApp's facilities and data throughout your program.

The following is the syntax of the most frequently used VkApp constructor:

VkApp(char *appClassName, int *argc, char **argv,
      XrmOptionDescRec *options = NULL,
      int numOptions = 0)

The appClassName argument designates the application class name, which is used when loading application resources. Note that VkApp differs from other ViewKit components in that you provide the application class name as an argument to the constructor rather than overriding the className() function. This allows you to set the application class name without creating a subclass of VkApp.VkApp also differs from other ViewKit components in that you do not provide a component name in the constructor; instead, ViewKit uses the command that you used to invoke your application (argv[0]) as the component name.

The second and third arguments to the VkApp constructor must be pointers to argc and the application's argv array. The VkApp constructor passes these arguments to XtOpenDisplay(3Xt), which parses the command line according to the standard Xt command-line options, loads recognized options into the application's resource database, and modifies argc and argv to remove all recognized options.

You can specify additional command-line options to parse by passing an XrmOptionDescRec(3Xt) table as the options argument and specifying the number of entries in the table with the numOptions argument. This is sufficient for setting simple resource values from the command line; however, if you want to set application-level variables using either the command line or resource values, you should follow these steps:

  1. Derive a subclass of VkApp.

  2. Use the protected member function VkApp::parseCommandLine() to parse command-line options.

  3. Use getResources() to set the variables based on resource values.

This process is illustrated in Example 3-6 in “Deriving Classes From VkApp”.

If your application has more elaborate needs than the normal constructor addresses, you may wish to use the following constructor:

VkApp (char *appClassName,
       int *arg_c,
       char **arg_v,
       ArgList arglist,
       Cardinal argCount,
       void (*preRealizeFunction)(Widget w),
       XrmOptionDescRec *optionList,
       int sizeOfOptionList)

You should use this constructor when your application must set creation-time resources on the invisible top-level shell widget that VkApp creates. For instance, the only way to ensure that your application has all of its shells in a single, non-default visual is to use this constructor to set the visual attributes. See the VkApp(3x) reference page for more details.

Running ViewKit Applications

Once you have instantiated a VkApp object and set up your program's interface, call VkApp::run():

virtual void run()

The run() function enters a custom main loop that supports dispatching raw events in addition to the normal Xt event handling. See “ViewKit Event Handling” for more information on event handling.


Note: Do not call XtMainLoop(3Xt) or XtAppMainLoop(3Xt) in a ViewKit application.

Example 3-1 illustrates the typical use of VkApp in the main body of a ViewKit program.

Example 3-1. Typical Use of the VkApp Class in a ViewKit Program

#include <Vk/VkApp.h>
 
// Application-specific setup
 
void main ( int argc, char **argv )
{
 
    VkApp   *myApp = new VkApp("MyApp", &argc, argv);
    // Application-specific code
 
    myApp->run();  // Run the application
}


ViewKit Event Handling

The VkApp::run() function is ViewKit's main event loop. run() implements the event handling normally supported by XtAppMainLoop() or XtMainLoop(). run() calls run_first() to do some internal initialization, and then enters a main loop that dispatches application events, raw X events, and normal Xt events. run() also allows for customized event handling. See “Customizing Event Handling” for more information.

Additionally, run() supports events not normally handled by the Xt dispatch mechanism. For example, run() can handle events registered for non-widgets (such as a PropertyNotify event on the root window).

When run() receives an event not handled by the Xt dispatch mechanism, it calls the virtual function VkApp::handleRawEvent():

virtual void handleRawEvent(XEvent *event)

The default action of VkApp::handleRawEvent() is to pass the event to the handleRawEvent() function of each instance of VkSimpleWindow (or subclass) in the application. By default, these member function are empty.

If you want to handle events through this mechanism, call XSelectInput(3X) to select the events that you want to receive, and override handleRawEvent() in a VkApp or VkSimpleWindow subclass to implement your event processing. Generally, in keeping with object-oriented practice, you should override handleRawEvent() in a VkSimpleWindow subclass rather than a VkApp subclass, unless your event processing has an application-wide effect. If you override VkApp::handleRawEvent() in a derived class, call the base class's handleRawEvent() function after performing your event processing.


Note: If you explicitly call XtNextEvent(3Xt) and XtDispatchEvent(3Xt) in your application, you should pass any undispatched events to handleRawEvent().

In addition to the automatic event dispatching provided by run(), you can force ViewKit to handle all pending events immediately by calling VkApp::handlePendingEvents():

virtual void handlePendingEvents()

This function retrieves and dispatches all X events as long as there are events pending. Unlike XmUpdateDisplay(3Xm), which handles only Expose events, handlePendingEvents() handles all events. In other words, handlePendingEvents() does not just refresh windows, it also handles all pending events including user input. You might want to call this function periodically to process events during a time-consuming task.

handlePendingEvents(), like run() can also be customized. See “Customizing Event Handling” for more information.

Customizing Event Handling

If you want to customize your application's event handling, you do not need to override run(). In fact, overriding run() is strongly discouraged. If you really must override, see the VkApp(3x) reference page for more information.

You can customize event handling in any of the following ways:

  • Use standard X mechanisms to add event handlers.

  • Use one or more workprocs.

  • Maintain your own queue of all that you need to do, and then dispatch that work in a single workproc.

  • Use run(Boolean(*appEventHandler) (XEvent &)) to provide custom event handling.

run(Boolean(*appEventHandler) (XEvent &)) is the only safe way to customize ViewKit's event loop. It allows you to customize the event loop without taking responsibility for the entire process.

Each time through the event loop, before doing any event processing of its own, run() calls appEventHandler() with the event. appEventHandler() can then handle the event completely, handle it partially, or not handle it at all. If appEventHandler() has completely handled the event, it returns TRUE and no further handling of that event occurs. If the application decides not to handle the event, or if more handling is needed, then appEventHandler() returns FALSE and run() finishes the job.

Much like run(), handlePendingEvents() can be customized by calling handlePendingEvents(Boolean(*appEventHandler)(XEvent &)).

For a better understanding of how to customize event handling, see the demo program /usr/share/src/ViewKit/Basic/run.c++.

Quitting ViewKit Applications

If you want to exit a ViewKit application, but also want to give other parts of the application the option to abort the shutdown if necessary, call VkApp::quitYourself():

virtual void quitYourself()

VkApp::quitYourself() calls the okToQuit() function for each top-level VkSimpleWindow (or subclass). All windows that return TRUE are deleted; however, if the okToQuit() function of any window returns FALSE, the shutdown is terminated and the windows returning FALSE are not deleted. quitYourself() queries the windows in the reverse order in which they were created, except that it checks the window designated as the main window last. (See “Managing Top-Level Windows” for information on designating the main window.)

The default, as provided by VkComponent, is for the okToQuit() function to return TRUE in all cases. You must override okToQuit() for all components that you want to perform a check before quitting. For example, you could override the okToQuit() function for a window to post a dialog asking the user whether he or she really wants to exit the application and then abort the shutdown if the user says to do so. Another possibility would be to return FALSE if a component is in the process of updating a file.

Usually, only VkSimpleWindow and its subclasses use okToQuit(). In some cases, you might want to check one or more components contained within a window before quitting. To do so, override the okToQuit() function for that window to call the okToQuit() functions for all the desired components. Override the okToQuit() functions for the other components to perform whatever checks are necessary.

A ViewKit application automatically exits once all of its windows are deleted. This can occur as a result of any of the following circumstances:

  • The application calls quitYourself().

  • The application deletes all of its windows individually.

  • The user deletes all application windows through window manager interaction (for example, choosing the Close option in the window menu provided by the window manager).

Once all windows are deleted, the application exits by calling VkApp::terminate():

virtual void terminate(int status = 0)

terminate() is a virtual function that calls exit(2). terminate() is also called from within ViewKit when any fatal error is detected.

You can call terminate() explicitly to exit a ViewKit application immediately. Usually you would use this if you encounter a fatal error. If you provide a status argument, your application uses it as the exit value that the application returns.

You can override terminate() in a VkApp subclass to perform any cleanup operations that your application requires before aborting (for example, closing a database). If you override terminate() in a derived class, call the base class's terminate() function after performing your cleanup operations.


Note: Even though you can override quitYourself() in a VkApp subclass, in most cases you should override terminate() instead. This ensures that any cleanup operations you add are performed no matter how the application exits (for example, by error condition or by user interaction with the window manager). If you decide to override quitYourself(), you must perform your cleanup operations before calling the base class's quitYourself(): if quitYourself() succeeds in deleting all windows, your application calls terminate() and exits before ever returning from quitYourself().


Managing Top-Level Windows

The VkApp object maintains a list of all windows created in an application. The VkApp object uses this list to manage the application's top-level windows. So that VkApp can properly manage windows, you should always use the VkSimpleWindow and VkWindow classes to create top-level windows in your application. The classes are discussed in Chapter 4, “ViewKit Windows.”

Every application has a main window. By default, the first window you create is treated as the main window. You can use the VkApp::setMainWindow() function to specify a different window to treat as the main window:

void setMainWindow(VkSimpleWindow *window)

The access function VkApp::mainWindow() returns a pointer to the VkSimpleWindow (or subclass) object installed as the application's main window:

VkSimpleWindow *mainWindow() const

Additionally, the VkApp class supports several operations that can be performed on all top-level windows in a multi-window application. All of the following functions take no arguments, have a void return value, and are declared virtual:

show() 

Displays all of the application's hidden, non-iconified windows.

hide() 

Removes all of the application's windows from the screen.

iconify() 

Iconifies all visible windows in the application.

open() 

Opens all iconified windows in the application.

raise() 

Raises all visible windows in the application to the top of the window manager's window stack.

lower() 

Lowers all visible windows in the application to the bottom of the window manager's window stack.

You can also specify whether or not your application's windows start in an iconified state using VkApp::startupIconified():

void startupIconified(const Boolean flag)

If flag is TRUE, then the application starts all windows in the iconified state.


Note: You must call startupIconified() before calling run(), otherwise it will not have any effect.


Setting Application Cursors

By default, VkApp installs two cursors for ViewKit applications: an arrow for normal use, and a watch for display during busy states. (See “Supporting Busy States” for information on busy states in ViewKit applications.) The VkApp class also provides several functions for installing your own cursors and retrieving the currently installed cursors.

Setting and Retrieving the Normal Cursor

VkApp::setNormalCursor() sets the normal cursor for use in all of your application's windows while the application is not busy:

void setNormalCursor(Cursor c)

You must provide setNormalCursor() with a Cursor argument. See the XCreateFontCursor(3X) reference page for more information on creating an X cursor.

You can retrieve the current normal cursor with VkApp::normalCursor():

virtual Cursor normalCursor()    

Setting and Retrieving the Busy Cursor

The VkApp class supports both fixed and animated busy cursors. A fixed busy cursor retains the same appearance throughout a busy state. An animated busy cursor is actually a sequence of pixmaps that you can cycle through while in a busy state, giving the appearance of animation. “Animating the Busy Cursor” describes the procedure to follow to cycle through an animated busy cursor's pixmaps. If you install an animated busy cursor but do not cycle it, VkApp simply uses the animated cursor's current pixmap as a fixed busy cursor.

The default busy cursor that VkApp installs, a watch, is actually an animated cursor.

Setting and Retrieving a Fixed Busy Cursor

VkApp::setBusyCursor() sets a fixed busy cursor for use in all of your application's windows while the application is busy:

void setBusyCursor(Cursor c)

You must provide setBusyCursor() with a Cursor argument.

You can retrieve the current busy cursor with VkApp::busyCursor():

virtual Cursor busyCursor()

Creating, Setting, and Retrieving an Animated Busy Cursor

To create an animated busy cursor, you must create a subclass of the abstract base class VkCursorList. The following is the syntax of the VkCursorList constructor:

VkCursorList (int numCursors)

numCursors is the number of cursor pixmaps in your animated cursor.The VkCursorList constructor uses this value to allocate space for an array of Cursor pointers. In your subclass constructor, you should perform any other initialization required by your cursor.

In your subclass, you must also override the pure virtual function VkCursorList::createCursor():

virtual void createCursor(int index)

createCursor() creates the cursor for the given index in the animated cursor array. Cursors are numbered sequentially beginning with zero. When your application animates the cursor, it step through the cursor array sequentially. createCursor() must assign the cursor it creates to the index entry in the protected _cursorList array:

Pixmap *_cursorList 

For example, Example 3-2 shows the code needed to create an animated hourglass busy cursor.

Example 3-2. Creating an Animated Busy Cursor

#include <Vk/VkApp.h>
#include <Vk/VkResource.h>
#include <Vk/VkCursorList.h>
 
// Define an array of bit patterns that represent each frame of the cursor
// animation.
 
#define NUMCURSORS 8
 
static char time_bits[NUMCURSORS][32*32] = {
{
   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
   0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0xff, 0xff, 0x32,
   0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32,
   0x8c, 0xfe, 0x7f, 0x31, 0x0c, 0xfd, 0xbf, 0x30, 0x0c, 0xfa, 0x5f, 0x30,
   0x0c, 0xe4, 0x27, 0x30, 0x0c, 0x98, 0x19, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x18, 0x18, 0x30, 0x0c, 0x04, 0x20, 0x30, 0x0c, 0x02, 0x40, 0x30,
   0x0c, 0x01, 0x80, 0x30, 0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x8c, 0x00, 0x00, 0x31, 0xfe, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00},
{
   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
   0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x03, 0xc0, 0x32,
   0x4c, 0x3f, 0xfc, 0x32, 0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32,
   0x8c, 0xfe, 0x7f, 0x31, 0x0c, 0xfd, 0xbf, 0x30, 0x0c, 0xfa, 0x5f, 0x30,
   0x0c, 0xe4, 0x27, 0x30, 0x0c, 0x98, 0x19, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x18, 0x19, 0x30, 0x0c, 0x84, 0x20, 0x30, 0x0c, 0x02, 0x41, 0x30,
   0x0c, 0x81, 0x80, 0x30, 0x8c, 0x00, 0x01, 0x31, 0x4c, 0x80, 0x00, 0x32,
   0x4c, 0x00, 0x01, 0x32, 0x4c, 0xfc, 0x3f, 0x32, 0x4c, 0xff, 0xff, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x8c, 0x00, 0x00, 0x31, 0xfe, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00},
{
   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
   0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
   0x4c, 0x03, 0xc0, 0x32, 0x4c, 0x1f, 0xf8, 0x32, 0x4c, 0x7f, 0xfe, 0x32,
   0x8c, 0xfe, 0x7f, 0x31, 0x0c, 0xfd, 0xbf, 0x30, 0x0c, 0xfa, 0x5f, 0x30,
   0x0c, 0xe4, 0x27, 0x30, 0x0c, 0x98, 0x19, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x18, 0x19, 0x30, 0x0c, 0x84, 0x20, 0x30, 0x0c, 0x02, 0x41, 0x30,
   0x0c, 0x81, 0x80, 0x30, 0x8c, 0x00, 0x01, 0x31, 0x4c, 0xc0, 0x07, 0x32,
   0x4c, 0xfc, 0x3f, 0x32, 0x4c, 0xfe, 0x7f, 0x32, 0x4c, 0xff, 0xff, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x8c, 0x00, 0x00, 0x31, 0xfe, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00},
{
   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
   0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x4c, 0x03, 0xc0, 0x32, 0x4c, 0x0f, 0xf0, 0x32,
   0x8c, 0x3e, 0x7c, 0x31, 0x0c, 0xfd, 0xbf, 0x30, 0x0c, 0xfa, 0x5f, 0x30,
   0x0c, 0xe4, 0x27, 0x30, 0x0c, 0x98, 0x19, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x18, 0x19, 0x30, 0x0c, 0x84, 0x20, 0x30, 0x0c, 0x02, 0x41, 0x30,
   0x0c, 0x81, 0x80, 0x30, 0x8c, 0xe0, 0x07, 0x31, 0x4c, 0xfc, 0x3f, 0x32,
   0x4c, 0xfe, 0x7f, 0x32, 0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x8c, 0x00, 0x00, 0x31, 0xfe, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00},
{
   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
   0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x03, 0xc0, 0x32,
   0x8c, 0x06, 0x60, 0x31, 0x0c, 0x1d, 0xb8, 0x30, 0x0c, 0x7a, 0x5e, 0x30,
   0x0c, 0xe4, 0x27, 0x30, 0x0c, 0x98, 0x19, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x18, 0x19, 0x30, 0x0c, 0x84, 0x20, 0x30, 0x0c, 0x82, 0x41, 0x30,
   0x0c, 0xf1, 0x8f, 0x30, 0x8c, 0xfc, 0x3f, 0x31, 0x4c, 0xfe, 0x7f, 0x32,
   0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x8c, 0x00, 0x00, 0x31, 0xfe, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00},
{
   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
   0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
   0x8c, 0x02, 0x40, 0x31, 0x0c, 0x05, 0xa0, 0x30, 0x0c, 0x1a, 0x58, 0x30,
   0x0c, 0x64, 0x26, 0x30, 0x0c, 0x98, 0x19, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x18, 0x19, 0x30, 0x0c, 0x84, 0x20, 0x30, 0x0c, 0xe2, 0x47, 0x30,
   0x0c, 0xf9, 0x9f, 0x30, 0x8c, 0xfe, 0x7f, 0x31, 0x4c, 0xff, 0xff, 0x32,
   0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x8c, 0x00, 0x00, 0x31, 0xfe, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00},
{
   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
   0x8c, 0xff, 0xff, 0x31, 0xcc, 0xff, 0xff, 0x33, 0x4c, 0x00, 0x00, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
   0x8c, 0x00, 0x00, 0x31, 0x0c, 0x01, 0x80, 0x30, 0x0c, 0x02, 0x40, 0x30,
   0x0c, 0x04, 0x20, 0x30, 0x0c, 0x18, 0x18, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
   0x0c, 0x98, 0x19, 0x30, 0x0c, 0xe4, 0x27, 0x30, 0x0c, 0xfa, 0x5f, 0x30,
   0x0c, 0xfd, 0xbf, 0x30, 0x8c, 0xfe, 0x7f, 0x31, 0x4c, 0xff, 0xff, 0x32,
   0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32, 0x4c, 0xff, 0xff, 0x32,
   0x4c, 0x00, 0x00, 0x32, 0x8c, 0x00, 0x00, 0x31, 0xfe, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00},
{
   0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0xfe, 0xff, 0xff, 0x7f,
   0xfe, 0xff, 0xff, 0x7f, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60,
   0xf6, 0x01, 0x80, 0x6f, 0x0e, 0x02, 0x40, 0x78, 0xe6, 0x05, 0x20, 0x78,
   0xe6, 0x0b, 0x10, 0x78, 0xe6, 0x17, 0x08, 0x78, 0xe6, 0x2f, 0x04, 0x78,
   0xe6, 0x2f, 0x04, 0x78, 0xe6, 0x5f, 0x02, 0x78, 0xe6, 0x5f, 0x02, 0x78,
   0xe6, 0xbf, 0x01, 0x78, 0xe6, 0xbf, 0x01, 0x78, 0xe6, 0x5f, 0x02, 0x78,
   0xe6, 0x5f, 0x02, 0x78, 0xe6, 0x2f, 0x04, 0x78, 0xe6, 0x2f, 0x04, 0x78,
   0xe6, 0x17, 0x08, 0x78, 0xe6, 0x0b, 0x10, 0x78, 0xe6, 0x05, 0x20, 0x78,
   0x0e, 0x02, 0x40, 0x78, 0xf6, 0x01, 0x80, 0x6f, 0x06, 0x00, 0x00, 0x60,
   0x06, 0x00, 0x00, 0x60, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
   0x06, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00}
};
 
// Masks used for this cursor. The last frame requires a different
// mask, but all other frames can use the same mask.
 
static  char time_mask_bits[] = {
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0x8e, 0xff, 0xff, 0x71, 0xce, 0xff, 0xff, 0x73, 0xce, 0xff, 0xff, 0x73,
   0xce, 0xff, 0xff, 0x73, 0xce, 0xff, 0xff, 0x73, 0xce, 0xff, 0xff, 0x73,
   0x8e, 0xff, 0xff, 0x71, 0x0e, 0xff, 0xff, 0x70, 0x0e, 0xfe, 0x7f, 0x70,
   0x0e, 0xfc, 0x3f, 0x70, 0x0e, 0xf8, 0x1f, 0x70, 0x0e, 0xe0, 0x07, 0x70,
   0x0e, 0x80, 0x01, 0x70, 0x0e, 0x80, 0x01, 0x70, 0x0e, 0xe0, 0x07, 0x70,
   0x0e, 0xf8, 0x1f, 0x70, 0x0e, 0xfc, 0x3f, 0x70, 0x0e, 0xfe, 0x7f, 0x70,
   0x0e, 0xff, 0xff, 0x70, 0x8e, 0xff, 0xff, 0x71, 0xce, 0xff, 0xff, 0x73,
   0xce, 0xff, 0xff, 0x73, 0xce, 0xff, 0xff, 0x73, 0xce, 0xff, 0xff, 0x73,
   0xce, 0xff, 0xff, 0x73, 0x8e, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
#define time7_mask_width 32
#define time7_mask_height 32
#define time7_mask_x_hot 15
#define time7_mask_y_hot 15
static  char time7_mask_bits[] = {
   0x0f, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0,
   0xf7, 0x01, 0x80, 0xef, 0xff, 0x03, 0xc0, 0xff, 0xff, 0x07, 0xe0, 0xff,
   0xff, 0x0f, 0xf0, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x3f, 0xfc, 0xff,
   0xff, 0x3f, 0xfc, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0xff,
   0xff, 0x7f, 0xfe, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff,
   0xff, 0x1f, 0xf8, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0x07, 0xe0, 0xff,
   0xff, 0x03, 0xc0, 0xff, 0xf7, 0x01, 0x80, 0xef, 0x07, 0x00, 0x00, 0xe0,
   0x07, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xf0};
 
/////////////////////////////////////////////////
// Class declaration. Subclass VkCursorList
///////////////////////////////////////////////////
 
class HourGlassCursors : public VkCursorList {
    
  public:
    HourGlassCursors( );
 
  protected:
    void createCursor(int index);   // Overrides base class' pure virtual
 
  private:
    XColor  xcolors[2];    
};
// The constructor gets two colors to use for the cursor.
 
HourGlassCursors::HourGlassCursors ( ) :  VkCursorList ( NUMCURSORS )
{
    xcolors[0].pixel= (Pixel) VkGetResource(theApplication->baseWidget(), 
                                            "busyCursorForeground", 
                                            XmCForeground, 
                                            XmRPixel, 
                                            (char *) "Black");
    
    xcolors[1].pixel= (Pixel) VkGetResource(theApplication->baseWidget(), 
                                            "busyCursorBackground",
                                            XmCBackground, 
                                            XmRPixel, 
                                            char *) "White");
    XQueryColors (theApplication->display(),
                  DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
                  xcolors, 2);
}
 
// This function is called as needed, to create a new cursor frame.
// Just create the cursor corresponding to the requested index and
// install it in _cursorList.

void HourGlassCursors::createCursor(int index)
{
    Pixmap pixmap = 0, maskPixmap = 0;
    Display *dpy = theApplication->display();
    pixmap = XCreateBitmapFromData (dpy,
                                    DefaultRootWindow(dpy),
                                    time_bits[index],
                                    32, 32);
 
    if(index == 7)
        maskPixmap = XCreateBitmapFromData (dpy,
                                            DefaultRootWindow(dpy),
                                            time7_mask_bits,
                                            32, 32);
    else
        maskPixmap = XCreateBitmapFromData (dpy,
                                            DefaultRootWindow(dpy),
                                            time_mask_bits,
                                            32, 32);
 
    _cursorList[index] = XCreatePixmapCursor ( dpy, pixmap, maskPixmap,
                                               &(xcolors[0]), &(xcolors[1]),
                                               0, 0);
    if(pixmap)
        XFreePixmap (dpy, pixmap);
    if(maskPixmap)
        XFreePixmap (dpy, maskPixmap);
}

Once you have created an animated busy cursor, you can install it as your application's busy cursor using an overloaded version of the VkApp::setBusyCursor() function:

void setBusyCursor(VkCursorList *animatedCursor)

You should provide as the argument to setBusyCursor() a pointer to your animated busy cursor object.

When you use an animated busy cursor, the busyCursor() function returns the currently displayed pixmap of your busy cursor.

Setting and Retrieving a Temporary Cursor

You can set a temporary cursor for use in all of your application's windows using VkApp::showCursor():

void showCursor(Cursor c)

Calling showCursor() immediately displays the temporary cursor. The cursor stays in effect until the application enters or exits a busy state, or you reset the cursor back to the normal cursor by calling showCursor() with a NULL cursor argument.

Use this function to display a cursor only briefly. If you want to change the cursor for an extended period, use setNormalCursor() or setBusyCursor().

Supporting Busy States

This section describes ViewKit's support for busy states, when you lock out user input during an operation.

Entering and Exiting Busy States Using ViewKit

Whenever you expect a procedure to take considerable time to complete, you can call the VkApp::busy() function before entering the relevant region of code to lock out user input in all application windows:

virtual void busy(char *msg = NULL,
                  VkSimpleWindow window = NULL)

If you call busy() with no arguments, the application simply displays a busy cursor. If you provide a string as the first argument, the application posts a dialog to display the string. The string is treated first as a resource name that busy() looks up relative to the dialog widget. If the resource exists, its value is used as the message. If the resource does not exist, or if the string contains spaces or newline characters, busy() uses the string itself as the message.

If you provide a VkSimpleWindow (or subclass) as the second argument, the application posts the dialog over this specified window. If you do not specify a window, the application posts the dialog over the main window. (See “Managing Top-Level Windows” for instructions on setting the main window. See Chapter 7, “Using Dialogs in ViewKit,” for more details on dialog behavior.)

The VkApp::notBusy() function undoes the previous call to busy():

virtual void notBusy()

You can nest calls to busy(), but you must always have matching busy() and notBusy() pairs. An application exits the busy state only when the number of notBusy() calls matches the number of busy() calls.


Note: ViewKit does not “stack” nested busy dialogs, it simply displays the most recently posted busy dialog. Once you post a busy dialog, it remains displayed until the busy state is over or you replace it with another busy dialog.

Example 3-3 shows an example of setting busy dialog messages using resource values and using nested busy() and notBusy() calls. Note that this is not a complete example: it lists only the code relating to the busy states.

Example 3-3. Using Busy States in a ViewKit Application

class ReportWindow: public VkSimpleWindow {
 
  public:
    ReportWindow ( const char *name );
    ~ReportWindow();
    virtual const char* className();
    void report();
    void sort();
 
  private:
    static String _defaultResources[];
};
String _defaultResources[] = {
    "*sortDialogMsg:    Sorting records...",
    "*reportDialogMsg:  Generating report...",
    NULL
};
 
ReportWindow::ReportWindow(const char *name) : VkSimpleWindow ( name )
{
  setDefaultResources(theApplication->baseWidget(), _defaultResources);
  // Create window...
}
 
void ReportWindow::sort()
{
  theApplication->busy("sortDialogMsg");
  // Sort records...
  theApplication->notBusy(); 
}
 
void ReportWindow::report()
{
  theApplication->busy("reportDialogMsg");
  // Report generation...
  sort();
  // Report generation continued...
  theApplication->notBusy(); 
}

The ReportWindow class defines the busy dialog messages as resource values and loads these values using setDefaultResources() in the ReportWindow constructor.[2] The calls to busy() pass these resource names instead of passing the actual dialog text. This allows you to override these resource values in an app-defaults file should you need to.

When the application calls ReportWindow::report(), it posts the busy dialog shown in Figure 3-2.

Figure 3-2. Busy Dialog

Figure 3-2 Busy Dialog

When the application calls ReportWindow::sort(), it posts the busy dialog shown in Figure 3-3.

Figure 3-3. Nested Busy Dialog

Figure 3-3 Nested Busy Dialog

Note that the application continues to display the second busy dialog until reaching the theApplication->notBusy() statement in ReportWindow::report().

Animating the Busy Cursor

To animate the busy cursor during a busy state, periodically call VkApp::progressing():

virtual void progressing(const char *msg = NULL)

If you have an animated busy cursor installed, progressing() cycles to the next pixmap in the cursor list. If you have a fixed cursor installed, progressing() has no effect on the busy cursor.

If you provide a character string argument, your application posts a dialog to display the message. The string is treated first as a resource name that progressing() looks up relative to the dialog widget. If the resource exists, its value is used as the message. If the resource does not exist, or if the string contains spaces or newline characters, progressing() uses the string itself as the message.

The code fragment in Example 3-4 performs a simulated lengthy task and periodically cycles the busy cursor.

Example 3-4. Animating the Busy Cursor

int i;
 
// Start being "busy"
 
theApplication->busy("Busy", (BusyWindow *) clientData);
 
for(i=0; i<100; i++)
{
  // Every so often, update the busy cursor
  theApplication->progressing();
  sleep(1);
}
 
// Task done, so we're not busy anymore
theApplication->notBusy();


Installing Different Busy Dialogs

By default, busy() displays the dialog using theBusyDialog, a global pointer to an instantiation of the VkBusyDialog class[3] (described in “Busy Dialog”). If you prefer to use a different dialog object, you can pass a pointer to the object to the setBusyDialog() function:

void setBusyDialog(VkBusyDialog *dialog)

This alternate busy dialog must be implemented as a subclass of VkBusyDialog. Calling setBusyDialog() with a NULL argument restores the default VkBusyDialog object.

Most frequently, you will use setBusyDialog() to install theInterruptDialog, a global pointer to an instantiation of the VkInterruptDialog class, which implements an interruptible busy dialog[4] . (“Interruptible Busy Dialog” describes the VkInterruptDialog class.) Example 3-5 shows a typical example of temporarily installing an interruptible busy dialog for a task.

Alternatively, you might wish use theProgressDialog, a global pointer to an instantiation of the VkProgressDialog class. VkProgressDialog implements an interruptible busy dialog displaying a bar graph that indicates the percentage of the task that has been completed (see “Progress Dialog” for more details).

Example 3-5. Temporarily Installing an Interruptible Busy Dialog

#inlcude <Vk/VkApp.h>
#include <Vk/VkInterruptDialog.h>
 
// ...
 
// Install theInterruptDialog as the busy dialog
 
theApplication->setBusyDialog(theInterruptDialog);
theApplication->busy("Generating report");  // Enter busy state
 
// Perform task...
 
theApplication->notBusy();                  // Exit busy state
theApplication->setBusyDialog(NULL);        // Install default busy dialog


Maintaining Product and Version Information

The VkApp class provides several access functions and constant data members that you can use to identify your application and the current ViewKit release.

VkApp::ViewKitMajorRelease is a static integer constant that identifies the major release of ViewKit; VkApp::ViewKitMinorRelease is a static integer constant that identifies the minor release of ViewKit, and VkApp::ViewKitReleaseString is a static character array constant that contains the complete major and minor release information. For example, in a 1.2 release, the value of VkApp::ViewKitMajorRelease would be 1, the value of VkApp::ViewKitMinorRelease would be 2, and the value of VkApp::ViewKitReleaseString would be “ViewKit Release: 1.2”. These values can be useful if you need to provide conditional statements in your code to handle different versions of the ViewKit library.

You can use VkApp::setVersionString() to set version information for an application based on ViewKit:

void setVersionString(const char *versionInfo)

You can retrieve the version string using VkApp::versionString():

const char *versionString()

ViewKit displays this version string in the Product Information dialog that is posted when a user chooses Product Information from the default Help menu. (See “ViewKit Help Menu” for more information on the default Help menu.) For example, consider an application that you invoke with the command MapMaker that includes the following line of code:

theApplication->setVersionString("MapMaker 2.1");

If you choose Product Information from the default Help menu, your application posts the dialog shown in Figure 3-4.

Figure 3-4. Product Information Dialog

Figure 3-4 Product Information Dialog

You can use VkApp::setAboutDialog() to replace the standard Product Information dialog with your own custom dialog:

void setAboutDialog(VkDialogManager *dialog)

You must provide setAboutDialog() with a pointer to an object that is a subclass of VkDialogManager. Most frequently, you will actually create a subclass of VkGenericDialog, an abstract subclass of VkDialogManager that simplifies the process of creating custom dialogs. “Deriving New Dialog Classes Using the Generic Dialog” describes creating a custom dialog.

The VkApp::aboutDialog() function returns a pointer to the custom Product Information dialog you have installed:

VkDialogManager* aboutDialog()

Application Data Access Functions

VkApp provides several access functions for retrieving data useful for your application:

char *name() const 


Returns the command name you used to invoke the application (argv[0]).

char *applicationClassName() const 


Returns the application class name set in the VkApp constructor. This application class name is used when loading application resources.

virtual const char *className() const 


Returns the class name of the VkApp (or subclass) instance being used. By default, this is “VkApp.” Note that unlike all other ViewKit components, the VkApp class does not use the value returned by className() when loading resources; instead, it uses the application class name that you provide as an argument to the VkApp constructor. This allows you to set the application class name without creating a subclass of VkApp.

static void setFallbacks(char **fallbacks)  


Sets fallbacks as the specification list needed to call XtAppSetFallBackResources(3X). setFallbacks() must be called before the application constructs its VkApp object, since the VkApp constructor calls XtAppSetFallbackResources() and passes it the specification list.

XtAppContext appContext() const 


Returns the application's XtAppContext structure, which is required by many Motif and Xt functions.

Display *display() const 


Returns a pointer to the X Display structure associated with the application's connection to the X server.

char *shellGeometry() const 


Returns a string containing the geometry of the application's base shell. You may want to use this information to size other windows in your application.

int argc() const 


Returns the number of items remaining in the argv array after all arguments recognized by Xt have been removed.

char **argv() const 


Called without arguments, this function returns a pointer to the argv array after all arguments recognized by Xt have been removed.

char *argv(int index) const 


Called with an integer argument, this function returns a single argv array item (after all arguments recognized by Xt have been removed) specified by the index argument.

Boolean startupIconified() const 


Called with no arguments, this function returns the value TRUE if the application starts with all windows iconified and FALSE if it starts with all windows displayed normally.

Widget baseWidget() 


For the VkApp class, baseWidget() returns the hidden shell widget.

Deriving Classes From VkApp

This section describes VkApp protected functions and data members that you can use in a VkApp subclass. Following that is an example of subclassing VkApp to parse command-line options.

VkApp Protected Functions and Data Members

You can use VkApp::parseCommandLine() to parse command line options:

int parseCommandLine(XrmOptionDescRec *options,
                     Cardinal numOptions)

You should call parseCommandLine() from within the constructor of your VkApp subclass. Provide an XrmOptionDescRec(3Xt) table as the options argument and specify the number of entries in the table with the numOptions argument. parseCommandLine() passes these arguments to XtOpenDisplay(3Xt), which parses the command line and loads recognized options into the application's resource database. parseCommandLine() modifies argv to remove all recognized options and returns an updated value of argc. Example 3-6 shows an example of using parseCommandLine().

You can override VkApp::afterRealizeHook() to perform certain actions after all application windows have been realized:

virtual void afterRealizeHook()

For example, you could override afterRealizeHook() to install a colormap or set properties on the application's windows. By default, this function is empty.

When subclassing VkApp, you also have access to the protected data member VkApp::_winList:

VkComponentList _winList

This data member maintains the list of the application's top-level windows. Consult the VkComponentList(3x) reference page for more information on the VkComponentList class.

Subclassing VkApp

The most common reason for creating a subclass of VkApp is to parse the command line and set global resources based on command-line options. Also, rather than use global variables, you can store data that is needed throughout your application in data members of your VkApp subclass.

The program in Example 3-6 creates MyApp, a VkApp subclass that recognizes a -verbose command-line argument and initializes a protected data member depending on whether or not the flag is present.

Note that this example uses the protected VkApp function parseCommandLine() to extract the flag if it exists. This function returns an updated value that the calling application must use to update its value of argc.

Example 3-6. Deriving a Subclass From VkApp

#include <Vk/VkApp.h>
#include <Vk/VkResource.h>
 
class MyApp : public VkApp {
 
  public:
    MyApp(char             *appClassName,
          int              *arg_c,
          char            **arg_v,
          XrmOptionDescRec *optionList       = NULL,
          int               sizeOfOptionList = 0);
    Boolean verbose() { return _verbose; }       // Access function
 
  protected:
    Boolean   _verbose;                         // Data member to initialize
 
  private:
    static XrmOptionDescRec _cmdLineOptions[];  // Command-line options
    static XtResource _resources[];             // Resource descriptions
};
 
// Describe the command line options
 
XrmOptionDescRec MyApp::_cmdLineOptions[] = 
{
    {
    "-verbose", "*verbose", XrmoptionNoArg, "TRUE",
    },
};
 
// Describe the resources to retrieve and use to initialize the class
 
XtResource MyApp::_resources [] = {
{
    "verbose", 
    "Verbose", 
    XmRBoolean, 
    sizeof ( Boolean ),
    XtOffset ( MyApp *, _verbose ), 
    XmRString,
    (XtPointer) "FALSE",
  },
};
MyApp::MyApp(char    *appClassName,
    int              *arg_c, 
    char            **arg_v,
    XrmOptionDescRec *optionList,
    int               sizeOfOptionList) : VkApp(appClassName, arg_c, 
                                                arg_v, optionList,
                                                sizeOfOptionList)
{
    // Parse the command line, loading options into the resource database
 
    *arg_c = parseCommandLine(_cmdLineOptions,
                              XtNumber(_cmdLineOptions));
 
    // Initialize this class from the resource data base
 
    getResources (_resources, XtNumber(_resources));
}


Putting Applications in the Overlay Planes

By default, the unrealized VkApp shell appears in the normal planes. That sets the normal planes as the default for all of its descendents as well. ViewKit, however, allows you to explicitly place your application shell, and therefore all of its descendents, in the overlay planes. Doing so prevents your application from causing expose events that disturb such things as complex GL rendering in other applications that are using the normal planes.

There are three ways to enable applications in the overlay planes:

  • Call VkApp::useOverlayApps(TRUE). This forces applications into the overlay planes, with no way to put them back in the normal planes without recompiling.

  • Put the resource string “*useOverlayApps:True” in your application's default file. This will put applications in the overlay planes by default, but allow users to use the normal planes by changing their .Xdefaults file.


    Note: This is an application-specific resource. There is no class resource, so “*UseOverlayApps” is not supported.


  • Have users add the -useOverlayApps command-line switch when they run your application if they wish to use the overlay planes for applications.

If you do decide to place applications in the overlay planes, here are some factors to consider:

  • Applications are placed in the deepest available overlay planes: generally 4- or 8-bit planes, occasionally 2-bit planes.

  • If the deepest available overlay is 2 bits, any applications placed in that visual may not look right. Because the colormap in the 2-bit overlay planes only has three color entries (the fourth being a transparent pixel), any items in the application other than labels (for example cascade or toggle buttons) may look odd.

  • Other applications using the overlay planes may display in the wrong colors when your application gets colormap focus. The colors in the other applications may flash because your application's colormap is installed and replaces any previous overlay colormap.

    
    



[2] Unlike most ViewKit components, the VkSimpleWindow class constructor is not passed a parent widget. All ViewKit windows are children of the application's VkApp base widget. So, to access a window's parent widget, you must use the VkApp::baseWidget() access function as shown in this example.

[3] theBusyDialog is actually implemented as a compiler macro that invokes a VkBusyDialog access function to return a pointer to the unique instantiation of the VkBusyDialog class. Although you should never need to use this access function directly, you might encounter it while debugging a ViewKit application that uses the busy dialog.

[4] theInterruptDialog is actually implemented as a compiler macro that invokes a VkInterruptDialog access function to return a pointer to the unique instantiation of the VkInterruptDialog class. Although you should never need to use this access function directly, you might encounter it while debugging a ViewKit application that uses the interruptible busy dialog.