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