[ Previous | Next | Contents | Glossary | Home | Search ]
Motif 2.1 Widget Writer's Guide



Writing a Conversion Routine

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:

  1. Declare Atom variables for every atom that the conversion routine uses.

  2. Provide code that converts requests for lists of targets supported by your widget. For example, your conversion routine must be able to return a list of TARGET atoms.

  3. Provide code that converts all the standard targets.

  4. If your widget can be the source of textual data, then your conversion routine should be able to convert the standard textual targets.

  5. Provide code that converts any other targets supported by your widget.

  6. Provide code that properly handles requests for targets not supported by your widget.

    The remainder of this section explores all of the preceding tasks.

  7. Declare Atoms

    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);

    Provide Target Lists

    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);

    Convert Standard Targets

    All Motif source widgets should be able to convert requests for the following standard targets:

    BACKGROUND

    Your widget transfers the value of Core's XmNbackground resource as type PIXEL.

    CLASS

    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.

    CLIENT_WINDOW
    Your widget finds the first shell in the widget hierarchy and transfers its window as type WINDOW.

    COLORMAP

    Your widget transfers the value of Core's XmNcolormap resource as type COLORMAP.

    FOREGROUND

    Your widget transfers the value of Primitive's or Manager's XmNforeground resource as type PIXEL.

    NAME

    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.

    TARGETS

    Your widget transfers, as type ATOM, a list of all the targets your widget can provide.

    TIMESTAMP

    Your widget transfers the timestamp used to acquire the selection as type INTEGER.

    _MOTIF_RENDER_TABLE

    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.

    _MOTIF_ENCODING_REGISTRY

    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;

    Convert Standard Textual Targets

    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:

    STRING

    The text includes only characters in ISO8859-1 plus TAB and NEWLINE. It is known as the C locale.

    LOCALE_ENCODING

    This is a string in the specified locale. The value of LOCALE_ENCODING in the C locale is STRING.

    TEXT
    This target returns either LOCALE_ENCODING or COMPOUND_TEXT.

    COMPOUND_TEXT

    This is an encoding the X Windows System supplies to deal with strings that have multiple encodings.

    _MOTIF_COMPOUND_STRING

    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);

    Targets with Side Effects for the Owner

    Some targets have side effects for the owner. Among these targets are the following:

    DELETE

    The owner deletes the selection and, if successful, returns a zero-length property of type NULL.

    INSERT_SELECTION

    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.

    INSERT_PROPERTY

    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.

    _MOTIF_LOSE_SELECTION

    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.

    Summary of Target Conversion

    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;
    }

    [ Previous | Next | Contents | Glossary | Home | Search ]