From 352a97e8334843ba6b51afe239544244947f7613 Mon Sep 17 00:00:00 2001 From: jwalz Date: Sat, 5 Jan 2002 21:05:55 +0000 Subject: [PATCH] *** empty log message *** --- sys/mac/mactty.c | 1201 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1201 insertions(+) create mode 100644 sys/mac/mactty.c diff --git a/sys/mac/mactty.c b/sys/mac/mactty.c new file mode 100644 index 000000000..c7cc56285 --- /dev/null +++ b/sys/mac/mactty.c @@ -0,0 +1,1201 @@ +/* SCCS Id: @(#)mactty.c 3.1 93/03/01 */ +/* Copyright (c) Jon W{tte 1993. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * mactty.c + * + * This file contains the actual code for the tty library. For a + * description, see the file mactty.h, which contains all you + * need to know to use the library. + */ + +#include "hack.h" /* to get flags */ +#include "mttypriv.h" +#include + +char game_active = 0; /* flag to window rendering routines not to use ppat */ + +/* these declarations are here because I can't include macwin.h without including the world */ +extern void dprintf(char *, ...); /* dprintf.c */ + +/* + * Borrowed from the Mac tty port + */ +extern WindowPtr _mt_window; + +static void select_onscreen_window (tty_record *record); +static void select_offscreen_port (tty_record *record); + +#define MEMORY_MARGIN 30000 + +/* + * Convenience macro for most functions - put last in declaration + */ +#define RECORD_EXISTS(record) \ + tty_record * record; \ + if (!window || !(record = (tty_record *) GetWRefCon (window))) \ + return general_failure; + + +/* + * Simple macro for deciding wether we draw at once or delay + */ +#define DRAW_DIRECT (TA_ALWAYS_REFRESH & record->attribute [TTY_ATTRIB_FLAGS]) + + +/* + * Table of special characters. Zero is ALWAYS special; it means + * end of string and would be MISSED if it was not included here. + */ +#define COOKED_CONTROLS 0X00002581 +#define RAW_CONTROLS 1 +static unsigned long s_control = COOKED_CONTROLS; + + +/* + * Memory-related error + */ +static short +mem_err (void) { + short ret_val = MemError(); + if (!ret_val) { + ret_val = general_failure; + } + return ret_val; +} + + +/* + * Make a rectangle empty + */ +static void +empty_rect (Rect *r) { + r->right = -20000; + r->left = 20000; + r->top = 20000; + r->bottom = -20000; +} + + +/* + * Union twp rect together + */ +static void +union_rect (Rect *r1, Rect *r2, Rect *dest) { + dest->left = min (r1->left, r2->left); + dest->top = min (r1->top, r2 ->top); + dest->bottom = max (r1->bottom, r2->bottom); + dest->right = max (r1->right, r2->right); +} + + +/* + * Dispose a pointer using the set memory-allocator + */ +static short +dispose_ptr (void *ptr) { + if (!ptr) { + return noErr; /* Silently accept disposing nulls */ + } + DisposePtr (ptr); + return MemError (); +} + + +/* + * Allocate a pointer using the set memory-allocator + */ +static short +alloc_ptr (void **ptr, long size) { + *ptr = NewPtr (size); + return MemError (); +} + + +/* + * Set up a GWorld in the record + */ +static short +allocate_offscreen_world (tty_record *record) { +GWorldPtr gw = (GWorldPtr)0; +GWorldFlags world_flags = 0; +long mem_here, mem_there, other, required_mem; +Point p = {0, 0}; +Rect r_screen; +GDHandle gdh; +short s_err; + + select_onscreen_window (record); + LocalToGlobal (&p); + r_screen = record->its_bits.bounds; + OffsetRect (&r_screen, p.h, p.v); + + gdh = GetMaxDevice (&r_screen); + required_mem = (long) (*((*gdh)->gdPMap))->pixelSize * + ((long) record->its_bits.bounds.right * + record->its_bits.bounds.bottom) >> 3; + + PurgeSpace (&other, &mem_here); + if (other < mem_here + MEMORY_MARGIN) { + mem_here = other - MEMORY_MARGIN; + } + dprintf ("Heap %ld Required %ld", mem_here, required_mem); + if (required_mem > mem_here) { + mem_there = required_mem; + if (required_mem > TempMaxMem (&mem_there)) { + dprintf ("No memory"); + return memFullErr; + } + world_flags |= useTempMem; + } + s_err = NewGWorld (&gw, 0, &r_screen, (CTabHandle) 0, (GDHandle) 0, world_flags); + if (!s_err) { + record->offscreen_world = gw; + select_offscreen_port (record); + SetOrigin (0, 0); + select_onscreen_window (record); + dprintf ("New GWorld @ %lx;dm", gw); + } + return s_err; +} + + +/* + * Done with GWorld, release data + */ +static short +deallocate_gworld (tty_record *record) { + if (record->offscreen_world) { + DisposeGWorld (record->offscreen_world); + record->offscreen_world = (GWorldPtr) 0; + } + return noErr; +} + + + + +/* + * Get rid of offscreen bitmap + */ +static short +free_bits (tty_record *record) { + short s_err; + + if (record->uses_gworld) { + s_err = deallocate_gworld (record); + } else { + s_err = dispose_ptr (record->its_bits.baseAddr); + if (!s_err) { + record->its_bits.baseAddr = (char *)0; + if (record->offscreen_port) { + ClosePort (record->offscreen_port); + s_err = dispose_ptr (record->offscreen_port); + if (!s_err) { + record->offscreen_port = (GrafPtr) 0; + } + } + } + } + return s_err; +} + + +/* + * Snatch a window from the resource fork. Create the record. + * Otherwise, do nothing. + */ + +short create_tty (WindowPtr *window, short resource_id, Boolean in_color) { +tty_record * record; +Boolean was_allocated = !!*window; + + if (in_color) { + *window = GetNewCWindow (resource_id, (Ptr) *window, (WindowPtr) -1L); + } else { + *window = GetNewWindow (resource_id, (Ptr) *window, (WindowPtr) -1L); + } + if (!*window) { + return mem_err (); + } + + record = (tty_record *) NewPtrClear (sizeof (tty_record)); + if (!record) { + if (was_allocated) { + CloseWindow (*window); + } else { + DisposeWindow (*window); + } + return mem_err (); + } + record->its_window = *window; + SetWRefCon (*window, (long) record); + record->was_allocated = was_allocated; + record->its_bits.baseAddr = (char *)0; + record->curs_state = TRUE; + +/* + * We need to keep the window world around if we switch worlds + */ + record->offscreen_world = (GWorldPtr) 0; + record->uses_gworld = in_color; + if (in_color) { + GDHandle gh; + + SetPort (*window); + GetGWorld ( &(record ->its_window_world), &gh); + } else { + record->its_window_world = (GWorldPtr)0; + } + +#if CLIP_RECT_ONLY + empty_rect (&(record->invalid_rect)); +#else + record->invalid_part = NewRgn (); + if (!record->invalid_part) { + return destroy_tty (*window); + } +#endif + + return noErr; +} + + +short +init_tty_number (WindowPtr window, short font_number, short font_size, + short x_size, short y_size) { +RECORD_EXISTS (record); + + record->font_number = font_number; + record->font_size = font_size; + record->x_size = x_size; + record->y_size = y_size; + + return force_tty_coordinate_system_recalc (window); +} + + +/* + * Done with a window - destroy it. Release the memory only if + * it wasn't allocated when we got it! + */ +short +destroy_tty (WindowPtr window) { +short s_err; +RECORD_EXISTS (record); + + s_err = free_bits (record); + if (!s_err) { + if (record->was_allocated) { + CloseWindow (window); + } else { + DisposeWindow (window); + } + s_err = dispose_ptr (record); + } + + return s_err; +} + + +static void +do_set_port_font (tty_record *record) { + + PenNormal (); + TextFont (record->font_number); + TextSize (record->font_size); + if (0L != (record->attribute [TTY_ATTRIB_FLAGS] & TA_OVERSTRIKE)) { + TextMode (srcOr); + } else { + TextMode (srcCopy); + } +} + + +/* + * Fill in some fields from some other fields that may have changed + */ +static void +calc_font_sizes (tty_record *record) { +FontInfo font_info; + + do_set_port_font (record); + + GetFontInfo (&font_info); + record->char_width = font_info.widMax; + record->ascent_height = font_info.ascent + font_info.leading; + record->row_height = record->ascent_height + font_info.descent; +} + + +/* + * Allocate memory for the bitmap holding the tty window + */ +static short +alloc_bits (tty_record *record) { +short s_err; + + SetRect (&record->its_bits.bounds, 0, 0, + record->char_width * record->x_size, + record->row_height * record->y_size); + +/* + * Clear two highest and lowest bit - not a color pixMap, and even in size + */ + record->its_bits.rowBytes = ((record->its_bits.bounds.right + 15) + >> 3) & 0x1ffe; + + if (record->uses_gworld) { + s_err = allocate_offscreen_world (record); + } else { + s_err = alloc_ptr ((void **) &(record->its_bits.baseAddr), + record->its_bits.rowBytes * record->its_bits.bounds.bottom); + if (!s_err) { + s_err = alloc_ptr ((void **) &(record->offscreen_port), + sizeof (GrafPort)); + } + if (!s_err) { + OpenPort (record->offscreen_port); + SetPort (record->offscreen_port); + ClipRect (&(record->its_bits.bounds)); + SetPortBits (&(record->its_bits)); + } + } + return s_err; +} + + +/* + * Save the current port/world in a safe place for later retrieval + */ +static void +save_port (tty_record *record, void *save) { +GWorldPtr gw; +GDHandle gh; +GrafPtr gp; + + if (record->uses_gworld) { + GetGWorld (&gw, &gh); + *(GWorldPtr *) save = gw; + } else { + GetPort (&gp); + *(GrafPtr *) save = gp; + } +} + + +/* + * Restore current port/world after a save + */ +static void +use_port (tty_record *record, void *port) { + if (record->uses_gworld) { + PixMapHandle pix_map; + + SetGWorld ((GWorldPtr) port, (GDHandle) 0); + pix_map = GetGWorldPixMap (record->offscreen_world); + if (pix_map) { + if (port == record->offscreen_world) + LockPixels (pix_map); + else + UnlockPixels (pix_map); + } + } else { + SetPort ((GrafPtr) port); + } +} + + +/* + * Use offscreen drawing - lock the pixels through use_port + */ +static void +select_offscreen_port (tty_record *record) { + if (record->uses_gworld) { + use_port (record, record->offscreen_world); + } else { + use_port (record, record->offscreen_port); + } +} + + +/* + * Use the window - unlock pixels + */ +static void +select_onscreen_window (tty_record *record) { + if (record->uses_gworld) { + use_port (record, record->its_window_world); + SetPort (record->its_window); + } else { + use_port (record, record->its_window); + } +} + + +/* + * Do bits copy depending on if we're using color or not + */ +static void +copy_bits (tty_record *record, Rect *bounds, short xfer_mode, RgnHandle mask_rgn) { +GWorldFlags pix_state; +BitMap * source; + + if (record->uses_gworld) { + pix_state = GetPixelsState (GetGWorldPixMap (record->offscreen_world)); + LockPixels (GetGWorldPixMap (record->offscreen_world)); + source = (BitMap *) &record->offscreen_world->portPixMap; + } + else source = &record->its_bits; + + CopyBits (source, &(record->its_window->portBits), bounds, bounds, xfer_mode, mask_rgn); + + if (record->uses_gworld) { + SetPixelsState (GetGWorldPixMap (record->offscreen_world), pix_state); + } +} + + +/* + * Fill an area with the background color + */ +static void +erase_rect (tty_record *record, Rect *area) { + if (game_active && u.uhp > 0 && iflags.use_stone && record->its_window == _mt_window) { + PixPatHandle ppat; + + ppat = GetPixPat(iflags.use_stone + 127); /* find which pat to get */ + if (ppat) { /* in game window, using backgroung pattern, and have pattern */ + FillCRect (area, ppat); + DisposePixPat (ppat); + return; + } + } + EraseRect (area); +} + + +/* + * Recalculate the window based on new size, font, extent values, + * and re-allocate the bitmap. + */ +short +force_tty_coordinate_system_recalc (WindowPtr window) { +short s_err; +RECORD_EXISTS (record); + + s_err = free_bits (record); + if (s_err) { + return s_err; + } + calc_font_sizes (record); + + s_err = alloc_bits (record); + if (s_err) { +/* + * Catastrophe! We could not allocate memory for the bitmap! Things may go very + * much downhill from here! + */ + dprintf ("alloc_bits returned null in force_tty_coordinate_system_recalc!"); + return s_err; + } + select_offscreen_port (record); + do_set_port_font (record); + return clear_tty (window); +} + + +/* + * Update TTY according to new color environment for the window + */ +static short +tty_environment_changed (tty_record *record) { +Point p = {0, 0}; +Rect r_screen; + + if (record->uses_gworld) { + r_screen = record->its_bits.bounds; + LocalToGlobal (&p); + OffsetRect (&r_screen, p.h, p.v); + UpdateGWorld (&(record->offscreen_world), 0, &r_screen, + (CTabHandle) 0, (GDHandle) 0, stretchPix); + select_offscreen_port (record); + SetOrigin (0, 0); + select_onscreen_window (record); + } + return 0; +} + + +/* + * Read a lot of interesting and useful information from the current tty + */ +short +get_tty_metrics (WindowPtr window, short *x_size, short *y_size, + short *x_size_pixels, short *y_size_pixels, short *font_number, + short *font_size, short *char_width, short *row_height) { +RECORD_EXISTS (record); + +/* + * First, test that we actually have something to draw to... + */ + if ((((char *)0 == record->its_bits.baseAddr) && !record->uses_gworld) || + (((GWorldPtr)0 == record->offscreen_world) && record->uses_gworld)) { + return general_failure; + } + + *x_size = record->x_size; + *y_size = record->y_size; + *x_size_pixels = record->its_bits.bounds.right; + *y_size_pixels = record->its_bits.bounds.bottom; + *font_number = record->font_number; + *font_size = record->font_size; + *char_width = record->char_width; + *row_height = record->row_height; + + return noErr; +} + + +/* + * Map a position on the map to screen coordinates + */ +static void +pos_rect (tty_record *record, Rect *r, short x_pos, short y_pos, + short x_end, short y_end) { + + SetRect (r, x_pos * (record->char_width), y_pos * (record->row_height), + (1 + x_end) * (record->char_width) , (1 + y_end) * + (record->row_height)); +} + + +static void +accumulate_rect (tty_record *record, Rect *rect) { +#if CLIP_RECT_ONLY + union_rect (rect, &(record->invalid_rect), &(record->invalid_rect)); +#else +RgnHandle rh = NewRgn (); + + RectRgn (rh, rect); + UnionRgn (record->invalid_part, rh, record->invalid_part); + DisposeRgn (rh); +#endif +} + + +/* + * get and set window invalid region. exposed for HandleUpdateEvent in macwin.c + * to correct display problem + */ + +short get_invalid_region (WindowPtr window, Rect *inval_rect) { + RECORD_EXISTS (record); +#if CLIP_RECT_ONLY + if (record->invalid_rect.right <= record->invalid_rect.left || + record->invalid_rect.bottom <= record->invalid_rect.top) { + return general_failure; + } + *inval_rect = record->invalid_rect; +#else + if (EmptyRgn (record->invalid_part)) { + return return general_failure; + } + *inval_rect = (*(record->invalid_part))->rgnBBox; +#endif + return noErr; +} + +short set_invalid_region (WindowPtr window, Rect *inval_rect) { + RECORD_EXISTS (record); + accumulate_rect (record, inval_rect); + return noErr; +} + + +/* + * Invert the specified position + */ +static void +curs_pos (tty_record *record, short x_pos, short y_pos, short to_state) { +Rect r; + + if (record->curs_state == to_state) { + return; + } + record->curs_state = to_state; + pos_rect (record, &r, x_pos, y_pos, x_pos, y_pos); + + if (DRAW_DIRECT) { + void *old_port; + + save_port (record, &old_port); + select_onscreen_window (record); + InvertRect (&r); + use_port (record, old_port); + } else { + accumulate_rect (record, &r); + } +} + + +/* + * Move the cursor (both as displayed and where drawing goes) + * HOWEVER: The cursor is NOT stored in the bitmap! + */ +short +move_tty_cursor (WindowPtr window, short x_pos, short y_pos) { +RECORD_EXISTS (record); + + if (record->x_curs == x_pos && record->y_curs == y_pos) { + return noErr; + } + if (record->x_size <= x_pos || x_pos < 0 || + record->y_size <= y_pos || y_pos < 0) { + return general_failure; + } + curs_pos (record, record->x_curs, record->y_curs, 0); + record->x_curs = x_pos; + record->y_curs = y_pos; + curs_pos (record, x_pos, y_pos, 1); + + return noErr; +} + + +/* + * Update the screen to match the current bitmap, after adding stuff + * with add_tty_char etc. + */ +short +update_tty (WindowPtr window) { +Rect r; +RECORD_EXISTS (record); + +#if CLIP_RECT_ONLY + if (record->invalid_rect.right <= record->invalid_rect.left || + record->invalid_rect.bottom <= record->invalid_rect.top) { + return noErr; + } + r = record->invalid_rect; +#else + if (EmptyRgn (record->invalid_part)) { + return noErr; + } + r = (*(record->invalid_part))->rgnBBox; +#endif + select_onscreen_window (record); + copy_bits (record, &r, srcCopy, (RgnHandle) 0); +#if CLIP_RECT_ONLY + empty_rect (&(record->invalid_rect)); +#else + SetEmptyRgn (record->invalid_part); +#endif + if (record->curs_state) { + pos_rect (record, &r, record->x_curs, record->y_curs, + record->x_curs, record->y_curs); + InvertRect (&r); + } + + return noErr; +} + + +/* + * Low level add to screen + */ +static void +do_add_string (tty_record *record, char *str, short len) { +Rect r; + + if (len < 1) { + return; + } + select_offscreen_port (record); + + MoveTo (record->x_curs * record->char_width, record->y_curs * + record->row_height + record->ascent_height); + DrawText (str, 0, len); + + pos_rect (record, &r, record->x_curs, record->y_curs, + record->x_curs + len - 1, record->y_curs); + select_onscreen_window (record); + if (DRAW_DIRECT) { + copy_bits (record, &r, srcCopy, (RgnHandle)0); + } else { + accumulate_rect (record, &r); + } +} + + +/* + * Low-level cursor handling routine + */ +static void +do_add_cursor (tty_record *record, short x_pos) { + + record->x_curs = x_pos; + if (record->x_curs >= record->x_size) { + if (0L != (record->attribute [TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND)) { + record->y_curs ++; + record->x_curs = 0; + if (record->y_curs >= record->y_size) { + if (0L != (record->attribute [TTY_ATTRIB_FLAGS] & + TA_INHIBIT_VERT_SCROLL)) { + record->y_curs = record->y_size; + } else { + scroll_tty (record->its_window, 0, 1 + record->y_curs - + record->y_size); + } + } + } else { + record->x_curs = record->x_size; + } + } +} + + +/* + * Do control character + */ +static void +do_control (tty_record *record, short character) { + int recurse = 0; + +/* + * Check recursion because nl_add_cr and cr_add_nl may both be set and invoke each other + */ + do { + switch (character) { + case CHAR_CR : + record->x_curs = 0; + if (!recurse && (record->attribute [TTY_ATTRIB_CURSOR] & TA_CR_ADD_NL)) { + recurse = 1; + } + else { + recurse = 0; + break; + } /* FALL-THROUGH: if CR-LF, don't bother with loop */ + case CHAR_LF : + record->y_curs++; + if (record->y_curs >= record->y_size) { + scroll_tty (record->its_window, 0, 1 + record->y_curs - record->y_size); + } + if (!recurse && (record->attribute [TTY_ATTRIB_CURSOR] & TA_NL_ADD_CR)) { + character = CHAR_CR; + recurse = 1; + } + else recurse = 0; + break; + case CHAR_BELL : + tty_nhbell(); + break; + case CHAR_BS : + if (record->x_curs > 0) + record->x_curs --; + default : + break; + } + } while (recurse); +} + + +/* + * Add a single character. It is drawn directly if the correct flag is set, + * else deferred to the next update event or call of update_tty() + */ +short +add_tty_char (WindowPtr window, short character) { +register char is_control; +char ch; +RECORD_EXISTS (record); + + if (!(record->attribute [TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND) && + record->x_curs >= record->x_size) + return noErr; /* Optimize away drawing across border without wrap */ + + if (record->curs_state != 0) + curs_pos (record, record->x_curs, record->y_curs, 0); + + ch = character; + is_control = (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L); + if (is_control) + do_control (record, ch); + else { + do_add_string (record, (char *)&ch, 1); + do_add_cursor (record, record->x_curs + 1); + } + + return noErr; +} + + +/* + * Add a null-terminated string of characters + */ +short +add_tty_string (WindowPtr window, const char *string) { +register const unsigned char * start_c; +register const unsigned char * the_c; +register unsigned char ch, is_control, tty_wrap; +register short max_x, pos_x; +RECORD_EXISTS (record); + + if (record->curs_state != 0) + curs_pos (record, record->x_curs, record->y_curs, 0); + + the_c = (const unsigned char *) string; + max_x = record->x_size; + tty_wrap = (record->attribute [TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND); + for (;;) { + pos_x = record->x_curs; + if (!tty_wrap && pos_x >= max_x) + break; /* Optimize away drawing across border without wrap */ + + start_c = the_c; + ch = *the_c; + while (pos_x < max_x) { + is_control = (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L); + if (is_control) + break; + the_c ++; ch = *the_c; + pos_x ++; + } + do_add_string (record, (char *) start_c, the_c - start_c); + do_add_cursor (record, pos_x); + if (!ch) + break; + + if (is_control) { + do_control (record, ch); + the_c ++; + } + } + + return noErr; +} + + +/* + * Read or change attributes for the tty. Note that some attribs may + * very well clear and reallocate the bitmap when changed, whereas + * others (color, highlight, ...) are guaranteed not to. + */ +short get_tty_attrib (WindowPtr window, tty_attrib attrib, long *value) { +RECORD_EXISTS (record); + + if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) { + return general_failure; + } + *value = record->attribute [attrib]; + + return noErr; +} + + +short set_tty_attrib (WindowPtr window, tty_attrib attrib, long value) { +RGBColor rgb_color; +RECORD_EXISTS (record); + + if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) { + return general_failure; + } + record->attribute [attrib] = value; + /* + * Presently, no attributes generate a new bitmap. + */ + switch (attrib) { + case TTY_ATTRIB_CURSOR : +/* + * Check if we should change tables + */ + if (0L != (value & TA_RAW_OUTPUT)) { + s_control = RAW_CONTROLS; + } else { + s_control = COOKED_CONTROLS; + } + break; + case TTY_ATTRIB_FLAGS : +/* + * Check if we should flush the output going from cached to draw-direct + */ + if (0L != (value & TA_ALWAYS_REFRESH)) { + update_tty (window); + } + break; + case TTY_ATTRIB_FOREGROUND : +/* + * Set foreground color + */ + TA_TO_RGB (value, rgb_color); + select_offscreen_port (record); + RGBForeColor (&rgb_color); + select_onscreen_window (record); + break; + case TTY_ATTRIB_BACKGROUND : +/* + * Set background color + */ + TA_TO_RGB (value, rgb_color); + select_offscreen_port (record); + RGBBackColor (&rgb_color); + select_onscreen_window (record); + break; + default : + break; + } + return noErr; +} + + +/* + * Scroll the window. Positive is up/left. scroll_tty ( window, 0, 1 ) is a line feed. + * Scroll flushes the accumulated update area by calling update_tty(). + */ + +short scroll_tty (WindowPtr window, short delta_x, short delta_y) { +RgnHandle rgn; +short s_err; +RECORD_EXISTS (record); + + s_err = update_tty (window); + + rgn = NewRgn (); + + select_offscreen_port (record); + ScrollRect (&(record->its_bits.bounds), -delta_x * record->char_width, + -delta_y * record->row_height, rgn); + EraseRgn (rgn); + SetEmptyRgn (rgn); + + select_onscreen_window (record); + ScrollRect (&(record->its_bits.bounds), -delta_x * record->char_width, + -delta_y*record->row_height, rgn); + EraseRgn (rgn); + DisposeRgn (rgn); + + record->y_curs -= delta_y; + record->x_curs -= delta_x; + + return noErr; +} + + +/* + * Clear the screen. Immediate. + */ +short clear_tty (WindowPtr window) { +RECORD_EXISTS (record); + + record->curs_state = 0; + select_offscreen_port (record); + erase_rect (record, &(record->its_bits.bounds)); + accumulate_rect (record, &(record->its_bits.bounds)); + update_tty (window); + + return noErr; +} + + +/* + * Blink cursor on window if necessary + */ +short blink_cursor (WindowPtr window, long when) { + RECORD_EXISTS (record); + + if ((record->attribute [TTY_ATTRIB_CURSOR] & TA_BLINKING_CURSOR)) { + if (when > record->last_cursor + GetCaretTime ()) { + curs_pos (record, record->x_curs, record->y_curs, !record->curs_state); + record->last_cursor = when; + update_tty (window); + } + } + return 0; +} + + +/* + * Draw an image of the tty - used for update events and can be called + * for screen dumps. + */ +short +image_tty (EventRecord *theEvent, WindowPtr window) { +#if defined(applec) || defined(__MWERKS__) +# pragma unused(theEvent) +#endif +RECORD_EXISTS (record); + +#if CLIP_RECT_ONLY + record->invalid_rect = record->its_bits.bounds; +#else +RgnHandle rh = NewRgn (); + + RectRgn (rh, record ->its_bits.bounds); + UnionRgn (record->invalid_part, rh, record->invalid_part); + DisposeRgn (rh); +#endif + return update_tty (window); +} + + + +/* + * Clear an area + */ +short clear_tty_window (WindowPtr window, short from_x, short from_y, + short to_x, short to_y) { +Rect r; +RECORD_EXISTS (record); + + if (from_x > to_x || from_y > to_y) { + return general_failure; + } + pos_rect (record, &r, from_x, from_y, to_x, to_y); + select_offscreen_port (record); + erase_rect (record, &r); + accumulate_rect (record, &r); + if (DRAW_DIRECT) { + update_tty (window); + } else + select_onscreen_window (record); + return noErr; +} + + +#if EXTENDED_SUPPORT +/* + * Delete or insert operations used by many terminals can bottleneck through + * here. Note that the order of executin for row/colum insertions is NOT + * specified. Negative values for num_ mean delete, zero means no effect. + */ +short mangle_tty_rows_columns (WindowPtr window, short from_row, short num_rows, + short from_column, short num_columns) { +Rect r; +RgnHandle rh = NewRgn (); +RECORD_EXISTS (record); + + update_tty (window); /* Always make sure screen is OK */ + curs_pos (record, record->x_curs, record->y_curs, 0); + + if (num_rows) { + pos_rect (record, &r, 0, from_row, record->x_size - 1, + record->y_size - 1); + select_offscreen_port (record); + ScrollRect (&r, 0, num_rows * record->row_height, rh); + EraseRgn (rh); + SetEmptyRgn (rh); + select_onscreen_window (record); + ScrollRect (&r, 0, num_rows * record->row_height, rh); + EraseRgn (rh); + SetEmptyRgn (rh); + } + if (num_columns) { + pos_rect (record, &r, from_column, 0, record->x_size - 1, + record->y_size - 1); + select_offscreen_port (record); + ScrollRect (&r, num_columns * record->char_width, 0, rh); + EraseRgn (rh); + SetEmptyRgn (rh); + select_onscreen_window (record); + ScrollRect (&r, num_columns * record->char_width, 0, rh); + EraseRgn (rh); + SetEmptyRgn (rh); + } + DisposeRgn (rh); + if (record->x_curs >= from_column) { + record->x_curs += num_columns; + } + if (record->y_curs >= from_row) { + record->y_curs += num_rows; + } + curs_pos (record, record->x_curs, record->y_curs, 1); + + return noErr; +} + +/* + * Frame an area in an aesthetically pleasing way. + */ +short frame_tty_window (WindowPtr window, short from_x, short from_y , + short to_x, short to_y, short frame_fatness) { +Rect r; +RECORD_EXISTS (record); + + if (from_x > to_x || from_y > to_y) { + return general_failure; + } + pos_rect (record, & r, from_x, from_y, to_x, to_y); + select_offscreen_port (record); + PenSize (frame_fatness, frame_fatness); + FrameRect (&r); + PenNormal (); + accumulate_rect (record, &r); + if (DRAW_DIRECT) { + update_tty (window); + } else + select_onscreen_window (record); +} + + +/* + * Highlighting a specific part of the tty window + */ +short invert_tty_window (WindowPtr window, short from_x, short from_y , + short to_x, short to_y) { +Rect r; +RECORD_EXISTS (record); + + if (from_x > to_x || from_y > to_y) { + return general_failure; + } + pos_rect (record, &r, from_x, from_y, to_x, to_y); + select_offscreen_port (record); + InvertRect ( &r); + accumulate_rect (record, &r); + if (DRAW_DIRECT) { + update_tty (window); + } else + select_onscreen_window (record); +} + + +static void +canonical_rect (Rect * r, short x1, short y1, short x2, short y2) { + if (x1 < x2) { + if (y1 < y2) { + SetRect (r, x1, x2, y1, y2); + } else { + SetRect (r, x1, x2, y2, y1); + } + } else { + if (y1 < y2) { + SetRect (r, x2, x1, y1, y2); + } else { + SetRect (r, x2, x1, y2, y1); + } + } +} + + +/* + * Line drawing - very device dependent + */ +short draw_tty_line (WindowPtr window, short from_x, short from_y , + short to_x, short to_y) { +Rect r; +RECORD_EXISTS (record); + + select_offscreen_port (record); + MoveTo (from_x, from_y); + LineTo (to_x, to_y); + canonical_rect (&r, from_x, from_y, to_x, to_y); + accumulate_rect (record, &r); + if (DRAW_DIRECT) { + update_tty (window); + } else + select_onscreen_window (record); +} + + +#endif /* EXTENDED_SUPPORT */