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 / os2pmcon.c < prev    next >
C/C++ Source or Header  |  2000-12-05  |  34KB  |  1,199 lines

  1. /* -*-C-*-
  2.  
  3. $Id: os2pmcon.c,v 1.26 2000/12/05 21:23:46 cph Exp $
  4.  
  5. Copyright (c) 1994-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. #define INCL_WIN
  23. #include "os2.h"
  24. #include "os2pmcon.h"
  25.  
  26. /* For the "about" dialog box.  */
  27. #include "version.h"
  28.  
  29. /* #define CONSOLE_WRAP */
  30.  
  31. static void grab_console_lock (void);
  32. static void release_console_lock (void);
  33. static unsigned short cx2x (unsigned short);
  34. static unsigned short cy2y (unsigned short, int);
  35. static unsigned short x2cx (short, int);
  36. static unsigned short y2cy (short, int);
  37. static void process_events (int);
  38. static void initialize_marked_region (short, short);
  39. static void update_marked_region (short, short);
  40. static void unmark_marked_region (void);
  41. static int marked_region_nonempty_p (void);
  42. static char * extract_marked_region (int);
  43. static void compute_marked_region
  44.   (short, short, short, short,
  45.    unsigned short *, unsigned short *, unsigned short *, unsigned short *);
  46. static void highlight_marked_region
  47.   (unsigned short, unsigned short, unsigned short, unsigned short, char);
  48. static void paint_marked_region_segment
  49.   (unsigned short, unsigned short, unsigned short, unsigned short);
  50. static void disable_marked_region (void);
  51. static void enable_menu_copy_items (int);
  52. static void console_resize (unsigned short, unsigned short);
  53. static void console_paint
  54.   (unsigned short, unsigned short, unsigned short, unsigned short);
  55. static unsigned short compute_run_length (const char *, const char *);
  56. static void console_clear
  57.   (unsigned short, unsigned short, unsigned short, unsigned short);
  58. static void console_clear_all (void);
  59. static int do_paste (void);
  60. static int translate_key_event
  61.   (MPARAM, MPARAM, unsigned short *, unsigned char *);
  62. static const char * find_nonprint (const char *, const char *);
  63. static void do_carriage_return (void);
  64. static void do_linefeed (void);
  65. static unsigned short find_invalid_line (unsigned short, unsigned short);
  66. static void do_formfeed (void);
  67. static void do_backspace (void);
  68. static void do_alert (void);
  69.  
  70. static HMTX console_lock;
  71. static unsigned short console_pel_width;
  72. static unsigned short console_pel_height;
  73. static unsigned short console_width;
  74. static unsigned short console_height;
  75. static char * console_chars;
  76. static char * console_highlights;
  77. static unsigned short * console_line_lengths;
  78. static font_metrics_t * console_metrics;
  79. static unsigned short point_x;
  80. static unsigned short point_y;
  81. static int console_visiblep;
  82. static int console_closedp;
  83. static unsigned short readahead_repeat;
  84. static char readahead_char;
  85. static const char * readahead_insert;
  86. static const char * readahead_insert_scan;
  87. static void * pending_events;
  88. static tqueue_t * console_tqueue;
  89. static qid_t console_event_qid;
  90. static qid_t console_pm_qid;
  91. static wid_t console_wid;
  92. static psid_t console_psid;
  93. static int console_tracking_mouse_p;
  94. static HWND console_tracking_mouse_pointer;
  95. static int console_marked_region_active_p;
  96. static HWND console_menu;
  97. static short console_mark_x;
  98. static short console_mark_y;
  99. static short console_point_x;
  100. static short console_point_y;
  101.  
  102. static const char * console_font_specs [] =
  103.   { "8.Courier", "10.Courier", "12.Courier", 
  104.     "4.System VIO", "10.System Monospaced" };
  105.  
  106. #define CHAR_WIDTH (FONT_METRICS_WIDTH (console_metrics))
  107. #define CHAR_HEIGHT (FONT_METRICS_HEIGHT (console_metrics))
  108. #define CHAR_DESCENDER (FONT_METRICS_DESCENDER (console_metrics))
  109. #define CHAR_LOC(x, y) (& (console_chars [((y) * console_width) + (x)]))
  110. #define CHAR_HL(x, y) (& (console_highlights [((y) * console_width) + (x)]))
  111. #define LINE_LEN_LOC(y) ((char *) (& (console_line_lengths [(y)])))
  112.  
  113. #define FASTFILL(p, n, c)                        \
  114. {                                    \
  115.   char * FASTFILL_scan = (p);                        \
  116.   char * FASTFILL_end = (FASTFILL_scan + (n));                \
  117.   while (FASTFILL_scan < FASTFILL_end)                    \
  118.     (*FASTFILL_scan++) = (c);                        \
  119. }
  120.  
  121. void
  122. OS2_initialize_pm_console (void)
  123. {
  124.   console_lock = (OS2_create_mutex_semaphore (0, 0));
  125.   console_pel_width = 0;
  126.   console_pel_height = 0;
  127.   console_width = 0;
  128.   console_height = 0;
  129.   console_chars = 0;
  130.   console_highlights = 0;
  131.   console_line_lengths = 0;
  132.   point_x = 0;
  133.   point_y = 0;
  134.   console_visiblep = 0;
  135.   console_closedp = 0;
  136.   console_tracking_mouse_p = 0;
  137.   console_tracking_mouse_pointer
  138.     = (WinQuerySysPointer (HWND_DESKTOP, SPTR_TEXT, FALSE));
  139.   readahead_repeat = 0;
  140.   readahead_insert = 0;
  141.   pending_events = (OS2_create_msg_fifo ());
  142.   console_tqueue = (OS2_make_std_tqueue ());
  143.   {
  144.     qid_t remote;
  145.     OS2_make_qid_pair ((&console_event_qid), (&remote));
  146.     OS2_open_qid (console_event_qid, console_tqueue);
  147.     console_pm_qid = (OS2_create_pm_qid (console_tqueue));
  148.     console_wid
  149.       = (OS2_window_open (console_pm_qid, remote,
  150.               (FCF_TITLEBAR | FCF_SYSMENU
  151.                | FCF_SHELLPOSITION | FCF_SIZEBORDER
  152.                | FCF_MINMAX | FCF_TASKLIST | FCF_NOBYTEALIGN
  153.                | FCF_MENU | FCF_ACCELTABLE | FCF_ICON),
  154.               NULLHANDLE,
  155.               ID_PMCON_RESOURCES,
  156.               0, "Scheme"));
  157.   }
  158.   OS2_window_permanent (console_wid);
  159.   {
  160.     psid_t psid = (OS2_window_client_ps (console_wid));
  161.     const char ** scan_specs = console_font_specs;
  162.     const char ** end_specs
  163.       = (scan_specs
  164.      + ((sizeof (console_font_specs)) / (sizeof (const char *))));
  165.     console_metrics = 0;
  166.     while (scan_specs < end_specs)
  167.       {
  168.     const char * spec = (*scan_specs++);
  169.     /* This prevents the font-change hook from being invoked.  */
  170.     console_psid = 0;
  171.     console_metrics = (OS2_ps_set_font (psid, 1, spec));
  172.     if (console_metrics != 0)
  173.       break;
  174.       }
  175.     if (console_metrics == 0)
  176.       OS2_logic_error ("Unable to find usable console font.");
  177.     console_psid = psid;
  178.   }
  179.   OS2_window_set_grid (console_wid, CHAR_WIDTH, CHAR_HEIGHT);
  180.   OS2_window_shape_cursor
  181.     (console_wid, CHAR_WIDTH, CHAR_HEIGHT, (CURSOR_SOLID | CURSOR_FLASH));
  182.   OS2_window_show_cursor (console_wid, 1);
  183.   OS2_window_show (console_wid, 1);
  184.   OS2_window_activate (console_wid);
  185.   {
  186.     unsigned short width;
  187.     unsigned short height;
  188.     unsigned short max_width = (80 * CHAR_WIDTH);
  189.     OS2_window_size (console_wid, (& width), (& height));
  190.     console_resize (width, height);
  191.     if (width > max_width)
  192.       OS2_window_set_size (console_wid, max_width, height);
  193.   }
  194.   console_menu
  195.     = (OS2_window_handle_from_id (console_pm_qid,
  196.                   (OS2_window_frame_handle (console_wid)),
  197.                   FID_MENU));
  198.   disable_marked_region ();
  199. }
  200.  
  201. wid_t
  202. OS2_console_wid (void)
  203. {
  204.   return (console_wid);
  205. }
  206.  
  207. psid_t
  208. OS2_console_psid (void)
  209. {
  210.   return (console_psid);
  211. }
  212.  
  213. void
  214. OS2_console_font_change_hook (font_metrics_t * metrics)
  215. {
  216.   font_metrics_t * copy = (OS_malloc (sizeof (font_metrics_t)));
  217.   FASTCOPY (((char *) metrics), ((char *) copy), (sizeof (font_metrics_t)));
  218.   grab_console_lock ();
  219.   OS_free (console_metrics);
  220.   console_metrics = copy;
  221.   OS2_window_set_grid (console_wid, CHAR_WIDTH, CHAR_HEIGHT);
  222.   OS2_window_shape_cursor
  223.     (console_wid, CHAR_WIDTH, CHAR_HEIGHT, (CURSOR_SOLID | CURSOR_FLASH));
  224.   console_resize (console_pel_width, console_pel_height);
  225.   OS2_window_invalidate (console_wid,
  226.              0, console_pel_width,
  227.              0, console_pel_height);
  228.   release_console_lock ();
  229. }
  230.  
  231. static void
  232. grab_console_lock (void)
  233. {
  234.   OS2_request_mutex_semaphore (console_lock);
  235. }
  236.  
  237. static void
  238. release_console_lock (void)
  239. {
  240.   OS2_release_mutex_semaphore (console_lock);
  241. }
  242.  
  243. static unsigned short
  244. cx2x (unsigned short x)
  245. {
  246.   return (x * CHAR_WIDTH);
  247. }
  248.  
  249. static unsigned short
  250. cy2y (unsigned short y, int lowerp)
  251. {
  252.   /* lowerp => result is bottommost pel of cell.  Otherwise result is
  253.      bottommost pel of cell above.  */
  254.   unsigned short limit = (lowerp ? (console_height - 1) : console_height);
  255.   return ((y < limit) ? ((limit - y) * CHAR_HEIGHT) : 0);
  256. }
  257.  
  258. static unsigned short
  259. x2cx (short x, int lowerp)
  260. {
  261.   /* lowerp => `x' is inclusive lower bound, and result is cell it
  262.      falls in.  Otherwise, `x' is exclusive upper bound, and result is
  263.      cell to its right, unless it falls on leftmost edge of cell.  If
  264.      the argument is inclusive-lower, then the result is also;
  265.      likewise for exclusive-upper.  */
  266.   short cx = (x / ((short) CHAR_WIDTH));
  267.   if (! (lowerp || ((x % ((short) CHAR_WIDTH)) == 0)))
  268.     cx += 1;
  269.   return ((cx < 0) ? 0 : (cx > console_width) ? console_width : cx);
  270. }
  271.  
  272. static unsigned short
  273. y2cy (short y, int lowerp)
  274. {
  275.   /* lowerp => `y' is inclusive lower bound, and result is cell below
  276.      the one it falls in.  Otherwise, `y' is exclusive upper bound,
  277.      and result is cell it falls in, unless it falls on bottommost
  278.      edge of cell, when result is cell below.  If the argument is
  279.      inclusive-lower, then the result is exclusive-upper, and
  280.      vice-versa.  */
  281.   short cy = (((short) (console_height - 1)) - (y / ((short) CHAR_HEIGHT)));
  282.   if (lowerp || ((y % ((short) CHAR_HEIGHT)) == 0))
  283.     cy += 1;
  284.   return ((cy < 0) ? 0 : (cy > console_height) ? console_height : cy);
  285. }
  286.  
  287. static void
  288. process_events (int blockp)
  289. {
  290.   while (1)
  291.     {
  292.       msg_t * message
  293.     = (OS2_receive_message (console_event_qid, blockp, 0));
  294.       if (message == 0)
  295.     break;
  296.       switch (MSG_TYPE (message))
  297.     {
  298.     case mt_paint_event:
  299.       {
  300.         unsigned short xl = (SM_PAINT_EVENT_XL (message));
  301.         unsigned short xh = (SM_PAINT_EVENT_XH (message));
  302.         unsigned short yl = (SM_PAINT_EVENT_YL (message));
  303.         unsigned short yh = (SM_PAINT_EVENT_YH (message));
  304.         OS2_destroy_message (message);
  305.         grab_console_lock ();
  306.         OS2_ps_clear (console_psid, xl, xh, yl, yh);
  307.         console_paint ((x2cx (xl, 1)),
  308.                (x2cx (xh, 0)),
  309.                (y2cy (yh, 0)),
  310.                (y2cy (yl, 1)));
  311.         release_console_lock ();
  312.         break;
  313.       }
  314.     case mt_pm_event:
  315.       {
  316.         ULONG msg = (SM_PM_EVENT_MSG (message));
  317.         MPARAM mp1 = (SM_PM_EVENT_MP1 (message));
  318.         MPARAM mp2 = (SM_PM_EVENT_MP2 (message));
  319.         switch (msg)
  320.           {
  321.           case WM_CHAR:
  322.           case WM_CLOSE:
  323.           postpone_event:
  324.         OS2_msg_fifo_insert (pending_events, message);
  325.         message = 0;
  326.         if (blockp)
  327.           return;
  328.         break;
  329.           case WM_SIZE:
  330.         {
  331.           unsigned short new_pel_width = (SHORT1FROMMP (mp2));
  332.           unsigned short new_pel_height = (SHORT2FROMMP (mp2));
  333.           grab_console_lock ();
  334.           console_resize (new_pel_width, new_pel_height);
  335.           release_console_lock ();
  336.           break;
  337.         }
  338.           case WM_SHOW:
  339.         if ((!console_visiblep) && (SHORT1FROMMP (mp1)))
  340.           {
  341.             grab_console_lock ();
  342.             OS2_window_invalidate (console_wid,
  343.                        0, console_pel_width,
  344.                        0, console_pel_height);
  345.             release_console_lock ();
  346.           }
  347.         console_visiblep = (SHORT1FROMMP (mp1));
  348.         break;
  349.           case WM_BUTTON1DOWN:
  350.         grab_console_lock ();
  351.         if (!OS2_window_focusp (console_wid))
  352.           OS2_window_activate (console_wid);
  353.         else if (OS2_window_set_capture (console_wid, 1))
  354.           {
  355.             console_tracking_mouse_p = 1;
  356.             initialize_marked_region ((SHORT1FROMMP (mp1)),
  357.                           (SHORT2FROMMP (mp1)));
  358.             OS2_window_mousetrack (console_wid, 1);
  359.             OS2_set_pointer (console_pm_qid,
  360.                      HWND_DESKTOP,
  361.                      console_tracking_mouse_pointer);
  362.           }
  363.         else
  364.           (void) WinAlarm (HWND_DESKTOP, WA_ERROR);
  365.         release_console_lock ();
  366.         break;
  367.           case WM_BUTTON1UP:
  368.         if (console_tracking_mouse_p)
  369.           {
  370.             grab_console_lock ();
  371.             update_marked_region ((SHORT1FROMMP (mp1)),
  372.                       (SHORT2FROMMP (mp1)));
  373.             (void) OS2_window_set_capture (console_wid, 0);
  374.             OS2_window_mousetrack (console_wid, 0);
  375.             enable_menu_copy_items (marked_region_nonempty_p ());
  376.             console_tracking_mouse_p = 0;
  377.             release_console_lock ();
  378.           }
  379.         break;
  380.           case WM_MOUSEMOVE:
  381.         if (console_tracking_mouse_p)
  382.           {
  383.             grab_console_lock ();
  384.             update_marked_region ((SHORT1FROMMP (mp1)),
  385.                       (SHORT2FROMMP (mp1)));
  386.             OS2_set_pointer (console_pm_qid,
  387.                      HWND_DESKTOP,
  388.                      console_tracking_mouse_pointer);
  389.             release_console_lock ();
  390.           }
  391.         break;
  392.           case WM_BUTTON2DOWN:
  393.           case WM_BUTTON3DOWN:
  394.         grab_console_lock ();
  395.         if (!OS2_window_focusp (console_wid))
  396.           OS2_window_activate (console_wid);
  397.         release_console_lock ();
  398.         break;
  399.           case WM_COMMAND:
  400.         switch (SHORT1FROMMP (mp1))
  401.           {
  402.           case IDM_CUT:
  403.           case IDM_COPY:
  404.           case IDM_PASTE:
  405.             goto postpone_event;
  406.           case IDM_FONT:
  407.             grab_console_lock ();
  408.             {
  409.               const char * font_spec
  410.             = (OS2_window_font_dialog (console_wid,
  411.                            "Console Window Font"));
  412.               if (font_spec != 0)
  413.             {
  414.               (void) OS2_ps_set_font (console_psid, 1, font_spec);
  415.               OS_free ((void *) font_spec);
  416.             }
  417.             }
  418.             release_console_lock ();
  419.             break;
  420.           case IDM_EXIT:
  421.             termination_normal (0);
  422.             break;
  423.           case IDM_ABOUT:
  424.             (void) WinMessageBox
  425.               (HWND_DESKTOP, NULLHANDLE,
  426.                "This is MIT Scheme Release "
  427.                SCHEME_RELEASE
  428.                ", brought to you by the MIT Scheme Team.\n",
  429.                "The Uncommon Lisp", 0, MB_OK);
  430.             break;
  431.           }
  432.           }
  433.         if (message != 0)
  434.           OS2_destroy_message (message);
  435.       }
  436.       break;
  437.     default:
  438.       OS2_destroy_message (message);
  439.       break;
  440.     }
  441.     }
  442. }
  443.  
  444. static void
  445. initialize_marked_region (short x, short y)
  446. {
  447.   unmark_marked_region ();
  448.   console_mark_x = x;
  449.   console_mark_y = y;
  450.   console_point_x = x;
  451.   console_point_y = y;
  452.   console_marked_region_active_p = 1;
  453. }
  454.  
  455. static void
  456. update_marked_region (short x, short y)
  457. {
  458.   unsigned short cx11;
  459.   unsigned short cy11;
  460.   unsigned short cx21;
  461.   unsigned short cy21;
  462.   unsigned short cx12;
  463.   unsigned short cy12;
  464.   unsigned short cx22;
  465.   unsigned short cy22;
  466.  
  467.   unsigned short i11;
  468.   unsigned short i21;
  469.   unsigned short i12;
  470.   unsigned short i22;
  471.  
  472.   if (!console_marked_region_active_p)
  473.     return;
  474.  
  475.   compute_marked_region (console_mark_x, console_mark_y,
  476.              console_point_x, console_point_y,
  477.              (&cx11), (&cy11), (&cx21), (&cy21));
  478.   highlight_marked_region (cx11, cy11, cx21, cy21, '\0');
  479.  
  480.   compute_marked_region (console_mark_x, console_mark_y, x, y,
  481.              (&cx12), (&cy12), (&cx22), (&cy22));
  482.   highlight_marked_region (cx12, cy12, cx22, cy22, '\1');
  483.  
  484.   i11 = ((cy11 * console_width) + cx11);
  485.   i21 = ((cy21 * console_width) + cx21);
  486.   i12 = ((cy12 * console_width) + cx12);
  487.   i22 = ((cy22 * console_width) + cx22);
  488.  
  489.   if (i11 < i12)
  490.     paint_marked_region_segment (cx11, cy11, cx12, cy12);
  491.   else if (i12 < i11)
  492.     paint_marked_region_segment (cx12, cy12, cx11, cy11);
  493.   if (i21 < i22)
  494.     paint_marked_region_segment (cx21, cy21, cx22, cy22);
  495.   else if (i22 < i21)
  496.     paint_marked_region_segment (cx22, cy22, cx21, cy21);
  497.  
  498.   console_point_x = x;
  499.   console_point_y = y;
  500. }
  501.  
  502. static void
  503. unmark_marked_region (void)
  504. {
  505.   if (console_marked_region_active_p)
  506.     {
  507.       unsigned short cx1;
  508.       unsigned short cy1;
  509.       unsigned short cx2;
  510.       unsigned short cy2;
  511.       compute_marked_region (console_mark_x, console_mark_y,
  512.                  console_point_x, console_point_y,
  513.                  (&cx1), (&cy1), (&cx2), (&cy2));
  514.       highlight_marked_region (cx1, cy1, cx2, cy2, '\0');
  515.       paint_marked_region_segment (cx1, cy1, cx2, cy2);
  516.       disable_marked_region ();
  517.     }
  518. }
  519.  
  520. static int
  521. marked_region_nonempty_p (void)
  522. {
  523.   if (console_marked_region_active_p)
  524.     {
  525.       unsigned short cx1;
  526.       unsigned short cy1;
  527.       unsigned short cx2;
  528.       unsigned short cy2;
  529.       unsigned short y;
  530.       compute_marked_region (console_mark_x, console_mark_y,
  531.                  console_point_x, console_point_y,
  532.                  (&cx1), (&cy1), (&cx2), (&cy2));
  533.       return
  534.     ((cy1 < cy2)
  535.      || ((cx1 < cx2) && (cx1 < (console_line_lengths[cy1]))));
  536.     }
  537.   else
  538.     return (0);
  539. }
  540.  
  541. static char *
  542. extract_marked_region (int cutp)
  543. {
  544.   if (console_marked_region_active_p)
  545.     {
  546.       unsigned short cx1;
  547.       unsigned short cy1;
  548.       unsigned short cx2;
  549.       unsigned short cy2;
  550.       unsigned short length;
  551.       unsigned short y;
  552.       char * result;
  553.       char * scan;
  554.  
  555.       compute_marked_region (console_mark_x, console_mark_y,
  556.                  console_point_x, console_point_y,
  557.                  (&cx1), (&cy1), (&cx2), (&cy2));
  558.       length = 1;
  559.       for (y = cy1; (y <= cy2); y += 1)
  560.     {
  561.       unsigned short xl = ((y == cy1) ? cx1 : 0);
  562.       unsigned short xh = ((y == cy2) ? cx2 : console_width);
  563.       unsigned short lx = (console_line_lengths[y]);
  564.       if (y > cy1)
  565.         length += 2;
  566.       if (xl < lx)
  567.         length += (((xh < lx) ? xh : lx) - xl);
  568.     }
  569.       if (length == 1)
  570.     return (0);
  571.       result = (OS_malloc (length));
  572.       scan = result;
  573.       for (y = cy1; (y <= cy2); y += 1)
  574.     {
  575.       unsigned short xl = ((y == cy1) ? cx1 : 0);
  576.       unsigned short xh = ((y == cy2) ? cx2 : console_width);
  577.       unsigned short lx = (console_line_lengths[y]);
  578.       if (y > cy1)
  579.         {
  580.           (*scan++) = '\r';
  581.           (*scan++) = '\n';
  582.         }
  583.       if (xl < lx)
  584.         {
  585.           unsigned short ll = (((xh < lx) ? xh : lx) - xl);
  586.           FASTCOPY ((CHAR_LOC (xl, y)), scan, ll);
  587.           scan += ll;
  588.         }
  589.     }
  590.       (*scan) = '\0';
  591.       if (cutp)
  592.     {
  593.       unsigned short x1
  594.         = ((cx1 < (console_line_lengths[cy1]))
  595.            ? cx1
  596.            : (console_line_lengths[cy1]));
  597.       {
  598.         unsigned short d
  599.           = ((cx2 < (console_line_lengths[cy2]))
  600.          ? ((console_line_lengths[cy2]) - cx2)
  601.          : 0);
  602.         FASTCOPY ((CHAR_LOC (cx2, cy2)), (CHAR_LOC (x1, cy1)), d);
  603.         FASTFILL ((CHAR_LOC ((x1 + d), cy1)),
  604.               (console_width - (x1 + d)),
  605.               ' ');
  606.         FASTCOPY ((CHAR_HL (cx2, cy2)), (CHAR_HL (x1, cy1)), d);
  607.         FASTFILL ((CHAR_HL ((x1 + d), cy1)),
  608.               (console_width - (x1 + d)),
  609.               '\0');
  610.         (console_line_lengths[cy1]) = (x1 + d);
  611.       }
  612.       if (cy1 < cy2)
  613.         {
  614.           unsigned short d = (console_height - (cy2 + 1));
  615.           FASTCOPY ((CHAR_LOC (0, (cy2 + 1))),
  616.             (CHAR_LOC (0, (cy1 + 1))),
  617.             (d * console_width));
  618.           FASTCOPY ((CHAR_HL (0, (cy2 + 1))),
  619.             (CHAR_HL (0, (cy1 + 1))),
  620.             (d * console_width));
  621.           FASTCOPY ((LINE_LEN_LOC (cy2 + 1)),
  622.             (LINE_LEN_LOC (cy1 + 1)),
  623.             (d * (sizeof (unsigned short))));
  624.         }
  625.       if ((cy1 < point_y) || ((cy1 == point_y) && (x1 < point_x)))
  626.         {
  627.           if ((cy2 > point_y) || ((cy2 == point_y) && (cx2 >= point_x)))
  628.         {
  629.           point_x = x1;
  630.           point_y = cy1;
  631.         }
  632.           else if (cy2 < point_y)
  633.         point_y -= (cy2 - cy1);
  634.           else
  635.         point_x -= (cx2 - ((cy1 == cy2) ? x1 : 0));
  636.           OS2_window_move_cursor (console_wid,
  637.                       (cx2x (point_x)),
  638.                       (cy2y (point_y, 1)));
  639.         }
  640.       console_paint (0, console_width, cy1, console_height);
  641.     }
  642.       return (result);
  643.     }
  644.   else
  645.     return (0);
  646. }
  647.  
  648. static void
  649. compute_marked_region (short x1, short y1, short x2, short y2,
  650.                unsigned short * cx1, unsigned short * cy1,
  651.                unsigned short * cx2, unsigned short * cy2)
  652. {
  653.   /* (cx1,cy1) is inclusive, and (cx2,cy2) is exclusive.  */
  654.   unsigned short cx1a = (x2cx (x1, 1));
  655.   unsigned short cy1a = (y2cy (y1, 0));
  656.   unsigned short cx2a = (x2cx (x2, 1));
  657.   unsigned short cy2a = (y2cy (y2, 0));
  658.   if (((cy1a * console_width) + cx1a) > ((cy2a * console_width) + cx2a))
  659.     {
  660.       unsigned short cx = cx1a;
  661.       unsigned short cy = cy1a;
  662.       cx1a = cx2a;
  663.       cy1a = cy2a;
  664.       cx2a = cx;
  665.       cy2a = cy;
  666.     }
  667.   if (cy1a >= console_height)
  668.     {
  669.       cx1a = (console_width - 1);
  670.       cy1a = (console_height - 1);
  671.     }
  672.   else if (cx1a >= console_width)
  673.     cx1a = (console_width - 1);
  674.   if (cy2a >= console_height)
  675.     {
  676.       cx2a = 0;
  677.       cy2a = console_height;
  678.     }
  679.   else if (cx2a > console_width)
  680.     cx2a = console_width;
  681.   (*cx1) = cx1a;
  682.   (*cy1) = cy1a;
  683.   (*cx2) = cx2a;
  684.   (*cy2) = cy2a;
  685. }
  686.  
  687. static void
  688. highlight_marked_region (unsigned short cx1, unsigned short cy1,
  689.              unsigned short cx2, unsigned short cy2,
  690.              char hl)
  691. {
  692.   char * start = (CHAR_HL (cx1, cy1));
  693.   FASTFILL (start, ((CHAR_HL (cx2, cy2)) - start), hl);
  694. }
  695.  
  696. static void
  697. paint_marked_region_segment (unsigned short x1, unsigned short y1,
  698.                  unsigned short x2, unsigned short y2)
  699. {
  700.   if (y1 == y2)
  701.     console_paint (x1, x2, y1, (y1 + 1));
  702.   else
  703.     {
  704.       console_paint (x1, console_width, y1, (y1 + 1));
  705.       if ((y1 + 1) < y2)
  706.     console_paint (0, console_width, (y1 + 1), y2);
  707.       console_paint (0, x2, y2, (y2 + 1));
  708.     }
  709. }
  710.  
  711. static void
  712. disable_marked_region (void)
  713. {
  714.   console_marked_region_active_p = 0;
  715.   enable_menu_copy_items (0);
  716. }
  717.  
  718. static void
  719. enable_menu_copy_items (int enablep)
  720. {
  721.   if (console_menu != NULLHANDLE)
  722.     {
  723.       USHORT value = (enablep ? 0 : MIA_DISABLED);
  724. #if 0
  725.       (void) OS2_menu_set_item_attributes
  726.     (console_pm_qid, console_menu, IDM_CUT, TRUE, MIA_DISABLED, value);
  727. #endif
  728.       (void) OS2_menu_set_item_attributes
  729.     (console_pm_qid, console_menu, IDM_COPY, TRUE, MIA_DISABLED, value);
  730.     }
  731. }
  732.  
  733. static void
  734. console_resize (unsigned short new_pel_width, unsigned short new_pel_height)
  735. {
  736.   unsigned short new_width = (new_pel_width / CHAR_WIDTH);
  737.   unsigned short new_height = (new_pel_height / CHAR_HEIGHT);
  738.   char * new_chars;
  739.   char * new_highlights;
  740.   unsigned short * new_line_lengths;
  741.  
  742.   if ((console_chars != 0)
  743.       && (new_width == console_width)
  744.       && (new_height == console_height))
  745.     return;
  746.  
  747.   new_chars = (OS_malloc (new_width * new_height));
  748.   new_highlights = (OS_malloc (new_width * new_height));
  749.   new_line_lengths = (OS_malloc ((sizeof (unsigned short)) * new_height));
  750.  
  751.   FASTFILL (new_chars, (new_width * new_height), ' ');
  752.   FASTFILL (new_highlights, (new_width * new_height), '\0');
  753.   FASTFILL (((char *) new_line_lengths),
  754.         ((sizeof (unsigned short)) * new_height),
  755.         0);
  756.  
  757.   if (console_chars != 0)
  758.     {
  759.       unsigned short xlim
  760.     = ((new_width < console_width) ? new_width : console_width);
  761.       unsigned short oy
  762.     = (((point_y + 1) > new_height) ? ((point_y + 1) - new_height) : 0);
  763.       unsigned short oylim
  764.     = (oy + ((new_height < console_height) ? new_height : console_height));
  765.       char * cfrom = (CHAR_LOC (0, oy));
  766.       char * cto = new_chars;
  767.       char * hfrom = (CHAR_HL (0, oy));
  768.       char * hto = new_highlights;
  769.       unsigned short ny = 0;
  770.       while (oy < oylim)
  771.     {
  772.       FASTCOPY (cfrom, cto, xlim);
  773.       FASTCOPY (hfrom, hto, xlim);
  774.       (new_line_lengths[ny]) = (console_line_lengths[oy]);
  775.       cfrom += console_width;
  776.       cto += new_width;
  777.       hfrom += console_width;
  778.       hto += new_width;
  779.       oy += 1;
  780.       ny += 1;
  781.     }
  782.       OS_free (console_chars);
  783.       OS_free (console_highlights);
  784.       OS_free (console_line_lengths);
  785.     }
  786.   console_pel_width = new_pel_width;
  787.   console_pel_height = new_pel_height;
  788.   console_width = new_width;
  789.   console_height = new_height;
  790.   console_chars = new_chars;
  791.   console_highlights = new_highlights;
  792.   console_line_lengths = new_line_lengths;
  793.   if (point_x >= new_width)
  794.     point_x = (new_width - 1);
  795.   if ((point_y + 1) >= new_height)
  796.     point_y -= ((point_y + 1) - new_height);
  797.   OS2_window_move_cursor (console_wid, (cx2x (point_x)), (cy2y (point_y, 1)));
  798.   OS2_window_invalidate (console_wid,
  799.              0, console_pel_width,
  800.              0, console_pel_height);
  801. }
  802.  
  803. static void
  804. console_paint (unsigned short cxl, unsigned short cxh,
  805.            unsigned short cyl, unsigned short cyh)
  806. {
  807.   if ((cxl < cxh) && (cyl < cyh))
  808.     {
  809.       COLOR foreground = (OS2_ps_get_foreground_color (console_psid));
  810.       COLOR background = (OS2_ps_get_background_color (console_psid));
  811.       unsigned short size = (cxh - cxl);
  812.       char current_hl = '\0';
  813.       while (cyl < cyh)
  814.     {
  815.       unsigned short x = (cx2x (cxl));
  816.       unsigned short y = ((cy2y (cyl, 1)) + CHAR_DESCENDER);
  817.       char * cstart = (CHAR_LOC (cxl, cyl));
  818.       char * hstart = (CHAR_HL (cxl, cyl));
  819.       char * hend = (hstart + size);
  820.       while (hstart < hend)
  821.         {
  822.           unsigned short run_length = (compute_run_length (hstart, hend));
  823.           if (current_hl != (*hstart))
  824.         {
  825.           if ((*hstart) == '\0')
  826.             OS2_ps_set_colors (console_psid, foreground, background);
  827.           else
  828.             OS2_ps_set_colors (console_psid, background, foreground);
  829.           current_hl = (*hstart);
  830.         }
  831.           OS2_ps_draw_text (console_psid, x, y, cstart, run_length);
  832.           x += (run_length * CHAR_WIDTH);
  833.           cstart += run_length;
  834.           hstart += run_length;
  835.         }
  836.       cyl += 1;
  837.     }
  838.       if (current_hl != '\0')
  839.     OS2_ps_set_colors (console_psid, foreground, background);
  840.     }
  841. }
  842.  
  843. static unsigned short
  844. compute_run_length (const char * start, const char * end)
  845. {
  846.   if (start < end)
  847.     {
  848.       const char * scan = start;
  849.       const char c = (*scan++);
  850.       while (scan < end)
  851.     if ((*scan) == c)
  852.       scan += 1;
  853.     else
  854.       break;
  855.       return (scan - start);
  856.     }
  857.   else
  858.     return (0);
  859. }
  860.  
  861. static void
  862. console_clear (unsigned short xl, unsigned short xh,
  863.            unsigned short yl, unsigned short yh)
  864. {
  865.   OS2_ps_clear (console_psid,
  866.         (cx2x (xl)), (cx2x (xh)),
  867.         (cy2y (yh, 0)), (cy2y (yl, 0)));
  868. }
  869.  
  870. static void
  871. console_clear_all (void)
  872. {
  873.   OS2_ps_clear (console_psid, 0, console_pel_width, 0, console_pel_height);
  874. }
  875.  
  876. int
  877. OS2_pm_console_getch (void)
  878. {
  879.   if (console_closedp)
  880.     return (-1);
  881.   if ((readahead_repeat == 0) && (readahead_insert == 0))
  882.     while (1)
  883.       {
  884.     process_events (OS2_msg_fifo_emptyp (pending_events));
  885.     {
  886.       msg_t * message = (OS2_msg_fifo_remove (pending_events));
  887.       ULONG msg = (SM_PM_EVENT_MSG (message));
  888.       MPARAM mp1 = (SM_PM_EVENT_MP1 (message));
  889.       MPARAM mp2 = (SM_PM_EVENT_MP2 (message));
  890.       OS2_destroy_message (message);
  891.       switch (msg)
  892.         {
  893.         case WM_CHAR:
  894.           {
  895.         unsigned short code;
  896.         unsigned char repeat;
  897.         if (translate_key_event (mp1, mp2, (&code), (&repeat)))
  898.           {
  899.             /* The feature that causes Delete and Backspace to
  900.                delete the marked region is disabled because it
  901.                is too much trouble to make the typeahead
  902.                buffer conform to the displayed characters.  */
  903. #if 0
  904.             /* Delete and Backspace must discard the marked
  905.                region if there is one.  */
  906.             if ((code == '\177') && (repeat > 0))
  907.               {
  908.             char * region = (extract_marked_region (1));
  909.             if (region != 0)
  910.               {
  911.                 OS_free (region);
  912.                 repeat -= 1;
  913.               }
  914.               }
  915. #endif
  916.             if (repeat > 0)
  917.               {
  918.             readahead_char = code;
  919.             readahead_repeat = repeat;
  920.             goto do_read;
  921.               }
  922.           }
  923.           }
  924.           break;
  925.         case WM_CLOSE:
  926.           switch
  927.         (WinMessageBox
  928.          (HWND_DESKTOP,
  929.           NULLHANDLE, /* client window handle */
  930.           "You have requested that this window be closed.\n\n"
  931.           "Press \"Yes\" to close this window and terminate Scheme; "
  932.           "doing so will discard data in unsaved Edwin buffers.\n\n"
  933.           "Press \"No\" to close only this window, leaving Scheme "
  934.           "running; the program will continue to run until the "
  935.           "next time it tries to read from the console.\n\n"
  936.           "Press \"Cancel\" if you don't want to close this window.",
  937.           "Terminate Scheme?",
  938.           0,
  939.           (MB_YESNOCANCEL | MB_WARNING)))
  940.           {
  941.           case MBID_YES:
  942.             termination_normal (0);
  943.             break;
  944.           case MBID_NO:
  945.             console_closedp = 1;
  946.             OS2_window_close (console_wid);
  947.             OS2_close_qid (console_event_qid);
  948.             OS2_close_std_tqueue (console_tqueue);
  949.             goto do_read;
  950.           }
  951.           break;
  952.         case WM_COMMAND:
  953.           {
  954.         ULONG msg = (SHORT1FROMMP (mp1));
  955.         switch (msg)
  956.           {
  957.           case IDM_PASTE:
  958.             if (do_paste ())
  959.               goto do_read;
  960.             break;
  961. #if 0
  962.           /* IDM_CUT is disabled because it is too much
  963.              trouble to make the typeahead buffer conform to
  964.              the displayed characters.  */
  965.           case IDM_CUT:
  966. #endif
  967.           case IDM_COPY:
  968.             grab_console_lock ();
  969.             {
  970.               char * region = (extract_marked_region (msg == IDM_CUT));
  971.               if (region != 0)
  972.             {
  973.               OS2_clipboard_write_text (console_pm_qid, region);
  974.               OS_free (region);
  975.               unmark_marked_region ();
  976.             }
  977.             }
  978.             release_console_lock ();
  979.             break;
  980.           }
  981.           }
  982.           break;
  983.         }
  984.     }
  985.       }
  986.  do_read:
  987.   if (readahead_insert != 0)
  988.     {
  989.       char c = (*readahead_insert_scan++);
  990.       if ((*readahead_insert_scan) == '\0')
  991.     {
  992.       OS_free ((void *) readahead_insert);
  993.       readahead_insert = 0;
  994.     }
  995.       return (c);
  996.     }
  997.   if (readahead_repeat != 0)
  998.     {
  999.       readahead_repeat -= 1;
  1000.       return (readahead_char);
  1001.     }
  1002.   return (-1);
  1003. }
  1004.  
  1005. static int
  1006. do_paste (void)
  1007. {
  1008.   const char * text = (OS2_clipboard_read_text (console_pm_qid));
  1009.   if ((text != 0) && ((*text) != '\0'))
  1010.     {
  1011.       readahead_insert = text;
  1012.       readahead_insert_scan = text;
  1013.       return (1);
  1014.     }
  1015.   else
  1016.     {
  1017.       OS_free ((void *) text);
  1018.       return (0);
  1019.     }
  1020. }
  1021.  
  1022. static int
  1023. translate_key_event (MPARAM mp1, MPARAM mp2,
  1024.              unsigned short * code, unsigned char * repeat)
  1025. {
  1026.   unsigned short flags;
  1027.   if (!OS2_translate_wm_char (mp1, mp2, code, (&flags), repeat))
  1028.     return (0);
  1029.   if ((flags & KC_VIRTUALKEY) != 0)
  1030.     switch (*code)
  1031.       {
  1032.       case VK_BACKSPACE:
  1033.       case VK_DELETE:
  1034.     (*code) = '\177';
  1035.     break;
  1036.       case VK_TAB:
  1037.     (*code) = '\t';
  1038.     break;
  1039.       case VK_ESC:
  1040.     (*code) = '\033';
  1041.     break;
  1042.       case VK_SPACE:
  1043.     (*code) = ' ';
  1044.     break;
  1045.       case VK_NEWLINE:
  1046.       case VK_ENTER:
  1047.     (*code) = '\r';
  1048.     break;
  1049.       default:
  1050.     return (0);
  1051.       }
  1052.   if (((*code) >= 0200) || ((flags & KC_ALT) != 0))
  1053.     return (0);
  1054.   if ((flags & KC_CTRL) != 0)
  1055.     if ((*code) >= 040)
  1056.       (*code) &= 037;
  1057.     else
  1058.       return (0);
  1059.   if ((*code) == 0)
  1060.     return (0);
  1061.   return (1);
  1062. }
  1063.  
  1064. void
  1065. OS2_pm_console_write (const char * data, size_t size)
  1066. {
  1067.   const char * end = (data + size);
  1068.   const char * nonprint;
  1069.   if (console_closedp)
  1070.     return;
  1071.   grab_console_lock ();
  1072.   unmark_marked_region ();
  1073.   while (data < end)
  1074.     {
  1075.       nonprint = (find_nonprint (data, end));
  1076.       if (data < nonprint)
  1077.     while (1)
  1078.       {
  1079.         unsigned short size = (nonprint - data);
  1080.         if (size > (console_width - point_x))
  1081.           size = (console_width - point_x);
  1082.         FASTCOPY (data, (CHAR_LOC (point_x, point_y)), size);
  1083.         FASTFILL ((CHAR_HL (point_x, point_y)), size, '\0');
  1084.         OS2_ps_draw_text (console_psid,
  1085.                   (cx2x (point_x)),
  1086.                   ((cy2y (point_y, 1)) + CHAR_DESCENDER),
  1087.                   data,
  1088.                   size);
  1089.         data += size;
  1090.         point_x += size;
  1091.         (console_line_lengths[point_y]) = point_x;
  1092.         if (point_x == console_width)
  1093.           {
  1094.         do_carriage_return ();
  1095.         do_linefeed ();
  1096.           }
  1097.         if (data == nonprint)
  1098.           break;
  1099.       }
  1100.       if (data < end)
  1101.     switch (*data++)
  1102.       {
  1103.       case '\r':
  1104.         do_carriage_return ();
  1105.         break;
  1106.       case '\012':
  1107.         do_linefeed ();
  1108.         break;
  1109.       case '\f':
  1110.         do_formfeed ();
  1111.         break;
  1112.       case '\b':
  1113.         do_backspace ();
  1114.         break;
  1115.       case '\a':
  1116.         do_alert ();
  1117.         break;
  1118.       }
  1119.     }
  1120.   OS2_window_move_cursor (console_wid, (cx2x (point_x)), (cy2y (point_y, 1)));
  1121.   release_console_lock ();
  1122. }
  1123.  
  1124. static const char *
  1125. find_nonprint (const char * start, const char * end)
  1126. {
  1127.   while (start < end)
  1128.     if (!isprint (*start++))
  1129.       return (--start);
  1130.   return (end);
  1131. }
  1132.  
  1133. static void
  1134. do_carriage_return (void)
  1135. {
  1136.   point_x = 0;
  1137. }
  1138.  
  1139. static void
  1140. do_linefeed (void)
  1141. {
  1142.   if (point_y < (console_height - 1))
  1143.     point_y += 1;
  1144.   else
  1145.     {
  1146. #ifdef CONSOLE_WRAP
  1147.       point_y = 0;
  1148. #else /* not CONSOLE_WRAP */
  1149.       point_y = (console_height - 1);
  1150.       FASTCOPY ((CHAR_LOC (0, 1)),
  1151.         (CHAR_LOC (0, 0)),
  1152.         (point_y * console_width));
  1153.       FASTCOPY ((CHAR_HL (0, 1)),
  1154.         (CHAR_HL (0, 0)),
  1155.         (point_y * console_width));
  1156.       FASTCOPY ((LINE_LEN_LOC (1)),
  1157.         (LINE_LEN_LOC (0)),
  1158.         (point_y * (sizeof (unsigned short))));
  1159.       OS2_window_scroll (console_wid,
  1160.              0, console_pel_width,
  1161.              0, (point_y * CHAR_HEIGHT),
  1162.              0, CHAR_HEIGHT);
  1163. #endif /* not CONSOLE_WRAP */
  1164.     }
  1165.   FASTFILL ((CHAR_LOC (0, point_y)), console_width, ' ');
  1166.   FASTFILL ((CHAR_HL (0, point_y)), console_width, '\0');
  1167.   (console_line_lengths[point_y]) = 0;
  1168.   console_clear (0, console_width, point_y, (point_y + 1));
  1169. }
  1170.  
  1171. static void
  1172. do_formfeed (void)
  1173. {
  1174.   point_x = 0;
  1175.   point_y = 0;
  1176.   FASTFILL ((CHAR_LOC (0, 0)), (console_height * console_width), ' ');
  1177.   FASTFILL ((CHAR_HL (0, 0)), (console_height * console_width), '\0');
  1178.   FASTFILL ((LINE_LEN_LOC (0)),
  1179.         (console_height * (sizeof (unsigned short))),
  1180.         0);
  1181.   console_clear_all ();
  1182. }
  1183.  
  1184. static void
  1185. do_backspace (void)
  1186. {
  1187.   if (point_x > 0)
  1188.     {
  1189.       point_x -= 1;
  1190.       (console_line_lengths[point_y]) = point_x;
  1191.     }
  1192. }
  1193.  
  1194. static void
  1195. do_alert (void)
  1196. {
  1197.   WinAlarm (HWND_DESKTOP, WA_ERROR);
  1198. }
  1199.