home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / program / pascal / pasdox / pasacc.txt < prev    next >
Text File  |  1985-11-18  |  12KB  |  322 lines

  1. { -----------------------------------------------------------------------------
  2.  
  3.                                  NOTICE:
  4.  
  5.       THESE MATERIALS are UNSUPPORTED by OSS!  If you do not understand how to
  6.       use them do not contact OSS for help!  We will not teach you how to 
  7.       program in Pascal.  If you find an error in these materials, feel free
  8.       to SEND US A LETTER explaining the error, and how to fix it.
  9.  
  10.       THE BOTTOM LINE:
  11.  
  12.          Use it, enjoy it, but you are on your own when using these materials!
  13.  
  14.  
  15.                                DISCLAIMER:
  16.  
  17.       OSS makes no representations or warranties with respect to the contents
  18.       hereof and specifically disclaim all warranties of merchantability or
  19.       fitness for any particular purpose.   This document is subject to change
  20.       without notice.
  21.       
  22.       OSS provides these materials for use with Personal Pascal.  Use them in
  23.       any way you wish.
  24.  
  25.    -------------------------------------------------------------------------- }
  26.  
  27.  
  28. WRITING DESK ACCESSORIES USING PERSONAL PASCAL
  29. ----------------------------------------------
  30.  
  31. In order to make a Personal Pascal program into a desk accessory, you must
  32. perform a few operations which are not described in the manual.  First of all,
  33. you must make sure your program can be made into an accessory as follows:
  34.  
  35. 1.  The start of your program should contain an S0 compiler directive.  This
  36.     command tells the compiler not to adjust the size of the stack.
  37.  
  38. 2.  You should NOT use debug mode.  Either change the option setting called
  39.     "Full debug mode", or use a D- command along with the S0 command.
  40.  
  41. 3.  The value actually returned by the Init_Gem routine is the application
  42.     identification number for your program.  You must save this number in a
  43.     variable, instead of just testing it.  Again, look at the sample accessory
  44.     for details.
  45.  
  46. 4.  Two additional GEM messages are sent to accessories.  These messages,
  47.     AC_Open and AC_Close, are not declared in the GEMCONST.PAS file.  You
  48.     should either declare them in your program (as the sample accessory does)
  49.     or add them to the GEMCONST.PAS include file.  You also must respond to
  50.     these messages as shown in the sample accessory.
  51.  
  52. 5.  You need to declare one more EXTERNAL function in your desk accessory
  53.     program:
  54.       FUNCTION Menu_Register( ap_id : integer ; VAR name : Str255 ) : integer ;
  55.         EXTERNAL ;
  56.     This function already appears in the PASGEM library, but it does not appear
  57.     in GEMSUBS.PAS (you can add it there, if you wish).  Use the Menu_Register
  58.     function to insert the name of your accessory in the "Desk" menu.  See the
  59.     sample accessory for details.
  60.  
  61. Next, you need to create a file called PASACC.O by running the MAKEACC.PAS
  62. program listed below.  You must enter a valid stack size; although you could
  63. use most any size, we recommend 5 Kbytes.  After creating the PASACC.O file,
  64. link your program as follows:
  65.  
  66. 1.  You must link PASACC.O as the first link file, not the object file produced
  67.     by your Pascal source program.  Put the name of your Pascal object program
  68.     in the "Additional Link Files" field of the link options dialog box.
  69.  
  70. 2.  Select the "Link..." item in the files menu.  When the ITEM SELECTOR dialog
  71.     appears, select the file PASACC.O-- remember, your program's .O file must
  72.     already be in the "Additional Link Files" list!
  73.  
  74. 3.  The linker should load and link your program normally.  The final output
  75.     file will be named PASACC.PRG.  Change this to any name, but give it the
  76.     extension ".ACC" (this tells GEM to load the accessory upon booting).  If
  77.     you have an early version of GEM/TOS, you may need to name your file
  78.     DESK3.ACC (the earliest version needed the "DESK#" primary name).
  79.  
  80. 4.  Copy your accessory file to a backup of your boot disk, and reboot your ST.
  81.     The name of your accessory should appear under the "Desk" menu.  If you
  82.     select your accessory, it should run.
  83.  
  84. LISTING OF MAKEACC.PAS
  85. ----------------------
  86.  
  87. PROGRAM Make_Accessory ;
  88.  
  89.   VAR
  90.     stack_size : Integer ;
  91.     answer : STRING ;
  92.  
  93.   PROCEDURE Write_Accstart( size : Integer ) ;
  94.  
  95.     VAR
  96.       f : FILE OF integer ;
  97.  
  98.     PROCEDURE Word( w : Integer ) ;
  99.  
  100.       BEGIN
  101.         f^ := w ;
  102.         put( f ) ;
  103.       END ;
  104.  
  105.     PROCEDURE Long( l : Long_Integer ) ;
  106.  
  107.       BEGIN
  108.         Word( Int(Shr( l, 16 )) ) ;
  109.         word( Int( l ) ) ;
  110.       END ;
  111.  
  112.     BEGIN
  113.       writeln( 'Opening PASACC.O...' ) ;
  114.       rewrite( f, 'pasacc.o' ) ;
  115.       writeln( 'Writing data...' ) ;
  116.       { Put out the object file header: }
  117.       Word( $601A ) ;
  118.       Long( $14 ) ;
  119.       Long( 0 ) ;
  120.       Long( size+4 ) ;
  121.       Long( 0 ) ;
  122.       Long( 0 ) ;
  123.       Long( 0 ) ;
  124.       Word( 0 ) ;
  125.       { Now the code: }
  126.       Word( $4FF9 ) ;       { lea user_stack,sp }
  127.       Long( size ) ;
  128.       Word( $41F9 ) ;       { lea stack_start,a0 }
  129.       Long( 0 ) ;
  130.       Word( $2248 ) ;       { movea.l a0,a1 }
  131.       Word( $4EF9 ) ;       { jmp prg_start+12 }
  132.       Long( $20 ) ;
  133.       { Now the relocation information: }
  134.       Word( 7 ) ;
  135.       Long( $50003 ) ;
  136.       Word( 7 ) ;
  137.       Long( $50003 ) ;
  138.       Word( 7 ) ;
  139.       Word( 7 ) ;
  140.       Long( $50002 ) ;
  141.       writeln( 'Finished!' ) ;
  142.     END ;
  143.  
  144.   BEGIN
  145.     REPEAT
  146.       write( 'How many Kbytes for desk accessory stack? ' ) ;
  147.       readln( stack_size ) ;
  148.       write( stack_size:1, ' Kbytes-- is this correct? ' ) ;
  149.       readln( answer ) ;
  150.     UNTIL (length(answer) > 0) AND ((answer[1] = 'y') OR (answer[1] = 'Y')) ;
  151.     IF ((answer[1] = 'y') OR (answer[1] = 'Y')) THEN
  152.       Write_Accstart( stack_size*1024 ) ;
  153.   END.
  154.  
  155. LISTING OF ACCDEMO.PAS (SAMPLE ACCESSORY)
  156. -----------------------------------------
  157.  
  158. { We don't want any stack (PASACC.O takes care of the stack) and we certainly
  159.   shouldn't be in full debug mode! }
  160.  
  161. {$S0,D-}
  162.  
  163. PROGRAM Sample_Accessory ;
  164.  
  165.   CONST
  166.     {$I gemconst.pas}
  167.     AC_Open  = 40 ;     { Two new messages which only accessories will get. }
  168.     AC_Close = 41 ;
  169.  
  170.   TYPE
  171.     {$I gemtype.pas}
  172.  
  173.   VAR
  174.     window,                     { The handle of our window. }
  175.     ap_id,                      { Our application identification handle. }
  176.     menu_id : integer ;         { The index of our menu item in "Desk" menu. }
  177.     our_name,                   { The name of our accessory. }
  178.     wind_name : Str255 ;        { The title of our window. }
  179.  
  180.   {$I gemsubs.pas}
  181.  
  182.   { You must declare this function either in your accessory program (as here)
  183.     or in the GEMSUBS.PAS file: }
  184.  
  185.   FUNCTION Menu_Register( id : integer ; VAR name : Str255 ) : integer ;
  186.     EXTERNAL ;
  187.  
  188.  
  189.   { Open our window, if not already open.  If our window IS open already, just
  190.     make it the front window. }
  191.  
  192.   PROCEDURE Do_Open ;
  193.  
  194.     BEGIN
  195.       { Does our window already exist? }
  196.       IF window <> No_Window THEN
  197.         Bring_To_Front( window )        { Yes, just make it front window. }
  198.       ELSE
  199.         BEGIN                           { No, open a new window. }
  200.           wind_name := ' Accessory Test ' ;
  201.           window := New_Window( G_Name|G_Close|G_Size|G_Move, wind_name,
  202.                                 0, 0, 0, 0 ) ;
  203.           Open_Window( window, 0, 0, 0, 0 )
  204.         END
  205.     END ;
  206.  
  207.  
  208.  
  209.   { Close our window and delete it from the system. }
  210.  
  211.   PROCEDURE Do_Close ;
  212.  
  213.     BEGIN
  214.       Close_Window( window ) ;
  215.       Delete_Window( window ) ;
  216.       window := No_Window
  217.     END ;
  218.  
  219.  
  220.  
  221.   { Redraw an area of our window.  The area to redraw is passed in the
  222.     parameters x0, y0, w0, and h0.  For simplicity, we just draw a rectangle
  223.     of the same size as the area to redraw and draw an X in it.  This is also
  224.     interesting to watch since it shows exactly what redraw messages GEM is
  225.     sending. }
  226.  
  227.   PROCEDURE Do_Redraw( handle, x0, y0, w0, h0 : integer ) ;
  228.  
  229.     VAR
  230.       x,                { These four variables are used to hold the size of }
  231.       y,                { the current rectangle in the list for our window. }
  232.       w,
  233.       h : integer ;
  234.  
  235.     BEGIN
  236.       Begin_Update ;            { Tell GEM we are updating, }
  237.       Hide_Mouse ;              { and hide mouse so we don't mess up screen. }
  238.       Paint_Color( White ) ;    { We'll be clearing each rectangle w/ white. }
  239.       { This loop should look familiar, since it is copied out of the
  240.         Pascal manual, p.
  241.       First_Rect( handle, x, y, w, h ) ;
  242.       WHILE (w <> 0) AND (h <> 0) DO
  243.         BEGIN
  244.           IF Rect_Intersect( x0, y0, w0, h0, x, y, w, h ) THEN
  245.             BEGIN
  246.               { The only thing that's new is what we're drawing: }
  247.               Set_Clip( x, y, w, h ) ;
  248.               Paint_Rect( x, y, w, h ) ;        { First clear to white... }
  249.               Frame_Rect( x, y, w, h ) ;        { Then draw rectangle outline }
  250.               Line( x, y, x+w-1, y+h-1 ) ;      { and two lines to form an X. }
  251.               Line( x+w-1, y, x, y+h-1 )
  252.             END ;
  253.           Next_Rect( handle, x, y, w, h ) ;
  254.         END ;
  255.       Show_Mouse ;              { OK, we can redraw the mouse, too, }
  256.       End_Update                { and tell GEM we're finished! }
  257.     END ;
  258.  
  259.  
  260.  
  261.   { This next routine performs all events we receive from GEM.  Since we are
  262.     an accessory, we will never reach a state where we will stop running, so
  263.     the loop below (for each event we get) is infinite! }
  264.  
  265.   PROCEDURE Event_Loop ;
  266.  
  267.     VAR
  268.       event, dummy : integer ;
  269.       msg : Message_Buffer ;
  270.  
  271.     BEGIN
  272.       WHILE true DO
  273.         BEGIN
  274.           { Get one event-- we're only interested in messages. }
  275.           event := Get_Event( E_Message, 0, 0, 0, 0,
  276.                         false, 0, 0, 0, 0, false, 0, 0, 0, 0,
  277.                         msg, dummy, dummy, dummy, dummy, dummy, dummy ) ;
  278.           CASE msg[0] OF
  279.             AC_Open:
  280.               IF msg[4] = menu_id THEN  { If our menu item was selected, }
  281.                 Do_Open ;               { open the window! }
  282.             AC_Close:
  283.               { If we haven't already closed our window, pretend it's closed
  284.                 (because GEM is going to close it for us!)  Presumably, the
  285.                 program that was running when we were opened has finished. }
  286.               IF (msg[4] = menu_id) AND (window <> No_Window) THEN
  287.                 BEGIN
  288.                   window := No_Window
  289.                 END ;
  290.             WM_Sized,           { Allow any size or position on the screen. }
  291.             WM_Moved:           { (we really should have a minimum size!) }
  292.               Set_WSize( msg[3], msg[4], msg[5], msg[6], msg[7] ) ;
  293.             WM_Closed:          { User wants to close our window-- close it. }
  294.               Do_Close ;
  295.             WM_Redraw:          { Need to redraw a portion of our window. }
  296.               Do_Redraw( msg[3], msg[4], msg[5], msg[6], msg[7] ) ;
  297.             WM_Topped:          { Aha, user wants us to be front window! }
  298.               Bring_To_Front( msg[3] ) ;
  299.           END
  300.         END
  301.     END ;
  302.  
  303.  
  304.  
  305.   { Main routine-- initialize GEM, then insert our name into the "Desk" menu
  306.     and go to our event loop.  That routine will NEVER return!  That's why we
  307.     don't need an Exit_Gem call at the end of the program. }
  308.  
  309.   BEGIN
  310.     ap_id := Init_Gem ;         { We do need to save our application ID... }
  311.     IF ap_id >= 0 THEN          { that's a change from most programs. }
  312.       BEGIN
  313.         { Starting off with no window on the screen: }
  314.         window := No_Window ;
  315.         { You should always put two spaces before the name of the accessory: }
  316.         our_name := '  Sample Accessory' ;
  317.         { Here is where we use the application ID number: }
  318.         menu_id := Menu_Register( ap_id, our_name ) ;
  319.         Event_Loop ;
  320.       END
  321.   END.
  322.