ToolTalk User's Guide

Chapter 10 Static Message Patterns

The static messaging method provides an easy way to specify the message pattern information if you want to receive a defined set of messages.

Defining Static Messages

To use the static method, you define your process types and object types and compile them with the ToolTalk type compiler, tt_type_comp. When you declare your process type, the ToolTalk service creates message patterns based on that type. These static message patterns remain in effect until you close communication with the ToolTalk service.

Defining Process Types

Your application can still be considered a potential message receiver even when no process is running the application. To do this, you provide message patterns and instructions on how to start the application in a process type (ptype) file. These instructions tell the ToolTalk service to perform one of the following actions when a message is available for an application but the application is not running:

To make the information available to the ToolTalk service, the ptype file is compiled with the ToolTalk type compiler, tt_type_comp, at application installation time.

When an application registers a ptype with the ToolTalk service, the message patterns listed in it are automatically registered, too.

Ptypes provide application information that the ToolTalk service can use when the application is not running. This information is used to start your process if necessary to receive a message or queue messages until the process starts.

A ptype begins with a process-type identifier (ptid). Following the ptid are:

  1. An optional start string — The ToolTalk service will execute this command, if necessary, to start a process running the program.

  2. Signatures — Describes the TT_PROCEDURE-addressed messages that the program wants to receive. Messages to be observed are described separately from messages to be handled.

Signatures

Signatures describe the messages that the program wants to receive. A signature is divided by an arrow (=>) into two parts. The first part of a signature specifies matching attribute values. The more attribute values specified in a signature, the fewer messages the signature will match. The second part of a signature specifies receiver values that the ToolTalk service will copy into messages that match the first part of the signature.

A ptype signature can contain values for disposition and operation numbers (opnum). The ToolTalk service uses the disposition value (start, queue, or the default discard) to determine what to do with a message that matches the signature when no process is running the program. The opnum value is provided as a convenience to message receivers. When two signatures have the same operation name but different arguments, different opnums makes incoming messages easy to identify.

Creating a Ptype File

The following listing illustrates a ptype file.

#include "Sun_EditDemo_opnums.h"

ptype Sun_EditDemo {
		/* setenv Sun_EditDemo_HOME to install dir for the demo */
	 start	“${Sun_EditDemo_HOME}/edit”;
	 handle:
	 /* edit file named in message, start editor if necessary */
	 session Sun_EditDemo_edit(void)
					=> start opnum=Sun_EditDemo_EDIT;

	 /* tell editor viewing file in message to save file */
	 session Sun_EditDemo_save(void)
					=> opnum=Sun_EditDemo_SAVE;

	 /* save file named in message to new filename */
	 session Sun_EditDemo_save_as(in string new_filename)
					=> opnum=Sun_EditDemo_SAVE_AS;

	 /* bring down editor viewing file in message */
	 session Sun_EditDemo_close(void)
					=> opnum=Sun_EditDemo_CLOSE;
};

The following listing shows the syntax for a ptype file.

ptype	::=	'ptype' ptid `{'
		property*		[`observe:' psignature*]
		[`handle:' psignature* ]
		[`handle_push:' psignature*]
		[`handle_rotate:' psignature*]
		`}' [`;']
property	::=	property_id value `;'
property_id	::=	`start'
value	::=	string
ptid	::=	identifier
psignature	::=	[scope] op args [contextdcl]
		[`=>'
		[`start'][`queue']
		[`opnum='number]]
		`;'
scope	::=	`file'
	|	`session'
	|	`file_in_session'
args	::=	`(` argspec {, argspec}* `)'
	|	`(void)'
	|	`()'
contextdcl	::=	`context' `(` identifier {, identifier}* `)' `;'
argspec	::=	mode type name
mode	::=	`in' | `out' | `inout'
type	::=	identifier
name	::=	identifier

Property_id Information

ptid—process type identifier (ptid). Identifies the process type. A ptid must be unique for every installation. Because this identifier cannot be changed after installation time, each chosen name must be unique. For example, you can use a name that includes the trademarked name of your product or company, such as Sun_EditDemo. The ptid cannot exceed 32 characters and should not be one of the reserved identifiers: ptype, otype, start, opnum, queue, file, session, observe, or handle.

start—start string for the process. If the ToolTalk service needs to start a process, it executes this command; /bin/sh is used as the shell.

Before executing the command, the ToolTalk service defines TT_FILE as an environment variable with the value of the file attribute of the message that started the application. This command runs in the environment of ttsession, not in the environment of the sender of the message that started the application, so any context information must be carried by message arguments or contexts.

Psignature Matching Information

scope—this pattern attribute is matched against the scope attribute in messages.

op—operation name. This name is matched against the op attribute in messages.


Note –

If you specify message signatures in both your ptype and otypes, use unique operation names in each. For example, do not specify a display operation in both your ptype and otype.


args—arguments for the operation. If the args list is void, the signature matches only messages with no arguments. If the args list is empty (that is, “()”), the signature matches without regard to the arguments.

contextdcl—context name. When a pattern with this named context is generated from the signature, it contains an empty value list.

Psignature Actions Information

start—if the psignature matches a message and no running process of this ptype has a pattern that matches the message, start a process of this ptype.

queue—if the psignature matches a message and no running process of this ptype has a pattern that matches the message, queue the message until a process of this ptype registers a pattern that matches it.

opnum—fill in the message's opnum attribute with the specified number to enable you to identify the signature that matched the message.

When the message matches the signature, the opnum from the signature is filled into the message. Your application can then retrieve the opnum with the tt_message_opnum call. By giving each signature a unique opnum, you can quickly determine which signature matched the message.

You can attach a callback routine to the opnum with the tt_ptype_opnum_callback_add call. When the message is matched, the ToolTalk service will check for any callbacks attached to the opnum and, if any are found, run them.

The Sun_EditDemo_opnums.h file defines symbolic definitions for all the opnums used by edit.c, allowing both the edit.types file and edit.c file to share the same definitions.

Automatically Starting a Tool

The listing below is a simple example of a ptype declaration that causes the ToolTalk service to automatically start a tool. The example code states:

If a message to display, edit, or compose is received and there is no current instance of the tool running that can handle the message, start “/home/toone/tools/mytest” and deliver the message.


Caution – Caution –

This example causes the ToolTalk service to search indefinitely for a handler.


ptype My_Test {
    start "/home/toone/tools/mytest";
    handle:

	session Display (in Ascii text) => start;
	session Edit (inout Ascii text) => start;
	session Compose (out Ascii text) => start;

	file Display (in Ascii file_name) => start;
	file Edit (inout Ascii file_name) => start;
	file Compose (out Ascii file_name) => start;
};

Defining Object Types

When a message is addressed to a specific object or a type of object, the ToolTalk service must be able to determine to which application the message is to be delivered. Applications provide this information in an object type (otype). An otype names the ptype of the application that manages the object and describes message patterns that pertain to the object.

These message patterns also contain instructions that tell the ToolTalk service what to do if a message is available but the application is not running. In this case, ToolTalk performs one of the following instructions:

To make the information available to the ToolTalk service, the otype file is compiled with the ToolTalk type compiler tt_type_comp at application installation time. When an application that manages objects registers with the ToolTalk service, it declares its ptype. When a ptype is registered, the ToolTalk service checks for otypes that mention the ptype and registers the patterns found in these otypes.

The otype for your application provides addressing information that the ToolTalk service uses when delivering object-oriented messages. The number of otypes you have, and what they represent, depends on the nature of your application. For example, a word processing application might have otypes for characters, words, paragraphs, and documents; a diagram editing application might have otypes for nodes, arcs, annotation boxes, and diagrams.

An otype begins with an object-type identifier (otid). Following the otid are:

  1. An optional start string — ToolTalk will execute this command, if necessary, to start a process running the program.

  2. Signatures — Code that defines the messages that can be addressed to objects of the type (that is, the operations that can be invoked on objects of the type).

Signatures

Signatures defines the messages that can be addressed to objects of the type. A signature is divided by an arrow (=>) into two parts. The first part of a signature define matching criteria for incoming messages. The second part of a signature defines receiver values which the ToolTalk service adds to each message that matches the first part of the signature. These values specify the ptid of the program that implements the operation and the message's scope and disposition.

Creating Otype Files

The following listing shows the syntax for an otype file.

otype	::=	obj_header	'{' objbody* '}' [';']
obj_header	::=	'otype' otid [':' otid+]
objbody	::=	`observe:' osignature*
	|	`handle:' osignature*
		`handle_push:' osignature*
		`handle_rotate:' osignature*
osignature	::=	op args [contextdcl] [rhs][inherit] `;'
rhs	::=	[`=>' ptid [scope]]
		[`start'][`queue']
		[`opnum='number]
inherit	::=	`from' otid
args	::=	`(` argspec {, argspec}* `)'
	|	`(void)'
	|	`()'
contextdcl	::=	`context' `(` identifier {, identifier}* `)' `;'
argspec	::=	mode type name
mode	::=	`in' | `out' | `inout'
type	::=	identifier
name	::=	identifier
otid	::=	identifier
ptid	::=	identifier

Obj_Header Information

otid—object type identifier (otid). Identifies the object type. An otid must be unique for every installation. Because this identifier cannot be changed after installation time, each chosen name must be unique. For example, begin with the ptid of the tool that implements the otype. The otid is limited to 64 characters and should not be one of the reserved identifiers: ptype, otype, start, opnum, queue, file, session, observe, or handle.

Osignature Information

The object body portion of the otype definition is a list of osignatures for messages about the object that your application wants to observe and handle.

op—operation name. This name is matched against the op attribute in messages.


Note –

If you specify message signatures in both your ptype and otypes, use unique operation names in each. For example, do not specify a display operation in both your ptype and otype.


args—arguments for the operation. If the args list is void, the signature matches only messages with no arguments. If the args list is empty (just “()”), the signature matches messages without regard to the arguments.

contextdcl—context name. When a pattern with this named context is generated from the signature, it contains an empty value list.

ptid—process type identifier for the application that manages this type of object.

opnum—fill in the message's opnum attribute with the specified number to enable you to identify the signature that matched the message.

When the message matches the signature, the opnum from the signature is filled into the message. Your application can then retrieve the opnum with the tt_message_opnum call. By giving each signature a unique opnum, you can quickly determine which signature matched the message.

You can attach a callback routine to the opnum with the tt_otype_opnum_callback_add call. When the message is matched, the ToolTalk service will check for any callbacks attached to the opnum and, if any are found, run them.

inherit—Otypes form an inheritance hierarchy in which operations can be inherited from base types. The ToolTalk service requires the otype definer to explicitly name all inherited operations and the otype from which to inherit. This explicit naming prevents later changes (such as adding a new level to the hierarchy, or adding new operations to base types) from unexpectedly affecting the behavior of an otype.

scope—this pattern attribute is matched against the scope attribute in messages. It appears on the rightmost side of the arrow and is filled in by the ToolTalk service during message dispatch. This means the definer of the otype can specify the attributes instead of requiring the message sender to know how the message should be delivered.

Osignature Actions Information

start—if the osignature matches a message and no running process of this otype has a pattern that matches the message, start a process of this otype.

queue—if the osignature matches a message and no running process of this otype has a pattern that matches the message, queue the message until a process of this otype registers a pattern that matches it.

The following listing illustrates an otype file.

#include "Sun_EditDemo_opnums.h"

otype Sun_EditDemo_object {
	 handle:
	 /* hilite object given by objid, starts an editor if necessary */
	 hilite_obj(in string objid)
		=> Sun_EditDemo session start opnum=Sun_EditDemo_HILITE_OBJ;
};

The Sun_EditDemo_opnums.h file defines symbolic definitions for all the opnums used by edit.c, allowing both the edit.types file and edit.c file to share the same definitions.

Installing Type Information

The ToolTalk Types Database makes ptype and otype information available on the host that executes the sending process, the host that executes the receiving process, and the hosts that run the sessions to which the processes are joined.

To place your type information into the ToolTalk Types Database and make it available to the ToolTalk service, you compile your type files with the ToolTalk type compiler, tt_type_comp. This compiler creates ToolTalk types definitions for your type information and stores them in the ToolTalk Types Database. See Chapter 5, Maintaining Application Information for detailed information.

This version of the ToolTalk service provides a function to merge a compiled ToolTalk type file into the currently running ttsession:

tt_session_types_load(current_session, compiled_types_file)

where current_session is the current default ToolTalk session and compiled_types_file is the name of the compiled ToolTalk types file. This function adds new types and replaces existing types of the same name; other existing types remain unchanged.


Caution – Caution –

The action of tt_session_types_load() is controlled both by arguments to ttsession(1) and by ttsession_file(4). Refer to those man pages before using tt_session_types_load().


Checking for Existing Process Types

The ToolTalk service provides a simple function to test if a given ptype is already registered in the current session.

tt_ptype_exists(const char *ptid)

where ptid is the identifier of the session to test for registration.

Declaring Process Type

Since type information is only specified once (when your application is installed), your application needs to only declare its ptype each time it starts.

To declare your ptype, use tt_ptype_declare during your application's ToolTalk initialization routine. The ToolTalk service will create the message patterns listed in your ptype and any otypes that reference the specified ptype.

The message patterns created when you declare your ptype exist in memory until your application exits the ToolTalk session.


Note –

The message patterns created when you declare your ptype information cannot be unregistered with tt_pattern_unregister; however, you can unregister these patterns with tt_ptype_undeclare.


The following listing illustrates how a ptype is registered during a program's initialization.

/*
 * Initialize our ToolTalk environment.
 */
int
edit_init_tt()
{
        int     mark;
        char    *procid = tt_open();
        int     ttfd;
        void    edit_receive_tt_message();

        mark = tt_mark();

        if (tt_pointer_error(procid) != TT_OK) {
                return 0;
        }
        if (tt_ptype_declare(“Sun_EditDemo”) != TT_OK) {
                fprintf(stderr,”Sun_EditDemo is not an installed ptype.\n”);
                return 0;
        }
        ttfd = tt_fd();
        tt_session_join(tt_default_session());
        notify_set_input_func(edit_ui_base_window,
                              (Notify_func)edit_receive_tt_message,
                              ttfd);

        /*
         * Note that without tt_mark() and tt_release(), the above
         * combination would leak storage -- tt_default_session() returns
         * a copy owned by the application, but since we don't assign the
         * pointer to a variable we could not free it explicitly.
         */

        tt_release(mark);
        return 1;
}

Undeclaring Process Types

There may be cases when you need to retract a declared ptype; for example, in the CASE environment:

To unregister a ptype, use tt_ptype_undeclare. This call reverses the effect of the tt_ptype_declare call; that is, all patterns generated from the ptype are unregistered and the process is removed from the session's list of active processes with this ptype. This call returns a status of TT_ERR_PTYPE if the named ptype was not declared by the calling process.


Caution – Caution –

One invocation of tt_type_undeclare will completely unregister the ptype regardless of how many times the process has declared the ptype; that is, multiple declarations of the ptype are the same as declaring it once.


Example 10–1 is an example of how to retract a a declared ptype.


Example 10–1 Undeclaring a Ptype

/*

 * Obtain procid
 */
tt_open();

/*

 * Undeclared Ptype

 */
tt_ptype_undeclare(ptype);