Implement -autoCopyPV
[xboard.git] / filebrowser / draw.c
1 /*
2  * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
3  *
4  * Permission to use, copy, modify, and distribute this software and its
5  * documentation for any purpose and without fee is hereby granted, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of Software Research Associates not be used
9  * in advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  Software Research Associates
11  * makes no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
16  * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
17  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
18  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
19  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20  * PERFORMANCE OF THIS SOFTWARE.
21  *
22  * Author: Erik M. van der Poel
23  *         Software Research Associates, Inc., Tokyo, Japan
24  *         erik@sra.co.jp
25  */
26
27 #include <stdio.h>
28 #include "xstat.h"
29 #include "selfile.h"
30 #include "config.h"
31 #include <X11/StringDefs.h>
32 #include <X11/Xaw/Scrollbar.h>
33 #include <X11/Xaw/Cardinals.h>
34
35 #define SF_DEFAULT_FONT "9x15"
36
37 #ifdef ABS
38 #undef ABS
39 #endif
40 #define ABS(x) (((x) < 0) ? (-(x)) : (x))
41
42 typedef struct {
43         char *fontname;
44 } TextData, *textPtr;
45
46 int SFcharWidth, SFcharAscent, SFcharHeight;
47
48 int SFcurrentInvert[3] = { -1, -1, -1 };
49
50 static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
51
52 static XtResource textResources[] = {
53         {XtNfont, XtCFont, XtRString, sizeof (char *),
54                 XtOffset(textPtr, fontname), XtRString, SF_DEFAULT_FONT},
55 };
56
57 #if ENABLE_NLS
58 extern XFontSet fontSet; //XXX should really be in a .h file
59 #else
60 static XFontStruct *SFfont;
61 #endif
62
63 static int SFcurrentListY;
64
65 static XtIntervalId SFscrollTimerId;
66
67 void
68 SFinitFont()
69 {
70 #if ENABLE_NLS
71         XFontSetExtents *fse = XExtentsOfFontSet(fontSet);
72         SFcharWidth = fse->max_logical_extent.width;
73         SFcharAscent = -fse->max_logical_extent.y;
74         SFcharHeight = fse->max_logical_extent.height;
75 #else
76         TextData        *data;
77
78         data = XtNew(TextData);
79
80         XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
81                 XtNumber(textResources), (Arg *) NULL, ZERO);
82
83         SFfont = XLoadQueryFont(SFdisplay, data->fontname);
84         if (!SFfont) {
85                 SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
86                 if (!SFfont) {
87                         char    sbuf[256];
88
89                         (void) sprintf(sbuf, "XsraSelFile: can't get font %s",
90                                 SF_DEFAULT_FONT);
91
92                         XtAppError(SFapp, sbuf);
93                 }
94         }
95
96         SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
97         SFcharAscent = SFfont->max_bounds.ascent;
98         SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
99 #endif
100         return;
101 }
102
103 void
104 SFcreateGC()
105 {
106         XGCValues       gcValues;
107         XRectangle      rectangles[1];
108
109         gcValues.foreground = SFfore;
110
111         SFlineGC = XtGetGC(
112                 selFileLists[0],
113                 (XtGCMask)
114                         GCForeground            |
115                         0,
116                 &gcValues
117         );
118
119         SFscrollGC = XtGetGC(
120                 selFileLists[0],
121                 (XtGCMask)
122                         0,
123                 &gcValues
124         );
125
126         gcValues.function = GXinvert;
127         gcValues.plane_mask = (SFfore ^ SFback);
128
129         SFinvertGC = XtGetGC(
130                 selFileLists[0],
131                 (XtGCMask)
132                         GCFunction              |
133                         GCPlaneMask             |
134                         0,
135                 &gcValues
136         );
137
138         gcValues.foreground = SFfore;
139         gcValues.background = SFback;
140 #if !ENABLE_NLS
141         gcValues.font = SFfont->fid;
142 #endif
143
144         SFtextGC = XCreateGC(
145                 SFdisplay,
146                 XtWindow(selFileLists[0]),
147                 (unsigned long)
148                         GCForeground            |
149                         GCBackground            |
150 #if !ENABLE_NLS
151                         GCFont                  |
152 #endif
153                         0,
154                 &gcValues
155         );
156
157         rectangles[0].x = SFlineToTextH + SFbesideText;
158         rectangles[0].y = 0;
159         rectangles[0].width = SFcharsPerEntry * SFcharWidth;
160         rectangles[0].height = SFupperY + 1;
161
162         XSetClipRectangles(
163                 SFdisplay,
164                 SFtextGC,
165                 0,
166                 0,
167                 rectangles,
168                 1,
169                 Unsorted
170         );
171         return;
172 }
173
174 void
175 SFclearList(n, doScroll)
176         int     n;
177         int     doScroll;
178 {
179         SFDir   *dir;
180
181         SFcurrentInvert[n] = -1;
182
183         XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
184
185         XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs,
186                 2);
187
188         if (doScroll) {
189                 dir = &(SFdirs[SFdirPtr + n]);
190
191                 if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars) {
192                         XawScrollbarSetThumb(
193                                 selFileVScrolls[n],
194                                 (float) (((double) dir->vOrigin) /
195                                         dir->nEntries),
196                                 (float) (((double) ((dir->nEntries < SFlistSize)
197                                         ? dir->nEntries : SFlistSize)) /
198                                         dir->nEntries)
199                         );
200
201                         XawScrollbarSetThumb(
202                                 selFileHScrolls[n],
203                                 (float) (((double) dir->hOrigin) / dir->nChars),
204                                 (float) (((double) ((dir->nChars <
205                                         SFcharsPerEntry) ? dir->nChars :
206                                         SFcharsPerEntry)) / dir->nChars)
207                         );
208                 } else {
209                         XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
210                                 (float) 1.0);
211                         XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
212                                 (float) 1.0);
213                 }
214         }
215         return;
216 }
217
218 static void
219 SFdeleteEntry(dir, entry)
220         SFDir   *dir;
221         SFEntry *entry;
222 {
223         register SFEntry        *e;
224         register SFEntry        *end;
225         int                     n;
226         int                     idx;
227
228         idx = entry - dir->entries;
229
230         if (idx < dir->beginSelection) {
231                 dir->beginSelection--;
232         }
233         if (idx <= dir->endSelection) {
234                 dir->endSelection--;
235         }
236         if (dir->beginSelection > dir->endSelection) {
237                 dir->beginSelection = dir->endSelection = -1;
238         }
239
240         if (idx < dir->vOrigin) {
241                 dir->vOrigin--;
242         }
243
244         XtFree(entry->real);
245
246         end = &(dir->entries[dir->nEntries - 1]);
247
248         for (e = entry; e < end; e++) {
249                 *e = *(e + 1);
250         }
251
252         if (!(--dir->nEntries)) {
253                 return;
254         }
255
256         n = dir - &(SFdirs[SFdirPtr]);
257         if ((n < 0) || (n > 2)) {
258                 return;
259         }
260
261         XawScrollbarSetThumb(
262                 selFileVScrolls[n],
263                 (float) (((double) dir->vOrigin) / dir->nEntries),
264                 (float) (((double) ((dir->nEntries < SFlistSize) ?
265                         dir->nEntries : SFlistSize)) / dir->nEntries)
266         );
267         return;
268 }
269
270 static void
271 SFwriteStatChar(name, last, statBuf)
272         char            *name;
273         int             last;
274         struct stat     *statBuf;
275 {
276         name[last] = SFstatChar(statBuf);
277         return;
278 }
279
280 static int
281 SFstatAndCheck(dir, entry)
282         SFDir   *dir;
283         SFEntry *entry;
284 {
285         struct stat     statBuf;
286         char            save;
287         int             last;
288
289         /*
290          * must be restored before returning
291          */
292         save = *(dir->path);
293         *(dir->path) = 0;
294
295         if (!SFchdir(SFcurrentPath)) {
296                 last = strlen(entry->real) - 1;
297                 entry->real[last] = 0;
298                 entry->statDone = 1;
299                 if (
300                         (!stat(entry->real, &statBuf))
301
302 #ifdef S_IFLNK
303
304                      || (!lstat(entry->real, &statBuf))
305
306 #endif /* ndef S_IFLNK */
307
308                 ) {
309                         if (SFfunc) {
310                                 char *shown;
311
312                                 shown = NULL;
313                                 if (SFfunc(entry->real, &shown, &statBuf)) {
314                                         if (shown) {
315                                                 int len;
316
317                                                 len = strlen(shown);
318                                                 entry->shown = XtMalloc(
319                                                         (unsigned) (len + 2)
320                                                 );
321                                                 (void) strcpy(entry->shown,
322                                                         shown);
323                                                 SFwriteStatChar(
324                                                         entry->shown,
325                                                         len,
326                                                         &statBuf
327                                                 );
328                                                 entry->shown[len + 1] = 0;
329                                         }
330                                 } else {
331                                         SFdeleteEntry(dir, entry);
332
333                                         *(dir->path) = save;
334                                         return 1;
335                                 }
336                         }
337                         SFwriteStatChar(entry->real, last, &statBuf);
338                 } else {
339                         entry->real[last] = ' ';
340                 }
341         }
342
343         *(dir->path) = save;
344         return 0;
345 }
346
347 static void
348 SFdrawStrings(w, dir, from, to)
349         register Window w;
350         register SFDir  *dir;
351         register int    from;
352         register int    to;
353 {
354         register int            i;
355         register SFEntry        *entry;
356         int                     x;
357
358         x = SFtextX - dir->hOrigin * SFcharWidth;
359
360         if (dir->vOrigin + to >= dir->nEntries) {
361                 to = dir->nEntries - dir->vOrigin - 1;
362         }
363         for (i = from; i <= to; i++) {
364                 entry = &(dir->entries[dir->vOrigin + i]);
365                 if (!(entry->statDone)) {
366                         if (SFstatAndCheck(dir, entry)) {
367                                 if (dir->vOrigin + to >= dir->nEntries) {
368                                         to = dir->nEntries - dir->vOrigin - 1;
369                                 }
370                                 i--;
371                                 continue;
372                         }
373                 }
374 #if ENABLE_NLS
375                 XmbDrawImageString(
376                         SFdisplay,
377                         w,
378                         fontSet,
379                         SFtextGC,
380                         x,
381                         SFtextYoffset + i * SFentryHeight,
382                         entry->shown,
383                         strlen(entry->shown)
384                 );
385 #else
386                 XDrawImageString(
387                         SFdisplay,
388                         w,
389                         SFtextGC,
390                         x,
391                         SFtextYoffset + i * SFentryHeight,
392                         entry->shown,
393                         strlen(entry->shown)
394                 );
395 #endif
396                 if (dir->vOrigin + i == dir->beginSelection) {
397                         XDrawLine(
398                                 SFdisplay,
399                                 w,
400                                 SFlineGC,
401                                 SFlineToTextH + 1,
402                                 SFlowerY + i * SFentryHeight,
403                                 SFlineToTextH + SFentryWidth - 2,
404                                 SFlowerY + i * SFentryHeight
405                         );
406                 }
407                 if (
408                         (dir->vOrigin + i >= dir->beginSelection) &&
409                         (dir->vOrigin + i <= dir->endSelection)
410                 ) {
411                         SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
412                                 SFlowerY + i * SFentryHeight;
413                         SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
414                                 SFlowerY + (i + 1) * SFentryHeight - 1;
415                         XDrawSegments(
416                                 SFdisplay,
417                                 w,
418                                 SFlineGC,
419                                 SFcompletionSegs,
420                                 2
421                         );
422                 }
423                 if (dir->vOrigin + i == dir->endSelection) {
424                         XDrawLine(
425                                 SFdisplay,
426                                 w,
427                                 SFlineGC,
428                                 SFlineToTextH + 1,
429                                 SFlowerY + (i + 1) * SFentryHeight - 1,
430                                 SFlineToTextH + SFentryWidth - 2,
431                                 SFlowerY + (i + 1) * SFentryHeight - 1
432                         );
433                 }
434         }
435         return;
436 }
437
438 void
439 SFdrawList(n, doScroll)
440         int     n;
441         int     doScroll;
442 {
443         SFDir   *dir;
444         Window  w;
445
446         SFclearList(n, doScroll);
447
448         if (SFdirPtr + (3-NR) + n < SFdirEnd) {
449                 dir = &(SFdirs[SFdirPtr + n + (3-NR)]);
450                 w = XtWindow(selFileLists[n]);
451 #if ENABLE_NLS
452                 XmbDrawImageString(
453                         SFdisplay,
454                         w,
455                         fontSet,
456                         SFtextGC,
457                         SFtextX - dir->hOrigin * SFcharWidth,
458                         SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
459                         dir->dir,
460                         strlen(dir->dir)
461                 );
462 #else
463                 XDrawImageString(
464                         SFdisplay,
465                         w,
466                         SFtextGC,
467                         SFtextX - dir->hOrigin * SFcharWidth,
468                         SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
469                         dir->dir,
470                         strlen(dir->dir)
471                 );
472 #endif
473                 SFdrawStrings(w, dir, 0, SFlistSize - 1);
474         }
475         return;
476 }
477
478 void
479 SFdrawLists(doScroll)
480         int     doScroll;
481 {
482         int     i;
483
484         for (i = 0; i < NR; i++) {
485                 SFdrawList(i, doScroll);
486         }
487         return;
488 }
489
490 static void
491 SFinvertEntry(n)
492         register int    n;
493 {
494         XFillRectangle(
495                 SFdisplay,
496                 XtWindow(selFileLists[n]),
497                 SFinvertGC,
498                 SFlineToTextH,
499                 SFcurrentInvert[n] * SFentryHeight + SFlowerY,
500                 SFentryWidth,
501                 SFentryHeight
502         );
503         return;
504 }
505
506 static unsigned long
507 SFscrollTimerInterval()
508 {
509         static int      maxVal = 200;
510         static int      varyDist = 50;
511         static int      minDist = 50;
512         int             t;
513         int             dist;
514
515         if (SFcurrentListY < SFlowerY) {
516                 dist = SFlowerY - SFcurrentListY;
517         } else if (SFcurrentListY > SFupperY) {
518                 dist = SFcurrentListY - SFupperY;
519         } else {
520                 return (unsigned long) 1;
521         }
522
523         t = maxVal - ((maxVal / varyDist) * (dist - minDist));
524
525         if (t < 1) {
526                 t = 1;
527         }
528
529         if (t > maxVal) {
530                 t = maxVal;
531         }
532
533         return (unsigned long) t;
534 }
535
536 static void
537 SFscrollTimer(p, id)
538         XtPointer       p;
539         XtIntervalId    *id;
540 {
541         SFDir   *dir;
542         int     save;
543         int     n;
544
545         n = (int)(intptr_t) p;
546
547         dir = &(SFdirs[SFdirPtr + n]);
548         save = dir->vOrigin;
549
550         if (SFcurrentListY < SFlowerY) {
551                 if (dir->vOrigin > 0) {
552                         SFvSliderMovedCallback(selFileVScrolls[n], n,
553                                 dir->vOrigin - 1);
554                 }
555         } else if (SFcurrentListY > SFupperY) {
556                 if (dir->vOrigin < dir->nEntries - SFlistSize) {
557                         SFvSliderMovedCallback(selFileVScrolls[n], n,
558                                 dir->vOrigin + 1);
559                 }
560         }
561
562         if (dir->vOrigin != save) {
563                 if (dir->nEntries) {
564                     XawScrollbarSetThumb(
565                         selFileVScrolls[n],
566                         (float) (((double) dir->vOrigin) / dir->nEntries),
567                         (float) (((double) ((dir->nEntries < SFlistSize) ?
568                                 dir->nEntries : SFlistSize)) / dir->nEntries)
569                     );
570                 }
571         }
572
573         if (SFbuttonPressed) {
574                 SFscrollTimerId = XtAppAddTimeOut(SFapp,
575                         SFscrollTimerInterval(), SFscrollTimer, (XtPointer)(intptr_t) n);
576         }
577 }
578
579 static int
580 SFnewInvertEntry(n, event)
581         register int            n;
582         register XMotionEvent   *event;
583 {
584         register int    x, y;
585         register int    new;
586         static int      SFscrollTimerAdded = 0;
587
588         x = event->x;
589         y = event->y;
590
591         if (SFdirPtr + n >= SFdirEnd) {
592                 return -1;
593         } else if (
594                 (x >= 0)        && (x <= SFupperX) &&
595                 (y >= SFlowerY) && (y <= SFupperY)
596         ) {
597                 register SFDir *dir = &(SFdirs[SFdirPtr + n]);
598
599                 if (SFscrollTimerAdded) {
600                         SFscrollTimerAdded = 0;
601                         XtRemoveTimeOut(SFscrollTimerId);
602                 }
603
604                 new = (y - SFlowerY) / SFentryHeight;
605                 if (dir->vOrigin + new >= dir->nEntries) {
606                         return -1;
607                 }
608                 return new;
609         } else {
610                 if (SFbuttonPressed) {
611                         SFcurrentListY = y;
612                         if (!SFscrollTimerAdded) {
613                                 SFscrollTimerAdded = 1;
614                                 SFscrollTimerId = XtAppAddTimeOut(SFapp,
615                                         SFscrollTimerInterval(), SFscrollTimer,
616                                         (XtPointer)(intptr_t) n);
617                         }
618                 }
619
620                 return -1;
621         }
622 }
623
624 /* ARGSUSED */
625 void
626 SFenterList(w, n, event)
627         Widget                          w;
628         register int                    n;
629         register XEnterWindowEvent      *event;
630 {
631         register int    new;
632
633         /* sanity */
634         if (SFcurrentInvert[n] != -1) {
635                 SFinvertEntry(n);
636                 SFcurrentInvert[n] = -1;
637         }
638
639         new = SFnewInvertEntry(n, (XMotionEvent *) event);
640         if (new != -1) {
641                 SFcurrentInvert[n] = new;
642                 SFinvertEntry(n);
643         }
644 }
645
646 /* ARGSUSED */
647 void
648 SFleaveList(w, n, event)
649         Widget          w;
650         register int    n;
651         XEvent          *event;
652 {
653         if (SFcurrentInvert[n] != -1) {
654                 SFinvertEntry(n);
655                 SFcurrentInvert[n] = -1;
656         }
657 }
658
659 /* ARGSUSED */
660 void
661 SFmotionList(w, n, event)
662         Widget                  w;
663         register int            n;
664         register XMotionEvent   *event;
665 {
666         register int    new;
667
668         new = SFnewInvertEntry(n, event);
669
670         if (new != SFcurrentInvert[n]) {
671                 if (SFcurrentInvert[n] != -1) {
672                         SFinvertEntry(n);
673                 }
674                 SFcurrentInvert[n] = new;
675                 if (new != -1) {
676                         SFinvertEntry(n);
677                 }
678         }
679         return;
680 }
681
682 /* ARGSUSED */
683 void
684 SFvSliderMovedCallback(w, n, new)
685         Widget  w;
686         int     n;
687         int     new;
688 {
689         int             old;
690         register Window win;
691         SFDir           *dir;
692
693         dir = &(SFdirs[SFdirPtr + n]);
694
695
696         old = dir->vOrigin;
697         if(new == -1) new = old + 1; else if(new == -2) new = old - 1; // [HGM] indicates scroll direction on mousewheel event
698         if(new < 0 || new > dir->nEntries - SFlistSize) return;
699         dir->vOrigin = new;
700
701         if (old == new) {
702                 return;
703         }
704
705         win = XtWindow(selFileLists[n]);
706
707         if (ABS(new - old) < SFlistSize) {
708                 if (new > old) {
709                         XCopyArea(
710                                 SFdisplay,
711                                 win,
712                                 win,
713                                 SFscrollGC,
714                                 SFlineToTextH,
715                                 SFlowerY + (new - old) * SFentryHeight,
716                                 SFentryWidth + SFlineToTextH,
717                                 (SFlistSize - (new - old)) * SFentryHeight,
718                                 SFlineToTextH,
719                                 SFlowerY
720                         );
721                         XClearArea(
722                                 SFdisplay,
723                                 win,
724                                 SFlineToTextH,
725                                 SFlowerY + (SFlistSize - (new - old)) *
726                                         SFentryHeight,
727                                 SFentryWidth + SFlineToTextH,
728                                 (new - old) * SFentryHeight,
729                                 False
730                         );
731                         SFdrawStrings(win, dir, SFlistSize - (new - old),
732                                 SFlistSize - 1);
733                 } else {
734                         XCopyArea(
735                                 SFdisplay,
736                                 win,
737                                 win,
738                                 SFscrollGC,
739                                 SFlineToTextH,
740                                 SFlowerY,
741                                 SFentryWidth + SFlineToTextH,
742                                 (SFlistSize - (old - new)) * SFentryHeight,
743                                 SFlineToTextH,
744                                 SFlowerY + (old - new) * SFentryHeight
745                         );
746                         XClearArea(
747                                 SFdisplay,
748                                 win,
749                                 SFlineToTextH,
750                                 SFlowerY,
751                                 SFentryWidth + SFlineToTextH,
752                                 (old - new) * SFentryHeight,
753                                 False
754                         );
755                         SFdrawStrings(win, dir, 0, old - new);
756                 }
757         } else {
758                 XClearArea(
759                         SFdisplay,
760                         win,
761                         SFlineToTextH,
762                         SFlowerY,
763                         SFentryWidth + SFlineToTextH,
764                         SFlistSize * SFentryHeight,
765                         False
766                 );
767                 SFdrawStrings(win, dir, 0, SFlistSize - 1);
768         }
769 }
770
771 /* ARGSUSED */
772 void
773 SFvFloatSliderMovedCallback(w, n, fnew)
774         Widget  w;
775         int     n;
776         float   *fnew;
777 {
778         int     new;
779
780         new = (*fnew) * SFdirs[SFdirPtr + n].nEntries;
781
782         SFvSliderMovedCallback(w, n, new);
783 }
784
785
786 /* ARGSUSED */
787 void
788 SFvAreaSelectedCallback(w, n, pnew)
789         Widget  w;
790         int     n;
791         int     pnew;
792 {
793         SFDir   *dir;
794         int     new;
795
796         dir = &(SFdirs[SFdirPtr + n]);
797
798         new = dir->vOrigin +
799                 (((double) pnew) / SFvScrollHeight) * dir->nEntries;
800
801         if (new > dir->nEntries - SFlistSize) {
802                 new = dir->nEntries - SFlistSize;
803         }
804
805         if (new < 0) {
806                 new = 0;
807         }
808
809         if (dir->nEntries) {
810                 float   f;
811
812                 f = ((double) new) / dir->nEntries;
813
814                 XawScrollbarSetThumb(
815                         w,
816                         f,
817                         (float) (((double) ((dir->nEntries < SFlistSize) ?
818                                 dir->nEntries : SFlistSize)) / dir->nEntries)
819                 );
820         }
821
822         SFvSliderMovedCallback(w, n, new);
823 }
824
825 /* ARGSUSED */
826 void
827 SFhSliderMovedCallback(w, n, new)
828         Widget  w;
829         int     n;
830         float   *new;
831 {
832         SFDir   *dir;
833         int     save;
834
835         dir = &(SFdirs[SFdirPtr + n]);
836         save = dir->hOrigin;
837         dir->hOrigin = (*new) * dir->nChars;
838         if (dir->hOrigin == save) {
839                 return;
840         }
841
842         SFdrawList(n, SF_DO_NOT_SCROLL);
843 }
844
845 /* ARGSUSED */
846 void
847 SFhAreaSelectedCallback(w, n, pnew)
848         Widget  w;
849         int     n;
850         int     pnew;
851 {
852         SFDir   *dir;
853         int     new;
854
855         dir = &(SFdirs[SFdirPtr + n]);
856
857         new = dir->hOrigin +
858                 (((double) pnew) / SFhScrollWidth) * dir->nChars;
859
860         if (new > dir->nChars - SFcharsPerEntry) {
861                 new = dir->nChars - SFcharsPerEntry;
862         }
863
864         if (new < 0) {
865                 new = 0;
866         }
867
868         if (dir->nChars) {
869                 float   f;
870
871                 f = ((double) new) / dir->nChars;
872
873                 XawScrollbarSetThumb(
874                         w,
875                         f,
876                         (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
877                                 dir->nChars : SFcharsPerEntry)) / dir->nChars)
878                 );
879
880                 SFhSliderMovedCallback(w, n, &f);
881         }
882 }
883
884 /* ARGSUSED */
885 void
886 SFpathSliderMovedCallback(w, client_data, new)
887         Widget          w;
888         XtPointer       client_data;
889         float   *new;
890 {
891         SFDir           *dir;
892         int             n;
893         XawTextPosition pos;
894         int     SFdirPtrSave;
895
896         SFdirPtrSave = SFdirPtr;
897         SFdirPtr = (*new) * SFdirEnd;
898         if (SFdirPtr == SFdirPtrSave) {
899                 return;
900         }
901
902         SFdrawLists(SF_DO_SCROLL);
903
904         n = 2;
905         while (SFdirPtr + n >= SFdirEnd) {
906                 n--;
907         }
908
909         dir = &(SFdirs[SFdirPtr + n]);
910
911         pos = dir->path - SFcurrentPath;
912
913         if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
914                 pos -= strlen(SFstartDir);
915                 if (pos < 0) {
916                         pos = 0;
917                 }
918         }
919
920         XawTextSetInsertionPoint(selFileField, pos);
921 }
922
923 /* ARGSUSED */
924
925 void
926 SFpathAreaSelectedCallback(w, client_data, pnew)
927         Widget          w;
928         XtPointer       client_data;
929         int             pnew;
930 {
931         int     new;
932         float   f;
933
934         new = SFdirPtr + (((double) pnew) / SFpathScrollWidth) * SFdirEnd;
935
936         if (new > SFdirEnd - 3) {
937                 new = SFdirEnd - 3;
938         }
939
940         if (new < 0) {
941                 new = 0;
942         }
943
944         f = ((double) new) / SFdirEnd;
945
946         XawScrollbarSetThumb(
947                 w,
948                 f,
949                 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
950                         SFdirEnd)
951         );
952
953         SFpathSliderMovedCallback(w, (XtPointer) NULL, &f);
954 }
955
956 Boolean
957 SFworkProc()
958 {
959         register SFDir          *dir;
960         register SFEntry        *entry;
961
962         for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) {
963                 if (!(dir->nEntries)) {
964                         continue;
965                 }
966                 for (
967                         entry = &(dir->entries[dir->nEntries - 1]);
968                         entry >= dir->entries;
969                         entry--
970                 ) {
971                         if (!(entry->statDone)) {
972                                 (void) SFstatAndCheck(dir, entry);
973                                 return False;
974                         }
975                 }
976         }
977
978         SFworkProcAdded = 0;
979
980         return True;
981 }