
| > Peter Aachten goes further. Based on the Clean group's experience, he | > thinks we can not only define a satisfactory (A), but also define a | > lower-level interface (expressed in the C language) that | > suffices to support (A) | > and yet contains no target specific code I phrased this badly. What I meant was this. Let's call the lower-level interface (L). Let's call the thing we are mapping to the "target". A target is either a portable library like GTK, or a native UI platform like Windows. A target is something we don't implement. The goals of (A) are: Reasonably easy for programmers to use Programmer's interface does not change across targets Rich enough to be useful The goals of (L) are Reasonably easy to implement (but maybe less easy to program with) Programmer's interface (from "above") does not change across targets Rich enough to implement (A) As I understand it: ObjectIO and Daan's Graphics.UI.GIO are examples of (A) Daan and Krasimir's Port is an example of (L) When I said "contains no target-specific" code, I meant that the code that implements (A) using (L) is not target specific. The implementation of (L) will certainly be target specific. You are right that (L) does not need to be written in C. Indeed there might be many implementations of (L): some which are entirely in Haskell (perhaps implemented by you), others written mostly in C (using existing libraries). I know little about particular UI libraries. My suggestion, though, is that we focus discussion on what (A) and (L) should look like, rather than on how they should be implemented. Simon

Hi All,
Let me rephrase shortly what Simon has already rephrased :-).
There are three different levels, a middle-ground
GUI library in the IO monad, called (A). A low-level
interface called (L) and a "target" that we map too (T).
The target (T) is any available GUI library, like the portable
GTK, win32, Qt, Aqua, Tcl/Tk, Xlib, but also
Gtk2Hs, the haskell Win32 library or HaskellTk.
Higher level libraries like Fruit, FranTk etc, can be implemented
on top of (A) (or maybe (L)).
The goals of (A) are:
- reasonably easy for programmers to use
- programmer's interface does not change across targets
- at first: rich enough to be useful
+ should have enough flexibility to evolve in time into an
industrial-strength library
The goals of (L) are
- Reasonably easy to implement (but maybe less easy to program with)
- Programmer's interface (from "above") does not change across targets
- Rich enough to implement (A)
+ Exposing platform dependent handles for extensibility
+ Very flat and abstracted interface -- otherwise, we could just as easily
use Qt, the Java AWT/Swing, IBM's SWT or GTK directly! This also means
that the (L) layer will never be as powerful as using the underlying
toolkit
directly. Because of this, (L) needs to expose the 'handles' to allow
power-users
to bypass (L) and call the underlying toolkit directly (= not portable).
There are an enormous amount possible choices in implementing
some GUI library for Haskell: ranging from implementing a complete
do-it yourself toolkit, via native toolkits, to using portable toolkits like
Qt.
** However, in the end, all these approaches will end up exposing an
interface like (L)!! (if only internally). ***
I therefore think that we should try to focus this discussion on
how (L) (and (A)) should look like, instead of trying to compare all
possible
implementation routes. Let us try to define a (L) interface and let people
implement it using their favorite platform.
What I am proposing is to use Port as a concrete proposal for how
the (L) interface should look like. Not that Port is complete, or "just
right",
but because it exists, is still quite small, has implementations on top of
both
GTK and Windows, and seems suitable for implementing an (A) library (i.e.
GIO).
(haddock docs: http://www.cs.uu.nl/~daan/doc/port)
(cvs: http://sourceforge.net/projects/htoolkit)
Another concrete proposal could be the (L) layer of the ObjectIO library.
The great thing about the ObjectIO interface is that it has been used in
large
projects and that people have lots of experience with it. However, at the
same time the library is rather cumbersome to use from Haskell (it has
some Clean quirks) and has only been implemented for Windows.
I am not aware of other (L) layers that are suitable for Haskell but I am
looking
forward to hear more about that.
All the best,
Daan.
----- Original Message -----
From: "Simon Peyton-Jones"
| > Peter Aachten goes further. Based on the Clean group's experience, he | > thinks we can not only define a satisfactory (A), but also define a | > lower-level interface (expressed in the C language) that | > suffices to support (A) | > and yet contains no target specific code
I phrased this badly. What I meant was this. Let's call the lower-level interface (L). Let's call the thing we are mapping to the "target". A target is either a portable library like GTK, or a native UI platform like Windows. A target is something we don't implement.
The goals of (A) are: Reasonably easy for programmers to use Programmer's interface does not change across targets Rich enough to be useful
The goals of (L) are Reasonably easy to implement (but maybe less easy to program with) Programmer's interface (from "above") does not change across targets Rich enough to implement (A)
As I understand it: ObjectIO and Daan's Graphics.UI.GIO are examples of (A)
Daan and Krasimir's Port is an example of (L)
When I said "contains no target-specific" code, I meant that the code that implements (A) using (L) is not target specific. The implementation of (L) will certainly be target specific.
You are right that (L) does not need to be written in C. Indeed there might be many implementations of (L): some which are entirely in Haskell (perhaps implemented by you), others written mostly in C (using existing libraries).
I know little about particular UI libraries. My suggestion, though, is that we focus discussion on what (A) and (L) should look like, rather than on how they should be implemented.
Simon
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui

On Sat, 25 Jan 2003 14:29:29 +0100
"Daan Leijen"
What I am proposing is to use Port as a concrete proposal for how the (L) interface should look like. Not that Port is complete, or "just right",
I reply not to insist on an idea which is surely not mine, but just would like to hear comments on it. Why don't we choose a document model for the interface, like adobe did with DPS and apple with quartz? This has many advantages instead of a C library, as I said before, and can be modeled with a client-server interface wich would avoid foreign-language interoperability problem, allowing one to implement the backend even in QT. Vincenzo -- Fedeli alla linea, anche quando non c'è Quando l'imperatore è malato, quando muore,o è dubbioso, o è perplesso. Fedeli alla linea la linea non c'è. [CCCP]

On Sat, Jan 25, 2003 at 03:01:50PM +0100, Nick Name wrote:
I reply not to insist on an idea which is surely not mine, but just would like to hear comments on it. Why don't we choose a document model for the interface, like adobe did with DPS and apple with quartz? This has many advantages instead of a C library, as I said before, and can be modeled with a client-server interface wich would avoid foreign-language interoperability problem, allowing one to implement the backend even in QT. For me this sounds like inventing another X protocol. This would be just beyond our (time) resources and acutal needs.
Axel.

On Sat, 25 Jan 2003 16:08:07 +0000
Axel Simon
For me this sounds like inventing another X protocol. This would be just beyond our (time) resources and acutal needs.
Axel.
Oh, I didn't notice that the private answer was just a CC. In short, I answered Axel privately about UIML, wich perhaps someone can find of interest; here are three links: http://www.uiml.org http://luxor-xul.sourceforge.net/ http://kuimlrenderer.sourceforge.net Vincenzo PS: Why does everybody on the list CC people who don't ask for it?

Nick Name wrote:
For me this sounds like inventing another X protocol. This would be just beyond our (time) resources and acutal needs.
Axel.
Oh, I didn't notice that the private answer was just a CC. In short, I answered Axel privately about UIML, wich perhaps someone can find of interest; here are three links:
This looks similar to UIL, which has been a standard part of Motif for
many years.
However, such an approach wouldn't actually save us anything.
Sometimes it's necessary to generate interfaces programmatically (e.g.
an HTML browser needs to be able to generate forms), so ultimately we
would still need a programmatic interface for creating and placing
widgets.
--
Glynn Clements

However, such an approach wouldn't actually save us anything. Sometimes it's necessary to generate interfaces programmatically (e.g. an HTML browser needs to be able to generate forms), so ultimately we would still need a programmatic interface for creating and placing widgets.
It's not difficult to design an XML renderer that allows dynamic modification of named (well formed) subdocuments. Surely the interest of such a thing is bigger than the haskell scope (because a server would be useable by many languages), and smaller than the haskell GUI scope (because here we are looking for a quick and not so bad solution). I mentioned it for those who wish to reimplement a backend from scratch, since I would like the advantages of such a solution, but I see that Ports and GTK are taking precedence :) Vincenzo -- Teatri vuoti e inutili potrebbero affollarsi se tu ti proponessi di recitare te [CCCP]

On Sat, Jan 25, 2003 at 02:29:29PM +0100, Daan Leijen wrote:
What I am proposing is to use Port as a concrete proposal for how the (L) interface should look like. Not that Port is complete, or "just right", but because it exists, is still quite small, has implementations on top of both GTK and Windows, and seems suitable for implementing an (A) library (i.e. GIO). Because gtk2hs exists and is availabe on all three platforms, everybody gets the benefit of a complete, professional interface right now, so everyone should accept it as standard and not mourn about the slight differences in UI appearnce :-)
I think existance is not a very good argument. I would like to define the portable library with techniques of the Object I/O and let everyone who has a backend (or is willing to write one) participate in its creation. Basically this is what I proposed as a reply to Simon PJ. Axel.

Hi Axel,
Because gtk2hs exists and is availabe on all three platforms, everybody gets the benefit of a complete, professional interface right now, so everyone should accept it as standard and not mourn about the slight differences in UI appearnce :-)
This is actually a rather good argument in favor of GTK. However, the GTK interface does not satisfy the constraint that it must be reasonably easy to implement. If someone wants a backend for Aqua or whatever, it is extremely hard to create a gtk implementation from scratch. The world would be good place when gtk would be the standard library for writing gui's, but right now, the toolkit is mainly portable across unix platforms.
I think existance is not a very good argument.
You are right about that. I should rephrase that: "since it is implemented for two different targets, it may be a good starting point for the definition of an (L) interface" -- I think it is quite hard to even come up with some interface that is just abstract enough to be implementable by a wide range of targets and is at the same time low-level enough that it is still reasonably easy to implement.
I would like to define the portable library with techniques of the Object I/O and let everyone who has a backend (or is willing to write one) participate in its creation.
That certainly seems a good idea to me. Participation of many people with different backends is fairly essential as the (L) interface will probably change and evolve a lot when different backends are added. To get people involved though, it may be good when the 'GUI task force' is able to define some initial (L) interface that people can try to write backends for. All the best, Daan.

On Sat, Jan 25, 2003 at 06:39:06PM +0100, Daan Leijen wrote:
Hi Axel,
Because gtk2hs exists and is availabe on all three platforms, everybody gets the benefit of a complete, professional interface right now, so everyone should accept it as standard and not mourn about the slight differences in UI appearnce :-)
This is actually a rather good argument in favor of GTK. However, the GTK interface does not satisfy the constraint that it must be reasonably easy to implement. It runs on the XonX implmentation of MacOS X. So one could argue that it is already implemented.
People here expressed the wish for using the native UI elements and the native way of presenting information and interaction with the user (look-and-feel). I grant that Gtk does not deliver this on Aqua and not 100% on Windows.
If someone wants a backend for Aqua or whatever, it is extremely hard to create a gtk implementation from scratch. The world would be good place when gtk would be the standard library for writing gui's, but right now, the toolkit is mainly portable across unix platforms.
Again, for the log-book: gtk2hs runs on Win32, Unix and MacOS X.
I think existance is not a very good argument.
You are right about that. I should rephrase that: "since it is implemented for two different targets, it may be a good starting point for the definition of an (L) interface" -- I think it is quite hard to even come up with some interface that is just abstract enough to be implementable by a wide range of targets and is at the same time low-level enough that it is still reasonably easy to implement.
But that is the gist of the discussion so far, if I am not mistaken. The lower the common API, the harder it is to define it. That is why I proposed to craft an Object I/O interface which enables programmers to write GUI application with a native look and feel albeit with a reduced functionality (because not everything can be expressed with the native set of UI elements). If the programmer is happy with this functionality, fine - (s)he has a portable program with the native look-and-feel. If not, then (s)he has to write non-portable code portions for hToolkit, gtk2hs, a potential Aqua binding, or whatever backends people provide. Only some backend specific code can guarantee that the application is tailored to the platforms native look-and-feel when it comes to more difficult user interfaces.
That certainly seems a good idea to me. Participation of many people with different backends is fairly essential as the (L) interface will probably change and evolve a lot when different backends are added. To get people involved though, it may be good when the 'GUI task force' is able to define some initial (L) interface that people can try to write backends for. Yes, but in my point of view this should be a medium level API like Object I/O, a bunch of IO function is doomed to be defined by the underlying backends. This certainly holds true for the Ports library.
I think Wolfgang will have a hard time making a sensible port of Ports to Aqua. The point is that the "common GUI" interface must enforce invariants such as "each application has exactly one menu bar" or "each pushbutton must have a text in it". Otherwise bindings to Aqua will not be possible. You cannot define a common abstraction without looking at all the implementations you have to do. I think we want three backends: Win32, Gtk and Aqua. So we need to look at all of them before we define the interface. Axel.

You cannot define a common abstraction without looking at all the implementations you have to do. I think we want three backends: Win32, Gtk and Aqua. So we need to look at all of them before we define the interface.
I'd be more inclined to first try to establish the interface we would like to use, and then evaluate that interface against the potential back ends.
Axel.
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui
---------------------------------- Seth Kurtzberg M. I. S. Corp. E-Mail: seth@cql.com Date: 26-Jan-2003 Time: 11:24:17 This message was sent by XFMail ----------------------------------

Axel wrote:
That is why I proposed to craft an Object I/O interface which enables programmers to write GUI application with a native look and feel albeit with a reduced functionality
I am also in favor of a medium level GUI interface. If I gave another impression, that is my fault.
Yes, but in my point of view this should be a medium level API like Object I/O, a bunch of IO function is doomed to be defined by the underlying backends. This certainly holds true for the Ports library.
The (Clean) ObjectIO library actually consists of two layers, an (A) and (L) part. Given their success, this proves that is certainly possible to define a decent (L) layer, on top of which a medium level API is built. Actually, Port is closely modelled after the low-level object IO interface. The "low-level" is not so low-level as you may think. It is rather the core medium-level functionality without any utility functions or abstractions. Again, I feel that we actually agree on all this topics. I am not a native speaker, so it may be that I am not always using the right words for expressing myself. Sorry for that, but I am doing my best :-)
You cannot define a common abstraction without looking at all the implementations you have to do. I think we want three backends: Win32, Gtk and Aqua. So we need to look at all of them before we define the interface.
You are right. I am not advocating that Port is the "right thing" or that it is already mature. I do not have a personal prejudice or something towards Port just because I have worked on it. (I am currently trying to finish my thesis, so I won't be working too much on it for now :-). Port is certainly not the greatest interface or something. If someone defines or proposes something better or more mature, I am all in favor of adapting that. The reason for mentioning Port, is because I believe that it may be a good starting point towards a concrete low-level API. Maybe we can use it directly, maybe the GUI task force can use it to propose a standard GUI API.
I think Wolfgang will have a hard time making a sensible port of Ports to Aqua.
If Wolfgang continues his quest, I am sure that he will find many deficiencies and hopefully Port will change accordingly. This is the whole point off course: Port is still small and flexible, and can easily change when we learn from our mistakes. Maybe more knowledgeable people about UI's will come up with a much better interface than Port provides -- and that would be great! Maybe others have the knowledge or man-power to define a medium level GUI directly for multiple platforms. However, till that moment, we might be better off trying to work with resources that we have, and use an evolutionary approach to building a portable GUI library. All the best, Daan.
Axel.

On Mon, Jan 27, 2003 at 12:21:07AM +0100, Daan Leijen wrote:
Axel wrote:
That is why I proposed to craft an Object I/O interface which enables programmers to write GUI application with a native look and feel albeit with a reduced functionality
I am also in favor of a medium level GUI interface. If I gave another impression, that is my fault.
Yes, but in my point of view this should be a medium level API like Object I/O, a bunch of IO function is doomed to be defined by the underlying backends. This certainly holds true for the Ports library.
The (Clean) ObjectIO library actually consists of two layers, an (A) and (L) part. Given their success, this proves that is certainly possible to define a decent (L) layer, on top of which a medium level API is built. We are aiming for a platform-independent solution. Clean's library seems to be quite complete which is the reason why people could write an IDE in it. The fact that it started on MacOS 8 and 9 once upon a time and was
Actually, Port is closely modelled after the low-level object IO interface. The "low-level" is not so low-level as you may think. It is rather the core medium-level functionality without any utility functions or abstractions.
Again, I feel that we actually agree on all this topics. I am not a native speaker, so it may be that I am not always using the right words for expressing myself. Sorry for that, but I am doing my best :-) No prob. I hope I make myself reasonably clear. I think we agree on: We want a GUI API specification which can be realized on all of the major
Well, Ports is very low level like gtk2hs, since it is merely a wrapper around the C functions of HToolkit. then converted to Windows doesn't make it portable: The Mac backend is broken and there is no Unix backend at all. Peter Achten may prove me wrong here, but if the Clean low level layer (L) which is written in C was portable, why don't we use that layer directly? Why did Krasismir start with HToolkit? IMHO it is easier to find a common API on the Object I/O level (A) not on the lower level. platforms without sacrificing the native conventions. The latter implies that the API will only have a reduced functionality, but we can live with that.
Maybe more knowledgeable people about UI's will come up with a much better interface than Port provides -- and that would be great! Maybe others have the knowledge or man-power to define a medium level GUI directly for multiple platforms. However, till that moment, we might be better off trying to work with resources that we have, and use an evolutionary approach to building a portable GUI library. Here is were we disagree :-)
I do not like the evolutionary approach. It will lead to an API which changes a lot. If we'd start off with the core Object I/O library and add functions/datatypes incrementally by democratic vote (all backend implementors agree), we can have a more stable API. It would be clear what has been done and what needs to be done. It would further enable people earlier to use this library, and it would enable people to use the backends directly and gradually convert their applications to the common API. Beyond that, I don't think I can make a reasonable interface to Ports from gtk2hs as it seems very low-level to me. You say it's not, so I will have to have a more thorough look. The reason I would like to fit my binding to the common GUI API is that - I don't want to bin the 13k+ lines of code we've written (which is 3 times as much as the HToolkit) (ok, my personal reason) - people should have a chance to write powerful GUI applications right now, and it might take years until the common API has stabilized And the reason I'd like to have (A) as the common layer is: - We could both put an Object I/O layer on top of our libraries. If we use the same core functionality, it would enable people to easily migrate their applications from one specific backend to the common API. What do you think? Axel.

I'd like to point out that it is quite possible to develop an interface at the desired level (I agree that the gtk level is too low for many purposes) without sacrificing functionality. The way to achieve this magic is this: Design your API at the optimal level which, as Daan and others have stated, implies reduced functionality (compared to wrapping the entire native API, for example). Having defined this interface, it is quite possible to add lower level hooks. Care is necessary to see that these hooks are interoperable with the higher level API (this is nontrivial but quite possible). For most projects the "standard" API would be adequate, and a program written with only the standard API is portable. For those cases where the reduced functionality of the standard interface is not acceptable, lowever level capabilities can be used. This implies that either (1) portability is lost or (2) the developer must implement the lower level functionality for all target platforms. This paradigm is also good for the toolkit developers. They must conform to the standard interface, but they aren't prohibited from providing functionality beyond the standard interface. On 27-Jan-2003 Axel Simon wrote:
On Mon, Jan 27, 2003 at 12:21:07AM +0100, Daan Leijen wrote:
Axel wrote:
That is why I proposed to craft an Object I/O interface which enables programmers to write GUI application with a native look and feel albeit with a reduced functionality
I am also in favor of a medium level GUI interface. If I gave another impression, that is my fault.
Well, Ports is very low level like gtk2hs, since it is merely a wrapper around the C functions of HToolkit.
Yes, but in my point of view this should be a medium level API like Object I/O, a bunch of IO function is doomed to be defined by the underlying backends. This certainly holds true for the Ports library.
The (Clean) ObjectIO library actually consists of two layers, an (A) and (L) part. Given their success, this proves that is certainly possible to define a decent (L) layer, on top of which a medium level API is built. We are aiming for a platform-independent solution. Clean's library seems to be quite complete which is the reason why people could write an IDE in it. The fact that it started on MacOS 8 and 9 once upon a time and was then converted to Windows doesn't make it portable: The Mac backend is broken and there is no Unix backend at all. Peter Achten may prove me wrong here, but if the Clean low level layer (L) which is written in C was portable, why don't we use that layer directly? Why did Krasismir start with HToolkit? IMHO it is easier to find a common API on the Object I/O level (A) not on the lower level.
Actually, Port is closely modelled after the low-level object IO interface. The "low-level" is not so low-level as you may think. It is rather the core medium-level functionality without any utility functions or abstractions.
Again, I feel that we actually agree on all this topics. I am not a native speaker, so it may be that I am not always using the right words for expressing myself. Sorry for that, but I am doing my best :-) No prob. I hope I make myself reasonably clear. I think we agree on: We want a GUI API specification which can be realized on all of the major platforms without sacrificing the native conventions. The latter implies that the API will only have a reduced functionality, but we can live with that.
Maybe more knowledgeable people about UI's will come up with a much better interface than Port provides -- and that would be great! Maybe others have the knowledge or man-power to define a medium level GUI directly for multiple platforms. However, till that moment, we might be better off trying to work with resources that we have, and use an evolutionary approach to building a portable GUI library. Here is were we disagree :-)
I do not like the evolutionary approach. It will lead to an API which changes a lot. If we'd start off with the core Object I/O library and add functions/datatypes incrementally by democratic vote (all backend implementors agree), we can have a more stable API. It would be clear what has been done and what needs to be done. It would further enable people earlier to use this library, and it would enable people to use the backends directly and gradually convert their applications to the common API.
Beyond that, I don't think I can make a reasonable interface to Ports from gtk2hs as it seems very low-level to me. You say it's not, so I will have to have a more thorough look. The reason I would like to fit my binding to the common GUI API is that - I don't want to bin the 13k+ lines of code we've written (which is 3 times as much as the HToolkit) (ok, my personal reason) - people should have a chance to write powerful GUI applications right now, and it might take years until the common API has stabilized
And the reason I'd like to have (A) as the common layer is: - We could both put an Object I/O layer on top of our libraries. If we use the same core functionality, it would enable people to easily migrate their applications from one specific backend to the common API.
What do you think? Axel.
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui
---------------------------------- Seth Kurtzberg M. I. S. Corp. E-Mail: seth@cql.com Date: 27-Jan-2003 Time: 03:53:33 This message was sent by XFMail ----------------------------------

On Mon, Jan 27, 2003 at 04:00:11AM -0700, seth@cql.com wrote:
I'd like to point out that it is quite possible to develop an interface at the desired level (I agree that the gtk level is too low for many purposes) without sacrificing functionality.
The way to achieve this magic is this: Design your API at the optimal level which, as Daan and others have stated, implies reduced functionality (compared to wrapping the entire native API, for example).
Having defined this interface, it is quite possible to add lower level hooks. Care is necessary to see that these hooks are interoperable with the higher level API (this is nontrivial but quite possible). For most projects the "standard" API would be adequate, and a program written with only the standard API is portable. For those cases where the reduced functionality of the standard interface is not acceptable, lowever level capabilities can be used. This implies that either (1) portability is lost or (2) the developer must implement the lower level functionality for all target platforms.
This paradigm is also good for the toolkit developers. They must conform to the standard interface, but they aren't prohibited from providing functionality beyond the standard interface. Yes, exactly. I couldn't have summarized it better!
The question we are pondering on now is whether to have an evolutionary approach (probably on Ports) or an incremental, constructive approach. Axel.

Dear Axel,
I am also in favor of a medium level GUI interface. If I gave another impression, that is my fault. Well, Ports is very low level like gtk2hs, since it is merely a wrapper around the C functions of HToolkit.
Well, the Port library is still medium-level. For example, the call "createWindow :: IO WindowHandle", basically creates a window with a working event loop, default handlers, a canvas, automatic scroll bars and a seperate world and view domain. It basically provides the core-functionality needed for ObjectIO (or something) but no utility functions type safety, or abstraction.
but if the Clean low level layer (L) which is written in C was portable, why don't we use that layer directly? Why did Krasismir start with HToolkit?
That is a good question. Personally, I would have preferred to see a GTK port of the low-level layer of Clean This would also allow us to work together with the Clean people, they have an excellent compiler and lots of experience with GUI's, and it could foster more exchange of knowledge between both communities. Maybe Krasimir can tell us more about the issues involved? (However, I can also live with Port since it seems much smaller and more tractable than the Clean layer.) This actually brings me to another issue I have been wondering about. Why don't we use the GTK library as our portable GUI library directly? I may have missed some discussions about this, but if it is a really portable library, we can use the fruits of their labor. (Of course, it does need to give a native look and fool, I wonder whether GTK does that?)
I do not like the evolutionary approach. It will lead to an API which changes a lot.
Well, we both started out as amoebes but evolutionized into beings that use electrical signals to exchange opinions about how to create specific patterns on cathode ray tubes :-) But seriously. We are trying to create a medium-level interface. The Port approach is to create that using two layers: one core medium-level interface (Port) and a convenience layer on top of that, using abstraction, overloading etc (GIO/Htoolkit). The advantage is off course that more work is shared and less work is needed for a different platform. Furthermore, the design of the convenience layer is seperated from the implementation of the core functionality. This is more important than it looks -- I think many truly useful libraries have failed because they didn't have this distinction. This made it too hard to port the library since there were too many dependencies on the platform. I think this happened for example with TkGofer and Haggis (still a wonderfully complete and documented! library) The disadvantage might be that Port is too low-level to bind to the GTK+HS binding but I don't think that this is the case. Maybe you can say more about this later.
And the reason I'd like to have (A) as the common layer is: - We could both put an Object I/O layer on top of our libraries. If we use the same core functionality, it would enable people to easily migrate their applications from one specific backend to the common API.
The other approach, that you are proposing, is to define just one medium level interface (with abstraction and all) and to implement backends for each platform directly. The advantage is that it probably easier to support more backends. The disadavantage is that you need to do more work for a port. However, it is not yet clear how that level should look like. We could take the ObjectIO interface as our layer but I would not recommend that. Note, this is not a critique on the ObjectIO library, I highly respect the work of the Clean people, and Peter van Achten in particular. However, the Haskell ObjectIO interface should be heavily revised to fit better in the style of Haskell. Right now, it is still influenced by the non-monadic uniqueness style of Clean. For example, the generation of identifiers (openId) is quit unsafe. In the Haskell tradition we would use a monadic bind to name widgets. ie.
w <- window []
instead of
w <- openId openWindow ... [ WindowId w, ...]
Other things are the widget attributes that are specified using constructors. A more Haskellish style would use function names instead of constructors (as to be able to abstract from them) and use type classes for grouping them (as to prevent using illegal attributes on a certain widget). i.e.
w <- window [title =: "My window" ]
instead of
w <- openId openWindow ... [ WindowId w, WindowTitle w...]
This is basically what I am trying to do in the GIO library. However, even than, there are still tons of other design decisions to make, I wonder whether consensus can ever be reached. All the best, Daan. ps. I am quite curious about what you think of Port. If it is high-level enough, it may serve the role of a core-functionality interface and you could create a port layer on top of gtk2hs. You can browse the interface directly at: http://htoolkit.sourceforge.net

That is a good question. Personally, I would have preferred to see a GTK port of the low-level layer of Clean This would also allow us to work together with the Clean people, they have an excellent compiler and lots of experience with GUI's, and it could foster more exchange of knowledge between both communities.
Maybe Krasimir can tell us more about the issues involved?
The first big stone which I was found was handling of scollbars in the windows. The scrollbars are implemented rather different in Windows and GTK. Under Windows the application must explicitly specify the exact scrollbar position in response to WM_VSCROLL and WM_HSCROLL messages. Under GTK the position are handled from GtkScrolledWindow and the application receives notifications after each change in horizontal or vertical position. Under GTK the scrollbars are automaticaly shown/hidden when the view domain becomes great/less than window size. Under Windows this requires explicit manipulation with scrollers. In the ObjectIO library this is realized with WindowHScroll/WindowVScroll attribute and value of type ScrollFunction. The ScrollFunction calculates new position of the scrollbar after each scroll event. That means that scrollbar manipulation is handled at top level instead of low level C code. I was tried to change library but I found that this reflects in too many places. For example each time when some control is resized then the view domain required for all controls is changed and this may reflect the scrollers. I think that it isn't imposible to improve the library but this was too discounraged for me. There was also some minor reasons anticipate from Daan:
For example, the generation of identifiers (openId) is quit unsafe. In the Haskell tradition we would use a monadic bind to name widgets. ie.
w <- window []
instead of
w <- openId openWindow ... [ WindowId w, ...]
Other things are the widget attributes that are specified using constructors. A more Haskellish style would use function names instead of constructors (as to be able to abstract from them) and use type classes for grouping them (as to prevent using illegal attributes on a certain widget). i.e.
w <- window [title =: "My window" ]
instead of
w <- openId openWindow ... [ WindowId w, WindowTitle w...]
I was thinking about this disadvantages about two months before to found the first reason. However this is not too important. I also don't like openId. What should happen if I forgot w is an Id window and use it again as Id for some control. The library has some validation routines and probably will found this as runtime error while I like to catch this error in compilation time. For that reason I was thinking about how to found some work around but I don't know any decision which are easy to implement in existing ObjectIO. The implementation of attributes is other disadvantage but I think that it is easy to replace them with functions and classes. The original HToolkit package uses list of values of type "Conf w" where w is the type of widget. The Conf is just function of type "w -> IO ()". This design was adopted from FranTk and solves trouble with attributes. To avoid openId I use some tricks. The window form is defined like function which takes as arguments variables which represent controls inside the form. In the same time the controls are defined in the same function. I use fixIO function and lazy evaluation to take result of function as its argument. There is also another trouble with OS layer in ObjectIO. Because the Clean FFI doesn't allow C functions to execute Clean the OS layer is implemented with two co-threads. The first thread is in the C world and is synchronized with Clean thread with mutexes. The C<->Haskell communication can be much more easy but the ObjectIO still uses old fashion comunication with threads. Avoidance of this trouble isn't so easy because large part of library depends on co-threads. This is avoided in both HToolkit and Port. Best regards, Krasimir __________________________________________________ Do you Yahoo!? Yahoo! Mail Plus - Powerful. Affordable. Sign up now. http://mailplus.yahoo.com

At 06:52 30-1-03 -0800, Krasimir Angelov wrote:
Maybe Krasimir can tell us more about the issues involved?
The first big stone which I was found was handling of scollbars in the windows. The scrollbars are implemented rather different in Windows and GTK. [..] ... The ScrollFunction calculates new position of the scrollbar after each scroll event. That means that scrollbar manipulation is handled at top level instead of low level C code. [..] I think that it isn't imposible to improve the library but this was too discounraged for me. The reason for the complicated implementation of scrollbars is that they have to be handled explicitly by the programmer on the Mac platform. The impression that I get from your account is that scrollbar handling on GTK is rather similar to Windows. In general, one really needs a ScrollFunction to determine its behaviour: imagine a textprocessor that allows you to handle text with different font (heights). Then scrolling down/up one line depends on the height of the current top/bottom line. I can't blaim you for being discouraged... the implementation of the Object I/O library isn't as 'clean' is I would like it to be.
[..] There is also another trouble with OS layer in ObjectIO. Because the Clean FFI doesn't allow C functions to execute Clean the OS layer is implemented with two co-threads. The first thread is in the C world and is synchronized with Clean thread with mutexes. The C<->Haskell communication can be much more easy but the ObjectIO still uses old fashion comunication with threads. Avoidance of this trouble isn't so easy because large part of library depends on co-threads. This is avoided in both HToolkit and Port. The co-thread architecture is indeed a major bottleneck both in understanding the implementation, and performance (which BTW is already very good). The reason is, as Krasimir says, the historical lack of calling Clean from C. Fortunately, this has been incorporated recently to Clean by John van Groningen, so this gives us a good opportunity to get rid of this approach and adopt a more natural and intuitive implementation. This will give another performance boost to the library.
Regards, Peter

This actually brings me to another issue I have been wondering about. Why don't we use the GTK library as our portable GUI library directly? I may have missed some discussions about this, but if it is a really portable library, we can use the fruits of their labor. (Of course, it does need to give a native look and fool, I wonder whether GTK does that?)
GTK currently does not give native look on Mac OS. I'm convinced that it will never provide native feel. The reason is that as a complete and therefore complex GUI toolkit, it makes too many assumptions about how the UI should behave. I'm not saying that GTK is bad, I'm just saying that it is not capable of providing native look and feel on all platforms. I know of no full-featured library that really achieves this goal. However, Port is not as "full-featured" as GTK, nor will it be in the forseeable future. A simple library like Port can probably achieve enough abstraction to bridge the differences. It will (hopefully) be possible to write programs with simple user interfaces that look and work well on all platforms. We shouldn't try to write a perfect full-featured cross-platform library. Haskell is a cool language, but if nobody has achieved that with any language (IMHO), why should we? There is definitely room for a good GTK binding and for a good high-level library based on that. But it can never be a "standard GUI library for Haskell" because it just doesn't work _well_ on all platforms (in order to say that a toolkit works well on MacOS, I mustn't easily recognize an application as "written using toolkit XY" when I use the Mac version of the application). On the other hand, a "standard cross-platform GUI library for Haskell" will never provide everything you would find in a platform-specific or not-quite-native-looking GUI library. People will choose what they need for their current task. Cheers, Wolfgang

On Thursday, 2003-01-30, 17:11, CET, Wolfgang Thaller wrote:
[...]
GTK currently does not give native look on Mac OS. I'm convinced that it will never provide native feel.
The same holds for Windows and certain X11-based desktop environments like KDE. The actual GTK uses the same implementation on every platform. This implementation is based on GDK which provides a platform-independent interface implemented for different platforms. This interface is at a very low level (drawing primitives and the like).
[...]
Wolfgang

Daan, Krasimir, Wolfgang, On Thu, Jan 30, 2003 at 02:32:50PM +0100, Daan Leijen wrote:
Maybe Krasimir can tell us more about the issues involved? Uhum. I read Krasimir's email. One quick question to verify that I understood: The intermediate layer of Clean's Object I/O is written in C because it is difficult to call Clean from C?
This actually brings me to another issue I have been wondering about. Why don't we use the GTK library as our portable GUI library directly? I may have missed some discussions about this, but if it is a really portable library, we can use the fruits of their labor. (Of course, it does need to give a native look and fool, I wonder whether GTK does that?) Wolfgang gave a good answer to that and I am convinced that Gtk alone is not the answer.
I do not like the evolutionary approach. It will lead to an API which changes a lot.
Well, we both started out as amoebes but evolutionized into beings that use electrical signals to exchange opinions about how to create specific patterns on cathode ray tubes :-) :-) Thanks Daan! The first time I really had to laugh reading all these messages...
But seriously. We are trying to create a medium-level interface. The Port approach is to create that using two layers: one core medium-level interface (Port) and a convenience layer on top of that, using abstraction, overloading etc (GIO/Htoolkit). Ok, I'll look at Ports and especially GIO over the weekend. The syntax of GIO looks really clever!
[..]
The other approach, that you are proposing, is to define just one medium level interface (with abstraction and all) and to implement backends for each platform directly. The advantage is that it probably easier to support more backends. The disadavantage is that you need to do more work for a port. Yes, true. But I think it is not as difficult to bind to a more abstract layer.
You hear from me :-), Axel.

--- Axel Simon
Daan, Krasimir, Wolfgang,
On Thu, Jan 30, 2003 at 02:32:50PM +0100, Daan Leijen wrote:
Maybe Krasimir can tell us more about the issues involved? Uhum. I read Krasimir's email. One quick question to verify that I understood: The intermediate layer of Clean's Object I/O is written in C because it is difficult to call Clean from C?
I don't think so. The layer is written in C and Clean. The Clean functions are wrapper around C functions, but the only way to connect Clean with C is with co-threads. Krasimir __________________________________________________ Do you Yahoo!? Yahoo! Mail Plus - Powerful. Affordable. Sign up now. http://mailplus.yahoo.com

Hello, several GUI-related e-mails of the last days spoke about different library "levels" (high, medium, low). I'm not sure, which the term "level" refers to. Does it refer to (a) different programming paradigms (high: functional; low: imperative) or (b) different views onto GUIs (high: application types (MDI, SDI etc.), common dialogs etc.; low: just widgets or even drawing primitives etc.)? My opinion concerning (L) is the following: If (a) is meant, (L) should be low-level and be implemented in C with a thin Haskell layer on top of it. (The C interface would also be useable outside the Haskell context.) If (b) is meant, (L) should be as high-level as it must be to provide native look-and-feel. A related question: What do you mean with "abstraction"? Has it something to do with "high-level" in the (b) meaning? Wolfgang

Hi Wolfgang,
several GUI-related e-mails of the last days spoke about different library "levels" (high, medium, low). I'm not sure, which the term "level" refers to. Does it refer to (a) different programming paradigms (high: functional; low: imperative) or (b) different views onto GUIs (high: application types (MDI, SDI etc.), common dialogs etc.; low: just widgets or even drawing primitives etc.)?
I can't speak for others but I interpreted the 'level' as the Haskell programmers level. That is, 'high level' means something really declarative like franTk or Fudgets. 'medium level' means that the library is imperative but offers a lot of convenient functionality, like TkGofer. Low-level means that it is imperative and offers no convenience, as Win32 or basic gtk2hs.
My opinion concerning (L) is the following: If (a) is meant, (L) should be low-level and be implemented in C with a thin Haskell layer on top of it. (The C interface would also be useable outside the Haskell context.) If (b) is meant, (L) should be as high-level as it must be to provide native look-and-feel.
In my opinion, (L) should be "low-level" from a Haskell programmer perspective. That is, there should be medium level library (A) built on top of (L) that offers convenient functions to access (L). In this sense, we could probably better talk about a core-functionality library for the medium level library (A). I think that it is really important to make this distinction, as we can share the work on (A) and make it much easier to make a port of (L). However, at the same time, (L) should be "high-level" from a GUI perspective to be as portable as possible and to give a native look-and-feel. (i.e. your (b) option). As you say, it should talk in terms of application types and common dialogs but not just in terms of drawing primitives. Port tries to be these things, but we (me and Axel) are still discussing whether Port is actually "high level" enough from a GUI perspective or wheter we need to look for another kind of interface.
A related question: What do you mean with "abstraction"? Has it something to do with "high-level" in the (b) meaning?
This depends entirely on the context :-) I think I used "abstraction" in connection with the (A) layer. In that sense, I meant that the (A) library should offer convenient abstractions that the (L) layer doesn't offer. For example, we can abstract over resource allocation by using foreign pointers on Bitmap resources. Or use type classes to be able to close any widget with "close" instead of "closeDialog" or "closeWindow". All the best, Daan. for an example of how I see the distinction between (A) and (L), you could browse the online docs of GIO (A) and Port (L) at: http://htoolkit.sourceforge.net

This has been a point of confusion and terminology mismatch for me too when reading this discussion. Rather than debate about it, lets look at the code, how about we submit the same small GUI program in each of the toolkits, it should be immediatly obvious how 'high' or 'low' level they are by whatever standards you wish to apply. I propose a simple program which pops up a window saying 'Hello World' with a button saying 'Bye' which you click and it changes the message to 'Goodbye'. if you click the button again the program exits. this should (hopefully) be a short program with most toolkits and demonstrate how one lays out 2 widgets, and responds to user input and mutates the display. note, this is not to compare the toolkits themselves, but the haskell APIs used to access them. I'd like to see samples using gtk+hs gtk2hs Ports GIO (on top of Ports) ObjectIO FranTk Fruit Htk ... more? actually, putting links to these little demo programs on the haskell library page would probably be tons more useful than the current information. John On Thu, Jan 30, 2003 at 11:36:24PM +0100, Daan Leijen wrote:
Hi Wolfgang,
several GUI-related e-mails of the last days spoke about different library "levels" (high, medium, low). I'm not sure, which the term "level" refers to. Does it refer to (a) different programming paradigms (high: functional; low: imperative) or (b) different views onto GUIs (high: application types (MDI, SDI etc.), common dialogs etc.; low: just widgets or even drawing primitives etc.)?
I can't speak for others but I interpreted the 'level' as the Haskell programmers level. That is, 'high level' means something really declarative like franTk or Fudgets. 'medium level' means that the library is imperative but offers a lot of convenient functionality, like TkGofer. Low-level means that it is imperative and offers no convenience, as Win32 or basic gtk2hs.
My opinion concerning (L) is the following: If (a) is meant, (L) should be low-level and be implemented in C with a thin Haskell layer on top of it. (The C interface would also be useable outside the Haskell context.) If (b) is meant, (L) should be as high-level as it must be to provide native look-and-feel.
In my opinion, (L) should be "low-level" from a Haskell programmer perspective. That is, there should be medium level library (A) built on top of (L) that offers convenient functions to access (L). In this sense, we could probably better talk about a core-functionality library for the medium level library (A). I think that it is really important to make this distinction, as we can share the work on (A) and make it much easier to make a port of (L).
However, at the same time, (L) should be "high-level" from a GUI perspective to be as portable as possible and to give a native look-and-feel. (i.e. your (b) option). As you say, it should talk in terms of application types and common dialogs but not just in terms of drawing primitives.
Port tries to be these things, but we (me and Axel) are still discussing whether Port is actually "high level" enough from a GUI perspective or wheter we need to look for another kind of interface.
A related question: What do you mean with "abstraction"? Has it something to do with "high-level" in the (b) meaning?
This depends entirely on the context :-) I think I used "abstraction" in connection with the (A) layer. In that sense, I meant that the (A) library should offer convenient abstractions that the (L) layer doesn't offer. For example, we can abstract over resource allocation by using foreign pointers on Bitmap resources. Or use type classes to be able to close any widget with "close" instead of "closeDialog" or "closeWindow".
All the best, Daan.
for an example of how I see the distinction between (A) and (L), you could browse the online docs of GIO (A) and Port (L) at: http://htoolkit.sourceforge.net
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui
-- --------------------------------------------------------------------------- John Meacham - California Institute of Technology, Alum. - john@foo.net ---------------------------------------------------------------------------

John Meacham wrote:
I propose a simple program which pops up a window saying
'Hello World' with a button saying 'Bye' which you click and it changes the message to 'Goodbye'. if you click the button again the program exits.
Although (as I have said repeatedly) Fruit is far too experimental to be suitable as a standardized, portable production GUI toolkit, I have, just for fun, implemented this little excercise in Fruit. Code is attached. -antony -- Antony Courtney Grad. Student, Dept. of Computer Science, Yale University antony@apocalypse.org http://www.apocalypse.org/pub/u/antony -- -- HelloGoodbye -- simple "Hello/Goodbye" example for GUI API comparison -- proposed by John Meacham -- -- Author: Antony Courtney, 1/31/03 module HelloGoodbye where import GUI import Arrow import AFRP import Haven import GAUtils -- The code here is short, but heavily commented. I've chosen to err -- on the side of verbosity with comments to try and describe a little -- of the design methodology and clarify many of the combinators that are -- relatively newer than published papers on Fruit or AFRP/Yampa. -- First, let's try to seperate the "model" from the interface: -- Our application model is a signal function that accepts button -- press events as input, and produces a String to display paired with -- an event that occurs when the application is done executing: appModel :: SF (Event ()) (String, Event ()) -- Our model is a simple state machine. We'll use kSwitch to switch -- from the "hello" state to the "goodbye" state on a button press: appModel = kSwitch helloSF -- initial signal function (arr fst) -- switch when input event occurs (\_ _ -> goodbyeSF) -- SF to switch in to -- The "hello" state just outputs "hello" and does not cause -- a program termination event: helloSF :: SF (Event ()) (String,Event ()) helloSF = (constant ("Hello World", noEvent)) -- The "goodbye" state outputs "Goodbye", and produces a program termination -- event when the input event occurs: goodbyeSF :: SF (Event ()) (String,Event ()) goodbyeSF = (constant "Goodbye") &&& identity -- Now for the GUI itself: -- The window content (or view) consists of a button and label. The -- String to display in the label is taken as an external signal (from -- the model), and the button press events are an output signal (to be -- fed to the model) -- Some notes: -- - "GA" is the type of a GUI Arrow, which uses the order in which GUIs -- appear in the Arrow notation to determine the order in which the -- GUI components will be layed out. -- - We use "hbox" to create a horizontal layout of GUI components. -- - The use of "id" as the input signal to the button specifies default -- configuration options for the button. -- - Since there is no returnA at the end of the proc, the output signal -- from the button is the output signal of the entire GUI viewGA :: GA (String) (Event ()) viewGA = hbox $ proc s -> do ltext s >- label -> _ id >- button (btext "Bye") -- Use feedback to wire the view to the model. The one subtlety here -- is that we must use 'iPre' to introduce an infinitesimal delay between -- the output signal of the view and the input signal of the model to ensure -- that the feedback loop is well-formed. appGUI :: GUI () (Event ()) appGUI = proc (gin,_) -> do rec (gin,s) >- unGA viewGA -> (pic,clickE) clickE >- iPre noEvent -> dClickE dClickE >- appModel -> (s,termE) (pic,termE) >- returnA -- Full Disclosure: The above code assumes that 'runGUI' observes the -- output event of the GUI, and exits the program when the event occurs. -- The current implementation doesn't actually support this, but adding -- it would be trivial. -- -- Main :: IO () -- main = runGUI appGUI

Hi Anthony,
Very interesting to see your program -- it is neat how one
can separate the model from the interface! (allthough the wiring
still seems a bit convoluted.)
I don't know if you have seen Koen Claessens bouncing balls
demo, but I would be quite interested to see how that would look in
Fruit (I think that especially the behaviour of the balls can be modelled nicer
in Fruit). See http://www.cs.chalmers.se/Cs/Grundutb/Kurser/afp/yahu.html
for the demo.
Anyway, I am off re-reading your papers :-)
-- Daan.
----- Original Message -----
From: "Antony Courtney"
John Meacham wrote:
I propose a simple program which pops up a window saying
'Hello World' with a button saying 'Bye' which you click and it changes the message to 'Goodbye'. if you click the button again the program exits.
Although (as I have said repeatedly) Fruit is far too experimental to be suitable as a standardized, portable production GUI toolkit, I have, just for fun, implemented this little excercise in Fruit. Code is attached.
-antony
-- Antony Courtney Grad. Student, Dept. of Computer Science, Yale University antony@apocalypse.org http://www.apocalypse.org/pub/u/antony
--------------------------------------------------------------------------------
-- -- HelloGoodbye -- simple "Hello/Goodbye" example for GUI API comparison -- proposed by John Meacham -- -- Author: Antony Courtney, 1/31/03
module HelloGoodbye where
import GUI import Arrow import AFRP import Haven import GAUtils
-- The code here is short, but heavily commented. I've chosen to err -- on the side of verbosity with comments to try and describe a little -- of the design methodology and clarify many of the combinators that are -- relatively newer than published papers on Fruit or AFRP/Yampa.
-- First, let's try to seperate the "model" from the interface:
-- Our application model is a signal function that accepts button -- press events as input, and produces a String to display paired with -- an event that occurs when the application is done executing:
appModel :: SF (Event ()) (String, Event ())
-- Our model is a simple state machine. We'll use kSwitch to switch -- from the "hello" state to the "goodbye" state on a button press: appModel = kSwitch helloSF -- initial signal function (arr fst) -- switch when input event occurs (\_ _ -> goodbyeSF) -- SF to switch in to
-- The "hello" state just outputs "hello" and does not cause -- a program termination event: helloSF :: SF (Event ()) (String,Event ()) helloSF = (constant ("Hello World", noEvent))
-- The "goodbye" state outputs "Goodbye", and produces a program termination -- event when the input event occurs: goodbyeSF :: SF (Event ()) (String,Event ()) goodbyeSF = (constant "Goodbye") &&& identity
-- Now for the GUI itself:
-- The window content (or view) consists of a button and label. The -- String to display in the label is taken as an external signal (from -- the model), and the button press events are an output signal (to be -- fed to the model) -- Some notes: -- - "GA" is the type of a GUI Arrow, which uses the order in which GUIs -- appear in the Arrow notation to determine the order in which the -- GUI components will be layed out. -- - We use "hbox" to create a horizontal layout of GUI components. -- - The use of "id" as the input signal to the button specifies default -- configuration options for the button. -- - Since there is no returnA at the end of the proc, the output signal -- from the button is the output signal of the entire GUI viewGA :: GA (String) (Event ()) viewGA = hbox $ proc s -> do ltext s >- label -> _ id >- button (btext "Bye")
-- Use feedback to wire the view to the model. The one subtlety here -- is that we must use 'iPre' to introduce an infinitesimal delay between -- the output signal of the view and the input signal of the model to ensure -- that the feedback loop is well-formed. appGUI :: GUI () (Event ()) appGUI = proc (gin,_) -> do rec (gin,s) >- unGA viewGA -> (pic,clickE) clickE >- iPre noEvent -> dClickE dClickE >- appModel -> (s,termE) (pic,termE) >- returnA
-- Full Disclosure: The above code assumes that 'runGUI' observes the -- output event of the GUI, and exits the program when the event occurs. -- The current implementation doesn't actually support this, but adding -- it would be trivial. -- -- Main :: IO () -- main = runGUI appGUI

Hi Daan, Daan Leijen wrote:
Hi Anthony,
Very interesting to see your program -- it is neat how one can separate the model from the interface! (allthough the wiring still seems a bit convoluted.)
Hmmm. Can you expand on why you think the wiring is a bit convoluted? Is it the syntax that you find difficult, or the conceptual framework of signal functions?
I don't know if you have seen Koen Claessens bouncing balls demo, but I would be quite interested to see how that would look in Fruit (I think that especially the behaviour of the balls can be modelled nicer in Fruit). See http://www.cs.chalmers.se/Cs/Grundutb/Kurser/afp/yahu.html for the demo.
I hadn't seen Koen's demo, but I had already done something quite similar. If you think the previous code looked convoluted, you ain't seen nothin' yet.... :-) The attached file contains a few increasingly sophisticated versions of the bouncing balls demo. Most versions use the pSwitch family of combinators to maintain a dynamic collection of bouncing balls. The user can spawn a new ball at any location using the mouse, and the balls bounce off of each other as well as off of the walls. One version also includes self-termination, where each ball only "lives" for 5 seconds after it is spawned. The pSwitch combinators are described in the paper: Henrik Nilsson, Antony Courtney and John Peterson, Functional Reactive Programming, Continued. In Proceedings of the Haskell Workshop, September, 2002. which is available here: http://apocalypse.org/~antony/pubs/genuinely-functional-guis.pdf regards, -antony -- Antony Courtney Grad. Student, Dept. of Computer Science, Yale University antony@apocalypse.org http://www.apocalypse.org/pub/u/antony -- -- BallTests.as -- animated bouncing balls to illustrate the basics -- of using pSwitch to switch over dynamic collections. -- module BallTests where import AFRP import Haven import GUI import FMUI -- hmmm. should probably put this in HavenCoreUtils: rpath :: Point -> Double -> Double -> Path rpath pt w h = outline $ rectangle pt w h -- walls: vWalls :: Path vWalls = rpath (point 0 0) 10 300 <++> rpath (point 290 0) 10 300 hWalls :: Path hWalls = rpath (point 0 290) 300 10 <++> rpath (point 0 0) 300 10 wallPath :: Path wallPath = hWalls <++> vWalls wallPic :: Picture wallPic = withColor red $ picFill wallPath wallGUI :: GUI () () wallGUI = constant (wallPic,()) ballShape :: Path ballShape = outline (circle origin 25) ballPic :: Picture ballPic = withColor green (picFill ballShape) -- A simple ball bouncing inside the walls: simpleBall :: Point -> Double -> SF () (Path) simpleBall pt0 vel = proc _ -> do rec xi <- integral -< xvel yi <- integral -< yvel let xpos = (pointX pt0) + xi let ypos = (pointY pt0) + yi let ball = translate (vector xpos ypos) %$ ballShape let bbounds = bounds ball xbounce <- edge -< intersectsRect vWalls bbounds ybounce <- edge -< intersectsRect hWalls bbounds xvel <- accumHold vel -< xbounce `tag` negate yvel <- accumHold vel -< ybounce `tag` negate returnA -< ball simpleBallGUI :: Point -> Double -> GUI () Path simpleBallGUI pt0 vel = proc _ -> do b <- simpleBall pt0 vel -< () let bpic = withColor green $ picFill b returnA -< (bpic,b) sbGUI :: GUI () () sbGUI = guiDropIO $ simpleBallGUI (point 75 120) 120 -- just sbTest in front of walls: dynTest0 :: GUI () () dynTest0 = let wallGUI :: GUI () () wallGUI = constGUI wallPic in guiDropIO $ sbGUI `overGUI` wallGUI -- first: let's just try a version of dynTest0 which is a singleton -- collection used in rpSwitch: dynTest1 :: GUI () () dynTest1 = proc (gin,_) -> do neChild <- never -< () pps <- rpSwitchB [dynTest0] -< ((gin,()),neChild) let pic = foldr (\ (p,_) bg -> p <++> bg) picEmpty pps returnA -< (pic,()) -- now let's try to spawn a ball under the mouse on lbp: spawnTest1 :: GUI () () spawnTest1 = proc (gin,_) -> do lbPress <- ginLbp -< gin mouse <- ginMouse -< gin let forkE = lbPress `tag` ((guiDropIO $ simpleBallGUI mouse 120):) pps <- rpSwitchB [dynTest0] -< ((gin,()),forkE) let pic = foldr (\ (p,_) bg -> p <++> bg) wallPic pps returnA -< (pic,()) -- a variation on simpleBallGUI that terminates after 5 seconds: -- -- could make a more general-purpose wrapper that would -- terminate ANY signal function after N seconds... -- termBallGUI :: Point -> Double -> GUI a (Event ()) termBallGUI pt0 vel = proc (gin,_) -> do t <- time -< () done <- edge -< (t > 5) (bpic,_) <- simpleBallGUI pt0 vel -< (gin,()) returnA -< (bpic,done) -- now let's try a version of spawnTest that allows for self-termination: -- We use pSwitch here. Note, however, that a switching Event may occur -- either because we are adding a new ball to the collection, or because -- some of the balls have terminated. We account for this by using the -- type (Maybe (GUI () Event ()),[Bool]) on the event occurence. The -- first component of the pair is (Just b) if we spawn a new ball b, -- and the second component is the indices of balls to remove from -- the collection. -- compute spawn or kill events for spawnTest2: spawnOrKill :: SF ((GUIInput,()),[(Picture,Event ())]) (Event ((Maybe (GUI () (Event ()))),[Bool])) spawnOrKill = proc ((gin,_),pes) -> do lbPress <- ginLbp -< gin mouse <- ginMouse -< gin let spawnE = lbPress `tag` (Just (termBallGUI mouse 120),repeat False) let termEs = map snd pes let killE = (mergeEvents termEs) `tag` (Nothing,map isEvent termEs) returnA -< mergeBy (\ (x,_) (_,y) -> (x,y)) spawnE killE -- A simple auxiliary filtering function: dropSome :: [a] -> [Bool] -> [a] dropSome as bs = [ a | (a,b) <- zip as bs, not b ] -- given the current World (a list of TermBallGUI's), and a -- (spawn,kill) pair, compute a new World: nextWorld :: [GUI () (Event ())] -> (Maybe (GUI () (Event ())),[Bool]) -> SF (GUIInput,()) [(Picture,Event ())] nextWorld world (Nothing,termEs) = let world' = dropSome world termEs in pSwitchB world' spawnOrKill nextWorld nextWorld world (Just b,termEs) = let world' = b:(dropSome world termEs) in pSwitchB world' spawnOrKill nextWorld spawnTest2 :: GUI () () spawnTest2 = let world0 = [termBallGUI (point 100 100) 120] in proc (gin,_) -> do pes <- pSwitchB world0 spawnOrKill nextWorld -< (gin,()) let pic = foldr (\ (p,_) bg -> p <++> bg) wallPic pes returnA -< (pic,()) -- A ball that changes direction whenever it hits another ball: -- like simpleBallGUI, but takes an input event whose occurence -- indicates a collision: hitBall :: Point -> Double -> SF (Event ()) (Path) hitBall pt0 vel = proc hitE -> do rec xi <- integral -< xvel yi <- integral -< yvel let xpos = (pointX pt0) + xi let ypos = (pointY pt0) + yi let ball = translate (vector xpos ypos) %$ ballShape let bbounds = bounds ball xHitWallE <- edge -< intersectsRect vWalls bbounds yHitWallE <- edge -< intersectsRect hWalls bbounds let xbounce = xHitWallE `lMerge` hitE let ybounce = yHitWallE `lMerge` hitE xvel <- accumHold vel -< xbounce `tag` negate yvel <- accumHold vel -< ybounce `tag` negate returnA -< ball hitBallGUI :: Point -> Double -> GUI (Event ()) Path hitBallGUI pt0 vel = proc (_,hitE) -> do b <- hitBall pt0 vel -< hitE let bpic = withColor green $ picFill b returnA -< (bpic,b) termHitBallGUI :: Point -> Double -> GUI (Event ()) (Path,Event ()) termHitBallGUI pt0 vel = proc (gin,hitE) -> do t <- time -< () done <- edge -< (t > 5) (pic,path) <- hitBallGUI pt0 vel -< (gin,hitE) returnA -< (pic,(path,done)) -- A WorldBall is a Ball that observes a World. However, we'll arrange -- it so that every ball sees all other balls but itself. worldBallGUI :: Point -> Double -> GUI [Path] Path worldBallGUI pt0 vel = proc (gin,others) -> do rec (bpic,b) <- hitBallGUI pt0 vel -< (gin,hitE) let bbounds = bounds b let touches = any (\ p -> intersectsRect p bbounds) others hitE <- edge -< touches returnA -< (bpic,b) -- Given a World of length n, construct n localized perceptions of the -- world, in which each member does not see himself. locPercept :: [a] -> [[a]] locPercept world = map (\i -> dropNth i world) [0..(length world)-1] dropNth :: Int -> [a] -> [a] dropNth n as = let (pre,suf) = splitAt n as in pre ++ (drop 1 suf) -- An implementation of the bouncing balls where each ball bounces off the -- walls and off all other balls. Note that each balls has a localized -- perception of the world in which it observes all other balls but does -- not see itself. -- other balls but itself. -- -- The implementation here is like spawnTest1, but using rpSwitchZ -- instead of rpSwitchB: spawnTest3 :: GUI () () spawnTest3 = proc (gin,_) -> do rec lbPress <- ginLbp -< gin mouse <- ginMouse -< gin let forkE = lbPress `tag` ((worldBallGUI mouse 120):) pps <- rpSwitchZ [worldBallGUI (point 100 100) 120] -< (zip (repeat gin) locWorlds, forkE) let locWorlds = locPercept (map snd pps) let pic = foldr (\ (p,_) bg -> p <++> bg) wallPic pps returnA -< (pic,())

cool, I have gotten several responses. I will put them online at the following URL as i recieve them. if your pet toolkit isn't represented then please send a sample of the hellogoodbye program. i will add a real web page and prettify the haskell for nice web viewing at some point soon. http://repetae.net/~john/computer/haskell/gui/ have fun. John -- --------------------------------------------------------------------------- John Meacham - California Institute of Technology, Alum. - john@foo.net ---------------------------------------------------------------------------

I propose a simple program which pops up a window saying 'Hello World' with a button saying 'Bye' which you click and it changes the message to 'Goodbye'. if you click the button again the program exits.
Good plan, John! Here is my contribution for the GIO library. All the best, Daan. ps. more examples are in the cvs. (http://htoolkit.sourceforge.net) --------------------------------------------------------------------------------{--------------------------------------------------------------------------------This program implements the "goodbye" demo as posted by John Meacham onthe Haskell GUI mailing list. Note that this demo also uses a nice layout: the label and button are centeredin the window with some padding around it. When the button is clicked thefirst time, it calls "bye". This function changes the text of the labeland installs another event handler on the button, that closes the main window.(by default, GIO exits the gui when all windows are closed).--------------------------------------------------------------------------------}module Main whereimport Graphics.UI.GIOmain = start demo -- "start" initializes the GUI. demo :: IO ()demo = do w <- window [title =: "Bye!"] l <- label [text =: "Hello World"] w b <- button [text =: "Bye"] w set w [layout =: pad 10 (center l ^^^^ center b)] set b [on command =: bye w l b] where -- called on the first click, with the window, label, and button as arguments. bye w l b = do set l [text =: "Goodbye"] set b [on command =: close w]

I propose a simple program which pops up a window saying 'Hello World' with a button saying 'Bye' which you click and it changes the message to 'Goodbye'. if you click the button again the program exits.
Hi all, here is the goodbye demo in ObjectIO. It shows nicely how a gui in the ObjectIO library is decribed purely as a datatype (i.e. Dialog in this case) and how it maintains local state for you. All the best, Daan. ps. Off course, I am not an ObjectIO expert so maybe Peter van Achten has an even nicer solution. pps. Everyone with a recent ghc on windows can run this program at home: ghci ByeDemo.hs -package objectio -------------------------------------------------------------------------------- {--------------------------------------------------------------------------------This program implements the "goodbye" demo as posted by John Meacham onthe Haskell GUI mailing list. The program is specified as:I propose a simple program which pops up a window saying 'Hello World' with a button saying 'Bye' which you click and it changes the message to 'Goodbye'. if you click the button again the program exits.This demo also uses a nice layout: the label and button are centeredin the dialog. Instead of a window, a dialog is used since it resizesautomatically to accomodate the controls.The dialog maintains a boolean local state that says whether the buttonis clicked for the first time or not. (The process state is unused.)When the button is clicked the "bye" function is called. This function checks the local state to see whether this is the first time that it is called.If so it changes the text of the label and updates the local state.Otherwise it closes the process.--------------------------------------------------------------------------------}module Main whereimport Graphics.UI.ObjectIOmain = do displayId <- openId startIO NDI () (openDialog True (dialog displayId)) [] -- local state = True, process state = () where dialog displayId = Dialog "Bye!" ( TextControl "Hello World" [ControlPos (Center,zero), ControlId displayId] :+: ButtonControl "Bye" [ControlPos (Center,zero), ControlFunction bye] ) [WindowClose (noLS closeProcess)] where -- called on a button click with a local state/process state tuple. bye (firstTime,ps) | firstTime = do setControlText displayId "Goodbye" return (False,ps) | otherwise = do closeProcess ps return (False,ps)

There is also ByeDemo example with HToolkit Cheers, Krasimir __________________________________________________ Do you Yahoo!? Yahoo! Mail Plus - Powerful. Affordable. Sign up now. http://mailplus.yahoo.com

On Fri, Jan 31, 2003 at 10:49:33AM -0800, John Meacham wrote:
I propose a simple program which pops up a window saying
'Hello World' with a button saying 'Bye' which you click and it changes the message to 'Goodbye'. if you click the button again the program exits.
Sorry for the delay. Here is the gtk2hs version. Compiled with ghc --make Demo.hs -package mogul Cheers, Axel.

I propose a simple program which pops up a window saying 'Hello World' with a button saying 'Bye' which you click and it changes the message to 'Goodbye'. if you click the button again the program exits.
I have been thinkering with the wxWindows library and made a small Haskell binding to it that just supports this example. It was an interesting exercise since the wxWindows library is a large object-oriented C++ library. (but very portable, well supported, efficient and with lots of super widgets, like an openGL canvas and a HTML renderer) Anyhow, I think it comes out rather nicely and I am quite surprised how well the wxWindows library lends itself to Haskell access. -- Daan. ----------------------------------------------------------------- main = wxRun $ do w <- wxCreateFrame wxFRAME_DEFAULT_STYLE wxSetWindowBackgroundColor w white wxSetWindowSize w (Size 100 80) wxSetFrameTitle w "Bye!" l <- wxCreateLabel w "Hello World" wxSetWindowPosition l (Point 10 5) b <- wxCreateButton w "Bye" wxSetWindowPosition b (Point 10 25) wxSetButtonOnCommand b (bye w b l) wxShowWindow w where bye w b l = do wxSetControlLabel l "Goodbye" wxSetButtonOnCommand b (wxWindowClose w False)

On Sun, 2 Feb 2003 17:13:12 +0100
"Daan Leijen"
I have been thinkering with the wxWindows library and made a small Haskell binding to it that just supports this example. It was an interesting exercise since the wxWindows library is a large object-oriented C++ library. (but very portable, well supported, efficient and with lots of super widgets, like an openGL canvas and a HTML renderer)
It is really interesting. How did you bind the library? Could you make a tarball of the binding, the example and a makefile? It could be used as an "Haskell->C++" tutorial. Vincenzo -- First they ignore you, then they laugh at you, then they fight you, then you win. [Gandhi]

I have been thinkering with the wxWindows library and made a small Haskell binding to it that just supports this example. It was an interesting exercise since the wxWindows library is a large object-oriented C++ library. (but very portable, well supported, efficient and with lots of super widgets, like an openGL canvas and a HTML renderer)
It is really interesting. How did you bind the library? Could you make a tarball of the binding, the example and a makefile? It could be used as an "Haskell->C++" tutorial.
(warning: rather detailed and long answer...) I have only done it for windows yet, both with mingw32 and visual C++. Funny thing: the final (stripped) DLL with mingw32 was 2.8mb, while the visual C++ DLL (with the same functionality) was just 640kb :-). In the end, I couldn't link it directly with a haskell application due to the difference between the C++ and plain C runtimes, so I have made dynamic link library (.dll) of the C++ code. This code exposes a plain C interface (with "extern "C""). This interface is basically a flat C view on the object oriented wxWindows library. This DLL is accessed with foreign imports from Haskell. Call backs are dynamically created using dynamic exports ("wrapper"). Actually, the hardest part was to make sure that the resource files (.rc) were properly linked in the DLL, as we don't want to deal with those from Haskell. I don't know yet if this approach also works for unix's (.so files?) or MacOSX, but there probably is a way to do this. In the end, it is good enough if there is some way of wrapping the C++ code into a C library. Maybe someone on this list can tell me more about how this could work on unix like platforms??? The part that is most challenging, and which I am still working on, is trying to fit the event model of wxWindows into a reasonable model for Haskell (or other languages for that matter). Somehow, I need to create "universal" widget objects that are programmable from outside (i.e. Haskell) but normally, one derives application specific objects for each widget in wxWindows. There are mechanisms for more dynamic applications (like I want) but I am still trying to figure out the right way to do it. I think this is basically a universal problem when trying to interface to foreign object oriented (or any other paradigm for that matter) with a functional language. It is not just the marshalling and calling conventions, but the programming model makes a huge difference. Years ago, when designing H/Direct we automated the marshalling process, but it seems that that is just a small part of the problem. Trying to fit into an entirely different programming model is very hard. For an extreme example, I think that there is no reasonable way of interfacing to the Java Swing model. Fortunately, it seems that the wxWindows library is much more flexible, and up till now, I haven't encountered any hard problems. Maybe this is actually the right way to go for a Haskell GUI library -- let others do the hard work of maintaining a rich,portable gui library, and we just have to do the hard work of interfacing to c++ once. All the best, Daan.
Vincenzo
-- First they ignore you, then they laugh at you, then they fight you, then you win. [Gandhi]
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui

--- Daan Leijen
In the end, I couldn't link it directly with a haskell application due to the difference between the C++ and plain C runtimes, so I have made dynamic link library (.dll) of the C++ code. This code exposes a plain C interface (with "extern "C""). This interface is basically a flat C view on the object oriented wxWindows library.
There is existing binding of wxWindows to Eiffel. The wxEiffel project uses the same approach to bind Eiffel code to C++ library. Is it possible to use flat C interface developed from Eiffel team? See http://elj.sourceforge.net/projects/gui/ewxw/ Best regards, Krasimir __________________________________________________ Do you Yahoo!? Yahoo! Mail Plus - Powerful. Affordable. Sign up now. http://mailplus.yahoo.com

This interface is basically a flat C view on the object oriented wxWindows library.
There is existing binding of wxWindows to Eiffel. The wxEiffel project uses the same approach to bind Eiffel code to C++ library. Is it possible to use flat C interface developed from Eiffel team?
Wow! I knew about the Eiffel binding but never knew that they used a 'flat' C interface. Actually, their code looks almost the same to the experimental code that I have written. It would be just perfect if I could use their code (or even DLL) directly to interface to Haskell. Alas, there are a few rough edges regarding strings and event handling, but maybe these can be sorted out on the Haskell side... I'll try something out this evening. All the best, Daan.
See http://elj.sourceforge.net/projects/gui/ewxw/
Best regards, Krasimir
__________________________________________________ Do you Yahoo!? Yahoo! Mail Plus - Powerful. Affordable. Sign up now. http://mailplus.yahoo.com _______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui

John Meacham
I propose a simple program which pops up a window saying
'Hello World' with a button saying 'Bye' which you click and it changes the message to 'Goodbye'. if you click the button again the program exits.
this should (hopefully) be a short program with most toolkits and demonstrate how one lays out 2 widgets, and responds to user input and mutates the display. note, this is not to compare the toolkits themselves, but the haskell APIs used to access them.
I'd like to see samples using
gtk+hs [..]
This request is quite old by now, but I thought I'll provide you with the Gtk+HS versions of the program nevertheless. I submit two versions: * Bye.hs: Based on the plain Gtk+HS API and IORefs (and naturally very close to the version for gtk2hs). * IHBye.hs: Based on the iHaskell API, which is a higher-level API implemented on top of Gtk+HS and part of the standard Gtk+HS distribution.[1] It's main feature is to avoid IORef's in favour for a more functional abstraction called ports.[2] More information is on the Gtk+HS web page http://www.cse.unsw.edu.au/~chak/haskell/gtk/ The attached code requires the current CVS version of Gtk+HS (to update the button label) and can also be found in the examples directories in CVS. Cheers, Manuel [1] It is not very complete, though. [2] It is unfortunate to have a name clash with Daan's Ports library, but the ports abstraction is being called so already for many years. -- A little demo program that was proposed on gui@haskell.org to compare -- toolkit APIs. This is a version for the plain Gtk+HS API. -- -- There is a single button, which, when clicked once, changes the display -- and, when clicked a second time, terminates the application. -- import Monad import IOExts (IORef, newIORef, readIORef, writeIORef) import Gtk hiding (init, main) import qualified Gtk (init, main) main :: IO () main = do Gtk.init Nothing -- create a new window with a box to pack widgets vertically -- window <- windowNew WindowToplevel vbox <- vBoxNew False 10 window `containerAdd` vbox -- terminate if the window disappears -- window `signalConnect` WidgetDeleteEventHandler (\_ _ -> mainQuit >> return False) -- add the label and button to the box -- label <- labelNew " Hello World " button <- buttonNewWithLabel " Bye " butlbl <- liftM fromWidget $ binGetChild button :: IO Label boxPackStart vbox label True True 2 boxPackStart vbox button True True 2 -- create a stateful signal handler for the button -- clickedAlreadyRef <- newIORef False button `signalConnect` ButtonClickedHandler (\_ -> do clickedAlready <- readIORef clickedAlreadyRef if clickedAlready then mainQuit else do labelSetText label " Goodbye " labelSetText butlbl " Exit " writeIORef clickedAlreadyRef True) -- display the window and enter the event loop -- widgetShowAll window Gtk.main -- A little demo program that was proposed on gui@haskell.org to compare -- toolkit APIs. This is a version for the iHaskell API. -- -- There is a single button, which, when clicked once, changes the display -- and, when clicked a second time, terminates the application. -- import Monad import Gtk (binGetChild) import IH hiding (init, main) import qualified IH (init, main) main :: IO () main = do IH.init Nothing -- create a counter for clicks -- clicksPort <- newPort 0 -- create the label and button, where the button increments the click count -- label <- newLabel " Hello World " button <- newButtonWithLabel " Bye " (clicksPort <-$ (+1)) butlbl <- liftM fromWidget $ binGetChild button :: IO Label -- pack the label and button vertically and embed them into a window -- contents <- newBox Vertical True 10 [widget label, widget button] newWindow " Bye Demo " contents mainQuit False -- clicks are handled by `handleClick' depending on the number of clicks -- let handleClick 2 = mainQuit handleClick 1 = do setLabelText label " Goodbye " setLabelText butlbl " Exit " clicks <- listenToPort clicksPort forkIO $ mapM_ handleClick clicks -- enter the event loop -- IH.main

At 14:32 30-1-03 +0100, Daan Leijen wrote:
[..] However, it is not yet clear how that level should look like. We could take the ObjectIO interface as our layer but I would not recommend that. Note, this is not a critique on the ObjectIO library, I highly respect the work of the Clean people, and Peter van Achten in particular. However, the Haskell ObjectIO interface should be heavily revised to fit better in the style of Haskell. Right now, it is still influenced by the non-monadic uniqueness style of Clean. For example, the generation of identifiers (openId) is quit unsafe. In the Haskell tradition we would use a monadic bind to name widgets. ie.
w <- window []
instead of
w <- openId openWindow ... [ WindowId w, ...] This issue has nothing to do with monads, but is rather a design decision how to identify GUI elements. One particular disadvantage of the w <- window []
style is that GUI creation is an (opaque) action, rather than a first-class description of the GUI. Identification values become available only after creation of GUI elements, which is less convenient than knowing them beforehand. The only 'danger' is forgetting to associate the identification value with the window, but the same problem exists with the other style: w <- window [] -- window identified by w ... close w -- window identified by w destroyed ... setTitle w "Hi there" -- unbound Also, if you do prefer the binding style, it is easily added to Object I/O: window :: IO WindowID window = do { w <- openId window [WindowId w] return w }
Other things are the widget attributes that are specified using constructors. A more Haskellish style would use function names instead of constructors (as to be able to abstract from them) and use type classes for grouping them (as to prevent using illegal attributes on a certain widget). i.e.
w <- window [title =: "My window" ]
instead of
w <- openId openWindow ... [ WindowId w, WindowTitle w...]
Window titles are mandatory in Object I/O, so the excerpt should read: w <- openId openWindow ... (Window "My window" [WindowId w]) The same argument applies here as above: data constructors are more 'first-class' than functions because one can do pattern-matching on them. Also, it is more general, as the elegant TkGofer style is built easily on top of it. For Object I/O devotees, it could be done as follows (in Clean): // The class that fixes the relation between widget and attribute: class Atts gui att where addAtt :: (gui .ls .pst) (att *(.ls,.pst)) -> gui .ls .pst getAtt :: (gui .ls .pst) -> att *(.ls,.pst) // 'Lift' current attribute data constructors to type constructors: :: WindowViewSize st = WindowViewSize` Size :: WindowHScroll st = WindowHScroll` ScrollFunction /* Instantiate the proper relations (note that view size and scroll bar are proper Window attributes, but for Dialogs only view size is valid. */ instance Atts (Window c) WindowViewSize | Controls c where ... instance Atts (Window c) WindowHScroll | Controls c where ... instance Atts (Dialog c) WindowViewSize | Controls c where ... // Convenient shorthand for addAtt: (<==) infixl :: (gui .ls .pst) (att *(.ls,.pst)) -> gui .ls .pst | Atts gui att (<==) w a = addAtt w a // Now one can set size and scroll attribute for a window... w = Window "Hi there" NilLS [] <== WindowViewSize` {w=100,h=200} <== WindowHScroll` (stdScrollFunction Horizontal 100) // ...and *only* the size for a dialog... d1 = Dialog "Hi there" NilLS [] <== WindowViewSize` {w=100,h=200} // ...but setting scrollbar won't type check... d2 = Dialog "Hi there" NilLS [] <== WindowHScroll` (stdScrollFunction Horizontal 100)
This is basically what I am trying to do in the GIO library. However, even than, there are still tons of other design decisions to make, I wonder whether consensus can ever be reached.
All the best, Daan.
The above is not a critique on Port or GIO (honest!). I just wanted to explain part of the design reasons for Object I/O and show that it supports elegant ideas such as advocated by Daan. Regards, Peter

Dear Peter This issue has nothing to do with monads, but is rather a design decision how to identify GUI elements. One particular disadvantage of the w <- window [] style is that GUI creation is an (opaque) action, rather than a first-class description of the GUI. Identification values become available only after creation of GUI elements, which is less convenient than knowing them beforehand. The only 'danger' is forgetting to associate the identification value with the window, but the same problem exists with the other style: w <- window [] -- window identified by w ... close w -- window identified by w destroyed ... setTitle w "Hi there" -- unbound There is more to this. Since ID's are untyped, it happened to me a few times that I attached the wrong id to the wrong widget. Each widget is later accessed with an untyped ID, that may be connected to a completely different widget kind. With the monadic style, not an identifier is returned but the typed entity itself and thus all further access is also checked. The other problem (closing and accessing) seems only solvable within a higher-level framework. The above is not a critique on Port or GIO (honest!). I just wanted to explain part of the design reasons for Object I/O and show that it supports elegant ideas such as advocated by Daan. Off course it does :-) Since ObjectIO is in this respect on a lower-level, GIO could be implemented on top of Object/IO -- that is also why one could implement the attribute approach on top of the ObjectIO constructors. The whole issue is probably more of a question of what should be part of a medium-level GUI library (and what not). In this respect, I believe that a medium-level library should a.. Offer as much type safety as possible without sacrificing flexibility or give incomprehensible type errors. That's why GIO doesn't use multiple parameter type classes to to implement attributes as in your example :-). This is also what I like ObjectIO -- it uses little overloading (but a fairly difficult GUI type). b.. Identify entities by value instead of by ID. c.. Not offer a model for structuring state but stay in the IO monad and use simple mutable variables. Even though a model like that of ObjectIO is convenient, I believe this belongs to a higher-level library. d.. Be fully dynamic -- each attribute should be changeable later (if sensible), like layout, titles and event handlers. The advantage of having attributes that can be set or read at any time, is that we don't need to double functionality, like WindowViewDomain, getWindowViewDomain, setWindowViewDomain, ControlViewDomain, setControlViewDomain and getControlViewDomain. For a user we just have an attribute "domain" that can be get or set.
class HasDomain w where> domain :: Attr w Size > instance HasDomain Window> instance HasDomain CompoundControl>> get :: w -> Attr w a -> IO a> set :: w -> [Prop w] -> IO ()> (=:) :: Attr w a -> a -> Prop w>> test = do w <- window []> set w [domain =: Size 100 100]> ....(btw. Allthough fairly straightforward, this nice attribute stuff is invented (I think) by Koen Claessen -- I read his lecture notes).
The "dynamic" ness of the library is also used to circumvent the problem that one wants to refer to a window before it is created, for example while specifying the layout of buttons in a window. In GIO, the layout can be set later, after the creation of the child controls.
do w <- window [title =: "Demo"]> q <- button [text =: "Quit", on command =: close w]> set w [layout =: center q]Same story for event handlers. I am not sure though how inconvenient this can be when creating larger applications but I feel that the extra type safety is worth the inconvenience. (Btw, layout is another dark area: what does it mean for example when a button is put next to itself (q <<< q), or when a button created in some window is layed out in another?) All the best, Daan.
ps. I have been thinking about more 'improvements' for the (haskell?) ObjectIO library. For example, getting rid of state transformers in the GUI monad, like the GUIFun for example: "(ls,ps) -> GUI ps (ls,ps)". The idea is put every state in a "UI ls ps a" monad with "getLS :: UI ls ps ls" etc. functions. I believe that the types become much easier to comprehend but it is a fairly extensive change. Maybe we should talk about this off-line some time.

At 18:36 31-1-03 +0100, Daan Leijen wrote:
Dear Peter
This issue has nothing to do with monads, but is rather a design decision how to identify GUI elements. One particular disadvantage of the w <- window []
style is that GUI creation is an (opaque) action, rather than a first-class description of the GUI. Identification values become available only after creation of GUI elements, which is less convenient than knowing them beforehand. The only 'danger' is forgetting to associate the identification value with the window, but the same problem exists with the other style: w <- window [] -- window identified by w ... close w -- window identified by w destroyed ... setTitle w "Hi there" -- unbound
There is more to this. Since ID's are untyped, it happened to me a few times that I attached the wrong id to the wrong widget. Each widget is later accessed with an untyped ID, that may be connected to a completely different widget kind. With the monadic style, not an identifier is returned but the typed entity itself and thus all further access is also checked. Object I/O can easily be extended with typed identification values, in the same way as has been done for receivers (RId m) and (R2Id m r). The binding of typed identification value and the GUI object is at the data constructor.
In this respect, I believe that a medium-level library should * Offer as much type safety as possible without sacrificing flexibility or give incomprehensible type errors. That's why GIO doesn't use multiple parameter type classes to to implement attributes as in your example :-). This is also what I like ObjectIO -- it uses little overloading (but a fairly difficult GUI type). I agree that we should obtain as much type safety as possible. The problem is that more detailed types sometimes hamper expressiveness. Consider for instance a function that returns the identification values of all GUI elements in a window. If these are all typed according to the different type of GUI elements (text input fields have different types than buttons, and so on), then the type of this function is not as straightforward as one might hope. * Identify entities by value instead of by ID. I contend that the Object I/O way of handling GUI creation in two steps is more flexible than only offering creation actions for reasons mentioned in my earlier e-mail. In this set-up using IDs is symmetric, which isn't the case with the action-creation set-up. * Not offer a model for structuring state but stay in the IO monad and use simple mutable variables. Even though a model like that of ObjectIO is convenient, I believe this belongs to a higher-level library. Your first sentence is a contradiction in terms. However, I agree that a medium-level library should try to support as many higher-level libraries as possible. My guess is that this bit will prove to be the hardest part to design well. * Be fully dynamic -- each attribute should be changeable later (if sensible), like layout, titles and event handlers. The advantage of having attributes that can be set or read at any time, is that we don't need to double functionality, like WindowViewDomain, getWindowViewDomain, setWindowViewDomain, ControlViewDomain, setControlViewDomain and getControlViewDomain. For a user we just have an attribute "domain" that can be get or set. I agree on fully dynamic, and so does Object I/O, it just doesn't use classes to organize these functions.
The "dynamic" ness of the library is also used to circumvent the problem that one wants to refer to a window before it is created, for example while specifying the layout of buttons in a window. In GIO, the layout can be set later, after the creation of the child controls.
do w <- window [title =: "Demo"]
q <- button [text =: "Quit", on command =: close w]
set w [layout =: center q] Same story for event handlers. I am not sure though how inconvenient this can be when creating larger applications but I feel that the extra type safety is worth the inconvenience. (Btw, layout is another dark area: what does it mean for example when a button is put next to itself (q <<< q), or when a button created in some window is layed out in another?) I must confess that I don't quite get your argument of circumventing the 'future reference problem'. Do you mean with the dark area something like the following? do w1 <- window [title =: "A"] w2 <- window [title =: "B"] b1 <- button [text =: "Hi"] set w1 [layout =: center b1] set w2 [layout =: center b1]
Can b be in two windows w1 and w2 at the same time? Regards, Peter

On Sat, 25 Jan 2003 14:29:29 +0100
"Daan Leijen"
IBM's SWT or GTK directly
After a bit more research I discovered that SWT would not be suitable because it too a thin a C layer to be useful to us. One interesting feature of SWT is to provide native access to any widget that exists on a given platform, but to emulate those that don't (in Java -- in our case Haskell). This allows for quick prototyping (the GUI runs everywhere) but also allows people to use the same library to customize their application to a different platform later (eg Mac OS X) if they so desire. It avoids the least common denominator problem where only basic GUIs can be written, and it avoids the need to rewrite your code from scratch each time you target a new platform and need more powerful features. Of course it pushes more work into the library. Sengan

On Mon, 27 Jan 2003 15:25:51 -0500 Sengan.Baring-Gould@nsc.com wrote:
One interesting feature of SWT is to provide native access to any widget that exists on a given platform, but to emulate those that don't (in Java -- in our case Haskell)
This way you are not achieving native look and feel. BTW, I 've seen many people mention the "just one menubar per application in aqua" problem. Can someone give me an example of a famous application under linux wich uses two different menubars in two different windows? Nothing comes to my mind. Vincenzo -- Fedeli alla linea, anche quando non c'è Quando l'imperatore è malato, quando muore,o è dubbioso, o è perplesso. Fedeli alla linea la linea non c'è. [CCCP]

Not just in linux, any "more than one menubar" app anywhere, on any O/S? On 27-Jan-2003 Nick Name wrote:
On Mon, 27 Jan 2003 15:25:51 -0500 Sengan.Baring-Gould@nsc.com wrote:
One interesting feature of SWT is to provide native access to any widget that exists on a given platform, but to emulate those that don't (in Java -- in our case Haskell)
This way you are not achieving native look and feel.
BTW, I 've seen many people mention the "just one menubar per application in aqua" problem.
Can someone give me an example of a famous application under linux wich uses two different menubars in two different windows? Nothing comes to my mind.
Vincenzo
-- Fedeli alla linea, anche quando non c'� Quando l'imperatore � malato, quando muore,o � dubbioso, o � perplesso. Fedeli alla linea la linea non c'�. [CCCP]
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui
---------------------------------- Seth Kurtzberg M. I. S. Corp. E-Mail: seth@cql.com Date: 27-Jan-2003 Time: 15:54:47 This message was sent by XFMail ----------------------------------

nick.name@inwind.it wrote:
Can someone give me an example of a famous application under linux wich uses two different menubars in two different windows? Nothing comes to my mind.
seth@cql.com wrote:
Not just in linux, any "more than one menubar" app anywhere, on any O/S?
I can't think of any either, but then I use MacOS more than Linux or Windows. Does that mean that it would be OK for a toolkit to support just one menubar per application on non-MacOS platforms? All allegedly cross-platform toolkits I know treat a menubar as a property of a window or even as an ordinary widget that you can place inside a window, which causes several problems for the Mac OS implementations of those toolkits. A related problem with Mac OS is that when you close the last window of an application, the application doesn't terminate, it's menu bar is still there. You can still open a new document from the menu. When you click on the icon of an open application that doesn't have any windows, a new empty document window should be created. I know of no cross-platform toolkit that supports this behaviour. Cheers, Wolfgang

I would say one menu bar per autonomous window, not one per application. On 27-Jan-2003 Wolfgang Thaller wrote:
nick.name@inwind.it wrote:
Can someone give me an example of a famous application under linux wich uses two different menubars in two different windows? Nothing comes to my mind.
seth@cql.com wrote:
Not just in linux, any "more than one menubar" app anywhere, on any O/S?
I can't think of any either, but then I use MacOS more than Linux or Windows. Does that mean that it would be OK for a toolkit to support just one menubar per application on non-MacOS platforms? All allegedly cross-platform toolkits I know treat a menubar as a property of a window or even as an ordinary widget that you can place inside a window, which causes several problems for the Mac OS implementations of those toolkits. A related problem with Mac OS is that when you close the last window of an application, the application doesn't terminate, it's menu bar is still there. You can still open a new document from the menu. When you click on the icon of an open application that doesn't have any windows, a new empty document window should be created. I know of no cross-platform toolkit that supports this behaviour.
Cheers,
Wolfgang
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui
---------------------------------- Seth Kurtzberg M. I. S. Corp. E-Mail: seth@cql.com Date: 27-Jan-2003 Time: 16:45:43 This message was sent by XFMail ----------------------------------

Nick Name wrote:
BTW, I 've seen many people mention the "just one menubar per application in aqua" problem.
Can someone give me an example of a famous application under linux wich uses two different menubars in two different windows? Nothing comes to my mind.
Netscape uses different menubars for different types of window.
If the OS allows the application to change the menubar dynamically,
then you can change it whenever the "active" window (e.g. the one with
the keyboard focus) changes. This is what Tk does for MacOS:
MENUBARS |
Any menu can be set as a menubar for a toplevel window |
(see toplevel command for syntax). On the Macintosh, when |
ever the toplevel is in front, this menu's cascade items |
will appear in the menubar across the top of the main mon |
itor. On Windows and Unix, this menu's items will be dis |
played in a menubar accross the top of the window. These |
menus will behave according to the interface guidelines of |
their platforms. For every menu set as a menubar, a clone |
menu is made. See the CLONES section for more information.
The main factor for ensuring portability is not to assume that a
menubar is just another widget. IOW, you should have a specific
interface for creating a menubar. Similarly, menu items should be
assumed to be distinct from normal widgets, even if most backends
don't actually make a distinction.
--
Glynn Clements

Glynn Clements wrote:
[...] If the OS allows the application to change the menubar dynamically, then you can change it whenever the "active" window (e.g. the one with the keyboard focus) changes. This is what Tk does for MacOS: [...]
The main factor for ensuring portability is not to assume that a menubar is just another widget [...]
All that you say is true, but... I'm not concerned about whether it will be implementable on Mac OS (it most definitely will be), but whether it will _feel_ right. This standard approach (the one used in Tk), violates the following "holy laws" of the Mac OS look & feel; a) Mac programs are simply not supposed to switch menu bars. It will confuse or at least annoy users. On Mac OS, the menu bar tells you which application is currently active - if it changes inside one application, that application will feel like one-and-a-half applications, novice users will get lost, and seasoned users will get annoyed. b) There still should be a menu bar when no window is around. The behaviour of a Mac OS application is similar to a Windows MDI application whose MDI frame window has been maximized to fill the screen. On Windows, when you switch between MDI child windows, the menu bar of the frame window doesn't change, and when you close the last child window, the frame window doesn't close. I maintain that a good cross-platform toolkit designed for Windows, X11 and Mac OS should provide some abstraction to bridge the differences in the behaviour of the different platforms. If I remember correlctly, Tk, Java and Qt were all first designed for X11 and then ported to Windows and Mac OS. Hence they had to use the "let's use the front window's menu bar" hack for Mac OS. Cheers, Wolfgang

On Tue, Jan 28, 2003 at 11:21:59AM +0100, Wolfgang Thaller wrote:
I maintain that a good cross-platform toolkit designed for Windows, X11 and Mac OS should provide some abstraction to bridge the differences in the behaviour of the different platforms. If I remember correlctly, Tk, Java and Qt were all first designed for X11 and then ported to Windows and Mac OS. Hence they had to use the "let's use the front window's menu bar" hack for Mac OS.
Yes, I think we can be pragmatic about some issues. Going for exactly one menu bar is a reasonable assumption for all platforms. You can force a lot into a Gtk application because there is no real style guide. An application with nearly several menu bars is Gimp: The menu bar for each drawing Window is hidden in a context menu. I think Gimp is like WinAmp (or Microsoft Media Player): It violates any common sense and style guide, but it's so widespread that you have to live with it. Let's be pragmatic and give programmers reasonable freedom: exactly one menu bar. Axel.

On Tue, 28 Jan 2003 10:33:20 +0000
Axel Simon
An application with nearly several menu bars is Gimp: The menu bar for each drawing Window is hidden in a context menu. I think Gimp is like WinAmp (or Microsoft Media Player): It violates any common sense and style guide, but it's so widespread that you have to live with it. Let's be pragmatic and give programmers reasonable freedom: exactly one menu bar.
In GIMP these are context menu, not menubars. If "the GIMP" had been designed with OSX in mind, that menu could have gone on the menubar, called "current window". Vincenzo -- Fedeli alla linea, anche quando non c'è Quando l'imperatore è malato, quando muore,o è dubbioso, o è perplesso. Fedeli alla linea la linea non c'è. [CCCP]

On Mon, 27 Jan 2003 23:48:31 +0100
"Nick Name"
On Mon, 27 Jan 2003 15:25:51 -0500 Sengan.Baring-Gould@nsc.com wrote:
One interesting feature of SWT is to provide native access to any widget that exists on a given platform, but to emulate those that don't (in Java -- in our case Haskell)
This way you are not achieving native look and feel.
The example they gave was tree widgets which are not supported by Motif, and which are therefore emulated. If a program assumes the existence of a widget, it is useful for the library supports it on an emasculated platform. If the program author feels like changing his program to no longer use such a feature on that platform to satisfy the Look and Feel gods, she/he is free to do so. I doubt many people would really want the native look & feel version in this case.
BTW, I 've seen many people mention the "just one menubar per application in aqua" problem.
Every time you spawn a new Acrobat you get a new menu with it. It just doesn't go at the top of the screen as on old Macs. I don't know what new Macs do. I'd be surprised if MDI is forced on you in gtk. It isn't in Windows: you can open a new window and put a menu on it if you want. Sengan
participants (14)
-
Antony Courtney
-
Axel Simon
-
Daan Leijen
-
Glynn Clements
-
John Meacham
-
Krasimir Angelov
-
Manuel M T Chakravarty
-
Nick Name
-
Peter Achten
-
Sengan.Baring-Gould@nsc.com
-
seth@cql.com
-
Simon Peyton-Jones
-
Wolfgang Jeltsch
-
Wolfgang Thaller