Deriving Window Subclasses

This section summarizes how to create subclasses from the ViewKit ObjectPak window classes. It describes additional virtual functions and data members not covered in previous sections, provides a window creation checklist, and shows an example of deriving a window subclass.

Additional Virtual Functions and Data Members

In addition to the functions described in previous sections, the ObjectPak window classes provide a number of virtual functions and data members that you can access from window subclasses. These functions and data allow you to perform the following tasks:

  • Provide a "safe quit" mechanism for your window
  • Determine your window's state and perform actions on state changes
  • Perform actions after realizing a window
  • Handle raw events not normally handled by the Xt dispatch mechanism

Providing a "safe quit" mechanism

The VkComponent class provides the virtual function okToQuit() to support "safe quit" mechanisms:

virtual Boolean okToQuit()

A component's okToQuit() function returns TRUE if it is "safe" for the application to quit. For example, you might want okToQuit() to return FALSE if a component is in the process of updating a file. By default, okToQuit() always returns TRUE; you must override okToQuit() for all components that you want to perform a check before quitting. Usually, only VkSimpleWindow and its subclasses use okToQuit().

When you call VkApp::quitYourself(), VkApp calls the okToQuit() function for all registered windows before quitting. If the okToQuit() function for any window returns FALSE, the application does not exit. ("Exiting ViewKit ObjectPak Applications" describes VkApp::quitYourself().)

Also, the window's handleWmDeleteMessage() function calls okToQuit() when the window receives a WM_DELETE_WINDOW message from the window manager. This determines whether it is safe to delete the window. ("Window Properties and Shell Resources" describes handleWmDeleteMessage().)

To perform a test to see whether it is safe to delete a window, override the window's okToQuit() function. If you want to check one or more components contained within a window, you can override the window's okToQuit() function so that it calls the okToQuit() functions for all the desired components. You can then override the okToQuit() functions for the other components so you can perform whatever checks or shutdown actions are necessary. For example, you could post a blocking dialog asking whether the user wants to save data before quitting. ( Chapter 7--Using Dialogs describes how to use ViewKit ObjectPak dialogs.)

Determining window states

The ObjectPak window classes provide the following protected data members for determining the current states of a window:

IconState _iconState Contains an enumerated constant of type IconState that describes the current iconification state of the window. This variable contains OPEN if the window is not iconified, CLOSED if it is iconified, and ICON_UNKNOWN if it is in an unknown state. (Typically, the unknown state is used only internally to the VkSimpleWindow class.)

VisibleState _visibleState Contains an enumerated constant of type VisibleState that describes the current visibility state of the window. This variable contains VISIBLE if the window is visible, HIDDEN if it is not visible, and VISIBLE_UNKNOWN if it is in an unknown state. (Typically, the unknown state occurs only before you add a view to your window.)

StackingState _stackingState Contains an enumerated constant of type StackingState that describes the current stacking state of the window relative to the application. This variable contains RAISED if the window is at the top of the application's window stack, LOWERED if it is at the bottom of the window stack, and STACKING_UNKNOWN if it is in an unknown state (the state before you make any calls to raise() or lower() on this window).

If you need to perform any operations when your window changes its iconification state, you can override stateChanged():

virtual void stateChanged(IconState newState)

stateChanged() is called whenever the window's iconification state changes, whether programmatically (by calls to iconify() and open()) or through window manager interaction. Because this function is responsible for maintaining the window's state information, if you override this function in a subclass you should call the base class's stateChanged() function before performing any additional operations.

Performing actions after realizing a window

To perform certain actions only after a window exists, you can override the afterRealizeHook() function inherited from VkComponent:

virtual void afterRealizeHook()


Note: Use setUpWindowProperties() to set window properties instead of afterRealizeHook(). The difference between afterRealizeHook() and setUpWindowProperties() is that setUpWindowProperties() is guaranteed to be called before the window manager is notified of the window's existence. Because of race conditions, this might not be true of afterRealizeHook(), which is appropriate for performing actions that do not affect the window's interaction with the window manager.


Handling raw events

Handle events not normally handled by the Xt dispatch mechanism by overriding the window's handleRawEvent() function:

virtual void handleRawEvent(XEvent *event)

As described in "ViewKit ObjectPak Event Handling" , VkApp::run() supports events not normally handled by the Xt dispatch mechanism. For example, VkApp::run() can handle client messages and 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(), which passes the event to the handleRawEvent() function of each instance of VkSimpleWindow (or subclass) in the application. By default, these member functions are empty.

If you want a window to handle events through this mechanism, call XSelectInput(3) to select the events that you want to receive, and override handleRawEvent() in the VkSimpleWindow subclass to implement your event processing.

Additional Data Members

The ObjectPak window classes also provide the protected data member _mainWindowWidget:

Widget _mainWindowWidget

_mainWindowWidget contains the XmMainWindow widget created by the window constructor. In a subclass, you can use this data member instead of calling mainWindowWidget(), although this is not recommended.

Window Creation Summary

The following lists a summary of guidelines for creating subclasses of the ObjectPak window classes:

  • Decide whether this window requires a menu bar. If it does, derive your subclass from VkWindow; otherwise, derive it from VkSimpleWindow.
  • In most cases where you provide a menu bar for your window, you should create it in the window class when you create the rest of your window's interface.
  • Determine whether users will often use your application without displaying this window even after the object is instantiated. If so, and the window interface is large or complex, you might consider creating the window interface using setUpInterface() to reduce the time it takes to start your application; otherwise, create the interface in the window's constructor.
  • Implement the window interface as a single-rooted widget subtree whose parent is the window's XmMainWindow widget (obtained by the mainWindowWidget() function). While some windows might contain only a single complex component, the majority of windows must create some type of container widget as the root of the window's interface; all other widgets and components are descendents of this widget.
  • Do not assign any widget to the _baseWidget data member. The ViewKit ObjectPak window classes assign the window's popup shell widget to _baseWidget.
  • Wherever appropriate, use resource values to set labels, other interface characteristics, and user-configurable component behavior. Define a default resource list as a static member variable of your window class, and call setDefaultResources() to set your window's default resources before creating the window interface.
  • Override the className() function to return the name of your window's class.
  • In addition to the widgets and components composing the window's interface, encapsulate any other required data and support functions as members of your window class.
  • If you explicitly allocate any memory in your derived window class, remember to free it in the window's destructor.
  • To explicitly set your window's title or its icon's title, call setTitle() or setIconName() respectively. You can also set these characteristics using the normal resource mechanisms.
  • To provide a "safe quit" mechanism for your window, override okToQuit() to perform any checking you want to perform before deleting the window.
  • To change how your window handles a WM_DELETE_MESSAGE from the window manager, override handleWmDeleteMessage().
  • To change how your window handles a WM_QUIT_APP from the window manager, override handleWmQuitMessage().
  • To set any additional properties on your window, override setUpWindowProperties().
  • To change the value of the window manager class hint stored on a window, call setClassHint().
  • To perform certain actions only after the window exists, override afterRealizeHook().
  • To handle events not normally handled by the Xt dispatch mechanism, call XSelectInput(3) to select the events that you want to receive, and override handleRawEvent() in your window subclass to implement your event processing.

Window Subclassing Example

The program in Example 22. creates ColorWindow, a VkSimpleWindow subclass that implements a simple utility for determining the results of mixing primary ink colors when printing. The user can use toggles to select any of the three primary colors--cyan, magenta, and yellow--and the window reports the resulting color.

Figure 14. shows the widget hierarchy of the ColorWindow subclass. The VkSimpleWindow constructor creates the window's popup shell and XmMainWindow widget. The ColorWindow constructor creates a Form widget to serve as the window's view. The constructor adds a VkCheckBox component as a child of the Form to provide the toggle buttons.

The constructor then adds a Frame widget as a child of the Form widget, and creates two Label gadgets as children of the Frame:

  • A Label gadget to serve as a title
  • A label gadget to report the resulting color

The constructor manages all of these widgets except for the top-level Form widget. (The constructor manages the VkCheckBox component by calling its show() member function.)

Figure 14. Widget Hierarchy of ColorWindow Subclass

This example illustrates a number of object-oriented techniques that you should follow when programming in ViewKit ObjectPak.


Note: All data and utility functions used by the window are declared as members of the ColorWindow class. ColorWindow uses resources to set all the text that it displays, including a set of default values. You can override these values in a resource file (for example, to provide German-language equivalents for all the strings).


Example 22. Creating a Window Subclass

Code

///////////////////////////
// ColorWindow.h
///////////////////////////
#include <Vk/VkSimpleWindow.h>
#include <Vk/VkCheckBox.h>
class ColorWindow: public VkSimpleWindow {
public:
ColorWindow (const char *);
~ColorWindow();
virtual const char* className();
private:
void displayColor(char *);
void colorChanged(VkCallbackObject *, void *, void *);
static String _defaultResources[]; // Default resource values
static String _colors[]; // Array of possible resulting colors
Widget _resultColor; // Label to display resulting color
VkCheckBox *_primaries; // Checkbox for setting colors
int _colorStatus; // Bit-wise color status variable
// Bit 0: Cyan
// Bit 1: Magenta
// Bit 2: Yellow
// Also used as index into _colors[]
};
///////////////////////////
// ColorWindow.C
///////////////////////////
#include "ColorWindow.h"
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Frame.h>
#include <Xm/LabelG.h>
#include <Vk/VkCheckBox.h>
#include <Vk/VkResource.h>
// Default ColorWindow class resource values.
String ColorWindow::_defaultResources[] = {
"*windowTitle: Color Mixer",
"*iconTitle: Color Mixer",
"*primaries*label*labelString: Primary Colors",
"*cyan.labelString: Cyan",
"*magenta.labelString: Magenta",
"*yellow.labelString: Yellow",
"*resultLabel.labelString: Resulting Color",
"*cyan: Cyan",
"*magenta: Magenta",
"*yellow: Yellow",
"*blue: Blue",
"*red: Red",
"*green: Green",
"*white: White",
"*black: Black",
NULL };
// Set _colors array to correspond to color values indicated by the
// bits in the _colorStatus variable.
String ColorWindow::_colors[] = {
"white",
"cyan",
"magenta",
"blue",
"yellow",
"green",
"red",
"black" };
ColorWindow::ColorWindow (const char *name) : VkSimpleWindow (name)
{
Arg args[5];
int n;
// Set default resources for the window.
setDefaultResources(mainWindowWidget(), _defaultResources);
// Create a Form widget to use as the window's view.
Widget _form = XmCreateForm(mainWindowWidget(), "form", NULL, 0);
// Create a VkCheckBox object to allow users to select primary colors.
// Add toggle buttons and set their intial values to FALSE (unselected).
// The labels for the checkbox frame and the toggle buttons are set
// by the resouce database.
_primaries = new VkCheckBox( "primaries", _form );
_primaries->addItem("cyan", FALSE);
_primaries->addItem("magenta", FALSE);
_primaries->addItem("yellow", FALSE);
_primaries->addCallback(VkCheckBox::itemChangedCallback, this,
(VkCallbackMethod) &ColorWindow::colorChanged);
_primaries->show();
// Set constraint resources on checkbox's base widget.
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetValues(_primaries->baseWidget(), args, n);
// Create a frame to display the name of the resulting blended color.
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNleftWidget, _primaries->baseWidget()); n++;
Widget _result = XmCreateFrame(_form, "result", args, n);
XtManageChild(_result);
// Create a frame title label. The label text is set by the resource
// database.
n = 0;
XtSetArg(args[n], XmNchildType, XmFRAME_TITLE_CHILD); n++;
Widget _resultLabel = XmCreateLabelGadget( _result, "resultLabel", args, n);
// Create the label to display the blended color name.
_resultColor = XmCreateLabelGadget( _result, "resultColor", NULL, 0);
// Set intial value of _colorStatus and label string to white (all off).
_colorStatus = 0;
displayColor(_colors[_colorStatus]);
XtManageChild(_resultLabel);
XtManageChild(_resultColor);
// Add the top-level Form widget as the window's view.
addView(_form);
// Set the window title and the icon title.
setTitle("windowTitle");
setIconName("iconTitle");
}
ColorWindow::~ColorWindow()
{
// Empty
}
const char* ColorWindow::className()
{
return "ColorWindow";
}
// Given a color name, update the label to display the color
void ColorWindow::displayColor(char *newColor)
{
Arg args[2];
int n;
// Common resource trick in ObjectPak applications.
// Given a string, check the resource database for a corresponding
// value. If none exists, use the string as the value.
char *_colorName = (char *) VkGetResource(_baseWidget, newColor, "Color",
XmRString, newColor);
// Update the label
XmString _label = XmStringCreateSimple(_colorName);
n = 0;
XtSetArg(args[n], XmNlabelString, _label); n++;
XtSetValues(_resultColor, args, n);
XmStringFree(_label);
}
// When the user changes the value of one of the toggles, update the
// display to show the new blended color.
void ColorWindow::colorChanged(VkCallbackObject *obj, void *, void *callData)
{
ColorWindow *win = (ColorWindow *) obj;
int index = (int) callData;
// Update color status based on toggle value. Set or rest the
// status bit corresponding to the respective toggle.
if (_primaries->getValue(index))
_colorStatus |= 1<<index;
else
_colorStatus &= ~(1<<index);
// Update the display to show the new blended color, using
// _colorStatus as an index.
displayColor(_colors[_colorStatus]);
}
///////////////////////////
// colors.C
///////////////////////////
#include <Vk/VkApp.h>
#include "ColorWindow.h"
void main ( int argc, char **argv )
{
VkApp *colorApp = new VkApp("ColorApp", &argc, argv);
ColorWindow *colorWin = new ColorWindow("colorWin");
colorWin->show();
colorApp->run();
}

The colors program displays the ColorWindow shown in Figure 15.

Figure 15. Example of the ColorWindow Window Subclass

This section summarizes how to create subclasses from the ViewKit ObjectPak window classes. It describes additional virtual functions and data members not covered in previous sections, provides a window creation checklist, and shows an example of deriving a window subclass.

Additional Virtual Functions and Data Members

In addition to the functions described in previous sections, the ObjectPak window classes provide a number of virtual functions and data members that you can access from window subclasses. These functions and data allow you to perform the following tasks:

  • Provide a "safe quit" mechanism for your window
  • Determine your window's state and perform actions on state changes
  • Perform actions after realizing a window
  • Handle raw events not normally handled by the Xt dispatch mechanism

Providing a "safe quit" mechanism

The VkComponent class provides the virtual function okToQuit() to support "safe quit" mechanisms:

virtual Boolean okToQuit()

A component's okToQuit() function returns TRUE if it is "safe" for the application to quit. For example, you might want okToQuit() to return FALSE if a component is in the process of updating a file. By default, okToQuit() always returns TRUE; you must override okToQuit() for all components that you want to perform a check before quitting. Usually, only VkSimpleWindow and its subclasses use okToQuit().

When you call VkApp::quitYourself(), VkApp calls the okToQuit() function for all registered windows before quitting. If the okToQuit() function for any window returns FALSE, the application does not exit. ("Exiting ViewKit ObjectPak Applications" describes VkApp::quitYourself().)

Also, the window's handleWmDeleteMessage() function calls okToQuit() when the window receives a WM_DELETE_WINDOW message from the window manager. This determines whether it is safe to delete the window. ("Window Properties and Shell Resources" describes handleWmDeleteMessage().)

To perform a test to see whether it is safe to delete a window, override the window's okToQuit() function. If you want to check one or more components contained within a window, you can override the window's okToQuit() function so that it calls the okToQuit() functions for all the desired components. You can then override the okToQuit() functions for the other components so you can perform whatever checks or shutdown actions are necessary. For example, you could post a blocking dialog asking whether the user wants to save data before quitting. ( Chapter 7--Using Dialogs describes how to use ViewKit ObjectPak dialogs.)

Determining window states

The ObjectPak window classes provide the following protected data members for determining the current states of a window:

IconState _iconState Contains an enumerated constant of type IconState that describes the current iconification state of the window. This variable contains OPEN if the window is not iconified, CLOSED if it is iconified, and ICON_UNKNOWN if it is in an unknown state. (Typically, the unknown state is used only internally to the VkSimpleWindow class.)

VisibleState _visibleState Contains an enumerated constant of type VisibleState that describes the current visibility state of the window. This variable contains VISIBLE if the window is visible, HIDDEN if it is not visible, and VISIBLE_UNKNOWN if it is in an unknown state. (Typically, the unknown state occurs only before you add a view to your window.)

StackingState _stackingState Contains an enumerated constant of type StackingState that describes the current stacking state of the window relative to the application. This variable contains RAISED if the window is at the top of the application's window stack, LOWERED if it is at the bottom of the window stack, and STACKING_UNKNOWN if it is in an unknown state (the state before you make any calls to raise() or lower() on this window).

If you need to perform any operations when your window changes its iconification state, you can override stateChanged():

virtual void stateChanged(IconState newState)

stateChanged() is called whenever the window's iconification state changes, whether programmatically (by calls to iconify() and open()) or through window manager interaction. Because this function is responsible for maintaining the window's state information, if you override this function in a subclass you should call the base class's stateChanged() function before performing any additional operations.

Performing actions after realizing a window

To perform certain actions only after a window exists, you can override the afterRealizeHook() function inherited from VkComponent:

virtual void afterRealizeHook()


Note: Use setUpWindowProperties() to set window properties instead of afterRealizeHook(). The difference between afterRealizeHook() and setUpWindowProperties() is that setUpWindowProperties() is guaranteed to be called before the window manager is notified of the window's existence. Because of race conditions, this might not be true of afterRealizeHook(), which is appropriate for performing actions that do not affect the window's interaction with the window manager.


Handling raw events

Handle events not normally handled by the Xt dispatch mechanism by overriding the window's handleRawEvent() function:

virtual void handleRawEvent(XEvent *event)

As described in "ViewKit ObjectPak Event Handling" , VkApp::run() supports events not normally handled by the Xt dispatch mechanism. For example, VkApp::run() can handle client messages and 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(), which passes the event to the handleRawEvent() function of each instance of VkSimpleWindow (or subclass) in the application. By default, these member functions are empty.

If you want a window to handle events through this mechanism, call XSelectInput(3) to select the events that you want to receive, and override handleRawEvent() in the VkSimpleWindow subclass to implement your event processing.

Additional Data Members

The ObjectPak window classes also provide the protected data member _mainWindowWidget:

Widget _mainWindowWidget

_mainWindowWidget contains the XmMainWindow widget created by the window constructor. In a subclass, you can use this data member instead of calling mainWindowWidget(), although this is not recommended.

Window Creation Summary

The following lists a summary of guidelines for creating subclasses of the ObjectPak window classes:

  • Decide whether this window requires a menu bar. If it does, derive your subclass from VkWindow; otherwise, derive it from VkSimpleWindow.
  • In most cases where you provide a menu bar for your window, you should create it in the window class when you create the rest of your window's interface.
  • Determine whether users will often use your application without displaying this window even after the object is instantiated. If so, and the window interface is large or complex, you might consider creating the window interface using setUpInterface() to reduce the time it takes to start your application; otherwise, create the interface in the window's constructor.
  • Implement the window interface as a single-rooted widget subtree whose parent is the window's XmMainWindow widget (obtained by the mainWindowWidget() function). While some windows might contain only a single complex component, the majority of windows must create some type of container widget as the root of the window's interface; all other widgets and components are descendents of this widget.
  • Do not assign any widget to the _baseWidget data member. The ViewKit ObjectPak window classes assign the window's popup shell widget to _baseWidget.
  • Wherever appropriate, use resource values to set labels, other interface characteristics, and user-configurable component behavior. Define a default resource list as a static member variable of your window class, and call setDefaultResources() to set your window's default resources before creating the window interface.
  • Override the className() function to return the name of your window's class.
  • In addition to the widgets and components composing the window's interface, encapsulate any other required data and support functions as members of your window class.
  • If you explicitly allocate any memory in your derived window class, remember to free it in the window's destructor.
  • To explicitly set your window's title or its icon's title, call setTitle() or setIconName() respectively. You can also set these characteristics using the normal resource mechanisms.
  • To provide a "safe quit" mechanism for your window, override okToQuit() to perform any checking you want to perform before deleting the window.
  • To change how your window handles a WM_DELETE_MESSAGE from the window manager, override handleWmDeleteMessage().
  • To change how your window handles a WM_QUIT_APP from the window manager, override handleWmQuitMessage().
  • To set any additional properties on your window, override setUpWindowProperties().
  • To change the value of the window manager class hint stored on a window, call setClassHint().
  • To perform certain actions only after the window exists, override afterRealizeHook().
  • To handle events not normally handled by the Xt dispatch mechanism, call XSelectInput(3) to select the events that you want to receive, and override handleRawEvent() in your window subclass to implement your event processing.

Window Subclassing Example

The program in Example 22. creates ColorWindow, a VkSimpleWindow subclass that implements a simple utility for determining the results of mixing primary ink colors when printing. The user can use toggles to select any of the three primary colors--cyan, magenta, and yellow--and the window reports the resulting color.

Figure 14. shows the widget hierarchy of the ColorWindow subclass. The VkSimpleWindow constructor creates the window's popup shell and XmMainWindow widget. The ColorWindow constructor creates a Form widget to serve as the window's view. The constructor adds a VkCheckBox component as a child of the Form to provide the toggle buttons.

The constructor then adds a Frame widget as a child of the Form widget, and creates two Label gadgets as children of the Frame:

  • A Label gadget to serve as a title
  • A label gadget to report the resulting color

The constructor manages all of these widgets except for the top-level Form widget. (The constructor manages the VkCheckBox component by calling its show() member function.)

Figure 14. Widget Hierarchy of ColorWindow Subclass

This example illustrates a number of object-oriented techniques that you should follow when programming in ViewKit ObjectPak.


Note: All data and utility functions used by the window are declared as members of the ColorWindow class. ColorWindow uses resources to set all the text that it displays, including a set of default values. You can override these values in a resource file (for example, to provide German-language equivalents for all the strings).


Example 22. Creating a Window Subclass

Code

///////////////////////////
// ColorWindow.h
///////////////////////////
#include <Vk/VkSimpleWindow.h>
#include <Vk/VkCheckBox.h>
class ColorWindow: public VkSimpleWindow {
public:
ColorWindow (const char *);
~ColorWindow();
virtual const char* className();
private:
void displayColor(char *);
void colorChanged(VkCallbackObject *, void *, void *);
static String _defaultResources[]; // Default resource values
static String _colors[]; // Array of possible resulting colors
Widget _resultColor; // Label to display resulting color
VkCheckBox *_primaries; // Checkbox for setting colors
int _colorStatus; // Bit-wise color status variable
// Bit 0: Cyan
// Bit 1: Magenta
// Bit 2: Yellow
// Also used as index into _colors[]
};
///////////////////////////
// ColorWindow.C
///////////////////////////
#include "ColorWindow.h"
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Frame.h>
#include <Xm/LabelG.h>
#include <Vk/VkCheckBox.h>
#include <Vk/VkResource.h>
// Default ColorWindow class resource values.
String ColorWindow::_defaultResources[] = {
"*windowTitle: Color Mixer",
"*iconTitle: Color Mixer",
"*primaries*label*labelString: Primary Colors",
"*cyan.labelString: Cyan",
"*magenta.labelString: Magenta",
"*yellow.labelString: Yellow",
"*resultLabel.labelString: Resulting Color",
"*cyan: Cyan",
"*magenta: Magenta",
"*yellow: Yellow",
"*blue: Blue",
"*red: Red",
"*green: Green",
"*white: White",
"*black: Black",
NULL };
// Set _colors array to correspond to color values indicated by the
// bits in the _colorStatus variable.
String ColorWindow::_colors[] = {
"white",
"cyan",
"magenta",
"blue",
"yellow",
"green",
"red",
"black" };
ColorWindow::ColorWindow (const char *name) : VkSimpleWindow (name)
{
Arg args[5];
int n;
// Set default resources for the window.
setDefaultResources(mainWindowWidget(), _defaultResources);
// Create a Form widget to use as the window's view.
Widget _form = XmCreateForm(mainWindowWidget(), "form", NULL, 0);
// Create a VkCheckBox object to allow users to select primary colors.
// Add toggle buttons and set their intial values to FALSE (unselected).
// The labels for the checkbox frame and the toggle buttons are set
// by the resouce database.
_primaries = new VkCheckBox( "primaries", _form );
_primaries->addItem("cyan", FALSE);
_primaries->addItem("magenta", FALSE);
_primaries->addItem("yellow", FALSE);
_primaries->addCallback(VkCheckBox::itemChangedCallback, this,
(VkCallbackMethod) &ColorWindow::colorChanged);
_primaries->show();
// Set constraint resources on checkbox's base widget.
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetValues(_primaries->baseWidget(), args, n);
// Create a frame to display the name of the resulting blended color.
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNleftWidget, _primaries->baseWidget()); n++;
Widget _result = XmCreateFrame(_form, "result", args, n);
XtManageChild(_result);
// Create a frame title label. The label text is set by the resource
// database.
n = 0;
XtSetArg(args[n], XmNchildType, XmFRAME_TITLE_CHILD); n++;
Widget _resultLabel = XmCreateLabelGadget( _result, "resultLabel", args, n);
// Create the label to display the blended color name.
_resultColor = XmCreateLabelGadget( _result, "resultColor", NULL, 0);
// Set intial value of _colorStatus and label string to white (all off).
_colorStatus = 0;
displayColor(_colors[_colorStatus]);
XtManageChild(_resultLabel);
XtManageChild(_resultColor);
// Add the top-level Form widget as the window's view.
addView(_form);
// Set the window title and the icon title.
setTitle("windowTitle");
setIconName("iconTitle");
}
ColorWindow::~ColorWindow()
{
// Empty
}
const char* ColorWindow::className()
{
return "ColorWindow";
}
// Given a color name, update the label to display the color
void ColorWindow::displayColor(char *newColor)
{
Arg args[2];
int n;
// Common resource trick in ObjectPak applications.
// Given a string, check the resource database for a corresponding
// value. If none exists, use the string as the value.
char *_colorName = (char *) VkGetResource(_baseWidget, newColor, "Color",
XmRString, newColor);
// Update the label
XmString _label = XmStringCreateSimple(_colorName);
n = 0;
XtSetArg(args[n], XmNlabelString, _label); n++;
XtSetValues(_resultColor, args, n);
XmStringFree(_label);
}
// When the user changes the value of one of the toggles, update the
// display to show the new blended color.
void ColorWindow::colorChanged(VkCallbackObject *obj, void *, void *callData)
{
ColorWindow *win = (ColorWindow *) obj;
int index = (int) callData;
// Update color status based on toggle value. Set or rest the
// status bit corresponding to the respective toggle.
if (_primaries->getValue(index))
_colorStatus |= 1<<index;
else
_colorStatus &= ~(1<<index);
// Update the display to show the new blended color, using
// _colorStatus as an index.
displayColor(_colors[_colorStatus]);
}
///////////////////////////
// colors.C
///////////////////////////
#include <Vk/VkApp.h>
#include "ColorWindow.h"
void main ( int argc, char **argv )
{
VkApp *colorApp = new VkApp("ColorApp", &argc, argv);
ColorWindow *colorWin = new ColorWindow("colorWin");
colorWin->show();
colorApp->run();
}

The colors program displays the ColorWindow shown in Figure 15.

Figure 15. Example of the ColorWindow Window Subclass