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