1 /*-------------------------------------------------------------------------*/
2 /* filelist.c --- Xcircuit routines for the filelist widget */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*-------------------------------------------------------------------------*/
5
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() */
12
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
20
21 #include <sys/stat.h>
22 #include <errno.h>
23 #include <limits.h>
24
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
42
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
48
49
50 /*-------------------------------------------------------------------------*/
51 /* Local includes */
52 /*-------------------------------------------------------------------------*/
53
54 #include "colordefs.h"
55 #include "xcircuit.h"
56
57 /*----------------------------------------------------------------------*/
58 /* Function prototype declarations */
59 /*----------------------------------------------------------------------*/
60 #include "prototypes.h"
61
62 /*-------------------------------------------------------------------------*/
63 /* Local definitions */
64 /*-------------------------------------------------------------------------*/
65
66 #define INITDIRS 10
67
68 /*-------------------------------------------------------------------------*/
69 /* Global Variable definitions */
70 /*-------------------------------------------------------------------------*/
71
72 #ifdef TCL_WRAPPER
73 extern Tcl_Interp *xcinterp;
74 #endif
75
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;
84
85 Pixmap flistpix = (Pixmap)NULL; /* For file-selection widget */
86 short flstart, flfiles, flcurrent;
87 int flcurwidth;
88
89 GC hgc = NULL, sgc = NULL;
90 char *cwdname = NULL;
91 fileliststruct *files;
92
93 #if !defined(XC_WIN32) || defined(TCL_WRAPPER)
94
95 /*-------------------------------------------------------------------------*/
96 /* Compare two filenames (for use by qsort()) */
97 /*-------------------------------------------------------------------------*/
98
fcompare(const void * a,const void * b)99 int fcompare(const void *a, const void *b)
100 {
101 return (strcmp((char *)(((fileliststruct *)a)->filename),
102 (char *)(((fileliststruct *)b)->filename)));
103 }
104
105 /*-------------------------------------------------------------------------*/
106 /* Routines for drawing a box around the currently selected file */
107 /*-------------------------------------------------------------------------*/
108
dragfilebox(xcWidget w,caddr_t clientdata,XMotionEvent * event)109 void dragfilebox(xcWidget w, caddr_t clientdata, XMotionEvent *event)
110 {
111 short filenum;
112 int twidth;
113 Window lwin = xcWindow(w);
114
115 filenum = (event->y - 10 + FILECHARHEIGHT) / FILECHARHEIGHT + flstart - 1;
116 if (filenum < 0) filenum = 0;
117 else if (filenum >= flfiles) filenum = flfiles - 1;
118
119 if (filenum == flcurrent) return;
120
121 if (flcurrent >= 0) /* erase previous box */
122 XDrawRectangle(dpy, lwin, areawin->gc, 5,
123 10 + FILECHARHEIGHT * (flcurrent
124 - flstart), flcurwidth + 10, FILECHARHEIGHT);
125
126 if (files == NULL) return;
127
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);
133
134 flcurrent = filenum;
135 flcurwidth = twidth;
136 }
137
138 /*-------------------------------------------------------------------------*/
139 /* Begin tracking the cursor position relative to the files in the list */
140 /*-------------------------------------------------------------------------*/
141
startfiletrack(xcWidget w,caddr_t clientdata,XCrossingEvent * event)142 void startfiletrack(xcWidget w, caddr_t clientdata, XCrossingEvent *event)
143 {
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
150
151 XSetFunction(dpy, areawin->gc, GXcopy);
152 XSetForeground(dpy, areawin->gc, colorlist[AUXCOLOR].color.pixel);
153 XSetLineAttributes(dpy, areawin->gc, 1, LineSolid, CapRound, JoinMiter);
154
155 /* draw initial box */
156
157 flcurrent = -1;
158 dragfilebox(w, NULL, (XMotionEvent *)event);
159
160 XSetFunction(dpy, areawin->gc, GXxor);
161 XSetForeground(dpy, areawin->gc, colorlist[AUXCOLOR].color.pixel ^
162 colorlist[BACKGROUND].color.pixel);
163 }
164
165 /*-------------------------------------------------------------------------*/
166 /* Stop tracking the cursor and return to default state */
167 /*-------------------------------------------------------------------------*/
168
endfiletrack(xcWidget w,caddr_t clientdata,XCrossingEvent * event)169 void endfiletrack(xcWidget w, caddr_t clientdata, XCrossingEvent *event)
170 {
171 Window lwin = xcWindow(w);
172
173 XDrawRectangle(dpy, lwin, areawin->gc, 5,
174 10 + FILECHARHEIGHT * (flcurrent
175 - flstart), flcurwidth + 10, FILECHARHEIGHT);
176
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
184
185 /* Restore graphics state values */
186 XSetForeground(dpy, areawin->gc, colorlist[areawin->gccolor].color.pixel);
187 XSetFunction(dpy, areawin->gc, GXcopy);
188 }
189
190 #endif
191
192 /*----------------------------------------------------------------------*/
193 /* Read a crash file to find the name of the original file. */
194 /*----------------------------------------------------------------------*/
195
getcrashfilename()196 char *getcrashfilename()
197 {
198 FILE *fi;
199 char temp[256];
200 char *retstr = NULL, *tpos, *spos;
201 int slen;
202
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);
212 }
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;
220 }
221 }
222 fclose(fi);
223 }
224 return retstr;
225 }
226
227 /*----------------------------------------------------------------------*/
228 /* Crash recovery: load the file, and link the tempfile name to it. */
229 /*----------------------------------------------------------------------*/
230
crashrecover()231 void crashrecover()
232 {
233 if (xobjs.tempfile != NULL) {
234 unlink(xobjs.tempfile);
235 free(xobjs.tempfile);
236 xobjs.tempfile = NULL;
237 }
238 if (strlen(_STR2) == 0) {
239 Wprintf("Error: No temp file name for crash recovery!");
240 }
241 else {
242 xobjs.tempfile = strdup(_STR2);
243 startloadfile(-1);
244 }
245 }
246
247 /*----------------------------------------------------------------------*/
248 /* Look for any files left over from a crash. */
249 /*----------------------------------------------------------------------*/
250
findcrashfiles()251 void findcrashfiles()
252 {
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;
262
263 cwd = opendir(xobjs.tempdir);
264 if (cwd == NULL) return; /* No tmp directory, no tmp files! */
265
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 = '.';
277 }
278 if ((!stat(_STR, &sbuf))
279 #ifndef _MSC_VER
280 && (sbuf.st_uid == userid)
281 #endif
282 ) {
283 if ((recent == 0) || (sbuf.st_ctime > recent)) {
284
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. */
288
289 #ifndef _MSC_VER
290 if (pid != -1)
291 if (kill((pid_t)pid, SIGCONT) == 0)
292 continue;
293 #endif
294
295 recent = sbuf.st_ctime;
296 strcpy(_STR2, _STR);
297 }
298 }
299 }
300 }
301 closedir(cwd);
302
303 if (recent > 0) { /* There exists at least one temporary file */
304 /* belonging to this user. Ask to recover */
305 /* the most recent one. */
306
307 /* Warn user of existing tempfile, and ask user if file */
308 /* should be recovered immediately. */
309
310 #ifdef TCL_WRAPPER
311 char *cfile = getcrashfilename();
312
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
323 }
324 }
325
326 /*----------------------------------------------------------------------*/
327 /* Match a filename extension against the file filter list. */
328 /*----------------------------------------------------------------------*/
329
330 #if !defined(XC_WIN32) || defined(TCL_WRAPPER)
331
match_filter(char * fname,char * filter)332 Boolean match_filter(char *fname, char *filter)
333 {
334 char *dotptr = strrchr(fname, '.');
335 char *filtptr, *endptr;
336 int filtlen, extlen;
337
338 if (filter == NULL) return False;
339 if (dotptr == NULL) return False;
340
341 /* New 11/08: Empty string for filter is a wildcard match, the same */
342 /* as turning off the filter. */
343
344 if (filter[0] == '\0') return True;
345
346 dotptr++;
347 extlen = strlen(dotptr);
348 filtptr = filter;
349
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;
357
358 filtptr = endptr;
359 while (*filtptr != '\0' && isspace(*filtptr)) filtptr++;
360 }
361 return False;
362 }
363
364 /*----------------------------------------------------------------------*/
365 /* Make a list of the files in the list widget window */
366 /*----------------------------------------------------------------------*/
367
listfiles(xcWidget w,popupstruct * okaystruct,caddr_t calldata)368 void listfiles(xcWidget w, popupstruct *okaystruct, caddr_t calldata)
369 {
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;
383
384 filter = okaystruct->filter;
385
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);
393 }
394
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
403
404 /* Generate a new flistpix pixmap if currently nonexistent */
405
406 if (!flistpix) {
407
408 /* get list of files in the current directory (cwd) */
409
410 flfiles = 0;
411 if (cwdname == NULL) {
412 cwdname = (char *) malloc (sizeof(char));
413 cwdname[0] = '\0';
414 }
415 if (cwdname[0] == '\0')
416 cwd = opendir(".");
417 else
418 cwd = opendir(cwdname);
419
420 /* If current directory cannot be accessed for some reason, */
421 /* print "Invalid Directory" to the file list window. */
422
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;
430 }
431 else {
432 if (files == NULL)
433 files = (fileliststruct *) malloc (INITDIRS * sizeof(fileliststruct));
434
435 /* write the contents of the current directory into the */
436 /* array "filenames[]" (except for current directory ".") */
437
438 while ((dp = readdir(cwd)) != NULL) {
439 /* don't put current directory in list */
440 if (!strcmp(dp->d_name, ".")) continue;
441
442 /* record the type of file */
443
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;
455 }
456
457 /* save the filename */
458
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));
468 }
469 }
470 }
471 closedir(cwd);
472
473 /* sort the files[] array into alphabetical order (like "ls") */
474
475 qsort((void *)files, (size_t)flfiles, sizeof(fileliststruct), fcompare);
476
477 pixheight = flfiles * FILECHARHEIGHT + 25;
478 if (pixheight < textheight) pixheight = textheight;
479
480 flistpix = XCreatePixmap(dpy, areawin->window, textwidth, pixheight,
481 DefaultDepthOfScreen(xcScreen(w)));
482
483 /* Write the filenames onto the pixmap */
484
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;
499 }
500 XDrawString(dpy, flistpix, sgc, 10, 10 + FILECHARASCENT + n * FILECHARHEIGHT,
501 files[n].filename, strlen(files[n].filename));
502 }
503 }
504
505 /* Copy the pixmap of filenames into the file list window */
506
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);
511 }
512
513 /*-------------------------------------------------------------------------*/
514 /* Generate a new pixmap for writing the filelist and set the scrollbar */
515 /* size accordingly. */
516 /*-------------------------------------------------------------------------*/
517
newfilelist(xcWidget w,popupstruct * okaystruct)518 void newfilelist(xcWidget w, popupstruct *okaystruct)
519 {
520 short n;
521
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;
529 }
530 result = Tcl_GetBoolean(xcinterp, cstr, &bval);
531 if (result != TCL_OK) {
532 Wprintf("Error: Bad variable $XCOps(filter) in Tcl!");
533 return;
534 }
535 xobjs.filefilter = bval;
536 #else
537 xcWidget textw = okaystruct->textw;
538 #endif
539
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
559 }
560
561 /*-------------------------------------------------------------------------*/
562 /* Button press handler for file list window */
563 /*-------------------------------------------------------------------------*/
564
fileselect(xcWidget w,popupstruct * okaystruct,XButtonEvent * event)565 void fileselect(xcWidget w, popupstruct *okaystruct, XButtonEvent *event)
566 {
567 Window lwin = xcWindow(w);
568 Dimension textwidth, textheight;
569 short filenum;
570 char *tbuf, *ebuf;
571
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;
579
580 XtnSetArg(XtNwidth, &textwidth);
581 XtnSetArg(XtNheight, &textheight);
582 XtGetValues(w, wargs, n);
583 #endif
584
585 flcurrent = -1;
586
587 if (files == NULL) return; /* shouldn't happen */
588
589 /* third mouse button cancels selection and reverts buffer to cwd name */
590
591 if (event->button == Button3) {
592 newfilelist(w, okaystruct);
593 return;
594 }
595
596 filenum = (event->y - 10 + FILECHARHEIGHT) / FILECHARHEIGHT + flstart - 1;
597 if (filenum < 0) filenum = 0;
598 else if (filenum >= flfiles) filenum = flfiles - 1;
599
600 /* Attempt to enter invalid directory. . . treat like button 3 */
601
602 if (filenum < 0) {
603 newfilelist(w, okaystruct);
604 return;
605 }
606
607 /* check if this file is a directory or not */
608
609 if (strchr(files[filenum].filename, '/') == NULL) {
610
611 /* highlight the entry. . . */
612
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);
618
619 /* . . .and append it to the text field */
620
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);
632
633 /* add a comma if there is already text in the destination buffer */
634
635 if (tbuf[0] != '\0') {
636 if (tbuf[strlen(tbuf) - 1] != '/') strcat(tbuf, ",");
637 }
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);
644 }
645 }
646 }
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);
658 }
659 else { /* move to new directory */
660
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';
669 }
670 else {
671 cwdname = (char *)realloc(cwdname, (strlen(cwdname) +
672 4) * sizeof(char));
673 strcat(cwdname, "../");
674 }
675 }
676 else {
677 cwdname = (char *)realloc(cwdname, (strlen(cwdname) +
678 strlen(files[filenum].filename) + 1) * sizeof(char));
679 strcat(cwdname, files[filenum].filename);
680 }
681 newfilelist(w, okaystruct);
682 }
683 }
684
685 /*-------------------------------------------------------------------------*/
686 /* Scrollbar handler for file list widget */
687 /*-------------------------------------------------------------------------*/
688
showlscroll(xcWidget w,caddr_t clientdata,caddr_t calldata)689 void showlscroll(xcWidget w, caddr_t clientdata, caddr_t calldata)
690 {
691 Window swin = xcWindow(w);
692 Dimension swidth, sheight;
693 int pstart, pheight, finscr;
694
695 #ifdef TCL_WRAPPER
696 swidth = Tk_Width(w);
697 sheight = Tk_Height(w);
698 #else
699
700 Arg wargs[2];
701 short n = 0;
702
703 XtnSetArg(XtNwidth, &swidth);
704 XtnSetArg(XtNheight, &sheight);
705 XtGetValues(w, wargs, n);
706 #endif
707
708 XClearWindow(dpy, swin);
709
710 if (flfiles > 0) { /* no files, no bar */
711
712 finscr = sheight / FILECHARHEIGHT;
713 if (finscr > flfiles) finscr = flfiles;
714
715 pstart = (flstart * sheight) / flfiles;
716 pheight = (finscr * sheight) / flfiles;
717
718 XSetForeground(dpy, sgc, colorlist[BARCOLOR].color.pixel);
719 XFillRectangle(dpy, swin, sgc, 0, pstart, swidth, pheight);
720 }
721 flcurrent = -1;
722 }
723
724 /*-------------------------------------------------------------------------*/
725 /* Button Motion handler for moving the scrollbar up and down */
726 /*-------------------------------------------------------------------------*/
727
draglscroll(xcWidget w,popupstruct * okaystruct,XButtonEvent * event)728 void draglscroll(xcWidget w, popupstruct *okaystruct, XButtonEvent *event)
729 {
730 Dimension sheight;
731 int phheight, finscr, flsave = flstart;
732 xcWidget filew = okaystruct->filew;
733
734 #ifdef TCL_WRAPPER
735 sheight = Tk_Height(w);
736 #else
737 Arg wargs[1];
738 short n = 0;
739
740 XtnSetArg(XtNheight, &sheight);
741 XtGetValues(w, wargs, n);
742 #endif
743
744 finscr = sheight / FILECHARHEIGHT;
745 if (finscr > flfiles) finscr = flfiles;
746
747 /* center scrollbar on pointer vertical position */
748
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);
752
753 if (flstart != flsave) {
754 showlscroll(w, NULL, NULL);
755 listfiles(filew, okaystruct, NULL);
756 }
757 }
758
759 /*----------------------------------------------------------------------*/
760 /* Set/unset the file filtering function */
761 /*----------------------------------------------------------------------*/
762
763 #ifndef TCL_WRAPPER
764
setfilefilter(xcWidget w,popupstruct * okaystruct,caddr_t calldata)765 void setfilefilter(xcWidget w, popupstruct *okaystruct, caddr_t calldata)
766 {
767 xobjs.filefilter = (xobjs.filefilter) ? False : True;
768
769 /* Force regeneration of the file list */
770
771 newfilelist(okaystruct->filew, okaystruct);
772 }
773
774 #endif
775
776 /*----------------------------------------------------------------------*/
777 /* Generate the file list window */
778 /*----------------------------------------------------------------------*/
779
780 #ifdef TCL_WRAPPER
781
genfilelist(xcWidget parent,popupstruct * okaystruct,Dimension width)782 void genfilelist(xcWidget parent, popupstruct *okaystruct, Dimension width)
783 {
784 xcWidget listarea, lscroll, entertext;
785
786 entertext = okaystruct->textw;
787 listarea = Tk_NameToWindow(xcinterp, ".filelist.listwin.win", parent);
788
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;
797
798 lscroll = Tk_NameToWindow(xcinterp, ".filelist.listwin.sb", parent);
799
800 Tk_CreateEventHandler(lscroll, Button1MotionMask | Button2MotionMask,
801 (Tk_EventProc *)xctk_draglscroll, (ClientData)okaystruct);
802
803 /* force new file list, in case the highlight filter changed */
804
805 if (flistpix != (Pixmap)NULL) XFreePixmap(dpy, flistpix);
806 flistpix = (Pixmap)NULL;
807 }
808
809 #else
810
genfilelist(xcWidget parent,popupstruct * okaystruct,Dimension width)811 void genfilelist(xcWidget parent, popupstruct *okaystruct, Dimension width)
812 {
813 Arg wargs[8];
814 xcWidget listarea, lscroll, entertext, dofilter;
815 short n = 0;
816 int wwidth;
817
818 XtnSetArg(XtNx, 20);
819 XtnSetArg(XtNy, FILECHARHEIGHT - 10);
820 XtnSetArg(XtNwidth, width - SBARSIZE - 40);
821 XtnSetArg(XtNheight, LISTHEIGHT - FILECHARHEIGHT);
822 XtnSetArg(XtNfont, appdata.filefont);
823
824 entertext = okaystruct->textw;
825
826 listarea = XtCreateManagedWidget("Filelist", XwworkSpaceWidgetClass,
827 parent, wargs, n); n = 0;
828 XtAddCallback(listarea, XtNexpose, (XtCallbackProc)listfiles, okaystruct);
829
830 xcAddEventHandler(listarea, ButtonPressMask, False,
831 (xcEventHandler)fileselect, okaystruct);
832 xcAddEventHandler(listarea, EnterWindowMask, False,
833 (xcEventHandler)startfiletrack, NULL);
834 xcAddEventHandler(listarea, LeaveWindowMask, False,
835 (xcEventHandler)endfiletrack, NULL);
836 flstart = 0;
837 okaystruct->filew = listarea;
838
839 XtnSetArg(XtNx, width - SBARSIZE - 20);
840 XtnSetArg(XtNy, FILECHARHEIGHT - 10);
841 XtnSetArg(XtNwidth, SBARSIZE);
842 XtnSetArg(XtNheight, LISTHEIGHT - FILECHARHEIGHT);
843 XtnSetArg(XtNfont, appdata.xcfont);
844
845 lscroll = XtCreateManagedWidget("LScroll", XwworkSpaceWidgetClass,
846 parent, wargs, n); n = 0;
847
848 XtAddCallback(lscroll, XtNexpose, (XtCallbackProc)showlscroll, NULL);
849 xcAddEventHandler(lscroll, Button1MotionMask | Button2MotionMask,
850 False, (xcEventHandler)draglscroll, okaystruct);
851
852 /* Add a toggle widget to turn file filtering on/off */
853
854 wwidth = XTextWidth(appdata.xcfont, "filter", strlen("filter"));
855 XtnSetArg(XtNx, width - wwidth - 50);
856 XtnSetArg(XtNy, LISTHEIGHT + 10);
857 XtnSetArg(XtNset, xobjs.filefilter);
858 XtnSetArg(XtNsquare, True);
859 XtnSetArg(XtNborderWidth, 0);
860 XtnSetArg(XtNfont, appdata.xcfont);
861 XtnSetArg(XtNlabelLocation, XwLEFT);
862 dofilter = XtCreateManagedWidget("Filter", XwtoggleWidgetClass,
863 parent, wargs, n); n = 0;
864 XtAddCallback(dofilter, XtNselect, (XtCallbackProc)setfilefilter, okaystruct);
865 XtAddCallback(dofilter, XtNrelease, (XtCallbackProc)setfilefilter, okaystruct);
866
867 /* force new file list, in case the highlight filter changed */
868
869 if (flistpix != (Pixmap)NULL) XFreePixmap(dpy, flistpix);
870 flistpix = (Pixmap)NULL;
871 }
872
873 #endif /* TCL_WRAPPER */
874
875 #endif
876
877 /*-------------------------------------------------------------------------*/
878 /* Look for a directory name in a string and update cwdname accordingly */
879 /*-------------------------------------------------------------------------*/
880
lookdirectory(char * lstring,int nchars)881 int lookdirectory(char *lstring, int nchars)
882 {
883 int slen;
884 DIR *cwd = NULL;
885
886 xc_tilde_expand(lstring, nchars);
887 slen = strlen(lstring);
888
889 if (lstring[slen - 1] == '/' || ((cwd=opendir(lstring)) != NULL)) {
890 if (cwd) closedir(cwd);
891 if (lstring[slen - 1] != '/') strcat(lstring, "/");
892 cwdname = (char *)realloc(cwdname, (slen + 2) * sizeof(char));
893 strcpy(cwdname, lstring);
894 return(1);
895 }
896 return(0);
897 }
898
899 /*-------------------------------------------------------------------------*/
900