This section details primary transfers.
A primary transfer involves interaction among a user, an application, a source widget, and a destination widget. Following are the steps involved in a typical primary transfer:
The ExmStringTransfer demonstration widget supports primary transfer. The following translations are relevant to the primary transfer:
<Btn1Down>: ExmStringTransferMoveFocus()ExmStringTransferCopyPrimary()\n\ <Btn2Down>: ExmStringTransferProcessDrag()\n\
A user starts a primary copy by pressing Btn1Down. However, the Btn2Down translation is far more puzzling because Btn2Down could mean either a primary paste or the start of a drag operation. ExmStringTransferProcessDrag solves this puzzle by determining whether or not ExmStringTransfer currently owns the primary selection. If it does, ExmStringTransferProcessDrag calls the ExmStringTransferPastePrimary routine.
The ExmStringTransfer widget contains the following relatively simple copy primary routine:
static void ExmStringTransferCopyPrimary( Widget w, XEvent *event, String *params, Cardinal *num_params) { Time time; ExmStringTransfer stw = (ExmStringTransfer) w; /* First we must obtain a timestamp. This is required for ICCCM compliance. XtLastTimestampProcessed holds the timestamp from the last event the Intrinsics saw with a timestamp. */ time = XtLastTimestampProcessed(XtDisplay(w)); /* Own the primary selection. Indicate this to the user by reversing the foreground and background in the text rendition (eventually) */ stw->string_transfer.own_primary = True; /* Once we call XmePrimarySource, the widget's transfer trait convert method will get called if a destination wishes to obtain the PRIMARY selection. */ XmePrimarySource(w, time); /* Update the widget to show the new state */ stw->core.widget_class->core_class.expose(w, NULL, NULL); }
In the preceding code, stw->string_transfer.own_primary is a Boolean field. ExmStringTransfer sets this field to True when the widget holds the primary selection and False when the widget relinquishes the primary selection.
The most important part of the paste primary routine of ExmStringTransfer is its call to XmePrimarySink. Following is the complete ExmStringTransferPastePrimary routine:
static void ExmStringTransferPastePrimary( Widget w, XEvent *event, String *params, Cardinal *num_params) { Time time; unsigned int op; /* 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)); /* We determine the right operation to perform by looking at the modifiers present */ if (event -> xbutton.state & ShiftMask) { if (event -> xbutton.state & ControlMask) op = XmLINK; else op = XmMOVE; } else op = XmCOPY; /* Calling XmePrimarySink will start the process of requesting the PRIMARY selection to be pasted using the transfer trait destination callback for this widget class */ XmePrimarySink(w, op, NULL, time); }
The second argument to XmePrimarySink (called op in the preceding code) describes the kind of operation that the user has requested. UTM will copy the value of op into the operation member of the XmDestinationCallbackStruct.