1 /************************************************************************
2 * This program is Copyright (C) 1986-1996 by Jonathan Payne. JOVE is *
3 * provided to you without charge, and with no warranty. You may give *
4 * away copies of JOVE, including sources, provided that this notice is *
5 * included in all the files. *
6 ************************************************************************/
7
8
9 /* (C) 1986, 1987, 1988 Ken Mitchum. This code is intended only for use with Jove. */
10
11 /* In 1995 December, D. Hugh Redelmeier hacked on the code to make
12 * it work again. The environment was Think C 5.0 under System 7.1.
13 *
14 * Obligatory excuses:
15 * - Hugh is not a Mac expert
16 * - Think C 5.0 is quite obsolete (1991)
17 * - The only goal was to get the code working, not working well.
18 *
19 * Known issues:
20 * - the keyboard routines were designed for the Mac Plus keyboard.
21 * + "Command" is taken as "Control" and ` is taken as ESC.
22 * + There should be support for a distinct Command keymap
23 * with Mac-like default bindings.
24 * - "macify" ought to be extended to find-file and perhaps
25 * other commands
26 * - perhaps there are newer MacOS facilities that ought to be
27 * exploited. Apple Events?
28 * - the hacky way the command keystrokes are described in About Jove
29 * ought to be improved.
30 * - Highlighting ought to be supported.
31 * - Mouse support ought to be better. For example, selecting text
32 * ought to be at least as well done as under XTerm!
33 * - [supposition] Because double-clicking is supported, nothing
34 * is done for a single click until the double-click timeout
35 * happens. Since the double-click action is a superset of
36 * the single-click action, the single click action ought to
37 * be immediately performed and then augmented if a double-click
38 * happens.
39 * - see also comments containing ???
40 */
41
42 #include "tune.h"
43
44 #ifdef MAC /* the body is the rest of this file */
45
46 #include "jove.h"
47
48 #include <Controls.h>
49 #include <Desk.h>
50 #include <Dialogs.h>
51 #include <Errors.h>
52 #include <Events.h>
53 #include <Files.h>
54 #include <Fonts.h>
55 #include <Lists.h>
56 #include <LoMem.h>
57 #include <Menus.h>
58 #include <Quickdraw.h>
59 #include <Resources.h>
60 #include <SegLoad.h>
61 #include <StandardFile.h>
62 #include <ToolUtils.h>
63 #include <Types.h>
64 #include <Windows.h>
65
66 #include <errno.h>
67 #include <pascal.h>
68
69 #include "mac.h"
70 #include "ask.h"
71 #include "chars.h"
72 #include "disp.h"
73 #include "extend.h"
74 #include "fp.h" /* for flushscreen() */
75 #include "commands.h"
76 #include "fmt.h"
77 #include "marks.h"
78 #include "misc.h"
79 #include "move.h"
80 #include "screen.h"
81 #include "scandir.h"
82 #include "term.h"
83 #include "vars.h"
84 #include "version.h"
85 #include "wind.h"
86
87 extern struct menu Menus[NMENUS]; /* from menumaps.txt => menumaps.c */
88
89 private EventRecord the_Event;
90
91 private void SetBounds proto((void));
92 private void Set_std proto((void));
93 private void Reset_std proto((void));
94 private bool findtext proto((void));
95
96
97 /* tn.h Modified for variable screen size 11/21/87. K. Mitchum */
98
99 #define SCREENSIZE (wc->w_rows * ROWSIZE)
100 #define FONT monaco
101 #define TEXTSIZE 9
102
103 #define HEIGHT 11
104 #define WIDTH 6
105 #define DESCENT 2
106 #define TWIDTH CO * WIDTH
107 #define THEIGHT LI * HEIGHT
108
109 /* window specs */
110
111 #define SCROLLWIDTH 16 /* width of scroll bar control in pixels */
112 #define WINDWIDTH (wc->w_width - SCROLLWIDTH + 1) /* local coordinates */
113 #define WINDHEIGHT (wc->w_height) /* local coordinates */
114 #define MAXROW ILI
115 #define MAXCOL (CO - 1)
116
117
118 /* for keyboard routines */
119 #define MCHARS 32 /* length of circular buffer -- must be a power of two */
120 #define NCHMASK (MCHARS - 1) /* mask for modulo MCHARS */
121
122
123 /***************************************************/
124
125 private void
126 putcurs proto((unsigned row, unsigned col, bool vis)),
127 curset proto((bool desired)),
128 dellines proto((int n, int bot)),
129 inslines proto((int n, int bot));
130
131 private Rect LimitRect; /* bounds we can't move past */
132
133 struct wind_config {
134 int w_width; /* pixel width of the Mac window */
135 int w_height;
136 int w_rows; /* rows of characters which fit the window */
137 int w_cols;
138 } wc_std, wc_user, *wc;
139
140 private WindowPtr theScreen;
141
142 bool
143 Windchange,
144 EventCmd,
145 Keyonly,
146 Bufchange,
147 Modechange;
148
149 bool
150 Macmode = NO; /* VAR: use Mac file selector */
151
152 /* Initialization Routines. */
153
154 void
getTERM()155 getTERM()
156 {
157 }
158
159 /* For each binding, mark the command with the binding.
160 * We use it for "About Jove ...".
161 * ??? This is faster than using find_binds, but it has problems:
162 * - it only notes the last binding of each command
163 * - it only reflects the three listed keymaps
164 * - it requires a wart on struct cmd
165 * - it is MAC-only
166 */
167
168 private void
InitMapBinds(km,kmc)169 InitMapBinds(km, kmc)
170 data_obj **km;
171 char kmc;
172 {
173 ZXchar i;
174
175 for (i = 0; i < NCHARS; i++) {
176 if (*km != NULL && obj_type(*km) == COMMAND) {
177 struct cmd *c = (struct cmd *) *km;
178
179 c->c_map = kmc;
180 c->c_key = i;
181 }
182 km += 1;
183 }
184 }
185
186 private void
InitBinds()187 InitBinds()
188 {
189 InitMapBinds(MainKeys, F_MAINMAP);
190 InitMapBinds(EscKeys, F_PREF1MAP);
191 InitMapBinds(CtlxKeys, F_PREF2MAP);
192 }
193
194 private WindowPtr window;
195 private Rect r;
196 private CursHandle cross;
197
198 private void InitSysMenu proto((void));
199
200 void
InitEvents()201 InitEvents()
202 {
203 window = theScreen;
204 InitSysMenu();
205 SetRect(&r, window->portRect.left,
206 window->portRect.top,
207 window->portRect.right - SCROLLWIDTH,
208 window->portRect.bottom - SCROLLWIDTH);
209 cross = GetCursor(crossCursor);
210 }
211
212 private void tn_init proto((void));
213 private int getdir proto((void));
214
215 void
MacInit()216 MacInit()
217 {
218 tn_init();
219 getdir();
220 strcpy(TmpDir, gethome());
221 strcpy(ShareDir, TmpDir);
222 InitBinds();
223 }
224
225 void
ttysetattr(n)226 ttysetattr(n)
227 bool n; /* also used as subscript! */
228 {
229 }
230
231 /* Surrogate unix-style file i/o routines for Jove. These replace the
232 routines distributed in the libraries. They work with Jove, but may
233 not be general enough for other purposes. */
234
235 #define NFILES 10
236
237 private int cur_vol; /* Disk or volume number */
238 private long cur_dir; /* Directory number */
239 private int cur_vref; /* ugh.. Vref for volume + directory */
240
241 struct ftab {
242 bool inuse;
243 int refnum; /* Mac file reference number */
244 } ft[NFILES];
245
246 private void
fsetup(p)247 fsetup(p)
248 HParmBlkPtr p;
249 {
250 byte_zero(p, sizeof(HParamBlockRec));
251 p->fileParam.ioVRefNum = cur_vol;
252 p->fileParam.ioDirID = cur_dir;
253 /* p->fileParam.ioFVersNum = 0; */
254 }
255
256 private void
isetup(p)257 isetup(p)
258 IOParam *p;
259 {
260 byte_zero(p, sizeof(IOParam));
261 p->ioVRefNum = cur_vol;
262 }
263
264
265 /* Kludge to convert Macintosh error codes to something like Unix. */
266
267 private int
cvt_err(err)268 cvt_err(err) /* some of these don't make sense... */
269 int err;
270 {
271 switch(err) {
272 case noErr:
273 errno = 0;
274 return 0;
275 case dirFulErr:
276 case dskFulErr:
277 errno = ENOSPC;
278 break;
279 /* case nsvErr: */
280 /* case mFulErr: */
281 /* case tmfoErr: */
282 /* case fnfErr: */
283 default:
284 errno = ENOENT;
285 break;
286 case ioErr:
287 errno = EIO;
288 break;
289 case bdNamErr:
290 case opWrErr:
291 case paramErr:
292 errno = EINVAL;
293 break;
294 case fnOpnErr: /* dubious... */
295 case rfNumErr:
296 errno = EBADF;
297 break;
298 case eofErr: /* ditto */
299 case posErr:
300 errno = /* no longer defined: ESPIPE */ EIO;
301 break;
302 case wPrErr:
303 errno = EROFS;
304 break;
305 case fLckdErr:
306 case permErr:
307 errno = EACCES;
308 break;
309 case fBsyErr:
310 errno = EBUSY;
311 break;
312 case dupFNErr:
313 errno = EEXIST;
314 break;
315 case gfpErr:
316 case volOffLinErr:
317 case volOnLinErr:
318 case nsDrvErr:
319 errno = ENODEV;
320 break;
321 case noMacDskErr:
322 case extFSErr:
323 errno = EIO;
324 break;
325 case fsRnErr:
326 case badMDBErr:
327 case wrPermErr:
328 errno = /* no longer defined: EPERM */ EACCES;
329 break;
330 }
331 return -1;
332 }
333
334 private StringPtr
cvt_fnm(file)335 cvt_fnm(file)
336 const char *file;
337 {
338 static char nm[255];
339 char *t;
340
341 if (*file == '/') {
342 strcpy(nm, file + 1); /* full path */
343 } else {
344 if (strchr(file + 1, '/') != NULL)
345 strcpy(nm, "/"); /* make a partial pathname */
346 else
347 nm[0] = '\0';
348 strcat(nm, file);
349 }
350 for (t = nm; (t = strchr(t, '/')) != NULL; )
351 *t++ = ':';
352 return CtoPstr(nm);
353 }
354
355 private int do_creat proto((HParmBlkPtr p, StringPtr nm));
356
357 int
creat(name,perm)358 creat(name, perm) /* permission mode is irrelevant on a Mac */
359 const char *name;
360 int perm;
361 {
362 int fd, err;
363 StringPtr nm;
364 HParamBlockRec p;
365
366 nm = cvt_fnm(name); /* convert filename to Mac type name */
367 for (fd = 0; ft[fd].inuse; fd++) {
368 if (fd == NFILES-1) {
369 errno = EMFILE;
370 return -1;
371 }
372 }
373 fsetup(&p); /* try to delete it, whether it is there or not. */
374 p.fileParam.ioNamePtr = nm;
375 if ((err = PBHDelete(&p, 0)) != noErr && err != fnfErr)
376 return cvt_err(err);
377 if (do_creat(&p, nm) != 0)
378 return -1;
379 ft[fd].inuse = YES;
380 ft[fd].refnum = p.ioParam.ioRefNum;
381 return fd + 1;
382 }
383
384 #ifdef USE_PROTOTYPES
385 int
open(const char * path,int flags,...)386 open(const char *path, int flags, ...)
387 #else
388 int
389 open(path, flags)
390 const char *path;
391 int flags;
392 #endif
393 {
394 int fd, err;
395 StringPtr nm;
396 HParamBlockRec p;
397
398 nm = cvt_fnm(path); /* convert filename to Mac type name */
399 for (fd = 0; ft[fd].inuse; fd++) {
400 if (fd == NFILES-1) {
401 errno = EMFILE;
402 return -1;
403 }
404 }
405 fsetup(&p);
406 switch (flags & 3) {
407 case 0: /* O_RDONLY */
408 p.ioParam.ioPermssn = fsRdPerm;
409 break;
410 case 1: /* O_WRONLY */
411 p.ioParam.ioPermssn = fsWrPerm;
412 break;
413 case 2: /* O_RDWR */
414 p.ioParam.ioPermssn = fsRdWrPerm;
415 break;
416 }
417 p.ioParam.ioNamePtr = nm;
418 p.ioParam.ioMisc = 0;
419 if ((err = PBHOpen(&p, 0)) != noErr)
420 return cvt_err(err);
421 ft[fd].refnum = p.ioParam.ioRefNum;
422 p.ioParam.ioPosMode = fsFromStart;
423 p.ioParam.ioPosOffset = 0;
424 if ((err = PBSetFPos((ParamBlockRec *) &p, 0)) != noErr)
425 return cvt_err(err);
426 ft[fd].inuse = YES;
427 errno = 0;
428 return fd + 1;
429 }
430
431 private int
do_creat(p,nm)432 do_creat(p, nm)
433 HParmBlkPtr p;
434 StringPtr nm;
435 {
436 int err;
437
438 fsetup(p);
439 p->fileParam.ioNamePtr = nm;
440 if ((err = PBHCreate(p, 0)) != noErr)
441 return cvt_err(err);
442
443 fsetup(p);
444 p->fileParam.ioNamePtr = nm;
445 p->fileParam.ioFDirIndex = 0;
446 if ((err = PBHGetFInfo(p, 0)) != noErr)
447 return cvt_err(err);
448
449 p->fileParam.ioDirID = cur_dir;
450 p->fileParam.ioFlFndrInfo.fdType = 'TEXT';
451 p->fileParam.ioFlFndrInfo.fdCreator = 'JV01';
452 p->fileParam.ioFlFndrInfo.fdFlags = 0;
453 p->fileParam.ioFVersNum = 0;
454 if ((err = PBHSetFInfo(p, 0)) != noErr)
455 return cvt_err(err);
456
457 fsetup(p);
458 p->ioParam.ioNamePtr = nm;
459 p->ioParam.ioPermssn = fsRdWrPerm;
460 p->ioParam.ioMisc = 0;
461 if (cvt_err(PBHOpen(p, 0)))
462 return -1;
463
464 return 0;
465 }
466
467
468 int
close(fd)469 close(fd)
470 int fd;
471 {
472 int err;
473 HParamBlockRec p;
474
475 if (!ft[--fd].inuse) {
476 errno = EBADF;
477 return -1;
478 }
479
480 fsetup(&p);
481 p.ioParam.ioRefNum = ft[fd].refnum;
482 ft[fd].inuse = NO;
483 if (cvt_err(PBClose((ParamBlockRec *) &p, 0)) < 0)
484 return -1;
485
486 fsetup(&p);
487 p.ioParam.ioNamePtr = NULL;
488 if (cvt_err(PBFlushVol((ParamBlockRec *) &p, 0)) < 0)
489 return -1;
490
491 return 0;
492 }
493
494 private SSIZE_T con_read proto((char *buf, size_t size));
495
496 /* Raw UNIX-like read */
497
498 SSIZE_T
read(fd,ubuf,n)499 read(fd, ubuf, n)
500 int fd;
501 UnivPtr ubuf;
502 size_t n;
503 {
504 char *buf = ubuf; /* char * is more useful */
505 int err;
506 IOParam p;
507
508 if (fd == 0) {
509 return con_read(buf, n);
510 } else {
511 if (!ft[--fd].inuse) {
512 errno = EBADF;
513 return -1;
514 }
515 isetup(&p);
516 p.ioRefNum = ft[fd].refnum;
517 p.ioBuffer = buf;
518 p.ioReqCount = n;
519 p.ioPosMode = fsFromMark;
520 p.ioPosOffset = 0;
521 if ((err = PBRead((ParamBlockRec *)&p, 0)) != noErr && err != eofErr)
522 return cvt_err(err);
523
524 errno = 0;
525 return p.ioActCount;
526 }
527 }
528
529 /* Raw UNIX-like write */
530
531 SSIZE_T
write(fd,ubuf,n)532 write(fd, ubuf, n)
533 int fd;
534 UnivConstPtr ubuf;
535 size_t n;
536 {
537 const char *buf = ubuf; /* char * is more convenient */
538
539 if (fd == 0) {
540 writetext((unsigned char *)buf, n);
541 return n;
542 } else {
543 IOParam p;
544 int err;
545 const char *ebuf = buf + n;
546
547 if (!ft[--fd].inuse) {
548 errno = EBADF;
549 return -1;
550 }
551 isetup(&p);
552 p.ioRefNum = ft[fd].refnum;
553 p.ioPosMode = fsFromMark;
554 p.ioReqCount = n;
555 p.ioBuffer = (Ptr)buf;
556 p.ioPosOffset = 0L; /* bidirectional */
557 if ((err = PBWrite((ParamBlockRec *)&p, 0)) != noErr)
558 return cvt_err(err);
559 return p.ioActCount;
560 }
561 }
562
563 long
lseek(fd,offset,whence)564 lseek(fd, offset, whence)
565 int fd;
566 long offset;
567 int whence;
568 {
569 int err;
570 long cur_mark, leof, new_mark;
571 IOParam p;
572
573 if (!ft[--fd].inuse) {
574 errno = EBADF;
575 return -1;
576 }
577
578 isetup(&p);
579 p.ioRefNum = ft[fd].refnum;
580 if ((err = PBGetFPos((ParamBlockRec *)&p, 0)) != noErr)
581 return cvt_err(err);
582
583 cur_mark = p.ioPosOffset;
584 isetup(&p);
585 p.ioRefNum = ft[fd].refnum;
586 if ((err = PBGetEOF((ParamBlockRec *)&p, 0)) != noErr)
587 return cvt_err(err);
588
589 leof = (long) p.ioMisc;
590 switch(whence) {
591 case 0:
592 new_mark = offset;
593 break;
594 case 1:
595 new_mark = offset + cur_mark;
596 break;
597 case 2:
598 new_mark = offset + leof;
599 break;
600 default:
601 errno = EINVAL;
602 return -1;
603 }
604 if (new_mark > leof) {
605 /* need more space in file -- grow it */
606 isetup(&p);
607 p.ioRefNum = ft[fd].refnum;
608 p.ioMisc = (Ptr) new_mark;
609 if ((err = PBSetEOF((ParamBlockRec *)&p, 0)) != noErr)
610 return cvt_err(err);
611 }
612 isetup(&p);
613 p.ioRefNum = ft[fd].refnum;
614 p.ioPosOffset = new_mark;
615 p.ioPosMode = fsFromStart;
616 if ((err = PBSetFPos((ParamBlockRec *)&p, 0)) != noErr)
617 return cvt_err(err);
618 errno = 0;
619 return p.ioPosOffset;
620 }
621
622 /* delete file, if it exists */
623
624 int
unlink(name)625 unlink(name)
626 const char *name;
627 {
628 int fd, err;
629 HParamBlockRec p;
630
631 fsetup(&p);
632 p.fileParam.ioNamePtr = cvt_fnm(name);
633 if ((err = PBHDelete(&p, 0)) != noErr && err != fnfErr)
634 return cvt_err(err);
635 return 0;
636 }
637
638 /* Console read routine */
639
640 private ZXchar rawgetc proto((void));
641
642 private SSIZE_T
con_read(buf,size)643 con_read(buf, size)
644 char *buf;
645 size_t size;
646 {
647 size_t n;
648 ZXchar p;
649
650
651 n = 0;
652 do {
653 p = rawgetc();
654 *buf++ = p;
655 n++;
656 } while (rawchkc() && n <= size);
657 return n;
658 }
659
660 void
dobell(n)661 dobell(n) /* declared in term.h */
662 int n;
663 {
664 while (--n >= 0)
665 SysBeep(5);
666 flushscreen();
667 }
668
669 /* Simplified stat() routine emulates what is needed most. */
670
671 int
stat(fname,buf)672 stat(fname, buf)
673 const char *fname;
674 struct stat *buf;
675 {
676 CInfoPBRec p;
677 StringPtr nm;
678
679 nm = cvt_fnm(fname);
680 byte_zero(&p, sizeof(CInfoPBRec));
681 p.hFileInfo.ioCompletion = 0;
682 p.hFileInfo.ioNamePtr = nm;
683 p.hFileInfo.ioFVersNum = 0;
684 p.hFileInfo.ioFDirIndex = 0;
685 p.hFileInfo.ioVRefNum = cur_vol;
686 p.hFileInfo.ioDirID = cur_dir;
687
688 switch (PBGetCatInfo(&p, 0)) {
689 case noErr:
690 errno = 0;
691 buf->st_dev = p.hFileInfo.ioVRefNum + 1; /* don't want 0 */
692 buf->st_ino = p.hFileInfo.ioDirID;
693 buf->st_size = p.hFileInfo.ioFlLgLen;
694 buf->st_mtime = p.hFileInfo.ioFlMdDat;
695 buf->st_mode = (p.hFileInfo.ioFlAttrib & 0x10) ? S_IFDIR : S_IFREG;
696 return 0;
697 case nsvErr:
698 case paramErr:
699 case bdNamErr:
700 case fnfErr:
701 errno = ENOENT;
702 break;
703 case ioErr:
704 errno = EIO;
705 break;
706 default:
707 errno = ENOENT;
708 break;
709 }
710 return -1;
711 }
712
713 /* Directory related routines. Jove keeps track of the true Volume (disk)
714 number and directory number, and avoids "Working Directory Reference
715 Numbers", which are confusing. */
716
717 private int
getdir()718 getdir() /* call this only once, during startup. */
719 {
720 WDPBRec p;
721
722 p.ioCompletion = 0;
723 p.ioNamePtr = NULL;
724 if (PBHGetVol(&p, 0) != noErr)
725 return -1; /* BIG trouble (but caller never checks returned value!) */
726 cur_vol = p.ioWDVRefNum;
727 cur_dir = p.ioWDDirID;
728 SFSaveDisk = 0 - cur_vol; /* these are for SF dialogs */
729 CurDirStore = cur_dir;
730 return 0;
731 }
732
733 private int
setdir(vol,dir)734 setdir(vol, dir)
735 int vol;
736 long dir;
737 {
738 WDPBRec p;
739
740 p.ioCompletion = 0;
741 p.ioNamePtr = NULL;
742 p.ioVRefNum = vol;
743 p.ioWDDirID = dir;
744 if (PBHSetVol(&p, 0) != noErr)
745 return -1;
746
747 cur_vol = vol;
748 cur_dir = dir;
749 SFSaveDisk = 0 - vol; /* these are for SF dialogs */
750 CurDirStore = dir;
751 return 0;
752 }
753
754 private bool
lookupdir(dir,d)755 lookupdir(dir, d)
756 const char *dir; /* UNIX-like pathname for directory */
757 CInfoPBPtr d; /* info from directory */
758 {
759 char
760 nm[FILESIZE + 1],
761 *t;
762
763 if (strcmp(dir, ".") == 0)
764 getcwd(nm, sizeof(nm) - 1);
765 else
766 strcpy(nm, dir);
767
768 for (t = nm; (t = strchr(t, '/')) != NULL; )
769 *t++ = ':';
770
771 t = nm; /* get rid of initial slashes */
772 while (*t == ':')
773 t++;
774
775 strcat(t, ":"); /* force trailing ':', signifying directory */
776
777 byte_zero(d, sizeof(*d));
778 /* d->dirInfo.ioCompletion = 0; */
779 d->dirInfo.ioNamePtr = CtoPstr(t);
780 d->dirInfo.ioVRefNum = cur_vol;
781 /* d->dirInfo.ioFDirIndex = 0; */
782 /* d->dirInfo.ioDrDirID = 0; */
783 PBGetCatInfo(d, 0);
784 return d->dirInfo.ioResult == noErr
785 && (d->dirInfo.ioFlAttrib & 0x10) != 0;
786 }
787
788 int
chdir(dir)789 chdir(dir)
790 const char *dir;
791 {
792 CInfoPBRec d;
793
794 if (strcmp(dir, "/") == 0 /* There is no root... */
795 || !lookupdir(dir, &d)
796 || setdir(d.dirInfo.ioVRefNum, d.dirInfo.ioDrDirID) < 0)
797 return -1;
798 return 0;
799 }
800
801 /* Scandir returns the number of entries or -1 if the directory cannot
802 be opened or malloc fails.
803 Note: if we ever support RECOVER, this code will have to be moved
804 to scandir.c */
805
806 int
jscandir(dir,nmptr,qualify,sorter)807 jscandir(dir, nmptr, qualify, sorter)
808 char *dir;
809 char ***nmptr;
810 bool (*qualify) ptrproto((char *));
811 int (*sorter) ptrproto((UnivConstPtr, UnivConstPtr));
812 {
813 long DirID;
814 char **ourarray;
815 unsigned int nalloc = 10,
816 nentries = 0,
817 index = 1;
818
819 if (strcmp(dir, "/") == 0) {
820 /* we are enumerating volumes */
821 DirID = 0;
822 } else {
823 /* we are enumerating the contents of a volume or directory */
824 CInfoPBRec d;
825
826 if (!lookupdir(dir, &d))
827 return -1;
828 DirID = d.dirInfo.ioDrDirID;
829 }
830
831 ourarray = (char **) emalloc(nalloc * sizeof (char *));
832 for (;;) {
833 Str32 name; /* 31 is limit, but we might add a '/' */
834
835 if (DirID == 0) {
836 /* we are enumerating volumes */
837 ParamBlockRec d;
838
839 byte_zero(&d, sizeof(d));
840 d.volumeParam.ioCompletion = 0;
841 d.volumeParam.ioNamePtr = name;
842 d.volumeParam.ioVRefNum = 0;
843 d.volumeParam.ioVolIndex = index++;
844 if (PBGetVInfo(&d, 0) != noErr)
845 break; /* we are done, then */
846 PtoCstr(name);
847 #ifdef DIRECTORY_ADD_SLASH
848 /* I *think* this has got to be a volume */
849 strcat((char *)name, "/");
850 #endif
851
852 } else {
853 /* we are enumerating the contents of a volume or directory */
854 CInfoPBRec d;
855
856 byte_zero(&d, sizeof(d));
857 d.dirInfo.ioCompletion = 0;
858 d.dirInfo.ioNamePtr = name;
859 d.dirInfo.ioVRefNum = cur_vol;
860 d.dirInfo.ioFDirIndex = index++;
861 d.dirInfo.ioDrDirID = DirID; /* .ioDirID == .ioDrDirID */
862 if (PBGetCatInfo(&d, 0) != noErr)
863 break; /* we are done, then */
864 PtoCstr(name);
865 #ifdef DIRECTORY_ADD_SLASH
866 if (d.dirInfo.ioFlAttrib & 0x10) /* see Inside Mac IV-122 */
867 strcat((char *)name, "/");
868 #endif
869 }
870 if (qualify != NULL && !(*qualify)((char *) name))
871 continue;
872 /* note: test ensures one space left in ourarray for NULL */
873 if (nentries+1 == nalloc)
874 ourarray = (char **) erealloc((char *) ourarray, (nalloc += 10) * sizeof (char *));
875 ourarray[nentries++] = copystr((char *)name);
876 }
877 ourarray[nentries] = NULL;
878
879 if (sorter != NULL)
880 qsort((char *) ourarray, nentries, sizeof (char **), sorter);
881 *nmptr = ourarray;
882
883 return nentries;
884 }
885
886
887 char *
getcwd(buf,size)888 getcwd(buf, size)
889 char *buf;
890 size_t size;
891 {
892 CInfoPBRec d;
893 Str31 nm;
894 char *p = buf + size; /* build from right */
895
896 if (p == buf)
897 return NULL; /* not even room for NUL */
898
899 *--p = '\0';
900
901 for (d.dirInfo.ioDrDirID = cur_dir; ; d.dirInfo.ioDrDirID = d.dirInfo.ioDrParID) {
902 d.dirInfo.ioCompletion = 0;
903 d.dirInfo.ioNamePtr = nm;
904 d.dirInfo.ioVRefNum = cur_vol;
905 d.dirInfo.ioFDirIndex = -1;
906 PBGetCatInfo(&d, 0);
907 if (d.dirInfo.ioResult != noErr)
908 return NULL;
909
910 if (p - buf <= Length(nm))
911 return NULL; /* insufficient room for / and name */
912
913 p -= Length(nm);
914 memcpy((UnivPtr)p, (UnivPtr) (nm+1), Length(nm));
915 *--p = '/';
916
917 if (d.dirInfo.ioDrDirID == 2)
918 break; /* home directory */
919 }
920 strcpy(buf, p); /* left justify */
921 return buf;
922 }
923
924 char *
gethome()925 gethome() /* this will be startup directory */
926 {
927 static char *ret = NULL;
928 char space[FILESIZE];
929
930 if (ret == NULL)
931 ret = copystr(getcwd(space, sizeof(space)));
932 return ret;
933 }
934
935
936
937 /* Routines that put up and manipulate the "About Jove" dialog. */
938
939
940 /* (ORIGINALLY IN) about_j.c. */
941
942
943 #define DLOGNAME "\pABOUT_JDLOG"
944
945 #define DONE_ITEM 1
946 #define LIST_ITEM 2
947
948
949 #define DWIDTH 460 /* there should be an easy way to get this */
950 #define DHEIGHT 240 /* from the resource file! */
951
952 WindowPtr makedisplay();
953 ListHandle makelist();
954
955
956 private WindowPtr theWindow;
957 private ListHandle theList;
958 private Rect theListRect;
959 private EventRecord theEvent;
960
961
962
963 private void
964 do_list proto((void)),
965 do_events proto((void));
966
967 private WindowPtr
968 makedisplay proto((void));
969
970 private ListHandle
971 makelist proto((void));
972
973 private void
about_j()974 about_j()
975 {
976 WindowPtr OldWindow;
977
978 GetPort(&OldWindow);
979
980 if ((theWindow = makedisplay()) == 0)
981 return;
982 SetPort(theWindow);
983 if (theList = makelist()) {
984 LActivate(1, theList);
985 do_list();
986 ShowWindow(theWindow);
987 do_events();
988 }
989 SetPort(OldWindow);
990 LDispose(theList);
991 DisposDialog(theWindow);
992 }
993
994
995 private WindowPtr
makedisplay()996 makedisplay()
997 {
998 static short dlogid = 0;
999
1000 DialogPtr theDialog;
1001 Handle theHandle;
1002 Handle theResource;
1003 Str255 buf;
1004 ResType resType;
1005 short itemType;
1006 Rect theRect;
1007 short dh, dv; /* to center dialog on the screen */
1008 Str255 nostring;
1009
1010 if (dlogid == 0) {
1011 if ((theResource = GetNamedResource('DLOG', DLOGNAME)) == NULL)
1012 return (WindowPtr)NULL;
1013 itemType = 'DLOG';
1014 GetResInfo(theResource, &dlogid, &resType, buf);
1015 }
1016
1017 theDialog = GetNewDialog(dlogid, 0L, (WindowPtr) -1);
1018 nostring[0] = 0; /* set length of Pascal String to 0 */
1019 ParamText(
1020 "\pMacJove - Copyright (C) 1986-1996 J. Payne, K. Gegenfurtner,",
1021 "\pK. Mitchum. Portions (C) THINK Technologies, Inc.",
1022 nostring, nostring);
1023
1024 dh = qd.screenBits.bounds.left + (qd.screenBits.bounds.right - DWIDTH) / 2;
1025 dv = qd.screenBits.bounds.top + (qd.screenBits.bounds.bottom - DHEIGHT) / 2;
1026 MoveWindow((WindowPtr)theDialog, dh, dv, 0);
1027 ShowWindow((WindowPtr)theDialog);
1028
1029
1030 GetDItem(theDialog, LIST_ITEM, &itemType, &theHandle, &theRect);
1031 theListRect = theRect;
1032 theListRect.right -= 15;
1033 ((WindowPtr)theDialog)->txFont = FONT;
1034 ((WindowPtr)theDialog)->txSize = TEXTSIZE;
1035
1036 return (WindowPtr) theDialog;
1037 }
1038
1039 private void
do_display()1040 do_display() /* draw necessary controls, lines */
1041 {
1042 Rect rViewF; /* framing rect for list */
1043 int offset;
1044
1045 rViewF = theListRect;
1046
1047 rViewF.left--;
1048 rViewF.top--;
1049 rViewF.right++;
1050 rViewF.bottom++;
1051 FrameRect(&rViewF);
1052
1053 DrawControls(theWindow);
1054 }
1055
1056 private ListHandle
makelist()1057 makelist()
1058 {
1059 Point csize;
1060 Rect dataBounds, rView; /* list boundaries */
1061
1062 csize.h = csize.v = 0;
1063 SetRect(&dataBounds, 0, 0, 1, 0);
1064 return LNew(&theListRect, &dataBounds, csize, 0, theWindow, 0, 0, 0, 1);
1065 }
1066
1067 private void
printbind(f,buf)1068 printbind(f, buf)
1069 const struct cmd *f;
1070 char *buf;
1071 {
1072 char c;
1073
1074 if (f->c_map == 0 || (c = f->c_key) == 0x7f) {
1075 strcpy(buf, " ");
1076 return;
1077 }
1078 switch(f->c_map) {
1079 case F_MAINMAP:
1080 strcpy(buf, " ");
1081 break;
1082
1083 case F_PREF1MAP:
1084 strcpy(buf, " ESC ");
1085 break;
1086
1087 case F_PREF2MAP:
1088 strcpy(buf, " ^X ");
1089 break;
1090 }
1091 if (c < ' ') {
1092 buf[5] = '^'; /* control char */
1093 c |= 0x40;
1094 } else {
1095 buf[5] = ' ';
1096 }
1097 if ('a' <= c && c <= 'z')
1098 c &= 0x5f;
1099 buf[6] = c;
1100 buf[7] = ' ';
1101 buf[8] = '\0';
1102 }
1103
1104 private void
do_list()1105 do_list()
1106 {
1107 int row, col;
1108 const struct cmd *f;
1109 char buf[255];
1110 Point theCell;
1111
1112 theCell.h = 0;
1113
1114 for (f = commands, row = 0; f->Name; f++, row++) {
1115 LAddRow(1, row, theList);
1116 theCell.v = row;
1117
1118 printbind(f, buf);
1119 strcat(buf, f->Name);
1120 LSetCell(buf, strlen(buf), theCell, theList);
1121 }
1122 }
1123
1124
1125
1126 private pascal Boolean
ProcFilter(theDialog,event,itemHit)1127 ProcFilter(theDialog, event, itemHit)
1128 DialogPtr theDialog;
1129 EventRecord *event;
1130 short *itemHit;
1131 {
1132 theEvent = *event;
1133 if (theEvent.what == keyDown && theEvent.message & charCodeMask == '\r') {
1134 *itemHit = 1;
1135 return YES;
1136 }
1137 if (theEvent.what == activateEvt && (WindowPtr) theEvent.message == theWindow) {
1138 LDoDraw(1, theList);
1139 LActivate(1, theList);
1140 }
1141 if (theEvent.what == updateEvt && (WindowPtr) theEvent.message == theWindow) {
1142 BeginUpdate(theWindow);
1143 do_display();
1144 DrawDialog(theWindow);
1145 LUpdate(theWindow->visRgn, theList);
1146 EndUpdate(theWindow);
1147 }
1148
1149 return NO;
1150 }
1151
1152
1153 void
do_events()1154 do_events()
1155 {
1156 short item;
1157 bool done = NO;
1158 Point p;
1159
1160 while (!done) {
1161 ModalDialog(ProcFilter, &item);
1162 switch(item) {
1163 case DONE_ITEM:
1164 done = YES;
1165 /* ??? fall through? -- DHR */
1166 case LIST_ITEM:
1167 p = theEvent.where;
1168 GlobalToLocal(&p);
1169 LClick(p, theEvent.modifiers, theList);
1170 break;
1171 }
1172 }
1173 }
1174
1175 /* Window and Control related routines. */
1176
1177 /* (ORIGINALLY IN) tcon.c.
1178 control handler routines for Jove. K. Mitchum 12/86 */
1179
1180
1181 #define MINC 0
1182 #define MAXC 100
1183 #define INITC 0
1184 #define EVENTLIST (mDownMask | keyDownMask )
1185
1186 private Point p;
1187 private bool wc_adjust proto((int, int, struct wind_config *, int));
1188
1189 private void
1190 MakeScrollBar proto((Window *w)),
1191 AdjustScrollBar proto((Window *w)),
1192 drawfluff proto((void));
1193
1194 void
docontrols()1195 docontrols() /* called from redisplay routines */
1196 {
1197 Window *w;
1198 int top;
1199
1200 w = fwind;
1201 top = 0;
1202 do {
1203 if (w->w_control != NULL)
1204 HideControl(w->w_control);
1205 w = w->w_next;
1206 } while (w != fwind);
1207 w = fwind;
1208 do {
1209 w->w_topline = top;
1210 if (w->w_control != NULL)
1211 AdjustScrollBar(w);
1212 else
1213 MakeScrollBar(w);
1214 ShowControl(w->w_control);
1215 top += w->w_height;
1216 w = w->w_next;
1217 } while (w != fwind);
1218 Windchange = NO;
1219 drawfluff();
1220 }
1221
1222
1223 private void
MakeScrollBar(w)1224 MakeScrollBar(w) /* set up control */
1225 Window *w;
1226 {
1227 Rect BarRect;
1228 int wheight, wtop;
1229 WindowPtr window = theScreen;
1230
1231 wheight = w->w_height;
1232 wtop = w->w_topline;
1233 SetRect(&BarRect, window->portRect.right - SCROLLWIDTH + 1,
1234 window->portRect.top -2 + wtop * HEIGHT,
1235 window->portRect.right +1,
1236 window->portRect.top + ((wheight + wtop) * HEIGHT + 1));
1237 w->w_control = NewControl(window, &BarRect, "\psbar", 1, INITC,
1238 MINC, MAXC, scrollBarProc, (long)w);
1239 }
1240
1241 private void
AdjustScrollBar(w)1242 AdjustScrollBar(w) /* redo existing control */
1243 Window *w;
1244 {
1245 ControlHandle handle = w->w_control;;
1246
1247 if (handle != NULL) {
1248 int wtop = w->w_topline;
1249 int wheight = w->w_height;
1250 WindowPtr window = (*handle)->contrlOwner;
1251
1252 SizeControl(handle, SCROLLWIDTH, wheight * HEIGHT + 1);
1253
1254 MoveControl(handle, window->portRect.right - SCROLLWIDTH + 1,
1255 window->portRect.top - 1 + wtop * HEIGHT);
1256 }
1257 }
1258
1259 private int ltoc proto((void)); /* calculate ctlvalue for line position */
1260
1261 void
SetScrollBar(w)1262 SetScrollBar(w) /* set value of the bar */
1263 Window *w;
1264 {
1265 SetCtlValue(w->w_control, ltoc());
1266 }
1267
1268 private void
drawfluff()1269 drawfluff() /* draw controls and dividers */
1270 {
1271 Window *w = fwind;
1272
1273 DrawControls(theScreen);
1274 DrawGrowIcon(theScreen);
1275 }
1276
1277 void
RemoveScrollBar(w)1278 RemoveScrollBar(w)
1279 Window *w;
1280 {
1281 if (w->w_control != NULL)
1282 DisposeControl(w->w_control);
1283 w->w_control = NULL;
1284 }
1285
1286 private pascal void
DScroll(control,part)1287 DScroll(control, part)
1288 ControlHandle control;
1289 int part;
1290 {
1291 DownScroll();
1292 redisplay();
1293 }
1294
1295 private pascal void
UScroll(control,part)1296 UScroll(control, part)
1297 ControlHandle control;
1298 int part;
1299 {
1300 UpScroll();
1301 redisplay();
1302 }
1303
1304 private pascal void
NPage(control,part)1305 NPage(control, part)
1306 ControlHandle control;
1307 int part;
1308 { NextPage();
1309 redisplay();
1310 }
1311
1312 private pascal void
PPage(control,part)1313 PPage(control, part)
1314 ControlHandle control;
1315 int part;
1316 { PrevPage();
1317 redisplay();
1318 }
1319
1320 private long npos; /* number of lines in buffer */
1321
1322 private int
ltoc()1323 ltoc() /* calculate ctlvalue for line position */
1324 {
1325 long ipos = LinesTo(curbuf->b_first, curline) + 1;
1326
1327 npos = ipos + LinesTo(curline, (LinePtr)NULL) - 1;
1328 return (int) ((ipos * MAXC) / npos);
1329 }
1330
1331 private LinePtr
ctol(ctlv)1332 ctol(ctlv) /* find buffer line for ctlvalue */
1333 int ctlv;
1334 {
1335 return next_line(curbuf->b_first, (int) ((npos * ctlv)/MAXC));
1336 }
1337
1338 private void
doWind(event,window)1339 doWind(event, window)
1340 EventRecord *event;
1341 WindowPtr window;
1342 {
1343 p = event->where;
1344 GlobalToLocal(&p);
1345
1346 if (event->what == mouseDown) {
1347 ControlHandle whichControl;
1348 Window
1349 *jwind,
1350 *cwind;
1351 bool notcurwind = NO;
1352 int cpart; /* control part */
1353
1354 if ((cpart = FindControl(p, window, &whichControl)) == 0)
1355 return;
1356
1357 if ((jwind = (Window *) (*whichControl)->contrlRfCon) != curwind) {
1358 notcurwind = YES;
1359 cwind = curwind;
1360 SetWind(jwind);
1361 }
1362 switch (cpart) {
1363 case inUpButton:
1364 TrackControl(whichControl, p, (ProcPtr) DScroll);
1365 break;
1366 case inDownButton:
1367 TrackControl(whichControl, p, (ProcPtr) UScroll);
1368 break;
1369 case inPageUp:
1370 TrackControl(whichControl, p, (ProcPtr) PPage);
1371 break;
1372 case inPageDown:
1373 TrackControl(whichControl, p, (ProcPtr) NPage);
1374 break;
1375 case inThumb:
1376 if (TrackControl(whichControl, p, (ProcPtr)NULL)) {
1377 int newval = GetCtlValue(whichControl);
1378
1379 if (newval == MAXC)
1380 Eof();
1381 else if (newval == MINC)
1382 Bof();
1383 else
1384 SetLine(ctol(newval));
1385 }
1386 break;
1387 }
1388 if (notcurwind) {
1389 SetWind(cwind);
1390 redisplay();
1391 }
1392 redisplay(); /* again, to set the cursor */
1393 } else {
1394 if (findtext())
1395 redisplay();
1396 }
1397 }
1398
1399 #define std_state(w) (*((WStateData **)((WindowPeek)((w)))->dataHandle))->stdState
1400 #define user_state(w) (*((WStateData **)((WindowPeek)((w)))->dataHandle))->userState
1401
1402 private void
doDrag(event,window)1403 doDrag(event, window)
1404 EventRecord *event;
1405 WindowPtr window;
1406 {
1407 Rect old_std = std_state(window);
1408
1409 DragWindow(window, event->where, &LimitRect);
1410 if (wc == &wc_std) {
1411 wc_user = wc_std;
1412 user_state(theScreen) = std_state(theScreen);
1413 ZoomWindow(window, 7, 1);
1414 wc = &wc_user;
1415 Reset_std();
1416 }
1417 }
1418
1419 private void
doGrow(event,window)1420 doGrow(event, window)
1421 EventRecord *event;
1422 WindowPtr window;
1423 {
1424 long size;
1425
1426 /* zero means user didn't change anything */
1427 if ((size = GrowWindow(window, event->where, &LimitRect)) != 0) {
1428 if (wc == &wc_std) {
1429 wc_user = wc_std;
1430 user_state(theScreen) = std_state(theScreen);
1431 ZoomWindow(window, 7, 1);
1432 wc = &wc_user;
1433 Reset_std();
1434 }
1435 if (wc_adjust(LoWord(size), HiWord(size), wc, 0)) {
1436 EraseRect(&window->portRect);
1437 SizeWindow(window, wc->w_width, wc->w_height, YES);
1438 win_reshape(0); /* no signals here... */
1439 }
1440 }
1441 }
1442
1443 private void
doZoomIn(event,window)1444 doZoomIn(event, window)
1445 EventRecord *event;
1446 WindowPtr window;
1447 {
1448 if (TrackBox(window, event->where, 7)) {
1449 EraseRect(&window->portRect);
1450 ZoomWindow(window, 7, 1);
1451 wc = &wc_user;
1452 win_reshape(0); /* we do our own toggle, not ZoomWindow() */
1453 }
1454 }
1455
1456 private void
doZoomOut(event,window)1457 doZoomOut(event, window)
1458 EventRecord *event;
1459 WindowPtr window;
1460 {
1461 if (TrackBox(window, event->where, 8)) {
1462 EraseRect(&window->portRect);
1463 ZoomWindow(window, 8, 1);
1464 wc = &wc_std;
1465 win_reshape(0); /* we do our own toggle, not ZoomWindow() */
1466 }
1467 }
1468
1469 private void
doGoAway(event,window)1470 doGoAway(event, window)
1471 EventRecord *event;
1472 WindowPtr window;
1473 {
1474 if (TrackGoAway(window, event->where))
1475 Leave();
1476 }
1477
1478 private Window *
rtowind(row)1479 rtowind(row) /* return jove window row is in */
1480 int row;
1481 {
1482 Window *w = fwind;
1483
1484 do {
1485 if ((w->w_topline <= row) && ((w->w_height + w->w_topline) > row))
1486 return w;
1487 w = w->w_next;
1488 } while (w != fwind);
1489 return NULL;
1490 }
1491
1492 private LinePtr
windtol(w,row)1493 windtol(w, row) /* return line for row in window */
1494 Window *w;
1495 int row;
1496 {
1497 LinePtr l = w->w_top;
1498
1499 while (row-- && l != NULL)
1500 l = l->l_next;
1501 return l;
1502 }
1503
1504 private int ptoxy proto((Point, int *, int *)); /* convert Point to terminal x, y coordinate */
1505
1506 private bool
findtext()1507 findtext() /* locate and move the point to match the mouse */
1508 {
1509 int row, col;
1510 int offset;
1511 long ticks;
1512 EventRecord event;
1513 Window *w;
1514 LinePtr l;
1515
1516 ticks = Ticks;
1517 ptoxy(p, &row, &col);
1518 if ((w = rtowind(row)) == NULL)
1519 return NO;
1520
1521 if (w != curwind)
1522 SetWind(w);
1523 offset = PhysScreen[row].s_offset; /* account for horizontal scrolling and */
1524 offset += SIWIDTH(offset) + W_NUMWIDTH(w); /* line number */
1525 row -= w->w_topline; /* now have row number in window */
1526 if (row >= w->w_height -1)
1527 return NO;
1528
1529 if ((l = windtol(w, row)) == NULL)
1530 return NO;
1531
1532 if (l->l_dline == NULL_DADDR)
1533 return NO;
1534
1535 this_cmd = LINECMD;
1536 SetLine(l); /* Curline is in linebuf now */
1537 col -= offset;
1538 if (col < 0)
1539 col = 0;
1540 curchar = how_far(curline, col);
1541 do {
1542 if (GetNextEvent(mUpMask, &event) && (event.when < ticks + DoubleTime)) {
1543 set_mark();
1544 break;
1545 }
1546 } while ((Ticks - ticks) < DoubleTime);
1547 return YES;
1548 }
1549
1550
1551 private int
ptoxy(p,row,col)1552 ptoxy(p, row, col) /* convert Point to terminal x, y coordinate */
1553 Point p;
1554 int *row, *col;
1555 {
1556 *row = (p.v / HEIGHT);
1557 *col = (p.h / WIDTH );
1558 if ((*row > MAXROW) || (*col > MAXCOL))
1559 return JMP_ERROR;
1560 return 0;
1561 }
1562
1563 /* Event-related routines. The Event loop is CheckEvents(), and is called
1564 whenever a console read occurs or a call to charp(). During certain
1565 activities, such as ask(), etc. non-keyboard events are ignored.
1566 This is set by the variable Keyonly. As an update or activate event
1567 generates a call to redisplay(), it is important that redisplay() and
1568 related routines NOT check for keyboard characters. */
1569
1570 /* (ORIGINALLY IN) tevent.c
1571 event handler for Jove. K Mitchum 12/86 */
1572
1573
1574 #define SYS_ID 100
1575 #define NOFUNC ((void (*) ptrproto((EventRecord *event)))NULL)
1576 #define NEVENTS 16
1577
1578 private void
1579 doMouse proto((EventRecord *event)),
1580 dokeyDown proto((EventRecord *event)),
1581 doUpdate proto((EventRecord *event)),
1582 doActivate proto((EventRecord *event));
1583
1584 private void p_refresh proto((void));
1585
1586 private MenuHandle SysMenu;
1587
1588 private void (*eventlist[]) ptrproto((EventRecord *event)) =
1589 {
1590 NOFUNC, /* nullEvent */
1591 doMouse, /* mouseDown */
1592 doMouse, /* mouseUp */
1593 dokeyDown, /* keyDown */
1594 NOFUNC, /* keyUp */
1595 dokeyDown, /* autoKey */
1596 doUpdate, /* updateEvt */
1597 NOFUNC, /* diskEvt */
1598 doActivate, /* activateEvt */
1599 NOFUNC, /* not used */
1600 NOFUNC, /* networkEvt = 10 */
1601 NOFUNC, /* driverEvt */
1602 NOFUNC, /* app1Evt */
1603 NOFUNC, /* app2Evt */
1604 NOFUNC, /* app3Evt */
1605 NOFUNC /* app4Ev */
1606 };
1607
1608
1609 private void
1610 SetBufMenu proto((void)),
1611 MarkModes proto((void));
1612
1613 private void
CheckEvents()1614 CheckEvents()
1615 {
1616 EventRecord theEvent;
1617 static long time = 0;
1618
1619 static void (*fptr) ptrproto((EventRecord *event));
1620
1621 if (FrontWindow() == window) {
1622 Point Mousep;
1623
1624 GetMouse(&Mousep);
1625 if (PtInRect(Mousep, &r))
1626 SetCursor(*cross);
1627 else
1628 SetCursor(&qd.arrow);
1629 }
1630
1631 SystemTask();
1632 if (EventCmd && !Keyonly)
1633 return;
1634 if (Bufchange)
1635 SetBufMenu();
1636 if (Modechange)
1637 MarkModes();
1638 while (GetNextEvent(everyEvent, &theEvent)) {
1639 if ((theEvent.what < NEVENTS) && (fptr = eventlist[theEvent.what])) {
1640 (*fptr)(&theEvent);
1641 }
1642 SystemTask();
1643 }
1644 if (TimeDisplayed && (Ticks - time) > 3600) {
1645 time = Ticks;
1646 UpdModLine = YES;
1647 redisplay();
1648 }
1649 }
1650
1651 private void InitLocalMenus proto((void));
1652
1653 private void
InitSysMenu()1654 InitSysMenu()
1655 {
1656 SysMenu = NewMenu(SYS_ID, "\p\24");
1657 AppendMenu(SysMenu, "\pAbout Jove");
1658 AddResMenu(SysMenu, 'DRVR');
1659 InsertMenu(SysMenu, 0);
1660 InitLocalMenus();
1661 DrawMenuBar();
1662 }
1663
1664 private void
1665 doWind proto((EventRecord *event, WindowPtr window)),
1666 doGoAway proto((EventRecord *event, WindowPtr window)),
1667 doSysMenu proto((EventRecord *event, WindowPtr window)),
1668 doSysClick proto((EventRecord *event, WindowPtr window)),
1669 doDrag proto((EventRecord *event, WindowPtr window)),
1670 doGrow proto((EventRecord *event, WindowPtr window)),
1671 doZoomIn proto((EventRecord *event, WindowPtr window)),
1672 doZoomOut proto((EventRecord *event, WindowPtr window));
1673
1674 #define NMEVENTS 9
1675
1676 private void (*mouselist[]) ptrproto((EventRecord *event, WindowPtr window)) =
1677 {
1678 (void (*) ptrproto((EventRecord *event, WindowPtr window)))NULL, /* inDesk */
1679 doSysMenu, /* inMenuBar */
1680 doSysClick, /* inSysWindow */
1681 doWind, /* inContent */
1682 doDrag, /* inDrag */
1683 doGrow, /* inGrow */
1684 doGoAway, /* inGoAway */
1685 doZoomIn, /* inZoomIn */
1686 doZoomOut /* inZoomOut */
1687 };
1688
1689
1690 private void
doMouse(event)1691 doMouse(event)
1692 EventRecord *event;
1693 {
1694 if (Keyonly) {
1695 if (event->what == mouseDown)
1696 SysBeep(2);
1697 } else {
1698 WindowPtr theWindow;
1699 int wpart = FindWindow(event->where, &theWindow);
1700 void (*fptr) ptrproto((EventRecord *event, WindowPtr window));
1701
1702 if (wpart < NMEVENTS && (fptr = mouselist[wpart]) != NULL)
1703 (*fptr)(event, theWindow);
1704 }
1705 }
1706
1707 private void ProcMenu proto((int menuno, int itemno));
1708
1709 private void
doSysMenu(event,window)1710 doSysMenu(event, window)
1711 EventRecord *event;
1712 WindowPtr window;
1713 {
1714 long result = MenuSelect(event->where);
1715 int Menu = (result >> 16) & 0xffff;
1716 int Item = result & 0xffff;
1717
1718 if (Item == 0)
1719 return; /* no choice made */
1720
1721 if (Menu == SYS_ID) { /* apple menu */
1722 Str255 Name;
1723 GrafPtr Port;
1724
1725 if (Item == 1) {
1726 about_j();
1727 } else {
1728 GetItem(SysMenu, Item, Name);
1729 GetPort(&Port);
1730 OpenDeskAcc(Name);
1731 SetPort(Port);
1732 }
1733 } else {
1734 ProcMenu(Menu, Item);
1735 }
1736 HiliteMenu(0);
1737 EventCmd = YES;
1738 menus_on();
1739 }
1740
1741 private void
doSysClick(event,window)1742 doSysClick(event, window)
1743 EventRecord *event;
1744 WindowPtr window;
1745 {
1746 SystemClick(event, window);
1747 }
1748
1749
1750 private void
doUpdate(event)1751 doUpdate(event)
1752 EventRecord *event;
1753 {
1754 WindowPtr
1755 theWindow = (WindowPtr) event->message,
1756 oldPort;
1757
1758 GetPort(&oldPort);
1759 SetPort(theWindow);
1760 BeginUpdate(theWindow);
1761 p_refresh();
1762 drawfluff();
1763 EndUpdate(theWindow);
1764 SetPort(oldPort);
1765 }
1766
1767 private void
doActivate(event)1768 doActivate(event)
1769 EventRecord *event;
1770 {
1771 WindowPtr theWindow = (WindowPtr) event->message;
1772 ControlHandle control;
1773 int hilite;
1774
1775 SetPort(theWindow);
1776 hilite = (event->modifiers & activeFlag)? 0 : 255;
1777 for (control = (ControlHandle) (((WindowPeek) theWindow)->controlList)
1778 ; (control != 0); control = (*control)->nextControl)
1779 {
1780 HiliteControl(control, hilite);
1781 }
1782 }
1783
1784 /* Keyboard routines. */
1785
1786 /* Keycodes (from Inside MacIntosh I-251). This table is ONLY used when
1787 * we are trying to make the Option key work as a Meta key. When we are
1788 * doing this, the system-supplied character is wrong, so we retranslate
1789 * the key code to a character code.
1790 *
1791 * Since we only use this table when the character generated by an
1792 * option-modified key is greater than DEL, and since the Option
1793 * modifier does not so affect keypad keys, we need not provide for
1794 * them in this table.
1795 *
1796 * ??? This may need to be updated to reflect keyboards newer than the Mac+!
1797 */
1798
1799 #define NOKEY '?'
1800
1801 private char nsh_keycodes[] = {
1802 'a','s','d','f','h', /* 00 - 04 */
1803 'g','z','x','c','v', /* 05 - 09 */
1804 NOKEY,'b','q','w','e', /* 0A - 0E */
1805 'r','y','t','1','2', /* 0F - 13 */
1806 '3','4','6','5','=', /* 14 - 18 */
1807 '9','7','-','8','0', /* 19 - 1D */
1808 ']','O','u','[','i', /* 1E - 22 */
1809 'p',CR,'l','j','\'', /* 23 - 27 */
1810 'k',';','\\',',','/', /* 28 - 2C */
1811 'n','m','.','\t',NOKEY, /* 2D - 31 */
1812 '`',DEL /* 32 - 33*/
1813 };
1814
1815 private char sh_keycodes[] = {
1816 'A','S','D','F','H', /* 00 - 04 */
1817 'G','Z','X','C','V', /* 05 - 09 */
1818 NOKEY,'B','Q','W','E', /* 0A - 0E */
1819 'R','Y','T','!','@', /* 0F - 13 */
1820 '#','$','^','%','+', /* 14 - 18 */
1821 '(','&','_','*',')', /* 19 - 1D */
1822 '}','O','U','{','I', /* 1E - 22 */
1823 'P',CR,'L','J','\'', /* 23 - 27 */
1824 'K',';','|','<','?', /* 28 - 2C */
1825 'N','M','>','\t',NOKEY, /* 2D - 31 */
1826 '~',DEL /* 32 - 33 */
1827 };
1828
1829 /* (ORIGINALLY IN) tkey.c
1830 keyboard routines for Macintosh. K Mitchum 12/86 */
1831
1832 jmp_buf auxjmp;
1833
1834 private nchars = 0;
1835 private char charbuf[MCHARS];
1836
1837 /* The following kludges a meta key out of the option key by
1838 sending an escape sequence back to the dispatch routines. This is
1839 not elegant but it works, and doesn't alter escape sequences for
1840 those that prefer them. To remap the control or meta keys,
1841 see mackeys.h. */
1842
1843 private void
dokeyDown(event)1844 dokeyDown(event)
1845 EventRecord *event;
1846 {
1847 unsigned mods;
1848 int c;
1849 static int cptr = 0;
1850
1851 if (MCHARS - nchars < 2)
1852 return;
1853
1854 c = event->message & charCodeMask;
1855
1856 mods = event->modifiers;
1857
1858 if (MetaKey && (mods & optionKey)) {
1859 /* Treat the Option key as a Meta key.
1860 * We have to "undo" the normal option key effect.
1861 * This means that, if the character is greater than DEL
1862 * and the code is known to our table, we retranslate the
1863 * code into a character.
1864 * This seems pretty dubious. I wonder if "KeyTrans" would
1865 * be a better tool.
1866 */
1867 int code = (event->message & keyCodeMask) >> 8;
1868
1869 if (c > DEL && code < elemsof(sh_keycodes))
1870 c = ((mods & shiftKey)? sh_keycodes : nsh_keycodes)[code];
1871
1872 /* jam an ESC prefix */
1873 charbuf[cptr++] = ESC;
1874 cptr &= NCHMASK;
1875 nchars++;
1876 }
1877
1878 if (mods & (cmdKey | controlKey)) {
1879 /* control key (command key is treated as a control key too) */
1880 if (c == '@' || c == '2' || c == ' ')
1881 c = '\0'; /* so we have a null char */
1882 if (c != '`')
1883 c = CTL(c); /* make a control char */
1884 } else if (c == '`') {
1885 c = ESC; /* for those used to escapes */
1886 }
1887
1888 charbuf[cptr++] = c;
1889 cptr &= NCHMASK;
1890 nchars++;
1891 }
1892
1893 private ZXchar
rawgetc()1894 rawgetc()
1895 {
1896 static int cptr = 0;
1897 ZXchar c;
1898
1899 if (EventCmd)
1900 longjmp(auxjmp, 1);
1901
1902 while (nchars <= 0) {
1903 nchars = 0;
1904 if (EventCmd)
1905 longjmp(auxjmp, 1);
1906
1907 CheckEvents(); /* ugh! WAIT for a character */
1908 }
1909 nchars--;
1910 c = ZXRC(charbuf[cptr++]);
1911 cptr &= NCHMASK; /* zero if necessary */
1912 return c;
1913 }
1914
1915 bool
rawchkc()1916 rawchkc()
1917 {
1918 if (EventCmd)
1919 longjmp(auxjmp, 1);
1920
1921 if (nchars == 0)
1922 CheckEvents(); /* this should NOT be necessary! */
1923 return nchars > 0;
1924 }
1925
1926 /* Routines for calling the standard file dialogs, when macify is YES.
1927 If the user changes the directory using the file dialogs, Jove's notion
1928 of the current directory is updated. */
1929
1930
1931 /* (ORIGINALLY IN) tmacf.c. K. Mitchum 12/86.
1932 Macify routines for jove. */
1933
1934 int CurrentVol; /* see tfile.c */
1935
1936 #define TYPES (-1)
1937
1938 private Point px = {100, 100};
1939 private unsigned char pmess[] = "\pSave file as: ";
1940
1941 private pascal Boolean
Ffilter(p)1942 Ffilter(p)
1943 ParmBlkPtr p;
1944 {
1945 Boolean r;
1946 char *name;
1947
1948 if (p->fileParam.ioFlFndrInfo.fdType == 'APPL')
1949 return YES;
1950
1951 /* Filter out our tempfiles.
1952 * ??? the test doesn't check to see if the directories match.
1953 */
1954 name = PtoCstr(p->fileParam.ioNamePtr);
1955 r = strcmp(name, ".joveXXX") == 0
1956 #ifdef ABBREV
1957 || strcmp(name, ".jabbXXX") == 0
1958 #endif
1959 #ifdef RECOVER
1960 || strcmp(name, ".jrecXXX") == 0
1961 #endif
1962 ;
1963 CtoPstr(name);
1964 return r;
1965 }
1966
1967 private void
check_dir()1968 check_dir()
1969 {
1970 if (cur_vol != 0 - SFSaveDisk || cur_dir != CurDirStore) {
1971 char space[FILESIZE];
1972
1973 setdir(0 - SFSaveDisk, CurDirStore);
1974 UpdModLine = YES; /* make sure jove knows the change */
1975 Modechange = YES;
1976 setCWD(getcwd(space, sizeof(space)));
1977 }
1978 }
1979
1980 char *
gfile(namebuf)1981 gfile(namebuf) /* return a filename to get */
1982 char *namebuf;
1983 {
1984 SFReply frec;
1985 char ans[FILESIZE];
1986
1987 SFSaveDisk = 0 - cur_vol; /* in case a Desk Accessory changed them */
1988 CurDirStore = cur_dir;
1989 SFGetFile(px, 0L, Ffilter, TYPES, 0L, 0L, &frec);
1990 check_dir(); /* see if any change, set if so */
1991 if (frec.good) {
1992 EventRecord theEvent;
1993
1994 do; while (GetNextEvent(updateMask, &theEvent) == 0);
1995 doUpdate(&theEvent);
1996 strcpy(ans, PtoCstr(frec.fName));
1997 CtoPstr((char *)frec.fName);
1998 PathParse(ans, namebuf);
1999 return namebuf;
2000 }
2001 return NULL;
2002 }
2003
2004 char *
pfile(namebuf)2005 pfile(namebuf)
2006 char *namebuf;
2007 {
2008 SFReply frec;
2009 StringPtr nm;
2010
2011 SFSaveDisk = 0 - cur_vol; /* in case a Desk Accessory changed them */
2012 CurDirStore = cur_dir;
2013 strncpy(namebuf, filename(curbuf), FILESIZE-1);
2014 nm = cvt_fnm(namebuf);
2015 SFPutFile(px, pmess, nm, 0L, &frec);
2016 check_dir(); /* see if any change, set if so */
2017 if (frec.good) {
2018 EventRecord theEvent;
2019 char *h, *p;
2020
2021 do; while (GetNextEvent(updateMask, &theEvent) == 0);
2022 doUpdate(&theEvent);
2023 h = PtoCstr(frec.fName);
2024 while (*h == ':')
2025 h++; /* convert to unix style */
2026 for (p = h; (p = strchr(p, ':')) != NULL; )
2027 *p++ = '/';
2028 PathParse(h, namebuf);
2029 return namebuf;
2030 }
2031 return NULL;
2032 }
2033
2034
2035 /* getArgs() returns an argument list based on documents clicked on by the user. */
2036
2037 int
getArgs(avp)2038 getArgs(avp)
2039 char ***avp;
2040 {
2041 int argc, old_vol;
2042 short nargs, type;
2043 long old_dir;
2044 char **argv;
2045 char *pathname;
2046 AppFile p;
2047 WDPBRec d;
2048
2049 old_vol = cur_vol;
2050 old_dir = cur_dir;
2051
2052 CountAppFiles(&type, &nargs);
2053 if (nargs > 0) { /* files to open... */
2054 argv = (char **) emalloc((nargs + 2) * sizeof(char *));
2055 for (argc = 1; argc <= nargs; argc++) {
2056 GetAppFiles(argc, &p);
2057 if (type == 0) {
2058 char space[FILESIZE];
2059
2060 PtoCstr((StringPtr)p.fName);
2061 d.ioCompletion = 0;
2062 d.ioNamePtr = NULL;
2063 d.ioVRefNum = p.vRefNum;
2064 d.ioWDIndex = 0;
2065 PBGetWDInfo(&d, 0);
2066 cur_vol = d.ioWDVRefNum;
2067 cur_dir = d.ioWDDirID;
2068 pathname = getcwd(space, sizeof(space));
2069 argv[argc] = emalloc(strlen((char *)p.fName) + strlen(pathname) + 2);
2070 strcpy(argv[argc], pathname);
2071 strcat(argv[argc], "/");
2072 strcat(argv[argc], (char *)p.fName);
2073 }
2074 ClrAppFiles(argc);
2075 }
2076 if (type != 0)
2077 argc = 1;
2078 } else {
2079 argv = (char **) emalloc(2 * sizeof(char*));
2080 argc = 1;
2081 }
2082 argv[0] = "jove";
2083
2084 argv[argc] = NULL;
2085 *avp = argv;
2086 cur_dir = old_dir;
2087 cur_vol = old_vol;
2088 return argc;
2089 }
2090
2091 char *
mktemp(name)2092 mktemp(name)
2093 char *name;
2094 {
2095 return name; /* what, me check? */
2096 }
2097
2098
2099 /* Menu routines. The menus items are set up in a similar manner as keys, and
2100 are bound prior to runtime. See menumaps.txt, which must be run through
2101 setmaps. Unlike keys, menu items may be bound to variables, and to
2102 buffers. Buffer binding is only done at runtime. */
2103
2104 private void
2105 InitMenu proto((struct menu *M)),
2106 make_edits proto((int menu));
2107
2108 private void
InitLocalMenus()2109 InitLocalMenus()
2110 {
2111 int i;
2112
2113 for (i = 0; i < NMENUS; i++) {
2114 InitMenu(&Menus[i]);
2115 if (i == 0)
2116 make_edits(Menus[i].menu_id + 1);
2117 }
2118 }
2119
2120 private void
InitMenu(M)2121 InitMenu(M)
2122 struct menu *M;
2123 {
2124 int i;
2125 StringPtr ps;
2126
2127 if (M->menu_id == 0)
2128 return;
2129
2130 M->Mn = NewMenu(M->menu_id, ps=CtoPstr(M->Name));
2131 PtoCstr(ps);
2132
2133 for (i = 0; i < NMENUITEMS; i++) {
2134 data_obj *d = M->m[i];
2135
2136 if (d == NULL)
2137 break; /* last item... */
2138
2139 switch (d->Type & TYPEMASK) {
2140 case STRING:
2141 AppendMenu(M->Mn, ps=CtoPstr(d->Name));
2142 PtoCstr(ps);
2143 break;
2144 case VARIABLE:
2145 AppendMenu(M->Mn, ps=CtoPstr(d->Name));
2146 PtoCstr(ps);
2147 if ((((struct variable *)d)->v_flags & V_TYPEMASK) == V_BOOL
2148 && *(bool *)(((struct variable *)d)->v_value))
2149 CheckItem(M->Mn, i + 1, YES);
2150 break;
2151 case COMMAND:
2152 AppendMenu(M->Mn, ps=CtoPstr(d->Name));
2153 PtoCstr(ps);
2154 break;
2155 }
2156 }
2157 InsertMenu(M->Mn, 0);
2158 }
2159
2160 private void MacSetVar proto((struct variable *vp, int mnu, int itm));
2161
2162 private void
ProcMenu(menuno,itemno)2163 ProcMenu(menuno, itemno)
2164 int menuno, itemno;
2165 {
2166 int i;
2167 data_obj *d;
2168
2169 for (i = 0; i < NMENUS; i++) {
2170 if (Menus[i].menu_id == menuno) {
2171 itemno--;
2172 d = Menus[i].m[itemno];
2173 switch(d->Type & TYPEMASK) {
2174 case COMMAND:
2175 ExecCmd((data_obj *) d);
2176 break;
2177 case BUFFER:
2178 SetABuf(curbuf);
2179 tiewind(curwind, (Buffer *) d);
2180 SetBuf((Buffer *) d);
2181 break;
2182 case VARIABLE:
2183 MacSetVar((struct variable *) d, i, itemno);
2184 break;
2185 }
2186 break;
2187 }
2188 }
2189 }
2190
2191
2192 private void
make_edits(menu)2193 make_edits(menu) /* add dummy edit menu */
2194 int menu;
2195 {
2196 MenuHandle M;
2197 int item;
2198 char *fname;
2199
2200 M = NewMenu((menu), "\pEdit");
2201 AppendMenu(M,
2202 "\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear;Select All;(-;Show Clipboard");
2203 InsertMenu(M, 0);
2204 DisableItem(M, 0);
2205 }
2206
2207 void
menus_off()2208 menus_off()
2209 {
2210 int i;
2211
2212 if (Keyonly || EventCmd)
2213 return;
2214
2215 #ifdef MENU_DISABLE /* NOBODY likes this, but it's here if you want it... */
2216 DisableItem(SysMenu, 0);
2217 for (i = 0; i < NMENUS; i++)
2218 if (Menus[i].Mn)
2219 DisableItem(Menus[i].Mn, 0);
2220 DrawMenuBar();
2221 #endif
2222 Keyonly = YES;
2223 }
2224
2225 void
menus_on()2226 menus_on()
2227 {
2228 int i;
2229
2230 if (!Keyonly)
2231 return;
2232
2233 #ifdef MENU_DISABLE
2234 EnableItem(SysMenu, 0);
2235 for (i = 0; i < NMENUS; i++)
2236 if (Menus[i].Mn)
2237 EnableItem(Menus[i].Mn, 0);
2238 DrawMenuBar();
2239 #endif
2240 Keyonly = NO;
2241 }
2242
2243 private char *
BufMPrint(b,i)2244 BufMPrint(b, i)
2245 Buffer *b;
2246 int i;
2247 {
2248 char *p;
2249 char *nm = filename(b);
2250 char t[35];
2251
2252 if (strlen(nm) > 30) {
2253 strcpy(t, "...");
2254 strcat(t, nm + strlen(nm) - 30);
2255 } else {
2256 strcpy(t, nm);
2257 }
2258 nm = t;
2259 while (*nm) {
2260 switch(*nm) { /* ugh... these are metacharacter for Menus */
2261 case '/':
2262 *nm = ':';
2263 break;
2264 case '^':
2265 case '!':
2266 case '<':
2267 case '(':
2268 case ';':
2269 *nm = '.';
2270 break; /* that will confuse everybody */
2271 }
2272 nm++;
2273 }
2274 p = sprint("%-2d %-11s \"%-s\"", i, b->b_name, t);
2275 return p;
2276 }
2277
2278 private void
SetBufMenu()2279 SetBufMenu()
2280 {
2281 Buffer *b;
2282 int i, j, stop;
2283 struct menu *M;
2284
2285 Bufchange = NO;
2286 for (i = 0; i < NMENUS; i++) {
2287 if (strcmp(Menus[i].Name, "Buffer") == 0) {
2288 M = &Menus[i];
2289 for (j = 0; j < NMENUITEMS; j++) {
2290 data_obj *d = Menus[i].m[j];
2291
2292 if (d == NULL)
2293 break;
2294
2295 if ((d->Type & TYPEMASK) == BUFFER) {
2296 for (i = j, b = world; i < NMENUITEMS && b != NULL; i++, b = b->b_next) {
2297
2298 if (M->m[i] == NULL)
2299 AppendMenu(M->Mn, CtoPstr(BufMPrint(b, i-j+1))); /* add the item */
2300 else
2301 SetItem(M->Mn, i + 1, CtoPstr(BufMPrint(b, i-j+1))); /* or change it */
2302 M->m[i] = (data_obj *) b;
2303 }
2304 stop = i;
2305 /* out of buffers? */
2306 for (; i < NMENUITEMS && M->m[i]; i++) {
2307 DelMenuItem(M->Mn, stop + 1); /* take off last item */
2308 M->m[i] = NULL;
2309 }
2310 break;
2311 }
2312 }
2313 break;
2314 }
2315 }
2316 }
2317
2318 private void
MacSetVar(vp,mnu,itm)2319 MacSetVar(vp, mnu, itm) /* Set a variable from the menu */
2320 struct variable *vp;
2321 int mnu, itm;
2322 {
2323 if ((vp->v_flags & V_TYPEMASK) == V_BOOL) {
2324 /* toggle the value */
2325 *((bool *) vp->v_value) = !*((bool *) vp->v_value);
2326 MarkVar(vp, mnu, itm);
2327 } else {
2328 char prompt[128];
2329
2330 swritef(prompt, sizeof(prompt), "Set %s: ", vp->Name);
2331 vset_aux(vp, prompt);
2332 }
2333 }
2334
2335 private void
MarkModes()2336 MarkModes()
2337 {
2338 int mnu, itm;
2339 data_obj *d;
2340
2341 Modechange = NO;
2342 for (mnu = 0; mnu < NMENUS; mnu++) {
2343 for (itm = 0; itm < NMENUITEMS; itm++) {
2344 if ((d = Menus[mnu].m[itm]) == NULL)
2345 break;
2346
2347 if ((d->Type & (MAJOR_MODE | MINOR_MODE))
2348 || ((d->Type & TYPEMASK) == BUFFER))
2349 {
2350 bool checked;
2351
2352 if (d->Type & (MAJOR_MODE))
2353 checked = curbuf->b_major == (d->Type >> 8);
2354 else if (d->Type & (MINOR_MODE))
2355 checked = (curbuf->b_minor & (d->Type >> 8)) != 0;
2356 else
2357 checked = d == (data_obj *) curbuf;
2358 CheckItem(Menus[mnu].Mn, itm + 1, checked);
2359 }
2360 }
2361 }
2362 }
2363
2364 void
MarkVar(vp,mnu,itm)2365 MarkVar(vp, mnu, itm) /* mark a boolean menu item */
2366 const struct variable *vp;
2367 int mnu, itm;
2368 {
2369 if (mnu == -1) { /* we don't know the item... slow */
2370 for (mnu = 0; ; mnu++) {
2371 if (mnu >= NMENUS)
2372 return; /* not found */
2373 for (itm = 0; (itm < NMENUITEMS); itm++) {
2374 if ((struct variable *) (Menus[mnu].m[itm]) == vp)
2375 break;
2376 }
2377 if (itm < NMENUITEMS)
2378 break;
2379 }
2380 }
2381 CheckItem(Menus[mnu].Mn, itm + 1, *(bool *)vp->v_value);
2382 }
2383
2384 /* Screen routines and driver. The Macinitosh Text Edit routines are not utilized,
2385 as they are slow and cumbersome for a terminal emulator. Instead, direct QuickDraw
2386 calls are used. The fastest output is obtained writing a line at a time, rather
2387 than on a character basis, so the major output routine is writechr(), which takes
2388 a pascal-style string as an argument. See do_sputc() in screen.c. */
2389
2390 void
Placur(line,col)2391 Placur(line, col)
2392 int line, col;
2393 {
2394 CapCol = col;
2395 CapLine = line;
2396 putcurs(line, col, YES);
2397 }
2398
2399 void
NPlacur(line,col)2400 NPlacur(line, col)
2401 int line, col;
2402 {
2403 CapCol = col;
2404 CapLine = line;
2405 putcurs(line, col, NO);
2406 }
2407
2408 void
i_lines(top,bottom,num)2409 i_lines(top, bottom, num)
2410 int top, bottom, num;
2411 {
2412 Placur(bottom - num + 1, 0);
2413 dellines(num, bottom);
2414 Placur(top, 0);
2415 inslines(num, bottom);
2416 }
2417
2418 void
d_lines(top,bottom,num)2419 d_lines(top, bottom, num)
2420 int top, bottom, num;
2421 {
2422 Placur(top, 0);
2423 dellines(num, bottom);
2424 Placur(bottom + 1 - num, 0);
2425 inslines(num, bottom);
2426 }
2427
2428 /* (ORIGINALLY IN) tn.c */
2429 /* window driver for MacIntosh using windows. */
2430 /* K. Mitchum 9/86 */
2431
2432
2433 /*#define VARFONT*/
2434 #ifdef VARFONT
2435 private height, width, theight, twidth, descent;
2436 #else
2437 # define height HEIGHT
2438 # define width WIDTH
2439 # define theight THEIGHT
2440 # define twidth TWIDTH
2441 # define descent DESCENT
2442 #endif
2443
2444 private int trow, tcol;
2445 private bool cursvis;
2446 #ifdef NEVER
2447 private bool insert;
2448 #endif
2449 private Rect cursor_rect;
2450 private char *p_scr, *p_curs; /* physical screen and cursor */
2451 private int p_size;
2452
2453 private Rect vRect;
2454 private WindowRecord myWindowRec;
2455
2456 #define active() SetPort(theScreen)
2457 #define maxadjust(r) OffsetRect((r), 0, 2)
2458
2459 private char *
conv_p_curs(row,col)2460 conv_p_curs(row, col)
2461 int row,
2462 col;
2463 {
2464 return p_scr + (row * (CO)) + col;
2465 }
2466
2467 #ifdef NEVER
2468 private void
INSmode(new)2469 INSmode(new)
2470 bool new;
2471 {
2472 insert = new;
2473 }
2474 #endif
2475
2476 void
SO_effect(new)2477 SO_effect(new)
2478 bool new;
2479 {
2480 theScreen->txMode = new? notSrcCopy : srcCopy;
2481 }
2482
2483 private void init_slate proto((void));
2484
2485 private void
tn_init()2486 tn_init()
2487 {
2488 #ifdef NEVER
2489 INSmode(NO);
2490 #endif
2491 init_slate();
2492 SO_off();
2493 ShowPen();
2494 }
2495
2496 void
clr_page()2497 clr_page() /* clear and home function */
2498 {
2499 Rect r;
2500
2501 memset(p_scr, ' ', p_size);
2502 active();
2503 SetRect(&r, 0, 0, WINDWIDTH, WINDHEIGHT);
2504 EraseRect(&r);
2505 putcurs(0, 0, NO); /* ??? "NO" guess by DHR */
2506 drawfluff();
2507 }
2508
2509 private void
putcurs(row,col,vis)2510 putcurs(row, col, vis)
2511 unsigned row, col;
2512 bool vis;
2513 {
2514 active();
2515 curset(NO);
2516 trow = row;
2517 tcol = col;
2518 curset(vis);
2519 }
2520
2521 private void
curset(invert)2522 curset(invert)
2523 bool invert;
2524 {
2525 int
2526 colpix = tcol * width,
2527 rowpix = trow * height;
2528
2529 if (trow == MAXROW)
2530 rowpix += 2; /* leave space for 2 pixel rule */
2531 p_curs = conv_p_curs(trow, tcol);
2532 MoveTo(colpix, rowpix + height - descent);
2533 DrawChar(*p_curs);
2534 cursvis = invert;
2535 if (invert) {
2536 SetRect(&cursor_rect, colpix, rowpix,
2537 colpix + width - 1, rowpix + height - 1);
2538 InvertRect(&cursor_rect);
2539 }
2540 MoveTo(colpix, rowpix + height - descent);
2541 }
2542
2543 void
clr_eoln()2544 clr_eoln()
2545 {
2546 Rect r;
2547
2548 active();
2549 SetRect(&r, tcol * width, trow * height, WINDWIDTH, (trow +1) * height);
2550 if (trow == MAXROW)
2551 maxadjust(&r);
2552 EraseRect(&r);
2553 memset(p_curs, ' ', CO - tcol);
2554 curset(YES);
2555 }
2556
2557 #ifdef NEVER
2558 private void
delchars()2559 delchars()
2560 {
2561 Rect r;
2562 RgnHandle updateRgn;
2563
2564 active();
2565 curset(NO);
2566 updateRgn = NewRgn();
2567 SetRect(&r, tcol * width, trow * height, twidth - width, (trow+1) * height);
2568 if (trow == MAXROW)
2569 maxadjust(&r);
2570 ScrollRect(&r, -width, 0, updateRgn);
2571 DisposeRgn(updateRgn);
2572 BlockMove(p_curs + 1, p_curs, (long) (MAXCOL - tcol));
2573 *conv_p_curs(trow, MAXCOL) = ' ';
2574 curset(YES);
2575 }
2576 #endif /* NEVER */
2577
2578 private void
dellines(n,bot)2579 dellines(n, bot)
2580 int n, bot;
2581 {
2582 RgnHandle updateRgn = NewRgn();
2583 Rect r;
2584 long len;
2585
2586 active();
2587 curset(NO);
2588 SetRect(&r, 0, ((trow) * height), WINDWIDTH, ((bot + 1) * height));
2589 ScrollRect(&r, 0, 0 - (n * height), updateRgn);
2590 DisposeRgn(updateRgn);
2591 len = ((bot - trow - n + 1) * CO);
2592 BlockMove(conv_p_curs(trow + n, 0), conv_p_curs(trow, 0), len);
2593 memset(conv_p_curs(bot - n + 1, 0), ' ', n * CO);
2594 putcurs(trow, 0, YES); /* ??? "YES" guess by DHR */
2595 }
2596
2597 private void
inslines(n,bot)2598 inslines(n, bot)
2599 int n, bot;
2600 {
2601 RgnHandle updateRgn = NewRgn();
2602 Rect r;
2603 long len;
2604
2605 active();
2606 curset(NO);
2607 SetRect(&r, 0, trow * height, WINDWIDTH, (bot +1) * height);
2608 ScrollRect(&r, 0, (n * height), updateRgn);
2609 DisposeRgn(updateRgn);
2610 len = ((bot - trow - n +1) * CO);
2611 BlockMove(conv_p_curs(trow, 0), conv_p_curs(trow + n, 0), len);
2612 memset(conv_p_curs(trow, 0), ' ', (n * CO));
2613 putcurs(trow, 0, YES); /* ??? "YES" guess by DHR */
2614 }
2615
2616 void
writetext(str,len)2617 writetext(str, len)
2618 const unsigned char *str;
2619 size_t len;
2620 {
2621 active();
2622 curset(NO);
2623 #ifdef NEVER
2624 if (insert) {
2625 RgnHandle updateRgn = NewRgn();
2626 Rect r;
2627
2628 SetRect(&r, tcol * width, trow * height, twidth - width * len, (trow +1) * height -1);
2629 if (trow == MAXROW)
2630 maxadjust(&r);
2631 ScrollRect(&r, width * len, 0, updateRgn);
2632 DisposeRgn(updateRgn);
2633 }
2634 #endif
2635 DrawText(str, (short)0, (short)len);
2636 #ifdef NEVER
2637 if (insert)
2638 BlockMove(p_curs, p_curs + len, (long) (CO - tcol - len));
2639 #endif
2640 memcpy((UnivPtr)p_curs, (UnivPtr)str, len);
2641 putcurs(trow, tcol+len <= MAXCOL? tcol+len : MAXCOL, YES); /* ??? "YES" guess by DHR */
2642 }
2643
2644 private Rect myBoundsRect;
2645
2646 private void
init_slate()2647 init_slate()
2648 {
2649 FontInfo f;
2650
2651 char *Name = "Jove ";
2652 char *Title;
2653
2654 InitGraf(&qd.thePort);
2655 InitWindows();
2656 InitCursor();
2657 InitFonts();
2658 InitMenus();
2659 InitDialogs((ProcPtr)NULL); /* no restart proc */
2660
2661 /* figure limiting rectangle for window moves */
2662 SetRect(&LimitRect,
2663 qd.screenBits.bounds.left + 3,
2664 qd.screenBits.bounds.top + 20,
2665 qd.screenBits.bounds.right - 3,
2666 qd.screenBits.bounds.bottom -3);
2667
2668 Set_std();
2669 SetBounds();
2670
2671 /* initialize char array for updates */
2672 p_scr = emalloc(p_size = wc_std.w_cols * wc_std.w_rows); /* only once */
2673 p_curs = p_scr;
2674
2675 Title = sprint("%s%s", Name, jversion);
2676 theScreen = NewWindow(&myWindowRec, &myBoundsRect, CtoPstr(Title),
2677 1, 8, (WindowPtr) -1, 1, 0L);
2678
2679 /* figure an initial window configuration and adjust it */
2680 wc = &wc_std;
2681 wc_user = wc_std; /* initially, only one configuration to toggle */
2682 user_state(theScreen) = std_state(theScreen);
2683 SetPort(theScreen);
2684
2685 theScreen->txFont = FONT;
2686 theScreen->txSize = TEXTSIZE;
2687
2688 #ifdef VARFONT
2689 GetFontInfo(&f);
2690 height = f.ascent+f.descent+f.leading;
2691 width = f.widMax;
2692 twidth = width * wc->w_cols;
2693 theight = height * wc->w_rows;
2694 descent = f.descent;
2695 #endif
2696
2697 theScreen->txMode = srcCopy;
2698 theScreen->pnMode = patCopy;
2699 PenNormal();
2700 }
2701
2702 private void
p_refresh()2703 p_refresh()
2704 {
2705 int lineno;
2706
2707 for (lineno = 0; lineno < LI; lineno++) {
2708 char *curs = conv_p_curs(lineno, 0);
2709
2710 MoveTo(0, (lineno+1) * height - descent + (lineno == MAXROW? 2 : 0));
2711 /* The following kludgy line is to get SO right. It depends on:
2712 * - !defined(HIGHLIGHTING)
2713 * - this routine not being called at an inauspicious time
2714 * i.e. in the middle of a SO output.
2715 * - the fact that the last line will non-SO so that the text
2716 * mode will be left non-SO.
2717 */
2718 SO_effect(Screen[lineno].s_effects);
2719 DrawText(curs, (short)0, (short)CO);
2720 }
2721 curset(cursvis);
2722 }
2723
2724
2725 private bool
wc_adjust(w,h,wcf,init)2726 wc_adjust(w, h, wcf, init) /* adjust window config to look nice */
2727 int w, h;
2728 struct wind_config *wcf;
2729 int init;
2730 {
2731 static int LIMIT_R, LIMIT_C;
2732 int rows, cols;
2733
2734 if (init) {
2735 LIMIT_R = (h - 4) / HEIGHT;
2736 LIMIT_C = (w - SCROLLWIDTH - 1) / WIDTH + 1;
2737 }
2738 if ((w < WIDTH * 40) ||(h < HEIGHT * 10) /* too small */
2739 || ((rows = (h - 4) / HEIGHT) > LIMIT_R) /* too big */
2740 || ((cols = (w - SCROLLWIDTH - 1) / WIDTH + 1) > LIMIT_C))
2741 return NO;
2742
2743 wcf->w_rows = rows;
2744 wcf->w_cols = cols;
2745 wcf->w_width = wcf->w_cols * WIDTH + 1 + SCROLLWIDTH;
2746 wcf->w_height = wcf->w_rows * HEIGHT + 4;
2747 return YES;
2748 }
2749
2750 private int
getCO()2751 getCO() /* so that jove knows params */
2752 {
2753 return wc->w_cols;
2754 }
2755
2756 private int
getLI()2757 getLI()
2758 {
2759 return wc->w_rows;
2760 }
2761
2762 void
ttsize()2763 ttsize()
2764 {
2765 /* ??? We really ought to wait until the screen is big enough:
2766 * at least three lines high (one line each for buffer, mode,
2767 * and message) and at least twelve columns wide (eight for
2768 * line number, one for content, two for overflow indicators,
2769 * and one blank at end).
2770 */
2771 /* ??? This should be made more like UNIX version */
2772 CO = getCO();
2773 if (CO > MAXCOLS)
2774 CO = MAXCOLS;
2775 LI = getLI();
2776 Windchange = YES;
2777 clr_page();
2778 ILI = LI - 1;
2779 }
2780
2781 private void
SetBounds()2782 SetBounds()
2783 {
2784 SetRect(&myBoundsRect,
2785 qd.screenBits.bounds.left + 3,
2786 qd.screenBits.bounds.top + 40,
2787 qd.screenBits.bounds.left + 3 + wc_std.w_width,
2788 qd.screenBits.bounds.top + 40 + wc_std.w_height);
2789 }
2790
2791 private void
Set_std()2792 Set_std()
2793 {
2794 (void) wc_adjust(qd.screenBits.bounds.right - qd.screenBits.bounds.left - 6,
2795 qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - 42,
2796 &wc_std, 1);
2797 }
2798
2799 private void
Reset_std()2800 Reset_std()
2801 {
2802 Set_std();
2803 std_state(theScreen) = myBoundsRect;
2804 }
2805 #endif /* MAC */
2806