Corrected a long-standing error in which ending text with a literal
[xcircuit.git] / filelist.c
blob5f7a1324d6d1286811f428fa464fb2e0dbc66d2f
1 /*-------------------------------------------------------------------------*/
2 /* filelist.c --- Xcircuit routines for the filelist widget */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*-------------------------------------------------------------------------*/
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <signal.h>
10 #include <sys/types.h>
11 #include <ctype.h> /* For isspace() */
13 #ifdef HAVE_DIRENT_H
14 #include <dirent.h>
15 #include <unistd.h>
16 #define direct dirent
17 #elif !defined(_MSC_VER)
18 #include <sys/dir.h>
19 #endif
21 #include <sys/stat.h>
22 #include <errno.h>
23 #include <limits.h>
25 #ifndef XC_WIN32
26 #include <X11/Intrinsic.h>
27 #include <X11/StringDefs.h>
28 #include <X11/Shell.h>
29 #include <X11/Xutil.h>
30 #include <X11/cursorfont.h>
31 #endif
32 #ifdef TCL_WRAPPER
33 #include <tk.h>
34 #else
35 #ifndef XC_WIN32
36 #include "Xw/Xw.h"
37 #include "Xw/WorkSpace.h"
38 #include "Xw/TextEdit.h"
39 #include "Xw/Toggle.h"
40 #endif
41 #endif
43 #if defined(XC_WIN32) && defined(TCL_WRAPPER)
44 #include <X11/Xlib.h>
45 #include <X11/Xutil.h>
46 #include <X11/cursorfont.h>
47 #endif
50 /*-------------------------------------------------------------------------*/
51 /* Local includes */
52 /*-------------------------------------------------------------------------*/
54 #include "colordefs.h"
55 #include "xcircuit.h"
57 /*----------------------------------------------------------------------*/
58 /* Function prototype declarations */
59 /*----------------------------------------------------------------------*/
60 #include "prototypes.h"
62 /*-------------------------------------------------------------------------*/
63 /* Local definitions */
64 /*-------------------------------------------------------------------------*/
66 #define INITDIRS 10
68 /*-------------------------------------------------------------------------*/
69 /* Global Variable definitions */
70 /*-------------------------------------------------------------------------*/
72 #ifdef TCL_WRAPPER
73 extern Tcl_Interp *xcinterp;
74 #endif
76 extern Display *dpy;
77 extern XCWindowData *areawin;
78 extern ApplicationData appdata;
79 extern colorindex *colorlist;
80 extern short popups; /* total number of popup windows */
81 extern char _STR2[250];
82 extern char _STR[150];
83 extern Globaldata xobjs;
85 Pixmap flistpix = (Pixmap)NULL; /* For file-selection widget */
86 short flstart, flfiles, flcurrent;
87 int flcurwidth;
89 GC hgc = NULL, sgc = NULL;
90 char *cwdname = NULL;
91 fileliststruct *files;
93 #if !defined(XC_WIN32) || defined(TCL_WRAPPER)
95 /*-------------------------------------------------------------------------*/
96 /* Compare two filenames (for use by qsort()) */
97 /*-------------------------------------------------------------------------*/
99 int fcompare(const void *a, const void *b)
101 return (strcmp((char *)(((fileliststruct *)a)->filename),
102 (char *)(((fileliststruct *)b)->filename)));
105 /*-------------------------------------------------------------------------*/
106 /* Routines for drawing a box around the currently selected file */
107 /*-------------------------------------------------------------------------*/
109 void dragfilebox(xcWidget w, caddr_t clientdata, XMotionEvent *event)
111 short filenum;
112 int twidth;
113 Window lwin = xcWindow(w);
115 filenum = (event->y - 10 + FILECHARHEIGHT) / FILECHARHEIGHT + flstart - 1;
116 if (filenum < 0) filenum = 0;
117 else if (filenum >= flfiles) filenum = flfiles - 1;
119 if (filenum == flcurrent) return;
121 if (flcurrent >= 0) /* erase previous box */
122 XDrawRectangle(dpy, lwin, areawin->gc, 5,
123 10 + FILECHARHEIGHT * (flcurrent
124 - flstart), flcurwidth + 10, FILECHARHEIGHT);
126 if (files == NULL) return;
128 twidth = XTextWidth(appdata.filefont, files[filenum].filename,
129 strlen(files[filenum].filename));
130 XDrawRectangle(dpy, lwin, areawin->gc, 5,
131 10 + FILECHARHEIGHT * (filenum
132 - flstart), twidth + 10, FILECHARHEIGHT);
134 flcurrent = filenum;
135 flcurwidth = twidth;
138 /*-------------------------------------------------------------------------*/
139 /* Begin tracking the cursor position relative to the files in the list */
140 /*-------------------------------------------------------------------------*/
142 void startfiletrack(xcWidget w, caddr_t clientdata, XCrossingEvent *event)
144 #ifdef TCL_WRAPPER
145 Tk_CreateEventHandler(w, PointerMotionMask,
146 (Tk_EventProc *)xctk_dragfilebox, (ClientData)w);
147 #else
148 xcAddEventHandler(w, PointerMotionMask, False, (xcEventHandler)dragfilebox, NULL);
149 #endif
151 XSetFunction(dpy, areawin->gc, GXcopy);
152 XSetForeground(dpy, areawin->gc, colorlist[AUXCOLOR].color.pixel);
153 XSetLineAttributes(dpy, areawin->gc, 1, LineSolid, CapRound, JoinMiter);
155 /* draw initial box */
157 flcurrent = -1;
158 dragfilebox(w, NULL, (XMotionEvent *)event);
160 XSetFunction(dpy, areawin->gc, GXxor);
161 XSetForeground(dpy, areawin->gc, colorlist[AUXCOLOR].color.pixel ^
162 colorlist[BACKGROUND].color.pixel);
165 /*-------------------------------------------------------------------------*/
166 /* Stop tracking the cursor and return to default state */
167 /*-------------------------------------------------------------------------*/
169 void endfiletrack(xcWidget w, caddr_t clientdata, XCrossingEvent *event)
171 Window lwin = xcWindow(w);
173 XDrawRectangle(dpy, lwin, areawin->gc, 5,
174 10 + FILECHARHEIGHT * (flcurrent
175 - flstart), flcurwidth + 10, FILECHARHEIGHT);
177 #ifdef TCL_WRAPPER
178 Tk_DeleteEventHandler(w, PointerMotionMask,
179 (Tk_EventProc *)xctk_dragfilebox, (ClientData)w);
180 #else
181 xcRemoveEventHandler(w, PointerMotionMask, False,
182 (xcEventHandler)dragfilebox, NULL);
183 #endif
185 /* Restore graphics state values */
186 XSetForeground(dpy, areawin->gc, colorlist[areawin->gccolor].color.pixel);
187 XSetFunction(dpy, areawin->gc, GXcopy);
190 #endif
192 /*----------------------------------------------------------------------*/
193 /* Read a crash file to find the name of the original file. */
194 /*----------------------------------------------------------------------*/
196 char *getcrashfilename()
198 FILE *fi;
199 char temp[256];
200 char *retstr = NULL, *tpos, *spos;
201 int slen;
203 if ((fi = fopen(_STR2, "r")) != NULL) {
204 while (fgets(temp, 255, fi) != NULL) {
205 if ((tpos = strstr(temp, "Title:")) != NULL) {
206 ridnewline(temp);
207 tpos += 7;
208 if ((spos = strrchr(temp, '/')) != NULL)
209 tpos = spos + 1;
210 retstr = (char *)malloc(1 + strlen(tpos));
211 strcpy(retstr, tpos);
213 else if ((tpos = strstr(temp, "CreationDate:")) != NULL) {
214 ridnewline(temp);
215 tpos += 14;
216 slen = strlen(retstr);
217 retstr = (char *)realloc(retstr, 4 + slen + strlen(tpos));
218 sprintf(retstr + slen, " (%s)", tpos);
219 break;
222 fclose(fi);
224 return retstr;
227 /*----------------------------------------------------------------------*/
228 /* Crash recovery: load the file, and link the tempfile name to it. */
229 /*----------------------------------------------------------------------*/
231 void crashrecover()
233 if (xobjs.tempfile != NULL) {
234 unlink(xobjs.tempfile);
235 free(xobjs.tempfile);
236 xobjs.tempfile = NULL;
238 if (strlen(_STR2) == 0) {
239 Wprintf("Error: No temp file name for crash recovery!");
241 else {
242 xobjs.tempfile = strdup(_STR2);
243 startloadfile(-1);
247 /*----------------------------------------------------------------------*/
248 /* Look for any files left over from a crash. */
249 /*----------------------------------------------------------------------*/
251 void findcrashfiles()
253 DIR *cwd;
254 struct direct *dp;
255 struct stat sbuf;
256 #ifndef _MSC_VER
257 uid_t userid = getuid();
258 #endif
259 time_t recent = 0;
260 char *snptr;
261 int pid;
263 cwd = opendir(xobjs.tempdir);
264 if (cwd == NULL) return; /* No tmp directory, no tmp files! */
266 while ((dp = readdir(cwd)) != NULL) {
267 sprintf(_STR, "%s/%s", xobjs.tempdir, dp->d_name);
268 snptr = _STR + strlen(xobjs.tempdir) + 1;
269 if (!strncmp(snptr, "XC", 2)) {
270 char *dotptr = strchr(snptr, '.');
271 pid = -1;
272 if (dotptr && dotptr > snptr + 2) {
273 *dotptr = '\0';
274 if (sscanf(snptr + 2, "%d", &pid) != 1)
275 pid = -1;
276 *dotptr = '.';
278 if ((!stat(_STR, &sbuf))
279 #ifndef _MSC_VER
280 && (sbuf.st_uid == userid)
281 #endif
283 if ((recent == 0) || (sbuf.st_ctime > recent)) {
285 /* Check if the PID belongs to an active process */
286 /* by sending a CONT signal and checking if */
287 /* there was no error result. */
289 #ifndef _MSC_VER
290 if (pid != -1)
291 if (kill((pid_t)pid, SIGCONT) == 0)
292 continue;
293 #endif
295 recent = sbuf.st_ctime;
296 strcpy(_STR2, _STR);
301 closedir(cwd);
303 if (recent > 0) { /* There exists at least one temporary file */
304 /* belonging to this user. Ask to recover */
305 /* the most recent one. */
307 /* Warn user of existing tempfile, and ask user if file */
308 /* should be recovered immediately. */
310 #ifdef TCL_WRAPPER
311 char *cfile = getcrashfilename();
313 sprintf(_STR, ".query.title.field configure -text "
314 "\"Recover file \'%s\'?\"",
315 (cfile == NULL) ? "(unknown)" : cfile);
316 Tcl_Eval(xcinterp, _STR);
317 Tcl_Eval(xcinterp, ".query.bbar.okay configure -command "
318 "{filerecover; wm withdraw .query}; wm deiconify .query");
319 if (cfile != NULL) free(cfile);
320 #else
321 getfile(NULL, (pointertype)RECOVER, NULL); /* Crash recovery mode */
322 #endif
326 /*----------------------------------------------------------------------*/
327 /* Match a filename extension against the file filter list. */
328 /*----------------------------------------------------------------------*/
330 #if !defined(XC_WIN32) || defined(TCL_WRAPPER)
332 Boolean match_filter(char *fname, char *filter)
334 char *dotptr = strrchr(fname, '.');
335 char *filtptr, *endptr;
336 int filtlen, extlen;
338 if (filter == NULL) return False;
339 if (dotptr == NULL) return False;
341 /* New 11/08: Empty string for filter is a wildcard match, the same */
342 /* as turning off the filter. */
344 if (filter[0] == '\0') return True;
346 dotptr++;
347 extlen = strlen(dotptr);
348 filtptr = filter;
350 while (*filtptr != '\0') {
351 endptr = filtptr;
352 while (*endptr != '\0' && !isspace(*endptr)) endptr++;
353 filtlen = (int)(endptr - filtptr);
354 if (filtlen == extlen)
355 if (!strncmp(dotptr, filtptr, extlen))
356 return True;
358 filtptr = endptr;
359 while (*filtptr != '\0' && isspace(*filtptr)) filtptr++;
361 return False;
364 /*----------------------------------------------------------------------*/
365 /* Make a list of the files in the list widget window */
366 /*----------------------------------------------------------------------*/
368 void listfiles(xcWidget w, popupstruct *okaystruct, caddr_t calldata)
370 XGCValues values;
371 #ifndef TCL_WRAPPER
372 Arg wargs[2];
373 #endif
374 DIR *cwd;
375 char *filter;
376 Window lwin = xcWindow(w);
377 short allocd = INITDIRS;
378 short n = 0;
379 struct direct *dp;
380 struct stat statbuf;
381 int pixheight;
382 Dimension textwidth, textheight;
384 filter = okaystruct->filter;
386 if (sgc == NULL) {
387 values.foreground = colorlist[FOREGROUND].color.pixel;
388 values.font = appdata.filefont->fid;
389 values.function = GXcopy;
390 values.graphics_exposures = False;
391 sgc = XCreateGC(dpy, lwin, GCForeground | GCFont | GCFunction
392 | GCGraphicsExposures, &values);
395 #ifdef TCL_WRAPPER
396 textwidth = Tk_Width(w);
397 textheight = Tk_Height(w);
398 #else
399 XtnSetArg(XtNwidth, &textwidth);
400 XtnSetArg(XtNheight, &textheight);
401 XtGetValues(w, wargs, n);
402 #endif
404 /* Generate a new flistpix pixmap if currently nonexistent */
406 if (!flistpix) {
408 /* get list of files in the current directory (cwd) */
410 flfiles = 0;
411 if (cwdname == NULL) {
412 cwdname = (char *) malloc (sizeof(char));
413 cwdname[0] = '\0';
415 if (cwdname[0] == '\0')
416 cwd = opendir(".");
417 else
418 cwd = opendir(cwdname);
420 /* If current directory cannot be accessed for some reason, */
421 /* print "Invalid Directory" to the file list window. */
423 if (cwd == NULL) {
424 XSetForeground(dpy, sgc, colorlist[BACKGROUND].color.pixel);
425 XFillRectangle(dpy, lwin, sgc, 0, 0, textwidth, textheight);
426 XSetForeground(dpy, sgc, colorlist[AUXCOLOR].color.pixel);
427 XDrawString(dpy, lwin, sgc, 10, textheight / 2,
428 "(Invalid Directory)", 19);
429 return;
431 else {
432 if (files == NULL)
433 files = (fileliststruct *) malloc (INITDIRS * sizeof(fileliststruct));
435 /* write the contents of the current directory into the */
436 /* array "filenames[]" (except for current directory ".") */
438 while ((dp = readdir(cwd)) != NULL) {
439 /* don't put current directory in list */
440 if (!strcmp(dp->d_name, ".")) continue;
442 /* record the type of file */
444 sprintf(_STR2, "%s%s", cwdname, dp->d_name);
445 if (stat(_STR2, &statbuf)) continue;
446 if ((statbuf.st_mode & S_IFDIR) != 0) /* is a directory */
447 files[flfiles].filetype = DIRECTORY;
448 else if (match_filter(dp->d_name, filter))
449 files[flfiles].filetype = MATCH;
450 else {
451 if (xobjs.filefilter)
452 continue;
453 else
454 files[flfiles].filetype = NONMATCH;
457 /* save the filename */
459 files[flfiles].filename = (char *) malloc ((strlen(dp->d_name) +
460 ((files[flfiles].filetype == DIRECTORY) ? 2 : 1)) * sizeof(char));
461 strcpy(files[flfiles].filename, dp->d_name);
462 if (files[flfiles].filetype == DIRECTORY)
463 strcat(files[flfiles].filename, "/");
464 if (++flfiles == allocd) {
465 allocd += INITDIRS;
466 files = (fileliststruct *) realloc(files,
467 allocd * sizeof(fileliststruct));
471 closedir(cwd);
473 /* sort the files[] array into alphabetical order (like "ls") */
475 qsort((void *)files, (size_t)flfiles, sizeof(fileliststruct), fcompare);
477 pixheight = flfiles * FILECHARHEIGHT + 25;
478 if (pixheight < textheight) pixheight = textheight;
480 flistpix = XCreatePixmap(dpy, areawin->window, textwidth, pixheight,
481 DefaultDepthOfScreen(xcScreen(w)));
483 /* Write the filenames onto the pixmap */
485 XSetForeground(dpy, sgc, colorlist[BACKGROUND].color.pixel);
486 XFillRectangle(dpy, flistpix, sgc, 0, 0, textwidth, pixheight);
487 XSetForeground(dpy, sgc, colorlist[FOREGROUND].color.pixel);
488 for (n = 0; n < flfiles; n++) {
489 switch (files[n].filetype) {
490 case DIRECTORY:
491 XSetForeground(dpy, sgc, colorlist[SELECTCOLOR].color.pixel);
492 break;
493 case MATCH:
494 XSetForeground(dpy, sgc, colorlist[FILTERCOLOR].color.pixel);
495 break;
496 case NONMATCH:
497 XSetForeground(dpy, sgc, colorlist[FOREGROUND].color.pixel);
498 break;
500 XDrawString(dpy, flistpix, sgc, 10, 10 + FILECHARASCENT + n * FILECHARHEIGHT,
501 files[n].filename, strlen(files[n].filename));
505 /* Copy the pixmap of filenames into the file list window */
507 XSetForeground(dpy, sgc, colorlist[BACKGROUND].color.pixel);
508 XFillRectangle(dpy, lwin, sgc, 0, 0, textwidth, textheight);
509 XCopyArea(dpy, flistpix, lwin, sgc, 0, flstart * FILECHARHEIGHT,
510 textwidth, textheight, 0, 0);
513 /*-------------------------------------------------------------------------*/
514 /* Generate a new pixmap for writing the filelist and set the scrollbar */
515 /* size accordingly. */
516 /*-------------------------------------------------------------------------*/
518 void newfilelist(xcWidget w, popupstruct *okaystruct)
520 short n;
522 #ifdef TCL_WRAPPER
523 int bval;
524 int result;
525 char *cstr = (char *)Tcl_GetVar2(xcinterp, "XCOps", "filter", 0);
526 if (cstr == NULL) {
527 Wprintf("Error: No variable $XCOps(filter) in Tcl!");
528 return;
530 result = Tcl_GetBoolean(xcinterp, cstr, &bval);
531 if (result != TCL_OK) {
532 Wprintf("Error: Bad variable $XCOps(filter) in Tcl!");
533 return;
535 xobjs.filefilter = bval;
536 #else
537 xcWidget textw = okaystruct->textw;
538 #endif
540 for (n = 0; n < flfiles; n++)
541 free(files[n].filename);
542 free(files);
543 if (flistpix != (Pixmap)NULL) XFreePixmap(dpy, flistpix);
544 files = NULL;
545 flistpix = (Pixmap)NULL;
546 flstart = 0;
547 listfiles(w, okaystruct, NULL);
548 #ifdef TCL_WRAPPER
549 showlscroll(Tk_NameToWindow(xcinterp, ".filelist.listwin.sb", w), NULL, NULL);
550 Tcl_Eval(xcinterp, ".filelist.textent.txt delete 0 end");
551 sprintf(_STR2, ".filelist.textent.txt insert 0 %s", cwdname);
552 Tcl_Eval(xcinterp, _STR2);
553 #else
554 showlscroll(XtNameToWidget(xcParent(w), "LScroll"), NULL, NULL);
555 XwTextClearBuffer(textw);
556 XwTextInsert(textw, cwdname);
557 XwTextResize(textw);
558 #endif
561 /*-------------------------------------------------------------------------*/
562 /* Button press handler for file list window */
563 /*-------------------------------------------------------------------------*/
565 void fileselect(xcWidget w, popupstruct *okaystruct, XButtonEvent *event)
567 Window lwin = xcWindow(w);
568 Dimension textwidth, textheight;
569 short filenum;
570 char *tbuf, *ebuf;
572 #ifdef TCL_WRAPPER
573 textwidth = Tk_Width(w);
574 textheight = Tk_Height(w);
575 #else
576 Arg wargs[2];
577 short n = 0;
578 xcWidget textw = okaystruct->textw;
580 XtnSetArg(XtNwidth, &textwidth);
581 XtnSetArg(XtNheight, &textheight);
582 XtGetValues(w, wargs, n);
583 #endif
585 flcurrent = -1;
587 if (files == NULL) return; /* shouldn't happen */
589 /* third mouse button cancels selection and reverts buffer to cwd name */
591 if (event->button == Button3) {
592 newfilelist(w, okaystruct);
593 return;
596 filenum = (event->y - 10 + FILECHARHEIGHT) / FILECHARHEIGHT + flstart - 1;
597 if (filenum < 0) filenum = 0;
598 else if (filenum >= flfiles) filenum = flfiles - 1;
600 /* Attempt to enter invalid directory. . . treat like button 3 */
602 if (filenum < 0) {
603 newfilelist(w, okaystruct);
604 return;
607 /* check if this file is a directory or not */
609 if (strchr(files[filenum].filename, '/') == NULL) {
611 /* highlight the entry. . . */
613 XSetForeground(dpy, sgc, colorlist[AUXCOLOR].color.pixel);
614 XDrawString(dpy, flistpix, sgc, 10, 10 + FILECHARASCENT + filenum * FILECHARHEIGHT,
615 files[filenum].filename, strlen(files[filenum].filename));
616 XCopyArea(dpy, flistpix, lwin, sgc, 0, flstart * FILECHARHEIGHT,
617 textwidth, textheight, 0, 0);
619 /* . . .and append it to the text field */
621 #ifdef TCL_WRAPPER
622 Tcl_Eval(xcinterp, ".filelist.textent.txt get");
623 ebuf = (char *)Tcl_GetStringResult(xcinterp);
624 tbuf = (char *)malloc((strlen(ebuf) +
625 strlen(files[filenum].filename) + 6) * sizeof(char));
626 #else
627 ebuf = (char *)XwTextCopyBuffer(textw);
628 tbuf = (char *)malloc((XwTextGetLastPos(textw)
629 + strlen(files[filenum].filename) + 5) * sizeof(char));
630 #endif
631 strcpy(tbuf, ebuf);
633 /* add a comma if there is already text in the destination buffer */
635 if (tbuf[0] != '\0') {
636 if (tbuf[strlen(tbuf) - 1] != '/') strcat(tbuf, ",");
638 else {
639 if (cwdname != NULL) {
640 if (cwdname[0] != '\0') {
641 tbuf = (char *)realloc(tbuf, (strlen(cwdname) +
642 strlen(files[filenum].filename) + 5) * sizeof(char));
643 strcpy(tbuf, cwdname);
647 strcat(tbuf, files[filenum].filename);
648 #ifdef TCL_WRAPPER
649 Tcl_Eval(xcinterp, ".filelist.textent.txt delete 0 end");
650 sprintf(_STR2, ".filelist.textent.txt insert 0 %s", tbuf);
651 Tcl_Eval(xcinterp, _STR2);
652 #else
653 XwTextClearBuffer(textw);
654 XwTextInsert(textw, tbuf);
655 XwTextResize(textw);
656 #endif
657 free(tbuf);
659 else { /* move to new directory */
661 if (!strcmp(files[filenum].filename, "../")) {
662 char *cptr, *sptr = cwdname;
663 if (!strcmp(cwdname, "/")) return; /* no way up from root dir. */
664 while(strstr(sptr, "../") != NULL) sptr += 3;
665 if ((cptr = strrchr(sptr, '/')) != NULL) {
666 *cptr = '\0';
667 if ((cptr = strrchr(sptr, '/')) != NULL) *(cptr + 1) = '\0';
668 else *sptr = '\0';
670 else {
671 cwdname = (char *)realloc(cwdname, (strlen(cwdname) +
672 4) * sizeof(char));
673 strcat(cwdname, "../");
676 else {
677 cwdname = (char *)realloc(cwdname, (strlen(cwdname) +
678 strlen(files[filenum].filename) + 1) * sizeof(char));
679 strcat(cwdname, files[filenum].filename);
681 newfilelist(w, okaystruct);
685 /*-------------------------------------------------------------------------*/
686 /* Scrollbar handler for file list widget */
687 /*-------------------------------------------------------------------------*/
689 void showlscroll(xcWidget w, caddr_t clientdata, caddr_t calldata)
691 Window swin = xcWindow(w);
692 Dimension swidth, sheight;
693 int pstart, pheight, finscr;
695 #ifdef TCL_WRAPPER
696 swidth = Tk_Width(w);
697 sheight = Tk_Height(w);
698 #else
700 Arg wargs[2];
701 short n = 0;
703 XtnSetArg(XtNwidth, &swidth);
704 XtnSetArg(XtNheight, &sheight);
705 XtGetValues(w, wargs, n);
706 #endif
708 XClearWindow(dpy, swin);
710 if (flfiles > 0) { /* no files, no bar */
712 finscr = sheight / FILECHARHEIGHT;
713 if (finscr > flfiles) finscr = flfiles;
715 pstart = (flstart * sheight) / flfiles;
716 pheight = (finscr * sheight) / flfiles;
718 XSetForeground(dpy, sgc, colorlist[BARCOLOR].color.pixel);
719 XFillRectangle(dpy, swin, sgc, 0, pstart, swidth, pheight);
721 flcurrent = -1;
724 /*-------------------------------------------------------------------------*/
725 /* Button Motion handler for moving the scrollbar up and down */
726 /*-------------------------------------------------------------------------*/
728 void draglscroll(xcWidget w, popupstruct *okaystruct, XButtonEvent *event)
730 Dimension sheight;
731 int phheight, finscr, flsave = flstart;
732 xcWidget filew = okaystruct->filew;
734 #ifdef TCL_WRAPPER
735 sheight = Tk_Height(w);
736 #else
737 Arg wargs[1];
738 short n = 0;
740 XtnSetArg(XtNheight, &sheight);
741 XtGetValues(w, wargs, n);
742 #endif
744 finscr = sheight / FILECHARHEIGHT;
745 if (finscr > flfiles) finscr = flfiles;
747 /* center scrollbar on pointer vertical position */
749 phheight = (finscr * sheight) / (flfiles * 2);
750 flstart = (event->y > phheight) ? ((event->y - phheight) * flfiles) / sheight : 0;
751 if (flstart > (flfiles - finscr + 2)) flstart = (flfiles - finscr + 2);
753 if (flstart != flsave) {
754 showlscroll(w, NULL, NULL);
755 listfiles(filew, okaystruct, NULL);
759 /*----------------------------------------------------------------------*/
760 /* Set/unset the file filtering function */
761 /*----------------------------------------------------------------------*/
763 #ifndef TCL_WRAPPER
765 void setfilefilter(xcWidget w, popupstruct *okaystruct, caddr_t calldata)
767 xobjs.filefilter = (xobjs.filefilter) ? False : True;
769 /* Force regeneration of the file list */
771 newfilelist(okaystruct->filew, okaystruct);
774 #endif
776 /*----------------------------------------------------------------------*/
777 /* Generate the file list window */
778 /*----------------------------------------------------------------------*/
780 #ifdef TCL_WRAPPER
782 void genfilelist(xcWidget parent, popupstruct *okaystruct, Dimension width)
784 xcWidget listarea, lscroll, entertext;
786 entertext = okaystruct->textw;
787 listarea = Tk_NameToWindow(xcinterp, ".filelist.listwin.win", parent);
789 xcAddEventHandler(listarea, ButtonPressMask, False,
790 (xcEventHandler)fileselect, okaystruct);
791 xcAddEventHandler(listarea, EnterWindowMask, False,
792 (xcEventHandler)startfiletrack, NULL);
793 xcAddEventHandler(listarea, LeaveWindowMask, False,
794 (xcEventHandler)endfiletrack, NULL);
795 flstart = 0;
796 okaystruct->filew = listarea;
798 lscroll = Tk_NameToWindow(xcinterp, ".filelist.listwin.sb", parent);
800 Tk_CreateEventHandler(lscroll, Button1MotionMask | Button2MotionMask,
801 (Tk_EventProc *)xctk_draglscroll, (ClientData)okaystruct);
803 /* force new file list, in case the highlight filter changed */
805 if (flistpix != (Pixmap)NULL) XFreePixmap(dpy, flistpix);
806 flistpix = (Pixmap)NULL;
809 #else
811 void genfilelist(xcWidget parent, popupstruct *okaystruct, Dimension width)
813 Arg wargs[8];
814 xcWidget listarea, lscroll, entertext, dofilter;
815 short n = 0;
816 int wwidth;
817 int sbarsize;
819 #ifdef TCL_WRAPPER
820 char *scale;
821 scale = Tcl_GetVar2(xcinterp, "XCOps", "scale", TCL_GLOBAL_ONLY);
822 sbarsize = SBARSIZE * atoi(scale);
823 #else
824 sbarsize = SBARSIZE;
825 #endif
827 XtnSetArg(XtNx, 20);
828 XtnSetArg(XtNy, FILECHARHEIGHT - 10);
829 XtnSetArg(XtNwidth, width - sbarsize - 40);
830 XtnSetArg(XtNheight, LISTHEIGHT - FILECHARHEIGHT);
831 XtnSetArg(XtNfont, appdata.filefont);
833 entertext = okaystruct->textw;
835 listarea = XtCreateManagedWidget("Filelist", XwworkSpaceWidgetClass,
836 parent, wargs, n); n = 0;
837 XtAddCallback(listarea, XtNexpose, (XtCallbackProc)listfiles, okaystruct);
839 xcAddEventHandler(listarea, ButtonPressMask, False,
840 (xcEventHandler)fileselect, okaystruct);
841 xcAddEventHandler(listarea, EnterWindowMask, False,
842 (xcEventHandler)startfiletrack, NULL);
843 xcAddEventHandler(listarea, LeaveWindowMask, False,
844 (xcEventHandler)endfiletrack, NULL);
845 flstart = 0;
846 okaystruct->filew = listarea;
848 XtnSetArg(XtNx, width - sbarsize - 20);
849 XtnSetArg(XtNy, FILECHARHEIGHT - 10);
850 XtnSetArg(XtNwidth, sbarsize);
851 XtnSetArg(XtNheight, LISTHEIGHT - FILECHARHEIGHT);
852 XtnSetArg(XtNfont, appdata.xcfont);
854 lscroll = XtCreateManagedWidget("LScroll", XwworkSpaceWidgetClass,
855 parent, wargs, n); n = 0;
857 XtAddCallback(lscroll, XtNexpose, (XtCallbackProc)showlscroll, NULL);
858 xcAddEventHandler(lscroll, Button1MotionMask | Button2MotionMask,
859 False, (xcEventHandler)draglscroll, okaystruct);
861 /* Add a toggle widget to turn file filtering on/off */
863 wwidth = XTextWidth(appdata.xcfont, "filter", strlen("filter"));
864 XtnSetArg(XtNx, width - wwidth - 50);
865 XtnSetArg(XtNy, LISTHEIGHT + 10);
866 XtnSetArg(XtNset, xobjs.filefilter);
867 XtnSetArg(XtNsquare, True);
868 XtnSetArg(XtNborderWidth, 0);
869 XtnSetArg(XtNfont, appdata.xcfont);
870 XtnSetArg(XtNlabelLocation, XwLEFT);
871 dofilter = XtCreateManagedWidget("Filter", XwtoggleWidgetClass,
872 parent, wargs, n); n = 0;
873 XtAddCallback(dofilter, XtNselect, (XtCallbackProc)setfilefilter, okaystruct);
874 XtAddCallback(dofilter, XtNrelease, (XtCallbackProc)setfilefilter, okaystruct);
876 /* force new file list, in case the highlight filter changed */
878 if (flistpix != (Pixmap)NULL) XFreePixmap(dpy, flistpix);
879 flistpix = (Pixmap)NULL;
882 #endif /* TCL_WRAPPER */
884 #endif
886 /*-------------------------------------------------------------------------*/
887 /* Look for a directory name in a string and update cwdname accordingly */
888 /*-------------------------------------------------------------------------*/
890 int lookdirectory(char *lstring, int nchars)
892 int slen;
893 DIR *cwd = NULL;
895 xc_tilde_expand(lstring, nchars);
896 slen = strlen(lstring);
898 if (lstring[slen - 1] == '/' || ((cwd=opendir(lstring)) != NULL)) {
899 if (cwd) closedir(cwd);
900 if (lstring[slen - 1] != '/') strcat(lstring, "/");
901 cwdname = (char *)realloc(cwdname, (slen + 2) * sizeof(char));
902 strcpy(cwdname, lstring);
903 return(1);
905 return(0);
908 /*-------------------------------------------------------------------------*/