Expand/Shrink

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 :

-- 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
The handler routine is associated with a control or Window by:

    setHandler(MAINWINDOW,routine_id("handler_MAINWINDOW"))
Multiple controls can be associated with the same handler by listing them in a sequence as the first parameter of setHandler(), eg:

    setHandler({BUTTON1,BUTTON2}, routine_id("handler_BUTTONS"))
Each handler routine is a function and must have the parameters in the following format:

function handler_CONTROL(integer id, integer msg, atom wParam, object lParam)
    -- some code
    return 0
end function
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 :

-- 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
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:

    while c_func(xGetMessage, {msg, NULL, 0, 0})<=0 do
        c_proc(xTranslateMessage, {msg})
        c_proc(xDispatchMessage, {msg})
    end while
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):

    setHandler(IDLE, routine_id("MyBackgroundRoutine"))
Now, the background operation may be started or stopped using calls to 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).