Mono Validates Swing Architecture
The Mono project is working on creating a portable version of the
System.Winforms .NET library. Like most such efforts to create a
cross-platform GUI toolkit, they had two main choices that I'm calling
"Bare Canvas" and "Native Controls":
- "Bare Canvas": Use only a bare canvas from the underlying
windowing system and render all controls themselves.
- "Native Controls": Use higher-level controls (buttons, labels,
combo boxes, etc.)
from the underlying windowing system and try to hide differences
in behavior between different systems.
Here the Mono WinForms
folks describe their choice of "Bare Canvas":
System.Windows.Forms in Mono is implemented using System.Drawing. All
controls are natively drawn through System.Drawing.
System.Windows.Forms implements it's own driver interface to
communicate with the host OS windowing system.
And the primary rationale:
The Gtk effort had the following problems:
* Mapping one toolkit semantics to another was very hard.
The Mono folks, regardless of your political views of Mono, are clearly
bright and energetic folks, having implemented a lot of high-quality
code in a short amount of time. For them to choose "Bare Canvas" is a
clear sign that the same decision made by the Swing team some years
back was the right one.
Problems with "Native Controls" Style
The problem with the Native Controls style, as groups like the SWT
team are finding, is that it is more difficult to make many different,
complicated native controls on different platforms work alike using
wrappers than it is to build those controls on top of a simple
abstraction layer, the bare canvas.
Let's say that right-clicking on a button produces an event on
platform A but nothing on platform B. Platform A advocates will
insist that feature be available in the toolkit to ensure equality
with native apps. But in order for apps to work the same on all
platforms, suddenly the toolkit must support a feature that isn't
available natively on platform B. So now there are several ugly
alternatives:
- Leave out the feature entirely from the toolkit. Users of
platform A miss the feature. The toolkit is missing useful
functionality. However, apps are guaranteed to work on all
platforms. Also, it is hard to add support for new platforms
since a new platform that has fewer features in some area will
not even meet the "least common denominator" requirements. Then
the toolkit has to have that feature removed (breaking apps that
use it) or the feature has to be emulated, which leads us to the
next item...
- Try to emulate platform A behavior on platform B. Perhaps put
a transparent window over the button, pass through left-clicks
and handle right-clicks. This requires potentially a lot of
work on platform B. It also means that on each successive
platform that comes along, if the feature is missing it must be
custom-coded, no matter how complex, in order to guarantee that
apps run the same. This has huge time costs and can make
porting to new platforms prohibitively expensive. However,
applications are guaranteed to work on all platforms.
- Give up on full cross-platform compatibility. Use neat
features on platforms that have them, but don't implement them
on platforms that make it too difficult. The toolkit is much
easier to create now. Portability is much easier, since if a
feature is too hard you can punt on it altogether. Of course
using the toolkit is now an exercise in masochism.
Want to use a toolkit control? Better check that it works on
your platform of interest. Want it on platform B? Better write
it yourself. This is scarcely better than writing the GUI
separately for each native windowing system and avoiding the
toolkit altogether.
|
|