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