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