Fix some resource leaks
[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) 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) 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) 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         old = dir->vOrigin;
659         dir->vOrigin = new;
660
661         if (old == new) {
662                 return;
663         }
664
665         win = XtWindow(selFileLists[n]);
666
667         if (ABS(new - old) < SFlistSize) {
668                 if (new > old) {
669                         XCopyArea(
670                                 SFdisplay,
671                                 win,
672                                 win,
673                                 SFscrollGC,
674                                 SFlineToTextH,
675                                 SFlowerY + (new - old) * SFentryHeight,
676                                 SFentryWidth + SFlineToTextH,
677                                 (SFlistSize - (new - old)) * SFentryHeight,
678                                 SFlineToTextH,
679                                 SFlowerY
680                         );
681                         XClearArea(
682                                 SFdisplay,
683                                 win,
684                                 SFlineToTextH,
685                                 SFlowerY + (SFlistSize - (new - old)) *
686                                         SFentryHeight,
687                                 SFentryWidth + SFlineToTextH,
688                                 (new - old) * SFentryHeight,
689                                 False
690                         );
691                         SFdrawStrings(win, dir, SFlistSize - (new - old),
692                                 SFlistSize - 1);
693                 } else {
694                         XCopyArea(
695                                 SFdisplay,
696                                 win,
697                                 win,
698                                 SFscrollGC,
699                                 SFlineToTextH,
700                                 SFlowerY,
701                                 SFentryWidth + SFlineToTextH,
702                                 (SFlistSize - (old - new)) * SFentryHeight,
703                                 SFlineToTextH,
704                                 SFlowerY + (old - new) * SFentryHeight
705                         );
706                         XClearArea(
707                                 SFdisplay,
708                                 win,
709                                 SFlineToTextH,
710                                 SFlowerY,
711                                 SFentryWidth + SFlineToTextH,
712                                 (old - new) * SFentryHeight,
713                                 False
714                         );
715                         SFdrawStrings(win, dir, 0, old - new);
716                 }
717         } else {
718                 XClearArea(
719                         SFdisplay,
720                         win,
721                         SFlineToTextH,
722                         SFlowerY,
723                         SFentryWidth + SFlineToTextH,
724                         SFlistSize * SFentryHeight,
725                         False
726                 );
727                 SFdrawStrings(win, dir, 0, SFlistSize - 1);
728         }
729 }
730
731 /* ARGSUSED */
732 void
733 SFvFloatSliderMovedCallback(w, n, fnew)
734         Widget  w;
735         int     n;
736         float   *fnew;
737 {
738         int     new;
739
740         new = (*fnew) * SFdirs[SFdirPtr + n].nEntries;
741
742         SFvSliderMovedCallback(w, n, new);
743 }
744
745
746 /* ARGSUSED */
747 void
748 SFvAreaSelectedCallback(w, n, pnew)
749         Widget  w;
750         int     n;
751         int     pnew;
752 {
753         SFDir   *dir;
754         int     new;
755
756         dir = &(SFdirs[SFdirPtr + n]);
757
758         new = dir->vOrigin +
759                 (((double) pnew) / SFvScrollHeight) * dir->nEntries;
760
761         if (new > dir->nEntries - SFlistSize) {
762                 new = dir->nEntries - SFlistSize;
763         }
764
765         if (new < 0) {
766                 new = 0;
767         }
768
769         if (dir->nEntries) {
770                 float   f;
771
772                 f = ((double) new) / dir->nEntries;
773
774                 XawScrollbarSetThumb(
775                         w,
776                         f,
777                         (float) (((double) ((dir->nEntries < SFlistSize) ?
778                                 dir->nEntries : SFlistSize)) / dir->nEntries)
779                 );
780         }
781
782         SFvSliderMovedCallback(w, n, new);
783 }
784
785 /* ARGSUSED */
786 void
787 SFhSliderMovedCallback(w, n, new)
788         Widget  w;
789         int     n;
790         float   *new;
791 {
792         SFDir   *dir;
793         int     save;
794
795         dir = &(SFdirs[SFdirPtr + n]);
796         save = dir->hOrigin;
797         dir->hOrigin = (*new) * dir->nChars;
798         if (dir->hOrigin == save) {
799                 return;
800         }
801
802         SFdrawList(n, SF_DO_NOT_SCROLL);
803 }
804
805 /* ARGSUSED */
806 void
807 SFhAreaSelectedCallback(w, n, pnew)
808         Widget  w;
809         int     n;
810         int     pnew;
811 {
812         SFDir   *dir;
813         int     new;
814
815         dir = &(SFdirs[SFdirPtr + n]);
816
817         new = dir->hOrigin +
818                 (((double) pnew) / SFhScrollWidth) * dir->nChars;
819
820         if (new > dir->nChars - SFcharsPerEntry) {
821                 new = dir->nChars - SFcharsPerEntry;
822         }
823
824         if (new < 0) {
825                 new = 0;
826         }
827
828         if (dir->nChars) {
829                 float   f;
830
831                 f = ((double) new) / dir->nChars;
832
833                 XawScrollbarSetThumb(
834                         w,
835                         f,
836                         (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
837                                 dir->nChars : SFcharsPerEntry)) / dir->nChars)
838                 );
839
840                 SFhSliderMovedCallback(w, n, &f);
841         }
842 }
843
844 /* ARGSUSED */
845 void
846 SFpathSliderMovedCallback(w, client_data, new)
847         Widget          w;
848         XtPointer       client_data;
849         float   *new;
850 {
851         SFDir           *dir;
852         int             n;
853         XawTextPosition pos;
854         int     SFdirPtrSave;
855
856         SFdirPtrSave = SFdirPtr;
857         SFdirPtr = (*new) * SFdirEnd;
858         if (SFdirPtr == SFdirPtrSave) {
859                 return;
860         }
861
862         SFdrawLists(SF_DO_SCROLL);
863
864         n = 2;
865         while (SFdirPtr + n >= SFdirEnd) {
866                 n--;
867         }
868
869         dir = &(SFdirs[SFdirPtr + n]);
870
871         pos = dir->path - SFcurrentPath;
872
873         if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
874                 pos -= strlen(SFstartDir);
875                 if (pos < 0) {
876                         pos = 0;
877                 }
878         }
879
880         XawTextSetInsertionPoint(selFileField, pos);
881 }
882
883 /* ARGSUSED */
884
885 void
886 SFpathAreaSelectedCallback(w, client_data, pnew)
887         Widget          w;
888         XtPointer       client_data;
889         int             pnew;
890 {
891         int     new;
892         float   f;
893
894         new = SFdirPtr + (((double) pnew) / SFpathScrollWidth) * SFdirEnd;
895
896         if (new > SFdirEnd - 3) {
897                 new = SFdirEnd - 3;
898         }
899
900         if (new < 0) {
901                 new = 0;
902         }
903
904         f = ((double) new) / SFdirEnd;
905
906         XawScrollbarSetThumb(
907                 w,
908                 f,
909                 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
910                         SFdirEnd)
911         );
912
913         SFpathSliderMovedCallback(w, (XtPointer) NULL, &f);
914 }
915
916 Boolean
917 SFworkProc()
918 {
919         register SFDir          *dir;
920         register SFEntry        *entry;
921
922         for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) {
923                 if (!(dir->nEntries)) {
924                         continue;
925                 }
926                 for (
927                         entry = &(dir->entries[dir->nEntries - 1]);
928                         entry >= dir->entries;
929                         entry--
930                 ) {
931                         if (!(entry->statDone)) {
932                                 (void) SFstatAndCheck(dir, entry);
933                                 return False;
934                         }
935                 }
936         }
937
938         SFworkProcAdded = 0;
939
940         return True;
941 }