home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / sys / mac / mactty.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  36.1 KB  |  1,551 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)mactty.c    3.1    93/03/01            */
  2. /* Copyright (c) Jon W{tte 1993.                    */
  3. /* NetHack may be freely redistributed.  See license for details.    */
  4.  
  5. /*
  6.  * mactty.c
  7.  *
  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.
  11.  */
  12.  
  13. #include "mttypriv.h"
  14.  
  15. #if PRINTF_TTY
  16. # include <stdio.h>
  17. # include <stdarg.h>
  18. #endif
  19.  
  20. extern void dprintf ( char * , ... ) ;
  21. static void select_onscreen_window ( tty_record * record ) ;
  22. static void select_offscreen_port ( tty_record * record ) ;
  23.  
  24. #define MEMORY_MARGIN 30000
  25.  
  26.  
  27. /*
  28.  * Error code returned when it's probably our fault, or
  29.  * bad parameters.
  30.  */
  31. #define general_failure 1
  32.  
  33. /*
  34.  * How long lines do we support for input?
  35.  */
  36. #define IB_LIMIT 80
  37.  
  38. /*
  39.  * Convenience macro for most functions - put last in declaration
  40.  */
  41. #define RECORD(record) \
  42. tty_record * record ; \
  43.     if ( ! window ) { \
  44.         dprintf ( "*** NULL Window ***" ) ; \
  45.         return general_failure ; \
  46.     } \
  47.     record = ( tty_record * ) GetWRefCon ( window ) ; \
  48.     if ( ! record ) { \
  49.         return general_failure ; \
  50.     }
  51.  
  52. /*
  53.  * Simple macro for deciding wether we draw at once or delay
  54.  */
  55. #define DRAW_DIRECT ( 0L != ( TA_ALWAYS_REFRESH & record -> \
  56.     attribute [ TTY_ATTRIB_FLAGS ] ) )
  57.  
  58.  
  59. /*
  60.  * Module variable used as return value for various calls.
  61.  */
  62. static short s_err = 0 ;
  63.  
  64. /*
  65.  * Table of special characters. Zero is ALWAYS special; it means
  66.  * end of string and would be MISSED if it was not included here.
  67.  */
  68. static const unsigned char s_cooked_controls [ ] = {
  69.     1,    0,    0,    0,    0,    0,    0,    1,    1,    0,    1,    0,    0,    1,    0,    0,
  70.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  71.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  72.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  73.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  74.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  75.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  76.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  77.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  78.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  79.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  80.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  81.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  82.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  83.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  84.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  85. } ;
  86.  
  87. static const unsigned char s_raw_controls [ ] = {
  88.     1,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  89.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  90.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  91.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  92.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  93.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  94.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  95.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  96.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  97.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  98.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  99.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  100.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  101.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  102.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  103.     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  104. } ;
  105.  
  106. static const unsigned char * s_control = s_cooked_controls ;
  107.  
  108.  
  109. /*
  110.  * Memory-related error
  111.  */
  112. static short
  113. mem_err ( void ) {
  114.     if ( MemError ( ) ) {
  115.         return MemError ( ) ;
  116.     }
  117.     return general_failure ;
  118. }
  119.  
  120.  
  121. /*
  122.  * Make a rectangle empty
  123.  */
  124. static void
  125. empty_rect ( Rect * r ) {
  126.  
  127.     r -> right = -20000 ;
  128.     r -> left = 20000 ;
  129.     r -> top = 20000 ;
  130.     r -> bottom = -20000 ;
  131. }
  132.  
  133.  
  134. /*
  135.  * Union twp rect together
  136.  */
  137. static void
  138. union_rect ( Rect * r1 , Rect * r2 , Rect * dest ) {
  139.  
  140.     if ( r1 -> left < r2 -> left ) {
  141.         dest -> left = r1 -> left ;
  142.     } else {
  143.         dest -> left = r2 -> left ;
  144.     }
  145.  
  146.     if ( r1 -> top < r2 -> top ) {
  147.         dest -> top = r1 -> top ;
  148.     } else {
  149.         dest -> top = r2 -> top ;
  150.     }
  151.  
  152.     if ( r1 -> bottom > r2 -> bottom ) {
  153.         dest -> bottom = r1 -> bottom ;
  154.     } else {
  155.         dest -> bottom = r2 -> bottom ;
  156.     }
  157.  
  158.     if ( r1 -> right > r2 -> right ) {
  159.         dest -> right = r1 -> right ;
  160.     } else {
  161.         dest -> right = r2 -> right ;
  162.     }
  163. }
  164.  
  165.  
  166. /*
  167.  * Dispose a pointer using the set memory-allocator
  168.  */
  169. static short
  170. dispose_ptr ( tty_record * record , void * ptr ) {
  171. pascal short ( * func ) ( WindowPtr window , void * ptr ) =
  172.     ( pascal short ( * ) ( WindowPtr , void * ) )
  173.     record -> attribute [ TTY_FREE_MEMORY_FUNCTION ] ;
  174.  
  175.     if ( ! ptr ) {
  176.         return noErr ; /* Silently accept disposing NULLs */
  177.     }
  178.     if ( func ) {
  179.         s_err = ( * func ) ( record -> its_window , ptr ) ;
  180.     } else {
  181.         DisposePtr ( ptr ) ;
  182.         s_err = MemError ( ) ;
  183.     }
  184.     return s_err ;
  185. }
  186.  
  187.  
  188. /*
  189.  * Allocate a pointer using the set memory-allocator
  190.  */
  191. static short
  192. alloc_ptr ( tty_record * record , void * * ptr , long size ) {
  193. pascal short ( * func ) ( WindowPtr window , void * * ptr , long ) =
  194.     ( pascal short ( * ) ( WindowPtr , void * * , long ) )
  195.     record -> attribute [ TTY_ALLOCATE_MEMORY_FUNCTION ] ;
  196.  
  197.     if ( func ) {
  198.         s_err = ( * func ) ( record -> its_window , ptr , size ) ;
  199.     } else {
  200.         * ptr = NewPtr ( size ) ;
  201.         s_err = * ptr ? noErr : mem_err ( ) ;
  202.     }
  203.     return s_err ;
  204. }
  205.  
  206.  
  207. /*
  208.  * Set up a GWorld in the record
  209.  */
  210. static short
  211. allocate_offscreen_world ( tty_record * record ) {
  212. GWorldPtr gw = NULL ;
  213. GWorldFlags world_flags = 0 ;
  214. long mem_here , mem_there , other , required_mem ;
  215. Point p = { 0 , 0 } ;
  216. Rect r_screen ;
  217. GDHandle gdh ;
  218.  
  219.     select_onscreen_window ( record ) ;
  220.     LocalToGlobal ( & p ) ;
  221.     r_screen = record -> its_bits . bounds ;
  222.     OffsetRect ( & r_screen , p . h , p . v ) ;
  223.  
  224.     gdh = GetMaxDevice ( & r_screen ) ;
  225.     required_mem = ( long ) ( * ( ( * gdh ) -> gdPMap ) ) -> pixelSize *
  226.         ( ( long ) record -> its_bits . bounds . right *
  227.         record -> its_bits . bounds . bottom ) >> 3 ;
  228.  
  229.     PurgeSpace ( & other , & mem_here ) ;
  230.     if ( other < mem_here + MEMORY_MARGIN ) {
  231.         mem_here = other - MEMORY_MARGIN ;
  232.     }
  233.     dprintf ( "Heap %ld Required %ld" , mem_here , required_mem ) ;
  234.     if ( required_mem > mem_here ) {
  235.         mem_there = required_mem ;
  236.         if ( required_mem > MFMaxMem ( & mem_there ) ) {
  237.             dprintf ( "No memory" ) ;
  238.             return memFullErr ;
  239.         }
  240.         world_flags |= useTempMem ;
  241.     }
  242.     s_err = NewGWorld ( & gw , 0 , & r_screen , NULL , NULL , world_flags ) ;
  243.     if ( ! s_err ) {
  244.         record -> offscreen_world = gw ;
  245.         select_offscreen_port ( record ) ;
  246.         SetOrigin ( 0 , 0 ) ;
  247.         select_onscreen_window ( record ) ;
  248.         dprintf ( "New GWorld @ %lx;dm %lx CGrafPtr" , gw , gw ) ;
  249.     }
  250.     return s_err ;
  251. }
  252.  
  253.  
  254. /*
  255.  * Done with GWorld, release data
  256.  */
  257. static short
  258. deallocate_gworld ( tty_record * record ) {
  259.     if ( record -> offscreen_world ) {
  260.         DisposeGWorld ( record -> offscreen_world ) ;
  261.         record -> offscreen_world = NULL ;
  262.     }
  263.     return noErr ;
  264. }
  265.  
  266.  
  267. /*
  268.  * Save the current port/world in a safe place for later retrieval
  269.  */
  270. static void
  271. save_port ( tty_record * record , void * save ) {
  272. GWorldPtr gw ;
  273. GDHandle gh ;
  274. GrafPtr gp ;
  275.  
  276.     if ( record -> uses_gworld ) {
  277.         GetGWorld ( & gw , & gh ) ;
  278.         * ( GWorldPtr * ) save = gw ;
  279.     } else {
  280.         GetPort ( & gp ) ;
  281.         * ( GrafPtr * ) save = gp ;
  282.     }
  283. }
  284.  
  285.  
  286. /*
  287.  * Restore current port/world after a save
  288.  */
  289. static void
  290. use_port ( tty_record * record , void * port ) {
  291.     if ( record -> uses_gworld ) {
  292.     PixMapHandle pix_map ;
  293.  
  294.         SetGWorld ( ( GWorldPtr ) port , NULL ) ;
  295.         if ( port == record -> offscreen_world ) {
  296.             pix_map = GetGWorldPixMap ( record -> offscreen_world ) ;
  297.             if ( pix_map ) {
  298.                 LockPixels ( pix_map ) ;
  299.             }
  300.         } else {
  301.             pix_map = GetGWorldPixMap ( record -> offscreen_world ) ;
  302.             if ( pix_map ) {
  303.                 UnlockPixels ( pix_map ) ;
  304.             }
  305.         }
  306.     } else {
  307.         SetPort ( ( GrafPtr ) port ) ;
  308.     }
  309. }
  310.  
  311.  
  312. /*
  313.  * Use offscreen drawing - lock the pixels through use_port
  314.  */
  315. static void
  316. select_offscreen_port ( tty_record * record ) {
  317.     if ( record -> uses_gworld ) {
  318.         use_port ( record , record -> offscreen_world ) ;
  319.     } else {
  320.         use_port ( record , record -> offscreen_port ) ;
  321.     }
  322. }
  323.  
  324.  
  325. /*
  326.  * Use the window - unlock pixels
  327.  */
  328. static void
  329. select_onscreen_window ( tty_record * record ) {
  330.     if ( record -> uses_gworld ) {
  331.         use_port ( record , record -> its_window_world ) ;
  332.         SetPort ( record -> its_window ) ;
  333.     } else {
  334.         use_port ( record , record -> its_window ) ;
  335.     }
  336. }
  337.  
  338.  
  339. /*
  340.  * Do bits copy depending on if we're using color or not
  341.  */
  342. static void
  343. copy_bits ( tty_record * record , Rect * bounds , short xfer_mode , RgnHandle mask_rgn ) {
  344. RGBColor old_fore , old_back ;
  345. RGBColor rgb_black = { 0 , 0 , 0 } ;
  346. RGBColor rgb_white = { 0xffff , 0xffff , 0xffff } ;
  347.  
  348.     if ( record -> uses_gworld ) {
  349.     GWorldFlags pix_state = GetPixelsState ( GetGWorldPixMap ( record -> offscreen_world ) ) ;
  350.  
  351.         LockPixels ( GetGWorldPixMap ( record -> offscreen_world ) ) ;
  352.         GetForeColor ( & old_fore ) ;
  353.         GetBackColor ( & old_back ) ;
  354.         RGBForeColor ( & rgb_black ) ;
  355.         RGBBackColor ( & rgb_white ) ;
  356.         CopyBits ( ( BitMap * ) & ( record -> offscreen_world -> portPixMap ) ,
  357.             & ( record -> its_window -> portBits ) , bounds , bounds , xfer_mode ,
  358.             mask_rgn ) ;
  359.         RGBForeColor ( & old_fore ) ;
  360.         RGBBackColor ( & old_back ) ;
  361.         SetPixelsState ( GetGWorldPixMap ( record -> offscreen_world ) , pix_state ) ;
  362.     } else {
  363.         CopyBits ( & ( record -> its_bits ) , & ( record -> its_window -> portBits ) ,
  364.             bounds , bounds , xfer_mode , mask_rgn ) ;
  365.     }
  366. }
  367.  
  368.  
  369. /*
  370.  * Fill an area with the background color
  371.  */
  372. static void
  373. erase_rect ( tty_record * record , Rect * area ) {
  374. #if defined(applec)
  375. # pragma unused(record)
  376. #endif
  377.  
  378.     EraseRect ( area ) ;
  379. }
  380.  
  381.  
  382. /*
  383.  * Get rid of offscreen bitmap
  384.  */
  385. static short
  386. free_bits ( tty_record * record ) {
  387.     if ( record -> uses_gworld ) {
  388.         s_err = deallocate_gworld ( record ) ;
  389.     } else {
  390.         if ( record -> offscreen_port ) {
  391.             ClosePort ( record -> offscreen_port ) ;
  392.             s_err = dispose_ptr ( record , record -> offscreen_port ) ;
  393.             if ( ! s_err ) {
  394.                 record -> offscreen_port = NULL ;
  395.             } else {
  396.                 return s_err ;
  397.             }
  398.         }
  399.         s_err = dispose_ptr ( record , record -> its_bits . baseAddr ) ;
  400.         if ( ! s_err ) {
  401.             record -> its_bits . baseAddr = NULL ;
  402.         }
  403.     }
  404.     return s_err ;
  405. }
  406.  
  407.  
  408. /*
  409.  * Snatch a window from the resource fork. Create the record.
  410.  * Otherwise, do nothing.
  411.  */
  412. pascal short
  413. create_tty ( WindowPtr * window , short resource_id , Boolean in_color ) {
  414. tty_record * record ;
  415. Boolean was_allocated = !! * window ;
  416.  
  417.     if ( in_color ) {
  418.         * window = GetNewCWindow ( resource_id , ( Ptr ) * window , ( WindowPtr ) -1L ) ;
  419.     } else {
  420.         * window = GetNewWindow ( resource_id , ( Ptr ) * window , ( WindowPtr ) -1L ) ;
  421.     }
  422.     if ( ! * window ) {
  423.         return mem_err ( ) ;
  424.     }
  425.  
  426.     record = ( tty_record * ) NewPtrClear ( sizeof ( tty_record ) ) ;
  427.     if ( ! record ) {
  428.         if ( was_allocated ) {
  429.             CloseWindow ( * window ) ;
  430.         } else {
  431.             DisposeWindow ( * window ) ;
  432.         }
  433.         return mem_err ( ) ;
  434.     }
  435.     record -> its_window = * window ;
  436.     SetWRefCon ( * window , ( long ) record ) ;
  437.     record -> was_allocated = was_allocated ;
  438.     record -> its_bits . baseAddr = NULL ;
  439. #if TTY_INPUT
  440.     record -> input_buffer = NULL ;
  441. #endif
  442.  
  443. /*
  444.  * Wee need to keep the window world around if we switch worlds
  445.  */
  446.     record -> offscreen_world = NULL ;
  447.     record -> uses_gworld = in_color ;
  448.     if ( in_color ) {
  449.     GDHandle gh ;
  450.  
  451.         SetPort ( * window ) ;
  452.         GetGWorld ( & ( record -> its_window_world ) , & gh ) ;
  453.     } else {
  454.         record -> its_window_world = NULL ;
  455.     }
  456.  
  457. #if CLIP_RECT_ONLY
  458.     empty_rect ( & ( record -> invalid_rect ) ) ;
  459. #else
  460.     record -> invalid_part = NewRgn ( ) ;
  461.     if ( ! record -> invalid_part ) {
  462.     short err = mem_err ( ) ;
  463.  
  464.         err = destroy_tty ( * window ) ;
  465.         return err ;
  466.     }
  467. #endif
  468.  
  469.     return noErr ;
  470. }
  471.  
  472.  
  473. /*
  474.  * Initialize the struct so it actually works as a tty.
  475.  */
  476. pascal short
  477. init_tty_name ( WindowPtr window , unsigned char * font_name , short font_size ,
  478.     short x_size , short y_size ) {
  479. short font_num = 0 ;
  480.  
  481.     GetFNum ( font_name , & font_num ) ;
  482.     if ( ! font_num ) {
  483.         return general_failure ;
  484.     }
  485.     return init_tty_number ( window , font_num , font_size , x_size , y_size ) ;
  486. }
  487.  
  488.  
  489. pascal short
  490. init_tty_number ( WindowPtr window , short font_number , short font_size ,
  491.     short x_size , short y_size ) {
  492. RECORD ( record ) ;
  493.  
  494.     record -> font_number = font_number ;
  495.     record -> font_size = font_size ;
  496.     record -> x_size = x_size ;
  497.     record -> y_size = y_size ;
  498.  
  499.     record -> offscreen_port = NULL ;
  500.     record -> attribute [ TTY_ATTRIB_BACKGROUND ] = 0xffffff ; /* White */
  501.  
  502. #if TTY_INPUT
  503.     record -> input_buffer_len = 0 ;
  504.     record -> input_buffer_limit = IB_LIMIT ;
  505.     s_err = alloc_ptr ( record , & ( record -> input_buffer ) , IB_LIMIT ) ;
  506.     if ( s_err ) {
  507.         return s_err ;
  508.     }
  509. #endif
  510.  
  511.     return force_tty_coordinate_system_recalc ( window ) ;
  512. }
  513.  
  514.  
  515. /*
  516.  * Done with a window - destroy it. Release the memory only if
  517.  * it wasn't allocated when we got it!
  518.  */
  519. pascal short
  520. destroy_tty ( WindowPtr window ) {
  521. Boolean close_flag ;
  522. RECORD ( record ) ;
  523.  
  524.     s_err = free_bits ( record ) ;
  525. #if TTY_INPUT
  526.     if ( ! s_err ) {
  527.         s_err = dispose_ptr ( record -> input_buffer ) ;
  528.         if ( ! s_err ) {
  529.             record -> input_buffer = NULL ;
  530.         }
  531.     }
  532. #endif
  533.     if ( ! s_err ) {
  534.         close_flag = record -> was_allocated ;
  535.         DisposePtr ( ( Ptr ) record ) ;
  536.         s_err = MemError ( ) ;
  537.         if ( close_flag ) {
  538.             CloseWindow ( window ) ;
  539.         } else {
  540.             DisposeWindow ( window ) ;
  541.         }
  542.     }
  543.     
  544.     return s_err ;
  545. }
  546.  
  547.  
  548. /*
  549.  * Use a new font for drawing.
  550.  */
  551. pascal short
  552. set_tty_font_name ( WindowPtr window , unsigned char * font_name ) {
  553. RECORD ( record ) ;
  554.  
  555.     record -> font_number = 0 ;
  556.     GetFNum ( font_name , & ( record -> font_number ) ) ;
  557.  
  558.     return ! record -> font_number ;
  559. }
  560.  
  561.  
  562. pascal short
  563. set_tty_font_number ( WindowPtr window , short font_number ) {
  564. RECORD ( record ) ;
  565.  
  566.     record -> font_number = font_number ;
  567.  
  568.     return noErr ;
  569. }
  570.  
  571.  
  572. pascal short
  573. set_tty_font_size ( WindowPtr window , short font_size ) {
  574. RECORD ( record ) ;
  575.  
  576.     record -> font_size = font_size ;
  577.  
  578.     return noErr ;
  579. }
  580.  
  581.  
  582. static void
  583. do_set_port_font ( tty_record * record ) {
  584.  
  585.     PenNormal ( ) ;
  586.     TextFont ( record -> font_number ) ;
  587.     TextFace ( 0 ) ;
  588.     TextSize ( record -> font_size ) ;
  589.     if ( 0L != ( record -> attribute [ TTY_ATTRIB_FLAGS ] & TA_OVERSTRIKE ) ) {
  590.         TextMode ( srcOr ) ;
  591.     } else {
  592.         TextMode ( srcCopy ) ;
  593.     }
  594. }
  595.  
  596.  
  597. /*
  598.  * Fill in some fields from some other fields that may have changed
  599.  */
  600. static void
  601. calc_font_sizes ( tty_record * record ) {
  602. FontInfo font_info ;
  603.  
  604.     do_set_port_font ( record ) ;
  605.  
  606.     GetFontInfo ( & font_info ) ;
  607.     record -> char_width = font_info . widMax ;
  608.     record -> ascent_height = font_info . ascent + font_info . leading ;
  609.     record -> row_height = record -> ascent_height + font_info . descent ;
  610. }
  611.  
  612.  
  613. /*
  614.  * Allocate memory for the bitmap holding the tty window
  615.  */
  616. static short
  617. alloc_bits ( tty_record * record ) {
  618. void * old_port ;
  619.  
  620.     save_port ( record , & old_port ) ;
  621.     SetRect ( & record -> its_bits . bounds , 0 , 0 ,
  622.         record -> char_width * record -> x_size ,
  623.         record -> row_height * record -> y_size ) ;
  624.  
  625. /*
  626.  * Clear two highest and lowest bit - not a color pixMap, and even in size
  627.  */
  628.     record -> its_bits . rowBytes = ( ( record -> its_bits . bounds . right + 15 )
  629.         >> 3 ) & 0x1ffe ;
  630.  
  631.     if ( record -> uses_gworld ) {
  632.         s_err = allocate_offscreen_world ( record ) ;
  633.     } else {
  634.         s_err = alloc_ptr ( record , ( void * * ) & ( record -> its_bits . baseAddr ) ,
  635.             record -> its_bits . rowBytes * record -> its_bits . bounds . bottom ) ;
  636.         if ( ! s_err ) {
  637.             s_err = alloc_ptr ( record , ( void * * ) & ( record -> offscreen_port ) ,
  638.                 sizeof ( GrafPort ) ) ;
  639.         }
  640.         if ( ! s_err ) {
  641.             OpenPort ( record -> offscreen_port ) ;
  642.             SetPort ( record -> offscreen_port ) ;
  643.             ClipRect ( & ( record -> its_bits . bounds ) ) ;
  644.             SetPortBits ( & ( record -> its_bits ) ) ;
  645.         }
  646.     }
  647.     use_port ( record , old_port ) ;
  648.  
  649.     return s_err ;
  650. }
  651.  
  652.  
  653. static void
  654. update_offscreen_info ( tty_record * record ) {
  655.  
  656.     select_offscreen_port ( record ) ;
  657.     do_set_port_font ( record ) ;
  658.     select_onscreen_window ( record ) ;
  659. }
  660.  
  661.  
  662. /*
  663.  * Recalculate the window based on new size, font, extent values,
  664.  * and re-allocate the bitmap.
  665.  */
  666. pascal short
  667. force_tty_coordinate_system_recalc ( WindowPtr window ) {
  668. RECORD ( record ) ;
  669.  
  670.     if ( s_err = free_bits ( record ) ) {
  671.         return s_err ;
  672.     }
  673.     select_onscreen_window ( record ) ;
  674.     calc_font_sizes ( record ) ;
  675.  
  676.     if ( s_err = alloc_bits ( record ) ) {
  677. /*
  678.  * Catastrophe! We could not allocate memory for the bitmap! Things may go very
  679.  * much downhill from here!
  680.  */
  681.          dprintf ( "alloc_bits returned NULL in force_tty_coordinate_system_recalc!" ) ;
  682.         return s_err ;
  683.     }
  684.  
  685.     update_offscreen_info ( record ) ;
  686.     return clear_tty ( window ) ;
  687. }
  688.  
  689.  
  690. /*
  691.  * Update TTY according to new color environment for the window
  692.  */
  693. pascal short
  694. tty_environment_changed ( WindowPtr window ) {
  695. Point p = { 0 , 0 } ;
  696. Rect r_screen ;
  697. RECORD ( record ) ;
  698.  
  699.     if ( record -> uses_gworld ) {
  700.         select_onscreen_window ( record ) ;
  701.         r_screen = record -> its_bits . bounds ;
  702.         LocalToGlobal ( & p )  ;
  703.         OffsetRect ( & r_screen , p . h , p . v ) ;
  704.         UpdateGWorld ( & ( record -> offscreen_world ) , 0 , & r_screen ,
  705.             NULL , NULL , stretchPix ) ;
  706.         select_offscreen_port ( record ) ;
  707.         SetOrigin ( 0 , 0 ) ;
  708.         select_onscreen_window ( record ) ;
  709.     }
  710.     return s_err ;
  711. }
  712.  
  713.  
  714. /*
  715.  * Read a lot of interesting and useful information from the current tty
  716.  */
  717. pascal short
  718. get_tty_metrics ( WindowPtr window , short * x_size , short * y_size ,
  719.     short * x_size_pixels , short * y_size_pixels , short * font_number ,
  720.     short * font_size , short * char_width , short * row_height ) {
  721. RECORD ( record ) ;
  722.  
  723. /*
  724.  * First, test that we actually have something to draw to...
  725.  */
  726.     if ( ( ( NULL == record -> its_bits . baseAddr ) && ! record -> uses_gworld ) ||
  727.         ( ( NULL == record -> offscreen_world ) && record -> uses_gworld ) ) {
  728.         return general_failure ;
  729.     }
  730.  
  731.     * x_size = record -> x_size ;
  732.     * y_size = record -> y_size ;
  733.     * x_size_pixels = record -> its_bits . bounds . right ;
  734.     * y_size_pixels = record -> its_bits . bounds . bottom ;
  735.     * font_number = record -> font_number ;
  736.     * font_size = record -> font_size ;
  737.     * char_width = record -> char_width ;
  738.     * row_height = record -> row_height ;
  739.  
  740.     return noErr ;
  741. }
  742.  
  743.  
  744. /*
  745.  * Map a position on the map to screen coordinates
  746.  */
  747. static void
  748. pos_rect ( tty_record * record , Rect * r , short x_pos , short y_pos ,
  749.     short x_end , short y_end ) {
  750.  
  751.     SetRect ( r , x_pos * ( record -> char_width ) , y_pos * ( record -> row_height ) ,
  752.         ( 1 + x_end ) * ( record -> char_width ) , ( 1 + y_end ) *
  753.         ( record -> row_height ) ) ;
  754. }
  755.  
  756.  
  757. static void
  758. accumulate_rect ( tty_record * record , Rect * rect ) {
  759. #if CLIP_RECT_ONLY
  760.     union_rect ( rect , & ( record -> invalid_rect ) , & ( record -> invalid_rect ) ) ;
  761. #else
  762. RgnHandle rh = NewRgn ( ) ;
  763.  
  764.     RectRgn ( rh , rect ) ;
  765.     UnionRgn ( record -> invalid_part , rh , record -> invalid_part ) ;
  766.     DisposeRgn ( rh ) ;
  767. #endif
  768. }
  769.  
  770.  
  771. /*
  772.  * Invert the specified position
  773.  */
  774. static void
  775. curs_pos ( tty_record * record , short x_pos , short y_pos , short to_state ) {
  776. Rect r ;
  777.  
  778.     if ( record -> curs_state == to_state ) {
  779.         return ;
  780.     }
  781.     record -> curs_state = to_state ;
  782.     pos_rect ( record , & r , x_pos , y_pos , x_pos , y_pos ) ;
  783.  
  784.     if ( DRAW_DIRECT ) {
  785.     void * old_port ;
  786.  
  787.         save_port ( record , & old_port ) ;
  788.         select_onscreen_window ( record ) ;
  789.         InvertRect ( & r ) ;
  790.         use_port ( record , old_port ) ;
  791.     } else {
  792.         accumulate_rect ( record , & r ) ;
  793.     }
  794. }
  795.  
  796.  
  797. /*
  798.  * Move the cursor (both as displayed and where drawing goes)
  799.  * HOWEVER: The cursor is NOT stored in the bitmap!
  800.  */
  801. pascal short
  802. move_tty_cursor ( WindowPtr window , short x_pos , short y_pos ) {
  803. RECORD ( record ) ;
  804.  
  805.     select_onscreen_window ( record ) ;
  806.     if ( record -> x_curs == x_pos && record -> y_curs == y_pos ) {
  807.         return noErr ;
  808.     }
  809.     if ( record -> x_size <= x_pos || x_pos < 0 ||
  810.         record -> y_size <= y_pos || y_pos < 0 ) {
  811.         return general_failure ;
  812.     }
  813.     curs_pos ( record , record -> x_curs , record -> y_curs , 0 ) ;
  814.     record -> x_curs = x_pos ;
  815.     record -> y_curs = y_pos ;
  816.     curs_pos ( record , x_pos , y_pos , 1 ) ;
  817.  
  818.     return noErr ;
  819. }
  820.  
  821.  
  822. /*
  823.  * Get the current cursor position. Note that the cursor may not be
  824.  * displayed there yet; it depends on wether you've called update_tty()
  825.  * or have the window in TA_ALWAYS_REFRESH mode.
  826.  */
  827. pascal short
  828. get_tty_cursor ( WindowPtr window , short * x_pos , short * y_pos ) {
  829. RECORD ( record ) ;
  830.  
  831.     * x_pos = record -> x_curs ;
  832.     * y_pos = record -> y_curs ;
  833.  
  834.     return noErr ;
  835. }
  836.  
  837.  
  838. /*
  839.  * Update the screen to match the current bitmap, after adding stuff
  840.  * with add_tty_char etc.
  841.  */
  842. pascal short
  843. update_tty ( WindowPtr window ) {
  844. Rect r ;
  845. RECORD ( record ) ;
  846.  
  847. #if CLIP_RECT_ONLY
  848.     if ( record -> invalid_rect . right <= record -> invalid_rect . left ||
  849.         record -> invalid_rect . bottom <= record -> invalid_rect . top ) {
  850.         return noErr ;
  851.     }
  852.     r = record -> invalid_rect ;
  853. #else
  854.     if ( EmptyRgn ( record -> invalid_part ) ) {
  855.         return noErr ;
  856.     }
  857.     r = ( * ( record -> invalid_part ) ) -> rgnBBox ;
  858. #endif
  859.     select_onscreen_window ( record ) ;
  860. #if CLIP_RECT_ONLY
  861.     copy_bits ( record , & r , srcCopy , NULL ) ;
  862.     empty_rect ( & ( record -> invalid_rect ) ) ;
  863. #else
  864.     copy_bits ( record , & r , srcCopy , NULL ) ;
  865.     SetEmptyRgn ( record -> invalid_part ) ;
  866. #endif
  867.     if ( record -> curs_state ) {
  868.  
  869.         pos_rect ( record , & r , record -> x_curs , record -> y_curs ,
  870.             record -> x_curs , record -> y_curs ) ;
  871.         InvertRect ( & r ) ;
  872.     }
  873.  
  874.     return noErr ;
  875. }
  876.  
  877.  
  878. /*
  879.  * Add a single character. It is drawn directly if the correct flag is set,
  880.  * else deferred to the next update event or call of update_tty()
  881.  */
  882. pascal short
  883. add_tty_char ( WindowPtr window , short character ) {
  884. char s [ 2 ] ;
  885.  
  886.     s [ 0 ] = character ;
  887.     s [ 1 ] = 0 ;
  888.     return add_tty_string ( window , s ) ;
  889. }
  890.  
  891.  
  892. /*
  893.  * Low level add to screen
  894.  */
  895. static void
  896. do_add_string ( tty_record * record , char * str , short len ) {
  897. Rect r ;
  898. register int x_pos , count = len ;
  899.  
  900.     if ( len < 1 ) {
  901.         return ;
  902.     }
  903.     select_offscreen_port ( record ) ;
  904.  
  905.     if ( 0L != ( record -> attribute [ TTY_ATTRIB_FLAGS ] & TA_MOVE_EACH_CHAR ) ) {
  906.         x_pos = record -> x_curs ;
  907.         while ( count -- ) {
  908.             MoveTo ( x_pos * record -> char_width , record -> y_curs *
  909.                 record -> row_height + record -> ascent_height ) ;
  910.             DrawChar ( * ( str ++ ) ) ;
  911.         }
  912.     } else {
  913.         MoveTo ( record -> x_curs * record -> char_width , record -> y_curs *
  914.             record -> row_height + record -> ascent_height ) ;
  915.         DrawText ( str , 0 , len ) ;
  916.     }
  917.  
  918.     pos_rect ( record , & r , record -> x_curs , record -> y_curs ,
  919.         record -> x_curs + len - 1 , record -> y_curs ) ;
  920.     if ( DRAW_DIRECT ) {
  921.         select_onscreen_window ( record ) ;
  922.         copy_bits ( record , & r , srcCopy , NULL ) ;
  923.     } else {
  924.         accumulate_rect ( record , & r ) ;
  925.         select_onscreen_window ( record ) ;
  926.     }
  927. }
  928.  
  929.  
  930. /*
  931.  * Low-level cursor handling routine
  932.  */
  933. static void
  934. do_add_cursor ( tty_record * record , short x_pos ) {
  935.  
  936.     record -> x_curs = x_pos ;
  937.     if ( record -> x_curs >= record -> x_size ) {
  938.         if ( 0L != ( record -> attribute [ TTY_ATTRIB_FLAGS ] & TA_WRAP_AROUND ) ) {
  939.             record -> y_curs ++ ;
  940.             record -> x_curs = 0 ;
  941.             if ( record -> y_curs >= record -> y_size ) {
  942.                 if ( 0L != ( record -> attribute [ TTY_ATTRIB_FLAGS ] &
  943.                     TA_INHIBIT_VERT_SCROLL ) ) {
  944.                     record -> y_curs = record -> y_size ;
  945.                 } else {
  946.                     scroll_tty ( record -> its_window , 0 , 1 + record -> y_curs -
  947.                         record -> y_size ) ;
  948.                 }
  949.             }
  950.         } else {
  951.             record -> x_curs = record -> x_size ;
  952.         }
  953.     }
  954. }
  955.  
  956.  
  957. /*
  958.  * Beep
  959.  */
  960. static void
  961. do_tty_beep ( tty_record * record ) {
  962.     if ( record -> attribute [ TTY_BEEP_FUNCTION ] ) {
  963.     pascal void ( * tty_beep ) ( WindowPtr ) = ( pascal void ( * ) ( WindowPtr ) )
  964.         record -> attribute [ TTY_BEEP_FUNCTION ] ;
  965.         ( * tty_beep ) ( record -> its_window ) ;
  966.     } else {
  967.         SysBeep ( 20 ) ;
  968.     }
  969. }
  970.  
  971.  
  972. /*
  973.  * Do control character
  974.  */
  975. static void
  976. do_control ( tty_record * record , short character ) {
  977. static int recurse = 0 ;
  978.  
  979. /*
  980.  * Check recursion because nl_add_cr and cr_add_nl may both be set and call each other
  981.  */
  982.     recurse ++ ;
  983.     if ( recurse > 2 ) {
  984.         return ;
  985.     }
  986.     switch ( character ) {
  987.     case 10 :
  988.         record -> y_curs ++ ;
  989.         if ( record -> y_curs >= record -> y_size ) {
  990.             scroll_tty ( record -> its_window , 0 , 1 + record -> y_curs -
  991.                 record -> y_size ) ;
  992.         }
  993.         if ( 0L != ( record -> attribute [ TTY_ATTRIB_CURSOR ] & TA_NL_ADD_CR ) ) {
  994.             do_control ( record , 13 ) ;
  995.         }
  996.         break ;
  997.     case 13 :
  998.         record -> x_curs = 0 ;
  999.         if ( 0L != ( record -> attribute [ TTY_ATTRIB_CURSOR ] & TA_CR_ADD_NL ) ) {
  1000.             do_control ( record , 10 ) ;
  1001.         }
  1002.         break ;
  1003.     case 7 :
  1004.         do_tty_beep ( record ) ;
  1005.         break ;
  1006.     case 8 :
  1007.         if ( record -> x_curs > 0 ) {
  1008.             record -> x_curs -- ;
  1009.         }
  1010.         break ;
  1011.     default :
  1012.         break ;
  1013.     }
  1014.     recurse -- ;
  1015. }
  1016.  
  1017.  
  1018. /*
  1019.  * Add a null-terminated string of characters
  1020.  */
  1021. pascal short
  1022. add_tty_string ( WindowPtr window , const char * string ) {
  1023. register const unsigned char * start_c ;
  1024. register const unsigned char * the_c ;
  1025. register short max_x , pos_x ;
  1026. RECORD ( record ) ;
  1027.  
  1028.     select_onscreen_window ( record ) ;
  1029.     curs_pos ( record , record -> x_curs , record -> y_curs , 0 ) ;
  1030.  
  1031.     the_c = ( const unsigned char * ) string ;
  1032.     max_x = record -> x_size ;
  1033.     while ( 1 ) {
  1034.         start_c = the_c ;
  1035.         pos_x = record -> x_curs ;
  1036.         if ( ( 0L == ( record -> attribute [ TTY_ATTRIB_FLAGS ] & TA_WRAP_AROUND ) ) &&
  1037.             pos_x >= max_x ) { /* Optimize away drawing across border without wrap */
  1038.             break ;
  1039.         }
  1040.         while ( pos_x < max_x && ! s_control [ * the_c ] ) {
  1041.             the_c ++ ;
  1042.             pos_x ++ ;
  1043.         }
  1044.         do_add_string ( record , ( char * ) start_c , the_c - start_c ) ;
  1045.         do_add_cursor ( record , pos_x ) ;
  1046.         if ( ! * the_c ) {
  1047.             break ;
  1048.         }
  1049.         if ( s_control [ * the_c ] ) {
  1050.             do_control ( record , * the_c ) ;
  1051.             the_c ++ ;
  1052.         }
  1053.     }
  1054.     select_onscreen_window ( record ) ;
  1055.     curs_pos ( record , record -> x_curs , record -> y_curs , 1 ) ;
  1056.  
  1057.     ShowWindow ( window ) ;
  1058.  
  1059.     return noErr ;
  1060. }
  1061.  
  1062.  
  1063. /*
  1064.  * Do a c-style printf - the result shouldn't be too long...
  1065.  */
  1066. short
  1067. printf_tty ( WindowPtr window , const char * fmt , ... ) {
  1068. static char buf [ 256 ] ;
  1069. va_list list ;
  1070.  
  1071.     va_start ( list , fmt ) ;
  1072.     vsprintf ( buf , fmt , list ) ;
  1073.     va_end ( list ) ;
  1074.  
  1075.     return add_tty_string ( window , buf ) ;
  1076. }
  1077.  
  1078.  
  1079. /*
  1080.  * Read or change attributes for the tty. Note that some attribs may
  1081.  * very well clear and reallocate the bitmap when changed, whereas
  1082.  * others (color, highlight, ...) are guaranteed not to.
  1083.  */
  1084. pascal short
  1085. get_tty_attrib ( WindowPtr window , tty_attrib attrib , long * value ) {
  1086. RECORD ( record ) ;
  1087.  
  1088.     if ( attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES ) {
  1089.         return general_failure ;
  1090.     }
  1091.     * value = record -> attribute [ attrib ] ;
  1092.  
  1093.     return noErr ;
  1094. }
  1095.  
  1096.  
  1097. pascal short
  1098. set_tty_attrib ( WindowPtr window , tty_attrib attrib , long value ) {
  1099. long old_value ;
  1100. RGBColor rgb_color ;
  1101. RECORD ( record ) ;
  1102.  
  1103.     if ( attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES ) {
  1104.         return general_failure ;
  1105.     }
  1106.     old_value = record -> attribute [ attrib ] ;
  1107.     if ( old_value == value ) {
  1108.         return noErr ;
  1109.     }
  1110.     record -> attribute [ attrib ] = value ;
  1111.     /*
  1112.      * Presently, no attributes generate a new bitmap.
  1113.      */
  1114.     switch ( attrib ) {
  1115.     case TTY_ATTRIB_CURSOR :
  1116. /*
  1117.  * Check if we should change tables
  1118.  */
  1119.         if ( 0L != ( value & TA_RAW_OUTPUT ) ) {
  1120.             s_control = s_raw_controls ;
  1121.         } else {
  1122.             s_control = s_cooked_controls ;
  1123.         }
  1124.         break ;
  1125.     case TTY_ATTRIB_FLAGS :
  1126. /*
  1127.  * Check if we should flush the output going from cached to draw-direct
  1128.  */
  1129.         if ( 0L != ( value & TA_ALWAYS_REFRESH ) ) {
  1130.             update_tty ( window ) ;
  1131.         }
  1132.         break ;
  1133.     case TTY_ATTRIB_FOREGROUND :
  1134. /*
  1135.  * Set foreground color
  1136.  */
  1137.          TA_TO_RGB ( value , rgb_color ) ;
  1138.         select_offscreen_port ( record ) ;
  1139.         RGBForeColor ( & rgb_color ) ;
  1140.         select_onscreen_window ( record ) ;
  1141.         RGBForeColor ( & rgb_color ) ;
  1142.         break ;
  1143.     case TTY_ATTRIB_BACKGROUND :
  1144. /*
  1145.  * Set background color
  1146.  */
  1147.          TA_TO_RGB ( value , rgb_color ) ;
  1148.         select_offscreen_port ( record ) ;
  1149.         RGBBackColor ( & rgb_color ) ;
  1150.         select_onscreen_window ( record ) ;
  1151.         RGBBackColor ( & rgb_color ) ;
  1152.         break ;
  1153.     default :
  1154.         break ;
  1155.     }
  1156.     return noErr ;
  1157. }
  1158.  
  1159.  
  1160. /*
  1161.  * Scroll the window. Positive is up/left. scroll_tty ( window , 0 , 1 ) is a line feed.
  1162.  * Scroll flushes the accumulated update area by calling update_tty().
  1163.  */
  1164. pascal short
  1165. scroll_tty ( WindowPtr window , short delta_x , short delta_y ) {
  1166. RgnHandle rgn ;
  1167. RECORD ( record ) ;
  1168.  
  1169.     select_onscreen_window ( record ) ;
  1170.     s_err = update_tty ( window ) ;
  1171.  
  1172.     rgn = NewRgn ( ) ;
  1173.  
  1174.     select_offscreen_port ( record ) ;
  1175.     ScrollRect ( & ( record -> its_bits . bounds ) , - delta_x * record -> char_width ,
  1176.         - delta_y * record -> row_height , rgn ) ;
  1177.     EraseRgn ( rgn ) ;
  1178.     SetEmptyRgn ( rgn ) ;
  1179.  
  1180.     select_onscreen_window ( record ) ;
  1181.     ScrollRect ( & ( record -> its_bits . bounds ) , - delta_x * record -> char_width ,
  1182.         - delta_y * record -> row_height , rgn ) ;
  1183.     EraseRgn ( rgn ) ;
  1184.     DisposeRgn ( rgn ) ;
  1185.  
  1186.     record -> y_curs -= delta_y ;
  1187.     record -> x_curs -= delta_x ;
  1188.  
  1189.     return noErr ;
  1190. }
  1191.  
  1192.  
  1193. /*
  1194.  * Clear the screen. Immediate.
  1195.  */
  1196. pascal short
  1197. clear_tty ( WindowPtr window ) {
  1198. RECORD ( record ) ;
  1199.  
  1200.     select_offscreen_port ( record ) ;
  1201.     erase_rect ( record , & ( record -> its_bits . bounds ) ) ;
  1202.     select_onscreen_window ( record ) ;
  1203.     curs_pos ( record , record -> x_curs , record -> y_curs , 0 ) ;
  1204.     erase_rect ( record , & ( record -> its_bits . bounds ) ) ;
  1205. #if CLIP_RECT_ONLY
  1206.     empty_rect ( & ( record -> invalid_rect ) ) ;
  1207. #else
  1208.     SetEmptyRgn ( record -> invalid_part ) ;
  1209. #endif
  1210.     curs_pos ( record , record -> x_curs , record -> y_curs , 1 ) ;
  1211.  
  1212.     return noErr ;
  1213. }
  1214.  
  1215.  
  1216. /*
  1217.  * Resize the area - clears and reallocates the bitmap.
  1218.  */
  1219. pascal short
  1220. resize_tty_area ( WindowPtr window , short x_size , short y_size ) {
  1221. RECORD ( record ) ;
  1222.  
  1223.     record -> x_size = x_size ;
  1224.     record -> y_size = y_size ;
  1225.  
  1226.     return force_tty_coordinate_system_recalc ( window ) ;
  1227. }
  1228.  
  1229.  
  1230. /*
  1231.  * Echo to the user if echo mode on
  1232.  */
  1233. static void
  1234. do_add_input_character ( tty_record * record , unsigned char character ) {
  1235.     if ( 0L != ( record -> attribute [ TTY_ATTRIB_CURSOR ] & TA_ECHO_INPUT ) ) {
  1236.         add_tty_char ( record -> its_window , character ) ;
  1237.     }
  1238. }
  1239.  
  1240.  
  1241. #if TTY_INPUT
  1242. /*
  1243.  * Add a key in the queue.
  1244.  */
  1245. static short
  1246. do_add_key ( tty_record * record , long message ) {
  1247.     if ( record -> input_buffer_len >= record -> input_buffer_limit ) {
  1248.         do_tty_beep ( record ) ;
  1249.         return general_failure ;
  1250.     } else {
  1251. /*
  1252.  * If input is cooked, we should fix up this here line to allow line editting...
  1253.  */
  1254.         record -> input_buffer [ record -> input_buffer_len ++ ] = message & 0xff ;
  1255.         do_add_input_character ( record , message & 0xff ) ;
  1256.         return noErr ;
  1257.     }
  1258. }
  1259. #endif
  1260.  
  1261.  
  1262. /*
  1263.  * Add a key in the queue.
  1264.  */
  1265. static short
  1266. do_cmd_key ( tty_record * record , EventRecord * event ) {
  1267.     pascal void ( * callback ) ( EventRecord * event , WindowPtr window ) =
  1268.         ( pascal void ( * ) ( EventRecord * , WindowPtr ) )
  1269.         record -> attribute [ TTY_COMMAND_KEY_CALLBACK ] ;
  1270.  
  1271.     if ( callback ) {
  1272.         ( * callback ) ( event , record -> its_window ) ;
  1273.         return noErr ;
  1274.     }
  1275.     return general_failure ;
  1276. }
  1277.  
  1278.  
  1279. /*
  1280.  * Handle a tty event:
  1281.  * Updates, pertaining to our window.
  1282.  * Key downs, entered into the queue (if we are frontmost)
  1283.  */
  1284. pascal short
  1285. handle_tty_event ( WindowPtr window , EventRecord * event ) {
  1286. RECORD ( record ) ;
  1287.  
  1288.     update_tty ( window ) ;
  1289.  
  1290.     if ( 0L != ( record -> attribute [ TTY_ATTRIB_CURSOR ] & TA_BLINKING_CURSOR ) ) {
  1291.         if ( event -> when > record -> last_cursor + GetCaretTime ( ) ) {
  1292.             curs_pos ( record , record -> x_curs , record -> y_curs ,
  1293.                 ! record -> curs_state ) ;
  1294.             record -> last_cursor = event -> when ;
  1295.         }
  1296.     }
  1297.  
  1298.     switch ( event -> what ) {
  1299.     case updateEvt :
  1300.         if ( event -> message == ( long ) window ) {
  1301.             BeginUpdate ( window ) ;
  1302.             
  1303.             /* Why do we have to erase the same area we are about to
  1304.                 do a copy_bits to?
  1305.                 
  1306.             erase_rect ( record , & ( record -> its_bits . bounds ) ) ;
  1307.             
  1308.             */
  1309.             
  1310.             tty_environment_changed ( window ) ;
  1311.             s_err = image_tty ( window ) ;
  1312.             EndUpdate ( window ) ;
  1313.             return s_err ;
  1314.         }
  1315.         break ;
  1316. #if TTY_INPUT
  1317.     case keyDown :
  1318.     case autoKey :
  1319.         if ( FrontWindow ( ) == window ) {
  1320.             if ( event -> modifiers & cmdKey ) {
  1321.                 return do_cmd_key ( record , event ) ;
  1322.             } else {
  1323.                 return do_add_key ( record , event -> message ) ;
  1324.             }
  1325.         }
  1326.         break ;
  1327. #endif
  1328.     deafult :
  1329.         break ;
  1330.     }
  1331.  
  1332.     return general_failure ;
  1333. }
  1334.  
  1335.  
  1336. /*
  1337.  * Draw an image of the tty - used for update events and can be called
  1338.  * for screen dumps.
  1339.  */
  1340. pascal short
  1341. image_tty ( WindowPtr window ) {
  1342. Rect r ;
  1343. RECORD ( record ) ;
  1344.  
  1345.     select_onscreen_window ( record ) ;
  1346.     copy_bits ( record , & ( record -> its_bits . bounds ) , srcCopy , NULL ) ;
  1347.     if ( record -> curs_state ) {
  1348.  
  1349.         pos_rect ( record , & r , record -> x_curs , record -> y_curs ,
  1350.             record -> x_curs , record -> y_curs ) ;
  1351.         InvertRect ( & r ) ;
  1352.     }
  1353.  
  1354.     return noErr ;
  1355. }
  1356.  
  1357.  
  1358. #if TTY_INPUT
  1359.  
  1360. /*
  1361.  * Read a character depending on the input mode
  1362.  */
  1363. pascal short
  1364. getchar_tty ( WindowPtr window , short * character ) {
  1365. RECORD ( record ) ;
  1366.  
  1367.     if ( 0L != ( record -> attribute [ TTY_ATTRIB_CURSOR ] & TA_RAW_INPUT ) ) {
  1368.         while ( ! record -> input_buffer_len ) {
  1369.         EventRecord er ;
  1370.  
  1371.             WaitNextEvent ( -1 , & er , GetCaretTime ( ) , NULL ) ;
  1372.             if ( handle_tty_event ( window , & er ) ) {
  1373.                 switch ( er . what ) {
  1374.                 default :
  1375.                     break ;
  1376.                 }
  1377.             }
  1378.         }
  1379.         * character = 
  1380.     } else {
  1381.  
  1382.     }
  1383. }
  1384.  
  1385. #endif /* TTY_INPUT */
  1386.  
  1387. #if EXTENDED_SUPPORT
  1388. /*
  1389.  * Delete or insert operations used by many terminals can bottleneck through
  1390.  * here. Note that the order of executin for row/colum insertions is NOT
  1391.  * specified. Negative values for num_ mean delete, zero means no effect.
  1392.  */
  1393. pascal short
  1394. mangle_tty_rows_columns ( WindowPtr window , short from_row , short num_rows ,
  1395.     short from_column , short num_columns ) {
  1396. Rect r ;
  1397. RgnHandle rh = NewRgn ( ) ;
  1398. RECORD ( record ) ;
  1399.  
  1400.     update_tty ( window ) ; /* Always make sure screen is OK */
  1401.     curs_pos ( record , record -> x_curs , record -> y_curs , 0 ) ;
  1402.  
  1403.     if ( num_rows ) {
  1404.         pos_rect ( record , & r , 0 , from_row , record -> x_size - 1 ,
  1405.             record -> y_size - 1 ) ;
  1406.         select_offscreen_port ( record ) ;
  1407.         ScrollRect ( & r , 0 , num_rows * record -> row_height , rh ) ;
  1408.         EraseRgn ( rh ) ;
  1409.         SetEmptyRgn ( rh ) ;
  1410.         select_onscreen_window ( record ) ;
  1411.         ScrollRect ( & r , 0 , num_rows * record -> row_height , rh ) ;
  1412.         EraseRgn ( rh ) ;
  1413.         SetEmptyRgn ( rh ) ;
  1414.     }
  1415.     if ( num_columns ) {
  1416.         pos_rect ( record , & r , from_column , 0 , record -> x_size - 1 ,
  1417.             record -> y_size - 1 ) ;
  1418.         select_offscreen_port ( record ) ;
  1419.         ScrollRect ( & r , num_columns * record -> char_width , 0 , rh ) ;
  1420.         EraseRgn ( rh ) ;
  1421.         SetEmptyRgn ( rh ) ;
  1422.         select_onscreen_window ( record ) ;
  1423.         ScrollRect ( & r , num_columns * record -> char_width , 0 , rh ) ;
  1424.         EraseRgn ( rh ) ;
  1425.         SetEmptyRgn ( rh ) ;
  1426.     }
  1427.     DisposeRgn ( rh ) ;
  1428.     if ( record -> x_curs >= from_column ) {
  1429.         record -> x_curs += num_columns ;
  1430.     }
  1431.     if ( record -> y_curs >= from_row ) {
  1432.         record -> y_curs += num_rows ;
  1433.     }
  1434.     curs_pos ( record , record -> x_curs , record -> y_curs , 1 ) ;
  1435.  
  1436.     return noErr ;
  1437. }
  1438.  
  1439.  
  1440. /*
  1441.  * Clear an area
  1442.  */
  1443. pascal short
  1444. clear_tty_window ( WindowPtr window , short from_x , short from_y ,
  1445.     short to_x , short to_y ) {
  1446. Rect r ;
  1447. RECORD ( record ) ;
  1448.  
  1449.     if ( from_x > to_x || from_y > to_y ) {
  1450.         return general_failure ;
  1451.     }
  1452.     pos_rect ( record , & r , from_x , from_y , to_x , to_y ) ;
  1453.     select_offscreen_port ( record ) ;
  1454.     erase_rect ( record , & r ) ;
  1455.     accumulate_rect ( record , & r ) ;
  1456.     if ( DRAW_DIRECT ) {
  1457.         update_tty ( window ) ;
  1458.     } else
  1459.         select_onscreen_window ( record ) ;
  1460. }
  1461.  
  1462.  
  1463. /*
  1464.  * Frame an area in an aesthetically pleasing way.
  1465.  */
  1466. pascal short
  1467. frame_tty_window ( WindowPtr window , short from_x , short from_y ,
  1468.     short to_x , short to_y , short frame_fatness ) {
  1469. Rect r ;
  1470. RECORD ( record ) ;
  1471.  
  1472.     if ( from_x > to_x || from_y > to_y ) {
  1473.         return general_failure ;
  1474.     }
  1475.     pos_rect ( record , & r , from_x , from_y , to_x , to_y ) ;
  1476.     select_offscreen_port ( record ) ;
  1477.     PenSize ( frame_fatness , frame_fatness ) ;
  1478.     FrameRect ( & r ) ;
  1479.     PenNormal ( ) ;
  1480.     accumulate_rect ( record , & r ) ;
  1481.     if ( DRAW_DIRECT ) {
  1482.         update_tty ( window ) ;
  1483.     } else
  1484.         select_onscreen_window ( record ) ;
  1485. }
  1486.  
  1487.  
  1488. /*
  1489.  * Highlighting a specific part of the tty window
  1490.  */
  1491. pascal short
  1492. invert_tty_window ( WindowPtr window , short from_x , short from_y ,
  1493.     short to_x , short to_y ) {
  1494. Rect r ;
  1495. RECORD ( record ) ;
  1496.  
  1497.     if ( from_x > to_x || from_y > to_y ) {
  1498.         return general_failure ;
  1499.     }
  1500.     pos_rect ( record , & r , from_x , from_y , to_x , to_y ) ;
  1501.     select_offscreen_port ( record ) ;
  1502.     InvertRect ( & r ) ;
  1503.     accumulate_rect ( record , & r ) ;
  1504.     if ( DRAW_DIRECT ) {
  1505.         update_tty ( window ) ;
  1506.     } else
  1507.         select_onscreen_window ( record ) ;
  1508. }
  1509.  
  1510.  
  1511. static void
  1512. canonical_rect ( Rect * r , short x1 , short y1 , short x2 , short y2 ) {
  1513.     if ( x1 < x2 ) {
  1514.         if ( y1 < y2 ) {
  1515.             SetRect ( r , x1 , x2 , y1 , y2 ) ;
  1516.         } else {
  1517.             SetRect ( r , x1 , x2 , y2 , y1 ) ;
  1518.         }
  1519.     } else {
  1520.         if ( y1 < y2 ) {
  1521.             SetRect ( r , x2 , x1 , y1 , y2 ) ;
  1522.         } else {
  1523.             SetRect ( r , x2 , x1 , y2 , y1 ) ;
  1524.         }
  1525.     }
  1526. }
  1527.  
  1528.  
  1529. /*
  1530.  * Line drawing - very device dependent
  1531.  */
  1532. pascal short
  1533. draw_tty_line ( WindowPtr window , short from_x , short from_y ,
  1534.     short to_x , short to_y ) {
  1535. Rect r ;
  1536. RECORD ( record ) ;
  1537.  
  1538.     select_offscreen_port ( record ) ;
  1539.     MoveTo ( from_x , from_y ) ;
  1540.     LineTo ( to_x , to_y ) ;
  1541.     canonical_rect ( & r , from_x , from_y , to_x , to_y ) ;
  1542.     accumulate_rect ( record , & r ) ;
  1543.     if ( DRAW_DIRECT ) {
  1544.         update_tty ( window ) ;
  1545.     } else
  1546.         select_onscreen_window ( record ) ;
  1547. }
  1548.  
  1549.  
  1550. #endif /* EXTENDED_SUPPORT */
  1551.