home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / windows / b007_1 / Docs / 5%a0PUAuthor < prev    next >
Text File  |  1993-05-25  |  17KB  |  387 lines

  1. Adding your own PopUp Handler
  2. =============================
  3.  
  4. You may add your own PopUp handlers to the PopUp Server application, either
  5. to provide new PopUp types, or to provide a different implementation for an
  6. existing PopUp type.
  7.  
  8. Your code may be written in any language from which you can get linkable
  9. AOF output (C, assembler). The basic procedure is as follows:
  10.  
  11.     Write the .c code for your handler, e.g. _ProgInfo.c
  12.     
  13.     Provide in this, an
  14.     
  15.         extern handler_info HandlerInfo_ProgInfo
  16.     
  17.     which describes your handler, and includes a pointer to it's entry
  18.     function, etc. Then edit HandlerTab.c - add a line to the list:
  19.     
  20.         HandlerInfo_Proginfo,
  21.     
  22.     Edit PopUps.h - add a prototype for your HandlerInfo:
  23.     
  24.         extern handler_info HandlerInfo_ProgInfo;
  25.  
  26. Compile this code, and link it with DeskLib 2.00 or later.
  27.  
  28.  
  29. Supplied functions/constants
  30. ============================
  31.  
  32. The PopUp Server supplies a few special functions for you to use instead of
  33. DeskLib functions, or to do special PopUp-related things, as well as some
  34. predefined constants which you should use to make your code more easily
  35. fixed if changes occur. These are defined at the bottom of Server.h and are
  36. listed again below.
  37. DO NOT use any functions/variables that are not listed here!
  38.  
  39.   /*  SendState
  40.    *  Packages the given PopUp-specific data section of the application params
  41.    *  into a message_PopUpState, and sends it back to the client task.
  42.    */
  43. extern void SendState(void *statedata, int statesize);
  44.  
  45.  
  46.   /*  ImDragging
  47.    *  If you wish to start a drag operation in your handler, you MUST call
  48.    *  this function as you do so - this tells the server that you are the
  49.    *  handler to call back when the drag finishes - if you do not call this
  50.    *  then the server will not call you (and will fail to process the drag
  51.    *  finish event)
  52.    */
  53. extern void ImDragging(void);
  54.  
  55.  
  56.   /*  SetIconText
  57.    *  Equivalent to DeskLib's Icon_SetText, with one VERY IMPORTANT difference
  58.    *  - it handles strings terminated with CR (13) instead of NUL (0), which
  59.    *  may be passed in from BASIC and assembler client tasks.
  60.    *  You therefore MUST use this version instead of Icon_SetText!!!
  61.    */
  62. extern void SetIconText(window_handle w, icon_handle i, char *text);
  63. #define Icon_SetText SetIconText
  64.  
  65.  
  66.   /*  ShowStaticPopUp
  67.    *  If you are providing a static PopUp, you will need to open it at
  68.    *  the x and y position requested by the user. To make this easier,
  69.    *  and help to share such code, this function is provided, which simply
  70.    *  opens the given window at the given top-left position.
  71.    *  (i.e. use ShowStaticPopUp(ctrl->basewindow, ctrl->openx, ctrl->openy);
  72.    *
  73.    *  This call will also repel your window approximately 64 OS units away
  74.    *  from the edges of the screen, which ensures that the iconbar is always
  75.    *  visible, and is generally much nicer than opening hard up against an
  76.    *  edge of the screen.
  77.    */
  78. extern void ShowStaticPopUp(window_handle window, int openx, int openy);
  79.  
  80.  
  81.   /*  KillMe
  82.    *  Will kill off the current PopUp 
  83.    *  If a PopUp wishes to let everyone know that it has closed, then
  84.    *  it MUST call KillMe(). This should only be necessary on event_CLOSE
  85.    *  Wimp events, or if a 'cancel' button is clicked, etc.
  86.    *  (You do not need to call this function if you are told to close with
  87.    *  a REASON_CLOSE)
  88.    *
  89.    *  If you do not call this function, then you will continue to recieve
  90.    *  WIMP events, and will tie up one static-instantiation slot. (bad)
  91.    *
  92.    *  VERY IMPORTANT NOTE:
  93.    *  This call removes your PopUp instantiation information, which means
  94.    *  after the call you cannot rely on the passed-in ctrl block and
  95.    *  private workspace any more. (The former may have been changed and the
  96.    *  latter WILL have been deallocated). This should therefore be the very
  97.    *  last thing in your code before you return control for the last time.
  98.    */
  99. extern void KillMe(void);
  100.  
  101.  
  102.   /*  Template_RMAFind
  103.    *  Roughly the same as Template_Find
  104.    *  However it actually clones into malloc() and RMA static memory chunks
  105.    *  so that the indirected data is always paged in.
  106.    *  THIS SHOULD ONLY be called if your PopUp is to be shown as a MENU LEAF
  107.    *  (because otherwise you will most likely be overwriting/overwritten by
  108.    *  another PopUp in these static memory areas)
  109.    *  i.e. only use it:
  110.    *    if ((ctrl->appflags & APPFLAGS_ISLEAF) != 0)
  111.    *  If this is not the case, or if it is a Static PopUp, then use the normal
  112.    *  Template_Find or Template_Clone.
  113.    *
  114.    *  This function only guarantees 1024 bytes of space for indirected icon
  115.    *  data. If you need more than this (shame on you!) you will need to
  116.    *  alter the constant at the top of Template.c
  117.    */
  118. extern window_block *Template_RMAFind(char *name);
  119.  
  120.  
  121.   /*  For REASON_OPEN, the pollblock contains a PopUpOpen message.
  122.    *  The definition of this includes the message header, the PopUp handle,
  123.    *  then the application parameter block header, followed (at offset 48 into
  124.    *  the complete WIMP message) by the PopUp-specific data.
  125.    *  Note that the pollblock includes a word at the front (event type), so
  126.    *  this shifts our data to offset 52 within the passed pollblock,
  127.    *  i.e. ((int) pollblock)+52 is the base address of the PopUp specific data
  128.    */
  129. #define POPUP_DATA_OFFSET 52
  130.  
  131.  
  132. For examples, see the enclosed source code, and preferably use it as a
  133. template/shell for your own code to ensure you do everything right.
  134.  
  135.  
  136. Your handler function
  137. =====================
  138.  
  139. It should be farly straightforward to see what is going on in the supplied
  140. PopUp sources. The basics are as follows, though:
  141.  
  142. You supply a single handler function, which is called with 4 parameters:
  143.   R0 (parameter 0) = reason code
  144.   R1 (parameter 1) = control block
  145.   R2 (parameter 2) = private workspace
  146.   R3 (parameter 3) = Wimp poll event description block
  147.  
  148. These parameters are described below.
  149.  
  150. Static PopUps, being 'permanent' windows (they only go away when explicitly
  151. closed), can possibly allow several of the same type of PopUp to be open at
  152. once (e.g. both Draw and Edit could be displaying a FontSelect at once)
  153.  
  154. Thus, static PopUp handlers should be able to handle multiple instantiations.
  155. To help this along, your handler is called with a different control block
  156. and workspace area for each PopUp type - USE THEM! Do NOT store window-specific
  157. data in static storage- use the provided workspace block.
  158.  
  159.  
  160. Reason code
  161. -----------
  162.  
  163. This number tells your handler function why it is being called. Currently
  164. there are 3 reason codes defined (plus some proposed ones). They are:
  165.  
  166.   Reason code = 0 (open)
  167.     You must create a new PopUp window according to the data passed in
  168.     the Wimp poll event description block (which contains a complete
  169.     Message_PopUpOpen - popup specific data starts at (event block) + 48)
  170.  
  171.     You should fill in appropriate sections of the control block (see below)
  172.     such as the window handle and the poll mask before you exit.
  173.  
  174.     To exit, you return TRUE if you succeeded in creating the PopUp, else FALSE
  175.  
  176.     MENU LEAF PopUp
  177.       Ensure the window does not have a close icon
  178.  
  179.       Duplicate the template using Template_FindRMA - if you do not do this,
  180.       the WIMP stupidly looks in the wrong place for indirected icon data
  181.       in the wrong application's workspace, and will crash your client!
  182.  
  183.       Create the window, but DO NOT SHOW IT - the server will do this for you.
  184.  
  185.     MENU STANDALONE PopUp
  186.       Ensure that the window does have a close icon
  187.  
  188.       If you do not supply a STATIC PopUp, then you may use Template_Find
  189.       to save memory - otherwise, you must use Template_Clone.
  190.  
  191.       Create the window, but DO NOT SHOW IT - the server will do this for you.
  192.  
  193.     STATIC PopUp
  194.       Use Template_Clone to create your windows (though Template_Find will
  195.       suffice if the window contains NO indirected data)
  196.  
  197.       Create AND OPEN the window. (Statics may use panes, so the server
  198.       can't make assumptions about how to open the PopUp for you)
  199.       Use ShowStaticPopUp() to open the window, to share existing code.
  200.  
  201.   Reason code = 1 (Close)
  202.     Simply Wimp_DeleteWindow your window. You MUST NOT close the menu tree,
  203.     as this call is used to remove your PopUp as the user moves the mouse
  204.     from one menu item to another!
  205.     Remember to call KillMe();
  206.  
  207.   Reason code = 2 (Wimp Event)
  208.     You must try to process the Wimp event passed to you (parameter 3).
  209.     If you succeed in processing the event, return TRUE, else FALSE.
  210.     Note that you may get events intended for OTHER PopUps - you MUST check
  211.     if the event really applies to the PopUp window referenced in the control
  212.     block, and return FALSE if it is not your window!
  213.  
  214.     Events will only be given to you if your poll mask allows it.
  215.     Events you fail to handle (and NULLs) will be passed on to the next
  216.     PopUp handler until somebody handles them. If nobody handles it, a default
  217.     action may be performed by the server (see below).
  218.  
  219.     IMPORTANT NOTES
  220.     1 If your window is not 'auto-redraw', you MUST supply a redraw handler,
  221.       or else an attempt to open your PopUp will result in the machine
  222.       locking up. (Check also that you have enabled event_REDRAW)
  223.  
  224.     2 If you ever start a Wimp drag operation in your event handler, you MUST
  225.       invoke
  226.         ImDragging();
  227.       so that the server knows where to deliver the related drag-finish event.
  228.       If you don't call this function, the drag-finish event will NOT be
  229.       delivered to you.
  230.       In your event_USERDRAG handler, you can assume that the event IS yours,
  231.       as you'll only ever get this event if you call ImDragging as you
  232.       start a drag. Obviously, you should only call ImDragging if you start
  233.       a drag!
  234.       (See _SaveAs.c for an example of a PopUp using drags)
  235.       P.S. Please use Icon_DragASprite where possible (code is already linked
  236.       into the application, and DragASprite looks good - it will do an
  237.       ordinary drag for you under RO2, or if DragASpr is not configured on)
  238.  
  239.     3 If nobody handles the event, the following default action is taken:
  240.         event_OPEN:     Wimp_OpenWindow(&event->data.openblock);
  241.         event_KEY:      Wimp_ProcessKey(event->data.key.code);
  242.  
  243.     4 If the event causes you to close the PopUp, then remember to call
  244.       KillMe() to let the server know the PopUp is closed.
  245.  
  246.     5 VERY VERY important - Menu PopUps
  247.       Whenever you delete your window, you MUST ensure that the menu
  248.       'containing' your window has been closed. In many circumstances you
  249.       can just Wimp_CreateMenu((menu_block *) -1, 0, 0); to kill the menu
  250.       before Wimp_DeleteWindow(), but in some cases you should check
  251.       if your window is open - if it IS open, you need to kill the menu
  252.       before you can Wimp_DeleteWindow.
  253.  
  254.       Failure to Close the menu first will result in the WIMP crashing.
  255.       Closing when it has been closed may result in you killing off another
  256.       (unrelated) menu (e.g. if your window is closed by a click outside the
  257.       window, that click could create a NEW menu before you are called to
  258.       close the window)
  259.  
  260.  
  261. Control Block
  262. -------------
  263.  
  264. This contains some useful information about how to open the PopUp, and
  265. is where you must store relevant information for the server to use.
  266. The control block is laid out as follows:
  267.  
  268.   event_pollmask pollmask        - You must keep this updated with a Wimp_Poll
  269.                                    style PollMask - mask out all events you
  270.                                    don't want, for efficient operation.
  271.   window_handle  basewindow;     - You must store the (BASE) window handle
  272.                                    here for the Server to use.
  273.  
  274.   task_handle    clienttask;     - read-only: The client's taskhandle
  275.   int            openx, openy;   - read only: The x/y position you should
  276.                                    open the window at (top left corner)
  277.   char           appflags;       - read-only: The application flag byte
  278.                                    as described in the application parameter
  279.                                    block details.
  280.  
  281.   NOTE that you will get one such work area for EACH PopUp INSTANTIATION
  282.   that you are controlling (i.e if the server asks you for 2 static PopUps,
  283.   you will be called with two different ctrl and private workspace blocks)
  284.  
  285.  
  286. Private Workspace
  287. -----------------
  288.  
  289.   In the structure used to link your handler to the server, the last item
  290.   is a 'private workspace size'. For each PopUp requested, a new chunk of
  291.   memory is allocated for the relevant handler to use, and is passed in to
  292.   that handler as it's private workspace.
  293.  
  294.   NOTE that you will get one such work area for EACH PopUp INSTANTIATION
  295.   that you are controlling (i.e if the server asks you for 2 static PopUps,
  296.   you will be called with two different ctrl and private workspace blocks)
  297.  
  298.   (See _Magnify.c for an example PopUp which uses the private workspace
  299.   to provide multiple STATIC (and 1 MENU) instantiations)
  300.  
  301.  
  302. Event data
  303. ----------
  304.  
  305. This is a normal DeskLib event_pollblock structure. That is, the first
  306. word contains the reasoncode returned by Wimp_Poll, and the remainder
  307. of the block contains the event-specific data returned by that SWI.
  308.  
  309. It comes to you in entirely uncensored form. If you do not handle the
  310. event, or if it is a NULL event, you MUST return with the block unchanged.
  311.  
  312.  
  313. Adding your own PopUp Server
  314. ============================
  315.  
  316. The PopUpManager module has the ability to use a different aplication as
  317. a server for each PopUp type it knows of. This allows you to write new
  318. server application(s) which replace old PopUps and/or provide new ones -
  319. in this way, you can add assembler or BASIC handlers without having to
  320. be able to link them into the supplied server application.
  321.  
  322. A PopUp server may also be a relocatable module, which may happen in the
  323. future with the base set of standard PopUps. The PopUp interface has been
  324. carefully designed to go through the manager module to allow this sort of
  325. flexibility in how PopUps are served.
  326.  
  327. A PopUp server is very simple to write, especially if you write a dedicated
  328. server for each PopUp (minimising the amount of generic 'handle multiple
  329. PopUp types' code you have to write).
  330.  
  331. It is basically a WIMP application which includes PopUp handler(s).
  332. When it starts up, it registers each handler in turn with the PopUpManager
  333. (SWI PopUp_Register), replacing any existing handlers for those PopUp types.
  334. On exit, it calls PopUp_Deregister for each supplied handler to inform the
  335. manager that they are no longer supported by a server.
  336.  
  337. The supplied PopUp Server plus two PopUps were written in less than a day.
  338. (Though admittedly, I had written similar things a few times before during
  339. development of the system, so knew exactly what to do!)
  340.  
  341. The server must provide a list of PopUp instantiations, indexed by the
  342. PopUp handle that the PopUp Manager generates on PopUp_Open. Of course, if
  343. you provide only a single Menu PopUp, you need not hassle yourself with
  344. multiple instantiations etc.
  345.  
  346. When the server recieves a Message_PopUpOpen, a Message PopUpClose, or
  347. a WIMP event, it adjusts its lists appropriately, and calls the appropriate
  348. handler with a reason code of 0 (open), 1 (close) or 2 (Wimp event).
  349.  
  350. When processing Wimp Events, you should check for important events such as
  351. a quit message, and if you then have not processed the event, pass it on to
  352. the handlers - use of an event mask for each handler can make this quite
  353. efficient. Pass the event around ueach instantiation until a handler has
  354. handled it (though pass NULLs to all handlers which haven't masked them out)
  355.  
  356. After calling the (0) Open Handler, you must check if the PopUp is a Menu
  357. PopUp - if it is, you must do the following:
  358.   IF PopUp is NOT a menu leaf THEN
  359.     SYS "Wimp_CreateMenu",,popupwindow, openx, openy
  360.   ELSE
  361.     Send PopUpRequest message to client task with
  362.       message!20 = popupwindow
  363.       message!24 = openx
  364.       message!28 = openy
  365.    ENDIF
  366.  
  367. The last detail is that the WIMP was not designed with PopUps in mind, and
  368. so the PopUp Manager has been designed around several rather difficult
  369. features (all of which are perfectly reasonable under normal use).
  370.  
  371. One, you see above - the WIMP won't let us attach our window to another task's
  372. menu tree, so we must (currently) request that the application attaches the
  373. window on our behalf using the PopUpRequest message.
  374.  
  375. The only other one that need concern you is that the WIMP assumes that any
  376. window in the menu tree belongs to the menu's creator - this would be fine,
  377. except that it means that when looking for indirected data, the WIMP looks
  378. in the WRONG application's memory slot! This has suitably undesirable effects.
  379. The only way to fix this (currently) is to allocate enough memory in the RMA
  380. to hold all indirected data. Luckily, very little is needed, as the only time
  381. this is a problem is with MENU LEAF PopUps. As only one such PopUp is ever
  382. open, we only ever need to store one such PopUp's data in the RMA.
  383.  
  384. (Standalone MENU and STATIC PopUps work fine, as the whole window/menu-tree
  385. belongs to the PopUpManager in these cases)
  386.  
  387.