Suppose you want the widget you are writing to support data transfer. To implement data transfer by using UTM, you must do the following:
This section details each of these steps. Throughout this section and the remainder of the chapter, we will examine how the ExmStringTransfer widget implements UTM. The ExmStringTransfer demonstration widget is a subclass of ExmString. The only feature that ExmStringTransfer layers on top of ExmString is its support of the following three data transfer mechanisms:
ExmStringTransfer gives us an excellent opportunity to isolate the code that implements UTM.
ExmStringTransfer has two important limitations. First, ExmStringTransfer does not let users transfer portions of the displayed text. In other words, a user may only transfer the entire contents of the ExmStringTransfer widget. By contrast, a more powerful widget such as XmText lets users copy a selected word, line, paragraph, and so forth.
Second, ExmStringTransfer only knows how to do copy operations; it cannot do a move operation. In fact, when ExmStringTransfer is a destination, the incoming string will overwrite any existing displayed string.
The sample application stored in directory demos/programs/Exm/app_in_c contains two ExmStringTransfer widgets. You might want to build this application and experiment with it. For example, try to copy data from one ExmStringTransfer widget to another. Then, try to copy text from a widget in another application to one of the ExmStringTransfer widgets.
You must decide what data transfer mechanisms your widget will support. Ideally, your widget should support as many data transfer mechanisms as possible. Writing a widget that supports multiple data transfer mechanisms is only slightly more time consuming than writing a widget that supports only one data transfer mechanism. Most of the data transfer code is independent of a particular form of data transfer.
You might be writing a read-only widget. In other words, the user is not allowed to transfer data into the widget. For these widgets, you need only supply the source side of data transfer; you can omit the destination side.
One way to help you decide what data transfer mechanisms your widget should
support is to examine how the widgets in the Motif toolkit support data
transfer. (By the way, as of Motif Release 2.0, all the widgets in the Motif
toolkit use UTM to implement data transfer.) Table 10-2 summarizes the data
transfer methods supported in the standard widget set. When an entry says
"Source only" or "Drag only," it means that a user can copy data in this
widget but cannot cut data out of it or paste data into it. For example, a
user can copy text from an XmLabel to an XmText widget but cannot copy text
from an XmText to an XmLabel widget.
Table 22. Data Transfer in the Standard Widget Set
Widget | Primary | Secondary | Clipboard | Drag and Drop |
XmCascadeButton | Yes (Source only) | No | No | Yes (Drag only) |
XmCascadeButtonGadget | Yes (Source only) | No | No | Yes (Drag only) |
XmDrawnButton | Yes (Source only) | No | No | Yes (Drag only) |
XmContainer | Yes | No | Yes | Yes |
XmLabel | No | No | No | Yes (Drag only) |
XmLabelGadget | No | No | No | Yes (Drag only) |
XmList | Yes (Source only) | No | Yes (source only) | Yes (Drag only) |
XmPushButton | Yes (Source only) | No | No | Yes (Drag only) |
XmPushButtonGadget | Yes (Source only) | No | No | Yes (Drag only) |
XmScale | No | No | No | Yes (Drag only) |
XmText | Yes | Yes | Yes | Yes |
XmTextField | Yes | Yes | Yes | Yes |
XmToggleButton | Yes (Source only) | No | No | Yes (Drag only) |
XmToggleButtonGadget | Yes (Source only) | No | No | Yes (Drag only) |
Users trigger data transfer by pressing keys or mouse buttons. Your widget must supply data transfer translations compatible with the Motif Style Guide.
Widgets typically provide two different kinds of translations to support data transfer.
The first kind of data transfer translation allows the user to select the data to be transferred. For example, the XmText widget provides several translations that allow a user to select different subsets of the displayed text. These subsets range from one character to the entire text. By contrast, XmLabel does not allow a user to select a portion of its displayed text; the user can only select the entire displayed text.
In addition to providing selection translations, your widget must also supply translations that let the user initiate and complete the data transfer. For example, if a widget is to support drag and drop, the widget must supply a translation that allows the user to mark the start of the drag operation. (Typically, the user starts a drag operation with a Button2 or Button2Press event.) The four different kinds of data transfer each require different translations.
The easiest way to supply appropriate Motif translations for your widget is to copy the data translations of the standard Motif widget that is most similar to your own. Translations for standard Motif widgets are documented in the Motif Programmer's Reference.
Your widget must provide actions that respond to the user's data transfer request. These action methods have to call the appropriate UTM Xme set-up routine. The routine your action calls depends on the type of data transfer, and on whether the action method is for the source side of the transfer or the destination side of the transfer.
If you are writing an action method that represents the source side of a data transfer, the action method must call one of the following routines:
For example, suppose a widget is to serve as a source for a clipboard transfer. This widget must respond to a selection translation by calling XmeClipboardSource.
Broadly speaking, each of the preceding Xme routines makes the following sequence of calls:
Actions in destination widgets must call one of the following routines:
For example, suppose a widget is to serve as a destination for a clipboard transfer. When the user triggers a clipboard paste, the clipboard paste action must call XmeClipboardSink.
Broadly speaking, each of the preceding four routines trigger the following sequence of calls:
The procedures and callbacks are described later in this section.
Your widget must install the XmQTtransfer trait in order to support UTM data transfers.
Your widget can install XmQTtransfer as it would install any trait; namely by calling XmeTraitSet. Typically, the call is made from a class_part_initialize method.
Widgets capable of acting as a source for data transfer must provide a convertProc trait method. Widgets capable of acting as a destination for data transfer must provide at least a destinationProc trait method. Frequently, a widget will be both a source and a destination. In this case, your widget must supply both trait methods. Destination widgets may optionally also provide a destinationPreHookProc trait method.
For example, the ExmStringTransfer widget installs the XmQTtransfer trait as part of its ClassPartInitialize method. The code that does the installation is as follows:
ClassPartInitialize(WidgetClass widgetclass) { XmeTraitSet((XtPointer) widgetclass, XmQTtransfer, (XtPointer) &StringTrT); }
where the StringTrT variable is declared earlier in the StringTrans.c file as follows:
static XmConstXmTransferTraitRec StringTrT = { 0, /* version */ (XmConvertCallbackProc) ConvertProc, /* convertProc */ (XmDestinationCallbackProc) DestinationProc, /* destinationProc */ NULL, /*no destinationPreHookProc */ };
Source widgets must supply a convertProc (convert procedure) trait method. The convertProc method is one of the trait methods of the XmQTtransfer trait. (See Chapter 18 for complete syntactic details on the XmQTtransfer trait.) UTM automatically calls convertProc whenever an object (typically, a destination widget) requests a conversion from the widget.
The convertProc has the same prototype as any Intrinsics callback. Therefore, the third argument to convertProc is call_data. UTM will pass an XmConvertCallbackStruct to the call_data argument. The XmConvertCallbackStruct contains all the raw data required for the conversion. For example, the targets member of this structure contains the name of the target atom that the destination procedure wants converted.
Your convertProc must respond to the following two general kinds of requests:
Later on in this chapter, we will discuss the specific targets your widget should support.
Your widget must supply a destinationProc (destination procedure) trait method in order to serve as a destination widget in a data transfer. The destinationProc trait method is one of the trait methods of the XmQTtransfer trait. (See Chapter 18 for complete syntactic details on the XmQTtransfer trait.) UTM automatically calls destinationProc whenever a user requests that data be transferred to the destination widget. The destinationProc trait method is responsible for requesting data from the source widget and for pasting this data into the destination widget. However, the destinationProc trait method will ask a transfer procedure to take over some of these responsibilities.
UTM calls destinationProc after calling any XmNdestinationCallback procedures defined by the application. The toolkit passes destinationProc an XmDestinationCallbackStruct structure. This structure contains all the fields necessary to make requests to the source widget.
The destinationProc trait method should typically call XmTransferValue to request a conversion from the source widget XmTransferValue automatically calls the source widget's convertProc. When the convertProc finishes, XmTransferValue typically calls the destination widget's transfer procedure. The name of the transfer procedure is identified by the third argument to the XmTransferValue call.
The destinationProc trait method can terminate a data transfer by calling XmTransferDone.
XmTransferValue, together with XmTransferDone, form the UTM replacements for the following older calls:
If you are writing a destination widget, you will probably have to write one or more transfer procedures. UTM calls a transfer procedure when the convertProc trait method finishes the conversion. UTM passes the transfer procedure a pointer to an XmSelectionCallbackStruct. (See the XmTransferDone(3) reference page of the Motif Programmer's Reference for details on this structure.) The value member of XmSelectionCallbackStruct holds the selection converted to the target that the destination widget has requested. The target procedure will take that converted target and paste it into the destination widget.