If neither the DragContext resources nor the Screen resources are specified, Motif uses hard−coded default icons. For
example, the running figure shown in the figure is used as the source icon whenever a source icon has not been
specified. Since this icon is rather arbitrary, you might want to set the XmN-defaultSourceCursorIcon
resource to something more appropriate for your application.
Before you can set the Screen resources in application code, you must create DragIcon objects for the different
resources. In Section #screateicon we describe how to create a drag icon using XmCreateDragIcon(). Once the
drag icon exists, you can retrieve the Screen object using XmGetXmScreen() and set its resources, as shown in the
following code fragment:
Widget drag_icon, screen, toplevel;
...
screen = XmGetXmScreen (XtScreen (toplevel));
XtVaSetValues (screen, XmNdefaultSourceCursorIcon, drag_icon, NULL);
...
The specified icon is used whenever the source icon has not been set for the DragContext for a drag and drop transfer.
The Screen resources can also be set in a resource file. In this case, the icons can be specified as bitmap files, so the
application does not have to create DragIcon objects. Both the icon and an optional mask can be specified using
resources as follows:
*defaultSourceCursorIcon.pixmap: icon.xbm
*defaultSourceCursorIcon.mask: icon_mask.xbm
Although it is convenient to be able to set the Screen resources in a resource file, this feature really isn't that useful
since the Motif widgets and most applications specify their drag icons using DragContext resources.
The XmN-validCursorForeground, XmN-invalidCursorForeground, and
XmN-noneCursorForeground resources of the DragContext can be used to further distinguish between the
different states in a drag and drop transfer. These resources can be specified in a resource file as follows:
*validCursorForeground: green
*invalidCursorForeground: red
*noneCursorForeground: yellow
In this case, the drag icon changes color as the user moves it between components that are valid drop sites,
components that are invalid drop sites, and components that are not drop sites. While it is possible to modify some
aspects of the drag−over effects using Screen and DragContext resources, if you really want to provide customized
visual effects, you need to understand more about the implementation of drag and drop. In Section #sdragcallbk we
discuss how to provide custom drag−over effects.
19.4 Working With Drag Sources
Many applications work with data other than text. In order to provide drag and drop capabilities, these applications
need to create drag sources for the data they manipulate. In this section, we describe the steps you need to follow to
create a new drag source. We use an example program that displays all the files in a directory and allows the user to
drag the files. However, in order for this drag to succeed, we need another application that understands files as objects
and allows the user to drop files. In Section #sdropsite, we present a text editor that handles the dropping of file data,
but for now we are just going to consider the ability to drag a file. the source code shows the file_manager.c
application, which we are going to describe in detail in the following sections. This chapter describes functionality
19 Drag and Drop 19.4 Working With Drag Sources
529
that is new in Motif 1.2, so this example only works with the 1.2 version of the Motif toolkit.
/* file_manager.c −− displays all of the files in the current directory
* and creates a drag source for each file. The user can drag the
* contents of the file to another application that understands
* dropping file data. Demonstrates creating a drag source, creating
* drag icons, and handling data conversion.
*/
#include <Xm/Screen.h>
#include <Xm/ScrolledW.h>
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/AtomMgr.h>
#include <Xm/DragDrop.h>
#include <X11/Xos.h>
#include <stdio.h>
#include <sys/stat.h>
typedef struct {
char *file_name;
Boolean is_directory;
} FileInfo;
/* global variable −− arbitrarily limit number of files to 256 */
FileInfo files[256];
void StartDrag();
/* translations and actions. Pressing mouse button 2 calls
* StartDrag to start a drag transaction */
static char dragTranslations[] =
"#override <Btn2Down>: StartDrag()";
static XtActionsRec dragActions[] =
{ {"StartDrag", (XtActionProc) StartDrag} };
main (argc, argv)
int argc;
char *argv[];
{
Arg args[10];
int num_files, n, i = 0;
Widget toplevel, sw, panel, form;
Display *dpy;
Atom FILE_CONTENTS, FILE_NAME, DIRECTORY;
XtAppContext app;
XtTranslations parsed_trans;
char *p, *buf[256];
FILE *pp, *popen();
struct stat s_buf;
Pixmap file, dir;
Pixel fg, bg;
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtAppInitialize (&app, "Demos", NULL, 0, &argc, argv,
NULL, NULL, 0);
/* intern the Atoms for data targets */
19 Drag and Drop 19.4 Working With Drag Sources
530
dpy = XtDisplay (toplevel);
FILE_CONTENTS = XmInternAtom (dpy, "FILE_CONTENTS", False);
FILE_NAME = XmInternAtom (dpy, "FILE_NAME", False);
DIRECTORY = XmInternAtom (dpy, "DIRECTORY", False);
/* use popen to get the files in the directory */
sprintf (buf, "/bin/ls .");
if (!(pp = popen (buf, "r"))) {
perror (buf);
exit (1);
}
/* read output from popen −− store filename and type */
while (fgets (buf, sizeof (buf), pp) && (i < 256)) {
if (p = index (buf, '0))
*p = 0;
if (stat (buf, &s_buf) == −1)
continue;
else if ((s_buf.st_mode &S_IFMT) == S_IFDIR)
files[i].is_directory = True;
else if (!(s_buf.st_mode & S_IFREG))
continue;
else
files[i].is_directory = False;
files[i].file_name = XtNewString (buf);
i++;
}
pclose (pp);
num_files = i;
/* create a scrolled window to contain the file labels */
sw = XtVaCreateManagedWidget ("sw",
xmScrolledWindowWidgetClass, toplevel,
XmNwidth, 200,
XmNheight, 300,
XmNscrollingPolicy, XmAUTOMATIC,
NULL);
panel = XtVaCreateWidget ("panel", xmRowColumnWidgetClass, sw, NULL);
/* get foreground and background colors and create label pixmaps */
XtVaGetValues (panel,
XmNforeground, &fg,
XmNbackground, &bg,
NULL);
file = XmGetPixmap (XtScreen (panel), "file.xbm", fg, bg);
dir = XmGetPixmap (XtScreen (panel), "dir.xbm", fg, bg);
if (file == XmUNSPECIFIED_PIXMAP || dir == XmUNSPECIFIED_PIXMAP) {
puts ("Couldn't load pixmaps");
exit (1);
}
parsed_trans = XtParseTranslationTable (dragTranslations);
XtAppAddActions (app, dragActions, XtNumber (dragActions));
/* create image and filename Labels for each file */
for (i = 0; i < num_files; i++) {
form = XtVaCreateWidget ("form", xmFormWidgetClass, panel, NULL);
XtVaCreateManagedWidget ("type", xmLabelWidgetClass, form,
/* specify translation for drag and index into file array */
XmNtranslations, parsed_trans,
XmNuserData, i,
19 Drag and Drop 19.4 Working With Drag Sources
531
XmNlabelType, XmPIXMAP,
XmNlabelPixmap, files[i].is_directory ? dir : file,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 25,
NULL);
XtVaCreateManagedWidget (files[i].file_name,
xmLabelWidgetClass, form,
XmNalignment, XmALIGNMENT_BEGINNING,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 25,
NULL);
XtManageChild (form);
}
XtManageChild (panel);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* StartDrag() −− action routine called by the initiator when a drag starts
* (in this case, when mouse button 2 is pressed). It starts
* the drag processing and establishes a drag context.
*/
void
StartDrag(widget, event, params, num_params)
Widget widget;
XEvent *event;
String *params;
Cardinal *num_params;
{
Arg args[10];
int n, i;
Display *dpy;
Atom FILE_CONTENTS, FILE_NAME, DIRECTORY;
Atom exportList[2];
Widget drag_icon, dc;
Pixel fg, bg;
Pixmap icon, iconmask;
XtPointer ptr;
Boolean ConvertProc();
void DragDropFinish();
/* 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,
XmNbackground, &bg,
XmNforeground, &fg,
19 Drag and Drop 19.4 Working With Drag Sources
532
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);
/* specify resources for DragContext for the transfer */
n = 0;
XtSetArg (args[n], XmNblendModel, XmBLEND_JUST_SOURCE); n++;
XtSetArg (args[n], XmNcursorBackground, bg); n++;
XtSetArg (args[n], XmNcursorForeground, fg); n++;
XtSetArg (args[n], XmNsourceCursorIcon, drag_icon); n++;
/* establish the list of valid target types */
if (files[i].is_directory) {
exportList[0] = DIRECTORY;
XtSetArg (args[n], XmNexportTargets, exportList); n++;
XtSetArg (args[n], XmNnumExportTargets, 1); n++;
}
else {
exportList[0] = FILE_CONTENTS;
exportList[1] = FILE_NAME;
XtSetArg (args[n], XmNexportTargets, exportList); n++;
XtSetArg (args[n], XmNnumExportTargets, 2); n++;
}
XtSetArg (args[n], XmNdragOperations, XmDROP_COPY); n++;
XtSetArg (args[n], XmNconvertProc, ConvertProc); n++;
XtSetArg (args[n], XmNclientData, widget); n++;
/* start the drag and register a callback to clean up when done */
dc = XmDragStart (widget, event, args, n);
XtAddCallback (dc, XmNdragDropFinishCallback, DragDropFinish, NULL);
}
/* ConvertProc() −− convert the file data to the format requested
* by the drop site.
*/
Boolean
ConvertProc(widget, selection, target, type_return, value_return,
length_return, format_return)
Widget widget;
Atom *selection;
Atom *target;
19 Drag and Drop 19.4 Working With Drag Sources
533

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.