1 /* $TOG: file.c /main/4 1999/07/20 14:49:49 mgreess $ */
2 /*****************************************************************************
3 *****************************************************************************
7 ** Description: File transfer functions for the CDE Drag & Drop Demo.
9 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
10 ** (c) Copyright 1993, 1994 International Business Machines Corp.
11 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
12 ** (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of
15 ****************************************************************************
16 ************************************<+>*************************************/
21 #include <sys/param.h>
23 #include <X11/Intrinsic.h>
26 #include <Xm/DrawingA.h>
28 #include <Xm/Protocols.h>
37 /*************************************************************************
39 * Data Structures & Private Declarations For Appointment Buffers
41 **************************************************************************/
44 * Specification of drag or drop directory
53 * File names and contents. The contents are the minimal required by the
54 * data typing service to correctly type the file via content-based typing.
55 * The file names are appropriate to the type of the contents as well. This
56 * demo uses content-based typing to get the appropriate icons for these files.
59 #define FILE_NAME_CSH "runit"
60 #define FILE_DATA_CSH "#! /bin/csh"
62 #define FILE_NAME_PS "map.ps"
63 #define FILE_DATA_PS "%!PS-Adobe-2.0"
65 #define FILE_NAME_TEXT "tasks"
66 #define FILE_DATA_TEXT "Nothing"
69 * Private file function declarations
72 static XtActionProc fileCheckForDragProc(Widget, XEvent*, String*,
74 static void fileConvertCallback(Widget, XtPointer, XtPointer);
75 static void fileCreateDirectory(char*);
76 static void fileCreateFile(char*, char*, char*);
77 static void fileCreateFiles(Widget);
78 static void fileDragStart(Widget, XEvent*, IconInfo*, int);
79 static char* fileGetContents(char*);
80 static char* fileGetDemoDirectory();
81 static char* fileGetDirectoryName(DragOrDrop);
82 static void fileRemoveDirectory(char*);
83 static void fileShutdown(Widget, XtPointer, XtPointer);
85 /*************************************************************************
87 * File Name Drag & Drop
89 **************************************************************************/
94 * When converting the data, fills in the file structure with the name(s) of
95 * the file(s). When converting DELETE, removes the given file(s) and icon(s)
96 * from the filesystem and drawing area respectively.
101 XtPointer clientData,
104 DtDndConvertCallbackStruct *convertInfo =
105 (DtDndConvertCallbackStruct *) callData;
106 IconInfo *iconArray = (IconInfo *) clientData;
107 char filePath[MAXPATHLEN + 1],
108 command[MAXPATHLEN + 4];
112 if (convertInfo == NULL) {
117 * Verify the protocol and callback reason
120 if (convertInfo->dragData->protocol != DtDND_FILENAME_TRANSFER ||
121 (convertInfo->reason != DtCR_DND_CONVERT_DATA &&
122 convertInfo->reason != DtCR_DND_CONVERT_DELETE)) {
126 switch (convertInfo->reason) {
127 case DtCR_DND_CONVERT_DATA:
130 * Supply the file names of the dragged files
133 for (ii = 0; ii < convertInfo->dragData->numItems; ii++) {
134 sprintf(filePath, "%s/%s",
135 fileGetDirectoryName(DragDirectory),
137 convertInfo->dragData->data.files[ii] =
138 XtNewString(filePath);
141 case DtCR_DND_CONVERT_DELETE:
144 * Delete dragged files as second part of a move operation
147 fileDraw = XtNameToWidget(demoTopLevel, "*fileDraw");
149 for (ii = 0; ii < convertInfo->dragData->numItems; ii++) {
153 sprintf(filePath, "%s/%s",
154 fileGetDirectoryName(DragDirectory),
156 sprintf(command, "rm %s", filePath);
157 if (system(command) != 0) {
158 printf("Unable to remove file \"%s\".\n",
164 if (fileDraw != NULL) {
165 IconDelete(fileDraw, &iconArray[ii]);
167 XClearWindow(XtDisplayOfObject(fileDraw),
168 (XtWindow(fileDraw)));
169 XtCallCallbacks(fileDraw, XmNexposeCallback,
178 * fileDragFinishCallback
180 * Free the file names allocated in fileConvertCallback()
183 fileDragFinishCallback(
185 XtPointer clientData,
188 DtDndDragFinishCallbackStruct *dragFinishInfo =
189 (DtDndDragFinishCallbackStruct *)callData;
190 DtDndContext *dragData = dragFinishInfo->dragData;
193 for (ii = 0; ii < dragData->numItems; ii++) {
194 XtFree(dragData->data.files[ii]);
199 * fileTransferCallback
201 * Handles the transfer of a file or appointment to the draw area.
202 * Adds the appropriate icon to the list of icons on the draw area.
205 fileTransferCallback(
207 XtPointer clientData,
210 DtDndTransferCallbackStruct *transferInfo =
211 (DtDndTransferCallbackStruct *) callData;
212 IconInfo *iconList = NULL, *iconPtr;
213 char *filePath, *name, *contents,
214 command[2*MAXPATHLEN + 5];
217 if (transferInfo == NULL) {
222 * Verify the protocol and callback reasons
225 if (transferInfo->dropData->protocol != DtDND_FILENAME_TRANSFER ||
226 transferInfo->reason != DtCR_DND_TRANSFER_DATA) {
230 if (widget != NULL) {
231 XtVaGetValues(widget, XmNuserData, &iconList, NULL);
235 * Copy the dropped file(s) to the drop directory
238 for (ii = 0; ii < transferInfo->dropData->numItems; ii++) {
240 /* Copy the file(s) */
242 filePath = transferInfo->dropData->data.files[ii];
244 contents = fileGetContents(filePath);
246 if ((name = strrchr(filePath,'/')) == NULL) {
251 sprintf(command, "cp %s %s", filePath,
252 fileGetDirectoryName(DropDirectory));
253 if (system(command) != 0) {
254 printf("Could not copy file \"%s\" to \"%s\".\n",
255 filePath, fileGetDirectoryName(DropDirectory));
256 transferInfo->status = DtDND_FAILURE;
260 /* Create icon(s) for new file(s) at the drop site */
263 IconInitialize(widget, iconPtr,
264 transferInfo->x + ii * 10,
265 transferInfo->y + ii * 10,
266 contents, strlen(contents), name, IconByData);
267 iconPtr->next = iconList;
268 if (iconList != NULL) {
269 iconList->prev = iconPtr;
272 XtVaSetValues(widget, XmNuserData, iconList, NULL);
280 * Prepares the file draw area to be a drag source.
286 char translations[] = "<Btn2Down>: fileCheckForDragProc()";
287 XtTranslations newTranslations;
288 XtActionsRec actionTable[] = {
289 {"fileCheckForDragProc", (XtActionProc)fileCheckForDragProc},
292 XtAppAddActions(demoAppContext, actionTable, 1);
293 newTranslations = XtParseTranslationTable(translations);
294 XtVaSetValues(fileDraw, XmNtranslations, newTranslations, NULL);
296 XtAddEventHandler(fileDraw, Button1MotionMask, False,
297 (XtEventHandler)demoDragMotionHandler,
298 (XtPointer)DtDND_FILENAME_TRANSFER);
300 fileCreateFiles(fileDraw);
306 * Such a function is not needed since the demoDropSetup() in demo.c registers
307 * the draw area as a drop site for drops of file names.
313 * Initiates a file drag. The function fileCheckForDrag() first determines
314 * if the pointer is over a file icon before calling this function.
323 static XtCallbackRec convertCBRec[] = { {fileConvertCallback, NULL},
325 static XtCallbackRec dragFinishCBRec[] =
326 { {demoDragFinishCallback, NULL},
327 {fileDragFinishCallback, NULL},
332 convertCBRec[0].closure = (XtPointer) iconArray;
339 if (iconArray[0].dragIcon == NULL) {
340 iconArray[0].dragIcon = DtDndCreateSourceIcon(widget,
341 iconArray[0].bitmap, iconArray[0].mask);
343 dragIcon = iconArray[0].dragIcon;
345 dragIcon = NULL; /* Use default multiple provided by library */
348 XtSetArg(arg[0], DtNsourceIcon, (XtArgVal)dragIcon);
354 if (DtDndDragStart(widget, event, DtDND_FILENAME_TRANSFER, numFiles,
355 XmDROP_COPY | XmDROP_MOVE,
356 convertCBRec, dragFinishCBRec, arg, 1)
359 printf("DragStart returned NULL.\n");
364 * fileCheckForDragProc
366 * Called when button 2 is pressed in the file drag area. Calls
367 * fileCheckForDrag() to determine if the button was pressed over a file
368 * icon in which case a drag is started.
371 fileCheckForDragProc(
377 fileCheckForDrag(widget, event, event->xbutton.x, event->xbutton.y);
383 * Determine if the pointer is over a file icon (within the drag threshold)
384 * when button 2 is pressed or when button 1 was pressed and the drag
385 * threshold has been exceeded.
394 IconInfo *iconList, *iconPtr, *iconArray;
396 XtVaGetValues(widget, XmNuserData, &iconList, NULL);
398 if (iconList == NULL) {
399 printf("Unable to locate icon list.\n");
402 for (iconPtr = iconList; iconPtr != NULL; iconPtr = iconPtr->next) {
403 if ((initialX > (int)iconPtr->icon.x &&
404 initialX < (int)(iconPtr->icon.x + iconPtr->icon.width)) &&
405 (initialY > (int)iconPtr->icon.y &&
406 initialY < (int)(iconPtr->icon.y + iconPtr->icon.height))){
409 * This starts a single file drag. To start a multiple
410 * file drag add elements to the icon array here. The
411 * convert and transfer callbacks are already written
412 * to handle multiple file transfers.
415 iconArray = (IconInfo *)XtCalloc(1,sizeof(IconInfo));
416 iconArray[0] = *iconPtr;
418 fileDragStart(widget, event, iconArray, 1);
423 /*************************************************************************
425 * File Creation, Initialization & Destruction
427 *************************************************************************/
430 * fileCreateDragSource
432 * Create draw area with a frame to serve as the drag source for files.
435 fileCreateDragSource(
441 fileFrame = XtVaCreateManagedWidget("fileFrame",
442 xmFrameWidgetClass, parent,
445 fileDraw = XtVaCreateManagedWidget("fileDraw",
446 xmDrawingAreaWidgetClass, fileFrame,
448 XtAddCallback(fileDraw, XmNexposeCallback, demoDrawExposeCallback,NULL);
456 * Such a function is not needed since the drop site is the draw area which
457 * is created in demoCreateDropSite() in demo.c
461 * fileCreateDirectory
463 * Create the given directory.
469 char command[MAXPATHLEN + 8];
471 sprintf(command, "mkdir %s", directory);
472 if (system(command) != 0) {
473 printf("Unable to create directory \"%s\"\n", directory);
481 * Given a path (partial or absolute), a file name and data create a file
482 * containing the given data using the given path.
491 char filePathAndName[MAXPATHLEN];
493 sprintf(filePathAndName, "%s/%s", filePath, fileName);
495 if ((fp = fopen(filePathAndName, "w")) == NULL) {
496 printf("Cannot create file \"%s\" in current directory.\n"
497 "Exiting...\n", filePathAndName);
500 if (fwrite(fileData, strlen(fileData), 1, fp) != 1) {
501 printf("Cannot write file \"%s\" in current directory.\n"
502 "Exiting...\n", filePathAndName);
511 * Create drag and drop directories and the files to drag.
521 Atom WM_DELETE_WINDOW;
524 XmInternAtom(XtDisplay(demoTopLevel), "WM_DELETE_WINDOW", False);
525 XmAddWMProtocolCallback(demoTopLevel, WM_DELETE_WINDOW, fileShutdown,
528 dragDirectory = fileGetDirectoryName(DragDirectory);
529 dropDirectory = fileGetDirectoryName(DropDirectory);
531 fileRemoveDirectory(dragDirectory);
532 fileCreateDirectory(dragDirectory);
534 fileRemoveDirectory(dropDirectory);
535 fileCreateDirectory(dropDirectory);
537 fileCreateFile(dragDirectory, FILE_NAME_TEXT, FILE_DATA_TEXT);
538 fileCreateFile(dragDirectory, FILE_NAME_CSH, FILE_DATA_CSH);
539 fileCreateFile(dragDirectory, FILE_NAME_PS, FILE_DATA_PS);
542 IconInitialize(fileDraw, iconPtr, 40, 25,
543 FILE_DATA_TEXT, strlen(FILE_DATA_TEXT),
544 FILE_NAME_TEXT, IconByData);
548 iconPtr->next = iconList;
549 iconList->prev = iconPtr;
551 IconInitialize(fileDraw, iconPtr, 105, 25,
552 FILE_DATA_CSH, strlen(FILE_DATA_CSH),
553 FILE_NAME_CSH, IconByData);
557 iconPtr->next = iconList;
558 iconList->prev = iconPtr;
560 IconInitialize(fileDraw, iconPtr, 75, 95,
561 FILE_DATA_PS, strlen(FILE_DATA_PS),
562 FILE_NAME_PS, IconByData);
566 XtVaSetValues(fileDraw, XmNuserData, iconList, NULL);
570 * fileRemoveDirectory
572 * Remove the given directory and its contents if the directory exists.
578 struct stat fileStatus;
579 char command[MAXPATHLEN + 8];
581 if (stat(directory, &fileStatus) == 0) { /* directory exists */
582 sprintf(command, "rm -rf %s", directory);
583 if (system(command) != 0) {
584 printf("Unable to remove directory \"%s\"\n"
585 "Please remove this directory by hand "
586 "and try again.\n", directory);
595 * Remove the temporary file
600 XtPointer clientData,
603 fileRemoveDirectory(fileGetDirectoryName(DragDirectory));
604 fileRemoveDirectory(fileGetDirectoryName(DropDirectory));
607 /*************************************************************************
609 * File Utility Functions
611 *************************************************************************/
616 * Open the specified file and read the contents into a buffer which is
623 char *contents = NULL;
624 struct stat fileStatus;
627 if (stat(filePath, &fileStatus) == 0) { /* file exists */
628 contents = (char *) XtMalloc(fileStatus.st_size + 1);
629 if ((fp = fopen(filePath, "r")) == NULL) {
630 printf("Cannot open file \"%s\" for reading.\n",
634 } else if (fread(contents, fileStatus.st_size, 1, fp) != 1) {
635 printf("Cannot read file \"%s\".\n", filePath);
639 if (contents != NULL) {
640 contents[fileStatus.st_size] = NULL;
648 * fileGetDemoDirectory
650 * Return the directory where the demo directories reside.
653 fileGetDemoDirectory()
655 static char *demoDirectory = NULL;
656 char currentDirectory[MAXPATHLEN];
659 if (demoDirectory == NULL) {
660 demoDirectory = (char *) getenv("DNDDEMODIR");
661 if (demoDirectory == NULL) {
662 demoDirectory = (char *) getcwd(NULL, MAXPATHLEN);
663 if (demoDirectory == NULL) {
665 "getcwd() could not get current directory.\n"
666 "\tUsing \".\" instead.\n",
670 /* strip off the /tmp_mnt */
671 if (strncmp(demoDirectory, "/tmp_mnt/", 9) == 0) {
677 return demoDirectory;
681 * fileGetDirectoryName
683 * Gets the name of the directory where the files are dragged from or dropped
684 * to depending on which is requested.
687 fileGetDirectoryName(
688 DragOrDrop dragOrDrop)
690 static char *dragDirectory = NULL;
691 static char *dropDirectory = NULL;
693 switch (dragOrDrop) {
695 if (dragDirectory == NULL) {
696 dragDirectory = (char *) XtMalloc(MAXPATHLEN + 1);
697 sprintf(dragDirectory, "%s/FileDragDir",
698 fileGetDemoDirectory());
700 return dragDirectory;
703 if (dropDirectory == NULL) {
704 dropDirectory = (char *) XtMalloc(MAXPATHLEN + 1);
705 sprintf(dropDirectory, "%s/FileDropDir",
706 fileGetDemoDirectory());
708 return dropDirectory;
718 * Store a buffer into a file in the drop directory.
719 * A temporary file may be created if required.
727 char path[MAXPATHLEN];
728 char *dir = fileGetDirectoryName(DropDirectory);
729 struct stat statInfo;
735 sprintf(path, "%s/%s", dir, name);
737 if (stat(path, &statInfo) == 0) {
740 if ((tPath = tempnam(dir, name)) == NULL)
746 if ((fp = fopen(path, "w")) == NULL) {
747 printf("Cannot create file \"%s\"\n", path);
751 if (fwrite(buf, len, 1, fp) != 1) {
752 printf("Cannot write to file \"%s\".\n", path);
758 return XtNewString(path);