This section explains how to write a conversion routine that can convert various targets. In this section, we will examine how ExmStringTransfer implemented its convertProc trait method.
Although we have assumed that you are a widget writer working on a convertProc trait method, the conversion information in this section also applies to an application programmer writing an XmNconvertCallback procedure. Throughout this section, we use the term "conversion routine" to mean either a convertProc trait method or an XmNconvertCallback procedure.
When writing a conversion routine, you must do the following tasks:
The remainder of this section explores all of the preceding tasks.
A conversion routine must declare Atom variables for every target referenced in the convert procedure. The ConvertProc trait method of ExmStringTransfer used XInternAtom as follows to create most of its Atom variables:
enum { CLIPBOARD, TEXT, COMPOUND_TEXT, FOREGROUND, BACKGROUND, TARGETS, MOTIF_DROP, MOTIF_C_S, MOTIF_EXPORT_TARGETS, CLIPBOARD_IMMEDIATE, LOSE_SELECTION, /* special values */ LOCALE_ATOM, NUM_ATOMS }; char* atom_names[] = { XmSCLIPBOARD, XmSTEXT, XmSCOMPOUND_TEXT, "FOREGROUND", "BACKGROUND", XmSTARGETS, XmS_MOTIF_DROP, XmS_MOTIF_COMPOUND_STRING, XmS_MOTIF_EXPORT_TARGETS, XmS_MOTIF_CLIPBOARD_TARGETS, XmS_MOTIF_LOSE_SELECTION }; Atom atoms[NUM_ATOMS]; assert(XtNumber(atom_names) == NUM_ATOMS - 1); XInternAtoms(XtDisplay(w), atom_names, NUM_ATOMS - 1, False, atoms); atoms[LOCALE_ATOM] = XmeGetEncodingAtom(w);
Wherever the code referenced one of these atoms (say "MOTIF_C_S"), that would be replaced by an index into the array ("atoms[MOTIF_C_S]"). The LOCALE_ATOM was the only exception; ConvertProc called XmeGetEncodingAtom as follows to get the LOCALE_ATOM:
Atom LOCALE_ATOM = XmeGetEncodingAtom(w);
The ICCCM insists that source widgets respond to a TARGETS request by returning a list of all the target atoms that your widget can convert. If your widget serves as a source for a clipboard transfer, then your conversion routine must also be able to handle the request for a list of _MOTIF_CLIPBOARD_TARGETS and _MOTIF_DEFERRED_CLIPBOARD_TARGETS. (See Section 10.5 for more details on this target.) If your widget serves as a source for a drag and drop transfer, then your conversion routine must also be able to handle the request for a list of _MOTIF_EXPORT_TARGETS. (See Section 10.6 for more details on this target.)
To help handle the TARGETS request, Motif provides the XmeStandardTargets routine. This routine carves out enough dynamic memory to hold a list of all the standard and nonstandard targets your widget supports. Then, this routine fills the first slots of this dynamic memory with the names of the standard targets. It is up to your code to fill in the remaining slots with the names of the nonstandard targets.
For example, the ExmStringTransfer widget needs to respond to TARGETS by returning a list consisting of all the standard targets and all the standard textual targets. The following code fragment shows how to build this list of targets:
XmConvertCallbackStruct *cs = (XmConvertCallbackStruct *) call_data; if (cs->target == TARGETS) { /* We convert the standard targets, plus up to five additional standard textual targets. */ Atom *targs = XmeStandardTargets(w, 5, &n); targs[n] = MOTIF_C_S; n++; targs[n] = COMPOUND_TEXT; n++; targs[n] = LOCALE_ATOM; n++; if (LOCALE_ATOM != XA_STRING) { targs[n] = XA_STRING; n++; } if (LOCALE_ATOM != TEXT) { targs[n] = TEXT; n++; } value = (XtPointer) targs; type = XA_ATOM; length = n; format = 32; ... }
(ConvertProc will eventually assign the values of the value, type, length, and format variables to their respective XmConvertCallbackStruct member fields.)
Although TARGETS should include all the standard targets, the more specialized target list requests (such as _MOTIF_EXPORT_TARGETS) do not have to. If you do not want the standard targets to be part of a targets list, use XtMalloc instead of XmeStandardTargets; for example:
if (cs -> target == MOTIF_EXPORT_TARGETS) { Atom *targs = (Atom *) XtMalloc(sizeof(Atom) * 7);
All Motif source widgets should be able to convert requests for the following standard targets:
Your widget transfers the value of Core's XmNbackground resource as type PIXEL.
Your widget finds the first shell in its widget hierarchy that has a WM_CLASS property and transfers the contents as text in the current locale.
Your widget transfers the value of Core's XmNcolormap resource as type COLORMAP.
Your widget transfers the value of Primitive's or Manager's XmNforeground resource as type PIXEL.
Your widget finds the first shell in the widget hierarchy that has a WM_NAME property and transfers the contents as text in the current locale.
Your widget transfers, as type ATOM, a list of all the targets your widget can provide.
Your widget transfers the timestamp used to acquire the selection as type INTEGER.
Your widget transfers the value of its render table resource if one exists, or else the default render table for the widget, as type STRING.
Your widget transfers the source widget's encoding registry as type STRING. The value is a list of NULL separated items in the form of tag encoding pairs. This target symbolizes the transfer target for the Motif Segment Encoding Registry. Widgets and applications can use this registry to register text encoding formats for specified render table tags. Applications access this registry by calling XmRegisterSegmentEncoding and XmMapSegmentEncoding. A destination widget can request the _MOTIF_ENCODING_REGISTRY target when transferring an XmString between two applications.
Fortunately, your conversion routine does not have to write conversion code for most of these targets. Your conversion routine can call XmeStandardConvert, which automatically converts 9 of the 10 standard targets. XmeStandardConvert cannot convert TIMESTAMP; however, the Intrinsics can. Even though XmeStandardConvert can convert TARGETS, your own conversion routine should typically take responsibility for doing this conversion. That is, XmeStandardConvert will convert TARGETS by returning a list of all the standard targets only. This returned list will be insufficient if your conversion routine can also convert some nonstandard targets.
For example, the following code from the ConvertProc trait method of ExmStringTransfer demonstrates how to convert the standard targets:
XmConvertCallbackStruct *cs = (XmConvertCallbackStruct *) call_data; ... XmeStandardConvert(w, NULL, cs); if (cs -> value == NULL) /* could not convert the target */ cs -> status = XmCONVERT_REFUSE; else /* successfully converted the target */ cs -> status = XmCONVERT_DONE;
Textual widgets vary a lot in the richness of the text they support. Some textual widgets only store the ASCII values of each character. Other textual widgets store a great wealth of information about the text, such as the fonts or the locale encoding. When a user tries to transfer data between two different kinds of textual widgets, there is no guarantee that the two widgets will share the same level of text "richness." For example, perhaps the source widget stores font information about its text, and the destination widget simply stores the ASCII value of each character.
The source widget must be able to supply the destination widget with text at the richest level that the source widget supports. In addition, the source widget must also be able to supply text at all poorer levels beneath that richest level. Here are the levels of text, from poorest to richest:
The text includes only characters in ISO8859-1 plus TAB and NEWLINE. It is known as the C locale.
This is a string in the specified locale. The value of LOCALE_ENCODING in the C locale is STRING.
This is an encoding the X Windows System supplies to deal with strings that have multiple encodings.
This is text in XmString format.
For example, a widget that displays text in XmString format must be able to convert requests from destination widgets for all five textual targets.
A selection owner can use XmbTextListToTextProperty or XwcTextListToTextProperty to convert text in its own locale to a text property. The type of the property is determined by the composition of the text and by the encoding style passed to XmbTextListToTextProperty. Encoding styles exist for converting text to STRING, COMPOUND_TEXT, and the encoding of the locale. Another encoding style specifies conversion to STRING if all the characters in the text can be so converted, or otherwise to COMPOUND_TEXT.
A Motif application that has text in compound strings can use XmCvtXmStringToCT to convert a compound string to compound text The application can then place the compound text in the requestor's property by using type COMPOUND_TEXT.
STRING, COMPOUND_TEXT, and the locale encoding can also be selection targets. To obtain a text selection in its own locale, an application can request conversion to one of these targets and can then call XmbTextPropertyToTextList or XwcTextPropertyToTextList to convert the returned property to text in the current locale. An application can also request conversion to TEXT, but there is no guarantee that it can convert the returned property to text in the current locale.
One possible strategy is first to request conversion to TARGETS. If one of the returned targets is the encoding of the current locale (as determined by a call to XmbTextListToTextProperty with an encoding style of XTextStyle), the application can request conversion to that target. Otherwise, if one of the returned targets is COMPOUND_TEXT, the application can request conversion to that target. If neither the locale encoding nor COMPOUND_TEXT is one of the returned targets, the application can request conversion to STRING or TEXT if the selection owner supports one of those targets.
A Motif application that has text in compound strings can request conversion of a selection to COMPOUND_TEXT and can then use XmCvtCTToXmString to convert the returned property to a compound string.
The ConvertProc trait method of ExmStringTransfer does not do these conversions itself. Instead, ConvertProc calls the ConvertCompoundString routine as follows to handle the text conversions:
if (cs->target == MOTIF_C_S || cs->target == COMPOUND_TEXT || cs->target == TEXT || cs->target == LOCALE_ATOM || cs->target == XA_STRING) { /* Convert the compound string to the appropriate target. */ cstatus = ConvertCompoundString(w, cstring, cs -> target, &value, &type, &format, &length, &nchars);
Some targets have side effects for the owner. Among these targets are the following:
The owner deletes the selection and, if successful, returns a zero-length property of type NULL.
The requestor places in its specified window property a pair of atoms that names a selection and a target. The owner requests conversion of the specified selection to the specified target and places the result at the location of the selection named in the INSERT_SELECTION request. The owner then returns a zero-length property of type NULL. For example, the Motif Text widget uses this target with the destination selection when it asks the owner of the destination selection to insert the secondary selection at the destination.
The requestor places in its specified window property some data to be inserted at the location of the selection named in the request. The owner then returns a zero-length property of type NULL.
UTM sends this atom to the former owner of the selection when that selection is lost. Upon receiving this message, your widget is responsible for changing the visuals of the formerly selected region to indicate that it is no longer selected.
The following fragment suggests the framework for an idealized convertProc trait method:
static void ConvertProc(Widget w, XtPointer client_data, XtPointer call_data) { /* Cast call_data to an XmConvertCallbackStruct. */ XmConvertCallbackStruct *cs = (XmConvertCallbackStruct *)call_data; /* Declare Atom variables for all targets used in converProc */ Atom TEXT = XInternAtom(XtDisplay(w), "TEXT", False); ... /* Handle requests for TARGETS by building a list of all standard targets and all X nonstandard targets. */ nonstandard_targets = 5; if (cs->target == TARGETS) Atom *targs = XmeStandardTargets(w, nonstandard_targets, &n); /* If your widget supports CLIPBOARD transfer, handle requests for _MOTIF_CLIPBOARD_TARGETS and _MOTIF_DEFERRED_CLIPBOARD_TARGETS. */ if (cs->target == _MOTIF_CLIPBOARD_TARGETS) XtMalloc(...) /* generate list of immediate clipboard targets */ else if (cs->target == _MOTIF_DEFERRED_CLIPBOARD_TARGETS) XtMalloc(...) /* generate list of deferred clipboard targets */ /* If your widget supports drag, handle requests for _MOTIF_EXPORT_TARGETS. */ if (cs->target == _MOTIF_EXPORT_TARGETS) XtMalloc(...) /* generate list of draggable targets */ /* If a previous conversion routine has supplied a list of some kind of target, merge it with the list your conversion routine has created. */ if (cs->status == XmCONVERT_MERGE) XmeConvertMerge(cs->value, cs->type, cs->format, cs->length, cs); ... /* Handle requests for nonstandard targets by converting to the requested target. */ ... /* Handle requests for standard targets by calling XmeStandardConvert. */ XmeStandardConvert(w, NULL, ConvertCallbackStruct); /* Return the appropriate status. */ if (conversion was not successful) cs->status = XmCONVERT_REFUSE; else if (conversion was successful) cs->status = XmCONVERT_DONE; }