home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d131 / mg1b.lha / Mg1b / Source / amiga / ttyio.c < prev    next >
C/C++ Source or Header  |  1988-03-14  |  24KB  |  988 lines

  1. /*
  2.  * Name:    MicroEmacs
  3.  *        Amiga terminal-dependent I/O (Intuition)
  4.  * Last Edit:    12-Mar-87 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
  5.  * Created:    21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
  6.  */
  7.  
  8. /*
  9.  * Lots of includes.
  10.  */
  11.  
  12. #include <exec/types.h>
  13. #include <exec/nodes.h>
  14. #include <exec/lists.h>
  15. #include <exec/tasks.h>
  16. #include <exec/ports.h>
  17. #include <exec/io.h>
  18. #include <devices/console.h>
  19. #include <libraries/dos.h>
  20. #include <graphics/clip.h>
  21. #include <graphics/view.h>
  22. #include <graphics/rastport.h>
  23. #include <graphics/layers.h>
  24. #include <graphics/text.h>
  25. #include <graphics/gfxbase.h>
  26. #include <intuition/intuition.h>
  27. #include <intuition/intuitionbase.h>
  28. #ifdef    CHANGE_FONT
  29. #include <libraries/diskfont.h>
  30. #endif
  31.  
  32. #undef    TRUE            /* avoid redefinition messages         */
  33. #undef    FALSE
  34. #include "def.h"        /* includes sysdef.h and ttydef.h    */
  35.  
  36. /*
  37.  * External Amiga functions.  Declared explicitly
  38.  * to avoid problems with different compilers.
  39.  */
  40. extern    LONG             AbortIO();
  41. extern    LONG             CloseDevice();
  42. extern    LONG             CloseLibrary();
  43. extern    LONG             CloseWindow();
  44. extern    struct    MsgPort        *CreatePort();
  45. extern    struct    IOStdReq    *CreateStdIO();
  46. extern    LONG             DeletePort();
  47. extern    LONG             DeleteStdIO();
  48. extern    struct    IntuiMessage    *GetMsg();
  49. extern    int             OpenConsole();
  50. extern    char            *OpenLibrary();
  51. extern    struct    Window        *OpenWindow();
  52. #ifdef    CHANGE_FONT
  53. extern    struct TextFont        *OpenDiskFont();
  54. #endif
  55. extern    LONG             RectFill();
  56. extern    LONG             ReplyMsg();
  57. extern    LONG             SetAPen();
  58. extern    LONG             SetDrMd();
  59. extern    LONG             Wait();
  60.  
  61. #ifdef    DO_MENU
  62. extern    LONG             ClearMenuStrip();    /* menu functions */
  63. extern    struct    Menu        *InitEmacsMenu();
  64. extern    struct    MenuItem    *ItemAddress();
  65. extern    LONG             SetMenuStrip();
  66. #endif
  67.  
  68. #ifdef    MANX
  69. extern    int    Enable_Abort;        /* Do NOT allow abort!        */
  70. #endif
  71.  
  72. #ifdef    LATTICE
  73. /*
  74.  * Internal functions that LATTICE wants to be void. Declare here to
  75.  *    avoid redeclaration errors.
  76.  */
  77. VOID    ttclose() ;
  78. VOID    ttputc(unsigned char) ;
  79. VOID    ttflush() ;
  80. VOID    setttysize() ;
  81. VOID    panic(char *) ;
  82. static VOID    remevt() ;
  83. static VOID    qchar(unsigned char) ;
  84. #ifdef    MOUSE
  85. static VOID    qmouse(SHORT, SHORT, USHORT) ;
  86. #endif
  87. #ifdef    DO_MENU
  88. static VOID    qmenu(USHORT) ;
  89. #endif
  90.  
  91. #else
  92. /*
  93.  * Internal functions for Manx, to avoid redeclaration errors.
  94.  */
  95. VOID    ttclose(), ttputc(), ttflush(), setttysize(), panic();
  96. static VOID    remevt(), qchar();
  97. #ifdef    MOUSE
  98. static VOID    qmouse();
  99. #endif
  100. #ifdef    DO_MENU
  101. static VOID    qmenu();
  102. #endif
  103.  
  104. #endif    LATTICE
  105.  
  106. /*
  107.  * External MicroEmacs functions and variables
  108.  */
  109. extern    int    quit();            /* Defined by "main.c"    */
  110. extern    char    *version;        /* Version information        */
  111.  
  112. /*
  113.  * Library bases (used by glue libraries)
  114.  */
  115. struct    IntuitionBase    *IntuitionBase;
  116. struct    GfxBase        *GfxBase;
  117. #ifdef    CHANGE_FONT
  118. ULONG            DiskfontBase;
  119. #endif
  120.  
  121. /*
  122.  * Intuition window and menu variables
  123.  */
  124. #define WINDOWGADGETS (WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE)
  125.  
  126. static short    borderless = FALSE;    /* Flag for borderless window    */
  127. static short    leftedge = 0,        /* Last top left position    */
  128.         topedge = 0;
  129. static short    width, height;        /* Set by ttopen()        */
  130.  
  131. struct NewWindow MicroEMACS = {
  132.     0,    0,            /* start position           */
  133.     0,    0,            /* width, height (set by ttopen)*/
  134.     0,    1,                 /* detail pen, block pen    */
  135. #ifdef    DO_MENU
  136.     MENUPICK |            /* If menu is used        */
  137. #endif
  138. #ifdef    MOUSE
  139.     MOUSEBUTTONS |             /* If mouse is used        */
  140. #endif
  141.     INTUITICKS |
  142.     CLOSEWINDOW | NEWSIZE,        /* IDCMP flags            */
  143.     0,                /* window flags    (set by ttopen)    */
  144.     NULL,                /* pointer to first user gadget */
  145.     NULL,                /* pointer to user checkmark    */ 
  146.     NULL,                /* title (filled in later)    */
  147.     NULL,                /* pointer to screen (none)    */
  148.     NULL,                /* pointer to superbitmap    */
  149.     359,101,            /* minimum size (with TOPAZ_80)    */
  150.     0, 0,                /* maximum size (set by ttopen)    */
  151.     WBENCHSCREEN            /* screen in which to open    */ 
  152. };
  153.  
  154. struct Window    *EmW;                /* Our window        */
  155. static short        toggling = FALSE;    /* Prevent menu wiping    */
  156.  
  157. #ifdef    DO_MENU
  158. static struct Menu    *EmacsMenu = NULL;    /* Our menu        */
  159. #endif
  160. #ifdef    CHANGE_FONT
  161. static    struct TextFont *EmFont = NULL;
  162. #endif
  163.  
  164. /*
  165.  * The bridge between Intuition events and Emacs' single
  166.  * input stream...
  167.  */
  168. static ULONG        class;            /* Intuition event    */
  169. static USHORT        code,            /*   information    */
  170.             qualifier;
  171. static APTR        address;
  172. static SHORT        x, y;
  173. static LONG        intuitionMsgBit;    /* Signal bit        */
  174. #define INTUITION_MESSAGE ((LONG) (1L << intuitionMsgBit))
  175.  
  176. /*
  177.  * To more thoroughly handle Intuition events, we buffer
  178.  * them into a circular queue until other routines ask
  179.  * for the information carried in them.
  180.  */
  181. #define    NIBUF    256            /* Rather roomy...        */
  182. #define    EVT_KBD        0
  183. #define    EVT_MOUSE    1
  184. #define EVT_MENU    2
  185. #define NULLEVT    ((struct event *) 0)
  186.  
  187. struct    event {
  188.     USHORT type;            /* What is it?            */
  189.     union    {
  190.         UBYTE    ch;        /* Keyboard event        */
  191.         struct {        /* Mouse click            */
  192.             SHORT row, col;    /* location in character raster    */
  193.             USHORT qualifier;
  194.         } mouse;
  195.         USHORT    code;        /* Menu event            */
  196.     } data;
  197. }        ibuf[NIBUF];        /* Input buffer            */
  198. int        ibufo, nibuf;        /* head, # of bytes in ibuf    */
  199.  
  200. /*
  201.  * Console output
  202.  */
  203. #define    CSI    0x9b            /* Command Sequence Introducer    */
  204. #define    ESC    0x1b            /* Escape key            */
  205. #define    NOBUF    512            /* About 1/4 screen        */
  206.  
  207. static struct MsgPort    *consoleWritePort;    /* I/O ports         */
  208. static struct MsgPort    *consoleReadPort;    
  209. static struct IOStdReq    *consoleWriteMsg;    /* I/O messages        */
  210. static struct IOStdReq    *consoleReadMsg;
  211. static LONG        consoleMsgBit;        /* signal bit        */
  212. #define CONSOLE_MESSAGE ((LONG) (1L << consoleMsgBit))
  213. static unsigned char    letter;            /* Console input buffer    */
  214.  
  215. static unsigned char    obuf[NOBUF];    /* Terminal output buffer    */
  216. int            nobuf;        /* # of bytes in above        */
  217. int            nrow;        /* Terminal size, rows.        */
  218. int            ncol;        /* Terminal size, columns.    */
  219. extern int        ttrow;        /* Current cursor row        */
  220.  
  221. #define    PROMPTWAIT 20            /* ticks to wait before timeout    */
  222. static    LONG        tickcount;    /* # intuiticks    since last char    */
  223.  
  224. /*
  225.  * Open up the virtual terminal MicroEMACS communicates with.
  226.  * Set up the window, console, and menu strip.  Also bumps the priority.
  227.  */
  228.  
  229. ttopen()
  230. {
  231.     register struct Screen *s;
  232.  
  233. #ifdef    MANX
  234.     Enable_Abort = 0;                /* Disable ^C    */
  235. #endif
  236.  
  237.         bumpprior() ;
  238.     GfxBase = (struct GfxBase *)
  239.         OpenLibrary("graphics.library", (LONG) 0);
  240.     if (GfxBase  == NULL)                /* Graphics lib    */
  241.         cleanup(1);
  242.  
  243.     IntuitionBase = (struct IntuitionBase *)    /* Intuition    */
  244.         OpenLibrary("intuition.library", (LONG) 0);
  245.     if (IntuitionBase == NULL)
  246.         cleanup(2);
  247.  
  248. #ifdef    CHANGE_FONT
  249.     DiskfontBase = (ULONG) OpenLibrary("diskfont.library", (LONG)0);
  250.     if (DiskfontBase == NULL)
  251.         cleanup(21);
  252. #endif
  253.     /*
  254.      * Create our window. Set window flags based on the current
  255.      * value of the borderless flag, and the maximum size of the
  256.      * window based on the size of the first screen in the screen
  257.      * list with screen type WBENCHSCREEN (of which there had better
  258.      * be *EXACTLY* one, right???...).  To avoid possible crashes
  259.      * if user is moving screens around, turn off multitasking
  260.      * during the loop.
  261.      */
  262.     Forbid();    /* user might be moving screen */
  263.     for (s = IntuitionBase->FirstScreen; s ; s = s->NextScreen)
  264.         if ((s->Flags & SCREENTYPE) == WBENCHSCREEN)
  265.             break;
  266.     width = MicroEMACS.MaxWidth = s->Width;
  267.     height = MicroEMACS.MaxHeight = s->Height;
  268.     Permit();
  269.  
  270.     /* Set the window size based on the last one that was open,
  271.      * if it was borderless. Otherwise make it fill the screen.
  272.      * Set max/min widths based on current screen size.
  273.      *
  274.      * Set flags and window title, then open window
  275.      */
  276.     if (borderless) {
  277.         MicroEMACS.Flags = WINDOWGADGETS | ACTIVATE | BORDERLESS;
  278. #ifdef    TOGGLE_ZOOMS
  279.         MicroEMACS.LeftEdge = 0;
  280.         MicroEMACS.TopEdge = 0;
  281.         MicroEMACS.Width = MicroEMACS.MaxWidth;
  282.         MicroEMACS.Height = MicroEMACS.MaxHeight;
  283. #endif
  284.     } else {
  285.         MicroEMACS.Flags = WINDOWGADGETS | ACTIVATE | WINDOWSIZING;
  286. #ifndef    TOGGLE_ZOOMS
  287.     }
  288. #endif
  289.         MicroEMACS.LeftEdge = leftedge;
  290.         MicroEMACS.TopEdge = topedge;
  291.         MicroEMACS.Width = width;
  292.         MicroEMACS.Height = height;
  293. #ifdef    TOGGLE_ZOOMS
  294.     }
  295. #endif
  296.     MicroEMACS.Title = (UBYTE *) version;    /* name for window */
  297.     if ((EmW = OpenWindow(&MicroEMACS)) == NULL)
  298.         cleanup(3);
  299.  
  300. #ifdef    CHANGE_FONT
  301.     /* If the user requested a different font for the text, EmFont
  302.      * will be non-null, so set the font for the RastPort.  The
  303.      * conole device will pick this up when we open it later on.
  304.      */
  305.     if (EmFont)
  306.         SetFont(EmW->RPort, EmFont);
  307. #endif
  308.  
  309.     /* Once the window is created, get the Intuition signal bit,
  310.      * set up the menu, and tell the virtual terminal how big
  311.      * it is.
  312.       */
  313.     intuitionMsgBit = EmW->UserPort->mp_SigBit;
  314. #ifdef    DO_MENU
  315.     if (toggling == FALSE)
  316.         EmacsMenu = InitEmacsMenu(EmW);
  317.     SetMenuStrip(EmW, EmacsMenu);
  318. #endif
  319.     setttysize();
  320.  
  321.     /* Set up the console device.  Create the necessary read/write
  322.      * ports and messages, attach the console device thus created
  323.      * to our window, initialize the console input buffer, and
  324.      * queue the first read to the console.
  325.      */
  326.  
  327.     consoleWritePort = CreatePort("Emacs.con.write",(LONG) 0);
  328.     if (consoleWritePort == NULL)
  329.         cleanup(4);
  330.     consoleWriteMsg = CreateStdIO(consoleWritePort);
  331.     if (consoleWriteMsg == NULL)
  332.         cleanup(5);
  333.  
  334.     consoleReadPort = CreatePort("Emacs.con.read",(LONG) 0);
  335.     if (consoleReadPort == NULL)
  336.         cleanup(6);
  337.     consoleReadMsg = CreateStdIO(consoleReadPort);
  338.     if (consoleReadMsg == NULL)
  339.         cleanup(7);
  340.  
  341.     if (OpenConsole(consoleWriteMsg,consoleReadMsg,EmW) != 0)
  342.         cleanup(8);
  343.     consoleMsgBit = consoleReadPort->mp_SigBit;
  344.  
  345.     QueueRead(consoleReadMsg,&letter);
  346.     nibuf = ibufo = 0;
  347.  
  348.     return (0);
  349. }
  350.  
  351. /*
  352.  * Close the virtual terminal, aborting any
  353.  * I/O to the console device and de-allocating
  354.  * everything we have allocated.
  355.  */
  356. VOID
  357. ttclose()
  358. {
  359.     ttflush();
  360.     AbortIO(consoleReadMsg);
  361.     CloseDevice(consoleWriteMsg);
  362.         unbumpprior() ;
  363.     cleanup(0);
  364. #ifdef    MANX
  365.     Enable_Abort = 1;
  366. #endif
  367. }
  368.  
  369. /*
  370.  * Toggle between a borderless window
  371.  * and a sizeable window. This lets you
  372.  * use the whole screen if you want.
  373.  * Bound to "toggle-window-hack" by
  374.  * ttykbd.c
  375.  */
  376.  
  377. togglewindow(f, n, k)
  378. {
  379.     toggling = TRUE;            /* Notify the system    */
  380. #ifdef    TOGGLE_ZOOMS
  381.     if (!borderless) {
  382. #endif
  383.         leftedge = EmW->LeftEdge;    /* save window state    */
  384.         topedge = EmW->TopEdge;
  385.         width = EmW->Width;
  386.         height = EmW->Height;
  387. #ifdef    TOGGLE_ZOOMS
  388.     }
  389. #endif
  390.     ttclose();                /* reset to zero    */
  391.  
  392.     borderless = !borderless;        /* toggle window flag    */
  393.     ttopen();                /* re-open tty window    */
  394.     ttinit();                /* re-initalize tty    */
  395.     sgarbf = TRUE;                /* screen was trashed    */
  396.     nrow = ncol = -1;            /* trash screen size    */
  397.     refresh();                /* and redraw it    */
  398.     toggling = FALSE;            /* Ok, done        */
  399.     return (TRUE);
  400. }
  401.  
  402. #ifdef    CHANGE_FONT
  403. /*
  404.  * Select a different font for the Emacs window.
  405.  * This obviously does not work very well
  406.  * with proportional fonts, so we ask the
  407.  * user to confirm before he uses one.
  408.  * It's available if you want to be able
  409.  * to use your own disk font (or Topaz 11
  410.  * under 1.2) to edit with.
  411.  */
  412.  
  413. setfont(f, n, k)
  414. {
  415.     register int    s, size;
  416.     register struct TextFont *newfont;
  417.     char        fontname[80], fontpath[84], fontsize[3];
  418.     struct TextAttr    ta;
  419.  
  420.     /* Get font size */
  421.     if (f == TRUE)
  422.         size = n;
  423.     else {
  424.         if ((s = ereply("Font size: ",
  425.                 fontsize, sizeof(fontsize))) != TRUE)
  426.             return (s);
  427.         size = atoi(fontsize);
  428.     }
  429.  
  430.     if (size <= 0) {    /* reset to default font    */
  431.         if (EmFont)
  432.             CloseFont(EmFont);
  433.         EmFont = NULL;
  434.     } else {        /* user wants to set a new font name */
  435.         if ((s = ereply("Font name: ",
  436.                 fontname, sizeof(fontname))) != TRUE)
  437.             return (s);
  438.         strcpy(fontpath,fontname);
  439.         strncat(fontpath,".font",sizeof(fontpath));/* make name */
  440.  
  441.         /* set up text attributes */
  442.         ta.ta_Name = (UBYTE *)fontpath;
  443.         ta.ta_YSize = size;
  444.         ta.ta_Style = FS_NORMAL;
  445.         ta.ta_Flags = 0; /* use either */
  446.  
  447.         /* Look for the font */
  448.         ewprintf("Looking for %s %d...",fontname,size);
  449.         if ((newfont = OpenDiskFont(&ta)) == NULL) {
  450.             ewprintf("Can't find %s %d!",fontname,size);
  451.             return (FALSE);
  452.         } else { /* Found it! Check before using it. */
  453.             if ((newfont->tf_YSize != size) && ((s = eyesno(
  454.                "Size unavailable - use closest"))!=TRUE)){
  455.                 CloseFont(newfont);
  456.                 return (FALSE);
  457.             }
  458.             if ((newfont->tf_Flags & FPF_PROPORTIONAL) &&
  459.                 (((s = eyesno("Use proportional font")))!=TRUE)){
  460.                 CloseFont(newfont);
  461.                 return (FALSE);
  462.             }
  463.             /* Get rid of old font and cache the new one */
  464.             if (EmFont)
  465.                 CloseFont(EmFont);
  466.             EmFont = newfont;
  467.         }
  468.     }
  469.  
  470.     /* Now that the font is selected, close the window. */
  471.     toggling = TRUE;            /* Notify the system    */
  472.     ttclose();                /* reset to zero    */
  473.     ttopen();                /* re-open w/new font    */
  474.     ttinit();                /* re-init console    */
  475.     nrow = -1;                /* trash size        */
  476.     ncol = -1;                /* so refresh() works    */
  477.     refresh();                /* redo whole screen    */
  478.     if (size > 0)
  479.         ewprintf("Now using font %s %d",fontname,EmFont->tf_YSize);
  480.     else
  481.         ewprintf("Now using default font");
  482.     return (TRUE);
  483. }
  484. #endif
  485.  
  486. /*
  487.  * Write a single character to the screen.
  488.  * Buffered for extra speed, so ttflush()
  489.  * does all the work.
  490.  */
  491. VOID
  492. ttputc(c)
  493. unsigned char c;
  494. {
  495.     obuf[nobuf++] = c;
  496.     if (nobuf >= NOBUF)
  497.         ttflush();
  498. }
  499.  
  500. /*
  501.  * Flush characters from the output buffer.
  502.  * Just blast it out with a console write call.
  503.  */
  504. VOID
  505. ttflush()
  506. {
  507.     if (nobuf > 0) {
  508.         ConWrite(consoleWriteMsg, obuf, nobuf);
  509.         nobuf = 0;
  510.     }
  511. }
  512.  
  513. /*
  514.  * Get a character for Emacs, without echo or
  515.  * translation.
  516.  */
  517. ttgetc()
  518. {
  519.     return handle_kbd(FALSE);    /* wait for char w/o timeout */
  520. }
  521.  
  522. /*
  523.  * Return TRUE if we've waited for 2 seconds and nothing has
  524.  * happened, else return false.
  525.  */
  526.  
  527. ttwait()
  528. {
  529.     return handle_kbd(TRUE);    /* time out after 2 sec */
  530. }
  531.  
  532. /*
  533.  * Common routine for handling character input, with and
  534.  * without timeout.  Handle events until:
  535.  *
  536.  *    1) a character is put in the input buffer
  537.  *    2) if timeout == TRUE, PROMPTWAIT IntuiTicks have gone by
  538.  *
  539.  * If timeout == FALSE, the character is returned and removed from
  540.  *    the input buffer.
  541.  * If timeout == TRUE, returns TRUE if the read timed out, else FALSE.
  542.  *    I.e. FALSE indicates a character was typed before the time limit
  543.  */
  544.  
  545. static handle_kbd(timeout)
  546. register int timeout;
  547. {
  548.     register struct    IntuiMessage *message;    /* IDCMP message     */
  549.     register LONG    wakeupmask;        /* which signals?    */
  550.     register int    charfound;        /* got a character yet?    */
  551.     unsigned char    nextchar();        /* return next char evt    */
  552.  
  553.     tickcount = 0;                /* always zero the count */
  554.     if (striptochar())            /* any chars in buffer?    */
  555.         return timeout ? FALSE : ((int) (nextchar() & 0xFF));
  556.  
  557.     charfound = FALSE;            /* nope -- have to wait    */
  558.     do {
  559.         wakeupmask = Wait(INTUITION_MESSAGE|CONSOLE_MESSAGE);
  560.  
  561.         if (wakeupmask & CONSOLE_MESSAGE) {    /* keyboard     */
  562.             GetMsg(consoleReadPort);    /* free message     */
  563.             qchar(letter);            /* do this FIRST */
  564.             QueueRead(consoleReadMsg, &letter);
  565.             charfound = TRUE;
  566.         }
  567.  
  568.         /* Intuition event.  Handle Intuiticks specially. */
  569.         if (wakeupmask & INTUITION_MESSAGE)
  570.             while(message =    GetMsg(EmW->UserPort))
  571.                 if (message->Class == INTUITICKS) {
  572.                     tickcount++;
  573.                     ReplyMsg(message);
  574.                 } else if (dispatch(message) == TRUE)
  575.                     charfound = TRUE;
  576.  
  577.         /* time out if enough ticks have gone by without
  578.          * any keyboard input.  We do this *after* all the
  579.          * events in the current list have been dispatched.
  580.          */
  581.         if (timeout && (tickcount > PROMPTWAIT))
  582.             break;
  583.     } while (charfound == FALSE);
  584.  
  585.     /* If called by ttwait(), return FALSE if a character was found.
  586.      * Else return the next character in the input buffer
  587.     */
  588.     return timeout ? (!charfound) : ((int) (nextchar() & 0xFF));
  589. }
  590.  
  591. /*
  592.  * Handle the events we handle...  The result
  593.  * returned indicates if we've put a character
  594.  * in the input buffer.
  595.  */
  596. static dispatch(msg)
  597. register struct IntuiMessage *msg;
  598. {
  599. #ifdef    DO_MENU
  600.     register struct    MenuItem    *item;
  601. #endif
  602.     register int            txheight, txwidth;
  603.     register struct RastPort    *rp;
  604.     int                dx, dy, fgpen, drmode;
  605.             
  606.     class =    msg->Class;        /* grab the info before we     */
  607.     code = msg->Code;        /* reply to the message        */
  608.     qualifier = msg->Qualifier;
  609.     address = msg->IAddress;
  610.     x = msg->MouseX;
  611.     y = msg->MouseY;
  612.     ReplyMsg(msg);            /* return it to Intuition    */
  613.  
  614.     switch(class) {            /* see what the fuss is about    */
  615. #ifdef    DO_MENU
  616.     case MENUPICK:
  617.         if (code == MENUNULL)
  618.             return (FALSE);
  619.         while (code != MENUNULL) {/* handle multiple selection    */
  620.             qmenu(code);
  621.             item = ItemAddress(EmacsMenu,(LONG) code);
  622.             code = item->NextSelect;
  623.         }
  624.         return (TRUE);        /* puts <CSI>M~ in event queue    */
  625.         break;
  626. #endif
  627.  
  628. #ifdef    MOUSE
  629.     case MOUSEBUTTONS:            /* fake the mouse key    */
  630.         if (code != SELECTDOWN)        /* ignore SELECTUP    */
  631.             return (FALSE);
  632.         qmouse(x, y, qualifier);
  633.         return (TRUE);
  634.         break;
  635. #endif
  636.     case NEWSIZE:
  637.         /* Sometimes when you resize the window to make it
  638.          * smaller, garbage is left at the right and bottom
  639.          * sides of the window. This code is devoted to
  640.          * (somehow) getting rid of this garbage.  Any
  641.          * suggestions?
  642.          */
  643.  
  644.         rp = EmW->RPort;
  645.         fgpen = rp->FgPen;        /* save params        */
  646.         drmode = rp->DrawMode;
  647.         SetDrMd(rp, (LONG) JAM1);
  648.         SetAPen(rp, (LONG) EmW->RPort->BgPen);
  649.  
  650.         /* Check the bottom of the window
  651.          */
  652.         txheight = EmW->Height - EmW->BorderTop - EmW->BorderBottom;
  653.         if (dy = (txheight % FontHeight(EmW)))
  654.             RectFill(rp,
  655.                 (LONG) EmW->BorderLeft,
  656.                 (LONG) EmW->BorderTop + txheight - dy - 1,
  657.                 (LONG) (EmW->Width - 1) - EmW->BorderRight,
  658.                 (LONG) (EmW->Height - 1) - EmW->BorderBottom);
  659.  
  660.         /* Check the right side
  661.          */
  662.         txwidth = EmW->Width - EmW->BorderLeft - EmW->BorderRight;
  663.         if (dx = txwidth % FontWidth(EmW))
  664.             RectFill(rp,
  665.                 (LONG) EmW->BorderLeft + txwidth - dx - 1,
  666.                 (LONG) EmW->BorderTop,
  667.                 (LONG) (EmW->Width - 1) - EmW->BorderRight,
  668.                 (LONG) (EmW->Height - 1) - EmW->BorderBottom);
  669.  
  670.         SetDrMd(rp, (LONG) drmode);
  671.         SetAPen(rp, (LONG) fgpen);    /* restore colors */
  672.  
  673.         /* Tell the console device to resize itself */
  674.         ttputc(CSI);
  675.         ttputc('t');
  676.         ttputc(CSI);
  677.         ttputc('u');
  678.         ttflush();
  679.  
  680.         /* Signal the editor that a new size has occurred */
  681.         qchar(ESC);
  682.         qchar('\f');
  683.  
  684.         return (TRUE);            /* we done (finally)    */
  685.         break;
  686.  
  687.         case CLOSEWINDOW:            /* Call quit() directly    */
  688.         quit(FALSE, 1, KRANDOM);
  689.         return (FALSE);
  690.                 break;
  691.  
  692.     default:
  693.         panic("HandleMsg: unknown event!!!");
  694.         break;
  695.     }
  696.     return(FALSE);
  697. }
  698.  
  699. #ifdef    DO_MENU
  700. /*
  701.  * Return the next menu selection number to
  702.  * the caller.  Used by "ttymenu.c".
  703.  */
  704. ttmenu(codep)
  705. USHORT *codep;
  706. {
  707.     register struct event *e;
  708.     struct event *nextevt();
  709.  
  710.     e = nextevt();
  711.     if (e->type != EVT_MENU)
  712.         return (FALSE);
  713.  
  714.     *codep = e->data.code;
  715.     remevt();            /* remove event by hand    */
  716.     return (TRUE);
  717. }
  718. #endif
  719.  
  720. #ifdef    MOUSE
  721. /*
  722.  * Return the next mouse click values to
  723.  * the caller.   *Rowp and *colp will contain
  724.  * the row and column where the mouse click occured.
  725.  * This is so that only the terminal driver has
  726.  * to know about the size of the window's font.
  727.  * If the flag argument f is FALSE, the mouse event
  728.  * is *not* removed from the queue, allowing routines
  729.  * that need to (mainly getmouse()) to peek at it.
  730.  */
  731. ttmouse(f, rowp,colp,qualp)
  732. int f;
  733. USHORT *rowp, *colp, *qualp;
  734. {
  735.     register struct event *e;
  736.     struct event *nextevt();
  737.  
  738.     e = nextevt();
  739.     if (e->type != EVT_MOUSE)
  740.         return (FALSE);        /* next isn't mouse evt */
  741.  
  742.     *colp = e->data.mouse.col;
  743.     *rowp = e->data.mouse.row;
  744.     *qualp = e->data.mouse.qualifier;
  745.     if (f)
  746.         remevt();            /* remove the event    */
  747.     return (TRUE);
  748. }
  749. #endif
  750.  
  751. /*
  752.  * Return the current size of the virtual
  753.  * terminal in nrow and ncol, making sure
  754.  * we don't go beyond the size of the internal
  755.  * video array.
  756.  * Assumes the current font is monospaced
  757.  * (not always safe bet any more :-) :-).
  758.  */
  759. VOID
  760. setttysize()
  761. {
  762.     nrow = (EmW->Height - TOP_OFFSET
  763.             - EmW->BorderBottom) / FontHeight(EmW);
  764.     ncol = (EmW->Width - EmW->BorderLeft
  765.             - EmW->BorderRight) / FontWidth(EmW);
  766.     if (nrow < 1)
  767.         nrow = 1;
  768.     if (nrow > NROW)
  769.         nrow = NROW;
  770.     if (ncol < 1)
  771.         ncol = 1;
  772.     if (ncol > NCOL)
  773.         ncol = NCOL;
  774. }
  775.  
  776. /*
  777.  * Exit as soon as possible, after displaying
  778.  * the message.
  779.  */
  780. VOID
  781. panic(s)
  782. char *s;
  783. {
  784.     ewprintf(s);        /* put message at bottom    */
  785.     Delay((ULONG) 90);    /* wait 1.5 seconds        */
  786.     ttclose();        /* get rid of window &resources    */
  787.     exit(10000);        /* go 'way            */
  788. }
  789.  
  790. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  791.  *             Event buffer management         *
  792.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  793.  
  794. /*
  795.  * If the buffer's full, crap out, else
  796.  * return a pointer to the (ibufo + nibuf)'th
  797.  * event record (mod NIBUF).  Postincrement
  798.  * nibuf so it points at the next record and
  799.  * also keeps track of how many events
  800.  * are in the buffer.
  801.  */
  802. static struct event *newevt()
  803. {
  804.     return ((nibuf < NIBUF) ? 
  805.         (ibuf + ((ibufo + nibuf++) % NIBUF)) : NULLEVT);
  806. }
  807.  
  808. /*
  809.  * Return pointer to next item in queue,
  810.  * *without* removing it.
  811.  */
  812. static struct event *nextevt()
  813. {
  814.     return (nibuf ? (ibuf + ibufo) : NULLEVT);
  815. }
  816.  
  817. /*
  818.  * Move buffer pointer to next item in queue.
  819.  */
  820. static VOID
  821. remevt()
  822. {
  823.     if (nibuf <= 0)
  824.         nibuf = 0;
  825.     else {
  826.         nibuf--;
  827.         ibufo++;
  828.         ibufo %= NIBUF;        /* wrap around in buffer    */
  829.     }
  830. }
  831.  
  832. /*
  833.  * Return true if there are some characters available
  834.  * in the buffer.  Unlike striptochar, don't do anything
  835.  * to the input buffer, just return a value.
  836.  */
  837. typeahead()
  838. {
  839.     register int bufp;
  840.  
  841.     for (bufp = 0; bufp < nibuf; bufp++)
  842.         if (ibuf[(ibufo + bufp) % NIBUF].type == EVT_KBD)
  843.             return (TRUE);
  844.     return (FALSE);
  845. }
  846.  
  847. /*
  848.  * See if there are any characters queued,
  849.  * stripping any other events that may
  850.  * be in the way.  *Don't* remove the character
  851.  * from the  queue.
  852.  */
  853. static
  854. striptochar()
  855. {
  856.     register struct event *e;
  857.  
  858.     while (e = nextevt())
  859.         if (e->type == EVT_KBD)
  860.             return (TRUE);
  861.         else
  862.             remevt();
  863.     return (FALSE);
  864. }
  865.  
  866. /*
  867.  * Return next character in event buffer.
  868.  */
  869. static unsigned char
  870. nextchar()
  871. {
  872.     register struct event *e;
  873.  
  874.     if (e = nextevt()) {
  875.         remevt();
  876.         return (e->data.ch);
  877.     }
  878.     else
  879.         return ((unsigned char) 0);    /* shouldn't happen    */
  880. }
  881.  
  882. /*
  883.  * Add a keyboard event to the queue
  884.  */
  885. static VOID
  886. qchar(c)
  887. unsigned char c;
  888. {
  889.     register struct event *e;
  890.  
  891.     if (e = newevt()) {
  892.         e->type = EVT_KBD;
  893.         e->data.ch = c;
  894.     }
  895. }
  896.  
  897. #ifdef    MOUSE
  898. /*
  899.  * Add a mouse event to the queue, calculating
  900.  * the row and column value from the current height
  901.  * and width of the window's font.
  902.  */
  903. static VOID
  904. qmouse(x, y, qual)
  905. SHORT x, y;
  906. USHORT qual;
  907. {
  908.     register struct event *e;
  909.  
  910.     qchar(CSI);
  911.     qchar('P');
  912.     qchar('~');
  913.     if (e = newevt()) {
  914.         e->type = EVT_MOUSE;
  915.         e->data.mouse.col = (x - EmW->BorderLeft) / FontWidth(EmW);
  916.         e->data.mouse.row = (y - TOP_OFFSET) / FontHeight(EmW);
  917.         e->data.mouse.qualifier = qual;
  918.     }
  919. }
  920. #endif
  921.  
  922. #ifdef    DO_MENU
  923. /*
  924.  * Add a menu key to queue
  925.  */
  926. static VOID
  927. qmenu(code)
  928. USHORT code;
  929. {
  930.     register struct event *e;
  931.  
  932.     qchar(CSI);        /* menu key sequence    */
  933.     qchar('M');
  934.     qchar('~');
  935.     if (e = newevt()) {
  936.         e->type = EVT_MENU;
  937.         e->data.code = code;
  938.     }
  939. }
  940. #endif
  941.  
  942. /*
  943.  * Clean up.
  944.  *
  945.  * Fall through all the possible cases (0 means
  946.  * get rid of everything and start with the case
  947.  * that fits the error situation).
  948.  */
  949.  
  950. static cleanup(prob)
  951. {
  952.     switch (prob) {
  953.     case 0:            /* just clean everything up
  954.     case 8:            /* couldn't open console device        */
  955.         DeleteStdIO(consoleReadMsg);
  956.     case 7:            /* couldn't get console read msg    */
  957.         DeletePort(consoleReadPort);
  958.     case 6:            /* couldn't get console read port    */
  959.         DeleteStdIO(consoleWriteMsg);
  960.     case 5:            /* couldn't get console write msg    */
  961.         DeletePort(consoleWritePort);
  962.     case 4:            /* couldn't get console write port    */
  963. #ifdef    CHANGE_FONT
  964.         if ((toggling == FALSE) && EmFont)
  965.             CloseFont(EmFont);/* access_count-- */
  966. #endif
  967. #ifdef    DO_MENU
  968.         if (toggling == FALSE) {
  969.             ClearMenuStrip(EmW);
  970.             DisposeMenus(EmacsMenu);
  971.         }
  972. #endif
  973.         CloseWindow(EmW);
  974.     case 3:            /* couldn't open window            */
  975. #ifdef    CHANGE_FONT
  976.         CloseLibrary(DiskfontBase);
  977. #endif
  978.     case 21:        /* couldn't open diskfonts        */
  979.         CloseLibrary(IntuitionBase);
  980.     case 2:            /* couldn't open Intuition        */
  981.         CloseLibrary(GfxBase);
  982.     case 1:            /* couldn't open graphics -- do nothing    */
  983.         break;
  984.     }
  985.         return(0);
  986. }
  987.  
  988.