
On Dienstag, Mär 18, 2003, at 12:33 Europe/Vienna, Daan Leijen wrote:
Hi all,
2) 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.
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"]
Yes, that looks nicer, but it now we can have only one callback for one event; I believe the people who first brought this design up (I was only copying what I had read on this list) were thinking of allowing multiple callbacks to be installed for a single event, as can be done using GTK's signal/slot mechanism. So what about... 2) Installing Callbacks 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. 2b) Callbacks are set using a general attribute get/set mechanism that we will probably design soon. There can be only one callback for one event. Please note that it is very easy to emulate one option using the other, so the features of the backend libraries are probably not an issue here. 2a can, of course, be useful in many situations. I'm not sure if I want the nice syntax or the nice functionality, so I withdraw my vote on 2) and abstain for now. Everyone please keep discussing :-) I'd like to provide an example of where I'd prefer to have 2a: Suppose we have a document window. In order to support a "Save Changes?" dialog, I'd perhaps add a callback for the "window about to close" event. No problems here. Suppose that we also have a utility window that shows information about some item in the document. When the document window closes, the utility window closes, too (we'd like to have a second "close" callback on the document window), but the utility window can also be closed by the user before the document closes (we'd like to uninstall our "close" callback in that case). In most other situations, I would probably prefer the single-callback approach because of the opportunities for nicer syntax.
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
Which is fine as long as you don't want to uninstall a callback. And we might want to use a threadsafe buttonModifyOnClick :: Button -> (IO () -> IO ()) -> IO () instead.
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. Normally, the callbacks are deinstalled when the widget dies. But for completeness, we might want to have:
buttonIgnoreOnClick :: Button -> IO ()
Definitely. For button clicks, it is a non-issue, but some X folk have said that mouse moved events are really bad for remote connections, and I wouldn't bet it's so unusual to track mouse movements only for a short period of time and then uninstall the callback. Cheers, Wolfgang