dtwm: basic multihead(xinerama only) support
[oweals/cde.git] / cde / programs / dtfile / File.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: File.c /main/22 1999/12/09 13:05:50 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           File.c
28  *
29  *   COMPONENT_NAME: Desktop File Manager (dtfile)
30  *
31  *   Description:    File processing functions.
32  *
33  *   FUNCTIONS: ABS
34  *              AddFileIcons
35  *              BuildObjectPositions
36  *              CommitWorkProcUpdates
37  *              CompressObjectList
38  *              CopyOrderedEntries
39  *              CreateNameChangeDialog
40  *              CreateTreeIcons
41  *              DeselectAllFiles
42  *              DeselectFile
43  *              DestroyIconName
44  *              DisplaySomeIcons
45  *              DisplayWorkProc
46  *              DragFinishCB
47  *              DrawingAreaRedisplay
48  *              DropOnRootCB
49  *              EraseTreeLines
50  *              EstimateIconSize
51  *              FileConvertCB
52  *              FileDateAscending
53  *              FileDateDescending
54  *              FileIconMotion
55  *              FileIsSelected
56  *              FileNameAscending
57  *              FileNameDescending
58  *              FileSizeAscending
59  *              FileSizeDescending
60  *              FileTypeAscending
61  *              FileTypeDescending
62  *              FilterFiles
63  *              FindCurrentPosition
64  *              FlattenTree
65  *              FmPopup
66  *              FreeLayoutData
67  *              GetAncestorInfo
68  *              GetBottomOfStack
69  *              GetDirName
70  *              GetDragIcon
71  *              GetDragIconMask
72  *              GetExtraHeight
73  *              GetFullName
74  *              GetIconLayoutParms
75  *              GetInsertPosition
76  *              GetLevel
77  *              GetPositionalData
78  *              GetSelectedCount
79  *              GetStrcollProc
80  *              GetTopOfStack
81  *              GetTreebtnPixmap
82  *              HorizontalScrollbarIsVisible
83  *              IconCallback
84  *              InMultipleObjectRegion
85  *              InitiateIconDrag
86  *              IntersectRects
87  *              IsButtonOrMotion
88  *              IsDesktopPtr
89  *              LayoutDesktopIcons
90  *              LayoutFileIcons
91  *              MakeReuseList
92  *              NewConvertDelete
93  *              NewConvertFileName
94  *              OrderChildrenList
95  *              OrderFiles
96  *              PositionDesktopIcon
97  *              PositionFileView
98  *              RedisplayUsingStackingOrder
99  *              RedrawOneGadget
100  *              RedrawTreeLines
101  *              RegisterDesktopHotspots
102  *              RelocateDesktopIcon
103  *              ReorderChildrenList
104  *              RepaintDesktop
105  *              RepairFileWindow
106  *              RepairStackingPointers
107  *              RepositionIcons
108  *              RepositionUpInStack
109  *              RestorePositionalData
110  *              SavePositionalData
111  *              SelectAllFiles
112  *              SelectFile
113  *              SetFileSelected
114  *              SetFileUnselected
115  *              SetHotRects
116  *              SetToNormalColors
117  *              SetToSelectColors
118  *              SpecialCases
119  *              StartDrag
120  *              StrCaseCmp
121  *              ToBeManaged
122  *              TreeBtnCallback
123  *              TreeLX
124  *              TreeOneWd
125  *              TreeWd
126  *              TypeToAction
127  *              TypeToDropOperations
128  *              UnmanageFileIcons
129  *              UnpostTextField
130  *              UnpostTextPath
131  *              UpdateFileIcons
132  *              UpdateOneFileIcon
133  *              UpdateOneIconLabel
134  *              VerticalScrollbarIsVisible
135  *              WidgetCmp
136  *              YSPACING
137  *              _UpdateFileIcons
138  *              InputForGadget
139  *              InputInGadget
140  *
141  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
142  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
143  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
144  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
145  *
146  ****************************************************************************
147  ************************************<+>*************************************/
148
149 #include <string.h>
150 #include <locale.h>
151 #include <ctype.h>
152 #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 occuring 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 occured 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 #ifdef MULTIBYTE
3146   int len;
3147 #endif /* MULTIBYTE */
3148
3149   width = x2 - x1;
3150
3151 #ifdef MULTIBYTE
3152   i = 0;
3153   tmp = name;
3154   while ((len = mblen(tmp, MB_CUR_MAX)) > 0)
3155 #else /* MULTIBYTE */
3156   for( tmp = name + 1, i = 0;
3157        *tmp != 0x0;
3158        ++tmp, ++i )
3159 #endif /* MULTIBYTE */
3160   {
3161     XmString string;
3162
3163 #ifdef MULTIBYTE
3164     tmp += len;
3165 #endif /* MULTIBYTE */
3166
3167     savedChar = *tmp;
3168     *tmp = 0x0;
3169     string = XmStringCreateLocalized( name );
3170     stringWidth = XmStringWidth( fontList, string );
3171     XmStringFree( string );
3172     *tmp = savedChar;
3173     if( stringWidth > width )
3174       break;
3175 #ifdef MULTIBYTE
3176     else
3177       i++;
3178 #endif /* MULTIBYTE */
3179   }
3180
3181   return( i );
3182 }
3183
3184 void
3185 CreateNameChangeDialog (
3186    Widget w,
3187    FileViewData *file_view_data,
3188    XtPointer client_data,
3189    int type)
3190 {
3191    XRectangle textExtent;
3192    FileMgrData * file_mgr_data;
3193    DesktopRec * desktopWindow;
3194    Widget parent = XtParent(w);
3195    Widget text;
3196    Arg args[8];
3197    int n;
3198    Position x, y;
3199    Widget frame, shell;
3200    Dimension fHeight, sHeight;
3201 #ifdef SHAPE
3202    Dimension tWidth, tHeight;
3203 #endif
3204    char * name;
3205    XtTranslations trans_table;
3206    XmFontList fontList;
3207    Dimension stringWidth;
3208    XmString fileNameString;
3209    char tmpBuf[MAX_PATH];
3210
3211    _DtIconGetTextExtent_r(w, &textExtent);
3212
3213    if(type == DESKTOP)
3214    {
3215       char buf[MAXPATHLEN];
3216
3217       desktopWindow = (DesktopRec *)client_data;
3218       if(desktopWindow->text != NULL)
3219          return;
3220
3221       sprintf( buf, "%s:%s", home_host_name, root_title );
3222
3223       /*
3224        * If the object is on the DESKTOP and its name is root_title, then
3225        * the user can't rename it.
3226        */
3227       if( strcmp( buf, desktopWindow->title ) == 0
3228           && strcmp( desktopWindow->dir_linked_to, "/" ) == 0
3229           && strcmp( desktopWindow->file_name, "." ) == 0 )
3230         return;
3231    }
3232    else
3233       file_mgr_data = (FileMgrData *)client_data;
3234
3235    /* if the object is in the trash, can't rename it */
3236    if( type != DESKTOP
3237        && file_mgr_data == trashFileMgrData )
3238       return;
3239
3240    /* if the object is an action, can't rename it */
3241    if( DtDtsDataTypeIsAction( file_view_data->file_data->logical_type ) )
3242    {
3243      char *tmpStr, *title, *msg;
3244
3245      tmpStr = GETMESSAGE(10, 39, "Rename error");
3246      title = XtNewString(tmpStr);
3247      tmpStr = GETMESSAGE(10, 40, "This object is an Action.\nAction icon labels cannot be directly renamed." );
3248      msg = XtNewString(tmpStr);
3249
3250      _DtMessage(toplevel, title, msg, NULL, HelpRequestCB);
3251      XtFree(title);
3252      XtFree(msg);
3253      return;
3254    }
3255    else if(file_view_data->file_data->action_name)
3256    {
3257      char *tmpStr, *title, *msg;
3258
3259      tmpStr = GETMESSAGE(10, 39, "Rename error");
3260      title = XtNewString(tmpStr);
3261      tmpStr = GETMESSAGE(11, 32, "Cannot rename %s");
3262      msg = XtMalloc(strlen(tmpStr)+strlen(file_view_data->file_data->
3263                   action_name) +1);
3264      sprintf(msg,tmpStr,file_view_data->file_data->action_name);
3265
3266      _DtMessage(toplevel, title, msg, NULL, HelpRequestCB);
3267      XtFree(title);
3268      XtFree(msg);
3269      return;
3270    }
3271
3272    /*
3273     * The selected objects name is attached as 'userData' to text field,
3274     * to aid us in mapping back to the original object later.
3275     */
3276    if( type == DESKTOP &&
3277        ( (strcmp(".", file_view_data->file_data->file_name) == 0)
3278          || strcmp("..", file_view_data->file_data->file_name) == 0) )
3279    {
3280       name = XtNewString(desktopWindow->file_name);
3281    }
3282    else if ( strcmp(".", file_view_data->file_data->file_name) == 0 ||
3283              strcmp("..", file_view_data->file_data->file_name) == 0 )
3284    {
3285       return;
3286    }
3287    else
3288       name = XtNewString(file_view_data->file_data->file_name);
3289
3290    /* set up translations in main edit widget */
3291    trans_table = XtParseTranslationTable(translations_escape);
3292
3293    /* We need to set the width of the text widget.
3294       Can't use XmNcolumns because of the double-byte.
3295    */
3296    {
3297      XtSetArg( args[0], XmNfontList, &fontList );
3298      XtGetValues( file_view_data->widget, args, 1 );
3299
3300      sprintf( tmpBuf, "%s    ", file_view_data->file_data->file_name );
3301      fileNameString = XmStringCreateLocalized( tmpBuf );
3302      stringWidth = XmStringWidth( fontList, fileNameString );
3303      XmStringFree( fileNameString );
3304
3305      n = 0;
3306      XtSetArg(args[n], XmNuserData, name);                   n++;
3307      XtSetArg(args[n], XmNmarginHeight, 0);                  n++;
3308      XtSetArg(args[n], XmNmarginWidth, 0);                   n++;
3309      XtSetArg(args[n], XmNvalue, name);                      n++;
3310      XtSetArg(args[n], XmNwidth, stringWidth);               n++;
3311    }
3312
3313    if(type == DESKTOP)
3314    {
3315       text = XmCreateTextField(parent, "nameChangeT_DT", args, n);
3316       XtAddCallback (text, XmNactivateCallback, ChangeIconNameDT,
3317                                                  (XtPointer)desktopWindow);
3318       XtAddCallback(text, XmNhelpCallback, (XtCallbackProc)DTHelpRequestCB,
3319                     HELP_NAMECHANGE_DIALOG_STR);
3320       desktopWindow->text = text;
3321
3322       frame = XtParent(parent);
3323       shell = XtParent(frame);
3324       XtSetArg(args[0], XmNheight, &fHeight);
3325       XtGetValues(frame, args, 1);
3326       XtSetArg(args[0], XmNheight, &sHeight);
3327       XtGetValues(shell, args, 1);
3328    }
3329    else
3330    {
3331       text = XmCreateTextField(parent, "nameChangeT", args, n);
3332       file_mgr_data->renaming = file_view_data;
3333       XtAddCallback (text, XmNmotionVerifyCallback,
3334                      (XtCallbackProc)ChangeIconName,
3335                      (XtPointer)file_mgr_data);
3336       XtAddCallback (text, XmNmodifyVerifyCallback,
3337                      (XtCallbackProc)ChangeIconName,
3338                      (XtPointer)file_mgr_data);
3339       XtAddCallback (text, XmNactivateCallback,
3340                      (XtCallbackProc)ChangeIconName,
3341                      (XtPointer)file_mgr_data);
3342       XtAddCallback(text, XmNhelpCallback, (XtCallbackProc)HelpRequestCB,
3343                     HELP_NAMECHANGE_DIALOG_STR);
3344    }
3345
3346    XtAddCallback (text, XmNdestroyCallback, DestroyIconName, (XtPointer)NULL);
3347
3348    /* set up translations in main edit widget */
3349    XtOverrideTranslations(text, trans_table);
3350
3351    if(type == DESKTOP && sHeight > fHeight) {
3352        /* status area has been attached in multi-byte case */
3353        x = 0;
3354        y = textExtent.y;
3355    }
3356    else {
3357        x = textExtent.x;
3358        y = textExtent.y - (Dimension)(text->core.height - textExtent.height);
3359    }
3360
3361    {
3362      Window rootWindow, childWindow;
3363      int pX, pY, rootX, rootY, insertPosition;
3364      unsigned int mask;
3365
3366      XQueryPointer( XtDisplay( parent ), XtWindow( file_view_data->widget ),
3367                     &rootWindow, &childWindow, &rootX, &rootY, &pX, &pY,
3368                     &mask );
3369      if( pX == 0 )
3370        insertPosition = strlen( name );
3371      else
3372      {
3373        if( type != DESKTOP )
3374        {
3375          if( pX > (int) x && pX < (int) x + (int) stringWidth )
3376            insertPosition = GetInsertPosition( x, pX, fontList, name );
3377          else
3378            insertPosition = strlen( name );
3379        }
3380        else
3381          insertPosition = GetInsertPosition( x, x + pX, fontList, name );
3382      }
3383      n = 0;
3384      XtSetArg( args[n], XmNcursorPosition, insertPosition);     n++;
3385      XtSetArg( args[n], XmNx, x);                               n++;
3386      XtSetArg( args[n], XmNy, y);                               n++;
3387      XtSetValues (text, args, n);
3388    }
3389
3390 #ifdef SHAPE
3391    if(shapeExtension)
3392       if(type == DESKTOP)
3393       {
3394          Dimension shadowThickness;
3395          XRectangle rect[2];
3396          unsigned char flags;
3397
3398          XtSetArg (args[0], XmNwidth, &tWidth);
3399          XtSetArg (args[1], XmNheight, &tHeight);
3400          XtGetValues (text, args, 2);
3401
3402          XtSetArg (args[0], XmNshadowThickness, &shadowThickness);
3403          XtGetValues (desktopWindow->iconGadget, args, 1);
3404
3405          _DtIconGetIconRects((DtIconGadget)desktopWindow->iconGadget,
3406                                                 &flags, &rect[0], &rect[1]);
3407         /* 1 */
3408          rect[0].x += 1;
3409          rect[0].y += 1;
3410          rect[0].width += 2*shadowThickness;
3411          rect[0].height += 2*shadowThickness;
3412
3413         /* 2 */
3414          if(type == DESKTOP && sHeight > fHeight) {
3415              /* status area has been attached in multi-byte case */
3416              rect[1].x = x + 1;
3417              rect[1].y = y + 1;
3418              rect[1].width = 2*shadowThickness + tWidth;
3419              rect[1].height = sHeight - y - 1;
3420          }
3421          else {
3422              rect[1].x += 1;
3423              rect[1].y += 1;
3424              rect[1].width = shadowThickness + tWidth;
3425              rect[1].height = tHeight;
3426          }
3427
3428          if(rect[0].width > rect[1].width)
3429            rect[1].width = rect[0].width;
3430
3431          XShapeCombineRectangles(XtDisplay(desktopWindow->shell),
3432                                  XtWindow(desktopWindow->shell),
3433                                  ShapeBounding, 0, 0, &rect[0], 2,
3434                                  ShapeSet, Unsorted);
3435       }
3436 #endif
3437    XtManageChild(text);
3438    XmProcessTraversal(text, XmTRAVERSE_CURRENT);
3439
3440    if(type != DESKTOP)
3441    {
3442       FileMgrRec *file_mgr_rec;
3443
3444       file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
3445       file_mgr_rec->menuStates &= ~RENAME;
3446    }
3447 }
3448
3449 /************************************************************************
3450  *
3451  *  SavePositionalData
3452  *      Save the desktop icon positional data.
3453  *
3454  ************************************************************************/
3455
3456 void
3457 SavePositionalData (
3458    int fd,
3459    FileMgrData * file_mgr_data,
3460    char ** name_list,
3461    char * name)
3462 {
3463    int i;
3464    FILE * fd_stream = fdopen(fd, "w");
3465    ObjectPosition * ptr;
3466
3467
3468    if(file_mgr_data->positionEnabled == RANDOM_ON &&
3469                   file_mgr_data->object_positions &&
3470                   file_mgr_data->show_type == SINGLE_DIRECTORY &&
3471                   file_mgr_data->host != NULL)
3472    {
3473       /* Number of object positions */
3474       fprintf(fd_stream, "*%s.%s.%s.%s:   %d\n#\n", name_list[0], name_list[1],
3475                name, "num_positions", file_mgr_data->num_objects);
3476
3477       for (i = 0; i < file_mgr_data->num_objects; i++)
3478       {
3479          ptr = file_mgr_data->object_positions[i];
3480          fprintf(fd_stream, "*%s.%s.%s.%s%d:   %s %d %d %d\n",
3481                    name_list[0], name_list[1], name, "object", i,
3482                    ptr->name,
3483                    ptr->x,
3484                    ptr->y,
3485                    ptr->stacking_order);
3486       }
3487    }
3488    else
3489    {
3490       /* Number of object positions */
3491       fprintf(fd_stream, "*%s.%s.%s.%s:   %d\n#\n", name_list[0], name_list[1],
3492                name, "num_positions", 0);
3493    }
3494
3495    fflush(fd_stream);
3496 }
3497
3498
3499
3500 /************************************************************************
3501  *
3502  *  RestorePositionalData
3503  *      Restore the desktop icon positional data.
3504  *
3505  ************************************************************************/
3506
3507 void
3508 RestorePositionalData (
3509    XrmDatabase db,
3510    char ** name_list,
3511    FileMgrData * file_mgr_data,
3512    char * name)
3513 {
3514    XrmName xrm_name[10];
3515    int i = 0;
3516    int j;
3517    char objectName[20];
3518    XrmRepresentation rep_type;
3519    XrmValue value;
3520    int num_objects;
3521    char * str;
3522    char * obj_name;
3523    ObjectPosition * ptr;
3524    int x, y;
3525    int s_order;
3526
3527    while (name_list[i])
3528    {
3529       xrm_name[i] = XrmStringToQuark(name_list[i]);
3530       i++;
3531    }
3532    xrm_name[i++] = XrmStringToQuark(name);
3533    xrm_name[i] = XrmStringToQuark("num_positions");
3534    xrm_name[i+1] = '\0';
3535
3536    /* Find out how many objects there are to be loaded */
3537    file_mgr_data->object_positions = NULL;
3538    num_objects = 0;
3539    if (XrmQGetResource (db, xrm_name, NULL, &rep_type, &value))
3540    {
3541       if ((num_objects = atoi (value.addr)) <= 0)
3542          num_objects = 0;
3543       else
3544       {
3545          file_mgr_data->object_positions = (ObjectPosition **)XtMalloc(
3546                              sizeof(ObjectPosition *) * num_objects);
3547       }
3548    }
3549
3550    file_mgr_data->num_objects = num_objects;
3551
3552    for (j = 0; j < num_objects; j++)
3553    {
3554       sprintf(objectName, "object%d", j);
3555       xrm_name[i] = XrmStringToQuark(objectName);
3556       ptr = file_mgr_data->object_positions[j] = (ObjectPosition *)
3557                                      XtMalloc(sizeof(ObjectPosition));
3558
3559       XrmQGetResource (db, xrm_name, NULL, &rep_type, &value);
3560       str = (char *)value.addr;
3561       obj_name = XtMalloc(strlen(str) + 1);
3562       sscanf((char *)value.addr, "%s %d %d %d", obj_name, &x, &y, &s_order);
3563       ptr->name = obj_name;
3564       ptr->x = x;
3565       ptr->y = y;
3566       ptr->stacking_order = s_order;
3567       ptr->in_use = False;
3568       ptr->late_bind = False;
3569       ptr->file_view_data = NULL;
3570       ptr->next = NULL;
3571       ptr->prev = NULL;
3572    }
3573
3574    /* Repair all of the next and prev pointers */
3575    RepairStackingPointers(file_mgr_data);
3576 }
3577
3578
3579 void
3580 UnpostTextField (
3581    FileMgrData * file_mgr_data)
3582
3583 {
3584    XmManagerWidget file_window;
3585    int i;
3586    FileMgrRec * file_mgr_rec;
3587
3588    file_mgr_data->renaming = NULL;
3589
3590    file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
3591    file_window = (XmManagerWidget) file_mgr_rec->file_window;
3592    for (i = 0; i < file_window->composite.num_children; i++)
3593    {
3594       if (XmIsTextField(file_window->composite.children[i]) &&
3595           !file_window->composite.children[i]->core.being_destroyed)
3596       {
3597          XtUnmanageChild(file_window->composite.children[i]);
3598          XtDestroyWidget(file_window->composite.children[i]);
3599          return;
3600       }
3601    }
3602 }
3603
3604
3605 void
3606 UnpostTextPath (
3607    FileMgrData * file_mgr_data)
3608
3609 {
3610   FileMgrRec * file_mgr_rec;
3611   Arg args[2];
3612
3613   file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
3614
3615   XtSetArg (args[0], XmNallowShellResize, False);
3616   XtSetValues(file_mgr_rec->shell, args, 1);
3617
3618   XtUnmanageChild(file_mgr_rec->current_directory_text);
3619
3620   XtSetArg (args[0], XmNallowShellResize, True);
3621   XtSetValues(file_mgr_rec->shell, args, 1);
3622
3623   file_mgr_data->fast_cd_enabled = False;
3624 }
3625
3626
3627 /*
3628  * Function to force a redraw of a single gadget.
3629  */
3630
3631 void
3632 RedrawOneGadget (
3633    Widget child,
3634    XEvent * event,
3635    Region region)
3636
3637 {
3638    if (child->core.widget_class->core_class.expose)
3639       (*(child->core.widget_class->core_class.expose))(child, event, region);
3640 }
3641
3642
3643 /*
3644  * Given a region describing the area to be repainted, repaint all icons,
3645  * in bottom to top order, which fall into this region.
3646  */
3647
3648 void
3649 RepaintDesktop (
3650    FileMgrData * file_mgr_data,
3651    XEvent * event,
3652    Region region)
3653
3654 {
3655    Widget child;
3656    ObjectPosition * bottom = GetBottomOfStack(file_mgr_data);
3657
3658    /* Redraw all affected gadgets */
3659    while(bottom)
3660    {
3661       if (!bottom->late_bind)
3662       {
3663          if (bottom->file_view_data != NULL &&
3664              !bottom->file_view_data->need_update)
3665          {
3666             child = bottom->file_view_data->widget;
3667             if (XRectInRegion(region, child->core.x, child->core.y,
3668                               child->core.width, child->core.height))
3669             {
3670                RedrawOneGadget(child, event, region);
3671             }
3672          }
3673       }
3674
3675       bottom = bottom->prev;
3676    }
3677 }
3678
3679
3680 /*
3681  * This function will extract all exposure events intended for this file
3682  * window, combine them into a single region, and then determine which of
3683  * the file icons need to be redrawn.  It is a two step process, as
3684  * described by the comments in the code.
3685  */
3686
3687 static void
3688 RedisplayUsingStackingOrder (
3689    FileMgrData * file_mgr_data,
3690    Widget w,
3691    register XEvent *event,
3692    Region region)
3693
3694 {
3695    register Widget child;
3696    FileViewData * file_view_data;
3697    ObjectPosition * bottom;
3698    ObjectPosition * top;
3699    Region redrawRegion = XCreateRegion();
3700    XRectangle rect;
3701    XEvent expEvent;
3702    int numChildren = 0;
3703    Widget * children = NULL;
3704    Region widget_region;
3705    Region tmp_region;
3706
3707    /* Get the initial region to redraw */
3708    if (region)
3709       XUnionRegion(redrawRegion, region, redrawRegion);
3710    else if (event)
3711    {
3712       rect.x = event->xexpose.x;
3713       rect.y = event->xexpose.y;
3714       rect.height = event->xexpose.height;
3715       rect.width = event->xexpose.width;
3716
3717       XUnionRectWithRegion(&rect, redrawRegion, redrawRegion);
3718    }
3719
3720    /*
3721     * Capture and encompass any other exposure events which are destined for
3722     * us, but are waiting in the wings.
3723     */
3724    while (XCheckWindowEvent(XtDisplay(w), XtWindow(w), ExposureMask, &expEvent))
3725    {
3726       rect.x = expEvent.xexpose.x;
3727       rect.y = expEvent.xexpose.y;
3728       rect.height = expEvent.xexpose.height;
3729       rect.width = expEvent.xexpose.width;
3730
3731       XUnionRectWithRegion(&rect, redrawRegion, redrawRegion);
3732    }
3733
3734    /* Nothing to do if the redraw region is empty */
3735    if (XEmptyRegion(redrawRegion))
3736    {
3737       XDestroyRegion(redrawRegion);
3738       return;
3739    }
3740
3741    /*
3742     * Starting at the top of the stack, find any items which fall into
3743     * the redraw region.  As items are found which need to be redrawn,
3744     * subtract them from the redraw region, so that any items lower on the
3745     * stack which might be under these gadgets, but are within the region,
3746     * are not redrawn.
3747     *
3748     * The second phase is to start at the bottom of the stack, and start
3749     * redrawing the gadgets which fell into the region, along with any
3750     * other gadgets on top of these (since they too now need to be redrawn.
3751     */
3752    top = GetTopOfStack(file_mgr_data);
3753    children = NULL;
3754    numChildren = 0;
3755
3756    while (top)
3757    {
3758       if (!top->late_bind)
3759       {
3760          file_view_data = top->file_view_data;
3761          if(file_view_data != NULL)
3762          {
3763             child = file_view_data->widget;
3764
3765             if (child && XmIsGadget(child) && XtIsManaged(child))
3766             {
3767                widget_region = XCreateRegion();
3768                WidgetRectToRegion(file_mgr_data, child, widget_region);
3769                XIntersectRegion(redrawRegion, widget_region, widget_region);
3770                if (!XEmptyRegion(widget_region))
3771                {
3772                   XSubtractRegion(redrawRegion, widget_region, redrawRegion);
3773                   children = (Widget *)XtRealloc((char *)children,
3774                                          (numChildren + 1) * sizeof(Widget));
3775                   children[numChildren] = child;
3776                   numChildren++;
3777                }
3778                XDestroyRegion(widget_region);
3779             }
3780          }
3781       }
3782       top = (ObjectPosition *)top->next;
3783    }
3784
3785    /* Now, start redrawing, in bottom to top order */
3786    bottom = GetBottomOfStack(file_mgr_data);
3787    numChildren--;
3788    while (bottom)
3789    {
3790       if (!bottom->late_bind)
3791       {
3792          file_view_data = bottom->file_view_data;
3793          if(file_view_data != NULL)
3794          {
3795             child = file_view_data->widget;
3796
3797             if (child && XmIsGadget(child) && XtIsManaged(child))
3798             {
3799                widget_region = XCreateRegion();
3800                WidgetRectToRegion(file_mgr_data, child, widget_region);
3801                if ((numChildren >= 0) && (children[numChildren] == child))
3802                {
3803                   XUnionRegion(redrawRegion, widget_region, redrawRegion);
3804                   RedrawOneGadget(child, event, redrawRegion);
3805                   numChildren--;
3806                }
3807                else
3808                {
3809                   /* Do we overlap something which was previously redrawn? */
3810                   tmp_region = XCreateRegion();
3811                   XIntersectRegion(redrawRegion, widget_region, tmp_region);
3812                   if (!XEmptyRegion(tmp_region))
3813                   {
3814                      XUnionRegion(redrawRegion, widget_region, redrawRegion);
3815                      RedrawOneGadget(child, event, redrawRegion);
3816                   }
3817                   XDestroyRegion(tmp_region);
3818                }
3819                XDestroyRegion(widget_region);
3820             }
3821          }
3822       }
3823       bottom = (ObjectPosition *)bottom->prev;
3824    }
3825
3826    XDestroyRegion(redrawRegion);
3827    XtFree((char *)children);
3828    children = NULL;
3829 }
3830
3831
3832 /*
3833  * This is the function which we use to override the class expose function
3834  * for the drawing area widget.  It allows us to catch exposure events
3835  * intended for the desktop, so that we can force the redrawing of the
3836  * gadgets to occur occording to the stacking order.
3837  */
3838
3839 void
3840 DrawingAreaRedisplay (
3841    Widget wid,
3842    XEvent *event,
3843    Region region)
3844
3845 {
3846    XmDrawingAreaWidget da = (XmDrawingAreaWidget) wid;
3847    XmDrawingAreaCallbackStruct cb;
3848    FileMgrData * file_mgr_data;
3849
3850    cb.reason = XmCR_EXPOSE;
3851    cb.event = event;
3852    cb.window = XtWindow (da);
3853
3854    DPRINTF2(("DrawingAreaRedisplay: event %d, x/y %d/%d, wd/ht %d/%d\n",
3855              event->xany.type,
3856              event->xexpose.x, event->xexpose.y,
3857              event->xexpose.width, event->xexpose.height));
3858
3859    file_mgr_data = ReturnDesktopPtr(wid);
3860
3861    if (file_mgr_data && PositioningEnabledInView(file_mgr_data))
3862       RedisplayUsingStackingOrder(file_mgr_data, (Widget)da, event, region);
3863    else
3864       XmeRedisplayGadgets((Widget)da, event, region);
3865
3866    XtCallCallbackList ((Widget)da, da->drawing_area.expose_callback, &cb);
3867 }
3868
3869
3870 /*
3871  * Return the bottom of the stacking order list.
3872  */
3873
3874 ObjectPtr
3875 GetBottomOfStack (
3876    FileMgrData * file_mgr_data)
3877
3878 {
3879    int i;
3880    ObjectPtr bottom;
3881
3882    for (i = 0, bottom = NULL; i < file_mgr_data->num_objects; i++)
3883    {
3884       if (file_mgr_data->object_positions[i]->next == NULL)
3885       {
3886          bottom = file_mgr_data->object_positions[i];
3887          break;
3888       }
3889    }
3890
3891    return(bottom);
3892 }
3893
3894
3895 /*
3896  * Return the top of the stacking order list.
3897  */
3898
3899 ObjectPtr
3900 GetTopOfStack (
3901    FileMgrData * file_mgr_data)
3902 {
3903    int i;
3904    ObjectPtr top;
3905
3906    for (i = 0, top = NULL; i < file_mgr_data->num_objects; i++)
3907    {
3908       if (file_mgr_data->object_positions[i]->prev == NULL)
3909       {
3910          top = file_mgr_data->object_positions[i];
3911          break;
3912       }
3913    }
3914
3915    return(top);
3916 }
3917
3918
3919 /*
3920  * Move an object up in the stacking order.  Will not work for moving an
3921  * object further down in the stacking order, but we currently have no
3922  * need for doing that.
3923  *
3924  * NOTE: The top of the stack is '1', not '0'!!
3925  */
3926
3927 void
3928 RepositionUpInStack (
3929    FileMgrData * file_mgr_data,
3930    int oldPos,
3931    int newPos)
3932
3933 {
3934    ObjectPtr ptr, ptr2, savePtr;
3935    register int i, j;
3936    XmManagerWidget file_window;
3937
3938    if (oldPos == newPos)
3939       return;
3940
3941    ptr = GetTopOfStack(file_mgr_data);
3942
3943    /* Find where item is to be inserted */
3944    while (ptr->stacking_order != newPos)
3945       ptr = ptr->next;
3946
3947    /* Find where item currently is */
3948    ptr2 = ptr;
3949    while (ptr2->stacking_order != oldPos)
3950       ptr2 = ptr2->next;
3951
3952    savePtr = ptr2;
3953
3954    if(savePtr->file_view_data == NULL)
3955       return;
3956
3957    /* Remove from its current location */
3958    if (ptr2->prev)
3959       ptr2->prev->next = ptr2->next;
3960    if (ptr2->next)
3961       ptr2->next->prev = ptr2->prev;
3962
3963    /* Link into new position */
3964    ptr2->prev = ptr->prev;
3965    ptr2->next = ptr;
3966    if (ptr->prev)
3967       ptr2->prev->next = ptr2;
3968    ptr->prev = ptr2;
3969
3970    /* Update the stacking order value */
3971    for (i = newPos; i <= oldPos; i++)
3972    {
3973       ptr2->stacking_order = i;
3974       ptr2 = ptr2->next;
3975    }
3976
3977    /* Update the children's list for the file window */
3978    file_window = (XmManagerWidget)
3979                   (((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window);
3980
3981    /* Find the affect child */
3982    for (i = 0; (i < file_window->composite.num_children) &&
3983        (file_window->composite.children[i] != savePtr->file_view_data->widget);
3984        i++);
3985
3986    /* Push intervening entries down */
3987    for (j = i; j >= newPos; j--)
3988       file_window->composite.children[j] = file_window->composite.children[j-1];
3989
3990    /* Insert into new position in children list */
3991    file_window->composite.children[newPos-1] = savePtr->file_view_data->widget;
3992 }
3993
3994
3995 /*
3996  * Reorder the file window's children list so that it matches the stacking
3997  * order.
3998  */
3999
4000 static void
4001 ReorderChildrenList (
4002    XmManagerWidget file_window,
4003    Widget * manage,
4004    int manageCount,
4005    Widget * unmanage,
4006    int unmanageCount)
4007
4008 {
4009    Widget * children = file_window->composite.children;
4010    register int i, j;
4011
4012    for (i = 0; i < manageCount; i++)
4013       children[i] = manage[i];
4014
4015    for (j = 0; j < unmanageCount; j++)
4016       children[i++] = unmanage[j];
4017 }
4018
4019
4020 /*
4021  * If positional information is available for the indicated file, then
4022  * return it; if not, then return NULL.
4023  */
4024
4025 ObjectPtr
4026 FindCurrentPosition (
4027    FileMgrData * file_mgr_data,
4028    char * file_name)
4029
4030 {
4031    int i;
4032
4033    for (i = 0; i < file_mgr_data->num_objects; i++)
4034    {
4035       if (strcmp(file_name, file_mgr_data->object_positions[i]->name) == 0)
4036       {
4037          /* Found a match */
4038          file_mgr_data->object_positions[i]->in_use = True;
4039          return(file_mgr_data->object_positions[i]);
4040       }
4041    }
4042
4043    return(NULL);
4044 }
4045
4046
4047 void
4048 RepairStackingPointers (
4049    FileMgrData * file_mgr_data)
4050
4051 {
4052    int i;
4053    int j;
4054    ObjectPosition * ptr;
4055    ObjectPosition * prev;
4056
4057    for (i = 1, prev = NULL; i <= file_mgr_data->num_objects; i++)
4058    {
4059       for (j = 0; j < file_mgr_data->num_objects; j++)
4060       {
4061          ptr = file_mgr_data->object_positions[j];
4062          if (ptr->stacking_order == i)
4063          {
4064             if (prev)
4065             {
4066                ptr->prev = prev;
4067                prev->next = ptr;
4068             }
4069             prev = ptr;
4070             break;
4071          }
4072       }
4073    }
4074 }
4075
4076 /*
4077  * Reorder the children's list for the file_window, so that it matches
4078  * the stacking order.  Also, set up all next and previous pointers.
4079  */
4080
4081 void
4082 OrderChildrenList (
4083    FileMgrData * file_mgr_data)
4084
4085 {
4086    FileMgrRec * file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
4087    XmManagerWidget file_window;
4088    Widget * managed;
4089    Widget * unmanaged;
4090    int num_managed;
4091    int num_unmanaged;
4092    ObjectPosition * top;
4093    int i, j;
4094
4095    file_window = (XmManagerWidget) file_mgr_rec->file_window;
4096    managed = (Widget *)XtMalloc(sizeof(Widget *) *
4097                         file_window->composite.num_children);
4098    unmanaged = (Widget *)XtMalloc(sizeof(Widget *) *
4099                         file_window->composite.num_children);
4100    num_managed = num_unmanaged = 0;
4101
4102    top = GetTopOfStack(file_mgr_data);
4103    while(top)
4104    {
4105       if (top->file_view_data != NULL && top->file_view_data->widget != NULL)
4106          managed[num_managed++] = top->file_view_data->widget;
4107       top = top->next;
4108    }
4109
4110    /* All the rest get put at the end of the children's list */
4111    for (i = 0; i < file_window->composite.num_children; i++)
4112    {
4113       for (j = 0; j < num_managed; j++)
4114       {
4115          if (managed[j] == file_window->composite.children[i])
4116             break;
4117       }
4118
4119       if (j >= num_managed)
4120          unmanaged[num_unmanaged++] = file_window->composite.children[i];
4121    }
4122
4123    ReorderChildrenList(file_window, managed, num_managed, unmanaged,
4124                        num_unmanaged);
4125    XtFree( (char *)managed );
4126    XtFree( (char *)unmanaged );
4127 }
4128
4129
4130 /*
4131  * SetHotRects
4132  */
4133
4134 void
4135 SetHotRects (
4136    FileViewData  * file_view_data,
4137    XtCallbackProc callback,
4138    XtPointer callback_data)
4139
4140 {
4141    Arg args[3];
4142
4143    if (file_view_data->displayed)
4144    {
4145       /*************************/
4146       /* icon gadget displayed */
4147       /*************************/
4148       DtIconGadget g = (DtIconGadget) file_view_data->widget;
4149       unsigned char operations;
4150
4151          /* find defined operations (M/C/L) for file type */
4152       operations = TypeToDropOperations(
4153                              file_view_data->file_data->logical_type);
4154
4155       /* if icon gadget not yet registered as a drop site, do so now */
4156       if (!file_view_data->registered)
4157       {
4158          /* register drop site for MCL but make drop site inactive */
4159          XtSetArg (args[0], XmNdropSiteOperations,
4160                    XmDROP_COPY | XmDROP_MOVE | XmDROP_LINK);
4161          XtSetValues (file_view_data->widget, args, 1);
4162
4163          file_view_data->registered = True;
4164       }
4165
4166       if (operations)
4167       {
4168          /***********************************/
4169          /* file has associated MCL actions */
4170          /***********************************/
4171          XRectangle rects[2];
4172          unsigned char flags;
4173          int numRects = 0;
4174          Cardinal n = 0;
4175          Dimension s_t, adj_xy, adj_size;
4176
4177          /* ensure drop site operations and drop area are correct */
4178          _DtIconGetIconRects(g, &flags, &rects[0], &rects[1]);
4179
4180          /*
4181           * Compute adjustments to the drop area:
4182           *
4183           *  - Add shadowThickness to the drop area:
4184           *    The icon gadget leaves space of width shadowThickness around
4185           *    the pixmap and label; use this space to make the drop zone
4186           *    larger.
4187           *
4188           *  - Compensate for bug in drop zone registration/drawing:
4189           *    For some reason the drop zone displayed on the screen is
4190           *    actually smaller than the rectangle we register:
4191           *    The drag&drop library seems to reduce the size of the drop
4192           *    area by the value of highlightThickness at the top and left
4193           *    border and by highlightThickness-1 at the bottom and right.
4194           *    Is this a Motif drag&drop bug?
4195           *    We compensate by registering a larger rectangle.
4196           */
4197          s_t = G_ShadowThickness(g);
4198          adj_xy = s_t + G_HighlightThickness(g);
4199          adj_size = adj_xy + s_t + G_HighlightThickness(g) - 1;
4200
4201          if (flags & XmPIXMAP_RECT)
4202          {
4203             rects[0].x -= g->rectangle.x + adj_xy;
4204             rects[0].y -= g->rectangle.y + adj_xy;
4205             rects[0].width += adj_size;
4206             rects[0].height += adj_size;
4207             numRects++;
4208           }
4209
4210          if (flags & XmLABEL_RECT)
4211          {
4212             rects[1].x -= g->rectangle.x + adj_xy;
4213             rects[1].y -= g->rectangle.y + adj_xy;
4214             rects[1].width += adj_size;
4215             rects[1].height += adj_size;
4216             if (!numRects) rects[0] = rects[1];
4217                numRects++;
4218           }
4219
4220           if (numRects)
4221           {
4222              XtSetArg(args[n], XmNdropRectangles, rects);        n++;
4223              XtSetArg(args[n], XmNnumDropRectangles, numRects);  n++;
4224           }
4225           XtSetArg (args[n], XmNdropSiteOperations, operations); n++;
4226
4227           XmDropSiteUpdate (file_view_data->widget, args, n);
4228           g->icon.operations = operations;
4229
4230           /* add client data */
4231           XtRemoveAllCallbacks(file_view_data->widget, XmNdropCallback);
4232           XtAddCallback(file_view_data->widget, XmNdropCallback,
4233                       callback, callback_data);
4234       }
4235       else
4236       {
4237          /*********************************************/
4238          /* file does not have associated MCL actions */
4239          /*********************************************/
4240          /* make drop site inactive */
4241          XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
4242          XmDropSiteUpdate (file_view_data->widget, args, 1);
4243          XtRemoveAllCallbacks(file_view_data->widget, XmNdropCallback);
4244       }
4245     }
4246     else
4247     {
4248       /*****************************/
4249       /* icon gadget not displayed */
4250       /*****************************/
4251       if (file_view_data->registered)
4252       {
4253          /***************************************/
4254          /* icon gadget registered as drop site */
4255          /***************************************/
4256          /* make drop site inactive */
4257          XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
4258          XmDropSiteUpdate (file_view_data->widget, args, 1);
4259          XtRemoveAllCallbacks(file_view_data->widget, XmNdropCallback);
4260       }
4261    }
4262 }
4263
4264
4265
4266 /*
4267  * TypeToDropOperations
4268  */
4269
4270 unsigned char
4271 TypeToDropOperations (
4272    char * file_type)
4273
4274 {
4275    unsigned char operations = 0L;
4276    char *action;
4277
4278    /* does object have MOVE, COPY, and/or LINK actions */
4279    /*    -- or no actions at all                       */
4280    if (action = DtDtsDataTypeToAttributeValue(file_type,
4281                                               DtDTS_DA_MOVE_TO_ACTION,
4282                                               NULL))
4283    {
4284       operations = operations | XmDROP_MOVE;
4285       DtDtsFreeAttributeValue(action);
4286    }
4287    if (action = DtDtsDataTypeToAttributeValue(file_type,
4288                                               DtDTS_DA_COPY_TO_ACTION,
4289                                               NULL))
4290    {
4291       operations = operations | XmDROP_COPY;
4292       DtDtsFreeAttributeValue(action);
4293    }
4294    if (action = DtDtsDataTypeToAttributeValue(file_type,
4295                                               DtDTS_DA_LINK_TO_ACTION,
4296                                               NULL))
4297    {
4298       operations = operations | XmDROP_LINK;
4299       DtDtsFreeAttributeValue(action);
4300    }
4301
4302    return(operations);
4303 }
4304
4305
4306 /*
4307  * TypeToAction
4308  */
4309
4310 char *
4311 TypeToAction (
4312    unsigned char dropOperation,
4313    char * logical_type)
4314 {
4315    char * action;
4316
4317    /* retrieve action from database based on dropOperation */
4318    switch(dropOperation)
4319    {
4320       case XmDROP_MOVE:
4321          action = DtDtsDataTypeToAttributeValue(logical_type,
4322                                                 DtDTS_DA_MOVE_TO_ACTION,
4323                                                 NULL);
4324          break;
4325       case XmDROP_COPY:
4326          action = DtDtsDataTypeToAttributeValue(logical_type,
4327                                                 DtDTS_DA_COPY_TO_ACTION,
4328                                                 NULL);
4329          break;
4330       case XmDROP_LINK:
4331          action = DtDtsDataTypeToAttributeValue(logical_type,
4332                                                 DtDTS_DA_LINK_TO_ACTION,
4333                                                 NULL);
4334          break;
4335       default:
4336          action = NULL;
4337          break;
4338    }
4339
4340    return(action);
4341 }
4342
4343
4344 /*
4345  * Given a fileViewData pointer, determine if it is part of a FileMgrData,
4346  * or a DesktopRec; return the appropriate pointer.
4347  */
4348
4349 static
4350 Boolean
4351 IsDesktopPtr (
4352    FileViewData * fileViewData,
4353    FileMgrData ** fileMgrData,
4354    DesktopRec ** desktopRec)
4355 {
4356    int i;
4357
4358    *desktopRec = NULL;
4359    *fileMgrData = NULL;
4360
4361    for (i = 0; i < desktop_data->numIconsUsed; i++)
4362    {
4363       if (desktop_data->desktopWindows[i]->file_view_data == fileViewData)
4364       {
4365          *desktopRec = desktop_data->desktopWindows[i];
4366          return(True);
4367       }
4368    }
4369
4370    *fileMgrData = (FileMgrData *)
4371                 ((DirectorySet *)fileViewData->directory_set)->file_mgr_data;
4372    return(False);
4373 }
4374
4375
4376 /******************************************************************
4377  *
4378  *  PositionFileView -
4379  *        Given a particular file, position the file view that file
4380  *        is in on that particular file.
4381  *
4382  ********************************************************************/
4383 void
4384 PositionFileView(
4385      FileViewData *file_view_data,
4386      FileMgrData *file_mgr_data)
4387 {
4388    Position x, y;
4389    Arg args[1];
4390    int value, size, increment, page, max;
4391    FileMgrRec * file_mgr_rec = (FileMgrRec *)(file_mgr_data->file_mgr_rec);
4392    Widget p;
4393
4394    /* if the file is filtered we can't highlight it! */
4395    if(!file_view_data->displayed)
4396       return;
4397
4398    /* Get the y location of the icon_gadget */
4399    y = file_view_data->y - file_mgr_data->grid_height;
4400
4401    /* Two things:
4402     * 
4403     * 1) not sure exactly how slow this is, but there seems to be no other
4404     *    way to do this. (CDExc23427)
4405     * 2) XmScrollVisible does not work if the work window is not managed...
4406     *    so, we call it, and then get the appropriate x,y back from the
4407     *    scroll bars and set them (CDExc23428) */
4408    p = XtVaCreateManagedWidget("positionicon", xmGadgetClass, 
4409                                file_mgr_rec->file_window,
4410                                XmNmappedWhenManaged, False,
4411                                XmNx, file_view_data->x,
4412                                XmNy, y, 
4413                                XmNwidth, file_mgr_data->grid_width,
4414                                XmNheight, file_mgr_data->grid_height,
4415                                NULL);
4416
4417    XmScrollVisible(file_mgr_rec->scroll_window, p,
4418                    XSPACING, YSPACING(file_mgr_data));
4419
4420    XtDestroyWidget(p);
4421
4422    XmScrollBarGetValues(file_mgr_rec->horizontal_scroll_bar,
4423                         &value, &size, &increment, &page);
4424    x = -((Position) value);
4425
4426    XmScrollBarGetValues(file_mgr_rec->vertical_scroll_bar,
4427                         &value, &size, &increment, &page);
4428    y = -((Position) value);
4429
4430    XtVaSetValues(file_mgr_rec->file_window, XmNx, x, XmNy, y, NULL);
4431 }
4432
4433
4434 static Boolean
4435 InMultipleObjectRegion (FileMgrData * file_mgr_data, FileViewData * fileViewData)
4436 {
4437   register int i;
4438   for( i = 0; i < file_mgr_data->selected_file_count; ++i )
4439     if( strcmp( file_mgr_data->selection_list[i]->file_data->file_name, fileViewData->file_data->file_name ) == 0 )
4440       return True;
4441   return False;
4442 }
4443
4444 void
4445 FmPopup (
4446       Widget w,
4447       XtPointer client_data,
4448       XEvent *event,
4449       FileMgrData *file_mgr_data)
4450 {
4451    FileMgrRec      *file_mgr_rec;
4452    Arg             args[2];
4453    FileViewData    *fileViewData = NULL;
4454    int             i, num_of_children, obj_btns;
4455    XmManagerWidget action_pane;
4456    XmString        label_string;
4457
4458
4459    /* set number of popup children based on annotation */
4460    num_of_children = FM_POPUP_CHILDREN_NA;
4461    obj_btns = OBJ_BTNS_NA;
4462
4463    /* attach the popup widget info to the menu */
4464    file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
4465    XtSetArg(args[0], XmNuserData, file_mgr_rec);
4466    XtSetValues(fileMgrPopup.menu, args, 1);
4467
4468    if(file_mgr_data)
4469      file_mgr_data->popup_menu_icon = NULL;
4470
4471    /* we are dealing with a white space popup */
4472    if((w == NULL)
4473       && (client_data == NULL)
4474 /*
4475       && (file_mgr_data->selected_file_count == 0)
4476 */
4477       )
4478    {
4479       DirectorySet *directory_set;
4480
4481       /* retrieve the fileViewData for the current directory */
4482       directory_set = file_mgr_data->directory_set[0];
4483       for (i = 0; i < directory_set->file_count; i++)
4484       {
4485          if(strcmp(directory_set->order_list[i]->file_data->file_name, ".")
4486             == 0)
4487          {
4488             fileViewData = directory_set->order_list[i];
4489             break;
4490          }
4491       }
4492
4493       /* manage the white space buttons and unmanage the object buttons */
4494       XtManageChildren(fileMgrPopup.wsPopup, WS_BTNS);
4495       XtUnmanageChildren(fileMgrPopup.objPopup, obj_btns);
4496       XtUnmanageChildren(fileMgrPopup.trash_objPopup, TRASH_OBJ_BTNS);
4497
4498       XtUnmanageChild(fileMgrPopup.wsPopup[BTN_UNSELECTALL]);
4499
4500       if(file_mgr_data == trashFileMgrData)
4501       {
4502          /* Set popup menu label */
4503          label_string = XmStringCreateLocalized ((GETMESSAGE(33, 2, "Current Folder")));
4504          XtSetArg (args[0], XmNlabelString, label_string);
4505          XtSetValues (fileMgrPopup.title, args, 1);
4506          XtManageChild(fileMgrPopup.title);
4507          XmStringFree (label_string);
4508
4509          /* trash white space popup -- unmanage the properties and show */
4510          /* hidden files buttons */
4511          XtUnmanageChild(fileMgrPopup.wsPopup[BTN_PROPERTIES]);
4512          XtUnmanageChild(fileMgrPopup.wsPopup[BTN_FIND]);
4513          XtUnmanageChild(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN]);
4514
4515          /* align the remaining buttons */
4516          XtSetArg(args[0], XmNmarginLeft, 0);
4517          if( PositioningEnabledInView( file_mgr_data ) )
4518          {
4519            file_mgr_rec->menuStates |= CLEAN_UP;
4520            XtSetValues(fileMgrPopup.wsPopup[BTN_CLEANUP], args, 1);
4521          }
4522          else
4523          {
4524            file_mgr_rec->menuStates &= ~(CLEAN_UP);
4525            XtUnmanageChild( fileMgrPopup.wsPopup[BTN_CLEANUP] );
4526          }
4527          XtSetValues(fileMgrPopup.wsPopup[BTN_SELECTALL], args, 1);
4528
4529          /* unmanage the action portion of the popup menu */
4530          XtUnmanageChild(fileMgrPopup.action_separator);
4531
4532          action_pane = (XmManagerWidget) fileMgrPopup.menu;
4533          for(i=num_of_children; i<action_pane->composite.num_children; i++)
4534             XtUnmanageChild(action_pane->composite.children[i]);
4535       }
4536       else
4537       {
4538          Dimension margin;
4539
4540          /* manage the properties and show hidden files buttons */
4541          if( file_mgr_data->toolbox )
4542            XtUnmanageChild(fileMgrPopup.wsPopup[BTN_PROPERTIES]);
4543          else
4544            XtManageChild(fileMgrPopup.wsPopup[BTN_PROPERTIES]);
4545          XtManageChild(fileMgrPopup.wsPopup[BTN_FIND]);
4546          XtManageChild(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN]);
4547
4548          /* Set popup menu label */
4549          label_string = XmStringCreateLocalized ((GETMESSAGE(33, 2, "Current Folder")));
4550          XtSetArg (args[0], XmNlabelString, label_string);
4551          XtSetValues (fileMgrPopup.title, args, 1);
4552          XtManageChild(fileMgrPopup.title);
4553          XmStringFree (label_string);
4554
4555          /* align the menu buttons */
4556          action_pane = (XmManagerWidget) fileMgrPopup.menu;
4557          XtSetArg(args[0], XmNmarginLeft, &margin);
4558          XtGetValues(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN], args, 1);
4559          XtSetArg(args[0], XmNmarginLeft, margin);
4560
4561          if( PositioningEnabledInView( file_mgr_data ) )
4562          {
4563            file_mgr_rec->menuStates |= CLEAN_UP;
4564            XtSetValues(fileMgrPopup.wsPopup[BTN_CLEANUP], args, 1);
4565          }
4566          else
4567          {
4568            file_mgr_rec->menuStates &= ~(CLEAN_UP);
4569            XtUnmanageChild( fileMgrPopup.wsPopup[BTN_CLEANUP] );
4570          }
4571
4572          XtSetValues(fileMgrPopup.wsPopup[BTN_SELECTALL], args, 1);
4573
4574          if(showFilesystem )
4575          {
4576            if (file_mgr_data->show_hid_enabled)
4577              XmToggleButtonGadgetSetState(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN], True, False);
4578            else
4579              XmToggleButtonGadgetSetState(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN], False, False);
4580          }
4581
4582          /* ensure that there was fileViewData for the current directory */
4583          if(fileViewData != NULL)
4584          {
4585             /* attach the current fileViewData to the 'Properties' button */
4586            if( ! file_mgr_data->toolbox )
4587            {
4588              XtRemoveAllCallbacks(fileMgrPopup.wsPopup[BTN_PROPERTIES],
4589                                   XmNactivateCallback);
4590              XtAddCallback (fileMgrPopup.wsPopup[BTN_PROPERTIES],
4591                             XmNactivateCallback,
4592                             ShowModAttrDialog, (XtPointer) fileViewData);
4593
4594              /* sensitize the 'Properties' option */
4595              XtSetSensitive(fileMgrPopup.wsPopup[BTN_PROPERTIES], True);
4596            }
4597             /* update the actions portion of the popup menu */
4598             XtManageChild(fileMgrPopup.action_separator);
4599
4600             XtFree(fileMgrPopup.action_pane_file_type);
4601             fileMgrPopup.action_pane_file_type =
4602                 XtNewString(fileViewData->file_data->logical_type);
4603
4604             UpdateActionMenuPane ((XtPointer)fileViewData, file_mgr_rec,
4605                                   fileViewData->file_data->logical_type,
4606                                   FM_POPUP, num_of_children,
4607                                   fileMgrPopup.menu,
4608                                   fileViewData->file_data->physical_type);
4609
4610             /* align actions portion of the popup menu */
4611             for(i=num_of_children; i<action_pane->composite.num_children; i++)
4612               XtSetValues(action_pane->composite.children[i], args, 1);
4613          }
4614          else
4615          {
4616            if( ! file_mgr_data->toolbox )
4617            {
4618              /* remove callback from 'Properties' button */
4619              XtRemoveAllCallbacks(fileMgrPopup.wsPopup[BTN_PROPERTIES],
4620                                   XmNactivateCallback);
4621
4622              /* desensitize the 'Properties' button */
4623              XtSetSensitive(fileMgrPopup.wsPopup[BTN_PROPERTIES], False);
4624            }
4625
4626             /* unmanage the action portion of the popup menu */
4627             XtUnmanageChild(fileMgrPopup.action_separator);
4628
4629             for(i=num_of_children; i<action_pane->composite.num_children; i++)
4630                XtUnmanageChild(action_pane->composite.children[i]);
4631          }
4632       }
4633    }
4634
4635    /* we are dealing with an object popup */
4636    else
4637    {
4638       char label[MAX_PATH];
4639
4640       /* retrieve the fileViewData for the selected icon */
4641       if (client_data)
4642          fileViewData = (FileViewData *) client_data;
4643       else if (file_mgr_data->selected_file_count != 0)
4644          fileViewData = file_mgr_data->selection_list[0];
4645
4646
4647       /* unmanage the white space buttons */
4648       XtUnmanageChildren(fileMgrPopup.wsPopup, WS_BTNS);
4649
4650       if(file_mgr_data == trashFileMgrData)
4651       {
4652           file_mgr_data->popup_menu_icon = fileViewData;
4653
4654          /* Set popup menu label */
4655          if( file_mgr_data->selected_file_count > 1
4656              && InMultipleObjectRegion(file_mgr_data, fileViewData))
4657          {
4658
4659            label_string = XmStringCreateLocalized ((GETMESSAGE(33,1, "Multiple Objects")));
4660          }
4661          else
4662          {
4663            char *tmp_label;
4664
4665            if (fileViewData->file_data->action_name)
4666               tmp_label = fileViewData->file_data->action_name;
4667            else
4668               tmp_label = fileViewData->file_data->file_name;
4669
4670            if( strlen( tmp_label ) > 20 )
4671              sprintf( label, "%-20.20s...", tmp_label );
4672            else
4673              sprintf( label, "%s", tmp_label );
4674
4675            label_string = XmStringCreateLocalized (label);
4676          }
4677          XtSetArg (args[0], XmNlabelString, label_string);
4678          XtSetValues (fileMgrPopup.title, args, 1);
4679          XtManageChild(fileMgrPopup.title);
4680          XmStringFree (label_string);
4681
4682          /* trash popup--unmanage the non-trash buttons, manage the trash */
4683          XtUnmanageChildren(fileMgrPopup.objPopup, obj_btns);
4684          XtManageChildren(fileMgrPopup.trash_objPopup, TRASH_OBJ_BTNS);
4685
4686          /* adjust callbacks */
4687          XtRemoveAllCallbacks(fileMgrPopup.trash_objPopup[BTN_RESTORE],
4688                               XmNactivateCallback);
4689          XtAddCallback(fileMgrPopup.trash_objPopup[BTN_RESTORE],
4690                        XmNactivateCallback, Restore, (XtPointer) fileViewData);
4691
4692          XtRemoveAllCallbacks(fileMgrPopup.trash_objPopup[BTN_REMOVE],
4693                               XmNactivateCallback);
4694          XtAddCallback(fileMgrPopup.trash_objPopup[BTN_REMOVE],
4695                        XmNactivateCallback, ConfirmRemove,
4696                        (XtPointer) fileViewData);
4697
4698          /* unmanage the action portion of the popup menu */
4699          XtUnmanageChild(fileMgrPopup.action_separator);
4700
4701          action_pane = (XmManagerWidget) fileMgrPopup.menu;
4702          for(i=num_of_children; i<action_pane->composite.num_children; i++)
4703             XtUnmanageChild(action_pane->composite.children[i]);
4704       }
4705       else
4706       {
4707          /* non-trash popup--manage the non-trash buttons, unmanage the trash */
4708          XtManageChildren(fileMgrPopup.objPopup, obj_btns);
4709          XtUnmanageChildren(fileMgrPopup.trash_objPopup, TRASH_OBJ_BTNS);
4710          if( file_mgr_data->toolbox )
4711            XtUnmanageChild(fileMgrPopup.objPopup[BTN_PROPERTIES]);
4712
4713          if(file_mgr_data->selected_file_count > 1
4714             && InMultipleObjectRegion(file_mgr_data, fileViewData))
4715          {
4716             /* we have many files selected; remove callbacks from the  */
4717             /* 'Properties', 'Put on Desktop', and 'Review' buttons    */
4718             /* and attach the selection list to the remaining buttons; */
4719             /* desensitize the 3 buttons listed above; unmanage the    */
4720             /* actions part of the popup menu                          */
4721
4722            /* adjust callbacks */
4723            if( ! file_mgr_data->toolbox )
4724              XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PROPERTIES],
4725                                   XmNactivateCallback);
4726
4727            XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PUTON],
4728                                 XmNactivateCallback);
4729            XtAddCallback(fileMgrPopup.objPopup[BTN_PUTON], XmNactivateCallback,
4730                          PutOnDTCB, (XtPointer) fileViewData);
4731
4732            XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_TRASH],
4733                                 XmNactivateCallback);
4734            XtAddCallback(fileMgrPopup.objPopup[BTN_TRASH], XmNactivateCallback,
4735                          TrashFiles, (XtPointer) fileViewData);
4736
4737            if( file_mgr_data->toolbox && geteuid() != root_user &&
4738                    access(file_mgr_data->current_directory,W_OK|X_OK) != 0)
4739              XtSetSensitive(fileMgrPopup.objPopup[BTN_TRASH], False);
4740
4741
4742            /* sensitize buttons */
4743            if( !file_mgr_data->toolbox )
4744              XtSetSensitive(fileMgrPopup.objPopup[BTN_PROPERTIES], False);
4745
4746            XtSetSensitive(fileMgrPopup.objPopup[BTN_HELP], False);
4747
4748            /* Set popup menu label */
4749            label_string = XmStringCreateLocalized ((GETMESSAGE(33, 1, "Multiple Objects")));
4750            XtSetArg (args[0], XmNlabelString, label_string);
4751            XtSetValues (fileMgrPopup.title, args, 1);
4752            XtManageChild(fileMgrPopup.title);
4753            XmStringFree (label_string);
4754
4755
4756            /* unmanage actions */
4757            XtUnmanageChild(fileMgrPopup.action_separator);
4758            action_pane = (XmManagerWidget) fileMgrPopup.menu;
4759            for(i = num_of_children;
4760                i < action_pane->composite.num_children;
4761                i++)
4762              XtUnmanageChild(action_pane->composite.children[i]);
4763          }
4764          else
4765          {
4766            char *tmp_label;
4767
4768            /* we have one file selected; attach fileViewData to buttons; */
4769            /* sensitize any desensitized buttons; update the actions     */
4770            /* part of the popup menu                                     */
4771
4772            /* adjust callbacks */
4773            if( ! file_mgr_data->toolbox )
4774            {
4775              XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PROPERTIES],
4776                                   XmNactivateCallback);
4777              XtAddCallback(fileMgrPopup.objPopup[BTN_PROPERTIES],
4778                            XmNactivateCallback, ShowModAttrDialog, (XtPointer) fileViewData);
4779            }
4780
4781             XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PUTON],
4782                                  XmNactivateCallback);
4783             XtAddCallback(fileMgrPopup.objPopup[BTN_PUTON],
4784                  XmNactivateCallback, PutOnDTCB, (XtPointer) fileViewData);
4785
4786             XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_TRASH],
4787                                  XmNactivateCallback);
4788             XtAddCallback(fileMgrPopup.objPopup[BTN_TRASH],
4789                  XmNactivateCallback, TrashFiles, (XtPointer) fileViewData);
4790
4791            if ( file_mgr_data->toolbox && geteuid() != root_user &&
4792                    access(file_mgr_data->current_directory,W_OK|X_OK) != 0 )
4793              XtSetSensitive(fileMgrPopup.objPopup[BTN_TRASH], False);
4794            else
4795              XtSetSensitive(fileMgrPopup.objPopup[BTN_TRASH], True);
4796
4797
4798             XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_HELP],
4799                                  XmNactivateCallback);
4800             XtAddCallback(fileMgrPopup.objPopup[BTN_HELP],
4801                  XmNactivateCallback, ObjectHelp, (XtPointer) fileViewData->widget);
4802
4803             /* sensitize buttons */
4804             if( ! file_mgr_data->toolbox )
4805               XtSetSensitive(fileMgrPopup.objPopup[BTN_PROPERTIES], True);
4806
4807             XtSetSensitive(fileMgrPopup.objPopup[BTN_PUTON], True);
4808             XtSetSensitive(fileMgrPopup.objPopup[BTN_HELP], True);
4809
4810             if (fileViewData->file_data->action_name)
4811                tmp_label = fileViewData->file_data->action_name;
4812             else
4813                tmp_label = fileViewData->file_data->file_name;
4814
4815             if( strlen( tmp_label ) > 20 )
4816               sprintf( label, "%-20.20s...", tmp_label );
4817             else
4818               sprintf( label, "%s", tmp_label );
4819
4820             /* Set popup menu label */
4821             label_string = XmStringCreateLocalized (label);
4822             XtSetArg (args[0], XmNlabelString, label_string);
4823             XtSetValues (fileMgrPopup.title, args, 1);
4824             XtManageChild(fileMgrPopup.title);
4825             XmStringFree (label_string);
4826
4827
4828             /* update actions */
4829             XtManageChild(fileMgrPopup.action_separator);
4830
4831             XtFree(fileMgrPopup.action_pane_file_type);
4832             fileMgrPopup.action_pane_file_type =
4833                 XtNewString(fileViewData->file_data->logical_type);
4834
4835             UpdateActionMenuPane ((XtPointer)fileViewData, file_mgr_rec,
4836                                   fileViewData->file_data->logical_type,
4837                                   FM_POPUP, num_of_children,
4838                                   fileMgrPopup.menu,
4839                                   fileViewData->file_data->physical_type);
4840
4841             /* align actions */
4842             action_pane = (XmManagerWidget) fileMgrPopup.menu;
4843             XtSetArg(args[0], XmNmarginLeft, 0);
4844             for(i = num_of_children; i < action_pane->composite.num_children; i++)
4845               XtSetValues(action_pane->composite.children[i], args, 1);
4846          }
4847       }
4848    }
4849
4850
4851    /* position and manage popup menu */
4852    if(event == NULL)
4853    {
4854       Position x, y;
4855       Dimension width, height;
4856       Dimension gWidth, gHeight;
4857       int displayWidth, displayHeight;
4858       DtIconGadget  g = (DtIconGadget)w;
4859
4860       XtSetArg (args[0], XmNwidth, &width);
4861       XtSetArg (args[1], XmNheight, &height);
4862       XtGetValues(XtParent(fileMgrPopup.menu), args, 2);
4863
4864       gWidth = g->icon.pixmap_width;
4865       gHeight = g->icon.pixmap_height;
4866
4867       displayWidth = DisplayWidth(XtDisplay(w), DefaultScreen(XtDisplay(w)));
4868       displayHeight =DisplayHeight(XtDisplay(w), DefaultScreen(XtDisplay(w)));
4869
4870       x = file_mgr_rec->shell->core.x +
4871           file_mgr_rec->scroll_window->core.x +
4872           w->core.x + gWidth/2;;
4873
4874       y = file_mgr_rec->shell->core.y +
4875           file_mgr_rec->header_frame->core.y +
4876           file_mgr_rec->header_frame->core.height +
4877           file_mgr_rec->scroll_window->core.y +
4878           w->core.y + gHeight/2;;
4879
4880       if((Dimension)(x + width) > (Dimension)displayWidth)
4881          x = displayWidth - width - 4;
4882       if((Dimension)(y + height) > (Dimension)displayHeight)
4883          y = displayHeight - height - 4;
4884
4885       XtSetArg (args[0], XmNx, x);
4886       XtSetArg (args[1], XmNy, y);
4887       XtSetValues(XtParent(fileMgrPopup.menu), args, 2);
4888    }
4889    else
4890    {
4891      if(( event->type == ButtonPress || event->type == ButtonRelease) ||
4892         ( ( event->type == KeyPress || event->type == KeyRelease) &&
4893           _XmIsEventUnique(event) ) )
4894      {
4895        XmMenuPosition(fileMgrPopup.menu, (XButtonPressedEvent *)event);
4896      }
4897    }
4898
4899    XtManageChild(fileMgrPopup.menu);
4900
4901    if( event->type == KeyPress || event->type == KeyRelease )
4902    {
4903      /* Specify that the focus is being moved by key, NOT mouse
4904      */
4905      _XmSetInDragMode(fileMgrPopup.menu,False);
4906
4907      XmProcessTraversal(fileMgrPopup.menu,XmTRAVERSE_CURRENT);
4908
4909      /* This function is being called twice.
4910         Record this event so the above check _XmIsEventUnique will work
4911      */
4912      _XmRecordEvent(event);
4913    }
4914 }
4915
4916
4917 static void
4918 DropOnRootCB (
4919      Widget w,
4920      XtPointer client_data,
4921      XtPointer call_data)
4922 {
4923    DtDndDropCallbackStruct *fileList = (DtDndDropCallbackStruct *)call_data;
4924    char * ptr;
4925    char ** file_set = NULL;
4926    char ** host_set = NULL;
4927    FileMgrRec * file_mgr_rec;
4928    FileMgrData * file_mgr_data;
4929    char   *next;
4930    int i, j;
4931    int wsNum;
4932    String end;
4933    String tmpStr;
4934    int numFiles;
4935    int effScreenWidth;
4936    int effScreenHeight;
4937    int start_x = 0, start_y = 0;
4938    int root_x, root_y;
4939    int step = 0, dstep = 0;
4940
4941    /* Check the protocol, set to failure if not the */
4942    /* File Transfer protocol                        */
4943    if (fileList->dropData->protocol != DtDND_FILENAME_TRANSFER)
4944      {
4945        fileList->status = DtDND_FAILURE;
4946        return;
4947      }
4948
4949
4950    numFiles = fileList->dropData->numItems;
4951
4952    DPRINTF (("DropOnRoot: Number of files dropped are %d\n", numFiles));
4953
4954    if(fileList->reason != DtCR_DND_DROP_ANIMATE)
4955    {
4956       /* set the complete move flag to False since it is not required to be called */
4957       /* In case when the drag is from non File manager client */
4958       if(!dragActive)
4959         initiating_view = NULL;
4960
4961       fileList->completeMove = False;
4962
4963       _DtSetDroppedFileInfo(fileList, &file_set, &host_set);
4964
4965       if(initiating_view != NULL)
4966       {
4967          file_mgr_rec = (FileMgrRec *)
4968                      (((FileMgrData *) initiating_view)->file_mgr_rec);
4969          file_mgr_data = (FileMgrData *) initiating_view;
4970       }
4971       else
4972          file_mgr_data = NULL;
4973
4974       /* get the correct position for the desktop icon shell */
4975       PositionDesktopIcon(fileList->x, fileList->y, &root_x, &root_y);
4976
4977       if (numFiles > 1)
4978       {
4979          /*
4980           * We will place the icons by marching down a diagonal starting
4981           * at the drop point.  But we don't want to march off-screen
4982           * if there are too many icons.  So ...
4983           *  - We choose a step width of 20, 10, 5, or 2 depending
4984           *    on the number of icons dropped.
4985           *  - When we run into the edge of the screen, we start a new
4986           *    diagonal shifted one step to the right.
4987           *  - If all icons still won't fit, we move the starting point
4988           *    closer to the top left corner of the screen.
4989           */
4990
4991          /* compute effective screen size (largest x,y where an icon
4992           * can be placed without going off-screen) */
4993          effScreenWidth = WidthOfScreen(XtScreen(w)) - (4 + 4+48+4 + 5);
4994          effScreenHeight = HeightOfScreen(XtScreen(w)) - (4 + 4+48+3+15+4 + 5);
4995
4996          /* chosee step depending on number of icons */
4997          if (numFiles <= 200)
4998            step = 20;
4999          else if (numFiles <= 400)
5000            step = 10;
5001          else  if (numFiles <= 1000)
5002            step = 5;
5003          else
5004            step = 2;
5005          dstep = 40 + 4+48+4 + 5;
5006
5007          /* choose starting point so at least two icons will fit */
5008          if (root_x <= effScreenWidth - step)
5009            start_x = root_x;
5010          else
5011            start_x = effScreenWidth - step;
5012
5013          if (root_y <= effScreenWidth - step)
5014            start_y = root_y;
5015          else
5016            start_y = effScreenWidth - step;
5017
5018          DPRINTF(("DropOnRootCB: numFiles %d, root_x %d, root_y %d, step %d\n",
5019                   numFiles, root_x, root_y, step));
5020
5021          /* check if all icons will fit */
5022          for (;;)
5023          {
5024            /* cacluclate how many will fit (add up icons on all diagonals) */
5025            int n = 0, nd = 0;
5026            for (root_x = start_x; root_x <= effScreenWidth; root_x += dstep)
5027            {
5028              int nx = (effScreenWidth - root_x)/step + 1;
5029              int ny = (effScreenHeight - start_y)/step + 1;
5030              n += (nx <= ny)? nx: ny;
5031              nd++;
5032            }
5033
5034            DPRINTF(("start_x %d, start_y %d, nd %d, n %d\n",
5035                     start_x, start_y, nd, n));
5036
5037            /* if everything fits - great! */
5038            if (n >= numFiles)
5039              break;
5040
5041            /* move the start point closer to the top left corner */
5042            if (effScreenWidth - start_x < effScreenHeight - start_y &&
5043                start_x >= step)
5044            {
5045              /* move left so more icons will fit */
5046              start_x -= step;
5047            }
5048            else if (effScreenWidth - start_x > effScreenHeight - start_y &&
5049                     start_y >= step)
5050            {
5051              /* move up so one more icon will fit in each diagonal */
5052              start_y -= step;
5053            }
5054            else if (start_x > 0 || start_y > 0)
5055            {
5056              /* move left and up */
5057              if (start_x >= step)
5058                start_x -= step;
5059              else
5060                start_x = 0;
5061              if (start_y >= step)
5062                start_y -= step;
5063              else
5064                start_y = 0;
5065            }
5066            else
5067              /* ran out of space - too bad! */
5068              break;
5069          }
5070          root_x = start_x;
5071          root_y = start_y;
5072       }
5073
5074       /* the icon that was dropped on the root window was an
5075          icon that was already on the root window */
5076       if (file_mgr_data == NULL)
5077       {
5078          DPRINTF(("DropOnRoot: Object already on Desktop\n"));
5079
5080          /* loop through the existing desktop icons to determine which
5081             ones are being dragged, then change their location */
5082          for(i=0; i < desktop_data->numIconsUsed; i++)
5083          {
5084             if((Widget)desktop_data->desktopWindows[i]->iconGadget ==
5085                                                    (Widget)widget_dragged)
5086             {
5087                if (DTFileIsSelected(desktop_data->desktopWindows[i],
5088                       desktop_data->desktopWindows[i]->file_view_data))
5089                {
5090                  for(j=0;j< desktop_data->numWorkspaces;j++)
5091                    if(desktop_data->workspaceData[j]->number ==
5092                       desktop_data->desktopWindows[i]->workspace_num)
5093                      break;
5094                  wsNum = j;
5095                  for (j = 0;
5096                       j < desktop_data->workspaceData[wsNum]->files_selected;
5097                       j++)
5098                  {
5099                    RelocateDesktopIcon(desktop_data->workspaceData[wsNum]->
5100                                        selectedDTWindows[j],
5101                                        root_x, root_y);
5102                    root_x += step;
5103                    root_y += step;
5104                    if (root_x > effScreenWidth || root_y > effScreenHeight)
5105                    {
5106                      start_x += dstep;
5107                      if (start_x > effScreenWidth)
5108                        start_x = 0;
5109                      root_x = start_x;
5110                      root_y = start_y;
5111                    }
5112                  }
5113                }
5114                else
5115                {
5116                   RelocateDesktopIcon(desktop_data->desktopWindows[i],
5117                                       root_x, root_y);
5118                   break;
5119                }
5120             }
5121          }
5122       }
5123       else if( file_mgr_data == trashFileMgrData )
5124       {
5125          /* if the file manager data is the trash, we want to tell the
5126             user that they can't drop trash on the desktop
5127          */
5128          char * msg;
5129          char * tmpStr;
5130
5131          DPRINTF(("DropOnRoot: Attempting to Drag Trash Object to Desktop\n"));
5132          file_mgr_rec = (FileMgrRec *)trashFileMgrData->file_mgr_rec;
5133          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."));
5134          msg = XtNewString(tmpStr);
5135          FileOperationError (file_mgr_rec->main, msg, NULL);
5136          XtFree(msg);
5137          return;
5138       }
5139       else /* it was dropped on the root window so lets process it */
5140       {
5141         int EndIndex = desktop_data->numIconsUsed;
5142
5143         for(i = 0; i < numFiles; i++)
5144         {
5145           ptr = strrchr(file_set[i], '/');
5146           if( strcmp(file_mgr_data->current_directory, file_set[i]) == 0)
5147           {
5148             SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
5149                                file_mgr_data, file_mgr_rec,
5150                                ".", host_set[i], file_set[i],
5151                                root_x, root_y,
5152                                NULL,EndIndex);
5153           }
5154           else if(strncmp(file_mgr_data->current_directory, file_set[i], strlen(file_set[i]) ) == 0 )
5155           {
5156             SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
5157                                file_mgr_data, file_mgr_rec,
5158                                "..", host_set[i],file_mgr_data->current_directory,
5159                                root_x, root_y,
5160                                NULL,EndIndex);
5161           }
5162           else
5163           {
5164             *ptr = '\0';
5165             if(*(file_set[i]) == 0)
5166             {
5167               SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
5168                                  file_mgr_data, file_mgr_rec,
5169                                  ptr + 1, host_set[i], "/",
5170                                  root_x, root_y,
5171                                  NULL,EndIndex);
5172             }
5173             else
5174             {
5175               SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
5176                                  file_mgr_data, file_mgr_rec,
5177                                  ptr + 1, host_set[i], file_set[i],
5178                                  root_x, root_y,
5179                                  NULL,EndIndex);
5180             }
5181           }
5182           root_x += step;
5183           root_y += step;
5184           if (root_x > effScreenWidth || root_y > effScreenHeight)
5185           {
5186             start_x += dstep;
5187             if (start_x > effScreenWidth)
5188               start_x = 0;
5189             root_x = start_x;
5190             root_y = start_y;
5191           }
5192         }
5193         initiating_view = (XtPointer)NULL;
5194       }
5195
5196       _DtFreeDroppedFileInfo(numFiles, file_set, host_set);
5197
5198       return;
5199    }
5200 }
5201
5202 /************************************************************************
5203  *
5204  *  FreeLayoutData
5205  *
5206  ************************************************************************/
5207
5208 void
5209 FreeLayoutData(XtPointer p)
5210 {
5211    IconLayoutData *layout_data;
5212
5213    if (p == NULL)
5214       return;
5215
5216    layout_data = (IconLayoutData *)p;
5217
5218    if (layout_data->work_id != 0)
5219    {
5220       DPRINTF(("FreeLayoutData: removing workproc\n"));
5221       XtRemoveWorkProc(layout_data->work_id);
5222       XmDropSiteEndUpdate(layout_data->drop_site_w);
5223    }
5224
5225    XtFree((char *)layout_data->order_list);
5226    layout_data->order_list = NULL;
5227    XtFree((char *)layout_data->reuse_icons);
5228    layout_data->reuse_icons = NULL;
5229    XtFree((char *)layout_data->reuse_btns);
5230    layout_data->reuse_btns = NULL;
5231    XtFree((char *)layout_data->manage);
5232    layout_data->manage = NULL;
5233
5234    XtFree((char *)layout_data);
5235    layout_data = NULL;
5236 }
5237
5238 /************************************************************************
5239  *
5240  *  UnmanageFileIcons
5241  *      Unmanage a subset of the file icons.
5242  *
5243  ************************************************************************/
5244
5245 void UnmanageFileIcons(
5246         FileMgrRec *file_mgr_rec,
5247         FileMgrData *file_mgr_data,
5248         FileViewData *file_view_data)
5249 {
5250    XmManagerWidget file_window;
5251    FileViewData **order_list;
5252    int order_count;
5253    int i, n;
5254    Widget *unmanage;
5255    Widget child;
5256    Arg args[20];
5257
5258
5259    /*  Set the size of the file window BIG so that it does not  */
5260    /*  try to force positioning on its children.                */
5261
5262    file_window = (XmManagerWidget) file_mgr_rec->file_window;
5263    XtResizeWidget ((Widget)file_window, 32767, 32767, 0);
5264
5265
5266    /*  Set the scrolled window and file window appropriately  */
5267    /*  to prevent a lot of gyrations.                         */
5268
5269    XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmSTATIC);
5270    XtSetValues (file_mgr_rec->scroll_window, args, 1);
5271
5272    order_list = ((IconLayoutData *)file_mgr_data->layout_data)->order_list;
5273    order_count = ((IconLayoutData *)file_mgr_data->layout_data)->order_count;
5274
5275    unmanage = (Widget *)XtMalloc(2*order_count*sizeof(Widget));
5276    n = 0;
5277    for (i = 0; i < order_count; i++)
5278    {
5279      if (order_list[i]->filtered)
5280        continue;
5281
5282      if ((n > 0 || order_list[i] == file_view_data) &&
5283          !order_list[i]->need_update)
5284      {
5285        unmanage[n++] = order_list[i]->widget;
5286        if (order_list[i]->treebtn)
5287          unmanage[n++] = order_list[i]->treebtn;
5288      }
5289    }
5290
5291    /* remember which icon currently has the focus */
5292    if (XtIsManaged(file_mgr_rec->file_window))
5293    {
5294       /* see if the focus is inside the file window */
5295       child = XmGetFocusWidget(file_mgr_rec->file_window);
5296       if (child != NULL && XtParent(child) == file_mgr_rec->file_window)
5297          file_mgr_rec->focus_widget = child;
5298    }
5299
5300    /* unmanage the selected children */
5301    if (n > 0)
5302       XtUnmanageChildren(unmanage, n);
5303
5304    XtFree((char *)unmanage);
5305 }
5306
5307
5308 /************************************************************************
5309  *
5310  *  UpdateFileIcons
5311  *      Create or reuse a set of file icons used to get the files
5312  *      displayed.  This is never called for the desktop.
5313  *
5314  ************************************************************************/
5315
5316 void
5317 UpdateFileIcons(
5318         FileMgrRec *file_mgr_rec,
5319         FileMgrData *file_mgr_data,
5320         Boolean new_directory)
5321 {
5322   _UpdateFileIcons(file_mgr_rec, file_mgr_data, new_directory, NULL);
5323 }
5324
5325 void
5326 AddFileIcons(
5327         FileMgrRec *file_mgr_rec,
5328         FileMgrData *file_mgr_data,
5329         DirectorySet * add_dir_set)
5330 {
5331   _UpdateFileIcons(file_mgr_rec, file_mgr_data, False, add_dir_set);
5332 }
5333
5334
5335 /*--------------------------------------------------------------------
5336  * MakeReuseList
5337  *
5338  *   Background information:
5339  *     After a refresh on a directory we want to reuse old icon and tree
5340  *   button widgets instead of destroying the old widgets and creating
5341  *   new ones.  Fourthermore, we want to reuse the same widgets for the
5342  *   same files, so that if the icon and/or label didn't change, less
5343  *   work needs to be done in _UpdateFileIcons().
5344  *     For this reason, after a refresh the GetFileData() routine copies
5345  *   Widgets from the old FileViewData list to the new FileViewData list
5346  *   for files that are both on the old and new list (i.e., files that
5347  *   already existed before the refresh and are still there after the
5348  *   refresh).  This allows _UpdateFileIcons() to reuse the old
5349  *   widget.
5350  *
5351  *   The purpose of MakeReuseList() is to find widgets that are no
5352  *   longer found in the new FileViewData list.  These are widgets
5353  *   from files that disappeared after the refresh (either because the
5354  *   file was deleted or because file is now filtered out).  These
5355  *   widgets can then be reused by _UpdateFileIcons()for new files that
5356  *   just appeared after the refresh.
5357  *
5358  *------------------------------------------------------------------*/
5359
5360 /* compare function for qsort and bsearch */
5361 static int
5362 WidgetCmp(Widget *w1, Widget *w2)
5363 {
5364   return *w1 - *w2;
5365 }
5366
5367 static void
5368 MakeReuseList(
5369         Widget *children,
5370         int num_children,
5371         FileViewData **order_list,
5372         int order_count,
5373         Widget **reuse_icons,
5374         Widget **reuse_btns)
5375 {
5376 #ifdef DEBUG
5377    int n_old, n_filtered, del_icon, del_btn;
5378 #endif
5379    Widget *sorted_chilren = NULL;
5380    Boolean *reuse = NULL;
5381    int icon_count;
5382    int btn_count;
5383    int i;
5384    Widget *p;
5385    Widget w;
5386
5387    /* allocate widget arrays */
5388    *reuse_icons = (Widget *)XtMalloc((num_children + 1)*sizeof(Widget));
5389    *reuse_btns = (Widget *)XtMalloc((num_children + 1)*sizeof(Widget));
5390    icon_count = btn_count = 0;
5391
5392    /* only figure things out if we already have children */
5393    if (num_children > 0) {
5394      /* create a sorted list of children */
5395      sorted_chilren = (Widget *)XtMalloc(num_children * sizeof(Widget));
5396      memcpy(sorted_chilren, children, num_children * sizeof(Widget));
5397      qsort(sorted_chilren, num_children, sizeof(Widget), (int (*)())WidgetCmp);
5398
5399      /* create reuse flags; initially assume all children can be reused */
5400      reuse = (Boolean *)XtMalloc(num_children * sizeof(Boolean));
5401      for (i = 0; i < num_children; i++)
5402        reuse[i] = True;
5403
5404    /* reset reuse flag for all widgets found in order_list */
5405 #ifdef DEBUG
5406      n_old = n_filtered = del_icon = del_btn = 0;
5407 #endif
5408      for (i = 0; i < order_count; i++)
5409        {
5410          if (order_list[i]->filtered &&
5411              strcmp(order_list[i]->file_data->file_name, ".") != 0)
5412            {
5413              /* don't reuse this widget later */
5414 #ifdef DEBUG
5415              n_filtered++;
5416              if (order_list[i]->widget)
5417                del_icon++;
5418              if (order_list[i]->treebtn)
5419                del_btn++;
5420 #endif
5421              order_list[i]->widget =
5422                order_list[i]->treebtn = NULL;
5423            }
5424          else
5425            {
5426              if (order_list[i]->widget)
5427                {
5428                  p = bsearch(&order_list[i]->widget,
5429                              sorted_chilren, num_children, sizeof(Widget),
5430                              (int (*)())WidgetCmp);
5431                  if (p)
5432                    {
5433                      /* don't reuse this widget for any other file */
5434                      reuse[p - sorted_chilren] = False;
5435 #ifdef DEBUG
5436                      n_old++;
5437 #endif
5438                    }
5439                  else
5440                    {
5441                      /* don't reuse this widget later */
5442                      order_list[i]->widget = NULL;
5443 #ifdef DEBUG
5444                      del_icon++;
5445 #endif
5446                    }
5447                }
5448
5449              if (order_list[i]->treebtn)
5450                {
5451                  p = bsearch(&order_list[i]->treebtn,
5452                              sorted_chilren, num_children, sizeof(Widget),
5453                              (int (*)())WidgetCmp);
5454                  if (p)
5455                    {
5456                      /* don't reuse this widget for any other file */
5457                      reuse[p - sorted_chilren] = False;
5458                    }
5459                  else
5460                    {
5461                      /* don't reuse this widget later */
5462                      order_list[i]->treebtn = NULL;
5463 #ifdef DEBUG
5464                      del_btn++;
5465 #endif
5466                    }
5467                }
5468            }
5469        }
5470
5471      /* copy reusable widgets into widget arrays */
5472      for (i = 0; i < num_children; i++)
5473        {
5474          if (reuse[i])
5475            {
5476              /* this widget can be reused for new files */
5477              w = sorted_chilren[i];
5478              if (XtClass(w) == dtIconGadgetClass)
5479                {
5480 #ifndef DELAYED_UNREGISTER
5481                  Arg args[1];
5482
5483                  XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
5484                  XtRemoveAllCallbacks(w, XmNdropCallback);
5485                  XtSetValues (w, args, 1);
5486 #endif
5487                  (*reuse_icons)[icon_count++] = w;
5488                }
5489              else if (XtClass(w) == xmPushButtonGadgetClass)
5490                (*reuse_btns)[btn_count++] = w;
5491            }
5492        }
5493    }
5494
5495    /* null-terminate the arrays */
5496    (*reuse_icons)[icon_count] = NULL;
5497    (*reuse_btns)[btn_count] = NULL;
5498
5499    /* free storage */
5500    XtFree((char *)sorted_chilren);
5501    XtFree((char *)reuse);
5502
5503    DPRINTF(("MakeReuseList: count %d (%d new, %d old, %d filtered)\n",
5504             order_count, order_count - n_filtered - n_old, n_old, n_filtered));
5505    DPRINTF(("               reuse %d + %d, del %d + %d\n",
5506             icon_count, btn_count, del_icon, del_btn));
5507 }
5508
5509
5510 /*--------------------------------------------------------------------
5511  * UpdateOneIconLabel
5512  *------------------------------------------------------------------*/
5513
5514 static void
5515 UpdateOneIconLabel(
5516         FileMgrData *file_mgr_data,
5517         FileViewData *file_view_data)
5518 {
5519    char *label;
5520    char *s;
5521
5522    /*  Get the label and icon to be used for the widget  */
5523    if (file_mgr_data->view != BY_ATTRIBUTES)
5524    {
5525       if (strcmp(file_view_data->file_data->file_name, "..") == 0)
5526       {
5527          /* label = ".. (go up)" */
5528          s = GetSharedMessage(UP_ONE_LEVEL_LABEL);
5529          label = (char *)XtMalloc(2 + strlen(s) + 1);
5530          strcpy(label, "..");
5531          strcat(label, s);
5532       }
5533       else if (file_mgr_data->view == BY_NAME &&
5534                file_view_data->file_data->physical_type == DtDIRECTORY &&
5535                file_mgr_data->show_type != MULTIPLE_DIRECTORY)
5536       {
5537          /* label = "name/" */
5538          label = (char *)XtMalloc(
5539                              strlen(file_view_data->file_data->file_name) + 2);
5540          strcpy(label, file_view_data->file_data->file_name);
5541          strcat(label, "/");
5542       }
5543       else if (file_mgr_data->view == BY_NAME &&
5544                file_view_data->file_data->physical_type == DtEXECUTABLE)
5545       {
5546          /* label = "name*" */
5547          label = (char *)XtMalloc(
5548                              strlen(file_view_data->file_data->file_name) + 2);
5549          strcpy(label, file_view_data->file_data->file_name);
5550          strcat(label, "*");
5551       }
5552       else if(file_view_data->file_data->action_name != NULL)
5553          /* label = action name */
5554          label = XtNewString(file_view_data->file_data->action_name);
5555       else
5556          /* label = file name */
5557          label = XtNewString(file_view_data->file_data->file_name);
5558    }
5559    else /* file_mgr_data->view == BY_ATTRIBUTES */
5560    {
5561       /* label = file name + attributes */
5562       label = GetLongName(file_view_data->file_data);
5563       if (strcmp(file_view_data->file_data->file_name, "..") == 0)
5564       {
5565          s = GetSharedMessage(UP_ONE_LEVEL_LABEL);
5566          label = (char *)XtRealloc(label, strlen(label) + strlen(s) + 1);
5567          strcat(label, s);
5568       }
5569    }
5570
5571    /* store new label */
5572    XtFree(file_view_data->label);
5573    file_view_data->label = label;
5574 }
5575
5576
5577 /*--------------------------------------------------------------------
5578  * UpdateOneFileIcon
5579  *------------------------------------------------------------------*/
5580
5581 static void
5582 UpdateOneFileIcon(
5583         FileMgrRec *file_mgr_rec,
5584         FileMgrData *file_mgr_data,
5585         FileViewData *file_view_data)
5586 {
5587    XmString icon_label;
5588    char *logical_type;
5589    PixmapData *pixmapData;
5590    Widget icon_widget;
5591    Widget btn_widget;
5592    Boolean is_instance_icon;
5593    Boolean instance_icon_changed;
5594    Arg args[35];
5595    int n_color_args;
5596    int argi_imageName;
5597    int n;
5598
5599    XmManagerWidget file_window = (XmManagerWidget) file_mgr_rec->file_window;
5600    DirectorySet *directory_set = (DirectorySet *)file_view_data->directory_set;
5601    IconLayoutData *layout_data = (IconLayoutData *)file_mgr_data->layout_data;
5602
5603    /* Get the label and icon to be used for the widget */
5604    if (!file_view_data->label)
5605      UpdateOneIconLabel(file_mgr_data, file_view_data);
5606
5607    icon_label = XmStringCreateLocalized(file_view_data->label);
5608
5609    /*  Get the icon name based on the file type  */
5610
5611    logical_type = file_view_data->file_data->logical_type;
5612
5613    if (file_mgr_data->view == BY_NAME)
5614       pixmapData = NULL;
5615    else if (openDirType == NEW &&
5616                file_view_data->file_data->physical_type == DtDIRECTORY)
5617    {
5618       pixmapData = CheckForOpenDirectory(file_view_data,
5619                                          directory_set,
5620                                          file_mgr_data,
5621                                          logical_type);
5622    }
5623    else
5624    {
5625       if (file_mgr_data->view == BY_NAME_AND_ICON)
5626          pixmapData = _DtRetrievePixmapData(
5627                          logical_type,
5628                          file_view_data->file_data->file_name,
5629                          directory_set->name,
5630                          (Widget) file_window,
5631                          LARGE);
5632       else
5633          pixmapData = _DtRetrievePixmapData(
5634                          logical_type,
5635                          file_view_data->file_data->file_name,
5636                          directory_set->name,
5637                          (Widget) file_window,
5638                          SMALL);
5639    }
5640
5641    /* check if this is an instance icon */
5642    is_instance_icon = False;
5643    if (pixmapData != NULL)
5644    {
5645      char tmp[1024];
5646
5647      strcpy(tmp, directory_set->name);
5648      strcat(tmp, "/");
5649      strcat(tmp, file_view_data->file_data->file_name);
5650      if (strcmp(pixmapData->iconFileName, tmp) == 0)
5651         is_instance_icon = True;
5652    }
5653
5654    /* check if instance icon was modified */
5655    instance_icon_changed = False;
5656    if (is_instance_icon)
5657    {
5658      if (file_view_data->icon_mtime != file_view_data->file_data->stat.st_mtime)
5659      {
5660         if (file_view_data->icon_mtime != 0)
5661            instance_icon_changed = True;
5662         file_view_data->icon_mtime = file_view_data->file_data->stat.st_mtime;
5663      }
5664    }
5665    else
5666      file_view_data->icon_mtime = 0;
5667
5668    /* Build the arg list for color resources.  */
5669    n = 0;
5670    XtSetArg (args[n], XmNarmColor, white_pixel);                     n++;
5671
5672    if (layout_data->background == white_pixel)
5673    {
5674       if (file_view_data->selected)
5675       {
5676          XtSetArg (args[n], XmNbackground, black_pixel);             n++;
5677          XtSetArg (args[n], XmNforeground, white_pixel);             n++;
5678       }
5679       else
5680       {
5681          XtSetArg (args[n], XmNbackground, white_pixel);             n++;
5682          XtSetArg (args[n], XmNforeground, layout_data->foreground); n++;
5683       }
5684       XtSetArg (args[n], XmNpixmapBackground, white_pixel);          n++;
5685       XtSetArg (args[n], XmNpixmapForeground, black_pixel);          n++;
5686    }
5687    else if (layout_data->background == black_pixel)
5688    {
5689       if (file_view_data->selected)
5690       {
5691          XtSetArg (args[n], XmNbackground, white_pixel);             n++;
5692          XtSetArg (args[n], XmNforeground, black_pixel);             n++;
5693       }
5694       else
5695       {
5696          XtSetArg (args[n], XmNbackground, black_pixel);             n++;
5697          XtSetArg (args[n], XmNforeground, layout_data->foreground); n++;
5698       }
5699       XtSetArg (args[n], XmNpixmapBackground, white_pixel);          n++;
5700       XtSetArg (args[n], XmNpixmapForeground, black_pixel);          n++;
5701    }
5702    else
5703    {
5704       if (file_view_data->selected)
5705       {
5706          XtSetArg (args[n], XmNbackground, white_pixel);             n++;
5707          XtSetArg (args[n], XmNforeground, black_pixel);             n++;
5708          XtSetArg (args[n], XmNpixmapBackground, white_pixel);       n++;
5709          XtSetArg (args[n], XmNpixmapForeground, black_pixel);       n++;
5710       }
5711       else
5712       {
5713          XtSetArg (args[n], XmNbackground, layout_data->background); n++;
5714          XtSetArg (args[n], XmNforeground, layout_data->foreground); n++;
5715          XtSetArg (args[n], XmNpixmapBackground, layout_data->pixmap_back); n++;
5716          XtSetArg (args[n], XmNpixmapForeground, layout_data->pixmap_fore); n++;
5717       }
5718    }
5719
5720    n_color_args = n;
5721
5722    /* Build the rest of the arg list and either create or reuse the widget. */
5723
5724    XtSetArg (args[n], XmNstring, icon_label);                        n++;
5725    argi_imageName = n;
5726    if (pixmapData)
5727      XtSetArg (args[n], XmNimageName, pixmapData->iconFileName);
5728    else
5729      XtSetArg (args[n], XmNimageName, NULL);
5730    n++;
5731    XtSetArg (args[n], XmNmaxPixmapWidth, layout_data->pixmap_width);   n++;
5732    XtSetArg (args[n], XmNmaxPixmapHeight, layout_data->pixmap_height); n++;
5733    XtSetArg (args[n], XmNuserData, directory_set);                     n++;
5734    XtSetArg (args[n], XmNunderline, False);                            n++;
5735    XtSetArg (args[n], XmNfillMode, XmFILL_TRANSPARENT);                n++;
5736    if (file_mgr_data->view == BY_NAME_AND_ICON &&
5737        file_mgr_data->show_type != MULTIPLE_DIRECTORY)
5738       XtSetArg (args[n], XmNpixmapPosition, XmPIXMAP_TOP);
5739    else
5740       XtSetArg (args[n], XmNpixmapPosition, XmPIXMAP_LEFT);            n++;
5741
5742    /* See if we can re-use the same or some other icon gadget */
5743    if (file_view_data->widget)
5744       icon_widget = file_view_data->widget;
5745    else if (*layout_data->next_icon_to_use)
5746       icon_widget = *layout_data->next_icon_to_use++;
5747    else
5748       icon_widget = NULL;
5749
5750    /* See if we found an available icon gadget */
5751    if (icon_widget)
5752    {
5753       /* reuse the icon gadget */
5754       if (icon_widget != file_view_data->widget || file_mgr_data->newSize)
5755       {
5756          XtSetArg (args[n], XmNdropSiteOperations, XmDROP_NOOP);n++;
5757          XtRemoveAllCallbacks(icon_widget, XmNdropCallback);
5758          file_view_data->registered = False;
5759       }
5760       XtRemoveAllCallbacks (icon_widget, XmNcallback);
5761
5762       /* if instance_icon_changed, force destroy of old pixmap */
5763       if (instance_icon_changed)
5764          XtSetArg (args[argi_imageName], XmNimageName, NULL);
5765
5766       /*
5767        * Move the gadget off the visible area; this avoids unnecessary
5768        * redraw events at the old position when the gadget is moved to
5769        * the correct position once it is determined in LayoutFileIcons.
5770        */
5771       icon_widget->core.x = -999;
5772       icon_widget->core.y = -999;
5773       XtSetValues (icon_widget, args, n);
5774
5775       if (instance_icon_changed && pixmapData)
5776       {
5777          XtSetArg (args[0], XmNimageName, pixmapData->iconFileName);
5778          XtSetValues (icon_widget, args, 1);
5779       }
5780    }
5781    else
5782    {
5783       /* create a new or duplicate an existing widget */
5784       XtSetArg (args[n], XmNshadowThickness, 2);             n++;
5785       XtSetArg (args[n], XmNdropSiteOperations, XmDROP_NOOP);n++;
5786       XtSetArg (args[n], XmNfontList, user_font);            n++;
5787       if( keybdFocusPolicy == XmEXPLICIT)
5788       {
5789          XtSetArg (args[n], XmNtraversalOn, True);           n++;
5790       }
5791       else
5792       {
5793          XtSetArg (args[n], XmNtraversalOn, False);          n++;
5794          XtSetArg (args[n], XmNhighlightThickness, 0);       n++;
5795       }
5796       XtSetArg (args[n], XmNborderType, DtNON_RECTANGLE);   n++;
5797
5798       if (layout_data->dup_icon_widget == NULL)
5799       {
5800 #ifdef HARDCODED_ICON_MARGINS
5801          XtSetArg (args[n], XmNmarginWidth, 0);  n++;
5802          XtSetArg (args[n], XmNmarginHeight, 0); n++;
5803 #endif
5804          XtSetArg (args[n], XmNx, -999);  n++;
5805          XtSetArg (args[n], XmNy, -999);  n++;
5806          icon_widget = layout_data->dup_icon_widget =
5807                    _DtCreateIcon ((Widget)file_window, "icon", args, n);
5808       }
5809       else
5810       {
5811          DtIconGadget g;
5812          int i = n_color_args;
5813
5814          icon_widget = _DtDuplicateIcon ((Widget)file_window,
5815                        layout_data->dup_icon_widget,
5816                        icon_label,
5817                        (pixmapData? pixmapData->iconFileName: NULL),
5818                        (XtPointer)directory_set, /* userData */
5819                        False);                   /* underline */
5820          g = (DtIconGadget)icon_widget;
5821          g->gadget.highlighted = False;
5822          g->gadget.highlight_drawn = False;
5823
5824          /*
5825           * Move the gadget off the visible area; this avoids unnecessary
5826           * redraw events at the old position when the gadget is moved to
5827           * the correct position once it is determined in LayoutFileIcons.
5828           */
5829          icon_widget->core.x = -999;
5830          icon_widget->core.y = -999;
5831
5832          /* make sure colors, drop operations, and clipping are right */
5833          XtSetArg(args[i], XmNdropSiteOperations, XmDROP_NOOP);             i++;
5834          XtSetArg(args[i], XmNmaxPixmapWidth, layout_data->pixmap_width);   i++;
5835          XtSetArg(args[i], XmNmaxPixmapHeight, layout_data->pixmap_height); i++;
5836          XtSetValues (icon_widget, args, i);
5837       }
5838       XtAddCallback(icon_widget, XmNhelpCallback,
5839                     (XtCallbackProc)HelpRequestCB, NULL);
5840       file_view_data->registered = False;
5841    }
5842
5843    if (file_mgr_data->view != BY_NAME)
5844       _DtCheckAndFreePixmapData(logical_type,
5845                                 (Widget) file_window,
5846                                 (DtIconGadget) icon_widget,
5847                                 pixmapData);
5848
5849 #ifdef _SHOW_LINK
5850    if (file_view_data->file_data->link != 0)
5851    {
5852       XtSetArg (args[0], XmNforeground, layout_data->topshadow);
5853       XtSetValues (icon_widget, args, 1);
5854    }
5855 #endif
5856
5857    /*
5858     * If viewing by attributes, adjust spacing between the icon pixmap and
5859     * the file name so that all file names are aligned.
5860     */
5861    if (file_mgr_data->view != BY_NAME_AND_ICON ||
5862        file_mgr_data->show_type == MULTIPLE_DIRECTORY)
5863    {
5864      Dimension pixmap_width = ((DtIconGadget)icon_widget)->icon.pixmap_width;
5865
5866      if (pixmap_width < layout_data->pixmap_width)
5867      {
5868         XtSetArg (args[0], XmNspacing,
5869               layout_data->spacing + layout_data->pixmap_width - pixmap_width);
5870         XtSetValues (icon_widget, args, 1);
5871      }
5872    }
5873
5874
5875    file_view_data->file_data->is_broken = False;
5876    file_view_data->widget = icon_widget;
5877    XtAddCallback (icon_widget, XmNcallback, (XtCallbackProc)IconCallback,
5878                   file_view_data);
5879
5880    XmStringFree (icon_label);
5881
5882    /* Check if we need a button for tree branch expand */
5883
5884    if (file_mgr_data->show_type != MULTIPLE_DIRECTORY ||
5885        !file_view_data->file_data->is_subdir)
5886    {
5887      /* no tree branch expand button needed */
5888      file_view_data->treebtn = NULL;
5889    }
5890    else
5891    {
5892      /* create a tree branch expand button */
5893      Pixmap px = GetTreebtnPixmap(file_mgr_data, file_view_data);
5894
5895      n = 0;
5896      XtSetArg(args[n], XmNlabelType, XmPIXMAP);                 n++;
5897      XtSetArg(args[n], XmNlabelPixmap, px);                     n++;
5898      XtSetArg(args[n], XmNbackground, layout_data->background); n++;
5899      XtSetArg(args[n], XmNtraversalOn, False);                  n++;
5900      XtSetArg(args[n], XmNhighlightThickness, 0);               n++;
5901      XtSetArg(args[n], XmNshadowThickness, 0);                  n++;
5902      XtSetArg(args[n], XmNmarginWidth, 0);                      n++;
5903      XtSetArg(args[n], XmNmarginHeight, 0);                     n++;
5904      XtSetArg(args[n], XmNuserData, file_mgr_data);             n++;
5905      XtSetArg(args[n], XmNx, -999);                             n++;
5906      XtSetArg(args[n], XmNy, -999);                             n++;
5907
5908      /* See if we can re-use the same or some other button gadget */
5909      if (file_view_data->treebtn)
5910         btn_widget = file_view_data->treebtn;
5911      else if (*layout_data->next_btn_to_use)
5912         btn_widget = *(layout_data->next_btn_to_use)++;
5913      else
5914         btn_widget = NULL;
5915
5916      /* See if we found an available button gadget */
5917      if (btn_widget) {
5918         XtRemoveAllCallbacks (btn_widget, XmNactivateCallback);
5919         XtSetValues (btn_widget, args, n);
5920      }
5921      else
5922      {
5923        btn_widget = XmCreatePushButtonGadget((Widget)file_window,
5924                                              "tree_button", args, n);
5925      }
5926      XtAddCallback(btn_widget, XmNactivateCallback,
5927                     (XtCallbackProc)TreeBtnCallback, file_view_data);
5928
5929      file_view_data->treebtn = btn_widget;
5930    }
5931
5932    /* this entry is now up-to-date */
5933    file_view_data->need_update = False;
5934 }
5935
5936
5937 /*--------------------------------------------------------------------
5938  * _UpdateFileIcons
5939  *------------------------------------------------------------------*/
5940
5941 static void
5942 _UpdateFileIcons(
5943         FileMgrRec *file_mgr_rec,
5944         FileMgrData *file_mgr_data,
5945         Boolean new_directory,
5946         DirectorySet * add_dir_set)
5947 {
5948    XmManagerWidget file_window;
5949    FileViewData **order_list;
5950    int order_count;
5951    Widget child;
5952    Arg args[5];
5953    IconLayoutData *layout_data;
5954    int i;
5955
5956 #ifdef DT_PERFORMANCE
5957    struct timeval update_time_s;
5958    struct timeval update_time_f;
5959 #endif
5960
5961    DPRINTF(("_UpdateFileIcons(\"%s\", new_dir %c, add_dir_set %p) ...\n",
5962             file_mgr_data->current_directory,
5963             new_directory? 'T': 'F', add_dir_set));
5964
5965    /*  Set the size of the file window BIG so that it does not  */
5966    /*  try to force positioning on its children.                */
5967    file_window = (XmManagerWidget) file_mgr_rec->file_window;
5968    XtResizeWidget ((Widget)file_window, 32767, 32767, 0);
5969
5970    /*  Set the scrolled window and file window appropriately  */
5971    /*  to prevent a lot of gyrations.                         */
5972
5973    XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmSTATIC);
5974    XtSetValues (file_mgr_rec->scroll_window, args, 1);
5975
5976    /* For faster updates, unmanage all the icons */
5977    if (XtIsManaged(file_mgr_rec->file_window))
5978    {
5979       /* see if the focus is inside the file window */
5980       child = XmGetFocusWidget(file_mgr_rec->file_window);
5981       if (child != NULL)
5982       {
5983         if (new_directory)
5984         {
5985           file_mgr_rec->focus_widget = file_mgr_rec->file_window;
5986         }
5987         else if( XtParent(child) == file_mgr_rec->file_window )
5988         {
5989           /* remember which widget had the focus */
5990           file_mgr_rec->focus_widget = child;
5991         }
5992       }
5993
5994       DPRINTF(("  focus_widget = %p (%s)\n",
5995                file_mgr_rec->focus_widget,
5996                file_mgr_rec->focus_widget?
5997                   XtName(file_mgr_rec->focus_widget): "nil"));
5998       XtUnmanageChild(file_mgr_rec->file_window);
5999    }
6000
6001    XtUnmanageChildren(file_window->composite.children,
6002                       file_window->composite.num_children);
6003
6004    /* if this is a new directory, scroll to the top */
6005    if (new_directory)
6006    {
6007       XtSetArg (args[0], XmNx, 0);
6008       XtSetArg (args[1], XmNy, 0);
6009       XtSetValues ((Widget)file_window, args, 2);
6010    }
6011
6012    /*
6013     * Don't leave the view in a munged state for too long.
6014     * Only do if we are not creating a new view.  This is because the
6015     * view is not yet in the 'view_list', and so the redisplay code
6016     * may not use the correct redisplay function.
6017     */
6018    if (ReturnDesktopPtr(file_mgr_rec->file_window))
6019    {
6020       UpdateHeaders(file_mgr_rec, file_mgr_data, False);
6021       XFlush (XtDisplay (file_window));
6022       XmUpdateDisplay ((Widget)file_window);
6023    }
6024
6025    /* free any old layout data */
6026    FreeLayoutData(file_mgr_data->layout_data);
6027    file_mgr_data->layout_data = NULL;
6028
6029    /* if directory-read still in progress, don't do anything more now */
6030    if (file_mgr_data->busy_status != not_busy)
6031    {
6032       DPRINTF(("done (busy)\n"));
6033       return;
6034    }
6035
6036 #ifdef DT_PERFORMANCE
6037    printf("   Beginning UpdateFileIcons\n");
6038    gettimeofday(&update_time_s, NULL);
6039
6040    /* added by Rafi */
6041    _DtPerfChkpntMsgSend("Begin Update Icons");
6042
6043 #endif
6044
6045    /* set up new layout data */
6046    layout_data = (IconLayoutData *)XtCalloc(1, sizeof(IconLayoutData));
6047    file_mgr_data->layout_data = (XtPointer)layout_data;
6048
6049    FlattenTree(file_mgr_data, &order_list, &order_count);
6050    layout_data->order_list = order_list;
6051    layout_data->order_count = order_count;
6052
6053    MakeReuseList(file_window->composite.children,
6054                  file_window->composite.num_children,
6055                  order_list, order_count,
6056                  &layout_data->reuse_icons,
6057                  &layout_data->reuse_btns);
6058    layout_data->next_icon_to_use = layout_data->reuse_icons;
6059    layout_data->next_btn_to_use = layout_data->reuse_btns;
6060
6061    layout_data->manage = (Widget *)XtMalloc(2*order_count*sizeof(Widget));
6062    layout_data->manage_count = 0;
6063
6064    layout_data->i_do_next_vis = 0;
6065    layout_data->i_do_next_all = 0;
6066
6067    /*
6068     * Iterate through the file list and mark all entries to be in
6069     * need of update.  We also construct icon labels at this time,
6070     * since they are need by LayoutFileIcons to estimate icon gadget
6071     * sizes.
6072     */
6073
6074    if (add_dir_set)
6075    {
6076      /* only need to iterate throught the new entries */;
6077      order_list = add_dir_set->order_list;
6078      order_count = add_dir_set->file_count;
6079    }
6080
6081    for (i = 0; i < order_count; i++)
6082    {
6083       order_list[i]->need_update = True;
6084       order_list[i]->selected = False;
6085       UpdateOneIconLabel(file_mgr_data, order_list[i]);
6086    }
6087
6088    /* set selected flag on all files in selection_list */
6089    for (i = 0; i < file_mgr_data->selected_file_count; i++)
6090       file_mgr_data->selection_list[i]->selected = True;
6091
6092 #ifdef DT_PERFORMANCE
6093    gettimeofday(&update_time_f, NULL);
6094    if (update_time_s.tv_usec > update_time_f.tv_usec) {
6095       update_time_f.tv_usec += 1000000;
6096       update_time_f.tv_sec--;
6097    }
6098    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);
6099
6100    /* added by Rafi */
6101    _DtPerfChkpntMsgSend("Done  Update Icons");
6102 #endif
6103
6104    DPRINTF(("done\n"));
6105 }
6106
6107
6108
6109
6110 /************************************************************************
6111  *
6112  *  CreateTreeIcons
6113  *      Create icons for tree-branch-expand buttons.
6114  *
6115  ************************************************************************/
6116
6117 static void
6118 CreateTreeIcons(Widget w)
6119 {
6120   Arg args[20];
6121   Pixel  background_color = 0;
6122   Pixel  foreground_color = 0;
6123   int i, j;
6124   TreePxId px;
6125   char pxname[128];
6126   unsigned int width, height, dummy;
6127
6128   XtSetArg (args[0], XmNbackground, &background_color);
6129   XtSetArg (args[1], XmNforeground, &foreground_color);
6130   XtGetValues (w, args, 2);
6131
6132   for (i = 0; i < 3; i++)
6133   {
6134     TreeBtnWd[i] = 5;
6135     TreeBtnHt[i] = 5;
6136     for (j = 0; j < tpxN; j++)
6137     {
6138       strcpy(pxname, TreePxTab[j].name);
6139       strcat(pxname, TreePxSuffix[i]);
6140       TreePxTab[j].px[i] = _DtGetPixmap(XtScreen(w), pxname,
6141                                      foreground_color, background_color);
6142       width = height = 0;
6143       XGetGeometry(XtDisplay(w), TreePxTab[j].px[i],
6144                    (Window *) &dummy,               /* returned root window */
6145                    (int *) &dummy, (int *) &dummy,  /* x, y of pixmap */
6146                    &width, &height,                 /* pixmap width, height */
6147                    &dummy, &dummy);                 /* border width, depth */
6148       if (j == tpxNil)
6149       {
6150          TreeNilWd[i] = width;
6151          TreeNilHt[i] = height;
6152       }
6153       else
6154       {
6155          if (width > TreeBtnWd[i])
6156            TreeBtnWd[i] = width;
6157          if (height > TreeBtnHt[i])
6158            TreeBtnHt[i] = height;
6159       }
6160     }
6161   }
6162 }
6163
6164
6165 /************************************************************************
6166  *
6167  *  GetTreebtnPixmap
6168  *      Get icon for tree-branch-expand buttons.
6169  *
6170  ************************************************************************/
6171
6172 Pixmap GetTreebtnPixmap(
6173         FileMgrData *file_mgr_data,
6174         FileViewData *file_view_data)
6175 {
6176    TreePxId pxid;
6177
6178    /* if not yet done, create tree button icons */
6179    /* @@@ do this earlier from main? */
6180    if (TreeBtnWd[0] == 0)
6181      CreateTreeIcons(((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window);
6182
6183    if (file_view_data->ts == tsNotRead)
6184      pxid = tpxNotRead;
6185    else if (file_view_data->ts == tsError)
6186      pxid = tpxError;
6187    else if (file_view_data->ndir == 0 &&
6188             (file_view_data->nfile == 0 ||
6189              file_mgr_data->tree_files == TREE_FILES_NEVER)
6190              && (file_view_data->ts == tsNone || !showEmptySet))
6191      pxid = tpxEmpty;
6192    else if (file_view_data->ts == tsNone)
6193      pxid = tpxMore;
6194    else if (file_view_data->ts == tsDirs)
6195      pxid = (file_view_data->nfile == 0 ||
6196              file_mgr_data->tree_files == TREE_FILES_NEVER)? tpxLess:
6197             (file_view_data->ndir == 0)?  tpxMore:
6198                                           tpxBoth;
6199    else if (file_view_data->ts == tsAll)
6200      pxid = tpxLess;
6201
6202    if (file_mgr_data->view == BY_NAME)
6203      return TreePxTab[pxid].px[0];   /* small pixmap */
6204    else if (file_mgr_data->view == BY_NAME_AND_ICON)
6205      return TreePxTab[pxid].px[2];   /* large pixmap */
6206    else
6207      return TreePxTab[pxid].px[1];   /* medium  pixmap */
6208 }
6209
6210
6211 /************************************************************************
6212  *
6213  *  GetIconSize
6214  *      Compute maximum icon size.
6215  *
6216  ************************************************************************/
6217
6218 static void
6219 GetIconLayoutParms(
6220         FileMgrRec *file_mgr_rec,
6221         FileMgrData *file_mgr_data,
6222         IconLayoutData *ld)
6223 {
6224    DirectorySet *directory_set;
6225    int file_count;
6226    FileViewData **file_list;
6227    int i;
6228    DtIconGadget g;
6229    Arg args[10];
6230    Dimension shadowThickness;
6231    Dimension marginWidth;
6232    Dimension maxWidth = ld->pixmap_width;
6233    Dimension gadgetWidth;
6234
6235    /* determine pixmap size */
6236    if (file_mgr_data->view == BY_NAME)
6237    {
6238       /* no pixmap */
6239       ld->pixmap_width = 0;
6240       ld->pixmap_height = 0;
6241    }
6242    else if (file_mgr_data->view == BY_NAME_AND_ICON)
6243    {
6244       /* large pixmap */
6245       ld->pixmap_width = largeIconWidth;
6246       ld->pixmap_height = largeIconHeight;
6247    }
6248    else
6249    {
6250       /* small pixmap */
6251       ld->pixmap_width = smallIconWidth;
6252       ld->pixmap_height = smallIconHeight;
6253    }
6254
6255    /* find the icon gadget for "." */
6256    directory_set = file_mgr_data->directory_set[0];
6257    file_count = directory_set->file_count;
6258    file_list = directory_set->file_view_data;
6259
6260    g = NULL;
6261    for (i = 0; i < file_count; i++)
6262    {
6263       if (strcmp(file_list[i]->file_data->file_name, ".") == 0)
6264       {
6265          g = (DtIconGadget)file_list[i]->widget;
6266          break;
6267       }
6268    }
6269
6270    /* get layout parameters from "." */
6271    if (g)
6272    {
6273       XtSetArg(args[0], XmNhighlightThickness, &ld->highlight);
6274       XtSetArg(args[1], XmNshadowThickness, &shadowThickness);
6275       XtSetArg(args[2], XmNmarginWidth, &marginWidth);
6276       XtSetArg(args[3], XmNspacing, &ld->spacing);
6277       XtSetArg(args[4], XmNalignment, &ld->alignment);
6278       XtSetArg(args[5], XmNpixmapPosition, &ld->pixmap_position);
6279       XtGetValues((Widget)g, args, 6);
6280
6281       if (g->icon.pixmap_width < maxWidth)
6282          ld->spacing = ld->spacing - (maxWidth - g->icon.pixmap_width);
6283
6284       ld->width = ((Widget)g)->core.width +
6285                                      ld->pixmap_width  - g->icon.pixmap_width;
6286       ld->height = ((Widget)g)->core.height +
6287                                      ld->pixmap_height - g->icon.pixmap_height;
6288
6289       ld->char_width = (g->icon.string_width)/strlen(file_list[i]->label);
6290       if (ld->pixmap_position != XmPIXMAP_TOP)
6291          ld->width -= g->icon.string_width;
6292       ld->margin = ld->highlight + shadowThickness + marginWidth;
6293    }
6294    else
6295    {
6296       /* No icon gadget for "." found: strange!  Guess some defaults.  */
6297       ld->char_width = 8;
6298       ld->margin = 2 + 1 + 1;
6299       ld->spacing = 2;
6300       ld->highlight = (keybdFocusPolicy == XmEXPLICIT)? 2: 0;
6301       ld->alignment = XmALIGNMENT_END;
6302       if (file_mgr_data->view == BY_NAME_AND_ICON &&
6303           file_mgr_data->show_type != MULTIPLE_DIRECTORY)
6304       {
6305          ld->pixmap_position = XmPIXMAP_TOP;
6306          ld->width = 2*ld->margin + ld->pixmap_width;
6307          ld->height = 2*ld->margin + ld->pixmap_height + ld->spacing + 14;
6308       }
6309       else
6310       {
6311          ld->pixmap_position = XmPIXMAP_LEFT;
6312          ld->width = 2*ld->margin + ld->pixmap_width +
6313                                                  ld->spacing + ld->char_width;
6314          ld->height = 2*ld->margin + ld->pixmap_height;
6315       }
6316    }
6317
6318    /* determine which size tree buttons to use */
6319    if (file_mgr_data->show_type != MULTIPLE_DIRECTORY)
6320       ld->treebtn_size = 0;   /* no tree buttons needed */
6321    else if (file_mgr_data->view == BY_NAME)
6322       ld->treebtn_size = 0;   /* small size */
6323    else if (file_mgr_data->view == BY_NAME_AND_ICON)
6324       ld->treebtn_size = 2;   /* large size */
6325    else
6326       ld->treebtn_size = 1;   /* medium size */
6327 }
6328
6329
6330 static void
6331 EstimateIconSize(
6332         FileMgrRec *file_mgr_rec,
6333         FileMgrData *file_mgr_data,
6334         IconLayoutData *layout_data,
6335         FileViewData *file_view_data,
6336         Dimension *width,
6337         Dimension *height)
6338 {
6339    int label_len;
6340    int label_width;
6341
6342    if (file_view_data == NULL) {
6343       label_len = 1;
6344    } else {
6345 #ifdef MULTIBYTE
6346       label_len = DtCharCount(file_view_data->label == NULL ?
6347                         file_view_data->file_data->file_name : file_view_data->label);
6348 #else
6349       label_len = strlen(file_view_data->label == NULL ?
6350                         file_view_data->file_data->file_name : file_view_data->label);
6351 #endif
6352    }
6353
6354    if (layout_data->pixmap_position == XmPIXMAP_TOP)
6355    {
6356       label_width = 2*layout_data->margin + label_len*layout_data->char_width;
6357       if ((Dimension)label_width > layout_data->width)
6358          *width = label_width;
6359       else
6360          *width = layout_data->width;
6361    }
6362    else
6363         *width = layout_data->width + (label_len) * layout_data->char_width;
6364    *height = layout_data->height;
6365 }
6366
6367
6368 /************************************************************************
6369  *
6370  *  GetExtraHeight
6371  *    Compute extra height for drawing nil symbol for empty tree branches.
6372  *
6373  ************************************************************************/
6374
6375 static Dimension
6376 GetExtraHeight(
6377         FileMgrData *file_mgr_data,
6378         FileViewData *file_view_data,
6379         int treebtn_size)
6380 {
6381    if (showEmptySet &&
6382        file_view_data->file_data->is_subdir &&
6383        file_view_data->ts >= tsDirs &&
6384        file_view_data->ndir == 0 &&
6385        (file_view_data->nfile == 0 ||
6386         file_mgr_data->tree_files == TREE_FILES_NEVER))
6387    {
6388       return YSPACING(file_mgr_data) + TreeNilHt[treebtn_size];
6389    }
6390    else
6391       return 0;
6392 }
6393
6394
6395 /************************************************************************
6396  *
6397  *  EraseTreeLines
6398  *    Erase connecting lines in tree mode from a specified icon widget
6399  *    on down; called when a tree branch is expanded or collapsed to
6400  *    erase previous tree lines before drawing new icons and tree lines.
6401  *
6402  ************************************************************************/
6403
6404 void
6405 EraseTreeLines(
6406         FileMgrRec *file_mgr_rec,
6407         FileMgrData *file_mgr_data,
6408         FileViewData *file_view_data)
6409 {
6410    XmManagerWidget file_window;
6411    Dimension fw_width, fw_height;
6412    Position x, y;
6413
6414    file_window = (XmManagerWidget) file_mgr_rec->file_window;
6415    if (!XtIsManaged((Widget)file_window))
6416       return;
6417
6418    /* get upper left corner of grid space for the icon widget */
6419    x = file_view_data->x;
6420    y = file_view_data->y - file_mgr_data->grid_height;
6421
6422    /*  Get file window width and height */
6423    fw_width = file_window->core.width;
6424    fw_height = file_window->core.height;
6425
6426    DPRINTF2(("EraseTreeLines(\"%s\"): x/y %d/%d (widget %d/%d)\n",
6427              file_view_data->file_data->file_name, x, y,
6428              file_view_data->widget->core.x,
6429              file_view_data->widget->core.y));
6430
6431    /* clear area from icon widget to bottom of file window */
6432    XClearArea(XtDisplay(file_window), XtWindow(file_window),
6433               x, y, fw_width - x, fw_height - y, False);
6434
6435    /*
6436     * clear area to the right and above the icon widget
6437     * (necessary if there are multiple columns, which happens if
6438     *  there are more icons than fit into a single column of
6439     *  maximum height 32767)
6440     */
6441    if (y > 0  &&  (Dimension)(x + file_mgr_data->grid_width) < fw_width)
6442    {
6443      x += file_mgr_data->grid_width;
6444      XClearArea(XtDisplay(file_window), XtWindow(file_window),
6445                 x, 0, fw_width - x, y, False);
6446    }
6447 }
6448
6449
6450 /************************************************************************
6451  *
6452  *  RedrawTreeLines
6453  *      Redraw connecting lines in tree mode.
6454  *
6455  ************************************************************************/
6456
6457 void
6458 RedrawTreeLines(
6459         Widget w,
6460         int ex, int ey, int ewidth, int eheight, int ecount,
6461         FileMgrRec *file_mgr_rec,
6462         FileMgrData *file_mgr_data)
6463 {
6464    static char *empty_msg = NULL;
6465
6466    FileViewData *file_view_data;
6467    IconLayoutData *layout_data;
6468    Dimension grid_width, grid_height;
6469    Dimension extra_height, e_height;
6470    int sz;
6471    FileViewData **order_list;
6472    int order_count;
6473    GC solid_gc, dash_gc;
6474    int i, k;
6475    Position x, xl;
6476    Position y, y0, y1;
6477    int level;
6478    Bool more[256];
6479    XFontSetExtents *extents;
6480    int font_height;
6481    int font_yoffset;
6482    int tmp;
6483
6484    if (!XtIsManaged(w))
6485       return;
6486
6487    /*  get layout parameters  */
6488    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
6489    order_list = layout_data->order_list;
6490    order_count = layout_data->order_count;
6491    grid_width = file_mgr_data->grid_width;
6492    grid_height = file_mgr_data->grid_height;
6493    sz = layout_data->treebtn_size;
6494
6495    DPRINTF2(("RedrawTreeLines(x %d, y %d, wd %d, ht %d, count %d)\n",
6496              ex, ey, ewidth, eheight, ecount));
6497
6498    if (grid_width == 0 || grid_height == 0)
6499       /* layout probably not yet done */
6500       return;
6501
6502    /* if not yet done, create tree button icons */
6503    /* @@@ do this earlier from main? */
6504    if (TreeBtnWd[0] == 0)
6505      CreateTreeIcons(((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window);
6506
6507    /* select line styles */
6508    if (file_mgr_data->view == BY_NAME) {
6509      solid_gc = file_mgr_data->tree_solid_thin_gc;
6510      dash_gc = file_mgr_data->tree_dash_thin_gc;
6511    } else {
6512      solid_gc = file_mgr_data->tree_solid_thick_gc;
6513      dash_gc = file_mgr_data->tree_dash_thick_gc;
6514    }
6515
6516    x = MARGIN;
6517    y = MARGIN;
6518
6519    for (k = 0; k < order_count; k++)
6520    {
6521       if (!order_list[k]->displayed)
6522          continue;
6523
6524       /* determine the height of this item */
6525       file_view_data = order_list[k];
6526       extra_height = GetExtraHeight(file_mgr_data, file_view_data, sz);
6527       GetLevel(file_view_data, &level);
6528
6529       /* check if we need to go to the next column */
6530       tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
6531       if (tmp + MARGIN > MAXWINSIZE)
6532       {
6533         /* window would exceed height limit; go to the next column */
6534         x += grid_width + XSPACING;
6535         y = MARGIN;
6536         tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
6537       }
6538
6539       /* check if current item intersects the exposed region */
6540       y0 = y - YSPACING(file_mgr_data)
6541              - grid_height
6542              + (Dimension)(grid_height - TreeBtnHt[sz])/(Dimension)2
6543              + TreeBtnHt[sz];
6544       y1 = y + grid_height + extra_height + YSPACING(file_mgr_data);
6545       if (x  <= ex + ewidth  && x + TreeWd(level, sz) > ex &&
6546           y0 <= ey + eheight && y1 > ey)
6547       {
6548          GetAncestorInfo(file_mgr_data, file_view_data, NULL, NULL, more);
6549
6550          /* draw vertical connecting lines for upper tree levels */
6551          for (i = 0; i < level; i++) {
6552            if (more[i])
6553              XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
6554                        x + TreeLX(i, sz), y0,
6555                        x + TreeLX(i, sz), y1);
6556          }
6557
6558          /* draw vertical connecting line for this tree level */
6559          xl = x + TreeLX(level, sz);
6560          if (level > 0) {
6561            XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
6562                      xl, y0,
6563                      xl, more[level]? y1: y + grid_height/2);
6564
6565            if (file_view_data->file_data->is_subdir || !more[level]) {
6566              /* draw horizontal line */
6567              XDrawLine(XtDisplay(w), XtWindow(w),
6568                        (file_view_data->file_data->is_subdir &&
6569                         file_view_data->ts == tsNotRead)? dash_gc: solid_gc,
6570                        xl, y + grid_height/2,
6571                        xl + TreeOffset, y + grid_height/2);
6572            }
6573          }
6574
6575          /* draw nil symbol for empty subdirs */
6576          if (extra_height)
6577          {
6578             xl += TreeOneWd(sz);
6579             y0 += grid_height + YSPACING(file_mgr_data);
6580             y1 = y + grid_height + YSPACING(file_mgr_data);
6581             e_height = extra_height - YSPACING(file_mgr_data);
6582
6583             XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
6584                       xl, y0,
6585                       xl, y1 + e_height/2);
6586
6587             XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
6588                       xl, y1 + e_height/2,
6589                       xl + TreeOffset, y1 + e_height/2);
6590
6591             xl = x + TreeWd(level, sz) + TreeBtnWd[sz];
6592             XCopyArea(XtDisplay(w), TreePxTab[tpxNil].px[sz],
6593                       XtWindow(w), solid_gc,
6594                       0, 0, TreeNilWd[sz], TreeNilHt[sz],
6595                       xl, y1);
6596 /*
6597             if (empty_msg == NULL)
6598                empty_msg = XtNewString("(empty)");
6599
6600             if (file_mgr_data->cd_fonttype == XmFONT_IS_FONTSET)
6601             {
6602                 extents = XExtentsOfFontSet(file_mgr_data->cd_fontset);
6603                 font_yoffset = extents->max_logical_extent.y;
6604                 font_height = extents->max_logical_extent.height;
6605             }
6606             else
6607             {
6608                 font_yoffset = file_mgr_data->cd_font->ascent;
6609                 font_height = file_mgr_data->cd_font->ascent +
6610                                 file_mgr_data->cd_font->descent;
6611             }
6612
6613             XDrawImageString(XtDisplay(w), XtWindow(w), solid_gc,
6614                       xl + TreeNilWd[sz] + 2,
6615                       y1 + (TreeNilHt[sz] - font_height)/2 + font_yoffset,
6616                       empty_msg, strlen(empty_msg));
6617 */
6618          }
6619       }
6620
6621       /* goto next item */
6622       y = (Position)tmp;
6623    }
6624 }
6625
6626
6627 /************************************************************************
6628  *
6629  *  DisplaySomeIcons
6630  *    Check if any incons or widgets in the area given by ex, ey, ewd,
6631  *    and eht need to be updated.
6632  *
6633  ************************************************************************/
6634
6635 #ifdef DEBUG
6636 static int g_workCount1 = 0;
6637 static int g_workCount2 = 0;
6638 static int g_callCount = 0;
6639 #endif
6640
6641 static Boolean
6642 ToBeManaged(
6643         IconLayoutData *layout_data,
6644         FileViewData *file_view_data)
6645 {
6646    int i;
6647
6648    for (i = 0; i < layout_data->manage_count; i++)
6649       if (layout_data->manage[i] == file_view_data->widget)
6650          return True;
6651
6652    return False;
6653 }
6654
6655
6656 static int
6657 DisplaySomeIcons(
6658         FileMgrRec *file_mgr_rec,
6659         FileMgrData *file_mgr_data,
6660         int ex, int ey, int ewd, int eht,
6661         int workLimit,
6662         Boolean doAll)
6663 {
6664 #ifdef DT_PERFORMANCE
6665    struct timeval update_time_s;
6666    struct timeval update_time_f;
6667 #endif
6668    XmManagerWidget file_window;
6669    FileViewData **order_list;
6670    int order_count;
6671    Arg args[10];
6672    Arg args_dso_get[1];
6673    Arg args_dso_set[1];
6674    IconLayoutData *layout_data;
6675    FileViewData **change;
6676    int changeCount;
6677    Widget *manage;
6678    int manageCount;
6679    int workCount1;
6680    int workCount2;
6681    Dimension grid_width, grid_height;
6682    Dimension icon_width, icon_height;
6683    Dimension extra_height;
6684    int i, k;
6685    Position x, y;
6686    FileViewData  *file_view_data;
6687    Boolean changed;
6688    Widget child;
6689    DtIconGadget g;
6690    int level;
6691    unsigned char operations;
6692    Widget *wp;
6693    ObjectPosition *position_data;
6694    XRectangle textExtent;
6695
6696    /* Get a list of icon and button widgets we can re-use */
6697    file_window = (XmManagerWidget) file_mgr_rec->file_window;
6698    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
6699    order_list = layout_data->order_list;
6700    order_count = layout_data->order_count;
6701    manage = layout_data->manage + layout_data->manage_count;
6702
6703    /* allocate storage for list of changed icons */
6704    change = (FileViewData **)XtMalloc(order_count * sizeof(FileViewData *));
6705
6706    /*  Find the maximum values for the icon heights and widths  */
6707    grid_width = file_mgr_data->grid_width;
6708    grid_height = file_mgr_data->grid_height;
6709
6710
6711 #ifdef DT_PERFORMANCE
6712    printf("   Begin Part 1, DisplaySomeIcons (update icons)\n");
6713    gettimeofday(&update_time_s, NULL);
6714
6715    /* added by Rafi */
6716    _DtPerfChkpntMsgSend("Begin Display Icons");
6717 #endif
6718
6719    DPRINTF2((
6720      "DisplaySomeIcons(\"%s\", x/y %d/%d, wd/ht %d/%d, i %d:%d) ...\n",
6721      file_mgr_data->current_directory, ex, ey, ewd, eht,
6722      layout_data->i_do_next_vis,
6723      layout_data->i_do_next_all));
6724
6725    /* set up args for querying/unregistering drop sites */
6726    XtSetArg (args_dso_get[0], XmNdropSiteOperations, &operations);
6727    XtSetArg (args_dso_set[0], XmNdropSiteOperations, XmDROP_NOOP);
6728
6729    /*
6730     * Iterate through the list of files and create/update and position
6731     * all visible icon gadgets for which this work hasn't been done yet
6732     * (need_update flag set).
6733     */
6734
6735    changeCount = 0;
6736    manageCount = 0;
6737    workCount1 = 0;
6738
6739    if (doAll)
6740       k = layout_data->i_do_next_all;
6741    else
6742       k = layout_data->i_do_next_vis;
6743    for ( ; k < order_count && workCount1 < workLimit; k++)
6744    {
6745       /*
6746        * Process focus widget before everything else so that we can restore
6747        * the focus when we manage the file_window again.  If a file was
6748        * being renamed, we do that one first.
6749        */
6750       if (!layout_data->focus_done)
6751       {
6752          /* search for focus widget in order_list and see if still displayed */
6753         file_view_data = NULL;
6754         if (file_mgr_rec->focus_widget != NULL)
6755         {
6756           if (file_mgr_rec->focus_widget == file_mgr_rec->file_window)
6757           {
6758             for (i = 0; i < order_count; i++)
6759               if (order_list[i]->displayed)
6760               {
6761                 file_view_data = order_list[i];
6762                 break;
6763               }
6764           }
6765           else
6766           {
6767             for (i = 0; i < order_count; i++)
6768               if (order_list[i]->widget == file_mgr_rec->focus_widget)
6769               {
6770                 if (order_list[i]->displayed)
6771                   file_view_data = order_list[i];
6772                 break;
6773               }
6774           }
6775         }
6776
6777          /* if not found, focus could be on a rename text widget */
6778         if (file_view_data == NULL)
6779           file_view_data = file_mgr_data->renaming;
6780
6781         layout_data->focus_done = True;
6782
6783         if (file_view_data)
6784         {
6785           k--;
6786           /* decrement loop index, so that the entry that was supposed to be
6787              processed here will be looked at again in the next iteration
6788           */
6789           goto do_this_entry;
6790         }
6791       }
6792
6793
6794       /* ignore files that are filtered */
6795       file_view_data = order_list[k];
6796       if (file_view_data->filtered &&
6797           strcmp(file_view_data->file_data->file_name, ".") != 0)
6798       {
6799          continue;
6800       }
6801
6802       /*
6803        * If the file is not currenly displayed (collapsed tree branch) or
6804        * is currenly scrolled out of view, we don't need to do anything
6805        * at this time.  Except ...
6806        */
6807       if (!file_view_data->displayed ||
6808           ((int)file_view_data->x + (int)grid_width) < ex  ||
6809           file_view_data->x >= ex + ewd ||
6810           file_view_data->y < ey ||
6811           ((int)file_view_data->y - (int)grid_height) >= (ey + eht))
6812       {
6813          /*
6814           * ... if this file still has an old icon widget, AND if the
6815           * old icon position is visible, AND if the icon was registered
6816           * as a drop site, we will have a "ghost drop zone" showing up where
6817           * the icon used to be.  The old icon gadget is unmanaged and will
6818           * remain unmanaged until later when we update it and move it to the
6819           * correct positon (happens only when the user scrolls to the new
6820           * position).  In the meantime, even though the gadget is unmanged,
6821           * its old position still remains registered as a drop site,
6822           * so we have to either unregister it or move the gadget to
6823           * its new position now.
6824           */
6825          child = file_view_data->widget;
6826          if (child != NULL &&
6827              (Position)(child->core.x + child->core.width) >= (Position)ex  &&
6828              child->core.x < ex + ewd &&
6829              (Position)(child->core.y + child->core.height) >= (Position)ey &&
6830              child->core.y < ey + eht)
6831          {
6832             if (!file_view_data->displayed)
6833             {
6834                XtGetValues (child, args_dso_get, 1);
6835                if (operations != XmDROP_NOOP)
6836                {
6837                   XtSetValues (child, args_dso_set, 1);
6838                   workCount1++;
6839                   file_view_data->registered = False;
6840                }
6841                continue;
6842             }
6843
6844          } else
6845            continue;
6846       }
6847
6848 do_this_entry:
6849       /*
6850        * If not yet done, create/update the icon gadget for this file
6851        */
6852       if (file_view_data->need_update)
6853       {
6854          UpdateOneFileIcon(file_mgr_rec, file_mgr_data, file_view_data);
6855          child = file_view_data->widget;
6856
6857          /*
6858           * We may need to adjust the icon position based on the difference
6859           * between estimated size and actual size.
6860           */
6861          if (layout_data->alignment == XmALIGNMENT_CENTER &&
6862              file_mgr_data->view == BY_NAME_AND_ICON)
6863          {
6864             EstimateIconSize(file_mgr_rec, file_mgr_data, layout_data,
6865                              file_view_data, &icon_width, &icon_height);
6866
6867             if (child->core.width != icon_width)
6868             {
6869                file_view_data->x = file_view_data->x
6870                  - (Dimension)(grid_width - icon_width)/(Dimension)2
6871                  + (Dimension)(grid_width - child->core.width)/(Dimension)2;
6872             }
6873          }
6874
6875          if (PositioningEnabledInView(file_mgr_data))
6876          {
6877             position_data = file_view_data->position_info;
6878             if (position_data->late_bind)
6879             {
6880                /*
6881                 * When new objects are dropped on the random placement window,
6882                 * they do not yet have a widget, so the drop_y could not be
6883                 * adjusted to take into account the height of the icon;
6884                 * this must be done now, after the object has an icon.
6885                 */
6886 /*
6887                position_data->y -= child->core.height/2;
6888 */
6889                position_data->late_bind = False;
6890                file_view_data->y = position_data->y + child->core.height;
6891             }
6892             else if (child->core.height != grid_height)
6893             {
6894                /* @@@ ??? @@@
6895                 * Not quite right: have to distinguish two cases:
6896                 *  (1) position_data->y read from .!xxx file
6897                 *      file_view_data->y computed by adding grid_height
6898                 *  (2) file_view_data->y from layout
6899                 *      position_data->y computed by subtracting grid_height
6900                 * In case (1) have to recompute file_view_data->y; in case
6901                 * (2) have to recompute position_data->y.  Code below only
6902                 * works for case (2).
6903                 */
6904 /*
6905                position_data->y = file_view_data->y - child->core.height;
6906 */
6907             }
6908          }
6909
6910          changed = True;
6911       }
6912       else
6913          changed = False;
6914
6915
6916       /* if focus is supposed to be in the file window, focus on this widget */
6917       if (file_mgr_rec->focus_widget == file_mgr_rec->file_window)
6918          file_mgr_rec->focus_widget = file_view_data->widget;
6919
6920
6921       /* determine desired icon postition */
6922       child = file_view_data->widget;
6923
6924       if (PositioningEnabledInView(file_mgr_data))
6925       {
6926          x = file_view_data->position_info->x;
6927          y = file_view_data->position_info->y;
6928       }
6929       else if (file_mgr_data->show_type != MULTIPLE_DIRECTORY)
6930       {
6931          x = file_view_data->x;
6932          y = file_view_data->y - child->core.height;
6933       }
6934       else /* file_mgr_data->show_type == MULTIPLE_DIRECTORY */
6935       {
6936          GetLevel(file_view_data, &level);
6937          extra_height = GetExtraHeight(file_mgr_data, file_view_data,
6938                                        layout_data->treebtn_size);
6939
6940          /* check position of tree button, if any */
6941          if (file_view_data->treebtn)
6942          {
6943            child = file_view_data->treebtn;
6944
6945            x = file_view_data->x
6946                  + TreeLX(level, layout_data->treebtn_size) + TreeOffset;
6947            y = file_view_data->y
6948                - grid_height
6949                + (Dimension)(grid_height - child->core.height)/(Dimension)2;
6950
6951            if (child->core.x != x || child->core.y != y)
6952               XmeConfigureObject(child, x, y, child->core.width,
6953                                  child->core.height, child->core.border_width);
6954
6955            child = file_view_data->widget;
6956          }
6957
6958          if (child->core.height < grid_height)
6959          {
6960             x = file_view_data->x + TreeWd(level, layout_data->treebtn_size);
6961             y = file_view_data->y
6962                 - grid_height
6963                 +(Dimension)(grid_height - child->core.height)/(Dimension)2;
6964          }
6965          else
6966          {
6967             x = file_view_data->x + TreeWd(level, layout_data->treebtn_size);
6968             y = file_view_data->y - grid_height;
6969          }
6970       }
6971
6972       if (child->core.x != x || child->core.y != y)
6973       {
6974           XmeConfigureObject(child, x, y, child->core.width,
6975                              child->core.height, child->core.border_width);
6976           changed = True;
6977       }
6978
6979       /* make sure the icon gadget and tree button, if any, are managed */
6980       if (!XtIsManaged(child) && !ToBeManaged(layout_data, file_view_data))
6981       {
6982          manage[manageCount++] = child;
6983          if (file_view_data->treebtn)
6984             manage[manageCount++] = file_view_data->treebtn;
6985          changed = True;
6986       }
6987
6988       if (changed)
6989       {
6990          /* remember which icons were changed */
6991          change[changeCount++] = file_view_data;
6992          workCount1++;
6993
6994          /*
6995           * If the icon we just changed was being renamed, make sure
6996           * the corresponding text widget is positioned correctly.
6997           */
6998          if (file_view_data == file_mgr_data->renaming)
6999          {
7000             for (i = 0; i < file_window->composite.num_children; i++)
7001             {
7002                child = file_window->composite.children[i];
7003                if (XmIsTextField(child))
7004                {
7005                   /* Check if the text field is still needed */
7006                   if (!child->core.being_destroyed)
7007                   {
7008                      /* move to the correct position */
7009                      _DtIconGetTextExtent_r(file_view_data->widget,
7010                                             &textExtent);
7011                      x = textExtent.x;
7012                      y = textExtent.y -
7013                          (Dimension)(child->core.height - textExtent.height)/(Dimension)2;
7014                      XmeConfigureObject(child, x, y, child->core.width,
7015                                         child->core.height,
7016                                         child->core.border_width);
7017
7018                      /* manage it */
7019                      manage[manageCount++] = child;
7020                   }
7021                   break;
7022                }
7023             }
7024          }
7025       }
7026    }
7027
7028    /* remember where we left off ... */
7029    if (doAll)
7030       layout_data->i_do_next_all = k;
7031    else
7032       layout_data->i_do_next_vis = k;
7033
7034 #ifdef DT_PERFORMANCE
7035    gettimeofday(&update_time_f, NULL);
7036    if (update_time_s.tv_usec > update_time_f.tv_usec) {
7037       update_time_f.tv_usec += 1000000;
7038       update_time_f.tv_sec--;
7039    }
7040    printf("    done Part 1, DisplaySomeIcons, time: %ld.%ld\n\n",
7041           update_time_f.tv_sec - update_time_s.tv_sec,
7042           update_time_f.tv_usec - update_time_s.tv_usec);
7043
7044    /* the following message send call added by Rafi */
7045    _DtPerfChkpntMsgSend("Done  Display Icons");
7046 #endif
7047
7048 #ifdef DT_PERFORMANCE
7049    printf("   Begin Part 2, DisplaySomeIcons (register drop sites)\n");
7050    gettimeofday(&update_time_s, NULL);
7051
7052    /* added by Rafi  */
7053    _DtPerfChkpntMsgSend("Begin Register drop sites");
7054 #endif
7055
7056    /* unregister drop sites of unused icon gadgets */
7057    workCount2 = 0;
7058 #ifdef DELAYED_UNREGISTER
7059    for (wp = layout_data->next_icon_to_use;
7060         (child = *wp) != NULL;
7061         wp++)
7062    {
7063       if ((Position)(child->core.x + child->core.width) >= (Position)ex  &&
7064           child->core.x < ex + ewd &&
7065           (Position)(child->core.y + child->core.height) >= (Position)ey &&
7066           child->core.y < ey + eht)
7067       {
7068          XtGetValues (child, args_dso_get, 1);
7069          if (operations != XmDROP_NOOP)
7070          {
7071             XtSetValues (child, args_dso_set, 1);
7072             workCount2++;
7073
7074             if (workCount2/2 >= workLimit)
7075                break;
7076          }
7077       }
7078    }
7079 #endif
7080
7081    /*
7082     * Register drop sites
7083     *
7084     * Note: in "as placed" mode, we defer this work and do it in
7085     * CommitWorkProcUpdates instead.  Reason: need to re-register
7086     * all drop sites in top-to-bottom stacking order at that time.
7087     */
7088    if (! PositioningEnabledInView(file_mgr_data) &&
7089        file_mgr_data != trashFileMgrData)
7090    {
7091       for (k = 0; k < changeCount; k++)
7092       {
7093          SetHotRects(change[k],
7094                      (XtCallbackProc) DropOnObject,
7095                      (XtPointer) change[k]);
7096       }
7097    }
7098
7099    /* free storage */
7100    XtFree((char *)change);
7101    change = NULL;
7102
7103    /* update count of children to be managed */
7104    layout_data->manage_count += manageCount;
7105
7106
7107 #ifdef DT_PERFORMANCE
7108    gettimeofday(&update_time_f, NULL);
7109    if (update_time_s.tv_usec > update_time_f.tv_usec) {
7110       update_time_f.tv_usec += 1000000;
7111       update_time_f.tv_sec--;
7112    }
7113    printf("    done Part 2 DisplaySomeIcons, time: %ld.%ld\n\n",
7114           update_time_f.tv_sec - update_time_s.tv_sec,
7115           update_time_f.tv_usec - update_time_s.tv_usec);
7116
7117    /* the following message send call added by Rafi */
7118    _DtPerfChkpntMsgSend("Done  Register drop sites");
7119 #endif
7120
7121    DPRINTF2((" ... %d+%d changed (%d managed)\n",
7122              workCount1, workCount2, manageCount));
7123
7124 #ifdef DEBUG
7125    g_workCount1 += workCount1;
7126    g_workCount2 += workCount2;
7127    g_callCount++;
7128 #endif
7129
7130    return (workCount1 >= workCount2)? workCount1: workCount2;
7131 }
7132
7133
7134 /************************************************************************
7135  *
7136  *  Display work procedure
7137  *
7138  ************************************************************************/
7139
7140 static void
7141 CommitWorkProcUpdates(
7142   FileMgrRec *file_mgr_rec,
7143   FileMgrData * file_mgr_data,
7144   Boolean reset)
7145 {
7146    XmManagerWidget file_window;
7147    IconLayoutData *layout_data;
7148    Widget w;
7149    int i;
7150
7151    file_window = (XmManagerWidget) file_mgr_rec->file_window;
7152    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
7153
7154    if (layout_data == NULL)
7155      return;
7156
7157    DPRINTF((
7158     "CommitWorkProcUpdates: %d+%d updates (m %d, n %d, i %d:%d, reset %d)\n",
7159             g_workCount1,
7160             g_workCount2,
7161             layout_data->manage_count,
7162             g_callCount,
7163             layout_data->i_do_next_vis,
7164             layout_data->i_do_next_all,
7165             reset));
7166
7167 #ifdef DEBUG
7168    g_workCount1 = 0;
7169    g_workCount2 = 0;
7170    g_callCount = 0;
7171 #endif
7172
7173    if (reset)
7174    {
7175       layout_data->i_do_next_vis = 0;
7176       layout_data->i_do_next_all = 0;
7177    }
7178
7179    /* if work proc no longer active, everything should already be commited */
7180    if (layout_data->work_id == 0)
7181      return;
7182
7183    /* manage new children */
7184    if (layout_data->manage_count > 0)
7185    {
7186       if (PositioningEnabledInView(file_mgr_data))
7187          OrderChildrenList(file_mgr_data);
7188       XtManageChildren(layout_data->manage, layout_data->manage_count);
7189    }
7190
7191    /*
7192     * In "as placed" mode, need to register drop sites now.
7193     * (If not "as placed" mode, this was already done in DisplaySomeIcons.)
7194     */
7195    if (PositioningEnabledInView(file_mgr_data))
7196       RegisterDesktopHotspots(file_mgr_data, file_mgr_rec);
7197
7198    /* commit drop site updates */
7199    XmDropSiteEndUpdate(layout_data->drop_site_w);
7200
7201    /* If not managed yet, manage the file window again */
7202    if (!XtIsManaged((Widget)file_window))
7203    {
7204      XtArgVal incr;
7205      Arg args[2];
7206
7207      XtManageChild ((Widget)file_window);
7208      XtVaGetValues(file_mgr_rec->vertical_scroll_bar,XmNuserData,&incr,NULL);
7209      if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
7210                                     file_mgr_rec->scroll_window)
7211          && incr > 0 )
7212      {
7213         XtSetArg (args[0], XmNincrement,incr);
7214         XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 1);
7215      }
7216      XmUpdateDisplay ((Widget)file_window);
7217    }
7218
7219    /* Try to preserve the focus */
7220    if (file_mgr_rec->focus_widget)
7221    {
7222       /* see if the widget that previously had the focus was just managed */
7223       w = NULL;
7224       for (i = 0; i < layout_data->manage_count; i++)
7225       {
7226          if (layout_data->manage[i] == file_mgr_rec->focus_widget)
7227          {
7228             w = file_mgr_rec->focus_widget;
7229             break;
7230          }
7231       }
7232
7233       /* if focus widget not found, set focus on file_window */
7234       if (w == NULL)
7235          w = (Widget)file_window;
7236
7237       XmProcessTraversal(w, XmTRAVERSE_CURRENT);
7238
7239       file_mgr_rec->focus_widget = NULL;
7240    }
7241
7242    layout_data->manage_count = 0;
7243
7244    /* start new update */
7245    XmDropSiteStartUpdate(layout_data->drop_site_w);
7246 }
7247
7248
7249 static Boolean
7250 DisplayWorkProc(
7251   XtPointer client_data)
7252 {
7253    FileMgrRec *file_mgr_rec = (FileMgrRec *)client_data;
7254    DialogData  * dialog_data;
7255    FileMgrData * file_mgr_data;
7256    XmManagerWidget file_window;
7257    IconLayoutData *layout_data;
7258    int ex, ey, ewd, eht;
7259    ObjectPosition *bottom;
7260    Widget child;
7261    int n;
7262    Boolean commit_updates = False;
7263
7264    int n1 = 1;
7265    int n2 = 1;
7266
7267    dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
7268    if (dialog_data == NULL)
7269       return False;
7270
7271    file_mgr_data = (FileMgrData *) dialog_data->data;
7272    file_window = (XmManagerWidget) file_mgr_rec->file_window;
7273    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
7274
7275    /* get the position and size of the currently visible area */
7276    ex = -file_window->core.x;
7277    ey = -file_window->core.y;
7278    ewd = XtParent(file_window)->core.width;
7279    eht = XtParent(file_window)->core.height;
7280
7281    /* check if the window scrolled */
7282    if (ex != layout_data->ex || ey != layout_data->ey)
7283    {
7284       layout_data->i_do_next_vis = layout_data->i_do_next_all;
7285       layout_data->visible_done = False;
7286    }
7287
7288    /* first work on icons in the currently visible area */
7289    if (layout_data->visible_done)
7290       n = 0;
7291    else
7292    {
7293      n = DisplaySomeIcons(file_mgr_rec, file_mgr_data, ex, ey, ewd, eht, n1, False);
7294      if (n == 0)
7295      {
7296        /* we just finished updating all visible icons */
7297        DPRINTF(("DisplayWorkProc: visible done.\n"));
7298        layout_data->visible_done = True;
7299        commit_updates = True;
7300      }
7301    }
7302
7303    /* if we still have some time left, work on other icons */
7304    if (layout_data->visible_done && n < n2)
7305    {
7306       n = DisplaySomeIcons(file_mgr_rec, file_mgr_data,
7307                            0, 0, 32767, 32767, n2 - n, True);
7308
7309       /* check if we are done */
7310       if (n == 0)
7311       {
7312          layout_data->all_done = True;
7313          commit_updates = True;
7314       }
7315       else if (layout_data->manage_count >= 100)
7316          commit_updates = True;
7317    }
7318
7319    if (commit_updates)
7320    {
7321       /* manage new children and commit drop site updates */
7322       CommitWorkProcUpdates(file_mgr_rec, file_mgr_data, False);
7323
7324       /*
7325        * In "as placed" mode, icons may overlap.
7326        * Force redraw in bottom to top stacking order.
7327        */
7328       if (PositioningEnabledInView(file_mgr_data))
7329       {
7330          for (bottom = GetBottomOfStack(file_mgr_data);
7331               bottom;
7332               bottom = (ObjectPosition *)bottom->prev)
7333          {
7334             if (bottom->file_view_data != NULL &&
7335                 bottom->file_view_data->displayed &&
7336                 !bottom->file_view_data->need_update)
7337             {
7338                child = bottom->file_view_data->widget;
7339                if ((Position)(child->core.x + child->core.width) >= (Position)ex  &&
7340                    child->core.x < ex + ewd &&
7341                    (Position)(child->core.y + child->core.height) >= (Position)ey &&
7342                    child->core.y < ey + eht)
7343                {
7344                   RedrawOneGadget(child, NULL, NULL);
7345                }
7346             }
7347          }
7348       }
7349    }
7350
7351    if (layout_data->all_done)
7352    {
7353       /* all work is done; all icons are up-to-date */
7354       file_mgr_data->newSize = False;
7355       layout_data->work_id = 0;
7356       XmDropSiteEndUpdate(layout_data->drop_site_w);
7357
7358       DPRINTF(("DisplayWorkProc: all done.\n"));
7359
7360       /* returning True will end the work proc */
7361       return True;
7362    }
7363    else
7364    {
7365       /* remember current scroll position */
7366       layout_data->ex = ex;
7367       layout_data->ey = ey;
7368       return False;
7369    }
7370 }
7371
7372
7373 /************************************************************************
7374  *
7375  *  LayoutFileIcons
7376  *      Position and size the full set of icons for the file mgr data.
7377  *
7378  ************************************************************************/
7379
7380 void
7381 LayoutFileIcons(
7382         FileMgrRec *file_mgr_rec,
7383         FileMgrData *file_mgr_data,
7384         Boolean update_scrolling_position,
7385         Boolean turn_off_hourglass )
7386 {
7387 #ifdef DT_PERFORMANCE
7388    struct timeval update_time_s;
7389    struct timeval update_time_f;
7390 #endif
7391    XmManagerWidget file_window;
7392    FileViewData ** order_list;
7393    int order_count;
7394    int total_icon_count;
7395    IconLayoutData *layout_data;
7396    Dimension file_window_width, file_window_height;
7397    Dimension scrolled_window_width, scrolled_window_height;
7398    Dimension vert_scrollbar_width, horiz_scrollbar_height;
7399    Dimension grid_width, grid_height;
7400    Dimension icon_width, icon_height;
7401    Dimension extra_height;
7402    Dimension sw_shadow_thickness, sb_highlight_thickness, space;
7403    int len, max_len;
7404    int level, max_level;
7405    FileViewData *file_view_data;
7406    Boolean overflow = False;
7407    int i, j, k;
7408    Position x, y;
7409    int row_count;
7410    int column_count;
7411    int tmp;
7412    Arg args[10];
7413    char *fileType;
7414
7415    unsigned char operations = 0L;
7416    static XtCallbackRec dropCB[] = { {DropOnFileWindow, NULL}, {NULL, NULL} };
7417
7418
7419    /* if directory-read still in progress, don't do anything now */
7420    if (file_mgr_data->busy_status != not_busy)
7421       return;
7422
7423    DPRINTF(("LayoutFileIcons(\"%s\", u_s_p %c, t_o_h %c) ...\n",
7424             file_mgr_data->current_directory,
7425             update_scrolling_position? 'T': 'F',
7426             turn_off_hourglass? 'T': 'F'));
7427
7428 #ifdef DT_PERFORMANCE
7429    printf("   Begin LayoutFileIcons\n");
7430    gettimeofday(&update_time_s, NULL);
7431
7432    /* added by Rafi */
7433    _DtPerfChkpntMsgSend("Begin Layout Icons");
7434 #endif
7435
7436    /*
7437     * Just in case a previous update work proc is still active,
7438     * we commit pending updates made by the work proc before we
7439     * start making changes.
7440     */
7441    CommitWorkProcUpdates(file_mgr_rec, file_mgr_data, True);
7442
7443    file_window = (XmManagerWidget) file_mgr_rec->file_window;
7444    layout_data = (IconLayoutData *)file_mgr_data->layout_data;
7445
7446    fileType = GetDirectoryLogicalType(file_mgr_data,
7447                                         file_mgr_data->current_directory);
7448    operations = TypeToDropOperations(fileType);
7449
7450    if (!file_mgr_data->dropSite)
7451    {
7452        dropCB[0].closure = (XtPointer)file_mgr_data;
7453
7454        DtDndVaDropRegister((Widget)file_mgr_rec->file_window,
7455                            DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
7456                            operations,
7457                            dropCB,
7458                            DtNdropAnimateCallback, dropCB,
7459                            DtNregisterChildren, True,
7460                            DtNtextIsBuffer,     True,
7461                            XmNanimationStyle,   XmDRAG_UNDER_SHADOW_IN,
7462                            NULL);
7463        file_mgr_data->dropSite = True;
7464
7465        if (!operations)
7466        {
7467            XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
7468            XmDropSiteUpdate((Widget)file_mgr_rec->file_window, args, 1);
7469        }
7470    }
7471    else
7472    {
7473        if (operations)
7474            XtSetArg (args[0], XmNdropSiteOperations, operations);
7475        else
7476            XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
7477        XmDropSiteUpdate((Widget)file_mgr_rec->file_window, args, 1);
7478    }
7479
7480    /*  Get the count of the total icon to be displayed.  */
7481    order_list = layout_data->order_list;
7482    order_count = layout_data->order_count;
7483    total_icon_count = 0;
7484    for (i = 0; i < order_count; i++)
7485    {
7486       if (order_list[i]->displayed)
7487          total_icon_count++;
7488    }
7489
7490    /*  Get the colors to be used for drawing the icons  */
7491    XtSetArg (args[0], XmNbackground, &layout_data->background);
7492    XtSetArg (args[1], XmNforeground, &layout_data->foreground);
7493 #ifdef _SHOW_LINK
7494    XtSetArg (args[2], XmNtopShadowColor, &layout_data->topshadow);
7495    XtGetValues (file_mgr_rec->file_window, args, 3);
7496 #else
7497    XtGetValues (file_mgr_rec->file_window, args, 2);
7498 #endif
7499    XtSetArg (args[0], XmNtopShadowColor, &layout_data->pixmap_back);
7500    XtSetArg (args[1], XmNbottomShadowColor, &layout_data->pixmap_fore);
7501    XtGetValues (file_mgr_rec->main, args, 2);
7502
7503    /*
7504     * Create/update icon gadget for ".".
7505     * This gadget may not actually be displayed (depends of filter settings;
7506     * by default it is filtered out), but we need at least one gadget
7507     * created here so we can figure out fonts and margins used by icon
7508     * gadgets.  This is necessary to compute the grid spacing.
7509     */
7510    for (i = 0; i < order_count; i++)
7511       if (strcmp(order_list[i]->file_data->file_name, ".") == 0)
7512       {
7513          UpdateOneFileIcon(file_mgr_rec, file_mgr_data, order_list[i]);
7514          order_list[i]->need_update = True;
7515          break;
7516       }
7517
7518    /* Find the icon with the longest label */
7519    max_len = 0;
7520    file_view_data = NULL;
7521    for (i = 0; i < order_count; i++)
7522    {
7523       if (!order_list[i]->filtered &&
7524           (len = strlen(order_list[i]->label)) > max_len)
7525       {
7526          file_view_data = order_list[i];
7527          max_len = len;
7528       }
7529    }
7530
7531    /* get the size of the icon with the longest label */
7532    GetIconLayoutParms(file_mgr_rec, file_mgr_data, layout_data);
7533    EstimateIconSize(file_mgr_rec, file_mgr_data, layout_data, file_view_data,
7534                     &grid_width, &grid_height);
7535
7536    /* for tree view add space for tree lines and buttons */
7537    max_level = 0;
7538    if (file_mgr_data->show_type == MULTIPLE_DIRECTORY)
7539    {
7540       for (i = 0; i < order_count; i++)
7541       {
7542          if (order_list[i]->displayed)
7543          {
7544             GetLevel(order_list[i], &level);
7545             if (level > max_level)
7546                max_level = level;
7547          }
7548       }
7549       grid_width += TreeWd(max_level, layout_data->treebtn_size);
7550    }
7551
7552    file_mgr_data->grid_height = grid_height;
7553    file_mgr_data->grid_width = grid_width;
7554
7555    /*
7556     * If positioning is enabled in this view, then we need to use the other
7557     * layout function, which is capable of handling overlapping icons and
7558     * stacking order.
7559     */
7560    if (PositioningEnabledInView(file_mgr_data))
7561    {
7562       if (file_mgr_data->object_positions)
7563       {
7564          LayoutDesktopIcons(file_mgr_rec, file_mgr_data,
7565                             order_list, order_count, turn_off_hourglass);
7566          /* RepairFileWindow(file_mgr_data); *OBSOLETE* */
7567          goto layout_done;
7568       }
7569    }
7570
7571    /*
7572     * Position and size the icons according to the show and view types.
7573     */
7574
7575    scrolled_window_width = file_mgr_rec->scroll_window->core.width;
7576    scrolled_window_height = file_mgr_rec->scroll_window->core.height;
7577    vert_scrollbar_width = file_mgr_rec->vertical_scroll_bar->core.width;
7578    horiz_scrollbar_height = file_mgr_rec->horizontal_scroll_bar->core.height;
7579
7580    if (file_mgr_data->show_type == MULTIPLE_DIRECTORY)
7581    {
7582      /* if not yet done, create tree button icons */
7583      if (TreeBtnWd[0] == 0)
7584        CreateTreeIcons(file_mgr_rec->file_window);
7585
7586      /* layout for tree mode */
7587      x = MARGIN;
7588      y = MARGIN;
7589      file_window_width = MARGIN + grid_width - TreeOffset + XSPACING;
7590
7591      for (k = 0; k < order_count; k++)
7592      {
7593        if (!order_list[k]->displayed)
7594          continue;
7595
7596        /* make sure window height won't exceed limit */
7597        extra_height = GetExtraHeight(file_mgr_data, order_list[k],
7598                                      layout_data->treebtn_size);
7599        tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
7600        if (tmp + MARGIN > MAXWINSIZE)
7601        {
7602          /* window would exceed height limit; start a new column */
7603          x += grid_width + XSPACING;
7604          y = MARGIN;
7605          file_window_width += grid_width + XSPACING;
7606          tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
7607          overflow = True;
7608        }
7609
7610        order_list[k]->x = x;
7611        order_list[k]->y = y + grid_height;
7612
7613        /* update y */
7614        y = (Position)tmp;
7615      }
7616
7617      if (overflow)
7618        file_window_height = MAXWINSIZE;
7619      else
7620        file_window_height = y + MARGIN;
7621    }
7622    else if (file_mgr_data->view == BY_ATTRIBUTES)
7623    {
7624       /* layout for details view, no tree mode */
7625       x = MARGIN;
7626       y = MARGIN;
7627       file_window_width = 2*MARGIN + grid_width;
7628
7629       for (k = 0; k < order_count; k++)
7630       {
7631          if (!order_list[k]->displayed)
7632             continue;
7633
7634          /* make sure window height won't exceed limit */
7635          tmp = (int)y + grid_height + YSPACING(file_mgr_data);
7636          if (tmp + MARGIN > MAXWINSIZE)
7637          {
7638             /* window would exceed height limit; start a new column */
7639             x += grid_width + XSPACING;
7640             y = MARGIN;
7641             file_window_width += grid_width + XSPACING;
7642             tmp = (int)y + grid_height + YSPACING(file_mgr_data);
7643             overflow = True;
7644          }
7645
7646          order_list[k]->x = x;
7647          order_list[k]->y = y + grid_height;
7648
7649          /* update y */
7650          y = (Position)tmp;
7651       }
7652
7653       if (overflow)
7654          file_window_height = MAXWINSIZE;
7655       else
7656          file_window_height = y + MARGIN;
7657    }
7658    else  /* show_type == SINGLE_DIRECTORY, view != BY_ATTRIBUTES */
7659    {
7660       /* layout for "normal" views (no tree mode, no details) */
7661
7662       /* calculate how many columns fit in the window width */
7663      column_count = ((int)scrolled_window_width - 4 - 2*MARGIN + XSPACING) /
7664        ((int)grid_width + XSPACING);
7665      if (column_count == 0)
7666        column_count = 1;  /* need at least one column */
7667
7668       /*
7669        * Calculate the window height.  Need to do calculation in int's
7670        * rather than short (Dimension) because of possible overflow.
7671        */
7672      row_count = (total_icon_count + column_count - 1) / column_count;
7673      tmp = 2*MARGIN - YSPACING(file_mgr_data) +
7674        row_count * ((int)grid_height + YSPACING(file_mgr_data));
7675
7676      /* check if the height is larger than the scrolled window */
7677      if (tmp >= (int)scrolled_window_height - 2*MARGIN)
7678      {
7679        /* need to recompute everything because of space for vert scrollbar */
7680        column_count = ((int)scrolled_window_width - 4 - 2*MARGIN + XSPACING
7681                        - (int)vert_scrollbar_width)
7682          / ((int)grid_width + XSPACING);
7683        if (column_count == 0)
7684          column_count = 1;
7685        row_count = (total_icon_count + column_count - 1) / column_count;
7686        tmp = 2*MARGIN - YSPACING(file_mgr_data) +
7687          row_count * ((int)grid_height + YSPACING(file_mgr_data));
7688      }
7689
7690      /* check if the window height is within the limit */
7691      if (tmp <= MAXWINSIZE)
7692        file_window_height = (Dimension)tmp;
7693      else
7694      {
7695        /* window height too large; use more columns */
7696        overflow = True;
7697        row_count = (int)(MAXWINSIZE - 2*MARGIN + YSPACING(file_mgr_data)) /
7698          (int)((int)grid_height + YSPACING(file_mgr_data));
7699        column_count = (total_icon_count  + row_count - 1) / row_count;
7700        row_count = (total_icon_count + column_count - 1) / column_count;
7701        file_window_height = (Dimension) (2*MARGIN - YSPACING(file_mgr_data) +
7702                                          row_count * ((int)grid_height + YSPACING(file_mgr_data)));
7703      }
7704
7705      DPRINTF(("  %d columns, %d rows (scroll_window width %d)\n",
7706               column_count, row_count,
7707               scrolled_window_width));
7708
7709      /* assign positions to all icons */
7710      y = MARGIN;
7711      file_window_width = (Dimension)
7712        (2*MARGIN - XSPACING + column_count*((int)grid_width + XSPACING));
7713
7714      k = 0;
7715      for (i = 0; i < row_count; i++)
7716      {
7717        x = MARGIN;
7718
7719        for (j = 0; j < column_count && k < order_count;)
7720        {
7721          /* find the next icon to display */
7722          while (k < order_count && !order_list[k]->displayed)
7723            k++;
7724          if (k == order_count)
7725            break;
7726
7727          if (layout_data->alignment == XmALIGNMENT_CENTER &&
7728              file_mgr_data->view == BY_NAME_AND_ICON)
7729          {
7730            EstimateIconSize(file_mgr_rec, file_mgr_data, layout_data,
7731                             order_list[k], &icon_width, &icon_height);
7732            order_list[k]->x = x +
7733              (Dimension)(grid_width - icon_width)/(Dimension)2;
7734          }
7735          else
7736            order_list[k]->x = x;
7737          order_list[k]->y = y + grid_height;
7738
7739          x += grid_width + XSPACING;
7740          j++;
7741          k++;
7742        }
7743
7744        y += grid_height + YSPACING(file_mgr_data);
7745      }
7746    }
7747
7748    DPRINTF(("  file_window size: width %d, height %d\n",
7749             file_window_width, file_window_height));
7750
7751    /*  Manage/unmanage the scrollbars as needed.  */
7752
7753    XtSetArg (args[0], XmNwidth, file_window_width);
7754    XtSetArg (args[1], XmNheight, file_window_height);
7755    XtSetValues ((Widget)file_window, args, 2);
7756
7757    XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmAS_NEEDED);
7758    XtSetValues (file_mgr_rec->scroll_window, args, 1);
7759
7760
7761    /*  Unmanage the horizontal scrollbar if it is not needed   */
7762    if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
7763                                   file_mgr_rec->scroll_window))
7764    {
7765       if (file_window_width >= (Dimension)(scrolled_window_width - 4 -
7766                                                          vert_scrollbar_width))
7767          XtManageChild (file_mgr_rec->horizontal_scroll_bar);
7768       else
7769       {
7770          XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
7771          XtSetArg (args[0], XmNx, 0);
7772          XtSetValues ((Widget)file_window, args, 1);
7773       }
7774    }
7775    else if (file_window_width >= (Dimension)(scrolled_window_width - 4))
7776       XtManageChild (file_mgr_rec->horizontal_scroll_bar);
7777    else
7778    {
7779       XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
7780       XtSetArg (args[0], XmNx, 0);
7781       XtSetValues ((Widget)file_window, args, 1);
7782    }
7783
7784    XSync (XtDisplay (file_window), False);
7785
7786    /*  Set the file window width and height to be at least  */
7787    /*  the size of the scrolled window.                     */
7788
7789    if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
7790                                   file_mgr_rec->scroll_window))
7791    {
7792       if(file_window_width <= (Dimension)(scrolled_window_width -
7793                            (vert_scrollbar_width + 4)))
7794
7795          file_window_width = scrolled_window_width -
7796                            (vert_scrollbar_width + 4);
7797    }
7798    else
7799    {
7800       if(file_window_width < (Dimension)(scrolled_window_width - 4))
7801          file_window_width = scrolled_window_width - 4;
7802    }
7803
7804    if (HorizontalScrollbarIsVisible(file_mgr_rec->horizontal_scroll_bar,
7805                                     file_mgr_rec->scroll_window))
7806    {
7807       int pad;
7808
7809       XtSetArg (args[0], XmNhighlightThickness, &sb_highlight_thickness);
7810       XtGetValues ((Widget)file_mgr_rec->horizontal_scroll_bar, args, 1);
7811
7812       XtSetArg (args[0], XmNshadowThickness, &sw_shadow_thickness);
7813       XtSetArg (args[1], XmNspacing, &space);
7814       XtGetValues ((Widget)file_mgr_rec->scroll_window, args, 2);
7815
7816       pad = (int)(((sb_highlight_thickness + sw_shadow_thickness) * 2) + space);
7817
7818       if(file_window_height < (Dimension)(scrolled_window_height -
7819                         (horiz_scrollbar_height + pad)))
7820          file_window_height = scrolled_window_height -
7821                         (horiz_scrollbar_height + pad);
7822    }
7823    else
7824    {
7825       if (file_window_height < (Dimension)(scrolled_window_height - 4))
7826          file_window_height = scrolled_window_height - 4;
7827    }
7828
7829
7830    XtSetArg (args[0], XmNwidth, file_window_width);
7831    XtSetArg (args[1], XmNheight, file_window_height);
7832    XtSetValues ((Widget)file_window, args, 2);
7833
7834    if( file_mgr_data->scrollToThisFile == NULL )
7835    {
7836      if (update_scrolling_position)
7837      {
7838        XtSetArg (args[0], XmNx, 0);
7839        XtSetArg (args[1], XmNy, 0);
7840        XtSetValues ((Widget)file_window, args, 2);
7841      }
7842
7843      /*  Set the vertical scrollbar's increment to icon height  */
7844      XtSetArg (args[0], XmNincrement, grid_height + YSPACING(file_mgr_data));
7845      XtSetArg (args[1], XmNuserData, grid_height + YSPACING(file_mgr_data));
7846      XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 2);
7847    }
7848
7849    if (PositioningEnabledInView(file_mgr_data))
7850    {
7851      BuildObjectPositions(file_mgr_data);
7852      /* RepairFileWindow(file_mgr_data); *OBSOLETE* */
7853    }
7854
7855    /*
7856     * Don't keep up the hourglass; this helps the user to get the impression
7857     * that all of the work is done.
7858     */
7859    if (turn_off_hourglass && !overflow)
7860       _DtTurnOffHourGlass(file_mgr_rec->shell);
7861
7862
7863 layout_done:
7864
7865
7866    /*
7867     * Start up a work proc that will update the display.
7868     */
7869    layout_data->visible_done = False;
7870    layout_data->all_done = False;
7871    if (layout_data->work_id == 0)
7872    {
7873       XtAppContext app_context =
7874         XtWidgetToApplicationContext(file_mgr_rec->shell);
7875
7876       DPRINTF(("LayoutFileIcons: starting workproc\n"));
7877       layout_data->drop_site_w = (Widget)file_mgr_rec->shell;
7878       XmDropSiteStartUpdate(layout_data->drop_site_w);
7879
7880       layout_data->work_id =
7881         XtAppAddWorkProc(app_context, DisplayWorkProc, file_mgr_rec);
7882    }
7883
7884
7885    if( file_mgr_data->scrollToThisFile )
7886    {
7887      int i;
7888      DirectorySet * directory_set = NULL;
7889
7890      file_view_data = NULL;
7891
7892      for( i = 0; i < file_mgr_data->directory_count; ++i)
7893      {
7894        if( strcmp( ((DirectorySet *)file_mgr_data->directory_set[i])->name, file_mgr_data->scrollToThisDirectory ) == 0 )
7895        {
7896          directory_set = (DirectorySet *)file_mgr_data->directory_set[i];
7897          break;
7898        }
7899      }
7900
7901      if( directory_set )
7902      {
7903        for( i = 0; i < directory_set->file_count; ++i )
7904        {
7905          if( strcmp( directory_set->order_list[i]->file_data->file_name,
7906                      file_mgr_data->scrollToThisFile ) == 0 )
7907          {
7908            file_view_data = directory_set->order_list[i];
7909            break;
7910          }
7911        }
7912      }
7913
7914      if( file_view_data
7915          && file_view_data->filtered == False )
7916      {
7917        FileMgrRec * file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
7918
7919        DeselectAllFiles( file_mgr_data );
7920        SelectFile( file_mgr_data, file_view_data );
7921        ActivateSingleSelect( file_mgr_rec,
7922              file_mgr_data->selection_list[0]->file_data->logical_type );
7923
7924        PositionFileView(file_view_data, file_mgr_data);
7925      }
7926      else
7927      {
7928        if (update_scrolling_position)
7929        {
7930          XtSetArg (args[0], XmNx, 0);
7931          XtSetArg (args[1], XmNy, 0);
7932          XtSetValues ((Widget)file_window, args, 2);
7933        }
7934
7935        /* Set the vertical scrollbar's increment to icon height  */
7936        XtSetArg (args[0], XmNincrement, grid_height + YSPACING(file_mgr_data));
7937        XtSetArg (args[1], XmNuserData, grid_height + YSPACING(file_mgr_data));
7938        XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 2);
7939      }
7940
7941      XtFree( file_mgr_data->scrollToThisFile );
7942      file_mgr_data->scrollToThisFile = NULL;
7943      XtFree( file_mgr_data->scrollToThisDirectory );
7944      file_mgr_data->scrollToThisDirectory = NULL;
7945    }
7946
7947 #ifdef DT_PERFORMANCE
7948    gettimeofday(&update_time_f, NULL);
7949    if (update_time_s.tv_usec > update_time_f.tv_usec) {
7950       update_time_f.tv_usec += 1000000;
7951       update_time_f.tv_sec--;
7952    }
7953    printf("    done LayoutFileIcons, time: %ld.%ld\n\n",
7954           update_time_f.tv_sec - update_time_s.tv_sec,
7955           update_time_f.tv_usec - update_time_s.tv_usec);
7956
7957    /* the following message send call added by Rafi */
7958    _DtPerfChkpntMsgSend("Done LayoutFileIcons");
7959 #endif
7960
7961    DPRINTF(("... done\n"));
7962 }
7963
7964
7965
7966 /************************************************************************
7967  *
7968  *  TreeBtnCallback
7969  *      Callback function invoked upon clicking the tree-branch-expand button.
7970  *
7971  ************************************************************************/
7972
7973 static void
7974 TreeBtnCallback(
7975         Widget w,
7976         XtPointer clientData,
7977         XmAnyCallbackStruct *callData )
7978 {
7979   FileMgrRec *file_mgr_rec;
7980   FileMgrData *file_mgr_data;
7981   FileViewData *file_view_data = (FileViewData *)clientData;
7982   Arg args[20];
7983   Bool expand;
7984
7985   /* check which mouse button was pressed */
7986   if ((callData->event->type == ButtonPress ||
7987        callData->event->type == ButtonRelease) &&
7988       ((XButtonEvent *)callData->event)->button != Button1)
7989   {
7990     return;
7991   }
7992   expand = True;
7993
7994   /* get file mgr data and record */
7995   XtSetArg (args[0], XmNuserData, &file_mgr_data);
7996   XtGetValues (w, args, 1);
7997   file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
7998
7999   XmDropSiteStartUpdate(file_mgr_rec->file_window);
8000   CommitWorkProcUpdates(file_mgr_rec, file_mgr_data, True);
8001   DirTreeExpand(file_mgr_data, file_view_data, expand);
8002   DrawCurrentDirectory (file_mgr_rec->current_directory,
8003                         file_mgr_rec, file_mgr_data);
8004   LayoutFileIcons(file_mgr_rec, file_mgr_data, False, True);
8005   XmDropSiteEndUpdate(file_mgr_rec->file_window);
8006   RedrawTreeLines(file_mgr_rec->file_window,
8007                   -file_mgr_rec->file_window->core.x,
8008                   -file_mgr_rec->file_window->core.y,
8009                   XtParent(file_mgr_rec->file_window)->core.width,
8010                   XtParent(file_mgr_rec->file_window)->core.height,
8011                   0, file_mgr_rec, file_mgr_data);
8012 }
8013
8014
8015 /*
8016  * When a drop occurs on a File Manger window, which now
8017  * support random placement, what is dropped may not ultimately be what
8018  * is displayed.  Since the dissolve transition effect has been disabled
8019  * for drops on the desktop, we can sometimes end up with garbage left on
8020  * the desktop.  This function will attempt to clear up the leftover garbage,
8021  * by resetting all areas of the desktop which are not covered by an icon
8022  * to the background color for the file window.
8023  *
8024  * This function is OBSOLETE (?).
8025  */
8026
8027 void
8028 RepairFileWindow (
8029    FileMgrData * file_mgr_data)
8030
8031 {
8032    FileMgrRec * file_mgr_rec;
8033    Region clipList;
8034    Region hotspot;
8035    Region redrawRegion;
8036    int i;
8037    XRectangle rect;
8038    int num_children;
8039    Widget * children;
8040    XmManagerWidget file_window;
8041    GC gc;
8042    unsigned long mask;
8043    XGCValues values;
8044
8045    file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
8046    file_window = (XmManagerWidget)file_mgr_rec->file_window;
8047
8048    /* Initialize the clip region to that of the file window */
8049    rect.x = 0;
8050    rect.y = 0;
8051    rect.height = file_window->core.height;
8052    rect.width = file_window->core.width;
8053    clipList = XCreateRegion();
8054    XUnionRectWithRegion(&rect, clipList, clipList);
8055
8056    /* Subtract out the hotspots associated with each icon */
8057    num_children = file_window->composite.num_children;
8058    children = file_window->composite.children;
8059    hotspot = XCreateRegion();
8060
8061    for (i = 0; i < num_children; i++)
8062    {
8063       if (XtIsManaged(children[i]) &&
8064           XtIsSubclass(children[i], dtIconGadgetClass))
8065       {
8066          WidgetRectToRegion(file_mgr_data, children[i], hotspot);
8067          XSubtractRegion(clipList, hotspot, clipList);
8068       }
8069    }
8070
8071    /* Create a GC for doing our drawing */
8072    mask = GCForeground;
8073    values.foreground = file_window->core.background_pixel;
8074    gc = XCreateGC(XtDisplay(file_window), XtWindow(file_window), mask, &values);
8075    XSetRegion(XtDisplay(file_window), gc, clipList);
8076
8077    /* Restore the window */
8078    XFillRectangle(XtDisplay(file_window), XtWindow(file_window), gc, 0, 0,
8079                   file_window->core.width, file_window->core.height);
8080
8081    /*
8082     * Force all icons to redraw, since we are only able to repair the
8083     * areas where icons are not; the drop image may have extended onto
8084     * some of the icons.
8085     */
8086    rect.x = 0;
8087    rect.y = 0;
8088    rect.height = file_window->core.height;
8089    rect.width = file_window->core.width;
8090    redrawRegion = XCreateRegion();
8091    XUnionRectWithRegion(&rect, redrawRegion, redrawRegion);
8092    (*file_window->core.widget_class->core_class.expose)
8093              ((Widget)file_window, NULL, redrawRegion);
8094
8095    /* Clean up */
8096    XFreeGC(XtDisplay(file_window), gc);
8097    XDestroyRegion(clipList);
8098    XDestroyRegion(hotspot);
8099    XDestroyRegion(redrawRegion);
8100 }
8101
8102
8103
8104
8105 /*
8106  * Compress the stacking order values, anytime an item is removed.
8107  */
8108
8109 static void
8110 CompressObjectList (
8111    ObjectPosition ** object_positions,
8112    int num_objects,
8113    int starting_index)
8114 {
8115    int i;
8116
8117    for (i = 0; i < num_objects; i++)
8118    {
8119       if (object_positions[i]->stacking_order > starting_index)
8120          object_positions[i]->stacking_order--;
8121    }
8122 }
8123
8124
8125
8126 /************************************************************************
8127  *
8128  *  LayoutDesktopIcons
8129  *      Position and size the full set of icons for the file mgr data.
8130  *
8131  ************************************************************************/
8132
8133 static void
8134 LayoutDesktopIcons (
8135      FileMgrRec  * file_mgr_rec,
8136      FileMgrData * file_mgr_data,
8137      FileViewData ** order_list,
8138      int order_count,
8139      Boolean turn_off_hourglass )
8140
8141 {
8142    XmManagerWidget file_window;
8143    int directory_count, largest_x, largest_y;
8144    int value, size, increment, page;
8145    Dimension current_wd;
8146    Dimension current_ht;
8147    Dimension file_window_width;
8148    Dimension grid_height;
8149    Dimension grid_width;
8150    FileViewData * object;
8151    ObjectPosition * position_data;
8152    ObjectPosition * bottom;
8153    ObjectPtr top;
8154    int i, j, k;
8155    Boolean set_size = False;
8156    char * edit_name;
8157    Arg args[2];
8158    int sorder;
8159
8160
8161    /*  Get the grid block size */
8162    file_window = (XmManagerWidget) file_mgr_rec->file_window;
8163    grid_height = file_mgr_data->grid_height;
8164    grid_width = file_mgr_data->grid_width;
8165
8166    file_window_width = file_mgr_rec->scroll_window->core.width - 4;
8167    current_ht = file_mgr_rec->file_window->core.height;
8168    current_wd = file_mgr_rec->file_window->core.width;
8169
8170
8171    /* Before positioning, mark all position entries as 'not used' */
8172    for (i = 0; i < file_mgr_data->num_objects; i++)
8173    {
8174       file_mgr_data->object_positions[i]->in_use = False;
8175       file_mgr_data->object_positions[i]->file_view_data = NULL;
8176    }
8177
8178    /*
8179     * Before attempting to place new icons, we need to make sure that
8180     * all of the existing object_positions entries have had their
8181     * file_view_data field filled in.  This is so that during placement,
8182     * we can get the height and width of the associated icons, to help
8183     * prevent overlap.
8184     */
8185    for (i = 0; i < order_count; i++)
8186    {
8187       object = order_list[i];
8188       if (object->displayed)
8189       {
8190          if (position_data = GetPositionalData(file_mgr_data, object, 0, False))
8191          {
8192             /* Save; used later during redraw */
8193             position_data->file_view_data = object;
8194             object->position_info = (ObjectPtr)position_data;
8195          }
8196       }
8197       else if (position_data = GetPositionalData(file_mgr_data, object, 0,
8198                                                  False))
8199       {
8200          /*
8201           * If an object has position information, but is currently
8202           * filtered, don't discard its position info; mark it as in-use.
8203           */
8204          position_data->file_view_data = object;
8205          object->position_info = (ObjectPtr)position_data;
8206       }
8207    }
8208
8209    /* Remove any unused position data entries */
8210    for (i = 0; i < file_mgr_data->num_objects; )
8211    {
8212       if (!file_mgr_data->object_positions[i]->in_use)
8213       {
8214          /* If this object had a text field, delete it */
8215          for (k = 0; k < file_window->composite.num_children; k++)
8216          {
8217             if (XmIsTextField(file_window->composite.children[k]) &&
8218                 !file_window->composite.children[k]->core.being_destroyed)
8219             {
8220                XtSetArg(args[0], XmNuserData, &edit_name);
8221                XtGetValues(file_window->composite.children[k], args, 1);
8222                if (strcmp(edit_name,file_mgr_data->object_positions[i]->name)
8223                         == 0)
8224                {
8225                   /* Match */
8226                   XtUnmanageChild(file_window->composite.children[k]);
8227                   XtDestroyWidget(file_window->composite.children[k]);
8228                   break;
8229                }
8230             }
8231          }
8232
8233          /* Free up the entry; bump up the other array entries */
8234          /* Update the linked list */
8235          if (file_mgr_data->object_positions[i]->prev)
8236          {
8237             file_mgr_data->object_positions[i]->prev->next = (ObjectPtr)
8238                 file_mgr_data->object_positions[i]->next;
8239          }
8240          if (file_mgr_data->object_positions[i]->next)
8241          {
8242             file_mgr_data->object_positions[i]->next->prev = (ObjectPtr)
8243                 file_mgr_data->object_positions[i]->prev;
8244          }
8245          sorder = file_mgr_data->object_positions[i]->stacking_order;
8246          XtFree(file_mgr_data->object_positions[i]->name);
8247          file_mgr_data->object_positions[i]->name = NULL;
8248          XtFree((char *)file_mgr_data->object_positions[i]);
8249          file_mgr_data->object_positions[i] = NULL;
8250          for (j = i; j < file_mgr_data->num_objects - 1; j++)
8251          {
8252             file_mgr_data->object_positions[j] =
8253                                    file_mgr_data->object_positions[j+1];
8254          }
8255          file_mgr_data->num_objects--;
8256          file_mgr_data->object_positions = (ObjectPosition **) XtRealloc(
8257                (char *)file_mgr_data->object_positions,
8258                sizeof(ObjectPosition *) * file_mgr_data->num_objects);
8259          CompressObjectList(file_mgr_data->object_positions,
8260                             file_mgr_data->num_objects, sorder);
8261       }
8262       else
8263          i++;
8264    }
8265
8266    /* Now, it is safe to position any unplaced objects */
8267    for (i = 0; i < order_count; i++)
8268    {
8269       object = order_list[i];
8270       if (object->displayed)
8271       {
8272          position_data = GetPositionalData(file_mgr_data, object,
8273                                            file_window_width, True);
8274
8275          /* Save; used later during redraw */
8276          position_data->file_view_data = object;
8277          object->position_info = (ObjectPtr)position_data;
8278
8279          /* record position of bottom left corner for DisplaySomeIcons */
8280          object->x = position_data->x;
8281          object->y = position_data->y +
8282                (object->need_update? grid_height: object->widget->core.height);
8283       }
8284    }
8285
8286    /* Get largest x value */
8287    largest_x = 0;
8288    largest_y = 0;
8289    bottom = GetBottomOfStack(file_mgr_data);
8290    while (bottom)
8291    {
8292       if (bottom->file_view_data != NULL && bottom->file_view_data->displayed)
8293       {
8294          if (bottom->file_view_data->position_info->x > largest_x)
8295             largest_x = bottom->file_view_data->position_info->x;
8296          if (bottom->file_view_data->position_info->y > largest_y)
8297             largest_y = bottom->file_view_data->position_info->y;
8298       }
8299       bottom = (ObjectPosition *)bottom->prev;
8300    }
8301    largest_x += grid_width;
8302    largest_y += grid_height;
8303
8304    /* if necessary, shrink the width & height to what we need */
8305    if (current_wd == 32767)
8306    {
8307       current_wd = largest_x;
8308       set_size = True;
8309    }
8310
8311    if (current_ht == 32767)
8312    {
8313       current_ht = largest_y;
8314       set_size = True;
8315    }
8316
8317    /*  Get the horizontal and vertical scrollbars.  */
8318    XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmAS_NEEDED);
8319    XtSetValues (file_mgr_rec->scroll_window, args, 1);
8320
8321    /*
8322     * Typically, dtfile does everything possible to prevent a horizontal
8323     * scrollbar from being displayed.  However, when random placement is
8324     * enabled, we don't mind having a horizontal scrollbar, when needed.
8325     * We need to manually manage this, since the normal dtfile layout
8326     * code may have forcably unmanaged the scrollbar earlier.
8327     */
8328    if (XtIsManaged(file_mgr_rec->horizontal_scroll_bar))
8329    {
8330       /* get scroll bar values */
8331       (void)XmScrollBarGetValues(file_mgr_rec->horizontal_scroll_bar,
8332                                  &value, &size, &increment, &page);
8333    }
8334
8335    if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
8336                                   file_mgr_rec->scroll_window))
8337    {
8338       if ((Dimension)largest_x >= (Dimension)(file_mgr_rec->scroll_window->core.width -
8339                           (file_mgr_rec->vertical_scroll_bar->core.width + 4)))
8340       {
8341          XtManageChild(file_mgr_rec->horizontal_scroll_bar);
8342       }
8343       else
8344       {
8345          /* set scroll bar values changing its position */
8346          if(value != 0 && XtIsManaged(file_mgr_rec->horizontal_scroll_bar))
8347             XtManageChild(file_mgr_rec->horizontal_scroll_bar);
8348          else
8349          {
8350             XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
8351             XtSetArg (args[0], XmNx, 0);
8352             XtSetValues ((Widget)file_window, args, 1);
8353          }
8354       }
8355    }
8356    else if ((Dimension)largest_x >= (Dimension)(file_mgr_rec->scroll_window->core.width - 4))
8357       XtManageChild(file_mgr_rec->horizontal_scroll_bar);
8358    else
8359    {
8360       /* set scroll bar values changing its position */
8361       if(value != 0 && XtIsManaged(file_mgr_rec->horizontal_scroll_bar))
8362          XtManageChild(file_mgr_rec->horizontal_scroll_bar);
8363       else
8364       {
8365          XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
8366          XtSetArg (args[0], XmNx, 0);
8367          XtSetValues ((Widget)file_window, args, 1);
8368       }
8369    }
8370
8371    /*  Set the file window width and height to be at least  */
8372    /*  the size of the scrolled window.                     */
8373    if ((Dimension)(current_wd) < (Dimension)(file_mgr_rec->scroll_window->core.width - 4))
8374    {
8375       if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
8376                                      file_mgr_rec->scroll_window))
8377          current_wd = file_mgr_rec->scroll_window->core.width -
8378                            (file_mgr_rec->vertical_scroll_bar->core.width + 4);
8379       else
8380          current_wd = file_mgr_rec->scroll_window->core.width - 4;
8381       set_size = True;
8382    }
8383
8384    if ((Dimension)(current_ht) < (Dimension)(file_mgr_rec->scroll_window->core.height - 4))
8385    {
8386       current_ht = file_mgr_rec->scroll_window->core.height - 4;
8387       set_size = True;
8388    }
8389
8390    if (set_size)
8391    {
8392       XtSetArg (args[0], XmNwidth, current_wd);
8393       XtSetArg (args[1], XmNheight, current_ht);
8394       XtSetValues (file_mgr_rec->file_window, args, 2);
8395    }
8396
8397    /*  Set the vertical scrollbar's increment to icon height  */
8398    XtSetArg (args[0], XmNincrement, file_mgr_data->grid_height + 2);
8399    XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 1);
8400
8401    /*
8402     * Don't keep up the hourglass; this helps the user to get the impression
8403     * that all of the work is done.
8404     */
8405    if (turn_off_hourglass)
8406       _DtTurnOffHourGlass(file_mgr_rec->shell);
8407 }
8408
8409
8410 /***************************************************
8411  *
8412  * Given a desktop object, see if it has already been assigned a position;
8413  * if not, then try to fit it into the next available grid position.
8414  *
8415  **************************************************/
8416
8417 static Boolean
8418 IntersectRects(
8419         Position x1,
8420         Position y1,
8421         Dimension w1,
8422         Dimension h1,
8423         Position x2,
8424         Position y2,
8425         Dimension w2,
8426         Dimension h2 )
8427
8428 {
8429    int srcABot, srcBBot;
8430    int srcARight, srcBRight;
8431    int dw, dh;
8432    int dx, dy;
8433
8434    srcABot = y1 + h1 - 1;
8435    srcBBot = y2 + h2 - 1;
8436    srcARight = x1 + w1 - 1;
8437    srcBRight = x2 + w2 - 1;
8438
8439    if (x1 >= x2)
8440       dx = x1;
8441    else
8442       dx = x2;
8443
8444    if (y1 > y2)
8445       dy = y1;
8446    else
8447       dy = y2;
8448
8449    if (srcARight >= srcBRight)
8450       dw = srcBRight - dx + 1;
8451    else
8452       dw = srcARight - dx + 1;
8453
8454    if (srcABot > srcBBot)
8455       dh = srcBBot - dy + 1;
8456    else
8457       dh = srcABot - dy + 1;
8458
8459    if (dw <= 0 || dh <= 0)
8460       return(FALSE);
8461
8462    return(TRUE);
8463 }
8464
8465 static ObjectPosition *
8466 GetPositionalData (
8467    FileMgrData * file_mgr_data,
8468    FileViewData * object,
8469    Dimension max_width,
8470    Boolean create)
8471 {
8472    int i;
8473    int k;
8474    ObjectPosition *entry, *top;
8475    Position x;
8476    Position y;
8477    Dimension grid_height;
8478    Dimension grid_width;
8479    Boolean hit;
8480    ObjectPosition * oP;
8481    Dimension objWidth, objHeight;
8482    Dimension oWidth, oHeight;
8483
8484    /* If object already has positional data, then use it */
8485    for (i = 0; i < file_mgr_data->num_objects; i++)
8486    {
8487       if (strcmp(object->file_data->file_name,
8488                  file_mgr_data->object_positions[i]->name) == 0)
8489       {
8490          /* Found a match */
8491          file_mgr_data->object_positions[i]->in_use = True;
8492          return(file_mgr_data->object_positions[i]);
8493       }
8494    }
8495
8496    if (!create)
8497       return(NULL);
8498
8499    /* Create a new entry, and place into the grid on the top of the stack */
8500    entry = (ObjectPosition *) XtMalloc(sizeof(ObjectPosition));
8501    entry->name = XtNewString(object->file_data->file_name);
8502    entry->in_use = True;
8503    entry->late_bind = False;
8504    entry->stacking_order = 2;
8505    entry->prev = NULL;
8506    entry->next = NULL;
8507    entry->file_view_data = NULL;
8508
8509    if(file_mgr_data->num_objects == 1)
8510    {
8511       top = file_mgr_data->object_positions[0];
8512       top->next = (ObjectPtr)entry;
8513       entry->prev = (ObjectPtr)top;
8514    }
8515    else
8516    {
8517       top = NULL;
8518       /* Push all other objects down in the stack */
8519       for (i = 0; i < file_mgr_data->num_objects; i++)
8520       {
8521          /* Find the previous top of the stack */
8522          if (file_mgr_data->object_positions[i]->stacking_order == 1)
8523          {
8524             top = file_mgr_data->object_positions[i];
8525             continue;
8526          }
8527          else if (file_mgr_data->object_positions[i]->stacking_order == 2)
8528          {
8529             if(top == NULL)
8530                top = GetTopOfStack(file_mgr_data);
8531             top->next = (ObjectPtr)entry;
8532             entry->next = (ObjectPtr)file_mgr_data->object_positions[i];
8533             entry->prev = (ObjectPtr)top;
8534             file_mgr_data->object_positions[i]->prev = (ObjectPtr)entry;
8535          }
8536          file_mgr_data->object_positions[i]->stacking_order++;
8537       }
8538    }
8539
8540    grid_height = file_mgr_data->grid_height;
8541    grid_width = file_mgr_data->grid_width;
8542    x = MARGIN;
8543    y = MARGIN;
8544
8545    if (object->widget && !object->need_update)
8546    {
8547       objWidth = object->widget->core.width;
8548       objHeight = object->widget->core.height;
8549    }
8550    else
8551    {
8552       objWidth = grid_width;
8553       objHeight = grid_height;
8554    }
8555
8556    /* Find the first open spot, which will not cause any overlap */
8557    do
8558    {
8559       hit = False;
8560
8561       for (i = 0; i < file_mgr_data->num_objects; i++)
8562       {
8563          oP = file_mgr_data->object_positions[i];
8564          if (oP->file_view_data->widget && !oP->file_view_data->need_update)
8565          {
8566             oWidth = oP->file_view_data->widget->core.width;
8567             oHeight = oP->file_view_data->widget->core.height;
8568          }
8569          else
8570          {
8571             oWidth = grid_width;
8572             oHeight = grid_height;
8573          }
8574          if (oP->file_view_data->displayed &&
8575              IntersectRects(x, y, objWidth, objHeight,
8576                             oP->x, oP->y, oWidth, oHeight))
8577          {
8578             /* Try next grid spot */
8579             x += grid_width + XSPACING;
8580
8581             if ((Dimension)(x + objWidth) >= max_width)
8582             {
8583                /* Go to next row */
8584                y += grid_height + YSPACING(file_mgr_data);
8585                x = MARGIN;
8586             }
8587             hit = True;
8588             break;
8589          }
8590       }
8591    } while (hit);
8592
8593    /* Add to the end of the list */
8594    entry->x = x;
8595    entry->y = y;
8596    file_mgr_data->num_objects++;
8597    file_mgr_data->object_positions = (ObjectPosition **) XtRealloc(
8598                    (char *)file_mgr_data->object_positions,
8599                    sizeof(ObjectPosition *) * file_mgr_data->num_objects);
8600
8601    /* Force the ordered list to be maintained */
8602    for (i = 0; i < file_mgr_data->num_objects - 1; i++)
8603    {
8604       if ((entry->y < file_mgr_data->object_positions[i]->y) ||
8605           ((entry->y == file_mgr_data->object_positions[i]->y) &&
8606            (entry->x < file_mgr_data->object_positions[i]->x)))
8607       {
8608          /* Fits here; slide later entries down */
8609          for (k = file_mgr_data->num_objects - 1; k > i; k--)
8610          {
8611             file_mgr_data->object_positions[k] =
8612                 file_mgr_data->object_positions[k-1];
8613          }
8614
8615          break;
8616       }
8617    }
8618
8619    file_mgr_data->object_positions[i] = entry;
8620    return(file_mgr_data->object_positions[i]);
8621 }
8622
8623
8624 /*******************************************************************
8625  *
8626  *  BuildObjectPositons - builds up the object positions for directories
8627  *    which have now object position information.
8628  *
8629  *********************************************************************/
8630 static void
8631 BuildObjectPositions(
8632    FileMgrData *file_mgr_data)
8633 {
8634    int i, j, k, l;
8635    FileViewData * file_view_data;
8636    ObjectPosition * ptr;
8637
8638    file_mgr_data->object_positions = (ObjectPosition **)XtMalloc(
8639                sizeof(ObjectPosition *) *
8640                file_mgr_data->directory_set[0]->file_count);
8641
8642    for (i = 0, j = 0; i < file_mgr_data->directory_set[0]->file_count; i++)
8643    {
8644       file_view_data = file_mgr_data->directory_set[0]->order_list[i];
8645
8646       if (file_view_data->filtered)
8647          continue;
8648
8649       ptr = (ObjectPosition *) XtMalloc(sizeof(ObjectPosition));
8650       ptr->name = XtNewString(file_view_data->file_data->file_name);
8651       ptr->x = file_view_data->x;
8652       ptr->y = file_view_data->y -
8653             (file_view_data->need_update? file_mgr_data->grid_height:
8654                                           file_view_data->widget->core.height);
8655       ptr->in_use = True;
8656       ptr->late_bind = False;
8657       ptr->stacking_order = j+1;
8658       ptr->file_view_data = file_view_data;
8659       file_view_data->position_info = (ObjectPtr)ptr;
8660       ptr->next = NULL;
8661       ptr->prev = NULL;
8662
8663       /* Sort according to left-to-right, top-to-bottom */
8664       for (k = 0; k < j; k++)
8665       {
8666          if ((ptr->y < file_mgr_data->object_positions[k]->y) ||
8667              ((ptr->y == file_mgr_data->object_positions[k]->y) &&
8668               (ptr->x < file_mgr_data->object_positions[k]->x)))
8669          {
8670             /* Shift others down, to open up a spot */
8671             for (l = j; l > k; l--)
8672             {
8673                file_mgr_data->object_positions[l] =
8674                      file_mgr_data->object_positions[l - 1];
8675             }
8676             break;
8677          }
8678       }
8679       file_mgr_data->object_positions[k] = ptr;
8680       j++;
8681    }
8682
8683    file_mgr_data->num_objects = j;
8684
8685    /* Repair all of the next and prev pointers */
8686    RepairStackingPointers(file_mgr_data);
8687    OrderChildrenList(file_mgr_data);
8688 }
8689
8690
8691 /***********************************
8692  *
8693  * When items are dragged around on a random placement window, they will be
8694  * repositioned at the point where they were dropped.  Multiple drop items
8695  * will be positioned 'around' where the drop occurred.
8696  *
8697  **********************************/
8698
8699 void
8700 RepositionIcons (
8701    FileMgrData * file_mgr_data,
8702    char ** file_list,
8703    int file_count,
8704    Position drop_x,
8705    Position drop_y,
8706    Boolean late_binding_needed)
8707
8708 {
8709    Position x;
8710    Position y;
8711    int i, i2, j, k, l;
8712    int adj;
8713    Position orig_x;
8714    Position orig_y;
8715    ObjectPosition * save_object;
8716    char * name;
8717    FileMgrRec * file_mgr_rec;
8718    XmManagerWidget file_window;
8719    Widget textWidget;
8720    char * edit_name;
8721    Arg args[10];
8722    Boolean newEntry;
8723    int newEntryCount = 0;
8724    char dot_dir[3] = ".";
8725    char dotdot_dir[3] = "..";
8726
8727    /* if random placement is not enabled, positioning doesn't matter */
8728    if(file_mgr_data->positionEnabled == RANDOM_OFF)
8729       return;
8730
8731    file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
8732
8733    /*
8734     * For directory views, no positional data may be present if positioning
8735     * was disabled for this view.  So ... we must create some now.
8736     */
8737    if ((file_mgr_data->num_objects == 0) &&
8738        (file_mgr_data->directory_set[0]->file_count > 0))
8739    {
8740          BuildObjectPositions(file_mgr_data);
8741    }
8742
8743    /*
8744     * Update to the new position.
8745     * The position needs to be adjusted so that the icon actually ends
8746     * up where the user dropped it.  This is because the drag icon includes
8747     * margins and shadow area, but not the highlight area of the icon gadget
8748     * that was dragged.  Coordinates drop_x, drop_y are the upper left corner
8749     * of the drag icon when it was dropped.  To convert to icon gadget
8750     * coordinates we need to subtract the highlight thickness.
8751     */
8752    if (file_mgr_data->layout_data != NULL)
8753      adj = ((IconLayoutData *)file_mgr_data->layout_data)->highlight;
8754    else
8755      adj = 0;
8756    x = drop_x - adj;
8757    y = drop_y - adj;
8758    file_window = (XmManagerWidget) file_mgr_rec->file_window;
8759
8760    /* Process each of the dropped files */
8761    /* Go from bottom to top, to retain stacking order */
8762    for (i = file_count - 1; i >= 0; i--)
8763    {
8764       textWidget = NULL;
8765
8766       /*
8767        * The names typically come in as complete paths; we only want
8768        * the filename portion.
8769        * fdt: this check will break for root (/)
8770        */
8771       if( strcmp(file_mgr_data->current_directory, file_list[i]) == 0)
8772          name = dot_dir;
8773       else if(strncmp(file_mgr_data->current_directory, file_list[i], strlen(file_list[i]) ) == 0 )
8774         name = dotdot_dir;
8775       else
8776       {
8777         if ((name = strrchr(file_list[i], '/')) == NULL)
8778           name = file_list[i];
8779         else
8780         {
8781           name++;
8782
8783          /* Try to gracefully handle root (/) */
8784           if (*name == '\0')
8785             name--;
8786         }
8787       }
8788
8789       newEntry = True;
8790
8791       /* Find the positional data for this object, if any */
8792       for (j = 0; j < file_mgr_data->num_objects; j++)
8793       {
8794          if (strcmp(name, file_mgr_data->object_positions[j]->name) == 0)
8795          {
8796             /* Find the associated widget */
8797             for (k = 0; strcmp(name,
8798              file_mgr_data->directory_set[0]->file_view_data[k]->file_data->                    file_name); k++);
8799
8800             newEntry = False;
8801
8802             /* If this object has a text field, then move it also */
8803             for (l = 0; l < file_window->composite.num_children; l++)
8804             {
8805                if (XmIsTextField(file_window->composite.children[l]) &&
8806                    !file_window->composite.children[l]->core.being_destroyed)
8807                {
8808                   XtSetArg(args[0], XmNuserData, &edit_name);
8809                   XtGetValues(file_window->composite.children[l], args, 1);
8810                   if (strcmp(edit_name, name) == 0)
8811                   {
8812                      textWidget = file_window->composite.children[l];
8813                      break;
8814                   }
8815                }
8816             }
8817             break;
8818          }
8819       }
8820
8821       if (newEntry)
8822       {
8823          ObjectPosition * data;
8824
8825          /* Create positional data at the top of the ordered array */
8826          newEntryCount++;
8827          j = 0;
8828          data = (ObjectPosition *) XtMalloc(sizeof(ObjectPosition));
8829          data->name = XtNewString(name);
8830          data->x = 0;
8831          data->y = 0;
8832          data->in_use = True;
8833          data->late_bind = True;
8834          data->stacking_order = 1;
8835          data->file_view_data = NULL;
8836          data->prev = NULL;
8837          data->next = NULL;
8838
8839          /* Push all other objects down in the stack */
8840          for (i2 = 0; i2 < file_mgr_data->num_objects; i2++)
8841          {
8842             /* Find the previous top of the stack */
8843             if (file_mgr_data->object_positions[i2]->stacking_order == 1)
8844             {
8845                data->next = (ObjectPtr)file_mgr_data->object_positions[i2];
8846                file_mgr_data->object_positions[i2]->prev = (ObjectPtr)data;
8847             }
8848             file_mgr_data->object_positions[i2]->stacking_order++;
8849          }
8850
8851          file_mgr_data->num_objects++;
8852          file_mgr_data->object_positions = (ObjectPosition **) XtRealloc(
8853                (char *)file_mgr_data->object_positions,
8854                sizeof(ObjectPosition *) * file_mgr_data->num_objects);
8855
8856          /* Add entry to the top of the ordered array */
8857          for (j = file_mgr_data->num_objects - 1; j > 0; j--)
8858          {
8859             file_mgr_data->object_positions[j] =
8860                     file_mgr_data->object_positions[j - 1];
8861          }
8862
8863          file_mgr_data->object_positions[0] = data;
8864       }
8865       else
8866       {
8867          /* Move item upto top of the stack */
8868          RepositionUpInStack(file_mgr_data,
8869                      file_mgr_data->object_positions[j]->stacking_order, 1);
8870       }
8871
8872       orig_x = file_mgr_data->object_positions[j]->x;
8873       orig_y = file_mgr_data->object_positions[j]->y;
8874       file_mgr_data->object_positions[j]->x = x;
8875       file_mgr_data->object_positions[j]->y = y;
8876       save_object = file_mgr_data->object_positions[j];
8877
8878       /* Move the object */
8879       if (!newEntry)
8880       {
8881          /* We need to force a geometry request */
8882          XtSetArg(args[0], XmNx, x);
8883          XtSetArg(args[1], XmNy, y);
8884          XtSetValues(file_mgr_data->directory_set[0]->file_view_data[k]->widget,
8885                      args, 2);
8886
8887          /* Move associated text widget, if there is one */
8888          if (textWidget)
8889          {
8890             Position t_x, t_y;
8891
8892             t_x = textWidget->core.x + x - orig_x;
8893             t_y = textWidget->core.y + y - orig_y;
8894
8895             /* We need to force a geometry request */
8896             XtSetArg(args[0], XmNx, t_x);
8897             XtSetArg(args[1], XmNy, t_y);
8898             XtSetValues(textWidget, args, 2);
8899          }
8900       }
8901
8902       /*
8903        * Reorder the positional array, so that it remains ordered.
8904        * Bubble down toward the end of the list if the object has moved
8905        * farther from the origin; bubble up if it has moved closer to
8906        * the origin.
8907        */
8908       if ((y > orig_y) || ((y == orig_y) && (x > orig_x)))
8909       {
8910          /* Bubble down */
8911          for (k = j + 1; k < file_mgr_data->num_objects; k++)
8912          {
8913             if ((y < file_mgr_data->object_positions[k]->y) ||
8914                 ((y == file_mgr_data->object_positions[k]->y) &&
8915                  (x < file_mgr_data->object_positions[k]->x)))
8916             {
8917                /* We fit right here */
8918                file_mgr_data->object_positions[k - 1] = save_object;
8919                break;
8920             }
8921             else
8922             {
8923                /* Bubble */
8924                file_mgr_data->object_positions[k - 1] =
8925                      file_mgr_data->object_positions[k];
8926             }
8927          }
8928
8929          /* See if it goes at the end */
8930          if (k == file_mgr_data->num_objects)
8931             file_mgr_data->object_positions[k - 1] = save_object;
8932       }
8933       else
8934       {
8935          /* Bubble up */
8936          for (k = j - 1; k >= 0; k--)
8937          {
8938             if ((y > file_mgr_data->object_positions[k]->y) ||
8939                 ((y == file_mgr_data->object_positions[k]->y) &&
8940                  (x > file_mgr_data->object_positions[k]->x)))
8941             {
8942                /* We fit right here */
8943                file_mgr_data->object_positions[k + 1] = save_object;
8944                break;
8945             }
8946             else
8947             {
8948                /* Bubble */
8949                file_mgr_data->object_positions[k + 1] =
8950                      file_mgr_data->object_positions[k];
8951             }
8952          }
8953
8954          /* See if it goes at the end */
8955          if (k < 0)
8956             file_mgr_data->object_positions[0] = save_object;
8957       }
8958
8959       /* Create position for the next file to be processed */
8960       x += 20;
8961       y += 20;
8962    }
8963    /*
8964     * Reregister the desktop hotspots.
8965     * Even if the caller told us that late binding was needed, if no new
8966     * objects were specified, then we need to register hotspots now, because
8967     * the layout function will never be called because the directory never
8968     * really changed.  This situation can occur when an icon is dropped on
8969     * the desktop from a regular dtfile view, but that icon is already on
8970     * the desktop (it thus is just a reposition).
8971     */
8972    if (!late_binding_needed ||
8973        (late_binding_needed && (newEntryCount == 0)))
8974    {
8975       RegisterDesktopHotspots(file_mgr_data, file_mgr_rec);
8976    }
8977 }
8978
8979 void
8980 RegisterDesktopHotspots (
8981    FileMgrData * file_mgr_data,
8982    FileMgrRec  * file_mgr_rec)
8983 {
8984    XmManagerWidget file_window;
8985    FileViewData  * file_view_data;
8986    int ex, ey, ewd, eht;
8987    ObjectPtr top;
8988    Widget icon;
8989
8990
8991    file_window = (XmManagerWidget) file_mgr_rec->file_window;
8992    ex = -file_window->core.x;
8993    ey = -file_window->core.y;
8994    ewd = XtParent(file_window)->core.width;
8995    eht = XtParent(file_window)->core.height;
8996
8997    /* Set up the icon location information with the drag handler  */
8998    /* Register in top to bottom stacking order */
8999    top = GetTopOfStack(file_mgr_data);
9000
9001    while (top)
9002    {
9003       file_view_data = top->file_view_data;
9004
9005       if (file_view_data != NULL &&
9006           file_view_data->displayed &&
9007           !file_view_data->need_update)
9008       {
9009          icon = file_view_data->widget;
9010          if ((Position)(icon->core.x + icon->core.width) >= (Position)ex  &&
9011              icon->core.x < ex + ewd &&
9012              (Position)(icon->core.y + icon->core.height) >= (Position)ey &&
9013              icon->core.y < ey + eht)
9014          {
9015             SetHotRects(file_view_data,
9016                         (XtCallbackProc) DropOnObject,
9017                         (XtPointer) file_view_data);
9018          }
9019       }
9020
9021       top = top->next;
9022    }
9023 }
9024
9025
9026 /*
9027  * Dtfile used to try to determine if the vertical scrollbar was visible
9028  * by checking to see if it was managed; the assumption here was that the
9029  * scrolled window widget unmanaged the scrollbar, when it was not needed.
9030  * Unfortunately, it turns out that instead of unmanaging the scrollbar,
9031  * the scrolled window simply moves the scrollbar out of sight; it is moved
9032  * such that the X for the scrollbar is the same as the width of the
9033  * scrolled window.  So ... in order for us to really determine if the
9034  * scrollbar is visible, we need to see whether or not its X falls within
9035  * the visible area of the scrolled window.
9036  */
9037
9038 Boolean
9039 VerticalScrollbarIsVisible(
9040         Widget vertSB,
9041         Widget scrolledWin)
9042
9043 {
9044    if (vertSB && XtIsManaged(vertSB) &&
9045        (vertSB->core.x < (Position)scrolledWin->core.width))
9046    {
9047       return(True);
9048    }
9049
9050    return(False);
9051 }
9052
9053 Boolean
9054 HorizontalScrollbarIsVisible(
9055         Widget hortSB,
9056         Widget scrolledWin)
9057
9058 {
9059    if (hortSB && XtIsManaged(hortSB) &&
9060        (hortSB->core.y <= (Position)scrolledWin->core.height))
9061    {
9062       return(True);
9063    }
9064
9065    return(False);
9066 }