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