home *** CD-ROM | disk | FTP | other *** search
- /* -*- 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";
-
- #ifdef 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
-
- // 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;
-
- 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++;
- 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?
- }
-
-
-