Brent 'Dax' Royal-Gordon wrote:

> Gordon Henriksen wrote:
> 
> >> Oh, it's worse than that—GUI commands need to be issued 
> from the main 
> >> thread, at least with OS X. (There's no actual requirement 
> as to which 
> >> thread handles the actual events as long as you treat the OS event 
> >> queue as the thread-unsafe thing it seems to be) Or so the 
> docs seem 
> >> to indicate, though they may be a bit conservative.
> ...
> >     1. Don't call it "events" so that people aren't 
> disappointed and 
> > frustrated, or
> >     2. Figure out some way to fold in GUI events.
> 
> One general-purpose Parrot event queue, plus another for the 
> GUI thread. 
>   When you call a method on the GUI bindings, it really enqueues an 
> event for the GUI thread, which receives the message and calls the 
> actual method.
> 
> Or for that matter, enqueue an event in the main queue that 
> only the GUI thread is interested in.

Brent,

That's tantamount to fine-grained locking on a collection; instead of a
mutex, an OS thread does the serialization. Fine-grained locking doesn't
work.

It's also going to be ridiculously slow.

Can you imagine what havoc this would wreak with multiple "writers"? Not
a solution.

The Carbon Event Manager is (synchronously) interested in your
callback's return value; if a Carbon event handler callback returns
kEventNotHandled, the Event Manager may supply a default implementation.

Not a solution. A GUI event simply MUST be handled from the context that
the operating system or GUI toolkit called the callback; anything else
is addled.



This might be too large a problem, despite seemingly easy to squash into
one API at the first pass. Might it help to consider breaking down and
decoupling the problem for better flexibility? Here's a pass...

 -> class: EventData
    
    Parameter block storing information about an event that has
    occurred. Passed as the only argument to event handlers by
    convention. No intrinsic fields or operations.
    
    Subclasses: IOEventData,
                SignalEventData,
                MacMouseEventData,
                Win32MouseEventData,
                ...
    
 -> class: Event
    
    A registery of event handlers for a particular event. Defines
    ordering and fallback behavior and soforth, should multiple
    handlers be registered.
    
    Instantiate one Event for each distinguishable kind of event
    which can occur; handlers can then.

    Anonymous handlers? Not so much. How magic collections which
    make Events on-demand?
    
    Methods: RegisterHandler(&handler)
             UnregisterHandler(&handler)
               This API is awkward without method pointers.
               So add a userdata parameter; whatever, details.

             CallHandlers([EMAIL PROTECTED])
               Synchronously calls registered handlers.
               Parrot's event loop would call this, as would
               anything which wanted to control the thread on
               which events were dispatched.
    
    Subclasses? Maybe to override the behavior of CallHandlers,
    for specialized fallback behaviors. Or perhaps to register
    "interest" in the event with the OS event.
    
 -> class: EventSource

    Something that can wake parrot's main event loop.
    
    Methods: Enable()
               Turn on the spigot: Register the event source
               with parrot's main event loop.

             Disable()
               Turn the spigot back off. Non-recurring sources
               (e.g., one-off timers) ought to disable themselves
               automatically.
    
    Subclasses: Timer,
                IOEventSource,
                SignalEventource

This is all "user-mode" API, very close to the operations I'd want to
see from an HLL. Adapt for C/parrot core use as appropriate. I've
avoided cluttering the API by adding state variables; method pointers
generally take care of that just fine.

If EventData is kept naïve of Event, and Event is kept naïve of
EventSource, then I think this comprises a pretty agile design.

All a GUI event loop needs to do to fit in is to invoke
CallHandlers(...) on an Event from a C shim. The event will be handled
synchronously on that thread, and any return values necessary can be
passed back in a field of the EventData. (Parameter blocks are good for
both directions, after all.) Since the event loop would know the
thread/interpreter, it can safely create the EventData object.

For high-performance subsystems, it might be best to be able to skip the
EventData if no parameters to the operation are necessary.

Also consider user-mode events. A user program might want to use events
to, say, signal changes in data to UI views which are displaying that
data. That's probably a synchronous, rather than asynchronous,
operation.

All of the scary asynchronous stuff is hidden away in the EventSource
and parrot's event loop. Nothing above is so intrinsically asynchronous.
Which is fine.

The internal event queue and runloop undoubtedly require considerable
platform specialization and otherwise voodoo; "enabling" the
SignalNotificationSource is undoubtedly more complex than just that.
Implementation detail. They don't even appear in the design above; all
user-level. (Which is not to say that these details are unnecessary.)


Hope that's useful.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]

Reply via email to