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



Clipboard Transfer Details

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:

  1. A high-level overview of clipboard transfers

  2. A description of deferred clipboard transfers and snapshots

  3. A step-by-step detailed walk through of a UTM clipboard transfer

  4. Sample code to implement a UTM clipboard transfer

  5. Compatibility with Previous Releases

    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.

    High-Level Overview of Clipboard Transfers

    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.

    Immediate Versus Deferred Clipboard Targets

    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.

    Snapshots

    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:

    1. Save a "snapshot" of the selection.

    2. Generate a new atom that uniquely distinguishes this snapshot.

      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:

      1. STRING as the target member

      2. The distinguisher atom as the selection member

        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.

      3. Clipboard Transfer: Step by Step

        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:

        1. The user selects some portion of the source widget. The source widget will probably highlight the selection.

        2. The user presses some mouse button or key sequence to initiate a clipboard cut or a clipboard copy. The Intrinsics respond to the event by calling the appropriate action method in the source widget.

        3. The called action method itself calls XmeClipboardSource.

        4. XmeClipboardSource asks the conversion routines to provide a list of _MOTIF_CLIPBOARD_TARGETS.

        5. The conversion routine returns the list of immediate clipboard targets that it intends to place on the clipboard. The conversion routine should not include TARGETS in this list.

        6. XmeClipboardSource places the list of _MOTIF_CLIPBOARD_TARGETS on the clipboard.

        7. XmeClipboardSource calls the conversion routines one time for each target in the list of _MOTIF_CLIPBOARD_TARGETS. So, for example, if four targets were returned in _MOTIF_CLIPBOARD_TARGETS, XmeClipboardSource calls the conversion routines four times, each time asking the conversion routine to convert the selection to a different immediate target.

        8. XmeClipboardSource asks the conversion routines to provide a list of _MOTIF_DEFERRED_CLIPBOARD_TARGETS.

        9. Regardless of the number of deferred clipboard targets, XmeClipboardSource calls the conversion routines only once. This call asks the conversion routines to convert the selection to the _MOTIF_SNAPSHOT target.

        10. The conversion routines convert the _MOTIF_SNAPSHOT target by saving a snapshot of the data and by returning a distinguisher atom that uniquely identifies the snapshot.

        11. XmeClipboardSource copies each deferred clipboard target to the clipboard, but it does not copy any converted data to the clipboard. For each deferred clipboard target, XmeClipboardSource sets the selection member to the distinguisher atom.

        12. If the user had requested a clipboard cut operation, XmeClipboardSource asks the conversion routine to convert the selection to the DELETE target. The conversion routine responds to this target by deleting the selection.

        13. XmeClipboardSource establishes a callback that is automatically called whenever a request is made to convert data to a deferred clipboard target. We will call that callback CallbackD.

        14. The user moves the cursor to the destination widget and presses some mouse button or key sequence to initiate a clipboard paste.

        15. The Intrinsics call the action method of the destination widget that is associated with the clipboard paste event. This action method calls XmeClipboardSink.

        16. XmeClipboardSink calls the destination widget's destinationPreHookProc trait method, if any.

        17. XmeClipboardSink then calls the destination routines associated with the destination widget. The first destination routines called are the XmNdestinationCallback procedures that the application has associated with the destination widget. The next destination routine called is the destinationProc trait method of the destination widget. Typically, one of the destination routines will ask the clipboard to return its list of TARGETS.

        18. The clipboard responds to a TARGETS request by returning a list of all the targets in _MOTIF_CLIPBOARD_TARGETS and _MOTIF_DEFERRED_CLIPBOARD_TARGETS, plus the two additional targets TIMESTAMP and TARGETS.

        19. The destination routine examines the returned list of TARGETS and requests the most desirable one from the clipboard.

        20. The clipboard examines the request. If the requested target is an immediate clipboard target, the clipboard transfers the data back to the destination routine. Skip to Step 22.

        21. If the requested target is a deferred clipboard target, UTM calls CallbackD, which was the callback established by XmeClipboardSource to handle this kind of request.

        22. CallbackD asks the conversion routines to convert the requested target. CallbackD will set the selection member to the distinguisher atom.

        23. The conversion routine locates the snapshot data and converts it to the requested target.

        24. UTM transfers the converted data to the transfer procedure of the destination routine.

        25. When the snapshot data is no longer needed, CallbackD asks the conversion routines to convert the snapshot to the DONE target, using the distinguisher atom as the selection.

        26. UTM returns control to the transfer procedure associated with a destination routine. The transfer procedure must paste the transferred data into the appropriate place in the destination widget.

        27. Sample Translations for a Clipboard Transfer

          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.

          A Sample Copy Clipboard Routine

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

          A Sample Paste Clipboard Routine

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

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