static char rcsid[] = "$Id: stio.c,v 1.9 1992/11/29 01:14:50 mike Exp $"; /* $Log: stio.c,v $ * Revision 1.9 1992/11/29 01:14:50 mike * - Set the default text height (10 pt) using `vst_point'. * * Revision 1.8 1992/11/10 02:21:06 mike * - Some clean ups to prevent warnings from gcc. * * Revision 1.7 1992/11/08 23:28:02 mike * - Show the cursor during `wait_for_key'. * * Revision 1.6 1992/10/28 15:12:14 mike * - Replaced `toggle_cursor()' by `Cursor_on()' and `Cursor_off()'. * - Fixed bug in the keyboard driver. * * Revision 1.5 1992/10/28 00:27:44 mike * - Added support for the buffers window. * * Revision 1.4 1992/10/12 22:26:04 mike * - Discarded virtual workstation `Vw_clear'. It's job is done by * `Vw_print' now. * * Revision 1.3 1992/10/02 22:31:40 mike * - Some changes for the Atari ST/TT version. * * Revision 1.2 1992/09/14 18:03:42 mike * - First set of changes for the Atari ST/TT version. * * Revision 1.1 1992/09/05 01:13:32 mike * Initial revision * */ /* * STIO.C * These functions negotiate with various flavors atariST TOS/MiNT * system for characters and write characters in a barely buffered fashion * to the display. * Signals are also handled for MiNT only. * * Most of this code cribbed from unixio.c and pcio.c * ++jrb bammi@cadence.com * * GEM stuff by Michael Brandt, mike@pc-labor.uni-bremen.de * * Public Domain */ #include #include #include "me2.h" #include "term.h" #include "config.h" /* * Codes for special keys for use with Kbshift() */ #define KBD_SHIFT 0x0003 #define KBD_CTRL 0x0004 #define KBD_ALT 0X0008 #define BOGUS (PFIX2 | '@') /* Code for bogus key combination */ /***************************************************************************/ /***** The top section of this file is for TOS, the bottom for MiNT *******/ /***************************************************************************/ #ifndef __MINT__ /***************************************************************************/ /***** TOS section *******/ /***************************************************************************/ #include #include #include #include #include "gem.h" static char *Keytable; /* Keytable to convert ALT keys */ /* ******************************************************************** */ /* ******** Opening and closing the terminal ************************** */ /* ******************************************************************** */ /* * Initialize the menu buffer. */ static void init_menu_buffer() { register long i; register long *buffer; register long *ptr; buffer = Menu_buffer = (long *) malloc(Menu_buffer_size << 2); i = Menu_buffer_size; ptr = (long *) Physbase(); while (i--) *buffer++ = *ptr++; } /* * This function is called to set up the terminal device streams. */ void ttopen() { extern void top_text_window(); extern int t_ncol,t_nrow; static char title[32]; static int work_in[11] = {1,1,1,1,1,1,1,1,1,1,2}; static int work_out[57]; int x,y,w,h; if (Text_window < 0) { menu_bar(Menu,1); Vw_print = Phys_handle; Vw_cursor = Phys_handle; v_opnvwk(work_in,&Vw_print,work_out); v_opnvwk(work_in,&Vw_cursor,work_out); v_opnvwk(work_in,&Bw.vw_text,work_out); if (!Vw_print || !Vw_cursor || !Bw.vw_text) { form_alert(1, "[3][PANIC: Cannot open|virtual screen workstation!][Abort]"); exit(1); } graf_mouse(ARROW,NULL); graf_mouse(M_OFF,NULL); vsf_interior(Vw_print,0); /* Empty */ vsf_perimeter(Vw_print,0); /* No frame */ vsf_color(Vw_print,0); /* Bg color */ vst_color(Vw_print,1); /* Text in "black" */ vst_alignment(Vw_print,0,3,&x,&x); vst_point(Vw_print,Font_size,&x,&x,&Wchar,&Hchar); vswr_mode(Vw_cursor,3); /* XOR writing mode */ if (!t_ncol) { Keytable = ((char **) Keytbl(-1L,-1L,-1L))[2]; Wkind = NAME | MOVER | FULLER; wind_get(0,WF_WORKXYWH,&Deskx,&Desky,&Deskw,&Deskh); wind_calc(WC_WORK,Wkind,Deskx,Desky,Deskw,Deskh,&Fullx,&Fully, &Fullw,&Fullh); if (load_setup()) { t_ncol = Workw / Wchar; t_nrow = Workh / Hchar - 1; Workw = t_ncol * Wchar; Workh = (t_nrow + 1) * Hchar; } else { t_ncol = Fullw / Wchar; t_nrow = Fullh / Hchar - 1; if (t_ncol > 80) t_ncol = 80; Workw = t_ncol * Wchar; Workh = (t_nrow + 1) * Hchar; Workx = Fullx + ((Fullw - Workw) >> 1); Worky = Fully; } Cursor_x = Workx; Cursor_y = Worky + Hchar - 1; Menu_buffer_size = (work_out[0] + 1) >> 5; vq_extnd(Vw_print,1,work_out); Menu_buffer_size *= work_out[4] * Desky; init_menu_buffer(); } if ((Text_window = wind_create(Wkind,Deskx,Desky,Deskw,Deskh)) < 0) { form_alert(1,"[3][PANIC: Cannot get a window!][Abort]"); exit(1); } sprintf(title," Mutt Editor 2 (%dx%d) ", t_ncol, t_nrow + 1); wind_set(Text_window,WF_NAME,title); wind_calc(WC_BORDER,Wkind,Workx,Worky,Workw,Workh,&x,&y,&w,&h); wind_open(Text_window,x,y,w,h); } if (Buffers_window > 0) { Buffers_window = 0; open_buffers_window(); top_text_window(); } } /* * This function is called to close the terminal device streams. */ void ttclose() { if (Text_window >= 0) { menu_bar(Menu,0); wind_close(Text_window); wind_delete(Text_window); Text_window = -1; v_clsvwk(Vw_print); v_clsvwk(Vw_cursor); v_clsvwk(Bw.vw_text); graf_mouse(M_ON,NULL); } if (Buffers_window > 0) { close_buffers_window(); Buffers_window = 1; } } /* * Toggle the state of the cursor and the mouse pointer. */ short Cursor_visible = 0; static int Cursor_array[4]; void Cursor_on() { if (!Cursor_visible) { Cursor_array[0] = Cursor_x - 1; Cursor_array[1] = Cursor_y + 1; Cursor_array[2] = Cursor_x + Wchar; Cursor_array[3] = Cursor_y - Hchar; v_bar(Vw_cursor,Cursor_array); graf_mouse(M_ON,NULL); Cursor_visible = 1; } } void Cursor_off() { if (Cursor_visible) { graf_mouse(M_OFF,NULL); v_bar(Vw_cursor,Cursor_array); Cursor_visible = 0; } } /* ******************************************************************** */ /* ************** Terminal I/O *************************************** */ /* ******************************************************************** */ /* * Write a character to the display. * Use the rawest console output routine that handles backspace, \r and \n. */ void t_putchar(c) int c; { static char text[2] = { '\0', '\0' }; switch (c) { case '\010' : if (Cursor_x - Wchar >= Workx) Cursor_x -= Wchar; break; case '\n' : if (Cursor_y + Hchar < Worky + Workh) Cursor_y += Hchar; break; case '\r' : Cursor_x = Workx; break; default : if (Cursor_x + Wchar < Workx + Workw) { text[0] = c; v_gtext(Vw_print,Cursor_x,Cursor_y,text); Cursor_x += Wchar; } } } void t_putstr(p1,p2) register char *p1,*p2; { char c; c = *p2; *p2 = '\0'; v_gtext(Vw_print,Cursor_x,Cursor_y,p1); Cursor_x += (p2 - p1) * Wchar; *p2 = c; } /* * Flush terminal buffer. Does real work when the terminal output is * buffered up. */ void t_flush() { } /* * Read a character from the terminal, performing no editing and doing no * echo at all. * Map terminal dependent things (like softkeys and other things ME doesn't * or can't know about) to ME keys. Do *NOT* map control keys. * In general, try just to read a character and return it. */ KeyCode t_getcharX(key) int key; { extern void t_beep(); register unsigned short sc; /* Scancode */ register unsigned short ascii; /* ASCII code */ register KeyCode keycode; /* Keycode */ unsigned short sk; /* Value from Kbshift() */ if (!key) key = evnt_keybd(); sk = Kbshift(-1); sc = (key >> 8) & 0xff; ascii = key & 0xff; if (ascii) /* Everything that returns a character */ { switch ((sc << 8) | ascii) { case 0x4b34 : /* Shift cursor left */ return SOFKEY | 'Q'; case 0x4d36 : /* Shift cursor right */ return SOFKEY | 'R'; case 0x5032 : /* Shift cursor down */ return SOFKEY | 'J'; case 0x4838 : /* Shift cursor up */ return SOFKEY | 'I'; case 0x5230 : /* Shift insert */ return SOFKEY | 'M'; case 0x4737 : /* Clr */ return SOFKEY | 'B'; case 0x537f : /* Del */ if (sk & KBD_SHIFT) return SOFKEY | 'L'; else return SOFKEY | 'H'; } return ascii; } else /* All non character keys */ { switch (sc) { case 0x4b : /* Cursor left */ return SOFKEY | 'F'; case 0x73 : /* Ctrl cursor left */ return SOFKEY | 'S'; case 0x4d : /* Cursor right */ return SOFKEY | 'E'; case 0x74 : /* Ctrl cursor right */ return SOFKEY | 'T'; case 0x50 : if (sk & KBD_CTRL) /* Ctrl cursor down */ return SOFKEY | 'O'; else /* Cursor down */ return SOFKEY | 'D'; case 0x48 : if (sk & KBD_CTRL) /* Ctrl cursor up */ return SOFKEY | 'P'; else /* Cursor up */ return SOFKEY | 'C'; case 0x52 : /* Insert */ return SOFKEY | 'G'; case 0x47 : /* Home */ return SOFKEY | 'A'; #if 0 case 0x77 : /* Ctrl home */ { keycode = BOGUS; goto done; } #endif case 0x62 : if (sk & KBD_CTRL) /* Ctrl Help */ return SOFKEY | 'U'; else return SOFKEY | 'K'; /* Help */ case 0x61 : /* Undo */ return SOFKEY | 'N'; } if (sk & KBD_ALT) keycode = PFIX2; else keycode = 0; if (sk & KBD_CTRL) keycode |= CTRL; if (sc >= 0x3b && sc <= 0x43) /* * F1 to F9 */ return keycode | SOFKEY | (sc - 0x3b + '1'); else if (sc >= 0x54 && sc <= 0x5c) /* * Shift F1 to Shift F9 */ return keycode | SOFKEY | SHIFT | (sc - 0x54 + '1'); else if (sc == 0x44) /* * F10 */ return keycode | SOFKEY | '0'; else if (sc == 0x5d) /* * Shift F10 */ return keycode | SOFKEY | SHIFT | '0'; else if (sc >= 120 && sc <= 128) /* * ALT-1 to ALT-9 */ return keycode | PFIX2 | (sc - 120 + '1'); else if (sc == 129) /* * ALT-0 */ return keycode | PFIX2 | '0'; } if (sk & KBD_ALT) return PFIX2 | Keytable[sc]; t_beep(); return BOGUS; /* Bogus key combination */ } KeyCode t_getchar() { KeyCode key; Cursor_on(); key = t_getcharX(0); Cursor_off(); return key; } /* Ask the window/screen size how big it is. * Input: * row: Pointer to a int * col: Pointer to a int * Munges: * row: The number of rows on the window or screen is put here. * col: The number of columns on the window or screen is put here. * Returns: * TRUE: If I know how to do this and row,col updated. * FALSE: Not supported or got bogus data. row, col not changed. */ int get_size_from_window(row, col) int *row, *col; { #if 0 extern int atoi(); extern char *getenv(); register char *p; if ((p = getenv("ROWS")) == NULL) return FALSE; *row = atoi(p); if ((p = getenv("COLUMNS")) == NULL) return FALSE; *col = atoi(p); return TRUE; #else return FALSE; #endif } /* ******************************************************************** */ /* *********** Key waiting? ******************************************* */ /* ******************************************************************** */ /* * Wait for a key to be pressed for no more than sec seconds. * Use 0 seconds to check to see if a key is in the input que. */ int wait_for_key(sec) int sec; { register long waitUntil; if (sec) { waitUntil = get_sysvar(_hz_200) + (((long) sec) << 8); if (!Cursor_visible) { Cursor_array[0] = Cursor_x - 1; Cursor_array[1] = Cursor_y + 1; Cursor_array[2] = Cursor_x + Wchar; Cursor_array[3] = Cursor_y - Hchar; v_bar(Vw_cursor,Cursor_array); } do { if (Bconstat(2)) { if (!Cursor_visible) v_bar(Vw_cursor,Cursor_array); return TRUE; } } while (get_sysvar(_hz_200) < waitUntil); if (!Cursor_visible) v_bar(Vw_cursor,Cursor_array); return FALSE; } return Bconstat(2); } /* * keywaiting: * Check to see if any characters are already in the keyboard buffer. */ int keywaiting() { return Bconstat(2); } #else /* __MINT__ */ /***************************************************************************/ /***** MiNT section *******/ /***************************************************************************/ #include /* for stty/gtty functions */ #include /* to get at the typeahead */ struct sgttyb ostate; /* saved tty state */ struct sgttyb nstate; /* values for editor mode */ struct tchars otchars; /* Saved terminal special character set */ struct tchars ntchars = /* A lot of nothing */ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* ******************************************************************** */ /* ******** Opening and closing the terminal ************************** */ /* ******************************************************************** */ /* * This function is called once to set up the terminal device streams. */ ttopen() { gtty(0,&ostate); /* save old state */ gtty(0,&nstate); /* get base of new state */ nstate.sg_flags |= RAW; /* nstate.sg_flags &= ~(ECHO | CRMOD);*/ /* no echo for now... */ nstate.sg_flags &= ~(ECHO | CRMOD | TANDEM); /* no echo for now... */ stty(0, &nstate); /* set mode */ ioctl(0, TIOCGETC, &otchars); /* Save old characters */ ioctl(0, TIOCSETC, &ntchars); /* Place new character into K */ set_signals(); } /* * This function gets called just before we exit ME. */ ttclose() { stty(0,&ostate); ioctl(0,TIOCSETC,&otchars); /* Place old character into K */ } /* ******************************************************************** */ /* ************** Terminal I/O *************************************** */ /* ******************************************************************** */ /* * Write a character to the display. * Use the rawest console output routine that handles backspace, \r and \n. */ t_putchar(c) unsigned char c; { fputc(c,stdout); } /* * Flush terminal buffer. Does real work when the terminal output is * buffered up. */ t_flush() { fflush(stdout); } /* * Read a character from the terminal, performing no editing and doing no * echo at all. * Map terminal dependent things (like softkeys and other things ME doesn't * or can't know about) to ME keys. Do *NOT* map control keys. * In general, try just to read a character and return it. * Note: * On Unix systems, system calls (like read()) can be interrupted. In * this case, read() will return -1 and errno will be set to EINTR. */ KeyCode t_getchar() { extern int errno; unsigned char c; int n; KeyCode keycode; while (TRUE) { n = read(0,&c,1); if (0 < n) return (KeyCode)c; /* the expected case */ /* Nothing read, error or (most likely) a signal. * Since it might be a signal that something needs to be done and we * aren't anything else right now, try to process any hooks. * Note: On some OSs, read() is automatically restarted so we will * never get this case. */ process_hooks(); } } /* Ask the window/screen size how big it is. * Input: * row: Pointer to a int * col: Pointer to a int * Munges: * row: The number of rows on the window or screen is put here. * col: The number of columns on the window or screen is put here. * Returns: * TRUE: If I know how to do this and row,col updated. * FALSE: Not supported or got bogus data. row, col not changed. * Notes: * According to the BSD tty(4) man page: If, for some unknown (to me) * reason, the terminal has bogus data, the winsize structure is * zeroed. On Apollo, this happens in special cases. ws_xpixel and * ws_ypixel always seem to be zero (probably something to do with * my terminal windows). */ int get_size_from_window(row, col) int *row, *col; { #ifdef TIOCGWINSZ struct winsize term_stats; /* */ /* Get the terminal size */ if (-1 == ioctl(0, TIOCGWINSZ, &term_stats) || 0 == term_stats.ws_row) return FALSE; /* something bad happened */ *row = term_stats.ws_row; *col = term_stats.ws_col; return TRUE; #else return FALSE; #endif } /* ******************************************************************** */ /* *********** Key waiting? ******************************************* */ /* ******************************************************************** */ /* Note: need 1 or 2 routines to check to see if a key is in the input que. * One routine is needed if it is reliable and fast or you need a fast * routine (for HP escape sequence parsing) and one thats fast (for * interrupting a display update). * Sync these up with config.h. */ #include /* Wait for a key to be pressed for no more than sec seconds. * Use 0 seconds to check to see if a key is in the input que. */ wait_for_key(sec) { int x = 1; /* stdin */ struct timeval timeout; timeout.tv_sec = sec; timeout.tv_usec = 0; return select(1, &x, 0, 0, &timeout); } /* keywaiting: * Check to see if any characters are already in the keyboard buffer. * This is reliable but slows things down if called much. * This HAS to work. Sometimes used to parse (HP like) keyboard generated * escape sequences. * Note: FIONREAD is no good on HPUX. */ keywaiting() { long int x; return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x); } /* ******************************************************************** */ /* ******************* Signals **************************************** */ /* ******************************************************************** */ #include #ifdef SIGWINCH /* The screen has been resized. * WARNING: Should NOT actually resize the display in a signal handler * because ME could be in the middle of doing all kinds of things and * this could really mess things up (I don't know for sure but I don't * want to have to debug that case!) or the signal might arrive before * the display system has been properly initialized. * Result: * Tell the main loop to call us when it can. */ static void sig_resize(dummy) { void sig_do_the_resize(); call_me_sometime(RESIZE_HOOK,sig_do_the_resize); } static void sig_do_the_resize() { int row, col; if (get_size_from_window(&row, &col)) { display_resized(row,col); update(); /* force the screen to be redrawn */ } } #endif /* An external process has told ME that it has some info. */ static void sig_expro(foo) { extern void process_talks(); signal(SIGUSR1, SIG_IGN); call_me_sometime(PROCESS_HOOK,process_talks); signal(SIGUSR1, sig_expro); /* reset the signal */ } /* Somebody, somewhere, told me to bite the big one. Well, I can take a * hint. * If there are any modified buffers, too bad. I suppose I could have a * ME-quit-hook. */ static void sig_die(dummy) { mlwrite("ME2 terminated via signal.\r\n"); quit(TRUE,1); } /* Put ME into the background. This can be invoked via signal or called * from ME. This means I gotta be careful when I send myself a signal. */ void sig_pause(dummy) { close_display(TRUE); /* restore terminal for normal user interface */ kill(getpid(),SIGSTOP); /* hello background. Can't catch SIGSTOP. */ open_display(); /* set up terminal for editor */ /* ME might not be in the keywait loop when this is called (because of * an external signal) and so might not redraw the screen until a key * is pressed. */ update(); /* force the screen to be redrawn */ } /* Setup the signals I'm going to catch: * Signal Action * SIGTSTP Put ME into the background. * SIGTERM Clean up and exit. * SIGHUP Clean up and exit. * SIGINT Clean up and exit. * SIGUSR1 Unused. * SIGUSR2 Unused. * SIGWINCH Resize the screen. * Ignore these signals: * SIGCONT sig_pause() will take care of everything it would do. */ static void set_signals() { signal(SIGTSTP,sig_pause); signal(SIGCONT,SIG_IGN); signal(SIGTERM,sig_die); signal(SIGHUP, sig_die); signal(SIGINT, sig_die); #ifdef SIGWINCH signal(SIGWINCH, sig_resize); #endif signal(SIGUSR1, sig_expro); signal(SIGUSR2, SIG_IGN); } #endif /* MiNT */