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
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:
The drop site is available for use. This is the default value.
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.
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);
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.
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);
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:
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.
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 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:
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.
The sensitive area of the drop site looks pushed out when it is valid.
The sensitive are of the drop site looks pushed in when it is valid.
A custom pixmap is used to indicate the drop site is valid. The pixmap is specified in XmNanimationPixmap.
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.
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.
The drag icon hotspot has entered the drop site.
The drag icon hotspot has left the drop site.
The drag icon hotspot has moved.
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:
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:
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:
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.
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.
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:
This method allows the toolkit to manage drop site messages and drag-under effects for each nested drop site.
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:
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.
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: ...
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.