home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / DragDrop.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  58.0 KB  |  2,032 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /* 
  19.    DragDrop.cpp -- Drag and Drop classes to hide Motif's API, and work with Desktop files.
  20.    Created: Alastair Gourlay(SGI) c/o Dora Hsu<dora@netscape.com>, 26 Nov 1996
  21.  */
  22.  
  23.  
  24.  
  25. // Classes in this file:
  26. //      XFE_DragBase
  27. //        XFE_DragDesktop
  28. //          XFE_DragNetscape
  29. //      XFE_DropBase
  30. //        XFE_DropDesktop
  31. //          XFE_DropNetscape
  32. //
  33.  
  34. #include <stdlib.h>
  35. #include <net.h>
  36. #include <netdb.h>
  37. #include <icondata.h>
  38. #include <unistd.h>
  39. #include <sys/param.h>
  40. #include <sys/types.h>
  41. #include <sys/stat.h>
  42. #include <ctype.h>
  43. #include <xp_mem.h>
  44. #include <xp_str.h>
  45. #include <xpassert.h>
  46. #include <xfe.h>
  47. #include "DragDrop.h"
  48. #include <Xm/DisplayP.h>
  49.  
  50. #if defined(SOLARIS)||defined(AIX)||defined(UNIXWARE)
  51. extern "C" int gethostname(char *, int);
  52. #endif
  53.  
  54. #if defined(SCO_SV)
  55. #include <sys/socket.h>  // Need MAXHOSTNAMELEN
  56. #endif
  57.  
  58. #ifndef MAXPATHLEN
  59. #define MAXPATHLEN 1024
  60. #endif
  61.  
  62. #if defined(DEBUG_sgidev) 
  63. #define XDEBUG(x) x
  64. #else
  65. #define XDEBUG(x)
  66. #endif
  67.  
  68. #ifdef MOZ_MAIL_NEWS
  69. // from libmsg/msgglue.c
  70. extern "C" XP_Bool MSG_RequiresMailMsgWindow(const char*);
  71. extern "C" XP_Bool MSG_RequiresNewsMsgWindow(const char*);
  72. extern "C" XP_Bool MSG_RequiresBrowserWindow(const char*);
  73. #endif
  74.  
  75. //
  76. // this list defines platforms for which Motif drag and drop is usable.
  77. //
  78.  
  79. // test - enable Drag and Drop for all platforms - need to find out now
  80. // if there are unavoidable Motif or X11 bugs on any platform.
  81.  
  82. //#if defined(IRIX) || defined(SOLARIS) || defined(HPUX) || defined(UNIXWARE)
  83. #define DRAG_ENABLED
  84. //#endif
  85. //#if defined(IRIX) || defined(SOLARIS) || defined(HPUX) || defined(UNIXWARE)
  86. #define DROP_ENABLED
  87. //#endif
  88.  
  89. // default FTR type
  90. static const char DEFAULT_FTR_TYPE[]="Unknown";
  91.  
  92. // global drag information
  93. Widget XFE_DragBase::_activeDragShell=NULL;
  94.  
  95. // Atoms, initialized by InitializeDisplayInfo(), called from drag and drop
  96. // base class constructors
  97.  
  98. Atom XFE_DragBase::_XA_TARGETS=None;
  99. Atom XFE_DragBase::_XA_DELETE=None;
  100. Atom XFE_DragBase::_XA_MULTIPLE=None;
  101. Atom XFE_DragBase::_XA_TIMESTAMP=None;
  102. Atom XFE_DragBase::_XA_NULL=None;
  103. Atom XFE_DragBase::_XA_SGI_ICON=None;
  104. Atom XFE_DragBase::_XA_SGI_ICON_TYPE=None;
  105. Atom XFE_DragBase::_XA_SGI_FILE=None;
  106. Atom XFE_DragBase::_XA_FILE_NAME=None;
  107. Atom XFE_DragBase::_XA_NETSCAPE_URL=None;
  108.  
  109. Atom XFE_DropBase::_XA_TARGETS=None;
  110. Atom XFE_DropBase::_XA_DELETE=None;
  111. Atom XFE_DropBase::_XA_NULL=None;
  112. Atom XFE_DropBase::_XA_SGI_ICON=None;
  113. Atom XFE_DropBase::_XA_SGI_FILE=None;
  114. Atom XFE_DropBase::_XA_SGI_URL=None;
  115. Atom XFE_DropBase::_XA_FILE_NAME=None;
  116. Atom XFE_DropBase::_XA_NETSCAPE_URL=None;
  117.  
  118. static char *localHostName=NULL;
  119.  
  120. static void InitializeDisplayInfo(Widget widget)
  121. {
  122.     static int idi_firstTime=TRUE;
  123.     if (!idi_firstTime)
  124.         return;
  125.     idi_firstTime=FALSE;
  126.  
  127.     // atoms used for drag and drop
  128.     XFE_DragBase::_XA_TARGETS=XmInternAtom(XtDisplay(widget),"TARGETS",FALSE);
  129.     XFE_DragBase::_XA_DELETE=XmInternAtom(XtDisplay(widget),"DELETE",FALSE);
  130.     XFE_DragBase::_XA_MULTIPLE=XmInternAtom(XtDisplay(widget),"MULTIPLE",FALSE);
  131.     XFE_DragBase::_XA_TIMESTAMP=XmInternAtom(XtDisplay(widget),"TIMESTAMP",FALSE);
  132.     XFE_DragBase::_XA_NULL=XmInternAtom(XtDisplay(widget),"NULL",FALSE);
  133.     XFE_DragBase::_XA_SGI_ICON=XmInternAtom(XtDisplay(widget),"_SGI_ICON",FALSE);
  134.     XFE_DragBase::_XA_SGI_ICON_TYPE=XmInternAtom(XtDisplay(widget),"_SGI_ICON_TYPE",FALSE);
  135.     XFE_DragBase::_XA_SGI_FILE=XmInternAtom(XtDisplay(widget),"SGI_FILE",FALSE);
  136.     XFE_DragBase::_XA_FILE_NAME=XmInternAtom(XtDisplay(widget),"FILE_NAME",FALSE);
  137.     XFE_DragBase::_XA_NETSCAPE_URL=XmInternAtom(XtDisplay(widget),"_NETSCAPE_URL",FALSE);
  138.  
  139.     XFE_DropBase::_XA_TARGETS=XmInternAtom(XtDisplay(widget),"TARGETS",FALSE);
  140.     XFE_DropBase::_XA_DELETE=XmInternAtom(XtDisplay(widget),"DELETE",FALSE);
  141.     XFE_DropBase::_XA_NULL=XmInternAtom(XtDisplay(widget),"NULL",FALSE);
  142.     XFE_DropBase::_XA_SGI_ICON=XmInternAtom(XtDisplay(widget),"_SGI_ICON",FALSE);
  143.     XFE_DropBase::_XA_SGI_FILE=XmInternAtom(XtDisplay(widget),"SGI_FILE",FALSE);
  144.     XFE_DropBase::_XA_SGI_URL=XmInternAtom(XtDisplay(widget),"_SGI_URL",FALSE);
  145.     XFE_DropBase::_XA_FILE_NAME=XmInternAtom(XtDisplay(widget),"FILE_NAME",FALSE);
  146.     XFE_DropBase::_XA_NETSCAPE_URL=XmInternAtom(XtDisplay(widget),"_NETSCAPE_URL",FALSE);
  147.  
  148.     // local hostname, used to process _SGI_ICON drag
  149.     char h[MAXHOSTNAMELEN+1];
  150.     if (gethostname(h, MAXHOSTNAMELEN)==0) {
  151.         h[MAXHOSTNAMELEN]='\0';
  152.         localHostName=strdup(h);
  153.     }
  154.     else {
  155.         localHostName="localhost";
  156.     }
  157. }
  158.  
  159.  
  160. //
  161. // XFE_DragBase
  162. //
  163.  
  164. // globally useful utilities
  165.  
  166. char *XFE_DragBase::guessUrlMimeType(const char *data)
  167. {    
  168.     // try to determine type of attachment
  169.  
  170.     // regular file
  171.     if (XP_STRNCASECMP(data,"file:",5)==0 || NET_URL_Type(data)==0) {
  172.         const char *fileData=data;
  173.         if (XP_STRNCASECMP(data,"file:",5)==0) // skip file: prefix
  174.             fileData=data+5;
  175.         if (fe_isDir((char*)fileData))
  176.             return "_directory"; // interal type, since there's no mime type
  177.         NET_cinfo *pMimeInfo = NET_cinfo_find_type((char*)data);
  178.         if ((pMimeInfo) && (pMimeInfo->type))
  179.             return pMimeInfo->type;
  180.         else
  181.             return APPLICATION_OCTET_STREAM;
  182.     }
  183.  
  184.     // addressbook entry
  185.     else if (XP_STRNCASECMP(data,"addbook:",8)==0)
  186.         return "text/x-vcard";
  187.  
  188. #ifdef MOZ_MAIL_NEWS
  189.     // mail or news message
  190.     else if (MSG_RequiresMailMsgWindow(data) || MSG_RequiresNewsMsgWindow(data))
  191.         return "message/rfc822";
  192.  
  193.     // document URL - use internal id, since there's no URL mime type
  194.     else if (MSG_RequiresBrowserWindow(data))
  195.         return "_url";
  196. #endif
  197.  
  198.     // fallback to generic type
  199.     else
  200.         return UNKNOWN_CONTENT_TYPE;
  201. }
  202.  
  203.  
  204. // callback wrappers
  205. void XFE_DragBase::ButtonPressCb(Widget w,XtPointer cd,XEvent *event,Boolean*)
  206. {
  207.     XFE_DragBase *d=(XFE_DragBase*)cd;
  208.     if (d &&
  209.         event->xany.type==ButtonPress &&
  210.         event->xbutton.button==1) {
  211.         d->_dragWidget=w;
  212.         d->buttonPressCb((XButtonPressedEvent*)event);
  213.     }
  214. }
  215.  
  216. void XFE_DragBase::ButtonMotionCb(Widget w,XtPointer cd,XEvent *event,Boolean *eatEvent)
  217. {
  218.     XFE_DragBase *d=(XFE_DragBase*)cd;
  219.     if (d &&
  220.         w==d->_dragWidget &&
  221.         event->xany.type==MotionNotify) {
  222.         *eatEvent=d->buttonMotionCb((XMotionEvent*)event);
  223.     }    
  224. }
  225.  
  226. Boolean XFE_DragBase::DragConvertCb(Widget w,Atom*,Atom *target,Atom *type,
  227.                                     XtPointer *value,unsigned long *length,int *format)
  228. {
  229.     if (!w || !XmIsDragContext(w))
  230.         return FALSE;
  231.         
  232.     XtPointer cd;
  233.     XtVaGetValues(w,XmNclientData,&cd,NULL);
  234.     XFE_DragBase *d=(XFE_DragBase*)cd;
  235.  
  236.     if (d) {
  237.         return d->dragConvertCb(target,type,value,length,format);
  238.     }
  239.     return FALSE;
  240. }
  241.  
  242. void XFE_DragBase::OperationChangedCb(Widget w,XtPointer cd,XtPointer)
  243. {
  244.     if (!w || !XmIsDragContext(w))
  245.         return;
  246.         
  247.     XFE_DragBase *d=(XFE_DragBase*)cd;
  248.  
  249.     // nyi - what callback struct info should be passed to method?
  250.     if (d) {
  251.         d->operationChangedCb();
  252.     }
  253. }
  254.  
  255. void XFE_DragBase::DragMotionCb(Widget w,XtPointer cd,XtPointer cb)
  256. {
  257.     if (!w || !XmIsDragContext(w))
  258.         return;
  259.         
  260.     XFE_DragBase *d=(XFE_DragBase*)cd;
  261.     XmDragMotionCallbackStruct *dmcb=(XmDragMotionCallbackStruct*)cb;
  262.  
  263.     // nyi - what callback struct info should be passed to method?
  264.     if (d) {
  265.         // record (x,y) of pointer during drag
  266.         if (dmcb) {
  267.             d->_dragEventX=dmcb->x;
  268.             d->_dragEventY=dmcb->y;
  269.         }        
  270.         d->dragMotionCb();
  271.     }
  272. }
  273.  
  274. void XFE_DragBase::DropStartCb(Widget w,XtPointer cd,XtPointer)
  275. {
  276.     if (!w || !XmIsDragContext(w))
  277.         return;
  278.         
  279.     XFE_DragBase *d=(XFE_DragBase*)cd;
  280.  
  281.     // nyi - what callback struct info should be passed to method?
  282.     if (d) {
  283.         d->dropStartCb();
  284.     }
  285. }
  286.  
  287. void XFE_DragBase::DropSiteEnterCb(Widget w,XtPointer cd,XtPointer cb)
  288. {
  289.     if (!w || !XmIsDragContext(w))
  290.         return;
  291.         
  292.     XFE_DragBase *d=(XFE_DragBase*)cd;
  293.  
  294.     XmDropSiteEnterCallbackStruct *dcb=(XmDropSiteEnterCallbackStruct*)cb;
  295.     
  296.     // nyi - what callback struct info should be passed to method?
  297.     if (d) {
  298.         d->dropSiteEnterCb(dcb->operations);
  299.     }
  300.     XDEBUG(printf("  operation=%x, operations=%x,status=%d\n",
  301.                   dcb->operation,dcb->operations,dcb->dropSiteStatus));
  302. }
  303.  
  304. void XFE_DragBase::DropSiteLeaveCb(Widget w,XtPointer cd,XtPointer)
  305. {
  306.     if (!w || !XmIsDragContext(w))
  307.         return;
  308.         
  309.     XFE_DragBase *d=(XFE_DragBase*)cd;
  310.  
  311.     // nyi - what callback struct info should be passed to method?
  312.     if (d) {
  313.         d->dropSiteLeaveCb();
  314.     }
  315. }
  316.  
  317. void XFE_DragBase::DropFinishCb(Widget w,XtPointer cd,XtPointer)
  318. {
  319.     if (!w || !XmIsDragContext(w))
  320.         return;
  321.         
  322.     XFE_DragBase *d=(XFE_DragBase*)cd;
  323.  
  324.     // nyi - what callback struct info should be passed to method?
  325.     if (d) {
  326.         d->dropFinishCb();
  327.     }
  328. }
  329.  
  330. void XFE_DragBase::DragDropFinishCb(Widget w,XtPointer cd,XtPointer)
  331. {
  332.     if (!w || !XmIsDragContext(w))
  333.         return;
  334.         
  335.     XFE_DragBase *d=(XFE_DragBase*)cd;
  336.  
  337.     // nyi - what callback struct info should be passed to method?
  338.     if (d) {
  339.         d->dragDropFinishCb();
  340.     }
  341. }
  342.  
  343. void XFE_DragBase::DestroyCb(Widget w,XtPointer,XtPointer)
  344. {
  345.     if (!w || !XmIsDragContext(w))
  346.         return;
  347.         
  348.     //XFE_DragBase *d=(XFE_DragBase*)cd;
  349.  
  350.     XDEBUG(printf("XFE_DragBase::DestroyCb()\n"));
  351. }
  352.  
  353. // constructor
  354.  
  355. // The drag classes will monitor drags from the widget passed
  356. // to the constructor. Simple drag classes can just pass
  357. // one widget to the constructor. Multi-item objects can use
  358. // one XFE_Drag class with additional widgets, specified by
  359. // addDragWidget(). During the drag, the field _dragWidget
  360. // will point to the widget currently being dragged.
  361.  
  362. XFE_DragBase::XFE_DragBase(Widget widget)
  363. {
  364.     _widget=widget;
  365.     _dragWidget=NULL;
  366.     _dragThreshold=4;
  367.     _dragStarted=FALSE;
  368.     _buttonPressed=FALSE;
  369.     _dragStartX=0;
  370.     _dragStartY=0;
  371.     _dragEventX=0;
  372.     _dragEventY=0;
  373.     _dragContext=NULL;
  374.     _dragIcon=NULL;    
  375.     _targets=NULL;
  376.     _numTargets=0;
  377.     _dragFilesAsLinks=FALSE;
  378.  
  379.     // default icon is blank document
  380.     _dragIconData=&GUnknown;
  381.     _dragIconPixmap=None;
  382.     _dragIconPixmapMask=None;
  383.     _dragIconWidth=0;
  384.     _dragIconHeight=0;
  385.  
  386.     InitializeDisplayInfo(widget);
  387.  
  388.     addDragWidget(widget);
  389.  
  390. #ifdef IRIX
  391.     // hack for SGI Motif - force it to sgidladd/dlopen conversion library
  392.     // now, not on the first drag - it can be slow, and blows the usability
  393.     // out the water - an early button release leaves a permanent cursor
  394.     // window turd. Note: performance hit is present only in 6.2 and
  395.     // 6.3. 6.3-R10K and 6.4 were improved greatly.
  396.     static int firstTime=TRUE;
  397.     if (firstTime) {
  398.         XDEBUG(printf("Hacking XmDragContext initialization {\n"));
  399.         firstTime=FALSE;
  400.         Atom tl[1]={ XA_STRING };
  401.         Arg args[2];
  402.         int n=0;
  403.         XtSetArg(args[n],XmNexportTargets,&tl);n++;
  404.         XtSetArg(args[n],XmNnumExportTargets,1);n++;
  405.         XtDestroyWidget(XtCreateWidget("dragContext",xmDragContextClass,
  406.                                        XmGetXmDisplay(XtDisplay(widget)),
  407.                                        args,n));
  408.         XDEBUG(printf("}\n"));
  409.     }
  410. #endif
  411. }
  412.  
  413.  
  414. // destructor
  415.  
  416. XFE_DragBase::~XFE_DragBase()
  417. {
  418.     XDEBUG(printf("XFE_DragBase::~XFE_DragBase()\n"));
  419.     
  420.     // destroy drag icon widget
  421.     // usually destroyed in dragDropFinishCb, but catch case of mid-drag Destroy.
  422.     if (_dragIcon) {
  423.         XtDestroyWidget(_dragIcon);
  424.         _dragIcon=NULL;
  425.     }
  426.  
  427.     // clean up drag icon data
  428.     setDragIcon(NULL);
  429. }
  430.  
  431.  
  432. //
  433. // drag methods
  434. //
  435.  
  436. void XFE_DragBase::addDragWidget(Widget widget)
  437. {    
  438.     if (widget) {
  439.         // catch button 1 press and motion
  440.         XtInsertEventHandler(widget,ButtonPressMask,FALSE,
  441.                              ButtonPressCb,(XtPointer)this,XtListHead);
  442.         XtInsertEventHandler(widget,Button1MotionMask,FALSE,
  443.                              ButtonMotionCb,(XtPointer)this,XtListHead);
  444.  
  445.         // clean up when widget is destroyed
  446.         XtAddCallback(widget,XmNdestroyCallback,dragWidgetDestroyCb,(XtPointer)this);
  447.     }
  448. }
  449.  
  450. void XFE_DragBase::dragWidgetDestroyCb(Widget widget,XtPointer cd,XtPointer)
  451. {
  452.     if (widget && cd) {
  453.         XDEBUG(printf("XFE_DragBase::dragWidgetDestroyCb(%s)\n",XtName(widget)));
  454.         XtRemoveEventHandler(widget,ButtonPressMask,FALSE,
  455.                              ButtonPressCb,cd);
  456.         XtRemoveEventHandler(widget,Button1MotionMask,FALSE,
  457.                              ButtonMotionCb,cd);
  458.         // _dragIcon widget is a child of the _dragWidget.
  459.         // It will get destroyed by Xt, so clean up our pointer.
  460.         XFE_DragBase *db=(XFE_DragBase*)cd;
  461.         db->_dragIcon=NULL;
  462.     }
  463. }
  464.  
  465. void XFE_DragBase::dragInitialize()
  466. {
  467.     if (_dragContext!=NULL) {
  468.         XDEBUG(printf("DRAG IN PROGRESS - new drag not started\n"));
  469.         return;
  470.     }
  471.  
  472.     if (!_dragWidget)
  473.         return;
  474.     
  475.     _dragFilesAsLinks=FALSE;
  476.     
  477.     // let derived class decide how to handle this drag
  478.     if (dragStart(_dragStartX,_dragStartY)==FALSE) {
  479.         dragDropFinishCb();
  480.         return;
  481.     }
  482.     
  483.     targets();
  484.     operations();
  485.  
  486.     if (_numTargets==0 || _operations==0) {
  487.         dragDropFinishCb();
  488.         return;
  489.     }
  490.  
  491.     // enable desktop LINK behavior, if application class asks
  492.     if (_dragFilesAsLinks) {
  493.         _operations|=(unsigned int)XmDROP_LINK;
  494.     }
  495.     
  496.     _dragIcon=NULL;
  497.     // create drag icons if necessary
  498.     // (i.e. first time, and after setDragIcon() )
  499. #ifdef DRAG_ENABLED
  500.     if (_dragIconData) {
  501.         if (_dragIconPixmap==None)
  502.             _dragIconPixmap=XCreateBitmapFromData(XtDisplay(_dragWidget),
  503.                                                   XtWindow(_dragWidget),
  504.                                                   (char*)_dragIconData->mono_bits,
  505.                                                   _dragIconData->width,
  506.                                                   _dragIconData->height);
  507.         if (_dragIconPixmapMask==None)
  508.             _dragIconPixmapMask=XCreateBitmapFromData(XtDisplay(_dragWidget),
  509.                                                       XtWindow(_dragWidget),
  510.                                                       (char*)_dragIconData->mask_bits,
  511.                                                       _dragIconData->width,
  512.                                                       _dragIconData->height);
  513.         Arg args[20];
  514.         int n=0;
  515.         XtSetArg(args[n],XmNwidth,_dragIconData->width);n++;
  516.         XtSetArg(args[n],XmNheight,_dragIconData->height);n++;
  517.         XtSetArg(args[n],XmNpixmap,_dragIconPixmap);n++;
  518.         if (_dragIconPixmapMask) {
  519.             XtSetArg(args[n],XmNmask,_dragIconPixmapMask);n++;
  520.         }
  521.         _dragIcon=XmCreateDragIcon(_dragWidget,"dragIcon",args,n);
  522. #endif
  523.     }
  524.  
  525.     // callback records
  526.     static XtCallbackRec operationChangedCbRec[]= {
  527.         {OperationChangedCb,NULL},{NULL,NULL}
  528.     };
  529.     static XtCallbackRec dragMotionCbRec[]= {
  530.         {DragMotionCb,NULL},{NULL,NULL}
  531.     };
  532.     static XtCallbackRec dropStartCbRec[]= {
  533.         {DropStartCb,NULL},{NULL,NULL}
  534.     };
  535.     static XtCallbackRec dropSiteEnterCbRec[]= {
  536.         {DropSiteEnterCb,NULL},{NULL,NULL}
  537.     };
  538.     static XtCallbackRec dropSiteLeaveCbRec[]= {
  539.         {DropSiteLeaveCb,NULL},{NULL,NULL}
  540.     };
  541.     static XtCallbackRec dropFinishCbRec[]= {
  542.         {DropFinishCb,NULL},{NULL,NULL}
  543.     };
  544.     static XtCallbackRec dragDropFinishCbRec[]= {
  545.         {DragDropFinishCb,NULL},{NULL,NULL}
  546.     };
  547.     static XtCallbackRec destroyCbRec[]= {
  548.         {DestroyCb,NULL},{NULL,NULL}
  549.     };
  550.     operationChangedCbRec[0].closure=this;
  551.     dragMotionCbRec[0].closure=this;
  552.     dropStartCbRec[0].closure=this;
  553.     dropSiteEnterCbRec[0].closure=this;
  554.     dropSiteLeaveCbRec[0].closure=this;
  555.     dropFinishCbRec[0].closure=this;
  556.     dragDropFinishCbRec[0].closure=this;
  557.     destroyCbRec[0].closure=this;
  558.     
  559.     Arg args[40];
  560.     int n=0;
  561.     XtSetArg(args[n],XmNexportTargets,_targets);n++;
  562.     XtSetArg(args[n],XmNnumExportTargets,_numTargets);n++;
  563.     XtSetArg(args[n],XmNclientData,(XtPointer)this);n++;
  564.     XtSetArg(args[n],XmNconvertProc,DragConvertCb);n++;
  565.     XtSetArg(args[n],XmNdragOperations,_operations);n++;
  566.     XtSetArg(args[n],XmNblendModel,XmBLEND_JUST_SOURCE);n++;
  567.     XtSetArg(args[n],XmNoperationChangedCallback,operationChangedCbRec);n++;
  568.     XtSetArg(args[n],XmNdragMotionCallback,dragMotionCbRec);n++;
  569.     XtSetArg(args[n],XmNdropStartCallback,dropStartCbRec);n++;
  570.     XtSetArg(args[n],XmNdropSiteEnterCallback,dropSiteEnterCbRec);n++;
  571.     XtSetArg(args[n],XmNdropSiteLeaveCallback,dropSiteLeaveCbRec);n++;
  572.     XtSetArg(args[n],XmNdropFinishCallback,dropFinishCbRec);n++;
  573.     XtSetArg(args[n],XmNdragDropFinishCallback,dragDropFinishCbRec);n++;
  574.     XtSetArg(args[n],XmNdestroyCallback,destroyCbRec);n++;
  575.     if (_dragIcon) {
  576. #ifdef IRIX
  577. #ifndef IRIX5_3
  578.         // We want the cursor colors to be black and white, but
  579.         // only IRIX Motif does the right thing with the color
  580.         // settings. Other platforms spew many X protocol errors
  581.         // from inside Xm/DragOverS.c in Motif.
  582.         //
  583.         // ifdef desired code for IRIX and let other platforms
  584.         // use default colors until we can figure out a way
  585.         // to stop the X protocol errors.
  586.         Pixel fg,bg;
  587.  
  588.         // get a context
  589.         MWContext *context=fe_WidgetToMWContext(_dragWidget);
  590.         if (!context)
  591.             context=XP_GetNonGridContext(fe_all_MWContexts->context);
  592.  
  593.         // extract color info
  594.         if (context) {
  595.             fg=fe_GetPixel(context,0,0,0);
  596.             bg=fe_GetPixel(context,0xff,0xff,0xff);
  597.         }
  598.         else {
  599.             XtVaGetValues(_dragWidget,XmNforeground,&fg,XmNbackground,&bg,NULL);
  600.         }
  601.         XtSetArg(args[n],XmNcursorBackground,bg);n++;
  602.         XtSetArg(args[n],XmNcursorForeground,fg);n++;
  603. #endif
  604. #endif
  605.         XtSetArg(args[n],XmNsourceCursorIcon,_dragIcon);n++;        
  606.     }
  607.  
  608. #if 0
  609.     // This seems fixed for now..  but I'm not deleting this code just yet,
  610.     // since I don't know the who or the how of the fix.
  611.     //
  612.     // What a hack - Something in the browser menu code is causing
  613.     // the menu system to think it's active each time a new browser
  614.     // is created. This prevents any drags from working until
  615.     // the first menu pops up, then down again, resetting the
  616.     // 'userGrabbed' flag in XmDisplay.
  617.     // We will reset that flag here to make dragging work. This
  618.     // is safe, since we know that we only call XmDragStart() in
  619.     // response to a button press - which will have already deactivated
  620.     //  any menu code. Cool. Now as a warm-down send a manned mission
  621.     // to Mars. Then find out why this happens in the first place!!!!
  622.     Widget xmDisplay=XmGetXmDisplay(XtDisplay(_widget));
  623.     XDEBUG(printf("XmDisplay.userGrabbed=%d\n",((XmDisplayRec*)xmDisplay)->display.userGrabbed));
  624.     ((XmDisplayRec*)xmDisplay)->display.userGrabbed=0;
  625. #endif
  626.     
  627. #ifndef DISABLE_DRAG
  628.     // check that Btn1 is still down
  629.     Window rootWin,childWin;
  630.     int rootX,rootY,childX,childY;
  631.     unsigned int buttonMask=0;
  632.  
  633.     XSync(XtDisplay(_widget),FALSE);
  634.     XQueryPointer(XtDisplay(_widget),XtWindow(_widget),
  635.                   &rootWin,&childWin,
  636.                   &rootX,&rootY,&childX,&childY,
  637.                   &buttonMask);
  638.     if (!(buttonMask & Button1Mask)) {
  639.         XDEBUG(printf("###Button1 not down - aborting drag!###\n"));
  640.         dragDropFinishCb();
  641.         return;
  642.     }    
  643.     
  644.     XDEBUG(printf("XmDragStart() {\n"));
  645.     _dragContext=XmDragStart(_dragWidget,(XEvent*)&_dragButtonEvent,args,n);
  646.     XDEBUG(printf("}  XmDragStart()\n"));
  647.     if (_dragContext) {
  648.         _dragStarted=TRUE;
  649.         // record global active drag shell
  650.         Widget shell=_widget;
  651.         while (!XtIsShell(shell)) shell=XtParent(shell);
  652.         _activeDragShell=shell;
  653.     }
  654.     else {
  655.         XDEBUG(printf("XmDragStart() failed!\n"));
  656.         dragDropFinishCb();
  657.         return;
  658.     }    
  659. #endif    
  660. }
  661.  
  662. int XFE_DragBase::isFileURL(const char *url)
  663. {
  664.     return (url && strlen(url)>0 &&
  665.             (XP_STRNCASECMP(url,"file:",5)==0 || XP_STRNCMP(url,"/",1)==0))
  666.         ? TRUE : FALSE;
  667. }
  668.  
  669. void XFE_DragBase::setDragIcon(struct fe_icon_data *iconData)
  670. {
  671.     // if this is a new icon, clean up old icon data
  672.     if (_dragIconData!=iconData) {
  673.         if (_dragIconPixmap!=None) {
  674.             XFreePixmap(XtDisplay(_widget),_dragIconPixmap);
  675.             _dragIconPixmap=None;
  676.         }
  677.         if (_dragIconPixmapMask!=None) {
  678.             XFreePixmap(XtDisplay(_widget),_dragIconPixmapMask);
  679.             _dragIconPixmapMask=None;
  680.         }
  681.     }
  682.  
  683.     // set up pointer, and let dragInitialize() create pixmaps
  684.     _dragIconData=iconData;
  685. }
  686.  
  687. void XFE_DragBase::setDragIconForType(const char *dataType)
  688. {
  689.     if (!dataType) {
  690.         setDragIcon(&GUnknown);
  691.         return;
  692.     }
  693.     
  694.     if (!dataType || XP_STRCASECMP(dataType,UNKNOWN_CONTENT_TYPE)==0)
  695.         setDragIcon(&GUnknown);
  696.     else if (XP_STRCASECMP(dataType,"_url")==0)    // internal type name for urls
  697.         setDragIcon(&LocationProxy);
  698.     else if (XP_STRCASECMP(dataType,"_directory")==0)    // internal type name for directories
  699.         setDragIcon(&GFolder);
  700.     else if (XP_STRNCASECMP(dataType,"audio",5)==0)
  701.         setDragIcon(&GAudio);
  702.     else if (XP_STRNCASECMP(dataType,"application",11)==0)
  703.         setDragIcon(&GBinary);
  704.     else if (XP_STRNCASECMP(dataType,"image",5)==0)
  705.         setDragIcon(&GImage);
  706. #ifdef MOZ_MAIL_NEWS
  707.     else if (XP_STRNCASECMP(dataType,"message",7)==0)
  708.         setDragIcon(&MNTB_Forward);
  709.     else if (XP_STRCASECMP(dataType,"text/x-vcard")==0)
  710.         setDragIcon(&MNAB_NewPerson);
  711. #endif
  712.     else if (XP_STRNCASECMP(dataType,"text",4)==0)
  713.         setDragIcon(>ext);
  714.     else if (XP_STRNCASECMP(dataType,"video",5)==0)
  715.         setDragIcon(&GMovie);
  716.     else
  717.         setDragIcon(&GUnknown);
  718. }
  719.  
  720.  
  721. //
  722. // default drag virtual methods - derived class can override
  723. //
  724.  
  725. // drag string data by default
  726. void XFE_DragBase::targets()
  727. {
  728.     _numTargets=1;
  729.     _targets=new Atom[_numTargets];
  730.  
  731.     _targets[0]=XA_STRING;
  732. }
  733.  
  734. // allow move or copy by default
  735. void XFE_DragBase::operations()
  736. {
  737.     _operations=(unsigned int)(XmDROP_MOVE | XmDROP_COPY);
  738. }
  739.  
  740.  
  741. // provide data for requested target from targets() list
  742. char *XFE_DragBase::getTargetData(Atom target)
  743. {
  744.     // WARNING - data *must* be allocated with Xt malloc API, or Xt
  745.     // will spring a leak!
  746.     
  747.     if (target==XA_STRING) {
  748.         return (char*)XtNewString("Netscape 4.0 Default Drag Data");
  749.     }
  750.  
  751.     return 0;
  752. }
  753.  
  754.  
  755. void XFE_DragBase::deleteTarget()
  756. {
  757.     XDEBUG(printf("XFE_DragBase::deleteTarget()\n"));
  758. }
  759.  
  760. //
  761. // button event handler methods
  762. //
  763.  
  764. extern "C" void fe_HTMLDragSetLayer(CL_Layer *layer);
  765.  
  766. void XFE_DragBase::buttonPressCb(XButtonPressedEvent *event) 
  767. {
  768.     XDEBUG(printf("XFE_DragBase::buttonPressCb(%d,%d)\n",event->x,event->y));
  769.  
  770.     // Hack: Clear global HTMLView drag layer before button event is processed by XFE_HTMLView
  771.     fe_HTMLDragSetLayer(NULL);
  772.  
  773.     // nyi - for now, don't lock out drags when Motif gets confused
  774.     _dragStarted=FALSE;
  775.     
  776.     // one at a time please..
  777.     if (_dragStarted)
  778.         return;
  779.  
  780.     _buttonPressed=TRUE;
  781.     _dragStartX=event->x;
  782.     _dragStartY=event->y;
  783.     _dragEventX=_dragStartX;
  784.     _dragEventY=_dragStartY;
  785.     
  786.     // gross - copy button event for later use by XmDragStart
  787.     // Note: Motif should allow Motion event in XmDragStart, docs
  788.     // say Yes, but the Xm code disagrees - only ButtonPress is accepted.
  789.     _dragButtonEvent=*event;
  790.  
  791.     // if there's no threshold, start drag immediately
  792.     if (_dragThreshold==0) {
  793.         dragInitialize();
  794.         _buttonPressed=FALSE; // reset the trigger
  795.     }
  796.  
  797. }
  798.  
  799. int XFE_DragBase::buttonMotionCb(XMotionEvent *event)
  800. {
  801.     // steal event if we're already dragging
  802.     if (_dragStarted)
  803.         return FALSE;
  804.  
  805.     // pass through event if we're not dragging 
  806.     if (!_buttonPressed)
  807.         return TRUE;
  808.     
  809.     XDEBUG(printf("XFE_DragBase::buttonMotionCb(%d,%d)\n",event->x,event->y));
  810.  
  811.     if (abs(_dragStartX-event->x)>=_dragThreshold ||
  812.         abs(_dragStartY-event->y)>=_dragThreshold) {
  813.         dragInitialize();
  814.         _buttonPressed=FALSE; // reset the trigger
  815.     }
  816.  
  817.     // steal event - user might be starting a drag
  818.     return FALSE;
  819. }
  820.  
  821. //
  822. // drag callbacks
  823. //
  824.  
  825. Boolean XFE_DragBase::dragConvertCb(Atom *target,Atom *type,XtPointer *value,
  826.                                     unsigned long *length,int *format)
  827. {
  828.     XDEBUG(printf("XFE_DragBase::dragConvertCb(%s)\n",XmGetAtomName(XtDisplay(_widget),*target)));
  829.     
  830.     // TARGETS - our targets, plus ICCCM standard targets
  831.     if (*target==_XA_TARGETS) {
  832.         // create targets list - freed by Xt selection API
  833.         Atom *targetData=(Atom*)XtMalloc((unsigned)((_numTargets+4)*sizeof(Atom)));
  834.         int i;
  835.         for(i=0;i<_numTargets;i++)
  836.             targetData[i]=_targets[i];
  837.         targetData[i++]=_XA_DELETE;
  838.         targetData[i++]=_XA_TARGETS;
  839.         targetData[i++]=_XA_MULTIPLE; // provided by Xt
  840.         targetData[i++]=_XA_TIMESTAMP; // provided by Xt
  841.  
  842.         // return ICCCM targets list
  843.         *value=(XtPointer)targetData;
  844.         *type=XA_ATOM;
  845.         *length=_numTargets+4;
  846.         *format=32;
  847.         return TRUE;
  848.     }
  849.     
  850.     // DELETE
  851.     if (*target==_XA_DELETE) {
  852.         // handle delete request for dragged object
  853.         deleteTarget();
  854.         
  855.         // return ICCCM acknowledgement of delete
  856.         *value=NULL;
  857.         *type=_XA_NULL;
  858.         *length=0;
  859.         *format=8;
  860.         return TRUE;
  861.     }
  862.  
  863.     // is it a request for the data as a desktop file?
  864.     if (isFileTarget(*target)) {
  865.         // write drag data in appropriate desktop file format, return filenames
  866.         // DragBase does not handle files - methods are provided by derived class.
  867.         // (but this is easier than adding yet another chained virtual method..)
  868.         getTargetDataAsFileWrapper(*target,value,length);
  869.         if (*value && *length>0) {
  870.             if (*target==_XA_FILE_NAME)
  871.                 *type=XA_STRING;
  872.             else
  873.                 *type=*target;
  874.             *format=8;
  875.             return TRUE;
  876.         }
  877.         else {
  878.             return FALSE;
  879.         }
  880.     }
  881.     
  882.     // All other targets - ask derived class method for data string
  883.     if ((*value=(XtPointer)getTargetData(*target))!=NULL) {
  884.         *type=*target;
  885.         *length=strlen((char*)*value);
  886.         *format=8;
  887. #if defined(DEBUG_tao)
  888.         printf("\nXFE_DragBase::dragConvertCb:value=%x,target=%d,length=%d\n",
  889.                *value, *target, *length);
  890. #endif
  891.  
  892.         return TRUE;
  893.     }
  894.  
  895.     // Can't provide data for requested target
  896.     return FALSE;
  897. }
  898.  
  899. void XFE_DragBase::operationChangedCb()
  900. {
  901.     XDEBUG(printf("XFE_DragBase::operationChangedCb()\n"));
  902. }
  903.  
  904. void XFE_DragBase::dragMotionCb()
  905. {
  906.     //XDEBUG(printf("XFE_DragBase::dragMotionCb()\n"));
  907. }
  908.  
  909. void XFE_DragBase::dropStartCb()
  910. {
  911.     XDEBUG(printf("XFE_DragBase::dropStartCb()\n"));
  912. }
  913.  
  914. void XFE_DragBase::dropSiteEnterCb(int operations)
  915. {
  916.     XDEBUG(printf("XFE_DragBase::dropSiteEnterCb()\n"));
  917.     if (_dragFilesAsLinks && (operations & XmDROP_LINK)) {
  918.         XtVaSetValues(_dragContext,XmNdragOperations,XmDROP_LINK,NULL);
  919.     }
  920. }
  921.  
  922. void XFE_DragBase::dropSiteLeaveCb()
  923. {
  924.     XDEBUG(printf("XFE_DragBase::dropSiteLeaveCb()\n"));
  925.     if (_dragFilesAsLinks)
  926.         XtVaSetValues(_dragContext,XmNdragOperations,_operations|XmDROP_LINK,NULL);
  927. }
  928.  
  929. void XFE_DragBase::dropFinishCb()
  930. {
  931.     XDEBUG(printf("XFE_DragBase::dropFinishCb()\n"));
  932. }
  933.  
  934. void XFE_DragBase::dragDropFinishCb()
  935. {
  936.     XDEBUG(printf("XFE_DragBase::dragDropFinishCb()\n"));
  937.  
  938.     dragComplete();
  939.  
  940.     // destroy drag icon widget
  941.     if (_dragIcon) {
  942.         XtDestroyWidget(_dragIcon);
  943.         _dragIcon=NULL;
  944.     }
  945.     
  946.     // delete targets list
  947.     
  948.     if (_targets) {
  949.         delete [] _targets;
  950.         _targets=NULL;
  951.         _numTargets=0;
  952.     }
  953.  
  954.     // reset drag data
  955.  
  956.     _operations=0;
  957.     _dragWidget=NULL;
  958.     _dragContext=NULL;
  959.     _dragStarted=FALSE;
  960.     _dragStartX=0;
  961.     _dragStartY=0;
  962.     _dragEventX=0;
  963.     _dragEventY=0;
  964.     _activeDragShell=NULL;
  965. }
  966.  
  967.  
  968.  
  969. //
  970. // XFE_DragDesktop
  971. //
  972. // app specifies dragging type via targets()
  973. // if request comes in for file:
  974. //      determine actual type from targets()
  975. //      call getTargetData() for actual type
  976. //      create tmp file in correct format
  977. //      return SGI_ICON/SGI_FILE/FILENAME as needed
  978. //      delete file when drop compete (assume force a file copy)
  979. //      DELETE still means delete data in Netscape, not file
  980.  
  981. XFE_DragDesktop::XFE_DragDesktop(Widget w) : XFE_DragBase(w)
  982. {
  983.     _fileTarget=None;
  984. }
  985.  
  986. XFE_DragDesktop::~XFE_DragDesktop()
  987. {
  988. }
  989.  
  990. void XFE_DragDesktop::setFileTarget(Atom target)
  991. {
  992.     if (!_targets || _numTargets==0)
  993.         return;
  994.     
  995.     _fileTarget=target;
  996.     
  997.     // insert desktop file dnd atoms into list
  998.     // must insert before generic STRING - some desktops (IRIX 6.3+)
  999.     // will treat STRING drop as a paste-to-new-file action.
  1000.     Atom *newTargets=new Atom[_numTargets+4];
  1001.     int i=0;
  1002.     int ni=0;
  1003.     int added=FALSE;
  1004.     while (i<_numTargets) {
  1005.         if (_targets[i]==XA_STRING) {
  1006.             newTargets[ni++]=_XA_SGI_ICON_TYPE;
  1007.             newTargets[ni++]=_XA_SGI_ICON;
  1008.             newTargets[ni++]=_XA_SGI_FILE;
  1009.             newTargets[ni++]=_XA_FILE_NAME;
  1010.             added=TRUE;
  1011.         }
  1012.         newTargets[ni++]=_targets[i++];
  1013.     }
  1014.     if (!added) {
  1015.         // no STRING in targets list, so append
  1016.         newTargets[ni++]=_XA_SGI_ICON_TYPE;
  1017.         newTargets[ni++]=_XA_SGI_ICON;
  1018.         newTargets[ni++]=_XA_SGI_FILE;
  1019.         newTargets[ni++]=_XA_FILE_NAME;
  1020.     }
  1021.  
  1022.     delete [] _targets;
  1023.     _targets=newTargets;
  1024.     _numTargets=ni;
  1025. }
  1026.  
  1027.  
  1028. int XFE_DragDesktop::isFileTarget(Atom target)
  1029. {
  1030.     return (target==_XA_SGI_ICON ||
  1031.             target==_XA_SGI_ICON_TYPE ||
  1032.             target==_XA_SGI_FILE ||
  1033.             target==_XA_FILE_NAME)
  1034.         ? TRUE : FALSE;
  1035. }
  1036.  
  1037. void XFE_DragDesktop::getTargetDataAsFileWrapper(Atom target, XtPointer *value, unsigned long *length)
  1038. {
  1039.     // create files for data and return desktop formatted description of files.
  1040.  
  1041.     *value=NULL;
  1042.     *length=0;
  1043.  
  1044.     XDEBUG(printf("XFE_DragDesktop::getTargetDataAsFileWrapper(%s)\n",XmGetAtomName(XtDisplay(_widget),target)));
  1045.     
  1046.     if (_fileTarget==None)
  1047.         return;
  1048.  
  1049.     // return type for desktop feedback during drag
  1050.     if (target==_XA_SGI_ICON_TYPE) {
  1051.         const char *ftrType=getTargetFTRType(_fileTarget);
  1052.         if (ftrType) {
  1053.             *value=(XtPointer)XtNewString(ftrType);
  1054.             *length=strlen(ftrType);
  1055.         }
  1056.         else {
  1057.             *value=NULL;
  1058.             *length=0;
  1059.         }
  1060.         return;
  1061.     }
  1062.  
  1063.     // get data as list of files
  1064.     // (usually one file per selected item, but it's up to derived class)
  1065.     char **fileList=NULL;
  1066.     int numFiles=0;
  1067.     getTargetDataAsFileList(_fileTarget,&fileList,&numFiles);
  1068.     
  1069.     if (!fileList || numFiles==0)
  1070.         return;
  1071.  
  1072.     const char *ftrType=getTargetFTRType(_fileTarget);
  1073.     const char SGI_ICON_FORMAT[] =
  1074.         "Category:%s Name:%s Type:%s Host:%s ViewX:%d ViewY:%d ViewGallery:%d";
  1075.     int i;
  1076.     int fileDataSize=0;
  1077.     // calculate space needed for formatted file list
  1078.     for (i=0;i<numFiles;i++)
  1079.         if (fileList[i]) fileDataSize+=strlen(fileList[i])+1;
  1080.     if (target==_XA_SGI_ICON)
  1081.         fileDataSize+=numFiles*(strlen(SGI_ICON_FORMAT)+
  1082.                                 strlen(ftrType)+
  1083.                                 strlen(localHostName)+
  1084.                                 50); // format string space plus ViewX,ViewY,ViewGallery + final \0
  1085.     else
  1086.         fileDataSize+=1; // + final \0
  1087.  
  1088.     // copy file list to value in appropriate format
  1089.     char *fileData=XtMalloc(fileDataSize);
  1090.     unsigned long fileDataLength=0;
  1091.     char *curPos=fileData;
  1092.     for (i=0;i<numFiles;i++) {
  1093.         if (target==_XA_SGI_ICON) {
  1094.             // nyi - tune values for ViewX,ViewY s.t. drop of icon looks right
  1095.             // nyi - do we need to tweak ViewX,ViewY for multiple item drops?  (orientation,spacing)
  1096.             sprintf(curPos,SGI_ICON_FORMAT,"File",fileList[i],ftrType,localHostName,
  1097.                     -10,-10,0);
  1098.         }
  1099.         else {
  1100.             strcpy(curPos,fileList[i]);
  1101.         }
  1102.         int segmentLen=strlen(curPos)+1;
  1103.         fileDataLength+=segmentLen;
  1104.         curPos+=segmentLen;
  1105.     }
  1106.     *curPos='\0'; // terminate with extra \0
  1107.     fileDataLength++;
  1108.  
  1109.     // free file list
  1110.     for (i=0;i<numFiles;i++)
  1111.         if (fileList[i]) XP_FREE(fileList[i]);
  1112.     delete fileList;
  1113.     
  1114.     *value=(XtPointer)fileData;
  1115.     *length=fileDataLength;
  1116. }
  1117.  
  1118.  
  1119. void XFE_DragDesktop::getTargetDataAsFileList(Atom,char ***fileList,int *numFiles)
  1120. {
  1121.     *fileList=NULL;
  1122.     *numFiles=0;
  1123.     return;
  1124. }
  1125.  
  1126. const char *XFE_DragDesktop::getTargetFTRType(Atom)
  1127. {
  1128.     return DEFAULT_FTR_TYPE;
  1129. }
  1130.  
  1131. void XFE_DragDesktop::dragDropFinishCb()
  1132. {
  1133.     XDEBUG(printf("XFE_DragDesktop::dragDropFinishCb()\n"));
  1134.     
  1135.     XFE_DragBase::dragDropFinishCb();
  1136.  
  1137.     // reset drag data
  1138.     _fileTarget=None;    
  1139. }
  1140.  
  1141.  
  1142. //
  1143. // XFE_DragNetscape
  1144. //      - provide support for all Netsape drag types
  1145. // and their conversion to a desktop file format. No actual
  1146. // drag targets are specified by this class. Derived class
  1147. // must specify targets(), operations() and getTargetData()
  1148. //
  1149.  
  1150. XFE_DragNetscape::XFE_DragNetscape(Widget w) : XFE_DragDesktop(w)
  1151. {
  1152.     _desktopFileData=NULL;
  1153. }
  1154.  
  1155. XFE_DragNetscape::~XFE_DragNetscape()
  1156. {
  1157.     if (_desktopFileData) {
  1158.         _desktopFileData->cleanupDataFiles();
  1159.         delete _desktopFileData;
  1160.         _desktopFileData=NULL;
  1161.     }
  1162. }
  1163.  
  1164.  
  1165. void XFE_DragNetscape::getTargetDataAsFileList(Atom target,char ***fileList,int *numFiles)
  1166. {
  1167.     *numFiles=0;
  1168.     *fileList=NULL;
  1169.  
  1170.     if (_desktopFileData!=NULL) {
  1171.         // make sure we only have one set of tmp files per drag
  1172.         // (dumb or malicious drop site might ask for FILE_NAME and _SGI_ICON)
  1173.         return;
  1174.     }
  1175.     
  1176.     XDEBUG(printf("XFE_DragNetscape::getTargetDataAsFileList(%s)\n",XmGetAtomName(XtDisplay(_widget),target)));
  1177.            
  1178.     // XA_STRING - interpret data as name of existing file
  1179.     if (target==XA_STRING) {
  1180.         char *filename=getTargetData(XA_STRING);
  1181.         if (filename) {
  1182.             *numFiles=1;
  1183.             *fileList=new char*[1];
  1184.             (*fileList)[0]=filename;
  1185.         }
  1186.         return;
  1187.     }
  1188.  
  1189.     // XA_FILE_NAME - interpret data as name of existing file
  1190.     if (target==_XA_FILE_NAME) {
  1191.         char *filename=getTargetData(_XA_FILE_NAME);
  1192.         if (filename) {
  1193.             *numFiles=1;
  1194.             *fileList=new char*[1];
  1195.             (*fileList)[0]=filename;
  1196.         }
  1197.         return;
  1198.     }
  1199.  
  1200.     // _XA_NETSCAPE_URL - translate data into NetscapeURL desktop file(s)
  1201.     if (target==_XA_NETSCAPE_URL) {
  1202.         char *stringData=getTargetData(_XA_NETSCAPE_URL);
  1203.         if (!stringData)
  1204.             return;
  1205.  
  1206.         XFE_URLDesktopType *urlData=new XFE_URLDesktopType(stringData);
  1207.         *numFiles=urlData->numItems();
  1208.         if (*numFiles==0) {
  1209.             delete urlData;
  1210.             XtFree(stringData);
  1211.             return;
  1212.         }
  1213.         
  1214.  
  1215.         // write files to tmp directory
  1216.         urlData->writeDataFiles(_dragFilesAsLinks);
  1217.         
  1218.  
  1219.         // extract filenames of tmp files for drag response
  1220.         *fileList=new char*[*numFiles];
  1221.         int i;
  1222.         for (i=0;i<*numFiles;i++) {
  1223.             if (urlData->filename(i))
  1224.                 (*fileList)[i]=XP_STRDUP(urlData->filename(i));
  1225.             else
  1226.                 (*fileList)[i]=NULL;
  1227.         }
  1228.         
  1229.         // save desktop tmp file data  for cleanup at end of drag
  1230.         _desktopFileData=(XFE_DesktopType*)urlData;
  1231.  
  1232.         XtFree(stringData);
  1233.     }
  1234.  
  1235.     return;
  1236. }
  1237.  
  1238. const char *XFE_DragNetscape::getTargetFTRType(Atom target)
  1239. {
  1240.     if (target==_XA_NETSCAPE_URL) return XFE_URLDesktopType::ftrType();
  1241.     
  1242.     return DEFAULT_FTR_TYPE;
  1243. }
  1244.  
  1245.  
  1246. void XFE_DragNetscape::dragDropFinishCb()
  1247. {
  1248.     XFE_DragDesktop::dragDropFinishCb();
  1249.  
  1250.     // cleanup temporary directory and files used for Netscape data
  1251.     if (_desktopFileData) {
  1252.         _desktopFileData->cleanupDataFiles();
  1253.         delete _desktopFileData;
  1254.         _desktopFileData=NULL;
  1255.     }
  1256. }
  1257.  
  1258.  
  1259. //
  1260. // XFE_DropBase
  1261. //
  1262.  
  1263. //
  1264. // callback stubs
  1265. //
  1266.  
  1267. void XFE_DropBase::DragProc(Widget w, XtPointer,XtPointer cb)
  1268. {
  1269.     XtPointer ud;
  1270.     XtVaGetValues(w,XmNuserData,&ud,NULL);
  1271.     XFE_DropBase *d=(XFE_DropBase*)ud;
  1272.     if (d)
  1273.         d->dragProc((XmDragProcCallbackStruct*)cb);
  1274. }
  1275.  
  1276.  
  1277. void XFE_DropBase::DropProc(Widget w,XtPointer,XtPointer cb) {
  1278.     XtPointer ud;
  1279.     XtVaGetValues(w,XmNuserData,&ud,NULL);
  1280.     XFE_DropBase *d=(XFE_DropBase*)ud;
  1281.     if (d)
  1282.         d->dropProc((XmDropProcCallbackStruct*)cb);
  1283. }
  1284.  
  1285. void XFE_DropBase::DestroyCb(Widget,XtPointer cd,XtPointer) {
  1286.     XFE_DropBase *d=(XFE_DropBase*)cd;
  1287.     if (d)
  1288.         d->dropComplete();
  1289. }
  1290.  
  1291. void XFE_DropBase::TransferProc(Widget w, XtPointer cd, Atom */*seltype*/, Atom *type,
  1292.                             XtPointer value, unsigned long *length, int */*format*/)
  1293. {
  1294. #if defined(DEBUG_tao)
  1295.     printf("\nXFE_DropBase::TransferProc, value=%x\n", value);
  1296. #endif
  1297.     XFE_DropBase *d=(XFE_DropBase*)cd;
  1298.     if (d)
  1299.         d->transferProc(w,*type,value,(unsigned int)*length);
  1300. }
  1301.  
  1302.  
  1303. // constructor
  1304.  
  1305. XFE_DropBase::XFE_DropBase(Widget widget)
  1306. {
  1307.     _widget=widget;
  1308.     _operations=(unsigned int)XmDROP_NOOP;
  1309.     _targets=NULL;
  1310.     _numTargets=0;
  1311.     _dropEventX=0;
  1312.     _dropEventY=0;
  1313.     _chosenTarget=None;
  1314.  
  1315.     InitializeDisplayInfo(widget);
  1316.     
  1317.     // create drop site, disabled by default
  1318. #ifdef DROP_ENABLED    
  1319.     Arg args[20];
  1320.     int n=0;
  1321.     XtSetArg(args[n],XmNdragProc,DragProc); n++;
  1322.     XtSetArg(args[n],XmNdropProc,DropProc); n++;
  1323.     XtSetArg(args[n],XmNdropSiteActivity,XmDROP_SITE_INACTIVE);n++;
  1324.     XtSetArg(args[n],XmNdropSiteType,XmDROP_SITE_COMPOSITE);n++;
  1325.     
  1326.     XmDropSiteRegister(_widget, args, n);
  1327. #endif
  1328.     // make XFE_DropBase available to DragProc, DropProc
  1329.     XtVaSetValues(widget,XmNuserData,this,NULL);
  1330.  
  1331.     // initialize destroy callback struct
  1332.     _destroyCbList[0].callback=DestroyCb;
  1333.     _destroyCbList[0].closure=(XtPointer)this;
  1334.     _destroyCbList[1].callback=NULL;
  1335.     _destroyCbList[1].closure=NULL;
  1336. }
  1337.  
  1338.  
  1339. // destructor
  1340.  
  1341. XFE_DropBase::~XFE_DropBase()
  1342. {
  1343. #ifdef DROP_ENABLED
  1344.     //
  1345.     //    Don't do this, because XmDropSiteRegister() sets up a destroy
  1346.     //    callback that does this (well the equivelent). If it's called twice,
  1347.     //    we crash in _XmIEndUpdate()....djw
  1348. #if 0
  1349.     if (_widget)
  1350.         XmDropSiteUnregister(_widget);
  1351. #endif
  1352. #endif
  1353.     freeTargetList();
  1354. }
  1355.  
  1356. // convenience fn - allow easy cleanup of old targets
  1357.  
  1358. void XFE_DropBase::freeTargetList()
  1359. {
  1360.     if (_targets) {
  1361.         delete [] _targets;
  1362.         _targets=NULL;
  1363.     }
  1364.     _numTargets=0;
  1365. }
  1366.  
  1367.  
  1368. // drop site management
  1369.  
  1370. void XFE_DropBase::enable()
  1371. {
  1372.     // enable site
  1373. #ifdef DROP_ENABLED    
  1374.     Arg args[1];
  1375.     XtSetArg(args[0],XmNdropSiteActivity,XmDROP_SITE_ACTIVE);
  1376.     XmDropSiteUpdate(_widget,args,1);
  1377. #endif
  1378.     // set targets and operations
  1379.     // (can't do it in constructor because targets() and operations() are virtual)
  1380.     update();
  1381. }
  1382.  
  1383.  
  1384. void XFE_DropBase::disable()
  1385. {
  1386. #ifdef DROP_ENABLED    
  1387.     Arg args[1];
  1388.     XtSetArg(args[0],XmNdropSiteActivity,XmDROP_SITE_INACTIVE);
  1389.     XmDropSiteUpdate(_widget,args,1);
  1390. #endif    
  1391. }
  1392.  
  1393. void XFE_DropBase::update()
  1394. {
  1395.     // allow derived class to change attributes
  1396.     operations();
  1397.     freeTargetList();
  1398.     targets();
  1399.     
  1400.     // apply changes to drop site
  1401. #ifdef DROP_ENABLED    
  1402.     Arg args[20];
  1403.     int n=0;
  1404.     XtSetArg(args[n], XmNimportTargets, _targets); n++;
  1405.     XtSetArg(args[n], XmNnumImportTargets, _numTargets); n++;
  1406.     XtSetArg(args[n], XmNdropSiteOperations, _operations); n++;
  1407.     XmDropSiteUpdate(_widget,args,n);
  1408. #endif    
  1409. }
  1410.  
  1411. void XFE_DropBase::update(ArgList args,Cardinal n)
  1412. {
  1413.     // apply target/operation changes to drop site
  1414.     update();
  1415.  
  1416.     // apply user defined changes to drop site
  1417. #ifdef DROP_ENABLED    
  1418.     XmDropSiteUpdate(_widget,args,n);
  1419. #endif    
  1420.  
  1421. }
  1422.  
  1423. // override to set _operations
  1424.  
  1425. void XFE_DropBase::operations()
  1426. {
  1427.     _operations=(unsigned int) (XmDROP_MOVE | XmDROP_COPY);
  1428. }
  1429.  
  1430. // override to set _targets
  1431.  
  1432. void XFE_DropBase::targets()
  1433. {
  1434.     freeTargetList();
  1435.  
  1436.     _numTargets=1;
  1437.     _targets=new Atom[_numTargets];
  1438.  
  1439.     _targets[0]=XA_STRING;
  1440. }
  1441.  
  1442. // override to add drag-in feature
  1443. void XFE_DropBase::dragIn()
  1444. {
  1445.     XDEBUG(printf("XFE_DropBase::dragIn(%d,%d)\n",_dropEventX,_dropEventY));
  1446. }
  1447.  
  1448. // override to add drag-out feature
  1449.  
  1450. void XFE_DropBase::dragOut()
  1451. {
  1452.     XDEBUG(printf("XFE_DropBase::dragOut(%d,%d)\n",_dropEventX,_dropEventY));
  1453. }
  1454.  
  1455. // override to add drag-motion feature
  1456. void XFE_DropBase::dragMotion()
  1457. {
  1458.     // XDEBUG(printf("XFE_DropBase::dragMotion(%d,%d)\n",_dropEventX,_dropEventY));
  1459. }
  1460.  
  1461. // override to add operation-changed feature
  1462.  
  1463. void XFE_DropBase::operationChanged()
  1464. {
  1465. }
  1466.  
  1467. // override to add validation of drop targets
  1468.  
  1469. Atom XFE_DropBase::acceptDrop(unsigned int dropOperation,Atom *dropTargets,unsigned int numDropTargets)
  1470. {
  1471.     // pick first matching target in class's list, if operation is valid
  1472.     
  1473.     if (!(dropOperation & _operations))
  1474.         return None;
  1475.  
  1476.     Atom selected=None;
  1477.     
  1478.     XDEBUG(printf("TARGETS:\n"));
  1479. #if defined(DEBUG_tao)
  1480.     printf("\nXFE_DropBase::acceptDrop\n");
  1481.     for (int ii=0; ii < _numTargets; ii++)
  1482.         printf("\n_targets[%d]=%s", 
  1483.                ii, XGetAtomName(XtDisplay(_widget),_targets[ii]));
  1484.     for (int jj=0; jj < numDropTargets; jj++)
  1485.         printf("\ndropTargets[%d]=%s", 
  1486.                jj, XGetAtomName(XtDisplay(_widget),dropTargets[jj]));
  1487. #endif
  1488.     for (int i=0;i<_numTargets; i++) {
  1489.         for (int j=0; j < (int)numDropTargets; j++) {
  1490.              XDEBUG(if (i==0) printf("  %s\n",XGetAtomName(XtDisplay(_widget),dropTargets[j])));
  1491.             if (_targets[i]==dropTargets[j]) {
  1492.                 selected=dropTargets[j];
  1493.                 break;
  1494.             }
  1495.         }
  1496.         if (selected!=None)
  1497.             break;
  1498.     }
  1499.  
  1500.     return selected;
  1501. }
  1502.  
  1503.  
  1504. // override to tidy up after drop
  1505.  
  1506. void XFE_DropBase::dropComplete()
  1507. {
  1508. }
  1509.  
  1510. // callback methods
  1511.  
  1512. void XFE_DropBase::dragProc(XmDragProcCallbackStruct *cb)
  1513. {
  1514.     // record location of drop:
  1515.     _dropEventX=cb->x;
  1516.     _dropEventY=cb->y;
  1517.  
  1518.     switch(cb->reason) {
  1519.         case XmCR_DROP_SITE_ENTER_MESSAGE:
  1520.             // verify that this combo of operation and targets is acceptable
  1521.             if (cb->operation!=XmDROP_NOOP &&
  1522.                 acceptDropWrapper(cb->operation,cb->dragContext)!=None) {
  1523.                 cb->dropSiteStatus = XmVALID_DROP_SITE;
  1524.                 dragIn();
  1525.             }
  1526.             else {
  1527.                 cb->dropSiteStatus = XmINVALID_DROP_SITE;
  1528.             }
  1529.             break;
  1530.         case XmCR_DROP_SITE_LEAVE_MESSAGE:
  1531.             dragOut();
  1532.             break;
  1533.         case XmCR_DROP_SITE_MOTION_MESSAGE:
  1534.             dragMotion();
  1535.             break;
  1536.         case XmCR_OPERATION_CHANGED:
  1537.             operationChanged();
  1538.             break;
  1539.         default:
  1540.             cb->dropSiteStatus = XmINVALID_DROP_SITE;
  1541.             break;
  1542.     }
  1543.  
  1544.     // allow animation to be performed
  1545.     cb->animate = True;
  1546. }
  1547.  
  1548.  
  1549.  
  1550. void XFE_DropBase::dropProc(XmDropProcCallbackStruct *cb)
  1551. {
  1552.     if (cb->dropAction != XmDROP_HELP) {
  1553.         handleDrop(cb);
  1554.     }
  1555.     else {
  1556.         // option to display help dialog - we just cancel drag
  1557.         Arg args[10];
  1558.         int n=0;
  1559.         cb->dropSiteStatus=XmINVALID_DROP_SITE;
  1560.         XtSetArg(args[n],XmNtransferStatus,XmTRANSFER_FAILURE); n++;
  1561.         XtSetArg(args[n],XmNnumDropTransfers,0); n++;
  1562.         XmDropTransferStart(cb->dragContext,args,n);
  1563.         return;        
  1564.     }
  1565. }
  1566.  
  1567. void XFE_DropBase::handleDrop(XmDropProcCallbackStruct *cb)
  1568. {
  1569.     Arg args[10];
  1570.     int n;
  1571.  
  1572.     // record location of drop:
  1573.     _dropEventX=cb->x;
  1574.     _dropEventY=cb->y;
  1575.     
  1576.     // Cancel the drop on invalid drop operations
  1577.  
  1578.     if (cb->operation==XmDROP_NOOP) {
  1579.         n = 0;
  1580.         cb->dropSiteStatus = XmINVALID_DROP_SITE;
  1581.         XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
  1582.         XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
  1583.         XmDropTransferStart(cb->dragContext, args, n);
  1584.         return;
  1585.     }
  1586.  
  1587.     // select target based on operation and available targets
  1588.     // (remember chosen target for use later in tranfer proc. naughty
  1589.     // CDE file mgr doesn't give the target it was asked for.)
  1590.     
  1591.     _chosenTarget=acceptDropWrapper(cb->operation,cb->dragContext);
  1592.     
  1593.     if (_chosenTarget==None) { // transfer not valid
  1594.         n = 0;
  1595.         cb->operation = (unsigned char)XmDROP_NOOP;
  1596.         cb->dropSiteStatus = XmINVALID_DROP_SITE;
  1597.         XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
  1598.         XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
  1599.         XmDropTransferStart(cb->dragContext, args, n);
  1600.         return;
  1601.     }
  1602.     
  1603.     // start transfer
  1604.  
  1605.     XmDropTransferEntryRec transfers[2];
  1606.     Cardinal numTransfers = 1;
  1607.     transfers[0].target = _chosenTarget;
  1608.     transfers[0].client_data=(XtPointer)this;
  1609.  
  1610.     // send DELETE to drag source if this is a move
  1611.     if (cb->operation == XmDROP_MOVE) {
  1612.         transfers[1].target=_XA_DELETE;
  1613.         transfers[1].client_data=(XtPointer)this;
  1614.         numTransfers+=1;
  1615.     }
  1616.  
  1617.         
  1618.     n = 0;
  1619.     cb->dropSiteStatus = XmVALID_DROP_SITE;
  1620.     XtSetArg(args[n], XmNdropTransfers, transfers); n++;
  1621.     XtSetArg(args[n], XmNnumDropTransfers, numTransfers); n++;
  1622.     XtSetArg(args[n], XmNdestroyCallback, _destroyCbList); n++;
  1623.     XtSetArg(args[n], XmNtransferProc, TransferProc); n++;
  1624.     XmDropTransferStart(cb->dragContext, args, n);
  1625. }
  1626.  
  1627.  
  1628. void XFE_DropBase::transferProc(Widget dragContext,Atom type, XtPointer value,unsigned int length)
  1629. {
  1630.     // transfer data via dropTransfer()
  1631.  
  1632.     XDEBUG(printf("XFE_DropBase::transferProc(%s)\n",type ? XmGetAtomName(XtDisplay(_widget),type):"(null)"));
  1633.  
  1634.     // check for response to a DELETE message - no action required
  1635.     if (type==None || type==_XA_NULL) {
  1636.         return;
  1637.     }
  1638.     
  1639.     if (value && length>0) {
  1640.         if (isFileTarget(_chosenTarget) &&
  1641.             (type==_chosenTarget || type==XA_STRING)) {
  1642.             // process file targets in XFE_DropDesktop
  1643.             // (test for XA_STRING is a hack to deal with CDE 1.0 bug, where
  1644.             // dtfile returns STRING data in response to request for FILE_NAME.)
  1645.             if (processFileTargetWrapper(_chosenTarget,value,length))
  1646.                 return; // success
  1647.         }
  1648.         else {
  1649.             // package up item into drop list and pass to derived class method
  1650.             Atom *targets=new Atom[1];
  1651.             const char **dropData=new const char*[1];
  1652.             char *dropInfo=new char[length+1];
  1653.             memcpy(dropInfo,(char*)value,length);
  1654.             dropInfo[length]='\0';
  1655.             targets[0]=type;
  1656.             dropData[0]=dropInfo;
  1657.             int dropStatus=processTargets(targets,dropData,1);
  1658.             delete [] targets;
  1659.             delete dropData;
  1660.             delete dropInfo;
  1661.  
  1662.             if (dropStatus)
  1663.                 return; // success
  1664.         }    
  1665.     }
  1666.     else {
  1667.         // transfer failed
  1668.         XtVaSetValues(dragContext,
  1669.                       XmNtransferStatus, XmTRANSFER_FAILURE,
  1670.                       XmNnumDropTransfers, 0,
  1671.                       NULL);
  1672.     }
  1673.     
  1674.     // nyi - is this right? doesn't Xt/Xm free this?, why not free above?
  1675.     if (value)
  1676.         XtFree((char*)value);
  1677. }
  1678.  
  1679. // wrapper around virtual function acceptDrop()
  1680. // (hide Motif cruft from dervived class)
  1681.  
  1682. Atom XFE_DropBase::acceptDropWrapper(unsigned int op,Widget dragContext)
  1683. {
  1684.     Atom *exportTargets=NULL;
  1685.     Cardinal numExportTargets=0;
  1686.     XtVaGetValues(dragContext,
  1687.                   XmNexportTargets, &exportTargets,
  1688.                   XmNnumExportTargets, &numExportTargets,
  1689.                   NULL);
  1690.     if (exportTargets && numExportTargets>0)
  1691.         return acceptDrop(op,exportTargets,numExportTargets);
  1692.     else
  1693.         return None;
  1694. }
  1695.  
  1696.  
  1697. //
  1698. // XFE_DropDesktop
  1699. //
  1700.  
  1701. // constructor
  1702.  
  1703. XFE_DropDesktop::XFE_DropDesktop(Widget widget) : XFE_DropBase(widget)
  1704. {
  1705. }
  1706.  
  1707.  
  1708. // destructor
  1709.  
  1710. XFE_DropDesktop::~XFE_DropDesktop()
  1711. {
  1712. }
  1713.  
  1714. //
  1715. // methods below override XFE_DropBase defaults
  1716. //
  1717.  
  1718. // desktop file types we understand
  1719. int XFE_DropDesktop::isFileTarget(Atom target)
  1720. {
  1721.     return (target==_XA_SGI_ICON ||
  1722.             target==_XA_SGI_FILE ||
  1723.             target==_XA_SGI_URL ||
  1724.             target==_XA_FILE_NAME)
  1725.         ? TRUE : FALSE;
  1726. }
  1727.  
  1728. void XFE_DropDesktop::acceptFileTargets()
  1729. {
  1730.     if (!_targets || _numTargets==0)
  1731.         return;
  1732.  
  1733.     // insert desktop file dnd atoms into list
  1734.     // must insert before generic STRING - some desktops (IRIX 6.3+)
  1735.     // will provide filename or URL as STRING - we want all the info
  1736.     Atom *newTargets=new Atom[_numTargets+5];
  1737.     int i=0;
  1738.     int ni=0;
  1739.     int added=FALSE;
  1740.     while (i<_numTargets) {
  1741.         if (_targets[i]==XA_STRING) {
  1742.             newTargets[ni++]=_XA_SGI_URL;
  1743.             newTargets[ni++]=_XA_SGI_ICON;
  1744.             newTargets[ni++]=_XA_SGI_FILE;
  1745.             newTargets[ni++]=_XA_FILE_NAME;
  1746.             newTargets[ni++]=_XA_TARGETS; // debugging hack - force display of all targets
  1747.             added=TRUE;
  1748.         }
  1749.         newTargets[ni++]=_targets[i++];
  1750.     }
  1751.     if (!added) {
  1752.         // no STRING in targets list, so append
  1753.         newTargets[ni++]=_XA_SGI_URL;
  1754.         newTargets[ni++]=_XA_SGI_ICON;
  1755.         newTargets[ni++]=_XA_SGI_FILE;
  1756.         newTargets[ni++]=_XA_FILE_NAME;
  1757.         newTargets[ni++]=_XA_TARGETS; // debugging hack - force display of all targets
  1758.     }
  1759.     
  1760.     delete [] _targets;
  1761.     _targets=newTargets;
  1762.     _numTargets=ni;
  1763. }
  1764.  
  1765. // process dropped data
  1766.  
  1767. int XFE_DropDesktop::processFileTargetWrapper(Atom type,XtPointer value,unsigned int length)
  1768. {
  1769.     if (!value || length==0)
  1770.         return FALSE;
  1771.  
  1772.     int dropStatus=FALSE;
  1773.     
  1774.     char *dropInfo=new char[length+1];
  1775.     memcpy(dropInfo,(char*)value,length);
  1776.     dropInfo[length]='\0';
  1777.     
  1778.     if (type==_XA_SGI_URL)
  1779.         dropStatus=processSGI_URL(dropInfo,length);
  1780.     else if (type==_XA_SGI_FILE)
  1781.         dropStatus=processFILE_NAME(dropInfo,length);
  1782.     else if (type==_XA_SGI_ICON)
  1783.         dropStatus=processSGI_ICON(dropInfo,length);
  1784.     else if (type==_XA_FILE_NAME)
  1785.         dropStatus=processFILE_NAME(dropInfo,length);
  1786.  
  1787.     delete dropInfo;
  1788.     
  1789.     return dropStatus;
  1790. }
  1791.  
  1792.  
  1793. int XFE_DropDesktop::processSGI_URL(char *dropInfo,unsigned int /*length*/)
  1794. {
  1795.     // parse url and title out of SGI_URL drop info
  1796.     
  1797.     char *url=NULL;
  1798.     char *title=NULL;
  1799.  
  1800.     // url
  1801.     char *urlStart=strstr(dropInfo,"SRC=\"");
  1802.     if (urlStart) {
  1803.         urlStart+=5;
  1804.         char *end=urlStart;
  1805.         while (*end && *end!='\"') // look for closing quotes
  1806.             end++;
  1807.         int len=end-urlStart;
  1808.         if (len>0) {
  1809.             url=new char[len+1];
  1810.             strncpy(url,urlStart,len);
  1811.             url[len]='\0';
  1812.         }
  1813.     }
  1814.  
  1815.     // title
  1816.     char *titleStart=strstr(dropInfo,"TITLE=\"");
  1817.     if (titleStart) {
  1818.         titleStart+=7;
  1819.         char *end=titleStart;
  1820.         while (*end && !(*end=='\"' && *(end-1)!='\\')) // look for non-escaped closing quotes
  1821.             end++;
  1822.         int len=end-titleStart;
  1823.         if (len>0) {
  1824.             title=new char[len+1];
  1825.             strncpy(title,titleStart,len);
  1826.             title[len]='\0';
  1827.         }
  1828.     }
  1829.  
  1830.     // should this be a list, separated by '\0'?
  1831.     int dropStatus=processDesktopURLTarget(title,url);
  1832.     
  1833.     if (url)
  1834.         delete url;
  1835.     if (title)
  1836.         delete title;
  1837.  
  1838.     return dropStatus;
  1839. }
  1840.  
  1841.  
  1842. int XFE_DropDesktop::processSGI_ICON(char *dropInfo,unsigned int length)
  1843. {
  1844.     const int FTR_MAX_SIZE=128; // from ftr header files
  1845.     const char SGI_ICON_FORMAT[] =
  1846.         "Category:%s Name:%s Type:%s Host:%s ViewX:%d ViewY:%d ViewGallery:%d";
  1847.     
  1848.     const int MAX_FILES=200;
  1849.     char *files[MAX_FILES];
  1850.     int numFiles=0;
  1851.  
  1852.     // parse individual files out of _SGI_ICON drop info
  1853.     
  1854.     char *start=dropInfo;;
  1855.     while (start<dropInfo+length && numFiles<MAX_FILES) {
  1856.         if (strlen(start)>0) {
  1857.  
  1858.             // parse _SGI_ICON data using standard format
  1859.             char filename[MAXPATHLEN]="";
  1860.             char ftrname[FTR_MAX_SIZE]="";
  1861.             char category[FTR_MAX_SIZE]="";
  1862.             char hostName[MAXHOSTNAMELEN]="";
  1863.             int viewx=0, viewy=0, gal=0;
  1864.             
  1865.             int numFields=sscanf(start, SGI_ICON_FORMAT,
  1866.                                category, filename, ftrname,
  1867.                                hostName, &viewx, &viewy, &gal);
  1868.             
  1869.             // ignore files located on remote hosts
  1870.             // (test strips off domain name, uses only host name)
  1871.             char *dot;
  1872.             if (dot=strchr(hostName,'.'))
  1873.                 *dot='\0';
  1874.             if (strcmp(hostName,localHostName)==0) {
  1875.                 // copy into file list
  1876.                 files[numFiles++]=strdup(filename);
  1877.             }
  1878.         }
  1879.         
  1880.         start+=strlen(start)+1;         // move to next file     
  1881.     }
  1882.  
  1883.     int dropStatus=processFileTarget((const char**)files,numFiles);
  1884.  
  1885.     // free file name strings and list
  1886.     for (int i=0;i<numFiles;i++)
  1887.         if (files[i]) free((void*)files[i]);
  1888.  
  1889.     return dropStatus;
  1890. }
  1891.  
  1892. int XFE_DropDesktop::processFILE_NAME(char *dropInfo,unsigned int length)
  1893. {
  1894.     const int MAX_FILES=200;
  1895.     char *files[MAX_FILES];
  1896.     int numFiles=0;
  1897.     int dropStatus=FALSE;
  1898.  
  1899.     // parse individual files out of drop info
  1900.  
  1901.     char *start=dropInfo;;
  1902.     while (start<dropInfo+length && numFiles<MAX_FILES) {
  1903.         // detect end of chunk, separated by null
  1904.         char *end=start;
  1905.         while(*end!='\0' && end<dropInfo+length)
  1906.             end++;
  1907.         *end='\0';  // ensure this chunk is terminated
  1908.         
  1909.         if (strlen(start)>0) {
  1910.             if (NET_URL_Type(start)==0) {
  1911.                 files[numFiles++]=start;       // add to file drop list
  1912.             }
  1913.         }
  1914.         
  1915.         start=end+1;     
  1916.     }
  1917.     
  1918.     if (processFileTarget((const char**)files,numFiles))
  1919.         dropStatus=TRUE;
  1920.     
  1921.     return dropStatus;
  1922. }
  1923.  
  1924. //
  1925. // XFE_DropNetscape
  1926. //
  1927.  
  1928. // constructor
  1929.  
  1930. XFE_DropNetscape::XFE_DropNetscape(Widget widget) : XFE_DropDesktop(widget)
  1931. {
  1932. }
  1933.  
  1934.  
  1935. // destructor
  1936.  
  1937. XFE_DropNetscape::~XFE_DropNetscape()
  1938. {
  1939. }
  1940.  
  1941. //
  1942. // methods below override XFE_DropDesktop defaults
  1943. //
  1944.  
  1945. int XFE_DropNetscape::processFileTarget(const char**files,int numFiles)
  1946. {
  1947.     XDEBUG(printf("XFE_DropNetscape::processFileTarget()\n"));
  1948.  
  1949.     Atom *targets=new Atom[numFiles];
  1950.     const char **data=new const char*[numFiles];
  1951.     const int MAX_LENGTH=4000;
  1952.     char line[MAX_LENGTH+1];
  1953.     line[MAX_LENGTH]='\0';
  1954.  
  1955.     int i;
  1956.  
  1957.     // build list of dropped items
  1958.     for (i=0;i<numFiles;i++) {
  1959.         // default is regular file
  1960.         targets[i]=_XA_FILE_NAME;
  1961.         data[i]=files[i];
  1962.         
  1963.         // if it's a Netscape desktop file, extract the data
  1964.         FILE *fp;
  1965.         if (fp=fopen(files[i],"r")) {
  1966.             line[0]='\0'; // ensure string will be null-terminated
  1967.             fgets(line,MAX_LENGTH,fp);
  1968.  
  1969.             // NetscapeURL
  1970.             if (XFE_URLDesktopType::isDesktopType(line)) {
  1971.                 targets[i]=_XA_NETSCAPE_URL;
  1972.                 XFE_URLDesktopType urlData(fp);
  1973.                 const char *str=urlData.getString();    
  1974.                 data[i]=(str ? XP_STRDUP(str) : 0);
  1975.             }
  1976.             
  1977.             // nyi - check for other Netscape desktop types here
  1978.             // (are no others..  yet.)
  1979.             fclose(fp);
  1980.         }
  1981.     }
  1982.  
  1983.     int dropStatus=processTargets(targets,data,numFiles);
  1984.  
  1985.     // free our copy of non-file data (FILE_NAME's were not copied)
  1986.     for (i=0;i<numFiles;i++) {
  1987.         if (targets[i]!=_XA_FILE_NAME)
  1988.             if (data[i])
  1989.                 XP_FREE((void*)data[i]);
  1990.     }
  1991.     
  1992.     delete [] targets;
  1993.     delete data;
  1994.     
  1995.     return dropStatus;
  1996. }
  1997.  
  1998. //
  1999. // translate desktop URL type into a NetscapeURL
  2000. //
  2001. int XFE_DropNetscape::processDesktopURLTarget(const char *title,const char *url)
  2002. {
  2003.     XDEBUG(printf("XFE_DropNetscape::processDesktopURLTarget(%s,%s)\n",title,url));
  2004.  
  2005.     if (!url)
  2006.         return FALSE;
  2007.     
  2008.     Atom targets[1];
  2009.     const char *data[1];
  2010.  
  2011.     targets[0]=_XA_NETSCAPE_URL;
  2012.     XFE_URLDesktopType urlData;
  2013.     urlData.createItemList(1);
  2014.     urlData.url(0,url);
  2015.     if (title) urlData.title(0,title);
  2016.     
  2017.     const char *str=urlData.getString();
  2018.     if (str) {
  2019.         data[0]=str;
  2020.         int dropStatus=processTargets(targets,data,1);
  2021.     // nyi - when we add more data, do cleanup here.
  2022.         return dropStatus;
  2023.     }
  2024.     else {
  2025.         return FALSE;
  2026.     }
  2027.  
  2028.     // nyi - delete data and/or contents?
  2029. }
  2030.  
  2031.  
  2032.