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



Drop Receiver Responsibilities for Dragging

In the dynamic protocol, motion messages go first to the receiver client. The receiver evaluates the state of the drag and sends an updated message to the initiator, which then manages its drag-over visuals based on the results.

If the drag protocol in effect is preregister, the drop site information is put in the database as the drop sites are registered and the receiver client does nothing until a drop is made. All visual effects are handled by the toolkit.

If the drag protocol is dynamic, messaging begins when the pointer enters the window containing the drop site. The receiver is given the opportunity to provide additional processing in its XmNdragProc. If the protocol is preregister, the opportunity is still available, as long as the initiator and receiver are the same client. The XmNdragProc

  1. Receives messages when the drag icon enters or leaves the drop site, the operation changes, the drag icon is in motion, or the drag is cancelled.

  2. Provides information back to the toolkit about the state of the drag (valid drop site, invalid drop site, no drop site) and the operation to be performed when a drop is made.

  3. Manages any custom drag-under visual effects.

  4. Establishing a Drop Site

    The widgets shown in Appendix B are already registered as drop sites. An application must register any other widget it wants to use for a drop site, but only if the widget provides an XmNdestinationCallback procedure. A widget may be registered as only one drop site.

    XmeDropSink registers a widget as a drop site, establishes callbacks to be used when a drag is made through the drop site or a drop is made in the drop site, and provides target and operation information. If the protocol is preregister, the information is stored in a database, which is read by the toolkit during the drag. If the drag protocol is dynamic, messaging is used to check for possible drop sites within a widget.

    The optional XmNdragProc routine is executed only if the drag protocol is dynamic, or, if the protocol is preregister, only if the initiator and receiver are the same client. It is called in response to events during the drag, and allows the receiver to provide additional drag-under effects or additional drag processing.

    The XmNdropSiteOperations resource lists all operations that the drop site will support, combined by the bitwise OR operations (|). For example, the default value

    XmDROP_COPY | XmDROP_MOVE

    means that Copy and Move are valid operations, but Link is not. During a drag, the toolkit on the receiver side compares this list with the DragContext's XmNdragOperations list and the user-selected operation to arrive at the operation that will be performed if a drop occurs on this site, along with a list of all operations possible between the initiator and the current drop site.

    If an application wants to use only one operation, such as Copy, it should set the XmNdropSiteOperations field to just that operation to ensure that the toolkit chooses the correct operation and drag icon during the drag and drop transaction.

    Drop sites that represent copying devices, such as printers, or transformation devices, such as compilers, should perform a Copy rather than a Move if both are possible.

    The XmNdropSiteActivity resource indicates whether the drop site is available for use:

    XmDROP_SITE_ACTIVE

    The drop site is available for use. This is the default value.

    XmDROP_SITE_INACTIVE

    The drop site is not available for use. If the drag icon is moved over the drop site, both the icon and drop site act as if the icon were not over a drop site.

    XmDROP_SITE_IGNORE
    Ignore this drop site for all purposes.

    Use the XmDropSiteRegistered function to determine whether a widget is already a registered drop site. The function accepts a widget as an argument, and returns a Boolean value, which is TRUE if the widget is a registered drop site.

    The XmDropSiteUnregister function removes a widget from the DropSite registry. Once a widget is unregistered, it displays no drag-under visual effects and cannot accept a drop.

    The difference between an unregistered drop site and an inactive drop site is that the inactive drop site is still registered; it still uses memory, but does not engage in any drag and drop transactions. One use for inactive drop sites is to provide the correct clipping on overlapping drop sites. An unregistered drop site is no longer involved in the drag and drop system. It is the same as a widget that was never registered.

    When the drag and drop is operating in preregister mode, and the receiving client is not the same as the initiating client, drop effects will be generated even if a drop site's widget is unmanaged. To avoid this, you can deactivate the drop site by calling XmDropSiteUpdate and setting XmNdropSiteActivity to XmDROP_SITE_INACTIVE. Specifying the resource as XmDROP_SITE_IGNORE at creation time will disable the drop site completely, producing some savings of computational overhead, since inactive drop sites are still used for clipping drag-under effects.

    The following code registers a DrawingArea widget as a drop site. The only operation it will accept is Copy. The only import target it will accept is COMPOUND_TEXT. The other resources, including drag-under effects, are left at their default values.

    DrawingArea = XmCreateDrawingArea(Frame, "Draw1", NULL, 0);
    XtManageChild(DrawingArea);
    Atom targets[2];
    Arg  args[4];
    int  n, nt;
    Atom COMPOUND_TEXT = XInternAtom(XtDisplay(w), "COMPOUND_TEXT", False);
     
      /* Register the DrawingArea as a drop site */
      nt=0
      targets[nt++] = COMPOUND_TEXT;
      n = 0;
      XtSetArg(args[n], XmNdropSiteOperations, XmDROP_COPY); n++;
      XtSetArg(args[n], XmNimportTargets, targets); n++;
      XtSetArg(args[n], XmNnumImportTargets, nt); n++;
      XmeDropSink(DrawingArea, args, n);
      XtAddCallback(DrawingArea1, XmNdestinationCallback,
                    DestinationCallback1, NULL);

    Changing a Drop Site

    The XmDropSiteUpdate function is used to change drop site resources for a single drop site. For multiple requests, XmDropSiteStartUpdate signals that a series of XmDropSiteUpdate requests will follow, and XmDropSiteEndUpdate ends the series and processes the requests at one time.

    XmDropSiteUpdate can also be used to change the resource values of the widgets that register themselves as drop sites.

    Specially Shaped Drop Sites

    The shape of a simple drop site can be specified as the union of a set of specified rectangles clipped by the associated widget.

    If only part of the widget is to be sensitive to a drop, it is defined by a list of rectangles in the XmNdropRectangles resource. If the resource is NULL, the drop site is the smallest enclosing widget and the shape of the drop site is the shape of the widget.

    The rectangles that make up the drop site do not need to be contiguous. All the noncontiguous segments of the drop site act as one; they are all highlighted the same way at the same time. A drop on one segment is the same as a drop on any of the other segments. This might look to the user as if there were several drop sites on a single widget, but the application handles nested drop sites differently from drop sites made of noncontiguous segments. Nested drop sites, whether simulated or real, may have different drag-under effects, targets, operations, or callback procedures.

    The following example establishes a sensitive area shaped like a plus sign on a DrawnButton widget named Button2. Even if the drag icon is within the Button2 widget, no drag-under effects are shown until the drag icon is within the sensitive area. The area is visible only when a drag icon enters it and highlighting occurs. The sensitive area is the only part of the widget that accepts a drop.

    Figure 17. Specially Shaped Drop Site.

    View figure.

    XRectangle plus[] = {
        {30, 0, 30, 30},
        {0, 30, 90, 30},
        {30, 60, 30, 30},
        };
    n = 0;
    XtSetArg(args[n], XmNimportTargets, importList); n++;
    XtSetArg(args[n], XmNnumImportTargets, 1); n++;
    XtSetArg(args[n], XmNdropRectangles, plus); n++;
    XtSetArg(args[n], XmNnumDropRectangles, 3); n++;
    XmeDropSink(Button2, args, n);

    Nested Drop Sites

    A widget can be registered as only one drop site. However, widgets that are registered as drop sites can be nested within each other, providing nested drop sites.

    The XmNdropSiteType indicates the complexity of the drop site:

    XmDROP_SITE_SIMPLE
    The drop site contains no other drop sites.

    XmDROP_SITE_COMPOSITE
    The drop site contains other drop sites. This value is generally associated with a Manager.

    A composite drop site must be registered before any of its children are registered. If a composite drop site is inactive, so are all of its children.

    The composite and children drop sites do not need to have the same operations or targets.

    A manager that contains a number of widgets with their associated drop sites does not need to be a composite drop site unless it is possible to drop in the background of the manager.

    It is possible for an application to simulate nested drop sites on a single widget, for example, a DrawingArea. The process is described as part of the discussion of the duties of the optional XmNdragProc routine in Section 15.4.2.

    Overlapping Drop Sites

    Drop sites can overlap. Their stacking order is assumed to correspond to the order in which they are registered, with the first-registered one on top. XmDropSiteQueryStackingOrder checks the stacking order, whereas XmDropSiteConfigureStackingOrder changes it.

    When a drop site is overlapped by another drop site, the drag-under effects of the drop site underneath are clipped as appropriate by the obscuring drop site.

    A widget or gadget that is not a drop site can overlap and partially obscure a drop site. To ensure that the drop-site's drag-under visuals are appropriately clipped by the obscuring widget, such sibling widgets should be registered as inactive drop sites. Parent widgets, whether drop sites or not, will clip their children's drop site visuals. If a parent has some active and some inactive drop site children, it should be registered as an active drop site.

    Drag-Under Visual Effects

    Drag-under visual effects are displayed only when the pointer is within the sensitive area of the drop site widget. An application can either handle all or none of the animation effects for a particular drop site. That is, an application should never do a partial job of animation on a particular drop site. Various drag-under styles can be chosen in the XmNanimationStyle DropSite resource:

    XmDRAG_UNDER_HIGHLIGHT

    A solid border around the sensitive area of the drop site is used to show the drop site is valid. This is the default value.

    XmDRAG_UNDER_SHADOW_OUT

    The sensitive area of the drop site looks pushed out when it is valid.

    XmDRAG_UNDER_SHADOW_IN

    The sensitive are of the drop site looks pushed in when it is valid.

    XmDRAG_UNDER_PIXMAP

    A custom pixmap is used to indicate the drop site is valid. The pixmap is specified in XmNanimationPixmap.

    XmDRAG_UNDER_NONE

    No indication is given that the drop site is valid.

    The following illustration shows the default drag-under animation around the Label widget drop site.

    Figure 18. Default Drag-Under Animation.

    View figure.

    If the value of XmNanimationStyle is XmDRAG_UNDER_PIXMAP, the resources XmNanimationPixmap, XmNanimationMask, and XmNanimationPixmapDepth are used to provide more information about the pixmap. If the depth does not match the depth of the window controlling the drop site widget, no animation occurs. Except for XmDRAG_UNDER_PIXMAP, the colors used for the visual effects are based on the colors of the widget associated with the drop site.

    The dynamic protocol provides the most control over the drop site animation. It is the only way to get visual effects that do not remain the same for the duration of the drag icon's stay in the drop site; for example, a background that flashes.

    XmNdragProc

    The procedure registered in the DropSite's XmNdragProc resource is called only when the dynamic protocol is in effect, or, in the case of the preregister protocol, if the initiator and receiver are the same client. This procedure is optional. Applications that need to provide special drag-under effects or other special processing during a drag can do so with this procedure.

    The XmNdragProc procedure is called in response to messages from the toolkit, before the initiator's equivalent drag callback. The pointer from the drop site's XmNclientData resource is passed as the client data to this procedure. Applications may use this resource to pass any manner of information desired to the XmNdragProc procedure. Fields in the callback structure provide information to the receiver about the drag.

    The reason field in the callback structure indicates why the procedure was called.

    XmCR_DROP_SITE_ENTER_MESSAGE

    The drag icon hotspot has entered the drop site.

    XmCR_DROP_SITE_LEAVE_MESSAGE

    The drag icon hotspot has left the drop site.

    XmCR_DRAG_MOTION_MESSAGE

    The drag icon hotspot has moved.

    XmCR_OPERATION_CHANGED_MESSAGE

    The operation has changed.

    The operations field lists all the operations that are valid for the drop site with the current drag source. The operations field is initialized by the toolkit as follows:

    1. If the user has selected an operation, the value of operations is initialized to that operation if it is in the DragContext's XmNdragOperations list.

    2. Otherwise, the operations field is initialized to the list in the DragContext's XmNdragOperations list.

      The operation field indicates the type of action a successful drop will perform. The toolkit initializes the operation field by taking the following steps, in order of precedence from highest to lowest:

      1. If Move is a valid operation (in both the operations field and the DropSite's XmNdropSiteOperations list), operation is initialized to XmDROP_MOVE.

      2. If Copy is a valid operation, operation is initialized to XmDROP_COPY.

      3. If Link is a valid operation, operation is initialized to XmDROP_LINK.

      4. Otherwise, operation is initialized to XmDROP_NOOP.

        The dropSiteStatus field provides an indication of whether a transfer between the initiator and this drop site could occur. The value that the toolkit selects for the dropSiteStatus field depends on the reason the XmNdragProc procedure was entered:

        1. If the reason is motion or drop site leave, and the drop site is the same as in the last call to XmNdragProc, the dropSiteStatus field is the same as at the end of the previous call.

        2. Otherwise, if there is at least one target in common and at least one operation in common, the value is initialized to XmDROP_SITE_VALID. If not, the value is initialized to XmDROP_SITE_INVALID.

        3. If the operation field is XmDROP_NOOP, the dropSiteStatus field is initialized to XmDROP_SITE_INVALID.

          The XmNdragProc procedure can update operation, operations, or dropSiteStatus further during its execution. The final values for these fields are available to the initiator in its drag callback structures. If the receiver's XmNdragProc procedure is called more than once while the drag icon is within the drop site (for example, because of motion events), the values used by the toolkit when it initializes the drag callback operations, operation, and dropSiteStatus fields are the ones at the end of the previous call to XmNdragProc.

          The animate field tells the toolkit who should provide the drag-under visual effects. It is initially set to True, but the XmNdragProc routine can set it to False.

        4. True
          The toolkit provides the drag-under visuals as if the protocol were preregister.

          False
          The receiver provides the drag-under visuals. The application can provide special visual effects, such as a blinking background, that are not possible with the toolkit.

          The DragProcCallback routine in the DNDDemo.c program is an example of a DragProc routine. It can process every drag message, changes the operations, operation, and dropSiteStatus as necessary, and sets the animate field to True, allowing the toolkit to manage the drag-under effects. The DragProcCallback routine is shown in the next section of this chapter.

          Simulating Nested Drop Sites

          A widget can be registered as only a single drop site. However, if the application needs one or more drop sites entirely enclosed within another drop site, there are two ways to accomplish this:

          1. Widgets that contain other widgets that are drop sites should be registered as composite drop sites as described earlier in this chapter.

            This method allows the toolkit to manage drop site messages and drag-under effects for each nested drop site.

          2. An application can simulate multiple drop sites on a single widget in the XmNdragProc and XmNdropProc routines. Because the XmNdragProc routine is executed only in the dynamic drag protocol mode, this method would only work if the drag procotol chosen is preregister in the case where the initiator and receiver are the same client.

            This method requires that the application manage all drag-under effects, because the toolkit is not aware of the simulated nesting.

            To simulate nested drop sites on a single widget:

            1. Register the widget as a single active drop site. Set XmNdropSiteOperations to all the operations possible for any of the nested drop sites. Set XmNimportTargets to all the targets possible for any of the nested drop sites. Register an XmNdragProc routine to provide any special drag-under effects for the simulated drop sites.

              The operations, operation, and dropSiteStatus fields are initialized by the toolkit only when this outer drop site is entered or left. The simulated drop sites must be managed by the application.

            2. When either XmNdragProc or XmNdropProc is called, check the x and y fields in the callback structure to determine which of the nested drop sites contains the pointer.

            3. If the pointer is within a simulated nested drop site, update the callback fields as follows:

              1. When the pointer enters the simulated nested drop site, save the value of the operations and operation fields.

              2. Remove any operations from the operations field that do not apply to the simulated drop site.

              3. Set operation to the valid operation preferred by the simulated drop site, or to XmDROP_NOOP if the operations list does not contain the preferred operation.

              4. The dropSiteStatus field must reflect the status of the simulated drop site so that the initiator can manage drag-over effects correctly:

                1. Set the dropSiteStatus to XmDROP_SITE_VALID if the operation is allowed in the simulated drop site and if there is at least one target in common between the simulated drop site and the initiator. (Use the XmTargetsAreCompatible routine to check the targets.)

                2. Set the dropSiteStatus to XmDROP_SITE_INVALID if the operation is not allowed in the simulated drop site, if there are no targets in common, or if the operation is XmDROP_NOOP.

                3. Display appropriate drag-under visual effects.

                4. When the pointer leaves the simulated drop site, restore the original values of operations and operation that apply to the outer drop site.

                5. If the pointer is not within a simulated drop site, but drops are allowed in the outer drop site, update the fields as described in the previous step.

                6. If the pointer is not within a simulated drop site, and drops are not allowed in the outer drop site, set the dropSiteStatus field to XmDROP_SITE_INVALID.

                  If the preregister protocol is in effect, the simulated drop sites cannot be managed during the move, because XmNdragProc is not performed; but they can be managed at the drop with XmNdropProc.

                  In the following example, only the top-level window, DNDDemo, is registered as a drop site. The user can create rectangles within the window that then act like drop sites themselves. The user can drag and drop colors from one of the six buttons in the lower part of the window onto the rectangles to change the color of the rectangle. However, these rectangles are not registered drop sites; they are simulated.

                  The user can also drag these rectangles to new locations.

                  Figure 19. Simulated Drop Sites.

                  View figure.

                  The RegisterDropSite routine registers the DrawingArea widget as a drop site. The list of operations and targets may not be valid for each simulated drop site, but are valid for other simulated drop sites.

                  static void
                  RegisterDropSite(Widget w)
                  {
                      Display *display = XtDisplay(w);
                      Atom    targets[3];
                      Arg     args[5];
                      int     n = 0;
                   
                      /* Only accept moves or copies */
                      XtSetArg(args[n], XmNdragOperations, XmDROP_COPY | XmDROP_MOVE);
                  n++;
                   
                      /* set all possible targets for any of the nested drop sites */
                      targets[0] = XmInternAtom(display, "_MY_RECTANGLE", False);
                      targets[1] = XmInternAtom(display, "BACKGROUND", False);
                      targets[2] = XmInternAtom(display, "PIXMAP", False);
                      XtSetArg(args[n], XmNimportTargets, targets); n++;
                      XtSetArg(args[n], XmNnumImportTargets, 3); n++;
                   
                      /* register a dragProc - necessary for simulating nested drop sites
                  */
                      XtSetArg(args[n], XmNdragProc, DragProcCallback); n++;
                      XmeDropSink(w, args, n);
                  }

                  The XmNdragProc routine, DragProcCallback, is called whenever a drag icon enters the registered drop site (the top-level window). The RectFind routine from DNDDraw.c determines if the pointer is in a simulated drop site. The CheckTargets routine determines if the object being dragged is one of the six colors (bgFound) or one of the created rectangles (rectFound). (The value pixFound to represent a pixmap being dragged is coded in this routine, but not in the rest of the program.)

                  The only drag-under visual is displayed when a color is dragged to a rectangle. The outline of the rectangle is highlighted.

                  The entire DragProcCallback routine is too long to be listed in its entirety here. The section dealing with the drop site enter message is used as an example.

                  static void
                  DragProcCallback(Widget w, XtPointer client, XtPointer call)
                  {
                   
                      XmDragProcCallbackStruct    *cb = (XmDragProcCallbackStruct *) call;
                      Display                     *display = XtDisplay(w);
                      Boolean                     rectFound, bgFound, pixFound;
                      static unsigned char        initial_operations;
                      static unsigned char        initial_operation;
                      RectPtr                     rect;
                   
                      CheckTargets(cb->dragContext, display, &rectFound, &bgFound, &pixFound);
                   
                      switch(cb->reason) {
                   
                          case XmCR_DROP_SITE_ENTER_MESSAGE:
                   
                              /* save the value of the operations and operation fields */
                              initial_operations = cb->operations;
                              initial_operation = cb->operation;
                   
                              rect = RectFind(cb->x, cb->y);
                   
                              /* Remove any operations for the operations field which do not */
                              /* apply to the simulated drop site.                           */
                              if (rect) {
                   
                                  if (bgFound || pixFound) {
                                      cb->operations = XmDROP_COPY;
                                      RectHighlight(w, rect);
                                  }
                                  else if (rectFound) {
                                      cb->operations = cb->operations &
                                                       (XmDROP_COPY | XmDROP_MOVE);
                                      RectUnhighlight(w);
                                  }
                   
                              }
                              else {
                                  cb->operations = initial_operations &
                                                   (XmDROP_COPY | XmDROP_MOVE);
                                  RectUnhighlight(w);
                              }
                   
                              /* Set operation to the valid operation preferred by the simulated
                               * drop site or to XmDROP_NOOP if the operations list does not    
                               * contain the preferred operation.                               */
                              if (rect) {
                   
                                  if (bgFound || pixFound) {
                   
                                      if (cb->operations & XmDROP_COPY)
                                          cb->operation = XmDROP_COPY;
                                      else
                                          cb->operation = XmDROP_NOOP;
                   
                                  }
                                  else if (rectFound) {
                   
                                      if (cb->operations & XmDROP_MOVE)
                                          cb->operation = XmDROP_MOVE;
                                      else if (cb->operations & XmDROP_COPY)
                                          cb->operation = XmDROP_COPY;
                                      else
                                          cb->operation = XmDROP_NOOP;
                   
                                  }
                   
                              }
                              else {
                   
                                  if (rectFound) {
                   
                                      if (cb->operations & XmDROP_MOVE)
                                          cb->operation = XmDROP_MOVE;
                                      else if (cb->operations & XmDROP_COPY)
                                          cb->operation = XmDROP_COPY;
                                      else
                                          cb->operation = XmDROP_NOOP;
                   
                                  }
                                  else
                                      cb->operation = initial_operation;
                   
                              }
                   
                              /*
                               * Set dropSiteStatus to XmDROP_SITE_INVALID if the operation
                               * field is XmDROP_NOOP, or if there are no common targets
                               * between the source and the nested drop site. Otherwise, set
                               * dropSiteStatus to XmDROP_SITE_VALID.
                               */
                              if (cb->operation == XmDROP_NOOP ||
                                 (rect && (!rectFound && !bgFound && !pixFound)) ||
                                 (!rect && !rectFound))
                                 cb->dropSiteStatus = XmINVALID_DROP_SITE;
                              else
                                 cb->dropSiteStatus = XmVALID_DROP_SITE;
                   
                              /*
                               * Display appropriate drag under visuals. Only highlight
                               * the rectangle if we are changing rectangle attributes.
                               */
                              if (rect && bgFound || pixFound &&
                                  cb->dropSiteStatus == XmVALID_DROP_SITE)
                                  RectHighlight(w, rect);
                              break;
                   
                          case XmCR_DROP_SITE_LEAVE_MESSAGE:
                              ...

                7. Autoscrolling (or Pause) Drag

                  Using the XmNdragProc routine, drag and drop can support pause drag. This is when, during a drag, a dragged object is held over a drop site (without releasing), with some drag-under effect resulting. The most common form of this is when a scrolled window will scroll in some direction while a dragged object is held over the border of the window, or in the scrollbar.

                  Since this feature depends on the XmNdragProc routine, it is only available with the dynamic protocol, or, with the preregister protocol, when the initiator and receiver share the same top-level shell.

                  This feature is fully implemented in the Motif ScrolledWindow widget. That widget has a resource called XmNautoDragModel, which, when set to XmAUTO_DRAG_ENABLED, will allow autoscroll drag. This is the default setting. The scrolling characteristics are set with the XmNinitialDelay, XmNrepeatDelay, and the XmNincrementFactor resources of that widget. Please refer to the documentation for XmScrolledWindow in the Motif Programmer's Reference for more information about these resources.


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