2007-09-23

Events and Multitasking

Switched from passing a pointer to the gadget in calls to the gadget event handler to using an “EventArgs” struct instead. This currently contains a pointer to the gadget, the x and y values of the stylus when the click took place (if relevant), relative to the screen (not the window - more on this later) and the keycode that triggered the event (if relevant, more on this later). This gives me much more information than just the gadget affected by the event.

After I’d done this, I briefly wondered whether I was taking the best approach with the handling functions. Woopsi currently has an event handler function defined for every kind of event - “handleClick()”, “handleRelease()”, “handleKeyPress()”, etc. I considered switching to a single “handleEvent()” function and including an “eventType” enum in the “EventArgs” class, but I decided that this would be just as cumbersome as any other event handling system, but messier with all of the switch() statements that it implied. The .NET-esque “one function per event” system seems much tidier and more maintainable.

The EventArgs struct includes the x and y co-ordinates of the click or release events relative to the DS’ screen rather than the gadget that triggered the event. This was another decision that required some thought. I’d planned to use the co-ordinates relative to the gadget, but decided that this would require laborious conversion back to screen co-ordinates, so thought that I’d include both screen and gadget co-ords. This would mean including the conversion in the gadget, which is a waste of CPU time if we work on the assumption that one of the sets of co-ords wouldn’t be used. In the end, screen co-ords seemed like the best choice.

I may regret this decision later.

Woopsi now includes three more event types - vertical blank, key press and key release. Whenever a key is pressed or released, the system notifies all gadgets within the active screen of the key that caused the event. This means that any gadget can react to d-pad or button presses or releases. I’m undecided as to whether just the active window should receive these events, or whether it’s more useful to send the events around all windows and have the programmer detect if the window he’s working with is active or not. At the moment I’ve got the latter system implemented (as it’s more powerful), but the former system would be faster and require less programmer effort. One to ponder.

Vertical blank events get sent to all gadgets each time the main program loop runs. This gives the system the ability to have screens, windows and gadgets perform actions without waiting for another kind of event, which is essential for things like windowed games, etc. Another decision here that may turn out to be incorrect - VBL events are sent only to the active screen, as any inactive screens are hidden. Makes sense from a graphics point of view, but not much sense from a processing/audio perspective, as they should run regardless of whether or not the screen is visible. Another one to ponder. One last new feature - gadgets now have a drawFilledRect() function that allows developers to draw rectangles into gadgets.

Anyway, all of this new functionality puts me in the position to create a new application with Woopsi; something that requires d-pad input, a realtime display, and boxes. Another version of Pong is the obvious choice, so I now have a very simplistic version of Pong running in a Woopsi window (no collision detection - the ball just bounces off the window edges - because I’m lazy). The strange thing about this is that, because each application runs in a window, and windows are sent VBL events one after another, I’ve implemented a kind of FIFO task scheduling system. Pong runs on the same screen as the calculator application, and both appear to run at the same time. Typing in the calculator doesn’t affect Pong in any way - the CPU bat continues to chase the ball, and the ball continues to move. It’s not a real task scheduler, because these things aren’t really separate tasks - in order to support that I’d have to write an OS, not a GUI. They’re just separate parts of the same application. None of that matters to the user, though. Anyone playing Pong wouldn’t realise that the calculator wasn’t a separate program.

What is increasingly obvious at this point is that I really need to sort out the gadget invalidation and redrawing routines. At present, clicking the screen depth gadget causes it to appear over any overlapping windows, and the Pong window gets drawn over the top of any other windows. Here’s a screenshot of the latest version (new demo soon):

Woopsi Demo V0.08

Comments

ant.simianzombie.com » Blog Archive » Refactoring Events on 2009-04-01 at 21:47 said:

[...] “handleDragEvent()”, etc. I originally followed this pattern, as described back in September 2007, but swapped to the single method on Jeff’s advice. As Woopsi has grown, though, this [...]

ant.simianzombie.com » Refactoring Events and Re-implementing the Wheel on 2009-10-07 at 12:08 said:

[...] “handleDragEvent()”, etc. I originally followed this pattern, as described back in September 2007, but swapped to the single method on Jeff’s advice. As Woopsi has grown, though, this [...]