2036 lines
56 KiB
C++
2036 lines
56 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
/*
|
|
DragDrop.cpp -- Drag and Drop classes to hide Motif's API, and work with Desktop files.
|
|
Created: Alastair Gourlay(SGI) c/o Dora Hsu<dora@netscape.com>, 26 Nov 1996
|
|
*/
|
|
|
|
|
|
|
|
// Classes in this file:
|
|
// XFE_DragBase
|
|
// XFE_DragDesktop
|
|
// XFE_DragNetscape
|
|
// XFE_DropBase
|
|
// XFE_DropDesktop
|
|
// XFE_DropNetscape
|
|
//
|
|
|
|
#include <stdlib.h>
|
|
#include <net.h>
|
|
#include <netdb.h>
|
|
#include <icondata.h>
|
|
#include <unistd.h>
|
|
#include <sys/param.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <ctype.h>
|
|
#include <xp_mem.h>
|
|
#include <xp_str.h>
|
|
#include <xpassert.h>
|
|
#include <xfe.h>
|
|
#include "DragDrop.h"
|
|
#include <Xm/DisplayP.h>
|
|
|
|
#if defined(SOLARIS)||defined(AIX)||defined(UNIXWARE)
|
|
extern "C" int gethostname(char *, int);
|
|
#endif
|
|
|
|
#if defined(SCO_SV)
|
|
#include <sys/socket.h> // Need MAXHOSTNAMELEN
|
|
#endif
|
|
|
|
#ifndef MAXPATHLEN
|
|
#define MAXPATHLEN 1024
|
|
#endif
|
|
|
|
#if defined(DEBUG_sgidev)
|
|
#define XDEBUG(x) x
|
|
#else
|
|
#define XDEBUG(x)
|
|
#endif
|
|
|
|
#ifdef MOZ_MAIL_NEWS
|
|
// from libmsg/msgglue.c
|
|
extern "C" XP_Bool MSG_RequiresMailMsgWindow(const char*);
|
|
extern "C" XP_Bool MSG_RequiresNewsMsgWindow(const char*);
|
|
extern "C" XP_Bool MSG_RequiresBrowserWindow(const char*);
|
|
#endif
|
|
|
|
//
|
|
// this list defines platforms for which Motif drag and drop is usable.
|
|
//
|
|
|
|
// test - enable Drag and Drop for all platforms - need to find out now
|
|
// if there are unavoidable Motif or X11 bugs on any platform.
|
|
|
|
//#if defined(IRIX) || defined(SOLARIS) || defined(HPUX) || defined(UNIXWARE)
|
|
#define DRAG_ENABLED
|
|
//#endif
|
|
//#if defined(IRIX) || defined(SOLARIS) || defined(HPUX) || defined(UNIXWARE)
|
|
#define DROP_ENABLED
|
|
//#endif
|
|
|
|
// default FTR type
|
|
static const char DEFAULT_FTR_TYPE[]="Unknown";
|
|
|
|
// global drag information
|
|
Widget XFE_DragBase::_activeDragShell=NULL;
|
|
|
|
// Atoms, initialized by InitializeDisplayInfo(), called from drag and drop
|
|
// base class constructors
|
|
|
|
Atom XFE_DragBase::_XA_TARGETS=None;
|
|
Atom XFE_DragBase::_XA_DELETE=None;
|
|
Atom XFE_DragBase::_XA_MULTIPLE=None;
|
|
Atom XFE_DragBase::_XA_TIMESTAMP=None;
|
|
Atom XFE_DragBase::_XA_NULL=None;
|
|
Atom XFE_DragBase::_XA_SGI_ICON=None;
|
|
Atom XFE_DragBase::_XA_SGI_ICON_TYPE=None;
|
|
Atom XFE_DragBase::_XA_SGI_FILE=None;
|
|
Atom XFE_DragBase::_XA_FILE_NAME=None;
|
|
Atom XFE_DragBase::_XA_NETSCAPE_URL=None;
|
|
|
|
Atom XFE_DropBase::_XA_TARGETS=None;
|
|
Atom XFE_DropBase::_XA_DELETE=None;
|
|
Atom XFE_DropBase::_XA_NULL=None;
|
|
Atom XFE_DropBase::_XA_SGI_ICON=None;
|
|
Atom XFE_DropBase::_XA_SGI_FILE=None;
|
|
Atom XFE_DropBase::_XA_SGI_URL=None;
|
|
Atom XFE_DropBase::_XA_FILE_NAME=None;
|
|
Atom XFE_DropBase::_XA_NETSCAPE_URL=None;
|
|
|
|
static char *localHostName=NULL;
|
|
|
|
static void InitializeDisplayInfo(Widget widget)
|
|
{
|
|
static int idi_firstTime=TRUE;
|
|
if (!idi_firstTime)
|
|
return;
|
|
idi_firstTime=FALSE;
|
|
|
|
// atoms used for drag and drop
|
|
XFE_DragBase::_XA_TARGETS=XmInternAtom(XtDisplay(widget),"TARGETS",FALSE);
|
|
XFE_DragBase::_XA_DELETE=XmInternAtom(XtDisplay(widget),"DELETE",FALSE);
|
|
XFE_DragBase::_XA_MULTIPLE=XmInternAtom(XtDisplay(widget),"MULTIPLE",FALSE);
|
|
XFE_DragBase::_XA_TIMESTAMP=XmInternAtom(XtDisplay(widget),"TIMESTAMP",FALSE);
|
|
XFE_DragBase::_XA_NULL=XmInternAtom(XtDisplay(widget),"NULL",FALSE);
|
|
XFE_DragBase::_XA_SGI_ICON=XmInternAtom(XtDisplay(widget),"_SGI_ICON",FALSE);
|
|
XFE_DragBase::_XA_SGI_ICON_TYPE=XmInternAtom(XtDisplay(widget),"_SGI_ICON_TYPE",FALSE);
|
|
XFE_DragBase::_XA_SGI_FILE=XmInternAtom(XtDisplay(widget),"SGI_FILE",FALSE);
|
|
XFE_DragBase::_XA_FILE_NAME=XmInternAtom(XtDisplay(widget),"FILE_NAME",FALSE);
|
|
XFE_DragBase::_XA_NETSCAPE_URL=XmInternAtom(XtDisplay(widget),"_NETSCAPE_URL",FALSE);
|
|
|
|
XFE_DropBase::_XA_TARGETS=XmInternAtom(XtDisplay(widget),"TARGETS",FALSE);
|
|
XFE_DropBase::_XA_DELETE=XmInternAtom(XtDisplay(widget),"DELETE",FALSE);
|
|
XFE_DropBase::_XA_NULL=XmInternAtom(XtDisplay(widget),"NULL",FALSE);
|
|
XFE_DropBase::_XA_SGI_ICON=XmInternAtom(XtDisplay(widget),"_SGI_ICON",FALSE);
|
|
XFE_DropBase::_XA_SGI_FILE=XmInternAtom(XtDisplay(widget),"SGI_FILE",FALSE);
|
|
XFE_DropBase::_XA_SGI_URL=XmInternAtom(XtDisplay(widget),"_SGI_URL",FALSE);
|
|
XFE_DropBase::_XA_FILE_NAME=XmInternAtom(XtDisplay(widget),"FILE_NAME",FALSE);
|
|
XFE_DropBase::_XA_NETSCAPE_URL=XmInternAtom(XtDisplay(widget),"_NETSCAPE_URL",FALSE);
|
|
|
|
// local hostname, used to process _SGI_ICON drag
|
|
char h[MAXHOSTNAMELEN+1];
|
|
if (gethostname(h, MAXHOSTNAMELEN)==0) {
|
|
h[MAXHOSTNAMELEN]='\0';
|
|
localHostName=strdup(h);
|
|
}
|
|
else {
|
|
localHostName="localhost";
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// XFE_DragBase
|
|
//
|
|
|
|
// globally useful utilities
|
|
|
|
char *XFE_DragBase::guessUrlMimeType(const char *data)
|
|
{
|
|
// try to determine type of attachment
|
|
|
|
// regular file
|
|
if (XP_STRNCASECMP(data,"file:",5)==0 || NET_URL_Type(data)==0) {
|
|
const char *fileData=data;
|
|
if (XP_STRNCASECMP(data,"file:",5)==0) // skip file: prefix
|
|
fileData=data+5;
|
|
if (fe_isDir((char*)fileData))
|
|
return "_directory"; // interal type, since there's no mime type
|
|
NET_cinfo *pMimeInfo = NET_cinfo_find_type((char*)data);
|
|
if ((pMimeInfo) && (pMimeInfo->type))
|
|
return pMimeInfo->type;
|
|
else
|
|
return APPLICATION_OCTET_STREAM;
|
|
}
|
|
|
|
// addressbook entry
|
|
else if (XP_STRNCASECMP(data,"addbook:",8)==0)
|
|
return "text/x-vcard";
|
|
|
|
#if defined(MOZ_MAIL_NEWS)
|
|
// mail or news message
|
|
else if (MSG_RequiresMailMsgWindow(data) || MSG_RequiresNewsMsgWindow(data))
|
|
return "message/rfc822";
|
|
|
|
// document URL - use internal id, since there's no URL mime type
|
|
else if (MSG_RequiresBrowserWindow(data))
|
|
return "_url";
|
|
#endif /* MOZ_MAIL_NEWS */
|
|
|
|
// fallback to generic type
|
|
else
|
|
return UNKNOWN_CONTENT_TYPE;
|
|
}
|
|
|
|
|
|
// callback wrappers
|
|
void XFE_DragBase::ButtonPressCb(Widget w,XtPointer cd,XEvent *event,Boolean*)
|
|
{
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
if (d &&
|
|
event->xany.type==ButtonPress &&
|
|
event->xbutton.button==1) {
|
|
d->_dragWidget=w;
|
|
d->buttonPressCb((XButtonPressedEvent*)event);
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::ButtonMotionCb(Widget w,XtPointer cd,XEvent *event,Boolean *eatEvent)
|
|
{
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
if (d &&
|
|
w==d->_dragWidget &&
|
|
event->xany.type==MotionNotify) {
|
|
*eatEvent=d->buttonMotionCb((XMotionEvent*)event);
|
|
}
|
|
}
|
|
|
|
Boolean XFE_DragBase::DragConvertCb(Widget w,Atom*,Atom *target,Atom *type,
|
|
XtPointer *value,unsigned long *length,int *format)
|
|
{
|
|
if (!w || !XmIsDragContext(w))
|
|
return FALSE;
|
|
|
|
XtPointer cd;
|
|
XtVaGetValues(w,XmNclientData,&cd,NULL);
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
|
|
if (d) {
|
|
return d->dragConvertCb(target,type,value,length,format);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void XFE_DragBase::OperationChangedCb(Widget w,XtPointer cd,XtPointer)
|
|
{
|
|
if (!w || !XmIsDragContext(w))
|
|
return;
|
|
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
|
|
// nyi - what callback struct info should be passed to method?
|
|
if (d) {
|
|
d->operationChangedCb();
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::DragMotionCb(Widget w,XtPointer cd,XtPointer cb)
|
|
{
|
|
if (!w || !XmIsDragContext(w))
|
|
return;
|
|
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
XmDragMotionCallbackStruct *dmcb=(XmDragMotionCallbackStruct*)cb;
|
|
|
|
// nyi - what callback struct info should be passed to method?
|
|
if (d) {
|
|
// record (x,y) of pointer during drag
|
|
if (dmcb) {
|
|
d->_dragEventX=dmcb->x;
|
|
d->_dragEventY=dmcb->y;
|
|
}
|
|
d->dragMotionCb();
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::DropStartCb(Widget w,XtPointer cd,XtPointer)
|
|
{
|
|
if (!w || !XmIsDragContext(w))
|
|
return;
|
|
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
|
|
// nyi - what callback struct info should be passed to method?
|
|
if (d) {
|
|
d->dropStartCb();
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::DropSiteEnterCb(Widget w,XtPointer cd,XtPointer cb)
|
|
{
|
|
if (!w || !XmIsDragContext(w))
|
|
return;
|
|
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
|
|
XmDropSiteEnterCallbackStruct *dcb=(XmDropSiteEnterCallbackStruct*)cb;
|
|
|
|
// nyi - what callback struct info should be passed to method?
|
|
if (d) {
|
|
d->dropSiteEnterCb(dcb->operations);
|
|
}
|
|
XDEBUG(printf(" operation=%x, operations=%x,status=%d\n",
|
|
dcb->operation,dcb->operations,dcb->dropSiteStatus));
|
|
}
|
|
|
|
void XFE_DragBase::DropSiteLeaveCb(Widget w,XtPointer cd,XtPointer)
|
|
{
|
|
if (!w || !XmIsDragContext(w))
|
|
return;
|
|
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
|
|
// nyi - what callback struct info should be passed to method?
|
|
if (d) {
|
|
d->dropSiteLeaveCb();
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::DropFinishCb(Widget w,XtPointer cd,XtPointer)
|
|
{
|
|
if (!w || !XmIsDragContext(w))
|
|
return;
|
|
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
|
|
// nyi - what callback struct info should be passed to method?
|
|
if (d) {
|
|
d->dropFinishCb();
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::DragDropFinishCb(Widget w,XtPointer cd,XtPointer)
|
|
{
|
|
if (!w || !XmIsDragContext(w))
|
|
return;
|
|
|
|
XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
|
|
// nyi - what callback struct info should be passed to method?
|
|
if (d) {
|
|
d->dragDropFinishCb();
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::DestroyCb(Widget w,XtPointer,XtPointer)
|
|
{
|
|
if (!w || !XmIsDragContext(w))
|
|
return;
|
|
|
|
//XFE_DragBase *d=(XFE_DragBase*)cd;
|
|
|
|
XDEBUG(printf("XFE_DragBase::DestroyCb()\n"));
|
|
}
|
|
|
|
// constructor
|
|
|
|
// The drag classes will monitor drags from the widget passed
|
|
// to the constructor. Simple drag classes can just pass
|
|
// one widget to the constructor. Multi-item objects can use
|
|
// one XFE_Drag class with additional widgets, specified by
|
|
// addDragWidget(). During the drag, the field _dragWidget
|
|
// will point to the widget currently being dragged.
|
|
|
|
XFE_DragBase::XFE_DragBase(Widget widget)
|
|
{
|
|
_widget=widget;
|
|
_dragWidget=NULL;
|
|
_dragThreshold=4;
|
|
_dragStarted=FALSE;
|
|
_buttonPressed=FALSE;
|
|
_dragStartX=0;
|
|
_dragStartY=0;
|
|
_dragEventX=0;
|
|
_dragEventY=0;
|
|
_dragContext=NULL;
|
|
_dragIcon=NULL;
|
|
_targets=NULL;
|
|
_numTargets=0;
|
|
_dragFilesAsLinks=FALSE;
|
|
|
|
// default icon is blank document
|
|
_dragIconData=&GUnknown;
|
|
_dragIconPixmap=None;
|
|
_dragIconPixmapMask=None;
|
|
_dragIconWidth=0;
|
|
_dragIconHeight=0;
|
|
_dragHotX=0;
|
|
_dragHotY=0;
|
|
|
|
InitializeDisplayInfo(widget);
|
|
|
|
addDragWidget(widget);
|
|
|
|
#ifdef IRIX
|
|
// hack for SGI Motif - force it to sgidladd/dlopen conversion library
|
|
// now, not on the first drag - it can be slow, and blows the usability
|
|
// out the water - an early button release leaves a permanent cursor
|
|
// window turd. Note: performance hit is present only in 6.2 and
|
|
// 6.3. 6.3-R10K and 6.4 were improved greatly.
|
|
static int firstTime=TRUE;
|
|
if (firstTime) {
|
|
XDEBUG(printf("Hacking XmDragContext initialization {\n"));
|
|
firstTime=FALSE;
|
|
Atom tl[1]={ XA_STRING };
|
|
Arg args[2];
|
|
int n=0;
|
|
XtSetArg(args[n],XmNexportTargets,&tl);n++;
|
|
XtSetArg(args[n],XmNnumExportTargets,1);n++;
|
|
XtDestroyWidget(XtCreateWidget("dragContext",xmDragContextClass,
|
|
XmGetXmDisplay(XtDisplay(widget)),
|
|
args,n));
|
|
XDEBUG(printf("}\n"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
// destructor
|
|
|
|
XFE_DragBase::~XFE_DragBase()
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::~XFE_DragBase()\n"));
|
|
|
|
// destroy drag icon widget
|
|
// usually destroyed in dragDropFinishCb, but catch case of mid-drag Destroy.
|
|
if (_dragIcon) {
|
|
XtDestroyWidget(_dragIcon);
|
|
_dragIcon=NULL;
|
|
}
|
|
|
|
// clean up drag icon data
|
|
setDragIcon(NULL);
|
|
}
|
|
|
|
|
|
//
|
|
// drag methods
|
|
//
|
|
|
|
void XFE_DragBase::addDragWidget(Widget widget)
|
|
{
|
|
if (widget) {
|
|
// catch button 1 press and motion
|
|
XtInsertEventHandler(widget,ButtonPressMask,FALSE,
|
|
ButtonPressCb,(XtPointer)this,XtListHead);
|
|
XtInsertEventHandler(widget,Button1MotionMask,FALSE,
|
|
ButtonMotionCb,(XtPointer)this,XtListHead);
|
|
|
|
// clean up when widget is destroyed
|
|
XtAddCallback(widget,XmNdestroyCallback,dragWidgetDestroyCb,(XtPointer)this);
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::dragWidgetDestroyCb(Widget widget,XtPointer cd,XtPointer)
|
|
{
|
|
if (widget && cd) {
|
|
XDEBUG(printf("XFE_DragBase::dragWidgetDestroyCb(%s)\n",XtName(widget)));
|
|
XtRemoveEventHandler(widget,ButtonPressMask,FALSE,
|
|
ButtonPressCb,cd);
|
|
XtRemoveEventHandler(widget,Button1MotionMask,FALSE,
|
|
ButtonMotionCb,cd);
|
|
// _dragIcon widget is a child of the _dragWidget.
|
|
// It will get destroyed by Xt, so clean up our pointer.
|
|
XFE_DragBase *db=(XFE_DragBase*)cd;
|
|
db->_dragIcon=NULL;
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::dragInitialize()
|
|
{
|
|
if (_dragContext!=NULL) {
|
|
XDEBUG(printf("DRAG IN PROGRESS - new drag not started\n"));
|
|
return;
|
|
}
|
|
|
|
if (!_dragWidget)
|
|
return;
|
|
|
|
_dragFilesAsLinks=FALSE;
|
|
|
|
// let derived class decide how to handle this drag
|
|
if (dragStart(_dragStartX,_dragStartY)==FALSE) {
|
|
dragDropFinishCb();
|
|
return;
|
|
}
|
|
|
|
targets();
|
|
operations();
|
|
|
|
if (_numTargets==0 || _operations==0) {
|
|
dragDropFinishCb();
|
|
return;
|
|
}
|
|
|
|
// enable desktop LINK behavior, if application class asks
|
|
if (_dragFilesAsLinks) {
|
|
_operations|=(unsigned int)XmDROP_LINK;
|
|
}
|
|
|
|
_dragIcon=NULL;
|
|
// create drag icons if necessary
|
|
// (i.e. first time, and after setDragIcon() )
|
|
#ifdef DRAG_ENABLED
|
|
if (_dragIconData) {
|
|
if (_dragIconPixmap==None)
|
|
_dragIconPixmap=XCreateBitmapFromData(XtDisplay(_dragWidget),
|
|
XtWindow(_dragWidget),
|
|
(char*)_dragIconData->mono_bits,
|
|
_dragIconData->width,
|
|
_dragIconData->height);
|
|
if (_dragIconPixmapMask==None)
|
|
_dragIconPixmapMask=XCreateBitmapFromData(XtDisplay(_dragWidget),
|
|
XtWindow(_dragWidget),
|
|
(char*)_dragIconData->mask_bits,
|
|
_dragIconData->width,
|
|
_dragIconData->height);
|
|
Arg args[20];
|
|
int n=0;
|
|
XtSetArg(args[n],XmNwidth,_dragIconData->width);n++;
|
|
XtSetArg(args[n],XmNheight,_dragIconData->height);n++;
|
|
XtSetArg(args[n],XmNpixmap,_dragIconPixmap);n++;
|
|
XtSetArg(args[n],XmNhotX,_dragHotX);n++;
|
|
XtSetArg(args[n],XmNhotY,_dragHotY);n++;
|
|
if (_dragIconPixmapMask) {
|
|
XtSetArg(args[n],XmNmask,_dragIconPixmapMask);n++;
|
|
}
|
|
_dragIcon=XmCreateDragIcon(_dragWidget,"dragIcon",args,n);
|
|
#endif
|
|
}
|
|
|
|
// callback records
|
|
static XtCallbackRec operationChangedCbRec[]= {
|
|
{OperationChangedCb,NULL},{NULL,NULL}
|
|
};
|
|
static XtCallbackRec dragMotionCbRec[]= {
|
|
{DragMotionCb,NULL},{NULL,NULL}
|
|
};
|
|
static XtCallbackRec dropStartCbRec[]= {
|
|
{DropStartCb,NULL},{NULL,NULL}
|
|
};
|
|
static XtCallbackRec dropSiteEnterCbRec[]= {
|
|
{DropSiteEnterCb,NULL},{NULL,NULL}
|
|
};
|
|
static XtCallbackRec dropSiteLeaveCbRec[]= {
|
|
{DropSiteLeaveCb,NULL},{NULL,NULL}
|
|
};
|
|
static XtCallbackRec dropFinishCbRec[]= {
|
|
{DropFinishCb,NULL},{NULL,NULL}
|
|
};
|
|
static XtCallbackRec dragDropFinishCbRec[]= {
|
|
{DragDropFinishCb,NULL},{NULL,NULL}
|
|
};
|
|
static XtCallbackRec destroyCbRec[]= {
|
|
{DestroyCb,NULL},{NULL,NULL}
|
|
};
|
|
operationChangedCbRec[0].closure=this;
|
|
dragMotionCbRec[0].closure=this;
|
|
dropStartCbRec[0].closure=this;
|
|
dropSiteEnterCbRec[0].closure=this;
|
|
dropSiteLeaveCbRec[0].closure=this;
|
|
dropFinishCbRec[0].closure=this;
|
|
dragDropFinishCbRec[0].closure=this;
|
|
destroyCbRec[0].closure=this;
|
|
|
|
Arg args[40];
|
|
int n=0;
|
|
XtSetArg(args[n],XmNexportTargets,_targets);n++;
|
|
XtSetArg(args[n],XmNnumExportTargets,_numTargets);n++;
|
|
XtSetArg(args[n],XmNclientData,(XtPointer)this);n++;
|
|
XtSetArg(args[n],XmNconvertProc,DragConvertCb);n++;
|
|
XtSetArg(args[n],XmNdragOperations,_operations);n++;
|
|
XtSetArg(args[n],XmNblendModel,XmBLEND_JUST_SOURCE);n++;
|
|
XtSetArg(args[n],XmNoperationChangedCallback,operationChangedCbRec);n++;
|
|
XtSetArg(args[n],XmNdragMotionCallback,dragMotionCbRec);n++;
|
|
XtSetArg(args[n],XmNdropStartCallback,dropStartCbRec);n++;
|
|
XtSetArg(args[n],XmNdropSiteEnterCallback,dropSiteEnterCbRec);n++;
|
|
XtSetArg(args[n],XmNdropSiteLeaveCallback,dropSiteLeaveCbRec);n++;
|
|
XtSetArg(args[n],XmNdropFinishCallback,dropFinishCbRec);n++;
|
|
XtSetArg(args[n],XmNdragDropFinishCallback,dragDropFinishCbRec);n++;
|
|
XtSetArg(args[n],XmNdestroyCallback,destroyCbRec);n++;
|
|
if (_dragIcon) {
|
|
#ifdef IRIX
|
|
#ifndef IRIX5_3
|
|
// We want the cursor colors to be black and white, but
|
|
// only IRIX Motif does the right thing with the color
|
|
// settings. Other platforms spew many X protocol errors
|
|
// from inside Xm/DragOverS.c in Motif.
|
|
//
|
|
// ifdef desired code for IRIX and let other platforms
|
|
// use default colors until we can figure out a way
|
|
// to stop the X protocol errors.
|
|
Pixel fg,bg;
|
|
|
|
// get a context
|
|
MWContext *context=fe_WidgetToMWContext(_dragWidget);
|
|
if (!context)
|
|
context=XP_GetNonGridContext(fe_all_MWContexts->context);
|
|
|
|
// extract color info
|
|
if (context) {
|
|
fg=fe_GetPixel(context,0,0,0);
|
|
bg=fe_GetPixel(context,0xff,0xff,0xff);
|
|
}
|
|
else {
|
|
XtVaGetValues(_dragWidget,XmNforeground,&fg,XmNbackground,&bg,NULL);
|
|
}
|
|
XtSetArg(args[n],XmNcursorBackground,bg);n++;
|
|
XtSetArg(args[n],XmNcursorForeground,fg);n++;
|
|
#endif
|
|
#endif
|
|
XtSetArg(args[n],XmNsourceCursorIcon,_dragIcon);n++;
|
|
}
|
|
|
|
#if 0
|
|
// This seems fixed for now.. but I'm not deleting this code just yet,
|
|
// since I don't know the who or the how of the fix.
|
|
//
|
|
// What a hack - Something in the browser menu code is causing
|
|
// the menu system to think it's active each time a new browser
|
|
// is created. This prevents any drags from working until
|
|
// the first menu pops up, then down again, resetting the
|
|
// 'userGrabbed' flag in XmDisplay.
|
|
// We will reset that flag here to make dragging work. This
|
|
// is safe, since we know that we only call XmDragStart() in
|
|
// response to a button press - which will have already deactivated
|
|
// any menu code. Cool. Now as a warm-down send a manned mission
|
|
// to Mars. Then find out why this happens in the first place!!!!
|
|
Widget xmDisplay=XmGetXmDisplay(XtDisplay(_widget));
|
|
XDEBUG(printf("XmDisplay.userGrabbed=%d\n",((XmDisplayRec*)xmDisplay)->display.userGrabbed));
|
|
((XmDisplayRec*)xmDisplay)->display.userGrabbed=0;
|
|
#endif
|
|
|
|
#ifndef DISABLE_DRAG
|
|
// check that Btn1 is still down
|
|
Window rootWin,childWin;
|
|
int rootX,rootY,childX,childY;
|
|
unsigned int buttonMask=0;
|
|
|
|
XSync(XtDisplay(_widget),FALSE);
|
|
XQueryPointer(XtDisplay(_widget),XtWindow(_widget),
|
|
&rootWin,&childWin,
|
|
&rootX,&rootY,&childX,&childY,
|
|
&buttonMask);
|
|
if (!(buttonMask & Button1Mask)) {
|
|
XDEBUG(printf("###Button1 not down - aborting drag!###\n"));
|
|
dragDropFinishCb();
|
|
return;
|
|
}
|
|
|
|
XDEBUG(printf("XmDragStart() {\n"));
|
|
_dragContext=XmDragStart(_dragWidget,(XEvent*)&_dragButtonEvent,args,n);
|
|
XDEBUG(printf("} XmDragStart()\n"));
|
|
if (_dragContext) {
|
|
_dragStarted=TRUE;
|
|
// record global active drag shell
|
|
Widget shell=_widget;
|
|
while (!XtIsShell(shell)) shell=XtParent(shell);
|
|
_activeDragShell=shell;
|
|
}
|
|
else {
|
|
XDEBUG(printf("XmDragStart() failed!\n"));
|
|
dragDropFinishCb();
|
|
return;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int XFE_DragBase::isFileURL(const char *url)
|
|
{
|
|
return (url && strlen(url)>0 &&
|
|
(XP_STRNCASECMP(url,"file:",5)==0 || XP_STRNCMP(url,"/",1)==0))
|
|
? TRUE : FALSE;
|
|
}
|
|
|
|
void XFE_DragBase::setDragIcon(struct fe_icon_data *iconData)
|
|
{
|
|
// if this is a new icon, clean up old icon data
|
|
if (_dragIconData!=iconData) {
|
|
if (_dragIconPixmap!=None) {
|
|
XFreePixmap(XtDisplay(_widget),_dragIconPixmap);
|
|
_dragIconPixmap=None;
|
|
}
|
|
if (_dragIconPixmapMask!=None) {
|
|
XFreePixmap(XtDisplay(_widget),_dragIconPixmapMask);
|
|
_dragIconPixmapMask=None;
|
|
}
|
|
}
|
|
|
|
// set up pointer, and let dragInitialize() create pixmaps
|
|
_dragIconData=iconData;
|
|
}
|
|
|
|
void XFE_DragBase::setDragIconForType(const char *dataType)
|
|
{
|
|
if (!dataType) {
|
|
setDragIcon(&GUnknown);
|
|
return;
|
|
}
|
|
|
|
if (!dataType || XP_STRCASECMP(dataType,UNKNOWN_CONTENT_TYPE)==0)
|
|
setDragIcon(&GUnknown);
|
|
else if (XP_STRCASECMP(dataType,"_url")==0) // internal type name for urls
|
|
setDragIcon(&LocationProxy);
|
|
else if (XP_STRCASECMP(dataType,"_directory")==0) // internal type name for directories
|
|
setDragIcon(&GFolder);
|
|
else if (XP_STRNCASECMP(dataType,"audio",5)==0)
|
|
setDragIcon(&GAudio);
|
|
else if (XP_STRNCASECMP(dataType,"application",11)==0)
|
|
setDragIcon(&GBinary);
|
|
else if (XP_STRNCASECMP(dataType,"image",5)==0)
|
|
setDragIcon(&GImage);
|
|
#ifdef MOZ_MAIL_NEWS
|
|
else if (XP_STRNCASECMP(dataType,"message",7)==0)
|
|
setDragIcon(&MNTB_Forward);
|
|
else if (XP_STRCASECMP(dataType,"text/x-vcard")==0)
|
|
setDragIcon(&MNAB_NewPerson);
|
|
#endif
|
|
else if (XP_STRNCASECMP(dataType,"text",4)==0)
|
|
setDragIcon(>ext);
|
|
else if (XP_STRNCASECMP(dataType,"video",5)==0)
|
|
setDragIcon(&GMovie);
|
|
else
|
|
setDragIcon(&GUnknown);
|
|
}
|
|
|
|
|
|
//
|
|
// default drag virtual methods - derived class can override
|
|
//
|
|
|
|
// drag string data by default
|
|
void XFE_DragBase::targets()
|
|
{
|
|
_numTargets=1;
|
|
_targets=new Atom[_numTargets];
|
|
|
|
_targets[0]=XA_STRING;
|
|
}
|
|
|
|
// allow move or copy by default
|
|
void XFE_DragBase::operations()
|
|
{
|
|
_operations=(unsigned int)(XmDROP_MOVE | XmDROP_COPY);
|
|
}
|
|
|
|
|
|
// provide data for requested target from targets() list
|
|
char *XFE_DragBase::getTargetData(Atom target)
|
|
{
|
|
// WARNING - data *must* be allocated with Xt malloc API, or Xt
|
|
// will spring a leak!
|
|
|
|
if (target==XA_STRING) {
|
|
return (char*)XtNewString("Netscape 4.0 Default Drag Data");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void XFE_DragBase::deleteTarget()
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::deleteTarget()\n"));
|
|
}
|
|
|
|
//
|
|
// button event handler methods
|
|
//
|
|
|
|
extern "C" void fe_HTMLDragSetLayer(CL_Layer *layer);
|
|
|
|
void XFE_DragBase::buttonPressCb(XButtonPressedEvent *event)
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::buttonPressCb(%d,%d)\n",event->x,event->y));
|
|
|
|
// Hack: Clear global HTMLView drag layer before button event is processed by XFE_HTMLView
|
|
fe_HTMLDragSetLayer(NULL);
|
|
|
|
// nyi - for now, don't lock out drags when Motif gets confused
|
|
_dragStarted=FALSE;
|
|
|
|
// one at a time please..
|
|
if (_dragStarted)
|
|
return;
|
|
|
|
_buttonPressed=TRUE;
|
|
_dragStartX=event->x;
|
|
_dragStartY=event->y;
|
|
_dragEventX=_dragStartX;
|
|
_dragEventY=_dragStartY;
|
|
|
|
// gross - copy button event for later use by XmDragStart
|
|
// Note: Motif should allow Motion event in XmDragStart, docs
|
|
// say Yes, but the Xm code disagrees - only ButtonPress is accepted.
|
|
_dragButtonEvent=*event;
|
|
|
|
// if there's no threshold, start drag immediately
|
|
if (_dragThreshold==0) {
|
|
dragInitialize();
|
|
_buttonPressed=FALSE; // reset the trigger
|
|
}
|
|
|
|
}
|
|
|
|
int XFE_DragBase::buttonMotionCb(XMotionEvent *event)
|
|
{
|
|
// steal event if we're already dragging
|
|
if (_dragStarted)
|
|
return FALSE;
|
|
|
|
// pass through event if we're not dragging
|
|
if (!_buttonPressed)
|
|
return TRUE;
|
|
|
|
XDEBUG(printf("XFE_DragBase::buttonMotionCb(%d,%d)\n",event->x,event->y));
|
|
|
|
if (abs(_dragStartX-event->x)>=_dragThreshold ||
|
|
abs(_dragStartY-event->y)>=_dragThreshold) {
|
|
dragInitialize();
|
|
_buttonPressed=FALSE; // reset the trigger
|
|
}
|
|
|
|
// steal event - user might be starting a drag
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// drag callbacks
|
|
//
|
|
|
|
Boolean XFE_DragBase::dragConvertCb(Atom *target,Atom *type,XtPointer *value,
|
|
unsigned long *length,int *format)
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::dragConvertCb(%s)\n",XmGetAtomName(XtDisplay(_widget),*target)));
|
|
|
|
// TARGETS - our targets, plus ICCCM standard targets
|
|
if (*target==_XA_TARGETS) {
|
|
// create targets list - freed by Xt selection API
|
|
Atom *targetData=(Atom*)XtMalloc((unsigned)((_numTargets+4)*sizeof(Atom)));
|
|
int i;
|
|
for(i=0;i<_numTargets;i++)
|
|
targetData[i]=_targets[i];
|
|
targetData[i++]=_XA_DELETE;
|
|
targetData[i++]=_XA_TARGETS;
|
|
targetData[i++]=_XA_MULTIPLE; // provided by Xt
|
|
targetData[i++]=_XA_TIMESTAMP; // provided by Xt
|
|
|
|
// return ICCCM targets list
|
|
*value=(XtPointer)targetData;
|
|
*type=XA_ATOM;
|
|
*length=_numTargets+4;
|
|
*format=32;
|
|
return TRUE;
|
|
}
|
|
|
|
// DELETE
|
|
if (*target==_XA_DELETE) {
|
|
// handle delete request for dragged object
|
|
deleteTarget();
|
|
|
|
// return ICCCM acknowledgement of delete
|
|
*value=NULL;
|
|
*type=_XA_NULL;
|
|
*length=0;
|
|
*format=8;
|
|
return TRUE;
|
|
}
|
|
|
|
// is it a request for the data as a desktop file?
|
|
if (isFileTarget(*target)) {
|
|
// write drag data in appropriate desktop file format, return filenames
|
|
// DragBase does not handle files - methods are provided by derived class.
|
|
// (but this is easier than adding yet another chained virtual method..)
|
|
getTargetDataAsFileWrapper(*target,value,length);
|
|
if (*value && *length>0) {
|
|
if (*target==_XA_FILE_NAME)
|
|
*type=XA_STRING;
|
|
else
|
|
*type=*target;
|
|
*format=8;
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// All other targets - ask derived class method for data string
|
|
if ((*value=(XtPointer)getTargetData(*target))!=NULL) {
|
|
*type=*target;
|
|
*length=strlen((char*)*value);
|
|
*format=8;
|
|
#if defined(DEBUG_tao)
|
|
printf("\nXFE_DragBase::dragConvertCb:value=%x,target=%d,length=%d\n",
|
|
*value, *target, *length);
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Can't provide data for requested target
|
|
return FALSE;
|
|
}
|
|
|
|
void XFE_DragBase::operationChangedCb()
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::operationChangedCb()\n"));
|
|
}
|
|
|
|
void XFE_DragBase::dragMotionCb()
|
|
{
|
|
//XDEBUG(printf("XFE_DragBase::dragMotionCb()\n"));
|
|
}
|
|
|
|
void XFE_DragBase::dropStartCb()
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::dropStartCb()\n"));
|
|
}
|
|
|
|
void XFE_DragBase::dropSiteEnterCb(int operations)
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::dropSiteEnterCb()\n"));
|
|
if (_dragFilesAsLinks && (operations & XmDROP_LINK)) {
|
|
XtVaSetValues(_dragContext,XmNdragOperations,XmDROP_LINK,NULL);
|
|
}
|
|
}
|
|
|
|
void XFE_DragBase::dropSiteLeaveCb()
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::dropSiteLeaveCb()\n"));
|
|
if (_dragFilesAsLinks)
|
|
XtVaSetValues(_dragContext,XmNdragOperations,_operations|XmDROP_LINK,NULL);
|
|
}
|
|
|
|
void XFE_DragBase::dropFinishCb()
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::dropFinishCb()\n"));
|
|
}
|
|
|
|
void XFE_DragBase::dragDropFinishCb()
|
|
{
|
|
XDEBUG(printf("XFE_DragBase::dragDropFinishCb()\n"));
|
|
|
|
dragComplete();
|
|
|
|
// destroy drag icon widget
|
|
if (_dragIcon) {
|
|
XtDestroyWidget(_dragIcon);
|
|
_dragIcon=NULL;
|
|
}
|
|
|
|
// delete targets list
|
|
|
|
if (_targets) {
|
|
delete [] _targets;
|
|
_targets=NULL;
|
|
_numTargets=0;
|
|
}
|
|
|
|
// reset drag data
|
|
|
|
_operations=0;
|
|
_dragWidget=NULL;
|
|
_dragContext=NULL;
|
|
_dragStarted=FALSE;
|
|
_dragStartX=0;
|
|
_dragStartY=0;
|
|
_dragEventX=0;
|
|
_dragEventY=0;
|
|
_activeDragShell=NULL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// XFE_DragDesktop
|
|
//
|
|
// app specifies dragging type via targets()
|
|
// if request comes in for file:
|
|
// determine actual type from targets()
|
|
// call getTargetData() for actual type
|
|
// create tmp file in correct format
|
|
// return SGI_ICON/SGI_FILE/FILENAME as needed
|
|
// delete file when drop compete (assume force a file copy)
|
|
// DELETE still means delete data in Netscape, not file
|
|
|
|
XFE_DragDesktop::XFE_DragDesktop(Widget w) : XFE_DragBase(w)
|
|
{
|
|
_fileTarget=None;
|
|
}
|
|
|
|
XFE_DragDesktop::~XFE_DragDesktop()
|
|
{
|
|
}
|
|
|
|
void XFE_DragDesktop::setFileTarget(Atom target)
|
|
{
|
|
if (!_targets || _numTargets==0)
|
|
return;
|
|
|
|
_fileTarget=target;
|
|
|
|
// insert desktop file dnd atoms into list
|
|
// must insert before generic STRING - some desktops (IRIX 6.3+)
|
|
// will treat STRING drop as a paste-to-new-file action.
|
|
Atom *newTargets=new Atom[_numTargets+4];
|
|
int i=0;
|
|
int ni=0;
|
|
int added=FALSE;
|
|
while (i<_numTargets) {
|
|
if (_targets[i]==XA_STRING) {
|
|
newTargets[ni++]=_XA_SGI_ICON_TYPE;
|
|
newTargets[ni++]=_XA_SGI_ICON;
|
|
newTargets[ni++]=_XA_SGI_FILE;
|
|
newTargets[ni++]=_XA_FILE_NAME;
|
|
added=TRUE;
|
|
}
|
|
newTargets[ni++]=_targets[i++];
|
|
}
|
|
if (!added) {
|
|
// no STRING in targets list, so append
|
|
newTargets[ni++]=_XA_SGI_ICON_TYPE;
|
|
newTargets[ni++]=_XA_SGI_ICON;
|
|
newTargets[ni++]=_XA_SGI_FILE;
|
|
newTargets[ni++]=_XA_FILE_NAME;
|
|
}
|
|
|
|
delete [] _targets;
|
|
_targets=newTargets;
|
|
_numTargets=ni;
|
|
}
|
|
|
|
|
|
int XFE_DragDesktop::isFileTarget(Atom target)
|
|
{
|
|
return (target==_XA_SGI_ICON ||
|
|
target==_XA_SGI_ICON_TYPE ||
|
|
target==_XA_SGI_FILE ||
|
|
target==_XA_FILE_NAME)
|
|
? TRUE : FALSE;
|
|
}
|
|
|
|
void XFE_DragDesktop::getTargetDataAsFileWrapper(Atom target, XtPointer *value, unsigned long *length)
|
|
{
|
|
// create files for data and return desktop formatted description of files.
|
|
|
|
*value=NULL;
|
|
*length=0;
|
|
|
|
XDEBUG(printf("XFE_DragDesktop::getTargetDataAsFileWrapper(%s)\n",XmGetAtomName(XtDisplay(_widget),target)));
|
|
|
|
if (_fileTarget==None)
|
|
return;
|
|
|
|
// return type for desktop feedback during drag
|
|
if (target==_XA_SGI_ICON_TYPE) {
|
|
const char *ftrType=getTargetFTRType(_fileTarget);
|
|
if (ftrType) {
|
|
*value=(XtPointer)XtNewString(ftrType);
|
|
*length=strlen(ftrType);
|
|
}
|
|
else {
|
|
*value=NULL;
|
|
*length=0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// get data as list of files
|
|
// (usually one file per selected item, but it's up to derived class)
|
|
char **fileList=NULL;
|
|
int numFiles=0;
|
|
getTargetDataAsFileList(_fileTarget,&fileList,&numFiles);
|
|
|
|
if (!fileList || numFiles==0)
|
|
return;
|
|
|
|
const char *ftrType=getTargetFTRType(_fileTarget);
|
|
const char SGI_ICON_FORMAT[] =
|
|
"Category:%s Name:%s Type:%s Host:%s ViewX:%d ViewY:%d ViewGallery:%d";
|
|
int i;
|
|
int fileDataSize=0;
|
|
// calculate space needed for formatted file list
|
|
for (i=0;i<numFiles;i++)
|
|
if (fileList[i]) fileDataSize+=strlen(fileList[i])+1;
|
|
if (target==_XA_SGI_ICON)
|
|
fileDataSize+=numFiles*(strlen(SGI_ICON_FORMAT)+
|
|
strlen(ftrType)+
|
|
strlen(localHostName)+
|
|
50); // format string space plus ViewX,ViewY,ViewGallery + final \0
|
|
else
|
|
fileDataSize+=1; // + final \0
|
|
|
|
// copy file list to value in appropriate format
|
|
char *fileData=XtMalloc(fileDataSize);
|
|
unsigned long fileDataLength=0;
|
|
char *curPos=fileData;
|
|
for (i=0;i<numFiles;i++) {
|
|
if (target==_XA_SGI_ICON) {
|
|
// nyi - tune values for ViewX,ViewY s.t. drop of icon looks right
|
|
// nyi - do we need to tweak ViewX,ViewY for multiple item drops? (orientation,spacing)
|
|
sprintf(curPos,SGI_ICON_FORMAT,"File",fileList[i],ftrType,localHostName,
|
|
-10,-10,0);
|
|
}
|
|
else {
|
|
strcpy(curPos,fileList[i]);
|
|
}
|
|
int segmentLen=strlen(curPos)+1;
|
|
fileDataLength+=segmentLen;
|
|
curPos+=segmentLen;
|
|
}
|
|
*curPos='\0'; // terminate with extra \0
|
|
fileDataLength++;
|
|
|
|
// free file list
|
|
for (i=0;i<numFiles;i++)
|
|
if (fileList[i]) XP_FREE(fileList[i]);
|
|
delete fileList;
|
|
|
|
*value=(XtPointer)fileData;
|
|
*length=fileDataLength;
|
|
}
|
|
|
|
|
|
void XFE_DragDesktop::getTargetDataAsFileList(Atom,char ***fileList,int *numFiles)
|
|
{
|
|
*fileList=NULL;
|
|
*numFiles=0;
|
|
return;
|
|
}
|
|
|
|
const char *XFE_DragDesktop::getTargetFTRType(Atom)
|
|
{
|
|
return DEFAULT_FTR_TYPE;
|
|
}
|
|
|
|
void XFE_DragDesktop::dragDropFinishCb()
|
|
{
|
|
XDEBUG(printf("XFE_DragDesktop::dragDropFinishCb()\n"));
|
|
|
|
XFE_DragBase::dragDropFinishCb();
|
|
|
|
// reset drag data
|
|
_fileTarget=None;
|
|
}
|
|
|
|
|
|
//
|
|
// XFE_DragNetscape
|
|
// - provide support for all Netsape drag types
|
|
// and their conversion to a desktop file format. No actual
|
|
// drag targets are specified by this class. Derived class
|
|
// must specify targets(), operations() and getTargetData()
|
|
//
|
|
|
|
XFE_DragNetscape::XFE_DragNetscape(Widget w) : XFE_DragDesktop(w)
|
|
{
|
|
_desktopFileData=NULL;
|
|
}
|
|
|
|
XFE_DragNetscape::~XFE_DragNetscape()
|
|
{
|
|
if (_desktopFileData) {
|
|
_desktopFileData->cleanupDataFiles();
|
|
delete _desktopFileData;
|
|
_desktopFileData=NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void XFE_DragNetscape::getTargetDataAsFileList(Atom target,char ***fileList,int *numFiles)
|
|
{
|
|
*numFiles=0;
|
|
*fileList=NULL;
|
|
|
|
if (_desktopFileData!=NULL) {
|
|
// make sure we only have one set of tmp files per drag
|
|
// (dumb or malicious drop site might ask for FILE_NAME and _SGI_ICON)
|
|
return;
|
|
}
|
|
|
|
XDEBUG(printf("XFE_DragNetscape::getTargetDataAsFileList(%s)\n",XmGetAtomName(XtDisplay(_widget),target)));
|
|
|
|
// XA_STRING - interpret data as name of existing file
|
|
if (target==XA_STRING) {
|
|
char *filename=getTargetData(XA_STRING);
|
|
if (filename) {
|
|
*numFiles=1;
|
|
*fileList=new char*[1];
|
|
(*fileList)[0]=filename;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// XA_FILE_NAME - interpret data as name of existing file
|
|
if (target==_XA_FILE_NAME) {
|
|
char *filename=getTargetData(_XA_FILE_NAME);
|
|
if (filename) {
|
|
*numFiles=1;
|
|
*fileList=new char*[1];
|
|
(*fileList)[0]=filename;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// _XA_NETSCAPE_URL - translate data into NetscapeURL desktop file(s)
|
|
if (target==_XA_NETSCAPE_URL) {
|
|
char *stringData=getTargetData(_XA_NETSCAPE_URL);
|
|
if (!stringData)
|
|
return;
|
|
|
|
XFE_URLDesktopType *urlData=new XFE_URLDesktopType(stringData);
|
|
*numFiles=urlData->numItems();
|
|
if (*numFiles==0) {
|
|
delete urlData;
|
|
XtFree(stringData);
|
|
return;
|
|
}
|
|
|
|
|
|
// write files to tmp directory
|
|
urlData->writeDataFiles(_dragFilesAsLinks);
|
|
|
|
|
|
// extract filenames of tmp files for drag response
|
|
*fileList=new char*[*numFiles];
|
|
int i;
|
|
for (i=0;i<*numFiles;i++) {
|
|
if (urlData->filename(i))
|
|
(*fileList)[i]=XP_STRDUP(urlData->filename(i));
|
|
else
|
|
(*fileList)[i]=NULL;
|
|
}
|
|
|
|
// save desktop tmp file data for cleanup at end of drag
|
|
_desktopFileData=(XFE_DesktopType*)urlData;
|
|
|
|
XtFree(stringData);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
const char *XFE_DragNetscape::getTargetFTRType(Atom target)
|
|
{
|
|
if (target==_XA_NETSCAPE_URL) return XFE_URLDesktopType::ftrType();
|
|
|
|
return DEFAULT_FTR_TYPE;
|
|
}
|
|
|
|
|
|
void XFE_DragNetscape::dragDropFinishCb()
|
|
{
|
|
XFE_DragDesktop::dragDropFinishCb();
|
|
|
|
// cleanup temporary directory and files used for Netscape data
|
|
if (_desktopFileData) {
|
|
_desktopFileData->cleanupDataFiles();
|
|
delete _desktopFileData;
|
|
_desktopFileData=NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// XFE_DropBase
|
|
//
|
|
|
|
//
|
|
// callback stubs
|
|
//
|
|
|
|
void XFE_DropBase::DragProc(Widget w, XtPointer,XtPointer cb)
|
|
{
|
|
XtPointer ud;
|
|
XtVaGetValues(w,XmNuserData,&ud,NULL);
|
|
XFE_DropBase *d=(XFE_DropBase*)ud;
|
|
if (d)
|
|
d->dragProc((XmDragProcCallbackStruct*)cb);
|
|
}
|
|
|
|
|
|
void XFE_DropBase::DropProc(Widget w,XtPointer,XtPointer cb) {
|
|
XtPointer ud;
|
|
XtVaGetValues(w,XmNuserData,&ud,NULL);
|
|
XFE_DropBase *d=(XFE_DropBase*)ud;
|
|
if (d)
|
|
d->dropProc((XmDropProcCallbackStruct*)cb);
|
|
}
|
|
|
|
void XFE_DropBase::DestroyCb(Widget,XtPointer cd,XtPointer) {
|
|
XFE_DropBase *d=(XFE_DropBase*)cd;
|
|
if (d)
|
|
d->dropComplete();
|
|
}
|
|
|
|
void XFE_DropBase::TransferProc(Widget w, XtPointer cd, Atom */*seltype*/, Atom *type,
|
|
XtPointer value, unsigned long *length, int */*format*/)
|
|
{
|
|
#if defined(DEBUG_tao)
|
|
printf("\nXFE_DropBase::TransferProc, value=%x\n", value);
|
|
#endif
|
|
XFE_DropBase *d=(XFE_DropBase*)cd;
|
|
if (d)
|
|
d->transferProc(w,*type,value,(unsigned int)*length);
|
|
}
|
|
|
|
|
|
// constructor
|
|
|
|
XFE_DropBase::XFE_DropBase(Widget widget)
|
|
{
|
|
_widget=widget;
|
|
_operations=(unsigned int)XmDROP_NOOP;
|
|
_targets=NULL;
|
|
_numTargets=0;
|
|
_dropEventX=0;
|
|
_dropEventY=0;
|
|
_chosenTarget=None;
|
|
|
|
InitializeDisplayInfo(widget);
|
|
|
|
// create drop site, disabled by default
|
|
#ifdef DROP_ENABLED
|
|
Arg args[20];
|
|
int n=0;
|
|
XtSetArg(args[n],XmNdragProc,DragProc); n++;
|
|
XtSetArg(args[n],XmNdropProc,DropProc); n++;
|
|
XtSetArg(args[n],XmNdropSiteActivity,XmDROP_SITE_INACTIVE);n++;
|
|
XtSetArg(args[n],XmNdropSiteType,XmDROP_SITE_COMPOSITE);n++;
|
|
|
|
XmDropSiteRegister(_widget, args, n);
|
|
#endif
|
|
// make XFE_DropBase available to DragProc, DropProc
|
|
XtVaSetValues(widget,XmNuserData,this,NULL);
|
|
|
|
// initialize destroy callback struct
|
|
_destroyCbList[0].callback=DestroyCb;
|
|
_destroyCbList[0].closure=(XtPointer)this;
|
|
_destroyCbList[1].callback=NULL;
|
|
_destroyCbList[1].closure=NULL;
|
|
}
|
|
|
|
|
|
// destructor
|
|
|
|
XFE_DropBase::~XFE_DropBase()
|
|
{
|
|
#ifdef DROP_ENABLED
|
|
//
|
|
// Don't do this, because XmDropSiteRegister() sets up a destroy
|
|
// callback that does this (well the equivelent). If it's called twice,
|
|
// we crash in _XmIEndUpdate()....djw
|
|
#if 0
|
|
if (_widget)
|
|
XmDropSiteUnregister(_widget);
|
|
#endif
|
|
#endif
|
|
freeTargetList();
|
|
}
|
|
|
|
// convenience fn - allow easy cleanup of old targets
|
|
|
|
void XFE_DropBase::freeTargetList()
|
|
{
|
|
if (_targets) {
|
|
delete [] _targets;
|
|
_targets=NULL;
|
|
}
|
|
_numTargets=0;
|
|
}
|
|
|
|
|
|
// drop site management
|
|
|
|
void XFE_DropBase::enable()
|
|
{
|
|
// enable site
|
|
#ifdef DROP_ENABLED
|
|
Arg args[1];
|
|
XtSetArg(args[0],XmNdropSiteActivity,XmDROP_SITE_ACTIVE);
|
|
XmDropSiteUpdate(_widget,args,1);
|
|
#endif
|
|
// set targets and operations
|
|
// (can't do it in constructor because targets() and operations() are virtual)
|
|
update();
|
|
}
|
|
|
|
|
|
void XFE_DropBase::disable()
|
|
{
|
|
#ifdef DROP_ENABLED
|
|
Arg args[1];
|
|
XtSetArg(args[0],XmNdropSiteActivity,XmDROP_SITE_INACTIVE);
|
|
XmDropSiteUpdate(_widget,args,1);
|
|
#endif
|
|
}
|
|
|
|
void XFE_DropBase::update()
|
|
{
|
|
// allow derived class to change attributes
|
|
operations();
|
|
freeTargetList();
|
|
targets();
|
|
|
|
// apply changes to drop site
|
|
#ifdef DROP_ENABLED
|
|
Arg args[20];
|
|
int n=0;
|
|
XtSetArg(args[n], XmNimportTargets, _targets); n++;
|
|
XtSetArg(args[n], XmNnumImportTargets, _numTargets); n++;
|
|
XtSetArg(args[n], XmNdropSiteOperations, _operations); n++;
|
|
XmDropSiteUpdate(_widget,args,n);
|
|
#endif
|
|
}
|
|
|
|
void XFE_DropBase::update(ArgList args,Cardinal n)
|
|
{
|
|
// apply target/operation changes to drop site
|
|
update();
|
|
|
|
// apply user defined changes to drop site
|
|
#ifdef DROP_ENABLED
|
|
XmDropSiteUpdate(_widget,args,n);
|
|
#endif
|
|
|
|
}
|
|
|
|
// override to set _operations
|
|
|
|
void XFE_DropBase::operations()
|
|
{
|
|
_operations=(unsigned int) (XmDROP_MOVE | XmDROP_COPY);
|
|
}
|
|
|
|
// override to set _targets
|
|
|
|
void XFE_DropBase::targets()
|
|
{
|
|
freeTargetList();
|
|
|
|
_numTargets=1;
|
|
_targets=new Atom[_numTargets];
|
|
|
|
_targets[0]=XA_STRING;
|
|
}
|
|
|
|
// override to add drag-in feature
|
|
void XFE_DropBase::dragIn()
|
|
{
|
|
XDEBUG(printf("XFE_DropBase::dragIn(%d,%d)\n",_dropEventX,_dropEventY));
|
|
}
|
|
|
|
// override to add drag-out feature
|
|
|
|
void XFE_DropBase::dragOut()
|
|
{
|
|
XDEBUG(printf("XFE_DropBase::dragOut(%d,%d)\n",_dropEventX,_dropEventY));
|
|
}
|
|
|
|
// override to add drag-motion feature
|
|
void XFE_DropBase::dragMotion()
|
|
{
|
|
// XDEBUG(printf("XFE_DropBase::dragMotion(%d,%d)\n",_dropEventX,_dropEventY));
|
|
}
|
|
|
|
// override to add operation-changed feature
|
|
|
|
void XFE_DropBase::operationChanged()
|
|
{
|
|
}
|
|
|
|
// override to add validation of drop targets
|
|
|
|
Atom XFE_DropBase::acceptDrop(unsigned int dropOperation,Atom *dropTargets,unsigned int numDropTargets)
|
|
{
|
|
// pick first matching target in class's list, if operation is valid
|
|
|
|
if (!(dropOperation & _operations))
|
|
return None;
|
|
|
|
Atom selected=None;
|
|
|
|
XDEBUG(printf("TARGETS:\n"));
|
|
#if defined(DEBUG_tao)
|
|
printf("\nXFE_DropBase::acceptDrop\n");
|
|
for (int ii=0; ii < _numTargets; ii++)
|
|
printf("\n_targets[%d]=%s",
|
|
ii, XGetAtomName(XtDisplay(_widget),_targets[ii]));
|
|
for (int jj=0; jj < numDropTargets; jj++)
|
|
printf("\ndropTargets[%d]=%s",
|
|
jj, XGetAtomName(XtDisplay(_widget),dropTargets[jj]));
|
|
#endif
|
|
for (int i=0;i<_numTargets; i++) {
|
|
for (int j=0; j < (int)numDropTargets; j++) {
|
|
XDEBUG(if (i==0) printf(" %s\n",XGetAtomName(XtDisplay(_widget),dropTargets[j])));
|
|
if (_targets[i]==dropTargets[j]) {
|
|
selected=dropTargets[j];
|
|
break;
|
|
}
|
|
}
|
|
if (selected!=None)
|
|
break;
|
|
}
|
|
|
|
return selected;
|
|
}
|
|
|
|
|
|
// override to tidy up after drop
|
|
|
|
void XFE_DropBase::dropComplete()
|
|
{
|
|
}
|
|
|
|
// callback methods
|
|
|
|
void XFE_DropBase::dragProc(XmDragProcCallbackStruct *cb)
|
|
{
|
|
// record location of drop:
|
|
_dropEventX=cb->x;
|
|
_dropEventY=cb->y;
|
|
|
|
switch(cb->reason) {
|
|
case XmCR_DROP_SITE_ENTER_MESSAGE:
|
|
// verify that this combo of operation and targets is acceptable
|
|
if (cb->operation!=XmDROP_NOOP &&
|
|
acceptDropWrapper(cb->operation,cb->dragContext)!=None) {
|
|
cb->dropSiteStatus = XmVALID_DROP_SITE;
|
|
dragIn();
|
|
}
|
|
else {
|
|
cb->dropSiteStatus = XmINVALID_DROP_SITE;
|
|
}
|
|
break;
|
|
case XmCR_DROP_SITE_LEAVE_MESSAGE:
|
|
dragOut();
|
|
break;
|
|
case XmCR_DROP_SITE_MOTION_MESSAGE:
|
|
dragMotion();
|
|
break;
|
|
case XmCR_OPERATION_CHANGED:
|
|
operationChanged();
|
|
break;
|
|
default:
|
|
cb->dropSiteStatus = XmINVALID_DROP_SITE;
|
|
break;
|
|
}
|
|
|
|
// allow animation to be performed
|
|
cb->animate = True;
|
|
}
|
|
|
|
|
|
|
|
void XFE_DropBase::dropProc(XmDropProcCallbackStruct *cb)
|
|
{
|
|
if (cb->dropAction != XmDROP_HELP) {
|
|
handleDrop(cb);
|
|
}
|
|
else {
|
|
// option to display help dialog - we just cancel drag
|
|
Arg args[10];
|
|
int n=0;
|
|
cb->dropSiteStatus=XmINVALID_DROP_SITE;
|
|
XtSetArg(args[n],XmNtransferStatus,XmTRANSFER_FAILURE); n++;
|
|
XtSetArg(args[n],XmNnumDropTransfers,0); n++;
|
|
XmDropTransferStart(cb->dragContext,args,n);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void XFE_DropBase::handleDrop(XmDropProcCallbackStruct *cb)
|
|
{
|
|
Arg args[10];
|
|
int n;
|
|
|
|
// record location of drop:
|
|
_dropEventX=cb->x;
|
|
_dropEventY=cb->y;
|
|
|
|
// Cancel the drop on invalid drop operations
|
|
|
|
if (cb->operation==XmDROP_NOOP) {
|
|
n = 0;
|
|
cb->dropSiteStatus = XmINVALID_DROP_SITE;
|
|
XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
|
|
XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
|
|
XmDropTransferStart(cb->dragContext, args, n);
|
|
return;
|
|
}
|
|
|
|
// select target based on operation and available targets
|
|
// (remember chosen target for use later in tranfer proc. naughty
|
|
// CDE file mgr doesn't give the target it was asked for.)
|
|
|
|
_chosenTarget=acceptDropWrapper(cb->operation,cb->dragContext);
|
|
|
|
if (_chosenTarget==None) { // transfer not valid
|
|
n = 0;
|
|
cb->operation = (unsigned char)XmDROP_NOOP;
|
|
cb->dropSiteStatus = XmINVALID_DROP_SITE;
|
|
XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
|
|
XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
|
|
XmDropTransferStart(cb->dragContext, args, n);
|
|
return;
|
|
}
|
|
|
|
// start transfer
|
|
|
|
XmDropTransferEntryRec transfers[2];
|
|
Cardinal numTransfers = 1;
|
|
transfers[0].target = _chosenTarget;
|
|
transfers[0].client_data=(XtPointer)this;
|
|
|
|
// send DELETE to drag source if this is a move
|
|
if (cb->operation == XmDROP_MOVE) {
|
|
transfers[1].target=_XA_DELETE;
|
|
transfers[1].client_data=(XtPointer)this;
|
|
numTransfers+=1;
|
|
}
|
|
|
|
|
|
n = 0;
|
|
cb->dropSiteStatus = XmVALID_DROP_SITE;
|
|
XtSetArg(args[n], XmNdropTransfers, transfers); n++;
|
|
XtSetArg(args[n], XmNnumDropTransfers, numTransfers); n++;
|
|
XtSetArg(args[n], XmNdestroyCallback, _destroyCbList); n++;
|
|
XtSetArg(args[n], XmNtransferProc, TransferProc); n++;
|
|
XmDropTransferStart(cb->dragContext, args, n);
|
|
}
|
|
|
|
|
|
void XFE_DropBase::transferProc(Widget dragContext,Atom type, XtPointer value,unsigned int length)
|
|
{
|
|
// transfer data via dropTransfer()
|
|
|
|
XDEBUG(printf("XFE_DropBase::transferProc(%s)\n",type ? XmGetAtomName(XtDisplay(_widget),type):"(null)"));
|
|
|
|
// check for response to a DELETE message - no action required
|
|
if (type==None || type==_XA_NULL) {
|
|
return;
|
|
}
|
|
|
|
if (value && length>0) {
|
|
if (isFileTarget(_chosenTarget) &&
|
|
(type==_chosenTarget || type==XA_STRING)) {
|
|
// process file targets in XFE_DropDesktop
|
|
// (test for XA_STRING is a hack to deal with CDE 1.0 bug, where
|
|
// dtfile returns STRING data in response to request for FILE_NAME.)
|
|
if (processFileTargetWrapper(_chosenTarget,value,length))
|
|
return; // success
|
|
}
|
|
else {
|
|
// package up item into drop list and pass to derived class method
|
|
Atom *targets=new Atom[1];
|
|
const char **dropData=new const char*[1];
|
|
char *dropInfo=new char[length+1];
|
|
memcpy(dropInfo,(char*)value,length);
|
|
dropInfo[length]='\0';
|
|
targets[0]=type;
|
|
dropData[0]=dropInfo;
|
|
int dropStatus=processTargets(targets,dropData,1);
|
|
delete [] targets;
|
|
delete dropData;
|
|
delete dropInfo;
|
|
|
|
if (dropStatus)
|
|
return; // success
|
|
}
|
|
}
|
|
else {
|
|
// transfer failed
|
|
XtVaSetValues(dragContext,
|
|
XmNtransferStatus, XmTRANSFER_FAILURE,
|
|
XmNnumDropTransfers, 0,
|
|
NULL);
|
|
}
|
|
|
|
// nyi - is this right? doesn't Xt/Xm free this?, why not free above?
|
|
if (value)
|
|
XtFree((char*)value);
|
|
}
|
|
|
|
// wrapper around virtual function acceptDrop()
|
|
// (hide Motif cruft from dervived class)
|
|
|
|
Atom XFE_DropBase::acceptDropWrapper(unsigned int op,Widget dragContext)
|
|
{
|
|
Atom *exportTargets=NULL;
|
|
Cardinal numExportTargets=0;
|
|
XtVaGetValues(dragContext,
|
|
XmNexportTargets, &exportTargets,
|
|
XmNnumExportTargets, &numExportTargets,
|
|
NULL);
|
|
if (exportTargets && numExportTargets>0)
|
|
return acceptDrop(op,exportTargets,numExportTargets);
|
|
else
|
|
return None;
|
|
}
|
|
|
|
|
|
//
|
|
// XFE_DropDesktop
|
|
//
|
|
|
|
// constructor
|
|
|
|
XFE_DropDesktop::XFE_DropDesktop(Widget widget) : XFE_DropBase(widget)
|
|
{
|
|
}
|
|
|
|
|
|
// destructor
|
|
|
|
XFE_DropDesktop::~XFE_DropDesktop()
|
|
{
|
|
}
|
|
|
|
//
|
|
// methods below override XFE_DropBase defaults
|
|
//
|
|
|
|
// desktop file types we understand
|
|
int XFE_DropDesktop::isFileTarget(Atom target)
|
|
{
|
|
return (target==_XA_SGI_ICON ||
|
|
target==_XA_SGI_FILE ||
|
|
target==_XA_SGI_URL ||
|
|
target==_XA_FILE_NAME)
|
|
? TRUE : FALSE;
|
|
}
|
|
|
|
void XFE_DropDesktop::acceptFileTargets()
|
|
{
|
|
if (!_targets || _numTargets==0)
|
|
return;
|
|
|
|
// insert desktop file dnd atoms into list
|
|
// must insert before generic STRING - some desktops (IRIX 6.3+)
|
|
// will provide filename or URL as STRING - we want all the info
|
|
Atom *newTargets=new Atom[_numTargets+5];
|
|
int i=0;
|
|
int ni=0;
|
|
int added=FALSE;
|
|
while (i<_numTargets) {
|
|
if (_targets[i]==XA_STRING) {
|
|
newTargets[ni++]=_XA_SGI_URL;
|
|
newTargets[ni++]=_XA_SGI_ICON;
|
|
newTargets[ni++]=_XA_SGI_FILE;
|
|
newTargets[ni++]=_XA_FILE_NAME;
|
|
newTargets[ni++]=_XA_TARGETS; // debugging hack - force display of all targets
|
|
added=TRUE;
|
|
}
|
|
newTargets[ni++]=_targets[i++];
|
|
}
|
|
if (!added) {
|
|
// no STRING in targets list, so append
|
|
newTargets[ni++]=_XA_SGI_URL;
|
|
newTargets[ni++]=_XA_SGI_ICON;
|
|
newTargets[ni++]=_XA_SGI_FILE;
|
|
newTargets[ni++]=_XA_FILE_NAME;
|
|
newTargets[ni++]=_XA_TARGETS; // debugging hack - force display of all targets
|
|
}
|
|
|
|
delete [] _targets;
|
|
_targets=newTargets;
|
|
_numTargets=ni;
|
|
}
|
|
|
|
// process dropped data
|
|
|
|
int XFE_DropDesktop::processFileTargetWrapper(Atom type,XtPointer value,unsigned int length)
|
|
{
|
|
if (!value || length==0)
|
|
return FALSE;
|
|
|
|
int dropStatus=FALSE;
|
|
|
|
char *dropInfo=new char[length+1];
|
|
memcpy(dropInfo,(char*)value,length);
|
|
dropInfo[length]='\0';
|
|
|
|
if (type==_XA_SGI_URL)
|
|
dropStatus=processSGI_URL(dropInfo,length);
|
|
else if (type==_XA_SGI_FILE)
|
|
dropStatus=processFILE_NAME(dropInfo,length);
|
|
else if (type==_XA_SGI_ICON)
|
|
dropStatus=processSGI_ICON(dropInfo,length);
|
|
else if (type==_XA_FILE_NAME)
|
|
dropStatus=processFILE_NAME(dropInfo,length);
|
|
|
|
delete dropInfo;
|
|
|
|
return dropStatus;
|
|
}
|
|
|
|
|
|
int XFE_DropDesktop::processSGI_URL(char *dropInfo,unsigned int /*length*/)
|
|
{
|
|
// parse url and title out of SGI_URL drop info
|
|
|
|
char *url=NULL;
|
|
char *title=NULL;
|
|
|
|
// url
|
|
char *urlStart=strstr(dropInfo,"SRC=\"");
|
|
if (urlStart) {
|
|
urlStart+=5;
|
|
char *end=urlStart;
|
|
while (*end && *end!='\"') // look for closing quotes
|
|
end++;
|
|
int len=end-urlStart;
|
|
if (len>0) {
|
|
url=new char[len+1];
|
|
strncpy(url,urlStart,len);
|
|
url[len]='\0';
|
|
}
|
|
}
|
|
|
|
// title
|
|
char *titleStart=strstr(dropInfo,"TITLE=\"");
|
|
if (titleStart) {
|
|
titleStart+=7;
|
|
char *end=titleStart;
|
|
while (*end && !(*end=='\"' && *(end-1)!='\\')) // look for non-escaped closing quotes
|
|
end++;
|
|
int len=end-titleStart;
|
|
if (len>0) {
|
|
title=new char[len+1];
|
|
strncpy(title,titleStart,len);
|
|
title[len]='\0';
|
|
}
|
|
}
|
|
|
|
// should this be a list, separated by '\0'?
|
|
int dropStatus=processDesktopURLTarget(title,url);
|
|
|
|
if (url)
|
|
delete url;
|
|
if (title)
|
|
delete title;
|
|
|
|
return dropStatus;
|
|
}
|
|
|
|
|
|
int XFE_DropDesktop::processSGI_ICON(char *dropInfo,unsigned int length)
|
|
{
|
|
const int FTR_MAX_SIZE=128; // from ftr header files
|
|
const char SGI_ICON_FORMAT[] =
|
|
"Category:%s Name:%s Type:%s Host:%s ViewX:%d ViewY:%d ViewGallery:%d";
|
|
|
|
const int MAX_FILES=200;
|
|
char *files[MAX_FILES];
|
|
int numFiles=0;
|
|
|
|
// parse individual files out of _SGI_ICON drop info
|
|
|
|
char *start=dropInfo;;
|
|
while (start<dropInfo+length && numFiles<MAX_FILES) {
|
|
if (strlen(start)>0) {
|
|
|
|
// parse _SGI_ICON data using standard format
|
|
char filename[MAXPATHLEN]="";
|
|
char ftrname[FTR_MAX_SIZE]="";
|
|
char category[FTR_MAX_SIZE]="";
|
|
char hostName[MAXHOSTNAMELEN]="";
|
|
int viewx=0, viewy=0, gal=0;
|
|
|
|
int numFields=sscanf(start, SGI_ICON_FORMAT,
|
|
category, filename, ftrname,
|
|
hostName, &viewx, &viewy, &gal);
|
|
|
|
// ignore files located on remote hosts
|
|
// (test strips off domain name, uses only host name)
|
|
char *dot;
|
|
if (dot=strchr(hostName,'.'))
|
|
*dot='\0';
|
|
if (strcmp(hostName,localHostName)==0) {
|
|
// copy into file list
|
|
files[numFiles++]=strdup(filename);
|
|
}
|
|
}
|
|
|
|
start+=strlen(start)+1; // move to next file
|
|
}
|
|
|
|
int dropStatus=processFileTarget((const char**)files,numFiles);
|
|
|
|
// free file name strings and list
|
|
for (int i=0;i<numFiles;i++)
|
|
if (files[i]) free((void*)files[i]);
|
|
|
|
return dropStatus;
|
|
}
|
|
|
|
int XFE_DropDesktop::processFILE_NAME(char *dropInfo,unsigned int length)
|
|
{
|
|
const int MAX_FILES=200;
|
|
char *files[MAX_FILES];
|
|
int numFiles=0;
|
|
int dropStatus=FALSE;
|
|
|
|
// parse individual files out of drop info
|
|
|
|
char *start=dropInfo;;
|
|
while (start<dropInfo+length && numFiles<MAX_FILES) {
|
|
// detect end of chunk, separated by null
|
|
char *end=start;
|
|
while(*end!='\0' && end<dropInfo+length)
|
|
end++;
|
|
*end='\0'; // ensure this chunk is terminated
|
|
|
|
if (strlen(start)>0) {
|
|
if (NET_URL_Type(start)==0) {
|
|
files[numFiles++]=start; // add to file drop list
|
|
}
|
|
}
|
|
|
|
start=end+1;
|
|
}
|
|
|
|
if (processFileTarget((const char**)files,numFiles))
|
|
dropStatus=TRUE;
|
|
|
|
return dropStatus;
|
|
}
|
|
|
|
//
|
|
// XFE_DropNetscape
|
|
//
|
|
|
|
// constructor
|
|
|
|
XFE_DropNetscape::XFE_DropNetscape(Widget widget) : XFE_DropDesktop(widget)
|
|
{
|
|
}
|
|
|
|
|
|
// destructor
|
|
|
|
XFE_DropNetscape::~XFE_DropNetscape()
|
|
{
|
|
}
|
|
|
|
//
|
|
// methods below override XFE_DropDesktop defaults
|
|
//
|
|
|
|
int XFE_DropNetscape::processFileTarget(const char**files,int numFiles)
|
|
{
|
|
XDEBUG(printf("XFE_DropNetscape::processFileTarget()\n"));
|
|
|
|
Atom *targets=new Atom[numFiles];
|
|
const char **data=new const char*[numFiles];
|
|
const int MAX_LENGTH=4000;
|
|
char line[MAX_LENGTH+1];
|
|
line[MAX_LENGTH]='\0';
|
|
|
|
int i;
|
|
|
|
// build list of dropped items
|
|
for (i=0;i<numFiles;i++) {
|
|
// default is regular file
|
|
targets[i]=_XA_FILE_NAME;
|
|
data[i]=files[i];
|
|
|
|
// if it's a Netscape desktop file, extract the data
|
|
FILE *fp;
|
|
if (fp=fopen(files[i],"r")) {
|
|
line[0]='\0'; // ensure string will be null-terminated
|
|
fgets(line,MAX_LENGTH,fp);
|
|
|
|
// NetscapeURL
|
|
if (XFE_URLDesktopType::isDesktopType(line)) {
|
|
targets[i]=_XA_NETSCAPE_URL;
|
|
XFE_URLDesktopType urlData(fp);
|
|
const char *str=urlData.getString();
|
|
data[i]=(str ? XP_STRDUP(str) : 0);
|
|
}
|
|
|
|
// nyi - check for other Netscape desktop types here
|
|
// (are no others.. yet.)
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
int dropStatus=processTargets(targets,data,numFiles);
|
|
|
|
// free our copy of non-file data (FILE_NAME's were not copied)
|
|
for (i=0;i<numFiles;i++) {
|
|
if (targets[i]!=_XA_FILE_NAME)
|
|
if (data[i])
|
|
XP_FREE((void*)data[i]);
|
|
}
|
|
|
|
delete [] targets;
|
|
delete data;
|
|
|
|
return dropStatus;
|
|
}
|
|
|
|
//
|
|
// translate desktop URL type into a NetscapeURL
|
|
//
|
|
int XFE_DropNetscape::processDesktopURLTarget(const char *title,const char *url)
|
|
{
|
|
XDEBUG(printf("XFE_DropNetscape::processDesktopURLTarget(%s,%s)\n",title,url));
|
|
|
|
if (!url)
|
|
return FALSE;
|
|
|
|
Atom targets[1];
|
|
const char *data[1];
|
|
|
|
targets[0]=_XA_NETSCAPE_URL;
|
|
XFE_URLDesktopType urlData;
|
|
urlData.createItemList(1);
|
|
urlData.url(0,url);
|
|
if (title) urlData.title(0,title);
|
|
|
|
const char *str=urlData.getString();
|
|
if (str) {
|
|
data[0]=str;
|
|
int dropStatus=processTargets(targets,data,1);
|
|
// nyi - when we add more data, do cleanup here.
|
|
return dropStatus;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
|
|
// nyi - delete data and/or contents?
|
|
}
|
|
|
|
|