/* $Id: ckmco2.c,v 1.9 91/12/27 21:28:52 fdc Exp $ * $Source: /uw/mackermit/RCS/ckmco2.c,v $ *------------------------------------------------------------------ * $Log: ckmco2.c,v $ * Revision 1.9 91/12/27 21:28:52 fdc * Change fatal to macfatal, make sure all lines width 80 or less. * * Revision 1.8 91/12/15 23:16:45 rick * ut9 * * Revision 1.7 91/10/13 13:43:05 rick * UT(7) * * Revision 1.6 91/10/01 12:16:12 rick * UT(5) * * Revision 1.5 91/09/25 12:16:26 rick * Command window in TE. Multiple vt100 windows for command window. * * Revision 1.4 91/09/12 21:50:31 rick * UT(3). Install on watsun * * Revision 1.3 1991/09/12 16:42:51 rick * Cleanups. * * Revision 1.2 1991/09/10 22:21:37 rick * Update to UTexas(2) * * Revision 1.1 1991/09/10 19:17:45 rick * Initial revision * *------------------------------------------------------------------ * $Endlog$ */ /* * FILE ckmco2.c * * Module of mackermit: contains code for dealing with the Mac side * of terminal emulation. */ /* Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use this software as long as it is not sold for profit. This copyright notice must be retained. This software may not be included in commercial products without written permission of Columbia University. */ #include "ckcdeb.h" #include "ckcasc.h" #include "ckmdef.h" #include "ckmasm.h" /* Assembler code */ #include "ckmres.h" /* kermit resources */ #include "ckmcon.h" /* defines, etc. for terminal emulator */ #include "ckmptp.h" /* ckm* Prototypes */ extern int escape; #define ABS(a) ((a) < 0 ? -(a) : (a)) char **myclip_h = NULL; /* internal clipboard */ int myclip_size = 0; /* size of above */ int my_scrapcount = -1; /* the value of PScrapStuff->scrapCount when we cut */ extern Boolean usingRAMdriver; /* CTB */ extern Boolean have_128roms; /* True if we are a Plus or better */ RgnHandle dummyRgn; /* dummy region for ScrollRect */ /* Initialized in mac_init */ long MyCaretTime; /* (UoR) ticks between flashes */ extern Cursor *textcurs, *normcurs, *watchcurs; /* mouse cursor shapes */ extern int to_printer; /*JAO*/ extern int to_screen; /*JAO*/ extern int printer_is_on_line_num; /*JAO*/ #ifdef COMMENT extern Handle hPrintBuffer; /*JAO*/ extern long lPrintBufferSize; /*JAO*/ extern long lPrintBufferChars; /*JAO*/ extern long lPrintBufferAt; /*JAO*/ extern DialogPtr bufferingDialog; /*JAO*/ #endif /* COMMENT */ extern DialogPtr overflowingDialog; /*JAO*/ extern MenuHandle menus[]; /* handle on our menus */ /*JAO*/ /* keyboard handling stuff */ extern char keytable[512]; /* the key redefintion flag table */ extern modrec modtable[NUMOFMODS]; /* modifier records */ #define myKeyCodeMask 0x7F00 #define keyModifierMask 0x1F00 #define ctrlCodeMask 0x1F #define metaOrBits 0x80 #define UnmodMask 0x80 /* action bits */ #define CapsMask 0x40 #define CtrlMask 0x20 #define MetaMask 0x10 Boolean have_scriptmgr = FALSE; long old_KCHR, old_SICN; /* pointers to current system key script, icon */ long cur_KCHR; Cursor *lastCursor=0L; /* what we set the cursor to last */ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /* keyboard event handling routines */ /****************************************************************************/ InitKeyStuff() { have_scriptmgr = NGetTrapAddress(num_UnknownTrap, 1) != NGetTrapAddress(num_ScriptTrap, 1); if (have_scriptmgr) { old_KCHR = GetScript( smRoman, smScriptKeys); old_SICN = GetScript( smRoman, smScriptIcon); } cur_KCHR = old_KCHR; UpdateOptKey(1); /* get things set right initially */ } UpdateOptKey(int enable) { int i; int futzit = 0; if (enable) { for (i = 0; i < NUMOFMODS; i++) { /* shift what to look for into high byte */ if ((modtable[i].modbits) & (optionKey >> 4)) /* if Option is selected */ futzit = 1; } } else { /* allways turn off when disabling window */ futzit = 0; } (void) FutzOptKey(futzit); } FutzOptKey(int enable) { int err; if (have_scriptmgr) { /* if we are system 4.1 or later... */ if (enable) { /* no deadkeys */ if (cur_KCHR != old_KCHR) return (1); /* we are allready fine */ if (GetEnvirons(smKeyScript) == smRoman) { /* set the key map only if in roman script */ err = SetScript (smRoman, smScriptKeys, NODEAD_KCHR); if (err != noErr) { printerr ("Trouble setting custom keymap (KCHR):", err); return (0); } /* set the icon */ err = SetScript (smRoman, smScriptIcon, NODEAD_SICN); if (err != noErr) { printerr ("Trouble setting custom keymap icon (SICN):", err); return (0); } KeyScript (smRoman); cur_KCHR = NODEAD_KCHR; return (1); /* success! */ } else { printerr("Can't disable Option key -- you have a non-US keyboard",0); return (0); } } else { /* back to normal */ if (cur_KCHR == old_KCHR) return (1); /* we are allready fine */ /* set the key map */ err = SetScript (smRoman, smScriptKeys, old_KCHR); if (err != noErr) { printerr ("Trouble resetting default keymap (KCHR):", err); return (0); } /* set the icon */ err = SetScript (smRoman, smScriptIcon, old_SICN); if (err != noErr) { printerr ("Trouble resetting default keymap icon (SICN):", err); return (0); } KeyScript (smRoman); cur_KCHR = old_KCHR; return (1); /* success! */ } } else { /* do something or other to do the old way */ /* printerr("Kermit can't disable Option on old systems",0); */ } return (0); } /****************************************************************************/ /* return the ASCII character which is generated by the keyCode specified */ /* with no modifiers pressed */ /****************************************************************************/ unsigned char DeModifyChar (long keyCode, long modifiers) { long c; long mystate; short s_keycode; Handle kchr_h; THz curZone; #ifdef COMMENT ProcHandle KeyTrans; if (keyCode > 64) KeyTrans = (ProcHandle) 0x2A2; /* keypad decode */ else KeyTrans = (ProcHandle) 0x29E; /* keyboard decode */ SaveRegs (); /* save all registers */ AllRegs (); /* setup regs for procedure call */ /* loadD1 ((long) modifiers); */ /* no modifiers */ loadD1 ((long) 0); /* no modifiers */ loadD2 ((long) keyCode); /* set the keycode */ loadA0 (*KeyTrans); /* load the content of Key1Trans to A0 */ /* run the translation routine */ execute (); /* call the Key1Trans procedure */ /* move the result from reg D0 to c */ loadA0 (&c); /* set destination address */ pushD0 (); /* move register D0 to stack */ poptoA0 (); /* load the stacktop to (A0) */ RestoreRegs (); /* restore all registers */ AllRegs (); #endif /* COMMENT */ if (have_scriptmgr) { /* if we are system 4.1 or later... */ mystate = 0; kchr_h = GetResource('KCHR', cur_KCHR); if (kchr_h == NIL) { printerr("DeModifyChar: couldn't get KCHR address",0); return(0); } LoadResource(kchr_h); HLock(kchr_h); s_keycode = (modifiers & 0xff00) | (keyCode & 0xff); c = KeyTrans(*kchr_h, s_keycode, &mystate); HUnlock(kchr_h); curZone = GetZone(); /* as per John Norstad's (Disinfectant) */ SetZone(HandleZone(kchr_h)); /* "Toolbox Gotchas" */ ReleaseResource(kchr_h); SetZone(curZone); } return (c); } /* DeModifyChar */ /****************************************************************************/ /* send a character to the line if it is in ASCII range. Do local echo if */ /* necessary */ /****************************************************************************/ OutputChar (struct termw *termw, unsigned char c) { unsigned char obuf[2]; /* single char output buffer */ /* * PWP: NO 7 bit masking!!! If we do this, then I can't use Emacs, and * the European users will be VERY unhappy, 'cause they won't be able to * send all of their characters. */ obuf[0] = 1; /* length of one character string */ obuf[1] = c; /* store character */ writeps (obuf); /* and write it out */ if (duplex != 0) { cursor_erase (termw); /* remove from screen */ printem (termw, &obuf[1], 1); /* Echo the char to the screen */ flushbuf(termw); /* flush the character */ cursor_draw(termw); /* put it back */ } } /* OutputChar */ #ifdef COMMENT /****************************************************************************/ /* Bittest returns the setting of an element in a Pascal PACKED ARRAY [0..n] OF Boolean such as the KeyMap argument returned by GetKey /****************************************************************************/ Boolean bittest (bitmap, bitnum) char bitmap[]; int bitnum; { return (0x01 & (bitmap[bitnum / 8] >> (bitnum % 8))); } /* bittest */ /* PWP: or, as a macro, */ #define bittest(bitmap,bitnum) (0x01 & (bitmap[bitnum / 8] >> (bitnum % 8))) #endif /* COMMENT */ /****************************************************************************/ /* Process a character received from the keyboard */ /****************************************************************************/ handle_char (struct termw *termw, EventRecord *evt) { short i; short len; short theCode; short modCode; short theModBits; char flags; Str255 tmpstr; unsigned char c; /* (UoR) check for auto repeated keys */ if ((termw->autorepeat == FALSE) && (evt->what == autoKey)) return; ObscureCursor (); /* PWP: hide the cursor until next move */ modCode = evt->modifiers & keyModifierMask; theCode = ((evt->message & myKeyCodeMask) >> 8) + (modCode >> 1); /* check for a special code for this key */ if (BitTst (keytable, theCode)) { GetMacro (theCode, &flags, tmpstr); /* get the macrostring */ if (flags) { /* check special flags */ switch (flags) { case shortBreak: sendbreak (5); return; case longBreak: sendbreak (70); return; case leftArrowKey: do_arrow (termw, leftARROW); return; case rightArrowKey: do_arrow (termw, rightARROW); return; case upArrowKey: do_arrow (termw, UPARROW); return; case downArrowKey: do_arrow (termw, DOWNARROW); return; case keycomma: case keyminus: case keyperiod: /* there is no keyslash */ case key0: case key1: case key2: case key3: case key4: case key5: case key6: case key7: case key8: case key9: do_keypad(termw, flags - keycomma); return; case keypf1: case keypf2: case keypf3: case keypf4: do_pfkey(termw, flags - keypf1); return; case keyenter: do_keyenter(termw); return; } } /* send key macro string */ /* * PWP: note, we DON'T have to convert it to a Pascal string, 'cause * the macros are now stored as Pascal strings */ writeps (tmpstr); /* send it to the line */ if (duplex != 0) printps(termw,tmpstr); /* echo it locally */ return; } for (i = 0; i < NUMOFMODS; i++) { /* shift what to look for into high byte */ theModBits = modtable[i].modbits << 4; len = strlen (modtable[i].prefix); if ((theModBits || len) && ((theModBits & modCode) == (theModBits & keyModifierMask))) { /* send prefix if there is one */ if (len) { /* PWP: these are saved as Pascal strings now */ BlockMove (modtable[i].prefix, tmpstr, (modtable[i].prefix[0] + 1)); writeps (tmpstr); /* send it to the line */ if (duplex != 0) printps(termw,tmpstr); /* echo it locally */ } /* * get the unmodified ASCII code if the unmodify action bit is * active */ if (theModBits & UnmodMask) c = DeModifyChar ((long) ((evt->message & myKeyCodeMask) >> 8), (long) (modCode & shiftKey)); /* PWP: we pass through the shiftedness of this key */ else c = evt->message & charCodeMask; /* otherwise get the * standard char */ /* make an uppercase character if the caps action bit is active */ if ((theModBits & CapsMask) && islower (c)) c = toupper (c); /* make a control character if the control action bit is active */ if (theModBits & CtrlMask) c &= ctrlCodeMask; /* PWP: for Meta characters (yes, I use Emacs) */ if (theModBits & MetaMask) c |= metaOrBits; if (!checkescape(c)) OutputChar (termw, c); return; } /* if */ } /* for */ /* get the ASCII code and send it */ c = evt->message & charCodeMask; if (!checkescape(c)) OutputChar(termw, c); } /* handle_char */ /* * checkescape * Handle escape sequences in connected mode * Return TRUE if character used. */ #define NKBUF 10 checkescape (char c) { int x; static int esclevel = 0; static char *kbp, kbuf[NKBUF]; extern int cmdmsk; switch (esclevel) { case 0: /* no escapes pending */ if ((c & 0x7f) == escape) { esclevel++; return TRUE; /* we ate the char */ } return FALSE; /* we did not process char */ case 1: /* process escape command */ if (doesc(c)) { /* if CMDQ */ esclevel++; kbp = kbuf; /* preset buffer */ *kbp++ = CMDQ; } else esclevel = 0; return TRUE; /* we ate the char */ case 2: /* quoted backslash sequence */ c &= cmdmsk; *kbp = c; if ((c != '\r') && (c != '\n')) { if (&kbuf[NKBUF-1] != kbp) /* if buffer not full */ kbp++; return TRUE; } *kbp = 0; esclevel = 0; kbp = kbuf; x = xxesc(&kbp); if (x >= 0) { c = dopar(x); ttoc(c); } else { /* Invalid backslash code. */ putchar(BEL); } return TRUE; } } /* * console_char * Handle keyboard events while not connected * Return TRUE if we inserted a character into the console buffer. * * THIS ROUTINE LIKELY NEEDS MORE WORK HANDLING SPECIAL CHARACTERS. * */ console_char (struct termw *termw, EventRecord *evt) { short i; short len; short theCode; short modCode; short theModBits; char flags; Str255 tmpstr; unsigned char c; /* (UoR) check for auto repeated keys */ if ((termw->autorepeat == FALSE) && (evt->what == autoKey)) return; ObscureCursor (); /* PWP: hide the cursor until next move */ modCode = evt->modifiers & keyModifierMask; theCode = ((evt->message & myKeyCodeMask) >> 8) + (modCode >> 1); /* check for a special code for this key */ if (BitTst (keytable, theCode)) { GetMacro (theCode, &flags, tmpstr); /* get the macrostring */ if (flags) { /* check special flags */ /* in local COMMAND mode, none of the special keys do anything */ /* $$$ (although we might want the keypad in numeric mode allways) */ return FALSE; } /* send key macro string */ writecb(tmpstr); return TRUE; } for (i = 0; i < NUMOFMODS; i++) { /* shift what to look for into high byte */ theModBits = modtable[i].modbits << 4; len = strlen (modtable[i].prefix); if ((theModBits || len) && ((theModBits & modCode) == (theModBits & keyModifierMask))) { /* send prefix if there is one */ if (len) { /* PWP: these are saved as Pascal strings now */ BlockMove (modtable[i].prefix, tmpstr, (modtable[i].prefix[0] + 1)); writecb(tmpstr); /* put in console buffer */ if (duplex != 0) printps(termw,tmpstr); /* echo it locally */ } /* * get the unmodified ASCII code if the unmodify action bit is * active */ if (theModBits & UnmodMask) c = DeModifyChar ((long) ((evt->message & myKeyCodeMask) >> 8), (long) (modCode & shiftKey)); /* PWP: we pass through the shiftedness of this key */ else c = evt->message & charCodeMask; /* otherwise get the * standard char */ /* make an uppercase character if the caps action bit is active */ if ((theModBits & CapsMask) && islower (c)) c = toupper (c); /* make a control character if the control action bit is active */ if (theModBits & CtrlMask) c &= ctrlCodeMask; /* PWP: for Meta characters (yes, I use Emacs) */ if (theModBits & MetaMask) c |= metaOrBits; writecbc(c); return TRUE; } /* if */ } /* for */ /* get the ASCII code and send it */ writecbc(evt->message & charCodeMask); return TRUE; } /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /* general rectangle routines */ /****************************************************************************/ /****************************************************************************/ /* * Routine makerect * * Make a rectangle in r starting on line lin and column col extending * numlin lines and numcol characters. * */ /****************************************************************************/ void makerect(struct termw *termw, Rect *r,int lin, int col, int numlin, int numcol) { r->top = lin * termw->lineheight + TOPMARGIN; r->left = col * termw->charwidth + LEFTMARGIN; r->bottom = r->top + numlin * termw->lineheight; r->right = r->left + numcol * termw->charwidth; } /* makerect */ /* the (almost) inverse of makerect() */ void recttocharpos(struct termw *termw, Rect *r, int *toplin_p, int *leftcol_p, int *botlin_p, int *rightcol_p) { /* Inverse of makerect(): find the bounding chars (rounding outward) */ *toplin_p = (r->top - TOPMARGIN) / termw->lineheight; *botlin_p = (r->bottom - TOPMARGIN + termw->lineheight - 1) / termw->lineheight; *leftcol_p = (r->left - LEFTMARGIN) / termw->charwidth; *rightcol_p = (r->right - LEFTMARGIN + termw->charwidth - 1) / termw->charwidth; /* bounds limit it to the actual screen area */ if (*toplin_p < 0) *toplin_p = 0; if (*botlin_p > termw->screensize) *botlin_p = termw->screensize; if (*leftcol_p < 0) *leftcol_p = 0; if (*rightcol_p > MAXCOL) *rightcol_p = MAXCOL; } /* (PWP) do what makerect does, then invert the rect */ void invertchars(struct termw *termw, int lin, int col, int numlin, int numcol) { Rect r; r.top = lin * termw->lineheight + TOPMARGIN; r.left = col * termw->charwidth + LEFTMARGIN; r.bottom = r.top + numlin * termw->lineheight; r.right = r.left + numcol * termw->charwidth; InvertRect (&r); } /* * Figure out how wide this line could be. Not constant any more because of * double width lines. */ int line_maxcol(struct termw *termw, int lin) { if (termw->line_attrs[lin] != VT_SNGL) return (MAXCOL / 2); else return (MAXCOL); } /****************************************************************************/ /* Connect support routines */ /****************************************************************************/ void term_new_font (struct termw *termw) { FontInfo fi; GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); SetFontLock(false); termw->font_is_locked = false; TextFont(termw->current_font); /* make sure to set this font */ TextSize(termw->current_size); GetFontInfo (&fi); termw->lineheight = fi.ascent + fi.descent + fi.leading; termw->chardescent = fi.descent; /* termw->charwidth = fi.widMax; */ termw->charwidth = CharWidth('W'); /* idea from NCSA telnet 2.3 */ SetPort (savePort); /* there just has to be a better way */ } /* consetup is called once at startup */ struct termw *consetup (int boxid) { struct termw *termw; GrafPtr savePort; extern struct termw *termwl; termw = (struct termw *)malloc(sizeof(struct termw)); if (!termw) macfatal("consetup: no memory for terminal window", 0); bzero((char *)termw, sizeof(struct termw)); termw->next = termwl; /* add to list */ termwl = termw; termw->current_font = VT100FONT; termw->current_size = 9; termw->scroll_drawn = -1; /* mark scroll bar invalid */ termw->oldlin = -1; termw->from_lin = -1; termw->screensize = INIT_SCREENSIZE; /* number of lines on screen */ termw->graphicsinset[0] = ASCII_SET; termw->graphicsinset[1] = ASCII_SET; termw->graphicsinset[2] = LAT1_SET; termw->graphicsinset[3] = LAT1_SET; termw->Gr_set = 1; /* (PWP) current chosen RH set */ termw->old_Gl_set = -1; /* set to come back to after */ /* single shift GL */ termw->autowrap = TRUE; /* Autowrap on by default */ termw->autorepeat = TRUE; /* (UoR) auto repeat flag */ termw->dispcontchar = TRUE; /* do not show control characters */ termw->blockcursor = TRUE; /* show block or underline cursor */ termw->cursor_shown = TRUE; /* (PWP) show the cursor */ termw->blinkcursor = TRUE; /* true if we make the cursor blink */ termw->charflg = CF_OUTC; /* state variable */ setWindowLoc(boxid); #ifdef notdef termw->window = GetNewWindow (boxid, (Ptr) &termw->terminalWRec, (WindowPtr) -1L); #endif termw->window = GetNewWindow (boxid, (Ptr) 0L, (WindowPtr) -1L); if (!termw->window) macfatal("Could not GetNewWindow() -- can't find window template", 0); GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); PenMode (srcCopy); /* (PWP) was patXor */ flushio (); /* Get rid of pending characters */ termw->current_font = VT100FONT; /* (UoR) Set initial font to VT100 */ termw->current_size = 9; if (termw->screeninvert) TextMode (srcBic); else TextMode (srcOr); TextFace (0); /* PWP: be safe. We allways stay like this */ init_term(termw); /* Set up some terminal variables */ /* reset the font (chosen above) */ term_new_font(termw); /* doesn't change #lines, but size of a line has changed */ grow_term_to(termw,termw->screensize); /* normal char mode, home cursor, clear screen, and save position */ norm_home_clear_save(termw); cursor_draw(termw); /* (UoR) be sure to draw it */ SetPort (savePort); /* there just has to be a better way */ return termw; } /* consetup */ void term_reset (struct termw *termw) { GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); PenMode (srcCopy); /* (PWP) was patXor */ flushio (); /* Get rid of pending characters */ screen_to_bottom(termw); /* slide the visible region to active area */ termw->graphicsinset[0] = ASCII_SET; termw->graphicsinset[1] = GRAF_SET; termw->Gl_set = 0; termw->Gr_set = 1; termw->textstyle = 0; termw->current_style = 0; termw->draw_sing_chars = 0; termw->font_is_locked = FALSE; termw->screeninvert = FALSE; /* (UoR) inverted screen flag */ termw->insert = FALSE; termw->newline = FALSE; /* (UoR) linefeed mode by default */ termw->autowrap = TRUE; /* Autowrap on by default */ termw->relorigin = FALSE; /* (UoR) relative origin off */ termw->autorepeat = TRUE; /* (UoR) auto repeat flag */ termw->appl_mode = FALSE; /* (PWP) keypad application mode */ termw->curskey_mode = FALSE; /* (PWP) cursor key application mode */ termw->smoothscroll = FALSE; /* do smooth scrolling (PWP: or not) */ termw->scroll_amount = 0; /* no pending scroll */ termw->refresh_amount = 0; /* no pending refresh */ termw->dispcontchar = TRUE; /* do not show control characters */ termw->blockcursor = TRUE; /* show block or underline cursor */ termw->cursor_shown = TRUE; /* (PWP) show the cursor */ termw->mouse_arrows = FALSE; /* mouse down in screen does arrow keys */ termw->visible_bell = FALSE; /* true if we do blink instead of bell */ termw->eightbit_disp = FALSE; /* default to 7 bits */ termw->blinkcursor = TRUE; /* true if we make the cursor blink */ termw->have_selection = FALSE; /* (PWP) we have no selected text */ termw->saved_tlin = 0; termw->saved_blin = 0; termw->current_font = VT100FONT; /* (UoR) Set initial font to VT100 */ termw->current_size = 9; termw->scroll_drawn = -1; /* mark scroll bar invalid */ if (termw->screeninvert) TextMode (srcBic); else TextMode (srcOr); TextFace (0); /* PWP: be safe. We allways stay like this */ /* reset the font (chosen above) */ term_new_font(termw); /* doesn't change #lines, but size of a line has changed */ grow_term_to(termw,termw->screensize); /* normal char mode, home cursor, clear screen, and save position */ norm_home_clear_save(termw); cursor_draw(termw); /* (UoR) be sure to draw it */ SetPort (savePort); /* there just has to be a better way */ } /* consetup */ /****************************************************************************/ /****************************************************************************/ /*************************************************/ /* cursor drawing stuff */ /*************************************************/ Boolean cursor_rect (struct termw *termw, int line, int col, Rect *r) { /* if cursor not on screen */ if (line - termw->display_topline >= termw->screensize) return FALSE; if (col >= 80) /* make it look like a VT100 */ col = 79; /* Get character rectangle */ makerect(termw,r, line - termw->display_topline, col, 1, 1); if (!termw->blockcursor) { r->top = r->bottom; r->bottom = r->top + 2; } return TRUE; } /* cursor_rect */ void cursor_draw (struct termw *termw) { Rect r; GrafPtr savePort; if (!termw->cursor_shown) /* (PWP) not if we are hiding cursor */ return; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); if (!termw->cursor_invert) { if (cursor_rect(termw,termw->curlin, termw->curcol, &r)) { if (termw->in_front) { InvertRect (&r); } else { PenMode (patXor); FrameRect (&r); PenMode (patCopy); } } } /* replace mouse cursor */ if ((termw->oldlin >= 0) && (!termw->mousecurs_drawn)) { makerect(termw ,&r, termw->oldlin, termw->oldcol, 1, 1); PenMode (patXor); FrameRect (&r); PenMode (patCopy); termw->mousecurs_drawn = TRUE; } termw->cursor_invert = TRUE; termw->cur_drawn = TRUE; SetPort (savePort); /* there just has to be a better way */ } /* cursor_draw */ void cursor_erase (struct termw *termw) { Rect r; GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); if (termw->cursor_invert) { if (cursor_rect(termw, termw->curlin, termw->curcol, &r)) { if (termw->in_front) { InvertRect (&r); } else { PenMode (patXor); FrameRect (&r); PenMode (patCopy); } } } /* remove mouse cursor */ if ((termw->oldlin >= 0) && (termw->mousecurs_drawn)) { makerect(termw ,&r, termw->oldlin, termw->oldcol, 1, 1); PenMode (patXor); FrameRect (&r); PenMode (patCopy); termw->mousecurs_drawn = FALSE; } termw->cursor_invert = FALSE; termw->cur_drawn = FALSE; SetPort (savePort); /* there just has to be a better way */ } /* cursor_erase */ void flash_cursor (struct termw *termw) { register long tc; Rect r; GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); tc = TickCount (); if (((tc - termw->last_flash) > MyCaretTime) || (tc - termw->last_flash) < 0L) { termw->last_flash = tc; if (termw->cur_drawn) { if (cursor_rect(termw,termw->curlin, termw->curcol, &r)) { /* PWP: only blink if asked for */ if (termw->blinkcursor && termw->in_front) { InvertRect (&r); termw->cursor_invert = !termw->cursor_invert; } else if (!termw->cursor_invert) { /* make sure that the cursor shows up */ if (termw->in_front) { InvertRect (&r); } else { PenMode (patXor); FrameRect (&r); PenMode (patCopy); } termw->cursor_invert = TRUE; } } } } SetPort (savePort); /* there just has to be a better way */ } /* flash_cursor */ /****************************************************************************/ /* PWP -- like waitasec(), but don't get any characters. Used for visable bell. */ /****************************************************************************/ waitnoinput () { long ticks = 2, end_time; Delay (ticks, &end_time); /* pause for 1/30th second */ } /* waitnoinput */ /****************************************************************************/ /* (UoR) get any characters, and pause for a while */ /****************************************************************************/ waitasec (struct termw *termw) { waitnoinput(); inpchars(termw); } /* waitasec */ /****************************************************************************/ /* updateCursor -- taken from NCSA Telnet for the Macintosh, v 2.2 */ /****************************************************************************/ void updateCursor (struct termw *termw, int force, WindowPeek myfrontwindow) { static Point lastPoint; static int optwasdown = 0; Cursor *thisCursor; int optDown; KeyMap allthekeys; /* Someplace to put the keymap */ char *cp_allthekeys = (char *) &allthekeys; /* $$$ HACK HACK */ int newlin, newcol; Point MousePt; Rect r; GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); GetMouse(&MousePt); GetKeys(allthekeys); optDown = cp_allthekeys[7] & 4; /* should be symbolic */ if ( (!force) && (!in_background) && (MousePt.v == lastPoint.v) && (MousePt.h == lastPoint.h) && (optDown == optwasdown)) { SetPort (savePort); return; } if (force) lastCursor=0L; if (in_background) { lastCursor = 0L; /* allways force if in background */ thisCursor = normcurs; /* default cursor shape */ } else if (protocmd != 0) { /* if doing a transfer */ thisCursor = watchcurs; /* in forground and doing a transfer */ } else if (((myfrontwindow == (WindowPeek) termw->window) || ((myfrontwindow == NIL) && (FrontWindow() == termw->window))) && PtInRect(MousePt, &termw->ScreenRect)) { if (termw->mouse_arrows || optDown) { newlin = (MousePt.v - TOPMARGIN) / termw->lineheight; newcol = (MousePt.h - LEFTMARGIN + termw->charwidth/2) / termw->charwidth; if ((termw->oldlin != newlin) || (termw->oldcol != newcol)) { PenMode (patXor); /* For FrameRect calls */ if (termw->oldlin >= 0) { /* if old rectangle */ if (termw->mousecurs_drawn) { makerect(termw,&r, termw->oldlin, termw->oldcol, 1, 1); FrameRect (&r); } } else { /* else if drawing for the first time */ HideCursor (); } makerect(termw,&r, newlin, newcol, 1, 1); FrameRect (&r); PenMode (patCopy); /* reset to normal pen mode */ termw->oldlin = newlin; termw->oldcol = newcol; termw->mousecurs_drawn = TRUE; } lastPoint=MousePt; optwasdown=optDown; SetPort (savePort); /* there just has to be a better way */ return; } else { thisCursor = textcurs; } } else { thisCursor = normcurs; /* default cursor shape */ } if (lastCursor!= thisCursor) { SetCursor(thisCursor); lastCursor = thisCursor; } lastPoint=MousePt; optwasdown=optDown; if (termw->oldlin >= 0) { /* if we hade drawn a movement outline */ if (termw->mousecurs_drawn) { PenMode (patXor); /* For FrameRect calls */ makerect(termw,&r, termw->oldlin, termw->oldcol, 1, 1); FrameRect (&r); } termw->oldlin = -1; termw->mousecurs_drawn = FALSE; ShowCursor (); PenMode (patCopy); /* reset to normal pen mode */ } SetPort (savePort); /* there just has to be a better way */ } /****************************************************************************/ /* Put characters onto the actual screen */ /****************************************************************************/ static int to_mac_style[] = { normal, underline, italic, underline|italic, bold|condense, bold|condense|underline, bold|condense|italic, bold|condense|underline|italic }; /****************************************************************************/ /* flushbuf(termw) -- draw all the buffered characters on the screen */ /****************************************************************************/ void flushbuf (struct termw *termw) { register int scrl_amt; if (termw->out_maxcol == 0) return; /* Nothing to flush */ if (to_printer) { /*JAO*/ #ifdef COMMENT /* This is the old stuff that should go away */ for (i = termw->out_mincol; i < termw->out_maxcol; i++) { (*hPrintBuffer)[lPrintBufferAt++] = termw->scr[termw->curlin+termw->display_topline][i]; if (lPrintBufferAt == lPrintBufferSize) lPrintBufferAt = 0L; lPrintBufferChars++; if (lPrintBufferChars == 1L) updatepstat(); if (lPrintBufferChars == lPrintBufferSize) { overflowingDialog = GetNewDialog(OVERFLOWINGBOXID, NILPTR, (WindowPtr) - 1); DrawDialog(overflowingDialog); break; /* PWP */ } } #endif /* COMMENT */ /* And this is the new way */ add_to_print (termw->out_maxcol - termw->out_mincol, (char *) termw->scr[termw->curlin+termw->display_topline] + termw->out_mincol); } if (!to_screen) { termw->out_maxcol = 0; /* Say no more chars to output */ return; /*JAO*/ } /* save because flushscroll() resets scroll_amount */ scrl_amt = termw->scroll_amount; #ifdef COMMENT if (scrl_amt) { /* * If we have pending scrolling, and we are about to draw outside * of the region that will be refreshed when the scrolling happens, * do the scrolling now. */ if ((termw->refresh_amount < 0) && ((termw->curlin < termw->saved_blin + termw->refresh_amount) || (termw->curlin > termw->saved_blin))) { flushscroll(termw); } else if ((termw->refresh_amount > 0) && ((termw->curlin < termw->saved_tlin) || (termw->curlin > termw->saved_tlin + termw->refresh_amount))) { flushscroll(termw); } else { termw->out_maxcol = 0; /* Say no more chars to output */ return; } } #endif /* COMMENT */ if (scrl_amt) flushscroll(termw); if (termw->have_selection) maybe_nuke_selection (termw, termw->curlin, termw->curlin); if (!termw->out_maxcol) /* if already drawn this line, return */ return; /* * PWP: Why have two routines to do the same thing? I centralized * all the font crap into draw_line_w_attrs so I didn't need * to keep track of code here too. Side benifit -- we can nuke * the outbuf array. * * Note that in draw_line_w_attrs(), the left and right columns are * SCREEN columns, not virtual buffer columns. Theses are usually * the same, unless we happen to be drawing onto a double-width line. */ if (termw->line_attrs[termw->curlin] == VT_SNGL) { /* single-width (normal) line */ draw_line_w_attrs(termw, termw->curlin + termw->display_topline, termw->curlin, termw->out_mincol, termw->out_maxcol, (scrl_amt == 0)); } else { /* line with double width characters */ draw_line_w_attrs(termw, termw->curlin + termw->display_topline, termw->curlin, 2 * termw->out_mincol, 2 * termw->out_maxcol, (scrl_amt == 0)); } termw->out_maxcol = 0; /* Say no more chars to output */ } /* flushbuf */ /****************************************************************************/ /* set_style(termw, style) - set the correct stuff for displaying chars in style */ /****************************************************************************/ void set_style (struct termw *termw, int style) { int m_sty, m_font; static int o_sty = 0, o_font = 0; if (style == termw->current_style) return; termw->current_style = style; m_sty = to_mac_style[style & STY_MSTY]; m_font = ((style & STY_FONT) >> 3) + termw->current_font; termw->draw_sing_chars = ((style & VT_BLINK) || (CharWidth('W')!=CharWidth('i')) || (!RealFont(termw->current_font, termw->current_size))); /* printerr("draw_sing_chars == ", draw_sing_chars); */ if (!have_128roms && (m_sty & bold)) { /* if on an old mac and bolding */ if (m_font == VT100FONT) { m_font = VT100BOLD; m_sty &= ~(bold|condense); } else { termw->draw_sing_chars = 1; } } if (m_font != o_font) { TextFont (m_font); /* new font */ o_font = m_font; } if (m_sty != o_sty) { TextFace (m_sty); /* new text face */ o_sty = m_sty; } } /**************************************************************************** * draw_line_w_attrs() -- draw the line including all character attributes * that is in the terminal buffer at line "lin" onto the screen at vertical * character offset "v", in as little time as possible. * * It seems to speed things up just a tad to skip leading and trailing * whitespace on the line, so we can draw only the characters in the middle. * On the other hand, it doesn't save any time to find the individual words * and draw just those. Likewise, if we have to draw the line one character * at a time it is really slow. * * Perhaps a later version of Kermit could take the current fonts and build * custom set of fixed width fonts (a'la BitFont), and then use that to draw * characters onto the screen. * * Another later addition could be correct handling of double width and double * height characters, by drawing the characters into an off-screen bitmap, * and then using CopyBits to stretch the characters to fit. */ void draw_line_w_attrs (struct termw *termw, register int lin, register int v, register int l_col, register int r_col, int must_drawblanks) { register int o, i, j, sty; register unsigned char *cp, *ap, *line_ch, *line_at; register int min, max; register int lines_attrs; int orig_l_col; Rect r; if (!termw) DebugStr("\ptermw == NULL"); /* this routine CAN be called with scrolling_region non-zero */ /* bounds limit the min and max columns */ if (l_col < 0) l_col = 0; if (l_col > MAXCOL) l_col = MAXCOL; if (r_col < 0) r_col = 0; if (r_col > MAXCOL) r_col = MAXCOL; /* if nothing to do, don't bother */ if ((r_col == 0) || (l_col == r_col)) return; /***** I shouldn't have to put this here! *****/ if (termw->screeninvert) { BackPat(qd.black); PenPat(qd.white); TextMode (srcBic); } else { BackPat(qd.white); PenPat(qd.black); TextMode (srcOr); } if ((v < 0) || (v > termw->screensize)) printerr("draw_line_w_attrs, v out of range:", v); line_ch = termw->scr[lin]; line_at = termw->scr_attrs[lin]; lines_attrs = (int) termw->line_attrs[lin]; if (lines_attrs != VT_SNGL) { /* double width lines have half as many characters (duh!) */ orig_l_col = l_col; l_col /= 2; r_col = (r_col + 1) / 2; /* round out to next highest */ } /* * find the last character that is not a plain space character */ sty = 0; /* the style for normal blank space */ cp = line_ch + r_col-1; ap = line_at + r_col-1; for (max = r_col-1; max >= l_col; max--) { /* PWP: we should never see a NUL in the line here */ if ((*cp-- != ' ') || (*ap-- != sty)) break; } max++; /* point to one after the last non-space character */ if (max > r_col) max = r_col; /* * find the first character that is not a plain space character */ sty = 0; /* the style for normal blank space */ cp = line_ch + l_col; ap = line_at + l_col; for (min = l_col; min < max; min++) { /* PWP: we should never see a NUL in the line here */ if ((*cp++ != ' ') || (*ap++ != sty)) break; } /* If there is anything to erase, erase it */ if (must_drawblanks) { if (lines_attrs == VT_SNGL) makerect(termw,&r, v, l_col, 1, r_col-l_col); else makerect(termw,&r, v, (2 * l_col), 1, 2 * (r_col-l_col)); EraseRect (&r); } /* A slight speedup -- tell the Mac not to remove this font from RAM */ if (!termw->font_is_locked) { SetFontLock(true); termw->font_is_locked = true; } if (lines_attrs == VT_SNGL) { /* * loop through all the characters up to max, looking for the longest * string of characters all of the same style. Draw them, switch * styles, and repeat until max. */ sty = line_at[min]; o = min; i = min; while (i <= max) { /* if this style != current style */ if ((line_at[i] != sty) || (i == max)) { if (sty != termw->current_style) set_style(termw, sty); if (termw->draw_sing_chars) { /* * We can't just increment o here because we may need * it to correctly draw the inverse video rect (below). */ for (j = o, cp = line_ch + o; j < i; j++, cp++) { MOVETOCHAR(j, v); DrawChar((short) (*cp & 0377)); } } else { /* non-blinking */ MOVETOCHAR(o, v); DrawText (line_ch, (short) o, (short) i-o); /* Output this part */ } if (sty & VT_INVERT) { makerect(termw,&r, v, o, 1, i-o); InvertRect (&r); } o = i; /* now left extent == current */ sty = line_at[i]; /* new current style */ } i++; } } else { #undef OFFSCREEN_STRETCHED_CHARS /* because this code doesn't work */ #ifdef OFFSCREEN_STRETCHED_CHARS RgnHandle clip_rgn = NewRgn(); Rect offRect; Rect src_r, dest_r; GrafPtr oldPort; GrafPort offScreen; /* allocate our off-screen bitmap */ GetPort(&oldPort); OpenPort(&offScreen); /* Make our off-screen bitmap the size of one line (plus a little) */ offRect.top = 0; offRect.left = 0; offRect.bottom = termw->lineheight + TOPMARGIN + 2; offRect.right = termw->charwidth + LEFTMARGIN + 2; offScreen.portRect = offRect; offScreen.portBits.bounds = offRect; SetRectRgn(offScreen.visRgn, 0, 0, offRect.right, offRect.bottom); SetRectRgn(offScreen.clipRgn, 0, 0, offRect.right, offRect.bottom); /* rowBytes is the size of a row, rounded up to an even number */ /* of bytes */ offScreen.portBits.rowBytes = (((offScreen.portBits.bounds.right - offScreen.portBits.bounds.left) + 15) >> 4) << 1; /* number of bytes in BitMap is rowBytes * number of rows */ /* this calculation must be down with longs */ offScreen.portBits.baseAddr = NewPtr((long) offScreen.portBits.rowBytes * (long) (offScreen.portBits.bounds.bottom - offScreen.portBits.bounds.top)); if (!offScreen.portBits.baseAddr) /* we didn't get the memory */ return; /* just forget it */ /* * We are drawing double-width (and maybe double height) chars. * * First, draw the line normally, but starting at the * real position of original the original value of l_col. */ SetPort (&offScreen); BackPat(qd.white); PenPat(qd.black); TextMode (srcOr); EraseRect(&qd.thePort->portRect); /* erase just in case */ o = 0; cp = line_ch + min; ap = line_at + min; termw->current_style = 0xFFFF; /* force set_style to set */ set_style(termw, *ap); /* CHECK THIS */ for (i = min; i <= max; i++) { if (*ap != termw->current_style) set_style(termw, *ap); MOVETOCHAR(o, 0); /* line 0 of off-screen port */ DrawChar((short) (*cp & 0377)); if (*ap & VT_INVERT) { makerect(termw,&r, v, o, 1, 1); InvertRect (&r); } o++; cp++; ap++; } /* set the output port back to the screen */ SetPort(oldPort); termw->current_style = 0xFFFF; /* force set_style to set again */ /* Next, stretch the characters using a CopyBits() */ /* find the clipping region */ makerect(termw, &r, v, (2 * l_col), 1, 2 * (r_col-l_col)); RectRgn (clip_rgn, &r); FillRgn (clip_rgn, qd.gray); /* compute the source rect (where we just drew characters into) */ r = offScreen.portRect; r.right = (max-min+1) * termw->charwidth; /* * Compute the dest rect. This also defines how we stretch * the characters out to be double width. */ if (lines_attrs == VT_DBLH_T) { makerect(termw, &dest_r, v, ((2 * l_col) + (min - l_col)), 2, (2 * (max-min+1))); } else if (lines_attrs == VT_DBLH_B) { makerect(termw, &dest_r, (v-1), ((2 * l_col) + (min - l_col)), 2, (2 * (max-min+1))); } else { /* lines_attrs == VT_DBLW */ makerect(termw, &dest_r, v, ((2 * l_col) + (min - l_col)), 1, (2 * (max-min+1))); } makerect(termw, &dest_r, v, (2 * min), 1, (1 * (max-min+1))); makerect(termw, &src_r, 0, min, 1, (max-min+1)); /* now stretch those bits */ CopyBits (&offScreen.portBits, &qd.thePort->portBits, &src_r, &dest_r, ((termw->screeninvert) ? notSrcCopy : srcCopy), clip_rgn); /* clean up */ DisposeRgn(clip_rgn); ClosePort(&offScreen); #else /* !OFFSCREEN_STRETCHED_CHARS */ /* draw the double width line as double spaced characters */ o = min; cp = line_ch + min; ap = line_at + min; for (i = min; i <= max; i++) { if (*ap != termw->current_style) set_style(termw, *ap); MOVETOCHAR((2 * o), v); DrawChar((short) (*cp & 0377)); if (*ap & VT_INVERT) { makerect(termw,&r, v, (2 * o), 1, 2); InvertRect (&r); } o++; cp++; ap++; } #endif /* !OFFSCREEN_STRETCHED_CHARS */ } } /* draw_line_w_attrs() */ /****************************************************************************/ /****************************************************************************/ void scroll_term (struct termw *termw) { register int new_topline, delta, lin, i; int fl, fc, tl, tc; Rect r; /* cannot be register */ new_topline = termw->screensize - termw->display_totlines + GetCtlValue (termw->t_vscroll); if ((new_topline > 0) || (new_topline < termw->screensize - MAX_SCREENSIZE)) { printerr("BUG: in scroll_term(), new_topline out of range:", new_topline); return; } if ((delta = (termw->display_topline - new_topline)) == 0) return; /* we didn't move */ makerect(termw,&r, 0, 0, termw->screensize, MAXCOL); /* if whole screen */ if ((delta >= termw->screensize) || (-delta >= termw->screensize)) { EraseRect(&r); lin = new_topline; /* new top line */ for (i = 0; i < termw->screensize; i++) { draw_line_w_attrs(termw, lin, i, 0, MAXCOL, 0); lin++; } termw->display_topline = new_topline; if (termw->have_selection) invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); return; /* we are done */ } /* if we get here, we are not doing the whole screen */ ScrollRect (&r, 0, delta * termw->lineheight, dummyRgn); if (delta > 0) { /* scrolling down (pushing top arrow) */ lin = new_topline; /* new top line */ for (i = 0; (i < delta) && (i < termw->screensize); i++) { draw_line_w_attrs(termw, lin, i, 0, MAXCOL, 0); lin++; } termw->display_topline = new_topline; if (termw->have_selection && (termw->from_lin < termw->display_topline + delta) && (termw->to_lin >= termw->display_topline)) { if (termw->from_lin < termw->display_topline) { fl = termw->display_topline; fc = 0; } else { fl = termw->from_lin; fc = termw->from_col; } if (termw->to_lin >= termw->display_topline + delta) { tl = termw->display_topline + delta - 1; tc = MAXCOL; } else { tl = termw->to_lin; tc = termw->to_col; } invert_text(termw, fl, fc, tl, tc); } } else { /* scrolling up (pushing bottom arrow) */ /* one past old bottom line*/ lin = termw->display_topline + termw->screensize; /*********** PWP: delta is negative here ****************/ i = termw->screensize + delta; if (i < 0) i = 0; /* bounds */ while (i < termw->screensize) draw_line_w_attrs(termw, lin++, i++, 0, MAXCOL, 0); termw->display_topline = new_topline; if (termw->have_selection && (termw->from_lin < (termw->display_topline + termw->screensize)) && (termw->to_lin >= (termw->display_topline + termw->screensize + delta))) { /* * If selection is partially off the top, * clip display of region at top */ if (termw->from_lin < termw->display_topline + termw->screensize + delta) { fl = termw->display_topline + termw->screensize + delta; fc = 0; } else { fl = termw->from_lin; fc = termw->from_col; } /* * If selection is partially off the top, * clip display of region at top. */ if (termw->to_lin >= termw->display_topline + termw->screensize) { tl = termw->display_topline + termw->screensize - 1; tc = MAXCOL; } else { tl = termw->to_lin; tc = termw->to_col; } invert_text(termw, fl, fc, tl, tc); } } } static pascal void doscroll (WHICHCONTROL, THECODE) ControlHandle WHICHCONTROL; short THECODE; { register int amount = 0, val, max; struct termw *termw; if (FrontWindow() == ctermw->window) termw = ctermw ; else if (FrontWindow() == ttermw->window) termw = ttermw ; else return; if (THECODE == inUpButton) amount = -1; if (THECODE == inDownButton) amount = 1; if (amount == 0) return; val = GetCtlValue (WHICHCONTROL) + amount; max = GetCtlMax (WHICHCONTROL); if ((val >= 0) && (val <= max)) { SetCtlValue (WHICHCONTROL, val); scroll_term(termw); } } /* doscroll */ /****************************************************************************/ /* we move the displayed region to the bottom when we recieve characters */ /****************************************************************************/ screen_to_bottom (struct termw *termw) { if (termw->display_topline != toplin) { SetCtlValue (termw->t_vscroll, termw->display_totlines - termw->screensize); scroll_term(termw); } } /****************************************************************************/ /* update_vscroll - adjust the scaling of the vertical scroll bar, or */ /* disable it if we havn't saved anything back yet */ /****************************************************************************/ update_vscroll (struct termw *termw) { short s; s = termw->display_totlines-termw->screensize; if (s != GetCtlMax (termw->t_vscroll)) SetCtlMax (termw->t_vscroll, s); if (s != GetCtlValue (termw->t_vscroll)) SetCtlValue (termw->t_vscroll, s); if (termw->in_front && termw->display_totlines > termw->screensize) { if (termw->scroll_drawn != 1) { HiliteControl (termw->t_vscroll, 0); termw->scroll_drawn = 1; } } else { if (termw->scroll_drawn != 0) { HiliteControl (termw->t_vscroll, 255); termw->scroll_drawn = 0; } } } /****************************************************************************/ /****************************************************************************/ void t_pagescroll (struct termw *termw, int code, int amount, ControlHandle ctrlh) { Point myPt; register int val, max; max = GetCtlMax (ctrlh); val = GetCtlValue (ctrlh); do { GetMouse (&myPt); if (TestControl (ctrlh, myPt) != code) continue; val += amount; if (val < 0) val = 0; if (val > max) val = max; SetCtlValue (ctrlh, val); scroll_term(termw); } while (StillDown ()); } /* pagescroll */ termmouse (struct termw *termw, EventRecord *evt) { int actrlcode; ControlHandle acontrol; GrafPtr savePort; GetPort (&savePort); /* save the current port */ SetPort (termw->window); GlobalToLocal (&evt->where);/* convert to local */ if (termw->mouse_arrows || (evt->modifiers & optionKey)) { /* In terminal content? */ if (PtInRect (evt->where, &termw->ScreenRect)) { mouse_cursor_move(termw, evt); SetPort (savePort); /* restore previous port */ return; /* yes, do mouse stuff */ } } cursor_erase(termw); actrlcode = FindControl (evt->where, termw->window, &acontrol); switch (actrlcode) { case inUpButton: case inDownButton: (void) TrackControl (acontrol, evt->where, (ProcPtr) doscroll); break; case inPageUp: t_pagescroll (termw, actrlcode, -(termw->screensize/2), acontrol); break; case inPageDown: t_pagescroll (termw, actrlcode, (termw->screensize/2), acontrol); break; case inThumb: (void) TrackControl (acontrol, evt->where, (ProcPtr) NIL); scroll_term(termw); break; case 0: /* in the window content itself */ mouse_region_select(termw, evt); break; } /* MOVETOCHAR(termw->curcol, termw->curlin - termw->display_topline); */ cursor_draw(termw); SetPort (savePort); /* restore previous port */ } /* * dir is 'A' (up), 'B' (down), 'C' (right), or 'D' (left) */ void do_arrow(struct termw *termw, unsigned char dir) { OutputChar(termw, '\033'); /* ESC */ if (termw->curskey_mode) OutputChar(termw, 'O'); /* SS3 */ else OutputChar(termw, '['); /* CSI */ OutputChar(termw, dir); } /* char to send is n + ',' */ void do_keypad (struct termw *termw, int n) { if (termw->appl_mode) { OutputChar(termw, '\033'); /* ESC */ OutputChar(termw, 'O'); /* SS3 */ OutputChar(termw, (unsigned char) n + 'l'); } else { OutputChar(termw, (unsigned char) n + ','); /* normal digit or glyph */ } } /* pf1 == 0 ... pf4 == 3 */ void do_pfkey(struct termw *termw, int n) { OutputChar(termw, '\033'); /* ESC */ OutputChar(termw, 'O'); /* SS3 */ OutputChar(termw, (unsigned char) n + 'P'); } void do_keyenter(struct termw *termw) { if (termw->appl_mode) { OutputChar(termw, '\033'); /* ESC */ OutputChar(termw, 'O'); /* SS3 */ OutputChar(termw, 'M'); } else { OutputChar(termw, '\015'); } } void mouse_cursor_move (struct termw *termw, EventRecord *evt) { int mouselin; int mousecol; int tempcol; int templin; int i; Point MousePt; MousePt = evt->where; mouselin = (MousePt.v - TOPMARGIN) / termw->lineheight; mousecol = (MousePt.h - LEFTMARGIN + termw->charwidth/2) / termw->charwidth; tempcol = termw->curcol; templin = termw->curlin; if (mousecol < tempcol) for (i = tempcol; i > mousecol; i--) { do_arrow (termw, leftARROW); waitasec (termw); /* If tabs are used, we may go too far, so end loop */ if (termw->curcol <= mousecol) i = mousecol; } if (mouselin < templin) for (i = templin; i > mouselin; i--) { do_arrow (termw, UPARROW); waitasec (termw); } else if (mouselin > templin) for (i = templin; i < mouselin; i++) { do_arrow (termw, DOWNARROW); waitasec (termw); } if (termw->curlin == mouselin) tempcol = termw->curcol; /* for short lines */ if (tempcol < mousecol) for (i = tempcol; i < mousecol; i++) { do_arrow (termw, rightARROW); waitasec (termw); /* If tabs are used, we may go too far, so end loop */ if (termw->curcol >= mousecol) i = mousecol; } } /* mouse_cursor_move */ void invert_text(struct termw *termw, int from_lin, int from_col, int to_lin, int to_col) { int t; if (from_lin > to_lin) { /* make from < to */ t = to_lin; to_lin = from_lin; from_lin = t; t = to_col; to_col = from_col; from_col = t; } /* if we are doing double width chars, the columns are twice as wide */ if (termw->line_attrs[from_lin] != VT_SNGL) from_col *= 2; if (termw->line_attrs[to_lin] != VT_SNGL) to_col *= 2; from_lin -= termw->display_topline; /* convert to screen coords */ if (from_lin < 0) { from_lin = 0; from_col = 0; } /* if down out of sight, forget it */ if (from_lin >= termw->screensize) return; to_lin -= termw->display_topline; /* convert to screen coords */ if (to_lin < 0) /* if up out of sight, forget it */ return; if (to_lin >= termw->screensize) { to_lin = termw->screensize-1; to_col = MAXCOL; } if (from_lin == to_lin) { /* if only one line */ if (from_col > to_col) { t = to_col; to_col = from_col; from_col = t; } if (from_col != to_col) /* then invert the characters in between */ invertchars(termw, from_lin, from_col, 1, to_col - from_col); } else { if (from_col < MAXCOL) invertchars(termw, from_lin, from_col, 1, MAXCOL - from_col); t = to_lin - from_lin - 1; if (t > 0) invertchars(termw, from_lin+1, 0, t, MAXCOL); if (to_col > 0) invertchars(termw, to_lin, 0, 1, to_col); } } int typeof_char(unsigned char c) { if ((c == ' ') || (c == '\240')) return (0); /* whitespace char */ if (((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '\300') && (c <= '\377') && (c != '\327') && (c != '\367')) || ((c >= '\271') && (c <= '\276') && (c != '\273')) || (c == '\262') || (c == '\263') || (c == '\252')) return (1); /* alpha-numeric char */ return (2); /* printing, non-alphanum char */ } int all_spaces (struct termw *termw, register int r, register int c) { register int i; for (i = c; i < line_maxcol(termw, r); i++) if ((termw->scr[r][i] != ' ') || (termw->scr_attrs[r][i] != 0)) return (0); /* found a non-space */ return (1); /* everything was spaces */ } void point_to_mouse_low_high (struct termw *termw, Point *MousePt_p, int n_clicks, int *mouselin_p, int *mousecol_p, int *mousecol_lp, int *mousecol_hp) { int real_lin, real_col; int ch_type, ch_attr; int i; real_lin = (MousePt_p->v-TOPMARGIN) / termw->lineheight + termw->display_topline; if (real_lin < termw->display_topline) real_lin = termw->display_topline; if (real_lin >= termw->display_topline + termw->screensize) real_lin = termw->display_topline + termw->screensize-1; *mouselin_p = real_lin; real_col = (MousePt_p->h - LEFTMARGIN + termw->charwidth/2) / termw->charwidth; if (real_col < 0) real_col = 0; if (real_col > MAXCOL) /* this is a real, not virtual, column */ real_col = MAXCOL; /* if on a double-width line, all columns are twice as wide */ if (termw->line_attrs[real_lin] != VT_SNGL) real_col /= 2; /* * We spoof things a bit here -- if the rest of the line is all blanks, * then we treat it as a single character (CRLF, really), and pretend * that the user clicked the mouse in the first blank character after all * text. */ if (all_spaces(termw,real_lin, real_col)) { for (i = real_col; i >= 0; i--) if ((termw->scr[real_lin][i] != ' ') || (termw->scr_attrs[real_lin][i] != 0)) break; real_col = i+1; if (real_col < 0) real_col = 0; if (real_col > line_maxcol(termw, real_lin)) real_col = line_maxcol(termw, real_lin); } *mousecol_p = real_col; if (n_clicks == 0) /* if a SINGLE click */ { *mousecol_lp = real_col; *mousecol_hp = real_col; } else if (n_clicks == 1) /* if a DOUBLE click */ { ch_type = typeof_char (termw->scr[real_lin][real_col]); ch_attr = termw->scr_attrs[real_lin][real_col]; for (i = real_col-1; i >= 0; i--) /* if a different type */ if ((typeof_char (termw->scr[real_lin][i]) != ch_type) /* or colored different */ || (termw->scr_attrs[real_lin][i] != ch_attr)) /* then it isn't the same kind of char */ break; *mousecol_lp = i+1; for (i = real_col+1; i < line_maxcol(termw, real_lin); i++) /* if a different type */ if ((typeof_char (termw->scr[real_lin][i]) != ch_type) /* or colored different */ || (termw->scr_attrs[real_lin][i] != ch_attr)) /* then it isn't the same kind of char */ break; *mousecol_hp = i; } else /* a TRIPLE click */ { *mousecol_lp = 0; *mousecol_hp = line_maxcol(termw, real_lin); } } void mouse_region_select (struct termw *termw, EventRecord *evt) { int mouselin; int mousecol_l, mousecol_h, real_mousecol; int i, shift, sval, smax; int old_from_lin, old_from_col, old_to_lin, old_to_col; Point MousePt; /* used for double-click determination */ static Point prev_mouse_point = {0, 0}; static long prev_mouse_up = 0L; static int n_clicks_here = 0; MousePt = evt->where; /* if no selection, then a shift drag is just a drag */ if (termw->have_selection) shift = (evt->modifiers) & shiftKey; else shift = 0; if (((evt->when - prev_mouse_up) <= GetDblTime()) && (ABS(MousePt.v - prev_mouse_point.v) < termw->lineheight) && (ABS(MousePt.h - prev_mouse_point.h) < termw->charwidth)) n_clicks_here = (n_clicks_here + 1) % 3; else n_clicks_here = 0; /* just one click */ prev_mouse_point = MousePt; /* save for next time */ prev_mouse_up = TickCount (); /* save when the mouse went up */ /* if not adding to region, remove old one */ if (!shift && termw->have_selection) invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); point_to_mouse_low_high(termw,&MousePt, n_clicks_here, &mouselin, &real_mousecol, &mousecol_l, &mousecol_h); if (shift) { /* * Swap from_* and to_* if closer to from. This sets the further-away * side as the anchor, and the closer one as the part we are changing. * * We aren't taking into account any double width lines here, but that * should be OK anyway (I hope) */ if (ABS((MAXCOL * termw->from_lin + termw->from_col) - (MAXCOL * mouselin + real_mousecol)) < ABS((MAXCOL * termw->to_lin + termw->to_col) - (MAXCOL * mouselin + real_mousecol))) { i = termw->to_lin; termw->to_lin = termw->from_lin; termw->from_lin = i; i = termw->to_col; termw->to_col = termw->from_col; termw->from_col = i; } } else { termw->from_lin = mouselin; termw->from_col = mousecol_l; termw->to_lin = mouselin; termw->to_col = mousecol_h; /* Select the text if a double or triple click. */ if (termw->from_col != termw->to_col) invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); } /* save in case we have to swap which point is the anchor */ old_from_lin = termw->from_lin; old_from_col = termw->from_col; old_to_lin = termw->to_lin; old_to_col = termw->to_col; while (StillDown()) { GetMouse(&MousePt); point_to_mouse_low_high(termw,&MousePt, n_clicks_here, &mouselin, &real_mousecol, &mousecol_l, &mousecol_h); /* * If above or below screen, auto-scroll the slider and select more. */ if (mouselin < termw->display_topline) { sval = GetCtlValue (termw->t_vscroll) - 1; smax = GetCtlMax (termw->t_vscroll); if ((sval >= 0) && (sval <= smax)) { SetCtlValue (termw->t_vscroll, sval); scroll_term(termw); } mouselin = termw->display_topline; real_mousecol = 0; } else if (mouselin >= termw->display_topline + termw->screensize) { sval = GetCtlValue (termw->t_vscroll) + 1; smax = GetCtlMax (termw->t_vscroll); if ((sval >= 0) && (sval <= smax)) { SetCtlValue (termw->t_vscroll, sval); scroll_term(termw); } mouselin = termw->display_topline + termw->screensize-1; real_mousecol = line_maxcol(termw, mouselin); } /* * If we are above the anchor, then the "interesting" side of the * click extent is mousecol_l, else it is mousecol_h. * * Again, we are not taking into account any intermediate double-width * lines, but hopefully that's OK. */ if ((MAXCOL * termw->from_lin + termw->from_col) > (MAXCOL * mouselin + real_mousecol)) { i = mousecol_l; /* "above" the anchor point */ /* but if we were below the anchor, restore and swap */ if ((MAXCOL * termw->from_lin + termw->from_col) < (MAXCOL * termw->to_lin + termw->to_col)) { /* Unselect current text. */ invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); termw->from_lin = old_to_lin; termw->from_col = old_to_col; termw->to_lin = old_from_lin; termw->to_col = old_from_col; /* Reselect new (old) text. */ invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); } } else { i = mousecol_h; /* "below" the anchor point */ /* but if we were above the anchor, restore and swap */ if ((MAXCOL * termw->from_lin + termw->from_col) > (MAXCOL * termw->to_lin + termw->to_col)) { /* Unselect current text. */ invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); termw->from_lin = old_from_lin; termw->from_col = old_from_col; termw->to_lin = old_to_lin; termw->to_col = old_to_col; /* Reselect new (old) text. */ invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); } } /* * If any new text was selected, invert it. */ if ((i != termw->to_col) || (mouselin != termw->to_lin)) { invert_text(termw, termw->to_lin, termw->to_col, mouselin, i); termw->to_lin = mouselin; termw->to_col = i; } } /* make from < to */ if ((MAXCOL * termw->from_lin + termw->from_col) > (MAXCOL * termw->to_lin + termw->to_col)) { i = termw->to_lin; termw->to_lin = termw->from_lin; termw->from_lin = i; i = termw->to_col; termw->to_col = termw->from_col; termw->from_col = i; } if ((termw->from_lin != termw->to_lin) || (termw->from_col != termw->to_col)) termw->have_selection = TRUE; else termw->have_selection = FALSE; /* * If the mouse wasn't down long enough to be a drag, time double click * from the mouse UP. */ if (((TickCount () - prev_mouse_up) <= GetDblTime()) && (ABS(MousePt.v - prev_mouse_point.v) < termw->lineheight) && (ABS(MousePt.h - prev_mouse_point.h) < termw->charwidth)) { prev_mouse_up = TickCount (); /* save when the mouse went up */ } } /* (PWP) if the selection is within [tlin,blin], then remove it */ void maybe_nuke_selection (struct termw *termw, int tlin, int blin) { int my_to_lin; if (!termw->have_selection) return; my_to_lin = termw->to_lin; if ((termw->to_col == 0) && (termw->from_lin != termw->to_lin)) my_to_lin--; if (!(((tlin < termw->from_lin) && (blin < termw->from_lin)) || ((tlin > my_to_lin) && (blin > my_to_lin))) ) { termw->have_selection = FALSE; invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); } } /* * Initialize the internal clipboard. */ void init_scr_clip() { /* check for multiple init */ if (myclip_h != NULL) { printerr("init_scr_clip(): internal clipboard already initialized!", 0); return; } myclip_h = (char **) NewHandle (256); myclip_size = 0; my_scrapcount = -1; } /* * Destroy internal clipboard. */ void destroy_scr_clip() { if (myclip_h) DisposHandle(myclip_h); myclip_h = NULL; } /* * Invalidate internal clip (for cut & copy from server window). */ void invalidate_scr_clip() { myclip_size = 0; my_scrapcount = -1; } /* * Copy the current selction to the (internal) clipboard. * * This is an external, but we don't have to save the GrafPort * because we don't do anything to the screen. */ scr_copy (struct termw *termw) { int lin, i, rcol; long sz; char *dp; ScrapStuff *pss; if (myclip_h == NIL) { printerr("scr_copy: clip handle not allocated", 0); return; } if (termw->have_selection) { /****** find out how big the text to copy is ******/ if (termw->from_lin == termw->to_lin) { /* * If we are copying to the end of line, we should really only copy * a CR instead of all those trailing blanks. So we must find out * where the last real character is. */ if (termw->to_col >= line_maxcol(termw, termw->to_lin)) { for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--) /* last */ if ((termw->scr[termw->to_lin][rcol-1] != ' ') || (termw->scr_attrs[termw->to_lin][rcol-1] != 0)) break; } else { rcol = termw->to_col; } sz = rcol - termw->from_col + 1; } else { for (rcol = line_maxcol(termw, termw->from_lin); rcol > termw->from_col; rcol--) /* first */ if ((termw->scr[termw->from_lin][rcol-1] != ' ') || (termw->scr_attrs[termw->from_lin][rcol-1] != 0)) break; /* chars plus one for the termw->newline */ sz = rcol - termw->from_col + 1; /* in between */ for (lin = termw->from_lin+1; lin < termw->to_lin; lin++) { for (rcol = line_maxcol(termw, lin); rcol > 0; rcol--) if ((termw->scr[lin][rcol-1] != ' ') || (termw->scr_attrs[lin][rcol-1] != 0)) break; sz += rcol + 1; /* chars plus one for the termw->newline */ } if (termw->to_col >= line_maxcol(termw, termw->to_lin)) { /***** find the last real character *****/ for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--) /* last */ if ((termw->scr[termw->to_lin][rcol-1] != ' ') || (termw->scr_attrs[termw->to_lin][rcol-1] != 0)) break; } else { rcol = termw->to_col; } sz += rcol; /* chars */ if (termw->to_col >= line_maxcol(termw, termw->to_lin)) sz++; } /***** Reality Check *****/ if (sz > 8192) { printerr("Too big to copy: ", sz); return; } /****** allocate and lock a buffer for the text ******/ if (sz > GetHandleSize ((Handle) myclip_h)) { HUnlock((Handle) myclip_h); SetHandleSize((Handle) myclip_h, sz); /* make sure our SetHandleSize() worked */ if (GetHandleSize((Handle) myclip_h) != sz) { printerr("scr_copy: could not expand clip handle", 0); return; } } HLock((Handle) myclip_h); dp = *myclip_h; /****** copy the characters over to the clip ******/ if (termw->from_lin == termw->to_lin) { if (termw->to_col >= line_maxcol(termw, termw->to_lin)) { for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--) /* last */ if ((termw->scr[termw->to_lin][rcol-1] != ' ') || (termw->scr_attrs[termw->to_lin][rcol-1] != 0)) break; } else { rcol = termw->to_col; } for (i = termw->from_col; i < rcol; i++) *dp++ = termw->scr[termw->from_lin][i]; if (termw->to_col >= line_maxcol(termw, termw->to_lin)) *dp++ = CR; /* add the return */ } else { /* trim off spaces */ for (rcol = line_maxcol(termw, termw->from_lin); rcol > termw->from_col; rcol--) /* first */ if ((termw->scr[termw->from_lin][rcol-1] != ' ') || (termw->scr_attrs[termw->from_lin][rcol-1] != 0)) break; for (i = termw->from_col; i < rcol; i++) *dp++ = termw->scr[termw->from_lin][i]; *dp++ = CR; /* in between */ for (lin = termw->from_lin+1; lin < termw->to_lin; lin++) { for (rcol = line_maxcol(termw, lin); rcol > 0; rcol--) if ((termw->scr[lin][rcol-1] != ' ') || (termw->scr_attrs[lin][rcol-1] != 0)) break; for (i = 0; i < rcol; i++) *dp++ = termw->scr[lin][i]; *dp++ = CR; } if (termw->to_col == line_maxcol(termw, termw->to_lin)) { for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--) /* last */ if ((termw->scr[termw->to_lin][rcol-1] != ' ') || (termw->scr_attrs[termw->to_lin][rcol-1] != 0)) break; } else { rcol = termw->to_col; } for (i = 0; i < rcol; i++) *dp++ = termw->scr[termw->to_lin][i]; if (termw->to_col >= line_maxcol(termw, termw->to_lin)) *dp++ = CR; } myclip_size = (dp - *myclip_h); /****** check to make sure we didn't overflow the clipboard ******/ if (myclip_size > sz) macfatal ("Overflow! myclip_size - sz ==", myclip_size - sz); /****** Now copy our internal clipboard to the Macintosh one *****/ /* * $$$ at this point we really should allocate a second buffer, * and copy the characters of our buffer into it, converting them * from whatever ISO set we are displaying with to the Mac char set. */ ZeroScrap(); if (PutScrap(myclip_size, 'TEXT', *myclip_h) != noErr) printerr("Couldn't PutScrap", 0); pss = InfoScrap(); my_scrapcount = pss->scrapCount; /* save this to see if the user */ /* cuts/copies outside of us */ /****** We are done. Unlock the handle ******/ HUnlock((Handle) myclip_h); } else { SysBeep(3); } } /* * Paste the clipboard into the terminal, by "typing" it in. * * This also is an external, but we don't have to save the GrafPort * because the only time we do anything to the screen, it's through * inpchars(), which saves the GrafPort itself. */ scr_paste (struct termw *termw) { char *cp, *endp; char **h; long l, o; ScrapStuff *pss; pss = InfoScrap(); if (my_scrapcount == pss->scrapCount) { /* if this is still the same scrap that we made */ if (myclip_size > 0) { HLock((Handle) myclip_h); cp = *myclip_h; endp = cp + myclip_size; for (; cp < endp; cp++) { OutputChar(termw, *cp); if (*cp == CR) waitasec (termw); } HUnlock((Handle) myclip_h); } else { SysBeep(3); } } else { /* we have to get the TEXT scrap from the clipboard */ h = NewHandle(0); l = GetScrap(h, 'TEXT', &o); if (l <= 0) { SysBeep(3); } else { HLock((Handle) h); cp = *h; endp = cp + l; for (; cp < endp; cp++) { /* $$$ Should convert *cp to whatever ISO font we are typing */ OutputChar(termw, *cp); if (*cp == CR) waitasec (termw); } HUnlock((Handle) h); } /* end if (l > 0) */ DisposHandle(h); } } /* * Paste into the command window. */ cmd_paste (struct termw *termw) { char *cp, *endp; char **h; long l, o; ScrapStuff *pss; pss = InfoScrap(); if (my_scrapcount == pss->scrapCount) { /* if this is still the same scrap that we made */ if (myclip_size > 0) { HLock((Handle) myclip_h); cp = *myclip_h; endp = cp + myclip_size; for (; cp < endp; cp++) { writecbc(*cp); if (*cp == CR) waitasec (termw); } HUnlock((Handle) myclip_h); } else { SysBeep(3); } } else { /* we have to get the TEXT scrap from the clipboard */ h = NewHandle(0); l = GetScrap(h, 'TEXT', &o); if (l <= 0) { SysBeep(3); } else { HLock((Handle) h); cp = *h; endp = cp + l; for (; cp < endp; cp++) { /* $$$ Should convert *cp to whatever ISO font we are typing */ writecbc(*cp); if (*cp == CR) waitasec (termw); } HUnlock((Handle) h); } /* end if (l > 0) */ DisposHandle(h); } } /****************************************************************************/ /****************************************************************************/ #ifdef COMMENT show_inval_rgn(w) WindowPeek w; { RgnHandle r = NewRgn(); CopyRgn (w->updateRgn, r); OffsetRgn(r, /* convert to local grafport coords */ (((w->port).portBits).bounds).left, (((w->port).portBits).bounds).top); FillRgn(r, qd.gray); DisposeRgn(r); waitnoinput (); waitnoinput (); waitnoinput (); waitnoinput (); } #endif /* COMMENT */ /****************************************************************************/ /* * PWP: actually do all the scrolling and refreshing we have promised to * do. * * Method (and many var and fcn names) stolen from X11 xterm. */ /****************************************************************************/ void flushscroll (struct termw *termw) { register int i, now; Rect r; /* , opened_r cannot be register */ GrafPtr currWindow; /* cannot be register */ RgnHandle newupdateRgn; Rect *rp; int lin; int vtoplin, vbotlin, vleftcol, vrightcol; if (termw->scroll_amount == 0) { printerr ("flushscroll() called with no scroll to flush", 0); return; } /* should hide the cursor here if not already hidden */ /* (PWP) if our selected region overlaps, but is not enclosed by the region we want to scroll, then remove it, because the region no longer contains what the user thought it did. */ if (termw->have_selection && (termw->saved_tlin != toplin) && (termw->saved_blin != botlin) && ((termw->from_lin < termw->saved_tlin) || (termw->to_lin > termw->saved_blin)) && ((termw->to_lin > termw->saved_tlin) || (termw->from_lin < termw->saved_blin))) { termw->have_selection = FALSE; invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); } if (!termw->in_front) { /* if not in front, compensate update region for scrolling */ GetPort (&currWindow); /* scroll the old updateRgn */ OffsetRgn (((WindowPeek) currWindow)->updateRgn, 0, -termw->lineheight); } /* * Do the scrolling */ makerect(termw,&r, termw->saved_tlin, 0, termw->saved_blin - termw->saved_tlin + 1, MAXCOL); newupdateRgn = NewRgn(); if (termw->smoothscroll && termw->in_front) { int dir = 1; /* direction */ if (termw->scroll_amount < 0) dir = -1; for (i = 1; i <= termw->scroll_amount*termw->lineheight*dir; i += 1) { /* PWP: wait for a vertical reblank (in a sneaky way) */ now = TickCount (); while (TickCount () == now) /* wait... */ ; ScrollRect (&r, 0, dir, newupdateRgn); } } else { ScrollRect (&r, 0, termw->scroll_amount * termw->lineheight, newupdateRgn); } /* * NOTE: We don't add the newupdateRgn to the actual window update region, * but instead we just update all the lines that are in the region now. * This is faster, gives a smoother appearance to background windows, and * avoids an apparent bug in the Mac that causes multiplely scrolled * update regions to be incorrect. */ termw->scroll_amount = 0; /* we've done it now */ /* * Find the intersection of what we just opened up and the visible portion * of the screen, and update all the lines in that rectangle. */ rp = &(**(newupdateRgn)).rgnBBox; /* show the region to be updated -- only for debugging */ /* FillRgn(newupdateRgn, qd.gray); */ /* FillRect (rp, qd.gray); */ /* Find the characters that bound this rectangle */ recttocharpos (termw, rp, &vtoplin, &vleftcol, &vbotlin, &vrightcol); /* Make sure we pick up any extra refresh region */ if (termw->refresh_amount < 0) { /* scrolling forward (UP) */ if (vtoplin > termw->saved_blin + termw->refresh_amount) vtoplin = termw->saved_blin + termw->refresh_amount; } else if (termw->refresh_amount > 0) { /* scrolling backward (DOWN) */ if (vbotlin < termw->saved_tlin + termw->refresh_amount - 1) vbotlin = termw->saved_tlin + termw->refresh_amount - 1; } /* bounds limit it to the actual screen area (again) */ if (vtoplin < 0) vtoplin = 0; if (vbotlin > termw->screensize) vbotlin = termw->screensize; lin = termw->display_topline + vtoplin; for (i = vtoplin; i < vbotlin; i++) { makerect(termw, &r, i, vleftcol, 1, (vrightcol - vleftcol)); /* * According to IM 1 pp 185, RectInRgn isn't always exact, so we might * try the more exact way if this isn't good enough. */ if (RectInRgn(&r, newupdateRgn)) { draw_line_w_attrs(termw, lin, i, vleftcol, vrightcol, 0); /* * If we just drew the line that flushbuf thinks is pending, * say we have done so in order to avoid drawing that line twice. */ if (i == termw->curlin) termw->out_maxcol = 0; } lin++; } DisposeRgn(newupdateRgn); termw->refresh_amount = 0; } /****************************************************************************/ /* * (UoR) * * Scroll lines within the scroll region upwards from line tlin * to line blin (lines are assumed to be in the region) * * (PWP) scroll_screen is the combination of scroll_up and scroll_down. * dir is the number of lines to scroll, <0 if up, >0 if down. * (actually, right now only -1 and 1 are handled.) */ /****************************************************************************/ void scroll_screen (termw, tlin, blin, delta) /* these are in scr[][] cordinates */ struct termw *termw; register int tlin; register int blin; register int delta; { register int i, j; unsigned char *savedline, *savedattr; /* temporary to hold screen line pointer */ unsigned char savedlattr; /* * flush out any pending characters. * * $$$ I bet this is the piece of bogus code that was causing me all the * trouble. We NEED to do this, or else keep track of where out_mincol and * out_maxcol were when we set up the scroll for the first time, so that * we don't mistakenly miss drawing the pending stuff. */ if (!termw->scroll_amount && termw->out_maxcol) flushbuf(termw); /* * See if we are scrolling something different and have to flush * our pending scroll. * We do if asked to scroll something different than the current * scrolling rgn, or if we are changing direction, or if we have * already collected an entire scrolling region worth of scroll to do. */ if (termw->scroll_amount) { i = termw->scroll_amount + delta; if (i < 0) i = -i; /* set i to ABS( old scroll plus new scroll ) */ if (termw->smoothscroll || (tlin != termw->saved_tlin) || (blin != termw->saved_blin) || ((termw->scroll_amount > 0) && (delta < 0)) || ((termw->scroll_amount < 0) && (delta > 0)) || (i >= (termw->saved_blin - termw->saved_tlin))) { flushscroll(termw); } } /* * Save up how much to scroll and where for later... */ termw->saved_tlin = tlin; termw->saved_blin = blin; termw->scroll_amount += delta; /* * Should really set termw->refresh_amount to 0, then add to it * when we "draw" characters onto lines, but this is safe. */ termw->refresh_amount += delta; /* printerr("termw->scroll_amount now ", scroll_amount); */ if (delta < 0) /* if scrolling UP (forwards) */ { /* adjust the internal character buffers */ if ((tlin == toplin) && (blin == botlin)) { /* if whole screen */ termw->display_totlines -= delta; /* remember delta is negitive */ if (termw->display_totlines > MAX_SCREENSIZE) termw->display_totlines = MAX_SCREENSIZE; /* bounds */ /*top of saved buffer*/ tlin = termw->screensize - termw->display_totlines; } /* * If only scrolling by one, just go up, else do more cleverly: * to scroll N lines by I, note that BA == rev(rev(A) rev(B)) * and to do a reverse we only need a single temporary variable. * Also note that we don't even have to reverse A (the lines to * scroll to the bottom) since we will just zero these anyway. */ if (delta == -1) { savedline = termw->scr[tlin]; savedattr = termw->scr_attrs[tlin]; savedlattr = termw->line_attrs[tlin]; for (i = tlin+1; i <= blin; i++) { termw->scr[i-1] = termw->scr[i]; termw->scr_attrs[i-1] = termw->scr_attrs[i]; termw->line_attrs[i-1] = termw->line_attrs[i]; } termw->scr[blin] = savedline; termw->scr_attrs[blin] = savedattr; termw->line_attrs[blin] = savedlattr; zeroline(termw, blin, 1); /* clear the line */ } else { for (i = tlin; i < tlin-delta; i++) /* remember that delta < 0 */ zeroline(termw, i, 1); /* clear the line to be moved to bottom */ for (i = tlin-delta, j = blin; i < j; i++, j--) { savedline = termw->scr[i]; savedattr = termw->scr_attrs[i]; savedlattr = termw->line_attrs[i]; termw->scr[i] = termw->scr[j]; termw->scr_attrs[i] = termw->scr_attrs[j]; termw->line_attrs[i] = termw->line_attrs[j]; termw->scr[j] = savedline; termw->scr_attrs[j] = savedattr; termw->line_attrs[j] = savedlattr; } for (i = tlin, j = blin; i < j; i++, j--) { savedline = termw->scr[i]; savedattr = termw->scr_attrs[i]; savedlattr = termw->line_attrs[i]; termw->scr[i] = termw->scr[j]; termw->scr_attrs[i] = termw->scr_attrs[j]; termw->line_attrs[i] = termw->line_attrs[j]; termw->scr[j] = savedline; termw->scr_attrs[j] = savedattr; termw->line_attrs[j] = savedlattr; } } /* adjust selection */ if (termw->have_selection && (termw->from_lin >= tlin) && (termw->to_lin <= blin)) { termw->from_lin += delta; if (termw->from_lin < termw->screensize - MAX_SCREENSIZE) termw->from_lin = termw->screensize - MAX_SCREENSIZE; termw->to_lin += delta; if (termw->to_lin < termw->screensize - MAX_SCREENSIZE) termw->to_lin = termw->screensize - MAX_SCREENSIZE; } } else /* else scrolling DOWN (reverse scroll) */ { /* adjust the internal buffers */ /* * If only scrolling by one, just go up, else do more cleverly: * to scroll N lines by I, note that BA == rev(rev(A) rev(B)) * and to do a reverse we only need a single temporary variable. * Also note that we don't even have to reverse A (the lines to * scroll to the bottom) since we will just zero these anyway. */ if (delta == -1) { savedline = termw->scr[blin]; savedattr = termw->scr_attrs[blin]; savedlattr = termw->line_attrs[blin]; for (i = blin-1; i >= tlin; i--) { termw->scr[i+1] = termw->scr[i]; termw->scr_attrs[i+1] = termw->scr_attrs[i]; termw->line_attrs[i+1] = termw->line_attrs[i]; } termw->scr[tlin] = savedline; termw->scr_attrs[tlin] = savedattr; termw->line_attrs[tlin] = savedlattr; zeroline(termw, tlin, 1); } else { for (i = blin-delta+1; i <= blin; i++) /* remember that delta > 0 */ zeroline(termw, i, 1); /* clear the line to be moved to top */ for (i = tlin, j = blin-delta; i < j; i++, j--) { savedline = termw->scr[i]; savedattr = termw->scr_attrs[i]; savedlattr = termw->line_attrs[i]; termw->scr[i] = termw->scr[j]; termw->scr_attrs[i] = termw->scr_attrs[j]; termw->line_attrs[i] = termw->line_attrs[j]; termw->scr[j] = savedline; termw->scr_attrs[j] = savedattr; termw->line_attrs[j] = savedlattr; } for (i = tlin, j = blin; i < j; i++, j--) { savedline = termw->scr[i]; savedattr = termw->scr_attrs[i]; savedlattr = termw->line_attrs[i]; termw->scr[i] = termw->scr[j]; termw->scr_attrs[i] = termw->scr_attrs[j]; termw->line_attrs[i] = termw->line_attrs[j]; termw->scr[j] = savedline; termw->scr_attrs[j] = savedattr; termw->line_attrs[j] = savedlattr; } } #ifdef COMMENT for (now = 0; now < delta; now++) { savedline = termw->scr[blin]; savedattr = termw->scr_attrs[blin]; savedlattr = termw->line_attrs[blin]; for (i = blin-1; i >= tlin; i--) { termw->scr[i+1] = termw->scr[i]; termw->scr_attrs[i+1] = termw->scr_attrs[i]; termw->line_attrs[i+1] = termw->line_attrs[i]; } termw->scr[tlin] = savedline; termw->scr_attrs[tlin] = savedattr; termw->line_attrs[tlin] = savedlattr; zeroline(termw, tlin, 1); } #endif /* adjust selection */ if (termw->have_selection && (termw->from_lin >= tlin) && (termw->to_lin <= blin)) { termw->from_lin += delta; if (termw->from_lin > botlin) termw->from_lin = botlin; termw->to_lin += delta; if (termw->to_lin > botlin) termw->to_lin = botlin; } } /* * but if we are smooth (slow) scrolling and in front, do the scroll now. * must do this after adjusting internal buffers, so that the refresh * lines don't get confused. */ if (termw->smoothscroll && termw->in_front) flushscroll(termw); } /* scroll_up */ /****************************************************************************/ /* redraw the terminal screen (we got a redraw event) */ /****************************************************************************/ term_redraw (struct termw *termw) { int i, lin; int vtoplin, vbotlin, vleftcol, vrightcol; Rect r, *rp; GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); if (termw->screeninvert) { BackPat(qd.black); PenPat(qd.white); } else { BackPat(qd.white); PenPat(qd.black); } if (termw->scroll_amount) flushscroll(termw); #ifdef COMMENT r = terminalWindow->portRect; /* copy the window size */ /* r.right -= 15; */ /* subtract control */ /* PWP: clear the screen first */ /* makerect(termw,&r, 0, 0, termw->screensize, MAXCOL); */ /* EraseRect (&r); */ #endif /* COMMENT */ /* See if the scroll bar and grow box need to be updated */ r = termw->window->portRect; /* copy of the window size */ /* r.left = r.right - 16; */ r.left = rightMARGIN; if (RectInRgn (&r, termw->window->visRgn)) { termw->scroll_drawn = -1; /* mark scroll bar invalid */ EraseRect (&r); /* don't add to invalid while redrawing invalid */ draw_grow_and_erase_line(termw, 0); DrawControls (termw->window); } /* Update area above first line */ r = termw->window->portRect; /* copy of the window size */ r.bottom = r.top + TOPMARGIN; r.right -= 16; if (RectInRgn (&r, termw->window->visRgn)) EraseRect (&r); /* Update area below last line */ r = termw->window->portRect; /* copy of the window size */ r.top = termw->bottommargin - 1; r.right -= 16; if (RectInRgn (&r, termw->window->visRgn)) EraseRect (&r); /* Update area to the left of first column */ r = termw->window->portRect; /* copy of the window size */ r.top = r.top + TOPMARGIN; r.bottom = termw->bottommargin; r.right = LEFTMARGIN; if (RectInRgn (&r, termw->window->visRgn)) EraseRect (&r); /* update_vscroll(termw); */ /* SetCtlValue (termw->t_vscroll, GetCtlValue (t_vscroll)); */ #ifdef COMMENT lin = termw->display_topline; for (i = 0; i < termw->screensize; i++) { makerect(termw,&r, i, 0, 1, MAXCOL); if (RectInRgn (&r, termw->window->visRgn)) draw_line_w_attrs(termw, lin, i, 0, MAXCOL, 1); lin++; } #endif rp = &(**(termw->window->visRgn)).rgnBBox; /* Find the characters that bound this rectangle */ recttocharpos(termw, rp, &vtoplin, &vleftcol, &vbotlin, &vrightcol); #ifdef COMMENT debug(F101,"term_redraw bounds vtoplin","",vtoplin); debug(F101,"term_redraw bounds vbotlin","",vbotlin); debug(F101,"term_redraw bounds vleftcol","",vleftcol); debug(F101,"term_redraw bounds vrightcol","",vrightcol); #endif lin = termw->display_topline + vtoplin; for (i = vtoplin; i < vbotlin; i++) { makerect(termw, &r, i, 0, 1, MAXCOL); if (RectInRgn (&r, termw->window->visRgn)) draw_line_w_attrs(termw, lin, i, vleftcol, vrightcol, 1); lin++; } if (termw->have_selection) invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, termw->to_col); /* (UoR) only if cursor is showing */ if (termw->cur_drawn && termw->cursor_invert) { termw->cursor_invert = FALSE; /* (UoR) make sure we draw it */ cursor_draw(termw); /* redraw cursor */ termw->last_flash = TickCount (); /* (UoR) reset timer */ } SetPort (savePort); /* there just has to be a better way */ } /* term_redraw */ draw_grow_and_erase_line (struct termw *termw, int invalidate_it) { Rect r; DrawGrowIcon (termw->window); /* erase the bottom scroll line (but only if inverted screen) */ if (!termw->screeninvert) { PenMode(patBic); MoveTo(0, (termw->window->portRect).bottom - 15); LineTo((termw->window->portRect).right - 15, (termw->window->portRect).bottom - 15); PenMode(patCopy); } if (invalidate_it) { r.top = (termw->window->portRect).bottom - 16; r.bottom = (termw->window->portRect).bottom - 14; r.left = 0; r.right = (termw->window->portRect).right - 16; InvalRect(&r); } } term_activate (struct termw *termw, int mod) { GrafPtr savePort; GetPort (&savePort); SetPort (termw->window); cursor_erase (termw); /* remove cursor from screen */ termw->in_front = mod & activeFlag; if (termw->in_front) { UpdateOptKey(1); DisableItem(menus[EDIT_MENU], UNDO_EDIT); DisableItem(menus[EDIT_MENU], CLEAR_EDIT); } else { UpdateOptKey(0); EnableItem(menus[EDIT_MENU], UNDO_EDIT); EnableItem(menus[EDIT_MENU], CLEAR_EDIT); } /* these do the right thing for background too */ update_vscroll (termw); draw_grow_and_erase_line(termw, 1); cursor_draw(termw); SetPort (savePort); } /* * This CAN be called external to inpchars(), so save and restore the * GrafPort just in case. */ set_term_invert (struct termw *termw, int new_inv) { GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); if (new_inv == termw->screeninvert) return; if (new_inv) { BackPat (qd.black); /* (UoR) use black background */ PenPat(qd.white); termw->screeninvert = TRUE; } else { BackPat (qd.white); PenPat(qd.black); termw->screeninvert = FALSE; } InvalRect(&termw->window->portRect);/* invalidate whole window rectangle */ SetPort (savePort); /* there just has to be a better way */ } /****************************************************************************/ /* sizevscroll - called when window is created and after a window grow */ /* sequence to resize the scroll window's bars. */ /****************************************************************************/ void sizevscroll (struct termw *termw) { register Rect *r; if (!termw) DebugStr("\psizevscroll called with termw == NULL"); r = &termw->window->portRect;/* window size */ HideControl (termw->t_vscroll); MoveControl (termw->t_vscroll, r->right - 15, r->top - 1); SizeControl (termw->t_vscroll, 16, r->bottom - r->top - 13); SetCtlMin (termw->t_vscroll, 0); termw->scroll_drawn = -1; /* mark scroll bar invalid */ update_vscroll(termw); ShowControl (termw->t_vscroll); } /****************************************************************************/ /* initalize the terminal emulator. */ /****************************************************************************/ init_term (struct termw *termw) { register int i, j; register unsigned char *scp, *acp; unsigned char *scr_cp, *attr_cp; GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); termw->topmargin = TOPMARGIN; /* Edges of adjustable window */ termw->bottommargin = bottomMARGIN; if ((scr_cp = (unsigned char *) NewPtr(((long)(MAXCOL+1) * (long) MAX_SCREENSIZE))) == NIL) macfatal("Could not allocate screen buffer", 0); if ((attr_cp = (unsigned char *) NewPtr(((long)(MAXCOL+1) * (long) MAX_SCREENSIZE))) == NIL) macfatal("Could not allocate screen attribute buffer", 0); if ((termw->real_scr = (ucharptr *) NewPtr ((long)(MAX_SCREENSIZE) * (long) sizeof(ucharptr))) == NIL) macfatal("Could not allocate screen buffer", 0); if ((termw->real_attrs = (ucharptr *) NewPtr ((long)(MAX_SCREENSIZE) * (long) sizeof(ucharptr))) == NIL) macfatal("Could not allocate screen buffer", 0); if ((termw->real_ln_attrs = (unsigned char *) NewPtr ((long)(MAX_SCREENSIZE) * (long) sizeof(unsigned char))) == NIL) macfatal("Could not allocate screen buffer", 0); for (i = 0; i < MAX_SCREENSIZE; i++) { /* divvy up screen buffer */ termw->real_scr[i] = scr_cp + (i * (MAXCOL+1)); /* divvy up screen attribute buf */ termw->real_attrs[i] = attr_cp + (i * (MAXCOL+1)); scp = termw->real_scr[i]; acp = termw->real_attrs[i]; j = MAXCOL; do { /* put normal spaces in all columns */ *scp++ = ' '; *acp++ = 0; } while (--j > 0); *scp = ' '; /* Terminate the lines as strings */ *acp = 0; /* Terminate the attrs as strings */ termw->real_ln_attrs[i] = VT_SNGL; /* reset line attributes */ } termw->scr = &termw->real_scr[MAX_SCREENSIZE - termw->screensize]; if (termw->scr[0] == NIL) macfatal("init_term: scr assignment botched for [0]", 0); if (termw->scr[termw->screensize-1] == NIL) macfatal("\ init_term: scr assignment botched for [termw->screensize-1]", 0); termw->scr_attrs = &termw->real_attrs[MAX_SCREENSIZE - termw->screensize]; if (termw->scr_attrs[0] == NIL) macfatal("init_term: scr assignment botched for [0]", 0); if (termw->scr_attrs[termw->screensize-1] == NIL) macfatal("\ init_term: scr assignment botched for [termw->screensize-1]", 0); termw->line_attrs = &termw->real_ln_attrs[MAX_SCREENSIZE - termw->screensize]; termw->scrtop = toplin; /* Scrolling region equals all */ termw->scrbot = botlin; termw->scroll_amount = 0; /* no pending scroll */ termw->refresh_amount = 0; /* no pending refresh */ termw->saved_tlin = 0; termw->saved_blin = 0; termw->display_topline = toplin; /* init display w/elevator at bottom */ termw->display_totlines = termw->screensize; makerect(termw,&termw->ScreenRect, 0, 0, termw->screensize, MAXCOL); /* (UoR) full screen rectangle */ SizeWindow(termw->window, rightMARGIN + 1 + 16, /* add extra to side for asthetics */ bottomMARGIN + TOPMARGIN, /* add extra to bottom for asthetics */ FALSE); /* PWP: make the window match it's real size */ termw->t_vscroll = GetNewControl (RCMDVSCROLL, termw->window); termw->scroll_drawn = -1; /* mark scroll bar invalid */ sizevscroll(termw); InitKeyStuff(); /* find the original KCHR keymaps */ #ifdef COMMENT draw_grow_and_erase_line(0); /* it's new so don't invalidate it */ #endif /* ClipRect(&termw->ScreenRect); */ SetPort (savePort); /* there just has to be a better way */ } /* init_term */ /****************************************************************************/ /* grow_term_to(termw, size) -- change the size of the terminal window to size. this is called by growterm() (see below) and the terminal settings dialog handler (termsetdialog()). /****************************************************************************/ grow_term_to (struct termw *termw, int size) { GrafPtr savePort; GetPort (&savePort); SetPort (termw->window); if ((size < 1) || (size > MAX_SCREENSIZE)) size = 24; /* the default case */ if (size > termw->display_totlines) { /* * if getting bigger than we were * We would zero out lines from (termw->screensize-size) to * (termw->screensize-display_totlines), * but these were already zeroed when the original screen was inited. */ termw->display_totlines = size; } /* $$$ Make sure to scroll screen to what will be the new bottom here */ /* adjust cursor row to match stretch */ termw->curlin += size - termw->screensize; if (termw->curlin < 0) termw->curlin = 0; if (termw->curlin > size-1) termw->curlin = size-1; termw->screensize = size; if (termw->screensize > MAX_SCREENSIZE) termw->screensize = MAX_SCREENSIZE; /* bounds check */ termw->scr = &termw->real_scr[MAX_SCREENSIZE - termw->screensize]; termw->scr_attrs = &termw->real_attrs[MAX_SCREENSIZE - termw->screensize]; termw->line_attrs = &termw->real_ln_attrs[MAX_SCREENSIZE - termw->screensize]; termw->bottommargin = bottomMARGIN; /* this changes */ termw->scrtop = toplin; /* Scrolling region equals all */ termw->scrbot = botlin; termw->display_topline = 0; /* re-init display w/elevator at bottom */ makerect(termw,&termw->ScreenRect, 0, 0, termw->screensize, MAXCOL); /* (UoR) full screen rectangle */ SizeWindow(termw->window, rightMARGIN + 1 + 16, /* add extra to side for asthetics */ bottomMARGIN + TOPMARGIN, /* add extra to bottom for asthetics */ FALSE); /* PWP: make the window match it's real size */ termw->scroll_drawn = -1; /* mark scroll bar invalid */ sizevscroll(termw); /* size the scroll bars */ /* ClipRect(&termw->ScreenRect); */ /* invalidate whole window rectangle */ InvalRect (&termw->window->portRect); SetPort (savePort); } /* grow_term_to */ /****************************************************************************/ /* * growterm() -- called when we get a mouse-down in the lower right corner grow * box. * Probably all right not to save the grafport, but we do anyway just to be * double extra safe. */ /****************************************************************************/ growterm (struct termw *termw, Point *p) { long gr; int height; int width; int size; Rect growRect; GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); growRect = qd.screenBits.bounds; growRect.top = 50; /* minimal horizontal size */ growRect.left = rightMARGIN + 18; /* minimal vertical size */ growRect.right = rightMARGIN + 18; /* minimal vertical size */ gr = GrowWindow (termw->window, *p, &growRect); if (gr == 0) return; height = HiWord (gr); width = LoWord (gr); size = (height - (2 * TOPMARGIN)) / termw->lineheight; if (size > MAX_SCREENSIZE) termw->screensize = MAX_SCREENSIZE; /* bounds check */ if (size < 1) size = 1; grow_term_to(termw, size); SetPort (savePort); /* there just has to be a better way */ } /* growterm */ /****************************************************************************/ get_term_pos(struct termw *termw, int *top_p, int *left_p) { Point mypoint; GrafPtr savePort; GetPort (&savePort); /* there just has to be a better way */ SetPort (termw->window); mypoint.v = termw->window->portRect.top; mypoint.h = termw->window->portRect.left; LocalToGlobal(&mypoint); if (top_p) *top_p = mypoint.v; if (top_p) *left_p = mypoint.h; SetPort (savePort); /* there just has to be a better way */ } set_term_pos(struct termw *termw, int top, int left) { MoveWindow(termw->window, left, top, TRUE); } /* * Junk so Emacs will set local variables to be compatible with Mac/MPW. * Should be at end of file. * This module was apparently formatted with tabs = 8 * * Local Variables: * tab-width: 8 * End: */