Chapter 15. ViewKit Process Control Classes

Viewkit provides several process control classes: the VkRunOnce and VkRunOnce2 classes allow applications to specify that only a single instance of the application can be run on a system at any one time; the VkBackground class provides a simple C++ interface for handling background tasks based on Xt work procedures; and the VkPeriodic class provides a simple, convenient interface to the Xt time-out mechanism. Figure 15-1 shows the inheritance graph for these classes.

Figure 15-1. Inheritance Graph for the ViewKit Process Control Classes

Figure 15-1 Inheritance Graph for the ViewKit Process Control Classes

VkRunOnce and VkRunOnce2

VkRunOnce and VkRunOnce2 can be useful when implementing applications that are meant to provide a system-wide service for multiple applications. For example, an audio control program that controls the volume and other parameters on a system would not normally need to have multiple instantiations. However, various programs or scripts might wish to launch the application, but have no way to check whether it is already running.

Using VkRunOnce and VkRunOnce2, such applications can be launched as many times as necessary. Only the first instance actually displays the program. Subsequent attempts notify the running instance, possibly passing some arguments. The running instance raises itself and responds to any arguments provided. The second instance of the application simply exits.

The two main differences between VkRunOnce2 and VkRunOnce are that VkRunOnce2 is more flexible and can be invoked before instantiating VkApp. This can prove more efficient, because an application can attempt to notify the currently running process before it starts the possibly time-consuming initialization process. If this is the first instance of the application to be launched, however, VkRunOnce2 is less efficient, since it opens the X display twice.

VkRunOnce Constructor and Destructor

The VkRunOnce constructor initializes a VkRunOnce object:

VkRunOnce(VkNameList *args, Boolean per_host = FALSE, 
          const char *name = NULL, Boolean auto_Raise = TRUE)

If there is no other instance of the application running on this system, the VkRunOnce constructor establishes the new instance as the sole runable instance for that particular application. Normally, “running on this system” is defined to mean an application whose X DISPLAY is set to the current display device. If per_host is TRUE, multiple instances are allowed on any given display, so long as each instance is running on a different host. If autoRaise is TRUE, the running application is raised when another instance is started. name is the name of the application.

When another instance of the application is started, the VkRunOnce constructor makes contact with the running instance, passing it any arguments supplied in the args parameter. The constructor then causes the second instance of the application to exit by calling VkApp::terminate().

The VkRunOnce destructor is as follows:

~VkRunOnce()

If the running application deletes its VkRunOnce object, and another instance of the application is launched, the new instance will be allowed to run.

Access Functions

  • arg()

    char *arg(int index)
    

    Returns the string at the position indicated by index in the VkNameList.

  • className()

    virtual const char* className()
    

    Returns the class name. The class name of this class is “VkRunOnce.”

  • numArgs()

    int numArgs()
    

    Returns the number of arguments in the VkNameList.

Using VkRunOnce

The program in Example 15-1 displays a string in a window. After the first instance, subsequent instances of the program pass the first command-line argument to the running instance, to be displayed as a string in the application's window. This program can also be found in /usr/share/src/ViewKit/Utilities.

Example 15-1. Using VkRunOnce

 
#include <Vk/VkApp.h>
#include <Vk/VkRunOnce.h>
#include <Vk/VkNameList.h>
#include <Vk/VkSimpleWindow.h>
#include <Xm/Label.h>
 
// Define a top-level window class
 
class RunOnceWindow : public VkSimpleWindow {
 
    Widget _label;
 
    public:
 
        RunOnceWindow ( const char *name );
        ~RunOnceWindow();
        void update(VkComponent *comp, XtPointer, XtPointer);
 
        virtual const char* className();
};
 
RunOnceWindow::RunOnceWindow ( const char *name ) : VkSimpleWindow ( name ) 
{ 
    _label =  XmCreateLabel ( mainWindowWidget(), “hello”, NULL, 0 );
    
    addView(_label);
} 
 
 
RunOnceWindow::~RunOnceWindow()
{
    // Empty
}
 
const char* RunOnceWindow::className() { return “RunOnceWindow”; }
 
void RunOnceWindow::update(VkComponent *comp, XtPointer, XtPointer)
{
    // Just retrieve the arguments, Use the first string as a new label
    // for the widget and the second as a color.
 
    VkRunOnce *obj = (VkRunOnce*) comp;
 
    if(obj->numArgs() > 0)
    {
        XmString xmstr = XmStringCreateLocalized( obj->arg(0));
 
        XtVaSetValues(_label, XmNlabelString, xmstr, NULL);
    }
 
    if(obj->numArgs() > 1)
    {
        XtVaSetValues(_label, XtVaTypedArg, XmNforeground, XmRString, 
                      obj->arg(1), strlen( obj->arg(1) ) + 1, NULL);
    }
}
 
// Main driver. Instantiate a VkApp and a top-level window, “show” 
// the window and then “run” the application. The VkRunOnce object
// prevents multiple instances of the application.
 
void main ( int argc, char **argv )
{
    VkApp        *app = new VkApp(“Hello”, &argc, argv);
 
    // Construct a VkNameList object to pass arguments
    // And load all left-over command line arguments
 
    VkNameList *args = new VkNameList();
 
    for(int i = 1; i < argc; i++)
        args->add(argv[i]);
 
    VkRunOnce *runOnce = new VkRunOnce(args);
 
    // Create a window
    
    RunOnceWindow  *win = new RunOnceWindow(“hello”);
 
    // Register a callback for running applications to recieve if
    // anyone attempts to run this application again.
 
    VkAddCallbackMethod(VkRunOnce::invokedCallback, runOnce, 
                        win, RunOnceWindow::update, NULL);
 
    win->show();
    app->run();
}   


VkRunOnce2 Constructor and Destructor

The overloaded versions of VkRunOnce2 constructor are as follows:

  • VkRunOnce2(Boolean autoRaise = FALSE)

  • VkRunOnce2(VkNameList *args, Boolean per_host = FALSE,

               const char *name = NULL, Boolean autoRaise = TRUE) 
    

  • VkRunOnce2(char **args, int numArgs, Boolean per_host = FALSE,

               const char *name = NULL, Boolean autoRaise = TRUE) 
    

If there is no other instance of the application running on this system, the VkRunOnce2 constructor establishes the new instance as the sole runable instance for that particular application. Normally, “running on this system” is defined to mean an application whose X DISPLAY is set to the current display device. If per_host is TRUE, multiple instances are allowed on any given display, so long as each instance is running on a different host. If autoRaise is TRUE, the running application is raised when another instance is started. Arguments may be passed as either a character array, or a VkNameList object.

When a second instance of the application is started, the VkRunOnce2 constructor makes contact with the running instance, passing it any arguments supplied in the args parameter. The constructor then causes the second instance of the application to exit by calling VkApp::terminate().


Note: If you use the first form of the VkRunOnce2 constructor, you must call the member functions notifyOthers() and takeCharge() in order to initiate the process of contacting running instances and establishing this instance as the sole runable process. If you use the second or third forms of the VkRunOnce2 constructor, you will not have to make any explicit calls.

The VkRunOnce2 destructor is as follows:

~VkRunOnce2()

If the running application deletes its VkRunOnce2 object, and another instance of the application is launched, the new instance will be allowed to run.

Access Functions

  • arg()

    char *arg(int index)
    

    Returns the string at the position indicated by index in the VkNameList.

  • className()

    virtual const char* className()
    

    Returns the class name; in this case, the name of the class is “VkRunOnce2.”

  • notifyOthers()

    • void notifyOthers(VkNameList *args,

                        Boolean per_host = FALSE,
                        const char *name = NULL)
      

    • void notifyOthers(char **args,

                        int numArgs,
                        Boolean per_host = FALSE,
                        const char *name = NULL)
      

      Notifies any currently running instance of this application that a new instance has been launched. Any arguments supplied in the parameter args are passed to the currently running instance.

      If there is already a running instance of the application, this function never returns; it exits after notifying the running instance. If this is the first instance, the function returns and the application should call takeCharge().

  • numArgs()

    int numArgs()
    

    Returns the number of arguments in the VkNameList.

  • takeCharge()

    void takeCharge()
    

    Establishes the calling application as the sole runable instance. You would typically call this function after calling notifyOthers().

Using VkRunOnce2

The program in Example 15-2, like Example 15-1, displays a string in a window. After the first instance, subsequent instances of the program will raise the original instance and then exit. This program illustrates the use of the first form of the VkRunOnce2 constructor described on page 403. This program can also be found in /usr/share/src/ViewKit/Utilities.

Example 15-2. Using VkRunOnce2

 
#include <Vk/VkApp.h>
#include <Vk/VkRunOnce2.h>
#include <Vk/VkNameList.h>
#include <Vk/VkSimpleWindow.h>
#include <Xm/Label.h>
// Define a top-level window class
 
class RunOnceWindow : public VkSimpleWindow {
 
    Widget _label;
 
 
    public:
 
        RunOnceWindow ( const char *name );
        ~RunOnceWindow();
 
        void update(VkComponent *comp, XtPointer, XtPointer);
 
        virtual const char* className();
};
 
RunOnceWindow::RunOnceWindow (const char *name) : VkSimpleWindow (name) 
{ 
     _label =  XmCreateLabel ( mainWindowWidget(), “hello”, NULL, 0 );
    
     addView(_label);
} 
 
RunOnceWindow::~RunOnceWindow()
{
    // Empty
}
 
const char* RunOnceWindow::className() { return “RunOnceWindow”; }
 
void RunOnceWindow::update(VkComponent *, XtPointer, XtPointer)
{
    // Empty
}
// Main driver. Instantiate a VkApp and a top-level window, “show” 
// the window and then “run” the application. The VkRunOnce2 object
// prevents multiple instances of the application.
 
void main ( int argc, char **argv )
{
    VkRunOnce2 *ro = new VkRunOnce2(TRUE);
 
    ro->notifyOthers(argv, argc);
    
    VkApp *app = new VkApp(“Hello”, &argc, argv);
 
    ro->takeCharge();
 
    // Create a window
    
    RunOnceWindow  *win = new RunOnceWindow(“hello”);
 
    // Register a callback for running applications to recieve if
    // anyone attempts to run this application again.
 
    VkAddCallbackMethod(VkRunOnce2::invokedCallback, ro, 
                        win, RunOnceWindow::update, NULL);
 
    win->show();
    app->run();
}   


VkBackground

VkBackground is an abstract base class that provides a simple C++ interface for handling background tasks based on Xt work procedures (functions that are called whenever there are no events pending in the application's event queue). VkBackground handles the details of registering a work procedure and provides a convenient way to maintain state between calls to the work procedure.

Derived classes must override the timeSlice() member function, which behaves just like an Xt work procedure. This member function is called whenever no events are pending in the application's event queue. It is expected to perform a small amount of work and return quickly. The function must return TRUE if the operation is done, or FALSE if the function should be called again.

The primary reason for using this class instead of using a work procedure directly is the ability to store state in your subclass's data members between calls to the timeSlice() function.

VkBackground Constructor and Destructor

The VkBackground constructor and destructor are as follows:

VkBackground()  


Initializes a VkBackground object but does not start the work procedure.

~VkBackground()  


Frees all storage associated with a VkBackground object. If this object's work procedure is currently active, the destructor removes it.

Member Functions

  • start()

    void start(void)
    

    Enables the work procedure.

  • stop()

    void stop(void)
    

    Disables the work procedure.

  • timeSlice()

    virtual Boolean timeSlice(void)
    

    Called whenever it is enabled and no events are pending in the application's event queue. This function must return quickly and return a value of TRUE if the function should not be called again, or FALSE if it should be called again at the next possible time.

VkPeriodic

The VkPeriodic class provides a simple, convenient interface to the Xt time-out mechanism. For many applications, it is sufficient to call XtAppAddTimeOut() directly. However, VkPeriodic provides the ability to encapsulate in a C++ class the use of XtAppAddTimeOut() as a cyclic timer.

One way to use VkPeriodic is to derive a new class that overrides the tick() virtual member function. The tick() function acts just like work procedure that is called for each cycle of the periodic time-out. It should perform a small amount of work and return quickly. This approach has the advantage that any data being used in connection with the time-out can be declared and maintained as data member(s) of the derived class.

The VkPeriodic class also supports a ViewKit callback that allows other C++ classes to register member functions to be called with each periodic time-out. This approach is more convenient when a simple timer is needed to drive some other class.

These two methods are not mutually exclusive and may be used together.

VkPeriodic Constructor and Destructor

The VkPeriodic() constructor and destructor are as follows:

VkPeriodic()  

Initializes a VkPeriodic object, creating a timer to be called every interval milliseconds:

VkPeriodic(int interval)

The interval is approximate because it relies on the underlying Xt mechanism.

~VkPeriodic()  

Cleans up all memory allocated by a VkPeriodic object and removes any pending timer.

Member Functions

  • start()

    void start(void)
    

    Starts the timer. You must call this function to start the periodic time-outs.

  • stop()

    void stop(void)
    

    Stops the timer.

  • tick()

    virtual void tick(void)
    

    This is an empty function. It can be overridden by derived classes to allow them to be notified when each time-out occurs.

Callbacks

The VkPeriodic class provides a callback list that allows other C++ classes derived from VkCallbackObject to register member functions to be called at periodic intervals:

static const char *const timerCallback