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



Case Study: Adding an Extra Target to XmText

This section illustrates how an application can use UTM to supplement the list of targets that an XmText widget can convert.

Here is the scenario. The application instantiates two XmText widgets. We will refer to one of these widgets as TextSource and the other as TextDestination. TextDestination has a rather unusual requirement; namely, it expects that any text transferred to it must not contain any lowercase letters. In other words, the source of a data transfer is responsible for converting any lowercase letters to uppercase before transferring the data.

The standard XmText widget does not provide any targets that can do this conversion. Therefore, the application must temporarily extend XmText to handle a new target named MYTEXT. The application must do the following:

  1. The application must associate an XmNconvertCallback procedure with TextSource. This procedure must be able to convert the MYTEXT target.

  2. The application must associate an XmNdestinationCallback procedure and a transfer procedure with TextDestination. These procedures are responsible for requesting that the selection be converted to MYTEXT and for pasting the transferred data into TextDestination.

    The application will support three different forms of data transfer: primary, clipboard, and drag and drop.

    The following subsections explains how the application accomplishes its goals.

  3. The XmNconvertCallback Procedure

    The application must associate an XmNconvertCallback procedure with widget TextSource. The following code does just that:

    XtAddCallback(TextSource, XmNconvertCallback, ConvertCallback,
    NULL);

    The application must provide an XmNconvertCallback procedure named ConvertCallback. This procedure must handle the following requests:

    1. The destination could request the list of targets that the source can convert.

    2. The destination could request that the selection be converted to MYTEXT.

      Following are the relevant parts of the ConvertCallback routine:

      void
      ConvertCallback(Widget  w,
                           XtPointer ignore,
                           XtPointer call_data)
      {
       XmConvertCallbackStruct  *ccs = (XmConvertCallbackStruct *)call_data;
       char    *selected_text;
       char    *copy_of_selected_text;
       Atom TARGETS = XInternAtom(XtDisplay(w), "TARGETS", False);
       Atom _MOTIF_CLIPBOARD_TARGETS = XInternAtom(XtDisplay(w),
                                    "_MOTIF_CLIPBOARD_TARGETS", False);
       Atom MYTEXT = XInternAtom(XtDisplay(w), "MYTEXT", False);
       int   n=0;
       Atom *targs = (Atom *)XtMalloc(sizeof(Atom) * 2);
       
        if ((ccs->target == TARGETS) ||
           (ccs->target == _MOTIF_CLIPBOARD_TARGETS)) {
       
        /* Use targs to hold a list of targets that my application can
           convert. This list will be merged with the targets that the
           XmText widget can convert. */
          targs[n] = MYTEXT; n++;
          ccs->value = (XtPointer) targs;
          ccs->type = XA_ATOM;
          ccs->format = 32;
          ccs->length = n;
          ccs->status = XmCONVERT_MERGE;
        }
        else if (ccs->target == MYTEXT)  {
        /* Get the selection. */
          selected_text = XmTextGetSelection(w);
          copy_of_selected_text = selected_text;
       
        /* Convert any lowercase letters in the selection to uppercase. */
          while (*selected_text++)  {
             if (islower(*selected_text))
               *selected_text = toupper(*selected_text);
          }
       
        /* Place the converted text into the XmConvertCallbackStruct. */
          ccs->value = copy_of_selected_text;
          ccs->type = ccs->target;
          ccs->format = 8;
          ccs->length = strlen(copy_of_selected_text);
          ccs->status = XmCONVERT_DONE;
        }
      }

      Notice how ConvertCallback sets the value of the status member of the XmConvertCallbackStruct. For example, when the destination requests TARGETS or _MOTIF_CLIPBOARD_TARGETS, ConvertCallback sets status to XmCONVERT_MERGE. This status tells UTM to call the convertProc trait method of XmText. This trait method will add MYTEXT to the list of supported targets. As another example, consider that ConvertCallback is taking full responsibility to convert the selection to MYTEXT. For this case, ConvertCallback sets status to XmCONVERT_DONE. This status tells UTM not to bother calling the convertProc trait method of XmText. Finally, consider what happens when ConvertCallback is asked to convert a target other than TARGETS, _MOTIF_CLIPBOARD_TARGETS, or MYTEXT. In this case, the status member will retain its default value of XmCONVERT_DEFAULT. This status tells UTM to call the convertProc trait method of XmText, and that the trait method will be reponsible for converting the target.

    3. The XmNdestinationCallback Procedure

      The application must associate an XmNdestinationCallback procedure with widget TextDestination. The following code does just that:

      XtAddCallback(TextDestination, XmNdestinationCallback,
                    DestinationCallback, NULL);

      The application must provide an XmNdestinationCallback procedure named DestinationCallback. We have implemented this procedure in a very basic fashion. This procedure merely requests a list of the targets that the source widget supports:

      void
      DestinationCallback(Widget  w,
                              XtPointer ignore,
                              XtPointer call_data)
      {
       XmDestinationCallbackStruct *dcs =
                 (XmDestinationCallbackStruct *)call_data;
       Atom TARGETS = XInternAtom(XtDisplay(w), "TARGETS", False);
       
       /* Ask the source to return a list of all the targets supported. */
         XmTransferValue(dcs->transfer_id, TARGETS,
                         (XtCallbackProc)TransferProc,
                         NULL, XtLastTimestampProcessed() );
      }

      The Transfer Procedure

      When the source returns the list of TARGETS, UTM calls the application's transfer procedure. The transfer procedure, TransferProc in this case, is named by the third argument to XmTransferValue.

      Here is the algorithm for the transfer procedure. The transfer procedure must examine the returned list of targets to see if the list contains MYTEXT. If it does, ask the source to convert the selection to MYTEXT. When the source completes the conversion, the transfer procedure must paste the converted text into the TextDestination widget.

      Following is the code for TransferProc:

      void
      TransferProc(Widget  w,
                   XtPointer ignore,
                   XtPointer call_data)
      {
       XmSelectionCallbackStruct *scs =
             (XmSelectionCallbackStruct *) call_data;
       Atom TARGETS = XInternAtom(XtDisplay(w), "TARGETS", False);
       Atom MYTEXT = XInternAtom(XtDisplay(w), "MYTEXT", False);
       Atom  *targets = (Atom *)scs->value;
       int    MYTEXT_is_supported = 0;
       unsigned long    n;
       
       
         if ((scs->target == TARGETS) && (scs->type == XA_ATOM))  {
           for (n=0; n<=scs->length; n++)  {
            /* Look through list of returned TARGETS to see if
               MYTEXT is there. */
              if (targets[n] == MYTEXT)
                MYTEXT_is_supported = 1;
           }
       
           if (MYTEXT_is_supported)
           /* Now ask the source widget to convert the selection
                to MYTEXT. */
             XmTransferValue(scs->transfer_id, MYTEXT,
                         (XtCallbackProc)TransferProc,
                         NULL, XtLastTimestampProcessed() );
         }
       
        if ((scs->target == MYTEXT)) {
          XmTextPosition current_insertion_position;
        /* Source widget has converted MYTEXT, paste it into the
           destination widget. */
          current_insertion_position = XmTextGetInsertionPosition(w);
          XmTextInsert(w, current_insertion_position, (char *)scs->value);
          XmTransferDone(scs->transfer_id, XmTRANSFER_DONE_SUCCEED);
        }
      }

      Notice how TransferProc calls XmTransferDone. This call marks the end of the transfer. Therefore, UTM will not call the destinationProc trait method inside the TextDestination widget.

      If the source does not know how to convert MYTEXT, UTM will call the destinationProc trait method inside the TextDestination widget.


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