This section explains some of the finer points of UTM clipboard transfer. As we shall see, it is quite a bit more complicated than UTM primary transfer. This section provides the following information:
Motif provides a large set of XmClipboard routines. (See the Motif Programmer's Reference for details on each routine, or see the Motif Programmer's Guide for a summary of the routines.)
Although these routines are still supported, we recommend that you use UTM instead. In other words, you should use UTM as your interface to the clipboard.
A clipboard transfer really consists of two separate transfers. In the first transfer, the source widget transfers the data to the clipboard. The clipboard acts as a pseudo-destination widget for this first transfer. In the second transfer, the clipboard transfers the data to the destination widget. For this second transfer, the clipboard acts as a pseudo-source widget.
When the source widget transfers data to the clipboard, the source widget has no idea what target the destination widget might request. Therefore, the source widget typically converts the selection to several different targets and transfers each of these targets to the clipboard. For example, if the source widget displays text, the source widget might transfer the selected text to the clipboard one time for each of the five standard textual targets. When the destination widget requests the data from the clipboard, the destination widget will (hopefully) ask for one of the five standard textual targets. If it does, the clipboard can transfer the selection to the destination widget.
Clipboard transfer is inherently less efficient than primary transfer. However, Motif does provide a somewhat more efficient mechanism for clipboard transfer called "deferred" clipboard transfer.
The main problem with any clipboard transfer is that the source widget has to copy many different versions of the selection to the clipboard. Using deferred clipboard transfer does not really solve this problem; however, it does make the copying operations significantly cheaper. That is because the source widget need only copy "pointers" or references to the selection, rather than copying the selection itself.
UTM always asks your clipboard source widget to provide a list of its immediate clipboard targets (_MOTIF_CLIPBOARD_TARGETS) and its list of deferred clipboard targets (_MOTIF_DEFERRED_CLIPBOARD_TARGETS ). It is up to you to decide which clipboard targets fall into which category. It is acceptable to make all clipboard targets immediate, or to make them all deferred, or to use some combination of the two. One rule of thumb is that a clipboard target should be deferred if it is relatively expensive to copy it to the clipboard.
This section explains how you must use snapshots to implement deferred clipboard targets.
If your source widget is to act as a clipboard source, UTM will ask your convertProc trait method to convert the _MOTIF_DEFERRED_CLIPBOARD_TARGETS target. Your convertProc trait method should respond to this request as it would respond to any request for a list of targets; namely, by building a list of deferred clipboard targets. For example, suppose we want the list of deferred clipboard targets to consist of _MOTIF_COMPOUND_STRING and STRING. In this case, the following convertProc code should be sufficient:
ConvertProc( Widget w, XtPointer client_data, XtPointer call_data) { XmConvertCallbackStruct *cs = (XmConvertCallbackStruct *) call_data; Atom _MOTIF_DEFERRED_CLIPBOARD_TARGETS = XInternAtom(XtDisplay(w), "_MOTIF_DEFERRED_CLIPBOARD_TARGETS", False); Atom _MOTIF_COMPOUND_STRING = XInternAtom(XtDisplay(w), "_MOTIF_COMPOUND_STRING", False); Atom STRING = XInternAtom(XtDisplay(w), "STRING", False); ... if (cs->target = _MOTIF_DEFERRED_CLIPBOARD_TARGETS) { Atom *targs = (Atom *) XtMalloc(sizeof(Atom) * 2); int n; n = 0; targs[n] = _MOTIF_COMPOUND_STRING; n++; targs[n] = STRING; n++; cs->value = (XtPointer)targs; cs->type = XA_ATOM; cs->length = n; cs->format = 32; } ...
Since the length member of the XmConvertCallbackStruct was non-zero, UTM will call the convertProc trait method again This time, UTM will ask your convertProc trait method to convert the _MOTIF_SNAPSHOT target. Your convertProc must respond to this target by doing the following:
A snapshot is nothing more than a copy of the current clipboard selection in whatever format you decide to save it in. (UTM does not define how the snapshot must be stored.) If you want, you can go ahead and convert the selection to _MOTIF_COMPOUND_STRING format and to STRING format and then save the converted selection somewhere in your widget. However, it will probably be more efficient just to save the selection somewhere safe and to worry about doing the conversions later.
The distinguisher atom must be unique, so you are going to have to devise some algorithm for generating unique atom string names. One idea is to base the snapshot atom string name on the widget ID itself. For example:
static Atom GenerateUniqueDistinguisherAtom(Widget w) { char distinguisher_atom_string[32]; ExmMyWidget my_widget = (ExmMyWidget)w; sprintf(distinguisher_atom_string, "_EXM_SNAP_%lX_%X", (long)w, my_widget.snap_counter++); return (XInternAtom(XtDisplay(w), distinguisher_atom_string, False)); }
Then your convertProc trait method can convert the _MOTIF_SNAPSHOT request as follows:
... Atom *distinguisher_pointer; if (cs->target = _MOTIF_SNAPSHOT) { /* Save the clipboard selection somewhere. */ ... /* Now return the distinguisher atom. */ distinguisher_pointer = (Atom *) XtMalloc(sizeof(Atom)); *distinguisher_pointer = GenerateUniqueDistinguisherAtom(w); cs->value = (XtPointer)distinguisher_pointer; cs->type = XA_ATOM; cs->length = 1; cs->format = 32; } ...
UTM stores this distinguisher atom on the clipboard. This one distinguisher atom symbolizes both the deferred clipboard targets ( STRING and _MOTIF_COMPOUND_STRING). Later, the destination widget may request one of the deferred clipboard targets; for example, STRING. If it does, UTM will call your widget's convertProc trait method, passing the following in the XmConvertCallbackStruct:
Your widget's convertProc trait method must respond to this request by finding the snapshot and converting it to STRING. When the conversion is completed, UTM automatically passes the converted data to the clipboard. Then, the clipboard automatically passes the converted data to the destination widget.
This section takes you step by step through a typical clipboard transfer. Remember that this is a typical transfer, but it is by no means the only way a clipboard transfer might happen. In this section, we use the term "conversion routines" to mean a combination of any XmNconvertCallback routines of the application and the convertProc trait method of the source widget.
Following are the steps:
The ExmStringTransfer demonstration widget supports clipboard transfer. The following translations are relevant to clipboard transfer:
:<Key>osfPaste: ExmStringTransferPasteClipboard()\n\ :<Key>osfCut: ExmStringTransferCopyClipboard()\n\ :s <Key>osfInsert: ExmStringTransferPasteClipboard()\n\ :s <Key>osfDelete: ExmStringTransferCopyClipboard()\n\
To copy the text in an ExmStringTransfer widget to the clipboard, a user can either press the osfCut or osfDelete virtual keys. Despite their ominous names, these keys do not remove or alter any text in the ExmStringTransfer widget. A user pastes data from the clipboard to an ExmStringTransfer widget by pressing the Shift osfInsert or Shift osfDelete virtual keys.
The clipboard copy routine of ExmStringTransfer is shown as follows:
static void ExmStringTransferCopyClipboard( Widget w, XEvent *event, String *params, Cardinal *num_params) { Time time; /* First we must obtain a timestamp. This is required for ICCCM compliant ownership of a selection. We use XtLastTimestampProcessed which holds the timestamp from the last event the Intrinsics saw with a timestamp. */ time = XtLastTimestampProcessed(XtDisplay(w)); /* When we call XmeClipboardSource, either the Motif clipboard will request the current selection data or an external clipboard manager will obtain the data. When the data is obtained, the CLIPBOARD selection will be owned by the data holder */ XmeClipboardSource(w, XmCOPY, time); }
The clipboard paste routine of the ExmStringTransfer widget is shown as follows:
static void ExmStringTransferPasteClipboard( Widget w, XEvent *event, String *params, Cardinal *num_params) { /* Calling XmeClipboardSink will start the process of requesting the CLIPBOARD selection to be pasted using the transfer trait destination callback for this widget class */ XmeClipboardSink(w, XmCOPY, NULL); }