Events
Perhaps the most important initial requirement for ARWEN was that the event
handling system be close to maximum speed, have fast background
processing capability and still be user-friendly. Win32lib is
event-based where each event of a control can have it's own
handler. EuWinGui uses a large, omni message loop where detected
events are fed to it by the library. ARWEN has a control-based
message system and is more similar to native Windows programming
than these other libraries. These other libraries also use
procedures to handle events but since ARWEN 0.90 handlers are
functions so that modifying message parameters is intuitive &
easy.
A single message-handler routine is written for each control and almost all messsages for that particular control are fed into it's handler routine, eg :
The handler routine is associated with a control or Window by:
Multiple controls can be associated with the same handler by
listing them in a sequence as the first parameter of
setHandler(), eg:
Each handler routine is a function and must have the parameters
in the following format:
The default value to return from any handler function must always
be 0 but certain messages can have other values and is explained
further on. The routine parameters are mostly identical to the
native Win32 parameters that are initially passed back to
SubProc() & WndProc() by Windows. The first difference is
that "atom hWnd" has been replaced with "integer
id". The second difference is that lParam can sometimes be a
sequence of parameters so you should probably use "object
lParam". These and other differences are specific to the
actual message and are shown later in this document. However,
generally speaking, the interpretation of each message parameter
is the same as a native Win32 message. Please note that almost
all Win32 messages will pass through the user handlers. ARWEN
does trap a few of them but, basically, the user has carte
blanche. This may be too much of a good thing in some cases and
unless you are an experienced Win32 programmer then I suggest you
stick to the core Win32 messages. To be honest, I have not mapped
out all the core messages myself and this document later shows
the ones I have. The advantage of having unrestricted access to
all messages sent to a particular control is that specialized
message processing can occur.
Important Notice: Messages are sent to a control OR the control's parent (usually a Window). Notification messages are sent from a control to it's parent. The library will try to trap this type of message and redirect them to the (child) control's handler routine. Messages redirected in this way should not be (intercepted and) altered since the redirection process alters the Message format. Whoever writes the handler routines must be aware of this.
The user can intercept and alter certain messages and thus modify the default Windows processing. This is done by returning a 2-element sequence containing your values of {wParam, lParam}. This can be used to advantage when, say, implementing a password window where you do not want the actual characters shown on the screen, eg :
The return value from the handler function will be ignored if the
handler is processing WM_MOUSE, WM_PAINT, WM_COMMAND or
WM_*SCROLL messages. The typical messages that can be
(intercepted &) modified usually relate to keystrokes, mouse
and also the focus but can include things such as the
TCN_SELCHANGING message trapped by the handler of a TabItem. This
message notifies that the TabItem is about to close and another
one will be opened. If the handler returns 1 then the tab change
will be aborted. ARWEN uses this capacity to emulate an intuitive
behaviour for disabled controls. Please consult the
Windows Messages
section for details on all
values that can be used with specific messages.
Generally speaking, the return values from handlers can be in 3 formats:
return 0 - this is the default value when you want windows to process the message
return {i} - use a 1-element sequence to tell windows to return with the enclosed value immediately
return {W, L} - intercept & modify original message for windows to process Apart from the specific messages that ARWEN traps, the user has access to all other messages but the user is advised to refer to the API for specific implementation details. In some instances the user may be able to return an atomic value other than 0 for certain messages. These cases are discussed in other sections.
If a control has been associated with a particular handler routine and you wish to replace that routine with another then simply call setHandler() again and pass the new routine id. If you wish to disassociate the control from any handler routine then call setHandler() and pass UNDEFINED as the 2nd parameter. Multiple controls may be relinked or disassociated in a single call.
The heart of an event-driven Windows program is the Message Loop. In my library this loop resides in the WinMain() routine. Usually it would be something like this:
The problem here is that the xGetMessage{} call will not return
until a message (aka event) is placed in the message buffer and
control is handed back to the application. This means that the
program will sit idly until some event occurs. Now, some
applications may need to perform certain background processing
tasks but are really unable to do so using this
"standard" message loop. I have modified the message
loop so that while there are NO pending messages in the buffer
the application can run a continuous background task. To set this
up the application must include this line (as if setting up a
regular handler):
Now, the background operation may be started or stopped using
calls to
Please note that
IDLE is a global atom that ARWEN recognizes. Please note about the IDLE handler :
1) It is a procedure and NO parameters are passed to it since ARWEN does the calling not Windows.
2) The handler should spend only a short time doing any processing before returning.
3) The handler will fire when a Common Dialog box is open.
4) The handler may be relinked or disassociated in exactly the same way as other control handlers can be but with the restriction of item 1).
A single message-handler routine is written for each control and almost all messsages for that particular control are fed into it's handler routine, eg :
-- This is a handler routine for a Window function handler_MAINWINDOW(integer id, integer msg, atom wParam, object lParam) if msg=WM_PAINT then -- paint the window elsif msg=WM_VSCROLL then -- scroll something elsif msg=WM_HSCROLL then -- scroll something elsif msg=WM_TIMER then moveFish() -- Eh? Whats going on here? end if return 0 end function -- This is a handler routine for a Button function handler_BUTTON1(integer id,integer msg, atom wParam, object lParam) if msg=WM_COMMAND then -- Button1 was clicked, do something end if return 0 end function
setHandler(MAINWINDOW,routine_id("handler_MAINWINDOW"))
setHandler({BUTTON1,BUTTON2}, routine_id("handler_BUTTONS"))
function handler_CONTROL(integer id, integer msg, atom wParam, object lParam) -- some code return 0 end function
Important Notice: Messages are sent to a control OR the control's parent (usually a Window). Notification messages are sent from a control to it's parent. The library will try to trap this type of message and redirect them to the (child) control's handler routine. Messages redirected in this way should not be (intercepted and) altered since the redirection process alters the Message format. Whoever writes the handler routines must be aware of this.
The user can intercept and alter certain messages and thus modify the default Windows processing. This is done by returning a 2-element sequence containing your values of {wParam, lParam}. This can be used to advantage when, say, implementing a password window where you do not want the actual characters shown on the screen, eg :
-- untested password capture code fragment sequence passwordstring -- holds the password entered passwordstring = "" function handler_PASSWORD_EDITBOX(integer id, integer msg, atom wParam, object lParam) if msg = WM_CHAR then -- printable key was pressed -- add new character to the string variable passwordstring &= wParam -- return new character to print, in this case it's an asterisk return {'*', lParam} elsif msg = WM_KEYUP then if wParam = '\13' then -- ENTER key pressed processPassword(passwordstring) end if end if return 0 end function
Generally speaking, the return values from handlers can be in 3 formats:
return 0 - this is the default value when you want windows to process the message
return {i} - use a 1-element sequence to tell windows to return with the enclosed value immediately
return {W, L} - intercept & modify original message for windows to process Apart from the specific messages that ARWEN traps, the user has access to all other messages but the user is advised to refer to the API for specific implementation details. In some instances the user may be able to return an atomic value other than 0 for certain messages. These cases are discussed in other sections.
If a control has been associated with a particular handler routine and you wish to replace that routine with another then simply call setHandler() again and pass the new routine id. If you wish to disassociate the control from any handler routine then call setHandler() and pass UNDEFINED as the 2nd parameter. Multiple controls may be relinked or disassociated in a single call.
The heart of an event-driven Windows program is the Message Loop. In my library this loop resides in the WinMain() routine. Usually it would be something like this:
while c_func(xGetMessage, {msg, NULL, 0, 0})<=0 do c_proc(xTranslateMessage, {msg}) c_proc(xDispatchMessage, {msg}) end while
setHandler(IDLE, routine_id("MyBackgroundRoutine"))
startIdle()
and
stopIdle()
.
Please note that
startIdle()
must pass a timing
value (in milliseconds) specifying the granularity of calls to the
runIdle()
manager. The particular timing
value is not very important since OS latency etc will mess it up
anyway. A value of, say, 50 milliseconds is probably allright.
IDLE is a global atom that ARWEN recognizes. Please note about the IDLE handler :
1) It is a procedure and NO parameters are passed to it since ARWEN does the calling not Windows.
2) The handler should spend only a short time doing any processing before returning.
3) The handler will fire when a Common Dialog box is open.
4) The handler may be relinked or disassociated in exactly the same way as other control handlers can be but with the restriction of item 1).