home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / microcode / ntscreen.c < prev    next >
C/C++ Source or Header  |  2000-12-05  |  111KB  |  3,932 lines

  1. /* -*-C-*-
  2.  
  3. $Id: ntscreen.c,v 1.46 2000/12/05 21:23:45 cph Exp $
  4.  
  5. Copyright (c) 1993-2000 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. /* #include <stdio.h> */
  23. #include <stdlib.h>
  24. #include "nt.h"
  25. #include "ntscreen.h"
  26. #include "ntgui.h"
  27. #include <windowsx.h>
  28.  
  29. /* constant definitions */
  30.  
  31. #define GWL_SCREEN        0
  32. #define SCREENEXTRABYTES        (sizeof(LONG))
  33.  
  34. #define MAXCOLS 180
  35. #define MAXROWS 100
  36.  
  37. /* ascii definitions */
  38.  
  39. #define ASCII_BEL       (0x07)
  40. #define ASCII_BS        (0x08)
  41. #define ASCII_LF        (0x0A)
  42. #define ASCII_FF        (0x0C)
  43. #define ASCII_CR        (0x0D)
  44. #define ASCII_ESC       (0x1B)
  45. #define ASCII_DEL       (0x7F)
  46.  
  47. #define ASCII_CONTROLIFY(ascii) ((ascii) - '@')
  48. #define ASCII_METAFY(ascii)     ((ascii) | 0200)
  49.  
  50. /* data structures */
  51.  
  52. #ifndef MAX_FREE_EVENTS
  53. #define MAX_FREE_EVENTS 1024
  54. #endif
  55.  
  56. typedef struct tagSCREEN_EVENT_LINK
  57. {
  58.   SCREEN_EVENT event;
  59.   struct tagSCREEN_EVENT_LINK * next;
  60. } SCREEN_EVENT_LINK;
  61.  
  62. #define MAX_COMMANDS 30
  63.  
  64. #define MAX_BINDINGS 10
  65.  
  66. #define MAX_LINEINPUT 1024
  67.  
  68. #define COMPUTE_SCROLL_LINES(height)    ((((height) * 2) + 4) / 5)
  69.  
  70. typedef struct tagSCREENINFO
  71. {
  72.    SCREEN  registry_link;
  73.  
  74.    HWND    hWnd;
  75.    HICON   hIcon;
  76.  
  77.    char              * chars;
  78.    SCREEN_ATTRIBUTE  * attrs;
  79.    unsigned long mode_flags;    /* event types & modes */
  80.    SCREEN_ATTRIBUTE  write_attribute;
  81.  
  82.    BOOL    cursor_visible;
  83.    BOOL    has_focus;
  84.  
  85.    HFONT   hFont;
  86.    LOGFONT lfFont;
  87.    DWORD   rgbFGColour;
  88.    DWORD   rgbBGColour;
  89.    int     xSize, ySize;
  90.    int     xScroll, yScroll;
  91.    int     xOffset, yOffset; /* coords of top left corner of client area wrt */
  92.                              /* character area */
  93.    int     column, row;      /* caret position */
  94.    int     xChar, yChar;     /* size of characters in pixels */
  95.    int     width, height;    /* size of text ares in characters */
  96.  
  97.    int n_commands;
  98.    struct
  99.    {
  100.      WORD wID;
  101.      COMMAND_HANDLER thunk;
  102.    } commands[MAX_COMMANDS];
  103.  
  104.    int n_bindings;
  105.    struct
  106.    {
  107.      char   key;
  108.      WORD   command;
  109.    } bindings[MAX_BINDINGS];
  110.  
  111.    /* for line input */
  112.    int n_chars;
  113.    char * line_buffer;
  114.  
  115.    /* ANSI emulator overflow */
  116.    int n_pending;
  117.    LPSTR pending;
  118.  
  119.    HBRUSH bkgnd_brush;
  120.    int scroll_lines;
  121.  
  122. } SCREEN_STRUCT;
  123.  
  124. /* #define WIDTH(screen) (screen->width) */
  125. #define WIDTH(screen) MAXCOLS
  126. #define HEIGHT(screen) MAXROWS
  127. /* macros ( for easier readability ) */
  128.  
  129. #define GETSCREEN( x ) ((SCREEN) GetWindowLong( x, GWL_SCREEN ))
  130. #define SETSCREEN( x, y ) SetWindowLong( x, GWL_SCREEN, (LONG) y )
  131.  
  132. /* CRT mappings to NT API */
  133.  
  134. #define _fmemset   memset
  135. #define _fmemmove  memmove
  136.  
  137. static LRESULT CreateScreenInfo (HWND);
  138. static VOID DestroyScreenInfo (HWND);
  139. static BOOL ResetScreen (SCREEN);
  140. extern BOOL KillScreenFocus (HWND);
  141. static VOID PaintScreen (HWND);
  142. /* static VOID EraseScreen (HWND, HDC); */
  143. static BOOL SetScreenFocus (HWND);
  144. static BOOL ScrollScreenHorz (HWND, WORD, WORD);
  145. static BOOL ScrollScreenVert (HWND, WORD, WORD);
  146. static BOOL SizeScreen (HWND, WORD, WORD);
  147. static BOOL handle_window_pos_changing (HWND, LPWINDOWPOS);
  148. static void reset_modifiers (void);
  149. static void record_modifier_transition (WPARAM, LPARAM, BOOL);
  150. static int process_keydown (HWND, UINT, WPARAM, LPARAM);
  151. static void process_character (HWND, UINT, WPARAM, LPARAM);
  152. static VOID ProcessMouseButton (HWND, UINT, UINT, LONG, BOOL);
  153. static VOID ProcessCloseMessage (SCREEN);
  154. static void process_focus_message (HWND, int);
  155. static void process_show_message (HWND, int);
  156. static BOOL WriteScreenBlock (HWND, LPSTR, int);
  157. static int  ReadScreen (SCREEN, char*, int);
  158. static VOID MoveScreenCursor (SCREEN);
  159. extern UINT ScreenPeekOrRead
  160.   (SCREEN, int count, SCREEN_EVENT* buffer, BOOL remove);
  161. extern void flush_typeahead (SCREEN);
  162. static COMMAND_HANDLER ScreenSetCommand
  163.   (SCREEN, WORD cmd, COMMAND_HANDLER handler);
  164. static WORD ScreenSetBinding (SCREEN, char key, WORD command);
  165. static VOID GetMinMaxSizes(HWND,LPPOINT,LPPOINT);
  166. static BOOL AdjustedSize (SCREEN,int*,int*);
  167. extern VOID Screen_Clear (SCREEN,int);
  168. static BOOL SelectScreenFont (SCREEN, HWND);
  169. static BOOL SelectScreenBackColor (SCREEN, HWND);
  170.  
  171. static HFONT set_font_1 (char *, LOGFONT *);
  172. static BOOL parse_logfont (char *, LOGFONT *);
  173. static long points_to_logical_units (long);
  174. static BOOL search_for_font (LOGFONT *);
  175. static int CALLBACK search_for_font_proc
  176.   (ENUMLOGFONT *, NEWTEXTMETRIC *, int, LPARAM);
  177.  
  178. extern LRESULT ScreenCommand_ChooseFont (HWND, WORD);
  179. extern LRESULT ScreenCommand_ChooseBackColor (HWND, WORD);
  180.  
  181. static SCREEN_EVENT * allocate_event (SCREEN, SCREEN_EVENT_TYPE);
  182. static int read_event (SCREEN, SCREEN_EVENT_TYPE, int, SCREEN_EVENT *);
  183.  
  184. /* void *xmalloc (int size); */
  185. /* void xfree (void*); */
  186. #define xfree free
  187. #define xmalloc malloc
  188.  
  189. extern LRESULT FAR CALLBACK ScreenWndProc (HWND, UINT, WPARAM, LPARAM);
  190.  
  191. static VOID RegisterScreen (SCREEN);
  192. static VOID UnregisterScreen (SCREEN);
  193.  
  194. static const char * translate_message_code (UINT);
  195.  
  196. /* FILE GLOBAL VARIABLES */
  197.  
  198. static  HANDLE  ghInstance;
  199. static  HICON   ghDefaultIcon;
  200.  
  201. static  LOGFONT lfDefaultLogFont;
  202.  
  203. static unsigned int n_free_events;
  204. static SCREEN_EVENT_LINK * free_events;
  205. static SCREEN_EVENT_LINK * event_queue_head;
  206. static SCREEN_EVENT_LINK * event_queue_tail;
  207.  
  208. FILE * win32_trace_file;
  209. unsigned long win32_trace_level;
  210.  
  211. static long
  212. screen_x_extra (SCREEN screen)
  213. {
  214.   return ((GetSystemMetrics (SM_CXFRAME)) * 2);
  215. }
  216.  
  217. static long
  218. screen_y_extra (SCREEN screen)
  219. {
  220.   return (((GetSystemMetrics (SM_CYFRAME)) * 2)
  221.       + (GetSystemMetrics (SM_CYCAPTION))
  222.       + ((GetMenu (screen -> hWnd)) ? (GetSystemMetrics (SM_CYMENU)) : 0)
  223. #ifdef __WATCOMC__
  224.       /* Magic: when the combination of cyframe*2 and cycaption is
  225.          28, AdjustWindowRect indicates that it should be 27.  I
  226.          don't know why this only happens under Watcom.  */
  227.       - 1
  228. #endif
  229.       );
  230. }
  231.  
  232. static long
  233. pixel_to_char_width (SCREEN screen, long pixel_width)
  234. {
  235.   return
  236.     (((pixel_width - (screen_x_extra (screen))) + (screen -> xOffset))
  237.      / (screen -> xChar));
  238. }
  239.  
  240. static long
  241. pixel_to_char_height (SCREEN screen, long pixel_height)
  242. {
  243.   return
  244.     (((pixel_height - (screen_y_extra (screen))) + (screen -> yOffset))
  245.      / (screen -> yChar));
  246. }
  247.  
  248. static long
  249. char_to_pixel_width (SCREEN screen, long char_width)
  250. {
  251.   return
  252.     (((char_width * (screen -> xChar)) - (screen -> xOffset))
  253.      + (screen_x_extra (screen)));
  254. }
  255.  
  256. static long
  257. char_to_pixel_height (SCREEN screen, long char_height)
  258. {
  259.   return
  260.     (((char_height * (screen -> yChar)) - (screen -> yOffset))
  261.      + (screen_y_extra (screen)));
  262. }
  263.  
  264. static void
  265. init_LOGFONT (LOGFONT *lf)
  266. {
  267.     lf->lfHeight =         0;
  268.     lf->lfWidth =          0;
  269.     lf->lfEscapement =     0;
  270.     lf->lfOrientation =    0;
  271.     lf->lfWeight =         FW_NORMAL;
  272.     lf->lfItalic =         0;
  273.     lf->lfUnderline =      0;
  274.     lf->lfStrikeOut =      0;
  275.     lf->lfCharSet =        ANSI_CHARSET;
  276.     lf->lfOutPrecision =   OUT_RASTER_PRECIS;
  277.     lf->lfClipPrecision =  CLIP_DEFAULT_PRECIS;
  278.     lf->lfQuality =        PROOF_QUALITY;
  279.     lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
  280.     lstrcpy (lf->lfFaceName, "");
  281. }
  282.  
  283. static BOOL
  284. init_color (char *color_symbol, HWND hWnd, DWORD *color)
  285. {
  286.   HDC hdc;
  287.   char * envvar = getenv (color_symbol);
  288.   if (envvar == NULL)
  289.     return  FALSE;
  290.   /* Use GetNearestColor to ensure consistency with the background
  291.      text color. */
  292.   hdc = GetDC (hWnd);
  293.   *color = GetNearestColor (hdc, strtoul (envvar, NULL, 0));
  294.   ReleaseDC (hWnd, hdc);
  295.   return  TRUE;
  296. }
  297.  
  298. static BOOL
  299. init_geometry (char *geom_symbol, int *params)
  300. {
  301.   int ctr;
  302.   char * token;
  303.   char * envvar = getenv (geom_symbol);
  304.   char tempvar[100];
  305.  
  306.   if (envvar == NULL)
  307.     return  FALSE;
  308.  
  309.   envvar = lstrcpy (tempvar, envvar);
  310.  
  311.   for (ctr = 0, token = (strtok (envvar, ",;*+ \t\n"));
  312.        ((ctr < 4) && (token != ((char *) NULL)));
  313.        ctr++, token = (strtok (((char *) NULL), ",;*+ \t\n")))
  314.     params[ctr] = strtoul (token, NULL, 0);
  315.   return  FALSE;
  316. }
  317.  
  318. #ifdef WINDOWSLOSES
  319.  
  320. static BOOL
  321.   MIT_trap_alt_tab = ((BOOL) 1),
  322.   MIT_trap_alt_escape = ((BOOL) 1);
  323.  
  324. static VOID
  325. init_flag (char *flag_symbol, BOOL *flag)
  326. {
  327.   extern int strcmp_ci (char *, char *);
  328.   char *envvar = getenv (flag_symbol);
  329.   if (envvar != NULL)
  330.   {
  331.     if ((strcmp_ci (envvar, "true")) || (strcmp_ci (envvar, "yes")))
  332.       *flag = (BOOL) 1;
  333.     else if ((strcmp_ci (envvar, "false")) || (strcmp_ci (envvar, "no")))
  334.       *flag = (BOOL) 0;
  335.   }
  336. }
  337.  
  338. VOID
  339. init_MIT_Keyboard (VOID)
  340. {
  341.   init_flag ("MITSCHEME_TRAP_ALT_TAB", (& MIT_trap_alt_tab));
  342.   init_flag ("MITSCHEME_TRAP_ALT_ESCAPE", (& MIT_trap_alt_escape));
  343. }
  344. #endif /* WINDOWSLOSES */
  345.  
  346. /* BOOL Screen_InitApplication (HANDLE hInstance)
  347.  
  348.    Description:
  349.      First time initialization stuff for screen class.
  350.      This registers information such as window classes.
  351.  
  352.    Parameters:
  353.      HANDLE hInstance
  354.         Handle to this instance of the application.
  355. */
  356.  
  357. BOOL
  358. Screen_InitApplication (HANDLE hInstance)
  359. {
  360.    WNDCLASSEX wndclass;
  361.    char * font_name = getenv ("MITSCHEME_FONT");
  362.  
  363.    init_LOGFONT (&lfDefaultLogFont);
  364.    if (font_name)
  365.      ScreenSetDefaultFont (font_name);
  366.  
  367.    win32_trace_file = 0;
  368.    win32_trace_level = 0;
  369.  
  370. #ifdef WINDOWSLOSES
  371.    init_MIT_Keyboard ();
  372. #endif /* WINDOWSLOSES */
  373.  
  374.    wndclass.cbSize =        (sizeof (wndclass));
  375.    wndclass.style =         0;
  376.    wndclass.lpfnWndProc =   ScreenWndProc;
  377.    wndclass.cbClsExtra =    0;
  378.    wndclass.cbWndExtra =    SCREENEXTRABYTES;
  379.    wndclass.hInstance =     hInstance;
  380.    wndclass.hIcon =         (LoadIcon (hInstance, "SHIELD3_ICON"));
  381.    wndclass.hCursor =       (LoadCursor (NULL, IDC_ARROW));
  382.    wndclass.hbrBackground = 0;
  383.    wndclass.lpszMenuName =  0;
  384.    wndclass.lpszClassName = "MIT-SCREEN";
  385.    wndclass.hIconSm =       (wndclass . hIcon);
  386.  
  387.    n_free_events = 0;
  388.    free_events = 0;
  389.    event_queue_head = 0;
  390.    event_queue_tail = 0;
  391.  
  392.    return (RegisterClassEx (&wndclass));
  393. }
  394.  
  395. /* BOOL Screen_InitInstance (HANDLE hInstance, int nCmdShow )
  396.  
  397.    Description:
  398.       Initializes instance specific information for the screen class.
  399.       returns TRUE on success.
  400.  
  401.    Parameters:
  402.       HANDLE hInstance
  403.          Handle to instance
  404.  
  405.       int nCmdShow
  406.          How do we show the window?
  407. */
  408.  
  409. BOOL
  410. Screen_InitInstance (HANDLE hInstance, int nCmdShow )
  411. {
  412.   ghInstance = hInstance;
  413.   ghDefaultIcon = LoadIcon (hInstance, "SHIELD2_ICON");
  414.   return  TRUE;
  415. }
  416.  
  417. /* SCREEN  Screen_Create (HANDLE hParent, LPCSTR title, int nCmdShow)
  418.  
  419.    Description:
  420.       Create a screen window with a given parent.
  421.  
  422.    Parameters:
  423.       hParent
  424.          Handle to parent window
  425. */
  426.  
  427. static int def_params[4] =
  428. {
  429.   CW_USEDEFAULT,                /* Left */
  430.   CW_USEDEFAULT,                /* Top */
  431.   CW_USEDEFAULT,                /* Width */
  432.   CW_USEDEFAULT                 /* Height */
  433. };
  434.  
  435. HANDLE
  436. Screen_Create (HANDLE hParent, LPCSTR title, int nCmdShow)
  437. {
  438.   HWND hwnd;
  439.   int ctr, params[4] = {-1, -1, -1, -1};
  440.  
  441.   if (hParent == ((HANDLE) NULL))
  442.     init_geometry ("MITSCHEME_GEOMETRY", ¶ms[0]);
  443.  
  444.   for (ctr = 0; ctr < 4; ctr++)
  445.     if (params[ctr] == -1)
  446.       params[ctr] = def_params[ctr];
  447.  
  448.   hwnd = CreateWindow ("MIT-SCREEN", title,
  449.                WS_OVERLAPPEDWINDOW,
  450.                params[0], params[1],
  451.                params[2], params[3],
  452.                hParent, NULL, ghInstance,
  453.                ((LPVOID) nCmdShow));
  454.   return  hwnd;
  455. }
  456.  
  457. VOID
  458. Screen_Destroy (BOOL root, HANDLE hwnd)
  459. {
  460.   DestroyWindow (hwnd);
  461. }
  462.  
  463. /* Registry of screen handles */
  464.  
  465. static SCREEN registered_screens = 0;
  466.  
  467. static VOID
  468. RegisterScreen (SCREEN screen)
  469. {
  470.   screen->registry_link = registered_screens;
  471.   registered_screens = screen;
  472. }
  473.  
  474. static SCREEN*
  475. head_to_registered_screen (HWND hWnd)
  476. {
  477.   SCREEN *link = ®istered_screens;
  478.   while (*link)
  479.     if ((*link)->hWnd == hWnd)
  480.       return  link;
  481.     else
  482.       link = &((*link)->registry_link);
  483.   return  0;
  484. }
  485.  
  486. static VOID
  487. UnregisterScreen (SCREEN screen)
  488. {
  489.   SCREEN *link = head_to_registered_screen (screen->hWnd);
  490.   /* if (link) */
  491.   *link = screen->registry_link;
  492. }
  493.  
  494. BOOL
  495. Screen_IsScreenHandle (HANDLE handle)
  496. {
  497.   return  head_to_registered_screen (handle) != 0;
  498. }
  499.  
  500. /* LRESULT FAR CALLBACK ScreenWndProc (HWND hWnd, UINT uMsg,
  501.                                        WPARAM wParam, LPARAM lParam )
  502.  
  503.    This is the TTY Window Proc.  This handles ALL messages to the tty
  504.    window.
  505. */
  506.  
  507. LRESULT FAR CALLBACK
  508. ScreenWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  509. {
  510.    SCREEN  screen = GETSCREEN (hWnd);
  511.  
  512.    /* Ignore common but uninteresting messages.  */
  513.    if (win32_trace_level
  514.        > (((uMsg == WM_SCHEME_INTERRUPT)
  515.        || (uMsg == WM_PAINT)
  516.        || (uMsg == WM_TIMER)
  517.        || (uMsg == WM_NCHITTEST)
  518.        || (uMsg == WM_SETCURSOR)
  519.        || (uMsg == WM_MOUSEMOVE))
  520.       ? 2
  521.       : 0))
  522.      {
  523.        const char * name = (translate_message_code (uMsg));
  524.        fprintf (win32_trace_file, "ScreenWndProc: ");
  525.        fprintf (win32_trace_file, "hWnd=0x%x, ", hWnd);
  526.        if (name)
  527.      fprintf (win32_trace_file, "uMsg=%s, ", name);
  528.        else
  529.      fprintf (win32_trace_file, "uMsg=0x%x, ", uMsg);
  530.        fprintf (win32_trace_file, "wParam=0x%x, lParam=0x%x\n",
  531.         wParam, lParam);
  532.        fflush (win32_trace_file);
  533.      }
  534.    switch (uMsg)
  535.      {
  536.      case WM_CREATE:
  537.        {
  538.      LRESULT result = CreateScreenInfo (hWnd);
  539.      ShowWindow (hWnd,
  540.              ((int) ((LPCREATESTRUCT) lParam) -> lpCreateParams));
  541.      UpdateWindow (hWnd);
  542.      return  result;
  543.        }
  544.  
  545.      case WM_SCHEME_INTERRUPT:
  546.        return (0);
  547.  
  548.      case SCREEN_SETPOSITION:
  549.        return  (LRESULT)Screen_SetPosition
  550.      (screen, HIWORD(lParam), LOWORD(lParam));
  551.  
  552.      case SCREEN_GETPOSITION:
  553.        return  MAKELRESULT(screen->column, screen->row);
  554.  
  555.      case SCREEN_SETATTRIBUTE:
  556.        screen->write_attribute = (SCREEN_ATTRIBUTE) wParam;
  557.        return  0;
  558.  
  559.      case SCREEN_GETATTRIBUTE:
  560.        return  (LRESULT) screen->write_attribute;
  561.  
  562.      case SCREEN_SETMODES:
  563.        (screen -> mode_flags) = ((unsigned long) wParam);
  564.        return (0);
  565.  
  566.      case SCREEN_GETMODES:
  567.        return  (LRESULT) screen->mode_flags;
  568.  
  569.      case SCREEN_SETCOMMAND:
  570.        return  (LRESULT)
  571.      ScreenSetCommand(screen, LOWORD(wParam), (COMMAND_HANDLER)lParam);
  572.  
  573.      case SCREEN_GETCOMMAND:
  574.        return  (LRESULT)
  575.      ScreenSetCommand(screen, LOWORD(wParam), (COMMAND_HANDLER)-1);
  576.  
  577.      case SCREEN_SETBINDING:
  578.        return  (LRESULT)
  579.      ScreenSetBinding(screen, LOBYTE(wParam), (WORD)lParam);
  580.  
  581.      case SCREEN_GETBINDING:
  582.        return  (LRESULT)
  583.      ScreenSetBinding(screen, LOBYTE(wParam), (WORD)-1);
  584.  
  585.      case SCREEN_PEEKEVENT:
  586.        return  (LRESULT)
  587.      ScreenPeekOrRead(screen, (int)wParam, (SCREEN_EVENT*)lParam, FALSE);
  588.  
  589.      case SCREEN_READEVENT:
  590.        return  (LRESULT)
  591.      ScreenPeekOrRead(screen, (int)wParam, (SCREEN_EVENT*)lParam, TRUE);
  592.  
  593.      case SCREEN_WRITE:
  594.        return  (LRESULT)WriteScreenBlock (hWnd, (LPSTR)lParam, (int)wParam);
  595.  
  596.      case SCREEN_READ:
  597.        return  (LRESULT)ReadScreen (screen, (LPSTR)lParam, (int)wParam);
  598.  
  599.      case SCREEN_SETMENU:
  600.        Screen_SetMenu (hWnd, (HMENU)lParam);
  601.        return  0L;
  602.  
  603.      case SCREEN_CLEAR:
  604.        Screen_Clear (screen, (int)wParam);
  605.        return  0L;
  606.  
  607.      case WM_MOUSEACTIVATE:
  608.        if ((LOWORD (lParam)) == HTCLIENT)
  609.      return (MA_ACTIVATEANDEAT);
  610.        break;
  611.  
  612.      case WM_LBUTTONDOWN:
  613.      case WM_MBUTTONDOWN:
  614.      case WM_RBUTTONDOWN:
  615.        if (IsIconic (hWnd)) goto use_default;
  616.        ProcessMouseButton (hWnd, uMsg, wParam, lParam, FALSE);
  617.        break;
  618.  
  619.      case WM_LBUTTONUP:
  620.      case WM_MBUTTONUP:
  621.      case WM_RBUTTONUP:
  622.        if (IsIconic (hWnd)) goto use_default;
  623.        ProcessMouseButton (hWnd, uMsg, wParam, lParam, TRUE);
  624.        break;
  625.  
  626.      case WM_COMMAND:
  627.      case WM_SYSCOMMAND:
  628.        {
  629.      WORD  wID = LOWORD (wParam);
  630.      int  i;
  631.      for (i=0;  i<screen->n_commands; i++)
  632.        if (screen->commands[i].wID == wID)
  633.          {
  634.            LRESULT intrpt = (screen->commands[i].thunk(hWnd, wID));
  635.  
  636.            if (intrpt)
  637.          flush_typeahead (screen);
  638.            return  intrpt;
  639.          }
  640.      return  DefWindowProc (hWnd, uMsg, wParam, lParam);
  641.        }
  642.        break;
  643.  
  644.      case WM_GETMINMAXINFO:
  645.        {
  646.      LPMINMAXINFO info = ((LPMINMAXINFO) lParam);
  647.      GetMinMaxSizes (hWnd, &info->ptMinTrackSize, &info->ptMaxTrackSize);
  648.        }
  649.        break;
  650.  
  651.      case WM_PAINT:
  652.        PaintScreen (hWnd);
  653.        break;
  654.  
  655.      case WM_ERASEBKGND:
  656.        /* We now do this in PaintScreen as it reduces flicker after
  657.       resizing.  */
  658.        break;
  659.  
  660.      case WM_QUERYDRAGICON:
  661.        return (LRESULT) (screen->hIcon ? screen->hIcon : ghDefaultIcon);
  662.  
  663.      case WM_SIZE:
  664.        if (wParam!=SIZE_MINIMIZED)
  665.      SizeScreen (hWnd, HIWORD(lParam), LOWORD(lParam));
  666.        break;
  667.  
  668.      HANDLE_MSG (hWnd, WM_WINDOWPOSCHANGING, handle_window_pos_changing);
  669.  
  670.      case WM_HSCROLL:
  671.        ScrollScreenHorz (hWnd, LOWORD(wParam), HIWORD(wParam));
  672.        break;
  673.  
  674.      case WM_VSCROLL:
  675.        ScrollScreenVert (hWnd, LOWORD(wParam), HIWORD(wParam));
  676.        break;
  677.  
  678.      case WM_SYSKEYDOWN:
  679.      case WM_KEYDOWN:
  680.        record_modifier_transition (wParam, lParam, 1);
  681.        if ((IsIconic (hWnd))
  682.        || (!process_keydown (hWnd, uMsg, wParam, lParam)))
  683.      goto use_default;
  684.        break;
  685.  
  686.      case WM_SYSKEYUP:
  687.      case WM_KEYUP:
  688.        record_modifier_transition (wParam, lParam, 0);
  689.        goto use_default;
  690.  
  691.      case WM_SYSCHAR:
  692.      case WM_CHAR:
  693.        if (IsIconic (hWnd)) goto use_default;
  694.        process_character (hWnd, uMsg, wParam, lParam);
  695.        break;
  696.  
  697.       case WM_NCACTIVATE:
  698.        /* Windows doesn't send us focus messages when putting up and
  699.       taking down a system popup dialog as for Ctrl-Alt-Del on
  700.       Windows 95. The only indication we get that something
  701.       happened is receiving this message afterwards.  So this is a
  702.       good time to reset our keyboard modifiers' state. */
  703.        reset_modifiers ();
  704.        goto use_default;
  705.  
  706.      case WM_INPUTLANGCHANGE:
  707.        /* Clear dead keys in the keyboard state; for simplicity only
  708.       preserve modifier key states.  */
  709.        {
  710.      BYTE keystate [256];
  711.      GetKeyboardState (keystate);
  712.      {
  713.        unsigned int i;
  714.        for (i = 0; (i < 256); i += 1)
  715.          switch (i)
  716.            {
  717.            case VK_SHIFT:
  718.            case VK_LSHIFT:
  719.            case VK_RSHIFT:
  720.            case VK_CAPITAL:
  721.            case VK_NUMLOCK:
  722.            case VK_SCROLL:
  723.            case VK_CONTROL:
  724.            case VK_LCONTROL:
  725.            case VK_RCONTROL:
  726.            case VK_MENU:
  727.            case VK_LMENU:
  728.            case VK_RMENU:
  729.            case VK_LWIN:
  730.            case VK_RWIN:
  731.          (keystate[i]) = 0;
  732.          break;
  733.            }
  734.      }
  735.      SetKeyboardState (keystate);
  736.        }
  737.       goto use_default;
  738.  
  739.      case WM_SETFOCUS:
  740.        SetScreenFocus (hWnd);
  741.        reset_modifiers ();
  742.        process_focus_message (hWnd, 1);
  743.        goto use_default;
  744.  
  745.      case WM_KILLFOCUS:
  746.        KillScreenFocus (hWnd);
  747.        process_focus_message (hWnd, 0);
  748.        goto use_default;
  749.  
  750.      case WM_SHOWWINDOW:
  751.        process_show_message (hWnd, ((int) wParam));
  752.        goto use_default;
  753.  
  754.      case WM_DESTROY:
  755.        DestroyScreenInfo (hWnd);
  756.        break;
  757.  
  758.      case WM_CATATONIC:
  759.        {
  760.      extern void catatonia_trigger (void);
  761.      catatonia_trigger ();
  762.        }
  763.        break;
  764.  
  765.      case WM_CLOSE:
  766.        {
  767.      extern HANDLE master_tty_window;
  768.  
  769.      if (!(screen->mode_flags & SCREEN_EVENT_TYPE_CLOSE))
  770.        {
  771.          if (IDOK !=
  772.          MessageBox (hWnd,
  773.                  hWnd==(HWND)master_tty_window
  774.                  ? ("Closing this window will terminate Scheme.\n"
  775.                 "Changes to Edwin buffers might be lost.\n"
  776.                 "\n"
  777.                 "Really Exit Scheme?")
  778.                  : "OK to close this window?",
  779.                  "MIT Scheme",
  780.                  (MB_ICONQUESTION | MB_OKCANCEL)))
  781.            break;
  782.        }
  783.      else
  784.        {
  785.          ProcessCloseMessage (screen);
  786.          break;
  787.        }
  788.  
  789.      if (hWnd == ((HWND) master_tty_window))
  790.        termination_normal (0);
  791.      goto use_default;
  792.        }
  793.  
  794. #ifdef USE_WM_TIMER
  795.      case WM_TIMER:
  796.        {
  797.      extern void TimerProc (HWND, UINT, UINT, DWORD);
  798.      TimerProc (hWnd, uMsg, wParam, lParam);
  799.        }
  800.        break;
  801. #endif /* USE_WM_TIMER */
  802.  
  803.      case WM_HOTKEY:
  804.        {
  805.      extern int signal_keyboard_character_interrupt (int);
  806.      signal_keyboard_character_interrupt (-2);
  807.        }
  808.  
  809.      use_default:
  810.      default:
  811.        return (DefWindowProc (hWnd, uMsg, wParam, lParam));
  812.      }
  813.    return (0L);
  814. }
  815.  
  816. static VOID
  817. ClearScreen_internal (SCREEN screen)
  818. {
  819.   screen->row                   = 0;
  820.   screen->column                = 0;
  821.   _fmemset (screen->chars, ' ', MAXROWS * MAXCOLS);
  822.   _fmemset (screen->attrs, screen->write_attribute,
  823.         MAXROWS * MAXCOLS * sizeof(SCREEN_ATTRIBUTE));
  824. }
  825.  
  826. /* LRESULT CreateScreenInfo (HWND hWnd)
  827.  
  828.    Description:
  829.       Creates the tty information structure and sets
  830.       menu option availability.  Returns -1 if unsuccessful.
  831.  
  832.    Parameters:
  833.       HWND  hWnd
  834. */
  835.  
  836. static LRESULT
  837. CreateScreenInfo (HWND hWnd)
  838. {
  839.    HMENU   hMenu;
  840.    SCREEN  screen;
  841.  
  842.    if (NULL == (screen =
  843.         (SCREEN) LocalAlloc (LPTR, sizeof(SCREEN_STRUCT) )))
  844.       return  (LRESULT) -1;
  845.  
  846.    screen->hWnd                 = hWnd;
  847.    screen->hIcon                =
  848.      LoadIcon ((HINSTANCE) GetWindowLong(hWnd,GWL_HINSTANCE), "SHIELD3_ICON");
  849.    screen->chars                = NULL;
  850.    screen->attrs                = NULL;
  851.    screen->write_attribute      = 0;
  852.    screen->cursor_visible       = TRUE;
  853.    screen->has_focus            = TRUE;
  854. #if 0
  855.    screen->mode_flags           = (SCREEN_EVENT_TYPE_MASK
  856. #endif
  857.    screen->mode_flags           = (SCREEN_EVENT_TYPE_KEY
  858.                    | SCREEN_MODE_AUTOWRAP
  859.                    | SCREEN_MODE_ECHO
  860. #if 0
  861.                    | SCREEN_MODE_CR_NEWLINES
  862. #endif
  863.                    | SCREEN_MODE_LINE_INPUT
  864.                    | SCREEN_MODE_PROCESS_OUTPUT
  865.                    | SCREEN_MODE_EAGER_UPDATE
  866.                    | SCREEN_MODE_NEWLINE_CRS);
  867.    screen->xSize                = 0;
  868.    screen->ySize                = 0;
  869.    screen->xScroll              = 0;
  870.    screen->yScroll              = 0;
  871.    screen->xOffset              = 0;
  872.    screen->yOffset              = 0;
  873.    screen->hFont                = NULL;
  874.    if (! (init_color ("MITSCHEME_FOREGROUND", hWnd, &screen->rgbFGColour)))
  875.      screen->rgbFGColour        = GetSysColor (COLOR_WINDOWTEXT);
  876.    if (! (init_color ("MITSCHEME_BACKGROUND", hWnd, &screen->rgbBGColour)))
  877.      screen->rgbBGColour        = GetSysColor (COLOR_WINDOW);
  878.    screen->width                = 0;
  879.    screen->height               = 0;
  880.    screen->scroll_lines         = 1;
  881.  
  882.    screen->chars = xmalloc (MAXROWS * MAXCOLS);
  883.    screen->attrs = xmalloc (MAXROWS * MAXCOLS * sizeof(SCREEN_ATTRIBUTE));
  884.  
  885.    /* clear screen space */
  886.    ClearScreen_internal (screen);
  887.  
  888.    /* setup default font information */
  889.    screen->lfFont = lfDefaultLogFont;
  890.  
  891.    /* set handle before any further message processing. */
  892.    SETSCREEN (hWnd, screen);
  893.    RegisterScreen (screen);
  894.  
  895.    screen->n_commands = 0;
  896.    screen->n_bindings = 0;
  897.    /* reset the character information, etc. */
  898.  
  899.    screen->bkgnd_brush = NULL;
  900.    ResetScreen (screen);
  901.  
  902.    hMenu = GetSystemMenu (hWnd, FALSE);
  903.    AppendMenu (hMenu, MF_SEPARATOR, 0, 0);
  904. /* AppendMenu (hMenu, MF_STRING, IDM_SETTINGS, "&Settings..."); */
  905.    AppendMenu (hMenu, MF_STRING, SCREEN_COMMAND_CHOOSEFONT, "&Font...");
  906.    AppendMenu (hMenu, MF_STRING, SCREEN_COMMAND_CHOOSEBACKCOLOR,
  907.            "&Background...");
  908.  
  909.    SendMessage (hWnd, SCREEN_SETCOMMAND,
  910.         SCREEN_COMMAND_CHOOSEFONT, (LPARAM)ScreenCommand_ChooseFont);
  911. /* SendMessage (hWnd, SCREEN_SETBINDING, 6, SCREEN_COMMAND_CHOOSEFONT); */
  912.    SendMessage (hWnd, SCREEN_SETCOMMAND, SCREEN_COMMAND_CHOOSEBACKCOLOR,
  913.         (LPARAM)ScreenCommand_ChooseBackColor);
  914. /* SendMessage (hWnd, SCREEN_SETBINDING, 7, SCREEN_COMMAND_CHOOSEBACKCOLOR); */
  915.  
  916.    screen->n_chars = 0;
  917.    screen->line_buffer = xmalloc (MAX_LINEINPUT + 1);
  918.  
  919.    screen->n_pending = 0;
  920.    screen->pending = ((LPSTR) NULL);
  921.    return  (LRESULT) TRUE;
  922. }
  923.  
  924. /* VOID DestroyScreenInfo (HWND hWnd )
  925.  
  926.    Description:
  927.       Destroys block associated with TTY window handle.
  928.  
  929.    Parameters:
  930.       HWND hWnd
  931.          handle to TTY window
  932. */
  933.  
  934. static VOID
  935. DestroyScreenInfo (HWND hWnd)
  936. {
  937.    SCREEN screen = GETSCREEN (hWnd);
  938.  
  939.    if (NULL == screen)
  940.      return;
  941.  
  942.    /* KillScreenFocus (hWnd); */
  943.    UnregisterScreen (screen);
  944.    DeleteObject (screen->hFont);
  945.  
  946.    if (screen->chars)
  947.      xfree (screen->chars);
  948.    if (screen->attrs)
  949.      xfree (screen->attrs);
  950.  
  951.    LocalFree (screen);
  952. }
  953.  
  954. /* COMMAND_HANDLER  ScreenSetCommand (SCREEN, WORD cmd, COMMAND_HANDLER h) */
  955.  
  956. static COMMAND_HANDLER
  957. ScreenSetCommand (SCREEN screen, WORD cmd, COMMAND_HANDLER thunk)
  958. {
  959.     int i;
  960.     for (i = 0; i < screen->n_commands; i++)
  961.       if (screen->commands[i].wID == cmd)
  962.       {
  963.     COMMAND_HANDLER  result = screen->commands[i].thunk;
  964.     if (thunk == 0)
  965.     {
  966.       /* remove by overwriting with last in list */
  967.       screen->commands[i] = screen->commands[screen->n_commands-1];
  968.       screen->n_commands--;
  969.     }
  970.     else if (thunk == ((COMMAND_HANDLER) -1))
  971.     {
  972.       /* just leave it alone */
  973.     }
  974.     else
  975.       /* redefine */
  976.       screen->commands[i].thunk = thunk;
  977.     return  result;
  978.       }
  979.  
  980.     /* didnt find it */
  981.     if ((thunk == 0) || (thunk == ((COMMAND_HANDLER) -1)))
  982.       return  0;
  983.     /* add new command */
  984.     if (screen->n_commands == MAX_COMMANDS)
  985.       return ((COMMAND_HANDLER) - 1);
  986.  
  987.     screen->commands[screen->n_commands].wID   = cmd;
  988.     screen->commands[screen->n_commands].thunk = thunk;
  989.     screen->n_commands++;
  990.  
  991.     return  0;
  992. }
  993.  
  994. /* WORD  ScreenSetBinding (SCREEN, char key, WORD command) */
  995.  
  996. static WORD
  997. ScreenSetBinding (SCREEN screen, char key, WORD command)
  998. {
  999.     int i;
  1000.     for (i=0; i < screen->n_bindings; i++)
  1001.       if (screen->bindings[i].key == key)
  1002.       {
  1003.     WORD  result = screen->bindings[i].command;
  1004.     if (command == 0)
  1005.     {
  1006.       /* remove by blatting with last in list */
  1007.       screen->bindings[i] = screen->bindings[screen->n_bindings-1];
  1008.       screen->n_bindings--;
  1009.     }
  1010.     else if (command == ((WORD) -1))
  1011.     {
  1012.       /* let it be */
  1013.     }
  1014.     else
  1015.       /* redefine */
  1016.       screen->bindings[i].command = command;
  1017.     return  result;
  1018.       }
  1019.  
  1020.     /* no existing binding for key */
  1021.     if ((command == 0) || (command == ((WORD) -1)))
  1022.       return  0;
  1023.     /* add new binding */
  1024.     if (screen->n_bindings == MAX_BINDINGS)
  1025.       return ((WORD) - 1);
  1026.  
  1027.     screen->bindings[screen->n_bindings].key     = key;
  1028.     screen->bindings[screen->n_bindings].command = command;
  1029.     screen->n_bindings++;
  1030.  
  1031.     return  0;
  1032. }
  1033.  
  1034. /* Standard commands */
  1035.  
  1036. LRESULT
  1037. ScreenCommand_ChooseFont (HWND hWnd, WORD command)
  1038. {
  1039.   SCREEN  screen = GETSCREEN (hWnd);
  1040.   if (screen == 0)
  1041.     return  1L;
  1042.   SelectScreenFont (screen, hWnd);
  1043.   return  0L;
  1044. }
  1045.  
  1046. LRESULT
  1047. ScreenCommand_ChooseBackColor (HWND hWnd, WORD command)
  1048. {
  1049.   SCREEN  screen = GETSCREEN (hWnd);
  1050.   if (screen == 0)
  1051.     return  1L;
  1052.   SelectScreenBackColor (screen, hWnd);
  1053.   return  0L;
  1054. }
  1055.  
  1056. VOID
  1057. Screen_SetMenu (SCREEN screen, HMENU hMenu)
  1058. {
  1059.   HMENU hOld = GetMenu (screen->hWnd);
  1060.   SetMenu (screen->hWnd, hMenu);
  1061.   if (hOld)
  1062.     DestroyMenu (hOld);
  1063. }
  1064.  
  1065. /* BOOL AdjustedSize
  1066.     make sure that proposed width & height of screen are ok.
  1067.     return TRUE if adjusted, FALSE if OK.  */
  1068. static BOOL
  1069. AdjustedSize (SCREEN screen, int *width, int *height)
  1070. {
  1071.   POINT minsz, maxsz;
  1072.   GetMinMaxSizes (screen->hWnd, &minsz, &maxsz);
  1073.   if (*width<minsz.x || *width>maxsz.x || *height<minsz.y || *height>maxsz.y)
  1074.     {
  1075.       *width  = min (maxsz.x, max(minsz.x, *width));
  1076.       *height = min (maxsz.y, max(minsz.y, *height));
  1077.       return (TRUE);
  1078.     }
  1079.   return (FALSE);
  1080. }
  1081.  
  1082. /* BOOL ResetScreen (SCREEN  screen)
  1083.    Description:
  1084.       Resets the SCREEN character information and causes the
  1085.       screen to resize to update the scroll information.  */
  1086.  
  1087. static BOOL
  1088. ResetScreen (SCREEN screen)
  1089. {
  1090.    HWND        hWnd;
  1091.    HDC         hDC;
  1092.    TEXTMETRIC  tm;
  1093.    RECT        rcWindow;
  1094.  
  1095.    if (NULL == screen)
  1096.       return  FALSE;
  1097.  
  1098.    hWnd = screen->hWnd;
  1099.  
  1100.    if (screen->hFont)
  1101.      DeleteObject (screen->hFont);
  1102.  
  1103.    screen->hFont = CreateFontIndirect (&screen->lfFont);
  1104.  
  1105.    hDC = GetDC (hWnd);
  1106.    SelectObject (hDC, screen->hFont);
  1107.    GetTextMetrics (hDC, &tm);
  1108.    ReleaseDC (hWnd, hDC);
  1109.  
  1110.    screen->xChar = tm.tmAveCharWidth;
  1111.    screen->yChar = tm.tmHeight /* + tm.tmExternalLeading */;
  1112.  
  1113.    /* a slimy hack to make the caret the correct size: un- and re- focus */
  1114.    if (screen->cursor_visible) {
  1115.      KillScreenFocus (hWnd);
  1116.      SetScreenFocus (hWnd);
  1117.    }
  1118.  
  1119.    if (screen->bkgnd_brush != NULL)
  1120.      DeleteObject (screen->bkgnd_brush);
  1121.    screen->bkgnd_brush = CreateSolidBrush (screen->rgbBGColour);
  1122.  
  1123.    /* a slimy hack to force the scroll position, region to */
  1124.    /* be recalculated based on the new character sizes ???? */
  1125.  
  1126.    /* Veto screens that are too small or too large */
  1127.    {
  1128.      int width, height;
  1129.      GetWindowRect (hWnd, &rcWindow);
  1130.      width  = (rcWindow.right - rcWindow.left - (screen_x_extra (screen)));
  1131.      height = (rcWindow.bottom - rcWindow.top - (screen_y_extra (screen)));
  1132.      if (AdjustedSize (screen, &width, &height))
  1133.        MoveWindow (hWnd, rcWindow.left, rcWindow.top, width, height, TRUE);
  1134.      else
  1135.        SendMessage (hWnd, WM_SIZE, SIZENORMAL,
  1136.             ((LPARAM) (MAKELONG (width,height))));
  1137.    }
  1138.    return  TRUE;
  1139. }
  1140.  
  1141. static VOID
  1142. Do_PaintScreen (HWND hWnd, SCREEN screen, HDC hDC, PAINTSTRUCT * ps)
  1143. {
  1144.   RECT          rect;
  1145.  
  1146.   int         nRow, nCol, nEndRow, nEndCol, nCount;
  1147.   int         nHorzPos, nVertPos, bias;
  1148.   HFONT       hOldFont;
  1149.  
  1150.   hOldFont = SelectObject (hDC, screen->hFont);
  1151.   rect = ps->rcPaint;
  1152.  
  1153.   { /* paint the background on the area surrounding the character grid */
  1154.     /* left strip */
  1155.     if (rect.left < - screen->xOffset) {
  1156.       RECT r = rect;
  1157.       r.right = -screen->xOffset;
  1158.       FillRect (hDC, &r, screen->bkgnd_brush);
  1159.     }
  1160.     /* right strip */
  1161.     if (rect.right > (screen->width * screen->xChar + screen->xOffset)) {
  1162.       RECT r = rect;
  1163.       r.left = (screen->width * screen->xChar + screen->xOffset);
  1164.       FillRect (hDC, &r, screen->bkgnd_brush);
  1165.     }
  1166.     /* top strip */
  1167.     if (rect.top < - screen->yOffset) {
  1168.       RECT r = rect;
  1169.       r.bottom =  - screen->yOffset;
  1170.       FillRect (hDC, &r, screen->bkgnd_brush);
  1171.     }
  1172.     /* bottom strip */
  1173.     if (rect.bottom > (screen->height * screen->yChar + screen->yOffset)) {
  1174.       RECT r = rect;
  1175.       r.top = (screen->height * screen->yChar + screen->yOffset);
  1176.       FillRect (hDC, &r, screen->bkgnd_brush);
  1177.     }
  1178.   }
  1179.  
  1180.   nRow =
  1181.     min (screen->height - 1,
  1182.      max (0, (rect.top + screen->yOffset) / screen->yChar));
  1183.   nEndRow =
  1184.     min (screen->height - 1,
  1185.      max (0, (rect.bottom + screen->yOffset - 1) / screen->yChar));
  1186.   nCol =
  1187.     min (screen->width - 1,
  1188.      max (0, (rect.left + screen->xOffset) / screen->xChar));
  1189.   nEndCol =
  1190.     min (screen->width - 1,
  1191.      max (0, (rect.right + screen->xOffset - 1) / screen->xChar));
  1192.   nCount = ((nEndCol - nCol) + 1);
  1193.   SetBkMode (hDC, OPAQUE);
  1194.   SetTextColor (hDC, screen->rgbFGColour);
  1195.   SetBkColor (hDC, screen->rgbBGColour);
  1196.  
  1197.   for (bias = ((nRow * MAXCOLS) + nCol),
  1198.        nVertPos = ((nRow * screen->yChar) - screen->yOffset);
  1199.        nRow <= nEndRow;
  1200.        nRow++, bias += MAXCOLS, nVertPos += screen->yChar)
  1201.   {
  1202.     int pos = 0;
  1203.     while (pos < nCount)
  1204.     {
  1205.       /* find consistent run of attributes */
  1206.       SCREEN_ATTRIBUTE  *attribp = &screen->attrs[bias + pos];
  1207.       SCREEN_ATTRIBUTE  attrib   = *attribp;
  1208.       int  nposn = (pos + 1);
  1209.       int  run_length;
  1210.  
  1211.       while ((nposn < nCount) && (*++attribp == attrib))
  1212.     nposn++;
  1213.  
  1214.       run_length = (nposn - pos);
  1215.       nHorzPos = (((nCol + pos) * screen->xChar) - screen->xOffset);
  1216.       rect.top    = nVertPos;
  1217.       rect.bottom = nVertPos + screen->yChar;
  1218.       rect.left   = nHorzPos;
  1219.       rect.right  = nHorzPos + (screen->xChar * run_length);
  1220.       if (attrib&1)
  1221.       {
  1222.     SetTextColor (hDC, screen->rgbBGColour);
  1223.     SetBkColor (hDC, screen->rgbFGColour);
  1224.       }
  1225.       ExtTextOut (hDC, nHorzPos, nVertPos, (ETO_OPAQUE | ETO_CLIPPED),
  1226.           &rect, &screen->chars[bias + pos],
  1227.           run_length, NULL);
  1228. #if 0
  1229.       if (attrib&2)  /* Bolden by horizontal 1-pixel smear */
  1230.         ExtTextOut (hDC, nHorzPos+1, nVertPos, (ETO_CLIPPED),
  1231.             &rect, &screen->chars[bias + pos],
  1232.             run_length, NULL);
  1233. #endif
  1234.       if (attrib&1)
  1235.       {
  1236.     SetTextColor (hDC, screen->rgbFGColour);
  1237.     SetBkColor (hDC, screen->rgbBGColour);
  1238.       }
  1239.       pos = nposn;
  1240.     }
  1241.   }
  1242.   SelectObject (hDC, hOldFont);
  1243. }
  1244.  
  1245. /* VOID PaintScreen (HWND hWnd )
  1246.  
  1247.    Description:
  1248.       Paints the rectangle determined by the paint struct of
  1249.       the DC.
  1250.  
  1251.    Parameters:
  1252.       HWND hWnd
  1253.          handle to TTY window (as always)
  1254. */
  1255.  
  1256. static VOID
  1257. PaintScreen (HWND hWnd)
  1258. {
  1259.   SCREEN        screen = GETSCREEN (hWnd);
  1260.   HDC           hDC;
  1261.   PAINTSTRUCT   ps;
  1262.  
  1263.   if (NULL == screen)
  1264.     return;
  1265.  
  1266.   hDC =  BeginPaint (hWnd, &ps);
  1267.   if (IsIconic (hWnd)) {
  1268.     DefWindowProc (hWnd, WM_ICONERASEBKGND, (WPARAM) hDC, 0L);
  1269.     DrawIcon (hDC, 0, 0, screen->hIcon ? screen->hIcon : ghDefaultIcon);
  1270.   } else {
  1271.     Do_PaintScreen (hWnd, screen, hDC, &ps);
  1272.   }
  1273.   EndPaint (hWnd, &ps);
  1274.   MoveScreenCursor (screen);
  1275. }
  1276.  
  1277. #if 0
  1278. static VOID
  1279. EraseScreen (HWND hWnd, HDC hDC)
  1280. {
  1281.   SCREEN    screen = GETSCREEN (hWnd);
  1282.   RECT      rect;
  1283.  
  1284.   if (NULL == screen)
  1285.     return;
  1286.  
  1287.   if (! (IsIconic (hWnd))) {
  1288.     GetClientRect (hWnd, &rect);
  1289.     FillRect (hDC, &rect, screen->bkgnd_brush);
  1290.   }
  1291. }
  1292. #endif
  1293.  
  1294. static VOID _fastcall
  1295. SetCells (SCREEN screen, int row, int col, int count,
  1296.       char ch, SCREEN_ATTRIBUTE attr)
  1297. {
  1298.   int  address1 = row * MAXCOLS + col;
  1299.   int  address2 = address1 + count;
  1300.   int  i;
  1301.   for (i = address1;  i<address2;  i++)
  1302.   {
  1303.     screen->chars[i] = ch;
  1304.     screen->attrs[i] = attr;
  1305.   }
  1306. }
  1307.  
  1308. static VOID
  1309. ScrollScreenBufferUp (SCREEN  screen,  int count)
  1310. {
  1311.   /* int  total_rows = MAXROWS; */
  1312.   int  total_rows = screen->height;
  1313.   int  rows_copied = max (total_rows - count, 0);
  1314.   count = min (count, total_rows);
  1315.  
  1316.   _fmemmove ((LPSTR) (screen->chars),
  1317.          (LPSTR) (screen->chars + count * MAXCOLS),
  1318.          rows_copied * MAXCOLS);
  1319.   _fmemmove ((LPSTR) (screen->attrs),
  1320.          (LPSTR) (screen->attrs + count * MAXCOLS),
  1321.          rows_copied * MAXCOLS);
  1322.   _fmemset ((LPSTR)(screen->chars + rows_copied * MAXCOLS),
  1323.         ' ', count*MAXCOLS);
  1324.   _fmemset ((LPSTR)(screen->attrs + rows_copied * MAXCOLS),
  1325.         screen->write_attribute, count*MAXCOLS);
  1326. }
  1327.  
  1328. /* BOOL SizeScreen (HWND hWnd, WORD wVertSize, WORD wHorzSize )
  1329.    Description:
  1330.       Set SCREEN size.  */
  1331.  
  1332. static BOOL
  1333. SizeScreen (HWND hWnd, WORD wVertSize, WORD wHorzSize )
  1334. {
  1335.    SCREEN screen = GETSCREEN (hWnd);
  1336.    int old_width, old_height;
  1337.    unsigned int new_width;
  1338.    unsigned int new_height;
  1339.  
  1340.    if (NULL == screen)
  1341.       return  FALSE;
  1342.  
  1343.    if (IsIconic(hWnd)) {
  1344.      /*   THis entire section is a crock to ensure a reasonably sized window
  1345.           when Scheme is started minimized
  1346.  
  1347.         Since we protect this procedure against minimizing in the WndProc, we
  1348.         can get here only when window is launched in a minimized state.  We
  1349.         get here because of the SendMessage in ScreenReset.  Our duty is to
  1350.     fake a normal position and size.
  1351.         Luckily none of the scrolling businness happens because all the cursor
  1352.         etc are at zero. (Hopefully it would be clipped).
  1353.      */
  1354.      WINDOWPLACEMENT pl;
  1355.      int width, height, params[4] = {-1, -1, 0, 0};  /* left,top,width,height*/
  1356.      init_geometry ("MITSCHEME_GEOMETRY", ¶ms[0]);
  1357.      width   = min (params[2] ? params[2] : 80*screen->xChar,
  1358.             GetSystemMetrics(SM_CXSCREEN));
  1359.      height  = min (params[3] ? params[3] : 40*screen->yChar,
  1360.             GetSystemMetrics(SM_CYSCREEN));
  1361.      GetWindowPlacement (hWnd, &pl);
  1362.      AdjustedSize (screen, &width, &height);
  1363.      pl.rcNormalPosition.left = params[0]==-1 ? 0 : params[0];
  1364.      pl.rcNormalPosition.top  = params[1]==-1 ? 0 : params[1];
  1365.      pl.rcNormalPosition.bottom = pl.rcNormalPosition.top + height;
  1366.      pl.rcNormalPosition.right  = pl.rcNormalPosition.left + width;
  1367.      SetWindowPlacement (hWnd, &pl);
  1368.      wVertSize = height;
  1369.      wHorzSize = width;
  1370.    }
  1371.  
  1372.    /* if (GetMenu(hWnd)) wVertSize -= GetSystemMetrics(SM_CYMENU); */
  1373.    old_width  = screen->width;
  1374.    old_height = screen->height;
  1375.  
  1376.    new_width  =
  1377.      max (1, min ((wHorzSize + screen->xOffset) / screen->xChar, MAXCOLS));
  1378.    new_height =
  1379.      max (1, min ((wVertSize + screen->yOffset) / screen->yChar, MAXROWS));
  1380.  
  1381.    if (new_width > old_width)
  1382.    {
  1383.      /* Clear out revealed character cells */
  1384.      int  row, rows = min (old_height, new_height);
  1385.      for (row = 0; row < rows; row++)
  1386.        SetCells (screen, row, old_width, new_width-old_width, ' ', 0);
  1387.    }
  1388.  
  1389.    if (new_height > old_height)
  1390.    {
  1391.      /* Clear out revealed character cells */
  1392.      int  row;
  1393.      for (row = old_height; row < new_height; row++)
  1394.        SetCells (screen, row, 0, new_width, ' ', 0);
  1395.    }
  1396.    else if (screen->row >= new_height)
  1397.    {
  1398.      ScrollScreenBufferUp (screen, ((screen->row - new_height) + 1));
  1399.      screen->row = (new_height - 1);
  1400.    }
  1401.  
  1402.    screen->width  = new_width;
  1403.    screen->height = new_height;
  1404.  
  1405.    /* scroll window to fit in cursor */
  1406.    if (screen->column >= new_width)
  1407.    {
  1408.      screen->column = 0;
  1409.      screen->row += 1;
  1410.    }
  1411.    if (screen->row >= new_height)
  1412.    {
  1413.      ScrollScreenBufferUp (screen, 1);
  1414.      screen->row = (new_height - 1);
  1415.    }
  1416.    MoveScreenCursor (screen);
  1417.  
  1418.    screen->ySize = (int) wVertSize;
  1419.    screen->xSize = (int) wHorzSize;
  1420.    screen->yScroll = 0;
  1421.    screen->xScroll = 0;
  1422.  
  1423.    if ((screen->mode_flags & SCREEN_MODE_EDWIN) == 0)
  1424.      screen->scroll_lines = (COMPUTE_SCROLL_LINES (new_height));
  1425.    else if (screen->mode_flags & SCREEN_EVENT_TYPE_RESIZE)
  1426.      {
  1427.        /* queue RESIZE event */
  1428.        SCREEN_EVENT * event
  1429.      = (allocate_event (screen, SCREEN_EVENT_TYPE_RESIZE));
  1430.        if (event)
  1431.      {
  1432.        event->event.resize.rows = new_height;
  1433.        event->event.resize.columns = new_width;
  1434.      }
  1435.      }
  1436.    else
  1437.      {
  1438.        /* Queue a character based resize event */
  1439.        SCREEN_EVENT * event = (allocate_event (screen, SCREEN_EVENT_TYPE_KEY));
  1440.        if (event)
  1441.      {
  1442.        event->event.key.repeat_count = 1;
  1443.        event->event.key.virtual_keycode = 0;
  1444.        event->event.key.virtual_scancode = 0;
  1445.        event->event.key.ch = SCREEN_EDWIN_RESIZE_COMMAND;
  1446.        event->event.key.control_key_state = 0;
  1447.      }
  1448.      }
  1449.    /* Cause screen to be redrawn, but if we are under Edwin, don't
  1450.       bother as Edwin has to calculate the redisplay anyway.  Well, we
  1451.       do bother otherwise we would have to clear the part of the
  1452.       screen that is not in a character box.  */
  1453. #if 0
  1454.    if ((screen->mode_flags & SCREEN_MODE_EDWIN) == 0)
  1455. #endif
  1456.      {
  1457.        InvalidateRect (hWnd, NULL, TRUE);
  1458.      }
  1459.  
  1460.    return  TRUE;
  1461.  
  1462. }
  1463.  
  1464. static BOOL
  1465. handle_window_pos_changing (HWND hwnd, LPWINDOWPOS wp)
  1466. {
  1467.   BOOL result = (FORWARD_WM_WINDOWPOSCHANGING (hwnd, wp, DefWindowProc));
  1468.   if ((wp -> flags) & SWP_NOSIZE)
  1469.     return (result);
  1470.   {
  1471.     SCREEN screen = (GETSCREEN (hwnd));
  1472.     (wp -> cx)
  1473.       = (char_to_pixel_width (screen,
  1474.                   (pixel_to_char_width (screen, (wp -> cx)))));
  1475.     (wp -> cy)
  1476.       = (char_to_pixel_height (screen,
  1477.                    (pixel_to_char_height (screen, (wp -> cy)))));
  1478.   }
  1479.   return (0);
  1480. }
  1481.  
  1482. void
  1483. screen_char_dimensions (HWND hwnd, int * xchar, int * ychar)
  1484. {
  1485.   SCREEN screen = (GETSCREEN (hwnd));
  1486.   (*xchar) = (screen -> xChar);
  1487.   (*ychar) = (screen -> yChar);
  1488. }
  1489.  
  1490. /* BOOL ScrollScreenVert (HWND hWnd, WORD wScrollCmd, WORD wScrollPos )
  1491.  
  1492.    Description:
  1493.       Scrolls TTY window vertically.
  1494.  
  1495.    Parameters:
  1496.       HWND hWnd
  1497.          handle to TTY window
  1498.  
  1499.       WORD wScrollCmd
  1500.          type of scrolling we're doing
  1501.  
  1502.       WORD wScrollPos
  1503.          scroll position
  1504. */
  1505.  
  1506. static BOOL
  1507. ScrollScreenVert (HWND hWnd, WORD wScrollCmd, WORD wScrollPos)
  1508. {
  1509.    int        nScrollAmt;
  1510.    SCREEN     screen = GETSCREEN (hWnd);
  1511.  
  1512.    if (NULL == screen)
  1513.       return  FALSE;
  1514.  
  1515.    switch (wScrollCmd)
  1516.    {
  1517.       case SB_TOP:
  1518.      nScrollAmt = -screen->yOffset;
  1519.      break;
  1520.  
  1521.       case SB_BOTTOM:
  1522.      nScrollAmt = screen->yScroll - screen->yOffset;
  1523.      break;
  1524.  
  1525.       case SB_PAGEUP:
  1526.      nScrollAmt = -screen->ySize;
  1527.      break;
  1528.  
  1529.       case SB_PAGEDOWN:
  1530.      nScrollAmt = screen->ySize;
  1531.      break;
  1532.  
  1533.       case SB_LINEUP:
  1534.      nScrollAmt = -screen->yChar;
  1535.      break;
  1536.  
  1537.       case SB_LINEDOWN:
  1538.      nScrollAmt = screen->yChar;
  1539.      break;
  1540.  
  1541.       case SB_THUMBPOSITION:
  1542.      nScrollAmt = wScrollPos - screen->yOffset;
  1543.      break;
  1544.  
  1545.       default:
  1546.      return  FALSE;
  1547.    }
  1548.    if ((screen->yOffset + nScrollAmt) > screen->yScroll)
  1549.       nScrollAmt = screen->yScroll - screen->yOffset;
  1550.    if ((screen->yOffset + nScrollAmt) < 0)
  1551.       nScrollAmt = -screen->yOffset;
  1552.    ScrollWindow (hWnd, 0, -nScrollAmt, NULL, NULL);
  1553.    screen->yOffset = screen->yOffset + nScrollAmt;
  1554.    SetScrollPos (hWnd, SB_VERT, screen->yOffset, TRUE);
  1555.  
  1556.    return  TRUE;
  1557. }
  1558.  
  1559. /* BOOL ScrollScreenHorz (HWND hWnd, WORD wScrollCmd, WORD wScrollPos )
  1560.  
  1561.    Description:
  1562.       Scrolls TTY window horizontally.
  1563.  
  1564.    Parameters:
  1565.       HWND hWnd
  1566.          handle to TTY window
  1567.  
  1568.       WORD wScrollCmd
  1569.          type of scrolling we're doing
  1570.  
  1571.       WORD wScrollPos
  1572.          scroll position
  1573. */
  1574.  
  1575. static BOOL
  1576. ScrollScreenHorz (HWND hWnd, WORD wScrollCmd, WORD wScrollPos)
  1577. {
  1578.    int        nScrollAmt;
  1579.    SCREEN     screen = GETSCREEN (hWnd);
  1580.  
  1581.    if (NULL == screen)
  1582.       return  FALSE;
  1583.  
  1584.    switch (wScrollCmd)
  1585.    {
  1586.       case SB_TOP:
  1587.      nScrollAmt = -screen->xOffset;
  1588.      break;
  1589.  
  1590.       case SB_BOTTOM:
  1591.      nScrollAmt = screen->xScroll - screen->xOffset;
  1592.      break;
  1593.  
  1594.       case SB_PAGEUP:
  1595.      nScrollAmt = -screen->xSize;
  1596.      break;
  1597.  
  1598.       case SB_PAGEDOWN:
  1599.      nScrollAmt = screen->xSize;
  1600.      break;
  1601.  
  1602.       case SB_LINEUP:
  1603.      nScrollAmt = -screen->xChar;
  1604.      break;
  1605.  
  1606.       case SB_LINEDOWN:
  1607.      nScrollAmt = screen->xChar;
  1608.      break;
  1609.  
  1610.       case SB_THUMBPOSITION:
  1611.      nScrollAmt = wScrollPos - screen->xOffset;
  1612.      break;
  1613.  
  1614.       default:
  1615.      return  FALSE;
  1616.    }
  1617.    if ((screen->xOffset + nScrollAmt) > screen->xScroll)
  1618.       nScrollAmt = screen->xScroll - screen->xOffset;
  1619.    if ((screen->xOffset + nScrollAmt) < 0)
  1620.       nScrollAmt = -screen->xOffset;
  1621.    ScrollWindow (hWnd, -nScrollAmt, 0, NULL, NULL);
  1622.    screen->xOffset = screen->xOffset + nScrollAmt;
  1623.    SetScrollPos (hWnd, SB_HORZ, screen->xOffset, TRUE);
  1624.  
  1625.    return  TRUE;
  1626. }
  1627.  
  1628. static SCREEN screen_focus = NULL;
  1629.  
  1630. HWND
  1631. ScreenCurrentFocus (void)
  1632. {
  1633.   SCREEN *link;
  1634.   HWND   hWnd;
  1635.  
  1636.   if (screen_focus)
  1637.     return  screen_focus->hWnd;
  1638.   hWnd = GetFocus();
  1639.   if (NULL == hWnd)
  1640.     return  NULL;
  1641.   link = head_to_registered_screen (hWnd);
  1642.   if (NULL == link)
  1643.     return  NULL;
  1644.   screen_focus = (*link);
  1645.   return  hWnd;
  1646. }
  1647.  
  1648. /* BOOL SetScreenFocus (HWND hWnd )
  1649.  
  1650.    Description:
  1651.       Sets the focus to the TTY window also creates caret.
  1652.  
  1653.    Parameters:
  1654.       HWND hWnd
  1655.          handle to TTY window
  1656. */
  1657.  
  1658. static BOOL
  1659. SetScreenFocus (HWND hWnd)
  1660. {
  1661.    SCREEN  screen = GETSCREEN (hWnd);
  1662.  
  1663.    if (NULL == screen)  return  FALSE;
  1664.  
  1665.    screen_focus = screen;
  1666.    CreateCaret (hWnd, NULL, screen->xChar, screen->yChar);
  1667.    if (screen->cursor_visible)
  1668.       ShowCaret (hWnd);
  1669.  
  1670.    MoveScreenCursor (screen);
  1671.    return  TRUE;
  1672. }
  1673.  
  1674. /* BOOL KillScreenFocus (HWND hWnd )
  1675.  
  1676.    Description:
  1677.       Kills TTY focus and destroys the caret.
  1678.  
  1679.    Parameters:
  1680.       HWND hWnd
  1681.          handle to TTY window
  1682. */
  1683.  
  1684. BOOL
  1685. KillScreenFocus (HWND hWnd )
  1686. {
  1687.    SCREEN  screen = GETSCREEN (hWnd);
  1688.  
  1689.    if (NULL == screen)  return  FALSE;
  1690.  
  1691.    screen_focus = NULL;
  1692. #if 0
  1693.    if (screen->cursor_visible)
  1694.      HideCaret (hWnd);
  1695. #endif
  1696.    DestroyCaret ();
  1697.    return  TRUE;
  1698. }
  1699.  
  1700. /* VOID MoveScreenCursor (SCREEN screen)
  1701.  
  1702.    Description:
  1703.       Moves caret to current position.
  1704. */
  1705.  
  1706. static VOID
  1707. MoveScreenCursor (SCREEN screen)
  1708. {
  1709.   ScreenCurrentFocus();
  1710.   if (screen == screen_focus)
  1711. #if 0
  1712.     SetCaretPos (screen->column * screen->xChar - screen->xOffset
  1713.          /* This ensures visiblity at the far left: */
  1714.          + ((screen->column == screen->width) ? -2 : 0),
  1715.          screen->row * screen->yChar - screen->yOffset);
  1716. #endif
  1717.   SetCaretPos (/* This ensures visiblity at the far left: */
  1718.            (screen->column >= screen->width)
  1719.            ? (screen->width * screen->xChar - screen->xOffset - 2)
  1720.            : (screen->column * screen->xChar - screen->xOffset),
  1721.            screen->row * screen->yChar - screen->yOffset);
  1722. }
  1723.  
  1724. BOOL
  1725. Screen_SetPosition (SCREEN screen, int row, int column)
  1726. {
  1727.   if ((row < 0) || (row >= screen->height))
  1728.     return (FALSE);
  1729. #if 0
  1730.   if ((column < 0) || (column > screen->width))         /* may be == */
  1731. #endif
  1732.   if ((column < 0) || (column >= MAXCOLS))
  1733.     return (FALSE);
  1734.   screen->row    = row;
  1735.   screen->column = column;
  1736.   MoveScreenCursor (screen);
  1737.   return  TRUE;
  1738. }
  1739.  
  1740. /* UINT ScreenPeekOrRead (SCREEN, n_to_read, SCREEN_EVENT* buffer, BOOL remove)
  1741.  
  1742.    Copy events into buffer.  Return number of events processed.
  1743.    If remove=TRUE, remove events from screen queue (i.e. Read)
  1744.    If remove=FALSE, leave events in queue (i.e. Peek)
  1745.    If buffer=NULL, process without copying.
  1746.    If n_to_read<0, process all events.
  1747.     .  n_to_read=-1, buffer=NULL, remove=FALSE -> count of pending events
  1748.     .  n_to_read=-1, buffer=NULL, remove=TRUE  -> flush queue
  1749.     .  n_to_read=n,  buffer=NULL, remove=TRUE  -> discard n events
  1750.  
  1751.    NB: if (n_to_read < 0), buffer is ignored.
  1752. */
  1753.  
  1754. UINT
  1755. ScreenPeekOrRead (SCREEN screen, int n_to_read, SCREEN_EVENT * buffer,
  1756.           BOOL remove)
  1757. {
  1758.   SCREEN_EVENT * scan_buffer = ((n_to_read < 0) ? 0 : buffer);
  1759.   SCREEN_EVENT event;
  1760.   int n_read = 0;
  1761.  
  1762.   if (remove)
  1763.     while (((n_read < n_to_read) || (n_to_read < 0))
  1764.        && (read_event (screen, 0, 1, (&event))))
  1765.       {
  1766.     if (scan_buffer)
  1767.       (*scan_buffer++) = event;
  1768.     n_read += 1;
  1769.       }
  1770.   else
  1771.     {
  1772.       SCREEN_EVENT_LINK * scan_queue = event_queue_head;
  1773.       while (((n_read < n_to_read) || (n_to_read < 0))
  1774.          && (scan_queue != 0))
  1775.     if (((scan_queue -> event) . handle) == (screen -> hWnd))
  1776.       {
  1777.         if (scan_buffer)
  1778.           (*scan_buffer++) = (scan_queue -> event);
  1779.         scan_queue = (scan_queue -> next);
  1780.         n_read += 1;
  1781.       }
  1782.     }
  1783.   return (n_read);
  1784. }
  1785.  
  1786. void
  1787. flush_typeahead (SCREEN screen)
  1788. {
  1789.   while (read_event (screen, SCREEN_EVENT_TYPE_KEY, 1, 0))
  1790.     ;
  1791.   (screen -> n_chars) = 0;
  1792. }
  1793.  
  1794. /* The following handling of the keyboard is taken with only minor
  1795.    changes from Emacs 20.5.  */
  1796.  
  1797. #define LP_REPEAT(lparam)     ((lparam) & 0x0000ffff)
  1798. #define LP_SCAN_CODE(lparam) (((lparam) & 0x00ff0000) >> 16)
  1799. #define LP_EXTENDED(lparam)  (((lparam) & 0x01000000) != 0)
  1800.  
  1801. /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
  1802.    between left and right keys as advertised.  We test for this
  1803.    support dynamically, and set a flag when the support is absent.  If
  1804.    absent, we keep track of the left and right control and alt keys
  1805.    ourselves.  This is particularly necessary on keyboards that rely
  1806.    upon the AltGr key, which is represented as having the left control
  1807.    and right alt keys pressed.  For these keyboards, we need to know
  1808.    when the left alt key has been pressed in addition to the AltGr key
  1809.    so that we can properly support M-AltGr-key sequences (such as M-@
  1810.    on Swedish keyboards).  */
  1811.  
  1812. #define MOD_LCONTROL 0
  1813. #define MOD_RCONTROL 1
  1814. #define MOD_LMENU 2
  1815. #define MOD_RMENU 3
  1816.  
  1817. static int modifiers [4] = { 0, 0, 0, 0 };
  1818. static int record_modifiers_p;
  1819.  
  1820. static void
  1821. record_modifier_transition (WPARAM wparam, LPARAM lparam, int down_p)
  1822. {
  1823.   static int modifier_key_support_tested = 0;
  1824.   if (down_p && (!modifier_key_support_tested))
  1825.     {
  1826.       if (wparam == VK_CONTROL)
  1827.     {
  1828.       record_modifiers_p
  1829.         = (((GetKeyState (VK_LCONTROL) & 0x8000) == 0)
  1830.            && ((GetKeyState (VK_RCONTROL) & 0x8000) == 0));
  1831.       modifier_key_support_tested = 1;
  1832.     }
  1833.       else if (wparam == VK_MENU)
  1834.     {
  1835.       record_modifiers_p
  1836.         = (((GetKeyState (VK_LMENU) & 0x8000) == 0)
  1837.            && ((GetKeyState (VK_RMENU) & 0x8000) == 0));
  1838.       modifier_key_support_tested = 1;
  1839.     }
  1840.     }
  1841.   if (record_modifiers_p)
  1842.     {
  1843.       if (down_p)
  1844.     {
  1845.       /* Synchronize modifier state with what is reported with the
  1846.          current keystroke.  Even if we cannot distinguish between
  1847.          left and right modifier keys, we know that, if no
  1848.          modifiers are set, then neither the left nor right
  1849.          modifier should be set.  */
  1850.       if ((GetKeyState (VK_CONTROL) & 0x8000) == 0)
  1851.         {
  1852.           (modifiers[MOD_RCONTROL]) = 0;
  1853.           (modifiers[MOD_LCONTROL]) = 0;
  1854.         }
  1855.       if ((GetKeyState (VK_MENU) & 0x8000) == 0)
  1856.         {
  1857.           (modifiers[MOD_RMENU]) = 0;
  1858.           (modifiers[MOD_LMENU]) = 0;
  1859.         }
  1860.     }
  1861.       if (wparam == VK_CONTROL)
  1862.     (modifiers [(LP_EXTENDED (lparam)) ? MOD_RCONTROL : MOD_LCONTROL])
  1863.       = down_p;
  1864.       else if (wparam == VK_MENU)
  1865.     (modifiers [(LP_EXTENDED (lparam)) ? MOD_RMENU : MOD_LMENU]) = down_p;
  1866.     }
  1867. }
  1868.  
  1869. /* We can lose focus while a modifier key has been pressed.  When
  1870.    we regain focus, be conservative and clear all modifiers since 
  1871.    we cannot reconstruct the left and right modifier state.  */
  1872.  
  1873. static void
  1874. copy_current_state (unsigned int vk, BYTE * keystate)
  1875. {
  1876.   (keystate[vk]) = ((GetAsyncKeyState (vk) & 0x8000) >> 8);
  1877. }
  1878.  
  1879. static void
  1880. reset_modifiers (void)
  1881. {
  1882.   if ((GetFocus ()) != 0)
  1883.     {
  1884.       if (((GetAsyncKeyState (VK_CONTROL)) & 0x08000) == 0)
  1885.     {
  1886.       /* Clear any recorded control modifier state.  */
  1887.       (modifiers[MOD_RCONTROL]) = 0;
  1888.       (modifiers[MOD_LCONTROL]) = 0;
  1889.     }
  1890.       if (((GetAsyncKeyState (VK_MENU)) & 0x08000) == 0)
  1891.     {
  1892.       /* Clear any recorded alt modifier state.  */
  1893.       (modifiers[MOD_RMENU]) = 0;
  1894.       (modifiers[MOD_LMENU]) = 0;
  1895.     }
  1896.       /* Update the state of all modifier keys, because modifiers used in
  1897.      hot-key combinations can get stuck on if Scheme loses focus as a
  1898.      result of a hot-key being pressed.  */
  1899.       {
  1900.     BYTE keystate [256];
  1901.     GetKeyboardState (keystate);
  1902.     copy_current_state (VK_SHIFT, keystate);
  1903.     copy_current_state (VK_CONTROL, keystate);
  1904.     copy_current_state (VK_LCONTROL, keystate);
  1905.     copy_current_state (VK_RCONTROL, keystate);
  1906.     copy_current_state (VK_MENU, keystate);
  1907.     copy_current_state (VK_LMENU, keystate);
  1908.     copy_current_state (VK_RMENU, keystate);
  1909.     copy_current_state (VK_LWIN, keystate);
  1910.     copy_current_state (VK_RWIN, keystate);
  1911.     copy_current_state (VK_APPS, keystate);
  1912.     SetKeyboardState (keystate);
  1913.       }
  1914.     }
  1915. }
  1916.  
  1917. static int
  1918. modifier_set_p (int vk)
  1919. {
  1920.   if (record_modifiers_p)
  1921.     switch (vk)
  1922.       {
  1923.       case VK_LCONTROL:
  1924.     return (modifiers[MOD_LCONTROL]);
  1925.       case VK_RCONTROL:
  1926.     return (modifiers[MOD_RCONTROL]);
  1927.       case VK_LMENU:
  1928.     return (modifiers[MOD_LMENU]);
  1929.       case VK_RMENU:
  1930.     return (modifiers[MOD_RMENU]);
  1931.       }
  1932.   /* For toggled modifiers, test the low-order bit; otherwise the
  1933.      high-order bit.  */
  1934.   return
  1935.     (((GetKeyState (vk))
  1936.       & (((vk == VK_CAPITAL) || (vk == VK_NUMLOCK) || (vk == VK_SCROLL))
  1937.      ? 0x0001
  1938.      : 0x8000))
  1939.      != 0);
  1940. }
  1941.  
  1942. static unsigned int
  1943. get_modifiers (void)
  1944. {
  1945.   unsigned int mods = 0;
  1946.  
  1947.   if (modifier_set_p (VK_SHIFT))    mods |= SCREEN_SHIFT_PRESSED;
  1948.   if (modifier_set_p (VK_CAPITAL))  mods |= SCREEN_CAPSLOCK_ON;
  1949.   if (modifier_set_p (VK_NUMLOCK))  mods |= SCREEN_NUMLOCK_ON;
  1950.   if (modifier_set_p (VK_SCROLL))   mods |= SCREEN_SCROLLLOCK_ON;
  1951.  
  1952.   if (modifier_set_p (VK_RCONTROL))
  1953.     mods |= (SCREEN_RIGHT_CONTROL_PRESSED | SCREEN_CONTROL_PRESSED);
  1954.   if (modifier_set_p (VK_LMENU))
  1955.     mods |= (SCREEN_LEFT_ALT_PRESSED | SCREEN_ALT_PRESSED);
  1956.  
  1957.   /* Slight complication to handle case where AltGr is pressed.  */
  1958.   if ((modifier_set_p (VK_LCONTROL)) && (!modifier_set_p (VK_RMENU)))
  1959.     mods |= (SCREEN_LEFT_CONTROL_PRESSED | SCREEN_CONTROL_PRESSED);
  1960.   if ((modifier_set_p (VK_RMENU)) && (!modifier_set_p (VK_LCONTROL)))
  1961.     mods |= (SCREEN_RIGHT_ALT_PRESSED | SCREEN_ALT_PRESSED);
  1962.  
  1963.   return (mods);
  1964. }
  1965.  
  1966. static void
  1967. use_translate_message (HWND handle, UINT message, WPARAM wparam, LPARAM lparam)
  1968. {
  1969.   MSG msg;
  1970.   (msg . hwnd) = handle;
  1971.   (msg . message) = message;
  1972.   (msg . wParam) = wparam;
  1973.   (msg . lParam) = lparam;
  1974.   (msg . time) = (GetMessageTime ());
  1975.   (msg . pt . x) = 0;
  1976.   (msg . pt . y) = 0;
  1977.   TranslateMessage (&msg);
  1978. }
  1979.  
  1980. static void
  1981. make_key_event (HWND handle, WPARAM wparam, LPARAM lparam, int ch)
  1982. {
  1983.   SCREEN screen = (GETSCREEN (handle));
  1984.   SCREEN_EVENT * event;
  1985.   unsigned int modifiers = (get_modifiers ());
  1986.  
  1987.   /* Translate the Backspace key to the Delete character.  */
  1988.   if ((ch == 0x08) && (wparam == VK_BACK))
  1989.     ch = ASCII_DEL;
  1990.  
  1991.   /* If the unmodified key is bound to a command, send the command.
  1992.      Extra hair here is due to need to handle control characters.  */
  1993.   if (((modifiers & SCREEN_ALT_PRESSED) == 0)
  1994.       && (((modifiers & SCREEN_CONTROL_PRESSED) == 0)
  1995.       || (('A' <= ch) && (ch <= 'Z'))
  1996.       || (('a' <= ch) && (ch <= 'z'))
  1997.       || (ch == '@') || (ch == '[') || (ch == '\\')
  1998.       || (ch == ']') || (ch == '^') || (ch == '_')))
  1999.     {
  2000.       int ch2 = ch;
  2001.       unsigned int i;
  2002.       if ((modifiers & SCREEN_CONTROL_PRESSED) != 0)
  2003.     {
  2004.       if (('a' <= ch) && (ch <= 'z'))
  2005.         ch2 -= ('a' - 'A');
  2006.       ch2 -= '@';
  2007.     }
  2008.       for (i = 0; (i < (screen -> n_bindings)); i += 1)
  2009.     if ((((screen -> bindings) [i]) . key) == ch2)
  2010.       {
  2011.         if (SendMessage
  2012.         (handle,
  2013.          WM_COMMAND,
  2014.          (MAKEWPARAM ((((screen -> bindings) [i]) . command), 0)),
  2015.          0))
  2016.           return;
  2017.         else
  2018.           break;
  2019.       }
  2020.     }
  2021.  
  2022.   if ((ch == (-1)) && (((screen -> mode_flags) & SCREEN_MODE_VK_KEYS) == 0))
  2023.     return;
  2024.  
  2025.   event = (allocate_event (screen, SCREEN_EVENT_TYPE_KEY));
  2026.   if (!event) return;
  2027.   ((event -> event.key) . repeat_count) = (LP_REPEAT (lparam));
  2028.   ((event -> event.key) . virtual_keycode) = wparam;
  2029.   ((event -> event.key) . virtual_scancode) = (LP_SCAN_CODE (lparam));
  2030.   ((event -> event.key) . ch) = ch;
  2031.   ((event -> event.key) . control_key_state) = modifiers;
  2032.  
  2033.   if (win32_trace_level > 0)
  2034.     {
  2035.       fprintf (win32_trace_file, "make_key_event: ");
  2036.       fprintf
  2037.     (win32_trace_file,
  2038.      "handle=0x%x keycode=0x%x scancode=0x%x ch=0x%x modifiers=0x%x\n",
  2039.      handle, wparam, (LP_SCAN_CODE (lparam)), ch, modifiers);
  2040.       fflush (win32_trace_file);
  2041.     }
  2042. }
  2043.  
  2044. /* Process WM_KEYDOWN and WM_SYSKEYDOWN.  Return 1 to indicate that
  2045.    the key was handled, and that the message proc should return;
  2046.    return 0 to indicate that the default action should take place.  */
  2047.  
  2048. static int
  2049. process_keydown (HWND handle, UINT message, WPARAM wparam, LPARAM lparam)
  2050. {
  2051.   switch (wparam)
  2052.     {
  2053.     case VK_MENU:
  2054.       /* Prevent Windows from activating the menu bar if an Alt key is
  2055.      pressed and released by itself.  */
  2056.       return (1);
  2057.  
  2058.     case VK_LWIN:
  2059.     case VK_RWIN:
  2060.     case VK_APPS:
  2061.     case VK_NUMLOCK:
  2062.     case VK_SCROLL:
  2063.     case VK_CAPITAL:
  2064.     case VK_CONTROL: 
  2065.     case VK_SHIFT:
  2066.       /* Let Windows handle the modifier keys.  */
  2067.       use_translate_message (handle, message, wparam, lparam);
  2068.       return (0);
  2069.     }
  2070.  
  2071.   /* Always let Windows handle AltGr key chords; for some reason,
  2072.      ToAscii doesn't always process AltGr chords correctly.  */
  2073.   if ((modifier_set_p (VK_LCONTROL)) && (modifier_set_p (VK_RMENU)))
  2074.     {
  2075.       use_translate_message (handle, message, wparam, lparam);
  2076.       return (0);
  2077.     }
  2078.  
  2079.   /* Edwin handles some of the special keys directly, so provide
  2080.      symbols for those keys rather than translating them.  */
  2081.   if ((((GETSCREEN (handle)) -> mode_flags) & SCREEN_MODE_VK_KEYS)
  2082.       && ((wparam == VK_LEFT)
  2083.       || (wparam == VK_RIGHT)
  2084.       || (wparam == VK_UP)
  2085.       || (wparam == VK_DOWN)
  2086.       || (wparam == VK_HOME)
  2087.       || (wparam == VK_END)
  2088.       || (wparam == VK_PRIOR)
  2089.       || (wparam == VK_NEXT)
  2090.       || (wparam == VK_INSERT)
  2091.       || (wparam == VK_DELETE)
  2092.       || ((wparam >= VK_F1) && (wparam <= VK_F24))))
  2093.     {
  2094.       make_key_event (handle, wparam, lparam, (-1));
  2095.       return (1);
  2096.     }
  2097.  
  2098.   /* Let TranslateMessage handle anything not involving Alt or Ctrl.  */
  2099.   if (((get_modifiers ())
  2100.        & (SCREEN_ALT_PRESSED | SCREEN_CONTROL_PRESSED))
  2101.       == 0)
  2102.     {
  2103.       use_translate_message (handle, message, wparam, lparam);
  2104.       return (0);
  2105.     }
  2106.  
  2107.   /* Otherwise, handle translation directly, as otherwise Windows
  2108.      will do the wrong thing.  */
  2109.  
  2110.   /* Don't translate modified alphabetic keystrokes, so the user
  2111.      doesn't need to constantly switch layout to type control or meta
  2112.      keystrokes when the normal layout translates alphabetic
  2113.      characters to non-ascii characters.  */
  2114.   if (('A' <= wparam) && (wparam <= 'Z'))
  2115.     {
  2116.       make_key_event
  2117.     (handle, wparam, lparam,
  2118.      (((modifier_set_p (VK_SHIFT)) || (modifier_set_p (VK_CAPITAL)))
  2119.       ? wparam
  2120.       : (wparam + ('a' - 'A'))));
  2121.       return (1);
  2122.     }
  2123.  
  2124.   /* OK, here's the real hair.  Translate the unmodified keystroke to
  2125.      the corresponding character(s), then add the modifiers back in.  */
  2126.   {
  2127.     BYTE keystate [256];
  2128.     BYTE ansi_code [4];
  2129.     int n_chars;
  2130.     int i;
  2131.  
  2132.     memset (keystate, 0, (sizeof (keystate)));
  2133.     (keystate[wparam]) = 0x80;
  2134.     if (modifier_set_p (VK_SHIFT))
  2135.       (keystate[VK_SHIFT]) = 0x80;
  2136.     if (modifier_set_p (VK_CAPITAL))
  2137.       (keystate[VK_CAPITAL]) = 0x01;
  2138.  
  2139.     /* On NT, call ToUnicode instead and then convert to the current
  2140.        locale's default codepage.  */
  2141.     if (NT_windows_type == wintype_nt)
  2142.       {
  2143.     WCHAR buffer [128];
  2144.     char code_page [20];
  2145.     int code_page_number;
  2146.  
  2147.     n_chars
  2148.       = (ToUnicode (wparam, (LP_SCAN_CODE (lparam)), keystate,
  2149.             buffer, 128, 0));
  2150.     if (n_chars <= 0)
  2151.       return (1);
  2152.     GetLocaleInfo ((GetThreadLocale ()), LOCALE_IDEFAULTANSICODEPAGE,
  2153.                code_page, (sizeof (code_page)));
  2154.     code_page_number = (atoi (code_page));
  2155.     n_chars
  2156.       = (WideCharToMultiByte (code_page_number, 0, buffer, n_chars,
  2157.                   ansi_code, (sizeof (ansi_code)), 0, 0));
  2158.       }
  2159.     else
  2160.       n_chars
  2161.     = (ToAscii (wparam, (LP_SCAN_CODE (lparam)), keystate,
  2162.             ((LPWORD) ansi_code), 0));
  2163.     for (i = 0; (i < n_chars); i += 1)
  2164.       make_key_event (handle, wparam, lparam, (ansi_code[i]));
  2165.     return (1);
  2166.   }
  2167. }
  2168.  
  2169. static void
  2170. process_character (HWND handle, UINT message, WPARAM wparam, LPARAM lparam)
  2171. {
  2172.   make_key_event
  2173.     (handle, (MapVirtualKey ((LP_SCAN_CODE (lparam)), 1)), lparam, wparam);
  2174. }
  2175.  
  2176. static void
  2177. process_focus_message (HWND handle, int gained_p)
  2178. {
  2179.   SCREEN screen = (GETSCREEN (handle));
  2180.   SCREEN_EVENT * event = (allocate_event (screen, SCREEN_EVENT_TYPE_FOCUS));
  2181.   if (event)
  2182.     (event->event.focus.gained_p) = gained_p;
  2183. }
  2184.  
  2185. static void
  2186. process_show_message (HWND handle, int show_p)
  2187. {
  2188.   SCREEN screen = (GETSCREEN (handle));
  2189.   SCREEN_EVENT * event
  2190.     = (allocate_event (screen, SCREEN_EVENT_TYPE_VISIBILITY));
  2191.   if (event)
  2192.     (event->event.visibility.show_p) = show_p;
  2193. }
  2194.  
  2195. static VOID
  2196. ProcessCloseMessage (SCREEN screen)
  2197. {
  2198.   (void) allocate_event (screen, SCREEN_EVENT_TYPE_CLOSE);
  2199. }
  2200.  
  2201. static VOID
  2202. ProcessMouseButton (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
  2203.                     BOOL up)
  2204. {
  2205.   SCREEN screen = GETSCREEN (hWnd);
  2206.   SCREEN_EVENT * event;
  2207.   unsigned int control = 0;
  2208.   unsigned int button = 0;
  2209.  
  2210.   if (NULL == screen)
  2211.     return;
  2212.  
  2213.   if (uMsg & MK_CONTROL)
  2214.     control |= SCREEN_CONTROL_PRESSED;
  2215.   if (uMsg & MK_SHIFT)
  2216.     control |= SCREEN_SHIFT_PRESSED;
  2217.  
  2218.   switch (uMsg)
  2219.     {
  2220.     case WM_LBUTTONDOWN:
  2221.     case WM_LBUTTONUP:
  2222.       button = SCREEN_MOUSE_EVENT_LEFT_PRESSED;
  2223.       break;
  2224.  
  2225.     case WM_MBUTTONDOWN:
  2226.     case WM_MBUTTONUP:
  2227.       button = SCREEN_MOUSE_EVENT_MIDDLE_PRESSED;
  2228.       break;
  2229.  
  2230.     case WM_RBUTTONDOWN:
  2231.     case WM_RBUTTONUP:
  2232.       button = SCREEN_MOUSE_EVENT_RIGHT_PRESSED;
  2233.       break;
  2234.     }
  2235.   event = (allocate_event (screen, SCREEN_EVENT_TYPE_MOUSE));
  2236.   if (event)
  2237.     {
  2238.       event->event.mouse.row = ((HIWORD (lParam)) / (screen -> yChar));
  2239.       event->event.mouse.column = ((LOWORD (lParam)) / (screen -> xChar));
  2240.       event->event.mouse.control_key_state = control;
  2241.       event->event.mouse.button_state = button;
  2242.       event->event.mouse.up = up;
  2243.       event->event.mouse.mouse_moved = 0;
  2244.       event->event.mouse.double_click = 0;
  2245.     }
  2246. }
  2247.  
  2248. /* Utilities for WriteScreenBlock */
  2249.  
  2250. static VOID _fastcall
  2251. Screen_BS (SCREEN screen)
  2252. {
  2253.   if (screen->column > 0)
  2254.     screen->column --;
  2255.   else if (screen->row > 0)
  2256.   {
  2257.     screen->row--;
  2258.     screen->column = (screen->width - 1);
  2259.   }
  2260.   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
  2261.     MoveScreenCursor (screen);
  2262. }
  2263.  
  2264. static VOID _fastcall
  2265. Screen_LF (SCREEN screen)
  2266. {
  2267.   if ((screen->row++) >= (screen->height - 1))
  2268.   {
  2269.     ScrollScreenBufferUp (screen, screen->scroll_lines);
  2270.     ScrollWindow (screen->hWnd, 0,
  2271.           (-screen->yChar * screen->scroll_lines),
  2272.           NULL,
  2273.           NULL);
  2274. #if 0
  2275.     InvalidateRect (hWnd, NULL, FALSE);
  2276.     screen->row--;
  2277. #endif
  2278.     screen->row = (screen->height - screen->scroll_lines);
  2279.   }
  2280.   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
  2281.   {
  2282.     MoveScreenCursor (screen);
  2283.     UpdateWindow (screen->hWnd);
  2284.   }
  2285. }
  2286.  
  2287. static VOID _fastcall
  2288. Screen_CR (SCREEN screen)
  2289. {
  2290.   screen->column = 0;
  2291.   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
  2292.     MoveScreenCursor (screen);
  2293. }
  2294.  
  2295. static VOID _fastcall
  2296. Screen_CRLF (SCREEN screen)
  2297. {
  2298.   Screen_CR (screen);
  2299.   Screen_LF (screen);
  2300. }
  2301.  
  2302. VOID _fastcall
  2303. clear_screen_rectangle (SCREEN screen,
  2304.             int lo_row, int lo_col,
  2305.             int hi_row, int hi_col)
  2306. {
  2307.   RECT rect;
  2308.   int row, delta_col;
  2309.   char * screen_chars;
  2310.   SCREEN_ATTRIBUTE * screen_attrs;
  2311.  
  2312.   delta_col = (hi_col - lo_col);
  2313.  
  2314.   for (row = lo_row,
  2315.        screen_chars = &screen->chars[lo_row * MAXCOLS + lo_col],
  2316.        screen_attrs = &screen->attrs[lo_row * MAXCOLS + lo_col];
  2317.        row < hi_row;
  2318.        row++,
  2319.        screen_chars += MAXCOLS,
  2320.        screen_attrs += MAXCOLS)
  2321.   {
  2322.     _fmemset (screen_chars, ' ', delta_col);
  2323.     _fmemset (screen_attrs,
  2324.           screen->write_attribute,
  2325.           (delta_col * (sizeof (SCREEN_ATTRIBUTE))));
  2326.   }
  2327.  
  2328.   rect.left   = ((lo_col * screen->xChar) - screen->xOffset);
  2329.   rect.right  = ((hi_col * screen->xChar) - screen->xOffset);
  2330.   rect.top    = ((lo_row * screen->yChar) - screen->yOffset);
  2331.   rect.bottom = ((hi_row * screen->yChar) - screen->yOffset);
  2332.   InvalidateRect (screen->hWnd, &rect, FALSE);
  2333. }
  2334.  
  2335. #define INIT_SCREEN_WRITE_CHAR_STATE(state) state.row = -1
  2336.  
  2337. static VOID _fastcall
  2338. Finish_ScreenWriteChar (SCREEN screen, struct screen_write_char_s * rectp)
  2339. {
  2340.   if (rectp->row != -1)
  2341.     InvalidateRect (screen->hWnd, &rectp->rect, FALSE);
  2342.   if ((screen->column >= screen->width)
  2343.       && ((screen->mode_flags & SCREEN_MODE_AUTOWRAP) != 0))
  2344.     Screen_CRLF (screen);
  2345.   rectp->row = -1;
  2346. }
  2347.  
  2348. VOID _fastcall
  2349. Screen_WriteCharUninterpreted (SCREEN screen, int ch,
  2350.                    struct screen_write_char_s * rectp)
  2351. {
  2352.   /* Line wrap/overwrite the last position */
  2353.  
  2354.   if (screen->column >= screen->width)
  2355.   {
  2356.     if ((screen->mode_flags & SCREEN_MODE_AUTOWRAP) != 0)
  2357.     {
  2358.       if ((rectp != ((struct screen_write_char_s *) NULL))
  2359.       && (rectp->row != -1))
  2360.       {
  2361.     InvalidateRect (screen->hWnd, &rectp->rect, FALSE);
  2362.     rectp->row = -1;
  2363.       }
  2364.       Screen_CRLF (screen);
  2365.     }
  2366.     else
  2367.     {
  2368.       screen->column -= 1;
  2369.       if (rectp != ((struct screen_write_char_s *) NULL))
  2370.       {
  2371.     rectp->col -= 1;
  2372.     rectp->rect.right -= screen->xChar;
  2373.       }
  2374.     }
  2375.   }
  2376.   if (screen->row >= MAXROWS)
  2377.     screen->row = (MAXROWS - 1);
  2378.  
  2379.   if (screen->column >= MAXCOLS)
  2380.     screen->column = (MAXCOLS - 1);
  2381.  
  2382.   if (screen->row < 0)
  2383.     screen->row = 0;
  2384.  
  2385.   if (screen->column < 0)
  2386.     screen->column = 0;
  2387.  
  2388.   screen->chars[screen->row * MAXCOLS + screen->column] = ch;
  2389.   screen->attrs[screen->row * MAXCOLS + screen->column] =
  2390.     screen->write_attribute;
  2391.   if (rectp == ((struct screen_write_char_s *) NULL))
  2392.   {
  2393.     RECT       rect;
  2394.  
  2395.     rect.left   = ((screen->column * screen->xChar) - screen->xOffset);
  2396.     rect.right  = rect.left + screen->xChar;
  2397.     rect.top    = ((screen->row * screen->yChar) - screen->yOffset);
  2398.     rect.bottom = rect.top + screen->yChar;
  2399.     InvalidateRect (screen->hWnd, &rect, FALSE);
  2400.   }
  2401.   else if ((rectp->row == screen->row) && (rectp->col == screen->column))
  2402.   {
  2403.     rectp->col += 1;
  2404.     rectp->rect.right += screen->xChar;
  2405.   }
  2406.   else
  2407.   {
  2408.     if (rectp->row != -1)
  2409.       InvalidateRect (screen->hWnd, &rectp->rect, FALSE);
  2410.  
  2411.     rectp->rect.left   = ((screen->column * screen->xChar) - screen->xOffset);
  2412.     rectp->rect.right  = rectp->rect.left + screen->xChar;
  2413.     rectp->rect.top    = ((screen->row * screen->yChar) - screen->yOffset);
  2414.     rectp->rect.bottom = rectp->rect.top + screen->yChar;
  2415.     rectp->col = (screen->column + 1);
  2416.     rectp->row = screen->row;
  2417.   }
  2418.   screen->column += 1;
  2419. }
  2420.  
  2421. static VOID _fastcall
  2422. Screen_TAB (SCREEN screen, struct screen_write_char_s * rectp)
  2423. {
  2424.   do
  2425.     Screen_WriteCharUninterpreted (screen, ' ', rectp);
  2426.   while ((screen->column % 8) != 0);
  2427. }
  2428.  
  2429. static VOID _fastcall
  2430. relocate_cursor (SCREEN screen, int row, int col)
  2431. {
  2432.   screen->row = ((row < 0)
  2433.          ? 0
  2434.          : ((row >= screen->height)
  2435.             ? (screen->height - 1)
  2436.             : row));
  2437.   screen->column = ((col < 0)
  2438.             ? 0
  2439.             : ((col >= screen->width)
  2440.                ? (screen->width - 1)
  2441.                : col));
  2442.   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
  2443.     MoveScreenCursor (screen);
  2444. }
  2445.  
  2446. static VOID _fastcall
  2447. cursor_right (SCREEN screen, int delta)
  2448. {
  2449.   int new_col = (screen->column + delta);
  2450.  
  2451.   if (new_col < screen->width)
  2452.     screen->column = new_col;
  2453.   else if ((screen->mode_flags & SCREEN_MODE_AUTOWRAP) == 0)
  2454.     screen->column = (screen->width - 1);
  2455.   else
  2456.   {
  2457.     while (new_col >= screen->width)
  2458.     {
  2459.       Screen_CRLF (screen);
  2460.       new_col -= screen->width;
  2461.     }
  2462.     screen->column = new_col;
  2463.   }
  2464. }
  2465.  
  2466. VOID _fastcall
  2467. scroll_screen_vertically (SCREEN screen,
  2468.               int lo_row_from, int lo_col,
  2469.               int hi_row_from, int hi_col,
  2470.               int lo_row_to)
  2471. {
  2472.   RECT rect;
  2473.   int row, delta_col, hi_row_to;
  2474.   char * chars_from, * chars_to;
  2475.   SCREEN_ATTRIBUTE * attrs_from, * attrs_to;
  2476.  
  2477.   if (lo_row_to < 0)
  2478.     lo_row_to = 0;
  2479.   if (lo_row_to > MAXCOLS)
  2480.     lo_row_to = MAXCOLS;
  2481.  
  2482.   delta_col = (hi_col - lo_col);
  2483.   hi_row_to = (lo_row_to + (hi_row_from - lo_row_from));
  2484.  
  2485.   if (lo_row_from > lo_row_to)          /* Scrolling up. */
  2486.     for (row = lo_row_from,
  2487.      chars_from = &screen->chars[lo_row_from * MAXCOLS + lo_col],
  2488.      attrs_from = &screen->attrs[lo_row_from * MAXCOLS + lo_col],
  2489.      chars_to = &screen->chars[lo_row_to * MAXCOLS + lo_col],
  2490.      attrs_to = &screen->attrs[lo_row_to * MAXCOLS + lo_col];
  2491.      row < hi_row_from;
  2492.      row++,
  2493.      chars_from += MAXCOLS,
  2494.      attrs_from += MAXCOLS,
  2495.      chars_to += MAXCOLS,
  2496.      attrs_to += MAXCOLS)
  2497.     {
  2498.       _fmemmove (((LPSTR) chars_to), ((LPSTR) chars_from), delta_col);
  2499.       _fmemmove (((LPSTR) attrs_to), ((LPSTR) attrs_from), delta_col);
  2500.     }
  2501.   else                                   /* Scrolling down. */
  2502.     for (row = (hi_row_from - 1),
  2503.      chars_from =  &screen->chars[(hi_row_from - 1) * MAXCOLS + lo_col],
  2504.      attrs_from =  &screen->attrs[(hi_row_from - 1) * MAXCOLS + lo_col],
  2505.      chars_to =  &screen->chars[(hi_row_to - 1) * MAXCOLS + lo_col],
  2506.      attrs_to =  &screen->attrs[(hi_row_to - 1) * MAXCOLS + lo_col];
  2507.      row >= lo_row_from;
  2508.      row--,
  2509.      chars_from -= MAXCOLS,
  2510.      attrs_from -= MAXCOLS,
  2511.      chars_to -= MAXCOLS,
  2512.      attrs_to -= MAXCOLS)
  2513.     {
  2514.       _fmemmove (((LPSTR) chars_to), ((LPSTR) chars_from), delta_col);
  2515.       _fmemmove (((LPSTR) attrs_to), ((LPSTR) attrs_from), delta_col);
  2516.     }
  2517.  
  2518.   rect.left   = ((lo_col * screen->xChar) - screen->xOffset);
  2519.   rect.right  = ((hi_col * screen->xChar) - screen->xOffset);
  2520.   rect.top    = ((lo_row_to * screen->yChar) - screen->yOffset);
  2521.   rect.bottom = ((hi_row_to * screen->yChar) - screen->yOffset);
  2522.   InvalidateRect (screen->hWnd, &rect, FALSE);
  2523. }
  2524.  
  2525. static VOID _fastcall
  2526. scroll_screen_line_horizontally (SCREEN screen, int row,
  2527.                  int lo_col_from, int hi_col_from,
  2528.                  int lo_col_to)
  2529. {
  2530.   RECT rect;
  2531.   int delta_col = (hi_col_from - lo_col_from);
  2532.   int hi_col_to = (lo_col_to + delta_col);
  2533.  
  2534.   _fmemmove (((LPSTR) &screen->chars[(row * MAXCOLS) + lo_col_to]),
  2535.          ((LPSTR) &screen->chars[(row * MAXCOLS) + lo_col_from]),
  2536.          delta_col);
  2537.   _fmemmove (((LPSTR) &screen->attrs[(row * MAXCOLS) + lo_col_to]),
  2538.          ((LPSTR) &screen->attrs[(row * MAXCOLS) + lo_col_from]),
  2539.          delta_col);
  2540.  
  2541.   rect.left   = ((lo_col_to * screen->xChar) - screen->xOffset);
  2542.   rect.right  = ((hi_col_to * screen->xChar) - screen->xOffset);
  2543.   rect.top    = ((row * screen->yChar) - screen->yOffset);
  2544.   rect.bottom = (((row + 1) * screen->yChar) - screen->yOffset);
  2545.   InvalidateRect (screen->hWnd, &rect, FALSE);
  2546. }
  2547.  
  2548. static int _fastcall
  2549. read_decimal (LPSTR str, int lo, int len, int * hi)
  2550. {
  2551.   int ctr, result;
  2552.  
  2553.   for (result = 0, ctr = lo;
  2554.        ctr < len;
  2555.        result = ((result * 10) + ((str[ctr]) - '0')), ctr++)
  2556.     if ((str[ctr] < '0') || (str[ctr] > '9'))
  2557.       break;
  2558.  
  2559.   * hi = ctr;
  2560.   return (result);
  2561. }
  2562.  
  2563. #ifdef PRETTY_PRINT_CHARS
  2564. static VOID _fastcall
  2565. screen_write_octal (SCREEN screen, unsigned char the_char,
  2566.             struct screen_write_char_s * rectp)
  2567. {
  2568.   Screen_WriteCharUninterpreted (screen, '\\', rectp);
  2569.   Screen_WriteCharUninterpreted (screen, ((the_char / 0100) + '0'), rectp);
  2570.   Screen_WriteCharUninterpreted (screen, (((the_char % 0100) / 010) + '0'),
  2571.                  rectp);
  2572.   Screen_WriteCharUninterpreted (screen, ((the_char % 010) + '0'), rectp);
  2573. }
  2574. #endif /* PRETTY_PRINT_CHARS */
  2575.  
  2576. static VOID
  2577. WriteScreenBlock_suspend (SCREEN screen, LPSTR lpBlock, int i, int nLength)
  2578. {
  2579.   screen->n_pending = (nLength - i);
  2580.   screen->pending = ((LPSTR) (LocalAlloc (NONZEROLPTR, screen->n_pending)));
  2581.   if (screen->pending != ((LPSTR) NULL))
  2582.     strncpy (screen->pending, (lpBlock + i), screen->n_pending);
  2583.   else
  2584.   {
  2585.     screen->n_pending = 0;
  2586.     MessageBeep (0);
  2587.   }
  2588. }
  2589.  
  2590. static VOID
  2591. WriteScreenBlock_continue (SCREEN screen,
  2592.                LPSTR lpBlock_in, int nLength_in,
  2593.                LPSTR * lpBlock, int * nLength)
  2594. {
  2595.   (* nLength) = (screen->n_pending + nLength_in);
  2596.   (* lpBlock) = ((LPSTR) (LocalAlloc (NONZEROLPTR, (* nLength))));
  2597.   if ((* lpBlock) == ((LPSTR) NULL))
  2598.   {
  2599.     MessageBeep (0);
  2600.     (* nLength) = nLength_in;
  2601.     (* lpBlock) = lpBlock_in;
  2602.   }
  2603.   else
  2604.   {
  2605.     strncpy ((* lpBlock), screen->pending, screen->n_pending);
  2606.     strncpy (((* lpBlock) + screen->n_pending), lpBlock_in, nLength_in);
  2607.   }
  2608.   LocalFree (screen->pending);
  2609.   screen->n_pending = 0;
  2610. }
  2611.  
  2612. /* BOOL WriteScreenBlock (HWND hWnd, LPSTR lpBlock_in, int nLength_in )
  2613.  
  2614.    Description:
  2615.       Writes block of characters to TTY screen.  Interprets lots of ANSI
  2616.       sequences.
  2617. */
  2618.  
  2619. BOOL
  2620. WriteScreenBlock (HWND hWnd, LPSTR lpBlock_in, int nLength_in)
  2621. {
  2622.   int i;
  2623.   LPSTR lpBlock;
  2624.   int nLength;
  2625.   WORD saved_mode_flags;
  2626.   SCREEN screen = (GETSCREEN (hWnd));
  2627.   struct screen_write_char_s state;
  2628.  
  2629.   if (NULL == screen)
  2630.     return (FALSE);
  2631.  
  2632.   INIT_SCREEN_WRITE_CHAR_STATE (state);
  2633.   saved_mode_flags = (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE);
  2634.   screen->mode_flags &= (~ (SCREEN_MODE_EAGER_UPDATE));
  2635.  
  2636.   if (screen->n_pending != 0)
  2637.     WriteScreenBlock_continue (screen,
  2638.                    lpBlock_in, nLength_in,
  2639.                    &lpBlock, &nLength);
  2640.   else
  2641.   {
  2642.     nLength = nLength_in;
  2643.     lpBlock = lpBlock_in;
  2644.   }
  2645.  
  2646.   if ((screen->mode_flags & SCREEN_MODE_PROCESS_OUTPUT) == 0)
  2647.     for (i = 0; i < nLength; i++)
  2648.       Screen_WriteCharUninterpreted (screen, (lpBlock[i]), &state);
  2649.   else for (i = 0; i < nLength; i++)
  2650.   {
  2651.     unsigned char the_char = ((unsigned char) (lpBlock[i]));
  2652.  
  2653.     switch (the_char)
  2654.     {
  2655.     case ASCII_BEL:
  2656.       MessageBeep (0);
  2657.       break;
  2658.  
  2659.     case ASCII_BS:
  2660.       Screen_BS (screen);
  2661.       break;
  2662.  
  2663.     case '\t':
  2664.       Screen_TAB (screen, &state);
  2665.       break;
  2666.  
  2667.     case ASCII_LF:
  2668.       if (screen->mode_flags & SCREEN_MODE_NEWLINE_CRS)
  2669.     Screen_CR (screen);
  2670.       Finish_ScreenWriteChar (screen, &state);
  2671.       Screen_LF (screen);
  2672.       break;
  2673.  
  2674.     case ASCII_CR:
  2675.       Screen_CR (screen);
  2676.       if (screen->mode_flags & SCREEN_MODE_CR_NEWLINES)
  2677.       {
  2678.     Finish_ScreenWriteChar (screen, &state);
  2679.     Screen_LF (screen);
  2680.       }
  2681.       break;
  2682.  
  2683.     case ASCII_FF:
  2684.       Finish_ScreenWriteChar (screen, &state);
  2685.       Screen_Clear (screen, 0);
  2686.       break;
  2687.  
  2688.     default:
  2689.     char_default:
  2690. #ifdef PRETTY_PRINT_CHARS
  2691.       if (the_char < ' ')
  2692.       {
  2693.     Screen_WriteCharUninterpreted (screen, '^', &state);
  2694.     Screen_WriteCharUninterpreted (screen, (the_char + '@'), &state);
  2695.       }
  2696.       else if (the_char < ASCII_DEL)
  2697.     Screen_WriteCharUninterpreted (screen, the_char, &state);
  2698.       else if (the_char == ASCII_DEL)
  2699.       {
  2700.     Screen_WriteCharUninterpreted (screen, '^', &state);
  2701.     Screen_WriteCharUninterpreted (screen, '?', &state);
  2702.       }
  2703.       else
  2704.     screen_write_octal (screen, ((unsigned char) the_char), &state);
  2705. #else /* not PRETTY_PRINT_CHARS */
  2706.       Screen_WriteCharUninterpreted (screen, the_char, &state);
  2707. #endif /* PRETTY_PRINT_CHARS */
  2708.       break;
  2709.  
  2710.     case ASCII_ESC:
  2711.     {
  2712.       char dispatch;
  2713.  
  2714.       Finish_ScreenWriteChar (screen, &state);
  2715.       if ((i + 2) >= nLength)
  2716.       {
  2717.     WriteScreenBlock_suspend (screen, lpBlock, i, nLength);
  2718.     i = (nLength - 1);      /* 1 added in for loop */
  2719.     break;
  2720.       }
  2721.  
  2722.       if (lpBlock[i + 1] != '[')
  2723.     goto char_default;
  2724.  
  2725.       dispatch = (lpBlock[i + 2]);
  2726.       switch (dispatch)
  2727.       {
  2728.       case 'K':
  2729.     /* Clear Line */
  2730.     clear_screen_rectangle (screen,
  2731.                 screen->row, screen->column,
  2732.                 (screen->row + 1), screen->width);
  2733.     i += 2;         /* 1 added in for loop */
  2734.     continue;
  2735.  
  2736.       case 'J':
  2737.     /* Clear to bottom */
  2738.     if (screen->column == 0)
  2739.       clear_screen_rectangle (screen, screen->row, 0,
  2740.                   screen->height, screen->width);
  2741.     else
  2742.     {
  2743.       clear_screen_rectangle (screen,
  2744.                   screen->row, screen->column,
  2745.                   (screen->row + 1), screen->width);
  2746.       clear_screen_rectangle (screen, (screen->row + 1), 0,
  2747.                   screen->height, screen->width);
  2748.     }
  2749.     i += 2;         /* 1 added in for loop */
  2750.     continue;
  2751.  
  2752.       case 'H':
  2753.     /* Cursor home */
  2754.     relocate_cursor (screen, 0, 0);
  2755.     i += 2;         /* 1 added in for loop */
  2756.     continue;
  2757.  
  2758.       case 'A':
  2759.     /* Cursor up */
  2760.     relocate_cursor (screen, (screen->row - 1), screen->column);
  2761.     i += 2;         /* 1 added in for loop */
  2762.     continue;
  2763.  
  2764.       case 'C':
  2765.     /* Cursor right */
  2766.     cursor_right (screen, 1);
  2767.     i += 2;         /* 1 added in for loop */
  2768.     continue;
  2769.  
  2770.       case 'L':
  2771.     /* Insert line */
  2772.     scroll_screen_vertically (screen,
  2773.                   screen->row, screen->column,
  2774.                   (screen->height - 1), screen->width,
  2775.                   (screen->row + 1));
  2776.     clear_screen_rectangle (screen,
  2777.                 screen->row, screen->column,
  2778.                 (screen->row + 1), screen->width);
  2779.     i += 2;         /* 1 added in for loop */
  2780.     continue;
  2781.  
  2782.       case 'M':
  2783.     /* Delete line */
  2784.     scroll_screen_vertically (screen,
  2785.                   (screen->row + 1), screen->column,
  2786.                   screen->height, screen->width,
  2787.                   screen->row);
  2788.     clear_screen_rectangle (screen,
  2789.                 (screen->height - 1), screen->column,
  2790.                 screen->height, screen->width);
  2791.     i += 2;         /* 1 added in for loop */
  2792.     continue;
  2793.  
  2794.       case 'P':
  2795.     /* Delete char */
  2796.     scroll_screen_line_horizontally (screen, screen->row,
  2797.                      (screen->column + 1), screen->width,
  2798.                      screen->column);
  2799.     i += 2;
  2800.     continue;
  2801.  
  2802.       case '@':
  2803.     /* Insert char */
  2804.     scroll_screen_line_horizontally (screen, screen->row,
  2805.                      screen->column, (screen->width - 1),
  2806.                      (screen->column + 1));
  2807.     i += 2;
  2808.     continue;
  2809.  
  2810.       default:
  2811.     if ((dispatch >= '0') && (dispatch <= '9'))
  2812.     {
  2813.       int j, x_value;
  2814.  
  2815.       x_value = (read_decimal (&lpBlock[0], (i + 2), nLength, &j));
  2816.       if (j >= nLength)
  2817.       {
  2818.         WriteScreenBlock_suspend (screen, lpBlock, i, nLength);
  2819.         i = (j - 1); /* 1 added in for loop */
  2820.         continue;
  2821.       }
  2822.       else switch (lpBlock[j])
  2823.       {
  2824.         case ';':
  2825.         {
  2826.           int k, y_value;
  2827.  
  2828.           y_value = (read_decimal (&lpBlock[0], (j + 1), nLength, &k));
  2829.           if ((k < nLength) && (lpBlock[k] == 'H'))
  2830.         /* Direct cursor motion */
  2831.         relocate_cursor (screen, (x_value - 1), (y_value - 1));
  2832.           else if (k < nLength)
  2833.         MessageBeep (0);
  2834.           else
  2835.         WriteScreenBlock_suspend (screen, lpBlock, i, nLength);
  2836.           i = k;    /* 1 added in for loop */
  2837.           continue;
  2838.         }
  2839.  
  2840.         case 'A':
  2841.           /* Multi cursor up */
  2842.           relocate_cursor (screen, (screen->row - x_value),
  2843.                    screen->column);
  2844.           i = j; /* 1 added in for loop */
  2845.           continue;
  2846.  
  2847.         case 'C':
  2848.           /* Multi cursor right */
  2849.           cursor_right (screen, x_value);
  2850.           i = j; /* 1 added in for loop */
  2851.           continue;
  2852.  
  2853.         case 'L':
  2854.           /* Multi insert line */
  2855.           scroll_screen_vertically (screen,
  2856.                     screen->row, screen->column,
  2857.                     (screen->height - 1), screen->width,
  2858.                     (screen->row + x_value));
  2859.           clear_screen_rectangle (screen,
  2860.                       screen->row, screen->column,
  2861.                       (screen->row + x_value), screen->width);
  2862.           i = j; /* 1 added in for loop */
  2863.           continue;
  2864.  
  2865.         case 'M':
  2866.           /* Multi delete line */
  2867.           scroll_screen_vertically (screen,
  2868.                     (screen->row + x_value),
  2869.                     screen->column,
  2870.                     screen->height, screen->width,
  2871.                     screen->row);
  2872.           clear_screen_rectangle (screen,
  2873.                       (screen->height - x_value),
  2874.                       screen->column,
  2875.                       screen->height, screen->width);
  2876.           i = j; /* 1 added in for loop */
  2877.           continue;
  2878.  
  2879.         case 'P':
  2880.           /* Multi delete char */
  2881.           scroll_screen_line_horizontally (screen, screen->row,
  2882.                            (screen->column + x_value),
  2883.                            screen->width,
  2884.                            screen->column);
  2885.           i = j; /* 1 added in for loop */
  2886.           continue;
  2887.  
  2888.         case '@':
  2889.           /* Multi insert char */
  2890.           scroll_screen_line_horizontally (screen, screen->row,
  2891.                            screen->column,
  2892.                            (screen->width - x_value),
  2893.                            (screen->column + x_value));
  2894.           i = j; /* 1 added in for loop */
  2895.           continue;
  2896.  
  2897.         case 'm':
  2898.           if ((j == (i + 3)) && ((x_value == 0) || (x_value == 7)))
  2899.           {
  2900.         /* Enter stdout (7) or exit stdout (0) */
  2901.         screen->write_attribute = (x_value == 7);
  2902.         i = j;  /* 1 added in for loop */
  2903.         continue;
  2904.           }
  2905.           goto use_default;
  2906.  
  2907.         case 'p':
  2908.           /* Not a real ANSI escape.  Modelled after aaa. */
  2909.           if ((j == (i + 3)) && (x_value < 2))
  2910.           {
  2911.         /* Enter edwin/emacs (1) mode or exit edwin/emacs (0) mode. */
  2912.         if (x_value == 1)
  2913.         {
  2914.           screen->mode_flags |= SCREEN_MODE_EDWIN;
  2915.           screen->mode_flags &= (~ SCREEN_MODE_NEWLINE_CRS);
  2916.           screen->scroll_lines = 1;
  2917.           SetWindowText (screen->hWnd, "Edwin");
  2918.         }
  2919.         else
  2920.         {
  2921.           screen->mode_flags &= (~ SCREEN_MODE_EDWIN);
  2922.           screen->mode_flags |= SCREEN_MODE_NEWLINE_CRS;
  2923.           screen->scroll_lines
  2924.             = (COMPUTE_SCROLL_LINES (screen->height));
  2925.           SetWindowText (screen->hWnd, "MIT Scheme");
  2926.         }
  2927.         i = j;  /* 1 added in for loop */
  2928.         continue;
  2929.           }
  2930.           goto use_default;
  2931.  
  2932.         default:
  2933.         use_default:
  2934.           MessageBeep (0);
  2935.           i = j;    /* 1 added in for loop */
  2936.           continue;
  2937.       }
  2938.     }
  2939.     break;
  2940.       }
  2941.     }
  2942.     }
  2943.   }
  2944.  
  2945.   if (lpBlock != lpBlock_in)
  2946.     LocalFree (lpBlock);
  2947.  
  2948.   Finish_ScreenWriteChar (screen, &state);
  2949.   if (saved_mode_flags != 0)
  2950.   {
  2951.     UpdateWindow (screen->hWnd);
  2952.     MoveScreenCursor (screen);
  2953.     screen->mode_flags |= saved_mode_flags;
  2954.   }
  2955.   return  TRUE;
  2956. }
  2957.  
  2958. /* A fast raw write to the screen memory. */
  2959. /* Client is responsible for invalidating the correct region */
  2960.  
  2961. VOID
  2962. WriteScreenBlock_NoInvalidRect (SCREEN screen, int row, int column,
  2963.                 LPSTR lpBlock, int nLength)
  2964. {
  2965.   int i, limit, start;
  2966.  
  2967.   if (row < 0  ||  row >= MAXROWS)
  2968.     return;
  2969.  
  2970.   if (column < 0) {
  2971.     lpBlock += (- column);
  2972.     nLength += column;
  2973.     column = 0;
  2974.   }
  2975.  
  2976.   if (column + nLength >= MAXCOLS)
  2977.     limit = MAXCOLS - column;
  2978.   else
  2979.     limit = nLength;
  2980.  
  2981.   start = row * MAXCOLS + column;
  2982.   for (i = 0; i < limit; i++) {
  2983.     int place = start + i;
  2984.     screen->chars[place] = lpBlock[i];
  2985.     screen->attrs[place] = screen->write_attribute;
  2986.   }
  2987. }
  2988.  
  2989. /* Utilities for line-buffered input. */
  2990.  
  2991. static VOID
  2992. key_buffer_insert_self (SCREEN screen, int ch)
  2993. {
  2994.   if (screen->n_chars < MAX_LINEINPUT)
  2995.   {
  2996.     screen->line_buffer[screen->n_chars++] = ch;
  2997.     if (screen->mode_flags & SCREEN_MODE_ECHO)
  2998.     {
  2999.       if (ch == '\n')
  3000.     Screen_CRLF (screen);
  3001.       else
  3002.       {
  3003.     char c = ((char) ch);
  3004. #if 0
  3005.     Screen_WriteCharUninterpreted (screen, ch, NULL);
  3006. #endif
  3007.     WriteScreenBlock (screen->hWnd, &c, 1);
  3008.       }
  3009.     }
  3010.   }
  3011. }
  3012.  
  3013. static VOID
  3014. key_buffer_erase_character (SCREEN screen)
  3015. {
  3016.   if (screen->n_chars > 0)
  3017.   {
  3018.     screen->n_chars -= 1;
  3019.     if (screen->mode_flags & SCREEN_MODE_ECHO)
  3020.     {
  3021.       Screen_BS (screen);
  3022.       Screen_WriteCharUninterpreted (screen, ' ', NULL);
  3023.       Screen_BS (screen);
  3024.     }
  3025.   }
  3026. }
  3027.  
  3028. static VOID
  3029. buffered_key_command (SCREEN screen,  int ch)
  3030. {
  3031.   switch (ch)
  3032.   {
  3033.     case '\n':
  3034.     case '\r':
  3035.       key_buffer_insert_self (screen, '\n');
  3036.       break;
  3037.  
  3038.     case '\b':
  3039.     case ASCII_DEL:
  3040.       key_buffer_erase_character (screen);
  3041.       break;
  3042.  
  3043.     default:
  3044.       key_buffer_insert_self (screen, ch);
  3045.       break;
  3046.   }
  3047.   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
  3048.     UpdateWindow (screen->hWnd);
  3049. }
  3050.  
  3051. /* Line-buffered input. */
  3052.  
  3053. static int
  3054. ReadScreen_line_input (SCREEN screen, LPSTR buffer, int buflen)
  3055. {
  3056.   SCREEN_EVENT event;
  3057.   int result = (-1);            /* No EOL seen yet. */
  3058.  
  3059.   while (read_event (screen, SCREEN_EVENT_TYPE_KEY, 1, (&event)))
  3060.     {
  3061.       int ch = event.event.key.ch;
  3062.       if ((event.event.key.control_key_state & SCREEN_ANY_ALT_KEY_MASK) != 0)
  3063.     ch |= 0200;
  3064.  
  3065.       if (ch != 0)
  3066.     buffered_key_command (screen, ch);
  3067.  
  3068.       if ((ch == '\n') || (ch == '\r'))
  3069.     {
  3070.       int i, count = (min (screen->n_chars, buflen));
  3071.  
  3072.       for (i = 0; i < count; i++)
  3073.         buffer[i] = screen->line_buffer[i];
  3074.       screen->n_chars -= count;
  3075.       if (screen->n_chars > 0)
  3076.         _fmemmove (&screen->line_buffer[0],
  3077.                &screen->line_buffer[count],
  3078.                screen->n_chars);
  3079.       result = (count);
  3080.       break;
  3081.     }
  3082.     }
  3083.   return (result);
  3084. }
  3085.  
  3086. /* Untranslated/unbuffered input */
  3087.  
  3088. static int
  3089. ReadScreen_raw (SCREEN screen, LPSTR buffer, int buflen)
  3090. {
  3091.   SCREEN_EVENT event;
  3092.   int position = 0;
  3093.  
  3094.   while ((position < buflen)
  3095.      && (read_event (screen, SCREEN_EVENT_TYPE_KEY, 1, (&event))))
  3096.     {
  3097.       int ch = event.event.key.ch;
  3098.       if ((event.event.key.control_key_state & SCREEN_ANY_ALT_KEY_MASK) != 0)
  3099.     ch |= 0200;
  3100.  
  3101.       /* Store the character */
  3102.       buffer[position++] = ch;
  3103.       if (screen->mode_flags & SCREEN_MODE_ECHO)
  3104.     {
  3105.       char c = ((char) ch);
  3106.       WriteScreenBlock (screen->hWnd, &c, 1);
  3107.     }
  3108.     }
  3109.   return ((position == 0) ? -1 : position);
  3110. }
  3111.  
  3112. /* int  ReadScreen (SCREEN screen, LPSTR buffer, int buflen)
  3113.  
  3114.    Read characters into buffer.
  3115.    If in line mode, collect characters into the line buffer.
  3116.    Return the number of characters read.
  3117.    In raw mode, return -1 if there are no characters.
  3118.    If in line mode and not yet at end of line, return -1 (i.e. this
  3119.      is a non-blocking read
  3120. */
  3121.  
  3122. static int
  3123. ReadScreen (SCREEN screen, LPSTR buffer, int buflen)
  3124. {
  3125.   if (screen->mode_flags & SCREEN_MODE_LINE_INPUT)
  3126.     return (ReadScreen_line_input (screen, buffer, buflen));
  3127.   else
  3128.     return (ReadScreen_raw (screen, buffer, buflen));
  3129. }
  3130.  
  3131. VOID
  3132. Screen_Clear (SCREEN screen, int kind)
  3133. {
  3134.   if (kind == 0)
  3135.   {
  3136.     /* clear whole screen */
  3137.       ClearScreen_internal(screen);
  3138.     InvalidateRect (screen->hWnd, NULL, TRUE);
  3139.     return;
  3140.   }
  3141.   if (kind == 1)
  3142.     /* clear to eol */
  3143.     return;
  3144. }
  3145.  
  3146. /* VOID GetMinMaxSizes (HWND hWnd, LPPOINT min_size, LPPOINT max_size)
  3147.  
  3148.    Description:
  3149.       determine the minimum and maxinum sizes for a screen window.
  3150. */
  3151.  
  3152. static VOID
  3153. GetMinMaxSizes (HWND hWnd, LPPOINT min_size, LPPOINT max_size)
  3154. {
  3155.     SCREEN  screen = GETSCREEN (hWnd);
  3156.     int  extra_width, extra_height;
  3157.  
  3158.     if (screen==0) return;
  3159.     extra_width  = 2*GetSystemMetrics(SM_CXFRAME);
  3160.     extra_height = 2*GetSystemMetrics(SM_CYFRAME)
  3161.          + GetSystemMetrics(SM_CYCAPTION)
  3162.          + (GetMenu(hWnd) ? GetSystemMetrics(SM_CYMENU) : 0);
  3163.     /* The min size sould be configurable so Edwin can configure it */
  3164.     /* to prevent the window being shrunk so far that the displayed */
  3165.     /* buffers wont fit. */
  3166.     min_size->x = screen->xChar * 5  +  extra_width;
  3167.     min_size->y = screen->yChar * 3  +  extra_height;
  3168.     max_size->x = screen->xChar * MAXCOLS  +  extra_width;
  3169.     max_size->y = screen->yChar * MAXROWS  +  extra_height;
  3170. }
  3171.  
  3172. static BOOL
  3173. SelectScreenFont (SCREEN  screen,  HWND owner)
  3174. {
  3175.    CHOOSEFONT  cfTTYFont;
  3176.  
  3177.    if (NULL == screen)  return  FALSE;
  3178.  
  3179.    cfTTYFont.lStructSize    = sizeof (CHOOSEFONT);
  3180.    cfTTYFont.hwndOwner      = owner;
  3181.    cfTTYFont.hDC            = NULL;
  3182.    cfTTYFont.rgbColors      = screen->rgbFGColour;
  3183.    cfTTYFont.lpLogFont      = &screen->lfFont;
  3184.    cfTTYFont.Flags          = (
  3185.                      CF_FIXEDPITCHONLY
  3186.                    | CF_SCREENFONTS
  3187.                    | CF_EFFECTS
  3188.                    | CF_INITTOLOGFONTSTRUCT
  3189.                    );
  3190.    cfTTYFont.lCustData      = 0;
  3191.    cfTTYFont.lpfnHook       = NULL;
  3192.    cfTTYFont.lpTemplateName = NULL;
  3193.    cfTTYFont.hInstance      = (HINSTANCE) GetWindowLong(owner, GWL_HINSTANCE);
  3194.  
  3195.    if (ChooseFont (&cfTTYFont))
  3196.    {
  3197.      screen->rgbFGColour = cfTTYFont.rgbColors;
  3198.      ResetScreen (screen);
  3199.    }
  3200.    return  TRUE;
  3201. }
  3202.  
  3203. /* BOOL SelectScreenBackColor (SCREEN screen, HWND owner)
  3204.  
  3205.    Description:
  3206.       Selects the background color for the TTY screen.
  3207.       Uses the Common Dialog ChooseColor() API.
  3208. */
  3209.  
  3210. static BOOL
  3211. SelectScreenBackColor (SCREEN  screen,  HWND owner)
  3212. {
  3213.    static DWORD custcolors[16] = {
  3214.       RGB(0x00,0x00,0x00)
  3215.      ,RGB(0x80,0x00,0x00)
  3216.      ,RGB(0x00,0x80,0x00)
  3217.      ,RGB(0x80,0x80,0x00)
  3218.      ,RGB(0x00,0x00,0x80)
  3219.      ,RGB(0x80,0x00,0x80)
  3220.      ,RGB(0x00,0x80,0x80)
  3221.      ,RGB(0xC0,0xC0,0xC0)
  3222.      ,RGB(0xC0,0xDC,0xC0)
  3223.      ,RGB(0xA6,0xCA,0xF0)
  3224.      ,RGB(0xFF,0xFB,0xF0)
  3225.      ,RGB(0xA0,0xA0,0xA4)
  3226.      ,RGB(0x80,0x80,0x80)
  3227.      /* ,RGB(0xFF,0x00,0x00) */
  3228.      ,RGB(0x00,0xFF,0x00)
  3229.      ,RGB(0xFF,0xFF,0x00)
  3230.      /* ,RGB(0x00,0x00,0xFF) */
  3231.      /* ,RGB(0xFF,0x00,0xFF) */
  3232.      /* ,RGB(0x00,0xFF,0xFF) */
  3233.      ,RGB(0xFF,0xFF,0xFF)
  3234.      };
  3235.  
  3236.    CHOOSECOLOR backcolor;
  3237.  
  3238.    if (NULL == screen)
  3239.      return  FALSE;
  3240.  
  3241.    backcolor.lStructSize    = sizeof (CHOOSECOLOR);
  3242.    backcolor.hwndOwner      = owner;
  3243.    backcolor.hInstance      = (HINSTANCE) GetWindowLong(owner, GWL_HINSTANCE);
  3244.  
  3245.    backcolor.rgbResult      = screen->rgbBGColour;
  3246.    backcolor.lpCustColors   = &custcolors[0];
  3247.    backcolor.Flags          = (CC_RGBINIT);
  3248.  
  3249.    backcolor.lCustData      = 0;
  3250.    backcolor.lpfnHook       = NULL;
  3251.    backcolor.lpTemplateName = NULL;
  3252.  
  3253.    if (ChooseColor (&backcolor))
  3254.    {
  3255.      HDC hdc = GetDC (owner);
  3256.  
  3257.      /* Use GetNearestColor to ensure consistency with the background */
  3258.      /* text color. */
  3259.      screen->rgbBGColour = GetNearestColor (hdc, (backcolor.rgbResult));
  3260.      if (screen->bkgnd_brush != NULL)
  3261.        DeleteObject (screen->bkgnd_brush);
  3262.      screen->bkgnd_brush = CreateSolidBrush (screen->rgbBGColour);
  3263.      InvalidateRect (owner, NULL, TRUE);
  3264.      ReleaseDC (owner, hdc);
  3265.    }
  3266.    return  TRUE;
  3267. }
  3268.  
  3269. /* Event Queue */
  3270.  
  3271. static SCREEN_EVENT *
  3272. allocate_event (SCREEN screen, SCREEN_EVENT_TYPE type)
  3273. {
  3274.   SCREEN_EVENT_LINK * new_event;
  3275.   if (((screen -> mode_flags) & type) == 0)
  3276.     return (0);
  3277.   if (free_events == 0)
  3278.     new_event = (xmalloc (sizeof (SCREEN_EVENT_LINK)));
  3279.   else
  3280.     {
  3281.       new_event = free_events;
  3282.       free_events = (free_events -> next);
  3283.       n_free_events -= 1;
  3284.     }
  3285.   (new_event -> next) = 0;
  3286.   if (event_queue_tail == 0)
  3287.     event_queue_head = new_event;
  3288.   else
  3289.     (event_queue_tail -> next) = new_event;
  3290.   event_queue_tail = new_event;
  3291.   ((new_event -> event) . handle) = (screen -> hWnd);
  3292.   ((new_event -> event) . type) = type;
  3293.   return (& (new_event -> event));
  3294. }
  3295.  
  3296. /* read_event (screen, type, delete_p, event)
  3297.    Reads the next matching event out of the queue.
  3298.    Returns non-zero iff a matching event is found.
  3299.    If screen is non-zero, only events for that screen are considered.
  3300.    If type is non-zero, only events of that type are considered.
  3301.    If delete_p is non-zero, the event is deleted from the queue.  */
  3302.  
  3303. static int
  3304. read_event (SCREEN screen, SCREEN_EVENT_TYPE type, int delete_p,
  3305.         SCREEN_EVENT * event)
  3306. {
  3307.   SCREEN_EVENT_LINK * scan_queue = event_queue_head;
  3308.   SCREEN_EVENT_LINK * prev_queue = 0;
  3309.   while (scan_queue != 0)
  3310.     {
  3311.       if (((screen == 0)
  3312.        || (((scan_queue -> event) . handle) == (screen -> hWnd)))
  3313.       && ((type == 0) || (((scan_queue -> event) . type) == type)))
  3314.     {
  3315.       if (event != 0)
  3316.         (*event) = (scan_queue -> event);
  3317.       if (delete_p)
  3318.         {
  3319.           if (prev_queue == 0)
  3320.         {
  3321.           event_queue_head = (event_queue_head -> next);
  3322.           if (event_queue_head == 0)
  3323.             event_queue_tail = 0;
  3324.         }
  3325.           else
  3326.         {
  3327.           (prev_queue -> next) = (scan_queue -> next);
  3328.           if (event_queue_tail == scan_queue)
  3329.             event_queue_tail = prev_queue;
  3330.         }
  3331.           ((scan_queue -> event) . handle) = INVALID_HANDLE_VALUE;
  3332.           if (n_free_events < MAX_FREE_EVENTS)
  3333.         {
  3334.           (scan_queue -> next) = free_events;
  3335.           free_events = scan_queue;
  3336.           n_free_events += 1;
  3337.         }
  3338.           else
  3339.         free (scan_queue);
  3340.         }
  3341.       return (1);
  3342.     }
  3343.       else
  3344.     {
  3345.       prev_queue = scan_queue;
  3346.       scan_queue = (scan_queue -> next);
  3347.     }
  3348.     }
  3349.   return (0);
  3350. }
  3351.  
  3352. int
  3353. Screen_read_event (SCREEN_EVENT * event)
  3354. {
  3355.   int result = (read_event (0, 0, 1, event));
  3356.   if (win32_trace_level > 1)
  3357.     {
  3358.       fprintf (win32_trace_file, "Screen_read_event: result=%d\n", result);
  3359.       fflush (win32_trace_file);
  3360.     }
  3361.   return (result);
  3362. }
  3363.  
  3364. int
  3365. Screen_pending_events_p (void)
  3366. {
  3367.   return (read_event (0, 0, 0, 0));
  3368. }
  3369.  
  3370. VOID
  3371. Screen_SetAttribute (HANDLE screen, SCREEN_ATTRIBUTE sa)
  3372. {
  3373.   SendMessage (screen, SCREEN_SETATTRIBUTE, (WPARAM)sa, 0);
  3374. }
  3375.  
  3376. VOID _fastcall
  3377. Screen_SetAttributeDirect (SCREEN screen, SCREEN_ATTRIBUTE sa)
  3378. {
  3379.   screen->write_attribute = sa;
  3380. }
  3381.  
  3382. VOID
  3383. Screen_WriteChar (HANDLE screen, char ch)
  3384. {
  3385.   SendMessage (screen, SCREEN_WRITE, 1, (LPARAM)(LPSTR) &ch);
  3386. }
  3387.  
  3388. VOID
  3389. Screen_WriteText (HANDLE screen, char *string)
  3390. {
  3391.   SendMessage (screen, SCREEN_WRITE, strlen(string), (LPARAM)(LPSTR)string);
  3392. }
  3393.  
  3394. VOID
  3395. Screen_SetCursorPosition (HANDLE screen, int line, int column)
  3396. {
  3397.   SendMessage (screen, SCREEN_SETPOSITION, 0, MAKELPARAM(column,line));
  3398. }
  3399.  
  3400. VOID
  3401. Screen_SetMode (HANDLE screen, int mode)
  3402. {
  3403.   SendMessage (screen, SCREEN_SETMODES, ((WPARAM) mode), 0);
  3404. }
  3405.  
  3406. int
  3407. Screen_GetMode (HANDLE screen)
  3408. {
  3409.   return  SendMessage (screen, SCREEN_GETMODES, 0, 0);
  3410. }
  3411.  
  3412. #define SCREEN_MODE_COOKED (SCREEN_MODE_LINE_INPUT | SCREEN_MODE_ECHO)
  3413.  
  3414. int
  3415. Screen_Read (HANDLE hWnd, BOOL buffered_p, char * buffer, int buflen)
  3416. {
  3417.   int result;
  3418.   WORD input_flags;
  3419.   SCREEN screen = (GETSCREEN (hWnd));
  3420.  
  3421.   if (screen != NULL)
  3422.   {
  3423.     input_flags = (screen->mode_flags & SCREEN_MODE_COOKED);
  3424.     screen->mode_flags &= (~ SCREEN_MODE_COOKED);
  3425.     if (buffered_p)
  3426.       screen->mode_flags |= SCREEN_MODE_COOKED;
  3427.   }
  3428.  
  3429.   result = (SendMessage (hWnd, SCREEN_READ,
  3430.              ((WPARAM) buflen), ((LPARAM) buffer)));
  3431.  
  3432.   if (screen != NULL)
  3433.   {
  3434.     screen->mode_flags &= (~ SCREEN_MODE_COOKED);
  3435.     screen->mode_flags |= input_flags;
  3436.   }
  3437.  
  3438.   return  result;
  3439. }
  3440.  
  3441. VOID
  3442. Screen_GetSize (HWND hWnd, int *rows, int *columns)
  3443. {
  3444.   SCREEN  screen = GETSCREEN (hWnd);
  3445.   if (screen == 0)
  3446.     return;
  3447.   *rows    = screen->height;
  3448.   *columns = screen->width;
  3449. }
  3450.  
  3451. VOID
  3452. Screen_CR_to_RECT (RECT * rect, SCREEN screen,
  3453.            int lo_row, int lo_col,
  3454.            int hi_row, int hi_col)
  3455. {
  3456.   rect->left   = ((lo_col * screen->xChar) - screen->xOffset);
  3457.   rect->right  = ((hi_col * screen->xChar) - screen->xOffset);
  3458.   rect->top    = ((lo_row * screen->yChar) - screen->yOffset);
  3459.   rect->bottom = ((hi_row * screen->yChar) - screen->yOffset);
  3460. }
  3461.  
  3462. VOID
  3463. Enable_Cursor (SCREEN screen, BOOL show)
  3464. {
  3465.   ScreenCurrentFocus();
  3466.   if (show) {
  3467.     if (!screen->cursor_visible) {
  3468.       screen->cursor_visible = TRUE;
  3469.       if (screen && screen == screen_focus)
  3470.     ShowCaret (screen->hWnd);
  3471.     }
  3472.   } else {
  3473.     if (screen->cursor_visible) {
  3474.       screen->cursor_visible = FALSE;
  3475.       if (screen && screen == screen_focus)
  3476.     HideCaret (screen->hWnd);
  3477.     }
  3478.   }
  3479. }
  3480.  
  3481. HICON
  3482. ScreenSetIcon(SCREEN screen, HICON hIcon)
  3483. {
  3484.   HICON  result = screen->hIcon;
  3485.   screen->hIcon = hIcon;
  3486.   return  result;
  3487. }
  3488.  
  3489. BOOL
  3490. ScreenSetDefaultFont (char *description)
  3491. {
  3492.   LOGFONT lf;
  3493.   HFONT hfont;
  3494.  
  3495.   /* modify default name & size, but undo characteristics */
  3496.   lf = lfDefaultLogFont;
  3497.   (lf . lfWeight) = FW_NORMAL;
  3498.   (lf . lfItalic) = FALSE;
  3499.   (lf . lfUnderline) = FALSE;
  3500.   (lf . lfStrikeOut) = FALSE;
  3501.   hfont = (set_font_1 (description, (&lf)));
  3502.   if (hfont == NULL)
  3503.     return (FALSE);
  3504.   else
  3505.     {
  3506.       DeleteObject (hfont);
  3507.       lfDefaultLogFont = lf;
  3508.       return (TRUE);
  3509.     }
  3510. }
  3511.  
  3512. BOOL
  3513. ScreenSetFont (SCREEN screen, char *description)
  3514. {
  3515.   LOGFONT lf;
  3516.   HFONT hfont;
  3517.  
  3518.   init_LOGFONT (&lf);
  3519.   hfont = (set_font_1 (description, (&lf)));
  3520.   if (hfont == NULL)
  3521.     return (FALSE);
  3522.   else
  3523.     {
  3524.       (screen -> hFont) = hfont;
  3525.       (screen -> lfFont) = lf;
  3526.       ResetScreen (screen);
  3527.       return (TRUE);
  3528.     }
  3529. }
  3530.  
  3531. static HFONT
  3532. set_font_1 (char * description, LOGFONT * lf)
  3533. {
  3534.   HFONT hfont = NULL;
  3535.   if (parse_logfont (description, lf))
  3536.     {
  3537.       (void) search_for_font (lf);
  3538.       hfont = (CreateFontIndirect (lf));
  3539.     }
  3540.   return (hfont);
  3541. }
  3542.  
  3543. static BOOL
  3544. parse_logfont (char * name, LOGFONT * lf)
  3545. {
  3546.   int i = 0;
  3547.   int name_ended = 0;
  3548.   int number_p;
  3549.   int len;
  3550.   char * start = name;
  3551.   char * end = name;
  3552.   char * scan;
  3553.  
  3554.   while (1)
  3555.     {
  3556.       while ((*start) == ' ')
  3557.     start += 1;
  3558.       if ((*start) == '\0')
  3559.     return (TRUE);
  3560.       end = start;
  3561.       while (((*end) != ' ') && ((*end) != '\0'))
  3562.     end += 1;
  3563.       len = (end - start);
  3564.       scan = start;
  3565.       number_p = 0;
  3566.       if (scan < end)
  3567.     while (1)
  3568.       {
  3569.         if (scan == end)
  3570.           {
  3571.         number_p = 1;
  3572.         break;
  3573.           }
  3574.         if (! (((*scan) >= '0') && ((*scan) <= '9')))
  3575.           {
  3576.         number_p = 0;
  3577.         break;
  3578.           }
  3579.         scan += 1;
  3580.       }
  3581.       if (number_p)
  3582.     {
  3583.       long points = (atol (start));
  3584.       (lf -> lfHeight) = (- (points_to_logical_units (points)));
  3585.       name_ended = 1;
  3586.     }
  3587.       else if ((len == 4) && ((_strnicmp (start, "bold", len)) == 0))
  3588.     {
  3589.       (lf -> lfWeight) = FW_BOLD;
  3590.       name_ended = 1;
  3591.     }
  3592.       else if ((len == 6) && ((_strnicmp (start, "italic", len)) == 0))
  3593.     {
  3594.       (lf -> lfItalic) = TRUE;
  3595.       name_ended = 1;
  3596.     }
  3597.       else if ((len == 7) && ((_strnicmp (start, "regular", len)) == 0))
  3598.     {
  3599.       (lf -> lfWeight) = FW_NORMAL;
  3600.       (lf -> lfItalic) = FALSE;
  3601.       name_ended = 1;
  3602.     }
  3603.       else if ((len == 9) && ((_strnicmp (start, "underline", len)) == 0))
  3604.     {
  3605.       (lf -> lfUnderline) = TRUE;
  3606.       name_ended = 1;
  3607.     }
  3608.       else if ((len == 9) && ((_strnicmp (start, "strikeout", len)) == 0))
  3609.     {
  3610.       (lf -> lfStrikeOut) = TRUE;
  3611.       name_ended = 1;
  3612.     }
  3613.       else if ((len < (LF_FACESIZE - i)) && (!name_ended))
  3614.     {
  3615.       if (i > 0)
  3616.         ((lf -> lfFaceName) [i++]) = ' ';
  3617.       while (start < end)
  3618.         ((lf -> lfFaceName) [i++]) = (*start++);
  3619.       ((lf -> lfFaceName) [i]) = '\0';
  3620.     }
  3621.       else
  3622.     return (FALSE);
  3623.       start = end;
  3624.     }
  3625. }
  3626.  
  3627. static long
  3628. points_to_logical_units (long points)
  3629. {
  3630.   HDC hdc = (CreateDC ("DISPLAY", NULL, NULL, NULL));
  3631.   float pixels_per_inch_y = ((float) (GetDeviceCaps (hdc, LOGPIXELSY)));
  3632.   float pixels = ((((float) points) / 72.0) * pixels_per_inch_y);
  3633.   POINT pt;
  3634.   (pt . x) = 0;
  3635.   (pt . y) = ((int) (pixels * 10.0));
  3636.   DPtoLP (hdc, (&pt), 1);
  3637.   DeleteDC (hdc);
  3638.   return ((pt . y) / 10);
  3639. }
  3640.  
  3641. struct enum_font_args
  3642. {
  3643.   LOGFONT * lf;
  3644.   ENUMLOGFONT elf;
  3645.   BOOL foundp;
  3646. };
  3647.  
  3648. static BOOL
  3649. search_for_font (LOGFONT * lf)
  3650. {
  3651.   HDC hdc = (CreateDC ("DISPLAY", NULL, NULL, NULL));
  3652.   struct enum_font_args args;
  3653.   (args . lf) = lf;
  3654.   (args . foundp) = FALSE;
  3655.   (void) EnumFontFamilies (hdc,
  3656.                (lf -> lfFaceName),
  3657.                search_for_font_proc,
  3658.                ((LPARAM) (&args)));
  3659.   if (args . foundp)
  3660.     (*lf) = (args . elf . elfLogFont);
  3661.   DeleteDC (hdc);
  3662.   return (args . foundp);
  3663. }
  3664.  
  3665. static int CALLBACK
  3666. search_for_font_proc (ENUMLOGFONT * elf, NEWTEXTMETRIC * ntm, int type,
  3667.               LPARAM a)
  3668. {
  3669.   struct enum_font_args * args = ((struct enum_font_args *) a);
  3670.   if ((((elf -> elfLogFont) . lfHeight) == (- (args -> lf -> lfHeight)))
  3671.       && (((elf -> elfLogFont) . lfWeight) == (args -> lf -> lfWeight))
  3672.       && (((elf -> elfLogFont) . lfItalic) == (args -> lf -> lfItalic))
  3673.       && (((elf -> elfLogFont) . lfUnderline) == (args -> lf -> lfUnderline))
  3674.       && (((elf -> elfLogFont) . lfStrikeOut) == (args -> lf -> lfStrikeOut)))
  3675.     {
  3676.       (args -> elf) = (*elf);
  3677.       (args -> foundp) = TRUE;
  3678.       return (0);
  3679.     }
  3680.   else
  3681.     return (1);
  3682. }
  3683.  
  3684. static BOOL
  3685. change_colour (SCREEN screen, DWORD requested_colour, DWORD *colour_slot)
  3686. {
  3687.   HWND hWnd = screen->hWnd;
  3688.   HDC hdc = GetDC (hWnd);
  3689.   COLORREF actual_colour = GetNearestColor (hdc, requested_colour);
  3690.   if (actual_colour == CLR_INVALID) {
  3691.     ReleaseDC (hWnd, hdc);
  3692.     return  FALSE;
  3693.   }
  3694.   *colour_slot = actual_colour;
  3695.  
  3696.   /* Redraw screen with new colours */
  3697.   if (screen->bkgnd_brush != NULL)
  3698.     DeleteObject (screen->bkgnd_brush);
  3699.   screen->bkgnd_brush = CreateSolidBrush (screen->rgbBGColour);
  3700.   InvalidateRect (hWnd, NULL, TRUE);
  3701.   ReleaseDC (hWnd, hdc);
  3702.  
  3703.   return  TRUE;
  3704. }
  3705.  
  3706. BOOL
  3707. ScreenSetForegroundColour (SCREEN screen, DWORD colour)
  3708. {
  3709.   return  change_colour (screen, colour, &screen->rgbFGColour);
  3710. }
  3711.  
  3712. BOOL
  3713. ScreenSetBackgroundColour (SCREEN screen, DWORD colour)
  3714. {
  3715.   return  change_colour (screen, colour, &screen->rgbBGColour);
  3716. }
  3717.  
  3718. static const char *
  3719. translate_message_code (UINT uMsg)
  3720. {
  3721.   switch (uMsg)
  3722.     {
  3723.     case WM_NULL: return ("WM_NULL");
  3724.     case WM_CREATE: return ("WM_CREATE");
  3725.     case WM_DESTROY: return ("WM_DESTROY");
  3726.     case WM_MOVE: return ("WM_MOVE");
  3727.     case WM_SIZE: return ("WM_SIZE");
  3728.     case WM_ACTIVATE: return ("WM_ACTIVATE");
  3729.     case WM_SETFOCUS: return ("WM_SETFOCUS");
  3730.     case WM_KILLFOCUS: return ("WM_KILLFOCUS");
  3731.     case WM_ENABLE: return ("WM_ENABLE");
  3732.     case WM_SETREDRAW: return ("WM_SETREDRAW");
  3733.     case WM_SETTEXT: return ("WM_SETTEXT");
  3734.     case WM_GETTEXT: return ("WM_GETTEXT");
  3735.     case WM_GETTEXTLENGTH: return ("WM_GETTEXTLENGTH");
  3736.     case WM_PAINT: return ("WM_PAINT");
  3737.     case WM_CLOSE: return ("WM_CLOSE");
  3738.     case WM_QUERYENDSESSION: return ("WM_QUERYENDSESSION");
  3739.     case WM_QUIT: return ("WM_QUIT");
  3740.     case WM_QUERYOPEN: return ("WM_QUERYOPEN");
  3741.     case WM_ERASEBKGND: return ("WM_ERASEBKGND");
  3742.     case WM_SYSCOLORCHANGE: return ("WM_SYSCOLORCHANGE");
  3743.     case WM_ENDSESSION: return ("WM_ENDSESSION");
  3744.     case WM_SHOWWINDOW: return ("WM_SHOWWINDOW");
  3745.     case WM_WININICHANGE: return ("WM_WININICHANGE");
  3746.     case WM_DEVMODECHANGE: return ("WM_DEVMODECHANGE");
  3747.     case WM_ACTIVATEAPP: return ("WM_ACTIVATEAPP");
  3748.     case WM_FONTCHANGE: return ("WM_FONTCHANGE");
  3749.     case WM_TIMECHANGE: return ("WM_TIMECHANGE");
  3750.     case WM_CANCELMODE: return ("WM_CANCELMODE");
  3751.     case WM_SETCURSOR: return ("WM_SETCURSOR");
  3752.     case WM_MOUSEACTIVATE: return ("WM_MOUSEACTIVATE");
  3753.     case WM_CHILDACTIVATE: return ("WM_CHILDACTIVATE");
  3754.     case WM_QUEUESYNC: return ("WM_QUEUESYNC");
  3755.     case WM_GETMINMAXINFO: return ("WM_GETMINMAXINFO");
  3756.     case WM_PAINTICON: return ("WM_PAINTICON");
  3757.     case WM_ICONERASEBKGND: return ("WM_ICONERASEBKGND");
  3758.     case WM_NEXTDLGCTL: return ("WM_NEXTDLGCTL");
  3759.     case WM_SPOOLERSTATUS: return ("WM_SPOOLERSTATUS");
  3760.     case WM_DRAWITEM: return ("WM_DRAWITEM");
  3761.     case WM_MEASUREITEM: return ("WM_MEASUREITEM");
  3762.     case WM_DELETEITEM: return ("WM_DELETEITEM");
  3763.     case WM_VKEYTOITEM: return ("WM_VKEYTOITEM");
  3764.     case WM_CHARTOITEM: return ("WM_CHARTOITEM");
  3765.     case WM_SETFONT: return ("WM_SETFONT");
  3766.     case WM_GETFONT: return ("WM_GETFONT");
  3767.     case WM_SETHOTKEY: return ("WM_SETHOTKEY");
  3768.     case WM_GETHOTKEY: return ("WM_GETHOTKEY");
  3769.     case WM_QUERYDRAGICON: return ("WM_QUERYDRAGICON");
  3770.     case WM_COMPAREITEM: return ("WM_COMPAREITEM");
  3771.     case WM_COMPACTING: return ("WM_COMPACTING");
  3772.     case WM_COMMNOTIFY: return ("WM_COMMNOTIFY");
  3773.     case WM_WINDOWPOSCHANGING: return ("WM_WINDOWPOSCHANGING");
  3774.     case WM_WINDOWPOSCHANGED: return ("WM_WINDOWPOSCHANGED");
  3775.     case WM_POWER: return ("WM_POWER");
  3776.     case WM_COPYDATA: return ("WM_COPYDATA");
  3777.     case WM_CANCELJOURNAL: return ("WM_CANCELJOURNAL");
  3778.     case WM_NCCREATE: return ("WM_NCCREATE");
  3779.     case WM_NCDESTROY: return ("WM_NCDESTROY");
  3780.     case WM_NCCALCSIZE: return ("WM_NCCALCSIZE");
  3781.     case WM_NCHITTEST: return ("WM_NCHITTEST");
  3782.     case WM_NCPAINT: return ("WM_NCPAINT");
  3783.     case WM_NCACTIVATE: return ("WM_NCACTIVATE");
  3784.     case WM_GETDLGCODE: return ("WM_GETDLGCODE");
  3785.     case WM_NCMOUSEMOVE: return ("WM_NCMOUSEMOVE");
  3786.     case WM_NCLBUTTONDOWN: return ("WM_NCLBUTTONDOWN");
  3787.     case WM_NCLBUTTONUP: return ("WM_NCLBUTTONUP");
  3788.     case WM_NCLBUTTONDBLCLK: return ("WM_NCLBUTTONDBLCLK");
  3789.     case WM_NCRBUTTONDOWN: return ("WM_NCRBUTTONDOWN");
  3790.     case WM_NCRBUTTONUP: return ("WM_NCRBUTTONUP");
  3791.     case WM_NCRBUTTONDBLCLK: return ("WM_NCRBUTTONDBLCLK");
  3792.     case WM_NCMBUTTONDOWN: return ("WM_NCMBUTTONDOWN");
  3793.     case WM_NCMBUTTONUP: return ("WM_NCMBUTTONUP");
  3794.     case WM_NCMBUTTONDBLCLK: return ("WM_NCMBUTTONDBLCLK");
  3795.     case WM_KEYDOWN: return ("WM_KEYDOWN");
  3796.     case WM_KEYUP: return ("WM_KEYUP");
  3797.     case WM_CHAR: return ("WM_CHAR");
  3798.     case WM_DEADCHAR: return ("WM_DEADCHAR");
  3799.     case WM_SYSKEYDOWN: return ("WM_SYSKEYDOWN");
  3800.     case WM_SYSKEYUP: return ("WM_SYSKEYUP");
  3801.     case WM_SYSCHAR: return ("WM_SYSCHAR");
  3802.     case WM_SYSDEADCHAR: return ("WM_SYSDEADCHAR");
  3803.     case WM_KEYLAST: return ("WM_KEYLAST");
  3804.     case WM_INITDIALOG: return ("WM_INITDIALOG");
  3805.     case WM_COMMAND: return ("WM_COMMAND");
  3806.     case WM_SYSCOMMAND: return ("WM_SYSCOMMAND");
  3807.     case WM_TIMER: return ("WM_TIMER");
  3808.     case WM_HSCROLL: return ("WM_HSCROLL");
  3809.     case WM_VSCROLL: return ("WM_VSCROLL");
  3810.     case WM_INITMENU: return ("WM_INITMENU");
  3811.     case WM_INITMENUPOPUP: return ("WM_INITMENUPOPUP");
  3812.     case WM_MENUSELECT: return ("WM_MENUSELECT");
  3813.     case WM_MENUCHAR: return ("WM_MENUCHAR");
  3814.     case WM_ENTERIDLE: return ("WM_ENTERIDLE");
  3815.     case WM_CTLCOLORMSGBOX: return ("WM_CTLCOLORMSGBOX");
  3816.     case WM_CTLCOLOREDIT: return ("WM_CTLCOLOREDIT");
  3817.     case WM_CTLCOLORLISTBOX: return ("WM_CTLCOLORLISTBOX");
  3818.     case WM_CTLCOLORBTN: return ("WM_CTLCOLORBTN");
  3819.     case WM_CTLCOLORDLG: return ("WM_CTLCOLORDLG");
  3820.     case WM_CTLCOLORSCROLLBAR: return ("WM_CTLCOLORSCROLLBAR");
  3821.     case WM_CTLCOLORSTATIC: return ("WM_CTLCOLORSTATIC");
  3822.     case WM_MOUSEMOVE: return ("WM_MOUSEMOVE");
  3823.     case WM_LBUTTONDOWN: return ("WM_LBUTTONDOWN");
  3824.     case WM_LBUTTONUP: return ("WM_LBUTTONUP");
  3825.     case WM_LBUTTONDBLCLK: return ("WM_LBUTTONDBLCLK");
  3826.     case WM_RBUTTONDOWN: return ("WM_RBUTTONDOWN");
  3827.     case WM_RBUTTONUP: return ("WM_RBUTTONUP");
  3828.     case WM_RBUTTONDBLCLK: return ("WM_RBUTTONDBLCLK");
  3829.     case WM_MBUTTONDOWN: return ("WM_MBUTTONDOWN");
  3830.     case WM_MBUTTONUP: return ("WM_MBUTTONUP");
  3831.     case WM_MBUTTONDBLCLK: return ("WM_MBUTTONDBLCLK");
  3832.     case WM_PARENTNOTIFY: return ("WM_PARENTNOTIFY");
  3833.     case WM_ENTERMENULOOP: return ("WM_ENTERMENULOOP");
  3834.     case WM_EXITMENULOOP: return ("WM_EXITMENULOOP");
  3835.     case WM_MDICREATE: return ("WM_MDICREATE");
  3836.     case WM_MDIDESTROY: return ("WM_MDIDESTROY");
  3837.     case WM_MDIACTIVATE: return ("WM_MDIACTIVATE");
  3838.     case WM_MDIRESTORE: return ("WM_MDIRESTORE");
  3839.     case WM_MDINEXT: return ("WM_MDINEXT");
  3840.     case WM_MDIMAXIMIZE: return ("WM_MDIMAXIMIZE");
  3841.     case WM_MDITILE: return ("WM_MDITILE");
  3842.     case WM_MDICASCADE: return ("WM_MDICASCADE");
  3843.     case WM_MDIICONARRANGE: return ("WM_MDIICONARRANGE");
  3844.     case WM_MDIGETACTIVE: return ("WM_MDIGETACTIVE");
  3845.     case WM_MDISETMENU: return ("WM_MDISETMENU");
  3846.     case WM_ENTERSIZEMOVE: return ("WM_ENTERSIZEMOVE");
  3847.     case WM_EXITSIZEMOVE: return ("WM_EXITSIZEMOVE");
  3848.     case WM_DROPFILES: return ("WM_DROPFILES");
  3849.     case WM_MDIREFRESHMENU: return ("WM_MDIREFRESHMENU");
  3850.     case WM_CUT: return ("WM_CUT");
  3851.     case WM_COPY: return ("WM_COPY");
  3852.     case WM_PASTE: return ("WM_PASTE");
  3853.     case WM_CLEAR: return ("WM_CLEAR");
  3854.     case WM_UNDO: return ("WM_UNDO");
  3855.     case WM_RENDERFORMAT: return ("WM_RENDERFORMAT");
  3856.     case WM_RENDERALLFORMATS: return ("WM_RENDERALLFORMATS");
  3857.     case WM_DESTROYCLIPBOARD: return ("WM_DESTROYCLIPBOARD");
  3858.     case WM_DRAWCLIPBOARD: return ("WM_DRAWCLIPBOARD");
  3859.     case WM_PAINTCLIPBOARD: return ("WM_PAINTCLIPBOARD");
  3860.     case WM_VSCROLLCLIPBOARD: return ("WM_VSCROLLCLIPBOARD");
  3861.     case WM_SIZECLIPBOARD: return ("WM_SIZECLIPBOARD");
  3862.     case WM_ASKCBFORMATNAME: return ("WM_ASKCBFORMATNAME");
  3863.     case WM_CHANGECBCHAIN: return ("WM_CHANGECBCHAIN");
  3864.     case WM_HSCROLLCLIPBOARD: return ("WM_HSCROLLCLIPBOARD");
  3865.     case WM_QUERYNEWPALETTE: return ("WM_QUERYNEWPALETTE");
  3866.     case WM_PALETTEISCHANGING: return ("WM_PALETTEISCHANGING");
  3867.     case WM_PALETTECHANGED: return ("WM_PALETTECHANGED");
  3868.     case WM_HOTKEY: return ("WM_HOTKEY");
  3869.     case WM_PENWINFIRST: return ("WM_PENWINFIRST");
  3870.     case WM_PENWINLAST: return ("WM_PENWINLAST");
  3871.  
  3872. #if(WINVER >= 0x0400)
  3873.     case WM_NOTIFY: return ("WM_NOTIFY");
  3874.     case WM_INPUTLANGCHANGEREQUEST: return ("WM_INPUTLANGCHANGEREQUEST");
  3875.     case WM_INPUTLANGCHANGE: return ("WM_INPUTLANGCHANGE");
  3876.     case WM_TCARD: return ("WM_TCARD");
  3877.     case WM_HELP: return ("WM_HELP");
  3878.     case WM_USERCHANGED: return ("WM_USERCHANGED");
  3879.     case WM_NOTIFYFORMAT: return ("WM_NOTIFYFORMAT");
  3880.     case WM_CONTEXTMENU: return ("WM_CONTEXTMENU");
  3881.     case WM_STYLECHANGING: return ("WM_STYLECHANGING");
  3882.     case WM_STYLECHANGED: return ("WM_STYLECHANGED");
  3883.     case WM_DISPLAYCHANGE: return ("WM_DISPLAYCHANGE");
  3884.     case WM_GETICON: return ("WM_GETICON");
  3885.     case WM_SETICON: return ("WM_SETICON");
  3886.     case WM_IME_STARTCOMPOSITION: return ("WM_IME_STARTCOMPOSITION");
  3887.     case WM_IME_ENDCOMPOSITION: return ("WM_IME_ENDCOMPOSITION");
  3888.     case WM_IME_COMPOSITION: return ("WM_IME_COMPOSITION");
  3889.     case WM_NEXTMENU: return ("WM_NEXTMENU");
  3890.     case WM_SIZING: return ("WM_SIZING");
  3891.     case WM_CAPTURECHANGED: return ("WM_CAPTURECHANGED");
  3892.     case WM_MOVING: return ("WM_MOVING");
  3893.     case WM_POWERBROADCAST: return ("WM_POWERBROADCAST");
  3894.     case WM_DEVICECHANGE: return ("WM_DEVICECHANGE");
  3895.     case WM_IME_SETCONTEXT: return ("WM_IME_SETCONTEXT");
  3896.     case WM_IME_NOTIFY: return ("WM_IME_NOTIFY");
  3897.     case WM_IME_CONTROL: return ("WM_IME_CONTROL");
  3898.     case WM_IME_COMPOSITIONFULL: return ("WM_IME_COMPOSITIONFULL");
  3899.     case WM_IME_SELECT: return ("WM_IME_SELECT");
  3900.     case WM_IME_CHAR: return ("WM_IME_CHAR");
  3901.     case WM_IME_KEYDOWN: return ("WM_IME_KEYDOWN");
  3902.     case WM_IME_KEYUP: return ("WM_IME_KEYUP");
  3903.     case WM_PRINT: return ("WM_PRINT");
  3904.     case WM_PRINTCLIENT: return ("WM_PRINTCLIENT");
  3905.     case WM_HANDHELDFIRST: return ("WM_HANDHELDFIRST");
  3906.     case WM_HANDHELDLAST: return ("WM_HANDHELDLAST");
  3907.     case WM_AFXFIRST: return ("WM_AFXFIRST");
  3908.     case WM_AFXLAST: return ("WM_AFXLAST");
  3909.     case WM_APP: return ("WM_APP");
  3910. #endif /* WINVER >= 0x0400 */
  3911.     case SCREEN_WRITE: return ("SCREEN_WRITE");
  3912.     case SCREEN_SETPOSITION: return ("SCREEN_SETPOSITION");
  3913.     case SCREEN_GETPOSITION: return ("SCREEN_GETPOSITION");
  3914.     case SCREEN_SETATTRIBUTE: return ("SCREEN_SETATTRIBUTE");
  3915.     case SCREEN_GETATTRIBUTE: return ("SCREEN_GETATTRIBUTE");
  3916.     case SCREEN_PEEKEVENT: return ("SCREEN_PEEKEVENT");
  3917.     case SCREEN_READEVENT: return ("SCREEN_READEVENT");
  3918.     case SCREEN_SETMODES: return ("SCREEN_SETMODES");
  3919.     case SCREEN_GETMODES: return ("SCREEN_GETMODES");
  3920.     case SCREEN_SETCOMMAND: return ("SCREEN_SETCOMMAND");
  3921.     case SCREEN_GETCOMMAND: return ("SCREEN_GETCOMMAND");
  3922.     case SCREEN_SETBINDING: return ("SCREEN_SETBINDING");
  3923.     case SCREEN_GETBINDING: return ("SCREEN_GETBINDING");
  3924.     case SCREEN_SETMENU: return ("SCREEN_SETMENU");
  3925.     case SCREEN_READ: return ("SCREEN_READ");
  3926.     case SCREEN_CLEAR: return ("SCREEN_CLEAR");
  3927.     case WM_CATATONIC: return ("WM_CATATONIC");
  3928.     case WM_SCHEME_INTERRUPT: return ("WM_SCHEME_INTERRUPT");
  3929.     default: return (0);
  3930.     }
  3931. }
  3932.