Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtfile / File.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: File.c /main/22 1999/12/09 13:05:50 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           File.c
28  *
29  *   COMPONENT_NAME: Desktop File Manager (dtfile)
30  *
31  *   Description:    File processing functions.
32  *
33  *   FUNCTIONS: ABS
34  *              AddFileIcons
35  *              BuildObjectPositions
36  *              CommitWorkProcUpdates
37  *              CompressObjectList
38  *              CopyOrderedEntries
39  *              CreateNameChangeDialog
40  *              CreateTreeIcons
41  *              DeselectAllFiles
42  *              DeselectFile
43  *              DestroyIconName
44  *              DisplaySomeIcons
45  *              DisplayWorkProc
46  *              DragFinishCB
47  *              DrawingAreaRedisplay
48  *              DropOnRootCB
49  *              EraseTreeLines
50  *              EstimateIconSize
51  *              FileConvertCB
52  *              FileDateAscending
53  *              FileDateDescending
54  *              FileIconMotion
55  *              FileIsSelected
56  *              FileNameAscending
57  *              FileNameDescending
58  *              FileSizeAscending
59  *              FileSizeDescending
60  *              FileTypeAscending
61  *              FileTypeDescending
62  *              FilterFiles
63  *              FindCurrentPosition
64  *              FlattenTree
65  *              FmPopup
66  *              FreeLayoutData
67  *              GetAncestorInfo
68  *              GetBottomOfStack
69  *              GetDirName
70  *              GetDragIcon
71  *              GetDragIconMask
72  *              GetExtraHeight
73  *              GetFullName
74  *              GetIconLayoutParms
75  *              GetInsertPosition
76  *              GetLevel
77  *              GetPositionalData
78  *              GetSelectedCount
79  *              GetStrcollProc
80  *              GetTopOfStack
81  *              GetTreebtnPixmap
82  *              HorizontalScrollbarIsVisible
83  *              IconCallback
84  *              InMultipleObjectRegion
85  *              InitiateIconDrag
86  *              IntersectRects
87  *              IsButtonOrMotion
88  *              IsDesktopPtr
89  *              LayoutDesktopIcons
90  *              LayoutFileIcons
91  *              MakeReuseList
92  *              NewConvertDelete
93  *              NewConvertFileName
94  *              OrderChildrenList
95  *              OrderFiles
96  *              PositionDesktopIcon
97  *              PositionFileView
98  *              RedisplayUsingStackingOrder
99  *              RedrawOneGadget
100  *              RedrawTreeLines
101  *              RegisterDesktopHotspots
102  *              RelocateDesktopIcon
103  *              ReorderChildrenList
104  *              RepaintDesktop
105  *              RepairFileWindow
106  *              RepairStackingPointers
107  *              RepositionIcons
108  *              RepositionUpInStack
109  *              RestorePositionalData
110  *              SavePositionalData
111  *              SelectAllFiles
112  *              SelectFile
113  *              SetFileSelected
114  *              SetFileUnselected
115  *              SetHotRects
116  *              SetToNormalColors
117  *              SetToSelectColors
118  *              SpecialCases
119  *              StartDrag
120  *              StrCaseCmp
121  *              ToBeManaged
122  *              TreeBtnCallback
123  *              TreeLX
124  *              TreeOneWd
125  *              TreeWd
126  *              TypeToAction
127  *              TypeToDropOperations
128  *              UnmanageFileIcons
129  *              UnpostTextField
130  *              UnpostTextPath
131  *              UpdateFileIcons
132  *              UpdateOneFileIcon
133  *              UpdateOneIconLabel
134  *              VerticalScrollbarIsVisible
135  *              WidgetCmp
136  *              YSPACING
137  *              _UpdateFileIcons
138  *              InputForGadget
139  *              InputInGadget
140  *
141  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
142  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
143  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
144  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
145  *
146  ****************************************************************************
147  ************************************<+>*************************************/
148
149 #include <string.h>
150 #include <locale.h>
151 #include <ctype.h>
152
153 #include <Xm/XmP.h>
154 #include <Xm/Xm.h>
155 #include <Xm/BulletinB.h>
156 #include <Xm/MwmUtil.h>
157 #include <X11/ShellP.h>
158 #include <X11/Shell.h>
159 #include <X11/Xutil.h>
160 #include <X11/Xatom.h>
161 #include <X11/keysymdef.h>
162
163 #ifdef SHAPE
164 #include <X11/extensions/shape.h>
165 #endif
166
167 #include <Xm/DrawingA.h>
168 #include <Xm/DrawingAP.h>
169 #include <Xm/RowColumn.h>
170 #include <Xm/LabelG.h>
171 #include <Xm/PushBG.h>
172 #include <Xm/SeparatoG.h>
173 #include <Xm/ScrollBar.h>
174 #include <Xm/TextF.h>
175 #include <Xm/Frame.h>
176 #include <Xm/Screen.h>
177 #include <sys/types.h>
178 #include <sys/stat.h>
179 #include <Dt/Icon.h>
180 #include <Dt/IconP.h>
181 #include <Dt/IconFile.h>
182
183 #include <Xm/DragIcon.h>
184 #include <Xm/DragC.h>
185 #include <Dt/Dnd.h>
186
187 #include <time.h>
188 #include <utime.h>
189
190 #include <Dt/Action.h>
191 #include <Dt/Connect.h>
192 #include <Dt/Wsm.h>
193 #include <Dt/DtNlUtils.h>
194 #include <Dt/HourGlass.h>
195 #include <Dt/Dts.h>
196 #include <Dt/UserMsg.h>
197
198 #include <Tt/tttk.h>
199
200 #include "Encaps.h"
201 #include "SharedProcs.h"
202 #include "FileMgr.h"
203 #include "Desktop.h"
204 #include "Main.h"
205 #include "Prefs.h"
206 #include "Common.h"
207 #include "Filter.h"
208 #include "Help.h"
209 #include "SharedMsgs.h"
210
211
212 extern Widget _DtDuplicateIcon ( Widget, Widget, XmString, String, XtPointer, Boolean );
213
214 /* absolute value macro */
215 #ifndef ABS
216 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
217 #endif
218
219 #define INIT_VALUE 5
220
221 /*
222  * MAXWINSIZE: maximum width of the file window
223  *
224  * Note: the file window width and height can't exceed the maximum value
225  * for a short (32767), because x and y coords of the icon gadgets placed
226  * in the file window are stored as short's by the Xt library (the
227  * Position type is a short).
228  *   Furthermore, somewhere in the code for registering icon drop sites
229  * in libDt or libXm calculations are done that overflow if the window
230  * size is too close to the maximum of 32767.  The symptom is observed
231  * most easily in tree mode on a directory large enough for icons to
232  * overflow into a second column: for values of MAXWINSIZE of 32767,
233  * none of the icons are sensitive as drop sites any more.  The value
234  * for MAXWINSIZE defined below has been found to be "safe" by experiment.
235  */
236 #define MAXWINSIZE 32600
237
238 /********    Static Function Declarations    ********/
239
240 static int FileNameAscending(
241                         FileViewData **t1,
242                         FileViewData **t2) ;
243 static int FileNameDescending(
244                         FileViewData **t1,
245                         FileViewData **t2) ;
246 static int FileTypeAscending(
247                         FileViewData **t1,
248                         FileViewData **t2) ;
249 static int FileTypeDescending(
250                         FileViewData **t1,
251                         FileViewData **t2) ;
252 static int FileSizeAscending(
253                         FileViewData **t1,
254                         FileViewData **t2) ;
255 static int FileSizeDescending(
256                         FileViewData **t1,
257                         FileViewData **t2) ;
258 static int FileDateAscending(
259                         FileViewData **t1,
260                         FileViewData **t2) ;
261 static int FileDateDescending(
262                         FileViewData **t1,
263                         FileViewData **t2) ;
264 static void CompressObjectList (
265                         ObjectPosition ** object_positions,
266                         int num_objects,
267                         int starting_index) ;
268 static ObjectPosition *GetPositionalData (
269                         FileMgrData * file_mgr_data,
270                         FileViewData * object,
271                         Dimension max_width,
272                         Boolean create) ;
273 static void RedisplayUsingStackingOrder (
274                         FileMgrData * file_mgr_data,
275                         Widget w,
276                         register XEvent *event,
277                         Region region) ;
278 static void ReorderChildrenList (
279                         XmManagerWidget file_window,
280                         Widget * manage,
281                         int manageCount,
282                         Widget * unmanage,
283                         int unmanageCount) ;
284 static Boolean IsDesktopPtr (
285                         FileViewData * fileViewData,
286                         FileMgrData ** fileMgrData,
287                         DesktopRec ** desktopRec) ;
288 static Boolean IntersectRects(
289                         Position x1,
290                         Position y1,
291                         Dimension w1,
292                         Dimension h1,
293                         Position x2,
294                         Position y2,
295                         Dimension w2,
296                         Dimension h2 ) ;
297 static void InitiateIconDrag(
298                         FileViewData * fileViewData,
299                         int rootX,
300                         int rootY,
301                         XEvent * event );
302 static void RelocateDesktopIcon(
303                         DesktopRec * desktopRec,
304                         int root_x,
305                         int root_y);
306 static void BuildObjectPositions(
307                         FileMgrData *file_mgr_data);
308 static void moveCopyLinkCancel(
309                         Widget w,
310                         XtPointer client_data,
311                         XtPointer call_data );
312 static void moveCopyLinkOK(
313                         Widget w,
314                         XtPointer client_data,
315                         XtPointer call_data );
316 static void DropOnRootCB (
317                         Widget w,
318                         XtPointer client_data,
319                         XtPointer call_data);
320 static void _UpdateFileIcons(
321                         FileMgrRec *file_mgr_rec,
322                         FileMgrData *file_mgr_data,
323                         Boolean new_directory,
324                         DirectorySet * add_dir_set );
325 static void CreateTreeIcons(
326                         Widget w);
327 static void TreeBtnCallback(
328                         Widget w,
329                         XtPointer clientData,
330                         XmAnyCallbackStruct * callData );
331 static void LayoutDesktopIcons(
332                         FileMgrRec *file_mgr_rec,
333                         FileMgrData *file_mgr_data,
334                         FileViewData ** order_list,
335                         int order_count,
336                         Boolean turn_off_hourglass);
337 static XmGadget InputInGadget (
338                         Widget w,
339                         register int x,
340                         register int y);
341 static XmGadget InputForGadget (
342                         Widget cw,
343                         int x,
344                         int y);
345
346 /********    End Static Function Declarations    ********/
347
348 /* cursor for double-click-drag (@@@ should be a resource) */
349 static Cursor loc_cursor1 = None;
350 static Cursor loc_cursor2 = None;
351 #define DBLCLICK_DRAG_THRESHOLD 20
352
353 /* layout constants (@@@ could be made resources) */
354 #define MARGIN          5
355 #define XSPACING        5
356 #define YSPACING(fmd)                                                              \
357   (fmd->layout_data?                                                               \
358     (fmd->view != BY_NAME? - ((IconLayoutData *)fmd->layout_data)->highlight:      \
359                            - ((IconLayoutData *)fmd->layout_data)->highlight + 2): \
360     0)
361 #define TreeSep         5
362 #define TreeOffset      15
363 #define TreeOneWd(sz)     (TreeOffset + TreeBtnWd[sz]/2)
364 #define TreeLX(level,sz)  (TreeBtnWd[sz]/2 + ((level) - 1)*TreeOneWd(sz))
365 #define TreeWd(level,sz)  \
366   (TreeLX(level,sz) + TreeOffset + TreeBtnWd[sz] + TreeSep)
367
368 /* maximum size of the small, medium, and large tree buttons */
369 static int TreeBtnWd[3] = { 0, 0, 0 };
370 static int TreeBtnHt[3] = { 0, 0, 0 };
371
372 static int TreeNilWd[3] = { 0, 0, 0 };
373 static int TreeNilHt[3] = { 0, 0, 0 };
374
375 /* tree expansion circle pixmap indices */
376 typedef enum {
377   tpxNotRead,    /* dotted circle */
378   tpxError,      /* crossed circle */
379   tpxMore,       /* "+" circle */
380   tpxLess,       /* "-" circle */
381   tpxBoth,       /* "+/-" circle */
382   tpxEmpty,      /* empty circle */
383   tpxNil,        /* empty-set symbol */
384   tpxN
385 } TreePxId;
386
387 /* pixmaps for expand circles in tree mode */
388 static struct TreePx {
389   char *name;            /*   name of pixmap file */
390   Pixmap px[3];          /*   small, medium, and large pixmap */
391 } TreePxTab[tpxN] =
392 {
393   { "Dttvnor", NULL },
394   { "Dttverr",   NULL },
395   { "Dttvmor",    NULL },
396   { "Dttvlss",    NULL },
397   { "Dttvbth",    NULL },
398   { "Dttvemp",   NULL },
399   { "Dttvnil",     NULL },
400 };
401
402 static char *TreePxSuffix[3] = { ".s", ".m", ".l" };
403
404 /* value need to to convert drop position to icon placement */
405 static int dragIconPixmapOffsetX;
406 static int dragIconPixmapOffsetY;
407
408 /*  Local defines  */
409
410 #define FILE_MOVE       0
411 #define FILE_COPY       1
412 #define FILE_INVALID    2
413
414
415 FileMgrPopup fileMgrPopup = {NULL};
416
417
418 /************************************************************************
419  ************************************************************************
420  *
421  *      Comparison functions used for sorting the files
422  *
423  ************************************************************************
424  ************************************************************************/
425 /* only use when LANG=C on platforms that don't
426 provide strcasecmp().   Otherwise, use strcoll() */
427 static int
428 StrCaseCmp (
429               const char  *s1,
430               const char  *s2)
431 {
432   /* Note: This is not really a string case insensitive compare. So don't
433      even think of replacing it with any other library routines.
434   */
435   char *s1a = (char *)s1, *s2a = (char *)s2;
436
437   if (s1 == s2) return  0;
438
439   for (; tolower(*s1) == tolower(*s2); ++s1, ++s2) {
440     if (*s1 == '\0' )
441     {
442       /* File Manager depends heavily on this routine to position the
443          icons in its window.
444          We want case INSENSITIVE comparision, however when we have
445          2 same size and case equivalent strings i.e.   "A" and "a", we
446          need this routine to behave like a case SENSITIVE comparision, so
447          the position of the icon is constant so "A" is always
448          before "a".
449       */
450       if (*s2 == 0x0)
451       {
452         for (; *s1a == *s2a; ++s1a, ++s2a) {
453           if (*s1 == '\0' )
454             return 0;
455         }
456         return *s1a - *s2a;
457       }
458       else
459         return 0;
460     }
461   }
462
463   return tolower(*s1) - tolower(*s2);
464 }
465
466 StrcollProc FMStrcoll = NULL;
467
468 StrcollProc
469 GetStrcollProc(void)
470 {
471   int Clang = 0;
472 #if defined(__hpux)
473   struct locale_data * li;
474 #else
475   char * locale;
476 #endif
477
478 #define C_LANG  "C"
479
480    /* if locale is C, use the explicit case insensitive compare */
481 #if defined(__hpux)
482   li = getlocale(LOCALE_STATUS);
483   if ( NULL == li->LC_COLLATE_D || strcmp(C_LANG,li->LC_COLLATE_D) == 0 )
484     Clang = 1;
485 #else
486   locale = setlocale(LC_COLLATE,NULL); /* put locale in buf */
487   if (strcmp(locale,C_LANG) == 0)
488     Clang = 1;
489 #endif
490
491   if (Clang)
492     return StrCaseCmp;
493
494   return ((StrcollProc)strcoll);
495 }
496
497 static Boolean
498 SpecialCases(
499              FileViewData **t1,
500              FileViewData **t2,
501              int *rc )
502 {
503   /* Tree mode */
504   if (((FileMgrData *)((DirectorySet *)((*t1)->directory_set))->file_mgr_data)
505       ->show_type == MULTIPLE_DIRECTORY)
506   {
507     if (!(*t1)->file_data->is_subdir && (*t2)->file_data->is_subdir)
508       *rc = -1;
509     else if ((*t1)->file_data->is_subdir && !(*t2)->file_data->is_subdir)
510       *rc = 1;
511     else
512       return False;
513     return True;
514   }
515
516
517
518
519
520
521
522   /* Special files */
523   if (FMStrcoll ((*t1)->file_data->file_name, "." ) == 0 )
524   {
525     *rc = -1;
526     return True;
527   }
528
529   if (FMStrcoll ((*t1)->file_data->file_name, "..") == 0 )
530   {
531     if ( FMStrcoll ((*t2)->file_data->file_name, ".") == 0 )
532       *rc = 1;
533     else
534       *rc = -1;
535     return True;
536   }
537
538   if (FMStrcoll ((*t2)->file_data->file_name, ".") == 0 || FMStrcoll ((*t2)->file_data->file_name, "..") == 0)
539   {
540     *rc = 1;
541     return True;
542   }
543
544
545
546
547
548
549
550
551   /* Directories */
552   if (!(*t1)->file_data->is_subdir && (*t2)->file_data->is_subdir)
553   {
554     *rc = 1;
555     return True;
556   }
557
558   if ((*t1)->file_data->is_subdir && !(*t2)->file_data->is_subdir)
559   {
560     *rc = -1;
561     return True;
562   }
563
564   return False;
565 }
566
567 static int
568 FileNameAscending(
569         FileViewData **t1,
570         FileViewData **t2 )
571 {
572   int rc;
573
574   if( SpecialCases( t1, t2, &rc ) )
575     return rc;
576
577   if((*t1)->file_data->action_name == NULL)
578   {
579      if((*t2)->file_data->action_name == NULL)
580         rc = FMStrcoll((*t1)->file_data->file_name,
581                                               (*t2)->file_data->file_name);
582      else
583         rc = FMStrcoll((*t1)->file_data->file_name,
584                                               (*t2)->file_data->action_name);
585   }
586   else
587   {
588      if((*t2)->file_data->action_name != NULL)
589         rc = FMStrcoll((*t1)->file_data->action_name,
590                                               (*t2)->file_data->action_name);
591      else
592         rc = FMStrcoll((*t1)->file_data->action_name,
593                                               (*t2)->file_data->file_name);
594   }
595
596   return rc;
597 }
598
599 static int
600 FileNameDescending(
601         FileViewData **t1,
602         FileViewData **t2 )
603 {
604    int rc;
605
606    if( SpecialCases( t1, t2, &rc ) )
607      return rc;
608
609    if((*t1)->file_data->action_name == NULL)
610    {
611       if((*t2)->file_data->action_name == NULL)
612          rc = FMStrcoll((*t1)->file_data->file_name,
613                                               (*t2)->file_data->file_name);
614       else
615          rc = FMStrcoll((*t1)->file_data->file_name,
616                                               (*t2)->file_data->action_name);
617    }
618    else
619    {
620       if((*t2)->file_data->action_name != NULL)
621          rc = FMStrcoll((*t1)->file_data->action_name,
622                                               (*t2)->file_data->action_name);
623       else
624          rc = FMStrcoll((*t1)->file_data->action_name,
625                                               (*t2)->file_data->file_name);
626    }
627
628    if (rc <= -1)
629      return 1;
630
631    if (rc >= 1)
632      return -1;
633
634    return 0;
635 }
636
637 static int
638 FileTypeAscending(
639         FileViewData **t1,
640         FileViewData **t2 )
641 {
642   int rc;
643
644   if( SpecialCases( t1, t2, &rc ) )
645     return rc;
646
647   rc = strcoll( (*t1)->file_data->logical_type, (*t2)->file_data->logical_type );
648   if( rc == 0 )
649     rc = FileNameAscending( t1, t2 );
650   return rc;
651 }
652
653
654 static int
655 FileTypeDescending(
656         FileViewData **t1,
657         FileViewData **t2 )
658 {
659   int rc;
660
661   if( SpecialCases( t1, t2, &rc ) )
662     return rc;
663
664    rc = strcoll( (*t1)->file_data->logical_type, (*t2)->file_data->logical_type );
665
666    if (rc <= -1)
667      return 1;
668
669    if (rc >= 1)
670      return -1;
671
672    rc = FileNameDescending( t1, t2 );
673
674    return rc;
675 }
676
677 static int
678 FileSizeAscending(
679         FileViewData **t1,
680         FileViewData **t2 )
681 {
682   int rc;
683
684   if( SpecialCases( t1, t2, &rc ) )
685     return rc;
686
687   if ((*t1)->file_data->stat.st_size < (*t2)->file_data->stat.st_size)
688     return -1;
689
690   else if ((*t1)->file_data->stat.st_size > (*t2)->file_data->stat.st_size)
691     return 1;
692
693   return 0;
694 }
695
696 static int
697 FileSizeDescending(
698         FileViewData **t1,
699         FileViewData **t2 )
700 {
701   int rc;
702
703   if( SpecialCases( t1, t2, &rc ) )
704     return rc;
705
706   if ((*t1)->file_data->stat.st_size < (*t2)->file_data->stat.st_size)
707     return 1;
708
709   if ((*t1)->file_data->stat.st_size > (*t2)->file_data->stat.st_size)
710     return -1;
711
712   return 0;
713 }
714
715 static int
716 FileDateAscending(
717         FileViewData **t1,
718         FileViewData **t2 )
719 {
720   int rc;
721
722   if( SpecialCases( t1, t2, &rc ) )
723     return rc;
724
725   if ((*t1)->file_data->stat.st_mtime < (*t2)->file_data->stat.st_mtime)
726     return -1;
727
728   if ((*t1)->file_data->stat.st_mtime > (*t2)->file_data->stat.st_mtime)
729     return 1;
730
731   return 0;
732 }
733
734 static int
735 FileDateDescending(
736         FileViewData **t1,
737         FileViewData **t2 )
738 {
739
740   int rc;
741
742   if( SpecialCases( t1, t2, &rc ) )
743     return rc;
744
745   if ((*t1)->file_data->stat.st_mtime < (*t2)->file_data->stat.st_mtime)
746     return 1;
747
748   if ((*t1)->file_data->stat.st_mtime > (*t2)->file_data->stat.st_mtime)
749     return -1;
750
751   return 0;
752 }
753
754
755
756
757
758 /************************************************************************
759  *
760  *  OrderFiles
761  *      Sort the file display list according to the ordering data.
762  *
763  ************************************************************************/
764
765 void
766 OrderFiles(
767         FileMgrData *file_mgr_data,
768         DirectorySet *directory_set )
769 {
770    FileViewData ** file_view_data;
771    int             file_count;
772    FileViewData ** order_list;
773    int * sort;
774    int * sub_sort;
775    register int i;
776    register int start;
777
778    file_view_data = directory_set->file_view_data;
779    file_count = directory_set->file_count;
780
781
782    /*  Allocate an ordering list  */
783
784    if (directory_set->order_list != NULL)
785    {
786       XtFree ((char *) directory_set->order_list);
787        directory_set->order_list = NULL;
788    }
789
790    if (file_count > 0)
791       directory_set->order_list = order_list =
792          (FileViewData **) XtMalloc (sizeof (FileViewData **) * file_count);
793    else
794       directory_set->order_list = order_list = NULL;
795
796    /*  Get pointers to all of the file data into the order list  */
797
798    for (i = 0; i < file_count; i++)
799       order_list[i] = file_view_data[i];
800
801    /*  Set up the sorting functions according to the order and direction.  */
802
803    sub_sort = NULL;
804
805    if (file_mgr_data->order == ORDER_BY_FILE_TYPE)
806    {
807       if (file_mgr_data->direction == DIRECTION_ASCENDING)
808       {
809          sort = (int *) FileTypeAscending;
810          sub_sort = (int *) FileNameAscending;
811       }
812       else
813       {
814          sort = (int *) FileTypeDescending;
815          sub_sort = (int *) FileNameDescending;
816
817       }
818    }
819    else if (file_mgr_data->order == ORDER_BY_ALPHABETICAL)
820    {
821       if (file_mgr_data->direction == DIRECTION_ASCENDING)
822          sort = (int *) FileNameAscending;
823       else
824          sort = (int *) FileNameDescending;
825    }
826    else if (file_mgr_data->order == ORDER_BY_DATE)
827    {
828       if (file_mgr_data->direction == DIRECTION_ASCENDING)
829          sort = (int *) FileDateAscending;
830       else
831          sort = (int *) FileDateDescending;
832
833    }
834    else if (file_mgr_data->order == ORDER_BY_SIZE)
835    {
836       if (file_mgr_data->direction == DIRECTION_ASCENDING)
837          sort = (int *) FileSizeAscending;
838       else
839          sort = (int *) FileSizeDescending;
840    }
841
842
843    /*  Sort the files and if the sub_sort function is non-null,  */
844    /*  sort sets of the files broken according to file type.     */
845
846    qsort (order_list, file_count, sizeof (FileViewData *), (int (*)())sort);
847
848    if (sub_sort != NULL)
849    {
850       start = 0;
851       i = 0;
852
853       while (i < file_count)
854       {
855          if (order_list[start]->file_data->logical_type !=
856              order_list[i]->file_data->logical_type)
857          {
858             qsort (order_list + start, i - start,
859                    sizeof (FileViewData *), (int (*)())sub_sort);
860             start = i;
861          }
862
863          i++;
864       }
865
866       qsort (order_list + start, i - start, sizeof (FileViewData *),
867                                                          (int (*)())sub_sort);
868    }
869 }
870
871
872
873 /************************************************************************
874  *
875  *  FilterFiles
876  *      Filter out the files which do not match the filtering criteria.
877  *
878  *      The `mustMatch' flag is used to determine whether the user has
879  *      requested that the files which match the specification are to
880  *      be displayed, or instead, filtered out.
881  *
882  ************************************************************************/
883
884 void
885 FilterFiles(
886         FileMgrData *file_mgr_data,
887         DirectorySet *directory_set )
888 {
889    FileViewData **file_view_data;
890    FilterData *   filter_data;
891    register int   i, j, k;
892    Boolean        show_hidden;
893    String         filter;
894    Boolean        mustMatch, matches;
895    int            filterCount = 0;
896    int            invisibleCount = 0;
897    FileViewData  *sub_root;
898 #ifdef DT_PERFORMANCE
899    struct timeval update_time_s;
900    struct timeval update_time_f;
901
902    printf("   Begin FilterFiles\n");
903    gettimeofday(&update_time_s, NULL);
904
905     /* added by Rafi */
906     _DtPerfChkpntMsgSend("Begin Filtering Files");
907
908 #endif
909
910    file_view_data = directory_set->file_view_data;
911
912    filter_data = (FilterData *)(file_mgr_data->filter_active->data);
913    show_hidden = filter_data->show_hidden;
914    filter = filter_data->filter;
915    mustMatch = filter_data->match_flag;
916
917    /* set the show hidden boolean depending on the filter specification */
918    if (show_hidden)
919       file_mgr_data->show_hid_enabled = True;
920    else
921       file_mgr_data->show_hid_enabled = False;
922
923    /*  Filter out all files not matching the specifications  */
924
925    for (i = 0; i < directory_set->file_count; i++)
926    {
927       /* Initially assume the file is not filtered out */
928
929       file_view_data[i]->filtered = False;
930
931       /* If in tree mode, explicitly filter out . and ..  */
932       if (file_mgr_data->show_type == MULTIPLE_DIRECTORY &&
933          (strcmp(file_view_data[i]->file_data->file_name, ".") == 0 ||
934           strcmp(file_view_data[i]->file_data->file_name, "..") == 0))
935       {
936          filterCount++;
937          file_view_data[i]->filtered = True;
938          continue;
939       }
940
941       /* filter out any files that have their attributes "invisible"   */
942       /* field set to false                                            */
943       if((_DtCheckForDataTypeProperty(
944              file_view_data[i]->file_data->logical_type,
945              "invisible")) &&
946          (file_mgr_data != trashFileMgrData))
947       {
948          filterCount++;
949          file_view_data[i]->filtered = True;
950          ++invisibleCount;
951          continue;
952       }
953
954       /* Filter hidden files, according to the user setting */
955
956       if (file_view_data[i]->file_data->file_name[0] == '.')
957       {
958          if(strcmp(file_mgr_data->current_directory, "/") == 0  &&
959               strcmp(file_view_data[i]->file_data->file_name, "..") == 0)
960          {
961             filterCount++;
962             file_view_data[i]->filtered = True;
963             continue;
964          }
965          if(file_mgr_data->restricted_directory != NULL)
966          {
967            if((strcmp(file_mgr_data->restricted_directory,
968                             file_mgr_data->current_directory) == 0 &&
969                        (strcmp(file_view_data[i]->file_data->file_name, ".") == 0 || strcmp(file_view_data[i]->file_data->file_name, "..") == 0 )) ||
970              (strncmp(file_mgr_data->restricted_directory,file_mgr_data->current_directory, strlen(file_mgr_data->restricted_directory)) == 0 &&
971                strcmp(file_view_data[i]->file_data->file_name, ".") == 0 ))
972            {
973              filterCount++;
974              file_view_data[i]->filtered = True;
975              continue;
976            }
977          }
978       }
979
980       if( restrictMode  &&
981            (strcmp(file_view_data[i]->file_data->file_name, "..") == 0 ||
982             strcmp(file_view_data[i]->file_data->file_name, ".") == 0))
983       {
984          char *tempName;
985
986          tempName = (char *)XtMalloc( strlen(file_mgr_data->current_directory) + 3);
987          sprintf( tempName, "%s/", file_mgr_data->current_directory );
988          if( strcmp(users_home_dir, tempName) == 0 ||
989              strcmp(users_home_dir, file_mgr_data->current_directory) == 0)
990          {
991             filterCount++;
992             file_view_data[i]->filtered = True;
993             XtFree(tempName);
994             continue;
995          }
996          XtFree(tempName);
997       }
998
999
1000       /* if we want to show the hidden files no more should be filtered out */
1001       if(show_hidden)
1002          continue;
1003
1004       /* don't show .trashinfo in the trash directory */
1005       if(trashFileMgrData == file_mgr_data &&
1006         (strcmp(file_view_data[i]->file_data->file_name, ".trashinfo") == 0))
1007       {
1008          filterCount++;
1009          file_view_data[i]->filtered = True;
1010          continue;
1011       }
1012
1013       /* Check for a match against the filter expression string, except for
1014        * files in the trash directory and sub directories in tree mode. */
1015
1016       matches = False;
1017       if (strcmp(filter, "") != 0 &&
1018           file_mgr_data != trashFileMgrData &&
1019           !(file_mgr_data->show_type == MULTIPLE_DIRECTORY &&
1020             file_view_data[i]->file_data->is_subdir))
1021       {
1022          /* Special case for ".." that need not be filtered */
1023          if( !strcmp( file_view_data[i]->file_data->file_name, ".." )
1024              || !strcmp( file_view_data[i]->file_data->file_name, "." ) )
1025          {
1026          }
1027          else if (file_view_data[i]->file_data->action_name)
1028          {
1029             if(fnmatch((const char *)filter,
1030                        (const char *)file_view_data[i]->file_data->action_name,
1031                        0) == 0)
1032             {
1033                 if ( mustMatch )
1034                 {
1035                     filterCount++;
1036                     file_view_data[i]->filtered = True;
1037                     continue;
1038                 }
1039                 else
1040                     matches = True;
1041             }
1042          }
1043          else if (fnmatch((const char *)filter,
1044              (const char *)file_view_data[i]->file_data->file_name, 0) == 0)
1045          {
1046             if ( mustMatch )
1047             {
1048                filterCount++;
1049                file_view_data[i]->filtered = True;
1050                continue;
1051             }
1052             else
1053                matches = True;
1054          }
1055       }
1056
1057       /* now lets check through the filter filetypes and if the file is  */
1058       /* filtered, filter it out                                         */
1059       if(file_mgr_data != trashFileMgrData)
1060       {
1061          /* This is for the case of files likes 'action' files which
1062             do not have a logical_type */
1063
1064          if(strcmp(file_view_data[i]->file_data->file_name,file_view_data[i]->
1065                     file_data->logical_type) == 0)
1066          {
1067             if(!filter_data->match_flag)
1068             {
1069               if(!matches)
1070               {
1071                filterCount++;
1072                file_view_data[i]->filtered = True;
1073               }
1074             }
1075          }
1076          else
1077            for(j = 0; j < filter_data->count; j++)
1078            {
1079              if(strcmp(filter_data->user_data[j]->filetype,
1080                        file_view_data[i]->file_data->logical_type) == 0)
1081              {
1082                 if((filter_data->user_data[j]->selected == True &&
1083                                                    filter_data->match_flag) ||
1084                 (filter_data->user_data[j]->selected == False &&
1085                                                    !filter_data->match_flag))
1086                 {
1087                    if(!matches)
1088                    {
1089                       filterCount++;
1090                       file_view_data[i]->filtered = True;
1091                    }
1092                 }
1093                 break;
1094              }
1095           }
1096       }
1097    }
1098
1099    /* update ndir, nfile counts for this sub directory */
1100    directory_set->filtered_file_count = filterCount;
1101    directory_set->invisible_file_count = invisibleCount;
1102    sub_root = directory_set->sub_root;
1103    sub_root->ndir = sub_root->nfile = 0;
1104    sub_root->nnew = 0;
1105
1106    for (i = 0; i < directory_set->file_count; i++)
1107    {
1108      if (!file_view_data[i]->filtered)
1109      {
1110        if (file_view_data[i]->file_data->is_subdir)
1111          sub_root->ndir++;
1112        else
1113          sub_root->nfile++;
1114      }
1115    }
1116
1117    UpdateBranchState(file_mgr_data, sub_root, BRANCH_UPDATE, False);
1118
1119 #ifdef DT_PERFORMANCE
1120    gettimeofday(&update_time_f, NULL);
1121    if (update_time_s.tv_usec > update_time_f.tv_usec) {
1122       update_time_f.tv_usec += 1000000;
1123       update_time_f.tv_sec--;
1124    }
1125    printf("    done FilterFiles, time: %ld.%ld\n\n", update_time_f.tv_sec - update_time_s.tv_sec, update_time_f.tv_usec - update_time_s.tv_usec);
1126
1127    /* added by Rafi */
1128    _DtPerfChkpntMsgSend("Done  Filtering Files");
1129
1130 #endif
1131 }
1132
1133
1134
1135
1136 /************************************************************************
1137  *
1138  *  GetAncestorInfo, GetLevel, GetFullName
1139  *
1140  ************************************************************************/
1141
1142 void
1143 GetAncestorInfo(
1144         FileMgrData *file_mgr_data,
1145         FileViewData *ip,
1146         int *levelp,
1147         char *path,
1148         Bool *morep)
1149 /*
1150  * Get information related to the ancestory of an entry:
1151  *  - tree depth level
1152  *  - full path name
1153  *  - for each level: flag indicating whether there are additional siblings
1154  *    to be diplayed after this entry
1155  */
1156 {
1157   FileViewData *pp, *pa[256];
1158   int i, l, level;
1159   char *p;
1160
1161   /* determine tree depth level of this entry */
1162   level = 0;
1163   for (pp = ip->parent; pp; pp = pp->parent)
1164     level++;
1165   if (levelp)
1166     *levelp = level;
1167
1168   /* get a list of all ancestors (including ip) in top down order */
1169   l = level;
1170   for (pp = ip; pp; pp = pp->parent)
1171     pa[l--] = pp;
1172
1173   /* construct path name of this entry */
1174   if (path) {
1175     strcpy(path, file_mgr_data->current_directory);
1176     p = path + strlen(path);
1177     for (l = 1; l <= level; l++) {
1178       if (p[-1] != '/')
1179         *p++ = '/';
1180       strcpy(p, pa[l]->file_data->file_name);
1181       p += strlen(p);
1182     }
1183   }
1184
1185   /* compile more array */
1186   if (morep) {
1187     for (l = 0; l <= level; l++) {
1188       DirectorySet *ds = (DirectorySet *)pa[l]->directory_set;
1189       morep[l] = False;
1190             if (ds->order_list == NULL)
1191         continue;
1192       for (i = 0; i < ds->file_count; i++)
1193         if (ds->order_list[i] == pa[l])
1194           break;
1195       for (i = i + 1; i < ds->file_count; i++) {
1196         if (ds->order_list[i]->displayed) {
1197           morep[l] = True;
1198           break;
1199         }
1200       }
1201     }
1202   }
1203 }
1204
1205
1206 void
1207 GetFullName(
1208         FileMgrData *file_mgr_data,
1209         FileViewData *ip,
1210         char *path)
1211 {
1212   GetAncestorInfo(file_mgr_data, ip, NULL, path, NULL);
1213 }
1214
1215
1216 void
1217 GetDirName(
1218         FileMgrData *file_mgr_data,
1219         FileViewData *ip,
1220         char *path)
1221 {
1222   char *p;
1223
1224   GetAncestorInfo(file_mgr_data, ip, NULL, path, NULL);
1225   p = strrchr(path, '/');
1226   *p = 0;
1227 }
1228
1229
1230 void
1231 GetLevel(
1232         FileViewData *ip,
1233         int *levelp)
1234 {
1235   int level = 0;
1236   for (ip = ip->parent; ip; ip = ip->parent)
1237     level++;
1238   *levelp = level;
1239 }
1240
1241
1242 /************************************************************************
1243  *
1244  *  FlattenTree
1245  *
1246  ************************************************************************/
1247
1248 static void
1249 CopyOrderedEntries(
1250         FileViewData *ip,
1251         FileViewData *fvd_array[],
1252         int *index)
1253 /*
1254  * Copy all entries from the tree to an array
1255  */
1256 {
1257   DirectorySet *directory_set;
1258   int i;
1259
1260   fvd_array[*index] = ip;
1261   (*index)++;
1262
1263   if (ip->desc)
1264   {
1265     directory_set = (DirectorySet *)ip->desc->directory_set;
1266     for (i = 0; i < directory_set->file_count; i++)
1267       CopyOrderedEntries(directory_set->order_list[i], fvd_array, index);
1268   }
1269 }
1270
1271
1272 void
1273 FlattenTree(
1274         FileMgrData *file_mgr_data,
1275         FileViewData ***file_view_data,
1276         int *file_count)
1277 {
1278   int i;
1279
1280   *file_count = 1;
1281   for (i = 0; i < file_mgr_data->directory_count; i++)
1282     *file_count += file_mgr_data->directory_set[i]->file_count;
1283
1284   *file_view_data =
1285     (FileViewData **) XtMalloc (*file_count * sizeof(FileViewData *));
1286   i = 0;
1287   CopyOrderedEntries(file_mgr_data->tree_root, *file_view_data, &i);
1288 }
1289
1290
1291 /************************************************************************
1292  *
1293  *  IconCallback
1294  *      Callback function invoked upon an action occuring on an icon.
1295  *
1296  ************************************************************************/
1297
1298 static Bool
1299 IsButtonOrMotion(
1300   Display *disp,
1301   XEvent *ep,
1302   char *arg)
1303 {
1304   return (ep->type == MotionNotify || ep->type == ButtonRelease);
1305 }
1306
1307
1308 void
1309 IconCallback(
1310         Widget w,
1311         XtPointer clientData,
1312         XtPointer callData )
1313 {
1314    XmAnyCallbackStruct * callback;
1315    XButtonEvent * event;
1316    FileViewData * fileViewData;
1317    FileMgrData  * fileMgrData;
1318    static Boolean highlightType = INIT_VALUE;
1319    static Widget highlightWidget = NULL;
1320    char * logicalType;
1321    char * command;
1322    DesktopRec * desktopRec;
1323    Boolean dragged;
1324    Window root;
1325    XEvent bevent;
1326    int dx, dy;
1327    WindowPosition position;
1328
1329    static int adjustState=-1;
1330    XrmValue value_return;
1331    char *str_type_return;
1332
1333
1334    if( adjustState == -1)
1335    {
1336       if (XrmGetResource(XrmGetDatabase(XtDisplay(w)), "*enableBtn1Transfer", "*EnableBtn1Transfer",&str_type_return, &value_return) && !strcmp(value_return.addr,"True") )
1337         {
1338              adjustState=True;
1339         }
1340       else
1341              adjustState=False;
1342    }
1343
1344    callback = (XmAnyCallbackStruct *) callData;
1345    fileViewData = (FileViewData *) clientData;
1346    event = (XButtonEvent *) callback->event;
1347
1348    if (callback->reason == XmCR_DRAG && event->button == bMenuButton)
1349       callback->reason = XmCR_POPUP;
1350
1351    if(callback->reason != XmCR_UNHIGHLIGHT)
1352    {
1353       /*  Get the directory data and the file manager data  */
1354       (void)IsDesktopPtr(fileViewData, &fileMgrData, &desktopRec);
1355    }
1356
1357    /*  Process the different callback types  */
1358    if ((callback->reason == XmCR_ARM) || (callback->reason == XmCR_SELECT))
1359    {
1360       /*
1361        * Both ARM and SELECT are generated using Button1. We pass on these
1362        * requests to the code responsible for processing button 1 selects
1363        * and drags.
1364        */
1365       FileMgrRec  * fileMgrRec;
1366       DtIconGadget new = (DtIconGadget)w;
1367
1368       if( event->type == KeyPress )
1369       {
1370         /* if a keypress we only want to select on an SELECT */
1371         if( callback->reason == XmCR_ARM )
1372           return;
1373         else
1374         {
1375           XKeyEvent *kevent;
1376           KeySym keysym;
1377           int offset;
1378
1379           kevent = (XKeyEvent *)event;
1380           if (kevent->state & ShiftMask)
1381             offset = 1;
1382           else
1383             offset = 0;
1384
1385           keysym = XLookupKeysym((XKeyEvent *)kevent, offset);
1386
1387           if( keysym == XK_Return )
1388             goto run_default_action;
1389         }
1390       }
1391
1392       if (callback->reason == XmCR_ARM)
1393          new->icon.armed = False;
1394
1395       if (desktopRec)
1396       {
1397          B1DragPossible = False;
1398          B2DragPossible = False;
1399          XtCallCallbacks(desktopRec->drawA, XmNinputCallback, callData);
1400       }
1401       else
1402       {
1403          B1DragPossible = False;
1404          B2DragPossible = False;
1405
1406          fileMgrRec = (FileMgrRec *)fileMgrData->file_mgr_rec;
1407          XtCallCallbacks(fileMgrRec->file_window, XmNinputCallback, callData);
1408       }
1409
1410       if (callback->reason == XmCR_ARM)
1411          new->icon.armed = True;
1412    }
1413    else if (callback->reason==XmCR_DISARM)
1414    {
1415       /*
1416        * DISARM is generated as the result of a button 1 up event.
1417        * If we are in the middle of a button 2 drag, then we'll ignore this;
1418        * otherwise, we now know a drag will not start, so clear all state flags.
1419        */
1420       if (B2DragPossible)
1421          return;
1422
1423       B1DragPossible = False;
1424       B2DragPossible = False;
1425       ProcessBtnUp = False;
1426    }
1427    else if (callback->reason == XmCR_DROP)
1428    {
1429       /*
1430        * DROP is generated as the result of a button 2 up event.
1431        * If we are in the middle of a button 1 drag, then we'll ignore this;
1432        * otherwise, we now know a drag will not start, so clear all state flags.
1433        */
1434       if (B1DragPossible)
1435          return;
1436
1437       B1DragPossible = False;
1438       B2DragPossible = False;
1439       ProcessBtnUp = False;
1440    }
1441    else if (callback->reason == XmCR_DEFAULT_ACTION)
1442    {
1443       Boolean Error;
1444
1445       if(event->type == KeyPress)
1446       {
1447          XKeyEvent *kevent;
1448          KeySym keysym;
1449          int offset;
1450
1451          kevent = (XKeyEvent *)event;
1452          if (kevent->state & ShiftMask)
1453             offset = 1;
1454          else
1455             offset = 0;
1456
1457          keysym = XLookupKeysym((XKeyEvent *)kevent, offset);
1458
1459          if (keysym == XK_Escape)
1460          {
1461             /* an escape unposts the name change text widget */
1462             if(desktopRec)
1463                UnpostDTTextField();
1464             else
1465                UnpostTextField(fileMgrData);
1466             return;
1467          }
1468          else
1469          {
1470            KeySym SpaceKeySym = XStringToKeysym( "space" );
1471            if( keysym == SpaceKeySym )
1472              return;
1473          }
1474       }
1475
1476       run_default_action:
1477
1478       Error = False;
1479
1480       /*
1481        * If DEFAULT_ACTION was generated by button press,
1482        * wait for the button release
1483        */
1484       dragged = False;
1485       if(event->type == ButtonPress)
1486       {
1487         if (loc_cursor1 == None)
1488           loc_cursor1 = XCreateFontCursor(XtDisplay(w), 40);
1489         if (loc_cursor2 == None)
1490           loc_cursor2 = XCreateFontCursor(XtDisplay(w), 34);
1491
1492         root = RootWindowOfScreen(XtScreen(w));
1493         XGrabPointer(XtDisplay(w), root,
1494                      False, ButtonReleaseMask | PointerMotionMask,
1495                      GrabModeAsync, GrabModeAsync,
1496                      None, loc_cursor1, CurrentTime);
1497         do {
1498           XIfEvent(XtDisplay(w), &bevent, IsButtonOrMotion, NULL);
1499           if (!dragged && bevent.type == MotionNotify) {
1500             dx = event->x_root - bevent.xmotion.x_root; if (dx < 0) dx = -dx;
1501             dy = event->y_root - bevent.xmotion.y_root; if (dy < 0) dy = -dy;
1502             if (dx > DBLCLICK_DRAG_THRESHOLD || dy > DBLCLICK_DRAG_THRESHOLD) {
1503               DPRINTF(("dragged!\n"));
1504               XGrabPointer(XtDisplay(w), root,
1505                            False, ButtonReleaseMask | PointerMotionMask,
1506                            GrabModeAsync, GrabModeAsync,
1507                            None, loc_cursor2, CurrentTime);
1508               dragged = True;
1509             }
1510           }
1511         } while (bevent.type != ButtonRelease);
1512
1513         XUngrabPointer(XtDisplay(w), CurrentTime);
1514         XFlush(XtDisplay(w));
1515
1516         position.x = bevent.xbutton.x_root;
1517         position.y = bevent.xbutton.y_root;
1518       }
1519
1520       /*
1521        * DEFAULT_ACTION is generated by a double-click of button 1.
1522        * We now know a drag will not start, so clear all state flags.
1523        */
1524       B1DragPossible = False;
1525       B2DragPossible = False;
1526       ProcessBtnUp = False;
1527
1528       logicalType = fileViewData->file_data->logical_type;
1529       command = _DtRetrieveDefaultAction(logicalType);
1530
1531       if (desktopRec)
1532       {
1533          /* Any button event unposts the text field */
1534          UnpostDTTextField();
1535
1536          if(command)
1537             RunDTCommand(command, desktopRec, NULL);
1538          else
1539             Error = True;
1540       }
1541       else
1542       {
1543          /* Any button event unposts the text field */
1544          UnpostTextField(fileMgrData);
1545
1546          if((openDirType == NEW && strcmp(command, openInPlace) == 0) ||
1547             (openDirType != NEW && strcmp(command, openNewView) == 0))
1548          {
1549             unsigned int modifiers = event->state;
1550
1551             RunCommand (openNewView, fileMgrData, fileViewData,
1552                         dragged? &position: NULL, NULL, NULL);
1553             if((modifiers != 0) && ((modifiers & ControlMask) != 0))
1554             {
1555                DialogData  *dialog_data;
1556
1557                dialog_data = _DtGetInstanceData(fileMgrData->file_mgr_rec);
1558                CloseView(dialog_data);
1559             }
1560          }
1561          else
1562          {
1563             if(command)
1564             {
1565                if ((fileMgrData->show_type == MULTIPLE_DIRECTORY || dragged) &&
1566                    strcmp(command, openInPlace) == 0)
1567                {
1568                  RunCommand (openNewView, fileMgrData, fileViewData,
1569                              dragged? &position: NULL, NULL, NULL);
1570                }
1571                else
1572                  RunCommand (command, fileMgrData, fileViewData,
1573                              NULL, NULL, NULL);
1574             }
1575             else
1576                Error = True;
1577          }
1578       }
1579
1580       XtFree(command);
1581
1582       if(Error)
1583       {
1584          char * title;
1585          char msg[512];
1586          char * tmpStr;
1587
1588          tmpStr = (GETMESSAGE(9,6, "Action Error"));
1589          title = (char *)XtMalloc(strlen(tmpStr) + 1);
1590          strcpy(title, tmpStr);
1591
1592          (void) sprintf (msg,
1593               (GETMESSAGE(9,7, "There are no actions defined for %s\n")),
1594               logicalType);
1595          if(desktopRec)
1596             _DtMessage (desktopRec->shell, title, msg, NULL, HelpRequestCB);
1597          else
1598             _DtMessage (fileViewData->widget, title, msg, NULL, HelpRequestCB);
1599          XtFree(title);
1600       }
1601    }
1602    else if (callback->reason == XmCR_DRAG)
1603    {
1604       /*
1605        * DRAG is generated by a button 2 down event. It flags that
1606        * the user may possible be initiating a drag; we won't know
1607        * for sure until the drag threshold is surpassed.
1608        * Ignore this if a Button 1 drag is ramping up.
1609        */
1610       if (B1DragPossible)
1611          return;
1612
1613       /* Any button event unposts the text field */
1614       if (desktopRec)
1615       {
1616          UnpostDTTextField();
1617          if(!DTFileIsSelected(desktopRec, fileViewData) && adjustState)
1618              SelectDTFile(desktopRec);
1619       }
1620       else
1621       {
1622          if( fileMgrData && !FileIsSelected(fileMgrData,fileViewData) &&
1623              adjustState
1624            )
1625            {
1626              SelectFile(fileMgrData, fileViewData);
1627            }
1628          UnpostTextField(fileMgrData);
1629       }
1630
1631       /* Save starting X & Y, in case a drag really starts */
1632       initialDragX = event->x;
1633       initialDragY = event->y;
1634       B2DragPossible = True;
1635       memcpy((char *) &desktop_data->event, (char *) event,
1636              (int) sizeof(XButtonEvent));
1637    }
1638    else if (callback->reason == XmCR_POPUP)
1639    {
1640       if(!desktopRec)
1641       {
1642          FmPopup (w, clientData, (XEvent *)event, fileMgrData);
1643       }
1644    }
1645    else if (callback->reason == XmCR_HIGHLIGHT)
1646    {
1647       DtIconGadget g = (DtIconGadget)w;
1648
1649       if (dragActive)
1650       {
1651          if ((g->icon.border_type == DtRECTANGLE) || (!g->icon.pixmap))
1652            _XmUnhighlightBorder(w);
1653
1654          B1DragPossible = False;
1655          B2DragPossible = False;
1656          return;
1657       }
1658
1659       if ((g->icon.border_type == DtRECTANGLE) || (!g->icon.pixmap))
1660          return;
1661
1662       if ((highlightType != INIT_VALUE) && (highlightWidget))
1663       {
1664          if (desktopRec)
1665          {
1666             if (highlightType == NOT_DESKTOP)
1667                DrawUnhighlight(highlightWidget, NOT_DESKTOP);
1668             else if (highlightWidget != w)
1669                DrawUnhighlight(highlightWidget, DESKTOP);
1670          }
1671          else
1672          {
1673             if (highlightType == DESKTOP)
1674                DrawUnhighlight(highlightWidget, DESKTOP);
1675             else if (highlightWidget != w)
1676                DrawUnhighlight(highlightWidget, NOT_DESKTOP);
1677          }
1678       }
1679
1680       if (desktopRec)
1681       {
1682          DrawHighlight(w, NULL, NULL, DESKTOP);
1683          highlightType = DESKTOP;
1684       }
1685       else
1686       {
1687          DrawHighlight(w, fileViewData, fileMgrData, NOT_DESKTOP);
1688          highlightType = NOT_DESKTOP;
1689       }
1690       highlightWidget = w;
1691    }
1692    else if (callback->reason == XmCR_UNHIGHLIGHT)
1693    {
1694       DtIconGadget g = (DtIconGadget)w;
1695
1696       if (dragActive)
1697       {
1698         if ((g->icon.border_type == DtRECTANGLE) || (!g->icon.pixmap))
1699           _XmHighlightBorder(w);
1700
1701         B1DragPossible = False;
1702         B2DragPossible = False;
1703         return;
1704       }
1705
1706       if ((g->icon.border_type == DtRECTANGLE) || (!g->icon.pixmap))
1707         return;
1708
1709       if (w == highlightWidget)
1710       {
1711          if (highlightType == DESKTOP)
1712             DrawUnhighlight(w, DESKTOP);
1713          else
1714             DrawUnhighlight(w, NOT_DESKTOP);
1715
1716          highlightType = INIT_VALUE;
1717          highlightWidget = NULL;
1718       }
1719    }
1720    else if (callback->reason == XmCR_SHADOW)
1721       DrawShadowTh(w, NULL, DESKTOP);
1722
1723 }
1724
1725 static int
1726 GetSelectedCount(
1727         FileViewData * fileViewData,
1728         FileMgrData * fileMgrData,
1729         DesktopRec * desktopRec,
1730         int * dt)
1731 {
1732    int selectedCount;
1733    char * wsName;
1734    Atom pCurrent;
1735
1736    /*  If the initiation of the drag occured upon an      */
1737    /*  already selected icon, check for a multiple drag.  */
1738
1739    if ((desktopRec == NULL) && FileIsSelected(fileMgrData, fileViewData))
1740       selectedCount = fileMgrData->selected_file_count;
1741    else if (desktopRec == NULL)
1742       selectedCount = 1;
1743    else
1744    {
1745       if (DTFileIsSelected(desktopRec, fileViewData))
1746       {
1747          if(DtWsmGetCurrentWorkspace(XtDisplay(desktopRec->shell),
1748                                RootWindowOfScreen(XtScreen(desktopRec->shell)),
1749                                &pCurrent) == Success)
1750          {
1751             wsName = XGetAtomName(XtDisplay(desktopRec->shell), pCurrent);
1752             CleanUpWSName(wsName);
1753          }
1754          else
1755             wsName = XtNewString("One");
1756
1757          for(*dt = 0; *dt < desktop_data->numWorkspaces; (*dt)++)
1758          {
1759             if(strcmp(wsName, desktop_data->workspaceData[*dt]->name) == 0)
1760             {
1761                selectedCount = desktop_data->workspaceData[*dt]->files_selected;
1762                break;
1763             }
1764          }
1765          XtFree(wsName);
1766       }
1767       else
1768          selectedCount = 1;
1769    }
1770
1771    return(selectedCount);
1772 }
1773
1774
1775 static Pixmap
1776 GetDragIconMask(
1777         Widget w,
1778         unsigned int wid,
1779         unsigned int hei)
1780 {
1781    Pixmap dragMask;
1782    Display *dpy = XtDisplay(w);
1783    unsigned char flags;
1784    XRectangle pRect, lRect;
1785    GC fillGC;
1786    XGCValues values;
1787    Arg args[8];
1788    Dimension shadowThickness;
1789    Dimension marginWidth, marginHeight;
1790    int minX, minY;
1791    Boolean minXUndefined, minYUndefined;
1792
1793    dragMask = XCreatePixmap(dpy, RootWindowOfScreen (XtScreenOfObject(w)),
1794                             wid, hei, 1);
1795
1796   /* Create a GC for drawing 0's into the pixmap */
1797    fillGC = XCreateGC(dpy, dragMask, 0, (XGCValues *) NULL);
1798
1799    XFillRectangle(dpy, dragMask, fillGC, 0, 0, wid, hei);
1800
1801    values.foreground = 1;
1802    XChangeGC(dpy, fillGC, GCForeground, &values);
1803
1804   /* Create the drag pixmap, and the associated mask bitmap */
1805    _DtIconGetIconRects((DtIconGadget)w, &flags, &pRect, &lRect);
1806
1807    minX= 0;
1808    minY= 0;
1809    minXUndefined = minYUndefined = True;
1810    if (flags & XmPIXMAP_RECT)
1811    {
1812        minX = pRect.x;
1813        minY = pRect.y;
1814        minXUndefined = minYUndefined = False;
1815    }
1816    if (flags & XmLABEL_RECT)
1817    {
1818       if ((lRect.x < minX) || minXUndefined)
1819          minX = lRect.x;
1820       if ((lRect.y < minY) || minYUndefined)
1821          minY = lRect.y;
1822    }
1823
1824     XtSetArg (args[0], XmNshadowThickness, &shadowThickness);
1825     XtSetArg (args[1], XmNmarginWidth, &marginWidth);
1826     XtSetArg (args[2], XmNmarginHeight, &marginHeight);
1827     XtGetValues (w, args, 3);
1828
1829     if (flags & XmPIXMAP_RECT)
1830        XFillRectangle(dpy, dragMask, fillGC,
1831                       pRect.x - minX + shadowThickness + marginWidth,
1832                       pRect.y - minY + shadowThickness + marginHeight,
1833                       pRect.width - 2*marginWidth,
1834                       pRect.height - 2*marginHeight);
1835     if (flags & XmLABEL_RECT)
1836     {
1837       XFillRectangle(dpy, dragMask, fillGC,
1838                      lRect.x - minX + shadowThickness + marginWidth,
1839                      lRect.y - minY + shadowThickness + marginHeight,
1840                      lRect.width - 2*marginWidth,
1841                      lRect.height - 2*marginHeight);
1842     }
1843     XFreeGC(dpy, fillGC);
1844
1845     return (dragMask);
1846 }
1847
1848 static Widget
1849 GetDragIcon(
1850         Widget w,
1851         FileViewData * fileViewData )
1852 {
1853    XmManagerWidget mw = (XmManagerWidget) XtParent(w);
1854    Widget screen_object = (Widget) XmGetXmScreen(XtScreenOfObject(w));
1855    Arg args[11];
1856    register int n;
1857    unsigned int wid, hei, d, junk;
1858    Widget dragIcon;
1859    Pixmap dragPixmap;
1860    Pixmap dragMask;
1861
1862    dragPixmap = _DtIconDraw (w, NULL, 0, 0, False);
1863
1864    XGetGeometry (XtDisplay(w), dragPixmap,
1865                  (Window *) &junk,             /* returned root window */
1866                  (int *) &junk, (int *) &junk, /* x, y of pixmap */
1867                  &wid, &hei,                   /* width, height of pixmap */
1868                  &junk,                        /* border width */
1869                  &d);                          /* depth */
1870
1871    if (initiating_view
1872        && ((FileMgrData *)initiating_view)->view == BY_ATTRIBUTES)
1873    {
1874      XmFontList fontList;
1875      XmString fileNameString;
1876      DtIconGadget g = (DtIconGadget)w;
1877
1878
1879      XtSetArg( args[0], XmNfontList, &fontList );
1880      XtGetValues( fileViewData->widget, args, 1 );
1881
1882      fileNameString = XmStringCreateLocalized( fileViewData->file_data->file_name );
1883      wid = XmStringWidth( fontList, fileNameString )
1884            + g->icon.pixmap_width
1885            + g->icon.cache->margin_width
1886            + g->icon.cache->spacing
1887            + G_ShadowThickness(g)
1888            + G_HighlightThickness(g);
1889      XmStringFree( fileNameString );
1890    }
1891
1892    dragMask = GetDragIconMask(w, wid, hei);
1893
1894    n = 0 ;
1895    XtSetArg(args[n], XmNhotX, 0);  n++;
1896    XtSetArg(args[n], XmNhotY, 0);  n++;
1897    XtSetArg(args[n], XmNwidth, wid);  n++;
1898    XtSetArg(args[n], XmNheight, hei);  n++;
1899    XtSetArg(args[n], XmNmaxWidth, wid);  n++;
1900    XtSetArg(args[n], XmNmaxHeight, hei);  n++;
1901    XtSetArg(args[n], XmNdepth, d);  n++;
1902    XtSetArg(args[n], XmNpixmap, dragPixmap);  n++;
1903    XtSetArg(args[n], XmNmask, dragMask);  n++;
1904    XtSetArg(args[n], XmNforeground, mw->core.background_pixel);  n++;
1905    XtSetArg(args[n], XmNbackground, mw->manager.foreground);  n++;
1906    dragIcon = XtCreateWidget("drag_icon", xmDragIconObjectClass,
1907                              screen_object, args, n);
1908
1909    return(dragIcon);
1910 }
1911
1912
1913
1914 /* The following function is called if the completeMove flag is   */
1915 /* set to TRUE. Internally, dtfile sets this to FALSE; thus, only */
1916 /* receiving clients that set this to true will get this function */
1917 /* called for them.                                               */
1918 /* This function will delete the files/dirs that were dropped     */
1919 /* on the receiving client.                                       */
1920
1921 static void
1922 NewConvertDelete(
1923         Widget w,
1924         FileViewData * fileViewData,
1925         char ** fileList,
1926         int numFiles)
1927 {
1928       static char *pname = "NewConvertDelete";
1929       int     i;
1930       int     child_pid = 0;
1931
1932       DPRINTF(("%s: Entering function\n", pname));
1933
1934       /* fork a background child process to honor the Move Completion */
1935        child_pid = fork();
1936
1937        if (child_pid == -1)
1938        {
1939             char *msg, *tmpStr, *title;
1940
1941             DBGFORK(("%s: Cannot create child process\n", pname));
1942
1943             tmpStr = GETMESSAGE(11,59, 
1944                         "Cannot create a child process to delete the dropped files.");
1945             msg = XtNewString(tmpStr);
1946             title = XtNewString((GETMESSAGE(11,58,"Process Create Error")));
1947
1948            /* Display Error message */
1949             _DtMessage(toplevel, title, msg, NULL, HelpRequestCB);
1950             XtFree(msg);
1951             XtFree(title);
1952             return;
1953        }
1954
1955
1956        /* In the Child Process, we simply erase the files   */
1957        /* and directories that were dropped on the receiver */
1958        if (child_pid == 0)
1959        {
1960             DBGFORK(("%s:  child forked\n", pname));
1961
1962             for (i = 0; i < numFiles; i++)
1963             {
1964              DPRINTF(("%s: Erasing file %s\n", pname, fileList[i]));
1965              EraseObject(fileList[i]);
1966             }
1967
1968             DBGFORK(("%s:  child exiting\n", pname));
1969
1970             exit(0);
1971        }
1972
1973        DBGFORK(("%s:  forked child<%d>\n", pname, child_pid));
1974
1975 }
1976
1977
1978 static void
1979 NewConvertFileName(
1980         Widget w,
1981         FileViewData * fileViewData,
1982         char ** fileList,
1983         Cardinal *numFiles)
1984 {
1985    FileMgrData * fileMgrData;
1986    DesktopRec * desktopRec;
1987    int selectedCount;
1988    int dt, i, count;
1989    char * directoryName;
1990    char * fileName;
1991    char * path;
1992
1993    if(fileViewData != NULL)
1994    {
1995       (void)IsDesktopPtr(fileViewData, &fileMgrData, &desktopRec);
1996       selectedCount = GetSelectedCount(fileViewData, fileMgrData, desktopRec, &dt);
1997    }
1998    else
1999    {
2000       /* If fileViewData is NULL, then the file no long exists */
2001       fileMgrData = (FileMgrData *)initiating_view;
2002       desktopRec = NULL;
2003       if(fileMgrData)
2004         selectedCount = fileMgrData->selected_file_count;
2005       else
2006         selectedCount = 0;
2007    }
2008
2009    if (selectedCount > 1)
2010    {
2011       for (i = (selectedCount-1); i >= 0; i--)
2012       {
2013          if (desktopRec)
2014          {
2015             fileViewData = desktop_data->workspaceData[dt]->
2016                                  selectedDTWindows[i]->file_view_data;
2017             directoryName = desktop_data->workspaceData[dt]->
2018                                  selectedDTWindows[i]->dir_linked_to;
2019             fileName = fileViewData->file_data->file_name;
2020          }
2021          else
2022          {
2023             fileViewData = fileMgrData->selection_list[i];
2024             directoryName = ((DirectorySet *)fileViewData->directory_set)->name;
2025             fileName = fileViewData->file_data->file_name;
2026          }
2027          path = (char *)XtMalloc(strlen(directoryName) + strlen(fileName) + 2);
2028          sprintf(path,"%s/%s", directoryName, fileName);
2029
2030          if ((!desktopRec) && (fileMgrData->toolbox))
2031             path = _DtResolveAppManPath(path,
2032                                         fileMgrData->restricted_directory);
2033
2034          fileList[i] = DtEliminateDots(path);
2035       }
2036    *numFiles = selectedCount;
2037    }
2038    else
2039    {
2040       if (desktopRec)
2041       {
2042          directoryName = desktopRec->dir_linked_to;
2043          fileName = fileViewData->file_data->file_name;
2044       }
2045       else if(fileViewData)
2046       {
2047          directoryName = ((DirectorySet *)fileViewData->directory_set)->name;
2048          fileName = fileViewData->file_data->file_name;
2049       }
2050       else
2051       {
2052          directoryName = fileMgrData->current_directory;
2053          fileName = NULL;
2054       }
2055       path = (char *)XtMalloc(strlen(directoryName) + strlen(fileName) + 2);
2056       sprintf(path,"%s/%s", directoryName, fileName);
2057
2058       if ((!desktopRec) && (fileMgrData->toolbox))
2059          path = _DtResolveAppManPath(path, fileMgrData->restricted_directory);
2060
2061       fileList[0] = DtEliminateDots( path );
2062       *numFiles = 1;
2063    }
2064
2065 #ifdef DEBUG
2066    if (debug)
2067    {
2068      printf("NewConvertFileName: returns %d files\n", selectedCount);
2069      for (i = 0; i < selectedCount; i++) {
2070        printf("\t\"%s\"\n", fileList[i]);
2071      }
2072      if (selectedCount == 0)
2073        printf("\t\"%s\"\n", fileList[0]);
2074    }
2075 #endif
2076
2077 }
2078
2079 /* ARGSUSED */
2080 static void
2081 FileConvertCB(
2082         Widget w,
2083         XtPointer client,
2084         XtPointer call)
2085 {
2086     FileViewData * fileViewData = (FileViewData *) client;
2087     DtDndConvertCallback cb = (DtDndConvertCallback) call;
2088     FileMgrData *fmd = (FileMgrData *)initiating_view;
2089
2090     if(fmd)
2091     {
2092        fileViewData = fmd->drag_file_view_data;
2093        fmd->drag_file_view_data = NULL;
2094     }
2095     if (cb->reason == DtCR_DND_CONVERT_DATA)
2096     {
2097        if(fmd && !fmd->selected_file_count && fileViewData == NULL)
2098        {
2099            cb->status = DtDND_FAILURE;
2100            cb->dragData->numItems = 0; /* Just to be on safe side */
2101            return;
2102        }
2103        NewConvertFileName(w, fileViewData,
2104                        cb->dragData->data.files, &cb->dragData->numItems);
2105     } else if (cb->reason == DtCR_DND_CONVERT_DELETE)
2106     {
2107        NewConvertDelete(w, fileViewData,
2108                        cb->dragData->data.files, cb->dragData->numItems);
2109     }
2110 }
2111
2112
2113 /* This callback procedure removes the icons when the drop is complete */
2114 /* ARGSUSED */
2115 static void
2116 DragFinishCB(Widget w, XtPointer client, XtPointer call)
2117 {
2118    DtDndDragFinishCallback cb = (DtDndDragFinishCallback) call;
2119    int                  i;
2120    static Window root = NULL;
2121
2122    DPRINTF(("DragFinishCB: dragActive -> False\n"));
2123
2124    dragActive = False;
2125    initialDragX = -1;
2126    initialDragY = -1;
2127    B1DragPossible = False;
2128    B2DragPossible = False;
2129    ProcessBtnUp = False;
2130
2131    if (cb->sourceIcon)
2132       XtDestroyWidget(cb->sourceIcon);
2133
2134    DPRINTF (("DragFinishCB: Number of items being freed are %d\n",
2135               cb->dragData->numItems));
2136    for (i = 0; i < cb->dragData->numItems; i++) {
2137
2138       DPRINTF(("DragFinishCB: Freeing %s\n", cb->dragData->data.files[i]));
2139       XtFree(cb->dragData->data.files[i]);
2140       cb->dragData->data.files[i] = NULL;
2141    }
2142
2143 }
2144
2145 /* ARGSUSED */
2146 void
2147 StartDrag(
2148         Widget w,
2149         FileViewData * fileViewData,
2150         XEvent * event)
2151 {
2152    static XtCallbackRec fileConvertCB[] = { {FileConvertCB, NULL},
2153                                            {NULL, NULL} };
2154    static XtCallbackRec dragFinishCB[] = { {DragFinishCB, NULL},
2155                                            {NULL, NULL} };
2156    static XtCallbackRec dropOnRootCB[] = { {DropOnRootCB, NULL},
2157                                            {NULL, NULL} };
2158    Widget drag_icon;
2159    Arg                  args[2];
2160    int                  numArgs;
2161    FileMgrData *        fileMgrData = NULL;
2162    DesktopRec *         desktopRec = NULL;
2163    int                  selectedCount;
2164    int                  dt;
2165    Boolean              desktopObj;
2166    unsigned char        operations;
2167
2168    if (event->type == INVALID_TYPE) return;
2169
2170    if (fileViewData == NULL) return;
2171
2172    fileConvertCB[0].closure = (XtPointer)fileViewData;
2173    dropOnRootCB[0].closure = (XtPointer)fileViewData;
2174
2175    desktopObj = IsDesktopPtr(fileViewData, &fileMgrData, &desktopRec);
2176    selectedCount = GetSelectedCount(fileViewData, fileMgrData,
2177                                     desktopRec, &dt);
2178
2179    if (selectedCount > 1)
2180       drag_icon = NULL;
2181    else
2182       drag_icon = GetDragIcon(w, fileViewData);
2183
2184    numArgs = 0;
2185    XtSetArg(args[numArgs], DtNsourceIcon, drag_icon);                numArgs++;
2186    XtSetArg(args[numArgs], DtNdropOnRootCallback, dropOnRootCB);     numArgs++;
2187
2188    if ((desktopObj && desktopRec->toolbox) ||
2189        (!desktopObj && fileMgrData->toolbox))
2190      operations = XmDROP_COPY;
2191    else
2192      operations = XmDROP_MOVE | XmDROP_COPY | XmDROP_LINK;
2193
2194    if (DtDndDragStart(w, event, DtDND_FILENAME_TRANSFER, selectedCount,
2195                         operations,
2196                         fileConvertCB, dragFinishCB, args, numArgs) == NULL) {
2197       DPRINTF(("StartDrag: dragActive -> False\n"));
2198
2199       dragActive = False;
2200       initialDragX = -1;
2201       initialDragY = -1;
2202       B1DragPossible = False;
2203       B2DragPossible = False;
2204       ProcessBtnUp = False;
2205    }
2206 }
2207
2208
2209 /*
2210  * This function is capable of initiating either a button 1 or button 2
2211  * drag operation; which one gets started is dependent upon which of the
2212  * two state flags (B1DragPossible or B2DragPossible) is set.
2213  */
2214
2215 static void
2216 InitiateIconDrag(
2217         FileViewData * fileViewData,
2218         int rootX,
2219         int rootY,
2220         XEvent * event )
2221
2222 {
2223    FileMgrData * fileMgrData;
2224    DtIconGadget iconG;
2225    Widget dragIcon;
2226    char * typeSet;
2227    char * fileSet;
2228    char * directoryName;
2229    Pixmap dragPixmap;
2230    XRectangle dragMask[2];
2231    Pixel  bg;
2232    XRectangle pRect, lRect;
2233    unsigned char flags;
2234    int stringSize;
2235    register int i;
2236    Arg args[10];
2237    Boolean allowDropInInitiatingWindow;
2238    int rectCount;
2239    int minX, minY;
2240    Boolean minXUndefined, minYUndefined;
2241    DesktopRec * desktopRec;
2242    int btn;
2243    char * hostName;
2244    Boolean spaces = False;
2245    Boolean trash = False;
2246    char *tmpStr, *link_path, *ptr;
2247
2248    /* Don't allow multi-drags to start */
2249    if (dragActive)
2250    {
2251       initialDragX = -1;
2252       initialDragY = -1;
2253       B1DragPossible = False;
2254       B2DragPossible = False;
2255       ProcessBtnUp = False;
2256       return;
2257    }
2258    else
2259       dragActive = True;
2260
2261    DPRINTF(("InitiateIconDrag: dragActive -> True\n"));
2262
2263    dragIcon = fileViewData->widget;
2264    (void)IsDesktopPtr(fileViewData, &fileMgrData, &desktopRec);
2265
2266    /* if what we are dragging is a trash item, we want the objects to be
2267     * real objects, not their links
2268     */
2269    if(fileMgrData == trashFileMgrData && trashFileMgrData != NULL)
2270       trash = True;
2271
2272    /*
2273     * We need to mark the icon which initiated the drag as no longer
2274     * being 'armed', since it will not receive the button up event,
2275     * because we will have release the drag.
2276     */
2277    iconG = (DtIconGadget)dragIcon;
2278    iconG->icon.armed = False;
2279
2280    /*
2281     * Remember the posistion of the icon pixmap within the drag icon.
2282     */
2283    dragIconPixmapOffsetX = G_ShadowThickness(iconG) + G_MarginWidth(iconG);
2284    dragIconPixmapOffsetY = G_ShadowThickness(iconG) + G_MarginHeight(iconG);
2285
2286    if(desktopRec)
2287    {
2288       initiating_view = (XtPointer) NULL;
2289       widget_dragged = dragIcon;
2290    }
2291    else
2292    {
2293       initiating_view = (XtPointer) fileMgrData;
2294       widget_dragged = NULL;
2295    }
2296    StartDrag(dragIcon, fileViewData, event);
2297 }
2298
2299
2300 /*
2301  * These are replacements for the corresponding libXm functions.  They allow
2302  * us to treat icon gadgets as non-rectangular, so that input processing
2303  * is handled correctly.
2304  */
2305
2306 static XmGadget
2307 InputInGadget (
2308    Widget w,
2309    register int x,
2310    register int y)
2311
2312 {
2313    CompositeWidget cw = (CompositeWidget)w;
2314    static Region r = NULL;
2315    FileMgrData * file_mgr_data;
2316    Boolean simpleCheck = False;
2317    register int i;
2318    unsigned char flags;
2319    XRectangle pRect, lRect;
2320    register Widget widget;
2321
2322    file_mgr_data = ReturnDesktopPtr((Widget)cw);
2323
2324    /*
2325     * Tree views and attribute views do not have the non-rectangular
2326     * hotspots, so we can resort to the standard checking algorithm.
2327     */
2328    if ((file_mgr_data == NULL) ||
2329        (file_mgr_data->show_type != SINGLE_DIRECTORY) ||
2330        (file_mgr_data->view == BY_ATTRIBUTES))
2331    {
2332       simpleCheck = True;
2333    }
2334
2335    for (i = 0; i < cw->composite.num_children; i++)
2336    {
2337       widget = cw->composite.children[i];
2338
2339       if (XmIsGadget(widget) && XtIsManaged(widget))
2340       {
2341          if (simpleCheck)
2342          {
2343             if (x >= widget->core.x && y >= widget->core.y &&
2344               (Position) x < (Position) (widget->core.x + widget->core.width) &&
2345               (Position) y < (Position) (widget->core.y + widget->core.height))
2346             {
2347                return ((XmGadget) widget);
2348             }
2349          }
2350          else
2351          {
2352             /* Initialize the region to be empty */
2353             if (r == NULL)
2354                r = XCreateRegion();
2355             else
2356                XSubtractRegion(r, r, r);
2357
2358             _DtIconGetIconRects((DtIconGadget)widget, &flags, &pRect, &lRect);
2359
2360             if (flags & XmPIXMAP_RECT)
2361                XUnionRectWithRegion(&pRect, r, r);
2362
2363             if (flags & XmLABEL_RECT)
2364                XUnionRectWithRegion(&lRect, r, r);
2365
2366             if (XPointInRegion(r, x, y))
2367                return ((XmGadget) widget);
2368          }
2369       }
2370    }
2371
2372    return(NULL);
2373 }
2374
2375
2376 /*
2377  * This function is identical to the libXm version; it needs to be here
2378  * so that it will call our InputInGadget() instead of the libXm
2379  * version, which was bundled together with it in GadgetUtil.c
2380  */
2381
2382 static XmGadget
2383 InputForGadget (
2384    Widget cw,
2385    int x,
2386    int y)
2387 {
2388    XmGadget gadget;
2389
2390    gadget = InputInGadget (cw, x, y);
2391
2392    if (!gadget  ||  !XtIsSensitive ((Widget)gadget))
2393    {
2394       return ((XmGadget) NULL);
2395    }
2396
2397    return (gadget);
2398 }
2399
2400
2401 /*
2402  * This function processes motion events anytime a B1 or B2 drag operation
2403  * has the potential of starting for a file icon.  When the drag threshold
2404  * is surpassed, a drag operation will be started.
2405  */
2406
2407 void
2408 FileIconMotion(
2409                Widget w,
2410                XtPointer clientData,
2411                XEvent *event)
2412 {
2413    int diffX, diffY;
2414    FileViewData * fileViewData = NULL;
2415    Position rootX, rootY;
2416    DirectorySet * directoryData = NULL;
2417    Arg args[10];
2418    int i;
2419    Widget dragIcon;
2420
2421    if ((B1DragPossible && (event->xmotion.state & Button1Mask)) ||
2422        (B2DragPossible && (event->xmotion.state & Button2Mask)))
2423    {
2424       /* Have we passed the drag threshold? */
2425       diffX = initialDragX - event->xmotion.x;
2426       diffY = initialDragY - event->xmotion.y;
2427
2428       if ((ABS(diffX) >= dragThreshold) || (ABS(diffY) >= dragThreshold))
2429       {
2430          /* Map the original (x,y) into a gadget Id */
2431          if (dragIcon =(Widget)InputForGadget(w, initialDragX, initialDragY))
2432          {
2433             /* Map the icon into its fileViewData structure */
2434             /* Check for desktop icon first */
2435             for (i = 0, fileViewData = NULL; i<desktop_data->numIconsUsed; i++)
2436             {
2437                if (desktop_data->desktopWindows[i]->iconGadget == dragIcon)
2438                {
2439                  fileViewData = desktop_data->desktopWindows[i]->file_view_data;
2440                  break;
2441                }
2442             }
2443             if (fileViewData == NULL)
2444             {
2445                /* Not a desktop icon */
2446                XtSetArg(args[0], XmNuserData, (XtPointer) &directoryData);
2447                XtGetValues(dragIcon, args, 1);
2448                for (i = 0; i < directoryData->file_count; i++)
2449                {
2450                   if (directoryData->file_view_data[i]->widget == dragIcon &&
2451                              directoryData->file_view_data[i]->displayed)
2452                   {
2453                      fileViewData = directoryData->file_view_data[i];
2454                      break;
2455                   }
2456                }
2457             }
2458
2459
2460             /* Map to root coordinates */
2461             XtTranslateCoords(w, (Position)initialDragX, (Position)initialDragY,
2462                               &rootX, &rootY);
2463
2464                if(directoryData)
2465                {
2466                  FileMgrData *fmd;
2467                  fmd = (FileMgrData *)(directoryData->file_mgr_data);
2468                  if(fmd)
2469                       fmd->drag_file_view_data = fileViewData;
2470                }
2471              InitiateIconDrag(fileViewData, (int)rootX, (int)rootY, event);
2472          }
2473          else
2474          {
2475             /*
2476              * The file manager view must have changed between the time
2477              * the user did the button down, and the time they moved
2478              * enough to pass the drag threshold, because there is now
2479              * no icon located where the drag initiated.  Therefore,
2480              * we'll just clean up, because there is much else we can do.
2481              */
2482             B1DragPossible = False;
2483             B2DragPossible = False;
2484             ProcessBtnUp = False;
2485          }
2486
2487          /* Force the button up to be ignored */
2488          initialDragX = -1;
2489          initialDragY = -1;
2490       }
2491    }
2492 }
2493
2494
2495 /* Compute position of desktop icon shell for given a drop position */
2496 static void
2497 PositionDesktopIcon(
2498    int drop_x,
2499    int drop_y,
2500    int *root_x,
2501    int *root_y)
2502
2503 {
2504   int pixmap_offset_x;
2505   int pixmap_offset_y;
2506   DtIconGadget g;
2507
2508   /*
2509    * We want to position the shell, so that the icon pixmap in the icon
2510    * gadget will appear at the same spot that the icon pixmap of the drag
2511    * cursor was when the drop occurred.
2512    */
2513
2514   /* First we caculate the top left corner of the drag pixmap by adding
2515    * the offset of the pixmap within the drag icon to the drop position. */
2516   drop_x += dragIconPixmapOffsetX;
2517   drop_y += dragIconPixmapOffsetY;
2518
2519   /* In order to calculate the correct position of the dektop icon shell
2520    * such that the pixmap within the icon gadget will end up at the desired
2521    * position, we need to know the offset of the gadget's icon pixmap relative
2522    * to the desktop icon shell.
2523    *   Since a desktop icon consists a frame widget, a drawing area and an
2524    * icon gadget (all within a popup shell), this offset is computed by adding
2525    * the frame width and and drawing area margins to the icon gadget's
2526    * highlight thickness.
2527    *   The frame width is 3 and and and the drawing area margin width is 1
2528    * (both hardcoded in Desktop.c).  We determine the remaining components
2529    * by looking at one of the existing desktop icon gadgets. */
2530   if (desktop_data != NULL &&
2531       desktop_data->numIconsUsed + desktop_data->numCachedIcons > 0)
2532   {
2533      g = (DtIconGadget) desktop_data->desktopWindows[0]->iconGadget;
2534      pixmap_offset_x =
2535       pixmap_offset_y = 3 + 1 + G_HighlightThickness(g) + G_ShadowThickness(g);
2536      pixmap_offset_x += G_MarginWidth(g);
2537      pixmap_offset_y += G_MarginHeight(g);
2538   }
2539   else
2540   {
2541      /* don't have an icon gadget; assume default values */
2542      pixmap_offset_x = pixmap_offset_y = 3 + 1 + 2 + 2 + 2;
2543   }
2544
2545   /* Finally, calculate the position of the dektop icon shell by
2546    * subtracting the offset of the gadget's icon pixmap from the
2547    * desired pixmap position */
2548   *root_x = drop_x - pixmap_offset_x;
2549   *root_y = drop_y - pixmap_offset_y;
2550 }
2551
2552
2553 /* Code to reposition a desktop icon after a drag */
2554
2555 static void
2556 RelocateDesktopIcon(
2557    DesktopRec * desktopRec,
2558    int root_x,
2559    int root_y)
2560
2561 {
2562    Widget pu_shell;
2563    Dimension width, height;
2564    Arg args[10];
2565    XSizeHints wmSizeHints;
2566
2567    pu_shell = desktopRec->shell;
2568
2569
2570    XtSetArg (args[0], XmNwidth, &width);
2571    XtSetArg (args[1], XmNheight, &height);
2572    XtGetValues(pu_shell, args, 2);
2573
2574    RegisterInGrid((int)width, (int)height,
2575                   desktopRec->root_x,
2576                   desktopRec->root_y,
2577                   desktopRec->workspace_num,
2578                   False);
2579
2580    XtSetArg (args[0], XmNx, root_x);
2581    XtSetArg (args[1], XmNy, root_y);
2582
2583    XtSetValues (pu_shell, args, 2);
2584    XRaiseWindow(XtDisplay(pu_shell), XtWindow(pu_shell));
2585    XSync(XtDisplay(pu_shell), False);
2586
2587    RegisterInGrid((int)width, (int)height, root_x, root_y,
2588                   desktopRec->workspace_num, True);
2589
2590    desktopRec->root_x = root_x;
2591    desktopRec->root_y = root_y;
2592    SaveDesktopInfo(NORMAL_RESTORE);
2593 }
2594
2595
2596 /************************************************************************
2597  *
2598  *  FileIsSelected
2599  *      Loop through the file selection list to see if the specified
2600  *      file is selected.
2601  *
2602  ************************************************************************/
2603
2604 Boolean
2605 FileIsSelected(
2606         FileMgrData *file_mgr_data,
2607         FileViewData *file_view_data )
2608 {
2609    return file_view_data->selected;
2610 }
2611
2612
2613
2614
2615 /************************************************************************
2616  *
2617  *  SetFileSelected
2618  *      Display the icon representing file_data as selected.
2619  *
2620  ************************************************************************/
2621
2622 static void
2623 SetFileSelected(
2624         FileMgrData *file_mgr_data,
2625         FileViewData *file_view_data )
2626 {
2627    /* mark selected */
2628    file_view_data->selected = True;
2629
2630    /* if this file has an up-to-date gadget, change its colors */
2631    if (!file_view_data->need_update)
2632    {
2633       if (file_view_data->file_data->link == NULL)
2634          SetToSelectColors (file_view_data->widget,
2635               (Widget)((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window,
2636               NULL);
2637       else
2638          SetToSelectColors (file_view_data->widget,
2639               (Widget)((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window,
2640               LINK_FILE);
2641       if (PositioningEnabledInView(file_mgr_data))
2642          RedrawOneGadget(file_view_data->widget, NULL, NULL);
2643    }
2644 }
2645
2646 /************************************************************************
2647  *
2648  *  SetFileUnselected
2649  *      Display the icon representing file_data as not selected.
2650  *
2651  ************************************************************************/
2652
2653 static void
2654 SetFileUnselected(
2655         FileMgrData *file_mgr_data,
2656         FileViewData *file_view_data )
2657 {
2658    /* mark selected */
2659    file_view_data->selected = False;
2660
2661    /* if this file has an up-to-date gadget, change its colors */
2662    if (!file_view_data->need_update)
2663    {
2664       if (file_view_data->file_data->link != NULL)
2665          SetToNormalColors (file_view_data->widget,
2666                     ((FileMgrRec *)(file_mgr_data->file_mgr_rec))->file_window,
2667                     ((FileMgrRec *)(file_mgr_data->file_mgr_rec))->main,
2668                     LINK_FILE);
2669       else
2670          SetToNormalColors (file_view_data->widget,
2671                     ((FileMgrRec *)(file_mgr_data->file_mgr_rec))->file_window,
2672                     ((FileMgrRec *)(file_mgr_data->file_mgr_rec))->main,
2673                     NULL);
2674
2675       if (PositioningEnabledInView(file_mgr_data))
2676          RedrawOneGadget(file_view_data->widget, NULL, NULL);
2677    }
2678 }
2679
2680 /************************************************************************
2681  *
2682  *  SelectFile
2683  *      Add the file to the selection list.
2684  *
2685  ************************************************************************/
2686
2687 void
2688 SelectFile(
2689         FileMgrData *file_mgr_data,
2690         FileViewData *file_view_data )
2691 {
2692    int selection_count;
2693    int i;
2694
2695    /* Add to the front of the selection list */
2696    selection_count = file_mgr_data->selected_file_count;
2697    file_mgr_data->selected_file_count++;
2698
2699    file_mgr_data->selection_list = (FileViewData **)
2700       XtRealloc ((char *) file_mgr_data->selection_list,
2701                  sizeof(FileViewData *) * (selection_count + 2));
2702
2703    for (i = file_mgr_data->selected_file_count; i > 0; i--)
2704       file_mgr_data->selection_list[i] = file_mgr_data->selection_list[i-1];
2705
2706    file_mgr_data->selection_list[0] = file_view_data;
2707
2708    /* mark selected */
2709    SetFileSelected(file_mgr_data, file_view_data);
2710 }
2711
2712
2713
2714
2715 /************************************************************************
2716  *
2717  *  DeselectFile
2718  *      Remove the file from the selection list.
2719  *
2720  ************************************************************************/
2721
2722 void
2723 DeselectFile(
2724         FileMgrData *file_mgr_data,
2725         FileViewData *file_view_data,
2726         Boolean valid)
2727 {
2728    int selection_count;
2729    register int i;
2730    register int j;
2731
2732
2733    selection_count = file_mgr_data->selected_file_count;
2734    file_mgr_data->selected_file_count--;
2735
2736    for (i = 0; i < selection_count; i++)
2737       if (file_mgr_data->selection_list[i] == file_view_data)
2738          break;
2739
2740    for (j = i; j < selection_count - 1; j++)
2741       file_mgr_data->selection_list[j] = file_mgr_data->selection_list[j + 1];
2742
2743    file_mgr_data->selection_list = (FileViewData **)
2744       XtRealloc ((char *) file_mgr_data->selection_list,
2745                   sizeof(FileViewData *) * selection_count);
2746    file_mgr_data->selection_list[selection_count - 1] = NULL;
2747
2748    if (valid)
2749      SetFileUnselected(file_mgr_data, file_view_data);
2750    else
2751      file_view_data->selected = False;
2752 }
2753
2754
2755
2756
2757 /************************************************************************
2758  *
2759  *  DeselectAllFiles
2760  *      Unselect all of the selected icons within the file manager data
2761  *
2762  ************************************************************************/
2763
2764 void
2765 DeselectAllFiles(
2766         FileMgrData *file_mgr_data )
2767 {
2768    FileViewData * file_view_data;
2769    register int i, j, k;
2770    ObjectPtr bottom;
2771    FileViewData ** repaint_list;
2772
2773
2774    /*  Get the color to reset the icons.  */
2775
2776    /*  Loop through the selection set, resetting the visuals for  */
2777    /*  each selected icon.                                        */
2778
2779    if (!PositioningEnabledInView(file_mgr_data))
2780    {
2781       for (i = 0; i < file_mgr_data->selected_file_count; i++)
2782       {
2783          file_view_data = file_mgr_data->selection_list[i];
2784          SetFileUnselected(file_mgr_data, file_view_data);
2785       }
2786    }
2787    else if (file_mgr_data->selected_file_count > 0)
2788    {
2789       /*
2790        * We can't simply redraw the selected files; we must also redraw
2791        * any unselected files which are higher on the stacking order.
2792        */
2793
2794       repaint_list = (FileViewData **)XtMalloc(sizeof(FileViewData *) *
2795                      file_mgr_data->selected_file_count);
2796
2797       /* Order the objects to be unselected */
2798       for (i = 0; i < file_mgr_data->selected_file_count; i++)
2799       {
2800          file_view_data = file_mgr_data->selection_list[i];
2801          for (j = 0; j < i; j++)
2802          {
2803             if (file_view_data->position_info->stacking_order <
2804                 repaint_list[j]->position_info->stacking_order)
2805             {
2806                /* Insert here, pushing down all lower entries */
2807                for (k = file_mgr_data->selected_file_count - 1; k > j; k--)
2808                   repaint_list[k] = repaint_list[k-1];
2809
2810                repaint_list[j] = file_view_data;
2811                break;
2812             }
2813          }
2814
2815          /* Insert at end, if necessary */
2816          if (j >= i)
2817             repaint_list[i] = file_view_data;
2818       }
2819
2820       /* Start the redraw process */
2821       i = file_mgr_data->selected_file_count - 1;
2822       bottom = repaint_list[i]->position_info;
2823
2824       while(bottom)
2825       {
2826          if ((i >= 0) && (bottom == repaint_list[i]->position_info))
2827          {
2828             /* Unselect this object */
2829             SetFileUnselected(file_mgr_data, bottom->file_view_data);
2830             i--;
2831          }
2832          if(bottom->file_view_data != NULL &&
2833             !bottom->file_view_data->need_update)
2834          {
2835             RedrawOneGadget(bottom->file_view_data->widget, NULL, NULL);
2836          }
2837          bottom = bottom->prev;
2838       }
2839
2840       XtFree((char *)repaint_list);
2841       repaint_list = NULL;
2842    }
2843
2844    if (file_mgr_data->selection_list != NULL)
2845    {
2846       XtFree ((char *) file_mgr_data->selection_list);
2847       file_mgr_data->selection_list = NULL;
2848    }
2849
2850    file_mgr_data->selection_list =
2851       (FileViewData **) XtMalloc (sizeof (FileViewData *));
2852    file_mgr_data->selection_list[0] = NULL;
2853    file_mgr_data->selected_file_count = 0;
2854
2855 }
2856
2857
2858
2859
2860 /************************************************************************
2861  *
2862  *  SelectAllFiles
2863  *      Select all of the files within the file manager data.
2864  *
2865  ************************************************************************/
2866
2867 void
2868 SelectAllFiles(
2869         FileMgrData *file_mgr_data )
2870 {
2871    DirectorySet * directory_data;
2872    FileViewData ** order_list;
2873    int directory_count;
2874    int selection_count;
2875    register int i;
2876    register int j;
2877    ObjectPtr top;
2878    FileViewData ** selection_list;
2879
2880
2881    if (PositioningEnabledInView(file_mgr_data))
2882    {
2883       /* Force selection list order to match stacking order */
2884       selection_list = (FileViewData **)XtMalloc(sizeof(FileViewData *) *
2885              (file_mgr_data->num_objects));
2886
2887       top = GetTopOfStack(file_mgr_data);
2888       selection_count = 0;
2889       for (i = 0; i < file_mgr_data->num_objects; i++)
2890       {
2891          /* If the there isn't file_view_data for it
2892             Or if it's a parent folder (..go up)
2893             Don't bother to select them
2894          */
2895          if( top->file_view_data != NULL
2896              && strcmp( top->name, ".." ) != 0 )
2897          {
2898            selection_list[selection_count] = top->file_view_data;
2899            ++selection_count;
2900          }
2901          top = top->next;
2902       }
2903       selection_list[selection_count] = NULL;
2904
2905       /* Force redraw in bottom to top order */
2906       for (i = selection_count - 1; i >= 0; i--)
2907       {
2908          if (!FileIsSelected(file_mgr_data, selection_list[i]))
2909             SetFileSelected(file_mgr_data, selection_list[i]);
2910          }
2911
2912       /* Free old selection list, and save new one */
2913       XtFree ((char *) file_mgr_data->selection_list);
2914       file_mgr_data->selection_list = selection_list;
2915    }
2916    else
2917    {
2918       /*  Free up any current selection and get the selection color.  */
2919
2920       if (file_mgr_data->selection_list != NULL)
2921       {
2922         DeselectAllFiles( file_mgr_data );
2923       }
2924
2925       if (file_mgr_data->show_type == SINGLE_DIRECTORY)
2926          directory_count = 1;
2927       else
2928          directory_count = file_mgr_data->directory_count;
2929
2930
2931       /*  Loop through the set of directories checking each file view   */
2932       /*  structure to see if the icon is filtered.  If not, select it  */
2933       /*  and increment the selection count.                            */
2934
2935       selection_count = 0;
2936
2937       /* For tree mode the index has to be -1 */
2938
2939       i = (file_mgr_data->show_type == MULTIPLE_DIRECTORY)?-1:0;
2940       for (; i < directory_count; i++)
2941       {
2942          directory_data = file_mgr_data->directory_set[i];
2943          order_list = directory_data->order_list;
2944
2945          for (j = 0; j < directory_data->file_count; j++)
2946          {
2947             /* If the file is being filtered out
2948                Or if it's a parent folder (..go up)
2949                Don't bother to select them
2950             */
2951             if (order_list[j]->filtered == True
2952                 || strcmp( order_list[j]->file_data->file_name, ".." ) == 0 )
2953                continue;
2954
2955             selection_count++;
2956
2957             file_mgr_data->selection_list = (FileViewData **)
2958                 XtRealloc ((char *) file_mgr_data->selection_list,
2959                            sizeof(FileViewData *) * (selection_count + 1));
2960
2961             file_mgr_data->selection_list[selection_count] = NULL;
2962             file_mgr_data->selection_list[selection_count - 1] = order_list[j];
2963             SetFileSelected(file_mgr_data, order_list[j]);
2964          }
2965       }
2966    }
2967
2968    file_mgr_data->selected_file_count = selection_count;
2969
2970    if(file_mgr_data != trashFileMgrData)
2971    {
2972       if (selection_count == 0)
2973          ActivateNoSelect ((FileMgrRec *)file_mgr_data->file_mgr_rec);
2974       else if (selection_count == 1)
2975       {
2976          ActivateSingleSelect ((FileMgrRec *)file_mgr_data->file_mgr_rec,
2977                     file_mgr_data->selection_list[0]->file_data->logical_type);
2978       }
2979       else
2980          ActivateMultipleSelect ((FileMgrRec *)file_mgr_data->file_mgr_rec);
2981    }
2982 }
2983
2984
2985
2986
2987 /************************************************************************
2988  *
2989  *  SetToSelectColors
2990  *      Set a single icon widget to selected colors.
2991  *
2992  ************************************************************************/
2993
2994 void
2995 SetToSelectColors(
2996         Widget widget,
2997         Widget file_window,
2998         int type)
2999 {
3000    int j;
3001    Pixel background_color;
3002    Arg args[3];
3003
3004
3005    /*  Get the select color to be used as the background of  */
3006    /*  the icon gadgets.                                     */
3007
3008    j = 0;
3009    XtSetArg (args[j], XmNbackground, &background_color); j++;
3010    XtGetValues (file_window, args, j);
3011
3012    j = 0;
3013    if (background_color == white_pixel)
3014    {
3015       XtSetArg (args[j], XmNbackground, black_pixel); j++;
3016       XtSetArg (args[j], XmNforeground, white_pixel); j++;
3017    }
3018    else if (background_color == black_pixel)
3019    {
3020       XtSetArg (args[j], XmNbackground, white_pixel); j++;
3021       XtSetArg (args[j], XmNforeground, black_pixel); j++;
3022    }
3023    else
3024    {
3025       XtSetArg (args[j], XmNbackground, white_pixel); j++;
3026       XtSetArg (args[j], XmNforeground, black_pixel); j++;
3027    }
3028
3029    XtSetValues (widget, args, j);
3030 }
3031
3032 /************************************************************************
3033  *
3034  *  SetToNormalColors
3035  *      Set a single icon widget to normal colors.
3036  *
3037  ************************************************************************/
3038
3039 void
3040 SetToNormalColors(
3041         Widget widget,
3042         Widget bg_fg_colors,
3043         Widget top_shadow_colors,
3044         int type)
3045 {
3046    int j;
3047    Pixel  background_color;
3048    Pixel  foreground_color;
3049    Pixel  pixmap_background;
3050    DtIconGadget new = (DtIconGadget)widget;
3051    Arg args[5];
3052
3053    /*  Get the colors to be used for drawing the icons  */
3054
3055    j = 0;
3056    XtSetArg (args[j], XmNbackground, &background_color); j++;
3057    XtSetArg (args[j], XmNforeground, &foreground_color); j++;
3058    XtGetValues (bg_fg_colors, args, j);
3059
3060    j = 0;
3061    XtSetArg (args[j], XmNtopShadowColor, &pixmap_background); j++;
3062    XtGetValues (top_shadow_colors, args, j);
3063
3064    j = 0;
3065 #ifdef _SHOW_LINK
3066    if(type == LINK_FILE)
3067       XtSetArg (args[j], XmNforeground, pixmap_background); j++;
3068    else
3069 #endif
3070       XtSetArg (args[j], XmNforeground, foreground_color); j++;
3071
3072    if (background_color == white_pixel)
3073    {
3074        XtSetArg (args[j], XmNbackground, white_pixel); j++;
3075    }
3076    else if (background_color == black_pixel)
3077    {
3078        XtSetArg (args[j], XmNbackground, black_pixel); j++;
3079    }
3080    else
3081    {
3082        XtSetArg (args[j], XmNbackground, background_color); j++;
3083    }
3084
3085    /* we want to make sure the armed value is off so that it will get
3086       the correct GC */
3087    if(new->icon.armed == True)
3088    {
3089       new->icon.armed = False;
3090    }
3091
3092    XtSetValues (widget, args, j);
3093 }
3094
3095
3096 /*
3097  * When a text widget is destroyed, we need to free up the string we
3098  * attached as userData.
3099  */
3100
3101 void
3102 DestroyIconName (
3103    Widget w,
3104    XtPointer client_data,
3105    XtPointer call_data)
3106 {
3107    char * str;
3108    Arg args[1];
3109
3110    XtSetArg(args[0], XmNuserData, &str);
3111    XtGetValues(w, args, 1);
3112    XtFree(str);
3113 }
3114
3115
3116 int
3117 #ifdef _NO_PROTO
3118 GetInsertPosition( x1, x2, fontList, name )
3119    int x1;
3120    int x2;
3121    XmFontList fontList;
3122    char * name;
3123 #else
3124 GetInsertPosition( int x1, int x2, XmFontList fontList, char * name )
3125 #endif
3126 {
3127   int i, width, stringWidth;
3128   char * tmp;
3129   char savedChar;
3130 #ifdef MULTIBYTE
3131   int len;
3132 #endif /* MULTIBYTE */
3133
3134   width = x2 - x1;
3135
3136 #ifdef MULTIBYTE
3137   i = 0;
3138   tmp = name;
3139   while ((len = mblen(tmp, MB_CUR_MAX)) > 0)
3140 #else /* MULTIBYTE */
3141   for( tmp = name + 1, i = 0;
3142        *tmp != 0x0;
3143        ++tmp, ++i )
3144 #endif /* MULTIBYTE */
3145   {
3146     XmString string;
3147
3148 #ifdef MULTIBYTE
3149     tmp += len;
3150 #endif /* MULTIBYTE */
3151
3152     savedChar = *tmp;
3153     *tmp = 0x0;
3154     string = XmStringCreateLocalized( name );
3155     stringWidth = XmStringWidth( fontList, string );
3156     XmStringFree( string );
3157     *tmp = savedChar;
3158     if( stringWidth > width )
3159       break;
3160 #ifdef MULTIBYTE
3161     else
3162       i++;
3163 #endif /* MULTIBYTE */
3164   }
3165
3166   return( i );
3167 }
3168
3169 void
3170 CreateNameChangeDialog (
3171    Widget w,
3172    FileViewData *file_view_data,
3173    XtPointer client_data,
3174    int type)
3175 {
3176    XRectangle textExtent;
3177    FileMgrData * file_mgr_data;
3178    DesktopRec * desktopWindow;
3179    Widget parent = XtParent(w);
3180    Widget text;
3181    Arg args[8];
3182    int n;
3183    Position x, y;
3184    Widget frame, shell;
3185    Dimension fHeight, sHeight;
3186 #ifdef SHAPE
3187    Dimension tWidth, tHeight;
3188 #endif
3189    char * name;
3190    XtTranslations trans_table;
3191    XmFontList fontList;
3192    Dimension stringWidth;
3193    XmString fileNameString;
3194    char tmpBuf[MAX_PATH];
3195
3196    _DtIconGetTextExtent_r(w, &textExtent);
3197
3198    if(type == DESKTOP)
3199    {
3200       char buf[MAXPATHLEN];
3201
3202       desktopWindow = (DesktopRec *)client_data;
3203       if(desktopWindow->text != NULL)
3204          return;
3205
3206       sprintf( buf, "%s:%s", home_host_name, root_title );
3207
3208       /*
3209        * If the object is on the DESKTOP and its name is root_title, then
3210        * the user can't rename it.
3211        */
3212       if( strcmp( buf, desktopWindow->title ) == 0
3213           && strcmp( desktopWindow->dir_linked_to, "/" ) == 0
3214           && strcmp( desktopWindow->file_name, "." ) == 0 )
3215         return;
3216    }
3217    else
3218       file_mgr_data = (FileMgrData *)client_data;
3219
3220    /* if the object is in the trash, can't rename it */
3221    if( type != DESKTOP
3222        && file_mgr_data == trashFileMgrData )
3223       return;
3224
3225    /* if the object is an action, can't rename it */
3226    if( DtDtsDataTypeIsAction( file_view_data->file_data->logical_type ) )
3227    {
3228      char *tmpStr, *title, *msg;
3229
3230      tmpStr = GETMESSAGE(10, 39, "Rename error");
3231      title = XtNewString(tmpStr);
3232      tmpStr = GETMESSAGE(10, 40, "This object is an Action.\nAction icon labels cannot be directly renamed." );
3233      msg = XtNewString(tmpStr);
3234
3235      _DtMessage(toplevel, title, msg, NULL, HelpRequestCB);
3236      XtFree(title);
3237      XtFree(msg);
3238      return;
3239    }
3240    else if(file_view_data->file_data->action_name)
3241    {
3242      char *tmpStr, *title, *msg;
3243
3244      tmpStr = GETMESSAGE(10, 39, "Rename error");
3245      title = XtNewString(tmpStr);
3246      tmpStr = GETMESSAGE(11, 32, "Cannot rename %s");
3247      msg = XtMalloc(strlen(tmpStr)+strlen(file_view_data->file_data->
3248                   action_name) +1);
3249      sprintf(msg,tmpStr,file_view_data->file_data->action_name);
3250
3251      _DtMessage(toplevel, title, msg, NULL, HelpRequestCB);
3252      XtFree(title);
3253      XtFree(msg);
3254      return;
3255    }
3256
3257    /*
3258     * The selected objects name is attached as 'userData' to text field,
3259     * to aid us in mapping back to the original object later.
3260     */
3261    if( type == DESKTOP &&
3262        ( (strcmp(".", file_view_data->file_data->file_name) == 0)
3263          || strcmp("..", file_view_data->file_data->file_name) == 0) )
3264    {
3265       name = XtNewString(desktopWindow->file_name);
3266    }
3267    else if ( strcmp(".", file_view_data->file_data->file_name) == 0 ||
3268              strcmp("..", file_view_data->file_data->file_name) == 0 )
3269    {
3270       return;
3271    }
3272    else
3273       name = XtNewString(file_view_data->file_data->file_name);
3274
3275    /* set up translations in main edit widget */
3276    trans_table = XtParseTranslationTable(translations_escape);
3277
3278    /* We need to set the width of the text widget.
3279       Can't use XmNcolumns because of the double-byte.
3280    */
3281    {
3282      XtSetArg( args[0], XmNfontList, &fontList );
3283      XtGetValues( file_view_data->widget, args, 1 );
3284
3285      sprintf( tmpBuf, "%s    ", file_view_data->file_data->file_name );
3286      fileNameString = XmStringCreateLocalized( tmpBuf );
3287      stringWidth = XmStringWidth( fontList, fileNameString );
3288      XmStringFree( fileNameString );
3289
3290      n = 0;
3291      XtSetArg(args[n], XmNuserData, name);                   n++;
3292      XtSetArg(args[n], XmNmarginHeight, 0);                  n++;
3293      XtSetArg(args[n], XmNmarginWidth, 0);                   n++;
3294      XtSetArg(args[n], XmNvalue, name);                      n++;
3295      XtSetArg(args[n], XmNwidth, stringWidth);               n++;
3296    }
3297
3298    if(type == DESKTOP)
3299    {
3300       text = XmCreateTextField(parent, "nameChangeT_DT", args, n);
3301       XtAddCallback (text, XmNactivateCallback, ChangeIconNameDT,
3302                                                  (XtPointer)desktopWindow);
3303       XtAddCallback(text, XmNhelpCallback, (XtCallbackProc)DTHelpRequestCB,
3304                     HELP_NAMECHANGE_DIALOG_STR);
3305       desktopWindow->text = text;
3306
3307       frame = XtParent(parent);
3308       shell = XtParent(frame);
3309       XtSetArg(args[0], XmNheight, &fHeight);
3310       XtGetValues(frame, args, 1);
3311       XtSetArg(args[0], XmNheight, &sHeight);
3312       XtGetValues(shell, args, 1);
3313    }
3314    else
3315    {
3316       text = XmCreateTextField(parent, "nameChangeT", args, n);
3317       file_mgr_data->renaming = file_view_data;
3318       XtAddCallback (text, XmNmotionVerifyCallback,
3319                      (XtCallbackProc)ChangeIconName,
3320                      (XtPointer)file_mgr_data);
3321       XtAddCallback (text, XmNmodifyVerifyCallback,
3322                      (XtCallbackProc)ChangeIconName,
3323                      (XtPointer)file_mgr_data);
3324       XtAddCallback (text, XmNactivateCallback,
3325                      (XtCallbackProc)ChangeIconName,
3326                      (XtPointer)file_mgr_data);
3327       XtAddCallback(text, XmNhelpCallback, (XtCallbackProc)HelpRequestCB,
3328                     HELP_NAMECHANGE_DIALOG_STR);
3329    }
3330
3331    XtAddCallback (text, XmNdestroyCallback, DestroyIconName, (XtPointer)NULL);
3332
3333    /* set up translations in main edit widget */
3334    XtOverrideTranslations(text, trans_table);
3335
3336    if(type == DESKTOP && sHeight > fHeight) {
3337        /* status area has been attached in multi-byte case */
3338        x = 0;
3339        y = textExtent.y;
3340    }
3341    else {
3342        x = textExtent.x;
3343        y = textExtent.y - (Dimension)(text->core.height - textExtent.height);
3344    }
3345
3346    {
3347      Window rootWindow, childWindow;
3348      int pX, pY, rootX, rootY, insertPosition;
3349      unsigned int mask;
3350
3351      XQueryPointer( XtDisplay( parent ), XtWindow( file_view_data->widget ),
3352                     &rootWindow, &childWindow, &rootX, &rootY, &pX, &pY,
3353                     &mask );
3354      if( pX == 0 )
3355        insertPosition = strlen( name );
3356      else
3357      {
3358        if( type != DESKTOP )
3359        {
3360          if( pX > (int) x && pX < (int) x + (int) stringWidth )
3361            insertPosition = GetInsertPosition( x, pX, fontList, name );
3362          else
3363            insertPosition = strlen( name );
3364        }
3365        else
3366          insertPosition = GetInsertPosition( x, x + pX, fontList, name );
3367      }
3368      n = 0;
3369      XtSetArg( args[n], XmNcursorPosition, insertPosition);     n++;
3370      XtSetArg( args[n], XmNx, x);                               n++;
3371      XtSetArg( args[n], XmNy, y);                               n++;
3372      XtSetValues (text, args, n);
3373    }
3374
3375 #ifdef SHAPE
3376    if(shapeExtension)
3377       if(type == DESKTOP)
3378       {
3379          Dimension shadowThickness;
3380          XRectangle rect[2];
3381          unsigned char flags;
3382
3383          XtSetArg (args[0], XmNwidth, &tWidth);
3384          XtSetArg (args[1], XmNheight, &tHeight);
3385          XtGetValues (text, args, 2);
3386
3387          XtSetArg (args[0], XmNshadowThickness, &shadowThickness);
3388          XtGetValues (desktopWindow->iconGadget, args, 1);
3389
3390          _DtIconGetIconRects((DtIconGadget)desktopWindow->iconGadget,
3391                                                 &flags, &rect[0], &rect[1]);
3392         /* 1 */
3393          rect[0].x += 1;
3394          rect[0].y += 1;
3395          rect[0].width += 2*shadowThickness;
3396          rect[0].height += 2*shadowThickness;
3397
3398         /* 2 */
3399          if(type == DESKTOP && sHeight > fHeight) {
3400              /* status area has been attached in multi-byte case */
3401              rect[1].x = x + 1;
3402              rect[1].y = y + 1;
3403              rect[1].width = 2*shadowThickness + tWidth;
3404              rect[1].height = sHeight - y - 1;
3405          }
3406          else {
3407              rect[1].x += 1;
3408              rect[1].y += 1;
3409              rect[1].width = shadowThickness + tWidth;
3410              rect[1].height = tHeight;
3411          }
3412
3413          if(rect[0].width > rect[1].width)
3414            rect[1].width = rect[0].width;
3415
3416          XShapeCombineRectangles(XtDisplay(desktopWindow->shell),
3417                                  XtWindow(desktopWindow->shell),
3418                                  ShapeBounding, 0, 0, &rect[0], 2,
3419                                  ShapeSet, Unsorted);
3420       }
3421 #endif
3422    XtManageChild(text);
3423    XmProcessTraversal(text, XmTRAVERSE_CURRENT);
3424
3425    if(type != DESKTOP)
3426    {
3427       FileMgrRec *file_mgr_rec;
3428
3429       file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
3430       file_mgr_rec->menuStates &= ~RENAME;
3431    }
3432 }
3433
3434 /************************************************************************
3435  *
3436  *  SavePositionalData
3437  *      Save the desktop icon positional data.
3438  *
3439  ************************************************************************/
3440
3441 void
3442 SavePositionalData (
3443    int fd,
3444    FileMgrData * file_mgr_data,
3445    char ** name_list,
3446    char * name)
3447 {
3448    int i;
3449    FILE * fd_stream = fdopen(fd, "w");
3450    ObjectPosition * ptr;
3451
3452
3453    if(file_mgr_data->positionEnabled == RANDOM_ON &&
3454                   file_mgr_data->object_positions &&
3455                   file_mgr_data->show_type == SINGLE_DIRECTORY &&
3456                   file_mgr_data->host != NULL)
3457    {
3458       /* Number of object positions */
3459       fprintf(fd_stream, "*%s.%s.%s.%s:   %d\n#\n", name_list[0], name_list[1],
3460                name, "num_positions", file_mgr_data->num_objects);
3461
3462       for (i = 0; i < file_mgr_data->num_objects; i++)
3463       {
3464          ptr = file_mgr_data->object_positions[i];
3465          fprintf(fd_stream, "*%s.%s.%s.%s%d:   %s %d %d %d\n",
3466                    name_list[0], name_list[1], name, "object", i,
3467                    ptr->name,
3468                    ptr->x,
3469                    ptr->y,
3470                    ptr->stacking_order);
3471       }
3472    }
3473    else
3474    {
3475       /* Number of object positions */
3476       fprintf(fd_stream, "*%s.%s.%s.%s:   %d\n#\n", name_list[0], name_list[1],
3477                name, "num_positions", 0);
3478    }
3479
3480    fflush(fd_stream);
3481 }
3482
3483
3484
3485 /************************************************************************
3486  *
3487  *  RestorePositionalData
3488  *      Restore the desktop icon positional data.
3489  *
3490  ************************************************************************/
3491
3492 void
3493 RestorePositionalData (
3494    XrmDatabase db,
3495    char ** name_list,
3496    FileMgrData * file_mgr_data,
3497    char * name)
3498 {
3499    XrmName xrm_name[10];
3500    int i = 0;
3501    int j;
3502    char objectName[20];
3503    XrmRepresentation rep_type;
3504    XrmValue value;
3505    int num_objects;
3506    char * str;
3507    char * obj_name;
3508    ObjectPosition * ptr;
3509    int x, y;
3510    int s_order;
3511
3512    while (name_list[i])
3513    {
3514       xrm_name[i] = XrmStringToQuark(name_list[i]);
3515       i++;
3516    }
3517    xrm_name[i++] = XrmStringToQuark(name);
3518    xrm_name[i] = XrmStringToQuark("num_positions");
3519    xrm_name[i+1] = NULL;
3520
3521    /* Find out how many objects there are to be loaded */
3522    file_mgr_data->object_positions = NULL;
3523    num_objects = 0;
3524    if (XrmQGetResource (db, xrm_name, NULL, &rep_type, &value))
3525    {
3526       if ((num_objects = atoi (value.addr)) <= 0)
3527          num_objects = 0;
3528       else
3529       {
3530          file_mgr_data->object_positions = (ObjectPosition **)XtMalloc(
3531                              sizeof(ObjectPosition *) * num_objects);
3532       }
3533    }
3534
3535    file_mgr_data->num_objects = num_objects;
3536
3537    for (j = 0; j < num_objects; j++)
3538    {
3539       sprintf(objectName, "object%d", j);
3540       xrm_name[i] = XrmStringToQuark(objectName);
3541       ptr = file_mgr_data->object_positions[j] = (ObjectPosition *)
3542                                      XtMalloc(sizeof(ObjectPosition));
3543
3544       XrmQGetResource (db, xrm_name, NULL, &rep_type, &value);
3545       str = (char *)value.addr;
3546       obj_name = XtMalloc(strlen(str) + 1);
3547       sscanf((char *)value.addr, "%s %d %d %d", obj_name, &x, &y, &s_order);
3548       ptr->name = obj_name;
3549       ptr->x = x;
3550       ptr->y = y;
3551       ptr->stacking_order = s_order;
3552       ptr->in_use = False;
3553       ptr->late_bind = False;
3554       ptr->file_view_data = NULL;
3555       ptr->next = NULL;
3556       ptr->prev = NULL;
3557    }
3558
3559    /* Repair all of the next and prev pointers */
3560    RepairStackingPointers(file_mgr_data);
3561 }
3562
3563
3564 void
3565 UnpostTextField (
3566    FileMgrData * file_mgr_data)
3567
3568 {
3569    XmManagerWidget file_window;
3570    int i;
3571    FileMgrRec * file_mgr_rec;
3572
3573    file_mgr_data->renaming = NULL;
3574
3575    file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
3576    file_window = (XmManagerWidget) file_mgr_rec->file_window;
3577    for (i = 0; i < file_window->composite.num_children; i++)
3578    {
3579       if (XmIsTextField(file_window->composite.children[i]) &&
3580           !file_window->composite.children[i]->core.being_destroyed)
3581       {
3582          XtUnmanageChild(file_window->composite.children[i]);
3583          XtDestroyWidget(file_window->composite.children[i]);
3584          return;
3585       }
3586    }
3587 }
3588
3589
3590 void
3591 UnpostTextPath (
3592    FileMgrData * file_mgr_data)
3593
3594 {
3595   FileMgrRec * file_mgr_rec;
3596   Arg args[2];
3597
3598   file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
3599
3600   XtSetArg (args[0], XmNallowShellResize, False);
3601   XtSetValues(file_mgr_rec->shell, args, 1);
3602
3603   XtUnmanageChild(file_mgr_rec->current_directory_text);
3604
3605   XtSetArg (args[0], XmNallowShellResize, True);
3606   XtSetValues(file_mgr_rec->shell, args, 1);
3607
3608   file_mgr_data->fast_cd_enabled = False;
3609 }
3610
3611
3612 /*
3613  * Function to force a redraw of a single gadget.
3614  */
3615
3616 void
3617 RedrawOneGadget (
3618    Widget child,
3619    XEvent * event,
3620    Region region)
3621
3622 {
3623    if (child->core.widget_class->core_class.expose)
3624       (*(child->core.widget_class->core_class.expose))(child, event, region);
3625 }
3626
3627
3628 /*
3629  * Given a region describing the area to be repainted, repaint all icons,
3630  * in bottom to top order, which fall into this region.
3631  */
3632
3633 void
3634 RepaintDesktop (
3635    FileMgrData * file_mgr_data,
3636    XEvent * event,
3637    Region region)
3638
3639 {
3640    Widget child;
3641    ObjectPosition * bottom = GetBottomOfStack(file_mgr_data);
3642
3643    /* Redraw all affected gadgets */
3644    while(bottom)
3645    {
3646       if (!bottom->late_bind)
3647       {
3648          if (bottom->file_view_data != NULL &&
3649              !bottom->file_view_data->need_update)
3650          {
3651             child = bottom->file_view_data->widget;
3652             if (XRectInRegion(region, child->core.x, child->core.y,
3653                               child->core.width, child->core.height))
3654             {
3655                RedrawOneGadget(child, event, region);
3656             }
3657          }
3658       }
3659
3660       bottom = bottom->prev;
3661    }
3662 }
3663
3664
3665 /*
3666  * This function will extract all exposure events intended for this file
3667  * window, combine them into a single region, and then determine which of
3668  * the file icons need to be redrawn.  It is a two step process, as
3669  * described by the comments in the code.
3670  */
3671
3672 static void
3673 RedisplayUsingStackingOrder (
3674    FileMgrData * file_mgr_data,
3675    Widget w,
3676    register XEvent *event,
3677    Region region)
3678
3679 {
3680    register Widget child;
3681    FileViewData * file_view_data;
3682    ObjectPosition * bottom;
3683    ObjectPosition * top;
3684    Region redrawRegion = XCreateRegion();
3685    XRectangle rect;
3686    XEvent expEvent;
3687    int numChildren = 0;
3688    Widget * children = NULL;
3689    Region widget_region;
3690    Region tmp_region;
3691
3692    /* Get the initial region to redraw */
3693    if (region)
3694       XUnionRegion(redrawRegion, region, redrawRegion);
3695    else if (event)
3696    {
3697       rect.x = event->xexpose.x;
3698       rect.y = event->xexpose.y;
3699       rect.height = event->xexpose.height;
3700       rect.width = event->xexpose.width;
3701
3702       XUnionRectWithRegion(&rect, redrawRegion, redrawRegion);
3703    }
3704
3705    /*
3706     * Capture and encompass any other exposure events which are destined for
3707     * us, but are waiting in the wings.
3708     */
3709    while (XCheckWindowEvent(XtDisplay(w), XtWindow(w), ExposureMask, &expEvent))
3710    {
3711       rect.x = expEvent.xexpose.x;
3712       rect.y = expEvent.xexpose.y;
3713       rect.height = expEvent.xexpose.height;
3714       rect.width = expEvent.xexpose.width;
3715
3716       XUnionRectWithRegion(&rect, redrawRegion, redrawRegion);
3717    }
3718
3719    /* Nothing to do if the redraw region is empty */
3720    if (XEmptyRegion(redrawRegion))
3721    {
3722       XDestroyRegion(redrawRegion);
3723       return;
3724    }
3725
3726    /*
3727     * Starting at the top of the stack, find any items which fall into
3728     * the redraw region.  As items are found which need to be redrawn,
3729     * subtract them from the redraw region, so that any items lower on the
3730     * stack which might be under these gadgets, but are within the region,
3731     * are not redrawn.
3732     *
3733     * The second phase is to start at the bottom of the stack, and start
3734     * redrawing the gadgets which fell into the region, along with any
3735     * other gadgets on top of these (since they too now need to be redrawn.
3736     */
3737    top = GetTopOfStack(file_mgr_data);
3738    children = NULL;
3739    numChildren = 0;
3740
3741    while (top)
3742    {
3743       if (!top->late_bind)
3744       {
3745          file_view_data = top->file_view_data;
3746          if(file_view_data != NULL)
3747          {
3748             child = file_view_data->widget;
3749
3750             if (child && XmIsGadget(child) && XtIsManaged(child))
3751             {
3752                widget_region = XCreateRegion();
3753                WidgetRectToRegion(file_mgr_data, child, widget_region);
3754                XIntersectRegion(redrawRegion, widget_region, widget_region);
3755                if (!XEmptyRegion(widget_region))
3756                {
3757                   XSubtractRegion(redrawRegion, widget_region, redrawRegion);
3758                   children = (Widget *)XtRealloc((char *)children,
3759                                          (numChildren + 1) * sizeof(Widget));
3760                   children[numChildren] = child;
3761                   numChildren++;
3762                }
3763                XDestroyRegion(widget_region);
3764             }
3765          }
3766       }
3767       top = (ObjectPosition *)top->next;
3768    }
3769
3770    /* Now, start redrawing, in bottom to top order */
3771    bottom = GetBottomOfStack(file_mgr_data);
3772    numChildren--;
3773    while (bottom)
3774    {
3775       if (!bottom->late_bind)
3776       {
3777          file_view_data = bottom->file_view_data;
3778          if(file_view_data != NULL)
3779          {
3780             child = file_view_data->widget;
3781
3782             if (child && XmIsGadget(child) && XtIsManaged(child))
3783             {
3784                widget_region = XCreateRegion();
3785                WidgetRectToRegion(file_mgr_data, child, widget_region);
3786                if ((numChildren >= 0) && (children[numChildren] == child))
3787                {
3788                   XUnionRegion(redrawRegion, widget_region, redrawRegion);
3789                   RedrawOneGadget(child, event, redrawRegion);
3790                   numChildren--;
3791                }
3792                else
3793                {
3794                   /* Do we overlap something which was previously redrawn? */
3795                   tmp_region = XCreateRegion();
3796                   XIntersectRegion(redrawRegion, widget_region, tmp_region);
3797                   if (!XEmptyRegion(tmp_region))
3798                   {
3799                      XUnionRegion(redrawRegion, widget_region, redrawRegion);
3800                      RedrawOneGadget(child, event, redrawRegion);
3801                   }
3802                   XDestroyRegion(tmp_region);
3803                }
3804                XDestroyRegion(widget_region);
3805             }
3806          }
3807       }
3808       bottom = (ObjectPosition *)bottom->prev;
3809    }
3810
3811    XDestroyRegion(redrawRegion);
3812    XtFree((char *)children);
3813    children = NULL;
3814 }
3815
3816
3817 /*
3818  * This is the function which we use to override the class expose function
3819  * for the drawing area widget.  It allows us to catch exposure events
3820  * intended for the desktop, so that we can force the redrawing of the
3821  * gadgets to occur occording to the stacking order.
3822  */
3823
3824 void
3825 DrawingAreaRedisplay (
3826    Widget wid,
3827    XEvent *event,
3828    Region region)
3829
3830 {
3831    XmDrawingAreaWidget da = (XmDrawingAreaWidget) wid;
3832    XmDrawingAreaCallbackStruct cb;
3833    FileMgrData * file_mgr_data;
3834
3835    cb.reason = XmCR_EXPOSE;
3836    cb.event = event;
3837    cb.window = XtWindow (da);
3838
3839    DPRINTF2(("DrawingAreaRedisplay: event %d, x/y %d/%d, wd/ht %d/%d\n",
3840              event->xany.type,
3841              event->xexpose.x, event->xexpose.y,
3842              event->xexpose.width, event->xexpose.height));
3843
3844    file_mgr_data = ReturnDesktopPtr(wid);
3845
3846    if (file_mgr_data && PositioningEnabledInView(file_mgr_data))
3847       RedisplayUsingStackingOrder(file_mgr_data, (Widget)da, event, region);
3848    else
3849       XmeRedisplayGadgets((Widget)da, event, region);
3850
3851    XtCallCallbackList ((Widget)da, da->drawing_area.expose_callback, &cb);
3852 }
3853
3854
3855 /*
3856  * Return the bottom of the stacking order list.
3857  */
3858
3859 ObjectPtr
3860 GetBottomOfStack (
3861    FileMgrData * file_mgr_data)
3862
3863 {
3864    int i;
3865    ObjectPtr bottom;
3866
3867    for (i = 0, bottom = NULL; i < file_mgr_data->num_objects; i++)
3868    {
3869       if (file_mgr_data->object_positions[i]->next == NULL)
3870       {
3871          bottom = file_mgr_data->object_positions[i];
3872          break;
3873       }
3874    }
3875
3876    return(bottom);
3877 }
3878
3879
3880 /*
3881  * Return the top of the stacking order list.
3882  */
3883
3884 ObjectPtr
3885 GetTopOfStack (
3886    FileMgrData * file_mgr_data)
3887 {
3888    int i;
3889    ObjectPtr top;
3890
3891    for (i = 0, top = NULL; i < file_mgr_data->num_objects; i++)
3892    {
3893       if (file_mgr_data->object_positions[i]->prev == NULL)
3894       {
3895          top = file_mgr_data->object_positions[i];
3896          break;
3897       }
3898    }
3899
3900    return(top);
3901 }
3902
3903
3904 /*
3905  * Move an object up in the stacking order.  Will not work for moving an
3906  * object further down in the stacking order, but we currently have no
3907  * need for doing that.
3908  *
3909  * NOTE: The top of the stack is '1', not '0'!!
3910  */
3911
3912 void
3913 RepositionUpInStack (
3914    FileMgrData * file_mgr_data,
3915    int oldPos,
3916    int newPos)
3917
3918 {
3919    ObjectPtr ptr, ptr2, savePtr;
3920    register int i, j;
3921    XmManagerWidget file_window;
3922
3923    if (oldPos == newPos)
3924       return;
3925
3926    ptr = GetTopOfStack(file_mgr_data);
3927
3928    /* Find where item is to be inserted */
3929    while (ptr->stacking_order != newPos)
3930       ptr = ptr->next;
3931
3932    /* Find where item currently is */
3933    ptr2 = ptr;
3934    while (ptr2->stacking_order != oldPos)
3935       ptr2 = ptr2->next;
3936
3937    savePtr = ptr2;
3938
3939    if(savePtr->file_view_data == NULL)
3940       return;
3941
3942    /* Remove from its current location */
3943    if (ptr2->prev)
3944       ptr2->prev->next = ptr2->next;
3945    if (ptr2->next)
3946       ptr2->next->prev = ptr2->prev;
3947
3948    /* Link into new position */
3949    ptr2->prev = ptr->prev;
3950    ptr2->next = ptr;
3951    if (ptr->prev)
3952       ptr2->prev->next = ptr2;
3953    ptr->prev = ptr2;
3954
3955    /* Update the stacking order value */
3956    for (i = newPos; i <= oldPos; i++)
3957    {
3958       ptr2->stacking_order = i;
3959       ptr2 = ptr2->next;
3960    }
3961
3962    /* Update the children's list for the file window */
3963    file_window = (XmManagerWidget)
3964                   (((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window);
3965
3966    /* Find the affect child */
3967    for (i = 0; (i < file_window->composite.num_children) &&
3968        (file_window->composite.children[i] != savePtr->file_view_data->widget);
3969        i++);
3970
3971    /* Push intervening entries down */
3972    for (j = i; j >= newPos; j--)
3973       file_window->composite.children[j] = file_window->composite.children[j-1];
3974
3975    /* Insert into new position in children list */
3976    file_window->composite.children[newPos-1] = savePtr->file_view_data->widget;
3977 }
3978
3979
3980 /*
3981  * Reorder the file window's children list so that it matches the stacking
3982  * order.
3983  */
3984
3985 static void
3986 ReorderChildrenList (
3987    XmManagerWidget file_window,
3988    Widget * manage,
3989    int manageCount,
3990    Widget * unmanage,
3991    int unmanageCount)
3992
3993 {
3994    Widget * children = file_window->composite.children;
3995    register int i, j;
3996
3997    for (i = 0; i < manageCount; i++)
3998       children[i] = manage[i];
3999
4000    for (j = 0; j < unmanageCount; j++)
4001       children[i++] = unmanage[j];
4002 }
4003
4004
4005 /*
4006  * If positional information is available for the indicated file, then
4007  * return it; if not, then return NULL.
4008  */
4009
4010 ObjectPtr
4011 FindCurrentPosition (
4012    FileMgrData * file_mgr_data,
4013    char * file_name)
4014
4015 {
4016    int i;
4017
4018    for (i = 0; i < file_mgr_data->num_objects; i++)
4019    {
4020       if (strcmp(file_name, file_mgr_data->object_positions[i]->name) == 0)
4021       {
4022          /* Found a match */
4023          file_mgr_data->object_positions[i]->in_use = True;
4024          return(file_mgr_data->object_positions[i]);
4025       }
4026    }
4027
4028    return(NULL);
4029 }
4030
4031
4032 void
4033 RepairStackingPointers (
4034    FileMgrData * file_mgr_data)
4035
4036 {
4037    int i;
4038    int j;
4039    ObjectPosition * ptr;
4040    ObjectPosition * prev;
4041
4042    for (i = 1, prev = NULL; i <= file_mgr_data->num_objects; i++)
4043    {
4044       for (j = 0; j < file_mgr_data->num_objects; j++)
4045       {
4046          ptr = file_mgr_data->object_positions[j];
4047          if (ptr->stacking_order == i)
4048          {
4049             if (prev)
4050             {
4051                ptr->prev = prev;
4052                prev->next = ptr;
4053             }
4054             prev = ptr;
4055             break;
4056          }
4057       }
4058    }
4059 }
4060
4061 /*
4062  * Reorder the children's list for the file_window, so that it matches
4063  * the stacking order.  Also, set up all next and previous pointers.
4064  */
4065
4066 void
4067 OrderChildrenList (
4068    FileMgrData * file_mgr_data)
4069
4070 {
4071    FileMgrRec * file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
4072    XmManagerWidget file_window;
4073    Widget * managed;
4074    Widget * unmanaged;
4075    int num_managed;
4076    int num_unmanaged;
4077    ObjectPosition * top;
4078    int i, j;
4079
4080    file_window = (XmManagerWidget) file_mgr_rec->file_window;
4081    managed = (Widget *)XtMalloc(sizeof(Widget *) *
4082                         file_window->composite.num_children);
4083    unmanaged = (Widget *)XtMalloc(sizeof(Widget *) *
4084                         file_window->composite.num_children);
4085    num_managed = num_unmanaged = 0;
4086
4087    top = GetTopOfStack(file_mgr_data);
4088    while(top)
4089    {
4090       if (top->file_view_data != NULL && top->file_view_data->widget != NULL)
4091          managed[num_managed++] = top->file_view_data->widget;
4092       top = top->next;
4093    }
4094
4095    /* All the rest get put at the end of the children's list */
4096    for (i = 0; i < file_window->composite.num_children; i++)
4097    {
4098       for (j = 0; j < num_managed; j++)
4099       {
4100          if (managed[j] == file_window->composite.children[i])
4101             break;
4102       }
4103
4104       if (j >= num_managed)
4105          unmanaged[num_unmanaged++] = file_window->composite.children[i];
4106    }
4107
4108    ReorderChildrenList(file_window, managed, num_managed, unmanaged,
4109                        num_unmanaged);
4110    XtFree( (char *)managed );
4111    XtFree( (char *)unmanaged );
4112 }
4113
4114
4115 /*
4116  * SetHotRects
4117  */
4118
4119 void
4120 SetHotRects (
4121    FileViewData  * file_view_data,
4122    XtCallbackProc callback,
4123    XtPointer callback_data)
4124
4125 {
4126    Arg args[3];
4127
4128    if (file_view_data->displayed)
4129    {
4130       /*************************/
4131       /* icon gadget displayed */
4132       /*************************/
4133       DtIconGadget g = (DtIconGadget) file_view_data->widget;
4134       unsigned char operations;
4135
4136          /* find defined operations (M/C/L) for file type */
4137       operations = TypeToDropOperations(
4138                              file_view_data->file_data->logical_type);
4139
4140       /* if icon gadget not yet registered as a drop site, do so now */
4141       if (!file_view_data->registered)
4142       {
4143          /* register drop site for MCL but make drop site inactive */
4144          XtSetArg (args[0], XmNdropSiteOperations,
4145                    XmDROP_COPY | XmDROP_MOVE | XmDROP_LINK);
4146          XtSetValues (file_view_data->widget, args, 1);
4147
4148          file_view_data->registered = True;
4149       }
4150
4151       if (operations)
4152       {
4153          /***********************************/
4154          /* file has associated MCL actions */
4155          /***********************************/
4156          XRectangle rects[2];
4157          unsigned char flags;
4158          int numRects = 0;
4159          Cardinal n = 0;
4160          Dimension s_t, adj_xy, adj_size;
4161
4162          /* ensure drop site operations and drop area are correct */
4163          _DtIconGetIconRects(g, &flags, &rects[0], &rects[1]);
4164
4165          /*
4166           * Compute adjustments to the drop area:
4167           *
4168           *  - Add shadowThickness to the drop area:
4169           *    The icon gadget leaves space of width shadowThickness around
4170           *    the pixmap and label; use this space to make the drop zone
4171           *    larger.
4172           *
4173           *  - Compensate for bug in drop zone registration/drawing:
4174           *    For some reason the drop zone displayed on the screen is
4175           *    actually smaller than the rectangle we register:
4176           *    The drag&drop library seems to reduce the size of the drop
4177           *    area by the value of highlightThickness at the top and left
4178           *    border and by highlightThickness-1 at the bottom and right.
4179           *    Is this a Motif drag&drop bug?
4180           *    We compensate by registering a larger rectangle.
4181           */
4182          s_t = G_ShadowThickness(g);
4183          adj_xy = s_t + G_HighlightThickness(g);
4184          adj_size = adj_xy + s_t + G_HighlightThickness(g) - 1;
4185
4186          if (flags & XmPIXMAP_RECT)
4187          {
4188             rects[0].x -= g->rectangle.x + adj_xy;
4189             rects[0].y -= g->rectangle.y + adj_xy;
4190             rects[0].width += adj_size;
4191             rects[0].height += adj_size;
4192             numRects++;
4193           }
4194
4195          if (flags & XmLABEL_RECT)
4196          {
4197             rects[1].x -= g->rectangle.x + adj_xy;
4198             rects[1].y -= g->rectangle.y + adj_xy;
4199             rects[1].width += adj_size;
4200             rects[1].height += adj_size;
4201             if (!numRects) rects[0] = rects[1];
4202                numRects++;
4203           }
4204
4205           if (numRects)
4206           {
4207              XtSetArg(args[n], XmNdropRectangles, rects);        n++;
4208              XtSetArg(args[n], XmNnumDropRectangles, numRects);  n++;
4209           }
4210           XtSetArg (args[n], XmNdropSiteOperations, operations); n++;
4211
4212           XmDropSiteUpdate (file_view_data->widget, args, n);
4213           g->icon.operations = operations;
4214
4215           /* add client data */
4216           XtRemoveAllCallbacks(file_view_data->widget, XmNdropCallback);
4217           XtAddCallback(file_view_data->widget, XmNdropCallback,
4218                       callback, callback_data);
4219       }
4220       else
4221       {
4222          /*********************************************/
4223          /* file does not have associated MCL actions */
4224          /*********************************************/
4225          /* make drop site inactive */
4226          XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
4227          XmDropSiteUpdate (file_view_data->widget, args, 1);
4228          XtRemoveAllCallbacks(file_view_data->widget, XmNdropCallback);
4229       }
4230     }
4231     else
4232     {
4233       /*****************************/
4234       /* icon gadget not displayed */
4235       /*****************************/
4236       if (file_view_data->registered)
4237       {
4238          /***************************************/
4239          /* icon gadget registered as drop site */
4240          /***************************************/
4241          /* make drop site inactive */
4242          XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
4243          XmDropSiteUpdate (file_view_data->widget, args, 1);
4244          XtRemoveAllCallbacks(file_view_data->widget, XmNdropCallback);
4245       }
4246    }
4247 }
4248
4249
4250
4251 /*
4252  * TypeToDropOperations
4253  */
4254
4255 unsigned char
4256 TypeToDropOperations (
4257    char * file_type)
4258
4259 {
4260    unsigned char operations = 0L;
4261    char *action;
4262
4263    /* does object have MOVE, COPY, and/or LINK actions */
4264    /*    -- or no actions at all                       */
4265    if (action = DtDtsDataTypeToAttributeValue(file_type,
4266                                               DtDTS_DA_MOVE_TO_ACTION,
4267                                               NULL))
4268    {
4269       operations = operations | XmDROP_MOVE;
4270       DtDtsFreeAttributeValue(action);
4271    }
4272    if (action = DtDtsDataTypeToAttributeValue(file_type,
4273                                               DtDTS_DA_COPY_TO_ACTION,
4274                                               NULL))
4275    {
4276       operations = operations | XmDROP_COPY;
4277       DtDtsFreeAttributeValue(action);
4278    }
4279    if (action = DtDtsDataTypeToAttributeValue(file_type,
4280                                               DtDTS_DA_LINK_TO_ACTION,
4281                                               NULL))
4282    {
4283       operations = operations | XmDROP_LINK;
4284       DtDtsFreeAttributeValue(action);
4285    }
4286
4287    return(operations);
4288 }
4289
4290
4291 /*
4292  * TypeToAction
4293  */
4294
4295 char *
4296 TypeToAction (
4297    unsigned char dropOperation,
4298    char * logical_type)
4299 {
4300    char * action;
4301
4302    /* retrieve action from database based on dropOperation */
4303    switch(dropOperation)
4304    {
4305       case XmDROP_MOVE:
4306          action = DtDtsDataTypeToAttributeValue(logical_type,
4307                                                 DtDTS_DA_MOVE_TO_ACTION,
4308                                                 NULL);
4309          break;
4310       case XmDROP_COPY:
4311          action = DtDtsDataTypeToAttributeValue(logical_type,
4312                                                 DtDTS_DA_COPY_TO_ACTION,
4313                                                 NULL);
4314          break;
4315       case XmDROP_LINK:
4316          action = DtDtsDataTypeToAttributeValue(logical_type,
4317                                                 DtDTS_DA_LINK_TO_ACTION,
4318                                                 NULL);
4319          break;
4320       default:
4321          action = NULL;
4322          break;
4323    }
4324
4325    return(action);
4326 }
4327
4328
4329 /*
4330  * Given a fileViewData pointer, determine if it is part of a FileMgrData,
4331  * or a DesktopRec; return the appropriate pointer.
4332  */
4333
4334 static
4335 Boolean
4336 IsDesktopPtr (
4337    FileViewData * fileViewData,
4338    FileMgrData ** fileMgrData,
4339    DesktopRec ** desktopRec)
4340 {
4341    int i;
4342
4343    *desktopRec = NULL;
4344    *fileMgrData = NULL;
4345
4346    for (i = 0; i < desktop_data->numIconsUsed; i++)
4347    {
4348       if (desktop_data->desktopWindows[i]->file_view_data == fileViewData)
4349       {
4350          *desktopRec = desktop_data->desktopWindows[i];
4351          return(True);
4352       }
4353    }
4354
4355    *fileMgrData = (FileMgrData *)
4356                 ((DirectorySet *)fileViewData->directory_set)->file_mgr_data;
4357    return(False);
4358 }
4359
4360
4361 /******************************************************************
4362  *
4363  *  PositionFileView -
4364  *        Given a particular file, position the file view that file
4365  *        is in on that particular file.
4366  *
4367  ********************************************************************/
4368 void
4369 PositionFileView(
4370      FileViewData *file_view_data,
4371      FileMgrData *file_mgr_data)
4372 {
4373    Position x, y;
4374    Arg args[1];
4375    int value, size, increment, page, max;
4376    FileMgrRec * file_mgr_rec = (FileMgrRec *)(file_mgr_data->file_mgr_rec);
4377    Widget p;
4378
4379    /* if the file is filtered we can't highlight it! */
4380    if(!file_view_data->displayed)
4381       return;
4382
4383    /* Get the y location of the icon_gadget */
4384    y = file_view_data->y - file_mgr_data->grid_height;
4385
4386    /* Two things:
4387     * 
4388     * 1) not sure exactly how slow this is, but there seems to be no other
4389     *    way to do this. (CDExc23427)
4390     * 2) XmScrollVisible does not work if the work window is not managed...
4391     *    so, we call it, and then get the appropriate x,y back from the
4392     *    scroll bars and set them (CDExc23428) */
4393    p = XtVaCreateManagedWidget("positionicon", xmGadgetClass, 
4394                                file_mgr_rec->file_window,
4395                                XmNmappedWhenManaged, False,
4396                                XmNx, file_view_data->x,
4397                                XmNy, y, 
4398                                XmNwidth, file_mgr_data->grid_width,
4399                                XmNheight, file_mgr_data->grid_height,
4400                                NULL);
4401
4402    XmScrollVisible(file_mgr_rec->scroll_window, p,
4403                    XSPACING, YSPACING(file_mgr_data));
4404
4405    XtDestroyWidget(p);
4406
4407    XmScrollBarGetValues(file_mgr_rec->horizontal_scroll_bar,
4408                         &value, &size, &increment, &page);
4409    x = -((Position) value);
4410
4411    XmScrollBarGetValues(file_mgr_rec->vertical_scroll_bar,
4412                         &value, &size, &increment, &page);
4413    y = -((Position) value);
4414
4415    XtVaSetValues(file_mgr_rec->file_window, XmNx, x, XmNy, y, NULL);
4416 }
4417
4418
4419 static Boolean
4420 InMultipleObjectRegion (FileMgrData * file_mgr_data, FileViewData * fileViewData)
4421 {
4422   register int i;
4423   for( i = 0; i < file_mgr_data->selected_file_count; ++i )
4424     if( strcmp( file_mgr_data->selection_list[i]->file_data->file_name, fileViewData->file_data->file_name ) == 0 )
4425       return True;
4426   return False;
4427 }
4428
4429 void
4430 FmPopup (
4431       Widget w,
4432       XtPointer client_data,
4433       XEvent *event,
4434       FileMgrData *file_mgr_data)
4435 {
4436    FileMgrRec      *file_mgr_rec;
4437    Arg             args[2];
4438    FileViewData    *fileViewData = NULL;
4439    int             i, num_of_children, obj_btns;
4440    XmManagerWidget action_pane;
4441    XmString        label_string;
4442
4443
4444    /* set number of popup children based on annotation */
4445    num_of_children = FM_POPUP_CHILDREN_NA;
4446    obj_btns = OBJ_BTNS_NA;
4447
4448    /* attach the popup widget info to the menu */
4449    file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
4450    XtSetArg(args[0], XmNuserData, file_mgr_rec);
4451    XtSetValues(fileMgrPopup.menu, args, 1);
4452
4453    if(file_mgr_data)
4454      file_mgr_data->popup_menu_icon = NULL;
4455
4456    /* we are dealing with a white space popup */
4457    if((w == NULL)
4458       && (client_data == NULL)
4459 /*
4460       && (file_mgr_data->selected_file_count == 0)
4461 */
4462       )
4463    {
4464       DirectorySet *directory_set;
4465
4466       /* retrieve the fileViewData for the current directory */
4467       directory_set = file_mgr_data->directory_set[0];
4468       for (i = 0; i < directory_set->file_count; i++)
4469       {
4470          if(strcmp(directory_set->order_list[i]->file_data->file_name, ".")
4471             == 0)
4472          {
4473             fileViewData = directory_set->order_list[i];
4474             break;
4475          }
4476       }
4477
4478       /* manage the white space buttons and unmanage the object buttons */
4479       XtManageChildren(fileMgrPopup.wsPopup, WS_BTNS);
4480       XtUnmanageChildren(fileMgrPopup.objPopup, obj_btns);
4481       XtUnmanageChildren(fileMgrPopup.trash_objPopup, TRASH_OBJ_BTNS);
4482
4483       XtUnmanageChild(fileMgrPopup.wsPopup[BTN_UNSELECTALL]);
4484
4485       if(file_mgr_data == trashFileMgrData)
4486       {
4487          /* Set popup menu label */
4488          label_string = XmStringCreateLocalized ((GETMESSAGE(33, 2, "Current Folder")));
4489          XtSetArg (args[0], XmNlabelString, label_string);
4490          XtSetValues (fileMgrPopup.title, args, 1);
4491          XtManageChild(fileMgrPopup.title);
4492          XmStringFree (label_string);
4493
4494          /* trash white space popup -- unmanage the properties and show */
4495          /* hidden files buttons */
4496          XtUnmanageChild(fileMgrPopup.wsPopup[BTN_PROPERTIES]);
4497          XtUnmanageChild(fileMgrPopup.wsPopup[BTN_FIND]);
4498          XtUnmanageChild(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN]);
4499
4500          /* align the remaining buttons */
4501          XtSetArg(args[0], XmNmarginLeft, 0);
4502          if( PositioningEnabledInView( file_mgr_data ) )
4503          {
4504            file_mgr_rec->menuStates |= CLEAN_UP;
4505            XtSetValues(fileMgrPopup.wsPopup[BTN_CLEANUP], args, 1);
4506          }
4507          else
4508          {
4509            file_mgr_rec->menuStates &= ~(CLEAN_UP);
4510            XtUnmanageChild( fileMgrPopup.wsPopup[BTN_CLEANUP] );
4511          }
4512          XtSetValues(fileMgrPopup.wsPopup[BTN_SELECTALL], args, 1);
4513
4514          /* unmanage the action portion of the popup menu */
4515          XtUnmanageChild(fileMgrPopup.action_separator);
4516
4517          action_pane = (XmManagerWidget) fileMgrPopup.menu;
4518          for(i=num_of_children; i<action_pane->composite.num_children; i++)
4519             XtUnmanageChild(action_pane->composite.children[i]);
4520       }
4521       else
4522       {
4523          Dimension margin;
4524
4525          /* manage the properties and show hidden files buttons */
4526          if( file_mgr_data->toolbox )
4527            XtUnmanageChild(fileMgrPopup.wsPopup[BTN_PROPERTIES]);
4528          else
4529            XtManageChild(fileMgrPopup.wsPopup[BTN_PROPERTIES]);
4530          XtManageChild(fileMgrPopup.wsPopup[BTN_FIND]);
4531          XtManageChild(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN]);
4532
4533          /* Set popup menu label */
4534          label_string = XmStringCreateLocalized ((GETMESSAGE(33, 2, "Current Folder")));
4535          XtSetArg (args[0], XmNlabelString, label_string);
4536          XtSetValues (fileMgrPopup.title, args, 1);
4537          XtManageChild(fileMgrPopup.title);
4538          XmStringFree (label_string);
4539
4540          /* align the menu buttons */
4541          action_pane = (XmManagerWidget) fileMgrPopup.menu;
4542          XtSetArg(args[0], XmNmarginLeft, &margin);
4543          XtGetValues(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN], args, 1);
4544          XtSetArg(args[0], XmNmarginLeft, margin);
4545
4546          if( PositioningEnabledInView( file_mgr_data ) )
4547          {
4548            file_mgr_rec->menuStates |= CLEAN_UP;
4549            XtSetValues(fileMgrPopup.wsPopup[BTN_CLEANUP], args, 1);
4550          }
4551          else
4552          {
4553            file_mgr_rec->menuStates &= ~(CLEAN_UP);
4554            XtUnmanageChild( fileMgrPopup.wsPopup[BTN_CLEANUP] );
4555          }
4556
4557          XtSetValues(fileMgrPopup.wsPopup[BTN_SELECTALL], args, 1);
4558
4559          if(showFilesystem )
4560          {
4561            if (file_mgr_data->show_hid_enabled)
4562              XmToggleButtonGadgetSetState(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN], True, False);
4563            else
4564              XmToggleButtonGadgetSetState(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN], False, False);
4565          }
4566
4567          /* ensure that there was fileViewData for the current directory */
4568          if(fileViewData != NULL)
4569          {
4570             /* attach the current fileViewData to the 'Properties' button */
4571            if( ! file_mgr_data->toolbox )
4572            {
4573              XtRemoveAllCallbacks(fileMgrPopup.wsPopup[BTN_PROPERTIES],
4574                                   XmNactivateCallback);
4575              XtAddCallback (fileMgrPopup.wsPopup[BTN_PROPERTIES],
4576                             XmNactivateCallback,
4577                             ShowModAttrDialog, (XtPointer) fileViewData);
4578
4579              /* sensitize the 'Properties' option */
4580              XtSetSensitive(fileMgrPopup.wsPopup[BTN_PROPERTIES], True);
4581            }
4582             /* update the actions portion of the popup menu */
4583             XtManageChild(fileMgrPopup.action_separator);
4584
4585             XtFree(fileMgrPopup.action_pane_file_type);
4586             fileMgrPopup.action_pane_file_type =
4587                 XtNewString(fileViewData->file_data->logical_type);
4588
4589             UpdateActionMenuPane ((XtPointer)fileViewData, file_mgr_rec,
4590                                   fileViewData->file_data->logical_type,
4591                                   FM_POPUP, num_of_children,
4592                                   fileMgrPopup.menu,
4593                                   fileViewData->file_data->physical_type);
4594
4595             /* align actions portion of the popup menu */
4596             for(i=num_of_children; i<action_pane->composite.num_children; i++)
4597               XtSetValues(action_pane->composite.children[i], args, 1);
4598          }
4599          else
4600          {
4601            if( ! file_mgr_data->toolbox )
4602            {
4603              /* remove callback from 'Properties' button */
4604              XtRemoveAllCallbacks(fileMgrPopup.wsPopup[BTN_PROPERTIES],
4605                                   XmNactivateCallback);
4606
4607              /* desensitize the 'Properties' button */
4608              XtSetSensitive(fileMgrPopup.wsPopup[BTN_PROPERTIES], False);
4609            }
4610
4611             /* unmanage the action portion of the popup menu */
4612             XtUnmanageChild(fileMgrPopup.action_separator);
4613
4614             for(i=num_of_children; i<action_pane->composite.num_children; i++)
4615                XtUnmanageChild(action_pane->composite.children[i]);
4616          }
4617       }
4618    }
4619
4620    /* we are dealing with an object popup */
4621    else
4622    {
4623       char label[MAX_PATH];
4624
4625       /* retrieve the fileViewData for the selected icon */
4626       if (client_data)
4627          fileViewData = (FileViewData *) client_data;
4628       else if (file_mgr_data->selected_file_count != 0)
4629          fileViewData = file_mgr_data->selection_list[0];
4630
4631
4632       /* unmanage the white space buttons */
4633       XtUnmanageChildren(fileMgrPopup.wsPopup, WS_BTNS);
4634
4635       if(file_mgr_data == trashFileMgrData)
4636       {
4637           file_mgr_data->popup_menu_icon = fileViewData;
4638
4639          /* Set popup menu label */
4640          if( file_mgr_data->selected_file_count > 1
4641              && InMultipleObjectRegion(file_mgr_data, fileViewData))
4642          {
4643
4644            label_string = XmStringCreateLocalized ((GETMESSAGE(33,1, "Multiple Objects")));
4645          }
4646          else
4647          {
4648            char *tmp_label;
4649
4650            if (fileViewData->file_data->action_name)
4651               tmp_label = fileViewData->file_data->action_name;
4652            else
4653               tmp_label = fileViewData->file_data->file_name;
4654
4655            if( strlen( tmp_label ) > 20 )
4656              sprintf( label, "%-20.20s...", tmp_label );
4657            else
4658              sprintf( label, "%s", tmp_label );
4659
4660            label_string = XmStringCreateLocalized (label);
4661          }
4662          XtSetArg (args[0], XmNlabelString, label_string);
4663          XtSetValues (fileMgrPopup.title, args, 1);
4664          XtManageChild(fileMgrPopup.title);
4665          XmStringFree (label_string);
4666
4667          /* trash popup--unmanage the non-trash buttons, manage the trash */
4668          XtUnmanageChildren(fileMgrPopup.objPopup, obj_btns);
4669          XtManageChildren(fileMgrPopup.trash_objPopup, TRASH_OBJ_BTNS);
4670
4671          /* adjust callbacks */
4672          XtRemoveAllCallbacks(fileMgrPopup.trash_objPopup[BTN_RESTORE],
4673                               XmNactivateCallback);
4674          XtAddCallback(fileMgrPopup.trash_objPopup[BTN_RESTORE],
4675                        XmNactivateCallback, Restore, (XtPointer) fileViewData);
4676
4677          XtRemoveAllCallbacks(fileMgrPopup.trash_objPopup[BTN_REMOVE],
4678                               XmNactivateCallback);
4679          XtAddCallback(fileMgrPopup.trash_objPopup[BTN_REMOVE],
4680                        XmNactivateCallback, ConfirmRemove,
4681                        (XtPointer) fileViewData);
4682
4683          /* unmanage the action portion of the popup menu */
4684          XtUnmanageChild(fileMgrPopup.action_separator);
4685
4686          action_pane = (XmManagerWidget) fileMgrPopup.menu;
4687          for(i=num_of_children; i<action_pane->composite.num_children; i++)
4688             XtUnmanageChild(action_pane->composite.children[i]);
4689       }
4690       else
4691       {
4692          /* non-trash popup--manage the non-trash buttons, unmanage the trash */
4693          XtManageChildren(fileMgrPopup.objPopup, obj_btns);
4694          XtUnmanageChildren(fileMgrPopup.trash_objPopup, TRASH_OBJ_BTNS);
4695          if( file_mgr_data->toolbox )
4696            XtUnmanageChild(fileMgrPopup.objPopup[BTN_PROPERTIES]);
4697
4698          if(file_mgr_data->selected_file_count > 1
4699             && InMultipleObjectRegion(file_mgr_data, fileViewData))
4700          {
4701             /* we have many files selected; remove callbacks from the  */
4702             /* 'Properties', 'Put on Desktop', and 'Review' buttons    */
4703             /* and attach the selection list to the remaining buttons; */
4704             /* desensitize the 3 buttons listed above; unmanage the    */
4705             /* actions part of the popup menu                          */
4706
4707            /* adjust callbacks */
4708            if( ! file_mgr_data->toolbox )
4709              XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PROPERTIES],
4710                                   XmNactivateCallback);
4711
4712            XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PUTON],
4713                                 XmNactivateCallback);
4714            XtAddCallback(fileMgrPopup.objPopup[BTN_PUTON], XmNactivateCallback,
4715                          PutOnDTCB, (XtPointer) fileViewData);
4716
4717            XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_TRASH],
4718                                 XmNactivateCallback);
4719            XtAddCallback(fileMgrPopup.objPopup[BTN_TRASH], XmNactivateCallback,
4720                          TrashFiles, (XtPointer) fileViewData);
4721
4722            if( file_mgr_data->toolbox && geteuid() != root_user &&
4723                    access(file_mgr_data->current_directory,W_OK|X_OK) != 0)
4724              XtSetSensitive(fileMgrPopup.objPopup[BTN_TRASH], False);
4725
4726
4727            /* sensitize buttons */
4728            if( !file_mgr_data->toolbox )
4729              XtSetSensitive(fileMgrPopup.objPopup[BTN_PROPERTIES], False);
4730
4731            XtSetSensitive(fileMgrPopup.objPopup[BTN_HELP], False);
4732
4733            /* Set popup menu label */
4734            label_string = XmStringCreateLocalized ((GETMESSAGE(33, 1, "Multiple Objects")));
4735            XtSetArg (args[0], XmNlabelString, label_string);
4736            XtSetValues (fileMgrPopup.title, args, 1);
4737            XtManageChild(fileMgrPopup.title);
4738            XmStringFree (label_string);
4739
4740
4741            /* unmanage actions */
4742            XtUnmanageChild(fileMgrPopup.action_separator);
4743            action_pane = (XmManagerWidget) fileMgrPopup.menu;
4744            for(i = num_of_children;
4745                i < action_pane->composite.num_children;
4746                i++)
4747              XtUnmanageChild(action_pane->composite.children[i]);
4748          }
4749          else
4750          {
4751            char *tmp_label;
4752
4753            /* we have one file selected; attach fileViewData to buttons; */
4754            /* sensitize any desensitized buttons; update the actions     */
4755            /* part of the popup menu                                     */
4756
4757            /* adjust callbacks */
4758            if( ! file_mgr_data->toolbox )
4759            {
4760              XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PROPERTIES],
4761                                   XmNactivateCallback);
4762              XtAddCallback(fileMgrPopup.objPopup[BTN_PROPERTIES],
4763                            XmNactivateCallback, ShowModAttrDialog, (XtPointer) fileViewData);
4764            }
4765
4766             XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PUTON],
4767                                  XmNactivateCallback);
4768             XtAddCallback(fileMgrPopup.objPopup[BTN_PUTON],
4769                  XmNactivateCallback, PutOnDTCB, (XtPointer) fileViewData);
4770
4771             XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_TRASH],
4772                                  XmNactivateCallback);
4773             XtAddCallback(fileMgrPopup.objPopup[BTN_TRASH],
4774                  XmNactivateCallback, TrashFiles, (XtPointer) fileViewData);
4775
4776            if ( file_mgr_data->toolbox && geteuid() != root_user &&
4777                    access(file_mgr_data->current_directory,W_OK|X_OK) != 0 )
4778              XtSetSensitive(fileMgrPopup.objPopup[BTN_TRASH], False);
4779            else
4780              XtSetSensitive(fileMgrPopup.objPopup[BTN_TRASH], True);
4781
4782
4783             XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_HELP],
4784                                  XmNactivateCallback);
4785             XtAddCallback(fileMgrPopup.objPopup[BTN_HELP],
4786                  XmNactivateCallback, ObjectHelp, (XtPointer) fileViewData->widget);
4787
4788             /* sensitize buttons */
4789             if( ! file_mgr_data->toolbox )
4790               XtSetSensitive(fileMgrPopup.objPopup[BTN_PROPERTIES], True);
4791
4792             XtSetSensitive(fileMgrPopup.objPopup[BTN_PUTON], True);
4793             XtSetSensitive(fileMgrPopup.objPopup[BTN_HELP], True);
4794
4795             if (fileViewData->file_data->action_name)
4796                tmp_label = fileViewData->file_data->action_name;
4797             else
4798                tmp_label = fileViewData->file_data->file_name;
4799
4800             if( strlen( tmp_label ) > 20 )
4801               sprintf( label, "%-20.20s...", tmp_label );
4802             else
4803               sprintf( label, "%s", tmp_label );
4804
4805             /* Set popup menu label */
4806             label_string = XmStringCreateLocalized (label);
4807             XtSetArg (args[0], XmNlabelString, label_string);
4808             XtSetValues (fileMgrPopup.title, args, 1);
4809             XtManageChild(fileMgrPopup.title);
4810             XmStringFree (label_string);
4811
4812
4813             /* update actions */
4814             XtManageChild(fileMgrPopup.action_separator);
4815
4816             XtFree(fileMgrPopup.action_pane_file_type);
4817             fileMgrPopup.action_pane_file_type =
4818                 XtNewString(fileViewData->file_data->logical_type);
4819
4820             UpdateActionMenuPane ((XtPointer)fileViewData, file_mgr_rec,
4821                                   fileViewData->file_data->logical_type,
4822                                   FM_POPUP, num_of_children,
4823                                   fileMgrPopup.menu,
4824                                   fileViewData->file_data->physical_type);
4825
4826             /* align actions */
4827             action_pane = (XmManagerWidget) fileMgrPopup.menu;
4828             XtSetArg(args[0], XmNmarginLeft, 0);
4829             for(i = num_of_children; i < action_pane->composite.num_children; i++)
4830               XtSetValues(action_pane->composite.children[i], args, 1);
4831          }
4832       }
4833    }
4834
4835
4836    /* position and manage popup menu */
4837    if(event == NULL)
4838    {
4839       Position x, y;
4840       Dimension width, height;
4841       Dimension gWidth, gHeight;
4842       int displayWidth, displayHeight;
4843       DtIconGadget  g = (DtIconGadget)w;
4844
4845       XtSetArg (args[0], XmNwidth, &width);
4846       XtSetArg (args[1], XmNheight, &height);
4847       XtGetValues(XtParent(fileMgrPopup.menu), args, 2);
4848
4849       gWidth = g->icon.pixmap_width;
4850       gHeight = g->icon.pixmap_height;
4851
4852       displayWidth = DisplayWidth(XtDisplay(w), DefaultScreen(XtDisplay(w)));
4853       displayHeight =DisplayHeight(XtDisplay(w), DefaultScreen(XtDisplay(w)));
4854
4855       x = file_mgr_rec->shell->core.x +
4856           file_mgr_rec->scroll_window->core.x +
4857           w->core.x + gWidth/2;;
4858
4859       y = file_mgr_rec->shell->core.y +
4860           file_mgr_rec->header_frame->core.y +
4861           file_mgr_rec->header_frame->core.height +
4862           file_mgr_rec->scroll_window->core.y +
4863           w->core.y + gHeight/2;;
4864
4865       if((Dimension)(x + width) > (Dimension)displayWidth)
4866          x = displayWidth - width - 4;
4867       if((Dimension)(y + height) > (Dimension)displayHeight)
4868          y = displayHeight - height - 4;
4869
4870       XtSetArg (args[0], XmNx, x);
4871       XtSetArg (args[1], XmNy, y);
4872       XtSetValues(XtParent(fileMgrPopup.menu), args, 2);
4873    }
4874    else
4875    {
4876      if(( event->type == ButtonPress || event->type == ButtonRelease) ||
4877         ( ( event->type == KeyPress || event->type == KeyRelease) &&
4878           _XmIsEventUnique(event) ) )
4879      {
4880        XmMenuPosition(fileMgrPopup.menu, (XButtonPressedEvent *)event);
4881      }
4882    }
4883
4884    XtManageChild(fileMgrPopup.menu);
4885
4886    if( event->type == KeyPress || event->type == KeyRelease )
4887    {
4888      /* Specify that the focus is being moved by key, NOT mouse
4889      */
4890      _XmSetInDragMode(fileMgrPopup.menu,False);
4891
4892      XmProcessTraversal(fileMgrPopup.menu,XmTRAVERSE_CURRENT);
4893
4894      /* This function is being called twice.
4895         Record this event so the above check _XmIsEventUnique will work
4896      */
4897      _XmRecordEvent(event);
4898    }
4899 }
4900
4901
4902 static void
4903 DropOnRootCB (
4904      Widget w,
4905      XtPointer client_data,
4906      XtPointer call_data)
4907 {
4908    DtDndDropCallbackStruct *fileList = (DtDndDropCallbackStruct *)call_data;
4909    char * ptr;
4910    char ** file_set = NULL;
4911    char ** host_set = NULL;
4912    FileMgrRec * file_mgr_rec;
4913    FileMgrData * file_mgr_data;
4914    char   *next;
4915    int i, j;
4916    int wsNum;
4917    String end;
4918    String tmpStr;
4919    int numFiles;
4920    int effScreenWidth;
4921    int effScreenHeight;
4922    int start_x, start_y;
4923    int root_x, root_y;
4924    int step, dstep;
4925
4926    /* Check the protocol, set to failure if not the */
4927    /* File Transfer protocol                        */
4928    if (fileList->dropData->protocol != DtDND_FILENAME_TRANSFER)
4929      {
4930        fileList->status = DtDND_FAILURE;
4931        return;
4932      }
4933
4934
4935    numFiles = fileList->dropData->numItems;
4936
4937    DPRINTF (("DropOnRoot: Number of files dropped are %d\n", numFiles));
4938
4939    if(fileList->reason != DtCR_DND_DROP_ANIMATE)
4940    {
4941       /* set the complete move flag to False since it is not required to be called */
4942       /* In case when the drag is from non File manager client */
4943       if(!dragActive)
4944         initiating_view = NULL;
4945
4946       fileList->completeMove = False;
4947
4948       _DtSetDroppedFileInfo(fileList, &file_set, &host_set);
4949
4950       if(initiating_view != NULL)
4951       {
4952          file_mgr_rec = (FileMgrRec *)
4953                      (((FileMgrData *) initiating_view)->file_mgr_rec);
4954          file_mgr_data = (FileMgrData *) initiating_view;
4955       }
4956       else
4957          file_mgr_data = NULL;
4958
4959       /* get the correct position for the desktop icon shell */
4960       PositionDesktopIcon(fileList->x, fileList->y, &root_x, &root_y);
4961
4962       if (numFiles > 1)
4963       {
4964          /*
4965           * We will place the icons by marching down a diagonal starting
4966           * at the drop point.  But we don't want to march off-screen
4967           * if there are too many icons.  So ...
4968           *  - We choose a step width of 20, 10, 5, or 2 depending
4969           *    on the number of icons dropped.
4970           *  - When we run into the edge of the screen, we start a new
4971           *    diagonal shifted one step to the right.
4972           *  - If all icons still won't fit, we move the starting point
4973           *    closer to the top left corner of the screen.
4974           */
4975
4976          /* compute effective screen size (largest x,y where an icon
4977           * can be placed without going off-screen) */
4978          effScreenWidth = WidthOfScreen(XtScreen(w)) - (4 + 4+48+4 + 5);
4979          effScreenHeight = HeightOfScreen(XtScreen(w)) - (4 + 4+48+3+15+4 + 5);
4980
4981          /* chosee step depending on number of icons */
4982          if (numFiles <= 200)
4983            step = 20;
4984          else if (numFiles <= 400)
4985            step = 10;
4986          else  if (numFiles <= 1000)
4987            step = 5;
4988          else
4989            step = 2;
4990          dstep = 40 + 4+48+4 + 5;
4991
4992          /* choose starting point so at least two icons will fit */
4993          if (root_x <= effScreenWidth - step)
4994            start_x = root_x;
4995          else
4996            start_x = effScreenWidth - step;
4997
4998          if (root_y <= effScreenWidth - step)
4999            start_y = root_y;
5000          else
5001            start_y = effScreenWidth - step;
5002
5003          DPRINTF(("DropOnRootCB: numFiles %d, root_x %d, root_y %d, step %d\n",
5004                   numFiles, root_x, root_y, step));
5005
5006          /* check if all icons will fit */
5007          for (;;)
5008          {
5009            /* cacluclate how many will fit (add up icons on all diagonals) */
5010            int n = 0, nd = 0;
5011            for (root_x = start_x; root_x <= effScreenWidth; root_x += dstep)
5012            {
5013              int nx = (effScreenWidth - root_x)/step + 1;
5014              int ny = (effScreenHeight - start_y)/step + 1;
5015              n += (nx <= ny)? nx: ny;
5016              nd++;
5017            }
5018
5019            DPRINTF(("start_x %d, start_y %d, nd %d, n %d\n",
5020                     start_x, start_y, nd, n));
5021
5022            /* if everything fits - great! */
5023            if (n >= numFiles)
5024              break;
5025
5026            /* move the start point closer to the top left corner */
5027            if (effScreenWidth - start_x < effScreenHeight - start_y &&
5028                start_x >= step)
5029            {
5030              /* move left so more icons will fit */
5031              start_x -= step;
5032            }
5033            else if (effScreenWidth - start_x > effScreenHeight - start_y &&
5034                     start_y >= step)
5035            {
5036              /* move up so one more icon will fit in each diagonal */
5037              start_y -= step;
5038            }
5039            else if (start_x > 0 || start_y > 0)
5040            {
5041              /* move left and up */
5042              if (start_x >= step)
5043                start_x -= step;
5044              else
5045                start_x = 0;
5046              if (start_y >= step)
5047                start_y -= step;
5048              else
5049                start_y = 0;
5050            }
5051            else
5052              /* ran out of space - too bad! */
5053              break;
5054          }
5055          root_x = start_x;
5056          root_y = start_y;
5057       }
5058
5059       /* the icon that was dropped on the root window was an
5060          icon that was already on the root window */
5061       if (file_mgr_data == NULL)
5062       {
5063          DPRINTF(("DropOnRoot: Object already on Desktop\n"));
5064
5065          /* loop through the existing desktop icons to determine which
5066             ones are being dragged, then change their location */
5067          for(i=0; i < desktop_data->numIconsUsed; i++)
5068          {
5069             if((Widget)desktop_data->desktopWindows[i]->iconGadget ==
5070                                                    (Widget)widget_dragged)
5071             {
5072                if (DTFileIsSelected(desktop_data->desktopWindows[i],
5073                       desktop_data->desktopWindows[i]->file_view_data))
5074                {
5075                  for(j=0;j< desktop_data->numWorkspaces;j++)
5076                    if(desktop_data->workspaceData[j]->number ==
5077                       desktop_data->desktopWindows[i]->workspace_num)
5078                      break;
5079                  wsNum = j;
5080                  for (j = 0;
5081                       j < desktop_data->workspaceData[wsNum]->files_selected;
5082                       j++)
5083                  {
5084                    RelocateDesktopIcon(desktop_data->workspaceData[wsNum]->
5085                                        selectedDTWindows[j],
5086                                        root_x, root_y);
5087                    root_x += step;
5088                    root_y += step;
5089                    if (root_x > effScreenWidth || root_y > effScreenHeight)
5090                    {
5091                      start_x += dstep;
5092                      if (start_x > effScreenWidth)
5093                        start_x = 0;
5094                      root_x = start_x;
5095                      root_y = start_y;
5096                    }
5097                  }
5098                }
5099                else
5100                {
5101                   RelocateDesktopIcon(desktop_data->desktopWindows[i],
5102                                       root_x, root_y);
5103                   break;
5104                }
5105             }
5106          }
5107       }
5108       else if( file_mgr_data == trashFileMgrData )
5109       {
5110          /* if the file manager data is the trash, we want to tell the
5111             user that they can't drop trash on the desktop
5112          */
5113          char * msg;
5114          char * tmpStr;
5115
5116          DPRINTF(("DropOnRoot: Attempting to Drag Trash Object to Desktop\n"));
5117          file_mgr_rec = (FileMgrRec *)trashFileMgrData->file_mgr_rec;
5118          tmpStr = (GETMESSAGE(11,37, "You can't drop files from\nthe Trash Can on to the Workspace.\nTo remove an object from Trash,\n   -Select the object, and\n   -Choose 'Put Back'\nfrom the File menu or the object's popup menu.\nYou can then drag the object out of File Manager and drop it on\nthe Workspace backdrop."));
5119          msg = XtNewString(tmpStr);
5120          FileOperationError (file_mgr_rec->main, msg, NULL);
5121          XtFree(msg);
5122          return;
5123       }
5124       else /* it was dropped on the root window so lets process it */
5125       {
5126         int EndIndex = desktop_data->numIconsUsed;
5127
5128         for(i = 0; i < numFiles; i++)
5129         {
5130           ptr = strrchr(file_set[i], '/');
5131           if( strcmp(file_mgr_data->current_directory, file_set[i]) == 0)
5132           {
5133             SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
5134                                file_mgr_data, file_mgr_rec,
5135                                ".", host_set[i], file_set[i],
5136                                root_x, root_y,
5137                                NULL,EndIndex);
5138           }
5139           else if(strncmp(file_mgr_data->current_directory, file_set[i], strlen(file_set[i]) ) == 0 )
5140           {
5141             SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
5142                                file_mgr_data, file_mgr_rec,
5143                                "..", host_set[i],file_mgr_data->current_directory,
5144                                root_x, root_y,
5145                                NULL,EndIndex);
5146           }
5147           else
5148           {
5149             *ptr = '\0';
5150             if(*(file_set[i]) == 0)
5151             {
5152               SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
5153                                  file_mgr_data, file_mgr_rec,
5154                                  ptr + 1, host_set[i], "/",
5155                                  root_x, root_y,
5156                                  NULL,EndIndex);
5157             }
5158             else
5159             {
5160               SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
5161                                  file_mgr_data, file_mgr_rec,
5162                                  ptr + 1, host_set[i], file_set[i],
5163                                  root_x, root_y,
5164                                  NULL,EndIndex);
5165             }
5166           }
5167           root_x += step;
5168           root_y += step;
5169           if (root_x > effScreenWidth || root_y > effScreenHeight)
5170           {
5171             start_x += dstep;
5172             if (start_x > effScreenWidth)
5173               start_x = 0;
5174             root_x = start_x;
5175             root_y = start_y;
5176           }
5177         }
5178         initiating_view = (XtPointer)NULL;
5179       }
5180
5181       _DtFreeDroppedFileInfo(numFiles, file_set, host_set);
5182
5183       return;
5184    }
5185 }
5186
5187 /************************************************************************
5188  *
5189  *  FreeLayoutData
5190  *
5191  ************************************************************************/
5192
5193 void
5194 FreeLayoutData(XtPointer p)
5195 {
5196    IconLayoutData *layout_data;
5197
5198    if (p == NULL)
5199       return;
5200
5201    layout_data = (IconLayoutData *)p;
5202
5203    if (layout_data->work_id != NULL)
5204    {
5205       DPRINTF(("FreeLayoutData: removing workproc\n"));
5206       XtRemoveWorkProc(layout_data->work_id);
5207       XmDropSiteEndUpdate(layout_data->drop_site_w);
5208    }
5209
5210    XtFree((char *)layout_data->order_list);
5211    layout_data->order_list = NULL;
5212    XtFree((char *)layout_data->reuse_icons);
5213    layout_data->reuse_icons = NULL;
5214    XtFree((char *)layout_data->reuse_btns);
5215    layout_data->reuse_btns = NULL;
5216    XtFree((char *)layout_data->manage);
5217    layout_data->manage = NULL;
5218
5219    XtFree((char *)layout_data);
5220    layout_data = NULL;
5221 }
5222
5223 /************************************************************************
5224  *
5225  *  UnmanageFileIcons
5226  *      Unmanage a subset of the file icons.
5227  *
5228  ************************************************************************/
5229
5230 void UnmanageFileIcons(
5231         FileMgrRec *file_mgr_rec,
5232         FileMgrData *file_mgr_data,
5233         FileViewData *file_view_data)
5234 {
5235    XmManagerWidget file_window;
5236    FileViewData **order_list;
5237    int order_count;
5238    int i, n;
5239    Widget *unmanage;
5240    Widget child;
5241    Arg args[20];
5242
5243
5244    /*  Set the size of the file window BIG so that it does not  */
5245    /*  try to force positioning on its children.                */
5246
5247    file_window = (XmManagerWidget) file_mgr_rec->file_window;
5248    XtResizeWidget ((Widget)file_window, 32767, 32767, 0);
5249
5250
5251    /*  Set the scrolled window and file window appropriately  */
5252    /*  to prevent a lot of gyrations.                         */
5253
5254    XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmSTATIC);
5255    XtSetValues (file_mgr_rec->scroll_window, args, 1);
5256
5257    order_list = ((IconLayoutData *)file_mgr_data->layout_data)->order_list;
5258    order_count = ((IconLayoutData *)file_mgr_data->layout_data)->order_count;
5259
5260    unmanage = (Widget *)XtMalloc(2*order_count*sizeof(Widget));
5261    n = 0;
5262    for (i = 0; i < order_count; i++)
5263    {
5264      if (order_list[i]->filtered)
5265        continue;
5266
5267      if ((n > 0 || order_list[i] == file_view_data) &&
5268          !order_list[i]->need_update)
5269      {
5270        unmanage[n++] = order_list[i]->widget;
5271        if (order_list[i]->treebtn)
5272          unmanage[n++] = order_list[i]->treebtn;
5273      }
5274    }
5275
5276    /* remember which icon currently has the focus */
5277    if (XtIsManaged(file_mgr_rec->file_window))
5278    {
5279       /* see if the focus is inside the file window */
5280       child = XmGetFocusWidget(file_mgr_rec->file_window);
5281       if (child != NULL && XtParent(child) == file_mgr_rec->file_window)
5282          file_mgr_rec->focus_widget = child;
5283    }
5284
5285    /* unmanage the selected children */
5286    if (n > 0)
5287       XtUnmanageChildren(unmanage, n);
5288
5289    XtFree((char *)unmanage);
5290 }
5291
5292
5293 /************************************************************************
5294  *
5295  *  UpdateFileIcons
5296  *      Create or reuse a set of file icons used to get the files
5297  *      displayed.  This is never called for the desktop.
5298  *
5299  ************************************************************************/
5300
5301 void
5302 UpdateFileIcons(
5303         FileMgrRec *file_mgr_rec,
5304         FileMgrData *file_mgr_data,
5305         Boolean new_directory)
5306 {
5307   _UpdateFileIcons(file_mgr_rec, file_mgr_data, new_directory, NULL);
5308 }
5309
5310 void
5311 AddFileIcons(
5312         FileMgrRec *file_mgr_rec,
5313         FileMgrData *file_mgr_data,
5314         DirectorySet * add_dir_set)
5315 {
5316   _UpdateFileIcons(file_mgr_rec, file_mgr_data, False, add_dir_set);
5317 }
5318
5319
5320 /*--------------------------------------------------------------------
5321  * MakeReuseList
5322  *
5323  *   Background information:
5324  *     After a refresh on a directory we want to reuse old icon and tree
5325  *   button widgets instead of destroying the old widgets and creating
5326  *   new ones.  Fourthermore, we want to reuse the same widgets for the
5327  *   same files, so that if the icon and/or label didn't change, less
5328  *   work needs to be done in _UpdateFileIcons().
5329  *     For this reason, after a refresh the GetFileData() routine copies
5330  *   Widgets from the old FileViewData list to the new FileViewData list
5331  *   for files that are both on the old and new list (i.e., files that
5332  *   already existed before the refresh and are still there after the
5333  *   refresh).  This allows _UpdateFileIcons() to reuse the old
5334  *   widget.
5335  *
5336  *   The purpose of MakeReuseList() is to find widgets that are no
5337  *   longer found in the new FileViewData list.  These are widgets
5338  *   from files that disappeared after the refresh (either because the
5339  *   file was deleted or because file is now filtered out).  These
5340  *   widgets can then be reused by _UpdateFileIcons()for new files that
5341  *   just appeared after the refresh.
5342  *
5343  *------------------------------------------------------------------*/
5344
5345 /* compare function for qsort and bsearch */
5346 static int
5347 WidgetCmp(Widget *w1, Widget *w2)
5348 {
5349   return *w1 - *w2;
5350 }
5351
5352 static void
5353 MakeReuseList(
5354         Widget *children,
5355         int num_children,
5356         FileViewData **order_list,
5357         int order_count,
5358         Widget **reuse_icons,
5359         Widget **reuse_btns)
5360 {
5361 #ifdef DEBUG
5362    int n_old, n_filtered, del_icon, del_btn;
5363 #endif
5364    Widget *sorted_chilren = NULL;
5365    Boolean *reuse = NULL;
5366    int icon_count;
5367    int btn_count;
5368    int i;
5369    Widget *p;
5370    Widget w;
5371
5372    /* allocate widget arrays */
5373    *reuse_icons = (Widget *)XtMalloc((num_children + 1)*sizeof(Widget));
5374    *reuse_btns = (Widget *)XtMalloc((num_children + 1)*sizeof(Widget));
5375    icon_count = btn_count = 0;
5376
5377    /* only figure things out if we already have children */
5378    if (num_children > 0) {
5379      /* create a sorted list of children */
5380      sorted_chilren = (Widget *)XtMalloc(num_children * sizeof(Widget));
5381      memcpy(sorted_chilren, children, num_children * sizeof(Widget));
5382      qsort(sorted_chilren, num_children, sizeof(Widget), (int (*)())WidgetCmp);
5383
5384      /* create reuse flags; initially assume all children can be reused */
5385      reuse = (Boolean *)XtMalloc(num_children * sizeof(Boolean));
5386      for (i = 0; i < num_children; i++)
5387        reuse[i] = True;
5388
5389    /* reset reuse flag for all widgets found in order_list */
5390 #ifdef DEBUG
5391      n_old = n_filtered = del_icon = del_btn = 0;
5392 #endif
5393      for (i = 0; i < order_count; i++)
5394        {
5395          if (order_list[i]->filtered &&
5396              strcmp(order_list[i]->file_data->file_name, ".") != 0)
5397            {
5398              /* don't reuse this widget later */
5399 #ifdef DEBUG
5400              n_filtered++;
5401              if (order_list[i]->widget)
5402                del_icon++;
5403              if (order_list[i]->treebtn)
5404                del_btn++;
5405 #endif
5406              order_list[i]->widget =
5407                order_list[i]->treebtn = NULL;
5408            }
5409          else
5410            {
5411              if (order_list[i]->widget)
5412                {
5413                  p = bsearch(&order_list[i]->widget,
5414                              sorted_chilren, num_children, sizeof(Widget),
5415                              (int (*)())WidgetCmp);
5416                  if (p)
5417                    {
5418                      /* don't reuse this widget for any other file */
5419                      reuse[p - sorted_chilren] = False;
5420 #ifdef DEBUG
5421                      n_old++;
5422 #endif
5423                    }
5424                  else
5425                    {
5426                      /* don't reuse this widget later */
5427                      order_list[i]->widget = NULL;
5428 #ifdef DEBUG
5429                      del_icon++;
5430 #endif
5431                    }
5432                }
5433
5434              if (order_list[i]->treebtn)
5435                {
5436                  p = bsearch(&order_list[i]->treebtn,
5437                              sorted_chilren, num_children, sizeof(Widget),
5438                              (int (*)())WidgetCmp);
5439                  if (p)
5440                    {
5441                      /* don't reuse this widget for any other file */
5442                      reuse[p - sorted_chilren] = False;
5443                    }
5444                  else
5445                    {
5446                      /* don't reuse this widget later */
5447                      order_list[i]->treebtn = NULL;
5448 #ifdef DEBUG
5449                      del_btn++;
5450 #endif
5451                    }
5452                }
5453            }
5454        }
5455
5456      /* copy reusable widgets into widget arrays */
5457      for (i = 0; i < num_children; i++)
5458        {
5459          if (reuse[i])
5460            {
5461              /* this widget can be reused for new files */
5462              w = sorted_chilren[i];
5463              if (XtClass(w) == dtIconGadgetClass)
5464                {
5465 #ifndef DELAYED_UNREGISTER
5466                  Arg args[1];
5467
5468                  XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
5469                  XtRemoveAllCallbacks(w, XmNdropCallback);
5470                  XtSetValues (w, args, 1);
5471 #endif
5472                  (*reuse_icons)[icon_count++] = w;
5473                }
5474              else if (XtClass(w) == xmPushButtonGadgetClass)
5475                (*reuse_btns)[btn_count++] = w;
5476            }
5477        }
5478    }
5479
5480    /* null-terminate the arrays */
5481    (*reuse_icons)[icon_count] = NULL;
5482    (*reuse_btns)[btn_count] = NULL;
5483
5484    /* free storage */
5485    XtFree((char *)sorted_chilren);
5486    XtFree((char *)reuse);
5487
5488    DPRINTF(("MakeReuseList: count %d (%d new, %d old, %d filtered)\n",
5489             order_count, order_count - n_filtered - n_old, n_old, n_filtered));
5490    DPRINTF(("               reuse %d + %d, del %d + %d\n",
5491             icon_count, btn_count, del_icon, del_btn));
5492 }
5493
5494
5495 /*--------------------------------------------------------------------
5496  * UpdateOneIconLabel
5497  *------------------------------------------------------------------*/
5498
5499 static void
5500 UpdateOneIconLabel(
5501         FileMgrData *file_mgr_data,
5502         FileViewData *file_view_data)
5503 {
5504    char *label;
5505    char *s;
5506
5507    /*  Get the label and icon to be used for the widget  */
5508    if (file_mgr_data->view != BY_ATTRIBUTES)
5509    {
5510       if (strcmp(file_view_data->file_data->file_name, "..") == 0)
5511       {
5512          /* label = ".. (go up)" */
5513          s = GetSharedMessage(UP_ONE_LEVEL_LABEL);
5514          label = (char *)XtMalloc(2 + strlen(s) + 1);
5515          strcpy(label, "..");
5516          strcat(label, s);
5517       }
5518       else if (file_mgr_data->view == BY_NAME &&
5519                file_view_data->file_data->physical_type == DtDIRECTORY &&
5520                file_mgr_data->show_type != MULTIPLE_DIRECTORY)
5521       {
5522          /* label = "name/" */
5523          label = (char *)XtMalloc(
5524                              strlen(file_view_data->file_data->file_name) + 2);
5525          strcpy(label, file_view_data->file_data->file_name);
5526          strcat(label, "/");
5527       }
5528       else if (file_mgr_data->view == BY_NAME &&
5529                file_view_data->file_data->physical_type == DtEXECUTABLE)
5530       {
5531          /* label = "name*" */
5532          label = (char *)XtMalloc(
5533                              strlen(file_view_data->file_data->file_name) + 2);
5534          strcpy(label, file_view_data->file_data->file_name);
5535          strcat(label, "*");
5536       }
5537       else if(file_view_data->file_data->action_name != NULL)
5538          /* label = action name */
5539          label = XtNewString(file_view_data->file_data->action_name);
5540       else
5541          /* label = file name */
5542          label = XtNewString(file_view_data->file_data->file_name);
5543    }
5544    else /* file_mgr_data->view == BY_ATTRIBUTES */
5545    {
5546       /* label = file name + attributes */
5547       label = GetLongName(file_view_data->file_data);
5548       if (strcmp(file_view_data->file_data->file_name, "..") == 0)
5549       {
5550          s = GetSharedMessage(UP_ONE_LEVEL_LABEL);
5551          label = (char *)XtRealloc(label, strlen(label) + strlen(s) + 1);
5552          strcat(label, s);
5553       }
5554    }
5555
5556    /* store new label */
5557    XtFree(file_view_data->label);
5558    file_view_data->label = label;
5559 }
5560
5561
5562 /*--------------------------------------------------------------------
5563  * UpdateOneFileIcon
5564  *------------------------------------------------------------------*/
5565
5566 static void
5567 UpdateOneFileIcon(
5568         FileMgrRec *file_mgr_rec,
5569         FileMgrData *file_mgr_data,
5570         FileViewData *file_view_data)
5571 {
5572    XmString icon_label;
5573    char *logical_type;
5574    PixmapData *pixmapData;
5575    Widget icon_widget;
5576    Widget btn_widget;
5577    Boolean is_instance_icon;
5578    Boolean instance_icon_changed;
5579    Arg args[35];
5580    int n_color_args;
5581    int argi_imageName;
5582    int n;
5583
5584    XmManagerWidget file_window = (XmManagerWidget) file_mgr_rec->file_window;
5585    DirectorySet *directory_set = (DirectorySet *)file_view_data->directory_set;
5586    IconLayoutData *layout_data = (IconLayoutData *)file_mgr_data->layout_data;
5587
5588    /* Get the label and icon to be used for the widget */
5589    if (!file_view_data->label)
5590      UpdateOneIconLabel(file_mgr_data, file_view_data);
5591
5592    icon_label = XmStringCreateLocalized(file_view_data->label);
5593
5594    /*  Get the icon name based on the file type  */
5595
5596    logical_type = file_view_data->file_data->logical_type;
5597
5598    if (file_mgr_data->view == BY_NAME)
5599       pixmapData = NULL;
5600    else if (openDirType == NEW &&
5601                file_view_data->file_data->physical_type == DtDIRECTORY)
5602    {
5603       pixmapData = CheckForOpenDirectory(file_view_data,
5604                                          directory_set,
5605                                          file_mgr_data,
5606                                          logical_type);
5607    }
5608    else
5609    {
5610       if (file_mgr_data->view == BY_NAME_AND_ICON)
5611          pixmapData = _DtRetrievePixmapData(
5612                          logical_type,
5613                          file_view_data->file_data->file_name,
5614                          directory_set->name,
5615                          (Widget) file_window,
5616                          LARGE);
5617       else
5618          pixmapData = _DtRetrievePixmapData(
5619                          logical_type,
5620                          file_view_data->file_data->file_name,
5621                          directory_set->name,
5622                          (Widget) file_window,
5623                          SMALL);
5624    }
5625
5626    /* check if this is an instance icon */
5627    is_instance_icon = False;
5628    if (pixmapData != NULL)
5629    {
5630      char tmp[1024];
5631
5632      strcpy(tmp, directory_set->name);
5633      strcat(tmp, "/");
5634      strcat(tmp, file_view_data->file_data->file_name);
5635      if (strcmp(pixmapData->iconFileName, tmp) == 0)
5636         is_instance_icon = True;
5637    }
5638
5639    /* check if instance icon was modified */
5640    instance_icon_changed = False;
5641    if (is_instance_icon)
5642    {
5643      if (file_view_data->icon_mtime != file_view_data->file_data->stat.st_mtime)
5644      {
5645         if (file_view_data->icon_mtime != 0)
5646            instance_icon_changed = True;
5647         file_view_data->icon_mtime = file_view_data->file_data->stat.st_mtime;
5648      }
5649    }
5650    else
5651      file_view_data->icon_mtime = 0;
5652
5653    /* Build the arg list for color resources.  */
5654    n = 0;
5655    XtSetArg (args[n], XmNarmColor, white_pixel);                     n++;
5656
5657    if (layout_data->background == white_pixel)
5658    {
5659       if (file_view_data->selected)
5660       {
5661          XtSetArg (args[n], XmNbackground, black_pixel);             n++;
5662          XtSetArg (args[n], XmNforeground, white_pixel);             n++;
5663       }
5664       else
5665       {
5666          XtSetArg (args[n], XmNbackground, white_pixel);             n++;
5667          XtSetArg (args[n], XmNforeground, layout_data->foreground); n++;
5668       }
5669       XtSetArg (args[n], XmNpixmapBackground, white_pixel);          n++;
5670       XtSetArg (args[n], XmNpixmapForeground, black_pixel);          n++;
5671    }
5672    else if (layout_data->background == black_pixel)
5673    {
5674       if (file_view_data->selected)
5675       {
5676          XtSetArg (args[n], XmNbackground, white_pixel);             n++;
5677          XtSetArg (args[n], XmNforeground, black_pixel);             n++;
5678       }
5679       else
5680       {
5681          XtSetArg (args[n], XmNbackground, black_pixel);             n++;
5682          XtSetArg (args[n], XmNforeground, layout_data->foreground); n++;
5683       }
5684       XtSetArg (args[n], XmNpixmapBackground, white_pixel);          n++;
5685       XtSetArg (args[n], XmNpixmapForeground, black_pixel);          n++;
5686    }
5687    else
5688    {
5689       if (file_view_data->selected)
5690       {
5691          XtSetArg (args[n], XmNbackground, white_pixel);             n++;
5692          XtSetArg (args[n], XmNforeground, black_pixel);             n++;
5693          XtSetArg (args[n], XmNpixmapBackground, white_pixel);       n++;
5694          XtSetArg (args[n], XmNpixmapForeground, black_pixel);       n++;
5695       }
5696       else
5697       {
5698          XtSetArg (args[n], XmNbackground, layout_data->background); n++;
5699          XtSetArg (args[n], XmNforeground, layout_data->foreground); n++;
5700          XtSetArg (args[n], XmNpixmapBackground, layout_data->pixmap_back); n++;
5701          XtSetArg (args[n], XmNpixmapForeground, layout_data->pixmap_fore); n++;
5702       }
5703    }
5704
5705    n_color_args = n;
5706
5707    /* Build the rest of the arg list and either create or reuse the widget. */
5708
5709    XtSetArg (args[n], XmNstring, icon_label);                        n++;
5710    argi_imageName = n;
5711    if (pixmapData)
5712      XtSetArg (args[n], XmNimageName, pixmapData->iconFileName);
5713    else
5714      XtSetArg (args[n], XmNimageName, NULL);
5715    n++;
5716    XtSetArg (args[n], XmNmaxPixmapWidth, layout_data->pixmap_width);   n++;
5717    XtSetArg (args[n], XmNmaxPixmapHeight, layout_data->pixmap_height); n++;
5718    XtSetArg (args[n], XmNuserData, directory_set);                     n++;
5719    XtSetArg (args[n], XmNunderline, False);                            n++;
5720    XtSetArg (args[n], XmNfillMode, XmFILL_TRANSPARENT);                n++;
5721    if (file_mgr_data->view == BY_NAME_AND_ICON &&
5722        file_mgr_data->show_type != MULTIPLE_DIRECTORY)
5723       XtSetArg (args[n], XmNpixmapPosition, XmPIXMAP_TOP);
5724    else
5725       XtSetArg (args[n], XmNpixmapPosition, XmPIXMAP_LEFT);            n++;
5726
5727    /* See if we can re-use the same or some other icon gadget */
5728    if (file_view_data->widget)
5729       icon_widget = file_view_data->widget;
5730    else if (*layout_data->next_icon_to_use)
5731       icon_widget = *layout_data->next_icon_to_use++;
5732    else
5733       icon_widget = NULL;
5734
5735    /* See if we found an available icon gadget */
5736    if (icon_widget)
5737    {
5738       /* reuse the icon gadget */
5739       if (icon_widget != file_view_data->widget || file_mgr_data->newSize)
5740       {
5741          XtSetArg (args[n], XmNdropSiteOperations, XmDROP_NOOP);n++;
5742          XtRemoveAllCallbacks(icon_widget, XmNdropCallback);
5743          file_view_data->registered = False;
5744       }
5745       XtRemoveAllCallbacks (icon_widget, XmNcallback);
5746
5747       /* if instance_icon_changed, force destroy of old pixmap */
5748       if (instance_icon_changed)
5749          XtSetArg (args[argi_imageName], XmNimageName, NULL);
5750
5751       /*
5752        * Move the gadget off the visible area; this avoids unnecessary
5753        * redraw events at the old position when the gadget is moved to
5754        * the correct position once it is determined in LayoutFileIcons.
5755        */
5756       icon_widget->core.x = -999;
5757       icon_widget->core.y = -999;
5758       XtSetValues (icon_widget, args, n);
5759
5760       if (instance_icon_changed && pixmapData)
5761       {
5762          XtSetArg (args[0], XmNimageName, pixmapData->iconFileName);
5763          XtSetValues (icon_widget, args, 1);
5764       }
5765    }
5766    else
5767    {
5768       /* create a new or duplicate an existing widget */
5769       XtSetArg (args[n], XmNshadowThickness, 2);             n++;
5770       XtSetArg (args[n], XmNdropSiteOperations, XmDROP_NOOP);n++;
5771       XtSetArg (args[n], XmNfontList, user_font);            n++;
5772       if( keybdFocusPolicy == XmEXPLICIT)
5773       {
5774          XtSetArg (args[n], XmNtraversalOn, True);           n++;
5775       }
5776       else
5777       {
5778          XtSetArg (args[n], XmNtraversalOn, False);          n++;
5779          XtSetArg (args[n], XmNhighlightThickness, 0);       n++;
5780       }
5781       XtSetArg (args[n], XmNborderType, DtNON_RECTANGLE);   n++;
5782
5783       if (layout_data->dup_icon_widget == NULL)
5784       {
5785 #ifdef HARDCODED_ICON_MARGINS
5786          XtSetArg (args[n], XmNmarginWidth, 0);  n++;
5787          XtSetArg (args[n], XmNmarginHeight, 0); n++;
5788 #endif
5789          XtSetArg (args[n], XmNx, -999);  n++;
5790          XtSetArg (args[n], XmNy, -999);  n++;
5791          icon_widget = layout_data->dup_icon_widget =
5792                    _DtCreateIcon ((Widget)file_window, "icon", args, n);
5793       }
5794       else
5795       {
5796          DtIconGadget g;
5797          int i = n_color_args;
5798
5799          icon_widget = _DtDuplicateIcon ((Widget)file_window,
5800                        layout_data->dup_icon_widget,
5801                        icon_label,
5802                        (pixmapData? pixmapData->iconFileName: NULL),
5803                        (XtPointer)directory_set, /* userData */
5804                        False);                   /* underline */
5805          g = (DtIconGadget)icon_widget;
5806          g->gadget.highlighted = False;
5807          g->gadget.highlight_drawn = False;
5808
5809          /*
5810           * Move the gadget off the visible area; this avoids unnecessary
5811           * redraw events at the old position when the gadget is moved to
5812           * the correct position once it is determined in LayoutFileIcons.
5813           */
5814          icon_widget->core.x = -999;
5815          icon_widget->core.y = -999;
5816
5817          /* make sure colors, drop operations, and clipping are right */
5818          XtSetArg(args[i], XmNdropSiteOperations, XmDROP_NOOP);             i++;
5819          XtSetArg(args[i], XmNmaxPixmapWidth, layout_data->pixmap_width);   i++;
5820          XtSetArg(args[i], XmNmaxPixmapHeight, layout_data->pixmap_height); i++;
5821          XtSetValues (icon_widget, args, i);
5822       }
5823       XtAddCallback(icon_widget, XmNhelpCallback,
5824                     (XtCallbackProc)HelpRequestCB, NULL);
5825       file_view_data->registered = False;
5826    }
5827
5828    if (file_mgr_data->view != BY_NAME)
5829       _DtCheckAndFreePixmapData(logical_type,
5830                                 (Widget) file_window,
5831                                 (DtIconGadget) icon_widget,
5832                                 pixmapData);
5833
5834 #ifdef _SHOW_LINK
5835    if (file_view_data->file_data->link != 0)
5836    {
5837       XtSetArg (args[0], XmNforeground, layout_data->topshadow);
5838       XtSetValues (icon_widget, args, 1);
5839    }
5840 #endif
5841
5842    /*
5843     * If viewing by attributes, adjust spacing between the icon pixmap and
5844     * the file name so that all file names are aligned.
5845     */
5846    if (file_mgr_data->view != BY_NAME_AND_ICON ||
5847        file_mgr_data->show_type == MULTIPLE_DIRECTORY)
5848    {
5849      Dimension pixmap_width = ((DtIconGadget)icon_widget)->icon.pixmap_width;
5850
5851      if (pixmap_width < layout_data->pixmap_width)
5852      {
5853         XtSetArg (args[0], XmNspacing,
5854               layout_data->spacing + layout_data->pixmap_width - pixmap_width);
5855         XtSetValues (icon_widget, args, 1);
5856      }
5857    }
5858
5859
5860    file_view_data->file_data->is_broken = False;
5861    file_view_data->widget = icon_widget;
5862    XtAddCallback (icon_widget, XmNcallback, (XtCallbackProc)IconCallback,
5863                   file_view_data);
5864
5865    XmStringFree (icon_label);
5866
5867    /* Check if we need a button for tree branch expand */
5868
5869    if (file_mgr_data->show_type != MULTIPLE_DIRECTORY ||
5870        !file_view_data->file_data->is_subdir)
5871    {
5872      /* no tree branch expand button needed */
5873      file_view_data->treebtn = NULL;
5874    }
5875    else
5876    {
5877      /* create a tree branch expand button */
5878      Pixmap px = GetTreebtnPixmap(file_mgr_data, file_view_data);
5879
5880      n = 0;
5881      XtSetArg(args[n], XmNlabelType, XmPIXMAP);                 n++;
5882      XtSetArg(args[n], XmNlabelPixmap, px);                     n++;
5883      XtSetArg(args[n], XmNbackground, layout_data->background); n++;
5884      XtSetArg(args[n], XmNtraversalOn, False);                  n++;
5885      XtSetArg(args[n], XmNhighlightThickness, 0);               n++;
5886      XtSetArg(args[n], XmNshadowThickness, 0);                  n++;
5887      XtSetArg(args[n], XmNmarginWidth, 0);                      n++;
5888      XtSetArg(args[n], XmNmarginHeight, 0);                     n++;
5889      XtSetArg(args[n], XmNuserData, file_mgr_data);             n++;
5890      XtSetArg(args[n], XmNx, -999);                             n++;
5891      XtSetArg(args[n], XmNy, -999);                             n++;
5892
5893      /* See if we can re-use the same or some other button gadget */
5894      if (file_view_data->treebtn)
5895         btn_widget = file_view_data->treebtn;
5896      else if (*layout_data->next_btn_to_use)
5897         btn_widget = *(layout_data->next_btn_to_use)++;
5898      else
5899         btn_widget = NULL;
5900
5901      /* See if we found an available button gadget */
5902      if (btn_widget) {
5903         XtRemoveAllCallbacks (btn_widget, XmNactivateCallback);
5904         XtSetValues (btn_widget, args, n);
5905      }
5906      else
5907      {
5908        btn_widget = XmCreatePushButtonGadget((Widget)file_window,
5909                                              "tree_button", args, n);
5910      }
5911      XtAddCallback(btn_widget, XmNactivateCallback,
5912                     (XtCallbackProc)TreeBtnCallback, file_view_data);
5913
5914      file_view_data->treebtn = btn_widget;
5915    }
5916
5917    /* this entry is now up-to-date */
5918    file_view_data->need_update = False;
5919 }
5920
5921
5922 /*--------------------------------------------------------------------
5923  * _UpdateFileIcons
5924  *------------------------------------------------------------------*/
5925
5926 static void
5927 _UpdateFileIcons(
5928         FileMgrRec *file_mgr_rec,
5929         FileMgrData *file_mgr_data,
5930         Boolean new_directory,
5931         DirectorySet * add_dir_set)
5932 {
5933    XmManagerWidget file_window;
5934    FileViewData **order_list;
5935    int order_count;
5936    Widget child;
5937    Arg args[5];
5938    IconLayoutData *layout_data;
5939    int i;
5940
5941 #ifdef DT_PERFORMANCE
5942    struct timeval update_time_s;
5943    struct timeval update_time_f;
5944 #endif
5945
5946    DPRINTF(("_UpdateFileIcons(\"%s\", new_dir %c, add_dir_set %p) ...\n",
5947             file_mgr_data->current_directory,
5948             new_directory? 'T': 'F', add_dir_set));
5949
5950    /*  Set the size of the file window BIG so that it does not  */
5951    /*  try to force positioning on its children.                */
5952    file_window = (XmManagerWidget) file_mgr_rec->file_window;
5953    XtResizeWidget ((Widget)file_window, 32767, 32767, 0);
5954
5955    /*  Set the scrolled window and file window appropriately  */
5956    /*  to prevent a lot of gyrations.                         */
5957
5958    XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmSTATIC);
5959    XtSetValues (file_mgr_rec->scroll_window, args, 1);
5960
5961    /* For faster updates, unmanage all the icons */
5962    if (XtIsManaged(file_mgr_rec->file_window))
5963    {
5964       /* see if the focus is inside the file window */
5965       child = XmGetFocusWidget(file_mgr_rec->file_window);
5966       if (child != NULL)
5967       {
5968         if (new_directory)
5969         {
5970           file_mgr_rec->focus_widget = file_mgr_rec->file_window;
5971         }
5972         else if( XtParent(child) == file_mgr_rec->file_window )
5973         {
5974           /* remember which widget had the focus */
5975           file_mgr_rec->focus_widget = child;
5976         }
5977       }
5978
5979       DPRINTF(("  focus_widget = %p (%s)\n",
5980                file_mgr_rec->focus_widget,
5981                file_mgr_rec->focus_widget?
5982                   XtName(file_mgr_rec->focus_widget): "nil"));
5983       XtUnmanageChild(file_mgr_rec->file_window);
5984    }
5985
5986    XtUnmanageChildren(file_window->composite.children,
5987                       file_window->composite.num_children);
5988
5989    /* if this is a new directory, scroll to the top */
5990    if (new_directory)
5991    {
5992       XtSetArg (args[0], XmNx, 0);
5993       XtSetArg (args[1], XmNy, 0);
5994       XtSetValues ((Widget)file_window, args, 2);
5995    }
5996
5997    /*
5998     * Don't leave the view in a munged state for too long.
5999     * Only do if we are not creating a new view.  This is because the
6000     * view is not yet in the 'view_list', and so the redisplay code
6001     * may not use the correct redisplay function.
6002     */
6003    if (ReturnDesktopPtr(file_mgr_rec->file_window))
6004    {
6005       UpdateHeaders(file_mgr_rec, file_mgr_data, False);
6006       XFlush (XtDisplay (file_window));
6007       XmUpdateDisplay ((Widget)file_window);
6008    }
6009
6010    /* free any old layout data */
6011    FreeLayoutData(file_mgr_data->layout_data);
6012    file_mgr_data->layout_data = NULL;
6013
6014    /* if directory-read still in progress, don't do anything more now */
6015    if (file_mgr_data->busy_status != not_busy)
6016    {
6017       DPRINTF(("done (busy)\n"));
6018       return;
6019    }
6020
6021 #ifdef DT_PERFORMANCE
6022    printf("   Beginning UpdateFileIcons\n");
6023    gettimeofday(&update_time_s, NULL);
6024
6025    /* added by Rafi */
6026    _DtPerfChkpntMsgSend("Begin Update Icons");
6027
6028 #endif
6029
6030    /* set up new layout data */
6031    layout_data = (IconLayoutData *)XtCalloc(1, sizeof(IconLayoutData));
6032    file_mgr_data->layout_data = (XtPointer)layout_data;
6033
6034    FlattenTree(file_mgr_data, &order_list, &order_count);
6035    layout_data->order_list = order_list;
6036    layout_data->order_count = order_count;
6037
6038    MakeReuseList(file_window->composite.children,
6039                  file_window->composite.num_children,
6040                  order_list, order_count,
6041                  &layout_data->reuse_icons,
6042                  &layout_data->reuse_btns);
6043    layout_data->next_icon_to_use = layout_data->reuse_icons;
6044    layout_data->next_btn_to_use = layout_data->reuse_btns;
6045
6046    layout_data->manage = (Widget *)XtMalloc(2*order_count*sizeof(Widget));
6047    layout_data->manage_count = 0;
6048
6049    layout_data->i_do_next_vis = 0;
6050    layout_data->i_do_next_all = 0;
6051
6052    /*
6053     * Iterate through the file list and mark all entries to be in
6054     * need of update.  We also construct icon labels at this time,
6055     * since they are need by LayoutFileIcons to estimate icon gadget
6056     * sizes.
6057     */
6058
6059    if (add_dir_set)
6060    {
6061      /* only need to iterate throught the new entries */;
6062      order_list = add_dir_set->order_list;
6063      order_count = add_dir_set->file_count;
6064    }
6065
6066    for (i = 0; i < order_count; i++)
6067    {
6068       order_list[i]->need_update = True;
6069       order_list[i]->selected = False;
6070       UpdateOneIconLabel(file_mgr_data, order_list[i]);
6071    }
6072
6073    /* set selected flag on all files in selection_list */
6074    for (i = 0; i < file_mgr_data->selected_file_count; i++)
6075       file_mgr_data->selection_list[i]->selected = True;
6076
6077 #ifdef DT_PERFORMANCE
6078    gettimeofday(&update_time_f, NULL);
6079    if (update_time_s.tv_usec > update_time_f.tv_usec) {
6080       update_time_f.tv_usec += 1000000;
6081       update_time_f.tv_sec--;
6082    }
6083    printf("    done UpdateFileIcons, time: %ld.%ld\n\n", update_time_f.tv_sec - update_time_s.tv_sec, update_time_f.tv_usec - update_time_s.tv_usec);
6084
6085    /* added by Rafi */
6086    _DtPerfChkpntMsgSend("Done  Update Icons");
6087 #endif
6088
6089    DPRINTF(("done\n"));
6090 }
6091
6092
6093
6094
6095 /************************************************************************
6096  *
6097  *  CreateTreeIcons
6098  *      Create icons for tree-branch-expand buttons.
6099  *
6100  ************************************************************************/
6101
6102 static void
6103 CreateTreeIcons(Widget w)
6104 {
6105   Arg args[20];
6106   Pixel  background_color = 0;
6107   Pixel  foreground_color = 0;
6108   int i, j;
6109   TreePxId px;
6110   char pxname[128];
6111   unsigned int width, height, dummy;
6112
6113   XtSetArg (args[0], XmNbackground, &background_color);
6114   XtSetArg (args[1], XmNforeground, &foreground_color);
6115   XtGetValues (w, args, 2);
6116
6117   for (i = 0; i < 3; i++)
6118   {
6119     TreeBtnWd[i] = 5;
6120     TreeBtnHt[i] = 5;
6121     for (j = 0; j < tpxN; j++)
6122     {
6123       strcpy(pxname, TreePxTab[j].name);
6124       strcat(pxname, TreePxSuffix[i]);
6125       TreePxTab[j].px[i] = _DtGetPixmap(XtScreen(w), pxname,
6126                                      foreground_color, background_color);
6127       width = height = 0;
6128       XGetGeometry(XtDisplay(w), TreePxTab[j].px[i],
6129                    (Window *) &dummy,               /* returned root window */
6130                    (int *) &dummy, (int *) &dummy,  /* x, y of pixmap */
6131                    &width, &height,                 /* pixmap width, height */
6132                    &dummy, &dummy);                 /* border width, depth */
6133       if (j == tpxNil)
6134       {
6135          TreeNilWd[i] = width;
6136          TreeNilHt[i] = height;
6137       }
6138       else
6139       {
6140          if (width > TreeBtnWd[i])
6141            TreeBtnWd[i] = width;
6142          if (height > TreeBtnHt[i])
6143            TreeBtnHt[i] = height;
6144       }
6145     }
6146   }
6147 }
6148
6149
6150 /************************************************************************
6151  *
6152  *  GetTreebtnPixmap
6153  *      Get icon for tree-branch-expand buttons.
6154  *
6155  ************************************************************************/
6156
6157 Pixmap GetTreebtnPixmap(
6158         FileMgrData *file_mgr_data,
6159         FileViewData *file_view_data)
6160 {
6161    TreePxId pxid;
6162
6163    /* if not yet done, create tree button icons */
6164    /* @@@ do this earlier from main? */
6165    if (TreeBtnWd[0] == 0)
6166      CreateTreeIcons(((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window);
6167
6168    if (file_view_data->ts == tsNotRead)
6169      pxid = tpxNotRead;
6170    else if (file_view_data->ts == tsError)
6171      pxid = tpxError;
6172    else if (file_view_data->ndir == 0 &&
6173             (file_view_data->nfile == 0 ||
6174              file_mgr_data->tree_files == TREE_FILES_NEVER)
6175              && (file_view_data->ts == tsNone || !showEmptySet))
6176      pxid = tpxEmpty;
6177    else if (file_view_data->ts == tsNone)
6178      pxid = tpxMore;
6179    else if (file_view_data->ts == tsDirs)
6180      pxid = (file_view_data->nfile == 0 ||
6181              file_mgr_data->tree_files == TREE_FILES_NEVER)? tpxLess:
6182             (file_view_data->ndir == 0)?  tpxMore:
6183                                           tpxBoth;
6184    else if (file_view_data->ts == tsAll)
6185      pxid = tpxLess;
6186
6187    if (file_mgr_data->view == BY_NAME)
6188      return TreePxTab[pxid].px[0];   /* small pixmap */
6189    else if (file_mgr_data->view == BY_NAME_AND_ICON)
6190      return TreePxTab[pxid].px[2];   /* large pixmap */
6191    else
6192      return TreePxTab[pxid].px[1];   /* medium  pixmap */
6193 }
6194
6195
6196 /************************************************************************
6197  *
6198  *  GetIconSize
6199  *      Compute maximum icon size.
6200  *
6201  ************************************************************************/
6202
6203 static void
6204 GetIconLayoutParms(
6205         FileMgrRec *file_mgr_rec,
6206         FileMgrData *file_mgr_data,
6207         IconLayoutData *ld)
6208 {
6209    DirectorySet *directory_set;
6210    int file_count;
6211    FileViewData **file_list;
6212    int i;
6213    DtIconGadget g;
6214    Arg args[10];
6215    Dimension shadowThickness;
6216    Dimension marginWidth;
6217    Dimension maxWidth = ld->pixmap_width;
6218    Dimension gadgetWidth;
6219
6220    /* determine pixmap size */
6221    if (file_mgr_data->view == BY_NAME)
6222    {
6223       /* no pixmap */
6224       ld->pixmap_width = 0;
6225       ld->pixmap_height = 0;
6226    }
6227    else if (file_mgr_data->view == BY_NAME_AND_ICON)
6228    {
6229       /* large pixmap */
6230       ld->pixmap_width = largeIconWidth;
6231       ld->pixmap_height = largeIconHeight;
6232    }
6233    else
6234    {
6235       /* small pixmap */
6236       ld->pixmap_width = smallIconWidth;
6237       ld->pixmap_height = smallIconHeight;
6238    }
6239
6240    /* find the icon gadget for "." */
6241    directory_set = file_mgr_data->directory_set[0];
6242    file_count = directory_set->file_count;
6243    file_list = directory_set->file_view_data;
6244
6245    g = NULL;
6246    for (i = 0; i < file_count; i++)
6247    {
6248       if (strcmp(file_list[i]->file_data->file_name, ".") == 0)
6249       {
6250          g = (DtIconGadget)file_list[i]->widget;
6251          break;
6252       }
6253    }
6254
6255    /* get layout parameters from "." */
6256    if (g)
6257    {
6258       XtSetArg(args[0], XmNhighlightThickness, &ld->highlight);
6259       XtSetArg(args[1], XmNshadowThickness, &shadowThickness);
6260       XtSetArg(args[2], XmNmarginWidth, &marginWidth);
6261       XtSetArg(args[3], XmNspacing, &ld->spacing);
6262       XtSetArg(args[4], XmNalignment, &ld->alignment);
6263       XtSetArg(args[5], XmNpixmapPosition, &ld->pixmap_position);
6264       XtGetValues((Widget)g, args, 6);
6265
6266       if (g->icon.pixmap_width < maxWidth)
6267          ld->spacing = ld->spacing - (maxWidth - g->icon.pixmap_width);
6268
6269       ld->width = ((Widget)g)->core.width +
6270                                      ld->pixmap_width  - g->icon.pixmap_width;
6271       ld->height = ((Widget)g)->core.height +
6272                                      ld->pixmap_height - g->icon.pixmap_height;
6273
6274       ld->char_width = (g->icon.string_width)/strlen(file_list[i]->label);
6275       if (ld->pixmap_position != XmPIXMAP_TOP)
6276          ld->width -= g->icon.string_width;
6277       ld->margin = ld->highlight + shadowThickness + marginWidth;
6278    }
6279    else
6280    {
6281       /* No icon gadget for "." found: strange!  Guess some defaults.  */
6282       ld->char_width = 8;
6283       ld->margin = 2 + 1 + 1;
6284       ld->spacing = 2;
6285       ld->highlight = (keybdFocusPolicy == XmEXPLICIT)? 2: 0;
6286       ld->alignment = XmALIGNMENT_END;
6287       if (file_mgr_data->view == BY_NAME_AND_ICON &&
6288           file_mgr_data->show_type != MULTIPLE_DIRECTORY)
6289       {
6290          ld->pixmap_position = XmPIXMAP_TOP;
6291          ld->width = 2*ld->margin + ld->pixmap_width;
6292          ld->height = 2*ld->margin + ld->pixmap_height + ld->spacing + 14;
6293       }
6294       else
6295       {
6296          ld->pixmap_position = XmPIXMAP_LEFT;
6297          ld->width = 2*ld->margin + ld->pixmap_width +
6298                                                  ld->spacing + ld->char_width;
6299          ld->height = 2*ld->margin + ld->pixmap_height;
6300       }
6301    }
6302
6303    /* determine which size tree buttons to use */
6304    if (file_mgr_data->show_type != MULTIPLE_DIRECTORY)
6305       ld->treebtn_size = 0;   /* no tree buttons needed */
6306    else if (file_mgr_data->view == BY_NAME)
6307       ld->treebtn_size = 0;   /* small size */
6308    else if (file_mgr_data->view == BY_NAME_AND_ICON)
6309       ld->treebtn_size = 2;   /* large size */
6310    else
6311       ld->treebtn_size = 1;   /* medium size */
6312 }
6313
6314
6315 static void
6316 EstimateIconSize(
6317         FileMgrRec *file_mgr_rec,
6318         FileMgrData *file_mgr_data,
6319         IconLayoutData *layout_data,
6320         FileViewData *file_view_data,
6321         Dimension *width,
6322         Dimension *height)
6323 {
6324    int label_len;
6325    int label_width;
6326
6327    if (file_view_data == NULL)
6328       label_len = 1;
6329    else if (file_view_data->label == NULL)
6330       label_len = strlen(file_view_data->file_data->file_name);
6331    else
6332       label_len = strlen(file_view_data->label);
6333
6334    if (layout_data->pixmap_position == XmPIXMAP_TOP)
6335    {
6336       label_width = 2*layout_data->margin + label_len*layout_data->char_width;
6337       if ((Dimension)label_width > layout_data->width)
6338          *width = label_width;
6339       else
6340          *width = layout_data->width;
6341    }
6342    else
6343         *width = layout_data->width + (label_len) * layout_data->char_width;
6344    *height = layout_data->height;
6345 }
6346
6347
6348 /************************************************************************
6349  *
6350  *  GetExtraHeight
6351  *    Compute extra height for drawing nil symbol for empty tree branches.
6352  *
6353  ************************************************************************/
6354
6355 static Dimension
6356 GetExtraHeight(
6357         FileMgrData *file_mgr_data,
6358         FileViewData *file_view_data,
6359         int treebtn_size)
6360 {
6361    if (showEmptySet &&
6362        file_view_data->file_data->is_subdir &&
6363        file_view_data->ts >= tsDirs &&
6364        file_view_data->ndir == 0 &&
6365        (file_view_data->nfile == 0 ||
6366         file_mgr_data->tree_files == TREE_FILES_NEVER))
6367    {
6368       return YSPACING(file_mgr_data) + TreeNilHt[treebtn_size];
6369    }
6370    else
6371       return 0;
6372 }
6373
6374
6375 /************************************************************************
6376  *
6377  *  EraseTreeLines
6378  *    Erase connecting lines in tree mode from a specified icon widget
6379  *    on down; called when a tree branch is expanded or collapsed to
6380  *    erase previous tree lines before drawing new icons and tree lines.
6381  *
6382  ************************************************************************/
6383
6384 void
6385 EraseTreeLines(
6386         FileMgrRec *file_mgr_rec,
6387         FileMgrData *file_mgr_data,
6388         FileViewData *file_view_data)
6389 {
6390    XmManagerWidget file_window;
6391    Dimension fw_width, fw_height;
6392    Position x, y;
6393
6394    file_window = (XmManagerWidget) file_mgr_rec->file_window;
6395    if (!XtIsManaged((Widget)file_window))
6396       return;
6397
6398    /* get upper left corner of grid space for the icon widget */
6399    x = file_view_data->x;
6400    y = file_view_data->y - file_mgr_data->grid_height;
6401
6402    /*  Get file window width and height */
6403    fw_width = file_window->core.width;
6404    fw_height = file_window->core.height;
6405
6406    DPRINTF2(("EraseTreeLines(\"%s\"): x/y %d/%d (widget %d/%d)\n",
6407              file_view_data->file_data->file_name, x, y,
6408              file_view_data->widget->core.x,
6409              file_view_data->widget->core.y));
6410
6411    /* clear area from icon widget to bottom of file window */
6412    XClearArea(XtDisplay(file_window), XtWindow(file_window),
6413               x, y, fw_width - x, fw_height - y, False);
6414
6415    /*
6416     * clear area to the right and above the icon widget
6417     * (necessary if there are multiple columns, which happens if
6418     *  there are more icons than fit into a single column of
6419     *  maximum height 32767)
6420     */
6421    if (y > 0  &&  (Dimension)(x + file_mgr_data->grid_width) < fw_width)
6422    {
6423      x += file_mgr_data->grid_width;
6424      XClearArea(XtDisplay(file_window), XtWindow(file_window),
6425                 x, 0, fw_width - x, y, False);
6426    }
6427 }
6428
6429
6430 /************************************************************************
6431  *
6432  *  RedrawTreeLines
6433  *      Redraw connecting lines in tree mode.
6434  *
6435  ************************************************************************/
6436
6437 void
6438 RedrawTreeLines(
6439         Widget w,
6440         int ex, int ey, int ewidth, int eheight, int ecount,
6441         FileMgrRec *file_mgr_rec,
6442         FileMgrData *file_mgr_data)
6443 {
6444    static char *empty_msg = NULL;
6445
6446    FileViewData *file_view_data;
6447    IconLayoutData *layout_data;
6448    Dimension grid_width, grid_height;
6449    Dimension extra_height, e_height;
6450    int sz;
6451    FileViewData **order_list;
6452    int order_count;
6453    GC solid_gc, dash_gc;
6454    int i, k;
6455    Position x, xl;
6456    Position y, y0, y1;
6457    int level;
6458    Bool more[256];
6459    XFontSetExtents *extents;
6460    int font_height;
6461    int font_yoffset;
6462    int tmp;
6463
6464    if (!XtIsManaged(w))
6465       return;
6466
6467    /*  get layout parameters  */
6468    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
6469    order_list = layout_data->order_list;
6470    order_count = layout_data->order_count;
6471    grid_width = file_mgr_data->grid_width;
6472    grid_height = file_mgr_data->grid_height;
6473    sz = layout_data->treebtn_size;
6474
6475    DPRINTF2(("RedrawTreeLines(x %d, y %d, wd %d, ht %d, count %d)\n",
6476              ex, ey, ewidth, eheight, ecount));
6477
6478    if (grid_width == 0 || grid_height == 0)
6479       /* layout probably not yet done */
6480       return;
6481
6482    /* if not yet done, create tree button icons */
6483    /* @@@ do this earlier from main? */
6484    if (TreeBtnWd[0] == 0)
6485      CreateTreeIcons(((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window);
6486
6487    /* select line styles */
6488    if (file_mgr_data->view == BY_NAME) {
6489      solid_gc = file_mgr_data->tree_solid_thin_gc;
6490      dash_gc = file_mgr_data->tree_dash_thin_gc;
6491    } else {
6492      solid_gc = file_mgr_data->tree_solid_thick_gc;
6493      dash_gc = file_mgr_data->tree_dash_thick_gc;
6494    }
6495
6496    x = MARGIN;
6497    y = MARGIN;
6498
6499    for (k = 0; k < order_count; k++)
6500    {
6501       if (!order_list[k]->displayed)
6502          continue;
6503
6504       /* determine the height of this item */
6505       file_view_data = order_list[k];
6506       extra_height = GetExtraHeight(file_mgr_data, file_view_data, sz);
6507       GetLevel(file_view_data, &level);
6508
6509       /* check if we need to go to the next column */
6510       tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
6511       if (tmp + MARGIN > MAXWINSIZE)
6512       {
6513         /* window would exceed height limit; go to the next column */
6514         x += grid_width + XSPACING;
6515         y = MARGIN;
6516         tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
6517       }
6518
6519       /* check if current item intersects the exposed region */
6520       y0 = y - YSPACING(file_mgr_data)
6521              - grid_height
6522              + (Dimension)(grid_height - TreeBtnHt[sz])/(Dimension)2
6523              + TreeBtnHt[sz];
6524       y1 = y + grid_height + extra_height + YSPACING(file_mgr_data);
6525       if (x  <= ex + ewidth  && x + TreeWd(level, sz) > ex &&
6526           y0 <= ey + eheight && y1 > ey)
6527       {
6528          GetAncestorInfo(file_mgr_data, file_view_data, NULL, NULL, more);
6529
6530          /* draw vertical connecting lines for upper tree levels */
6531          for (i = 0; i < level; i++) {
6532            if (more[i])
6533              XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
6534                        x + TreeLX(i, sz), y0,
6535                        x + TreeLX(i, sz), y1);
6536          }
6537
6538          /* draw vertical connecting line for this tree level */
6539          xl = x + TreeLX(level, sz);
6540          if (level > 0) {
6541            XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
6542                      xl, y0,
6543                      xl, more[level]? y1: y + grid_height/2);
6544
6545            if (file_view_data->file_data->is_subdir || !more[level]) {
6546              /* draw horizontal line */
6547              XDrawLine(XtDisplay(w), XtWindow(w),
6548                        (file_view_data->file_data->is_subdir &&
6549                         file_view_data->ts == tsNotRead)? dash_gc: solid_gc,
6550                        xl, y + grid_height/2,
6551                        xl + TreeOffset, y + grid_height/2);
6552            }
6553          }
6554
6555          /* draw nil symbol for empty subdirs */
6556          if (extra_height)
6557          {
6558             xl += TreeOneWd(sz);
6559             y0 += grid_height + YSPACING(file_mgr_data);
6560             y1 = y + grid_height + YSPACING(file_mgr_data);
6561             e_height = extra_height - YSPACING(file_mgr_data);
6562
6563             XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
6564                       xl, y0,
6565                       xl, y1 + e_height/2);
6566
6567             XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
6568                       xl, y1 + e_height/2,
6569                       xl + TreeOffset, y1 + e_height/2);
6570
6571             xl = x + TreeWd(level, sz) + TreeBtnWd[sz];
6572             XCopyArea(XtDisplay(w), TreePxTab[tpxNil].px[sz],
6573                       XtWindow(w), solid_gc,
6574                       0, 0, TreeNilWd[sz], TreeNilHt[sz],
6575                       xl, y1);
6576 /*
6577             if (empty_msg == NULL)
6578                empty_msg = XtNewString("(empty)");
6579
6580             if (file_mgr_data->cd_fonttype == XmFONT_IS_FONTSET)
6581             {
6582                 extents = XExtentsOfFontSet(file_mgr_data->cd_fontset);
6583                 font_yoffset = extents->max_logical_extent.y;
6584                 font_height = extents->max_logical_extent.height;
6585             }
6586             else
6587             {
6588                 font_yoffset = file_mgr_data->cd_font->ascent;
6589                 font_height = file_mgr_data->cd_font->ascent +
6590                                 file_mgr_data->cd_font->descent;
6591             }
6592
6593             XDrawImageString(XtDisplay(w), XtWindow(w), solid_gc,
6594                       xl + TreeNilWd[sz] + 2,
6595                       y1 + (TreeNilHt[sz] - font_height)/2 + font_yoffset,
6596                       empty_msg, strlen(empty_msg));
6597 */
6598          }
6599       }
6600
6601       /* goto next item */
6602       y = (Position)tmp;
6603    }
6604 }
6605
6606
6607 /************************************************************************
6608  *
6609  *  DisplaySomeIcons
6610  *    Check if any incons or widgets in the area given by ex, ey, ewd,
6611  *    and eht need to be updated.
6612  *
6613  ************************************************************************/
6614
6615 #ifdef DEBUG
6616 static int g_workCount1 = 0;
6617 static int g_workCount2 = 0;
6618 static int g_callCount = 0;
6619 #endif
6620
6621 static Boolean
6622 ToBeManaged(
6623         IconLayoutData *layout_data,
6624         FileViewData *file_view_data)
6625 {
6626    int i;
6627
6628    for (i = 0; i < layout_data->manage_count; i++)
6629       if (layout_data->manage[i] == file_view_data->widget)
6630          return True;
6631
6632    return False;
6633 }
6634
6635
6636 static int
6637 DisplaySomeIcons(
6638         FileMgrRec *file_mgr_rec,
6639         FileMgrData *file_mgr_data,
6640         int ex, int ey, int ewd, int eht,
6641         int workLimit,
6642         Boolean doAll)
6643 {
6644 #ifdef DT_PERFORMANCE
6645    struct timeval update_time_s;
6646    struct timeval update_time_f;
6647 #endif
6648    XmManagerWidget file_window;
6649    FileViewData **order_list;
6650    int order_count;
6651    Arg args[10];
6652    Arg args_dso_get[1];
6653    Arg args_dso_set[1];
6654    IconLayoutData *layout_data;
6655    FileViewData **change;
6656    int changeCount;
6657    Widget *manage;
6658    int manageCount;
6659    int workCount1;
6660    int workCount2;
6661    Dimension grid_width, grid_height;
6662    Dimension icon_width, icon_height;
6663    Dimension extra_height;
6664    int i, k;
6665    Position x, y;
6666    FileViewData  *file_view_data;
6667    Boolean changed;
6668    Widget child;
6669    DtIconGadget g;
6670    int level;
6671    unsigned char operations;
6672    Widget *wp;
6673    ObjectPosition *position_data;
6674    XRectangle textExtent;
6675
6676    /* Get a list of icon and button widgets we can re-use */
6677    file_window = (XmManagerWidget) file_mgr_rec->file_window;
6678    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
6679    order_list = layout_data->order_list;
6680    order_count = layout_data->order_count;
6681    manage = layout_data->manage + layout_data->manage_count;
6682
6683    /* allocate storage for list of changed icons */
6684    change = (FileViewData **)XtMalloc(order_count * sizeof(FileViewData *));
6685
6686    /*  Find the maximum values for the icon heights and widths  */
6687    grid_width = file_mgr_data->grid_width;
6688    grid_height = file_mgr_data->grid_height;
6689
6690
6691 #ifdef DT_PERFORMANCE
6692    printf("   Begin Part 1, DisplaySomeIcons (update icons)\n");
6693    gettimeofday(&update_time_s, NULL);
6694
6695    /* added by Rafi */
6696    _DtPerfChkpntMsgSend("Begin Display Icons");
6697 #endif
6698
6699    DPRINTF2((
6700      "DisplaySomeIcons(\"%s\", x/y %d/%d, wd/ht %d/%d, i %d:%d) ...\n",
6701      file_mgr_data->current_directory, ex, ey, ewd, eht,
6702      layout_data->i_do_next_vis,
6703      layout_data->i_do_next_all));
6704
6705    /* set up args for querying/unregistering drop sites */
6706    XtSetArg (args_dso_get[0], XmNdropSiteOperations, &operations);
6707    XtSetArg (args_dso_set[0], XmNdropSiteOperations, XmDROP_NOOP);
6708
6709    /*
6710     * Iterate through the list of files and create/update and position
6711     * all visible icon gadgets for which this work hasn't been done yet
6712     * (need_update flag set).
6713     */
6714
6715    changeCount = 0;
6716    manageCount = 0;
6717    workCount1 = 0;
6718
6719    if (doAll)
6720       k = layout_data->i_do_next_all;
6721    else
6722       k = layout_data->i_do_next_vis;
6723    for ( ; k < order_count && workCount1 < workLimit; k++)
6724    {
6725       /*
6726        * Process focus widget before everything else so that we can restore
6727        * the focus when we manage the file_window again.  If a file was
6728        * being renamed, we do that one first.
6729        */
6730       if (!layout_data->focus_done)
6731       {
6732          /* search for focus widget in order_list and see if still displayed */
6733         file_view_data = NULL;
6734         if (file_mgr_rec->focus_widget != NULL)
6735         {
6736           if (file_mgr_rec->focus_widget == file_mgr_rec->file_window)
6737           {
6738             for (i = 0; i < order_count; i++)
6739               if (order_list[i]->displayed)
6740               {
6741                 file_view_data = order_list[i];
6742                 break;
6743               }
6744           }
6745           else
6746           {
6747             for (i = 0; i < order_count; i++)
6748               if (order_list[i]->widget == file_mgr_rec->focus_widget)
6749               {
6750                 if (order_list[i]->displayed)
6751                   file_view_data = order_list[i];
6752                 break;
6753               }
6754           }
6755         }
6756
6757          /* if not found, focus could be on a rename text widget */
6758         if (file_view_data == NULL)
6759           file_view_data = file_mgr_data->renaming;
6760
6761         layout_data->focus_done = True;
6762
6763         if (file_view_data)
6764         {
6765           k--;
6766           /* decrement loop index, so that the entry that was supposed to be
6767              processed here will be looked at again in the next iteration
6768           */
6769           goto do_this_entry;
6770         }
6771       }
6772
6773
6774       /* ignore files that are filtered */
6775       file_view_data = order_list[k];
6776       if (file_view_data->filtered &&
6777           strcmp(file_view_data->file_data->file_name, ".") != 0)
6778       {
6779          continue;
6780       }
6781
6782       /*
6783        * If the file is not currenly displayed (collapsed tree branch) or
6784        * is currenly scrolled out of view, we don't need to do anything
6785        * at this time.  Except ...
6786        */
6787       if (!file_view_data->displayed ||
6788           ((int)file_view_data->x + (int)grid_width) < ex  ||
6789           file_view_data->x >= ex + ewd ||
6790           file_view_data->y < ey ||
6791           ((int)file_view_data->y - (int)grid_height) >= (ey + eht))
6792       {
6793          /*
6794           * ... if this file still has an old icon widget, AND if the
6795           * old icon position is visible, AND if the icon was registered
6796           * as a drop site, we will have a "ghost drop zone" showing up where
6797           * the icon used to be.  The old icon gadget is unmanaged and will
6798           * remain unmanaged until later when we update it and move it to the
6799           * correct positon (happens only when the user scrolls to the new
6800           * position).  In the meantime, even though the gadget is unmanged,
6801           * its old position still remains registered as a drop site,
6802           * so we have to either unregister it or move the gadget to
6803           * its new position now.
6804           */
6805          child = file_view_data->widget;
6806          if (child != NULL &&
6807              (Position)(child->core.x + child->core.width) >= (Position)ex  &&
6808              child->core.x < ex + ewd &&
6809              (Position)(child->core.y + child->core.height) >= (Position)ey &&
6810              child->core.y < ey + eht)
6811          {
6812             if (!file_view_data->displayed)
6813             {
6814                XtGetValues (child, args_dso_get, 1);
6815                if (operations != XmDROP_NOOP)
6816                {
6817                   XtSetValues (child, args_dso_set, 1);
6818                   workCount1++;
6819                   file_view_data->registered = False;
6820                }
6821                continue;
6822             }
6823
6824          } else
6825            continue;
6826       }
6827
6828 do_this_entry:
6829       /*
6830        * If not yet done, create/update the icon gadget for this file
6831        */
6832       if (file_view_data->need_update)
6833       {
6834          UpdateOneFileIcon(file_mgr_rec, file_mgr_data, file_view_data);
6835          child = file_view_data->widget;
6836
6837          /*
6838           * We may need to adjust the icon position based on the difference
6839           * between estimated size and actual size.
6840           */
6841          if (layout_data->alignment == XmALIGNMENT_CENTER &&
6842              file_mgr_data->view == BY_NAME_AND_ICON)
6843          {
6844             EstimateIconSize(file_mgr_rec, file_mgr_data, layout_data,
6845                              file_view_data, &icon_width, &icon_height);
6846
6847             if (child->core.width != icon_width)
6848             {
6849                file_view_data->x = file_view_data->x
6850                  - (Dimension)(grid_width - icon_width)/(Dimension)2
6851                  + (Dimension)(grid_width - child->core.width)/(Dimension)2;
6852             }
6853          }
6854
6855          if (PositioningEnabledInView(file_mgr_data))
6856          {
6857             position_data = file_view_data->position_info;
6858             if (position_data->late_bind)
6859             {
6860                /*
6861                 * When new objects are dropped on the random placement window,
6862                 * they do not yet have a widget, so the drop_y could not be
6863                 * adjusted to take into account the height of the icon;
6864                 * this must be done now, after the object has an icon.
6865                 */
6866 /*
6867                position_data->y -= child->core.height/2;
6868 */
6869                position_data->late_bind = False;
6870                file_view_data->y = position_data->y + child->core.height;
6871             }
6872             else if (child->core.height != grid_height)
6873             {
6874                /* @@@ ??? @@@
6875                 * Not quite right: have to distinguish two cases:
6876                 *  (1) position_data->y read from .!xxx file
6877                 *      file_view_data->y computed by adding grid_height
6878                 *  (2) file_view_data->y from layout
6879                 *      position_data->y computed by subtracting grid_height
6880                 * In case (1) have to recompute file_view_data->y; in case
6881                 * (2) have to recompute position_data->y.  Code below only
6882                 * works for case (2).
6883                 */
6884 /*
6885                position_data->y = file_view_data->y - child->core.height;
6886 */
6887             }
6888          }
6889
6890          changed = True;
6891       }
6892       else
6893          changed = False;
6894
6895
6896       /* if focus is supposed to be in the file window, focus on this widget */
6897       if (file_mgr_rec->focus_widget == file_mgr_rec->file_window)
6898          file_mgr_rec->focus_widget = file_view_data->widget;
6899
6900
6901       /* determine desired icon postition */
6902       child = file_view_data->widget;
6903
6904       if (PositioningEnabledInView(file_mgr_data))
6905       {
6906          x = file_view_data->position_info->x;
6907          y = file_view_data->position_info->y;
6908       }
6909       else if (file_mgr_data->show_type != MULTIPLE_DIRECTORY)
6910       {
6911          x = file_view_data->x;
6912          y = file_view_data->y - child->core.height;
6913       }
6914       else /* file_mgr_data->show_type == MULTIPLE_DIRECTORY */
6915       {
6916          GetLevel(file_view_data, &level);
6917          extra_height = GetExtraHeight(file_mgr_data, file_view_data,
6918                                        layout_data->treebtn_size);
6919
6920          /* check position of tree button, if any */
6921          if (file_view_data->treebtn)
6922          {
6923            child = file_view_data->treebtn;
6924
6925            x = file_view_data->x
6926                  + TreeLX(level, layout_data->treebtn_size) + TreeOffset;
6927            y = file_view_data->y
6928                - grid_height
6929                + (Dimension)(grid_height - child->core.height)/(Dimension)2;
6930
6931            if (child->core.x != x || child->core.y != y)
6932               XmeConfigureObject(child, x, y, child->core.width,
6933                                  child->core.height, child->core.border_width);
6934
6935            child = file_view_data->widget;
6936          }
6937
6938          if (child->core.height < grid_height)
6939          {
6940             x = file_view_data->x + TreeWd(level, layout_data->treebtn_size);
6941             y = file_view_data->y
6942                 - grid_height
6943                 +(Dimension)(grid_height - child->core.height)/(Dimension)2;
6944          }
6945          else
6946          {
6947             x = file_view_data->x + TreeWd(level, layout_data->treebtn_size);
6948             y = file_view_data->y - grid_height;
6949          }
6950       }
6951
6952       if (child->core.x != x || child->core.y != y)
6953       {
6954           XmeConfigureObject(child, x, y, child->core.width,
6955                              child->core.height, child->core.border_width);
6956           changed = True;
6957       }
6958
6959       /* make sure the icon gadget and tree button, if any, are managed */
6960       if (!XtIsManaged(child) && !ToBeManaged(layout_data, file_view_data))
6961       {
6962          manage[manageCount++] = child;
6963          if (file_view_data->treebtn)
6964             manage[manageCount++] = file_view_data->treebtn;
6965          changed = True;
6966       }
6967
6968       if (changed)
6969       {
6970          /* remember which icons were changed */
6971          change[changeCount++] = file_view_data;
6972          workCount1++;
6973
6974          /*
6975           * If the icon we just changed was being renamed, make sure
6976           * the corresponding text widget is positioned correctly.
6977           */
6978          if (file_view_data == file_mgr_data->renaming)
6979          {
6980             for (i = 0; i < file_window->composite.num_children; i++)
6981             {
6982                child = file_window->composite.children[i];
6983                if (XmIsTextField(child))
6984                {
6985                   /* Check if the text field is still needed */
6986                   if (!child->core.being_destroyed)
6987                   {
6988                      /* move to the correct position */
6989                      _DtIconGetTextExtent_r(file_view_data->widget,
6990                                             &textExtent);
6991                      x = textExtent.x;
6992                      y = textExtent.y -
6993                          (Dimension)(child->core.height - textExtent.height)/(Dimension)2;
6994                      XmeConfigureObject(child, x, y, child->core.width,
6995                                         child->core.height,
6996                                         child->core.border_width);
6997
6998                      /* manage it */
6999                      manage[manageCount++] = child;
7000                   }
7001                   break;
7002                }
7003             }
7004          }
7005       }
7006    }
7007
7008    /* remember where we left off ... */
7009    if (doAll)
7010       layout_data->i_do_next_all = k;
7011    else
7012       layout_data->i_do_next_vis = k;
7013
7014 #ifdef DT_PERFORMANCE
7015    gettimeofday(&update_time_f, NULL);
7016    if (update_time_s.tv_usec > update_time_f.tv_usec) {
7017       update_time_f.tv_usec += 1000000;
7018       update_time_f.tv_sec--;
7019    }
7020    printf("    done Part 1, DisplaySomeIcons, time: %ld.%ld\n\n",
7021           update_time_f.tv_sec - update_time_s.tv_sec,
7022           update_time_f.tv_usec - update_time_s.tv_usec);
7023
7024    /* the following message send call added by Rafi */
7025    _DtPerfChkpntMsgSend("Done  Display Icons");
7026 #endif
7027
7028 #ifdef DT_PERFORMANCE
7029    printf("   Begin Part 2, DisplaySomeIcons (register drop sites)\n");
7030    gettimeofday(&update_time_s, NULL);
7031
7032    /* added by Rafi  */
7033    _DtPerfChkpntMsgSend("Begin Register drop sites");
7034 #endif
7035
7036    /* unregister drop sites of unused icon gadgets */
7037    workCount2 = 0;
7038 #ifdef DELAYED_UNREGISTER
7039    for (wp = layout_data->next_icon_to_use;
7040         (child = *wp) != NULL;
7041         wp++)
7042    {
7043       if ((Position)(child->core.x + child->core.width) >= (Position)ex  &&
7044           child->core.x < ex + ewd &&
7045           (Position)(child->core.y + child->core.height) >= (Position)ey &&
7046           child->core.y < ey + eht)
7047       {
7048          XtGetValues (child, args_dso_get, 1);
7049          if (operations != XmDROP_NOOP)
7050          {
7051             XtSetValues (child, args_dso_set, 1);
7052             workCount2++;
7053
7054             if (workCount2/2 >= workLimit)
7055                break;
7056          }
7057       }
7058    }
7059 #endif
7060
7061    /*
7062     * Register drop sites
7063     *
7064     * Note: in "as placed" mode, we defer this work and do it in
7065     * CommitWorkProcUpdates instead.  Reason: need to re-register
7066     * all drop sites in top-to-bottom stacking order at that time.
7067     */
7068    if (! PositioningEnabledInView(file_mgr_data) &&
7069        file_mgr_data != trashFileMgrData)
7070    {
7071       for (k = 0; k < changeCount; k++)
7072       {
7073          SetHotRects(change[k],
7074                      (XtCallbackProc) DropOnObject,
7075                      (XtPointer) change[k]);
7076       }
7077    }
7078
7079    /* free storage */
7080    XtFree((char *)change);
7081    change = NULL;
7082
7083    /* update count of children to be managed */
7084    layout_data->manage_count += manageCount;
7085
7086
7087 #ifdef DT_PERFORMANCE
7088    gettimeofday(&update_time_f, NULL);
7089    if (update_time_s.tv_usec > update_time_f.tv_usec) {
7090       update_time_f.tv_usec += 1000000;
7091       update_time_f.tv_sec--;
7092    }
7093    printf("    done Part 2 DisplaySomeIcons, time: %ld.%ld\n\n",
7094           update_time_f.tv_sec - update_time_s.tv_sec,
7095           update_time_f.tv_usec - update_time_s.tv_usec);
7096
7097    /* the following message send call added by Rafi */
7098    _DtPerfChkpntMsgSend("Done  Register drop sites");
7099 #endif
7100
7101    DPRINTF2((" ... %d+%d changed (%d managed)\n",
7102              workCount1, workCount2, manageCount));
7103
7104 #ifdef DEBUG
7105    g_workCount1 += workCount1;
7106    g_workCount2 += workCount2;
7107    g_callCount++;
7108 #endif
7109
7110    return (workCount1 >= workCount2)? workCount1: workCount2;
7111 }
7112
7113
7114 /************************************************************************
7115  *
7116  *  Display work procedure
7117  *
7118  ************************************************************************/
7119
7120 static void
7121 CommitWorkProcUpdates(
7122   FileMgrRec *file_mgr_rec,
7123   FileMgrData * file_mgr_data,
7124   Boolean reset)
7125 {
7126    XmManagerWidget file_window;
7127    IconLayoutData *layout_data;
7128    Widget w;
7129    int i;
7130
7131    file_window = (XmManagerWidget) file_mgr_rec->file_window;
7132    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
7133
7134    if (layout_data == NULL)
7135      return;
7136
7137    DPRINTF((
7138     "CommitWorkProcUpdates: %d+%d updates (m %d, n %d, i %d:%d, reset %d)\n",
7139             g_workCount1,
7140             g_workCount2,
7141             layout_data->manage_count,
7142             g_callCount,
7143             layout_data->i_do_next_vis,
7144             layout_data->i_do_next_all,
7145             reset));
7146
7147 #ifdef DEBUG
7148    g_workCount1 = 0;
7149    g_workCount2 = 0;
7150    g_callCount = 0;
7151 #endif
7152
7153    if (reset)
7154    {
7155       layout_data->i_do_next_vis = 0;
7156       layout_data->i_do_next_all = 0;
7157    }
7158
7159    /* if work proc no longer active, everything should already be commited */
7160    if (layout_data->work_id == NULL)
7161      return;
7162
7163    /* manage new children */
7164    if (layout_data->manage_count > 0)
7165    {
7166       if (PositioningEnabledInView(file_mgr_data))
7167          OrderChildrenList(file_mgr_data);
7168       XtManageChildren(layout_data->manage, layout_data->manage_count);
7169    }
7170
7171    /*
7172     * In "as placed" mode, need to register drop sites now.
7173     * (If not "as placed" mode, this was already done in DisplaySomeIcons.)
7174     */
7175    if (PositioningEnabledInView(file_mgr_data))
7176       RegisterDesktopHotspots(file_mgr_data, file_mgr_rec);
7177
7178    /* commit drop site updates */
7179    XmDropSiteEndUpdate(layout_data->drop_site_w);
7180
7181    /* If not managed yet, manage the file window again */
7182    if (!XtIsManaged((Widget)file_window))
7183    {
7184      int incr;
7185      Arg args[2];
7186
7187      XtManageChild ((Widget)file_window);
7188      XtVaGetValues(file_mgr_rec->vertical_scroll_bar,XmNuserData,&incr,NULL);
7189      if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
7190                                     file_mgr_rec->scroll_window)
7191          && incr > 0 )
7192      {
7193         XtSetArg (args[0], XmNincrement,incr);
7194         XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 1);
7195      }
7196      XmUpdateDisplay ((Widget)file_window);
7197    }
7198
7199    /* Try to preserve the focus */
7200    if (file_mgr_rec->focus_widget)
7201    {
7202       /* see if the widget that previously had the focus was just managed */
7203       w = NULL;
7204       for (i = 0; i < layout_data->manage_count; i++)
7205       {
7206          if (layout_data->manage[i] == file_mgr_rec->focus_widget)
7207          {
7208             w = file_mgr_rec->focus_widget;
7209             break;
7210          }
7211       }
7212
7213       /* if focus widget not found, set focus on file_window */
7214       if (w == NULL)
7215          w = (Widget)file_window;
7216
7217       XmProcessTraversal(w, XmTRAVERSE_CURRENT);
7218
7219       file_mgr_rec->focus_widget = NULL;
7220    }
7221
7222    layout_data->manage_count = 0;
7223
7224    /* start new update */
7225    XmDropSiteStartUpdate(layout_data->drop_site_w);
7226 }
7227
7228
7229 static Boolean
7230 DisplayWorkProc(
7231   XtPointer client_data)
7232 {
7233    FileMgrRec *file_mgr_rec = (FileMgrRec *)client_data;
7234    DialogData  * dialog_data;
7235    FileMgrData * file_mgr_data;
7236    XmManagerWidget file_window;
7237    IconLayoutData *layout_data;
7238    int ex, ey, ewd, eht;
7239    ObjectPosition *bottom;
7240    Widget child;
7241    int n;
7242    Boolean commit_updates = False;
7243
7244    int n1 = 1;
7245    int n2 = 1;
7246
7247    dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
7248    if (dialog_data == NULL)
7249       return;
7250
7251    file_mgr_data = (FileMgrData *) dialog_data->data;
7252    file_window = (XmManagerWidget) file_mgr_rec->file_window;
7253    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
7254
7255    /* get the position and size of the currently visible area */
7256    ex = -file_window->core.x;
7257    ey = -file_window->core.y;
7258    ewd = XtParent(file_window)->core.width;
7259    eht = XtParent(file_window)->core.height;
7260
7261    /* check if the window scrolled */
7262    if (ex != layout_data->ex || ey != layout_data->ey)
7263    {
7264       layout_data->i_do_next_vis = layout_data->i_do_next_all;
7265       layout_data->visible_done = False;
7266    }
7267
7268    /* first work on icons in the currently visible area */
7269    if (layout_data->visible_done)
7270       n = 0;
7271    else
7272    {
7273      n = DisplaySomeIcons(file_mgr_rec, file_mgr_data, ex, ey, ewd, eht, n1, False);
7274      if (n == 0)
7275      {
7276        /* we just finished updating all visible icons */
7277        DPRINTF(("DisplayWorkProc: visible done.\n"));
7278        layout_data->visible_done = True;
7279        commit_updates = True;
7280      }
7281    }
7282
7283    /* if we still have some time left, work on other icons */
7284    if (layout_data->visible_done && n < n2)
7285    {
7286       n = DisplaySomeIcons(file_mgr_rec, file_mgr_data,
7287                            0, 0, 32767, 32767, n2 - n, True);
7288
7289       /* check if we are done */
7290       if (n == 0)
7291       {
7292          layout_data->all_done = True;
7293          commit_updates = True;
7294       }
7295       else if (layout_data->manage_count >= 100)
7296          commit_updates = True;
7297    }
7298
7299    if (commit_updates)
7300    {
7301       /* manage new children and commit drop site updates */
7302       CommitWorkProcUpdates(file_mgr_rec, file_mgr_data, False);
7303
7304       /*
7305        * In "as placed" mode, icons may overlap.
7306        * Force redraw in bottom to top stacking order.
7307        */
7308       if (PositioningEnabledInView(file_mgr_data))
7309       {
7310          for (bottom = GetBottomOfStack(file_mgr_data);
7311               bottom;
7312               bottom = (ObjectPosition *)bottom->prev)
7313          {
7314             if (bottom->file_view_data != NULL &&
7315                 bottom->file_view_data->displayed &&
7316                 !bottom->file_view_data->need_update)
7317             {
7318                child = bottom->file_view_data->widget;
7319                if ((Position)(child->core.x + child->core.width) >= (Position)ex  &&
7320                    child->core.x < ex + ewd &&
7321                    (Position)(child->core.y + child->core.height) >= (Position)ey &&
7322                    child->core.y < ey + eht)
7323                {
7324                   RedrawOneGadget(child, NULL, NULL);
7325                }
7326             }
7327          }
7328       }
7329    }
7330
7331    if (layout_data->all_done)
7332    {
7333       /* all work is done; all icons are up-to-date */
7334       file_mgr_data->newSize = False;
7335       layout_data->work_id = NULL;
7336       XmDropSiteEndUpdate(layout_data->drop_site_w);
7337
7338       DPRINTF(("DisplayWorkProc: all done.\n"));
7339
7340       /* returning True will end the work proc */
7341       return True;
7342    }
7343    else
7344    {
7345       /* remember current scroll position */
7346       layout_data->ex = ex;
7347       layout_data->ey = ey;
7348       return False;
7349    }
7350 }
7351
7352
7353 /************************************************************************
7354  *
7355  *  LayoutFileIcons
7356  *      Position and size the full set of icons for the file mgr data.
7357  *
7358  ************************************************************************/
7359
7360 void
7361 LayoutFileIcons(
7362         FileMgrRec *file_mgr_rec,
7363         FileMgrData *file_mgr_data,
7364         Boolean update_scrolling_position,
7365         Boolean turn_off_hourglass )
7366 {
7367 #ifdef DT_PERFORMANCE
7368    struct timeval update_time_s;
7369    struct timeval update_time_f;
7370 #endif
7371    XmManagerWidget file_window;
7372    FileViewData ** order_list;
7373    int order_count;
7374    int total_icon_count;
7375    IconLayoutData *layout_data;
7376    Dimension file_window_width, file_window_height;
7377    Dimension scrolled_window_width, scrolled_window_height;
7378    Dimension vert_scrollbar_width, horiz_scrollbar_height;
7379    Dimension grid_width, grid_height;
7380    Dimension icon_width, icon_height;
7381    Dimension extra_height;
7382    Dimension sw_shadow_thickness, sb_highlight_thickness, space;
7383    int len, max_len;
7384    int level, max_level;
7385    FileViewData *file_view_data;
7386    Boolean overflow = False;
7387    int i, j, k;
7388    Position x, y;
7389    int row_count;
7390    int column_count;
7391    int tmp;
7392    Arg args[10];
7393    char *fileType;
7394
7395    unsigned char operations = 0L;
7396    static XtCallbackRec dropCB[] = { {DropOnFileWindow, NULL}, {NULL, NULL} };
7397
7398
7399    /* if directory-read still in progress, don't do anything now */
7400    if (file_mgr_data->busy_status != not_busy)
7401       return;
7402
7403    DPRINTF(("LayoutFileIcons(\"%s\", u_s_p %c, t_o_h %c) ...\n",
7404             file_mgr_data->current_directory,
7405             update_scrolling_position? 'T': 'F',
7406             turn_off_hourglass? 'T': 'F'));
7407
7408 #ifdef DT_PERFORMANCE
7409    printf("   Begin LayoutFileIcons\n");
7410    gettimeofday(&update_time_s, NULL);
7411
7412    /* added by Rafi */
7413    _DtPerfChkpntMsgSend("Begin Layout Icons");
7414 #endif
7415
7416    /*
7417     * Just in case a previous update work proc is still active,
7418     * we commit pending updates made by the work proc before we
7419     * start making changes.
7420     */
7421    CommitWorkProcUpdates(file_mgr_rec, file_mgr_data, True);
7422
7423    file_window = (XmManagerWidget) file_mgr_rec->file_window;
7424    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
7425
7426    fileType = GetDirectoryLogicalType(file_mgr_data,
7427                                         file_mgr_data->current_directory);
7428    operations = TypeToDropOperations(fileType);
7429
7430    if (!file_mgr_data->dropSite)
7431    {
7432        dropCB[0].closure = (XtPointer)file_mgr_data;
7433
7434        DtDndVaDropRegister((Widget)file_mgr_rec->file_window,
7435                            DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
7436                            operations,
7437                            dropCB,
7438                            DtNdropAnimateCallback, dropCB,
7439                            DtNregisterChildren, True,
7440                            DtNtextIsBuffer,     True,
7441                            XmNanimationStyle,   XmDRAG_UNDER_SHADOW_IN,
7442                            NULL);
7443        file_mgr_data->dropSite = True;
7444
7445        if (!operations)
7446        {
7447            XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
7448            XmDropSiteUpdate((Widget)file_mgr_rec->file_window, args, 1);
7449        }
7450    }
7451    else
7452    {
7453        if (operations)
7454            XtSetArg (args[0], XmNdropSiteOperations, operations);
7455        else
7456            XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
7457        XmDropSiteUpdate((Widget)file_mgr_rec->file_window, args, 1);
7458    }
7459
7460    /*  Get the count of the total icon to be displayed.  */
7461    order_list = layout_data->order_list;
7462    order_count = layout_data->order_count;
7463    total_icon_count = 0;
7464    for (i = 0; i < order_count; i++)
7465    {
7466       if (order_list[i]->displayed)
7467          total_icon_count++;
7468    }
7469
7470    /*  Get the colors to be used for drawing the icons  */
7471    XtSetArg (args[0], XmNbackground, &layout_data->background);
7472    XtSetArg (args[1], XmNforeground, &layout_data->foreground);
7473 #ifdef _SHOW_LINK
7474    XtSetArg (args[2], XmNtopShadowColor, &layout_data->topshadow);
7475    XtGetValues (file_mgr_rec->file_window, args, 3);
7476 #else
7477    XtGetValues (file_mgr_rec->file_window, args, 2);
7478 #endif
7479    XtSetArg (args[0], XmNtopShadowColor, &layout_data->pixmap_back);
7480    XtSetArg (args[1], XmNbottomShadowColor, &layout_data->pixmap_fore);
7481    XtGetValues (file_mgr_rec->main, args, 2);
7482
7483    /*
7484     * Create/update icon gadget for ".".
7485     * This gadget may not actually be displayed (depends of filter settings;
7486     * by default it is filtered out), but we need at least one gadget
7487     * created here so we can figure out fonts and margins used by icon
7488     * gadgets.  This is necessary to compute the grid spacing.
7489     */
7490    for (i = 0; i < order_count; i++)
7491       if (strcmp(order_list[i]->file_data->file_name, ".") == 0)
7492       {
7493          UpdateOneFileIcon(file_mgr_rec, file_mgr_data, order_list[i]);
7494          order_list[i]->need_update = True;
7495          break;
7496       }
7497
7498    /* Find the icon with the longest label */
7499    max_len = 0;
7500    file_view_data = NULL;
7501    for (i = 0; i < order_count; i++)
7502    {
7503       if (!order_list[i]->filtered &&
7504           (len = strlen(order_list[i]->label)) > max_len)
7505       {
7506          file_view_data = order_list[i];
7507          max_len = len;
7508       }
7509    }
7510
7511    /* get the size of the icon with the longest label */
7512    GetIconLayoutParms(file_mgr_rec, file_mgr_data, layout_data);
7513    EstimateIconSize(file_mgr_rec, file_mgr_data, layout_data, file_view_data,
7514                     &grid_width, &grid_height);
7515
7516    /* for tree view add space for tree lines and buttons */
7517    max_level = 0;
7518    if (file_mgr_data->show_type == MULTIPLE_DIRECTORY)
7519    {
7520       for (i = 0; i < order_count; i++)
7521       {
7522          if (order_list[i]->displayed)
7523          {
7524             GetLevel(order_list[i], &level);
7525             if (level > max_level)
7526                max_level = level;
7527          }
7528       }
7529       grid_width += TreeWd(max_level, layout_data->treebtn_size);
7530    }
7531
7532    file_mgr_data->grid_height = grid_height;
7533    file_mgr_data->grid_width = grid_width;
7534
7535    /*
7536     * If positioning is enabled in this view, then we need to use the other
7537     * layout function, which is capable of handling overlapping icons and
7538     * stacking order.
7539     */
7540    if (PositioningEnabledInView(file_mgr_data))
7541    {
7542       if (file_mgr_data->object_positions)
7543       {
7544          LayoutDesktopIcons(file_mgr_rec, file_mgr_data,
7545                             order_list, order_count, turn_off_hourglass);
7546          /* RepairFileWindow(file_mgr_data); *OBSOLETE* */
7547          goto layout_done;
7548       }
7549    }
7550
7551    /*
7552     * Position and size the icons according to the show and view types.
7553     */
7554
7555    scrolled_window_width = file_mgr_rec->scroll_window->core.width;
7556    scrolled_window_height = file_mgr_rec->scroll_window->core.height;
7557    vert_scrollbar_width = file_mgr_rec->vertical_scroll_bar->core.width;
7558    horiz_scrollbar_height = file_mgr_rec->horizontal_scroll_bar->core.height;
7559
7560    if (file_mgr_data->show_type == MULTIPLE_DIRECTORY)
7561    {
7562      /* if not yet done, create tree button icons */
7563      if (TreeBtnWd[0] == 0)
7564        CreateTreeIcons(file_mgr_rec->file_window);
7565
7566      /* layout for tree mode */
7567      x = MARGIN;
7568      y = MARGIN;
7569      file_window_width = MARGIN + grid_width - TreeOffset + XSPACING;
7570
7571      for (k = 0; k < order_count; k++)
7572      {
7573        if (!order_list[k]->displayed)
7574          continue;
7575
7576        /* make sure window height won't exceed limit */
7577        extra_height = GetExtraHeight(file_mgr_data, order_list[k],
7578                                      layout_data->treebtn_size);
7579        tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
7580        if (tmp + MARGIN > MAXWINSIZE)
7581        {
7582          /* window would exceed height limit; start a new column */
7583          x += grid_width + XSPACING;
7584          y = MARGIN;
7585          file_window_width += grid_width + XSPACING;
7586          tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
7587          overflow = True;
7588        }
7589
7590        order_list[k]->x = x;
7591        order_list[k]->y = y + grid_height;
7592
7593        /* update y */
7594        y = (Position)tmp;
7595      }
7596
7597      if (overflow)
7598        file_window_height = MAXWINSIZE;
7599      else
7600        file_window_height = y + MARGIN;
7601    }
7602    else if (file_mgr_data->view == BY_ATTRIBUTES)
7603    {
7604       /* layout for details view, no tree mode */
7605       x = MARGIN;
7606       y = MARGIN;
7607       file_window_width = 2*MARGIN + grid_width;
7608
7609       for (k = 0; k < order_count; k++)
7610       {
7611          if (!order_list[k]->displayed)
7612             continue;
7613
7614          /* make sure window height won't exceed limit */
7615          tmp = (int)y + grid_height + YSPACING(file_mgr_data);
7616          if (tmp + MARGIN > MAXWINSIZE)
7617          {
7618             /* window would exceed height limit; start a new column */
7619             x += grid_width + XSPACING;
7620             y = MARGIN;
7621             file_window_width += grid_width + XSPACING;
7622             tmp = (int)y + grid_height + YSPACING(file_mgr_data);
7623             overflow = True;
7624          }
7625
7626          order_list[k]->x = x;
7627          order_list[k]->y = y + grid_height;
7628
7629          /* update y */
7630          y = (Position)tmp;
7631       }
7632
7633       if (overflow)
7634          file_window_height = MAXWINSIZE;
7635       else
7636          file_window_height = y + MARGIN;
7637    }
7638    else  /* show_type == SINGLE_DIRECTORY, view != BY_ATTRIBUTES */
7639    {
7640       /* layout for "normal" views (no tree mode, no details) */
7641
7642       /* calculate how many columns fit in the window width */
7643      column_count = ((int)scrolled_window_width - 4 - 2*MARGIN + XSPACING) /
7644        ((int)grid_width + XSPACING);
7645      if (column_count == 0)
7646        column_count = 1;  /* need at least one column */
7647
7648       /*
7649        * Calculate the window height.  Need to do calculation in int's
7650        * rather than short (Dimension) because of possible overflow.
7651        */
7652      row_count = (total_icon_count + column_count - 1) / column_count;
7653      tmp = 2*MARGIN - YSPACING(file_mgr_data) +
7654        row_count * ((int)grid_height + YSPACING(file_mgr_data));
7655
7656      /* check if the height is larger than the scrolled window */
7657      if (tmp >= (int)scrolled_window_height - 2*MARGIN)
7658      {
7659        /* need to recompute everything because of space for vert scrollbar */
7660        column_count = ((int)scrolled_window_width - 4 - 2*MARGIN + XSPACING
7661                        - (int)vert_scrollbar_width)
7662          / ((int)grid_width + XSPACING);
7663        if (column_count == 0)
7664          column_count = 1;
7665        row_count = (total_icon_count + column_count - 1) / column_count;
7666        tmp = 2*MARGIN - YSPACING(file_mgr_data) +
7667          row_count * ((int)grid_height + YSPACING(file_mgr_data));
7668      }
7669
7670      /* check if the window height is within the limit */
7671      if (tmp <= MAXWINSIZE)
7672        file_window_height = (Dimension)tmp;
7673      else
7674      {
7675        /* window height too large; use more columns */
7676        overflow = True;
7677        row_count = (int)(MAXWINSIZE - 2*MARGIN + YSPACING(file_mgr_data)) /
7678          (int)((int)grid_height + YSPACING(file_mgr_data));
7679        column_count = (total_icon_count  + row_count - 1) / row_count;
7680        row_count = (total_icon_count + column_count - 1) / column_count;
7681        file_window_height = (Dimension) (2*MARGIN - YSPACING(file_mgr_data) +
7682                                          row_count * ((int)grid_height + YSPACING(file_mgr_data)));
7683      }
7684
7685      DPRINTF(("  %d columns, %d rows (scroll_window width %d)\n",
7686               column_count, row_count,
7687               scrolled_window_width));
7688
7689      /* assign positions to all icons */
7690      y = MARGIN;
7691      file_window_width = (Dimension)
7692        (2*MARGIN - XSPACING + column_count*((int)grid_width + XSPACING));
7693
7694      k = 0;
7695      for (i = 0; i < row_count; i++)
7696      {
7697        x = MARGIN;
7698
7699        for (j = 0; j < column_count && k < order_count;)
7700        {
7701          /* find the next icon to display */
7702          while (k < order_count && !order_list[k]->displayed)
7703            k++;
7704          if (k == order_count)
7705            break;
7706
7707          if (layout_data->alignment == XmALIGNMENT_CENTER &&
7708              file_mgr_data->view == BY_NAME_AND_ICON)
7709          {
7710            EstimateIconSize(file_mgr_rec, file_mgr_data, layout_data,
7711                             order_list[k], &icon_width, &icon_height);
7712            order_list[k]->x = x +
7713              (Dimension)(grid_width - icon_width)/(Dimension)2;
7714          }
7715          else
7716            order_list[k]->x = x;
7717          order_list[k]->y = y + grid_height;
7718
7719          x += grid_width + XSPACING;
7720          j++;
7721          k++;
7722        }
7723
7724        y += grid_height + YSPACING(file_mgr_data);
7725      }
7726    }
7727
7728    DPRINTF(("  file_window size: width %d, height %d\n",
7729             file_window_width, file_window_height));
7730
7731    /*  Manage/unmanage the scrollbars as needed.  */
7732
7733    XtSetArg (args[0], XmNwidth, file_window_width);
7734    XtSetArg (args[1], XmNheight, file_window_height);
7735    XtSetValues ((Widget)file_window, args, 2);
7736
7737    XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmAS_NEEDED);
7738    XtSetValues (file_mgr_rec->scroll_window, args, 1);
7739
7740
7741    /*  Unmanage the horizontal scrollbar if it is not needed   */
7742    if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
7743                                   file_mgr_rec->scroll_window))
7744    {
7745       if (file_window_width >= (Dimension)(scrolled_window_width - 4 -
7746                                                          vert_scrollbar_width))
7747          XtManageChild (file_mgr_rec->horizontal_scroll_bar);
7748       else
7749       {
7750          XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
7751          XtSetArg (args[0], XmNx, 0);
7752          XtSetValues ((Widget)file_window, args, 1);
7753       }
7754    }
7755    else if (file_window_width >= (Dimension)(scrolled_window_width - 4))
7756       XtManageChild (file_mgr_rec->horizontal_scroll_bar);
7757    else
7758    {
7759       XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
7760       XtSetArg (args[0], XmNx, 0);
7761       XtSetValues ((Widget)file_window, args, 1);
7762    }
7763
7764    XSync (XtDisplay (file_window), False);
7765
7766    /*  Set the file window width and height to be at least  */
7767    /*  the size of the scrolled window.                     */
7768
7769    if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
7770                                   file_mgr_rec->scroll_window))
7771    {
7772       if(file_window_width <= (Dimension)(scrolled_window_width -
7773                            (vert_scrollbar_width + 4)))
7774
7775          file_window_width = scrolled_window_width -
7776                            (vert_scrollbar_width + 4);
7777    }
7778    else
7779    {
7780       if(file_window_width < (Dimension)(scrolled_window_width - 4))
7781          file_window_width = scrolled_window_width - 4;
7782    }
7783
7784    if (HorizontalScrollbarIsVisible(file_mgr_rec->horizontal_scroll_bar,
7785                                     file_mgr_rec->scroll_window))
7786    {
7787       int pad;
7788
7789       XtSetArg (args[0], XmNhighlightThickness, &sb_highlight_thickness);
7790       XtGetValues ((Widget)file_mgr_rec->horizontal_scroll_bar, args, 1);
7791
7792       XtSetArg (args[0], XmNshadowThickness, &sw_shadow_thickness);
7793       XtSetArg (args[1], XmNspacing, &space);
7794       XtGetValues ((Widget)file_mgr_rec->scroll_window, args, 2);
7795
7796       pad = (int)(((sb_highlight_thickness + sw_shadow_thickness) * 2) + space);
7797
7798       if(file_window_height < (Dimension)(scrolled_window_height -
7799                         (horiz_scrollbar_height + pad)))
7800          file_window_height = scrolled_window_height -
7801                         (horiz_scrollbar_height + pad);
7802    }
7803    else
7804    {
7805       if (file_window_height < (Dimension)(scrolled_window_height - 4))
7806          file_window_height = scrolled_window_height - 4;
7807    }
7808
7809
7810    XtSetArg (args[0], XmNwidth, file_window_width);
7811    XtSetArg (args[1], XmNheight, file_window_height);
7812    XtSetValues ((Widget)file_window, args, 2);
7813
7814    if( file_mgr_data->scrollToThisFile == NULL )
7815    {
7816      if (update_scrolling_position)
7817      {
7818        XtSetArg (args[0], XmNx, 0);
7819        XtSetArg (args[1], XmNy, 0);
7820        XtSetValues ((Widget)file_window, args, 2);
7821      }
7822
7823      /*  Set the vertical scrollbar's increment to icon height  */
7824      XtSetArg (args[0], XmNincrement, grid_height + YSPACING(file_mgr_data));
7825      XtSetArg (args[1], XmNuserData, grid_height + YSPACING(file_mgr_data));
7826      XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 2);
7827    }
7828
7829    if (PositioningEnabledInView(file_mgr_data))
7830    {
7831      BuildObjectPositions(file_mgr_data);
7832      /* RepairFileWindow(file_mgr_data); *OBSOLETE* */
7833    }
7834
7835    /*
7836     * Don't keep up the hourglass; this helps the user to get the impression
7837     * that all of the work is done.
7838     */
7839    if (turn_off_hourglass && !overflow)
7840       _DtTurnOffHourGlass(file_mgr_rec->shell);
7841
7842
7843 layout_done:
7844
7845
7846    /*
7847     * Start up a work proc that will update the display.
7848     */
7849    layout_data->visible_done = False;
7850    layout_data->all_done = False;
7851    if (layout_data->work_id == NULL)
7852    {
7853       XtAppContext app_context =
7854         XtWidgetToApplicationContext(file_mgr_rec->shell);
7855
7856       DPRINTF(("LayoutFileIcons: starting workproc\n"));
7857       layout_data->drop_site_w = (Widget)file_mgr_rec->shell;
7858       XmDropSiteStartUpdate(layout_data->drop_site_w);
7859
7860       layout_data->work_id =
7861         XtAppAddWorkProc(app_context, DisplayWorkProc, file_mgr_rec);
7862    }
7863
7864
7865    if( file_mgr_data->scrollToThisFile )
7866    {
7867      int i;
7868      DirectorySet * directory_set = NULL;
7869
7870      file_view_data = NULL;
7871
7872      for( i = 0; i < file_mgr_data->directory_count; ++i)
7873      {
7874        if( strcmp( ((DirectorySet *)file_mgr_data->directory_set[i])->name, file_mgr_data->scrollToThisDirectory ) == 0 )
7875        {
7876          directory_set = (DirectorySet *)file_mgr_data->directory_set[i];
7877          break;
7878        }
7879      }
7880
7881      if( directory_set )
7882      {
7883        for( i = 0; i < directory_set->file_count; ++i )
7884        {
7885          if( strcmp( directory_set->order_list[i]->file_data->file_name,
7886                      file_mgr_data->scrollToThisFile ) == 0 )
7887          {
7888            file_view_data = directory_set->order_list[i];
7889            break;
7890          }
7891        }
7892      }
7893
7894      if( file_view_data
7895          && file_view_data->filtered == False )
7896      {
7897        FileMgrRec * file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
7898
7899        DeselectAllFiles( file_mgr_data );
7900        SelectFile( file_mgr_data, file_view_data );
7901        ActivateSingleSelect( file_mgr_rec,
7902              file_mgr_data->selection_list[0]->file_data->logical_type );
7903
7904        PositionFileView(file_view_data, file_mgr_data);
7905      }
7906      else
7907      {
7908        if (update_scrolling_position)
7909        {
7910          XtSetArg (args[0], XmNx, 0);
7911          XtSetArg (args[1], XmNy, 0);
7912          XtSetValues ((Widget)file_window, args, 2);
7913        }
7914
7915        /* Set the vertical scrollbar's increment to icon height  */
7916        XtSetArg (args[0], XmNincrement, grid_height + YSPACING(file_mgr_data));
7917        XtSetArg (args[1], XmNuserData, grid_height + YSPACING(file_mgr_data));
7918        XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 2);
7919      }
7920
7921      XtFree( file_mgr_data->scrollToThisFile );
7922      file_mgr_data->scrollToThisFile = NULL;
7923      XtFree( file_mgr_data->scrollToThisDirectory );
7924      file_mgr_data->scrollToThisDirectory = NULL;
7925    }
7926
7927 #ifdef DT_PERFORMANCE
7928    gettimeofday(&update_time_f, NULL);
7929    if (update_time_s.tv_usec > update_time_f.tv_usec) {
7930       update_time_f.tv_usec += 1000000;
7931       update_time_f.tv_sec--;
7932    }
7933    printf("    done LayoutFileIcons, time: %ld.%ld\n\n",
7934           update_time_f.tv_sec - update_time_s.tv_sec,
7935           update_time_f.tv_usec - update_time_s.tv_usec);
7936
7937    /* the following message send call added by Rafi */
7938    _DtPerfChkpntMsgSend("Done LayoutFileIcons");
7939 #endif
7940
7941    DPRINTF(("... done\n"));
7942 }
7943
7944
7945
7946 /************************************************************************
7947  *
7948  *  TreeBtnCallback
7949  *      Callback function invoked upon clicking the tree-branch-expand button.
7950  *
7951  ************************************************************************/
7952
7953 static void
7954 TreeBtnCallback(
7955         Widget w,
7956         XtPointer clientData,
7957         XmAnyCallbackStruct *callData )
7958 {
7959   FileMgrRec *file_mgr_rec;
7960   FileMgrData *file_mgr_data;
7961   FileViewData *file_view_data = (FileViewData *)clientData;
7962   Arg args[20];
7963   Bool expand;
7964
7965   /* check which mouse button was pressed */
7966   if ((callData->event->type == ButtonPress ||
7967        callData->event->type == ButtonRelease) &&
7968       ((XButtonEvent *)callData->event)->button != Button1)
7969   {
7970     return;
7971   }
7972   expand = True;
7973
7974   /* get file mgr data and record */
7975   XtSetArg (args[0], XmNuserData, &file_mgr_data);
7976   XtGetValues (w, args, 1);
7977   file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
7978
7979   XmDropSiteStartUpdate(file_mgr_rec->file_window);
7980   CommitWorkProcUpdates(file_mgr_rec, file_mgr_data, True);
7981   DirTreeExpand(file_mgr_data, file_view_data, expand);
7982   DrawCurrentDirectory (file_mgr_rec->current_directory,
7983                         file_mgr_rec, file_mgr_data);
7984   LayoutFileIcons(file_mgr_rec, file_mgr_data, False, True);
7985   XmDropSiteEndUpdate(file_mgr_rec->file_window);
7986   RedrawTreeLines(file_mgr_rec->file_window,
7987                   -file_mgr_rec->file_window->core.x,
7988                   -file_mgr_rec->file_window->core.y,
7989                   XtParent(file_mgr_rec->file_window)->core.width,
7990                   XtParent(file_mgr_rec->file_window)->core.height,
7991                   0, file_mgr_rec, file_mgr_data);
7992 }
7993
7994
7995 /*
7996  * When a drop occurs on a File Manger window, which now
7997  * support random placement, what is dropped may not ultimately be what
7998  * is displayed.  Since the dissolve transition effect has been disabled
7999  * for drops on the desktop, we can sometimes end up with garbage left on
8000  * the desktop.  This function will attempt to clear up the leftover garbage,
8001  * by resetting all areas of the desktop which are not covered by an icon
8002  * to the background color for the file window.
8003  *
8004  * This function is OBSOLETE (?).
8005  */
8006
8007 void
8008 RepairFileWindow (
8009    FileMgrData * file_mgr_data)
8010
8011 {
8012    FileMgrRec * file_mgr_rec;
8013    Region clipList;
8014    Region hotspot;
8015    Region redrawRegion;
8016    int i;
8017    XRectangle rect;
8018    int num_children;
8019    Widget * children;
8020    XmManagerWidget file_window;
8021    GC gc;
8022    unsigned long mask;
8023    XGCValues values;
8024
8025    file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
8026    file_window = (XmManagerWidget)file_mgr_rec->file_window;
8027
8028    /* Initialize the clip region to that of the file window */
8029    rect.x = 0;
8030    rect.y = 0;
8031    rect.height = file_window->core.height;
8032    rect.width = file_window->core.width;
8033    clipList = XCreateRegion();
8034    XUnionRectWithRegion(&rect, clipList, clipList);
8035
8036    /* Subtract out the hotspots associated with each icon */
8037    num_children = file_window->composite.num_children;
8038    children = file_window->composite.children;
8039    hotspot = XCreateRegion();
8040
8041    for (i = 0; i < num_children; i++)
8042    {
8043       if (XtIsManaged(children[i]) &&
8044           XtIsSubclass(children[i], dtIconGadgetClass))
8045       {
8046          WidgetRectToRegion(file_mgr_data, children[i], hotspot);
8047          XSubtractRegion(clipList, hotspot, clipList);
8048       }
8049    }
8050
8051    /* Create a GC for doing our drawing */
8052    mask = GCForeground;
8053    values.foreground = file_window->core.background_pixel;
8054    gc = XCreateGC(XtDisplay(file_window), XtWindow(file_window), mask, &values);
8055    XSetRegion(XtDisplay(file_window), gc, clipList);
8056
8057    /* Restore the window */
8058    XFillRectangle(XtDisplay(file_window), XtWindow(file_window), gc, 0, 0,
8059                   file_window->core.width, file_window->core.height);
8060
8061    /*
8062     * Force all icons to redraw, since we are only able to repair the
8063     * areas where icons are not; the drop image may have extended onto
8064     * some of the icons.
8065     */
8066    rect.x = 0;
8067    rect.y = 0;
8068    rect.height = file_window->core.height;
8069    rect.width = file_window->core.width;
8070    redrawRegion = XCreateRegion();
8071    XUnionRectWithRegion(&rect, redrawRegion, redrawRegion);
8072    (*file_window->core.widget_class->core_class.expose)
8073              ((Widget)file_window, NULL, redrawRegion);
8074
8075    /* Clean up */
8076    XFreeGC(XtDisplay(file_window), gc);
8077    XDestroyRegion(clipList);
8078    XDestroyRegion(hotspot);
8079    XDestroyRegion(redrawRegion);
8080 }
8081
8082
8083
8084
8085 /*
8086  * Compress the stacking order values, anytime an item is removed.
8087  */
8088
8089 static void
8090 CompressObjectList (
8091    ObjectPosition ** object_positions,
8092    int num_objects,
8093    int starting_index)
8094 {
8095    int i;
8096
8097    for (i = 0; i < num_objects; i++)
8098    {
8099       if (object_positions[i]->stacking_order > starting_index)
8100          object_positions[i]->stacking_order--;
8101    }
8102 }
8103
8104
8105
8106 /************************************************************************
8107  *
8108  *  LayoutDesktopIcons
8109  *      Position and size the full set of icons for the file mgr data.
8110  *
8111  ************************************************************************/
8112
8113 static void
8114 LayoutDesktopIcons (
8115      FileMgrRec  * file_mgr_rec,
8116      FileMgrData * file_mgr_data,
8117      FileViewData ** order_list,
8118      int order_count,
8119      Boolean turn_off_hourglass )
8120
8121 {
8122    XmManagerWidget file_window;
8123    int directory_count, largest_x, largest_y;
8124    int value, size, increment, page;
8125    Dimension current_wd;
8126    Dimension current_ht;
8127    Dimension file_window_width;
8128    Dimension grid_height;
8129    Dimension grid_width;
8130    FileViewData * object;
8131    ObjectPosition * position_data;
8132    ObjectPosition * bottom;
8133    ObjectPtr top;
8134    int i, j, k;
8135    Boolean set_size = False;
8136    char * edit_name;
8137    Arg args[2];
8138    int sorder;
8139
8140
8141    /*  Get the grid block size */
8142    file_window = (XmManagerWidget) file_mgr_rec->file_window;
8143    grid_height = file_mgr_data->grid_height;
8144    grid_width = file_mgr_data->grid_width;
8145
8146    file_window_width = file_mgr_rec->scroll_window->core.width - 4;
8147    current_ht = file_mgr_rec->file_window->core.height;
8148    current_wd = file_mgr_rec->file_window->core.width;
8149
8150
8151    /* Before positioning, mark all position entries as 'not used' */
8152    for (i = 0; i < file_mgr_data->num_objects; i++)
8153    {
8154       file_mgr_data->object_positions[i]->in_use = False;
8155       file_mgr_data->object_positions[i]->file_view_data = NULL;
8156    }
8157
8158    /*
8159     * Before attempting to place new icons, we need to make sure that
8160     * all of the existing object_positions entries have had their
8161     * file_view_data field filled in.  This is so that during placement,
8162     * we can get the height and width of the associated icons, to help
8163     * prevent overlap.
8164     */
8165    for (i = 0; i < order_count; i++)
8166    {
8167       object = order_list[i];
8168       if (object->displayed)
8169       {
8170          if (position_data = GetPositionalData(file_mgr_data, object, 0, False))
8171          {
8172             /* Save; used later during redraw */
8173             position_data->file_view_data = object;
8174             object->position_info = (ObjectPtr)position_data;
8175          }
8176       }
8177       else if (position_data = GetPositionalData(file_mgr_data, object, 0,
8178                                                  False))
8179       {
8180          /*
8181           * If an object has position information, but is currently
8182           * filtered, don't discard its position info; mark it as in-use.
8183           */
8184          position_data->file_view_data = object;
8185          object->position_info = (ObjectPtr)position_data;
8186       }
8187    }
8188
8189    /* Remove any unused position data entries */
8190    for (i = 0; i < file_mgr_data->num_objects; )
8191    {
8192       if (!file_mgr_data->object_positions[i]->in_use)
8193       {
8194          /* If this object had a text field, delete it */
8195          for (k = 0; k < file_window->composite.num_children; k++)
8196          {
8197             if (XmIsTextField(file_window->composite.children[k]) &&
8198                 !file_window->composite.children[k]->core.being_destroyed)
8199             {
8200                XtSetArg(args[0], XmNuserData, &edit_name);
8201                XtGetValues(file_window->composite.children[k], args, 1);
8202                if (strcmp(edit_name,file_mgr_data->object_positions[i]->name)
8203                         == 0)
8204                {
8205                   /* Match */
8206                   XtUnmanageChild(file_window->composite.children[k]);
8207                   XtDestroyWidget(file_window->composite.children[k]);
8208                   break;
8209                }
8210             }
8211          }
8212
8213          /* Free up the entry; bump up the other array entries */
8214          /* Update the linked list */
8215          if (file_mgr_data->object_positions[i]->prev)
8216          {
8217             file_mgr_data->object_positions[i]->prev->next = (ObjectPtr)
8218                 file_mgr_data->object_positions[i]->next;
8219          }
8220          if (file_mgr_data->object_positions[i]->next)
8221          {
8222             file_mgr_data->object_positions[i]->next->prev = (ObjectPtr)
8223                 file_mgr_data->object_positions[i]->prev;
8224          }
8225          sorder = file_mgr_data->object_positions[i]->stacking_order;
8226          XtFree(file_mgr_data->object_positions[i]->name);
8227          file_mgr_data->object_positions[i]->name = NULL;
8228          XtFree((char *)file_mgr_data->object_positions[i]);
8229          file_mgr_data->object_positions[i] = NULL;
8230          for (j = i; j < file_mgr_data->num_objects - 1; j++)
8231          {
8232             file_mgr_data->object_positions[j] =
8233                                    file_mgr_data->object_positions[j+1];
8234          }
8235          file_mgr_data->num_objects--;
8236          file_mgr_data->object_positions = (ObjectPosition **) XtRealloc(
8237                (char *)file_mgr_data->object_positions,
8238                sizeof(ObjectPosition *) * file_mgr_data->num_objects);
8239          CompressObjectList(file_mgr_data->object_positions,
8240                             file_mgr_data->num_objects, sorder);
8241       }
8242       else
8243          i++;
8244    }
8245
8246    /* Now, it is safe to position any unplaced objects */
8247    for (i = 0; i < order_count; i++)
8248    {
8249       object = order_list[i];
8250       if (object->displayed)
8251       {
8252          position_data = GetPositionalData(file_mgr_data, object,
8253                                            file_window_width, True);
8254
8255          /* Save; used later during redraw */
8256          position_data->file_view_data = object;
8257          object->position_info = (ObjectPtr)position_data;
8258
8259          /* record position of bottom left corner for DisplaySomeIcons */
8260          object->x = position_data->x;
8261          object->y = position_data->y +
8262                (object->need_update? grid_height: object->widget->core.height);
8263       }
8264    }
8265
8266    /* Get largest x value */
8267    largest_x = 0;
8268    largest_y = 0;
8269    bottom = GetBottomOfStack(file_mgr_data);
8270    while (bottom)
8271    {
8272       if (bottom->file_view_data != NULL && bottom->file_view_data->displayed)
8273       {
8274          if (bottom->file_view_data->position_info->x > largest_x)
8275             largest_x = bottom->file_view_data->position_info->x;
8276          if (bottom->file_view_data->position_info->y > largest_y)
8277             largest_y = bottom->file_view_data->position_info->y;
8278       }
8279       bottom = (ObjectPosition *)bottom->prev;
8280    }
8281    largest_x += grid_width;
8282    largest_y += grid_height;
8283
8284    /* if necessary, shrink the width & height to what we need */
8285    if (current_wd == 32767)
8286    {
8287       current_wd = largest_x;
8288       set_size = True;
8289    }
8290
8291    if (current_ht == 32767)
8292    {
8293       current_ht = largest_y;
8294       set_size = True;
8295    }
8296
8297    /*  Get the horizontal and vertical scrollbars.  */
8298    XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmAS_NEEDED);
8299    XtSetValues (file_mgr_rec->scroll_window, args, 1);
8300
8301    /*
8302     * Typically, dtfile does everything possible to prevent a horizontal
8303     * scrollbar from being displayed.  However, when random placement is
8304     * enabled, we don't mind having a horizontal scrollbar, when needed.
8305     * We need to manually manage this, since the normal dtfile layout
8306     * code may have forcably unmanaged the scrollbar earlier.
8307     */
8308    if (XtIsManaged(file_mgr_rec->horizontal_scroll_bar))
8309    {
8310       /* get scroll bar values */
8311       (void)XmScrollBarGetValues(file_mgr_rec->horizontal_scroll_bar,
8312                                  &value, &size, &increment, &page);
8313    }
8314
8315    if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
8316                                   file_mgr_rec->scroll_window))
8317    {
8318       if ((Dimension)largest_x >= (Dimension)(file_mgr_rec->scroll_window->core.width -
8319                           (file_mgr_rec->vertical_scroll_bar->core.width + 4)))
8320       {
8321          XtManageChild(file_mgr_rec->horizontal_scroll_bar);
8322       }
8323       else
8324       {
8325          /* set scroll bar values changing its position */
8326          if(value != 0 && XtIsManaged(file_mgr_rec->horizontal_scroll_bar))
8327             XtManageChild(file_mgr_rec->horizontal_scroll_bar);
8328          else
8329          {
8330             XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
8331             XtSetArg (args[0], XmNx, 0);
8332             XtSetValues ((Widget)file_window, args, 1);
8333          }
8334       }
8335    }
8336    else if ((Dimension)largest_x >= (Dimension)(file_mgr_rec->scroll_window->core.width - 4))
8337       XtManageChild(file_mgr_rec->horizontal_scroll_bar);
8338    else
8339    {
8340       /* set scroll bar values changing its position */
8341       if(value != 0 && XtIsManaged(file_mgr_rec->horizontal_scroll_bar))
8342          XtManageChild(file_mgr_rec->horizontal_scroll_bar);
8343       else
8344       {
8345          XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
8346          XtSetArg (args[0], XmNx, 0);
8347          XtSetValues ((Widget)file_window, args, 1);
8348       }
8349    }
8350
8351    /*  Set the file window width and height to be at least  */
8352    /*  the size of the scrolled window.                     */
8353    if ((Dimension)(current_wd) < (Dimension)(file_mgr_rec->scroll_window->core.width - 4))
8354    {
8355       if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
8356                                      file_mgr_rec->scroll_window))
8357          current_wd = file_mgr_rec->scroll_window->core.width -
8358                            (file_mgr_rec->vertical_scroll_bar->core.width + 4);
8359       else
8360          current_wd = file_mgr_rec->scroll_window->core.width - 4;
8361       set_size = True;
8362    }
8363
8364    if ((Dimension)(current_ht) < (Dimension)(file_mgr_rec->scroll_window->core.height - 4))
8365    {
8366       current_ht = file_mgr_rec->scroll_window->core.height - 4;
8367       set_size = True;
8368    }
8369
8370    if (set_size)
8371    {
8372       XtSetArg (args[0], XmNwidth, current_wd);
8373       XtSetArg (args[1], XmNheight, current_ht);
8374       XtSetValues (file_mgr_rec->file_window, args, 2);
8375    }
8376
8377    /*  Set the vertical scrollbar's increment to icon height  */
8378    XtSetArg (args[0], XmNincrement, file_mgr_data->grid_height + 2);
8379    XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 1);
8380
8381    /*
8382     * Don't keep up the hourglass; this helps the user to get the impression
8383     * that all of the work is done.
8384     */
8385    if (turn_off_hourglass)
8386       _DtTurnOffHourGlass(file_mgr_rec->shell);
8387 }
8388
8389
8390 /***************************************************
8391  *
8392  * Given a desktop object, see if it has already been assigned a position;
8393  * if not, then try to fit it into the next available grid position.
8394  *
8395  **************************************************/
8396
8397 static Boolean
8398 IntersectRects(
8399         Position x1,
8400         Position y1,
8401         Dimension w1,
8402         Dimension h1,
8403         Position x2,
8404         Position y2,
8405         Dimension w2,
8406         Dimension h2 )
8407
8408 {
8409    int srcABot, srcBBot;
8410    int srcARight, srcBRight;
8411    int dw, dh;
8412    int dx, dy;
8413
8414    srcABot = y1 + h1 - 1;
8415    srcBBot = y2 + h2 - 1;
8416    srcARight = x1 + w1 - 1;
8417    srcBRight = x2 + w2 - 1;
8418
8419    if (x1 >= x2)
8420       dx = x1;
8421    else
8422       dx = x2;
8423
8424    if (y1 > y2)
8425       dy = y1;
8426    else
8427       dy = y2;
8428
8429    if (srcARight >= srcBRight)
8430       dw = srcBRight - dx + 1;
8431    else
8432       dw = srcARight - dx + 1;
8433
8434    if (srcABot > srcBBot)
8435       dh = srcBBot - dy + 1;
8436    else
8437       dh = srcABot - dy + 1;
8438
8439    if (dw <= 0 || dh <= 0)
8440       return(FALSE);
8441
8442    return(TRUE);
8443 }
8444
8445 static ObjectPosition *
8446 GetPositionalData (
8447    FileMgrData * file_mgr_data,
8448    FileViewData * object,
8449    Dimension max_width,
8450    Boolean create)
8451 {
8452    int i;
8453    int k;
8454    ObjectPosition *entry, *top;
8455    Position x;
8456    Position y;
8457    Dimension grid_height;
8458    Dimension grid_width;
8459    Boolean hit;
8460    ObjectPosition * oP;
8461    Dimension objWidth, objHeight;
8462    Dimension oWidth, oHeight;
8463
8464    /* If object already has positional data, then use it */
8465    for (i = 0; i < file_mgr_data->num_objects; i++)
8466    {
8467       if (strcmp(object->file_data->file_name,
8468                  file_mgr_data->object_positions[i]->name) == 0)
8469       {
8470          /* Found a match */
8471          file_mgr_data->object_positions[i]->in_use = True;
8472          return(file_mgr_data->object_positions[i]);
8473       }
8474    }
8475
8476    if (!create)
8477       return(NULL);
8478
8479    /* Create a new entry, and place into the grid on the top of the stack */
8480    entry = (ObjectPosition *) XtMalloc(sizeof(ObjectPosition));
8481    entry->name = XtNewString(object->file_data->file_name);
8482    entry->in_use = True;
8483    entry->late_bind = False;
8484    entry->stacking_order = 2;
8485    entry->prev = NULL;
8486    entry->next = NULL;
8487    entry->file_view_data = NULL;
8488
8489    if(file_mgr_data->num_objects == 1)
8490    {
8491       top = file_mgr_data->object_positions[0];
8492       top->next = (ObjectPtr)entry;
8493       entry->prev = (ObjectPtr)top;
8494    }
8495    else
8496    {
8497       top = NULL;
8498       /* Push all other objects down in the stack */
8499       for (i = 0; i < file_mgr_data->num_objects; i++)
8500       {
8501          /* Find the previous top of the stack */
8502          if (file_mgr_data->object_positions[i]->stacking_order == 1)
8503          {
8504             top = file_mgr_data->object_positions[i];
8505             continue;
8506          }
8507          else if (file_mgr_data->object_positions[i]->stacking_order == 2)
8508          {
8509             if(top == NULL)
8510                top = GetTopOfStack(file_mgr_data);
8511             top->next = (ObjectPtr)entry;
8512             entry->next = (ObjectPtr)file_mgr_data->object_positions[i];
8513             entry->prev = (ObjectPtr)top;
8514             file_mgr_data->object_positions[i]->prev = (ObjectPtr)entry;
8515          }
8516          file_mgr_data->object_positions[i]->stacking_order++;
8517       }
8518    }
8519
8520    grid_height = file_mgr_data->grid_height;
8521    grid_width = file_mgr_data->grid_width;
8522    x = MARGIN;
8523    y = MARGIN;
8524
8525    if (object->widget && !object->need_update)
8526    {
8527       objWidth = object->widget->core.width;
8528       objHeight = object->widget->core.height;
8529    }
8530    else
8531    {
8532       objWidth = grid_width;
8533       objHeight = grid_height;
8534    }
8535
8536    /* Find the first open spot, which will not cause any overlap */
8537    do
8538    {
8539       hit = False;
8540
8541       for (i = 0; i < file_mgr_data->num_objects; i++)
8542       {
8543          oP = file_mgr_data->object_positions[i];
8544          if (oP->file_view_data->widget && !oP->file_view_data->need_update)
8545          {
8546             oWidth = oP->file_view_data->widget->core.width;
8547             oHeight = oP->file_view_data->widget->core.height;
8548          }
8549          else
8550          {
8551             oWidth = grid_width;
8552             oHeight = grid_height;
8553          }
8554          if (oP->file_view_data->displayed &&
8555              IntersectRects(x, y, objWidth, objHeight,
8556                             oP->x, oP->y, oWidth, oHeight))
8557          {
8558             /* Try next grid spot */
8559             x += grid_width + XSPACING;
8560
8561             if ((Dimension)(x + objWidth) >= max_width)
8562             {
8563                /* Go to next row */
8564                y += grid_height + YSPACING(file_mgr_data);
8565                x = MARGIN;
8566             }
8567             hit = True;
8568             break;
8569          }
8570       }
8571    } while (hit);
8572
8573    /* Add to the end of the list */
8574    entry->x = x;
8575    entry->y = y;
8576    file_mgr_data->num_objects++;
8577    file_mgr_data->object_positions = (ObjectPosition **) XtRealloc(
8578                    (char *)file_mgr_data->object_positions,
8579                    sizeof(ObjectPosition *) * file_mgr_data->num_objects);
8580
8581    /* Force the ordered list to be maintained */
8582    for (i = 0; i < file_mgr_data->num_objects - 1; i++)
8583    {
8584       if ((entry->y < file_mgr_data->object_positions[i]->y) ||
8585           ((entry->y == file_mgr_data->object_positions[i]->y) &&
8586            (entry->x < file_mgr_data->object_positions[i]->x)))
8587       {
8588          /* Fits here; slide later entries down */
8589          for (k = file_mgr_data->num_objects - 1; k > i; k--)
8590          {
8591             file_mgr_data->object_positions[k] =
8592                 file_mgr_data->object_positions[k-1];
8593          }
8594
8595          break;
8596       }
8597    }
8598
8599    file_mgr_data->object_positions[i] = entry;
8600    return(file_mgr_data->object_positions[i]);
8601 }
8602
8603
8604 /*******************************************************************
8605  *
8606  *  BuildObjectPositons - builds up the object positions for directories
8607  *    which have now object position information.
8608  *
8609  *********************************************************************/
8610 static void
8611 BuildObjectPositions(
8612    FileMgrData *file_mgr_data)
8613 {
8614    int i, j, k, l;
8615    FileViewData * file_view_data;
8616    ObjectPosition * ptr;
8617
8618    file_mgr_data->object_positions = (ObjectPosition **)XtMalloc(
8619                sizeof(ObjectPosition *) *
8620                file_mgr_data->directory_set[0]->file_count);
8621
8622    for (i = 0, j = 0; i < file_mgr_data->directory_set[0]->file_count; i++)
8623    {
8624       file_view_data = file_mgr_data->directory_set[0]->order_list[i];
8625
8626       if (file_view_data->filtered)
8627          continue;
8628
8629       ptr = (ObjectPosition *) XtMalloc(sizeof(ObjectPosition));
8630       ptr->name = XtNewString(file_view_data->file_data->file_name);
8631       ptr->x = file_view_data->x;
8632       ptr->y = file_view_data->y -
8633             (file_view_data->need_update? file_mgr_data->grid_height:
8634                                           file_view_data->widget->core.height);
8635       ptr->in_use = True;
8636       ptr->late_bind = False;
8637       ptr->stacking_order = j+1;
8638       ptr->file_view_data = file_view_data;
8639       file_view_data->position_info = (ObjectPtr)ptr;
8640       ptr->next = NULL;
8641       ptr->prev = NULL;
8642
8643       /* Sort according to left-to-right, top-to-bottom */
8644       for (k = 0; k < j; k++)
8645       {
8646          if ((ptr->y < file_mgr_data->object_positions[k]->y) ||
8647              ((ptr->y == file_mgr_data->object_positions[k]->y) &&
8648               (ptr->x < file_mgr_data->object_positions[k]->x)))
8649          {
8650             /* Shift others down, to open up a spot */
8651             for (l = j; l > k; l--)
8652             {
8653                file_mgr_data->object_positions[l] =
8654                      file_mgr_data->object_positions[l - 1];
8655             }
8656             break;
8657          }
8658       }
8659       file_mgr_data->object_positions[k] = ptr;
8660       j++;
8661    }
8662
8663    file_mgr_data->num_objects = j;
8664
8665    /* Repair all of the next and prev pointers */
8666    RepairStackingPointers(file_mgr_data);
8667    OrderChildrenList(file_mgr_data);
8668 }
8669
8670
8671 /***********************************
8672  *
8673  * When items are dragged around on a random placement window, they will be
8674  * repositioned at the point where they were dropped.  Multiple drop items
8675  * will be positioned 'around' where the drop occurred.
8676  *
8677  **********************************/
8678
8679 void
8680 RepositionIcons (
8681    FileMgrData * file_mgr_data,
8682    char ** file_list,
8683    int file_count,
8684    Position drop_x,
8685    Position drop_y,
8686    Boolean late_binding_needed)
8687
8688 {
8689    Position x;
8690    Position y;
8691    int i, i2, j, k, l;
8692    int adj;
8693    Position orig_x;
8694    Position orig_y;
8695    ObjectPosition * save_object;
8696    char * name;
8697    FileMgrRec * file_mgr_rec;
8698    XmManagerWidget file_window;
8699    Widget textWidget;
8700    char * edit_name;
8701    Arg args[10];
8702    Boolean newEntry;
8703    int newEntryCount = 0;
8704    char dot_dir[3] = ".";
8705    char dotdot_dir[3] = "..";
8706
8707    /* if random placement is not enabled, positioning doesn't matter */
8708    if(file_mgr_data->positionEnabled == RANDOM_OFF)
8709       return;
8710
8711    file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
8712
8713    /*
8714     * For directory views, no positional data may be present if positioning
8715     * was disabled for this view.  So ... we must create some now.
8716     */
8717    if ((file_mgr_data->num_objects == 0) &&
8718        (file_mgr_data->directory_set[0]->file_count > 0))
8719    {
8720          BuildObjectPositions(file_mgr_data);
8721    }
8722
8723    /*
8724     * Update to the new position.
8725     * The position needs to be adjusted so that the icon actually ends
8726     * up where the user dropped it.  This is because the drag icon includes
8727     * margins and shadow area, but not the highlight area of the icon gadget
8728     * that was dragged.  Coordinates drop_x, drop_y are the upper left corner
8729     * of the drag icon when it was dropped.  To convert to icon gadget
8730     * coordinates we need to subtract the highlight thickness.
8731     */
8732    if (file_mgr_data->layout_data != NULL)
8733      adj = ((IconLayoutData *)file_mgr_data->layout_data)->highlight;
8734    else
8735      adj = 0;
8736    x = drop_x - adj;
8737    y = drop_y - adj;
8738    file_window = (XmManagerWidget) file_mgr_rec->file_window;
8739
8740    /* Process each of the dropped files */
8741    /* Go from bottom to top, to retain stacking order */
8742    for (i = file_count - 1; i >= 0; i--)
8743    {
8744       textWidget = NULL;
8745
8746       /*
8747        * The names typically come in as complete paths; we only want
8748        * the filename portion.
8749        * fdt: this check will break for root (/)
8750        */
8751       if( strcmp(file_mgr_data->current_directory, file_list[i]) == 0)
8752          name = dot_dir;
8753       else if(strncmp(file_mgr_data->current_directory, file_list[i], strlen(file_list[i]) ) == 0 )
8754         name = dotdot_dir;
8755       else
8756       {
8757         if ((name = strrchr(file_list[i], '/')) == NULL)
8758           name = file_list[i];
8759         else
8760         {
8761           name++;
8762
8763          /* Try to gracefully handle root (/) */
8764           if (*name == '\0')
8765             name--;
8766         }
8767       }
8768
8769       newEntry = True;
8770
8771       /* Find the positional data for this object, if any */
8772       for (j = 0; j < file_mgr_data->num_objects; j++)
8773       {
8774          if (strcmp(name, file_mgr_data->object_positions[j]->name) == 0)
8775          {
8776             /* Find the associated widget */
8777             for (k = 0; strcmp(name,
8778              file_mgr_data->directory_set[0]->file_view_data[k]->file_data->                    file_name); k++);
8779
8780             newEntry = False;
8781
8782             /* If this object has a text field, then move it also */
8783             for (l = 0; l < file_window->composite.num_children; l++)
8784             {
8785                if (XmIsTextField(file_window->composite.children[l]) &&
8786                    !file_window->composite.children[l]->core.being_destroyed)
8787                {
8788                   XtSetArg(args[0], XmNuserData, &edit_name);
8789                   XtGetValues(file_window->composite.children[l], args, 1);
8790                   if (strcmp(edit_name, name) == 0)
8791                   {
8792                      textWidget = file_window->composite.children[l];
8793                      break;
8794                   }
8795                }
8796             }
8797             break;
8798          }
8799       }
8800
8801       if (newEntry)
8802       {
8803          ObjectPosition * data;
8804
8805          /* Create positional data at the top of the ordered array */
8806          newEntryCount++;
8807          j = 0;
8808          data = (ObjectPosition *) XtMalloc(sizeof(ObjectPosition));
8809          data->name = XtNewString(name);
8810          data->x = 0;
8811          data->y = 0;
8812          data->in_use = True;
8813          data->late_bind = True;
8814          data->stacking_order = 1;
8815          data->file_view_data = NULL;
8816          data->prev = NULL;
8817          data->next = NULL;
8818
8819          /* Push all other objects down in the stack */
8820          for (i2 = 0; i2 < file_mgr_data->num_objects; i2++)
8821          {
8822             /* Find the previous top of the stack */
8823             if (file_mgr_data->object_positions[i2]->stacking_order == 1)
8824             {
8825                data->next = (ObjectPtr)file_mgr_data->object_positions[i2];
8826                file_mgr_data->object_positions[i2]->prev = (ObjectPtr)data;
8827             }
8828             file_mgr_data->object_positions[i2]->stacking_order++;
8829          }
8830
8831          file_mgr_data->num_objects++;
8832          file_mgr_data->object_positions = (ObjectPosition **) XtRealloc(
8833                (char *)file_mgr_data->object_positions,
8834                sizeof(ObjectPosition *) * file_mgr_data->num_objects);
8835
8836          /* Add entry to the top of the ordered array */
8837          for (j = file_mgr_data->num_objects - 1; j > 0; j--)
8838          {
8839             file_mgr_data->object_positions[j] =
8840                     file_mgr_data->object_positions[j - 1];
8841          }
8842
8843          file_mgr_data->object_positions[0] = data;
8844       }
8845       else
8846       {
8847          /* Move item upto top of the stack */
8848          RepositionUpInStack(file_mgr_data,
8849                      file_mgr_data->object_positions[j]->stacking_order, 1);
8850       }
8851
8852       orig_x = file_mgr_data->object_positions[j]->x;
8853       orig_y = file_mgr_data->object_positions[j]->y;
8854       file_mgr_data->object_positions[j]->x = x;
8855       file_mgr_data->object_positions[j]->y = y;
8856       save_object = file_mgr_data->object_positions[j];
8857
8858       /* Move the object */
8859       if (!newEntry)
8860       {
8861          /* We need to force a geometry request */
8862          XtSetArg(args[0], XmNx, x);
8863          XtSetArg(args[1], XmNy, y);
8864          XtSetValues(file_mgr_data->directory_set[0]->file_view_data[k]->widget,
8865                      args, 2);
8866
8867          /* Move associated text widget, if there is one */
8868          if (textWidget)
8869          {
8870             Position t_x, t_y;
8871
8872             t_x = textWidget->core.x + x - orig_x;
8873             t_y = textWidget->core.y + y - orig_y;
8874
8875             /* We need to force a geometry request */
8876             XtSetArg(args[0], XmNx, t_x);
8877             XtSetArg(args[1], XmNy, t_y);
8878             XtSetValues(textWidget, args, 2);
8879          }
8880       }
8881
8882       /*
8883        * Reorder the positional array, so that it remains ordered.
8884        * Bubble down toward the end of the list if the object has moved
8885        * farther from the origin; bubble up if it has moved closer to
8886        * the origin.
8887        */
8888       if ((y > orig_y) || ((y == orig_y) && (x > orig_x)))
8889       {
8890          /* Bubble down */
8891          for (k = j + 1; k < file_mgr_data->num_objects; k++)
8892          {
8893             if ((y < file_mgr_data->object_positions[k]->y) ||
8894                 ((y == file_mgr_data->object_positions[k]->y) &&
8895                  (x < file_mgr_data->object_positions[k]->x)))
8896             {
8897                /* We fit right here */
8898                file_mgr_data->object_positions[k - 1] = save_object;
8899                break;
8900             }
8901             else
8902             {
8903                /* Bubble */
8904                file_mgr_data->object_positions[k - 1] =
8905                      file_mgr_data->object_positions[k];
8906             }
8907          }
8908
8909          /* See if it goes at the end */
8910          if (k == file_mgr_data->num_objects)
8911             file_mgr_data->object_positions[k - 1] = save_object;
8912       }
8913       else
8914       {
8915          /* Bubble up */
8916          for (k = j - 1; k >= 0; k--)
8917          {
8918             if ((y > file_mgr_data->object_positions[k]->y) ||
8919                 ((y == file_mgr_data->object_positions[k]->y) &&
8920                  (x > file_mgr_data->object_positions[k]->x)))
8921             {
8922                /* We fit right here */
8923                file_mgr_data->object_positions[k + 1] = save_object;
8924                break;
8925             }
8926             else
8927             {
8928                /* Bubble */
8929                file_mgr_data->object_positions[k + 1] =
8930                      file_mgr_data->object_positions[k];
8931             }
8932          }
8933
8934          /* See if it goes at the end */
8935          if (k < 0)
8936             file_mgr_data->object_positions[0] = save_object;
8937       }
8938
8939       /* Create position for the next file to be processed */
8940       x += 20;
8941       y += 20;
8942    }
8943    /*
8944     * Reregister the desktop hotspots.
8945     * Even if the caller told us that late binding was needed, if no new
8946     * objects were specified, then we need to register hotspots now, because
8947     * the layout function will never be called because the directory never
8948     * really changed.  This situation can occur when an icon is dropped on
8949     * the desktop from a regular dtfile view, but that icon is already on
8950     * the desktop (it thus is just a reposition).
8951     */
8952    if (!late_binding_needed ||
8953        (late_binding_needed && (newEntryCount == 0)))
8954    {
8955       RegisterDesktopHotspots(file_mgr_data, file_mgr_rec);
8956    }
8957 }
8958
8959 void
8960 RegisterDesktopHotspots (
8961    FileMgrData * file_mgr_data,
8962    FileMgrRec  * file_mgr_rec)
8963 {
8964    XmManagerWidget file_window;
8965    FileViewData  * file_view_data;
8966    int ex, ey, ewd, eht;
8967    ObjectPtr top;
8968    Widget icon;
8969
8970
8971    file_window = (XmManagerWidget) file_mgr_rec->file_window;
8972    ex = -file_window->core.x;
8973    ey = -file_window->core.y;
8974    ewd = XtParent(file_window)->core.width;
8975    eht = XtParent(file_window)->core.height;
8976
8977    /* Set up the icon location information with the drag handler  */
8978    /* Register in top to bottom stacking order */
8979    top = GetTopOfStack(file_mgr_data);
8980
8981    while (top)
8982    {
8983       file_view_data = top->file_view_data;
8984
8985       if (file_view_data != NULL &&
8986           file_view_data->displayed &&
8987           !file_view_data->need_update)
8988       {
8989          icon = file_view_data->widget;
8990          if ((Position)(icon->core.x + icon->core.width) >= (Position)ex  &&
8991              icon->core.x < ex + ewd &&
8992              (Position)(icon->core.y + icon->core.height) >= (Position)ey &&
8993              icon->core.y < ey + eht)
8994          {
8995             SetHotRects(file_view_data,
8996                         (XtCallbackProc) DropOnObject,
8997                         (XtPointer) file_view_data);
8998          }
8999       }
9000
9001       top = top->next;
9002    }
9003 }
9004
9005
9006 /*
9007  * Dtfile used to try to determine if the vertical scrollbar was visible
9008  * by checking to see if it was managed; the assumption here was that the
9009  * scrolled window widget unmanaged the scrollbar, when it was not needed.
9010  * Unfortunately, it turns out that instead of unmanaging the scrollbar,
9011  * the scrolled window simply moves the scrollbar out of sight; it is moved
9012  * such that the X for the scrollbar is the same as the width of the
9013  * scrolled window.  So ... in order for us to really determine if the
9014  * scrollbar is visible, we need to see whether or not its X falls within
9015  * the visible area of the scrolled window.
9016  */
9017
9018 Boolean
9019 VerticalScrollbarIsVisible(
9020         Widget vertSB,
9021         Widget scrolledWin)
9022
9023 {
9024    if (vertSB && XtIsManaged(vertSB) &&
9025        (vertSB->core.x < (Position)scrolledWin->core.width))
9026    {
9027       return(True);
9028    }
9029
9030    return(False);
9031 }
9032
9033 Boolean
9034 HorizontalScrollbarIsVisible(
9035         Widget hortSB,
9036         Widget scrolledWin)
9037
9038 {
9039    if (hortSB && XtIsManaged(hortSB) &&
9040        (hortSB->core.y <= (Position)scrolledWin->core.height))
9041    {
9042       return(True);
9043    }
9044
9045    return(False);
9046 }