Chapter 7. Interapplication Data Exchange

This chapter describes how to implement the recommended data exchange mechanisms in your applications. It contains these sections:

Data Exchange Overview

As detailed in Chapter 5, “Data Exchange on the Indigo Magic Desktop,” in the Indigo Magic User Interface Guidelines, Silicon Graphics recommends that your application support both the Primary and Clipboard Transfer Models. The Primary Transfer Model allows users to copy data using mouse buttons, whereas the Clipboard Transfer model allows users to use the “Cut,” “Copy,” and “Paste” options from the Edit menu (or the corresponding keyboard accelerators) to transfer data.

The data exchange model recommended by Silicon Graphics is based on the standard mechanisms provided by the X and Xt. You can consult the O'Reilly & Associates book The X Window System, Volume 4: X Toolkit Intrinsics Programming Manual by Adrian Nye for more information on the standard Xt data exchange methods.


Note: Silicon Graphics recommends that you not use the IRIS IM clipboard routines for handling data exchange.


Primary Transfer Model Overview

When the user selects some data in an application, the application should highlight that data and assert ownership of the PRIMARY selection. Until the application loses the PRIMARY selection, it should then be prepared to respond to requests for the selected data in various target formats. “Supported Target Formats” describes the standard target formats.

When the user selects data in another application, your application loses ownership of the PRIMARY selection. In general, when your application loses the primary selection, it should keep its current selection highlighted. When a user has selections highlighted in more than one window at a time, the most recent selection is always the primary selection. This is consistent with the persistent always selection discussed in Section 4.2, “Selection Actions,” in the OSF/Motif Style Guide, Release 1.2. There is an exception to this guideline: those applications that use selection only for primary transfer, for example, the winterm shell window. The only reason for users to select text in a shell window is to transfer that text using the primary transfer mechanism. In this case, when the winterm window loses the primary selection, the highlighting is removed. This is referred to as nonpersistent selection in Section 4.2, “Selection Actions,” in the OSF/Motif Style Guide, Release 1.2.

The persistent always selection mechanism allows the user to have data selected in different applications. The user can still manipulate selected data using application controls. Furthermore, the user can reassert the selected data as the PRIMARY selection by pressing <Alt–Insert>.

When the user clicks the middle mouse button (BTransfer) in your application, your application should attempt to copy the primary selection to the current location of the mouse pointer. First, your application should request a list of target formats supported by the primary selection owner. Then your application should select the most appropriate target format and request the primary selection in that format.

“Supporting the Primary Transfer Model” in Chapter 5 of the Indigo Magic User Interface Guidelines further discusses use of the Primary Transfer Model.

Clipboard Transfer Model Overview

When the user selects the “Copy” option from your application's Edit menu (or uses the keyboard accelerator), your application should assert ownership of the CLIPBOARD selection. Until the application loses the CLIPBOARD selection, it should then be prepared to respond to requests for the data selected at the time your application took ownership of the CLIPBOARD selection. (In other words, your application must somehow store the value of the selection when the user performs the copy action; the application can then provide this value even if the user subsequently changes the application's selection.)

When the user selects the “Cut” option for your application's Edit menu (or uses the keyboard accelerator), your application should assert ownership of the CLIPBOARD selection. Your application must cut the selected data, but it should store the data and be prepared to respond to requests for the data until it loses ownership of the CLIPBOARD selection.

When the user selects the “Paste” option for your application's Edit menu (or uses the keyboard accelerator), your application should attempt to copy the clipboard selection to the current location of the location cursor. First, your application should request a list of target formats supported by the clipboard selection owner. Then your application should select the most appropriate target format and request the clipboard selection in that format.

“Supporting the Clipboard Transfer Model” in Chapter 5 of the Indigo Magic User Interface Guidelines further discusses use of the Clipboard Transfer Model.

Interaction Between the Primary and Clipboard Transfer Models

Silicon Graphics recommends that you implement the Primary and Clipboard Transfer Models so that they operate separately. The only complication is maintaining data in the PRIMARY selection when the user performs a cut action. Consider the following example:

  1. The user selects data in an application. The application asserts ownership of the PRIMARY selection.

  2. The user performs a cut action. The application asserts ownership of the CLIPBOARD selection and removes the selected data from the display.

  3. The user goes to another application that already has data selected.

  4. The user cuts the data selected in the second application. The second application asserts ownership of the CLIPBOARD selection and removes the selected data from the display.

The clipboard actions described above should not affect the PRIMARY selection. In this example, the first application should retain ownership of the PRIMARY selection and continue to be prepared to respond to requests for the value of the PRIMARY selection. To support this, the application should somehow store the value of the PRIMARY selection until it no longer owns the PRIMARY selection.

To properly handle the situation described above, your application should implement the following:

  1. In the function that handles the Clipboard Transfer Model's cut action, test to see whether the application owns the PRIMARY selection. If it does, you should preserve the selected data. If selections in your application are typically small (for example, ASCII text), you might simply copy the data to a buffer. If selections in your application are typically large (for example, sound or movie clips), you might remove the data from the display but retain pointers to it.

  2. In the function that handles losing the PRIMARY selection, test to see whether you have data preserved from a cut action. If so, and the application currently doesn't own the CLIPBOARD selection, you should free that data or reset the pointers to it.

Implementing the Primary Transfer Model

This section describes how to implement support for the Primary Transfer Model in your application.


Note: Silicon Graphics recommends that you don't use the IRIS IM clipboard routines, because they are not as flexible as the Xt selection routines.


Data Selection

When the user selects data in a window of your application, it should call XtOwnSelection(3Xt) to assert ownership of the PRIMARY selection and highlight the selected data.

The code fragment in Example 7-1 shows a simple example of asserting ownership of the PRIMARY selection. For clarity, this example omits code for manipulating the selection itself (for example, setting up pointers to the selection).

“Selection” in Chapter 7 of the Indigo Magic User Interface Guidelines discusses guidelines for allowing users to select data and for hightlighting selected data.

Example 7-1. Asserting Ownership of PRIMARY Selection

Boolean ownPrimary;

/*
   w is window in which selection occurred
   event is pointer to event that caused selection
*/

void dataSelected(Widget w, XButtonEvent *event)
{
...
  /* 
     Assert ownership of PRIMARY selection.

     XA_PRIMARY is the slection.
     event->time is timestamp of the event.
     primaryRequestCallback is the function called
         whenever another application requests the
         value of the PRIMARY selection.
     lostPrimaryCallback is the function called whenever
         the application loses the selection.
  */

  ownPrimary = XtOwnSelection(w, XA_PRIMARY, event->time,
                              primaryRequestCallback,
                              lostPrimaryCallback,
                              NULL);

  /*
     If we successfully obtained ownership, highlight
     the data; otherwise, clean up
  */

  if (ownPrimary)
    highlightSelection();
  else
    lostPrimaryCallback(w, XA_PRIMARY);
...
}


Requests for the Primary Selection

When you assert ownership of the PRIMARY selection, one of the parameters you pass to XtOwnSelection() is a callback function to handle requests for the value of the PRIMARY selection. When another application requests the value of the PRIMARY selection, the Xt selection mechanism invokes your application's callback function.

The requesting application indicates a desired target format. Typically, a requestor first asks for the special target format TARGETS. Your application should respond with a list of target formats it supports. The requestor then chooses an appropriate target format and requests the selection value in that format. “Supported Target Formats” describes some of the common target formats your application should support.

Loss of the Primary Selection

When your application loses the PRIMARY selection and your application follows the persistent always selection model discussed in “Primary Transfer Model Overview”, don't remove the highlight from any selected data. The user should still be able to cut or copy any selected data using the Clipboard Transfer Model. If your application follows the nonpersistent selection model as discussed in “Primary Transfer Model Overview,” you should remove the highlight.

Your application should also test to see whether you have data preserved from a cut action (see “Cut Actions”). If so, and your application currently doesn't own the CLIPBOARD selection, you should free that data or reset the pointers to it. “Interaction Between the Primary and Clipboard Transfer Models” describes the rationale for this procedure.


Note: To comply with the Indigo Magic User Interface Guidelines, if the user presses <Alt–Insert> in your application, you should reassert ownership of PRIMARY for your application.


Inserting the Primary Selection

When the user clicks the middle mouse button in your application, it should perform the steps described below.

  1. Your application should ask the owner of the PRIMARY selection for a list of its TARGETS, using XtGetSelectionValue() with selection PRIMARY and target TARGETS.

  2. Your application should look through the list of supported targets, select the one that is appropriate for your application, and call XtGetSelectionValue() again with that new target.

  3. If the selection owner does not support TARGETS, then your application should ask for the target STRING, if it can support that target.

    Silicon Graphics recommends that you support STRING, even if your application doesn't support text. For instance, a movie player could get the selection as a string and try to parse it as a filename. That way users could select a filename in a terminal emulator window and paste it into another application.

Implementing the Clipboard Transfer Model

This section describes how to implement support for the Clipboard Transfer Model in your application.

Cut Actions

When the user performs a cut action, your application should:

  1. Call XtOwnSelection(3Xt) to assert ownership of the CLIPBOARD selection.

  2. Remove the selected data from the display. Retain the selected data until your application loses ownership of the CLIPBOARD selection.

  3. Test to see whether the application owns the PRIMARY selection. If it does, you should preserve the selected data, even after losing ownership of the CLIPBOARD selection. You should retain the data until your application also loses ownership of the PRIMARY selection.

    If selections in your application are typically small (for example, ASCII text), you might simply copy the data to a buffer. If selections in your application are typically large (for example, sound or movie clips), you might remove the data from the display but retain pointers to it.

The code fragment in Example 7-2 shows a simple example of handling a cut action and asserting ownership of the CLIPBOARD selection. For clarity, this example omits code for manipulating the selection itself (for example, setting up pointers to the selection).

Example 7-2. Handling Cut Actions in the Clipboard Transfer Model

Boolean ownPrimary;
Boolean primaryPreserved;

/*
   w is window in which selection occurred
   event is pointer to event that caused selection
  */

void selectionCut(Widget w, XButtonEvent *event)
{
...
  /* 
     Assert ownership of CLIPBOARD selection.

     XA_CLIPBOARD is the selection.
     event->time is timestamp of the event.
     clipboardRequestCallback is the function called
         whenever another application requests the
         value of the CLIPBOARD selection.
     lostClipboardCallback is the function called whenever
         the application loses the selection.
  */

  ownClipboard = XtOwnSelection(w, XA_CLIPBOARD, event->time,
                                clipboardRequestCallback,
                                lostClipboardCallback,
                                NULL);

  if (ownClipboard)
  {
    /*
       Retain the selected data until the application loses
       ownership of the CLIPBOARD selection.
    */

    preserveClipboardSelection();

    /*
       If we also own the PRIMARY selection, we need to
       preserve the selected data separately so that we can
       continue to satisfy requests for the PRIMARY selection
       even if we lose the CLIPBOARD selection.
    */

    if (ownPrimary)
      primaryPreserved = preservePrimarySelection();
  }
...
}


Copy Actions

When the user performs a copy action, your application should call XtOwnSelection(3Xt) to assert ownership of the CLIPBOARD selection. No other actions are required.

Requests for the Clipboard Selection

When you assert ownership of the CLIPBOARD selection, one of the parameters you pass to XtOwnSelection() is a callback function to handle requests for the value of the CLIPBOARD selection. When another application requests the value of the CLIPBOARD selection, the Xt selection mechanism invokes your application's callback function.

The requesting application indicates a desired target format. Typically, a requestor first asks for the special target format TARGETS. Your application should respond with a list of target formats it supports. The requestor then chooses an appropriate target format and requests the selection value in that format. “Supported Target Formats” describes some of the common target formats your application should support.

Paste Actions

When the user selects “Paste” from the File menu, your application should:

  1. Ask the owner of the CLIPBOARD selection for a list of its TARGETS, using XtGetSelectionValue() with selection CLIPBOARD and target TARGETS.

  2. Look through the list of supported targets, select the one that is appropriate for your application, and call XtGetSelectionValue() again with that new target.

  3. If the selection owner does not support TARGETS, then your application should ask for the target STRING, if it can support that target.

    Silicon Graphics recommends that you support STRING, even if your application doesn't support text. For instance, a movie player could get the selection as a string and try to parse it as a filename. That way users could select a filename in a terminal emulator window and paste it into another application.

Loss of the Clipboard Selection

When your application loses the Clipboard selection, don't remove the highlight from any selected data. The user should still be able to cut or copy any selected data. Your application can discard any data it had retained as a result of a cut operation (see “Cut Actions”).

Supported Target Formats

Every application should support the TARGETS, TIMESTAMP, MULTIPLE, and STRING targets. The Xt selection functions support the MULTIPLE targets for you. XmuConvertStandardSelection() supports the TIMESTAMP target. (Silicon Graphics recommends that applications use XmuConvertStandardSelection() because it also supports HOSTNAME, NAME, CLIENT_WINDOW, and a variety of other useful targets.) Your application must support the TARGETS and STRING targets itself.

In addition, Silicon Graphics has defined other targets for data types used by Silicon Graphics applications and libraries. Table 7-1 lists the atom names for these Silicon Graphics data types.

Table 7-1. Additional Data Types Supported by Silicon Graphics

Name of Atom/Target

Description

INVENTOR

Data appropriate for inventor widgets. (This is already defined by Inventor and described in Inventor documentation.)

_SGI_RGB_IMAGE_FILENAME

The name of a file that contains a Silicon Graphics format image file. This is an rgb file. The file is the responsibility of the receiver, once the selection owner has generated it.

_SGI_AUDIO_FILENAME

The name of a file that contains Silicon Graphics format sound data, that can be read using libaudiofile. The file is the responsibility of the receiver, once the selection owner has generated it.

_SGI_MOVIE_FILENAME

The name of a file that contains a Silicon Graphics format movie. This file can be viewed with the Silicon Graphics movie library or the movie widget. The file is the responsibility of the receiver, once the selection owner has generated it.



Caution: Xt implements a timeout when transferring data using the selection mechanism. The default is five seconds. Often, this is inadequate for applications transferring audio, image, or movie data. Therefore, if your application supports receiving such selections, you should call XtAppSetSelectionTimeout() to change the timeout to a larger value; 60 to 120 seconds is usually sufficient.