Click here to Skip to main content
15,868,306 members
Articles / Programming Languages / C#

Develop a Mono application for the XO laptop

Rate me:
Please Sign up or sign in to vote.
5.00/5 (19 votes)
21 Apr 2009CPOL10 min read 102.2K   170   28  
Learn how to develop an application for the XO laptop - the OLPC project's machine - using Mono on Sugar OS
This is an old version of the currently published article.

Abstract

This article will learn you how to develop an application for Sugar and the XO, the OLPC project machine. More precisely, In this article, I will use C# and Mono to create a new "activity" which works on the XO and on the Sugar emulator included in the downloadable virtual machine.

Introduction

About the OLPC project and the XO

One Laptop per Child

The One Laptop per Child association develops a low-cost laptop—the "XO Laptop"—to revolutionize how we educate the world's children. The mission of the OLPC project is to provide educational opportunities for the world's poorest children by providing each child with a rugged, low-cost, low-power, connected laptop with content and software designed for collaborative, joyful, self-empowered learning.

The XO laptop

Shortly, the XO is a netbook. The XO is an innovative hardware design, with a dual-mode display—both a full-color transmissive mode and a black and white reflective mode (sunlight-readable). The laptops have a 433 Mhz processor and 256MB of DRAM, with 1GB of NAND flash memory (there is no hard disk). The laptops have wireless broadband that allow them to work with a standard access point or as a mesh network—each laptop is able to talk to its nearest neighbors, creating an ad hoc, local-area network (based on 802.11s standard). The laptops use a wide range of DC power inputs (including wind-up and solar).

Sugar inside

Sugar is the operating system of the XO laptop. The Sugar Learning Platform promotes collaborative and critical-thinking learning. It is already in use worldwide on 800,000 XO distributed to developing countries. Sugar is supported by a large community of developers and teachers around the world. Sugar is useful not only on the XO laptop but on every other laptop.

Technically speaking, Sugar is based on a Fedora Core Linux and on the Gnome user interface. However, Sugar could also be used on other Linux distribution (Debian, Fedora, Mandriva, ...).

Sugar Architecture

Sugar has an unique window manager with simplified concepts that every children can understand very quickly. More, most of the interface could be handle by children which don't had yet teach to read.

Sugar desktop

Mono

The Mono Project is an open development initiative to develop an open source version of the Microsoft .NET development platform. Its objective is to enable Linux developers to build and deploy cross-platform .NET Applications. The project implements technologies developed by Microsoft and submitted to the ECMA organization for standardization.

Mono

Mono is not only a ".NET clone". Mono comes with some uniques C#-based components, libraries and frameworks. The most important one is Gtk# which allow building of Gnome application in C#. Gtk# is a "binding" for the Gtk+ GUI toolkit. The word "binding" means that it allows a call to native libraries directly from the C# source code.

The following screen capture shows a very basic sample in Mono using command line compiler.

A sample in Mono

If you are a .NET developer, this sample should look familiar for you. The only difference with .NET is that the .EXE resulting file is not directly executable on Linux so you should prefix the command line call by mono.

Create your first Activity

Sugarize C#

Sugar is mainly write in python. python is a scripting language so it's a good tool to let users customize the system. If you want to create new applications (named "Activities"), Sugar will provides you a large number of python API for that.

Torello Querci is a contributor on the Mono project. Torello wrote one year ago a C#/Sugar binding to let you use Mono to create Sugar Activities. This binding is packaged as a .NET assembly named Sugar.dll. Most of Sugar API is callable from this assembly. Of course, the Sugar.dll assembly is need for the sample described here.

Create the project

To create our first activity, we're going to use MonoDevelop. MonoDevelop is a Visual Studio like IDE. So MonoDevelop let you edit and package a Mono application.

Let's start:

  • Launch MonoDevelop (Applications/Programming/MonoDevelop),
  • Create a new solution (File/New Solution…) Choose a "C# / Gtk# 2.0 Project" template,
  • Fill the form with "LabActivity" as name.

Choose a template in MonoDevelop

We're using the Gtk# template because Sugar is based on Gtk. Let's now configure this solution to add the Sugar binding.

We just need to add the Sugar.dll assembly. Right click on References, "Edit References…", choose the ".Net Assembly" sheet and select the right assembly.

Add the Sugar assembly as reference

That's all, the solution is now ready.

Create the main window

Here is the source code to create the main window for the activity:

using System;
using System.Collections;
using Gtk;
using Sugar;

namespace LabActivity
{ 
   public class MainWindow : Sugar.Window
   { 
        public new static string activityId = "";
        public new static string bundleId = ""; 

        public MainWindow(string activityId, string bundleId) 
            : base("Lab", activityId, bundleId) 
        { 
            this.SetDefaultSize(400, 400); 
            this.Maximize(); 
            this.DeleteEvent += new DeleteEventHandler(OnMainWindowDelete); 
            VBox vbox = new VBox(); 
            vbox.BorderWidth = 8; 
            Label _text = new Label("Hello Lab Activity"); 
            vbox.Add(_text); 
            Button _button = new Button(); 
            _button.Label = "Quit"; 
            _button.Clicked += new EventHandler(OnClick); 
            vbox.Add(_button); 
            this.Add(vbox); 
            ShowAll(); 
        } 

        void OnMainWindowDelete(object sender, DeleteEventArgs a) 
        { 
            Application.Quit(); 
            a.RetVal = true; 
        } 

        void OnClick(object sender, EventArgs a) 
        { 
            Application.Quit(); 
        } 
    }
} 

If you are a .NET WinForm developer, the Gtk framework should look familiar to you.

The MainWindow's constructor is responsible of the window initialization: it creates controls and setup event handlers. The Sugar binding adds the need to inherit from the Sugar.Window class to access to the low level communication with the Sugar API. More precisely, the main Window should handle the activity's identifier and the instance's identifier. Both values are send to the window manager and should be retrieve from the activity entry point. Here's how:

public static void Main(string[] args)
{
    if (args.Length > 0)
    {
        IEnumerator en = args.GetEnumerator();
        while (en.MoveNext())
        {
            if (en.Current.ToString().Equals("-sugarActivityId"))
            {
                if (en.MoveNext())
                {
                    activityId = en.Current.ToString();
                }
            }
            if (en.Current.ToString().Equals("-sugarBundleId"))
            {
                if (en.MoveNext())
                {
                    bundleId = en.Current.ToString();
                }
            }
        }
    }

    Application.Init();
    new MainWindow(activityId, bundleId);
    Application.Run();
}

We can now build and run the new application: click on "Project/Run". You should obtain this:

Our sample activity on Ubuntu

It's a first success: we've got a first C# Gtk application which is compliant with Sugar.

Mono bundle

A pre-requisite to run a .NET application is that the .NET framework should be installed. Of course, it's the same thing for Mono, you should have Mono installed on your machine. Unfortunately, Mono is not a standard package on the XO and we can't force each user to pre-installed it to run our application.

Hopefully, Mono provides an unique feature on .NET: the capacity to package Mono into the executable file. It's what we call a "bundle".

A bundle allows you to generate a runable file embedding all things need to execute it: assemblies for the .NET Framework, user assemblies and the JIT compiler to translate MSIL to the machine code instruction suitable for the processor.

A Mono bundle

The previous schema shows what means a bundle for the Hello World application. On the left side, the .EXE file is just a standard assembly. This assembly only contains the MSIL code for the application and use JIT Compiler and the .NET Framework at runtime. On the right side, we create a Mono bundle. The bundle embeds the JIT Compiler and only the .NET Framework assemblies needed. Nothing more is needed at runtime.

Here how you can create the Mono bundle for the Hello World application using the mkbundle2 command:

Our sample activity on Ubuntu

Of course both hello.exe assembly and hello bundle do the same thing. Note that the hello bundle do no longer need the mono prefix and is very huge (4Mo to compare to 3Ko for the initial assembly !).

The Mono bundle for our sample activity is not shown here but could be build in a very same way.

Build the .XO file

On the Activities page of the OLPC wiki, you could find all activities downloadable on the XO laptop.

The following screen capture shows a small part of this page. As you could see, downloading a new activity means downloading a .XO file. Let's see what is a ".xo" file and how we can generate this sort of file ?

Activities on OLPC wiki

Like other common file format (.JAR, .DOCX, ...), the .XO file is a zip file containing all needed files for the activity: binary and resource. We describe it below.

The most important file in the .XO file is the manifest. The manifest should be located at the root of the file. Here is the content of the manifest (named MANIFEST) for the activity:

activity/activity-labactivity.svg
activity/activity.info
bin/libgdksharpglue-2.so
bin/libgladesharpglue-2.so
bin/libglibsharpglue-2.so
bin/libgtksharpglue-2.so
bin/libMonoPosixHelper.so
bin/libpangosharpglue-2.so
bin/labactivity-activity
bin/labactivity.exe
bin/uiX11Util.so

The manifest file describes all files in the .XO file. The .XO file has two directories: activity which hold activity's properties and bin which hold binary files.

Binary files are: Mono bundle for the activity (labactivity.exe), Gtk# shared libraries (.so files) and a python script to start activity (labactivity-activity).

The first file in the activity directory is the activity's icon. This file use the SVG format. SVG is a vectorial format based on XML. The SVG file used here just draws a little square:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
  <!ENTITY stroke_color "#666666">
  <!ENTITY fill_color "#FFFFFF">
]>
<svg xmlns="http://www.w3.org/2000/svg" width="55" height="55">
  <rect x="5" y="5" width="45" height="45" stroke="&stroke_color;" fill="&fill_color;" stroke-width="3.5"/>
</svg>

Another important file is the activity.info file. This file contains all properties for the activity. Here is our file:

[Activity]
name = LabActivity
activity_version = 1
host_version = 1
service_name = org.olpcfrance.LabActivity
icon = activity-labactivity
exec = labactivity-activity
mime_types =

The activity.info file is just a text file containing values for each property: name, id, link to the icon file, link to the start script, ...

So, as a conclusion, to create the .xo file you should:

  • Launch the build for the Mono application,
  • Create a Mono bundle,
  • Build a .zip file with all binaries and config files,
  • Rename the file from .zip to .xo.

The deploy script included with the source file of the project build automatically the .XO file. You should launch it at the end of each build. At the end of the script, a LabActivity-1.xo is generated:

Generating XO file

Run the activity

Our activity could be installed on the Sugar emulator. A shortcut for this emulator is available on the Ubuntu desktop from the virtual machine included with this article.

Sugar emulator shortcut

Once launched, the Sugar Emulator displays the Sugar home page:

Sugar homepage in the emulator

To install a new activity, first click on the Terminal activity (icon square with an included dollar). Then, launch the command line sugar-install-bundle on the ".xo" file. This system command unzip the package and add the activity.

Installing activity

The icon's activity is now visible at the top of the desktop (the little white square).

Sample activity on the desktop

A click on the icon launch our activity:

Our activity in Sugar

Note that Gtk controls are slightly different on Sugar than on Ubuntu: buttons square are rounded.

If you have the luck to get a XO machine, you could install the activity with an USB key where you previously put the .XO file or using the Browse activity if you previously deployed the .XO file on a web site. The resulting window is exactly the same than the one in the emulator.

Sugarize your application

The previous part of this article shows you how you can write a new activity from scratch. Alternatively you could be interested to port an existing application. It's what we call "Sugarize" an application. Torello Querci has done a great job to sugarize the existing Mono Gbrainy application. Gbrainy is a collection of little games based on memory. The following screen capture shows you the application on the XO.

Gbrainy in Sugar

Gbrainy was initially wrote in pure Gtk. Gbrainy is also an interesting application because it use two advanced Mono features: Glade and Gettext.

Glade is a window design tool for Gtk. Glade comes with a dedicated designing tool and use a file format based on XML to store resources.

Gettext is the localization tool for Gnome. The Mono.Unix namespace allow call to Gettext from your C# application. Note that both Gettext and the standard localization mechanism of .NET are usable from Mono. The main advantage of Gettext is to be supported by a large community of developers and to be compliant with lot of common tools like the Pootle server or the Poedit editor.

The following source code comes from the Sugarized Gbrainy application. You could see: the Sugar features, the use of Glade properties ([Glade.Widget]) and some calls to localization methods (Catalog.GetString(...)).

public class gbrainy
{
        [Glade.Widget("gbrainy")] Gtk.Window app_window;
        [Glade.Widget] Box drawing_vbox;
        [Glade.Widget] Gtk.Label question_label;
        [Glade.Widget] Gtk.Label solution_label;
        [Glade.Widget] Gtk.Entry answer_entry;
        [Glade.Widget] Gtk.Button answer_button;
        [Glade.Widget] Gtk.Button tip_button;
        [Glade.Widget] Gtk.Button next_button;
        [Glade.Widget] Gtk.Statusbar statusbar;
        [Glade.Widget] Gtk.Toolbar toolbar;
        GameDrawingArea drawing_area;
        GameSession session;
        const int ok_buttonid = -5;
        ToolButton pause_tbbutton;    
        string activityId="";
        string bundleId="";
 
        public gbrainy (string [] args, params object [] props) 
        {
              Catalog.Init ("gbrainy", Defines.GNOME_LOCALE_DIR);
              IconFactory icon_factory = new IconFactory ();
              AddIcon (icon_factory, "math-games", "math-games-32.png");
              AddIcon (icon_factory, "memory-games", "memory-games-32.png");
              AddIcon (icon_factory, "pause", "pause-32.png");
              AddIcon (icon_factory, "resume", "resume-32.png");
              AddIcon (icon_factory, "endgame", "endgame-32.png");
              AddIcon (icon_factory, "allgames", "allgames-32.png");
              AddIcon (icon_factory, "endprogram", "endprogram-32.png");
              icon_factory.AddDefault ();

              Glade.XML gXML = new Glade.XML (null, "gbrainy.glade", "gbrainy", null);
              gXML.Autoconnect (this);
              Sugar.Activity activity=new Sugar.Activity(app_window, activityId, bundleId);
              activity.SetActiveEvent += activeChanged;

              app_window.Show();

              toolbar.IconSize = Gtk.IconSize.Dnd;
                
              Tooltips tooltips = new Tooltips ();

              ToolButton button = new ToolButton ("allgames");
              button.SetTooltip (tooltips, Catalog.GetString ("Play all the games"), null);
              button.Label = Catalog.GetString ("All");
              button.Clicked += OnAllGames;
              toolbar.Insert (button, -1);
                               
              // ...
      }

      // ...
}

Conclusion

This article is an introduction to Sugar development using Mono. Mono allows you to use your .NET and C# skill to create software for the XO laptop, to contribute to the OLPC project and then to provide educative material for the world's poorest children. Why don't take this chance ?

Links

This article comes from a full tutorial on the SugarLabs wiki. A French version is also available on the TechHead Brothers web site. Do not hesitate to contact me for more information on the OLPC project.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect C2S
France France
Lionel is a software architect at C2S, a software company based in France and subsidiary of the Bouygues group.
Lionel is also the author of Liogo, an open-source Logo compiler for .NET.
Lionel is a contributor of DotNetGuru and Dr.Dobb's Journal.
Lionel is President and co-founder of OLPC France.

Comments and Discussions

Discussions on this specific version of this article. Add your comments on how to improve this article here. These comments will not be visible on the final published version of this article.