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

Application Programmer's Overview of Drag and Drop

This section explains some drag and drop concepts, and provides a general view of the initiator and receiver duties during the drag and at the drop.

The Motif toolkit for drag and drop consists of

  1. Widgets and widget classes that provide resources containing details about the source and destination of the transfer

  2. Functions that applications use to manage the widgets and widget classes

  3. Protocols that specify how interactions between source and destination clients are to take place

  4. Functions that manage messages, call callbacks, decide on the valid operations for a potential drop, and keep the drop site status updated

    If the initiator and receiver are in the same client, they share the same toolkit. If the initiator and receiver are different clients, each client has a version of the toolkit.

    An application can allow any widget to be a drag source or initiator by specifying a translation for Btn2Down in that widget. The corresponding action creates a DragContext, which starts the drag and drop transaction. The toolkit on the initiator side is in charge during the drag and manages all drag messages and callbacks.

    An application can register any widget as a drop site. The drop site widget may change visually as a drag icon moves in and out of it, providing drag-under visual clues to the status of the drag. The application controlling the current drop site is known as the receiver. The toolkit on the receiver side is in charge of the drop operation, and manages all drop messages and callbacks.

    Each drag source and drop site specifies the types of data it is prepared to handle and what operations it can perform on that data.

    The state of the drag indicates whether the drag icon is over a valid drop site, an invalid drop site, or no drop site. For a drop site to be valid, there must be at least one target type and one operation in common between the drag source and drop site.

  5. Ways an Application Can Provide Drag and Drop

    Applications can use drag and drop functionality on any of several levels:

    1. Appendix B lists the widgets that are already defined as drag sources and as drop sites. Therefore, at the simplest, an application can compile with the Motif libraries, and have those widgets participate in drag and drop. For example, text from a Text widget could be selected from one application and moved into the Text widget in another application.

    2. On a slightly more advanced level, applications can let the toolkit do most of the work, but provide some customization. For example, an application could register an XmPushButton as a drop site, but still use default visual effects. In this case, the application would register a widget as a DropSite and provide code to handle drop and transfer duties. The example programs simple_drag and simple_drop in the following subsections are at that level.

    3. A complex application can take much of the control of the drag and drop itself. It can provide custom visuals for both drag icon and drop site. It can manage overlapping drop sites and can include complex transfers of information. The online example program DNDDemo.c contains extensive customization.

    4. Extending a Widget To Support Drop

      Any UTM widget that provides an XmNdestinationCallback resource has the potential to be a drop site. Conversely, if a widget does not provide an XmNdestinationCallback resource, it cannot be a UTM drop site.

      Of the widgets that provide an XmNdestinationCallback resource, many already contain all the required code to become a drop site. That is, many of the standard widgets can serve as drop sites without you, the application programmer, doing anything. However, some of the widgets that do provide an XmNdestinationCallback resource do not provide the drop site code. You can extend these widgets to become drop sites. For example, the XmDrawingArea widget provides an XmNdestinationCallback resource but does not provide any drop site code. You can write an application that makes XmDrawingArea into a drop site.

      Consider the simple_drop sample program stored online in simple_drop.c. This program displays both a Label widget and a DrawingArea widget. The Label widget displays whatever pixmap you pass on the invocation command line. For example, if you invoke this application as follows:

      $ simple_drop mypixmap.xpm

      then the Label widget will display the contents of the mypixmap.xpm file. To experiment with this application, simply drag the pixmap from the Label and drop it into the framed DrawingArea.

      The standard Label widget knows how to be a drag source without any help from the application. However, the standard DrawingArea does not know how to be a drop site. Therefore, simple_drop provides both of the following procedures in order to add pixmap drop support to the DrawingArea:

      1. An XmNdestinationCallback procedure

      2. A transfer procedure

        The only drop target that our DrawingArea supports is PIXMAP. The Label widget in the application provides a convenient PIXMAP source. In addition, you can drop a pixmap from any widget on the screen that knows how to convert a PIXMAP target.

        The main routine instantiates the Label and DrawingArea widgets. main also calls XmeDropSink to establish the DrawingArea as a drop site.

        main(int argc, char **argv)
         static Widget  MainWindow;
         XtAppContext   app_context;
         Widget         Frame1, RC1, Label1, DrawingArea1;
         Pixmap         pixmap;
         GC             gc;
           toplevel = XtAppInitialize(&app_context, "Test", NULL, 0,
                                       &argc, argv, NULL, NULL, 0);
           MainWindow = XtVaCreateManagedWidget("MainWindow1",
                                            xmMainWindowWidgetClass, toplevel,
           RC1 = XtVaCreateManagedWidget("RC1", xmRowColumnWidgetClass,
                                         MainWindow, NULL);
           if (!argv[1]) {
                printf("usage: %s bitmap-file\n", *argv);
           /* Load bitmap given in argv[1] */
            pixmap = XmGetPixmap(XtScreen(toplevel), argv[1],
            if (pixmap == XmUNSPECIFIED_PIXMAP) {
                printf("can't create pixmap from %s\n", argv[1]);
          /* Now instantiate an XmLabel widget that displays pixmap. */
            Label1 = XtVaCreateManagedWidget("Label1",
                xmLabelWidgetClass, RC1,
                XmNlabelType,   XmPIXMAP,
                XmNlabelPixmap, pixmap,
            Frame1 = XtVaCreateManagedWidget("Frame1",
                xmFrameWidgetClass, RC1,
                XmNshadowThickness, 3,
            DrawingArea1 = XtVaCreateManagedWidget("DrawingArea1",
                xmDrawingAreaWidgetClass, Frame1,
                XmNwidth, 150,
                XmNheight, 150,
                XmNresizePolicy, XmRESIZE_NONE,
            XmeDropSink(DrawingArea1, NULL, 0);
            XtAddCallback(DrawingArea1, XmNdestinationCallback,
                          DestinationCallback, NULL);

        When the user attempts a drop on the DrawingArea, UTM will call the DestinationCallback routine. This routine will call XmTransferValue, asking the source widget (the drag initiator) to convert its list of _MOTIF_EXPORT_TARGETS.

        DestinationCallback(Widget  w,
                            XtPointer ignore,
                            XtPointer call_data)
         XmDestinationCallbackStruct *dcs =
                   (XmDestinationCallbackStruct *)call_data;
         Atom TARGETS = XInternAtom(XtDisplay(w), "TARGETS", False);
         Atom _MOTIF_EXPORT_TARGETS = XInternAtom(XtDisplay(w),
                                     "_MOTIF_EXPORT_TARGETS", False);
         /* Ask the source to return a list of all the export targets that
            it knows how to convert. */
         XmTransferValue(dcs->transfer_id, _MOTIF_EXPORT_TARGETS,
                         (XtCallbackProc)TransferProc, NULL, NULL);

        UTM calls the TransferProc routine when the source widget has finished converting _MOTIF_EXPORT_TARGETS. If the source widget knows how to convert the PIXMAP target, the TransferProc routine will request it. When the source widget finishes converting PIXMAP, the TransferProc routine will paste a copy of the returned pixmap into the DrawingArea.

        TransferProc(Widget  w,
                     XtPointer ignore,
                     XtPointer call_data)
         XmSelectionCallbackStruct *scs =
               (XmSelectionCallbackStruct *) call_data;
         Atom TARGETS = XInternAtom(XtDisplay(w), "TARGETS", False);
         Atom _MOTIF_EXPORT_TARGETS = XInternAtom(XtDisplay(w),
                                     "_MOTIF_EXPORT_TARGETS", False);
         Atom PIXMAP = XInternAtom(XtDisplay(w), "PIXMAP", False);
         Atom  *targets = (Atom *)scs->value;
         int    PIXMAP_is_supported = 0;
         unsigned long    n;
         Widget Label2;
           if ((scs->target == _MOTIF_EXPORT_TARGETS) && (scs->type ==
        XA_ATOM))  {
             printf("Number of supported targets is %ld\n", scs->length);
             ListAllTheTargets(w, targets, scs->length);
             for (n=0; n<=scs->length; n++)  {
          /* Look through list of returned TARGETS to see if PIXMAP is there. */
                if (targets[n] == PIXMAP)  {
                  PIXMAP_is_supported = 1;
             if (PIXMAP_is_supported)  {
               XmTransferValue(scs->transfer_id, PIXMAP,
                           (XtCallbackProc)TransferProc, NULL, NULL);
          if ((scs->target == PIXMAP)) {
            Pixmap        transferred_pixmap = *(Pixmap*) scs->value;
            Pixmap        copy_of_transferred_pixmap;
            Window        root_return;
            int           x, y;
            unsigned int  width, height;
            unsigned int  border_width, depth;
            GC            gc;
            XtGCMask      valueMask;
            XGCValues     values;
            printf("TransferProc: source has transferred the PIXMAP.\n");
            printf("We need to paste it into the DrawingArea.\n");
          /* It is better to display a copy of the returned pixmap than
             to display the returned pixmap itself. The following code
             creates the copy. */
            XGetGeometry(XtDisplay(w), (Drawable)transferred_pixmap,
                         &root_return, &x, &y, &width,
                         &border_width, &depth);
            copy_of_transferred_pixmap =
                         XCreatePixmap(XtDisplay(w), XtWindow(w), width,
                                       height, depth);
            valueMask = GCFunction;
            values.function = GXcopy;
            gc = XtGetGC(w, valueMask, &values);
            XCopyArea(XtDisplay(w), transferred_pixmap,
                      copy_of_transferred_pixmap, gc, x, y,
                      width, height, x, y);
            Label2 = XtVaCreateManagedWidget("Label2", xmLabelWidgetClass, w,
                XmNlabelType,   XmPIXMAP,
                XmNlabelPixmap, copy_of_transferred_pixmap,
            XtReleaseGC(w, gc);
            XmTransferDone(scs->transfer_id, XmTRANSFER_DONE_SUCCEED);

      3. Extending a Widget to Support Drag

        Any widget that provides an XmNconvertCallback resource has the potential to be a drag source. However, not all the potential drag sources are actual drag sources. For example, XmScrollBar supports an XmNconvertCallback resource (through its superclass, XmPrimitive) but does not provide any code to become a drag source. However, your application can turn an XmScrollBar into a drag source. In fact, that is just what the sample program, simple_drag does. This program is stored in simple_drag.c.

        The normal action for Button 2 Press has been overridden to cause it to call the StartDrag routine, which causes the drag to begin. The program allows only the Copy operation, and will reply to requests for compound text.

        When a drag is started on the ScrollBar, the default drag icons are used.

        The main routine of the simple_drag program instantiates a ScrollBar and a Text widget. The main routine also alters the translations of the ScrollBar widget, which is detailed later on in this chapter.

        main(int argc, char **argv)
         static Widget  MainWindow;
         XtAppContext   app_context;
         Widget         Frame1, RC1;
         Widget         Text1, ScrollBar1;
         char    dragTranslations[] = "#override <Btn2Down>: StartDrag()";
         static  XtActionsRec  dragActions[] =
            {"StartDrag", (XtActionProc)StartDrag}
         XtTranslations            parsed_xlations;
           toplevel = XtAppInitialize(&app_context, "Test", NULL, 0,
                                       &argc, argv, NULL, NULL, 0);
           MainWindow = XtVaCreateManagedWidget("MainWindow1",
                                            xmMainWindowWidgetClass, toplevel,
         /* Create a RowColumn to contain the ScrollBar and Text widgets. */
            RC1 = XtVaCreateManagedWidget("RC1",
                                            xmRowColumnWidgetClass, MainWindow,
           /* Create a ScrollBar. */
            parsed_xlations = XtParseTranslationTable(dragTranslations);
            XtAppAddActions(app_context, dragActions, XtNumber(dragActions));
            ScrollBar1 = XtVaCreateManagedWidget("SB1",
                                            xmScrollBarWidgetClass, RC1,
                                            XmNorientation, XmHORIZONTAL,
                                            XmNtranslations, parsed_xlations,
          /* Associate a convert callback with the ScrollBar. */
           XtAddCallback(ScrollBar1, XmNconvertCallback, ConvertCallback, NULL);
          /* Create a text widget; it will be a potential drop site. */
           Text1 = XtVaCreateManagedWidget("Text",
                                            xmTextWidgetClass, RC1,
                                            XmNeditMode, XmMULTI_LINE_EDIT,
                                            XmNrows, 25,
                                            XmNcolumns, 25,

        When the user presses <Btn2Down>, StartDrag will be called. The StartDrag routine calls XmeDragSource as follows:

        StartDrag(Widget w,
                  XEvent *event)
         Arg       args[2];
         Cardinal  n=0;
          XtSetArg(args[n], XmNdragOperations, XmDROP_COPY); n++;
          XmeDragSource(w, NULL, event, args, n);

        The simple_drag program provides an XmNconvertCallback procedure named ConvertCallback. This routine handles requests to convert targets. It knows how to convert the following targets:


        2. TARGETS

        3. COMPOUND_TEXT
          ConvertCallback(Widget  w,
                          XtPointer ignore,
                          XtPointer call_data)
           XmConvertCallbackStruct  *ccs = (XmConvertCallbackStruct *)call_data;
           int  *value;
           Atom COMPOUND_TEXT = XInternAtom(XtDisplay(w), XmSCOMPOUND_TEXT,
           Atom TARGETS = XInternAtom(XtDisplay(w), "TARGETS", False);
           Atom MOTIF_EXPORT_TARGETS =
             XInternAtom(XtDisplay(w), XmS_MOTIF_EXPORT_TARGETS, False);
           int n;
           /* XmeDragSource is going to call ConvertCallback and ask
              it to convert MOTIF_EXPORT_TARGETS. */
            if ( (ccs->target == MOTIF_EXPORT_TARGETS) ||
                 (ccs->target == TARGETS))
           /* We have to create a list of targets that ConvertCallback
              can convert. For simplicity, we are going to restrict
              that list to one target: COMPOUND_TEXT. */
               Atom *targs = (Atom *) XtMalloc(sizeof(Atom) * 1);
               if (targs == NULL) {
                ccs->status = XmCONVERT_REFUSE;
               n = 0;
               targs[n] = COMPOUND_TEXT; n++;
               ccs->value = (XtPointer) targs;
               ccs->type = XA_ATOM;
               ccs->length = n;
               ccs->format = 32;
               ccs->status = XmCONVERT_DONE;  /* Yes, we converted the target. */
           /* If the drop site supports COMPOUND_TEXT as an import target, then
              the drop site will ask ConvertCallback to convert the
              value to COMPOUND_TEXT format. */
             else if (ccs->target == COMPOUND_TEXT) {
               char     *passtext;
               char     *ctext;
               XmString  cstring;
               char      ValueAsAString[10];
            /* The part of the ScrollBar that we are transferring is its
               XmNvalue resource. */
               XtVaGetValues(w, XmNvalue, &value, NULL);
            /* Convert XmNvalue to COMPOUND_TEXT. */
                 sprintf(ValueAsAString, "%d", value);
                 cstring = XmStringCreateLocalized(ValueAsAString);
                 ctext = XmCvtXmStringToCT(cstring);
                 passtext = XtMalloc(strlen(ctext)+1);
                 memcpy(passtext, ctext, strlen(ctext)+1);
            /* Assign converted string to XmConvertCallbackStruct. */
               ccs->value  = (XtPointer)passtext;
               ccs->type   = XA_STRING;
               ccs->length = strlen(passtext);
               ccs->format = 8;
               ccs->status = XmCONVERT_DONE;
             else  {
               /* Unexpected target. */
               ccs->status = XmCONVERT_REFUSE;

        4. The DropSite Registry

          The DropSite registry contains information about widgets that have been registered as drop sites. Although the drag icon can be dropped anywhere on the screen, only widgets that have been registered as drop sites can accept information from the initiator. The receiver is the application controlling the current drop site.

          The "sensitive area" is the part of the widget that responds to drag and drop. By default, the sensitive area is the whole widget. However, the application can specify that only part of the widget is sensitive.

          Widgets that are drop sites can be stacked on each other, with one widget partially or completely within the boundary of another. The sensitive areas of lower drop sites are clipped if they are covered by a higher widget.

          The stacking order of the widgets with drop sites can be changed by the application.


          The protocol describes how the initiator and receiver clients interact through the toolkit with each other.

          Drag Protocols

          There are two types of drag protocol:

          Does not require messaging

          Requires messaging; this is the default and is the recommended drag protocol.

          Applications can support either, both, or neither. At Motif Release 2.0, dynamic is the default; you should try to use this. The Motif toolkit automatically supports both unless a user or client sets resources to force the use of one or the other.

          The user can specify which drag protocol to use when the client is the initiator or receiver. The application can specify drag protocol in an application-class defaults file. If neither the application nor the user specifies a protocol, the dynamic drag protocol is used.

          The toolkit uses the requested protocols and the protocols allowed by the initiator and receiver clients to arrive at the protocol actually being used. Therefore, the protocol can change as the drag icon moves from window to window, depending on which protocols each window supports. If the initiator and receiver cannot agree on a protocol, static default drag-over effects are generated.

          Even if no drag-over or drag-under visual effects are shown, a drop can still occur with the drop protocol, unless a client has specified that that window does not participate in drag and drop.

          Drop Protocol

          Motif Release 2.0 uses UTM as the drop protocol. See Chapter 16 for details.

          Drag and Drop Widget Classes

          Motif provides a number of Xt objects and widgets to encapsulate the underlying protocol; however, these are not mapped onto the screen:


          An object that contains display-specific information, such as the initiator and receiver protocol styles.


          An object that describes screen-specific information, such as font and default drag-over icons.


          A widget that describes the pixmap, mask, and attachment of an icon. The source icon, state icon, operation icon, and the resulting blended drag icon are all Drag Icons.


          A widget that describes the resources specified by each drag initiator, such as target type, custom icons, custom colors, blending model, permitted operations, and callback routines for various situations encountered during the drag and drop transaction.


          A drop site database that maintains a registry of the resources unique to each drop site, such as animation for drag-under effects, valid target types and operations, and callback routines for situations encountered during a drag and drop transaction. It is not an Xt object, although it acts like one with respect to resource fetching.


          A widget that describes the information desired from the initiator client and the procedure used to process the results.

          Drag and Drop Functions

          Motif provides many functions to support drag and drop processing. However, many drag and drop functions were developed prior to UTM and, although not obsolete, no longer get much direct use. Application programmers will find the following drag and drop functions to be most useful:


          Initiates a drag.


          Establishes a widget as a drop site.


          Creates any of the parts of a drag icon (status icon, operation icon, or source icon) from a cursor or pixmap. This allows custom icons for all or part of the drag icon, rather than the default icons.


          Cancels a drag that is in progress. This function is called when the user presses osfCancel.


          This function is typically called by XmeDragSource when the user asks to start a drag. This function creates a DragContext object, which is referenced by other functions whenever information about the drag initiator is needed. The XmDragStart function also calls the DragStart callback procedure, if one has been nominated with the XmNdragStartCallback resource of the XmDisplay widget.


          Sets the order of overlapping drop sites. The default order is with the first-registered drop site on the bottom and the last-declared drop site on top.


          Causes the XmDropSiteUpdate requests made after XmDropSiteStartUpdate to take place.


          Provides information about the stacking order of overlapping drop sites. The order can be changed with XmDropSiteConfigureStackingOrder.


          Registers a drop site. Resources describing the drop site are defined. XmeDropSink calls XmDropSiteRegister.


          Retrieves the values of drop site resources.


          Signals the toolkit to wait until XmDropSiteEndUpdate is called to process drop site changes requested by XmDropSiteUpdate. This provides a more efficient way to update several drop sites than changing them one at a time.


          Updates drop site resources for a single drop site. If a series of XmDropSiteUpdate requests are surrounded by XmDropSiteStartUpdate and XmDropSiteEndUpdate, then the changes will be made all at once after the end update request.


          Removes a drop site. After a drop site has been unregistered, it is unavailable as a destination for a drag.


          Adds additional transfer requests once a transfer has started.


          Specifies what information should be requested from the drag initiator, and starts the process to get the information.


          Returns the DragContext ID associated with a particular time stamp.


          Returns the ID for the specified display.


          Returns the ID for a specified screen. Some resources, such as the drag icons, are screen-specific.


          Checks if there are any matching targets between the initiator and destination to help determine the correct drag state.


          Each drag source and drop site specifies what kinds of data types it can process, called targets. These targets are atoms, such as XA_STRING.

          The DragContext resources XmNexportTargets and XmNnumExportTargets provide a list and number of the data types provided by the drag source. These are export targets.

          The DropSite resources XmNimportTargets and XmNnumImportTargets provide a list and number of the data types accepted by the drop site. These are known as import targets. The primary purpose of the targets in XmNimportTargets is to provide visual feedback about the validity of the drop site. The XmNdestinationCallback procedure need not use the same targets as those specified by XmNimportTargets.

          Any number of targets may be listed for each source and site. A drop site is considered valid for a particular drag if at least one of its targets matches any of the source's targets and if the source and drop site operations are compatible.

          An application can define anything it wants as a target. Be aware, however, that other applications might not recognize that target.


          There are three ways that the initiator and receiver can interact with each other:

          1. Data can be moved from the initiator to the receiver (Move).

          2. Data can be copied from the initiator to the receiver (Copy).

          3. Data can be linked from the receiver to the initiator (Link).

            When a drag is started, the initiator provides a list of valid operations in the DragContext XmNdragOperations resource. When a drop site is registered, the receiver provides a list of operations it supports in the DropSite XmNdropSiteOperations resource. These lists are the values XmDROP_MOVE, XmDROP_COPY, or XmDROP_LINK, connected by the bitwise OR operator (|). For example, the following value means that Move and Copy are valid operations, but Link is not:

            XmDROP_MOVE | XmDROP_COPY

            The value XmDROP_NOOP indicates that there are no operations possible for a drop at the current site.

            The user can specify an operation by using key combinations discussed earlier in this chapter. The user can also change the operation at any time until the drop starts.

            The initiator and the receiver need to be able to handle all the operations their application supports. If the operation is Move, the receiver first gets a copy of the data, then tells the initiator that it can delete the data. If the operation is Copy, both applications have the data, making two copies of it. If the operation is Link, there is only one copy of the data, and the receiver establishes a link to that copy.

          4. Drop Site Status

            The drag and drop callbacks for both receiver and initiator contain a dropSiteStatus field. This field is initialized and maintained by the receiver through the toolkit, although the receiver's drag and drop procedures can update it if they wish. This field is used by the toolkit to determine what drag-over and drag-under visual effects to use.

            The dropSiteStatus field indicates the relationship of the drag source to the drop site over which the drag icon is located:


            A drop can take place. There is at least one matching target and operation between the drag source and the drop site.


            A drop cannot take place. Either there were no matching targets, no matching operations, or the receiver's XmNdragProc or XmNdropProc discovered some other problem that would make a drop impossible.


            The drag icon is not over a drop site.

            If the toolkit on the receiver's side has set either the operation or the operations field to XmDROP_NOOP, it also sets the dropSiteStatus field to XmDROP_SITE_INVALID.

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