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