home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckmco2.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  103KB  |  3,499 lines

  1. /* $Id: ckmco2.c,v 1.9 91/12/27 21:28:52 fdc Exp $
  2.  * $Source: /uw/mackermit/RCS/ckmco2.c,v $
  3.  *------------------------------------------------------------------
  4.  * $Log:    ckmco2.c,v $
  5.  * Revision 1.9  91/12/27  21:28:52  fdc
  6.  * Change fatal to macfatal, make sure all lines width 80 or less.
  7.  * 
  8.  * Revision 1.8  91/12/15  23:16:45  rick
  9.  * ut9
  10.  * 
  11.  * Revision 1.7  91/10/13  13:43:05  rick
  12.  * UT(7)
  13.  * 
  14.  * Revision 1.6  91/10/01  12:16:12  rick
  15.  * UT(5)
  16.  * 
  17.  * Revision 1.5  91/09/25  12:16:26  rick
  18.  * Command window in TE. Multiple vt100 windows for command window.
  19.  * 
  20.  * Revision 1.4  91/09/12  21:50:31  rick
  21.  * UT(3). Install on watsun
  22.  * 
  23.  * Revision 1.3  1991/09/12  16:42:51  rick
  24.  * Cleanups.
  25.  *
  26.  * Revision 1.2  1991/09/10  22:21:37  rick
  27.  * Update to UTexas(2)
  28.  *
  29.  * Revision 1.1  1991/09/10  19:17:45  rick
  30.  * Initial revision
  31.  *
  32.  *------------------------------------------------------------------
  33.  * $Endlog$
  34.  */
  35.  
  36. /*
  37.  * FILE ckmco2.c
  38.  *
  39.  * Module of mackermit: contains code for dealing with the Mac side
  40.  * of terminal emulation.
  41.  */
  42.  
  43. /*
  44.   Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  45.   York.  Permission is granted to any individual or institution to use this
  46.   software as long as it is not sold for profit.  This copyright notice must be
  47.   retained.  This software may not be included in commercial products without
  48.   written permission of Columbia University.
  49. */
  50. #include "ckcdeb.h"
  51. #include "ckcasc.h"
  52. #include "ckmdef.h"
  53. #include "ckmasm.h"        /* Assembler code */
  54. #include "ckmres.h"        /* kermit resources */
  55. #include "ckmcon.h"        /* defines, etc. for terminal emulator */
  56. #include "ckmptp.h"        /* ckm* Prototypes */
  57.  
  58. extern int escape;
  59.  
  60. #define ABS(a)    ((a) < 0 ? -(a) : (a))
  61.  
  62. char **myclip_h = NULL;        /* internal clipboard */
  63. int myclip_size = 0;        /* size of above */
  64. int my_scrapcount = -1;        /* the value of PScrapStuff->scrapCount when we cut */
  65.  
  66. extern Boolean usingRAMdriver;        /* CTB */
  67. extern Boolean have_128roms;        /* True if we are a Plus or better */
  68.  
  69. RgnHandle dummyRgn;        /* dummy region for ScrollRect */
  70.                 /* Initialized in mac_init */
  71.  
  72. long MyCaretTime;        /* (UoR) ticks between flashes */
  73.  
  74. extern Cursor *textcurs, *normcurs, *watchcurs;    /* mouse cursor shapes */
  75.  
  76. extern    int        to_printer;        /*JAO*/
  77. extern    int        to_screen;        /*JAO*/
  78. extern    int        printer_is_on_line_num;    /*JAO*/
  79.  
  80. #ifdef COMMENT
  81. extern    Handle    hPrintBuffer;            /*JAO*/
  82. extern    long    lPrintBufferSize;        /*JAO*/
  83. extern    long    lPrintBufferChars;        /*JAO*/
  84. extern    long    lPrintBufferAt;            /*JAO*/
  85.  
  86. extern    DialogPtr    bufferingDialog;    /*JAO*/
  87. #endif /* COMMENT */
  88.  
  89. extern    DialogPtr    overflowingDialog;    /*JAO*/
  90.  
  91. extern    MenuHandle menus[];    /* handle on our menus */  /*JAO*/
  92.  
  93. /* keyboard handling stuff */
  94.  
  95. extern char keytable[512];    /* the key redefintion flag table */
  96. extern modrec modtable[NUMOFMODS];    /* modifier records */
  97.  
  98. #define myKeyCodeMask    0x7F00
  99. #define keyModifierMask    0x1F00
  100. #define ctrlCodeMask    0x1F
  101. #define metaOrBits    0x80
  102.  
  103. #define UnmodMask    0x80        /* action bits */
  104. #define CapsMask    0x40
  105. #define CtrlMask    0x20
  106. #define MetaMask    0x10
  107.  
  108.  
  109. Boolean have_scriptmgr = FALSE;
  110.  
  111. long old_KCHR, old_SICN;    /* pointers to current system key script, icon */
  112. long cur_KCHR;
  113. Cursor *lastCursor=0L;            /* what we set the cursor to last */
  114.  
  115.  
  116. /****************************************************************************/
  117. /****************************************************************************/
  118. /****************************************************************************/
  119. /* keyboard event handling routines                                         */
  120. /****************************************************************************/
  121.  
  122.  
  123. InitKeyStuff()
  124. {
  125.     have_scriptmgr = NGetTrapAddress(num_UnknownTrap, 1) !=
  126.              NGetTrapAddress(num_ScriptTrap, 1);
  127.              
  128.     if (have_scriptmgr) {
  129.     old_KCHR = GetScript( smRoman, smScriptKeys);
  130.     old_SICN = GetScript( smRoman, smScriptIcon);
  131.     }
  132.     cur_KCHR = old_KCHR;
  133.  
  134.     UpdateOptKey(1);    /* get things set right initially */
  135. }
  136.  
  137. UpdateOptKey(int enable)
  138. {
  139.     int i;
  140.     int futzit = 0;
  141.     
  142.     if (enable) {
  143.     for (i = 0; i < NUMOFMODS; i++) {
  144.     /* shift what to look for into high byte */
  145.         if ((modtable[i].modbits) & (optionKey >> 4))
  146.                 /* if Option is selected */
  147.             futzit = 1;
  148.     }
  149.     } else {    /* allways turn off when disabling window */
  150.         futzit = 0;
  151.     }
  152.     
  153.     (void) FutzOptKey(futzit);
  154. }
  155.  
  156. FutzOptKey(int enable)
  157. {
  158.     int err;
  159.     
  160.     if (have_scriptmgr) {        /* if we are system 4.1 or later... */
  161.     if (enable) {    /* no deadkeys */
  162.         if (cur_KCHR != old_KCHR)
  163.         return (1);    /* we are allready fine */
  164.         if (GetEnvirons(smKeyScript) == smRoman) {
  165.         /* set the key map only if in roman script */
  166.         err = SetScript (smRoman, smScriptKeys, NODEAD_KCHR);
  167.         if (err != noErr) {
  168.             printerr ("Trouble setting custom keymap (KCHR):", err);
  169.             return (0);
  170.         }
  171.         /* set the icon */
  172.         err = SetScript (smRoman, smScriptIcon, NODEAD_SICN);
  173.         if (err != noErr) {
  174.             printerr ("Trouble setting custom keymap icon (SICN):",
  175.                   err);
  176.             return (0);
  177.         }
  178.         KeyScript (smRoman);
  179.         cur_KCHR = NODEAD_KCHR;
  180.         return (1);    /* success! */
  181.         } else {
  182.       printerr("Can't disable Option key -- you have a non-US keyboard",0);
  183.             return (0);
  184.         }
  185.     } else {    /* back to normal */
  186.         if (cur_KCHR == old_KCHR)
  187.         return (1);    /* we are allready fine */
  188.         /* set the key map */
  189.         err = SetScript (smRoman, smScriptKeys, old_KCHR);
  190.         if (err != noErr) {
  191.         printerr ("Trouble resetting default keymap (KCHR):", err);
  192.         return (0);
  193.         }
  194.         /* set the icon */
  195.         err = SetScript (smRoman, smScriptIcon, old_SICN);
  196.         if (err != noErr) {
  197.         printerr ("Trouble resetting default keymap icon (SICN):",
  198.               err);
  199.         return (0);
  200.         }
  201.         KeyScript (smRoman);
  202.         cur_KCHR = old_KCHR;
  203.         return (1);        /* success! */
  204.     }
  205.     } else {
  206.     /* do something or other to do the old way */
  207.     /* printerr("Kermit can't disable Option on old systems",0); */
  208.     }
  209.     return (0);
  210. }
  211.  
  212.  
  213. /****************************************************************************/
  214. /* return the ASCII character which is generated by the keyCode specified */
  215. /* with no modifiers pressed */
  216. /****************************************************************************/
  217. unsigned char DeModifyChar (long keyCode, long modifiers)
  218. {
  219.     long c;
  220.     long mystate;
  221.     short s_keycode;
  222.     Handle kchr_h;
  223.     THz curZone;
  224.  
  225. #ifdef COMMENT
  226.     ProcHandle KeyTrans;
  227.  
  228.     if (keyCode > 64)
  229.     KeyTrans = (ProcHandle) 0x2A2;    /* keypad decode */
  230.     else
  231.     KeyTrans = (ProcHandle) 0x29E;    /* keyboard decode */
  232.  
  233.     SaveRegs ();        /* save all registers */
  234.     AllRegs ();
  235.  
  236.     /* setup regs for procedure call */
  237.     /* loadD1 ((long) modifiers); */        /* no modifiers */
  238.     loadD1 ((long) 0);        /* no modifiers */
  239.     loadD2 ((long) keyCode);    /* set the keycode */
  240.     loadA0 (*KeyTrans);        /* load the content of Key1Trans to A0 */
  241.  
  242.     /* run the translation routine */
  243.     execute ();            /* call the Key1Trans procedure */
  244.  
  245.     /* move the result from reg D0 to c */
  246.     loadA0 (&c);        /* set destination address */
  247.     pushD0 ();            /* move register D0 to stack */
  248.     poptoA0 ();            /* load the stacktop to (A0) */
  249.  
  250.     RestoreRegs ();        /* restore all registers */
  251.     AllRegs ();
  252.  
  253. #endif /* COMMENT */
  254.  
  255.     if (have_scriptmgr) {        /* if we are system 4.1 or later... */
  256.         mystate = 0;
  257.     
  258.     kchr_h = GetResource('KCHR', cur_KCHR);
  259.     if (kchr_h == NIL) {
  260.         printerr("DeModifyChar: couldn't get KCHR address",0);
  261.         return(0);
  262.     }
  263.     LoadResource(kchr_h);
  264.     HLock(kchr_h);
  265.     
  266.     s_keycode = (modifiers & 0xff00) | (keyCode & 0xff);
  267.  
  268.     c = KeyTrans(*kchr_h, s_keycode, &mystate);
  269.     HUnlock(kchr_h);
  270.     curZone = GetZone();        /* as per John Norstad's (Disinfectant) */
  271.     SetZone(HandleZone(kchr_h));    /* "Toolbox Gotchas" */
  272.     ReleaseResource(kchr_h);
  273.     SetZone(curZone);
  274.     }    
  275.     return (c);
  276. }                /* DeModifyChar */
  277.  
  278.  
  279.  
  280. /****************************************************************************/
  281. /* send a character to the line if it is in ASCII range. Do local echo if */
  282. /* necessary */
  283. /****************************************************************************/
  284. OutputChar (struct termw *termw, unsigned char c)
  285. {
  286.     unsigned char obuf[2];        /* single char output buffer */
  287.  
  288.     /*
  289.      * PWP: NO 7 bit masking!!!  If we do this, then I can't use Emacs, and
  290.      * the European users will be VERY unhappy, 'cause they won't be able to
  291.      * send all of their characters.
  292.      */
  293.     obuf[0] = 1;        /* length of one character string */
  294.     obuf[1] = c;        /* store character */
  295.     writeps (obuf);        /* and write it out */
  296.  
  297.     if (duplex != 0) {
  298.     cursor_erase (termw);    /* remove from screen */
  299.     printem (termw, &obuf[1], 1);    /* Echo the char to the screen */
  300.     flushbuf(termw);        /* flush the character */
  301.     cursor_draw(termw);        /* put it back */
  302.     }
  303. }                /* OutputChar */
  304.  
  305. #ifdef COMMENT
  306. /****************************************************************************/
  307. /* Bittest returns the setting of an element in a Pascal PACKED ARRAY [0..n]
  308.    OF Boolean such as the KeyMap argument returned by GetKey
  309. /****************************************************************************/
  310. Boolean
  311. bittest (bitmap, bitnum)
  312. char bitmap[];
  313. int bitnum;
  314. {
  315.     return (0x01 & (bitmap[bitnum / 8] >> (bitnum % 8)));
  316. }                /* bittest */
  317.  
  318. /* PWP: or, as a macro, */
  319. #define bittest(bitmap,bitnum)    (0x01 & (bitmap[bitnum / 8] >> (bitnum % 8)))
  320.  
  321. #endif /* COMMENT */
  322.  
  323.  
  324. /****************************************************************************/
  325. /* Process a character received from the keyboard */
  326. /****************************************************************************/
  327. handle_char (struct termw *termw, EventRecord *evt)
  328. {
  329.     short i;
  330.     short len;
  331.     short theCode;
  332.     short modCode;
  333.     short theModBits;
  334.     char flags;
  335.     Str255 tmpstr;
  336.     unsigned char c;
  337.  
  338.     /* (UoR) check for auto repeated keys */
  339.     if ((termw->autorepeat == FALSE) && (evt->what == autoKey))
  340.     return;
  341.  
  342.     ObscureCursor ();        /* PWP: hide the cursor until next move */
  343.  
  344.     modCode = evt->modifiers & keyModifierMask;
  345.     theCode = ((evt->message & myKeyCodeMask) >> 8) + (modCode >> 1);
  346.     
  347.     /* check for a special code for this key */
  348.     if (BitTst (keytable, theCode)) {
  349.     GetMacro (theCode, &flags, tmpstr);    /* get the macrostring */
  350.  
  351.     if (flags) {        /* check special flags */
  352.         switch (flags) {
  353.           case shortBreak:
  354.         sendbreak (5);
  355.         return;
  356.  
  357.           case longBreak:
  358.         sendbreak (70);
  359.         return;
  360.  
  361.           case leftArrowKey:
  362.         do_arrow (termw, leftARROW);
  363.         return;
  364.  
  365.           case rightArrowKey:
  366.         do_arrow (termw, rightARROW);
  367.         return;
  368.  
  369.           case upArrowKey:
  370.         do_arrow (termw, UPARROW);
  371.         return;
  372.  
  373.           case downArrowKey:
  374.         do_arrow (termw, DOWNARROW);
  375.         return;
  376.         
  377.           case keycomma:
  378.           case keyminus:
  379.           case keyperiod:
  380.           /* there is no keyslash */
  381.           case key0:
  382.           case key1:
  383.           case key2:
  384.           case key3:
  385.           case key4:
  386.           case key5:
  387.           case key6:
  388.           case key7:
  389.           case key8:
  390.           case key9:
  391.         do_keypad(termw, flags - keycomma);
  392.         return;
  393.         
  394.           case keypf1:
  395.           case keypf2:
  396.           case keypf3:
  397.           case keypf4:
  398.         do_pfkey(termw, flags - keypf1);
  399.         return;
  400.         
  401.           case keyenter:
  402.         do_keyenter(termw);
  403.         return;        
  404.         }
  405.     }
  406.     /* send key macro string */
  407.  
  408.     /*
  409.      * PWP: note, we DON'T have to convert it to a Pascal string, 'cause
  410.      * the macros are now stored as Pascal strings
  411.      */
  412.     writeps (tmpstr);    /* send it to the line */
  413.     if (duplex != 0)
  414.         printps(termw,tmpstr);    /* echo it locally */
  415.     return;
  416.     }
  417.     for (i = 0; i < NUMOFMODS; i++) {
  418.     /* shift what to look for into high byte */
  419.     theModBits = modtable[i].modbits << 4;
  420.     len = strlen (modtable[i].prefix);
  421.  
  422.     if ((theModBits || len) &&
  423.         ((theModBits & modCode) == (theModBits & keyModifierMask))) {
  424.         /* send prefix if there is one */
  425.         if (len) {
  426.         /* PWP: these are saved as Pascal strings now */
  427.         BlockMove (modtable[i].prefix, tmpstr,
  428.                (modtable[i].prefix[0] + 1));
  429.         writeps (tmpstr);    /* send it to the line */
  430.         if (duplex != 0)
  431.             printps(termw,tmpstr);    /* echo it locally */
  432.         }
  433.  
  434.         /*
  435.          * get the unmodified ASCII code if the unmodify action bit is
  436.          * active
  437.          */
  438.         if (theModBits & UnmodMask)
  439.         c = DeModifyChar ((long) ((evt->message & myKeyCodeMask) >> 8),
  440.                   (long) (modCode & shiftKey));
  441.              /* PWP: we pass through the shiftedness of this key */
  442.         else
  443.         c = evt->message & charCodeMask;    /* otherwise get the
  444.                              * standard char */
  445.  
  446.         /* make an uppercase character if the caps action bit is active */
  447.         if ((theModBits & CapsMask) && islower (c))
  448.         c = toupper (c);
  449.  
  450.         /* make a control character if the control action bit is active */
  451.         if (theModBits & CtrlMask)
  452.         c &= ctrlCodeMask;
  453.  
  454.         /* PWP: for Meta characters (yes, I use Emacs) */
  455.         if (theModBits & MetaMask)
  456.         c |= metaOrBits;
  457.  
  458.         if (!checkescape(c))
  459.         OutputChar (termw, c);
  460.         return;
  461.     }            /* if */
  462.     }                /* for */
  463.  
  464.     /* get the ASCII code and send it */
  465.     c = evt->message & charCodeMask;
  466.     if (!checkescape(c))
  467.     OutputChar(termw, c);
  468. }                /* handle_char */
  469.  
  470.  
  471. /*
  472.  * checkescape
  473.  * Handle escape sequences in connected mode
  474.  * Return TRUE if character used.
  475.  */
  476. #define NKBUF 10
  477. checkescape (char c)
  478. {
  479.     int x;
  480.     static int esclevel = 0;
  481.     static char *kbp, kbuf[NKBUF];
  482.     extern int cmdmsk;
  483.  
  484.     switch (esclevel) {
  485.     case 0:                /* no escapes pending */
  486.     if ((c & 0x7f) == escape) {
  487.         esclevel++;
  488.         return TRUE;        /* we ate the char */
  489.     }
  490.     return FALSE;            /* we did not process char */
  491.  
  492.     case 1:                /* process escape command */
  493.     if (doesc(c)) {            /* if CMDQ */
  494.         esclevel++;
  495.         kbp = kbuf;            /* preset buffer */
  496.         *kbp++ = CMDQ;
  497.     }
  498.     else
  499.         esclevel = 0;
  500.     return TRUE;            /* we ate the char */
  501.  
  502.     case 2:                /* quoted backslash sequence */
  503.     c &= cmdmsk;
  504.     *kbp = c;
  505.     if ((c != '\r') && (c != '\n')) {
  506.         if (&kbuf[NKBUF-1] != kbp)    /* if buffer not full */
  507.         kbp++;
  508.         return TRUE;
  509.     }
  510.     *kbp = 0;
  511.     esclevel = 0;
  512.  
  513.     kbp = kbuf;
  514.     x = xxesc(&kbp);
  515.     if (x >= 0) {
  516.         c = dopar(x);
  517.         ttoc(c);
  518.     } else {        /* Invalid backslash code. */
  519.         putchar(BEL);
  520.     }
  521.     return TRUE;
  522.     }
  523. }
  524.  
  525.  
  526. /*
  527.  * console_char
  528.  * Handle keyboard events while not connected
  529.  * Return TRUE if we inserted a character into the console buffer.
  530.  *
  531.  * THIS ROUTINE LIKELY NEEDS MORE WORK HANDLING SPECIAL CHARACTERS.
  532.  * 
  533.  */
  534. console_char (struct termw *termw, EventRecord *evt)
  535. {
  536.     short i;
  537.     short len;
  538.     short theCode;
  539.     short modCode;
  540.     short theModBits;
  541.     char flags;
  542.     Str255 tmpstr;
  543.     unsigned char c;
  544.  
  545.     /* (UoR) check for auto repeated keys */
  546.     if ((termw->autorepeat == FALSE) && (evt->what == autoKey))
  547.     return;
  548.  
  549.     ObscureCursor ();        /* PWP: hide the cursor until next move */
  550.  
  551.     modCode = evt->modifiers & keyModifierMask;
  552.     theCode = ((evt->message & myKeyCodeMask) >> 8) + (modCode >> 1);
  553.     
  554.     /* check for a special code for this key */
  555.     if (BitTst (keytable, theCode)) {
  556.     GetMacro (theCode, &flags, tmpstr); /* get the macrostring */
  557.  
  558.     if (flags) {            /* check special flags */
  559.        /* in local COMMAND mode, none of the special keys do anything */
  560.        /* $$$ (although we might want the keypad in numeric mode allways) */
  561.        return FALSE;        
  562.     }
  563.     /* send key macro string */
  564.     writecb(tmpstr);
  565.     return TRUE;
  566.     }
  567.  
  568.     for (i = 0; i < NUMOFMODS; i++) {
  569.     /* shift what to look for into high byte */
  570.     theModBits = modtable[i].modbits << 4;
  571.     len = strlen (modtable[i].prefix);
  572.  
  573.     if ((theModBits || len) &&
  574.         ((theModBits & modCode) == (theModBits & keyModifierMask))) {
  575.         /* send prefix if there is one */
  576.         if (len) {
  577.         /* PWP: these are saved as Pascal strings now */
  578.         BlockMove (modtable[i].prefix, tmpstr, 
  579.                (modtable[i].prefix[0] + 1));
  580.         writecb(tmpstr);    /* put in console buffer */
  581.         if (duplex != 0)
  582.             printps(termw,tmpstr);    /* echo it locally */
  583.         }
  584.  
  585.         /*
  586.          * get the unmodified ASCII code if the unmodify action bit is
  587.          * active
  588.          */
  589.         if (theModBits & UnmodMask)
  590.         c = DeModifyChar ((long) ((evt->message & myKeyCodeMask) >> 8),
  591.                   (long) (modCode & shiftKey));
  592.         /* PWP: we pass through the shiftedness of this key */
  593.         else
  594.         c = evt->message & charCodeMask; /* otherwise get the
  595.                           * standard char */
  596.  
  597.         /* make an uppercase character if the caps action bit is active */
  598.         if ((theModBits & CapsMask) && islower (c))
  599.         c = toupper (c);
  600.  
  601.         /* make a control character if the control action bit is active */
  602.         if (theModBits & CtrlMask)
  603.         c &= ctrlCodeMask;
  604.  
  605.         /* PWP: for Meta characters (yes, I use Emacs) */
  606.         if (theModBits & MetaMask)
  607.         c |= metaOrBits;
  608.  
  609.         writecbc(c);
  610.         return TRUE;
  611.     }                /* if */
  612.     }                    /* for */
  613.  
  614.     /* get the ASCII code and send it */
  615.     writecbc(evt->message & charCodeMask);
  616.     return TRUE;
  617. }
  618.  
  619.  
  620. /****************************************************************************/
  621. /****************************************************************************/
  622. /****************************************************************************/
  623. /* general rectangle routines                                               */
  624. /****************************************************************************/
  625.  
  626.  
  627.  
  628. /****************************************************************************/
  629. /*
  630.  * Routine makerect
  631.  *
  632.  * Make a rectangle in r starting on line lin and column col extending
  633.  * numlin lines and numcol characters.
  634.  *
  635.  */
  636. /****************************************************************************/
  637. void
  638. makerect(struct termw *termw, Rect *r,int lin, int col, int numlin,
  639.      int numcol)
  640. {
  641.     r->top = lin * termw->lineheight + TOPMARGIN;
  642.     r->left = col * termw->charwidth + LEFTMARGIN;
  643.     r->bottom = r->top + numlin * termw->lineheight;
  644.     r->right = r->left + numcol * termw->charwidth;
  645. }                /* makerect */
  646.  
  647. /* the (almost) inverse of makerect() */
  648. void
  649. recttocharpos(struct termw *termw, Rect *r, int *toplin_p, int *leftcol_p,
  650.           int *botlin_p, int *rightcol_p)
  651. {
  652.     /* Inverse of makerect(): find the bounding chars (rounding outward) */
  653.     *toplin_p = (r->top - TOPMARGIN) / termw->lineheight;
  654.     *botlin_p = (r->bottom - TOPMARGIN + termw->lineheight - 1)
  655.     / termw->lineheight;
  656.     *leftcol_p = (r->left - LEFTMARGIN) / termw->charwidth;
  657.     *rightcol_p = (r->right - LEFTMARGIN + termw->charwidth - 1)
  658.     / termw->charwidth;
  659.  
  660.     /* bounds limit it to the actual screen area */
  661.     if (*toplin_p < 0) *toplin_p = 0;
  662.     if (*botlin_p > termw->screensize) *botlin_p = termw->screensize;
  663.     if (*leftcol_p < 0) *leftcol_p = 0;
  664.     if (*rightcol_p > MAXCOL) *rightcol_p = MAXCOL;
  665. }
  666.  
  667. /* (PWP) do what makerect does, then invert the rect */
  668. void
  669. invertchars(struct termw *termw, int lin, int col, int numlin, int numcol)
  670. {
  671.     Rect r;
  672.     r.top = lin * termw->lineheight + TOPMARGIN;
  673.     r.left = col * termw->charwidth + LEFTMARGIN;
  674.     r.bottom = r.top + numlin * termw->lineheight;
  675.     r.right = r.left + numcol * termw->charwidth;
  676.     InvertRect (&r);
  677. }
  678.  
  679. /*
  680.  * Figure out how wide this line could be.  Not constant any more because of
  681.  * double width lines.
  682.  */
  683. int
  684. line_maxcol(struct termw *termw, int lin)
  685. {
  686.     if (termw->line_attrs[lin] != VT_SNGL)
  687.     return (MAXCOL / 2);
  688.     else
  689.     return (MAXCOL);
  690. }
  691.  
  692. /****************************************************************************/
  693. /* Connect support routines */
  694. /****************************************************************************/
  695. void term_new_font (struct termw *termw)
  696. {
  697.     FontInfo fi;
  698.     GrafPtr savePort;
  699.     
  700.     GetPort (&savePort);    /* there just has to be a better way */
  701.     SetPort (termw->window);
  702.  
  703.     SetFontLock(false);
  704.     termw->font_is_locked = false;
  705.     
  706.     TextFont(termw->current_font);    /* make sure to set this font */
  707.     TextSize(termw->current_size);
  708.     
  709.     GetFontInfo (&fi);
  710.     
  711.     termw->lineheight = fi.ascent + fi.descent + fi.leading;
  712.     termw->chardescent = fi.descent;
  713.     /* termw->charwidth = fi.widMax; */
  714.     termw->charwidth = CharWidth('W');        /* idea from NCSA telnet 2.3 */
  715.  
  716.     SetPort (savePort);        /* there just has to be a better way */
  717. }
  718.     
  719. /* consetup is called once at startup */
  720. struct termw *consetup (int boxid)
  721. {
  722.     struct termw *termw;
  723.     GrafPtr savePort;
  724.     extern struct termw *termwl;
  725.     
  726.     termw = (struct termw *)malloc(sizeof(struct termw));
  727.     if (!termw)
  728.     macfatal("consetup: no memory for terminal window", 0);
  729.     bzero((char *)termw, sizeof(struct termw));
  730.     termw->next = termwl;        /* add to list */
  731.     termwl = termw;
  732.     termw->current_font = VT100FONT;
  733.     termw->current_size = 9;
  734.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  735.     termw->oldlin = -1;
  736.     termw->from_lin = -1;
  737.     termw->screensize = INIT_SCREENSIZE; /* number of lines on screen */
  738.     termw->graphicsinset[0] = ASCII_SET;
  739.     termw->graphicsinset[1] = ASCII_SET;
  740.     termw->graphicsinset[2] = LAT1_SET;
  741.     termw->graphicsinset[3] = LAT1_SET;
  742.     termw->Gr_set = 1;            /* (PWP) current chosen RH set */
  743.     termw->old_Gl_set = -1;        /* set to come back to after */
  744.                     /* single shift GL */
  745.     termw->autowrap = TRUE;        /* Autowrap on by default */
  746.     termw->autorepeat = TRUE;        /* (UoR) auto repeat flag */
  747.     termw->dispcontchar = TRUE;        /* do not show control characters */
  748.     termw->blockcursor = TRUE;        /* show block or underline cursor */
  749.     termw->cursor_shown = TRUE;        /* (PWP) show the cursor */
  750.     termw->blinkcursor = TRUE;        /* true if we make the cursor blink */
  751.     termw->charflg = CF_OUTC;        /* state variable */
  752.  
  753.     setWindowLoc(boxid);
  754. #ifdef notdef
  755.     termw->window = GetNewWindow (boxid, (Ptr) &termw->terminalWRec, 
  756.                  (WindowPtr) -1L);
  757. #endif
  758.     termw->window = GetNewWindow (boxid, (Ptr) 0L, (WindowPtr) -1L);
  759.  
  760.     if (!termw->window)
  761.         macfatal("Could not GetNewWindow() -- can't find window template", 0);
  762.  
  763.     GetPort (&savePort);    /* there just has to be a better way */
  764.     SetPort (termw->window);
  765.  
  766.     PenMode (srcCopy);        /* (PWP) was patXor */
  767.     flushio ();            /* Get rid of pending characters */
  768.  
  769.     termw->current_font = VT100FONT;    /* (UoR) Set initial font to VT100 */
  770.     termw->current_size = 9;
  771.     
  772.     if (termw->screeninvert)
  773.     TextMode (srcBic);
  774.     else
  775.     TextMode (srcOr);
  776.     TextFace (0);        /* PWP: be safe.  We allways stay like this */
  777.  
  778.     init_term(termw);        /* Set up some terminal variables */
  779.  
  780.     /* reset the font (chosen above) */
  781.     term_new_font(termw);
  782.     /* doesn't change #lines, but size of a line has changed */
  783.     grow_term_to(termw,termw->screensize);
  784.  
  785.     /* normal char mode, home cursor, clear screen, and save position */
  786.     norm_home_clear_save(termw);
  787.  
  788.     cursor_draw(termw);        /* (UoR) be sure to draw it */
  789.  
  790.     SetPort (savePort);        /* there just has to be a better way */
  791.     
  792.     return termw;
  793. }                /* consetup */
  794.  
  795. void term_reset (struct termw *termw)
  796. {
  797.     GrafPtr savePort;
  798.     
  799.     GetPort (&savePort);    /* there just has to be a better way */
  800.     SetPort (termw->window);
  801.  
  802.     PenMode (srcCopy);        /* (PWP) was patXor */
  803.     flushio ();            /* Get rid of pending characters */
  804.     screen_to_bottom(termw);    /* slide the visible region to active area */
  805.  
  806.     termw->graphicsinset[0] = ASCII_SET;
  807.     termw->graphicsinset[1] = GRAF_SET;
  808.     termw->Gl_set = 0;
  809.     termw->Gr_set = 1;
  810.     termw->textstyle = 0;
  811.     termw->current_style = 0;
  812.     termw->draw_sing_chars = 0;
  813.     termw->font_is_locked = FALSE;
  814.     termw->screeninvert = FALSE;    /* (UoR) inverted screen flag */
  815.     termw->insert = FALSE;
  816.     termw->newline = FALSE;        /* (UoR) linefeed mode by default */
  817.     termw->autowrap = TRUE;        /* Autowrap on by default */
  818.     termw->relorigin = FALSE;        /* (UoR) relative origin off */
  819.     termw->autorepeat = TRUE;        /* (UoR) auto repeat flag */
  820.     termw->appl_mode = FALSE;        /* (PWP) keypad application mode */
  821.     termw->curskey_mode = FALSE;    /* (PWP) cursor key application mode */
  822.     termw->smoothscroll = FALSE;    /* do smooth scrolling (PWP: or not) */
  823.     termw->scroll_amount = 0;        /* no pending scroll */
  824.     termw->refresh_amount = 0;        /* no pending refresh */
  825.     termw->dispcontchar = TRUE;    /* do not show control characters */
  826.     termw->blockcursor = TRUE;        /* show block or underline cursor */
  827.     termw->cursor_shown = TRUE;    /* (PWP) show the cursor */
  828.     termw->mouse_arrows = FALSE;    /* mouse down in screen does arrow keys */
  829.     termw->visible_bell = FALSE;    /* true if we do blink instead of bell */
  830.     termw->eightbit_disp = FALSE;    /* default to 7 bits */
  831.     termw->blinkcursor = TRUE;        /* true if we make the cursor blink */
  832.  
  833.  
  834.     termw->have_selection = FALSE;    /* (PWP) we have no selected text */
  835.     
  836.     termw->saved_tlin = 0;
  837.     termw->saved_blin = 0;
  838.     
  839.     termw->current_font = VT100FONT;    /* (UoR) Set initial font to VT100 */
  840.     termw->current_size = 9;
  841.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  842.  
  843.     if (termw->screeninvert)
  844.     TextMode (srcBic);
  845.     else
  846.     TextMode (srcOr);
  847.     TextFace (0);        /* PWP: be safe.  We allways stay like this */
  848.     
  849.     /* reset the font (chosen above) */
  850.     term_new_font(termw);
  851.     /* doesn't change #lines, but size of a line has changed */
  852.     grow_term_to(termw,termw->screensize);
  853.  
  854.     /* normal char mode, home cursor, clear screen, and save position */
  855.     norm_home_clear_save(termw);
  856.     
  857.     cursor_draw(termw);        /* (UoR) be sure to draw it */
  858.  
  859.     SetPort (savePort);        /* there just has to be a better way */
  860. }                /* consetup */
  861.  
  862. /****************************************************************************/
  863. /****************************************************************************/
  864.  
  865.  
  866. /*************************************************/
  867. /* cursor drawing stuff                          */
  868. /*************************************************/
  869.  
  870. Boolean cursor_rect (struct termw *termw, int line, int col, Rect *r)
  871. {
  872.     /* if cursor not on screen */
  873.     if (line - termw->display_topline >= termw->screensize)
  874.         return FALSE;
  875.     
  876.     if (col >= 80)            /* make it look like a VT100 */
  877.     col = 79;
  878.     
  879.     /* Get character rectangle */
  880.     makerect(termw,r, line - termw->display_topline, col, 1, 1);
  881.     if (!termw->blockcursor) {
  882.     r->top = r->bottom;
  883.     r->bottom = r->top + 2;
  884.     }
  885.  
  886.     return TRUE;
  887. }                    /* cursor_rect */
  888.  
  889. void cursor_draw (struct termw *termw)
  890. {
  891.     Rect r;
  892.     GrafPtr savePort;
  893.  
  894.     if (!termw->cursor_shown)         /* (PWP) not if we are hiding cursor */
  895.     return;
  896.     
  897.     GetPort (&savePort);    /* there just has to be a better way */
  898.     SetPort (termw->window);
  899.  
  900.     if (!termw->cursor_invert) {
  901.     if (cursor_rect(termw,termw->curlin, termw->curcol, &r)) {
  902.         if (termw->in_front) {
  903.         InvertRect (&r);
  904.         } else {
  905.         PenMode (patXor);
  906.         FrameRect (&r);
  907.         PenMode (patCopy);
  908.         }
  909.     }
  910.     }
  911.  
  912.     /* replace mouse cursor */
  913.     if ((termw->oldlin >= 0) && (!termw->mousecurs_drawn)) {
  914.     makerect(termw ,&r, termw->oldlin, termw->oldcol, 1, 1);
  915.     PenMode (patXor);
  916.     FrameRect (&r);
  917.     PenMode (patCopy);
  918.     termw->mousecurs_drawn = TRUE;
  919.     }
  920.     
  921.     termw->cursor_invert = TRUE;
  922.     termw->cur_drawn = TRUE;
  923.  
  924.     SetPort (savePort);        /* there just has to be a better way */
  925. }                /* cursor_draw */
  926.  
  927.  
  928. void cursor_erase (struct termw *termw)
  929. {
  930.     Rect r;
  931.     GrafPtr savePort;
  932.     
  933.     GetPort (&savePort);    /* there just has to be a better way */
  934.     SetPort (termw->window);
  935.  
  936.     if (termw->cursor_invert) {
  937.     if (cursor_rect(termw, termw->curlin, termw->curcol, &r)) {
  938.         if (termw->in_front) {
  939.         InvertRect (&r);
  940.         } else {
  941.         PenMode (patXor);
  942.         FrameRect (&r);
  943.         PenMode (patCopy);
  944.         }
  945.     }
  946.     }
  947.     /* remove mouse cursor */    
  948.     if ((termw->oldlin >= 0) && (termw->mousecurs_drawn)) {
  949.     makerect(termw ,&r, termw->oldlin, termw->oldcol, 1, 1);
  950.     PenMode (patXor);
  951.     FrameRect (&r);
  952.     PenMode (patCopy);
  953.      termw->mousecurs_drawn = FALSE;
  954.    }
  955.  
  956.     termw->cursor_invert = FALSE;
  957.     termw->cur_drawn = FALSE;
  958.  
  959.     SetPort (savePort);        /* there just has to be a better way */
  960. }                /* cursor_erase */
  961.  
  962. void flash_cursor (struct termw *termw)
  963. {
  964.     register long tc;
  965.     Rect r;
  966.     GrafPtr savePort;
  967.     
  968.     GetPort (&savePort);    /* there just has to be a better way */
  969.     SetPort (termw->window);
  970.  
  971.     tc = TickCount ();
  972.     if (((tc - termw->last_flash) > MyCaretTime) ||
  973.     (tc - termw->last_flash) < 0L) {
  974.     termw->last_flash = tc;
  975.  
  976.     if (termw->cur_drawn) {
  977.         if (cursor_rect(termw,termw->curlin, termw->curcol, &r)) {
  978.         /* PWP: only blink if asked for */
  979.         if (termw->blinkcursor && termw->in_front) {
  980.             InvertRect (&r);
  981.             termw->cursor_invert = !termw->cursor_invert;
  982.         } else if (!termw->cursor_invert) {
  983.                 /* make sure that the cursor shows up */
  984.             if (termw->in_front) {
  985.             InvertRect (&r);
  986.             } else {
  987.             PenMode (patXor);
  988.             FrameRect (&r);
  989.             PenMode (patCopy);
  990.             }
  991.             termw->cursor_invert = TRUE;
  992.         }
  993.         }
  994.     }
  995.     }
  996.  
  997.     SetPort (savePort);        /* there just has to be a better way */
  998. }                /* flash_cursor */
  999.  
  1000.  
  1001. /****************************************************************************/
  1002. /* PWP -- like waitasec(), but don't get any characters.  Used for 
  1003.    visable bell. */
  1004. /****************************************************************************/
  1005. waitnoinput ()
  1006. {
  1007.     long ticks = 2, end_time;
  1008.  
  1009.     Delay (ticks, &end_time);    /* pause for 1/30th second */
  1010. }                /* waitnoinput */
  1011.  
  1012.  
  1013. /****************************************************************************/
  1014. /* (UoR) get any characters, and pause for a while */
  1015. /****************************************************************************/
  1016. waitasec (struct termw *termw)
  1017. {
  1018.     waitnoinput();
  1019.     inpchars(termw);
  1020. }                /* waitasec */
  1021.  
  1022.  
  1023. /****************************************************************************/
  1024. /* updateCursor -- taken from NCSA Telnet for the Macintosh, v 2.2   */
  1025. /****************************************************************************/
  1026. void updateCursor (struct termw *termw, int force, WindowPeek myfrontwindow)
  1027. {
  1028.     static Point lastPoint;
  1029.     static int optwasdown = 0;
  1030.     Cursor *thisCursor;
  1031.     int optDown;
  1032.     KeyMap allthekeys;    /* Someplace to put the keymap */
  1033.     char *cp_allthekeys = (char *) &allthekeys;    /* $$$ HACK HACK */
  1034.     int newlin, newcol;
  1035.     Point MousePt;
  1036.     Rect r;
  1037.     GrafPtr savePort;
  1038.     
  1039.     GetPort (&savePort);    /* there just has to be a better way */
  1040.     SetPort (termw->window);
  1041.  
  1042.     GetMouse(&MousePt);
  1043.  
  1044.     GetKeys(allthekeys);
  1045.     optDown = cp_allthekeys[7] & 4;    /* should be symbolic */
  1046.  
  1047.     if ( (!force) && (!in_background)
  1048.         && (MousePt.v == lastPoint.v) && (MousePt.h == lastPoint.h)
  1049.     && (optDown == optwasdown))
  1050.     {
  1051.     SetPort (savePort);
  1052.     return;
  1053.     }
  1054.     
  1055.     if (force)
  1056.     lastCursor=0L;
  1057.     
  1058.     if (in_background) {
  1059.     lastCursor = 0L;        /* allways force if in background */
  1060.     thisCursor = normcurs;        /* default cursor shape */
  1061.     } else if (protocmd != 0) {        /* if doing a transfer */
  1062.     thisCursor = watchcurs;        /* in forground and doing a transfer */
  1063.     } else if (((myfrontwindow == (WindowPeek) termw->window) ||
  1064.         ((myfrontwindow == NIL) &&
  1065.          (FrontWindow() == termw->window))) &&
  1066.            PtInRect(MousePt, &termw->ScreenRect)) {
  1067.     if (termw->mouse_arrows || optDown) {
  1068.         newlin = (MousePt.v - TOPMARGIN) / termw->lineheight;
  1069.         newcol = (MousePt.h - LEFTMARGIN + termw->charwidth/2) / 
  1070.         termw->charwidth;
  1071.     
  1072.         if ((termw->oldlin != newlin) || (termw->oldcol != newcol)) {
  1073.         PenMode (patXor);    /* For FrameRect calls */
  1074.         if (termw->oldlin >= 0) { /* if old rectangle */
  1075.             if (termw->mousecurs_drawn) {
  1076.             makerect(termw,&r, termw->oldlin, termw->oldcol, 1, 1);
  1077.             FrameRect (&r);
  1078.             }
  1079.         } else {           /* else if drawing for the first time */
  1080.             HideCursor ();
  1081.         }
  1082.         
  1083.         makerect(termw,&r, newlin, newcol, 1, 1);
  1084.         FrameRect (&r);
  1085.         PenMode (patCopy);    /* reset to normal pen mode */
  1086.     
  1087.         termw->oldlin = newlin;
  1088.         termw->oldcol = newcol;
  1089.         termw->mousecurs_drawn = TRUE;
  1090.         }
  1091.         lastPoint=MousePt;
  1092.         optwasdown=optDown;
  1093.         SetPort (savePort);        /* there just has to be a better way */
  1094.         return;
  1095.     } else {            
  1096.         thisCursor = textcurs;
  1097.     }
  1098.     } else {
  1099.     thisCursor  = normcurs;        /* default cursor shape */
  1100.     }
  1101.     
  1102.     if  (lastCursor!= thisCursor) {
  1103.     SetCursor(thisCursor);
  1104.     lastCursor = thisCursor;
  1105.     }
  1106.  
  1107.     lastPoint=MousePt;
  1108.     optwasdown=optDown;
  1109.  
  1110.     if (termw->oldlin >= 0) {         /* if we hade drawn a movement outline */
  1111.     if (termw->mousecurs_drawn) {
  1112.         PenMode (patXor);    /* For FrameRect calls */
  1113.         makerect(termw,&r, termw->oldlin, termw->oldcol, 1, 1);
  1114.         FrameRect (&r);
  1115.     }
  1116.     
  1117.     termw->oldlin = -1;
  1118.      termw->mousecurs_drawn = FALSE;
  1119.     ShowCursor ();
  1120.     PenMode (patCopy);    /* reset to normal pen mode */
  1121.     }
  1122.  
  1123.     SetPort (savePort);        /* there just has to be a better way */
  1124. }
  1125.  
  1126.  
  1127. /****************************************************************************/
  1128. /* Put characters onto the actual screen                                    */
  1129. /****************************************************************************/
  1130.  
  1131. static int to_mac_style[] = {
  1132.     normal,    underline, italic, underline|italic,
  1133.     bold|condense, bold|condense|underline,
  1134.     bold|condense|italic, bold|condense|underline|italic
  1135. };
  1136.  
  1137. /****************************************************************************/
  1138. /* flushbuf(termw) -- draw all the buffered characters on the screen */
  1139. /****************************************************************************/
  1140. void flushbuf (struct termw *termw)
  1141. {
  1142.     register int scrl_amt;
  1143.  
  1144.     if (termw->out_maxcol == 0)
  1145.     return;            /* Nothing to flush */
  1146.  
  1147.     if (to_printer) {                    /*JAO*/
  1148. #ifdef COMMENT
  1149.         /* This is the old stuff that should go away */
  1150.     for (i = termw->out_mincol; i < termw->out_maxcol; i++) {
  1151.         (*hPrintBuffer)[lPrintBufferAt++] = 
  1152.         termw->scr[termw->curlin+termw->display_topline][i];
  1153.         if (lPrintBufferAt == lPrintBufferSize)
  1154.         lPrintBufferAt = 0L;
  1155.         lPrintBufferChars++;
  1156.         if (lPrintBufferChars == 1L)
  1157.         updatepstat();
  1158.         if (lPrintBufferChars == lPrintBufferSize) {
  1159.         overflowingDialog = GetNewDialog(OVERFLOWINGBOXID, NILPTR, 
  1160.                          (WindowPtr) - 1);
  1161.         DrawDialog(overflowingDialog);
  1162.         break;                    /* PWP */
  1163.         }
  1164.     }
  1165. #endif /* COMMENT */
  1166.     
  1167.     /* And this is the new way */
  1168.     add_to_print (termw->out_maxcol - termw->out_mincol,
  1169.               (char *) termw->scr[termw->curlin+termw->display_topline]
  1170.                    + termw->out_mincol);
  1171.     }
  1172.  
  1173.     if (!to_screen) {
  1174.     termw->out_maxcol = 0;        /* Say no more chars to output */
  1175.     return;                /*JAO*/
  1176.     }
  1177.     
  1178.     /* save because flushscroll() resets scroll_amount */
  1179.     scrl_amt = termw->scroll_amount;
  1180. #ifdef COMMENT
  1181.     if (scrl_amt) {
  1182.     /*
  1183.      * If we have pending scrolling, and we are about to draw outside 
  1184.      * of the region that will be refreshed when the scrolling happens, 
  1185.      * do the scrolling now.
  1186.      */
  1187.         if ((termw->refresh_amount < 0) && 
  1188.         ((termw->curlin < termw->saved_blin + termw->refresh_amount)
  1189.          || (termw->curlin > termw->saved_blin)))
  1190.     {
  1191.         flushscroll(termw);
  1192.     }
  1193.     else if ((termw->refresh_amount > 0) && 
  1194.          ((termw->curlin < termw->saved_tlin)
  1195.           || (termw->curlin
  1196.               > termw->saved_tlin + termw->refresh_amount)))
  1197.     {
  1198.         flushscroll(termw);
  1199.     }
  1200.     else
  1201.     {
  1202.         termw->out_maxcol = 0;    /* Say no more chars to output */
  1203.         return;
  1204.     }
  1205.     }
  1206. #endif /* COMMENT */
  1207.  
  1208.     if (scrl_amt)
  1209.     flushscroll(termw);
  1210.  
  1211.     if (termw->have_selection)
  1212.     maybe_nuke_selection (termw, termw->curlin, termw->curlin);
  1213.  
  1214.     if (!termw->out_maxcol)    /* if already drawn this line, return */
  1215.     return;
  1216.  
  1217.     /*
  1218.      * PWP: Why have two routines to do the same thing?  I centralized
  1219.      * all the font crap into draw_line_w_attrs so I didn't need
  1220.      * to keep track of code here too.  Side benifit -- we can nuke
  1221.      * the outbuf array.
  1222.      *
  1223.      * Note that in draw_line_w_attrs(), the left and right columns are
  1224.      * SCREEN columns, not virtual buffer columns.  Theses are usually
  1225.      * the same, unless we happen to be drawing onto a double-width line.
  1226.      */
  1227.     if (termw->line_attrs[termw->curlin] == VT_SNGL) {
  1228.     /* single-width (normal) line */
  1229.     draw_line_w_attrs(termw, termw->curlin + termw->display_topline, 
  1230.               termw->curlin, termw->out_mincol, termw->out_maxcol, 
  1231.               (scrl_amt == 0));
  1232.     } else {
  1233.     /* line with double width characters */
  1234.     draw_line_w_attrs(termw, termw->curlin + termw->display_topline, 
  1235.               termw->curlin, 2 * termw->out_mincol,
  1236.               2 * termw->out_maxcol, (scrl_amt == 0));
  1237.     }
  1238.     termw->out_maxcol = 0;        /* Say no more chars to output */
  1239. }                /* flushbuf */
  1240.  
  1241. /****************************************************************************/
  1242. /* set_style(termw, style)
  1243.  - set the correct stuff for displaying chars in style   */
  1244. /****************************************************************************/
  1245. void set_style (struct termw *termw, int style)
  1246. {
  1247.     int m_sty, m_font;
  1248.     static int o_sty = 0, o_font = 0;
  1249.     
  1250.     if (style == termw->current_style) 
  1251.     return;
  1252.     termw->current_style = style;
  1253.     
  1254.     m_sty = to_mac_style[style & STY_MSTY];
  1255.     m_font = ((style & STY_FONT) >> 3) + termw->current_font;
  1256.     termw->draw_sing_chars = ((style & VT_BLINK)
  1257.                   || (CharWidth('W')!=CharWidth('i'))
  1258.                   || (!RealFont(termw->current_font,
  1259.                         termw->current_size)));
  1260.     /* printerr("draw_sing_chars == ", draw_sing_chars); */
  1261.  
  1262.     if (!have_128roms && (m_sty & bold)) {   /* if on an old mac and bolding */
  1263.     if (m_font == VT100FONT) {
  1264.         m_font = VT100BOLD;
  1265.         m_sty &= ~(bold|condense);
  1266.     } else {
  1267.         termw->draw_sing_chars = 1;
  1268.     }
  1269.     }
  1270.  
  1271.     if (m_font != o_font) {
  1272.     TextFont (m_font);        /* new font */
  1273.     o_font = m_font;
  1274.     }
  1275.     if (m_sty != o_sty) {
  1276.     TextFace (m_sty);        /* new text face */
  1277.     o_sty = m_sty;
  1278.     }
  1279. }
  1280.  
  1281. /****************************************************************************
  1282.  * draw_line_w_attrs() -- draw the line including all character attributes
  1283.  * that is in the terminal buffer at line "lin" onto the screen at vertical
  1284.  * character offset "v", in as little time as possible.
  1285.  *
  1286.  * It seems to speed things up just a tad to skip leading and trailing
  1287.  * whitespace on the line, so we can draw only the characters in the middle.
  1288.  * On the other hand, it doesn't save any time to find the individual words
  1289.  * and draw just those.  Likewise, if we have to draw the line one character
  1290.  * at a time it is really slow. 
  1291.  *
  1292.  * Perhaps a later version of Kermit could take the current fonts and build 
  1293.  * custom set of fixed width fonts (a'la BitFont), and then use that to draw
  1294.  * characters onto the screen.
  1295.  *
  1296.  * Another later addition could be correct handling of double width and double
  1297.  * height characters, by drawing the characters into an off-screen bitmap,
  1298.  * and then using CopyBits to stretch the characters to fit.
  1299.  */
  1300.  
  1301. void draw_line_w_attrs (struct termw *termw, register int lin, register int v,
  1302.           register int l_col, register int r_col,
  1303.           int must_drawblanks)
  1304. {
  1305.     register int o, i, j, sty;
  1306.     register unsigned char *cp, *ap, *line_ch, *line_at;
  1307.     register int min, max;
  1308.     register int lines_attrs;
  1309.     int orig_l_col;
  1310.     Rect r;
  1311.     
  1312.     if (!termw)
  1313.     DebugStr("\ptermw == NULL");
  1314.  
  1315.     /* this routine CAN be called with scrolling_region non-zero */
  1316.     
  1317.     /* bounds limit the min and max columns */
  1318.     if (l_col < 0) l_col = 0;
  1319.     if (l_col > MAXCOL) l_col = MAXCOL;
  1320.     if (r_col < 0) r_col = 0;
  1321.     if (r_col > MAXCOL) r_col = MAXCOL;
  1322.     
  1323.     /* if nothing to do, don't bother */
  1324.     if ((r_col == 0) || (l_col == r_col))
  1325.     return;
  1326.     
  1327.     /***** I shouldn't have to put this here! *****/
  1328.     if (termw->screeninvert) {
  1329.     BackPat(qd.black);
  1330.     PenPat(qd.white);
  1331.     TextMode (srcBic);
  1332.     } else {
  1333.     BackPat(qd.white);
  1334.     PenPat(qd.black);
  1335.     TextMode (srcOr);
  1336.     }
  1337.  
  1338.     if ((v < 0) || (v > termw->screensize))
  1339.     printerr("draw_line_w_attrs, v out of range:", v);
  1340.  
  1341.     line_ch = termw->scr[lin];
  1342.     line_at = termw->scr_attrs[lin];
  1343.     lines_attrs = (int) termw->line_attrs[lin];
  1344.     if (lines_attrs != VT_SNGL) {
  1345.     /* double width lines have half as many characters (duh!) */
  1346.     orig_l_col = l_col;
  1347.     l_col /= 2;
  1348.     r_col = (r_col + 1) / 2;    /* round out to next highest */
  1349.     }
  1350.     
  1351.     /*
  1352.      * find the last character that is not a plain space character
  1353.      */
  1354.     sty = 0;    /* the style for normal blank space */
  1355.     cp = line_ch + r_col-1;
  1356.     ap = line_at + r_col-1;
  1357.     for (max = r_col-1; max >= l_col; max--) {
  1358.             /* PWP: we should never see a NUL in the line here */
  1359.     if ((*cp-- != ' ') || (*ap-- != sty))
  1360.         break;
  1361.     
  1362.     }
  1363.     max++;    /* point to one after the last non-space character */
  1364.     if (max > r_col) max = r_col;
  1365.  
  1366.     /*
  1367.      * find the first character that is not a plain space character
  1368.      */
  1369.     sty = 0;    /* the style for normal blank space */
  1370.     cp = line_ch + l_col;
  1371.     ap = line_at + l_col;
  1372.     for (min = l_col; min < max; min++) {
  1373.             /* PWP: we should never see a NUL in the line here */
  1374.     if ((*cp++ != ' ') || (*ap++ != sty))
  1375.         break;
  1376.     }
  1377.  
  1378.     /* If there is anything to erase, erase it */
  1379.     if (must_drawblanks) {
  1380.     if (lines_attrs == VT_SNGL)
  1381.         makerect(termw,&r, v, l_col, 1, r_col-l_col);
  1382.     else
  1383.         makerect(termw,&r, v, (2 * l_col), 1, 2 * (r_col-l_col));
  1384.     EraseRect (&r);
  1385.     }
  1386.         
  1387.     /* A slight speedup -- tell the Mac not to remove this font from RAM */
  1388.     if (!termw->font_is_locked) {
  1389.     SetFontLock(true);
  1390.     termw->font_is_locked = true;
  1391.     }
  1392.         
  1393.  
  1394.     if (lines_attrs == VT_SNGL) {
  1395.     /*
  1396.      * loop through all the characters up to max, looking for the longest
  1397.      * string of characters all of the same style.  Draw them, switch
  1398.      * styles, and repeat until max.
  1399.      */
  1400.     sty = line_at[min];
  1401.     o = min;
  1402.     i = min;
  1403.     while (i <= max) {
  1404.         /* if this style != current style */
  1405.         if ((line_at[i] != sty) || (i == max)) {
  1406.         if (sty != termw->current_style)
  1407.             set_style(termw, sty);
  1408.  
  1409.         if (termw->draw_sing_chars) {
  1410.             /*
  1411.              * We can't just increment o here because we may need
  1412.              * it to correctly draw the inverse video rect (below).
  1413.              */
  1414.             for (j = o, cp = line_ch + o; j < i; j++, cp++) {
  1415.             MOVETOCHAR(j, v);
  1416.             DrawChar((short) (*cp & 0377));
  1417.             }
  1418.         } else {    /* non-blinking */
  1419.             MOVETOCHAR(o, v);
  1420.             DrawText (line_ch, (short) o, (short) i-o);
  1421.                 /* Output this part */
  1422.         }
  1423.         
  1424.         if (sty & VT_INVERT) {
  1425.             makerect(termw,&r, v, o, 1, i-o);
  1426.             InvertRect (&r);
  1427.         }
  1428.         
  1429.         o = i;    /* now left extent == current */
  1430.         sty = line_at[i];    /* new current style */
  1431.         }
  1432.         i++;
  1433.     }
  1434.     } else {
  1435. #undef OFFSCREEN_STRETCHED_CHARS /* because this code doesn't work */
  1436. #ifdef OFFSCREEN_STRETCHED_CHARS
  1437.  
  1438.     RgnHandle clip_rgn = NewRgn();
  1439.     Rect offRect;
  1440.     Rect src_r, dest_r;
  1441.     GrafPtr oldPort;
  1442.     GrafPort offScreen;
  1443.         
  1444.     /* allocate our off-screen bitmap */
  1445.     GetPort(&oldPort);
  1446.     OpenPort(&offScreen);
  1447.     
  1448.     /* Make our off-screen bitmap the size of one line (plus a little) */
  1449.     offRect.top = 0;
  1450.     offRect.left = 0;
  1451.     offRect.bottom = termw->lineheight + TOPMARGIN + 2;
  1452.     offRect.right = termw->charwidth + LEFTMARGIN + 2;
  1453.  
  1454.     offScreen.portRect = offRect;
  1455.     offScreen.portBits.bounds = offRect;
  1456.     SetRectRgn(offScreen.visRgn, 0, 0, offRect.right, offRect.bottom);
  1457.     SetRectRgn(offScreen.clipRgn, 0, 0, offRect.right, offRect.bottom);
  1458.  
  1459.     /* rowBytes is the size of a row, rounded up to an even number */
  1460.     /* of bytes */
  1461.     offScreen.portBits.rowBytes = (((offScreen.portBits.bounds.right
  1462.             - offScreen.portBits.bounds.left) + 15) >> 4) << 1;
  1463.     
  1464.     /* number of bytes in BitMap is rowBytes * number of rows */
  1465.     /* this calculation must be down with longs */
  1466.     offScreen.portBits.baseAddr
  1467.         = NewPtr((long) offScreen.portBits.rowBytes
  1468.              * (long) (offScreen.portBits.bounds.bottom
  1469.                    - offScreen.portBits.bounds.top));
  1470.     
  1471.     if (!offScreen.portBits.baseAddr)    /* we didn't get the memory */
  1472.         return;        /* just forget it */
  1473.  
  1474.     /*
  1475.      * We are drawing double-width (and maybe double height) chars.
  1476.      *
  1477.      * First, draw the line normally, but starting at the
  1478.      * real position of original the original value of l_col.
  1479.      */
  1480.     SetPort (&offScreen);
  1481.     BackPat(qd.white);
  1482.     PenPat(qd.black);
  1483.     TextMode (srcOr);
  1484.     EraseRect(&qd.thePort->portRect);    /* erase just in case */
  1485.  
  1486.     o = 0;
  1487.     cp = line_ch + min;
  1488.     ap = line_at + min;
  1489.     termw->current_style = 0xFFFF;        /* force set_style to set */
  1490.     set_style(termw, *ap);            /* CHECK THIS */
  1491.     for (i = min; i <= max; i++) {
  1492.         if (*ap != termw->current_style)
  1493.         set_style(termw, *ap);
  1494.         MOVETOCHAR(o, 0);            /* line 0 of off-screen port */
  1495.         DrawChar((short) (*cp & 0377));
  1496.         if (*ap & VT_INVERT) {
  1497.         makerect(termw,&r, v, o, 1, 1);
  1498.         InvertRect (&r);
  1499.         }
  1500.         o++;
  1501.         cp++;
  1502.         ap++;
  1503.     }
  1504.  
  1505.     /* set the output port back to the screen */
  1506.     SetPort(oldPort);
  1507.     termw->current_style = 0xFFFF;    /* force set_style to set again */
  1508.  
  1509.     /* Next, stretch the characters using a CopyBits() */
  1510.     /* find the clipping region */
  1511.     makerect(termw, &r, v, (2 * l_col), 1, 2 * (r_col-l_col));
  1512.     RectRgn (clip_rgn, &r);
  1513.     FillRgn (clip_rgn, qd.gray);
  1514.     
  1515.     /* compute the source rect (where we just drew characters into) */
  1516.     r = offScreen.portRect;
  1517.     r.right = (max-min+1) * termw->charwidth;
  1518.  
  1519.     /* 
  1520.      * Compute the dest rect.  This also defines how we stretch
  1521.      * the characters out to be double width.
  1522.      */
  1523.     if (lines_attrs == VT_DBLH_T) {
  1524.         makerect(termw, &dest_r, v, ((2 * l_col) + (min - l_col)),
  1525.         2, (2 * (max-min+1)));
  1526.     } else if (lines_attrs == VT_DBLH_B) {
  1527.         makerect(termw, &dest_r, (v-1), ((2 * l_col) + (min - l_col)),
  1528.         2, (2 * (max-min+1)));
  1529.     } else {        /* lines_attrs == VT_DBLW */
  1530.         makerect(termw, &dest_r, v, ((2 * l_col) + (min - l_col)),
  1531.         1, (2 * (max-min+1)));
  1532.     }
  1533.  
  1534.     makerect(termw, &dest_r, v, (2 * min), 1, (1 * (max-min+1)));
  1535.  
  1536.     makerect(termw, &src_r, 0, min, 1, (max-min+1));
  1537.  
  1538.     /* now stretch those bits */
  1539.     CopyBits (&offScreen.portBits, &qd.thePort->portBits,
  1540.           &src_r, &dest_r,
  1541.           ((termw->screeninvert) ? notSrcCopy : srcCopy), clip_rgn);
  1542.     
  1543.     /* clean up */
  1544.     DisposeRgn(clip_rgn);
  1545.     ClosePort(&offScreen);
  1546.  
  1547. #else /* !OFFSCREEN_STRETCHED_CHARS */
  1548.  
  1549.     /* draw the double width line as double spaced characters */
  1550.     o = min;
  1551.     cp = line_ch + min;
  1552.     ap = line_at + min;
  1553.     for (i = min; i <= max; i++) {
  1554.         if (*ap != termw->current_style)
  1555.         set_style(termw, *ap);
  1556.         MOVETOCHAR((2 * o), v);
  1557.         DrawChar((short) (*cp & 0377));
  1558.         if (*ap & VT_INVERT) {
  1559.         makerect(termw,&r, v, (2 * o), 1, 2);
  1560.         InvertRect (&r);
  1561.         }
  1562.         o++;
  1563.         cp++;
  1564.         ap++;
  1565.     }
  1566.  
  1567. #endif /* !OFFSCREEN_STRETCHED_CHARS */
  1568.  
  1569.     }
  1570. }                /* draw_line_w_attrs() */
  1571.  
  1572.  
  1573. /****************************************************************************/
  1574. /****************************************************************************/
  1575. void scroll_term (struct termw *termw)
  1576. {
  1577.     register int new_topline, delta, lin, i;
  1578.     int fl, fc, tl, tc;
  1579.     Rect r;            /* cannot be register */
  1580.  
  1581.     new_topline = termw->screensize - termw->display_totlines + 
  1582.     GetCtlValue (termw->t_vscroll);
  1583.     if ((new_topline > 0) ||
  1584.     (new_topline <  termw->screensize - MAX_SCREENSIZE)) {
  1585.         printerr("BUG: in scroll_term(), new_topline out of range:",
  1586.          new_topline);
  1587.     return;
  1588.     }
  1589.     if ((delta = (termw->display_topline - new_topline)) == 0)
  1590.     return;        /* we didn't move */
  1591.  
  1592.     makerect(termw,&r, 0, 0, termw->screensize, MAXCOL);
  1593.     
  1594.     /* if whole screen */
  1595.     if ((delta >= termw->screensize) || (-delta >= termw->screensize)) {
  1596.         EraseRect(&r);
  1597.     
  1598.         lin = new_topline;            /* new top line */
  1599.     for (i = 0; i < termw->screensize; i++) {
  1600.         draw_line_w_attrs(termw, lin, i, 0, MAXCOL, 0);
  1601.         lin++;
  1602.     }
  1603.     termw->display_topline = new_topline;
  1604.  
  1605.     if (termw->have_selection)
  1606.         invert_text(termw,
  1607.             termw->from_lin,
  1608.             termw->from_col,
  1609.             termw->to_lin,
  1610.             termw->to_col);
  1611.         
  1612.     return;    /* we are done */
  1613.     }
  1614.  
  1615.     /* if we get here, we are not doing the whole screen */
  1616.     ScrollRect (&r, 0, delta * termw->lineheight, dummyRgn);
  1617.  
  1618.     if (delta > 0) {    /* scrolling down (pushing top arrow) */
  1619.         lin = new_topline;            /* new top line */
  1620.     for (i = 0; (i < delta) && (i < termw->screensize); i++) {
  1621.         draw_line_w_attrs(termw, lin, i, 0, MAXCOL, 0);
  1622.         lin++;
  1623.     }
  1624.     termw->display_topline = new_topline;
  1625.  
  1626.     if (termw->have_selection &&
  1627.         (termw->from_lin < termw->display_topline + delta) &&
  1628.         (termw->to_lin >= termw->display_topline)) {
  1629.         if (termw->from_lin < termw->display_topline) {
  1630.         fl = termw->display_topline;
  1631.         fc = 0;
  1632.         } else {
  1633.         fl = termw->from_lin;
  1634.         fc = termw->from_col;
  1635.         }
  1636.         if (termw->to_lin >= termw->display_topline + delta) {
  1637.         tl = termw->display_topline + delta - 1;
  1638.         tc = MAXCOL;
  1639.         } else {
  1640.         tl = termw->to_lin;
  1641.         tc = termw->to_col;
  1642.         }
  1643.         invert_text(termw, fl, fc, tl, tc);
  1644.     }
  1645.     } else {        
  1646.     /* scrolling up (pushing bottom arrow) */
  1647.     /* one past old bottom line*/
  1648.         lin = termw->display_topline + termw->screensize;
  1649.     /*********** PWP: delta is negative here ****************/
  1650.     i = termw->screensize + delta;
  1651.     if (i < 0) i = 0;    /* bounds */
  1652.     while (i < termw->screensize)
  1653.         draw_line_w_attrs(termw, lin++, i++, 0, MAXCOL, 0);
  1654.     termw->display_topline = new_topline;
  1655.  
  1656.     if (termw->have_selection &&
  1657.         (termw->from_lin <
  1658.          (termw->display_topline + termw->screensize)) &&
  1659.         (termw->to_lin >=
  1660.          (termw->display_topline + termw->screensize + delta))) {
  1661.  
  1662.         /*
  1663.          * If selection is partially off the top,
  1664.          * clip display of region at top
  1665.          */
  1666.         if (termw->from_lin <
  1667.         termw->display_topline + termw->screensize + delta) {
  1668.         fl = termw->display_topline + termw->screensize + delta;
  1669.         fc = 0;
  1670.         } else {
  1671.         fl = termw->from_lin;
  1672.         fc = termw->from_col;
  1673.         }
  1674.  
  1675.         /*
  1676.          * If selection is partially off the top,
  1677.          * clip display of region at top.
  1678.          */
  1679.         if (termw->to_lin >= termw->display_topline + termw->screensize) {
  1680.         tl = termw->display_topline + termw->screensize - 1;
  1681.         tc = MAXCOL;
  1682.         } else {
  1683.         tl = termw->to_lin;
  1684.         tc = termw->to_col;
  1685.         }
  1686.  
  1687.         invert_text(termw, fl, fc, tl, tc);
  1688.     }
  1689.     }
  1690. }
  1691.  
  1692. static pascal void
  1693. doscroll (WHICHCONTROL, THECODE)
  1694. ControlHandle WHICHCONTROL;
  1695. short THECODE;
  1696. {
  1697.     register int amount = 0, val, max;
  1698.     struct termw *termw;
  1699.     
  1700.     if (FrontWindow() == ctermw->window)
  1701.         termw = ctermw    ;
  1702.     else if (FrontWindow() == ttermw->window)
  1703.         termw = ttermw    ;
  1704.     else
  1705.         return;
  1706.  
  1707.     if (THECODE == inUpButton)
  1708.     amount = -1;
  1709.     if (THECODE == inDownButton)
  1710.     amount = 1;
  1711.     if (amount == 0)
  1712.     return;
  1713.     val = GetCtlValue (WHICHCONTROL) + amount;
  1714.     max = GetCtlMax (WHICHCONTROL);
  1715.     if ((val >= 0) && (val <= max)) {
  1716.     SetCtlValue (WHICHCONTROL, val);
  1717.     scroll_term(termw);
  1718.     }
  1719. }                /* doscroll */
  1720.  
  1721.  
  1722. /****************************************************************************/
  1723. /* we move the displayed region to the bottom when we recieve characters */
  1724. /****************************************************************************/
  1725.  
  1726. screen_to_bottom (struct termw *termw)
  1727. {
  1728.     if (termw->display_topline != toplin) {
  1729.     SetCtlValue (termw->t_vscroll, 
  1730.              termw->display_totlines - termw->screensize);
  1731.     scroll_term(termw);
  1732.     }
  1733. }
  1734.  
  1735. /****************************************************************************/
  1736. /* update_vscroll - adjust the scaling of the vertical scroll bar, or  */
  1737. /*                      disable it if we havn't saved anything back yet */
  1738. /****************************************************************************/
  1739. update_vscroll (struct termw *termw)
  1740. {
  1741.     short s;
  1742.     
  1743.     s = termw->display_totlines-termw->screensize;
  1744.  
  1745.     if (s != GetCtlMax (termw->t_vscroll))
  1746.     SetCtlMax (termw->t_vscroll, s);
  1747.  
  1748.     if (s != GetCtlValue (termw->t_vscroll))
  1749.     SetCtlValue (termw->t_vscroll, s);
  1750.  
  1751.     if (termw->in_front && termw->display_totlines > termw->screensize) {
  1752.     if (termw->scroll_drawn != 1) {
  1753.         HiliteControl (termw->t_vscroll, 0);
  1754.         termw->scroll_drawn = 1;
  1755.     }
  1756.     } else {
  1757.     if (termw->scroll_drawn != 0) {
  1758.         HiliteControl (termw->t_vscroll, 255);
  1759.         termw->scroll_drawn = 0;
  1760.     }
  1761.     }
  1762. }
  1763.  
  1764. /****************************************************************************/
  1765. /****************************************************************************/
  1766. void t_pagescroll (struct termw *termw, int code, int amount, 
  1767.            ControlHandle ctrlh)
  1768. {
  1769.     Point myPt;
  1770.     register int val, max;
  1771.  
  1772.     max = GetCtlMax (ctrlh);
  1773.     val = GetCtlValue (ctrlh);
  1774.     
  1775.     do {
  1776.     GetMouse (&myPt);
  1777.     if (TestControl (ctrlh, myPt) != code)
  1778.         continue;
  1779.     
  1780.     val += amount;
  1781.     if (val < 0)
  1782.         val = 0;
  1783.     if (val > max)
  1784.         val = max;
  1785.     SetCtlValue (ctrlh,  val);
  1786.     scroll_term(termw);
  1787.     } while (StillDown ());
  1788. }                /* pagescroll */
  1789.  
  1790.  
  1791. termmouse (struct termw *termw, EventRecord *evt)
  1792. {
  1793.     int actrlcode;
  1794.     ControlHandle acontrol;
  1795.     GrafPtr savePort;
  1796.     
  1797.     GetPort (&savePort);    /* save the current port */
  1798.     SetPort (termw->window);
  1799.  
  1800.     GlobalToLocal (&evt->where);/* convert to local */
  1801.     if (termw->mouse_arrows || (evt->modifiers & optionKey)) {
  1802.     /* In terminal content? */
  1803.     if (PtInRect (evt->where, &termw->ScreenRect)) {
  1804.         mouse_cursor_move(termw, evt);        
  1805.         SetPort (savePort);        /* restore previous port */
  1806.         return;            /* yes, do mouse stuff */
  1807.     }
  1808.     }
  1809.     cursor_erase(termw);
  1810.     actrlcode = FindControl (evt->where, termw->window, &acontrol);
  1811.     switch (actrlcode) {    
  1812.       case inUpButton:
  1813.       case inDownButton:
  1814.     (void) TrackControl (acontrol, evt->where, (ProcPtr) doscroll);
  1815.     break;
  1816.  
  1817.       case inPageUp:
  1818.     t_pagescroll (termw, actrlcode, -(termw->screensize/2), acontrol);
  1819.     break;
  1820.  
  1821.       case inPageDown:
  1822.     t_pagescroll (termw, actrlcode, (termw->screensize/2), acontrol);
  1823.     break;
  1824.  
  1825.       case inThumb:
  1826.     (void) TrackControl (acontrol, evt->where, (ProcPtr) NIL);
  1827.     scroll_term(termw);
  1828.     break;
  1829.     
  1830.       case 0:        /* in the window content itself */
  1831.     mouse_region_select(termw, evt);
  1832.     break;
  1833.     }
  1834.     /* MOVETOCHAR(termw->curcol, termw->curlin - termw->display_topline); */
  1835.     cursor_draw(termw);
  1836.     SetPort (savePort);        /* restore previous port */
  1837. }
  1838.  
  1839.  
  1840. /* 
  1841.  * dir is 'A' (up), 'B' (down), 'C' (right), or 'D' (left) 
  1842.  */
  1843. void do_arrow(struct termw *termw, unsigned char dir)
  1844. {
  1845.     OutputChar(termw, '\033');        /* ESC */
  1846.     if (termw->curskey_mode)
  1847.         OutputChar(termw, 'O');    /* SS3 */
  1848.     else
  1849.         OutputChar(termw, '[');    /* CSI */
  1850.     OutputChar(termw, dir);
  1851. }
  1852.  
  1853. /* char to send is n + ',' */
  1854. void do_keypad (struct termw *termw, int n)
  1855. {
  1856.     if (termw->appl_mode) {
  1857.         OutputChar(termw, '\033');        /* ESC */
  1858.         OutputChar(termw, 'O');    /* SS3 */
  1859.     OutputChar(termw, (unsigned char) n + 'l');
  1860.     } else {
  1861.         OutputChar(termw, (unsigned char) n + ',');    /* normal digit or glyph */
  1862.     }
  1863. }
  1864.  
  1865. /* pf1 == 0 ... pf4 == 3 */
  1866. void do_pfkey(struct termw *termw, int n)
  1867. {
  1868.     OutputChar(termw, '\033');        /* ESC */
  1869.     OutputChar(termw, 'O');    /* SS3 */
  1870.     OutputChar(termw, (unsigned char) n + 'P');
  1871. }
  1872.  
  1873. void do_keyenter(struct termw *termw)
  1874. {
  1875.     if (termw->appl_mode) {
  1876.         OutputChar(termw, '\033');        /* ESC */
  1877.         OutputChar(termw, 'O');    /* SS3 */
  1878.     OutputChar(termw, 'M');
  1879.     } else {
  1880.         OutputChar(termw, '\015');
  1881.     }
  1882. }
  1883.  
  1884. void mouse_cursor_move (struct termw *termw, EventRecord *evt)
  1885. {
  1886.     int mouselin;
  1887.     int mousecol;
  1888.     int tempcol;
  1889.     int templin;
  1890.     int i;
  1891.     Point MousePt;
  1892.  
  1893.     MousePt = evt->where;
  1894.     mouselin = (MousePt.v - TOPMARGIN) / termw->lineheight;
  1895.     mousecol = (MousePt.h - LEFTMARGIN + termw->charwidth/2) / 
  1896.     termw->charwidth;
  1897.     tempcol = termw->curcol;
  1898.     templin = termw->curlin;
  1899.  
  1900.     if (mousecol < tempcol)
  1901.     for (i = tempcol; i > mousecol; i--) {
  1902.         do_arrow (termw, leftARROW);
  1903.         waitasec (termw);
  1904.         /* If tabs are used, we may go too far, so end loop */
  1905.         if (termw->curcol <= mousecol)
  1906.         i = mousecol;
  1907.     }
  1908.  
  1909.     if (mouselin < templin)
  1910.     for (i = templin; i > mouselin; i--) {
  1911.         do_arrow (termw, UPARROW);
  1912.         waitasec (termw);
  1913.     }
  1914.  
  1915.     else if (mouselin > templin)
  1916.     for (i = templin; i < mouselin; i++) {
  1917.         do_arrow (termw, DOWNARROW);
  1918.         waitasec (termw);
  1919.     }
  1920.  
  1921.     if (termw->curlin == mouselin)
  1922.     tempcol = termw->curcol;    /* for short lines */
  1923.  
  1924.     if (tempcol < mousecol)
  1925.     for (i = tempcol; i < mousecol; i++) {
  1926.         do_arrow (termw, rightARROW);
  1927.         waitasec (termw);
  1928.         /* If tabs are used, we may go too far, so end loop */
  1929.         if (termw->curcol >= mousecol)
  1930.         i = mousecol;
  1931.     }
  1932. }                /* mouse_cursor_move */
  1933.  
  1934. void invert_text(struct termw *termw, 
  1935.             int from_lin, 
  1936.             int from_col, 
  1937.             int to_lin, 
  1938.             int to_col)
  1939. {
  1940.     int t;
  1941.     
  1942.     if (from_lin > to_lin) {        /* make from < to */
  1943.         t = to_lin;
  1944.     to_lin = from_lin;
  1945.     from_lin = t;
  1946.         t = to_col;
  1947.     to_col = from_col;
  1948.     from_col = t;
  1949.     }
  1950.     
  1951.     /* if we are doing double width chars, the columns are twice as wide */
  1952.     if (termw->line_attrs[from_lin] != VT_SNGL)
  1953.     from_col *= 2;
  1954.     if (termw->line_attrs[to_lin] != VT_SNGL)
  1955.     to_col *= 2;
  1956.  
  1957.     from_lin -= termw->display_topline;    /* convert to screen coords */
  1958.     if (from_lin < 0) {
  1959.     from_lin = 0;
  1960.     from_col = 0;
  1961.     }
  1962.     
  1963.     /* if down out of sight, forget it */
  1964.     if (from_lin >= termw->screensize)
  1965.     return;
  1966.     
  1967.     to_lin -= termw->display_topline;    /* convert to screen coords */
  1968.     
  1969.     if (to_lin < 0)            /* if up out of sight, forget it */
  1970.     return;
  1971.     
  1972.     if (to_lin >= termw->screensize) {
  1973.     to_lin = termw->screensize-1;
  1974.     to_col = MAXCOL;
  1975.     }
  1976.  
  1977.     if (from_lin == to_lin) {        /* if only one line */
  1978.     if (from_col > to_col) {
  1979.             t = to_col;
  1980.         to_col = from_col;
  1981.         from_col = t;
  1982.     }
  1983.                   
  1984.     if (from_col != to_col)     /* then invert the characters in between */
  1985.         invertchars(termw, from_lin, from_col, 1, to_col - from_col);
  1986.     } else {
  1987.     if (from_col < MAXCOL)
  1988.         invertchars(termw, from_lin, from_col, 1, MAXCOL - from_col);
  1989.     t = to_lin - from_lin - 1;
  1990.     if (t > 0)
  1991.         invertchars(termw, from_lin+1, 0, t, MAXCOL);
  1992.     if (to_col > 0)
  1993.         invertchars(termw, to_lin, 0, 1, to_col);
  1994.     }
  1995. }
  1996.  
  1997.  
  1998. int typeof_char(unsigned char c)
  1999. {
  2000.     if ((c == ' ') || (c == '\240'))
  2001.         return (0);            /* whitespace char */
  2002.  
  2003.     if (((c >= '0') && (c <= '9'))
  2004.         || ((c >= 'A') && (c <= 'Z'))
  2005.         || ((c >= 'a') && (c <= 'z'))
  2006.         || ((c >= '\300') && (c <= '\377') && (c != '\327') && (c != '\367'))
  2007.         || ((c >= '\271') && (c <= '\276') && (c != '\273'))
  2008.         || (c == '\262') || (c == '\263') || (c == '\252'))
  2009.     return (1);            /* alpha-numeric char */
  2010.  
  2011.     return (2);                /* printing, non-alphanum char */
  2012. }
  2013.  
  2014.  
  2015. int all_spaces (struct termw *termw, register int r, register int c)
  2016. {
  2017.     register int i;
  2018.     
  2019.     for (i = c; i < line_maxcol(termw, r); i++)
  2020.     if ((termw->scr[r][i] != ' ')
  2021.         || (termw->scr_attrs[r][i] != 0))
  2022.         return (0);            /* found a non-space */
  2023.  
  2024.     return (1);                /* everything was spaces */
  2025. }
  2026.  
  2027.  
  2028. void point_to_mouse_low_high (struct termw *termw, 
  2029.              Point *MousePt_p,
  2030.              int n_clicks,
  2031.              int *mouselin_p,
  2032.              int *mousecol_p,
  2033.              int *mousecol_lp,
  2034.              int *mousecol_hp)
  2035. {
  2036.     int real_lin, real_col;
  2037.     int ch_type, ch_attr;
  2038.     int i;
  2039.     
  2040.     real_lin = (MousePt_p->v-TOPMARGIN) / termw->lineheight + 
  2041.     termw->display_topline;
  2042.     if (real_lin < termw->display_topline)
  2043.     real_lin = termw->display_topline;
  2044.     if (real_lin >= termw->display_topline + termw->screensize)
  2045.     real_lin = termw->display_topline + termw->screensize-1;
  2046.  
  2047.     *mouselin_p = real_lin;
  2048.     
  2049.     real_col = (MousePt_p->h - LEFTMARGIN + termw->charwidth/2) / 
  2050.     termw->charwidth;
  2051.     if (real_col < 0) real_col = 0;
  2052.     if (real_col > MAXCOL)        /* this is a real, not virtual, column */
  2053.         real_col = MAXCOL;
  2054.  
  2055.     /* if on a double-width line, all columns are twice as wide */
  2056.     if (termw->line_attrs[real_lin] != VT_SNGL)
  2057.     real_col /= 2;
  2058.     
  2059.     /*
  2060.      * We spoof things a bit here -- if the rest of the line is all blanks,
  2061.      * then we treat it as a single character (CRLF, really), and pretend
  2062.      * that the user clicked the mouse in the first blank character after all
  2063.      * text.
  2064.      */
  2065.     if (all_spaces(termw,real_lin, real_col))
  2066.     {
  2067.         for (i = real_col; i >= 0; i--)
  2068.         if ((termw->scr[real_lin][i] != ' ')
  2069.             || (termw->scr_attrs[real_lin][i] != 0))
  2070.         break;
  2071.     real_col = i+1;
  2072.     if (real_col < 0) real_col = 0;
  2073.     if (real_col > line_maxcol(termw, real_lin))
  2074.         real_col = line_maxcol(termw, real_lin);
  2075.     }
  2076.     
  2077.     *mousecol_p = real_col;
  2078.  
  2079.     if (n_clicks == 0)        /* if a SINGLE click */
  2080.     {
  2081.         *mousecol_lp = real_col;
  2082.     *mousecol_hp = real_col;
  2083.     }
  2084.     else if (n_clicks == 1)    /* if a DOUBLE click */
  2085.     {
  2086.     ch_type = typeof_char (termw->scr[real_lin][real_col]);
  2087.     ch_attr = termw->scr_attrs[real_lin][real_col];
  2088.     for (i = real_col-1; i >= 0; i--)
  2089.       /* if a different type */
  2090.         if ((typeof_char (termw->scr[real_lin][i]) != ch_type)
  2091.         /* or colored different */
  2092.             || (termw->scr_attrs[real_lin][i] != ch_attr))
  2093.           /* then it isn't the same kind of char */
  2094.           break;            
  2095.     *mousecol_lp = i+1;
  2096.     for (i = real_col+1; i < line_maxcol(termw, real_lin); i++)
  2097.       /* if a different type */
  2098.         if ((typeof_char (termw->scr[real_lin][i]) != ch_type)
  2099.         /* or colored different */
  2100.             || (termw->scr_attrs[real_lin][i] != ch_attr)) 
  2101.           /* then it isn't the same kind of char */
  2102.           break;
  2103.     *mousecol_hp = i;
  2104.     }
  2105.     else                /* a TRIPLE click */
  2106.     {
  2107.         *mousecol_lp = 0;
  2108.     *mousecol_hp = line_maxcol(termw, real_lin);
  2109.     }
  2110. }
  2111.  
  2112.  
  2113. void mouse_region_select (struct termw *termw, EventRecord *evt)
  2114. {
  2115.     int mouselin;
  2116.     int mousecol_l, mousecol_h, real_mousecol;
  2117.     int i, shift, sval, smax;
  2118.     int old_from_lin, old_from_col, old_to_lin, old_to_col;
  2119.     Point MousePt;
  2120.     /* used for double-click determination */
  2121.     static Point prev_mouse_point = {0, 0};
  2122.     static long prev_mouse_up = 0L;
  2123.     static int n_clicks_here = 0;
  2124.  
  2125.     MousePt = evt->where;
  2126.  
  2127.     /* if no selection, then a shift drag is just a drag */
  2128.     if (termw->have_selection)
  2129.     shift = (evt->modifiers) & shiftKey;
  2130.     else
  2131.     shift = 0;
  2132.  
  2133.     if (((evt->when - prev_mouse_up) <= GetDblTime())
  2134.         && (ABS(MousePt.v - prev_mouse_point.v) < termw->lineheight)
  2135.     && (ABS(MousePt.h - prev_mouse_point.h) < termw->charwidth))
  2136.     n_clicks_here = (n_clicks_here + 1) % 3;
  2137.     else
  2138.         n_clicks_here = 0;        /* just one click */
  2139.  
  2140.     prev_mouse_point = MousePt;            /* save for next time */
  2141.     prev_mouse_up = TickCount ();        /* save when the mouse went up */
  2142.  
  2143.     /* if not adding to region, remove old one */
  2144.     if (!shift && termw->have_selection)
  2145.         invert_text(termw,
  2146.             termw->from_lin,
  2147.             termw->from_col,
  2148.             termw->to_lin,
  2149.             termw->to_col);
  2150.  
  2151.  
  2152.     point_to_mouse_low_high(termw,&MousePt, n_clicks_here, &mouselin,
  2153.                      &real_mousecol, &mousecol_l, &mousecol_h);
  2154.  
  2155.     if (shift) {
  2156.     /*
  2157.      * Swap from_* and to_* if closer to from.  This sets the further-away
  2158.      * side as the anchor, and the closer one as the part we are changing.
  2159.      *
  2160.      * We aren't taking into account any double width lines here, but that
  2161.      * should be OK anyway (I hope)
  2162.      */
  2163.     if (ABS((MAXCOL * termw->from_lin + termw->from_col) -
  2164.         (MAXCOL * mouselin + real_mousecol)) <
  2165.         ABS((MAXCOL * termw->to_lin + termw->to_col)
  2166.         - (MAXCOL * mouselin + real_mousecol))) {
  2167.             i = termw->to_lin;
  2168.         termw->to_lin = termw->from_lin;
  2169.         termw->from_lin = i;
  2170.             i = termw->to_col;
  2171.         termw->to_col = termw->from_col;
  2172.         termw->from_col = i;
  2173.     }
  2174.     } else {
  2175.     termw->from_lin = mouselin;
  2176.     termw->from_col = mousecol_l;
  2177.     termw->to_lin = mouselin;
  2178.     termw->to_col = mousecol_h;
  2179.     
  2180.     /* Select the text if a double or triple click. */
  2181.     if (termw->from_col != termw->to_col)
  2182.             invert_text(termw,
  2183.             termw->from_lin,
  2184.             termw->from_col,
  2185.             termw->to_lin,
  2186.             termw->to_col);
  2187.     }
  2188.     /* save in case we have to swap which point is the anchor */
  2189.     old_from_lin = termw->from_lin;
  2190.     old_from_col = termw->from_col;
  2191.     old_to_lin = termw->to_lin;
  2192.     old_to_col = termw->to_col;
  2193.     
  2194.     while (StillDown()) {
  2195.     GetMouse(&MousePt);
  2196.     point_to_mouse_low_high(termw,&MousePt, n_clicks_here, &mouselin,
  2197.                      &real_mousecol, &mousecol_l, &mousecol_h);
  2198.  
  2199.     /*
  2200.      * If above or below screen, auto-scroll the slider and select more.
  2201.      */
  2202.     
  2203.     if (mouselin < termw->display_topline) {
  2204.         sval = GetCtlValue (termw->t_vscroll) - 1;
  2205.         smax = GetCtlMax (termw->t_vscroll);
  2206.         if ((sval >= 0) && (sval <= smax)) {
  2207.         SetCtlValue (termw->t_vscroll, sval);
  2208.         scroll_term(termw);
  2209.         }
  2210.         mouselin = termw->display_topline;
  2211.         real_mousecol = 0;
  2212.  
  2213.     } else if (mouselin >= termw->display_topline + termw->screensize) {
  2214.         sval = GetCtlValue (termw->t_vscroll) + 1;
  2215.         smax = GetCtlMax (termw->t_vscroll);
  2216.         if ((sval >= 0) && (sval <= smax)) {
  2217.         SetCtlValue (termw->t_vscroll, sval);
  2218.         scroll_term(termw);
  2219.         }
  2220.         mouselin = termw->display_topline + termw->screensize-1;
  2221.         real_mousecol = line_maxcol(termw, mouselin);
  2222.     }
  2223.     
  2224.     /*
  2225.      * If we are above the anchor, then the "interesting" side of the 
  2226.      * click extent is mousecol_l, else it is mousecol_h.
  2227.      *
  2228.      * Again, we are not taking into account any intermediate double-width
  2229.      * lines, but hopefully that's OK.
  2230.      */
  2231.     if ((MAXCOL * termw->from_lin + termw->from_col) > 
  2232.         (MAXCOL * mouselin + real_mousecol))
  2233.     {
  2234.         i = mousecol_l;        /* "above" the anchor point */
  2235.  
  2236.         /* but if we were below the anchor, restore and swap */
  2237.         if ((MAXCOL * termw->from_lin + termw->from_col) < 
  2238.         (MAXCOL * termw->to_lin + termw->to_col))
  2239.         {
  2240.         /* Unselect current text. */
  2241.          invert_text(termw, termw->from_lin, termw->from_col, 
  2242.                 termw->to_lin, termw->to_col);
  2243.  
  2244.         termw->from_lin = old_to_lin;
  2245.         termw->from_col = old_to_col;
  2246.         termw->to_lin = old_from_lin;
  2247.         termw->to_col = old_from_col;
  2248.         
  2249.         /* Reselect new (old) text. */
  2250.          invert_text(termw, termw->from_lin, termw->from_col, 
  2251.                 termw->to_lin, termw->to_col);
  2252.         }
  2253.     } else {
  2254.         i = mousecol_h;        /* "below" the anchor point */
  2255.  
  2256.         /* but if we were above the anchor, restore and swap */
  2257.         if ((MAXCOL * termw->from_lin + termw->from_col) > 
  2258.         (MAXCOL * termw->to_lin + termw->to_col))
  2259.         {
  2260.         /* Unselect current text. */
  2261.          invert_text(termw, termw->from_lin, termw->from_col, 
  2262.                 termw->to_lin, termw->to_col);
  2263.  
  2264.         termw->from_lin = old_from_lin;
  2265.         termw->from_col = old_from_col;
  2266.         termw->to_lin = old_to_lin;
  2267.         termw->to_col = old_to_col;
  2268.         
  2269.         /* Reselect new (old) text. */
  2270.          invert_text(termw, termw->from_lin, termw->from_col, 
  2271.                 termw->to_lin, termw->to_col);
  2272.         }
  2273.     }
  2274.         
  2275.     
  2276.     /*
  2277.      * If any new text was selected, invert it.
  2278.      */
  2279.     if ((i != termw->to_col) || (mouselin != termw->to_lin)) {
  2280.         invert_text(termw, termw->to_lin, termw->to_col, mouselin, i);
  2281.         termw->to_lin = mouselin;
  2282.         termw->to_col = i;
  2283.     }
  2284.     }
  2285.     
  2286.     /* make from < to */    
  2287.     if ((MAXCOL * termw->from_lin + termw->from_col) > 
  2288.     (MAXCOL * termw->to_lin + termw->to_col)) {
  2289.         i = termw->to_lin;
  2290.     termw->to_lin = termw->from_lin;
  2291.     termw->from_lin = i;
  2292.         i = termw->to_col;
  2293.     termw->to_col = termw->from_col;
  2294.     termw->from_col = i;
  2295.     }
  2296.     
  2297.     if ((termw->from_lin != termw->to_lin) ||
  2298.     (termw->from_col != termw->to_col))
  2299.     termw->have_selection = TRUE;
  2300.     else
  2301.     termw->have_selection = FALSE;
  2302.     
  2303.     /*
  2304.      * If the mouse wasn't down long enough to be a drag, time double click
  2305.      * from the mouse UP.
  2306.      */
  2307.     if (((TickCount () - prev_mouse_up) <= GetDblTime())
  2308.         && (ABS(MousePt.v - prev_mouse_point.v) < termw->lineheight)
  2309.     && (ABS(MousePt.h - prev_mouse_point.h) < termw->charwidth)) {
  2310.     prev_mouse_up = TickCount ();    /* save when the mouse went up */
  2311.     }
  2312. }
  2313.  
  2314. /* (PWP) if the selection is within [tlin,blin], then remove it */
  2315.  
  2316. void maybe_nuke_selection (struct termw *termw, int tlin, int blin)
  2317. {
  2318.     int my_to_lin;
  2319.  
  2320.     if (!termw->have_selection)
  2321.     return;
  2322.  
  2323.     my_to_lin = termw->to_lin;
  2324.     if ((termw->to_col == 0) && (termw->from_lin != termw->to_lin))
  2325.         my_to_lin--;
  2326.  
  2327.     if (!(((tlin < termw->from_lin) && (blin < termw->from_lin))
  2328.       || ((tlin > my_to_lin) && (blin > my_to_lin))) ) {
  2329.     termw->have_selection = FALSE;
  2330.     invert_text(termw,
  2331.             termw->from_lin,
  2332.             termw->from_col,
  2333.             termw->to_lin,
  2334.             termw->to_col);
  2335.     }
  2336. }
  2337.  
  2338. /*
  2339.  * Initialize the internal clipboard.
  2340.  */
  2341. void
  2342. init_scr_clip()
  2343. {
  2344.     /* check for multiple init */
  2345.     if (myclip_h != NULL) {
  2346.         printerr("init_scr_clip(): internal clipboard already initialized!", 0);
  2347.         return;
  2348.     }
  2349.     myclip_h = (char **) NewHandle (256);
  2350.     myclip_size = 0;
  2351.     my_scrapcount = -1;
  2352. }
  2353.  
  2354. /*
  2355.  * Destroy internal clipboard.
  2356.  */
  2357. void
  2358. destroy_scr_clip()
  2359. {
  2360.     if (myclip_h)
  2361.     DisposHandle(myclip_h);
  2362.     myclip_h = NULL;
  2363. }
  2364.  
  2365. /*
  2366.  * Invalidate internal clip (for cut & copy from server window).
  2367.  */
  2368. void
  2369. invalidate_scr_clip()
  2370. {
  2371.     myclip_size = 0;
  2372.     my_scrapcount = -1;
  2373. }
  2374.  
  2375. /*
  2376.  * Copy the current selction to the (internal) clipboard.
  2377.  *
  2378.  * This is an external, but we don't have to save the GrafPort
  2379.  * because we don't do anything to the screen.
  2380.  */
  2381. scr_copy (struct termw *termw)
  2382. {
  2383.     int lin, i, rcol;
  2384.     long sz;
  2385.     char *dp;
  2386.     ScrapStuff *pss;
  2387.     
  2388.     if (myclip_h == NIL) {
  2389.     printerr("scr_copy: clip handle not allocated", 0);
  2390.     return;
  2391.     }
  2392.     
  2393.     if (termw->have_selection) {
  2394.     /****** find out how big the text to copy is ******/
  2395.         if (termw->from_lin == termw->to_lin) {
  2396.         /*
  2397.          * If we are copying to the end of line, we should really only copy
  2398.          * a CR instead of all those trailing blanks.  So we must find out
  2399.          * where the last real character is.
  2400.          */
  2401.         if (termw->to_col >= line_maxcol(termw, termw->to_lin)) {
  2402.         for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--)
  2403.             /* last */
  2404.             if ((termw->scr[termw->to_lin][rcol-1] != ' ')
  2405.             || (termw->scr_attrs[termw->to_lin][rcol-1] != 0))
  2406.             break;
  2407.         } else {
  2408.             rcol = termw->to_col;
  2409.         }
  2410.         sz = rcol - termw->from_col + 1;
  2411.     } else {
  2412.         for (rcol = line_maxcol(termw, termw->from_lin);
  2413.              rcol > termw->from_col; rcol--)    /* first */
  2414.         if ((termw->scr[termw->from_lin][rcol-1] != ' ')
  2415.             || (termw->scr_attrs[termw->from_lin][rcol-1] != 0))
  2416.             break;
  2417.         /* chars plus one for the termw->newline */
  2418.         sz = rcol - termw->from_col + 1;
  2419.  
  2420.         /* in between */
  2421.         for (lin = termw->from_lin+1; lin < termw->to_lin; lin++) {
  2422.         for (rcol = line_maxcol(termw, lin); rcol > 0; rcol--)
  2423.             if ((termw->scr[lin][rcol-1] != ' ')
  2424.             || (termw->scr_attrs[lin][rcol-1] != 0))
  2425.             break;
  2426.         sz += rcol + 1;    /* chars plus one for the termw->newline */
  2427.         }
  2428.  
  2429.         if (termw->to_col >= line_maxcol(termw, termw->to_lin)) {
  2430.             /***** find the last real character *****/
  2431.         for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--)
  2432.             /* last */
  2433.             if ((termw->scr[termw->to_lin][rcol-1] != ' ')
  2434.             || (termw->scr_attrs[termw->to_lin][rcol-1] != 0))
  2435.             break;
  2436.         } else {
  2437.         rcol = termw->to_col;
  2438.         }
  2439.         sz += rcol;        /* chars */
  2440.         if (termw->to_col >= line_maxcol(termw, termw->to_lin))
  2441.             sz++;
  2442.     }
  2443.     
  2444.     /***** Reality Check *****/
  2445.     if (sz > 8192) {
  2446.         printerr("Too big to copy: ", sz);
  2447.         return;
  2448.     }
  2449.         
  2450.     /****** allocate and lock a buffer for the text ******/
  2451.     if (sz > GetHandleSize ((Handle) myclip_h)) {
  2452.         HUnlock((Handle) myclip_h);
  2453.         SetHandleSize((Handle) myclip_h, sz);
  2454.         /* make sure our SetHandleSize() worked */
  2455.         if (GetHandleSize((Handle) myclip_h) != sz) {
  2456.             printerr("scr_copy: could not expand clip handle", 0);
  2457.         return;
  2458.         }
  2459.     }
  2460.     HLock((Handle) myclip_h);
  2461.     dp = *myclip_h;
  2462.     
  2463.     /****** copy the characters over to the clip ******/
  2464.         if (termw->from_lin == termw->to_lin) {
  2465.         if (termw->to_col >= line_maxcol(termw, termw->to_lin)) {
  2466.         for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--)
  2467.             /* last */
  2468.             if ((termw->scr[termw->to_lin][rcol-1] != ' ')
  2469.             || (termw->scr_attrs[termw->to_lin][rcol-1] != 0))
  2470.             break;
  2471.         } else {
  2472.             rcol = termw->to_col;
  2473.         }
  2474.         for (i = termw->from_col; i < rcol; i++)
  2475.             *dp++ = termw->scr[termw->from_lin][i];
  2476.         if (termw->to_col >= line_maxcol(termw, termw->to_lin))
  2477.             *dp++ = CR;        /* add the return */
  2478.     } else {
  2479.         /* trim off spaces */
  2480.         for (rcol = line_maxcol(termw, termw->from_lin);
  2481.          rcol > termw->from_col; rcol--)    /* first */
  2482.         if ((termw->scr[termw->from_lin][rcol-1] != ' ')
  2483.             || (termw->scr_attrs[termw->from_lin][rcol-1] != 0))
  2484.             break;
  2485.         for (i = termw->from_col; i < rcol; i++)
  2486.         *dp++ = termw->scr[termw->from_lin][i];
  2487.         *dp++ = CR;
  2488.  
  2489.         /* in between */
  2490.         for (lin = termw->from_lin+1; lin < termw->to_lin; lin++) {
  2491.         for (rcol = line_maxcol(termw, lin); rcol > 0; rcol--)
  2492.             if ((termw->scr[lin][rcol-1] != ' ')
  2493.             || (termw->scr_attrs[lin][rcol-1] != 0))
  2494.             break;
  2495.         for (i = 0; i < rcol; i++)
  2496.             *dp++ = termw->scr[lin][i];
  2497.         *dp++ = CR;
  2498.         }
  2499.  
  2500.         if (termw->to_col == line_maxcol(termw, termw->to_lin)) {
  2501.         for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--)
  2502.             /* last */
  2503.             if ((termw->scr[termw->to_lin][rcol-1] != ' ')
  2504.             || (termw->scr_attrs[termw->to_lin][rcol-1] != 0))
  2505.             break;
  2506.         } else {
  2507.         rcol = termw->to_col;
  2508.         }
  2509.         for (i = 0; i < rcol; i++)
  2510.         *dp++ = termw->scr[termw->to_lin][i];
  2511.         if (termw->to_col >= line_maxcol(termw, termw->to_lin))
  2512.         *dp++ = CR;
  2513.     }
  2514.     myclip_size = (dp - *myclip_h);
  2515.  
  2516.     /****** check to make sure we didn't overflow the clipboard ******/
  2517.     if (myclip_size > sz)
  2518.         macfatal ("Overflow! myclip_size - sz ==",
  2519.             myclip_size - sz);
  2520.  
  2521.  
  2522.     /****** Now copy our internal clipboard to the Macintosh one *****/
  2523.     /*
  2524.      * $$$ at this point we really should allocate a second buffer,
  2525.      * and copy the characters of our buffer into it, converting them
  2526.      * from whatever ISO set we are displaying with to the Mac char set.
  2527.      */
  2528.     ZeroScrap();
  2529.     if (PutScrap(myclip_size, 'TEXT', *myclip_h) != noErr)
  2530.         printerr("Couldn't PutScrap", 0);        
  2531.     
  2532.     pss = InfoScrap();
  2533.     my_scrapcount = pss->scrapCount;    /* save this to see if the user */
  2534.                         /* cuts/copies outside of us */
  2535.     
  2536.     /****** We are done.  Unlock the handle ******/
  2537.     HUnlock((Handle) myclip_h);
  2538.     } else {
  2539.     SysBeep(3);
  2540.     }
  2541. }
  2542.  
  2543. /*
  2544.  * Paste the clipboard into the terminal, by "typing" it in.
  2545.  *
  2546.  * This also is an external, but we don't have to save the GrafPort
  2547.  * because the only time we do anything to the screen, it's through
  2548.  * inpchars(), which saves the GrafPort itself.
  2549.  */
  2550. scr_paste (struct termw *termw)
  2551. {
  2552.     char *cp, *endp;
  2553.     char **h;
  2554.     long l, o;
  2555.     ScrapStuff *pss;
  2556.  
  2557.     pss = InfoScrap();
  2558.     if (my_scrapcount == pss->scrapCount) {
  2559.         /* if this is still the same scrap that we made */
  2560.     if (myclip_size > 0) {
  2561.         HLock((Handle) myclip_h);
  2562.         cp = *myclip_h;
  2563.         endp = cp + myclip_size;
  2564.         for (; cp < endp; cp++) {
  2565.         OutputChar(termw, *cp);
  2566.         if (*cp == CR)
  2567.             waitasec (termw);
  2568.         }
  2569.         HUnlock((Handle) myclip_h);
  2570.     } else {
  2571.         SysBeep(3);
  2572.     }
  2573.     } else {    /* we have to get the TEXT scrap from the clipboard */
  2574.     h = NewHandle(0);
  2575.     l = GetScrap(h, 'TEXT', &o);
  2576.     if (l <= 0) {
  2577.         SysBeep(3);
  2578.     } else {
  2579.         HLock((Handle) h);
  2580.         cp = *h;
  2581.         endp = cp + l;
  2582.         for (; cp < endp; cp++) {
  2583.             /* $$$ Should convert *cp to whatever ISO font we are typing */
  2584.         OutputChar(termw, *cp);
  2585.         if (*cp == CR)
  2586.             waitasec (termw);
  2587.         }
  2588.         HUnlock((Handle) h);
  2589.     }    /* end if (l > 0) */
  2590.     DisposHandle(h);
  2591.     }
  2592. }
  2593.  
  2594. /*
  2595.  * Paste into the command window.
  2596.  */
  2597. cmd_paste (struct termw *termw)
  2598. {
  2599.     char *cp, *endp;
  2600.     char **h;
  2601.     long l, o;
  2602.     ScrapStuff *pss;
  2603.  
  2604.     pss = InfoScrap();
  2605.     if (my_scrapcount == pss->scrapCount) {
  2606.         /* if this is still the same scrap that we made */
  2607.     if (myclip_size > 0) {
  2608.         HLock((Handle) myclip_h);
  2609.         cp = *myclip_h;
  2610.         endp = cp + myclip_size;
  2611.         for (; cp < endp; cp++) {
  2612.         writecbc(*cp);
  2613.         if (*cp == CR)
  2614.             waitasec (termw);
  2615.         }
  2616.         HUnlock((Handle) myclip_h);
  2617.     } else {
  2618.         SysBeep(3);
  2619.     }
  2620.     } else {    /* we have to get the TEXT scrap from the clipboard */
  2621.     h = NewHandle(0);
  2622.     l = GetScrap(h, 'TEXT', &o);
  2623.     if (l <= 0) {
  2624.         SysBeep(3);
  2625.     } else {
  2626.         HLock((Handle) h);
  2627.         cp = *h;
  2628.         endp = cp + l;
  2629.         for (; cp < endp; cp++) {
  2630.             /* $$$ Should convert *cp to whatever ISO font we are typing */
  2631.         writecbc(*cp);
  2632.         if (*cp == CR)
  2633.             waitasec (termw);
  2634.         }
  2635.         HUnlock((Handle) h);
  2636.     }    /* end if (l > 0) */
  2637.     DisposHandle(h);
  2638.     }
  2639. }
  2640.  
  2641.  
  2642. /****************************************************************************/
  2643. /****************************************************************************/
  2644.  
  2645. #ifdef COMMENT
  2646. show_inval_rgn(w)
  2647. WindowPeek w;
  2648. {
  2649.     RgnHandle r = NewRgn();
  2650.  
  2651.     CopyRgn (w->updateRgn, r);
  2652.     OffsetRgn(r,            /* convert to local grafport coords */
  2653.           (((w->port).portBits).bounds).left,
  2654.           (((w->port).portBits).bounds).top);
  2655.     FillRgn(r, qd.gray);
  2656.     DisposeRgn(r);
  2657.     waitnoinput ();
  2658.     waitnoinput ();
  2659.     waitnoinput ();
  2660.     waitnoinput ();
  2661. }
  2662. #endif /* COMMENT */
  2663.  
  2664. /****************************************************************************/
  2665. /*
  2666.  * PWP: actually do all the scrolling and refreshing we have promised to
  2667.  * do.
  2668.  *
  2669.  * Method (and many var and fcn names) stolen from X11 xterm.
  2670.  */
  2671. /****************************************************************************/
  2672. void flushscroll (struct termw *termw)
  2673. {
  2674.     register int i, now;
  2675.     Rect r;            /* , opened_r   cannot be register */
  2676.     GrafPtr currWindow;        /* cannot be register */
  2677.     RgnHandle newupdateRgn;
  2678.     Rect *rp;
  2679.     int lin;
  2680.     int vtoplin, vbotlin, vleftcol, vrightcol;
  2681.     
  2682.     if (termw->scroll_amount == 0) {
  2683.         printerr ("flushscroll() called with no scroll to flush", 0);
  2684.         return;
  2685.     }
  2686.     
  2687.     /* should hide the cursor here if not already hidden */
  2688.     
  2689.     /* (PWP) if our selected region overlaps, but is not enclosed by the region
  2690.        we want to scroll, then remove it, because the region no longer contains
  2691.        what the user thought it did. */
  2692.     if (termw->have_selection && (termw->saved_tlin != toplin) && 
  2693.     (termw->saved_blin != botlin) && 
  2694.     ((termw->from_lin < termw->saved_tlin) || 
  2695.      (termw->to_lin > termw->saved_blin)) &&
  2696.         ((termw->to_lin > termw->saved_tlin)   || 
  2697.      (termw->from_lin < termw->saved_blin))) {
  2698.     termw->have_selection = FALSE;
  2699.     invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, 
  2700.             termw->to_col);
  2701.     }
  2702.     
  2703.     if (!termw->in_front) {
  2704.     /* if not in front, compensate update region for scrolling */
  2705.     GetPort (&currWindow);
  2706.     /* scroll the old updateRgn */
  2707.     OffsetRgn (((WindowPeek) currWindow)->updateRgn, 0, 
  2708.            -termw->lineheight);
  2709.     }
  2710.     
  2711.  
  2712.     /* 
  2713.      * Do the scrolling
  2714.      */
  2715.     makerect(termw,&r, termw->saved_tlin, 0,
  2716.          termw->saved_blin - termw->saved_tlin + 1, MAXCOL);
  2717.     newupdateRgn = NewRgn();
  2718.     
  2719.     if (termw->smoothscroll && termw->in_front) {
  2720.     int dir = 1;            /* direction */
  2721.     if (termw->scroll_amount < 0)
  2722.         dir = -1;
  2723.     for (i = 1; i <= termw->scroll_amount*termw->lineheight*dir; i += 1) {
  2724.         /* PWP: wait for a vertical reblank (in a sneaky way) */
  2725.         now = TickCount ();
  2726.         while (TickCount () == now)
  2727.         /* wait... */ ;
  2728.         ScrollRect (&r, 0, dir, newupdateRgn);
  2729.     }
  2730.     } else {
  2731.     ScrollRect (&r, 0, termw->scroll_amount * termw->lineheight, 
  2732.             newupdateRgn);
  2733.     }
  2734.  
  2735.     /*
  2736.      * NOTE: We don't add the newupdateRgn to the actual window update region,
  2737.      * but instead we just update all the lines that are in the region now.
  2738.      * This is faster, gives a smoother appearance to background windows, and
  2739.      * avoids an apparent bug in the Mac that causes multiplely scrolled
  2740.      * update regions to be incorrect.
  2741.      */
  2742.  
  2743.  
  2744.     termw->scroll_amount = 0;        /* we've done it now */
  2745.  
  2746.     /*
  2747.      * Find the intersection of what we just opened up and the visible portion
  2748.      * of the screen, and update all the lines in that rectangle.
  2749.      */
  2750.     rp = &(**(newupdateRgn)).rgnBBox;
  2751.  
  2752.     /* show the region to be updated -- only for debugging */
  2753.     /* FillRgn(newupdateRgn, qd.gray); */
  2754.     /* FillRect (rp, qd.gray); */
  2755.  
  2756.     /* Find the characters that bound this rectangle */
  2757.     recttocharpos (termw, rp, &vtoplin, &vleftcol, &vbotlin, &vrightcol);
  2758.  
  2759.     /* Make sure we pick up any extra refresh region */
  2760.     if (termw->refresh_amount < 0) {        /* scrolling forward (UP) */
  2761.     if (vtoplin > termw->saved_blin + termw->refresh_amount)
  2762.         vtoplin = termw->saved_blin + termw->refresh_amount;
  2763.     } else if (termw->refresh_amount > 0) {    /* scrolling backward (DOWN) */
  2764.     if (vbotlin < termw->saved_tlin + termw->refresh_amount - 1)
  2765.         vbotlin = termw->saved_tlin + termw->refresh_amount - 1;
  2766.     }
  2767.     
  2768.     /* bounds limit it to the actual screen area (again) */
  2769.     if (vtoplin < 0) vtoplin = 0;
  2770.     if (vbotlin > termw->screensize) vbotlin = termw->screensize;
  2771.  
  2772.     lin = termw->display_topline + vtoplin;
  2773.     for (i = vtoplin; i < vbotlin; i++) {
  2774.     makerect(termw, &r, i, vleftcol, 1, (vrightcol - vleftcol));
  2775.  
  2776.     /*
  2777.      * According to IM 1 pp 185, RectInRgn isn't always exact, so we might
  2778.      * try the more exact way if this isn't good enough.
  2779.      */
  2780.     if (RectInRgn(&r, newupdateRgn)) {
  2781.         draw_line_w_attrs(termw, lin, i, vleftcol, vrightcol, 0);
  2782.  
  2783.         /*
  2784.          * If we just drew the line that flushbuf thinks is pending,
  2785.          * say we have done so in order to avoid drawing that line twice.
  2786.          */
  2787.         if (i == termw->curlin)
  2788.         termw->out_maxcol = 0;
  2789.     }
  2790.     lin++;
  2791.     }
  2792.  
  2793.     DisposeRgn(newupdateRgn);
  2794.  
  2795.     termw->refresh_amount = 0;
  2796. }
  2797.  
  2798.  
  2799. /****************************************************************************/
  2800. /*
  2801.  * (UoR)
  2802.  *
  2803.  * Scroll lines within the scroll region upwards from line tlin
  2804.  * to line blin (lines are assumed to be in the region)
  2805.  *
  2806.  * (PWP) scroll_screen is the combination of scroll_up and scroll_down.
  2807.  *       dir is the number of lines to scroll, <0 if up, >0 if down.
  2808.  *     (actually, right now only -1 and 1 are handled.)
  2809.  */
  2810. /****************************************************************************/
  2811. void scroll_screen (termw, tlin, blin, delta)
  2812. /* these are in scr[][] cordinates */
  2813.     struct termw *termw;
  2814.     register int tlin;
  2815.     register int blin;
  2816.     register int delta;
  2817. {
  2818.     register int i, j;
  2819.     unsigned char *savedline, *savedattr;  /* temporary to hold screen line pointer */
  2820.     unsigned char savedlattr;
  2821.     
  2822.     /*
  2823.      * flush out any pending characters.
  2824.      *
  2825.      * $$$ I bet this is the piece of bogus code that was causing me all the
  2826.      * trouble.  We NEED to do this, or else keep track of where out_mincol and
  2827.      * out_maxcol were when we set up the scroll for the first time, so that
  2828.      * we don't mistakenly miss drawing the pending stuff.
  2829.      */
  2830.     if (!termw->scroll_amount && termw->out_maxcol) 
  2831.     flushbuf(termw);
  2832.  
  2833.     /*
  2834.      * See if we are scrolling something different and have to flush
  2835.      * our pending scroll.
  2836.      * We do if asked to scroll something different than the current
  2837.      * scrolling rgn, or if we are changing direction, or if we have 
  2838.      * already collected an entire scrolling region worth of scroll to do.
  2839.      */
  2840.     if (termw->scroll_amount) {
  2841.     i = termw->scroll_amount + delta;
  2842.     if (i < 0) i = -i;    /* set i to ABS( old scroll plus new scroll ) */
  2843.     if (termw->smoothscroll || 
  2844.         (tlin != termw->saved_tlin) || 
  2845.         (blin != termw->saved_blin) || 
  2846.         ((termw->scroll_amount > 0) && (delta < 0)) ||
  2847.         ((termw->scroll_amount < 0) && (delta > 0)) ||
  2848.         (i >= (termw->saved_blin - termw->saved_tlin))) 
  2849.     {
  2850.         flushscroll(termw);
  2851.     }
  2852.     }
  2853.  
  2854.     /*
  2855.      * Save up how much to scroll and where for later...
  2856.      */
  2857.     termw->saved_tlin = tlin;
  2858.     termw->saved_blin = blin;
  2859.     termw->scroll_amount += delta;
  2860.     /*
  2861.      * Should really set termw->refresh_amount to 0, then add to it 
  2862.      * when we "draw" characters onto lines, but this is safe.
  2863.      */
  2864.     termw->refresh_amount += delta;
  2865.     
  2866.     /* printerr("termw->scroll_amount now ", scroll_amount); */
  2867.  
  2868.     if (delta < 0)        /* if scrolling UP (forwards) */
  2869.     {
  2870.     /* adjust the internal character buffers */
  2871.     if ((tlin == toplin) && (blin == botlin)) { /* if whole screen */
  2872.         termw->display_totlines -= delta; /* remember delta is negitive */
  2873.         if (termw->display_totlines > MAX_SCREENSIZE)
  2874.         termw->display_totlines = MAX_SCREENSIZE; /* bounds */
  2875.         /*top of saved buffer*/
  2876.             tlin = termw->screensize - termw->display_totlines;
  2877.     }
  2878.     /*
  2879.      * If only scrolling by one, just go up, else do more cleverly:
  2880.      * to scroll N lines by I, note that BA == rev(rev(A) rev(B))
  2881.      * and to do a reverse we only need a single temporary variable.
  2882.      * Also note that we don't even have to reverse A (the lines to
  2883.      * scroll to the bottom) since we will just zero these anyway.
  2884.      */
  2885.     if (delta == -1) {
  2886.          savedline = termw->scr[tlin];
  2887.         savedattr = termw->scr_attrs[tlin];
  2888.         savedlattr = termw->line_attrs[tlin];
  2889.         for (i = tlin+1; i <= blin; i++) {
  2890.             termw->scr[i-1] = termw->scr[i];
  2891.             termw->scr_attrs[i-1] = termw->scr_attrs[i];
  2892.         termw->line_attrs[i-1] = termw->line_attrs[i];
  2893.         }
  2894.         termw->scr[blin] = savedline;
  2895.         termw->scr_attrs[blin] = savedattr;
  2896.         termw->line_attrs[blin] = savedlattr;
  2897.  
  2898.         zeroline(termw, blin, 1);        /* clear the line */
  2899.     } else {
  2900.         for (i = tlin; i < tlin-delta; i++)    /* remember that delta < 0 */
  2901.             zeroline(termw, i, 1);    /* clear the line to be moved to bottom */
  2902.         for (i = tlin-delta, j = blin; i < j; i++, j--) {
  2903.          savedline = termw->scr[i];
  2904.         savedattr = termw->scr_attrs[i];
  2905.         savedlattr = termw->line_attrs[i];
  2906.             termw->scr[i] = termw->scr[j];
  2907.             termw->scr_attrs[i] = termw->scr_attrs[j];
  2908.         termw->line_attrs[i] = termw->line_attrs[j];
  2909.             termw->scr[j] = savedline;
  2910.         termw->scr_attrs[j] = savedattr;
  2911.         termw->line_attrs[j] = savedlattr;
  2912.         }
  2913.         for (i = tlin, j = blin; i < j; i++, j--) {
  2914.          savedline = termw->scr[i];
  2915.         savedattr = termw->scr_attrs[i];
  2916.         savedlattr = termw->line_attrs[i];
  2917.             termw->scr[i] = termw->scr[j];
  2918.             termw->scr_attrs[i] = termw->scr_attrs[j];
  2919.         termw->line_attrs[i] = termw->line_attrs[j];
  2920.             termw->scr[j] = savedline;
  2921.         termw->scr_attrs[j] = savedattr;
  2922.         termw->line_attrs[j] = savedlattr;
  2923.         }
  2924.     }
  2925.  
  2926.     /* adjust selection */
  2927.     if (termw->have_selection && (termw->from_lin >= tlin) && 
  2928.         (termw->to_lin <= blin)) 
  2929.     {
  2930.         termw->from_lin += delta;
  2931.         if (termw->from_lin < termw->screensize - MAX_SCREENSIZE)
  2932.             termw->from_lin = termw->screensize - MAX_SCREENSIZE;
  2933.         termw->to_lin += delta;
  2934.         if (termw->to_lin < termw->screensize - MAX_SCREENSIZE)
  2935.             termw->to_lin = termw->screensize - MAX_SCREENSIZE;
  2936.     }
  2937.     }
  2938.     else            /* else scrolling DOWN (reverse scroll) */
  2939.     {
  2940.         /* adjust the internal buffers */
  2941.  
  2942.     /*
  2943.      * If only scrolling by one, just go up, else do more cleverly:
  2944.      * to scroll N lines by I, note that BA == rev(rev(A) rev(B))
  2945.      * and to do a reverse we only need a single temporary variable.
  2946.      * Also note that we don't even have to reverse A (the lines to
  2947.      * scroll to the bottom) since we will just zero these anyway.
  2948.      */
  2949.     if (delta == -1) {
  2950.         savedline = termw->scr[blin];
  2951.         savedattr = termw->scr_attrs[blin];
  2952.         savedlattr = termw->line_attrs[blin];
  2953.         for (i = blin-1; i >= tlin; i--) {
  2954.             termw->scr[i+1] = termw->scr[i];
  2955.             termw->scr_attrs[i+1] = termw->scr_attrs[i];
  2956.         termw->line_attrs[i+1] = termw->line_attrs[i];
  2957.         }
  2958.         termw->scr[tlin] = savedline;
  2959.         termw->scr_attrs[tlin] = savedattr;
  2960.         termw->line_attrs[tlin] = savedlattr;
  2961.  
  2962.         zeroline(termw, tlin, 1);
  2963.     } else {
  2964.         for (i = blin-delta+1; i <= blin; i++)    /* remember that delta > 0 */
  2965.             zeroline(termw, i, 1);    /* clear the line to be moved to top */
  2966.         for (i = tlin, j = blin-delta; i < j; i++, j--) {
  2967.          savedline = termw->scr[i];
  2968.         savedattr = termw->scr_attrs[i];
  2969.         savedlattr = termw->line_attrs[i];
  2970.             termw->scr[i] = termw->scr[j];
  2971.             termw->scr_attrs[i] = termw->scr_attrs[j];
  2972.         termw->line_attrs[i] = termw->line_attrs[j];
  2973.             termw->scr[j] = savedline;
  2974.         termw->scr_attrs[j] = savedattr;
  2975.         termw->line_attrs[j] = savedlattr;
  2976.         }
  2977.         for (i = tlin, j = blin; i < j; i++, j--) {
  2978.          savedline = termw->scr[i];
  2979.         savedattr = termw->scr_attrs[i];
  2980.         savedlattr = termw->line_attrs[i];
  2981.             termw->scr[i] = termw->scr[j];
  2982.             termw->scr_attrs[i] = termw->scr_attrs[j];
  2983.         termw->line_attrs[i] = termw->line_attrs[j];
  2984.             termw->scr[j] = savedline;
  2985.         termw->scr_attrs[j] = savedattr;
  2986.         termw->line_attrs[j] = savedlattr;
  2987.         }
  2988.     }
  2989.  
  2990. #ifdef COMMENT
  2991.     for (now = 0; now < delta; now++) {
  2992.         savedline = termw->scr[blin];
  2993.         savedattr = termw->scr_attrs[blin];
  2994.         savedlattr = termw->line_attrs[blin];
  2995.         for (i = blin-1; i >= tlin; i--) {
  2996.             termw->scr[i+1] = termw->scr[i];
  2997.             termw->scr_attrs[i+1] = termw->scr_attrs[i];
  2998.         termw->line_attrs[i+1] = termw->line_attrs[i];
  2999.         }
  3000.         termw->scr[tlin] = savedline;
  3001.         termw->scr_attrs[tlin] = savedattr;
  3002.         termw->line_attrs[tlin] = savedlattr;
  3003.  
  3004.         zeroline(termw, tlin, 1);
  3005.     }
  3006. #endif
  3007.     
  3008.     /* adjust selection */
  3009.     if (termw->have_selection && (termw->from_lin >= tlin) && 
  3010.         (termw->to_lin <= blin)) 
  3011.     {
  3012.         termw->from_lin += delta;
  3013.         if (termw->from_lin > botlin) termw->from_lin = botlin;
  3014.         termw->to_lin += delta;
  3015.         if (termw->to_lin > botlin) termw->to_lin = botlin;
  3016.     }
  3017.     }
  3018.  
  3019.     /*
  3020.      * but if we are smooth (slow) scrolling and in front, do the scroll now.
  3021.      * must do this after adjusting internal buffers, so that the refresh
  3022.      * lines don't get confused.
  3023.      */
  3024.     if (termw->smoothscroll && termw->in_front)
  3025.         flushscroll(termw);
  3026. }                /* scroll_up */
  3027.  
  3028. /****************************************************************************/
  3029. /* redraw the terminal screen (we got a redraw event) */
  3030. /****************************************************************************/
  3031. term_redraw (struct termw *termw)
  3032. {
  3033.     int i, lin;
  3034.     int vtoplin, vbotlin, vleftcol, vrightcol;
  3035.     Rect r, *rp;
  3036.     GrafPtr savePort;
  3037.     
  3038.     GetPort (&savePort);    /* there just has to be a better way */
  3039.     SetPort (termw->window);
  3040.  
  3041.     if (termw->screeninvert) {
  3042.     BackPat(qd.black);
  3043.     PenPat(qd.white);
  3044.     } else {
  3045.     BackPat(qd.white);
  3046.     PenPat(qd.black);
  3047.     }
  3048.  
  3049.     if (termw->scroll_amount)
  3050.     flushscroll(termw);
  3051.  
  3052. #ifdef COMMENT
  3053.     r = terminalWindow->portRect;    /* copy the window size */
  3054.     /* r.right -= 15;    */        /* subtract control */
  3055.     /* PWP: clear the screen first */
  3056.     /* makerect(termw,&r, 0, 0, termw->screensize, MAXCOL); */
  3057.     /* EraseRect (&r); */
  3058. #endif /* COMMENT */
  3059.  
  3060.     /* See if the scroll bar and grow box need to be updated */
  3061.     r = termw->window->portRect;    /* copy of the window size */
  3062.     /* r.left = r.right - 16; */
  3063.     r.left = rightMARGIN;
  3064.     if (RectInRgn (&r, termw->window->visRgn))
  3065.     {
  3066.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  3067.     EraseRect (&r);
  3068.     /* don't add to invalid while redrawing invalid */
  3069.     draw_grow_and_erase_line(termw, 0);
  3070.     DrawControls (termw->window);
  3071.     }
  3072.  
  3073.     /* Update area above first line */
  3074.     r = termw->window->portRect;    /* copy of the window size */
  3075.     r.bottom = r.top + TOPMARGIN;
  3076.     r.right -= 16;
  3077.     if (RectInRgn (&r, termw->window->visRgn))
  3078.     EraseRect (&r);
  3079.  
  3080.     /* Update area below last line */
  3081.     r = termw->window->portRect;    /* copy of the window size */
  3082.     r.top = termw->bottommargin - 1;
  3083.     r.right -= 16;
  3084.     if (RectInRgn (&r, termw->window->visRgn))
  3085.     EraseRect (&r);
  3086.  
  3087.     /* Update area to the left of first column */
  3088.     r = termw->window->portRect;    /* copy of the window size */
  3089.     r.top = r.top + TOPMARGIN;
  3090.     r.bottom = termw->bottommargin;
  3091.     r.right = LEFTMARGIN;
  3092.     if (RectInRgn (&r, termw->window->visRgn))
  3093.     EraseRect (&r);
  3094.  
  3095.     
  3096.     /* update_vscroll(termw); */
  3097.     /* SetCtlValue (termw->t_vscroll, GetCtlValue (t_vscroll)); */
  3098.  
  3099. #ifdef COMMENT
  3100.     lin = termw->display_topline;
  3101.     for (i = 0; i < termw->screensize; i++) {
  3102.         makerect(termw,&r, i, 0, 1, MAXCOL);
  3103.     if (RectInRgn (&r, termw->window->visRgn))
  3104.         draw_line_w_attrs(termw, lin, i, 0, MAXCOL, 1);
  3105.     lin++;
  3106.     }
  3107. #endif
  3108.  
  3109.     rp = &(**(termw->window->visRgn)).rgnBBox;
  3110.  
  3111.     /* Find the characters that bound this rectangle */
  3112.     recttocharpos(termw, rp, &vtoplin, &vleftcol, &vbotlin, &vrightcol);
  3113.  
  3114. #ifdef COMMENT
  3115.     debug(F101,"term_redraw bounds vtoplin","",vtoplin);
  3116.     debug(F101,"term_redraw bounds vbotlin","",vbotlin);
  3117.     debug(F101,"term_redraw bounds vleftcol","",vleftcol);
  3118.     debug(F101,"term_redraw bounds vrightcol","",vrightcol);
  3119. #endif
  3120.  
  3121.     lin = termw->display_topline + vtoplin;
  3122.     for (i = vtoplin; i < vbotlin; i++) {
  3123.     makerect(termw, &r, i, 0, 1, MAXCOL);
  3124.     if (RectInRgn (&r, termw->window->visRgn))
  3125.         draw_line_w_attrs(termw, lin, i, vleftcol, vrightcol, 1);
  3126.     lin++;
  3127.     }
  3128.     
  3129.     
  3130.     if (termw->have_selection)
  3131.         invert_text(termw,
  3132.             termw->from_lin,
  3133.             termw->from_col,
  3134.             termw->to_lin,
  3135.             termw->to_col);
  3136.  
  3137.     /* (UoR) only if cursor is showing */
  3138.     if (termw->cur_drawn && termw->cursor_invert) {
  3139.     termw->cursor_invert = FALSE;    /* (UoR) make sure we draw it */
  3140.     cursor_draw(termw);        /* redraw cursor */
  3141.     termw->last_flash = TickCount (); /* (UoR) reset timer */
  3142.     }
  3143.  
  3144.     SetPort (savePort);        /* there just has to be a better way */
  3145. }                /* term_redraw */
  3146.  
  3147. draw_grow_and_erase_line (struct termw *termw, int invalidate_it)
  3148. {
  3149.     Rect r;
  3150.  
  3151.     DrawGrowIcon (termw->window);
  3152.     /* erase the bottom scroll line (but only if inverted screen) */
  3153.     if (!termw->screeninvert) {
  3154.     PenMode(patBic);
  3155.     MoveTo(0, (termw->window->portRect).bottom - 15);
  3156.     LineTo((termw->window->portRect).right - 15,
  3157.             (termw->window->portRect).bottom - 15);
  3158.     PenMode(patCopy);
  3159.     }
  3160.     
  3161.     if (invalidate_it) {
  3162.     r.top = (termw->window->portRect).bottom - 16;
  3163.     r.bottom = (termw->window->portRect).bottom - 14;
  3164.     r.left = 0;
  3165.     r.right = (termw->window->portRect).right - 16;
  3166.     InvalRect(&r);
  3167.     }
  3168. }
  3169.  
  3170. term_activate (struct termw *termw, int mod)
  3171. {
  3172.     GrafPtr savePort;
  3173.     
  3174.     GetPort (&savePort);
  3175.     SetPort (termw->window);
  3176.  
  3177.     cursor_erase (termw);        /* remove cursor from screen */
  3178.     termw->in_front = mod & activeFlag;
  3179.     if (termw->in_front) {
  3180.     UpdateOptKey(1);
  3181.     DisableItem(menus[EDIT_MENU], UNDO_EDIT);
  3182.     DisableItem(menus[EDIT_MENU], CLEAR_EDIT);
  3183.     } else {
  3184.     UpdateOptKey(0);
  3185.     EnableItem(menus[EDIT_MENU], UNDO_EDIT);
  3186.     EnableItem(menus[EDIT_MENU], CLEAR_EDIT);
  3187.     }
  3188.     /* these do the right thing for background too */
  3189.     update_vscroll (termw);
  3190.     draw_grow_and_erase_line(termw, 1);
  3191.     cursor_draw(termw);
  3192.  
  3193.     SetPort (savePort);
  3194. }
  3195.  
  3196. /*
  3197.  * This CAN be called external to inpchars(), so save and restore the
  3198.  * GrafPort just in case.
  3199.  */
  3200. set_term_invert (struct termw *termw, int new_inv)
  3201. {
  3202.     GrafPtr savePort;
  3203.     
  3204.     GetPort (&savePort);    /* there just has to be a better way */
  3205.     SetPort (termw->window);
  3206.  
  3207.     if (new_inv == termw->screeninvert)
  3208.         return;
  3209.     
  3210.     if (new_inv) {
  3211.     BackPat (qd.black);    /* (UoR) use black background */
  3212.     PenPat(qd.white);
  3213.     termw->screeninvert = TRUE;
  3214.     } else {
  3215.     BackPat (qd.white);
  3216.     PenPat(qd.black);
  3217.     termw->screeninvert = FALSE;
  3218.     }
  3219.     InvalRect(&termw->window->portRect);/* invalidate whole window rectangle */
  3220.     SetPort (savePort);        /* there just has to be a better way */
  3221. }
  3222.  
  3223. /****************************************************************************/
  3224. /* sizevscroll - called when window is created and after a window grow */
  3225. /*                      sequence to resize the scroll window's bars. */
  3226. /****************************************************************************/
  3227. void sizevscroll (struct termw *termw)
  3228. {
  3229.     register Rect *r;
  3230.  
  3231.     if (!termw)
  3232.     DebugStr("\psizevscroll called with termw == NULL");
  3233.  
  3234.     r = &termw->window->portRect;/* window size */
  3235.     HideControl (termw->t_vscroll);
  3236.  
  3237.     MoveControl (termw->t_vscroll, r->right - 15, r->top - 1);
  3238.     SizeControl (termw->t_vscroll, 16, r->bottom - r->top - 13);
  3239.  
  3240.     SetCtlMin (termw->t_vscroll, 0);
  3241.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  3242.     update_vscroll(termw);
  3243.     ShowControl (termw->t_vscroll);
  3244. }
  3245.  
  3246. /****************************************************************************/
  3247. /* initalize the terminal emulator. */
  3248. /****************************************************************************/
  3249. init_term (struct termw *termw)
  3250. {
  3251.     register int i, j;
  3252.     register unsigned char *scp, *acp;
  3253.     unsigned char *scr_cp, *attr_cp;
  3254.     GrafPtr savePort;
  3255.     
  3256.     GetPort (&savePort);    /* there just has to be a better way */
  3257.     SetPort (termw->window);
  3258.    
  3259.     termw->topmargin = TOPMARGIN;    /* Edges of adjustable window */
  3260.     termw->bottommargin = bottomMARGIN;
  3261.     
  3262.     if ((scr_cp = (unsigned char *) NewPtr(((long)(MAXCOL+1)
  3263.                             * (long) MAX_SCREENSIZE)))
  3264.     == NIL)
  3265.       macfatal("Could not allocate screen buffer", 0);
  3266.     
  3267.     if ((attr_cp = (unsigned char *) NewPtr(((long)(MAXCOL+1)
  3268.                              * (long) MAX_SCREENSIZE)))
  3269.     == NIL)
  3270.       macfatal("Could not allocate screen attribute buffer", 0);
  3271.     
  3272.     if ((termw->real_scr = (ucharptr *) NewPtr ((long)(MAX_SCREENSIZE)
  3273.                      * (long) sizeof(ucharptr))) == NIL)
  3274.     macfatal("Could not allocate screen buffer", 0);
  3275.     
  3276.     if ((termw->real_attrs = (ucharptr *) NewPtr ((long)(MAX_SCREENSIZE)
  3277.                        * (long) sizeof(ucharptr))) == NIL)
  3278.     macfatal("Could not allocate screen buffer", 0);
  3279.  
  3280.     if ((termw->real_ln_attrs
  3281.      = (unsigned char *) NewPtr ((long)(MAX_SCREENSIZE)
  3282.                      * (long) sizeof(unsigned char))) == NIL)
  3283.     macfatal("Could not allocate screen buffer", 0);
  3284.  
  3285.     for (i = 0; i < MAX_SCREENSIZE; i++) {
  3286.     /* divvy up screen buffer */
  3287.         termw->real_scr[i] = scr_cp + (i * (MAXCOL+1));
  3288.     /* divvy up screen attribute buf */
  3289.         termw->real_attrs[i] = attr_cp + (i * (MAXCOL+1));
  3290.  
  3291.     scp = termw->real_scr[i];
  3292.     acp = termw->real_attrs[i];
  3293.     j = MAXCOL;
  3294.     do {            /* put normal spaces in all columns */
  3295.         *scp++ = ' ';
  3296.         *acp++ = 0;
  3297.     } while (--j > 0);
  3298.     *scp = ' ';        /* Terminate the lines as strings */
  3299.     *acp = 0;        /* Terminate the attrs as strings */
  3300.     termw->real_ln_attrs[i] = VT_SNGL;    /* reset line attributes */
  3301.     }
  3302.     
  3303.     termw->scr = &termw->real_scr[MAX_SCREENSIZE - termw->screensize];
  3304.     if (termw->scr[0] == NIL)
  3305.     macfatal("init_term: scr assignment botched for [0]", 0);
  3306.     if (termw->scr[termw->screensize-1] == NIL)
  3307.     macfatal("\
  3308. init_term: scr assignment botched for [termw->screensize-1]", 0);
  3309.  
  3310.     termw->scr_attrs = &termw->real_attrs[MAX_SCREENSIZE - termw->screensize];
  3311.     if (termw->scr_attrs[0] == NIL)
  3312.     macfatal("init_term: scr assignment botched for [0]", 0);
  3313.     if (termw->scr_attrs[termw->screensize-1] == NIL)
  3314.     macfatal("\
  3315. init_term: scr assignment botched for [termw->screensize-1]", 0);
  3316.     
  3317.     termw->line_attrs = &termw->real_ln_attrs[MAX_SCREENSIZE
  3318.                           - termw->screensize];
  3319.  
  3320.     termw->scrtop = toplin;        /* Scrolling region equals all */
  3321.     termw->scrbot = botlin;
  3322.     
  3323.     termw->scroll_amount = 0;        /* no pending scroll */
  3324.     termw->refresh_amount = 0;        /* no pending refresh */
  3325.     termw->saved_tlin = 0;
  3326.     termw->saved_blin = 0;
  3327.     
  3328.     termw->display_topline = toplin;    /* init display w/elevator at bottom */
  3329.     termw->display_totlines = termw->screensize;
  3330.     makerect(termw,&termw->ScreenRect, 0, 0, termw->screensize, MAXCOL);
  3331.     /* (UoR) full screen rectangle */
  3332.     
  3333.     SizeWindow(termw->window,
  3334.         rightMARGIN + 1 + 16,     /* add extra to side for asthetics */
  3335.     bottomMARGIN + TOPMARGIN,     /* add extra to bottom for asthetics */
  3336.     FALSE);
  3337.     /* PWP: make the window match it's real size */
  3338.  
  3339.     termw->t_vscroll = GetNewControl (RCMDVSCROLL, termw->window);
  3340.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  3341.     sizevscroll(termw);
  3342.  
  3343.     InitKeyStuff();        /* find the original KCHR keymaps */
  3344.  
  3345. #ifdef COMMENT
  3346.     draw_grow_and_erase_line(0);    /* it's new so don't invalidate it */
  3347. #endif
  3348.  
  3349.     /* ClipRect(&termw->ScreenRect); */
  3350.  
  3351.     SetPort (savePort);        /* there just has to be a better way */
  3352. }                /* init_term */
  3353.  
  3354. /****************************************************************************/
  3355. /* grow_term_to(termw, size) -- change the size of the terminal window to size.
  3356.    this is called by growterm() (see below) and the terminal settings dialog
  3357.    handler (termsetdialog()).
  3358. /****************************************************************************/
  3359. grow_term_to (struct termw *termw, int size)
  3360. {
  3361.     GrafPtr savePort;
  3362.  
  3363.     GetPort (&savePort);
  3364.     SetPort (termw->window);
  3365.  
  3366.     if ((size < 1) || (size > MAX_SCREENSIZE))
  3367.        size = 24;    /* the default case */
  3368.     
  3369.     if (size > termw->display_totlines) { 
  3370.     /* 
  3371.      * if getting bigger than we were
  3372.      * We would zero out lines from (termw->screensize-size) to 
  3373.      * (termw->screensize-display_totlines),
  3374.      * but these were already zeroed when the original screen was inited.
  3375.      */
  3376.     termw->display_totlines = size;
  3377.     }
  3378.     
  3379.     /* $$$ Make sure to scroll screen to what will be the new bottom here */
  3380.  
  3381.     /* adjust cursor row to match stretch */
  3382.     termw->curlin += size - termw->screensize;
  3383.     if (termw->curlin < 0)
  3384.     termw->curlin = 0;
  3385.     if (termw->curlin > size-1)
  3386.     termw->curlin = size-1;
  3387.     
  3388.     termw->screensize = size;
  3389.     if (termw->screensize > MAX_SCREENSIZE)
  3390.         termw->screensize = MAX_SCREENSIZE;        /* bounds check */
  3391.  
  3392.     termw->scr = &termw->real_scr[MAX_SCREENSIZE - termw->screensize];
  3393.     termw->scr_attrs = &termw->real_attrs[MAX_SCREENSIZE - termw->screensize];
  3394.     termw->line_attrs = &termw->real_ln_attrs[MAX_SCREENSIZE
  3395.                           - termw->screensize];
  3396.    
  3397.     termw->bottommargin = bottomMARGIN;    /* this changes */
  3398.     
  3399.     termw->scrtop = toplin;        /* Scrolling region equals all */
  3400.     termw->scrbot = botlin;
  3401.     termw->display_topline = 0;    /* re-init display w/elevator at bottom */
  3402.     makerect(termw,&termw->ScreenRect, 0, 0, termw->screensize, MAXCOL);
  3403.     /* (UoR) full screen rectangle */
  3404.     
  3405.     SizeWindow(termw->window,
  3406.         rightMARGIN + 1 + 16,     /* add extra to side for asthetics */
  3407.     bottomMARGIN + TOPMARGIN,     /* add extra to bottom for asthetics */
  3408.     FALSE);
  3409.     /* PWP: make the window match it's real size */
  3410.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  3411.     sizevscroll(termw);    /* size the scroll bars */
  3412.  
  3413.     /* ClipRect(&termw->ScreenRect); */
  3414.  
  3415.     /* invalidate whole window rectangle */
  3416.     InvalRect (&termw->window->portRect);
  3417.  
  3418.     SetPort (savePort);
  3419. }                /* grow_term_to */
  3420.  
  3421. /****************************************************************************/
  3422. /* 
  3423.  * growterm() -- called when we get a mouse-down in the lower right corner grow
  3424.  * box.
  3425.  * Probably all right not to save the grafport, but we do anyway just to be
  3426.  * double extra safe.
  3427.  */
  3428. /****************************************************************************/
  3429. growterm (struct termw *termw, Point *p)
  3430. {
  3431.     long gr;
  3432.     int height;
  3433.     int width;
  3434.     int size;
  3435.     Rect growRect;
  3436.     GrafPtr savePort;
  3437.     
  3438.     GetPort (&savePort);    /* there just has to be a better way */
  3439.     SetPort (termw->window);
  3440.  
  3441.     growRect = qd.screenBits.bounds;
  3442.     growRect.top = 50;        /* minimal horizontal size */
  3443.     growRect.left = rightMARGIN + 18;    /* minimal vertical size */
  3444.     growRect.right = rightMARGIN + 18;    /* minimal vertical size */
  3445.  
  3446.     gr = GrowWindow (termw->window, *p, &growRect);
  3447.  
  3448.     if (gr == 0)
  3449.     return;
  3450.     height = HiWord (gr);
  3451.     width = LoWord (gr);
  3452.  
  3453.     size = (height - (2 * TOPMARGIN)) / termw->lineheight;
  3454.     if (size > MAX_SCREENSIZE)
  3455.         termw->screensize = MAX_SCREENSIZE;        /* bounds check */
  3456.     if (size < 1)
  3457.         size = 1;
  3458.  
  3459.     grow_term_to(termw, size);
  3460.  
  3461.     SetPort (savePort);        /* there just has to be a better way */
  3462. }                /* growterm */
  3463.  
  3464. /****************************************************************************/
  3465. get_term_pos(struct termw *termw, int *top_p, int *left_p)
  3466. {
  3467.     Point mypoint;
  3468.     GrafPtr savePort;
  3469.     
  3470.     GetPort (&savePort);    /* there just has to be a better way */
  3471.     SetPort (termw->window);
  3472.  
  3473.     mypoint.v = termw->window->portRect.top;
  3474.     mypoint.h = termw->window->portRect.left;
  3475.     LocalToGlobal(&mypoint);
  3476.     
  3477.     if (top_p)
  3478.     *top_p = mypoint.v;
  3479.     if (top_p)
  3480.     *left_p = mypoint.h;
  3481.     
  3482.     SetPort (savePort);        /* there just has to be a better way */
  3483. }
  3484.  
  3485. set_term_pos(struct termw *termw, int top, int left)
  3486. {
  3487.     MoveWindow(termw->window, left, top, TRUE);
  3488. }
  3489.  
  3490. /*
  3491.  * Junk so Emacs will set local variables to be compatible with Mac/MPW.
  3492.  * Should be at end of file.
  3493.  * This module was apparently formatted with tabs = 8
  3494.  * 
  3495.  * Local Variables:
  3496.  * tab-width: 8
  3497.  * End:
  3498.  */
  3499.