fix 'crash when reviving shopkeeper'
[aNetHack.git] / sys / mac / mactty.c
blob2fe8a1e33049845d8532945b0d689a054f44be25
1 /* NetHack 3.6 mactty.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */
2 /* Copyright (c) Jon W{tte 1993. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /*
6 * mactty.c
8 * This file contains the actual code for the tty library. For a
9 * description, see the file mactty.h, which contains all you
10 * need to know to use the library.
13 #include "hack.h" /* to get flags */
14 #include "mttypriv.h"
15 #if !TARGET_API_MAC_CARBON
16 #include <Resources.h>
17 #endif
19 char game_active = 0; /* flag to window rendering routines not to use ppat */
21 /* these declarations are here because I can't include macwin.h without
22 * including the world */
23 extern void dprintf(char *, ...); /* dprintf.c */
26 * Borrowed from the Mac tty port
28 extern WindowPtr _mt_window;
30 static void select_onscreen_window(tty_record *record);
31 static void select_offscreen_port(tty_record *record);
33 #define MEMORY_MARGIN 30000
36 * Convenience macro for most functions - put last in declaration
38 #define RECORD_EXISTS(record) \
39 tty_record *record; \
40 if (!window || !(record = (tty_record *) GetWRefCon(window))) \
41 return general_failure;
44 * Simple macro for deciding whether we draw at once or delay
46 #define DRAW_DIRECT (TA_ALWAYS_REFRESH & record->attribute[TTY_ATTRIB_FLAGS])
49 * Table of special characters. Zero is ALWAYS special; it means
50 * end of string and would be MISSED if it was not included here.
52 #define COOKED_CONTROLS 0X00002581
53 #define RAW_CONTROLS 1
54 static unsigned long s_control = COOKED_CONTROLS;
57 * Memory-related error
59 static short
60 mem_err(void)
62 short ret_val = MemError();
63 if (!ret_val) {
64 ret_val = general_failure;
66 return ret_val;
70 * Make a rectangle empty
72 static void
73 empty_rect(Rect *r)
75 r->right = -20000;
76 r->left = 20000;
77 r->top = 20000;
78 r->bottom = -20000;
82 * Union twp rect together
84 static void
85 union_rect(Rect *r1, Rect *r2, Rect *dest)
87 dest->left = min(r1->left, r2->left);
88 dest->top = min(r1->top, r2->top);
89 dest->bottom = max(r1->bottom, r2->bottom);
90 dest->right = max(r1->right, r2->right);
94 * Dispose a pointer using the set memory-allocator
96 static short
97 dispose_ptr(void *ptr)
99 if (!ptr) {
100 return noErr; /* Silently accept disposing nulls */
102 DisposePtr(ptr);
103 return MemError();
106 #if 0 /* Use alloc.c instead */
108 * Allocate a pointer using the set memory-allocator
110 static short
111 alloc_ptr (void **ptr, long size) {
112 *ptr = NewPtr (size);
113 return MemError ();
115 #endif
118 * Set up a GWorld in the record
120 static short
121 allocate_offscreen_world(tty_record *record)
123 GWorldPtr gw = (GWorldPtr) 0;
124 GWorldFlags world_flags = 0;
125 long mem_here, mem_there, other, required_mem;
126 Point p = { 0, 0 };
127 Rect r_screen;
128 GDHandle gdh;
129 short s_err;
131 select_onscreen_window(record);
132 LocalToGlobal(&p);
133 r_screen = record->its_bits.bounds;
134 OffsetRect(&r_screen, p.h, p.v);
136 gdh = GetMaxDevice(&r_screen);
137 required_mem = (long) (*((*gdh)->gdPMap))->pixelSize
138 * ((long) record->its_bits.bounds.right
139 * record->its_bits.bounds.bottom)
140 >> 3;
142 PurgeSpace(&other, &mem_here);
143 if (other < mem_here + MEMORY_MARGIN) {
144 mem_here = other - MEMORY_MARGIN;
146 dprintf("Heap %ld Required %ld", mem_here, required_mem);
147 if (required_mem > mem_here) {
148 mem_there = required_mem;
149 if (required_mem > TempMaxMem(&mem_there)) {
150 dprintf("No memory");
151 return memFullErr;
153 world_flags |= useTempMem;
155 s_err = NewGWorld(&gw, 0, &r_screen, (CTabHandle) 0, (GDHandle) 0,
156 world_flags);
157 if (!s_err) {
158 record->offscreen_world = gw;
159 select_offscreen_port(record);
160 SetOrigin(0, 0);
161 select_onscreen_window(record);
162 dprintf("New GWorld @ %lx;dm", gw);
164 return s_err;
168 * Done with GWorld, release data
170 static short
171 deallocate_gworld(tty_record *record)
173 if (record->offscreen_world) {
174 DisposeGWorld(record->offscreen_world);
175 record->offscreen_world = (GWorldPtr) 0;
177 return noErr;
181 * Get rid of offscreen bitmap
183 static short
184 free_bits(tty_record *record)
186 short s_err;
188 if (record->uses_gworld) {
189 s_err = deallocate_gworld(record);
190 #if !TARGET_API_MAC_CARBON
191 } else {
192 s_err = dispose_ptr(record->its_bits.baseAddr);
193 if (!s_err) {
194 record->its_bits.baseAddr = (char *) 0;
195 if (record->offscreen_port) {
196 ClosePort(record->offscreen_port);
197 s_err = dispose_ptr(record->offscreen_port);
198 if (!s_err) {
199 record->offscreen_port = (GrafPtr) 0;
203 #endif
205 return s_err;
209 * Snatch a window from the resource fork. Create the record.
210 * Otherwise, do nothing.
213 short
214 create_tty(WindowRef *window, short resource_id, Boolean in_color)
216 tty_record *record;
217 Boolean was_allocated = !!*window;
219 if (in_color) {
220 *window = GetNewCWindow(resource_id, (Ptr) *window, (WindowRef) -1L);
221 } else {
222 *window = GetNewWindow(resource_id, (Ptr) *window, (WindowRef) -1L);
224 if (!*window) {
225 return mem_err();
228 record = (tty_record *) NewPtrClear(sizeof(tty_record));
229 if (!record) {
230 #if !TARGET_API_MAC_CARBON
231 if (was_allocated) {
232 CloseWindow(*window);
233 } else {
234 #endif
235 DisposeWindow(*window);
236 #if !TARGET_API_MAC_CARBON
238 #endif
239 return mem_err();
241 record->its_window = *window;
242 SetWRefCon(*window, (long) record);
243 record->was_allocated = was_allocated;
244 record->its_bits.baseAddr = (char *) 0;
245 record->curs_state = TRUE;
248 * We need to keep the window world around if we switch worlds
250 record->offscreen_world = (GWorldPtr) 0;
251 record->uses_gworld = in_color;
252 if (in_color) {
253 GDHandle gh;
255 SetPortWindowPort(*window);
256 GetGWorld(&(record->its_window_world), &gh);
257 } else {
258 record->its_window_world = (GWorldPtr) 0;
261 #if CLIP_RECT_ONLY
262 empty_rect(&(record->invalid_rect));
263 #else
264 record->invalid_part = NewRgn();
265 if (!record->invalid_part) {
266 return destroy_tty(*window);
268 #endif
270 return noErr;
273 short
274 init_tty_number(WindowPtr window, short font_number, short font_size,
275 short x_size, short y_size)
277 RECORD_EXISTS(record);
279 record->font_number = font_number;
280 record->font_size = font_size;
281 record->x_size = x_size;
282 record->y_size = y_size;
284 return force_tty_coordinate_system_recalc(window);
288 * Done with a window - destroy it. Release the memory only if
289 * it wasn't allocated when we got it!
291 short
292 destroy_tty(WindowPtr window)
294 short s_err;
295 RECORD_EXISTS(record);
297 s_err = free_bits(record);
298 if (!s_err) {
299 #if !TARGET_API_MAC_CARBON
300 if (record->was_allocated) {
301 CloseWindow(window);
302 } else {
303 #endif
304 DisposeWindow(window);
305 #if !TARGET_API_MAC_CARBON
307 #endif
308 s_err = dispose_ptr(record);
311 return s_err;
314 static void
315 do_set_port_font(tty_record *record)
317 PenNormal();
318 TextFont(record->font_number);
319 TextSize(record->font_size);
320 if (0L != (record->attribute[TTY_ATTRIB_FLAGS] & TA_OVERSTRIKE)) {
321 TextMode(srcOr);
322 } else {
323 TextMode(srcCopy);
328 * Fill in some fields from some other fields that may have changed
330 static void
331 calc_font_sizes(tty_record *record)
333 FontInfo font_info;
335 do_set_port_font(record);
337 GetFontInfo(&font_info);
338 record->char_width = font_info.widMax;
339 record->ascent_height = font_info.ascent + font_info.leading;
340 record->row_height = record->ascent_height + font_info.descent;
344 * Allocate memory for the bitmap holding the tty window
346 static short
347 alloc_bits(tty_record *record)
349 short s_err;
351 SetRect(&record->its_bits.bounds, 0, 0,
352 record->char_width * record->x_size,
353 record->row_height * record->y_size);
356 * Clear two highest and lowest bit - not a color pixMap, and even in size
358 record->its_bits.rowBytes =
359 ((record->its_bits.bounds.right + 15) >> 3) & 0x1ffe;
361 if (record->uses_gworld) {
362 s_err = allocate_offscreen_world(record);
363 #if !TARGET_API_MAC_CARBON
364 } else {
365 s_err = alloc_ptr((void **) &(record->its_bits.baseAddr),
366 record->its_bits.rowBytes
367 * record->its_bits.bounds.bottom);
368 if (!s_err) {
369 s_err = alloc_ptr((void **) &(record->offscreen_port),
370 sizeof(GrafPort));
372 if (!s_err) {
373 OpenPort(record->offscreen_port);
374 SetPort(record->offscreen_port);
375 ClipRect(&(record->its_bits.bounds));
376 SetPortBits(&(record->its_bits));
378 #endif
380 return s_err;
384 * Save the current port/world in a safe place for later retrieval
386 static void
387 save_port(tty_record *record, void *save)
389 GWorldPtr gw;
390 GDHandle gh;
391 GrafPtr gp;
393 if (record->uses_gworld) {
394 GetGWorld(&gw, &gh);
395 *(GWorldPtr *) save = gw;
396 } else {
397 GetPort(&gp);
398 *(GrafPtr *) save = gp;
403 * Restore current port/world after a save
405 static void
406 use_port(tty_record *record, void *port)
408 if (record->uses_gworld) {
409 PixMapHandle pix_map;
411 SetGWorld((GWorldPtr) port, (GDHandle) 0);
412 pix_map = GetGWorldPixMap(record->offscreen_world);
413 if (pix_map) {
414 if (port == record->offscreen_world)
415 LockPixels(pix_map);
416 else
417 UnlockPixels(pix_map);
419 } else {
420 SetPort((GrafPtr) port);
425 * Use offscreen drawing - lock the pixels through use_port
427 static void
428 select_offscreen_port(tty_record *record)
430 if (record->uses_gworld) {
431 use_port(record, record->offscreen_world);
432 } else {
433 use_port(record, record->offscreen_port);
438 * Use the window - unlock pixels
440 static void
441 select_onscreen_window(tty_record *record)
443 if (record->uses_gworld) {
444 use_port(record, record->its_window_world);
445 SetPortWindowPort(record->its_window);
446 } else {
447 use_port(record, record->its_window);
452 * Do bits copy depending on if we're using color or not
454 static void
455 copy_bits(tty_record *record, Rect *bounds, short xfer_mode,
456 RgnHandle mask_rgn)
458 GWorldFlags pix_state;
459 BitMap *source;
461 if (record->uses_gworld) {
462 pix_state = GetPixelsState(GetGWorldPixMap(record->offscreen_world));
463 LockPixels(GetGWorldPixMap(record->offscreen_world));
464 source = (BitMapPtr) *GetGWorldPixMap(record->offscreen_world);
465 } else
466 source = &record->its_bits;
468 SetPortWindowPort(record->its_window);
469 CopyBits(source,
470 GetPortBitMapForCopyBits(GetWindowPort(record->its_window)),
471 bounds, bounds, xfer_mode, mask_rgn);
473 if (record->uses_gworld) {
474 SetPixelsState(GetGWorldPixMap(record->offscreen_world), pix_state);
479 * Fill an area with the background color
481 static void
482 erase_rect(tty_record *record, Rect *area)
484 if (game_active && u.uhp > 0 && iflags.use_stone
485 && record->its_window == _mt_window) {
486 PixPatHandle ppat;
488 ppat = GetPixPat(iflags.use_stone + 127); /* find which pat to get */
489 if (ppat) { /* in game window, using backgroung pattern, and have
490 pattern */
491 FillCRect(area, ppat);
492 DisposePixPat(ppat);
493 return;
496 EraseRect(area);
500 * Recalculate the window based on new size, font, extent values,
501 * and re-allocate the bitmap.
503 short
504 force_tty_coordinate_system_recalc(WindowPtr window)
506 short s_err;
507 RECORD_EXISTS(record);
509 s_err = free_bits(record);
510 if (s_err) {
511 return s_err;
513 calc_font_sizes(record);
515 s_err = alloc_bits(record);
516 if (s_err) {
518 * Catastrophe! We could not allocate memory for the bitmap! Things
519 * may go very
520 * much downhill from here!
522 dprintf("alloc_bits returned null in "
523 "force_tty_coordinate_system_recalc!");
524 return s_err;
526 select_offscreen_port(record);
527 do_set_port_font(record);
528 return clear_tty(window);
531 #if 0
533 * Update TTY according to new color environment for the window
535 static short
536 tty_environment_changed (tty_record *record) {
537 Point p = {0, 0};
538 Rect r_screen;
540 if (record->uses_gworld) {
541 r_screen = record->its_bits.bounds;
542 LocalToGlobal (&p);
543 OffsetRect (&r_screen, p.h, p.v);
544 UpdateGWorld (&(record->offscreen_world), 0, &r_screen,
545 (CTabHandle) 0, (GDHandle) 0, stretchPix);
546 select_offscreen_port (record);
547 SetOrigin (0, 0);
548 select_onscreen_window (record);
550 return 0;
552 #endif
555 * Read a lot of interesting and useful information from the current tty
557 short
558 get_tty_metrics(WindowPtr window, short *x_size, short *y_size,
559 short *x_size_pixels, short *y_size_pixels,
560 short *font_number, short *font_size, short *char_width,
561 short *row_height)
563 RECORD_EXISTS(record);
566 * First, test that we actually have something to draw to...
568 if ((((char *) 0 == record->its_bits.baseAddr) && !record->uses_gworld)
569 || (((GWorldPtr) 0 == record->offscreen_world)
570 && record->uses_gworld)) {
571 return general_failure;
574 *x_size = record->x_size;
575 *y_size = record->y_size;
576 *x_size_pixels = record->its_bits.bounds.right;
577 *y_size_pixels = record->its_bits.bounds.bottom;
578 *font_number = record->font_number;
579 *font_size = record->font_size;
580 *char_width = record->char_width;
581 *row_height = record->row_height;
583 return noErr;
587 * Map a position on the map to screen coordinates
589 static void
590 pos_rect(tty_record *record, Rect *r, short x_pos, short y_pos, short x_end,
591 short y_end)
593 SetRect(r, x_pos * (record->char_width), y_pos * (record->row_height),
594 (1 + x_end) * (record->char_width),
595 (1 + y_end) * (record->row_height));
598 static void
599 accumulate_rect(tty_record *record, Rect *rect)
601 #if CLIP_RECT_ONLY
602 union_rect(rect, &(record->invalid_rect), &(record->invalid_rect));
603 #else
604 RgnHandle rh = NewRgn();
606 RectRgn(rh, rect);
607 UnionRgn(record->invalid_part, rh, record->invalid_part);
608 DisposeRgn(rh);
609 #endif
613 * get and set window invalid region. exposed for HandleUpdateEvent in
614 * macwin.c
615 * to correct display problem
618 short
619 get_invalid_region(WindowPtr window, Rect *inval_rect)
621 RECORD_EXISTS(record);
622 #if CLIP_RECT_ONLY
623 if (record->invalid_rect.right <= record->invalid_rect.left
624 || record->invalid_rect.bottom <= record->invalid_rect.top) {
625 return general_failure;
627 *inval_rect = record->invalid_rect;
628 #else
629 if (EmptyRgn(record->invalid_part)) {
630 return general_failure;
632 *inval_rect = (*(record->invalid_part))->rgnBBox;
633 #endif
634 return noErr;
637 short
638 set_invalid_region(WindowPtr window, Rect *inval_rect)
640 RECORD_EXISTS(record);
641 accumulate_rect(record, inval_rect);
642 return noErr;
646 * Invert the specified position
648 static void
649 curs_pos(tty_record *record, short x_pos, short y_pos, short to_state)
651 Rect r;
653 if (record->curs_state == to_state) {
654 return;
656 record->curs_state = to_state;
657 pos_rect(record, &r, x_pos, y_pos, x_pos, y_pos);
659 if (DRAW_DIRECT) {
660 void *old_port;
662 save_port(record, &old_port);
663 select_onscreen_window(record);
664 InvertRect(&r);
665 use_port(record, old_port);
666 } else {
667 accumulate_rect(record, &r);
672 * Move the cursor (both as displayed and where drawing goes)
673 * HOWEVER: The cursor is NOT stored in the bitmap!
675 short
676 move_tty_cursor(WindowPtr window, short x_pos, short y_pos)
678 RECORD_EXISTS(record);
680 if (record->x_curs == x_pos && record->y_curs == y_pos) {
681 return noErr;
683 if (record->x_size <= x_pos || x_pos < 0 || record->y_size <= y_pos
684 || y_pos < 0) {
685 return general_failure;
687 curs_pos(record, record->x_curs, record->y_curs, 0);
688 record->x_curs = x_pos;
689 record->y_curs = y_pos;
690 curs_pos(record, x_pos, y_pos, 1);
692 return noErr;
696 * Update the screen to match the current bitmap, after adding stuff
697 * with add_tty_char etc.
699 short
700 update_tty(WindowPtr window)
702 Rect r;
703 RECORD_EXISTS(record);
705 #if CLIP_RECT_ONLY
706 if (record->invalid_rect.right <= record->invalid_rect.left
707 || record->invalid_rect.bottom <= record->invalid_rect.top) {
708 return noErr;
710 r = record->invalid_rect;
711 #else
712 if (EmptyRgn(record->invalid_part)) {
713 return noErr;
715 r = (*(record->invalid_part))->rgnBBox;
716 #endif
717 select_onscreen_window(record);
718 copy_bits(record, &r, srcCopy, (RgnHandle) 0);
719 #if CLIP_RECT_ONLY
720 empty_rect(&(record->invalid_rect));
721 #else
722 SetEmptyRgn(record->invalid_part);
723 #endif
724 if (record->curs_state) {
725 pos_rect(record, &r, record->x_curs, record->y_curs, record->x_curs,
726 record->y_curs);
727 InvertRect(&r);
730 return noErr;
734 * Low level add to screen
736 static void
737 do_add_string(tty_record *record, char *str, short len)
739 Rect r;
741 if (len < 1) {
742 return;
744 select_offscreen_port(record);
746 MoveTo(record->x_curs * record->char_width,
747 record->y_curs * record->row_height + record->ascent_height);
748 DrawText(str, 0, len);
750 pos_rect(record, &r, record->x_curs, record->y_curs,
751 record->x_curs + len - 1, record->y_curs);
752 select_onscreen_window(record);
753 if (DRAW_DIRECT) {
754 copy_bits(record, &r, srcCopy, (RgnHandle) 0);
755 } else {
756 accumulate_rect(record, &r);
761 * Low-level cursor handling routine
763 static void
764 do_add_cursor(tty_record *record, short x_pos)
766 record->x_curs = x_pos;
767 if (record->x_curs >= record->x_size) {
768 if (0L != (record->attribute[TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND)) {
769 record->y_curs++;
770 record->x_curs = 0;
771 if (record->y_curs >= record->y_size) {
772 if (0L != (record->attribute[TTY_ATTRIB_FLAGS]
773 & TA_INHIBIT_VERT_SCROLL)) {
774 record->y_curs = record->y_size;
775 } else {
776 scroll_tty(record->its_window, 0,
777 1 + record->y_curs - record->y_size);
780 } else {
781 record->x_curs = record->x_size;
787 * Do control character
789 static void
790 do_control(tty_record *record, short character)
792 int recurse = 0;
795 * Check recursion because nl_add_cr and cr_add_nl may both be set and
796 * invoke each other
798 do {
799 switch (character) {
800 case CHAR_CR:
801 record->x_curs = 0;
802 if (!recurse
803 && (record->attribute[TTY_ATTRIB_CURSOR] & TA_CR_ADD_NL)) {
804 recurse = 1;
805 } else {
806 recurse = 0;
807 break;
808 } /* FALL-THROUGH: if CR-LF, don't bother with loop */
809 case CHAR_LF:
810 record->y_curs++;
811 if (record->y_curs >= record->y_size) {
812 scroll_tty(record->its_window, 0,
813 1 + record->y_curs - record->y_size);
815 if (!recurse
816 && (record->attribute[TTY_ATTRIB_CURSOR] & TA_NL_ADD_CR)) {
817 character = CHAR_CR;
818 recurse = 1;
819 } else
820 recurse = 0;
821 break;
822 case CHAR_BELL:
823 tty_nhbell();
824 break;
825 case CHAR_BS:
826 if (record->x_curs > 0)
827 record->x_curs--;
828 default:
829 break;
831 } while (recurse);
835 * Add a single character. It is drawn directly if the correct flag is set,
836 * else deferred to the next update event or call of update_tty()
838 short
839 add_tty_char(WindowPtr window, short character)
841 register char is_control;
842 char ch;
843 RECORD_EXISTS(record);
845 if (!(record->attribute[TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND)
846 && record->x_curs >= record->x_size)
847 return noErr; /* Optimize away drawing across border without wrap */
849 if (record->curs_state != 0)
850 curs_pos(record, record->x_curs, record->y_curs, 0);
852 ch = character;
853 is_control = (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L);
854 if (is_control)
855 do_control(record, ch);
856 else {
857 do_add_string(record, (char *) &ch, 1);
858 do_add_cursor(record, record->x_curs + 1);
861 return noErr;
865 * Add a null-terminated string of characters
867 short
868 add_tty_string(WindowPtr window, const char *string)
870 register const unsigned char *start_c;
871 register const unsigned char *the_c;
872 register unsigned char ch, is_control = 0, tty_wrap;
873 register short max_x, pos_x;
874 RECORD_EXISTS(record);
876 if (record->curs_state != 0)
877 curs_pos(record, record->x_curs, record->y_curs, 0);
879 the_c = (const unsigned char *) string;
880 max_x = record->x_size;
881 tty_wrap = (record->attribute[TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND);
882 for (;;) {
883 pos_x = record->x_curs;
884 if (!tty_wrap && pos_x >= max_x)
885 break; /* Optimize away drawing across border without wrap */
887 start_c = the_c;
888 ch = *the_c;
889 while (pos_x < max_x) {
890 is_control =
891 (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L);
892 if (is_control)
893 break;
894 the_c++;
895 ch = *the_c;
896 pos_x++;
898 do_add_string(record, (char *) start_c, the_c - start_c);
899 do_add_cursor(record, pos_x);
900 if (!ch)
901 break;
903 if (is_control) {
904 do_control(record, ch);
905 the_c++;
909 return noErr;
913 * Read or change attributes for the tty. Note that some attribs may
914 * very well clear and reallocate the bitmap when changed, whereas
915 * others (color, highlight, ...) are guaranteed not to.
917 short
918 get_tty_attrib(WindowPtr window, tty_attrib attrib, long *value)
920 RECORD_EXISTS(record);
922 if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) {
923 return general_failure;
925 *value = record->attribute[attrib];
927 return noErr;
930 short
931 set_tty_attrib(WindowPtr window, tty_attrib attrib, long value)
933 RGBColor rgb_color;
934 RECORD_EXISTS(record);
936 if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) {
937 return general_failure;
939 record->attribute[attrib] = value;
941 * Presently, no attributes generate a new bitmap.
943 switch (attrib) {
944 case TTY_ATTRIB_CURSOR:
946 * Check if we should change tables
948 if (0L != (value & TA_RAW_OUTPUT)) {
949 s_control = RAW_CONTROLS;
950 } else {
951 s_control = COOKED_CONTROLS;
953 break;
954 case TTY_ATTRIB_FLAGS:
956 * Check if we should flush the output going from cached to
957 * draw-direct
959 if (0L != (value & TA_ALWAYS_REFRESH)) {
960 update_tty(window);
962 break;
963 case TTY_ATTRIB_FOREGROUND:
965 * Set foreground color
967 TA_TO_RGB(value, rgb_color);
968 select_offscreen_port(record);
969 RGBForeColor(&rgb_color);
970 select_onscreen_window(record);
971 break;
972 case TTY_ATTRIB_BACKGROUND:
974 * Set background color
976 TA_TO_RGB(value, rgb_color);
977 select_offscreen_port(record);
978 RGBBackColor(&rgb_color);
979 select_onscreen_window(record);
980 break;
981 default:
982 break;
984 return noErr;
988 * Scroll the window. Positive is up/left. scroll_tty ( window, 0, 1 ) is a
989 * line feed.
990 * Scroll flushes the accumulated update area by calling update_tty().
993 short
994 scroll_tty(WindowPtr window, short delta_x, short delta_y)
996 RgnHandle rgn;
997 short s_err;
998 RECORD_EXISTS(record);
1000 s_err = update_tty(window);
1002 rgn = NewRgn();
1004 select_offscreen_port(record);
1005 ScrollRect(&(record->its_bits.bounds), -delta_x * record->char_width,
1006 -delta_y * record->row_height, rgn);
1007 EraseRgn(rgn);
1008 SetEmptyRgn(rgn);
1010 select_onscreen_window(record);
1011 ScrollRect(&(record->its_bits.bounds), -delta_x * record->char_width,
1012 -delta_y * record->row_height, rgn);
1013 EraseRgn(rgn);
1014 DisposeRgn(rgn);
1016 record->y_curs -= delta_y;
1017 record->x_curs -= delta_x;
1019 return noErr;
1023 * Clear the screen. Immediate.
1025 short
1026 clear_tty(WindowPtr window)
1028 RECORD_EXISTS(record);
1030 record->curs_state = 0;
1031 select_offscreen_port(record);
1032 erase_rect(record, &(record->its_bits.bounds));
1033 accumulate_rect(record, &(record->its_bits.bounds));
1034 update_tty(window);
1036 return noErr;
1040 * Blink cursor on window if necessary
1042 short
1043 blink_cursor(WindowPtr window, long when)
1045 RECORD_EXISTS(record);
1047 if ((record->attribute[TTY_ATTRIB_CURSOR] & TA_BLINKING_CURSOR)) {
1048 if (when > record->last_cursor + GetCaretTime()) {
1049 curs_pos(record, record->x_curs, record->y_curs,
1050 !record->curs_state);
1051 record->last_cursor = when;
1052 update_tty(window);
1055 return 0;
1059 * Draw an image of the tty - used for update events and can be called
1060 * for screen dumps.
1062 short
1063 image_tty(EventRecord *theEvent, WindowPtr window)
1065 #if defined(__SC__) || defined(__MRC__)
1066 #pragma unused(theEvent)
1067 #endif
1068 RECORD_EXISTS(record);
1070 #if CLIP_RECT_ONLY
1071 record->invalid_rect = record->its_bits.bounds;
1072 #else
1073 RgnHandle rh = NewRgn();
1075 RectRgn(rh, record->its_bits.bounds);
1076 UnionRgn(record->invalid_part, rh, record->invalid_part);
1077 DisposeRgn(rh);
1078 #endif
1079 return update_tty(window);
1083 * Clear an area
1085 short
1086 clear_tty_window(WindowPtr window, short from_x, short from_y, short to_x,
1087 short to_y)
1089 Rect r;
1090 RECORD_EXISTS(record);
1092 if (from_x > to_x || from_y > to_y) {
1093 return general_failure;
1095 pos_rect(record, &r, from_x, from_y, to_x, to_y);
1096 select_offscreen_port(record);
1097 erase_rect(record, &r);
1098 accumulate_rect(record, &r);
1099 if (DRAW_DIRECT) {
1100 update_tty(window);
1101 } else
1102 select_onscreen_window(record);
1103 return noErr;
1106 #if EXTENDED_SUPPORT
1108 * Delete or insert operations used by many terminals can bottleneck through
1109 * here. Note that the order of executin for row/colum insertions is NOT
1110 * specified. Negative values for num_ mean delete, zero means no effect.
1112 short
1113 mangle_tty_rows_columns(WindowPtr window, short from_row, short num_rows,
1114 short from_column, short num_columns)
1116 Rect r;
1117 RgnHandle rh = NewRgn();
1118 RECORD_EXISTS(record);
1120 update_tty(window); /* Always make sure screen is OK */
1121 curs_pos(record, record->x_curs, record->y_curs, 0);
1123 if (num_rows) {
1124 pos_rect(record, &r, 0, from_row, record->x_size - 1,
1125 record->y_size - 1);
1126 select_offscreen_port(record);
1127 ScrollRect(&r, 0, num_rows * record->row_height, rh);
1128 EraseRgn(rh);
1129 SetEmptyRgn(rh);
1130 select_onscreen_window(record);
1131 ScrollRect(&r, 0, num_rows * record->row_height, rh);
1132 EraseRgn(rh);
1133 SetEmptyRgn(rh);
1135 if (num_columns) {
1136 pos_rect(record, &r, from_column, 0, record->x_size - 1,
1137 record->y_size - 1);
1138 select_offscreen_port(record);
1139 ScrollRect(&r, num_columns * record->char_width, 0, rh);
1140 EraseRgn(rh);
1141 SetEmptyRgn(rh);
1142 select_onscreen_window(record);
1143 ScrollRect(&r, num_columns * record->char_width, 0, rh);
1144 EraseRgn(rh);
1145 SetEmptyRgn(rh);
1147 DisposeRgn(rh);
1148 if (record->x_curs >= from_column) {
1149 record->x_curs += num_columns;
1151 if (record->y_curs >= from_row) {
1152 record->y_curs += num_rows;
1154 curs_pos(record, record->x_curs, record->y_curs, 1);
1156 return noErr;
1160 * Frame an area in an aesthetically pleasing way.
1162 short
1163 frame_tty_window(WindowPtr window, short from_x, short from_y, short to_x,
1164 short to_y, short frame_fatness)
1166 Rect r;
1167 RECORD_EXISTS(record);
1169 if (from_x > to_x || from_y > to_y) {
1170 return general_failure;
1172 pos_rect(record, &r, from_x, from_y, to_x, to_y);
1173 select_offscreen_port(record);
1174 PenSize(frame_fatness, frame_fatness);
1175 FrameRect(&r);
1176 PenNormal();
1177 accumulate_rect(record, &r);
1178 if (DRAW_DIRECT) {
1179 update_tty(window);
1180 } else
1181 select_onscreen_window(record);
1185 * Highlighting a specific part of the tty window
1187 short
1188 invert_tty_window(WindowPtr window, short from_x, short from_y, short to_x,
1189 short to_y)
1191 Rect r;
1192 RECORD_EXISTS(record);
1194 if (from_x > to_x || from_y > to_y) {
1195 return general_failure;
1197 pos_rect(record, &r, from_x, from_y, to_x, to_y);
1198 select_offscreen_port(record);
1199 InvertRect(&r);
1200 accumulate_rect(record, &r);
1201 if (DRAW_DIRECT) {
1202 update_tty(window);
1203 } else
1204 select_onscreen_window(record);
1207 static void
1208 canonical_rect(Rect *r, short x1, short y1, short x2, short y2)
1210 if (x1 < x2) {
1211 if (y1 < y2) {
1212 SetRect(r, x1, x2, y1, y2);
1213 } else {
1214 SetRect(r, x1, x2, y2, y1);
1216 } else {
1217 if (y1 < y2) {
1218 SetRect(r, x2, x1, y1, y2);
1219 } else {
1220 SetRect(r, x2, x1, y2, y1);
1226 * Line drawing - very device dependent
1228 short
1229 draw_tty_line(WindowPtr window, short from_x, short from_y, short to_x,
1230 short to_y)
1232 Rect r;
1233 RECORD_EXISTS(record);
1235 select_offscreen_port(record);
1236 MoveTo(from_x, from_y);
1237 LineTo(to_x, to_y);
1238 canonical_rect(&r, from_x, from_y, to_x, to_y);
1239 accumulate_rect(record, &r);
1240 if (DRAW_DIRECT) {
1241 update_tty(window);
1242 } else
1243 select_onscreen_window(record);
1246 #endif /* EXTENDED_SUPPORT */