1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/examples/dtdnd/file.c
2018-04-28 12:30:20 -06:00

781 lines
22 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $TOG: file.c /main/4 1999/07/20 14:49:49 mgreess $ */
/*****************************************************************************
*****************************************************************************
**
** File: file.c
**
** Description: File transfer functions for the CDE Drag & Drop Demo.
**
** (c) Copyright 1993, 1994 Hewlett-Packard Company
** (c) Copyright 1993, 1994 International Business Machines Corp.
** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
** (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of
** Novell, Inc.
**
****************************************************************************
************************************<+>*************************************/
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/DrawingA.h>
#include <Xm/Frame.h>
#include <Xm/Protocols.h>
#include <Dt/Dt.h>
#include <Dt/Dnd.h>
#include "icon.h"
#include "demo.h"
#include "file.h"
/*************************************************************************
*
* Data Structures & Private Declarations For Appointment Buffers
*
**************************************************************************/
/*
* Specification of drag or drop directory
*/
typedef enum {
DragDirectory,
DropDirectory
} DragOrDrop;
/*
* File names and contents. The contents are the minimal required by the
* data typing service to correctly type the file via content-based typing.
* The file names are appropriate to the type of the contents as well. This
* demo uses content-based typing to get the appropriate icons for these files.
*/
#define FILE_NAME_CSH "runit"
#define FILE_DATA_CSH "#! /bin/csh"
#define FILE_NAME_PS "map.ps"
#define FILE_DATA_PS "%!PS-Adobe-2.0"
#define FILE_NAME_TEXT "tasks"
#define FILE_DATA_TEXT "Nothing"
/*
* Private file function declarations
*/
static XtActionProc fileCheckForDragProc(Widget, XEvent*, String*,
Cardinal*);
static void fileConvertCallback(Widget, XtPointer, XtPointer);
static void fileCreateDirectory(char*);
static void fileCreateFile(char*, char*, char*);
static void fileCreateFiles(Widget);
static void fileDragStart(Widget, XEvent*, IconInfo*, int);
static char* fileGetContents(char*);
static char* fileGetDemoDirectory();
static char* fileGetDirectoryName(DragOrDrop);
static void fileRemoveDirectory(char*);
static void fileShutdown(Widget, XtPointer, XtPointer);
/*************************************************************************
*
* File Name Drag & Drop
*
**************************************************************************/
/*
* fileConvertCallback
*
* When converting the data, fills in the file structure with the name(s) of
* the file(s). When converting DELETE, removes the given file(s) and icon(s)
* from the filesystem and drawing area respectively.
*/
static void
fileConvertCallback(
Widget dragContext,
XtPointer clientData,
XtPointer callData)
{
DtDndConvertCallbackStruct *convertInfo =
(DtDndConvertCallbackStruct *) callData;
IconInfo *iconArray = (IconInfo *) clientData;
char filePath[MAXPATHLEN + 1],
command[MAXPATHLEN + 4];
int ii;
Widget fileDraw;
if (convertInfo == NULL) {
return;
}
/*
* Verify the protocol and callback reason
*/
if (convertInfo->dragData->protocol != DtDND_FILENAME_TRANSFER ||
(convertInfo->reason != DtCR_DND_CONVERT_DATA &&
convertInfo->reason != DtCR_DND_CONVERT_DELETE)) {
return;
}
switch (convertInfo->reason) {
case DtCR_DND_CONVERT_DATA:
/*
* Supply the file names of the dragged files
*/
for (ii = 0; ii < convertInfo->dragData->numItems; ii++) {
sprintf(filePath, "%s/%s",
fileGetDirectoryName(DragDirectory),
iconArray[ii].name);
convertInfo->dragData->data.files[ii] =
XtNewString(filePath);
}
break;
case DtCR_DND_CONVERT_DELETE:
/*
* Delete dragged files as second part of a move operation
*/
fileDraw = XtNameToWidget(demoTopLevel, "*fileDraw");
for (ii = 0; ii < convertInfo->dragData->numItems; ii++) {
/* Remove file(s) */
sprintf(filePath, "%s/%s",
fileGetDirectoryName(DragDirectory),
iconArray[ii].name);
sprintf(command, "rm %s", filePath);
if (system(command) != 0) {
printf("Unable to remove file \"%s\".\n",
filePath);
}
/* Remove icon(s) */
if (fileDraw != NULL) {
IconDelete(fileDraw, &iconArray[ii]);
XClearWindow(XtDisplayOfObject(fileDraw),
(XtWindow(fileDraw)));
XtCallCallbacks(fileDraw, XmNexposeCallback,
NULL);
}
}
break;
}
}
/*
* fileDragFinishCallback
*
* Free the file names allocated in fileConvertCallback()
*/
void
fileDragFinishCallback(
Widget widget,
XtPointer clientData,
XtPointer callData)
{
DtDndDragFinishCallbackStruct *dragFinishInfo =
(DtDndDragFinishCallbackStruct *)callData;
DtDndContext *dragData = dragFinishInfo->dragData;
int ii;
for (ii = 0; ii < dragData->numItems; ii++) {
XtFree(dragData->data.files[ii]);
}
}
/*
* fileTransferCallback
*
* Handles the transfer of a file or appointment to the draw area.
* Adds the appropriate icon to the list of icons on the draw area.
*/
void
fileTransferCallback(
Widget widget,
XtPointer clientData,
XtPointer callData)
{
DtDndTransferCallbackStruct *transferInfo =
(DtDndTransferCallbackStruct *) callData;
IconInfo *iconList = NULL, *iconPtr;
char *filePath, *name, *contents,
command[2*MAXPATHLEN + 5];
int ii;
if (transferInfo == NULL) {
return;
}
/*
* Verify the protocol and callback reasons
*/
if (transferInfo->dropData->protocol != DtDND_FILENAME_TRANSFER ||
transferInfo->reason != DtCR_DND_TRANSFER_DATA) {
return;
}
if (widget != NULL) {
XtVaGetValues(widget, XmNuserData, &iconList, NULL);
}
/*
* Copy the dropped file(s) to the drop directory
*/
for (ii = 0; ii < transferInfo->dropData->numItems; ii++) {
/* Copy the file(s) */
filePath = transferInfo->dropData->data.files[ii];
contents = fileGetContents(filePath);
if ((name = strrchr(filePath,'/')) == NULL) {
name = filePath;
} else {
name++;
}
sprintf(command, "cp %s %s", filePath,
fileGetDirectoryName(DropDirectory));
if (system(command) != 0) {
printf("Could not copy file \"%s\" to \"%s\".\n",
filePath, fileGetDirectoryName(DropDirectory));
transferInfo->status = DtDND_FAILURE;
return;
}
/* Create icon(s) for new file(s) at the drop site */
iconPtr = IconNew();
IconInitialize(widget, iconPtr,
transferInfo->x + ii * 10,
transferInfo->y + ii * 10,
contents, strlen(contents), name, IconByData);
iconPtr->next = iconList;
if (iconList != NULL) {
iconList->prev = iconPtr;
}
iconList = iconPtr;
XtVaSetValues(widget, XmNuserData, iconList, NULL);
XtFree(contents);
}
}
/*
* fileDragSetup
*
* Prepares the file draw area to be a drag source.
*/
void
fileDragSetup(
Widget fileDraw)
{
char translations[] = "<Btn2Down>: fileCheckForDragProc()";
XtTranslations newTranslations;
XtActionsRec actionTable[] = {
{"fileCheckForDragProc", (XtActionProc)fileCheckForDragProc},
};
XtAppAddActions(demoAppContext, actionTable, 1);
newTranslations = XtParseTranslationTable(translations);
XtVaSetValues(fileDraw, XmNtranslations, newTranslations, NULL);
XtAddEventHandler(fileDraw, Button1MotionMask, False,
(XtEventHandler)demoDragMotionHandler,
(XtPointer)DtDND_FILENAME_TRANSFER);
fileCreateFiles(fileDraw);
}
/*
* fileDropSetup
*
* Such a function is not needed since the demoDropSetup() in demo.c registers
* the draw area as a drop site for drops of file names.
*/
/*
* fileDragStart
*
* Initiates a file drag. The function fileCheckForDrag() first determines
* if the pointer is over a file icon before calling this function.
*/
static void
fileDragStart(
Widget widget,
XEvent *event,
IconInfo *iconArray,
int numFiles)
{
static XtCallbackRec convertCBRec[] = { {fileConvertCallback, NULL},
{NULL, NULL} };
static XtCallbackRec dragFinishCBRec[] =
{ {demoDragFinishCallback, NULL},
{fileDragFinishCallback, NULL},
{NULL, NULL} };
Widget dragIcon;
Arg arg[1];
convertCBRec[0].closure = (XtPointer) iconArray;
/*
* Set up drag icon
*/
if (numFiles == 1) {
if (iconArray[0].dragIcon == NULL) {
iconArray[0].dragIcon = DtDndCreateSourceIcon(widget,
iconArray[0].bitmap, iconArray[0].mask);
}
dragIcon = iconArray[0].dragIcon;
} else {
dragIcon = NULL; /* Use default multiple provided by library */
}
XtSetArg(arg[0], DtNsourceIcon, (XtArgVal)dragIcon);
/*
* Start the drag
*/
if (DtDndDragStart(widget, event, DtDND_FILENAME_TRANSFER, numFiles,
XmDROP_COPY | XmDROP_MOVE,
convertCBRec, dragFinishCBRec, arg, 1)
== NULL) {
printf("DragStart returned NULL.\n");
}
}
/*
* fileCheckForDragProc
*
* Called when button 2 is pressed in the file drag area. Calls
* fileCheckForDrag() to determine if the button was pressed over a file
* icon in which case a drag is started.
*/
static XtActionProc
fileCheckForDragProc(
Widget widget,
XEvent *event,
String *params,
Cardinal *numParams)
{
fileCheckForDrag(widget, event, event->xbutton.x, event->xbutton.y);
}
/*
* fileCheckForDrag
*
* Determine if the pointer is over a file icon (within the drag threshold)
* when button 2 is pressed or when button 1 was pressed and the drag
* threshold has been exceeded.
*/
void
fileCheckForDrag(
Widget widget,
XEvent *event,
int initialX,
int initialY)
{
IconInfo *iconList, *iconPtr, *iconArray;
XtVaGetValues(widget, XmNuserData, &iconList, NULL);
if (iconList == NULL) {
printf("Unable to locate icon list.\n");
}
for (iconPtr = iconList; iconPtr != NULL; iconPtr = iconPtr->next) {
if ((initialX > (int)iconPtr->icon.x &&
initialX < (int)(iconPtr->icon.x + iconPtr->icon.width)) &&
(initialY > (int)iconPtr->icon.y &&
initialY < (int)(iconPtr->icon.y + iconPtr->icon.height))){
/*
* This starts a single file drag. To start a multiple
* file drag add elements to the icon array here. The
* convert and transfer callbacks are already written
* to handle multiple file transfers.
*/
iconArray = (IconInfo *)XtCalloc(1,sizeof(IconInfo));
iconArray[0] = *iconPtr;
fileDragStart(widget, event, iconArray, 1);
}
}
}
/*************************************************************************
*
* File Creation, Initialization & Destruction
*
*************************************************************************/
/*
* fileCreateDragSource
*
* Create draw area with a frame to serve as the drag source for files.
*/
Widget
fileCreateDragSource(
Widget parent)
{
Widget fileFrame,
fileDraw;
fileFrame = XtVaCreateManagedWidget("fileFrame",
xmFrameWidgetClass, parent,
NULL);
fileDraw = XtVaCreateManagedWidget("fileDraw",
xmDrawingAreaWidgetClass, fileFrame,
NULL);
XtAddCallback(fileDraw, XmNexposeCallback, demoDrawExposeCallback,NULL);
return fileDraw;
}
/*
* fileCreateDropSite
*
* Such a function is not needed since the drop site is the draw area which
* is created in demoCreateDropSite() in demo.c
*/
/*
* fileCreateDirectory
*
* Create the given directory.
*/
static void
fileCreateDirectory(
char *directory)
{
char command[MAXPATHLEN + 8];
sprintf(command, "mkdir %s", directory);
if (system(command) != 0) {
printf("Unable to create directory \"%s\"\n", directory);
exit(1);
}
}
/*
* fileCreateFile
*
* Given a path (partial or absolute), a file name and data create a file
* containing the given data using the given path.
*/
static void
fileCreateFile(
char *filePath,
char *fileName,
char *fileData)
{
FILE *fp;
char filePathAndName[MAXPATHLEN];
sprintf(filePathAndName, "%s/%s", filePath, fileName);
if ((fp = fopen(filePathAndName, "w")) == NULL) {
printf("Cannot create file \"%s\" in current directory.\n"
"Exiting...\n", filePathAndName);
exit(1);
}
if (fwrite(fileData, strlen(fileData), 1, fp) != 1) {
printf("Cannot write file \"%s\" in current directory.\n"
"Exiting...\n", filePathAndName);
exit(1);
}
fclose(fp);
}
/*
* fileCreateFiles
*
* Create drag and drop directories and the files to drag.
*/
static void
fileCreateFiles(
Widget fileDraw)
{
IconInfo *iconList,
*iconPtr;
char *dragDirectory,
*dropDirectory;
Atom WM_DELETE_WINDOW;
WM_DELETE_WINDOW =
XmInternAtom(XtDisplay(demoTopLevel), "WM_DELETE_WINDOW", False);
XmAddWMProtocolCallback(demoTopLevel, WM_DELETE_WINDOW, fileShutdown,
(XtPointer)NULL);
dragDirectory = fileGetDirectoryName(DragDirectory);
dropDirectory = fileGetDirectoryName(DropDirectory);
fileRemoveDirectory(dragDirectory);
fileCreateDirectory(dragDirectory);
fileRemoveDirectory(dropDirectory);
fileCreateDirectory(dropDirectory);
fileCreateFile(dragDirectory, FILE_NAME_TEXT, FILE_DATA_TEXT);
fileCreateFile(dragDirectory, FILE_NAME_CSH, FILE_DATA_CSH);
fileCreateFile(dragDirectory, FILE_NAME_PS, FILE_DATA_PS);
iconPtr = IconNew();
IconInitialize(fileDraw, iconPtr, 40, 25,
FILE_DATA_TEXT, strlen(FILE_DATA_TEXT),
FILE_NAME_TEXT, IconByData);
iconList = iconPtr;
iconPtr = IconNew();
iconPtr->next = iconList;
iconList->prev = iconPtr;
IconInitialize(fileDraw, iconPtr, 105, 25,
FILE_DATA_CSH, strlen(FILE_DATA_CSH),
FILE_NAME_CSH, IconByData);
iconList = iconPtr;
iconPtr = IconNew();
iconPtr->next = iconList;
iconList->prev = iconPtr;
IconInitialize(fileDraw, iconPtr, 75, 95,
FILE_DATA_PS, strlen(FILE_DATA_PS),
FILE_NAME_PS, IconByData);
iconList = iconPtr;
XtVaSetValues(fileDraw, XmNuserData, iconList, NULL);
}
/*
* fileRemoveDirectory
*
* Remove the given directory and its contents if the directory exists.
*/
static void
fileRemoveDirectory(
char *directory)
{
struct stat fileStatus;
char command[MAXPATHLEN + 8];
if (stat(directory, &fileStatus) == 0) { /* directory exists */
sprintf(command, "rm -rf %s", directory);
if (system(command) != 0) {
printf("Unable to remove directory \"%s\"\n"
"Please remove this directory by hand "
"and try again.\n", directory);
exit(1);
}
}
}
/*
* fileShutdown
*
* Remove the temporary file
*/
static void
fileShutdown(
Widget widget,
XtPointer clientData,
XtPointer callData)
{
fileRemoveDirectory(fileGetDirectoryName(DragDirectory));
fileRemoveDirectory(fileGetDirectoryName(DropDirectory));
}
/*************************************************************************
*
* File Utility Functions
*
*************************************************************************/
/*
* fileGetContents
*
* Open the specified file and read the contents into a buffer which is
* returned.
*/
static char*
fileGetContents(
char *filePath)
{
char *contents = NULL;
struct stat fileStatus;
FILE *fp;
if (stat(filePath, &fileStatus) == 0) { /* file exists */
contents = (char *) XtMalloc(fileStatus.st_size + 1);
if ((fp = fopen(filePath, "r")) == NULL) {
printf("Cannot open file \"%s\" for reading.\n",
filePath);
XtFree(contents);
contents = NULL;
} else if (fread(contents, fileStatus.st_size, 1, fp) != 1) {
printf("Cannot read file \"%s\".\n", filePath);
XtFree(contents);
contents = NULL;
}
if (contents != NULL) {
contents[fileStatus.st_size] = NULL;
}
fclose(fp);
}
return contents;
}
/*
* fileGetDemoDirectory
*
* Return the directory where the demo directories reside.
*/
static char*
fileGetDemoDirectory()
{
static char *demoDirectory = NULL;
char currentDirectory[MAXPATHLEN];
int status;
if (demoDirectory == NULL) {
demoDirectory = (char *) getenv("DNDDEMODIR");
if (demoDirectory == NULL) {
demoDirectory = (char *) getcwd(NULL, MAXPATHLEN);
if (demoDirectory == NULL) {
sprintf(
"getcwd() could not get current directory.\n"
"\tUsing \".\" instead.\n",
NULL);
demoDirectory = ".";
} else {
/* strip off the /tmp_mnt */
if (strncmp(demoDirectory, "/tmp_mnt/", 9) == 0) {
demoDirectory += 8;
}
}
}
}
return demoDirectory;
}
/*
* fileGetDirectoryName
*
* Gets the name of the directory where the files are dragged from or dropped
* to depending on which is requested.
*/
static char*
fileGetDirectoryName(
DragOrDrop dragOrDrop)
{
static char *dragDirectory = NULL;
static char *dropDirectory = NULL;
switch (dragOrDrop) {
case DragDirectory:
if (dragDirectory == NULL) {
dragDirectory = (char *) XtMalloc(MAXPATHLEN + 1);
sprintf(dragDirectory, "%s/FileDragDir",
fileGetDemoDirectory());
}
return dragDirectory;
break;
case DropDirectory:
if (dropDirectory == NULL) {
dropDirectory = (char *) XtMalloc(MAXPATHLEN + 1);
sprintf(dropDirectory, "%s/FileDropDir",
fileGetDemoDirectory());
}
return dropDirectory;
break;
default:
return NULL;
}
}
/*
* fileStoreBuffer
*
* Store a buffer into a file in the drop directory.
* A temporary file may be created if required.
*/
char *
fileStoreBuffer(
char *name,
void *buf,
int len)
{
char path[MAXPATHLEN];
char *dir = fileGetDirectoryName(DropDirectory);
struct stat statInfo;
FILE *fp;
if (name == NULL)
name = "unnamed";
sprintf(path, "%s/%s", dir, name);
if (stat(path, &statInfo) == 0) {
char *tPath;
if ((tPath = tempnam(dir, name)) == NULL)
return (char *)NULL;
strcpy(path, tPath);
free(tPath);
}
if ((fp = fopen(path, "w")) == NULL) {
printf("Cannot create file \"%s\"\n", path);
return (char *)NULL;
}
if (fwrite(buf, len, 1, fp) != 1) {
printf("Cannot write to file \"%s\".\n", path);
return (char *)NULL;
}
fclose(fp);
return XtNewString(path);
}