home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
hensa
/
windows
/
b007_1
/
Docs
/
5%a0PUAuthor
< prev
next >
Wrap
Text File
|
1993-05-25
|
17KB
|
387 lines
Adding your own PopUp Handler
=============================
You may add your own PopUp handlers to the PopUp Server application, either
to provide new PopUp types, or to provide a different implementation for an
existing PopUp type.
Your code may be written in any language from which you can get linkable
AOF output (C, assembler). The basic procedure is as follows:
Write the .c code for your handler, e.g. _ProgInfo.c
Provide in this, an
extern handler_info HandlerInfo_ProgInfo
which describes your handler, and includes a pointer to it's entry
function, etc. Then edit HandlerTab.c - add a line to the list:
HandlerInfo_Proginfo,
Edit PopUps.h - add a prototype for your HandlerInfo:
extern handler_info HandlerInfo_ProgInfo;
Compile this code, and link it with DeskLib 2.00 or later.
Supplied functions/constants
============================
The PopUp Server supplies a few special functions for you to use instead of
DeskLib functions, or to do special PopUp-related things, as well as some
predefined constants which you should use to make your code more easily
fixed if changes occur. These are defined at the bottom of Server.h and are
listed again below.
DO NOT use any functions/variables that are not listed here!
/* SendState
* Packages the given PopUp-specific data section of the application params
* into a message_PopUpState, and sends it back to the client task.
*/
extern void SendState(void *statedata, int statesize);
/* ImDragging
* If you wish to start a drag operation in your handler, you MUST call
* this function as you do so - this tells the server that you are the
* handler to call back when the drag finishes - if you do not call this
* then the server will not call you (and will fail to process the drag
* finish event)
*/
extern void ImDragging(void);
/* SetIconText
* Equivalent to DeskLib's Icon_SetText, with one VERY IMPORTANT difference
* - it handles strings terminated with CR (13) instead of NUL (0), which
* may be passed in from BASIC and assembler client tasks.
* You therefore MUST use this version instead of Icon_SetText!!!
*/
extern void SetIconText(window_handle w, icon_handle i, char *text);
#define Icon_SetText SetIconText
/* ShowStaticPopUp
* If you are providing a static PopUp, you will need to open it at
* the x and y position requested by the user. To make this easier,
* and help to share such code, this function is provided, which simply
* opens the given window at the given top-left position.
* (i.e. use ShowStaticPopUp(ctrl->basewindow, ctrl->openx, ctrl->openy);
*
* This call will also repel your window approximately 64 OS units away
* from the edges of the screen, which ensures that the iconbar is always
* visible, and is generally much nicer than opening hard up against an
* edge of the screen.
*/
extern void ShowStaticPopUp(window_handle window, int openx, int openy);
/* KillMe
* Will kill off the current PopUp
* If a PopUp wishes to let everyone know that it has closed, then
* it MUST call KillMe(). This should only be necessary on event_CLOSE
* Wimp events, or if a 'cancel' button is clicked, etc.
* (You do not need to call this function if you are told to close with
* a REASON_CLOSE)
*
* If you do not call this function, then you will continue to recieve
* WIMP events, and will tie up one static-instantiation slot. (bad)
*
* VERY IMPORTANT NOTE:
* This call removes your PopUp instantiation information, which means
* after the call you cannot rely on the passed-in ctrl block and
* private workspace any more. (The former may have been changed and the
* latter WILL have been deallocated). This should therefore be the very
* last thing in your code before you return control for the last time.
*/
extern void KillMe(void);
/* Template_RMAFind
* Roughly the same as Template_Find
* However it actually clones into malloc() and RMA static memory chunks
* so that the indirected data is always paged in.
* THIS SHOULD ONLY be called if your PopUp is to be shown as a MENU LEAF
* (because otherwise you will most likely be overwriting/overwritten by
* another PopUp in these static memory areas)
* i.e. only use it:
* if ((ctrl->appflags & APPFLAGS_ISLEAF) != 0)
* If this is not the case, or if it is a Static PopUp, then use the normal
* Template_Find or Template_Clone.
*
* This function only guarantees 1024 bytes of space for indirected icon
* data. If you need more than this (shame on you!) you will need to
* alter the constant at the top of Template.c
*/
extern window_block *Template_RMAFind(char *name);
/* For REASON_OPEN, the pollblock contains a PopUpOpen message.
* The definition of this includes the message header, the PopUp handle,
* then the application parameter block header, followed (at offset 48 into
* the complete WIMP message) by the PopUp-specific data.
* Note that the pollblock includes a word at the front (event type), so
* this shifts our data to offset 52 within the passed pollblock,
* i.e. ((int) pollblock)+52 is the base address of the PopUp specific data
*/
#define POPUP_DATA_OFFSET 52
For examples, see the enclosed source code, and preferably use it as a
template/shell for your own code to ensure you do everything right.
Your handler function
=====================
It should be farly straightforward to see what is going on in the supplied
PopUp sources. The basics are as follows, though:
You supply a single handler function, which is called with 4 parameters:
R0 (parameter 0) = reason code
R1 (parameter 1) = control block
R2 (parameter 2) = private workspace
R3 (parameter 3) = Wimp poll event description block
These parameters are described below.
Static PopUps, being 'permanent' windows (they only go away when explicitly
closed), can possibly allow several of the same type of PopUp to be open at
once (e.g. both Draw and Edit could be displaying a FontSelect at once)
Thus, static PopUp handlers should be able to handle multiple instantiations.
To help this along, your handler is called with a different control block
and workspace area for each PopUp type - USE THEM! Do NOT store window-specific
data in static storage- use the provided workspace block.
Reason code
-----------
This number tells your handler function why it is being called. Currently
there are 3 reason codes defined (plus some proposed ones). They are:
Reason code = 0 (open)
You must create a new PopUp window according to the data passed in
the Wimp poll event description block (which contains a complete
Message_PopUpOpen - popup specific data starts at (event block) + 48)
You should fill in appropriate sections of the control block (see below)
such as the window handle and the poll mask before you exit.
To exit, you return TRUE if you succeeded in creating the PopUp, else FALSE
MENU LEAF PopUp
Ensure the window does not have a close icon
Duplicate the template using Template_FindRMA - if you do not do this,
the WIMP stupidly looks in the wrong place for indirected icon data
in the wrong application's workspace, and will crash your client!
Create the window, but DO NOT SHOW IT - the server will do this for you.
MENU STANDALONE PopUp
Ensure that the window does have a close icon
If you do not supply a STATIC PopUp, then you may use Template_Find
to save memory - otherwise, you must use Template_Clone.
Create the window, but DO NOT SHOW IT - the server will do this for you.
STATIC PopUp
Use Template_Clone to create your windows (though Template_Find will
suffice if the window contains NO indirected data)
Create AND OPEN the window. (Statics may use panes, so the server
can't make assumptions about how to open the PopUp for you)
Use ShowStaticPopUp() to open the window, to share existing code.
Reason code = 1 (Close)
Simply Wimp_DeleteWindow your window. You MUST NOT close the menu tree,
as this call is used to remove your PopUp as the user moves the mouse
from one menu item to another!
Remember to call KillMe();
Reason code = 2 (Wimp Event)
You must try to process the Wimp event passed to you (parameter 3).
If you succeed in processing the event, return TRUE, else FALSE.
Note that you may get events intended for OTHER PopUps - you MUST check
if the event really applies to the PopUp window referenced in the control
block, and return FALSE if it is not your window!
Events will only be given to you if your poll mask allows it.
Events you fail to handle (and NULLs) will be passed on to the next
PopUp handler until somebody handles them. If nobody handles it, a default
action may be performed by the server (see below).
IMPORTANT NOTES
1 If your window is not 'auto-redraw', you MUST supply a redraw handler,
or else an attempt to open your PopUp will result in the machine
locking up. (Check also that you have enabled event_REDRAW)
2 If you ever start a Wimp drag operation in your event handler, you MUST
invoke
ImDragging();
so that the server knows where to deliver the related drag-finish event.
If you don't call this function, the drag-finish event will NOT be
delivered to you.
In your event_USERDRAG handler, you can assume that the event IS yours,
as you'll only ever get this event if you call ImDragging as you
start a drag. Obviously, you should only call ImDragging if you start
a drag!
(See _SaveAs.c for an example of a PopUp using drags)
P.S. Please use Icon_DragASprite where possible (code is already linked
into the application, and DragASprite looks good - it will do an
ordinary drag for you under RO2, or if DragASpr is not configured on)
3 If nobody handles the event, the following default action is taken:
event_OPEN: Wimp_OpenWindow(&event->data.openblock);
event_KEY: Wimp_ProcessKey(event->data.key.code);
4 If the event causes you to close the PopUp, then remember to call
KillMe() to let the server know the PopUp is closed.
5 VERY VERY important - Menu PopUps
Whenever you delete your window, you MUST ensure that the menu
'containing' your window has been closed. In many circumstances you
can just Wimp_CreateMenu((menu_block *) -1, 0, 0); to kill the menu
before Wimp_DeleteWindow(), but in some cases you should check
if your window is open - if it IS open, you need to kill the menu
before you can Wimp_DeleteWindow.
Failure to Close the menu first will result in the WIMP crashing.
Closing when it has been closed may result in you killing off another
(unrelated) menu (e.g. if your window is closed by a click outside the
window, that click could create a NEW menu before you are called to
close the window)
Control Block
-------------
This contains some useful information about how to open the PopUp, and
is where you must store relevant information for the server to use.
The control block is laid out as follows:
event_pollmask pollmask - You must keep this updated with a Wimp_Poll
style PollMask - mask out all events you
don't want, for efficient operation.
window_handle basewindow; - You must store the (BASE) window handle
here for the Server to use.
task_handle clienttask; - read-only: The client's taskhandle
int openx, openy; - read only: The x/y position you should
open the window at (top left corner)
char appflags; - read-only: The application flag byte
as described in the application parameter
block details.
NOTE that you will get one such work area for EACH PopUp INSTANTIATION
that you are controlling (i.e if the server asks you for 2 static PopUps,
you will be called with two different ctrl and private workspace blocks)
Private Workspace
-----------------
In the structure used to link your handler to the server, the last item
is a 'private workspace size'. For each PopUp requested, a new chunk of
memory is allocated for the relevant handler to use, and is passed in to
that handler as it's private workspace.
NOTE that you will get one such work area for EACH PopUp INSTANTIATION
that you are controlling (i.e if the server asks you for 2 static PopUps,
you will be called with two different ctrl and private workspace blocks)
(See _Magnify.c for an example PopUp which uses the private workspace
to provide multiple STATIC (and 1 MENU) instantiations)
Event data
----------
This is a normal DeskLib event_pollblock structure. That is, the first
word contains the reasoncode returned by Wimp_Poll, and the remainder
of the block contains the event-specific data returned by that SWI.
It comes to you in entirely uncensored form. If you do not handle the
event, or if it is a NULL event, you MUST return with the block unchanged.
Adding your own PopUp Server
============================
The PopUpManager module has the ability to use a different aplication as
a server for each PopUp type it knows of. This allows you to write new
server application(s) which replace old PopUps and/or provide new ones -
in this way, you can add assembler or BASIC handlers without having to
be able to link them into the supplied server application.
A PopUp server may also be a relocatable module, which may happen in the
future with the base set of standard PopUps. The PopUp interface has been
carefully designed to go through the manager module to allow this sort of
flexibility in how PopUps are served.
A PopUp server is very simple to write, especially if you write a dedicated
server for each PopUp (minimising the amount of generic 'handle multiple
PopUp types' code you have to write).
It is basically a WIMP application which includes PopUp handler(s).
When it starts up, it registers each handler in turn with the PopUpManager
(SWI PopUp_Register), replacing any existing handlers for those PopUp types.
On exit, it calls PopUp_Deregister for each supplied handler to inform the
manager that they are no longer supported by a server.
The supplied PopUp Server plus two PopUps were written in less than a day.
(Though admittedly, I had written similar things a few times before during
development of the system, so knew exactly what to do!)
The server must provide a list of PopUp instantiations, indexed by the
PopUp handle that the PopUp Manager generates on PopUp_Open. Of course, if
you provide only a single Menu PopUp, you need not hassle yourself with
multiple instantiations etc.
When the server recieves a Message_PopUpOpen, a Message PopUpClose, or
a WIMP event, it adjusts its lists appropriately, and calls the appropriate
handler with a reason code of 0 (open), 1 (close) or 2 (Wimp event).
When processing Wimp Events, you should check for important events such as
a quit message, and if you then have not processed the event, pass it on to
the handlers - use of an event mask for each handler can make this quite
efficient. Pass the event around ueach instantiation until a handler has
handled it (though pass NULLs to all handlers which haven't masked them out)
After calling the (0) Open Handler, you must check if the PopUp is a Menu
PopUp - if it is, you must do the following:
IF PopUp is NOT a menu leaf THEN
SYS "Wimp_CreateMenu",,popupwindow, openx, openy
ELSE
Send PopUpRequest message to client task with
message!20 = popupwindow
message!24 = openx
message!28 = openy
ENDIF
The last detail is that the WIMP was not designed with PopUps in mind, and
so the PopUp Manager has been designed around several rather difficult
features (all of which are perfectly reasonable under normal use).
One, you see above - the WIMP won't let us attach our window to another task's
menu tree, so we must (currently) request that the application attaches the
window on our behalf using the PopUpRequest message.
The only other one that need concern you is that the WIMP assumes that any
window in the menu tree belongs to the menu's creator - this would be fine,
except that it means that when looking for indirected data, the WIMP looks
in the WRONG application's memory slot! This has suitably undesirable effects.
The only way to fix this (currently) is to allocate enough memory in the RMA
to hold all indirected data. Luckily, very little is needed, as the only time
this is a problem is with MENU LEAF PopUps. As only one such PopUp is ever
open, we only ever need to store one such PopUp's data in the RMA.
(Standalone MENU and STATIC PopUps work fine, as the whole window/menu-tree
belongs to the PopUpManager in these cases)