Atom *, XtPointer *, unsigned long *, int *);
Widget widget;
Atom *selection;
Atom *target;
Atom *type_return;
XtPointer *value_return;
unsigned long *length_return;
int *format_return;
The widget parameter is the DragContext for the drag operation, selection is the selection atom, which in this
case is _MOTIF_DROP, and target is the type of information requested about the selection. The type_return,
value_return, length_return, and format_return parameters return the type, value, length, and format
of the converted data. The routine should return True if the conversion succeeds and False otherwise. For more
information about this procedure type, see Volume Four, X Toolkit Intrinsics Programming Manual, and the
appropriate reference page in Volume Five, X Toolkit Intrinsics Reference Manual.
The ConvertProc() routine in the source code starts by retrieving the Label widget from the XmN-clientData
resource of the DragContext. The goal is to get an index into the files array so that we can access information about
the file. The index is stored in the -XmNuserData resource of the Label widget. Once we have the index, we can
use it to get the filename from the array.
Our conversion routine only handles requests for a filename or the contents of a file. If target is set to
FILE_CONTENTS, ConvertProc() retrieves the contents of the file and formats the data for transfer back to the
receiving client. The contents of the file are passed as a pointer to the text, using the value_return parameter. If
the drop site has requested the FILE_NAME target, the routine returns the filename in value_return. In either
case, the length_return argument is set to the length of the text, and format_return is set to 8 to specify the
length of each of the elements in value_return. The return_type parameter is set to the appropriate target. If
the drop site has requested any other target, the routine returns False to indicate that the transfer has failed.
The conversion routine does not handle the DIRECTORY target, partly because we have not implemented any drop
sites that understand the target. A real file manager application would want to support the dragging of directories to
allow the user to modify the file system using drag and drop. In this case, the conversion procedure would need to
have another branch for handling the DIRECTORY target.
Since the drag source only supports the copy operation, the conversion routine does not have to worry about deleting
the existing data. With a copy operation, the XmN-convertProc returns a pointer to the data so that when the
operation is done, both the initiator and the receiver have a copy of the data. With a move operation, the initiating
application returns a pointer to the data and then waits for the receiver to tell it to delete the data. The receiving
application gets the data, stores it, and then specifies the DELETE target to handle this situation. When the initiating
client gets this target, it can safely delete the data. With a link operation, the initiator again passes a pointer to the data,
but in this case the receiver uses the pointer to establish a link to the data.
19.4.4 Modifying an Existing Drag Source
In file_manager.c, we decided to replace the existing drag capabilities of the image Label widgets and provide our
own functionality instead. By default, the Labels would function as graphical drag sources, but since there are no drop
sites that support graphical data, there is no reason to preserve this functionality.
However, if you want to provide the default functionality for a drag source as well as your own functionality, the set
up of the drag source becomes more complicated. Each Motif widget that acts as a drag source has a translation and
action that starts the drag. Since the existing action calls XmDragStart() for the transfer, another action routine
cannot call XmDragStart() again. The solution to this problem is to write an action routine that retrieves the
19 Drag and Drop 19.4.4 Modifying an Existing Drag Source
539
DragContext for the transfer and modifies its resources.
In our application, we want to augment the drag source functionality of the filename Labels. If the user drags the
Label to a drop site that understands file objects, the actual file is transferred. Otherwise, the default drag functionality
for the Label causes the text of the Label to be passed to the drop site. The first thing that we need to do is modify the
translations for the Label widgets. Since we want to provide the default functionality, the new translation calls the
widget's existing drag action routine followed by our own action. The existing drag action routine for the Label widget
is ProcessDrag(), so the translations and actions for the application can be defined as follows:
static char dragTranslations[] =
"#override <Btn2Down>: StartDrag()";
static char newdragTranslations[] =
"#override <Btn2Down>: ProcessDrag() UpdateDrag()";
static XtActionsRec dragActions[] =
{ {"StartDrag", (XtActionProc) StartDrag},
{"UpdateDrag", (XtActionProc) UpdateDrag} };
As always, the translations need to be parsed using XtParseTranslationTable(), and the actions need to be
registered using XtAppAddActions(). Now, when we create each of the filename Labels, we can specify the new
translation for the XmN-translations resource, as shown in the following code fragment:
parsed_trans_text = XtParseTranslationTable (newdragTranslations);
...
XtVaCreateManagedWidget (files[i].file_name,
xmLabelWidgetClass, form,
XmNtranslations, parsed_trans_text,
XmNuserData, i,
...
NULL);
Note that we also specify the index in the files array as the XmN-userData for these widgets, just as we did for
the image Labels in the source code
The UpdateDrag() action routine is invoked after the Label's default drag action, which means that
XmDragStart() has already been called for the operation. Our action routine retrieves the DragContext for the
operation and modifies it, as shown in the source code
void (*convert_proc) ();
void
UpdateDrag(widget, event, params, num_params)
Widget widget;
XEvent *event;
String *params;
Cardinal *num_params;
{
Arg args[10];
int n, m, i;
Display *dpy;
Atom FILE_CONTENTS, FILE_NAME, DIRECTORY;
Widget drag_icon, dc;
Pixel fg, bg;
Pixmap icon, iconmask;
XtPointer ptr;
Boolean NewConvertProc();
19 Drag and Drop 19.4.4 Modifying an Existing Drag Source
540
void DragDropFinish();
Cardinal numExportTargets;
Atom *exportTargets, *newTargets;
/* intern the Atoms for data targets */
dpy = XtDisplay (widget);
FILE_CONTENTS = XmInternAtom (dpy, "FILE_CONTENTS", False);
FILE_NAME = XmInternAtom (dpy, "FILE_NAME", False);
DIRECTORY = XmInternAtom (dpy, "DIRECTORY", False);
/* get background and foreground colors and fetch index into file
* array from XmNuserData.
*/
XtVaGetValues (widget,
XmNforeground, &fg,
XmNbackground, &bg,
XmNuserData, &ptr,
NULL);
/* create pixmaps for drag icon −− either file or directory */
i = (int) ptr;
if (files[i].is_directory) {
icon = XmGetPixmapByDepth (XtScreen (widget), "dir.xbm", 1, 0, 1);
iconmask = XmGetPixmapByDepth (XtScreen (widget), "dirmask.xbm",
1, 0, 1);
}
else {
icon = XmGetPixmapByDepth (XtScreen (widget), "file.xbm", 1, 0, 1);
iconmask = XmGetPixmapByDepth (XtScreen (widget), "filemask.xbm",
1, 0, 1);
}
if (icon == XmUNSPECIFIED_PIXMAP || iconmask == XmUNSPECIFIED_PIXMAP) {
puts ("Couldn't load pixmaps");
exit (1);
}
n = 0;
XtSetArg(args[n], XmNpixmap, icon); n++;
XtSetArg(args[n], XmNmask, iconmask); n++;
drag_icon = XmCreateDragIcon (widget, "drag_icon", args, n);
/* get the DragContext and retrive info about it */
dc = XmGetDragContext (widget, event−>xbutton.time);
n = 0;
XtSetArg (args[n], XmNexportTargets, &exportTargets); n++;
XtSetArg (args[n], XmNnumExportTargets, &numExportTargets); n++;
XtSetArg (args[n], XmNconvertProc, &convert_proc); n++;
XtGetValues (dc, args, n);
/* add new targets to the list of targets */
n = 0;
if (files[i].is_directory) {
newTargets = (Atom *) XtMalloc
(sizeof (Atom) * (numExportTargets + 1));
for (m = 0; m < numExportTargets; m++)
newTargets[m] = exportTargets[m];
newTargets[m] = DIRECTORY;
XtSetArg (args[n], XmNexportTargets, newTargets); n++;
XtSetArg (args[n], XmNnumExportTargets, numExportTargets + 1); n++;
}
19 Drag and Drop 19.4.4 Modifying an Existing Drag Source
541
Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.