/main.cs
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Cairo;
using Gtk;

public class Nebula {
	static Gtk.Window window;
	static VBox stack;
        static TextDisplay display;
	static TextDocument doc;
	static bool fullscreened = false;

        static void Main (string[] args) {
                Application.Init ();
                window = new Gtk.Window("Nebula");
		stack = new VBox(false, 0);

		if (args.Length > 0) {
			doc = new TextDocument(args[0]);
		} else {
			doc = new TextDocument();
		}
                display = new TextDisplay();
		display.SetDocument(doc);

                stack.Add(display);

                window.Add(stack);
                window.Resize(640,480);
                window.ShowAll();

		window.KeyPressEvent += new KeyPressEventHandler(KeyPress);
		window.KeyReleaseEvent += display.KeyRelease;
		SelectInput(display);
		window.DeleteEvent += delegate(object o, DeleteEventArgs e) {
			Application.Quit();
		};

                Application.Run();
        }

	static void SelectInput(IKeyPress w) {
		window.KeyPressEvent -= display.KeyPress;
		window.KeyPressEvent += w.KeyPress;
	}

	[GLib.ConnectBefore ()]
	static void KeyPress(object o, KeyPressEventArgs args) {
		TextInput input;
		if ((args.Event.State & Gdk.ModifierType.ControlMask) != 0) {
			switch(args.Event.Key) {
			case Gdk.Key.n:
				doc = new TextDocument();
				display.SetDocument(doc);
				break;
			case Gdk.Key.o:
				input = new FileSelector();
				stack.PackEnd(input);
				SelectInput(input);
				input.Show();
				input.Selected += delegate(object o2, TextInputEventArgs t) {
					if (t.Value != null) {
						doc = new TextDocument(t.Value);
						display.SetDocument(doc);
					}
					SelectInput(display);
					stack.Remove(input);
					input = null;
				};
				break;
			case Gdk.Key.s:
				if (doc.filename == null) {
					input = new FileSelector();
					stack.PackEnd(input);
					SelectInput(input);
					input.Show();
					input.Selected += delegate(object o2, TextInputEventArgs t) {
						if (t.Value != null) {
							doc.Save(t.Value);
						}
						SelectInput(display);
						stack.Remove(input);
						input.Destroy();
					};
				} else {
					doc.Save();
				}
				break;
			case Gdk.Key.q:
				Application.Quit();
				break;
			}
		} else if ((args.Event.State & Gdk.ModifierType.Mod1Mask) != 0) {
			switch(args.Event.Key) {
			case Gdk.Key.Return:
				if (fullscreened)
					((Window)o).Unfullscreen();
				else
					((Window)o).Fullscreen();
				fullscreened = ! fullscreened;
				break;
			}
		}
		display.Update();
	}
}