In the March issue of .NET Developer's Journal Miguel de Icaza, project
leader for the Mono project, wrote an article introducing Mono. In the same
issue Dennis Hayes showed us how we could download and evaluate Mono. Since
then a lot has happened...
Background
The Mono project, which was launched by Ximian, Inc., in July 2001, led
by CTO de Icaza, has come a long way. By using the technical documentation
that Microsoft submitted to ECMA (the European Computer Manufacturers
Association), Mono developers have been able to create an implementation of
the Common Language Infrastructure (CLI), a C# compiler, and close to 4,000
classes. Several spin-off effects have already been noticed, with companies
using Mono in commercial software and new projects starting more or less
every week. If you want to know more about the latest version of Mono, or
the Mono project and related projects, please see the main project site at
www.go-mono.com.
In May, Mono version 0.24 was released, which contained among many
other things a new code generation engine and a graphical user interface
(GUI) toolkit binding called Gtk# (pronounced GTK-sharp).
The updates to Mono mentioned above were important. The new code
generation engine provided developers with an excellent opportunity to port
Mono to different hardware architectures, in our case ARM (Advanced RISC
Machine) based architectures. ARM, in particular one of its latest
reincarnations, called XScale, is commonly used in PDAs such as iPAQ and
Zaurus. But we should not forget to mention that ports of Mono to other
hardware also exist, most notably PPC, S/390, and soon SPARC.
Gtk#, the .NET language binding for the GTK+ toolkit, was included in a
Mono release for the first time. Gtk# gives a developer bindings to several
libraries (GNOME and GTK) that are more or less a de facto standard on a
Linux distribution. These libraries have been used for a long period of
time, should be considered stable, and help a developer create
cross-platform GUI applications for Unix and Windows. As a side note we must
mention the Qt# language bindings that bind to the Qt toolkit. Qt# might be
the better binding for PDAs using Qt as their main GUI toolkit.
Handhelds and Linux
Several PDAs come with Linux pre-installed, most notably the Sharp
Zaurus. But a developer or user can install Linux on an iPAQ handheld,
thanks to the work of the developers at www.handhelds.org. Using Linux on
your iPAQ is a pleasant experience, although it should be noted that a
certain level of Linux knowledge is necessary for the more complicated
procedures such as installation. We have the thttpd Web server installed on
our iPAQ 3970, serving HTML pages to visitors while everything is
administrated via SSH Secure Shell. Of course, since the Mono project also
contains an ASP.NET implementation, it is only a matter of time before we
have it on our iPAQ.
We installed the Familiar Linux distribution with GPE (GNU PDA
Environment) on our iPAQ. By doing so we had instant access to several
libraries that Gtk# can bind to. For installation instructions and more,
please see www.handhelds.org.
The remainder of this article will present three application examples
covering different aspects of development that are useful to a developer.
First, we will demonstrate how to create a simple Hello World command-line
application on the iPAQ. Second, we'll discuss how to create and deploy a
simple Hello World GUI application created with Gtk#, and finally we will
show you how to write a simple GUI that uses googleGateway (XML-RPC Web
service) to help users with their spelling.
Instructions for installing Mono on your workstation can of course be
found at the Mono Web site. We are used to working with Linux workstations,
so we will use a Linux workstation for this article. But since both Mono and
Gtk# can be run under the Windows operating system you have freedom of
choice. In short, everything in this article is developed on Linux and later
transferred to the iPAQ.
Create a Simple Command-Line Application
Let's focus now on development and write a simple command-line
application.
using System;
class HelloWorld {
public static void Main() {
Console.WriteLine(``Hello Mono Developers!'');
}
}
This example is the standard Hello World application that most, if not all,
programming languages use as an introductory example. Save the code in the
file hello.cs and compile it into Intermediate Language using the
command-line Mono C# compiler mcs:
mcs hello.cs
This command produces the executable hello.exe.
The iPAQ handhelds and other Linux handhelds have a large number of
applications available to them. A lightweight package manager called iPKG
was developed to help users install and manage applications. If a developer
creates an iPKG package of the application and then provides it via a
package feed, anyone with a connection to the Internet can download and
install it automatically, either through a GUI or via the command line, like
this:
ipkg install MyApp
This snippet invokes iPKG and tells it to download and install an
application called MyApp if it exists in any of the known feeds. A user can
easily add feeds to iPKG and have instant access to new software.
To install and run our example on the iPAQ you must first have Mono
installed. A feed is provided at the http://amy.udd.htu.se/~malte/mono Web site, which you can use to install Mono. The packages you should install are named mono and gtk-sharp. Add the mono::handhelds feed into your iPKG configuration and install mono and gtk-sharp by typing:
ipkg install mono
ipkg install gtk-sharp
If, on the other hand, you have a Zaurus and wish to run Mono, then you
should install GLib-2.0 instead of gtk-sharp, as there is at the moment no
easy way to use Gtk# on Zaurus, which uses the Qt toolkit. GLib-2.0, which
does not ship with the Zaurus, provides you with the functionality required
to run Mono.
If you open up a shell and type mono (JIT) or mint (interpreter), you
should see the Mono or Mint help being written to the console. Mint is an
interpreter that is slower but also smaller and can be appropriate for this
type of development. Mono, on the other hand, is the JIT compilation engine,
which is faster but also larger and still in early development stages on ARM
architecture.
Next, download the Hello World application to the iPAQ and run it with
the interpreter by typing the following in a console window:
mint hello.exe
Create and Deploy a Simple GUI Application
Next we create a simple GUI application that takes advantage of Gtk#
(see Listing 1). The code is fairly straightforward and should not be
difficult to understand, but the first few lines are probably new to most
.NET developers.
The Gtk, GtkSharp, and Gdk namespaces provide basic functionality for
using a GUI in our application. After declaring the namespaces, we
initialize the application, create a dialog, retrieve an image from the
assembly, and add it to the dialog. Then we add a Delete-
EventHandler, and show the dialog. A DeleteEvent is fired whenever a user
chooses to close a window. Finally, we instruct the application to run,
which essentially means starting the event loop and waiting to process any
incoming events. Let's compile the example:
mcs /r:gtk-sharp,gdk-sharp /res:mono.png hello-gtk.cs
Since we wish to use assemblies that are not part of the standard
library we must make sure to pass them as references to the compiler. We
will also include the image in the assembly.
Start up the application by typing mint hello-gtk.exe and view the
simple GUI application written in C# using Gtk# and Mono on an iPAQ
running Linux (see Figure 1). Of course, we could add this application to
the start menu and then start it by simply clicking an icon, but for the
sake of brevity we will leave this out for now.
XML-RPC and Handhelds
Charles Cook recently released the XML-RPC.NET library, a .NET
implementation of XML-RPC. This library allows applications to make remote
procedure calls using HTTP as the transport and XML as the encoding. We
chose to present a remoting example that used XML-based encoding rather than
binary, as binary-style remoting is implementation specific and would
restrict the application to communicating only with another Mono
application. The same limitation is of course also valid from other
implementations' viewpoints. To become truly cross-platform, XML-based
encoding is the ideal way to go.
Using Mono, Gtk#, and XML-RPC.NET we will now develop a simple GUI
application that consumes an XML-RPC service provided by xmlrpc.com. The Web
service is an XML-RPC gateway to Google's Web APIs. You will need a license
key, which you can get free from Google, to run this example. As you will
notice, it is extremely easy and straightforward to use Gtk# and XML-RPC.
The complete source code for this application can be found in Listing 2.
Let's look now at one of the less obvious parts. In Main we have the
creation of the main window within a try/catch statement. The reason for
that is that the picture is downloaded and later added to the window. If no
picture can be retrieved, then there probably is no connection, thus
rendering the application useless. The rest of the code should be fairly
self-explanatory. To try it out, compile the source code like this:
mcs /r:gtk-sharp,gdk-sharp,CookComputing.XmlRpc
google.cs
Run the application in the same manner as we did before: mint
google.exe. When the window is shown, enter a poorly spelled word and click
the button. After a while you should see a suggested spelling delivered by
way of the XML-RPC gateway from one of Google's servers (see Figure 2).
Conclusion
In this article we presented some of the things Mono already is capable
of doing on PDAs. Using Gtk# and Mono, developing graphical user interfaces
on PDAs is a small task, and third-party libraries such as XML-RPC.NET can
easily be fit, here giving us the opportunity to develop a simple
application that consumed a Web service. In similar fashion it is simple to
work with another graphical toolkit, for instance by compiling with the Qt#
bindings an application would be ready to be deployed in a Qt-based
environment.
Mono and the technologies surrounding it are in constant development.
Over the past few months we have seen the Mono project advance at an
astonishing pace, but as always, the team welcomes developers and users who
would like to help out. You can find details about how you can contribute at
www.go-mono.com/contributing.html. We welcome you!
References
The Mono project: www.go-mono.com
Ximian: www.ximian.com
Gtk# project: http://gtksharp.sf.net
Qt# project: http://qtcsharp.sf.net
XML-RPC.NET: www.xml-rpc.net
mono::handhelds: http://amy.udd.htu.se/~malte/mono
iPKG feed: http://amy.udd.htu.se/~malte/mono/feed
Google API: www.google.com/apis
Linux on iPAQ: http://handhelds.org
XML-RPC.Com: www.xmlrpc.com/googleGateway
GNOME: www.gnome.org
GTK: www.gtk.org
About The Authors
Malte Hildingson is a student at the University of Trollhättan/Uddevalla.
tds00mahi@thn.htu.se
Richard Torkar is a PhD student at the University of Trollhättan/Uddevalla.
richard.torkar@htu.se
Listing 1
using Gdk;
using Gtk;
using GtkSharp;
using System;
class Hello
{
public static void Main()
{
Application.Init();
Dialog d = new Dialog();
d.Title = "Go Mono!";
d.VBox.Add(new Gtk.Image(
new Pixbuf (null, ``mono.png'')));
d.SetDefaultSize(128, 64);
d.HasSeparator = false;
d.DeleteEvent += new DeleteEventHandler(Deleted);
d.ShowAll();
Application.Run();
}
public static void Deleted(object o, DeleteEventArgs args)
{
Application.Quit();
}
}
Listing 2
using System;
using System.Net;
using System.Threading;
using Gtk;
using GtkSharp;
using CookComputing.XmlRpc;
[XmlRpcUrl("http://google.xmlrpc.com/RPC2")]
internal interface IGoogle
{
[XmlRpcMethod("googleGateway.spellingSuggestion")]
string SuggestSpelling(string phrase, string key);
}
public class GoogleWindow : Window
{
static string Key = @"YOUR-GOOGLE-KEY-HERE";
static string ImageUri =
@"http://amy.udd.htu.se/malte/mono/ndj/google.png";
private IGoogle google;
private Entry entry;
private Label label;
private Button button;
public static void Main()
{
Application.Init();
try
{
new GoogleWindow().ShowAll();
}
catch (Exception e)
{
MessageDialog dialog;
dialog = new MessageDialog(null,
DialogFlags.Modal,
MessageType.Error, ButtonsType.Ok,
"An error occured: " + e.Message);
dialog.Run();
return;
}
Application.Run();
}
public GoogleWindow() : base("Google Spells")
{
Container vbox = new VBox(false, 4);
Container hbox = new HBox(false, 4);
vbox.BorderWidth = 2;
hbox.BorderWidth = 2;
entry = new Entry();
entry.Activated += new
EventHandler(this.RequestLookup);
vbox.Add(entry);
WebClient client = new WebClient();
Gdk.Pixbuf pixels = new
Gdk.Pixbuf(client.OpenRead(ImageUri));
hbox.Add(new Image(pixels));
button = new Button("Suggest");
button.Clicked += new
EventHandler(this.RequestLookup);
hbox.Add(button);
vbox.Add(hbox);
label = new Label("");
vbox.Add(label);
Add(vbox);
DeleteEvent += new
DeleteEventHandler(this.RequestDelete);
}
private void RequestLookup(object sender, EventArgs args)
{
if (google == null)
google = (IGoogle)
XmlRpcProxyGen.Create(typeof(IGoogle));
try
{
string s =
google.SuggestSpelling(entry.Text, Key);
if (s.Length > 0)
label.Text = "Suggestion: " + s;
else
label.Text = "No suggestion";
}
catch (Exception e)
{
label.Text = e.Message;
}
entry.GrabFocus();
entry.SelectRegion(0, entry.Text.Length);
}
private void RequestDelete(object sender,
DeleteEventArgs args)
{
Application.Quit();
}
}
All Rights Reserved
Copyright © 2004 SYS-CON Media, Inc.
E-mail:
info@sys-con.com