Appendix A. ViewKit Interprocess Message Facility

This appendix describes the ViewKit interprocess message facility, which consists of a set of classes that support the ToolTalk™ message service for interprocess communication.


Note: To develop applications that use ToolTalk, you must purchase the ToolTalk Development Option. In the United States and Canada, call SGI Direct at 800-800-SGI1 (7441) for more information about how to order the ToolTalk Development Option; outside the United States and Canada, please contact your local sales office or distributor. The ToolTalk development library provides low-level functions for setting up connections to the ToolTalk server and sending and receiving messages. The ViewKit message facility is built on top of the ToolTalk development library to provide a higher-level interface to creating and handling interprocess messages.

Figure A-1 shows the inheritance graph for the classes supporting the ViewKit message facility. The ViewKit message facility also provides several utility functions that are not class member functions.

Figure A-1. The Inheritance Graph for the ViewKit Message Facility Classes


Review of ToolTalk Concepts

This section provides a brief review of some ToolTalk concepts and terms. For a complete description of the ToolTalk message service and directions for creating applications that interface with the ToolTalk service, consult the ToolTalk Programmer's Guide.

The ToolTalk message service allows independent applications to communicate with each other without having direct knowledge of each other. Applications exchange ToolTalk messages to communicate with other applications. Sending applications create, fill in, and send a message; the ToolTalk service determines the recipients and delivers the message to the receiving applications. Receiving applications retrieve messages, examine the information in the message, and then either discard the message or perform an operation and reply with the results.

Messages consist of a character string operator, followed by any number of arguments. The arguments can be integers, character strings, or binary strings. Also, a message can have attributes such as a filename. The receiver of a message is told the number and type of arguments, and is also given access to any attribute values.

For each type of message an application wants to receive, it must register a message pattern with the ToolTalk service. The message pattern describes the operator, arguments, and attributes that a message must have to be delivered to the application. When the application registers a pattern, it must indicate whether it wants to observe or handle messages of that type. Any number of applications can observe a message. The ToolTalk service forwards a copy of the message to each application with a matching message pattern. On the other hand, to ensure that a requested operation is performed only once, only one application can handle a message. If the ToolTalk service cannot find a handler for a message, it returns the message to the sending application indicating that delivery failed.

There are two types of messages: notices and requests. A sending application sends a notice to provide information to other applications; the sending application does not expect a reply to a notice. Receiving applications receive notices and perform whatever actions are needed to process the notice; the receiving applications do not send reply message in response to notices. A sending application sends a request to ask another application to perform an action; the sending application expects a single reply to a request. A receiving application receives the request, performs whatever actions are needed to process the request, and sends a reply message. The ToolTalk service handles the details of how requests are handled, and ensures that only one receiver gets to reply.

When the ToolTalk service determines that a message needs to be delivered to a specific process, but the process is not currently running, the ToolTalk service looks for instructions (provided by the application at installation time) on how to start the application.

Overview of ViewKit's ToolTalk Support

This section provides an overview of ViewKit's ToolTalk support. It discusses the classes you use to interface with ToolTalk and the policies enforced by those classes.

ViewKit Classes Supporting ToolTalk

The VkMsgClient class is the basis for interacting with ToolTalk in your application. VkMsgClient allows you to register and manage message patterns; declare actions for your application to perform when it receives messages; compose messages; and send notices and requests.

The VkMsgApp class, a subclass of VkApp, opens a ToolTalk connection and sets up all resources needed to send and receive ToolTalk messages.[11] You must instantiate a VkMsgApp object in your application instead of a VkApp object if you want ToolTalk support for your application. The VkMsgApp constructor creates an instance of VkMsgClient that you can use to manage messages in your application.

The VkMsgWindow class is a subclass of VkWindow that works with VkMsgApp to support the ViewKit interprocess message facility. To provide ToolTalk support for your application, you must use VkMsgWindow for your application's windows instead of VkSimpleWindow or VkWindow. The VkMsgWindow constructor creates an instance of VkMsgClient that you can use to manage messages in that window.

The VkMsgComponent class is a subclass of VkComponent that works with VkMsgApp to support the ViewKit interprocess message facility. You should use VkMsgComponent to derive new components if those components must send or receive ToolTalk messages. You do not need to derive components from VkMsgComponent if those components do not interact with ToolTalk. The VkMsgComponent constructor creates an instance of VkMsgClient that you can use to manage messages in that component.

The ViewKit message facility also provides several utility functions for manipulating messages. These functions are implemented as normal functions rather than class member functions.

ViewKit Message Facility Policies

The ViewKit message facility provides mostly a mechanism for exchanging ToolTalk messages between applications, but it does impose some policies:

  • Messages are always sent to all members of the session.

  • Message actions receive all messages for a given operator, and cannot set patterns based on argument number or type.

  • By default, applications connect to the default session when they're started.

These are the policies currently implemented, but they are subject to change in future releases of ViewKit; however, applications that adhere to these policies should not be affected by future changes.

Establishing a Connection to the ToolTalk Service

Creating an instance of the VkMsgApp class opens a ToolTalk connection and sets up all resources needed to send and receive ToolTalk messages. Remember to use the VkMsgApp class in your application instead of a VkApp object if you want ToolTalk support for your application. The syntax of the VkMsgApp constructor is:

VkMsgApp(char* appClassName, int* argc, char** argv,
         XrmOptionDescRec* optionList = NULL,
         int sizeOfOptionList = 0,
         const char* ptid = NULL,
         const char* sessid = NULL
         Boolean noProtocol = FALSE)

The first five arguments are the same as those that you can provide to the VkApp constructor. The ptid argument specifies a process type. It defaults to NULL which indicates no process type. You need to provide a ptid argument only if this application is autostarted (see “Registering Services for Autostart”). sessid specifies a session to join. If you don't provide a value, the process joins the default session.

The noProtocol argument determines whether your application automatically provides support for handling “Lower,” “Raise,” and “Quit” messages. If this value is FALSE (the default), your application calls VkApp::iconify() upon receiving a “Lower” message, VkApp::open() and VkApp::raise() upon receiving a “Raise” message, and VkApp::quitYourself() upon receiving a “Quit” message.

You can also specify the session using command line arguments when you invoke your applications:

-project sessid 


Join the session specified by sessid

-projectWindow windowid 


Join the same session as the window specified by windowid

-projectWindow 


Allow the user to click a window and join the same session as the window specified

The VkMsgApp class also creates an instance of VkMsgClient that you can use to manage messages in your application. You can retrieve a pointer to this object with the VkMsgApp::messageClient() function:

VkMsgClient* messageClient()

Sending and Receiving ToolTalk Messages

This section describes how to register and manage message patterns, declare actions for your application to perform when it receives messages, composes messages, and sends notices and requests. You accomplish all of these tasks using the VkMsgClient class.

You do not explicitly instantiate VkMsgClient objects. Instead, the VkMsgApp, VkMsgWindow, and VkMsgComponent classes all automatically instantiate their own VkMsgClient objects and provide access functions to those objects.

Sending Notices and Requests

This section describes how to send notices and requests using VkMsgClient. Both notices and requests are types of messages.

A sending application sends a notice message to provide information to other applications; the sending application does not expect a reply to a notice. All of the parameters in a notice have a mode of “in”, which indicates that receiving applications should read only those parameters.

A sending application sends a request message to ask another application to perform an action; the sending application expects a single reply to a request. In a request, some of the message parameters have a mode of “out”, which indicates that the receiving application should fill in these parameters for the reply message, or “in/out”, which indicates that the receiving application should read those parameters and then fill them in with new values for the reply message.

Sending Simple Notices

If you're sending a notice consisting of only string arguments or only integer arguments, you can use the VkMsgClient::sendStringNotice() or VkMsgClient::sendIntNotice() function, respectively:

void sendStringNotice(char *op ...)
void sendIntNotice(char *op ...)

For both functions, op is the message operator. sendStringNotice() expects a NULL-terminated list of pointers to character strings; sendIntNotice() expects a NULL-terminated list of integers. These functions create a message with the arguments you provide, send the message, and then automatically delete the message (that is, delete the storage space allocated by your application when the functions create the message).


Caution: Because sendIntNotice() expects a NULL-terminated list of arguments, be sure that you don't provide a zero-valued argument or else you'll prematurely terminate your argument list.


Composing and Sending Messages

To send requests or to send notices that contain a mix of argument types, you must compose the message before sending it. To begin composing a message, call VkMsgClient::composeBegin():

void composeBegin()


Note: You can compose only one message at a time among all VkMsgClient objects.

You can then add arguments to your message one at a time, using VkMsgClient::composeAdd():

void composeAdd(char *val, VkMsgMode mode = VK_MSG_IN)
void composeAdd(int ival, VkMsgMode mode = VK_MSG_IN)
void composeAdd(unsigned char *val, int len,
                VkMsgMode mode = VK_MSG_IN)

You can add as an argument: 1) a NULL-terminated character string; 2) an integer value; or 3) a binary string. If you provide a binary string, you must also specify the length of the string as the len argument.

The mode argument is an enumerated value of type VkMsgMode. VK_MSG_IN indicates that the argument is written by the sending application and can be read by the handling application and any observing applications. VK_MSG_OUT indicates that the argument is written by the handling applications and is read by the sending application. VK_MSG_INOUT indicates that the argument can be written by both the sending and handling applications, and can be read by the sending, handling, or any observing applications.

Once you finish composing the message, you send the message. If the message is a notice, use VkMsgClient::sendNotice():

void sendNotice(char *op)

op is the message operator. sendNotice() sends the message you composed, and then automatically deletes the message (that is, deletes the storage space allocated by your application when you compose the message).

To send a request, use VkMsgClient::sendRequest():

VkMsgMessage sendRequest(char *op)

sendRequest() sends the message you composed. op is the message operator. sendRequest() returns an opaque message handle. You can use this handle when calling the various utility functions provided by the ViewKit message facility as described in “Useful Functions When Handling Messages”.

When you send a request using sendRequest(), the function returns immediately. To obtain and handle the reply message to your request, your application must register a message action as described in “Receiving Notices and Handling Requests”.


Note: The ViewKit message facility automatically deletes the request message when your application receives the corresponding reply or failure message.


Sending Synchronous Requests

In some cases, your application might require a reply to a request before performing any other processing. In these cases, you can use VkMsgClient::sendSyncRequest() to send a synchronous request:

VkMsgMessage sendSyncRequest(char *op)

sendSyncRequest() uses a secondary X event loop to simulate a synchronous reply to a request. sendSyncRequest() blocks until it receives the reply message, which it passes as its return value. If the request fails, sendSyncRequest() returns NULL. Note that because sendSyncRequest() uses a secondary X event loop, you should beware of any problems with re-entrant code in any callbacks that could be invoked.

Once you receive the reply message, you can use the various utility functions provided by the ViewKit message facility, as described in “Useful Functions When Handling Messages”, to parse the reply. You must also use VkMsgDestroy() to destroy the message when you no longer need the reply:

VkMsgStatus VkMsgDestroy(VkMsgMessage msg)

VkMsgDestroy() is implemented as a normal function rather than a class member function. It is declared in the header file <Vk/VkMsg.h>. The VkMsgStatus return value is the same as the tt_status values used by ToolTalk; consult the ToolTalk Programmer's Guide for information on these values.

Specifying a Filename Message Attribute

The convention for passing a filename argument in a message is to specify the filename as a message attribute rather than a message argument. The VkMsgClient class provides the following functions for sending a message with a filename attribute:

void sendStringFileNotice(char *op, char *file ...)
void sendIntFileNotice(char *op, char *file ...)
void sendFileNotice(char *op, char *file)
void sendFileRequest(char *op, char *file)
void sendSyncFileRequest(char *op, char *file)

In these functions, file is the filename.

Receiving Notices and Handling Requests

This section describes how to receive notices and handle requests using the ViewKit message facility. It discusses message dispatch, writing message action callbacks, creating message patterns, associating message actions with the message patterns, and registering and unregistering message patterns.

Overview of Message Dispatch

For each type of message an application wants to receive, it must register a message pattern with the ToolTalk service. The message pattern describes the operator, arguments, and attributes that a message must have to be delivered to the application. Your application must also register message actions, callback functions that are called when your application receives messages with a particular message pattern.

When the ToolTalk service receives a message, it matches the message against all registered patterns. If the message is a notice, the ToolTalk service delivers a separate message to each application with a matching pattern; if the message is a request, the ToolTalk service selects the “best” pattern match and delivers a single message to the application with the matching pattern.

The ViewKit message facility then dispatches the message received by the application to each action registered for the matching operator, regardless of any other pattern information you provided when registering the action. Your action is responsible for testing the message arguments and determining whether to process the message or not.

As an example, consider an application that registers an action for a message pattern consisting of a “show” operator and an integer argument. If another process then sends a “show” message with an integer argument, the ToolTalk service sends the message to your application, and your application dispatches the message to the action. On the other hand, if another process sends a “show” message with a character string argument, the ToolTalk service does not send the message to your application because it does not match the registered pattern.

A complication arises if you have multiple actions registered for a particular message operator; for example, if in addition to the action described above, your application registered an action for a message pattern consisting of a “show” operator and a character string argument. In this case, the ToolTalk service sends to your application any “show” message with either an integer or a character string argument. The ViewKit message facility then dispatches those messages to each action in your application registered for the “show” operator. Each action is then responsible for testing the message arguments and determining whether to process the message or not.

Writing Message Action Callbacks

You implement message actions as callback functions that your application invokes when it receives a message matching a given message pattern. This section describes how to write the message action callback functions. “Creating and Registering Simple Message Patterns” describes how to register these callback functions with the ViewKit message facility.

All message action callback functions must be of type VkMsgClientAction:

typedef Boolean (*VkMsgClientAction)(
  void*                /* clientData */,
  VkMsgFacilityReason  /* reason */,  
  VkMsgMessage         /* msg_in */,
  char*                /* op */,
  int                  /* argc */,
  VkMsgArg*            /* argv */
)


Note: The VkMsgClientAction function must be a regular function or a static member function; it cannot be a regular class member function.

The callback function arguments are:

clientData 

The arbitrary client data you provided as the clientData argument when you registered this callback function using the addAction() function, as described in “Creating and Registering Simple Message Patterns”.

reason 

The reason for calling the callback function, expressed as an enumerated value of type VkMsgFacilityReason. Possible values are:

  • VK_MSG_FACILITY_NOTICE—Notice

  • VK_MSG_FACILITY_REQUEST—Request

  • VK_MSG_FACILITY_REPLY—Reply to a previous request

  • VK_MSG_FACILITY_FAILED—Request failed (not handled)

  • VK_MSG_FACILITY_STARTED—Request caused autostart of the handler and was queued

msg_in 

The incoming message in the form of an opaque message handle. You can use this handle when calling the various utility functions provided by the ViewKit message facility as described in “Useful Functions When Handling Messages”. For example, you might want to compare returned values against those you sent in your request.

op 

The message operator

argc 

The number of message arguments

argv 

The message arguments, passed as an array of VkMsgArg structures.

The format of the VkMsgArg structure, used to pass the message arguments, is:

typedef struct {
  char *type;
  VkMsgValue value;
  VkMsgMode mode;
} VkMsgArg

The elements of the structure are:

type 

The argument type. This can take any of three pre-defined constant values:

  • VK_MSG_INT_MSG_ARG_TYPE—integer value

  • VK_MSG_STRING_MSG_ARG_TYPE—character string value

  • VK_MSG_BSTRING_MSG_ARG_TYPE—binary string value

type 

The argument value, expressed as a VkMsgValue union. The definition of the VkMsgValue union is:

typedef union {
  int ival;
  char *val;
  VkMsgBValue bval;
} VkMsgValue
typedef struct {
  unsigned char *val;
  int len;
} VkMsgBValue

type 

The argument mode, expressed as an enumerated value of type VkMsgMode. Possible values are:

  • VK_MSG_IN—the argument is written by the sending application and can be read by the handling application and any observing applications.

  • VK_MSG_OUT—the argument is written by the handling applications and is read by the sending application.

  • VK_MSG_INOUT—the argument can be written by both the sending and handling applications, and can be read by the sending, handling, or any observing applications.


Note: Remember that the ViewKit message facility dispatches the messages received by the application to each action registered for the matching operator, regardless of any other pattern information you provided when registering the actions. Your actions are responsible for testing the message arguments and determining whether or not to process the messages they receive.

Message action callbacks that process notices are relatively straightforward to write; the callback simply examines the message data and performs any actions required by the application. You can use the various utility functions provided by the ViewKit message facility, as described in “Useful Functions When Handling Messages”, to parse the message. Notice callbacks are not expected to send reply messages.

Message action callbacks that process requests must first decide whether or not to handle the request. If so, the callback should: 1) read any required data from the message's “in” or “in/out” arguments; 2) perform any appropriate actions; 3) modify any “out” or “in/out” arguments; and 4) send the reply message using VkMsgReply():

VkMsgStatus VkMsgReply(VkMsgMessage msg)

VkMsgReply() is implemented as a normal function rather than a class member function. It is declared in the header file <Vk/VkMsg.h>.

After performing any appropriate actions, your message action callback should return a Boolean value to indicate whether or not the ViewKit message facility should propagate the message to other callbacks registered for that action. A Boolean value of FALSE propagates the message; a value of TRUE does not propagate the message.

If a message action callback that processes a request decides to handle a request, it should return TRUE to prevent other message action callbacks from attempting to handle the request as well. If the callback decides not to handle a request, it should return FALSE to allow other callbacks to attempt to handle the message. If all of an application's message actions reject a message, the ToolTalk service tries to dispatch the request to another application.

You should always return FALSE in message action callbacks that process notice messages.

The ViewKit message facility automatically destroys request messages when your application receives the corresponding reply or failure message. If for some reason you need to explicitly destroy a request message, call the VkMsgDestroyRequest() function:

VkMsgStatus VkMsgDestroyRequest(VkMsgMessage msg)

VkMsgDestroyRequest() is implemented as a normal function rather than a class member function. It is declared in the header file <Vk/VkMsg.h>. The VkMsgStatus return value is the same as the tt_status values used by ToolTalk; consult the ToolTalk Programmer's Guide for information on these values.

Useful Functions When Handling Messages

The ViewKit message facility also provides several utility functions for manipulating messages. These functions are implemented as normal functions rather than class member functions. Most of these utility function are actually redefined ToolTalk functions. The ViewKit message facility provides this level of indirection to allow messaging services other than ToolTalk to be used. You should never directly call any of the ToolTalk routines in your application. Similarly, all of the ToolTalk constants (TT_*) have been replaced by ViewKit message facility equivalents (VK_MSG_*).

VkMsgTypeIsInt(), VkMsgTypeIsString(), and VkMsgTypeIsBString() check to see whether a given argument is an integer, a character string, or a binary string respectively:

Boolean VkMsgTypeIsInt(char *atype)
Boolean VkMsgTypeIsString(char *atype)
Boolean VkMsgTypeIsBString(char *atype)

The header file <Vk/VkMsgUtils.h> contains these declarations.

VkMsgSetIVal(), VkMsgSetVal(), and VkMsgSetBVal() change the integer, character string, or binary string value, respectively, of a given message argument:

VkMsgSetIVal(VkMsgMessage msg, int index, int value)
VkMsgSetVal(VkMsgMessage msg, int index, char *value)
VkMsgSetBVal(VkMsgMessage msg, int index,
             unsigned char *value, int len)

The header file <Vk/VkMsg.h> contains these declarations.

You can parse a message's arguments into a VkMsgArg structure (as described in “Writing Message Action Callbacks”) with the VkMsgParseArguments() function:

void VkMsgParseArguments(VkMsgMessage msg, int *argc_return, VkMsgArg **argv_return)

This function is declared in the header file <Vk/VkMsgUtils.h>. You must free the argv result when done.

You can retrieve the file attribute associated with a message using the VkMsgFile() function:

char *VkMsgFile(VkMsgMessage msg)

This function is declared in the header file <Vk/VkMsg.h>. You are responsible for freeing the returned value when you are finished using it. If there is no file attribute, VkMsgFile() returns NULL.

VkMsgIsErr() checks to see whether a VkMsgStatus value is an error status:

int VkMsgIsErr(VkMsgStatus status)

This function is declared in the header file <Vk/VkMsg.h>. If the VkMsgStatus value is a warning, VkMsgIsErr() returns 0; if it is an error VkMsgIsErr() returns 1.

VkMsgPtrError() determines whether a given opaque handle returned by a ViewKit message facility function is valid:

VkMsgStatus VkMsgPtrError(void *pointer)

This function is declared in the header file <Vk/VkMsg.h>. You can use this function to test for valid message handles or pattern handles. If the handle is valid, VkMsgPtrError() returns the constant VK_MSG_OK.

VkMsgFail() informs the ToolTalk service that your process cannot handle this request and that the message should not be offered to other processes of the same ptype as yours:

VkMsgStatus VkMsgFail(VkMsgMessage msg)

This function is declared in the header file <Vk/VkMsg.h>. The ToolTalk service sends the message back to the sender with state VK_MSG_FAILED.

VkMsgReject() informs the ToolTalk service that your process cannot handle this message:

VkMsgStatus VkMsgReject(VkMsgMesage msg)

This function is declared in the header file <Vk/VkMsg.h>. The ToolTalk service will try other handlers.

Creating and Registering Simple Message Patterns

To use your message actions, you must associate them with message patterns and then register those patterns with the ViewKit message facility.


Note: Be sure to register your application's message actions before executing VkApp::run() or posting any ViewKit dialog. You must register your message actions before entering any Xt event loop; otherwise your application might receive messages before registering message actions, and your application will not process the message as expected.

Use the VkMsgClient::addAction() function to create a message pattern and associate a message action with that pattern:

VkMsgPattern addAction(char *op, VkMsgClientAction proc,
                       void *clientData, VkMsgActionType type,
                       Boolean deleteMessage = TRUE)

addAction() creates and registers a simple message pattern consisting of only a message operator, op. You can create more detailed message patterns using the functions described in “Creating More Detailed Message Patterns”. After your application registers this pattern, it receives all messages sent that contain this operator. addAction() returns an opaque message pattern handle. You use this handle to remove this action with the removeAction() function described later in this section.

The proc argument is the callback function invoked when your application receives a message matching the message pattern. The function must be of type VkMsgClientAction. The ViewKit message facility passes the clientData argument to the function as client data. See “Writing Message Action Callbacks” for information on writing message action callbacks.

The type argument specifies the type of message processing the message action implements. type is an enumerated value of type VkMsgActionType, which can take any of the following values:

VK_MSG_ACTION_OBSERVE 


Observe messages; use this value to process notices

VK_MSG_ACTION_HANDLE 


Handle messages; use this value to process requests

VK_MSG_ACTION_REPLY 


Process replies to a request

VK_MSG_ACTION_FAIL 


Process request failures

VK_MSG_ACTION_START 


Process notices of a message handler starting

The deleteMessage argument determines whether or not your application automatically deletes the message after all actions process it. By default, the ViewKit message facility automatically destroys the message and your message actions don't need to worry about it. However, if you want to save a copy of the message to deal with it later (for example, to send a reply), you must set deleteMessage to False.

After you've created your message patterns, you must call VkMsgClient::updatePatterns() to register those patterns:

void updatePatterns()

The VkMsgClient::removeAction() function removes an action:

void removeAction(VkMsgPattern pat)

pat is the message pattern returned by addAction(). removeAction() automatically unregisters the associated message pattern from the ViewKit message facility.

Creating More Detailed Message Patterns

The message pattern created by addAction() consists of only the message operator string. Any message received with that operator matches the particular message pattern and is dispatched to your action.

You can create more detailed message patterns, adding arguments and attributes, to restrict the messages that the ToolTalk service dispatches to your application. To create a more detailed pattern, you first create a basic message pattern using the VkMsgClient::createAction() function:

VkMsgPattern createAction(char *op, VkMsgClientAction proc,
                          void *clientData, VkMsgActionType type,
                          Boolean deleteMessage = TRUE)

createAction() accepts the same arguments as addAction(). Like addAction(), it creates a simple message pattern consisting of only a message operator, op, and associates the message action, proc, with that pattern. Unlike addAction(), createAction() does not automatically register the pattern with the ViewKit message facility. Instead, you can specify additional arguments or attributes to the message pattern using various pattern modifier functions.

All of the pattern modifier functions are implemented as normal functions rather than class member functions. They are actually redefined ToolTalk functions. The header file <Vk/VkMsg.h> contains these declarations. The ViewKit message facility provides this level of indirection to allow messaging services other than ToolTalk to be used. You should never directly call any of the ToolTalk routines in your application.

Consult the <Vk/VkMsg.h> header file for a list of pattern modifier functions you might find useful. Refer to the ToolTalk Programmer's Guide for information on these functions.

After modifying the message pattern, call VkMsgClient::registerPattern() to register the pattern with the ViewKit message facility:

VkMsgStatus registerPattern(VkMsgPattern pat)

pat is the opaque message pattern handle returned by createAction(). registerPattern() returns a VkMsgStatus value indicating its status. The VkMsgStatus values are the same as the tt_status values used by ToolTalk; consult the ToolTalk Programmer's Guide for information on these values.

After you've created your message patterns, you must call VkMsgClient::updatePatterns() to register those patterns:

void updatePatterns()

You can unregister a message pattern with the VkMsgClient::unregisterPattern() function:

VkMsgStatus unregisterPattern(VkMsgPattern pat)

pat is the opaque message pattern handle returned by createAction(). unregisterPattern() returns a VkMsgStatus value indicating its status. The VkMsgStatus values are the same as the tt_status values used by ToolTalk; consult the ToolTalk Programmer's Guide for information on these values.

As an example of creating a detailed message pattern, consider the following code:

pat = createAction("message_op", callback, this, VK_MSG_ACTION_HANDLE);
VkMsgPatternArg(pat, VK_MSG_IN, VK_MSG_INT_MSG_ARG_TYPE, NULL)
VkMsgPatternArg(pat, VK_MSG_OUT, VK_MSG_ALL_MSG_ARG_TYPE, NULL);
VkMsgPatternIArg(pat, VK_MSG_IN, VK_MSG_INT_MSG_ARG_TYPE, 5);
registerPattern(pat);
updatePatterns();

This example creates a message pattern that matches messages with the operator “message_op,” and has three arguments. The first is an “in” integer argument. The second is an “out” argument of any type. The last is an “in” integer argument with
value 5.

Detecting and Handling Errors in Handling Requests

There are two kinds of errors that can occur when a request is made and a reply is expected. Either no one handles the request (and ToolTalk could not autostart an appropriate service), or someone does handle the request and replies, but some error occurs while handling the request.

For instance, a request to “Raise the Mail Tool” would fail if there is no mail tool, since no reply could be received. In this case, if you had registered a VK_MSG_ACTION_FAIL type message action for the “Raise the Mail Tool” operator, your application would call that message action. If you were using VkMsgClient::sendSyncRequest(), it would return NULL.

If your request is successfully sent to a handler, but an error occurs while processing the request, most handlers send a reply but indicate that an error condition occurred. Many handlers return a status code indicating the return status. To obtain the status code of a reply, call the VkMsgStatusCode() function:

int VkMsgStatusCode(VkMsgMessage msg)

Furthermore, some handlers provide useful error strings to display in the case of errors. To obtain the error string of a reply, call the VkMsgStatusString() function:

char *VkMsgStatusString(VkMsgMessage msg)

The meaning of status codes and the validity of status strings is dependent on the service handling the request. Both of these functions are implemented as a normal functions rather than class member functions. They are actually redefined ToolTalk functions. The header file <Vk/VkMsg.h> contains these declarations.

Supporting Messaging in Application Windows

The VkMsgWindow class is a subclass of VkWindow that works with VkMsgApp to support the ViewKit interprocess message facility. You should use VkMsgWindow for your application's windows instead of VkSimpleWindow or VkWindow if you want ToolTalk support for your application.

The VkMsgWindow constructor creates an instance of VkMsgClient that you can use to manage messages in that window. You can access the window's VkMsgClient object with the VkMsgWindow::messageClient() function:

VkMsgClient *messageClient()

VkMsgWindow also provides a variety of convenience functions for directly manipulating a window's VkMsgClient object. Consult the VkMsgWindow(3Vk) reference page for more information on these functions.

Supporting Messaging in Components

The VkMsgComponent class is a subclass of VkComponent that works with VkMsgApp to support the ViewKit interprocess message facility. You should use VkMsgComponent to derive new components if those components must send or receive ToolTalk messages. You do not need to derive components from VkMsgComponent if those components do not interact with ToolTalk. Furthermore, you usually should handle the ToolTalk interaction in an application through the application's VkMsgApp object or one of its VkMsgWindow objects.

The VkMsgComponent constructor creates an instance of VkMsgClient that you can use to manage messages in that component. You can access the window's VkMsgClient object with the VkMsgWindow::messageClient() function:

VkMsgClient *messageClient()

VkMsgComponent also provides a variety of convenience functions for directly manipulating a component's VkMsgClient object. Consult the VkMsgComponent(3Vk) reference page for more information on these functions.

Registering Services for Autostart

For some messages, you might want a service process to get autostarted as necessary. When the message is sent and the process is not available, the ToolTalk service starts the process and queues the message.

To set this up, you need to register your application class with what ToolTalk calls a “ptype,” a process type. Refer to the ToolTalk Programmer's Guide for details, but in most situations the setup is similar. For example, you might have a file called myapp.ptype that contains:

ptype USR_MY_APP
{
  start "/usr/sbin/myApp";
  observe: session load_file() => start;
}

This indicates that the message “load_file” is observed by a process typed “USR_MY_APP” and that when a “load_file” message is sent, the ToolTalk service should execute “/usr/sbin/myApp.”

Then, you instantiate the VkMsgApp object in the myApp application as follows:

VkMsgApp *myApp = new VkMsgApp("MyApp", &argc, argv, NULL, 0,
                               "USR_MY_APP");

Finally, when you install your application, you need to register this information in the static ToolTalk config file by executing:

/usr/sbin/tt_type_comp -dsystem myapp.ptype
/etc/killall -USR2 ttsession

This adds the contents of myapp.ptype to the system config file, and tells all existing ttsession processes to update their configurations.

When you express message patterns in a ptype, you should not register the pattern in your application. Otherwise, your message handler will be called twice. To register an action but not register the corresponding pattern, use createAction() instead of addAction().

Troubleshooting Checklist

Here are some common mistakes to watch out for:

  • When using ptype-registered patterns for autostart, make sure your executable has registered its ptype name in VkMsgApp::VkMsgApp() and that it has a non-specific action with no pattern (use VkMsgClient::createAction() instead of addAction()) to handle the request. Otherwise, ToolTalk autostarts your executable indefinitely.

  • If you don't set the optional deleteMessage argument to TRUE in VkMsgClient::addAction(), you should never call VkMsgDestroy() or VkMsgDestroyRequest() in your message action.

  • If you set the optional deleteMessage argument to FALSE in VkMsgClient::addAction(), you're responsible for destroying the message when you're through with it. If the message is a request, be sure to use VkMsgDestroyRequest() instead of VkMsgDestroy(). Otherwise, you may have memory heap corruption caused by double frees, if the requestor and handler are in the same process.

  • You must call VkMsgClient::updatePatterns() after you use VkMsgClient:::addAction(). Otherwise, your new actions have no effect.

  • When using the VkMsgClient::composeAdd() routines, be careful that you call VkMsgClient::composeBegin() first to reset the state of your composed arguments. Otherwise, random arguments will get added to your message.

  • If you return TRUE from a message action where the reason was VK_MSG_ACTION_HANDLE, be sure that you call VkMsgReply(). Otherwise, ToolTalk assumes that your process is handling the message when in fact you never reply. The requestor waits forever for a response.

Also, it is useful to turn on ttsession (the ToolTalk server process) debugging output. You can toggle it on/off with:

/etc/killall -USR1 ttsession 



[11] VkMsgApp actually instantiates a VkMsgService object—which is in turn a subclass of VkMsgFacility—to perform ToolTalk initialization and support ToolTalk interaction. Although you should never need to use either the VkMsgFacility or VkMsgService classes directly, you might encounter them while debugging a ViewKit application that uses the ViewKit interprocess message facility. Consult the VkMsgFacility(3Vk) and the VkMsgService(3Vk) reference pages for more information on these classes.