[GUI] Another call for votes

Glynn Clements glynn.clements@virgin.net
Tue, 18 Mar 2003 18:46:42 +0000


Daan Leijen wrote:

> This mechanism is enough to build a nice framework around. For example, you
> could add a callback to the existing ones.
> 
>   buttonAddOnClick io button
>     = do prev <-buttonGetOnClick button
>          buttonSetOnClick (do{ io; prev }) button

The problem arises when the completely unrelated code which installed
the original callback want to remove it. The "daisy chain" approach
only works if callbacks are removed in the reverse order to their
installation.

> The only think lacking is indeed the "unregister" call but I think
> it is a highly unusual thing to deinstall a callback without
> replacement on an existing widget.

Maybe on Windows, where you can just have the callback do nothing if a
flag is set. On X, it's important to deregister callbacks
(particularly for mouse motion) when they aren't required.

> >  I disagree with this design. It is very awkward to install callbacks
> >  this way as we have to maintain the "unregister" function. We can no
> >  longer use "nice" syntax like:
> > 
> >    button [on click := messageBox "hi there"]
> 
> You can have the "unregister onClick action" in the resulting
> "ButtonType" value, just as you keep there other important attributes of
> a button.

Not if you want to support multiple callbacks for each event. In that
case, you need to be able to identify a specific callback, which gets
us back to the issue of equality of function types.

Unfortunately, the easiest solution (require the application to
provide a FunPtr, as that's what's going to be passed to the lower
levels) is also the ugliest.

>      2a)
>          For every callback, there should be a register function.
>          The register function should return an IO action that can be 
>          used to unregister the callback.
>          There can be multiple callbacks for one event.

> I'd like to provide an example of where I'd prefer to have 2a:

A more obvious example: libraries. Code which is passed a reference to
a widget should be able to add and remove callbacks for that widget
independently of any other code.

Having a single callback necessitates global coordination.

Axel Simon wrote:

> > I disagree with this design. It is very awkward to install callbacks this 
> > way as we
> > have to maintain the "unregister" function. We can no longer use "nice" 
> > syntax like:
> > 
> >  button [on click := messageBox "hi there"]
> 
>  I think this is one of the mid-level features we want to keep: A 
> convenient syntax, not just a bunch of IO functions like
> 
> >  buttonOnClick    :: IO () -> Button -> IO ()
> >  buttonGetOnClick :: Button -> IO (IO ())

The "convenient syntax" only makes sense if you view events and
callbacks as being in 1:1 correspondence. Not all toolkits take this
view. Xt has callback lists, where callbacks can be added and removed
independently (callbacks are identified by equality on function
pointers, which becomes problematic if you want to pass Haskell
functions directly); similarly for the signal/slot approach.

-- 
Glynn Clements <glynn.clements@virgin.net>