[gnome-games: 2/3] gnomine: Port from C to Vala



commit 905f8f3f46cfc41ba7b6e4d308934079a88400c7
Author: Robert Ancell <robert ancell canonical com>
Date:   Wed Oct 26 08:08:41 2011 -0400

    gnomine: Port from C to Vala

 configure.in                                  |    6 +-
 gnomine/Makefile.am                           |   64 +-
 gnomine/data/Makefile.am                      |   62 +-
 gnomine/data/org.gnome.gnomine.gschema.xml.in |    2 +-
 gnomine/src/Makefile.am                       |   70 +-
 gnomine/src/gnomine.c                         | 1129 -------------------
 gnomine/src/gnomine.vala                      |  804 ++++++++++++++
 gnomine/src/minefield-view.vala               |  603 ++++++++++
 gnomine/src/minefield.c                       | 1474 -------------------------
 gnomine/src/minefield.h                       |  124 ---
 gnomine/src/minefield.vala                    |  333 ++++++
 libgames-support/GnomeGamesSupport-1.0.vapi   |    3 +-
 po/POTFILES.in                                |    8 +-
 13 files changed, 1773 insertions(+), 2909 deletions(-)
---
diff --git a/configure.in b/configure.in
index 712dc8c..e82b510 100644
--- a/configure.in
+++ b/configure.in
@@ -848,8 +848,10 @@ gnect/data/Makefile
 gnect/pixmaps/Makefile
 gnect/help/Makefile
 gnomine/Makefile
-gnomine/icons/Makefile
+gnomine/data/Makefile
 gnomine/help/Makefile
+gnomine/icons/Makefile
+gnomine/src/Makefile
 swell-foop/Makefile
 swell-foop/help/Makefile
 mahjongg/Makefile
@@ -912,7 +914,7 @@ gtali/gtali.desktop.in
 gnome-sudoku/gnome-sudoku.desktop.in
 iagno/iagno.desktop.in
 gnect/data/gnect.desktop.in
-gnomine/gnomine.desktop.in
+gnomine/data/gnomine.desktop.in
 lightsoff/Makefile
 lightsoff/help/Makefile
 lightsoff/lightsoff.desktop.in
diff --git a/gnomine/Makefile.am b/gnomine/Makefile.am
index 3cd1396..86983cb 100644
--- a/gnomine/Makefile.am
+++ b/gnomine/Makefile.am
@@ -1,64 +1,10 @@
-SUBDIRS = icons
+SUBDIRS = data icons src
 
 if BUILD_HELP
 SUBDIRS += help
 endif
 
-bin_PROGRAMS = gnomine
-
-gnomine_SOURCES =	\
-	gnomine.c	\
-	minefield.h	\
-	minefield.c
-
-gnomine_CPPFLAGS = \
-	-I$(top_srcdir) \
-	$(AM_CPPFLAGS)
-
-gnomine_CFLAGS = \
-	$(GTK_CFLAGS) \
-	$(AM_CFLAGS)
-
-gnomine_LDADD = \
-	$(top_builddir)/libgames-support/libgames-support.la \
-	$(GTK_LIBS)
-
-if HAVE_GNOME
-gnomine_CFLAGS += $(GNOME_CFLAGS)
-gnomine_LDADD += $(GNOME_LIBS)
-endif
-
-if HAVE_RSVG
-gnomine_CFLAGS += $(RSVG_CFLAGS)
-gnomine_LDADD += $(RSVG_LIBS)
-endif
-
-if WITH_GTHREAD
-gnomine_CFLAGS += $(GHTREAD_CFLAGS)
-gnomine_LDADD += $(GTHREAD_LIBS)
-endif
-
-gsettings_in_file = org.gnome.gnomine.gschema.xml.in
-gsettings_SCHEMAS = $(gsettings_in_file:.xml.in=.xml)
- INTLTOOL_XML_NOMERGE_RULE@
- GSETTINGS_RULES@
-
-man_MANS = gnomine.6
-
-pixmapdir   = $(datadir)/gnome-games/gnomine/pixmaps
-pixmap_DATA = face-cool.svg face-sad.svg face-smile.svg face-win.svg 	\
-	face-worried.svg \
-	flag.svg flag-question.svg mine.svg bang.svg warning.svg
-
-EXTRA_DIST = README AUTHORS \
-             $(gsettings_in_file) \
-             $(man_MANS) \
-             $(pixmap_DATA)
-
-Gamesdir = $(datadir)/applications
-Games_in_files = gnomine.desktop.in.in
-Games_DATA = $(Games_in_files:.desktop.in.in=.desktop)
- INTLTOOL_DESKTOP_RULE@
+EXTRA_DIST = README AUTHORS
 
 SCOREFILES = Small Medium Large Custom
 
@@ -74,11 +20,5 @@ install-data-local:
 	   chmod 664 $(DESTDIR)$(scoredir)/gnomine.$$i.scores; \
 	 done
 
-install-exec-hook:
-	-if test "$(setgid)" = "true"; then \
-	  chgrp $(scores_group) $(DESTDIR)$(bindir)/gnomine && chmod 2555 $(DESTDIR)$(bindir)/gnomine ;\
-	fi
-
-DISTCLEANFILES = $(Games_DATA) $(gsettings_SCHEMAS)
 
 -include $(top_srcdir)/git.mk
diff --git a/gnomine/data/Makefile.am b/gnomine/data/Makefile.am
index 7f79fdf..107b8d8 100644
--- a/gnomine/data/Makefile.am
+++ b/gnomine/data/Makefile.am
@@ -1,43 +1,3 @@
-SUBDIRS = data icons src
-
-if BUILD_HELP
-SUBDIRS += help
-endif
-
-bin_PROGRAMS = gnomine
-
-gnomine_SOURCES =	\
-	gnomine.c	\
-	minefield.h	\
-	minefield.c
-
-gnomine_CPPFLAGS = \
-	-I$(top_srcdir) \
-	$(AM_CPPFLAGS)
-
-gnomine_CFLAGS = \
-	$(GTK_CFLAGS) \
-	$(AM_CFLAGS)
-
-gnomine_LDADD = \
-	$(top_builddir)/libgames-support/libgames-support.la \
-	$(GTK_LIBS)
-
-if HAVE_GNOME
-gnomine_CFLAGS += $(GNOME_CFLAGS)
-gnomine_LDADD += $(GNOME_LIBS)
-endif
-
-if HAVE_RSVG
-gnomine_CFLAGS += $(RSVG_CFLAGS)
-gnomine_LDADD += $(RSVG_LIBS)
-endif
-
-if WITH_GTHREAD
-gnomine_CFLAGS += $(GHTREAD_CFLAGS)
-gnomine_LDADD += $(GTHREAD_LIBS)
-endif
-
 gsettings_in_file = org.gnome.gnomine.gschema.xml.in
 gsettings_SCHEMAS = $(gsettings_in_file:.xml.in=.xml)
 @INTLTOOL_XML_NOMERGE_RULE@
@@ -50,8 +10,7 @@ pixmap_DATA = face-cool.svg face-sad.svg face-smile.svg face-win.svg 	\
 	face-worried.svg \
 	flag.svg flag-question.svg mine.svg bang.svg warning.svg
 
-EXTRA_DIST = README AUTHORS \
-             $(gsettings_in_file) \
+EXTRA_DIST = $(gsettings_in_file) \
              $(man_MANS) \
              $(pixmap_DATA)
 
@@ -60,25 +19,6 @@ Games_in_files = gnomine.desktop.in.in
 Games_DATA = $(Games_in_files:.desktop.in.in=.desktop)
 @INTLTOOL_DESKTOP_RULE@
 
-SCOREFILES = Small Medium Large Custom
-
-install-data-local:
-	-$(mkinstalldirs) $(DESTDIR)$(scoredir)
-	## Change the names of the high score files, unless the local user has 
-	## beaten us to it.
-	-if [ -f $(DESTDIR)$(scoredir)/gnomine.Tiny.scores -a ! -f $(DESTDIR)$(scoredir)/gnomine.Small.scores ]; then mv -f $(DESTDIR)$(scoredir)/gnomine.Tiny.scores $(DESTDIR)$(scoredir)/gnomine.Small.scores  ; fi
-	-if [ -f $(DESTDIR)$(scoredir)/gnomine.Biiiig.scores -a ! -f $(DESTDIR)$(scoredir)/gnomine.Large.scores ]; then mv -f $(DESTDIR)$(scoredir)/gnomine.Biiiig.scores $(DESTDIR)$(scoredir)/gnomine.Large.scores  ; fi
-	-for i in ${SCOREFILES} ; do \
-	   touch $(DESTDIR)$(scoredir)/gnomine.$$i.scores; \
-	   chown $(scores_user):$(scores_group) $(DESTDIR)$(scoredir)/gnomine.$$i.scores; \
-	   chmod 664 $(DESTDIR)$(scoredir)/gnomine.$$i.scores; \
-	 done
-
-install-exec-hook:
-	-if test "$(setgid)" = "true"; then \
-	  chgrp $(scores_group) $(DESTDIR)$(bindir)/gnomine && chmod 2555 $(DESTDIR)$(bindir)/gnomine ;\
-	fi
-
 DISTCLEANFILES = $(Games_DATA) $(gsettings_SCHEMAS)
 
 -include $(top_srcdir)/git.mk
diff --git a/gnomine/data/org.gnome.gnomine.gschema.xml.in b/gnomine/data/org.gnome.gnomine.gschema.xml.in
index 6a090a7..6719ac2 100644
--- a/gnomine/data/org.gnome.gnomine.gschema.xml.in
+++ b/gnomine/data/org.gnome.gnomine.gschema.xml.in
@@ -1,5 +1,5 @@
 <schemalist>
-  <schema id="org.gnome.gnomine" path="/apps/gnomine/" gettext-domain="gnome-games">
+  <schema id="org.gnome.gnomine" path="/org/gnome/gnomine/" gettext-domain="gnome-games">
     <key name="use-question-marks" type="b">
       <default>false</default>
       <_summary>Use the unknown flag</_summary>
diff --git a/gnomine/src/Makefile.am b/gnomine/src/Makefile.am
index 7f79fdf..548a7ed 100644
--- a/gnomine/src/Makefile.am
+++ b/gnomine/src/Makefile.am
@@ -1,24 +1,30 @@
-SUBDIRS = data icons src
-
-if BUILD_HELP
-SUBDIRS += help
-endif
-
 bin_PROGRAMS = gnomine
 
 gnomine_SOURCES =	\
-	gnomine.c	\
-	minefield.h	\
-	minefield.c
-
-gnomine_CPPFLAGS = \
-	-I$(top_srcdir) \
-	$(AM_CPPFLAGS)
+	config.vapi	\
+	gnomine.vala \
+	minefield.vala \
+	minefield-view.vala
 
 gnomine_CFLAGS = \
+	-I$(top_srcdir)/libgames-support \
+	-DVERSION=\"$(VERSION)\" \
+	-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
 	$(GTK_CFLAGS) \
 	$(AM_CFLAGS)
 
+gnomine_VALAFLAGS = \
+	--pkg posix \
+	--pkg gtk+-3.0 \
+	--pkg pango \
+	--pkg pangocairo \
+	--vapidir $(top_srcdir)/libgames-support \
+	--pkg GnomeGamesSupport-1.0
+
+if ENABLE_SETGID
+gnomine_VALAFLAGS += -D ENABLE_SETGID
+endif
+
 gnomine_LDADD = \
 	$(top_builddir)/libgames-support/libgames-support.la \
 	$(GTK_LIBS)
@@ -38,47 +44,9 @@ gnomine_CFLAGS += $(GHTREAD_CFLAGS)
 gnomine_LDADD += $(GTHREAD_LIBS)
 endif
 
-gsettings_in_file = org.gnome.gnomine.gschema.xml.in
-gsettings_SCHEMAS = $(gsettings_in_file:.xml.in=.xml)
- INTLTOOL_XML_NOMERGE_RULE@
- GSETTINGS_RULES@
-
-man_MANS = gnomine.6
-
-pixmapdir   = $(datadir)/gnome-games/gnomine/pixmaps
-pixmap_DATA = face-cool.svg face-sad.svg face-smile.svg face-win.svg 	\
-	face-worried.svg \
-	flag.svg flag-question.svg mine.svg bang.svg warning.svg
-
-EXTRA_DIST = README AUTHORS \
-             $(gsettings_in_file) \
-             $(man_MANS) \
-             $(pixmap_DATA)
-
-Gamesdir = $(datadir)/applications
-Games_in_files = gnomine.desktop.in.in
-Games_DATA = $(Games_in_files:.desktop.in.in=.desktop)
- INTLTOOL_DESKTOP_RULE@
-
-SCOREFILES = Small Medium Large Custom
-
-install-data-local:
-	-$(mkinstalldirs) $(DESTDIR)$(scoredir)
-	## Change the names of the high score files, unless the local user has 
-	## beaten us to it.
-	-if [ -f $(DESTDIR)$(scoredir)/gnomine.Tiny.scores -a ! -f $(DESTDIR)$(scoredir)/gnomine.Small.scores ]; then mv -f $(DESTDIR)$(scoredir)/gnomine.Tiny.scores $(DESTDIR)$(scoredir)/gnomine.Small.scores  ; fi
-	-if [ -f $(DESTDIR)$(scoredir)/gnomine.Biiiig.scores -a ! -f $(DESTDIR)$(scoredir)/gnomine.Large.scores ]; then mv -f $(DESTDIR)$(scoredir)/gnomine.Biiiig.scores $(DESTDIR)$(scoredir)/gnomine.Large.scores  ; fi
-	-for i in ${SCOREFILES} ; do \
-	   touch $(DESTDIR)$(scoredir)/gnomine.$$i.scores; \
-	   chown $(scores_user):$(scores_group) $(DESTDIR)$(scoredir)/gnomine.$$i.scores; \
-	   chmod 664 $(DESTDIR)$(scoredir)/gnomine.$$i.scores; \
-	 done
-
 install-exec-hook:
 	-if test "$(setgid)" = "true"; then \
 	  chgrp $(scores_group) $(DESTDIR)$(bindir)/gnomine && chmod 2555 $(DESTDIR)$(bindir)/gnomine ;\
 	fi
 
-DISTCLEANFILES = $(Games_DATA) $(gsettings_SCHEMAS)
-
 -include $(top_srcdir)/git.mk
diff --git a/gnomine/src/gnomine.vala b/gnomine/src/gnomine.vala
new file mode 100644
index 0000000..0cdb03f
--- /dev/null
+++ b/gnomine/src/gnomine.vala
@@ -0,0 +1,804 @@
+public class GnoMine
+{
+    /* Settings keys */
+    private Settings settings;
+    private const string KEY_XSIZE = "xsize";
+    private const int XSIZE_MIN = 4;
+    private const int XSIZE_MAX = 100;
+    private const string KEY_YSIZE = "ysize";
+    private const int YSIZE_MIN = 4;
+    private const int YSIZE_MAX = 100;
+    private const string KEY_NMINES = "nmines";
+    private const string KEY_MODE = "mode";
+    private const string KEY_USE_QUESTION_MARKS = "use-question-marks";
+    private const string KEY_USE_OVERMINE_WARNING = "use-overmine-warning";
+    private const string KEY_USE_AUTOFLAG = "use-autoflag";
+
+    /* Faces for new game button */
+    private Gtk.Image win_face_image;
+    private Gtk.Image sad_face_image;
+    private Gtk.Image smile_face_image;
+    private Gtk.Image cool_face_image;
+    private Gtk.Image worried_face_image;
+    private Gtk.Image? current_face_image = null;
+
+    /* Main window */
+    private Gtk.Window window;
+
+    /* Minefield widget */
+    private Minefield minefield;
+    private MinefieldView minefield_view;
+
+    private Gtk.Dialog? pref_dialog = null;
+    private Gtk.Button resume_button;
+    private Gtk.Alignment resume_container;
+    private Gtk.Label flag_label;
+    private Gtk.SpinButton n_mines_spin;
+    private Gtk.Button new_game_button;
+    private GnomeGamesSupport.Frame custom_size_frame;
+    private GnomeGamesSupport.Clock clock;
+    private Gtk.Action hint_action;
+    private GnomeGamesSupport.FullscreenAction fullscreen_action;
+    private GnomeGamesSupport.PauseAction pause_action;
+
+    private const GnomeGamesSupport.ScoresCategory scorecats[] =
+    {
+        {"Small",  NC_("board size", "Small") },
+        {"Medium", NC_("board size", "Medium") },
+        {"Large",  NC_("board size", "Large") },
+        {"Custom", NC_("board size", "Custom") }
+    };
+
+    private GnomeGamesSupport.Scores highscores;
+
+    public GnoMine ()
+    {
+        settings = new Settings ("org.gnome.gnomine");
+
+        highscores = new GnomeGamesSupport.Scores ("gnomine", scorecats, "board size", null, 0 /* default category */, GnomeGamesSupport.ScoreStyle.TIME_ASCENDING);
+
+        Gtk.Window.set_default_icon_name ("gnome-mines");
+
+        window = new Gtk.Window (Gtk.WindowType.TOPLEVEL);
+        window.border_width = 6;
+        window.title = _("Mines");
+
+        GnomeGamesSupport.settings_bind_window_state ("/org/gnome/gnomine/", window);
+
+        GnomeGamesSupport.stock_init ();
+
+        window.delete_event.connect (delete_event_cb);
+
+        var main_vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
+        window.add (main_vbox);
+        main_vbox.show ();
+
+        var ui_manager = create_ui_manager ("GnomineActions");
+        window.add_accel_group (ui_manager.get_accel_group ());
+        var menubar = (Gtk.MenuBar) ui_manager.get_widget ("/MainMenu");
+        menubar.show ();
+        main_vbox.pack_start (menubar, false, false, 0);
+
+        var new_game_button_alignment = new Gtk.Alignment (0.5f, 0.5f, 0.0f, 0.0f);
+        main_vbox.pack_start (new_game_button_alignment, false, false, 0);
+        new_game_button_alignment.show ();
+
+        new_game_button = new Gtk.Button ();
+        new_game_button.clicked.connect (new_game);
+        new_game_button_alignment.add (new_game_button);
+        new_game_button.show ();
+
+        var face_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 5);
+        new_game_button.add (face_box);
+        face_box.show ();
+
+        win_face_image = load_face_image ("face-win.svg");
+        sad_face_image = load_face_image ("face-sad.svg");
+        smile_face_image = load_face_image ("face-smile.svg");
+        cool_face_image = load_face_image ("face-cool.svg");
+        worried_face_image = load_face_image ("face-worried.svg");
+
+        face_box.pack_start (win_face_image, false, false, 0);
+        face_box.pack_start (sad_face_image, false, false, 0);
+        face_box.pack_start (smile_face_image, false, false, 0);
+        face_box.pack_start (cool_face_image, false, false, 0);
+        face_box.pack_start (worried_face_image, false, false, 0);
+
+        var separator = new Gtk.HSeparator ();
+        main_vbox.pack_start (separator, false, false, 0);
+        separator.show ();
+
+        minefield_view = new MinefieldView ();
+        minefield_view.set_use_question_marks (settings.get_boolean (KEY_USE_QUESTION_MARKS));
+        minefield_view.set_use_overmine_warning (settings.get_boolean (KEY_USE_OVERMINE_WARNING));
+        minefield_view.set_use_autoflag (settings.get_boolean (KEY_USE_AUTOFLAG));
+        minefield_view.look.connect (look_cb);
+        minefield_view.unlook.connect (unlook_cb);
+        main_vbox.pack_start (minefield_view, true, true, 0);
+        minefield_view.show ();
+
+        resume_container = new Gtk.Alignment (0.5f, 0.5f, 0.0f, 0.0f);
+        main_vbox.pack_start (resume_container, true, true, 0);
+
+        resume_button = new Gtk.Button.with_label (_("Press to Resume"));
+        resume_button.clicked.connect (resume_game_cb);
+        resume_container.add (resume_button);
+        resume_button.show ();
+
+        separator = new Gtk.HSeparator ();
+        main_vbox.pack_start (separator, false, false, 0);
+        separator.show ();
+
+        var status_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
+        status_box.homogeneous = true;
+        main_vbox.pack_start (status_box, false, false, 0);
+        status_box.show ();
+
+        flag_label = new Gtk.Label ("");
+        status_box.pack_start (flag_label, false, false, 0);
+        flag_label.show ();
+
+        var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
+        status_box.pack_start (box, false, false, 0);
+        box.show ();
+
+        var label = new Gtk.Label (_("Time: "));
+        box.pack_start (label, false, false, 0);
+
+        clock = new GnomeGamesSupport.Clock ();
+        box.pack_start (clock, false, false, 0);
+        clock.show ();
+
+        new_game ();
+    }
+
+    public void start ()
+    {
+        window.show ();
+
+        /* All this hiding is a bit ugly, but it's better than a ton of show calls. */
+        resume_container.hide ();
+        win_face_image.hide ();
+        sad_face_image.hide ();
+        cool_face_image.hide ();
+        worried_face_image.hide ();
+
+        set_face_image (smile_face_image);
+    }
+
+    private Gtk.Image load_face_image (string name)
+    {
+        var image = new Gtk.Image ();
+        var dname = GnomeGamesSupport.runtime_get_directory (GnomeGamesSupport.RuntimeDirectory.GAME_PIXMAP_DIRECTORY);
+        var filename = Path.build_filename (dname, name);
+
+        if (filename != null)
+            image.set_from_file (filename);
+
+        return image;
+    }
+
+    private void set_face_image (Gtk.Image face_image)
+    {
+        if (current_face_image == face_image)
+            return;
+
+        if (current_face_image != null)
+            current_face_image.hide ();
+        hint_action.set_sensitive ((face_image == cool_face_image) || (face_image == smile_face_image));
+        face_image.show ();
+
+        current_face_image = face_image;
+    }
+
+    private bool delete_event_cb (Gdk.EventAny event)
+    {
+        Gtk.main_quit ();
+        return false;    
+    }
+
+    private void quit_game_cb ()
+    {
+        Gtk.main_quit ();
+    }
+
+    private void update_flag_label ()
+    {
+        flag_label.set_text ("Flags: %u/%u".printf (minefield.n_flags, minefield.n_mines));
+    }
+
+    /* Show the high scores dialog - creating it if necessary. If pos is
+     * greater than 0 the appropriate score is highlighted. If the score isn't
+     * a high score and this isn't a direct request to see the scores, we
+     * only show a simple dialog. */
+    private int show_scores (int pos, bool endofgame)
+    {
+        if (endofgame && (pos <= 0))
+        {
+            var dialog = new Gtk.MessageDialog.with_markup (window,
+                                                            Gtk.DialogFlags.DESTROY_WITH_PARENT,
+                                                            Gtk.MessageType.INFO,
+                                                            Gtk.ButtonsType.NONE,
+                                                            "<b>%s</b>\n%s",
+                                                            _("The Mines Have Been Cleared!"),
+                                                            _("Great work, but unfortunately your score did not make the top ten."));
+            dialog.add_buttons (Gtk.Stock.QUIT, Gtk.ResponseType.REJECT,
+                                _("_New Game"), Gtk.ResponseType.ACCEPT, null);
+            dialog.set_default_response (Gtk.ResponseType.ACCEPT);
+            dialog.set_title ("");
+            var result = dialog.run ();
+            dialog.destroy ();
+            return result;
+        }
+        else
+        {
+            var dialog = new GnomeGamesSupport.ScoresDialog (window, highscores, _("Mines Scores"));
+            dialog.set_category_description (_("Size:"));
+
+            if (pos > 0)
+            {
+                dialog.set_hilight (pos);
+                var message = "<b>%s</b>\n\n%s".printf (_("Congratulations!"), pos == 1 ? _("Your score is the best!") : _("Your score has made the top ten."));
+                dialog.set_message (message);
+            }
+            else
+                dialog.set_message (null);
+
+            if (endofgame)
+                dialog.set_buttons (GnomeGamesSupport.ScoresButtons.QUIT_BUTTON | GnomeGamesSupport.ScoresButtons.NEW_GAME_BUTTON);
+            else
+                dialog.set_buttons (0);
+            var result = dialog.run ();
+            dialog.destroy ();
+            return result;
+        }
+    }
+
+    private void scores_cb ()
+    {
+        show_scores (0, false);
+    }
+
+    private void new_game ()
+    {
+        if (minefield != null && minefield.n_cleared > 0 && !minefield.exploded && !minefield.is_complete)
+        {
+            var dialog = new Gtk.MessageDialog (window, Gtk.DialogFlags.MODAL, Gtk.MessageType.QUESTION, Gtk.ButtonsType.NONE, "%s", _("Cancel current game?"));
+            dialog.add_buttons (_("Start New Game"), Gtk.ResponseType.ACCEPT,
+                                _("Keep Current Game"), Gtk.ResponseType.REJECT,
+                                null);
+            var result = dialog.run ();
+            dialog.destroy ();
+            if (result == Gtk.ResponseType.REJECT)
+                return;
+        }
+
+        clock.reset ();
+        set_face_image (smile_face_image);
+
+        int x, y, n;
+        var score_key = "";
+        switch (settings.get_int (KEY_MODE))
+        {
+        case 0:
+            x = 8;
+            y = 8;
+            n = 10;
+            score_key = "Small";
+            break;
+        case 1:
+            x = 16;
+            y = 16;
+            n = 40;
+            score_key = "Medium";
+            break;
+        case 2:
+            x = 30;
+            y = 16;
+            n = 99;
+            score_key = "Large";
+            break;
+        default:
+        case 3:
+            x = settings.get_int (KEY_XSIZE).clamp (XSIZE_MIN, XSIZE_MAX);
+            y = settings.get_int (KEY_YSIZE).clamp (YSIZE_MIN, YSIZE_MAX);
+            n = settings.get_int (KEY_NMINES).clamp (1, x * y - 10);
+            score_key = "Custom";
+            break;
+        }
+
+        highscores.set_category (score_key);
+        if (minefield != null)
+            SignalHandler.disconnect_by_func (minefield, null, this);
+        minefield = new Minefield (x, y, n);
+        minefield.marks_changed.connect (marks_changed_cb);
+        minefield.explode.connect (explode_cb);
+        minefield.cleared.connect (cleared_cb);
+
+        minefield_view.minefield = minefield;
+
+        update_flag_label ();
+
+        pause_action.set_sensitive (true);
+        resume_container.hide ();
+        minefield_view.show ();
+    }
+
+    private void hint_cb ()
+    {
+        uint x, y;
+        minefield.hint (out x, out y);
+
+        /* There is a ten second penalty for accepting a hint. */
+        minefield.clear_mine (x, y);
+        clock.add_seconds (10);
+    }
+
+    private void new_game_cb ()
+    {
+        new_game ();
+    }
+
+    private void pause_cb (Gtk.Action action)
+    {
+        if (pause_action.get_is_paused ())
+        {
+            minefield_view.hide ();
+            resume_container.show ();
+            resume_button.grab_focus ();
+
+            hint_action.set_sensitive (false);
+            clock.stop ();
+        }
+        else
+        {
+            resume_container.hide ();
+            minefield_view.show ();
+            hint_action.set_sensitive (true);
+            clock.start ();
+        }
+    }
+
+    private void resume_game_cb (Gtk.Widget widget)
+    {
+        pause_action.set_is_paused (false);
+    }
+
+    private void marks_changed_cb (Minefield minefield)
+    {
+        update_flag_label ();
+        clock.start ();
+    }
+
+    private void explode_cb (Minefield minefield)
+    {
+        set_face_image (sad_face_image);
+
+        new_game_button.grab_focus ();
+
+        clock.stop ();
+    }
+
+    private void cleared_cb (Minefield minefield)
+    {
+        clock.stop ();
+
+        new_game_button.grab_focus ();
+
+        set_face_image (win_face_image);
+
+        var seconds = clock.get_seconds ();
+        var pos = highscores.add_time_score ((float) (seconds / 60) + (float) (seconds % 60) / 100);
+
+        if (show_scores (pos, true) == Gtk.ResponseType.REJECT)
+            Gtk.main_quit ();
+        else
+            new_game ();
+    }
+
+    private void look_cb (MinefieldView minefield_view)
+    {
+        set_face_image (worried_face_image);
+        clock.start ();
+    }
+
+    private void unlook_cb (MinefieldView minefield_view)
+    {
+        set_face_image (cool_face_image);
+    }
+
+    private void about_cb ()
+    {
+        string[] authors =
+        {
+            _("Main game:"),
+            "Szekeres Istvan",
+            "Robert Ancell",
+            "",
+            _("Score:"),
+            "Horacio J. Pe\xc3\xb1a",
+            "",
+            _("Resizing and SVG support:"),
+            "Steve Chaplin",
+            "Callum McKenzie",
+            null
+        };
+
+        string[] artists =
+        {
+            _("Faces:"),
+            "Lapo Calamandrei and Ulisse Perusin",
+            "",
+            _("Graphics:"),
+            "Richard Hoelscher",
+            null
+        };
+
+        string[] documenters =
+        {
+            "Callum McKenzie",
+            null
+        };
+
+        Gtk.show_about_dialog (window,
+                               "name", _("Mines"),
+                               "version", VERSION,
+                               "comments",
+                               _("The popular logic puzzle minesweeper. Clear mines from a board using hints from squares you have already uncovered.\n\nMines is a part of GNOME Games."),
+                               "copyright",
+                               "Copyright \xc2\xa9 1997-2008 Free Software Foundation, Inc.",
+                               "license", GnomeGamesSupport.get_license (_("Mines")),
+                               "authors", authors,
+                               "artists", artists,
+                               "documenters", documenters,
+                               "translator-credits", _("translator-credits"),
+                               "logo-icon-name", "gnomine", "website",
+                               "http://www.gnome.org/projects/gnome-games/";,
+                               "website-label", _("GNOME Games web site"),
+                               "wrap-license", true, null);
+    }
+
+    private void set_n_mines_limit ()
+    {
+        /* Fix up the maximum number of mines so that there is always at least
+         * ten free spaces. Nine are so we can clear at least the immediate
+         * eight neighbours at the start and one more so the game isn't over
+         * immediately. */
+        var max_mines = settings.get_int (KEY_XSIZE) * settings.get_int (KEY_YSIZE) - 10;
+        if (settings.get_int (KEY_NMINES) > max_mines)
+        {
+            settings.set_int (KEY_NMINES, max_mines);
+            n_mines_spin.set_value (max_mines);
+        }
+        n_mines_spin.set_range (1, max_mines);
+    }
+
+    private void xsize_spin_cb (Gtk.SpinButton spin)
+    {
+        var xsize = spin.get_value_as_int ();        
+        if (xsize == settings.get_int (KEY_XSIZE))
+            return;
+
+        settings.set_int (KEY_XSIZE, xsize);
+        set_n_mines_limit ();
+        new_game ();
+    }
+
+    private void ysize_spin_cb (Gtk.SpinButton spin)
+    {
+        var ysize = spin.get_value_as_int ();        
+        if (ysize == settings.get_int (KEY_YSIZE))
+            return;
+
+        settings.set_int (KEY_YSIZE, ysize);
+        set_n_mines_limit ();
+        new_game ();
+    }
+
+    private void n_mines_spin_cb (Gtk.SpinButton spin)
+    {
+        var n_mines = spin.get_value_as_int ();
+        if (n_mines == settings.get_int (KEY_NMINES))
+            return;
+
+        settings.set_int (KEY_NMINES, n_mines);
+        new_game ();
+    }
+
+    private void use_question_toggle_cb (Gtk.ToggleButton button)
+    {
+        var use_question_marks = button.get_active ();
+        settings.set_boolean (KEY_USE_QUESTION_MARKS, use_question_marks);
+        minefield_view.set_use_question_marks (use_question_marks);
+    }
+
+    private void use_overmine_toggle_cb (Gtk.ToggleButton button)
+    {
+        var use_overmine_warning = button.get_active ();
+        settings.set_boolean (KEY_USE_OVERMINE_WARNING, use_overmine_warning);
+        minefield_view.set_use_overmine_warning (use_overmine_warning);
+    }
+
+    private Gtk.Dialog create_preferences ()
+    {
+        var table = new Gtk.Table (3, 2, false);
+        table.border_width = 5;
+        table.set_row_spacings (18);
+        table.set_col_spacings (18);
+
+        var frame = new GnomeGamesSupport.Frame (_("Field Size"));
+
+        var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
+
+        var small_button = new Gtk.RadioButton.with_mnemonic (null, dpgettext2 (null, "board size", "_Small"));
+        small_button.toggled.connect (small_size_toggled_cb);
+        vbox.pack_start (small_button, false, false, 0);
+
+        var medium_button = new Gtk.RadioButton.with_mnemonic (small_button.get_group (), dpgettext2 (null, "board size", "_Medium"));
+        medium_button.toggled.connect (medium_size_toggled_cb);
+        vbox.pack_start (medium_button, false, false, 0);
+
+        var large_button = new Gtk.RadioButton.with_mnemonic (medium_button.get_group (), dpgettext2 (null, "board size", "_Large"));
+        large_button.toggled.connect (large_size_toggled_cb);
+        vbox.pack_start (large_button, false, false, 0);
+
+        var custom_button = new Gtk.RadioButton.with_mnemonic (large_button.get_group (), dpgettext2 (null, "board size", "_Custom"));
+        custom_button.toggled.connect (custom_size_toggled_cb);
+        vbox.pack_start (custom_button, false, false, 0);
+
+        switch (settings.get_int (KEY_MODE))
+        {
+        case 0:
+            small_button.active = true;
+            break;
+        case 1:
+            medium_button.active = true;
+            break;
+        case 2:
+            large_button.active = true;
+            break;
+        default:
+        case 3:
+            custom_button.active = true;
+            break;
+        }
+
+        frame.add (vbox);
+
+        table.attach_defaults (frame, 0, 1, 0, 1);
+
+        custom_size_frame = new GnomeGamesSupport.Frame (_("Custom Size"));
+        custom_size_frame.sensitive = settings.get_int (KEY_MODE) == 3;
+
+        var custom_field_table = new Gtk.Table (2, 2, false);
+        custom_field_table.set_row_spacings (6);
+        custom_field_table.set_col_spacings (12);
+        custom_size_frame.add (custom_field_table);
+
+        var label = new Gtk.Label.with_mnemonic (_("_Number of mines:"));
+        label.set_alignment (0, 0.5f);
+        custom_field_table.attach (label, 0, 1, 2, 3, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0);
+
+        n_mines_spin = new Gtk.SpinButton.with_range (1, XSIZE_MAX * YSIZE_MAX, 1);
+        n_mines_spin.value_changed.connect (n_mines_spin_cb);
+        n_mines_spin.set_value (settings.get_int (KEY_NMINES));
+        custom_field_table.attach (n_mines_spin, 1, 2, 2, 3, 0, 0, 0, 0);
+        set_n_mines_limit ();
+        label.set_mnemonic_widget (n_mines_spin);
+
+        label = new Gtk.Label.with_mnemonic (_("_Horizontal:"));
+        label.set_alignment (0, 0.5f);
+        custom_field_table.attach (label, 0, 1, 0, 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0);
+
+        var field_width_entry = new Gtk.SpinButton.with_range (XSIZE_MIN, XSIZE_MAX, 1);
+        field_width_entry.value_changed.connect (xsize_spin_cb);
+        field_width_entry.set_value (settings.get_int (KEY_XSIZE));
+        custom_field_table.attach (field_width_entry, 1, 2, 0, 1, 0, 0, 0, 0);
+        label.set_mnemonic_widget (field_width_entry);
+
+        label = new Gtk.Label.with_mnemonic (_("_Vertical:"));
+        label.set_alignment (0, 0.5f);
+        custom_field_table.attach (label, 0, 1, 1, 2, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0);
+
+        var field_height_entry = new Gtk.SpinButton.with_range (YSIZE_MIN, YSIZE_MAX, 1);
+        field_height_entry.value_changed.connect (ysize_spin_cb);
+        field_height_entry.set_value (settings.get_int (KEY_YSIZE));
+        custom_field_table.attach (field_height_entry, 1, 2, 1, 2, 0, 0, 0, 0);
+        label.set_mnemonic_widget (field_height_entry);
+
+        table.attach (custom_size_frame, 1, 2, 0, 1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL, 0, 0);
+
+        frame = new GnomeGamesSupport.Frame (_("Flags"));
+        table.attach_defaults (frame, 0, 2, 1, 2);
+        
+        var flag_options_vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
+        flag_options_vbox.show ();
+        frame.add (flag_options_vbox);
+
+        var question_toggle = new Gtk.CheckButton.with_mnemonic (_("_Use \"I'm not sure\" flags"));
+        question_toggle.toggled.connect (use_question_toggle_cb);
+        question_toggle.set_active (settings.get_boolean (KEY_USE_QUESTION_MARKS));
+        flag_options_vbox.pack_start (question_toggle, false, true, 0);
+
+        var overmine_toggle = new Gtk.CheckButton.with_mnemonic (_("_Warn if too many flags placed"));
+        overmine_toggle.toggled.connect (use_overmine_toggle_cb);
+        overmine_toggle.set_active (settings.get_boolean (KEY_USE_OVERMINE_WARNING));
+        flag_options_vbox.pack_start (overmine_toggle, false, true, 0);
+
+        var dialog = new Gtk.Dialog.with_buttons (_("Mines Preferences"),
+                                                  window,
+                                                  0,
+                                                  Gtk.Stock.CLOSE,
+                                                  Gtk.ResponseType.CLOSE, null);
+        dialog.set_border_width (5);
+        dialog.set_resizable (false);
+        var box = (Gtk.Box) dialog.get_content_area ();
+        box.set_spacing (2);
+        box.pack_start (table, false, false, 0);
+
+        dialog.response.connect (pref_response_cb);
+        dialog.delete_event.connect (pref_delete_event_cb);
+
+        table.show_all ();
+
+        return dialog;
+    }
+    
+    private void set_mode (int mode)
+    {
+        if (mode == settings.get_int (KEY_MODE))
+            return;
+
+        settings.set_int (KEY_MODE, mode);
+        custom_size_frame.sensitive = mode == 3;
+        new_game ();
+    }
+
+    private void small_size_toggled_cb (Gtk.ToggleButton button)
+    {
+        if (button.active)
+            set_mode (0);
+    }
+
+    private void medium_size_toggled_cb (Gtk.ToggleButton button)
+    {
+        if (button.active)
+            set_mode (1);
+    }
+
+    private void large_size_toggled_cb (Gtk.ToggleButton button)
+    {
+        if (button.active)
+            set_mode (2);
+    }
+
+    private void custom_size_toggled_cb (Gtk.ToggleButton button)
+    {
+        if (button.active)
+            set_mode (3);
+    }
+    
+    private void pref_response_cb (Gtk.Dialog dialog, int response_id)
+    {
+        pref_dialog.hide ();
+    }
+
+    private bool pref_delete_event_cb (Gtk.Widget widget, Gdk.EventAny event)
+    {
+        pref_dialog.hide ();
+        return true;
+    }
+
+    private void preferences_cb ()
+    {
+        if (pref_dialog == null)
+            pref_dialog = create_preferences ();
+        pref_dialog.present ();
+    }
+
+    private void help_cb ()
+    {
+        GnomeGamesSupport.help_display (window, "gnomine", null);
+    }
+
+    private const Gtk.ActionEntry actions[] =
+    {
+        {"GameMenu", null, N_("_Game")},
+        {"SettingsMenu", null, N_("_Settings")},
+        {"HelpMenu", null, N_("_Help")},
+        {"NewGame", GnomeGamesSupport.STOCK_NEW_GAME, null, null, null, new_game_cb},
+        {"Hint", GnomeGamesSupport.STOCK_HINT, null, null, null, hint_cb},
+        {"Scores", GnomeGamesSupport.STOCK_SCORES, null, null, null, scores_cb},
+        {"Quit", Gtk.Stock.QUIT, null, null, null, quit_game_cb},
+        {"Preferences", Gtk.Stock.PREFERENCES, null, null, null, preferences_cb},
+        {"Contents", GnomeGamesSupport.STOCK_CONTENTS, null, null, null, help_cb},
+        {"About", Gtk.Stock.ABOUT, null, null, null, about_cb}
+    };
+
+    private const string ui_description =
+        "<ui>" +
+        "    <menubar name='MainMenu'>" +
+        "        <menu action='GameMenu'>" +
+        "            <menuitem action='NewGame'/>" +
+        "            <menuitem action='Hint'/>" +
+        "            <menuitem action='PauseGame'/>" +
+        "            <separator/>" +
+        "            <menuitem action='Scores'/>" +
+        "            <separator/>" +
+        "            <menuitem action='Quit'/>" +
+        "        </menu>" +
+        "        <menu action='SettingsMenu'>" +
+        "            <menuitem action='Fullscreen'/>" +
+        "            <menuitem action='Preferences'/>" +
+        "        </menu>" +
+        "        <menu action='HelpMenu'>" +
+        "            <menuitem action='Contents'/>" +
+        "            <menuitem action='About'/>" +
+        "        </menu>" +
+        "    </menubar>" +
+        "</ui>";
+
+    private Gtk.UIManager create_ui_manager (string group)
+    {
+        var action_group = new Gtk.ActionGroup ("group");
+        action_group.set_translation_domain (GETTEXT_PACKAGE);
+        action_group.add_actions (actions, this);
+
+        var ui_manager = new Gtk.UIManager ();
+        ui_manager.insert_action_group (action_group, 0);
+        try
+        {
+            ui_manager.add_ui_from_string (ui_description, -1);
+        }
+        catch (Error e)
+        {
+        }
+        hint_action = action_group.get_action ("Hint");
+
+        fullscreen_action = new GnomeGamesSupport.FullscreenAction ("Fullscreen", window);
+        action_group.add_action_with_accel (fullscreen_action, null);
+
+        pause_action = new GnomeGamesSupport.PauseAction ("PauseGame");
+        pause_action.state_changed.connect (pause_cb);
+        action_group.add_action_with_accel (pause_action, null);
+
+        return ui_manager;
+    }
+
+    public static int main (string[] args)
+    {
+        if (!GnomeGamesSupport.runtime_init ("gnomine"))
+            return 1;
+
+#if ENABLE_SETGID
+        GnomeGamesSupport.setgid_io_init ();
+#endif
+
+        var context = new OptionContext ("");
+        context.set_translation_domain (GETTEXT_PACKAGE);
+        context.add_group (Gtk.get_option_group (true));
+
+        try
+        {
+            context.parse (ref args);
+        }
+        catch (Error e)
+        {
+            stderr.printf ("%s\n", e.message);
+            return Posix.EXIT_FAILURE;
+        }
+
+        Environment.set_application_name (_("Mines"));
+
+        var app = new GnoMine ();
+        app.start ();
+
+        Gtk.main ();
+
+        Settings.sync ();
+
+        GnomeGamesSupport.runtime_shutdown ();
+
+        return Posix.EXIT_SUCCESS;
+    }
+}
diff --git a/gnomine/src/minefield-view.vala b/gnomine/src/minefield-view.vala
new file mode 100644
index 0000000..a3bdb8b
--- /dev/null
+++ b/gnomine/src/minefield-view.vala
@@ -0,0 +1,603 @@
+public class MinefieldView : Gtk.Widget
+{
+    /* true if allowed to mark locations with question marks */
+    private bool use_question_marks;
+
+    /* true if should warn when too many flags set */
+    private bool use_overmine_warning;
+
+    /* true if automatically set flags on middle click */
+    private bool use_autoflag;
+
+    /* Location being clicked on */
+    private int selected_x = -1;
+    private int selected_y = -1;
+
+    /* Images for flags and mines */
+    private GnomeGamesSupport.Preimage flag_preimage;
+    private GnomeGamesSupport.Preimage mine_preimage;
+    private GnomeGamesSupport.Preimage question_preimage;
+    private GnomeGamesSupport.Preimage bang_preimage;
+    private GnomeGamesSupport.Preimage warning_preimage;
+
+    /* Pre-rendered images */
+    private uint render_size = 0;
+    private Cairo.Pattern? flag_pattern;
+    private Cairo.Pattern? mine_pattern;
+    private Cairo.Pattern? question_pattern;
+    private Cairo.Pattern? bang_pattern;
+    private Cairo.Pattern? warning_pattern;
+    private Cairo.Pattern[] number_patterns;
+
+    private uint mine_size
+    {
+        get
+        {
+            return int.min (get_allocated_width () / (int) minefield.width, get_allocated_height () / (int) minefield.height);
+        }
+    }
+
+    private uint minimum_size
+    {
+        get
+        {
+            var w = 320 / minefield.width;
+            var h = 200 / minefield.height;
+            var s = uint.min (w, h);
+            if (s < 20)
+                s = 20;
+            return s;
+        }
+    }
+
+    public signal void look ();
+    public signal void unlook ();
+
+    public MinefieldView ()
+    {
+        var pixmap_dir = GnomeGamesSupport.runtime_get_directory (GnomeGamesSupport.RuntimeDirectory.GAME_PIXMAP_DIRECTORY);
+        flag_preimage = load_preimage (Path.build_filename (pixmap_dir, "flag.svg"));
+        mine_preimage = load_preimage (Path.build_filename (pixmap_dir, "mine.svg"));
+        question_preimage = load_preimage (Path.build_filename (pixmap_dir, "flag-question.svg"));
+        bang_preimage = load_preimage (Path.build_filename (pixmap_dir, "bang.svg"));
+        warning_preimage = load_preimage (Path.build_filename (pixmap_dir, "warning.svg"));
+        number_patterns = new Cairo.Pattern[8];
+    }
+    
+    private Minefield _minefield;
+    public Minefield minefield
+    {
+        get { return _minefield; }
+        set
+        {
+            if (_minefield != null)
+                SignalHandler.disconnect_by_func (_minefield, null, this);
+            _minefield = value;
+            selected_x = -1;
+            selected_y = -1;
+            _minefield.redraw_sector.connect (redraw_sector_cb);
+            _minefield.explode.connect (explode_cb);
+            queue_resize ();
+        }
+    }
+
+    public void set_use_question_marks (bool use_question_marks)
+    {
+        this.use_question_marks = use_question_marks;
+    }
+
+    public void set_use_overmine_warning (bool use_overmine_warning)
+    {
+        this.use_overmine_warning = use_overmine_warning;
+        queue_draw ();
+    }
+
+    public void set_use_autoflag (bool use_autoflag)
+    {
+        this.use_autoflag = use_autoflag;
+    }
+
+    private void explode_cb (Minefield minefield)
+    {
+        /* Show the mines that we missed or the flags that were wrong */
+        for (var x = 0; x < minefield.width; x++)
+            for (var y = 0; y < minefield.height; y++)
+                if (minefield.has_mine (x, y) || (!minefield.has_mine (x, y) && minefield.get_flag (x, y) == FlagType.FLAG))
+                    redraw_sector_cb (x, y);
+    }
+
+    private GnomeGamesSupport.Preimage? load_preimage (string filename)
+    {
+        try
+        {
+            return new GnomeGamesSupport.Preimage.from_file (filename);
+        }
+        catch (Error e)
+        {
+            return null;
+        }
+    }
+
+    private Cairo.Pattern render_preimage_pattern (GnomeGamesSupport.Preimage preimage)
+    {
+        var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, (int) mine_size, (int) mine_size);
+        var c = new Cairo.Context (surface);
+        var pixbuf = preimage.render ((int) mine_size - 2, (int) mine_size - 2);
+        Gdk.cairo_set_source_pixbuf (c, pixbuf, 1, 1);
+        c.paint ();
+
+        var pattern = new Cairo.Pattern.for_surface (surface);
+        pattern.set_extend (Cairo.Extend.REPEAT);
+        return pattern;
+    }
+    
+    private Cairo.Pattern render_number_pattern (uint n)
+    {
+        var layout = create_pango_layout ("%u".printf (n));
+        layout.set_alignment (Pango.Alignment.CENTER);
+
+        /* set attributes for the layout */
+        var attributes = new Pango.AttrList ();
+
+        /* Color */
+        Pango.Attribute color_attribute;
+        switch (n)
+        {
+        case 1:
+            color_attribute = Pango.attr_foreground_new (0x0000, 0x0000, 0xffff); /* Blue */
+            break;
+        case 2:
+            color_attribute = Pango.attr_foreground_new (0x0000, 0xa0a0, 0x0000); /* Green */
+            break;
+        case 3:
+            color_attribute = Pango.attr_foreground_new (0xffff, 0x0000, 0x0000); /* Red */
+            break;
+        case 4:
+            color_attribute = Pango.attr_foreground_new (0x0000, 0x0000, 0x7fff); /* Dark Blue */
+            break;
+        case 5:
+            color_attribute = Pango.attr_foreground_new (0xa0a0, 0x0000, 0x0000); /* Dark Red */
+            break;
+        case 6:
+            color_attribute = Pango.attr_foreground_new (0x0000, 0xffff, 0xffff); /* Cyan */
+            break;
+        case 7:
+            color_attribute = Pango.attr_foreground_new (0xa0a0, 0x0000, 0xa0a0); /* Dark Violet */
+            break;
+        default:
+        case 8:
+            color_attribute = Pango.attr_foreground_new (0x0000, 0x0000, 0x0000); /* Black */
+            break;
+        }
+        color_attribute.start_index = 0;
+        color_attribute.end_index = uint.MAX;
+        attributes.insert ((owned) color_attribute);
+
+        var font_desc = new Pango.FontDescription ();
+        font_desc.set_family ("Sans");
+        var font_size = (mine_size - 2) * Pango.SCALE * 0.85;
+        font_desc.set_absolute_size (font_size);
+        font_desc.set_weight (Pango.Weight.BOLD);
+        var font_attribute = new Pango.AttrFontDesc (font_desc);
+        font_attribute.start_index = 0;
+        font_attribute.end_index = uint.MAX;
+        attributes.insert ((owned) font_attribute);
+
+        layout.set_attributes (attributes);
+
+        var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, (int) mine_size, (int) mine_size);
+        var c = new Cairo.Context (surface);
+        Pango.Rectangle extent;
+        layout.get_extents (null, out extent);
+        var dx = ((int) mine_size - 2 - extent.width / Pango.SCALE) / 2 + 1;
+        var dy = ((int) mine_size - 2 - extent.height / Pango.SCALE) / 2 + 1;
+        c.move_to (dx, dy);
+        Pango.cairo_show_layout (c, layout);
+
+        var pattern = new Cairo.Pattern.for_surface (surface);
+        pattern.set_extend (Cairo.Extend.REPEAT);
+        return pattern;
+    }
+
+    public override void realize ()
+    {
+        set_realized (true);
+
+        Gtk.Allocation allocation;
+        get_allocation (out allocation);
+
+        var attributes = Gdk.WindowAttr ();
+        attributes.window_type = Gdk.WindowType.CHILD;
+        attributes.x = allocation.x;
+        attributes.y = allocation.y;
+        attributes.width = allocation.width;
+        attributes.height = allocation.height;
+        attributes.wclass = Gdk.WindowWindowClass.OUTPUT;
+        attributes.visual = get_visual ();
+        attributes.event_mask = get_events ();
+        attributes.event_mask |= Gdk.EventMask.EXPOSURE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK;
+
+        var window = new Gdk.Window (get_parent_window (), attributes, Gdk.WindowAttributesType.X | Gdk.WindowAttributesType.Y | Gdk.WindowAttributesType.VISUAL);
+        set_window (window);
+        window.set_user_data (this);
+
+        var style = get_style ().attach (window);
+        set_style (style);
+        style.set_background (window, Gtk.StateType.ACTIVE);
+    }
+
+    /* The frame makes sure that the minefield is allocated the correct size */
+    /* This is the standard allocate routine - it could be removed and the parents routine inherited */
+    public override void size_allocate (Gtk.Allocation allocation)
+    {
+        set_allocation (allocation);
+        if (get_realized ())
+        {
+            var width = minefield.width * mine_size;
+            var height = minefield.height * mine_size;
+            var x = allocation.x + (allocation.width - width) / 2;
+            var y = allocation.y + (allocation.height - height) / 2;
+
+            get_window ().move_resize ((int) x, (int) y, (int) width, (int) height);
+        }
+    }
+    
+    public override void get_preferred_width (out int minimum, out int natural)
+    {
+        minimum = natural = (int) (minefield.width * minimum_size);
+    }
+
+    public override void get_preferred_height (out int minimum, out int natural)
+    {
+        minimum = natural = (int) (minefield.height * minimum_size);
+    }
+
+    private void redraw_sector_cb (uint x, uint y)
+    {
+        queue_draw_area ((int) (x * mine_size), (int) (y * mine_size), (int) mine_size, (int) mine_size);
+    }
+    
+    private void draw_square (Cairo.Context cr, uint x, uint y)
+    {
+        /* Work out if the cursor is being held down on this square */
+        var is_down = x == selected_x && y == selected_y && minefield.get_flag (x, y) != FlagType.FLAG;
+        if (selected_x >= 0 && minefield.is_cleared (selected_x, selected_y))
+        {
+            foreach (var neighbour in neighbour_map)
+            {
+                var nx = selected_x + neighbour.x;
+                var ny = selected_y + neighbour.y;
+                if (!minefield.is_location (nx, ny))
+                    continue;
+                if (x == nx && y == ny && minefield.get_flag (nx, ny) != FlagType.FLAG)
+                    is_down = true;
+            }
+        }
+
+        /* Draw grid on ocean floor */
+        if (minefield.is_cleared (x, y))
+        {
+            Gtk.paint_box (get_style (), cr, is_down ? Gtk.StateType.ACTIVE : Gtk.StateType.NORMAL, Gtk.ShadowType.IN, this,
+                           "button", (int) (x * mine_size), (int) (y * mine_size), (int) mine_size, (int) mine_size);
+
+            /* Draw dotted border */
+            if (y == 0)
+            {
+                cr.move_to (x * mine_size, 0);
+                cr.line_to (x * mine_size + mine_size - 1, 0);
+            }
+            if (x == 0)
+            {
+                cr.move_to (0, y * mine_size);
+                cr.line_to (0, y * mine_size + mine_size - 1);
+            }
+            cr.move_to (x * mine_size + mine_size - 1 + 0.5, y * mine_size + 0.5);
+            cr.line_to (x * mine_size + mine_size - 1 + 0.5, y * mine_size + mine_size - 1 + 0.5);
+            cr.move_to (x * mine_size + 0.5, y * mine_size + mine_size - 1 + 0.5);
+            cr.line_to (x * mine_size + mine_size - 1 + 0.5, y * mine_size + mine_size - 1 + 0.5);
+            cr.save ();
+            Gdk.cairo_set_source_color (cr, get_style ().dark[get_state ()]);
+            cr.set_line_width (1);
+            double[] dots = {2, 2};
+            cr.set_dash (dots, 0);
+            cr.stroke ();
+            cr.restore ();
+
+            /* Draw explosion if have uncovered a mine */
+            if (minefield.has_mine (x, y))
+            {
+                if (bang_pattern == null)
+                    bang_pattern = render_preimage_pattern (bang_preimage);
+                cr.set_source (bang_pattern);
+                cr.rectangle (x * mine_size, y * mine_size, mine_size, mine_size);
+                cr.fill ();
+            }
+            /* Indicate the number of mines around this location */
+            else
+            {
+                /* Warn if more flags than the number of mines available */
+                if (use_overmine_warning && minefield.has_flag_warning (x, y))
+                {
+                    if (warning_pattern == null)
+                        warning_pattern = render_preimage_pattern (warning_preimage);
+                    cr.set_source (warning_pattern);
+                    cr.rectangle (x * mine_size, y * mine_size, mine_size, mine_size);
+                    cr.fill ();
+                }
+
+                var n = minefield.get_n_adjacent_mines (x, y);
+                if (n != 0)
+                {
+                    if (number_patterns[n-1] == null)
+                        number_patterns[n-1] = render_number_pattern (n);
+                    cr.set_source (number_patterns[n-1]);
+                    cr.rectangle (x * mine_size, y * mine_size, mine_size, mine_size);
+                    cr.fill ();
+                }
+            }
+        }
+        else
+        {
+            /* Draw shadow around possible mine location */
+            Gtk.paint_box (get_style (), cr,
+                           is_down ? Gtk.StateType.ACTIVE : Gtk.StateType.SELECTED,
+                           is_down ? Gtk.ShadowType.IN : Gtk.ShadowType.OUT,
+                           this,
+                           "button", (int) (x * mine_size), (int) (y * mine_size), (int) mine_size, (int) mine_size);
+
+            /* Draw flags on uncleared locations */
+            if (minefield.get_flag (x, y) == FlagType.FLAG)
+            {
+                if (flag_pattern == null)
+                    flag_pattern = render_preimage_pattern (flag_preimage);                    
+                cr.set_source (flag_pattern);
+                cr.rectangle (x * mine_size, y * mine_size, mine_size, mine_size);
+                cr.fill ();
+
+                /* Cross out incorrect flags */
+                if (minefield.exploded && !minefield.has_mine (x, y))
+                {
+                    var x1 = x * mine_size + 0.1 * mine_size;
+                    var y1 = y * mine_size + 0.1 * mine_size;
+                    var x2 = x * mine_size + 0.9 * mine_size;
+                    var y2 = y * mine_size + 0.9 * mine_size;
+
+                    cr.move_to (x1, y1);
+                    cr.line_to (x2, y2);
+                    cr.move_to (x1, y2);
+                    cr.line_to (x2, y1);
+
+                    cr.save ();
+                    Gdk.cairo_set_source_color (cr, get_style ().black);
+                    cr.set_line_width (double.max (1, 0.1 * mine_size));
+                    cr.set_line_join (Cairo.LineJoin.ROUND);
+                    cr.set_line_cap (Cairo.LineCap.ROUND);
+                    cr.stroke ();
+                    cr.restore ();
+                }
+            }
+            else if (minefield.exploded && minefield.has_mine (x, y))
+            {
+                if (mine_pattern == null)
+                    mine_pattern = render_preimage_pattern (mine_preimage);
+                cr.set_source (mine_pattern);
+                cr.rectangle (x * mine_size, y * mine_size, mine_size, mine_size);
+                cr.fill ();
+            }
+            else if (minefield.get_flag (x, y) == FlagType.MAYBE)
+            {
+                if (question_pattern == null)
+                    question_pattern = render_preimage_pattern (question_preimage);
+                cr.set_source (question_pattern);
+                cr.rectangle (x * mine_size, y * mine_size, mine_size, mine_size);
+                cr.fill ();
+            }
+        }
+    }
+
+    public override bool draw (Cairo.Context cr)
+    {
+        /* Resize images */
+        if (render_size != mine_size)
+        {
+            render_size = mine_size;
+            flag_pattern = null;
+            mine_pattern = null;
+            question_pattern = null;
+            bang_pattern = null;
+            warning_pattern = null;
+            for (var i = 0; i < number_patterns.length; i++)
+                number_patterns[i] = null;
+        }
+
+        for (var x = 0; x < minefield.width; x++)
+            for (var y = 0; y < minefield.height; y++)
+                draw_square (cr, x, y);
+
+        return false;
+    }
+
+    private void toggle_mark (uint x, uint y)
+    {
+        switch (minefield.get_flag (x, y))
+        {
+        case FlagType.NONE:
+            /* If we've used all the flags don't plant any more,
+             * this should be an indication to the player that they
+             * have made a mistake. */
+            if (minefield.n_flags >= minefield.n_mines && use_question_marks)
+                minefield.set_flag (x, y, FlagType.MAYBE);
+            else
+                minefield.set_flag (x, y, FlagType.FLAG);
+            break;
+
+        case FlagType.MAYBE:
+            minefield.set_flag (x, y, FlagType.NONE);
+            break;
+
+        case FlagType.FLAG:
+            if (use_question_marks)
+                minefield.set_flag (x, y, FlagType.MAYBE);
+            else
+                minefield.set_flag (x, y, FlagType.NONE);
+            break;
+        }
+    }
+
+    private void redraw_adjacent (uint x, uint y)
+    {
+        foreach (var neighbour in neighbour_map)
+        {
+            var nx = x + neighbour.x;
+            var ny = y + neighbour.y;
+            if (minefield.is_location (nx, ny))
+                redraw_sector_cb (nx, ny);
+        }
+    }
+
+    private void multi_release (uint x, uint y)
+    {
+        if (!minefield.is_cleared (x, y) || minefield.get_flag (x, y) == FlagType.FLAG)
+            return;
+
+        /* Work out how many flags / unknown squares surround this one */
+        var n_mines = minefield.get_n_adjacent_mines (x, y);
+        uint n_flags = 0;
+        uint n_unknown = 0;
+        foreach (var neighbour in neighbour_map)
+        {
+            var nx = x + neighbour.x;
+            var ny = y + neighbour.y;
+            if (!minefield.is_location (nx, ny))
+                continue;
+            if (minefield.get_flag (nx, ny) == FlagType.FLAG)
+                n_flags++;
+            if (!minefield.is_cleared (nx, ny))
+                n_unknown++;
+        }
+
+        /* If have correct number of flags to mines then clear the other
+         * locations, otherwise if the number of unknown squares is the
+         * same as the number of mines flag them all */
+        var do_clear = false;
+        if (n_mines == n_flags)
+            do_clear = true;
+        else if (use_autoflag && n_unknown == n_mines)
+            do_clear = false;        
+        else
+            return;
+
+        /* Use the same minefield for the whole time (it may complete as we do it) */
+        var m = minefield;
+
+        foreach (var neighbour in neighbour_map)
+        {
+            var nx = x + neighbour.x;
+            var ny = y + neighbour.y;
+            if (!m.is_location (nx, ny))
+                continue;
+            
+            if (do_clear && m.get_flag (nx, ny) != FlagType.FLAG)
+                m.clear_mine (nx, ny);
+            else
+                m.set_flag (nx, ny, FlagType.FLAG);
+        }
+    }
+
+    public override bool button_press_event (Gdk.EventButton event)
+    {
+        /* Ignore double click events */
+        if (event.type != Gdk.EventType.BUTTON_PRESS)
+            return false;
+            
+        if (minefield.exploded || minefield.is_complete)
+            return false;
+
+        var x = (int) (event.x / mine_size);
+        var y = (int) (event.y / mine_size);
+        if (!minefield.is_location (x, y))
+            return false;
+
+        /* Right or Ctrl+Left button to toggle flags */
+        if (event.button == 3 || (event.button == 1 && (event.state & Gdk.ModifierType.CONTROL_MASK) != 0))
+        {
+            toggle_mark (x, y);
+            return false;
+        }
+
+        /* Left button to clear */
+        if (event.button == 1)
+        {
+            selected_x = x;
+            selected_y = y;
+            redraw_sector_cb (x, y);
+
+            look ();
+
+            if (minefield.is_cleared (x, y))
+                redraw_adjacent (x, y);
+        }
+
+        return false;
+    }
+
+    public override bool motion_notify_event (Gdk.EventMotion event)
+    {
+        if (minefield.exploded || minefield.is_complete)
+            return false;
+            
+        if (selected_x < 0)
+            return false;
+
+        var x = (int) (event.x / mine_size);
+        var y = (int) (event.y / mine_size);
+        if (!minefield.is_location (x, y))
+            return false;
+
+        if (x == selected_x && y == selected_y)
+            return false;
+
+        /* Redraw existing selected squares */
+        redraw_sector_cb (selected_x, selected_y);
+        if (minefield.is_cleared (selected_x, selected_y))
+            redraw_adjacent (selected_x, selected_y);
+
+        /* Draw new selected squares */
+        redraw_sector_cb (x, y);
+        if (minefield.is_cleared (x, y))
+            redraw_adjacent (x, y);
+
+        selected_x = x;
+        selected_y = y;
+
+        return false;
+    }
+
+    public override bool button_release_event (Gdk.EventButton event)
+    {
+        if (minefield.exploded || minefield.is_complete)
+            return false;
+
+        if (selected_x < 0)
+            return false;
+
+        if (event.button == 1)
+        {
+            unlook ();
+
+            if (minefield.is_cleared (selected_x, selected_y))
+            {
+                multi_release (selected_x, selected_y);
+                redraw_adjacent (selected_x, selected_y);
+            }
+            else if (minefield.get_flag (selected_x, selected_y) != FlagType.FLAG)
+                minefield.clear_mine (selected_x, selected_y);
+            redraw_sector_cb (selected_x, selected_y);
+        }
+
+        selected_x = -1;
+        selected_y = -1;
+
+        return false;
+    }
+}
diff --git a/gnomine/src/minefield.vala b/gnomine/src/minefield.vala
new file mode 100644
index 0000000..4760b25
--- /dev/null
+++ b/gnomine/src/minefield.vala
@@ -0,0 +1,333 @@
+public enum FlagType
+{
+    NONE,
+    FLAG,
+    MAYBE
+}
+
+private class Location
+{
+    /* true if contains a mine */
+    public bool has_mine = false;
+    
+    /* true if cleared */
+    public bool cleared = false;
+
+    /* Flag */
+    public FlagType flag = FlagType.NONE;
+}
+
+/* Table of offsets to adjacent squares */
+private struct Neighbour
+{
+    public int x;
+    public int y;
+}
+private static const Neighbour neighbour_map[] =
+{
+    {-1, 1},
+    {0, 1},
+    {1, 1},
+    {1, 0},
+    {1, -1},
+    {0, -1},
+    {-1, -1},
+    {-1, 0}
+};
+
+public class Minefield
+{
+    /* Size of map */
+    public uint width = 0;
+    public uint height = 0;
+    
+    /* Number of mines in map */
+    public uint n_mines = 0;
+
+    /* State of each location */
+    private Location[,] locations;
+
+    /* true if have hit a mine */
+    public bool exploded = false;
+
+    /* true if have placed the mines onto the map */
+    private bool placed_mines = false;
+
+    public uint n_cleared
+    {
+        get
+        {
+            var n = 0;
+            for (var x = 0; x < width; x++)
+                for (var y = 0; y < height; y++)
+                    if (locations[x, y].cleared)
+                        n++;
+            return n;
+        }
+    }
+
+    public bool is_complete
+    {
+        get { return n_cleared == width * height - n_mines; }
+    }
+
+    public uint n_flags
+    {
+        get
+        {
+            var n = 0;
+            for (var x = 0; x < width; x++)
+                for (var y = 0; y < height; y++)
+                    if (locations[x, y].flag == FlagType.FLAG)
+                        n++;
+            return n;
+        }
+    }
+
+    public signal void redraw_sector (uint x, uint y);
+
+    public signal void marks_changed ();
+    public signal void explode ();
+    public signal void cleared ();
+
+    public Minefield (uint width, uint height, uint n_mines)
+    {
+        locations = new Location[width, height];
+        for (var x = 0; x < width; x++)
+            for (var y = 0; y < height; y++)
+                locations[x, y] = new Location ();
+        this.width = width;
+        this.height = height;
+        this.n_mines = n_mines;
+    }
+   
+    public bool has_mine (uint x, uint y)
+    {
+        return locations[x, y].has_mine;
+    }
+
+    public bool is_cleared (uint x, uint y)
+    {
+        return locations[x, y].cleared;
+    }
+
+    public bool is_location (uint x, uint y)
+    {
+        return x >= 0 && y >= 0 && x < width && y < height;
+    }
+
+    public void clear_mine (uint x, uint y)
+    {
+        /* Place mines on first attempt to clear */
+        if (!placed_mines)
+        {
+            place_mines (x, y);
+            placed_mines = true;
+        }
+
+        if (locations[x, y].cleared || locations[x, y].flag == FlagType.FLAG)
+            return;
+
+        clear_mines_recursive (x, y);
+
+        /* Failed if this contained a mine */
+        if (locations[x, y].has_mine)
+        {
+            if (!exploded)
+            {
+                exploded = true;
+                explode ();
+            }
+            return;
+        }
+
+        /* Mark unmarked mines when won */
+        if (is_complete)
+        {
+            for (var tx = 0; tx < width; tx++)
+                for (var ty = 0; ty < height; ty++)
+                    if (has_mine (tx, ty))
+                        set_flag (tx, ty, FlagType.FLAG);
+            cleared ();
+        }
+    }
+
+    private void clear_mines_recursive (uint x, uint y)
+    {
+        /* Ignore if already cleared */
+        if (locations[x, y].cleared)
+            return;
+
+        locations[x, y].cleared = true;
+        locations[x, y].flag = FlagType.NONE;
+        redraw_sector (x, y);
+        marks_changed ();
+
+        /* Automatically clear locations if no adjacent mines */
+        if (!locations[x, y].has_mine && get_n_adjacent_mines (x, y) == 0)
+        {
+            foreach (var neighbour in neighbour_map)
+            {
+                var nx = x + neighbour.x;
+                var ny = y + neighbour.y;
+                if (is_location (nx, ny))
+                    clear_mines_recursive (nx, ny);
+            }
+        }
+    }
+
+    public void set_flag (uint x, uint y, FlagType flag)
+    {
+        if (locations[x, y].cleared || locations[x, y].flag == flag)
+            return;
+
+        locations[x, y].flag = flag;
+        redraw_sector (x, y);
+
+        /* Update warnings */
+        /* FIXME: Doesn't check if have changed, just if might have changed */
+        foreach (var neighbour in neighbour_map)
+        {
+            var nx = x + neighbour.x;
+            var ny = y + neighbour.y;
+            if (is_location (nx, ny) && is_cleared (nx, ny))
+                redraw_sector (nx, ny);
+        }
+
+        marks_changed ();
+    }
+    
+    public FlagType get_flag (uint x, uint y)
+    {
+        return locations[x, y].flag;
+    }
+
+    public void hint (out uint x, out uint y)
+    {
+        /* We search for three cases:
+         *
+         * Case 1: we look for squares adjacent to both a mine and a revealed
+         * square since these are most likely to help the player and resolve
+         * ambiguous situations.
+         *
+         * Case 2: we look for squares that are adjacent to a mine
+         * (this will only occur in the rare case that a square is completely
+         * encircled by mines, but at that point this case is probably
+         * useful).
+         *
+         * Case 3: we look for any unrevealed square without a mine (as a
+         * consequence of the previous cases this won't be adjacent to a
+         * mine).
+         */
+
+        List<uint> case1list = null;
+        List<uint> case2list = null;
+        List<uint> case3list = null;
+
+        for (var mx = 0; mx < width; mx++)
+        {
+            for (var my = 0; my < height; my++)
+            {
+                var m = locations[mx, my];
+                if (!m.has_mine && !m.cleared && m.flag == FlagType.NONE)
+                {
+                    case3list.append (mx * width + my);
+                    if (get_n_adjacent_mines (mx, my) > 0)
+                    {
+                        case2list.append (mx * width + my);
+                        foreach (var neighbour in neighbour_map)
+                        {
+                            if (!is_location (mx + neighbour.x, my + neighbour.y))
+                                 continue;
+                            if (locations[mx + neighbour.x, my + neighbour.y].cleared)
+                            {
+                                case1list.append (mx * width + my);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        uint hint_location = 0;
+        if (case1list.length () > 0)
+            hint_location = case1list.nth_data (Random.int_range (0, (int32) case1list.length ()));
+        else if (case2list.length () > 0)
+            hint_location = case2list.nth_data (Random.int_range (0, (int32) case2list.length ()));
+        else if (case3list.length () > 0)
+            hint_location = case3list.nth_data (Random.int_range (0, (int32) case3list.length ()));
+
+        /* Makes sure that the program knows about the successful
+         * hint before a possible win. */
+        x = hint_location / width;
+        y = hint_location % width;
+    }
+
+    public uint get_n_adjacent_mines (uint x, uint y)
+    {
+        uint n = 0;
+        foreach (var neighbour in neighbour_map)
+        {
+            var nx = x + neighbour.x;
+            var ny = y + neighbour.y;
+            if (is_location (nx, ny) && has_mine (nx, ny))
+                n++;
+        }
+        return n;
+    }
+
+    public bool has_flag_warning (uint x, uint y)
+    {
+        if (!is_cleared (x, y))
+            return false;
+
+        uint n_mines = 0, n_flags = 0;
+        foreach (var neighbour in neighbour_map)
+        {
+            var nx = x + neighbour.x;
+            var ny = y + neighbour.y;
+            if (!is_location (nx, ny))
+                continue;
+            if (has_mine (nx, ny))
+                n_mines++;
+            if (get_flag (nx, ny) == FlagType.FLAG)
+                n_flags++;
+        }
+
+        return n_flags > n_mines;
+    }
+
+    /* Randomly set the mines, but avoid the current and adjacent locations */
+    private void place_mines (uint x, uint y)
+    {
+        for (var n = 0; n < n_mines;)
+        {
+            var rx = Random.int_range (0, (int32) width);
+            var ry = Random.int_range (0, (int32) height);
+            
+            if (rx == x && ry == y)
+                continue;
+
+            if (!locations[rx, ry].has_mine)
+            {
+                var adj_found = false;
+
+                foreach (var neighbour in neighbour_map)
+                {
+                    if (rx == x + neighbour.x && ry == y + neighbour.y)
+                    {
+                        adj_found = true;
+                        break;
+                    }
+                }
+
+                if (!adj_found)
+                {
+                    locations[rx, ry].has_mine = true;
+                    n++;
+                }
+            }
+        }
+    }
+}
diff --git a/libgames-support/GnomeGamesSupport-1.0.vapi b/libgames-support/GnomeGamesSupport-1.0.vapi
index 56e3f2e..7c5aa16 100644
--- a/libgames-support/GnomeGamesSupport-1.0.vapi
+++ b/libgames-support/GnomeGamesSupport-1.0.vapi
@@ -119,6 +119,7 @@ namespace GnomeGamesSupport
     {
         public signal void state_changed ();
         public PauseAction (string name);
+        public void set_is_paused (bool is_paused);
         public bool get_is_paused ();
     }
 
@@ -192,7 +193,7 @@ namespace GnomeGamesSupport
         public ScoresDialog (Gtk.Window parent_window, Scores scores, string title);
         public void set_category_description (string description);
         public void set_hilight (uint pos);
-        public void set_message (string message);
+        public void set_message (string? message);
         public void set_buttons (uint buttons);
     }
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f39954e..ae85b81 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -80,10 +80,10 @@ gnome-sudoku/src/lib/timer.py
 gnome-sudoku/src/lib/number_box.py
 gnome-sudoku/src/lib/gnome_sudoku.py
 gnome-sudoku/src/lib/__init__.py
-gnomine/gnomine.c
-gnomine/gnomine.desktop.in.in
-gnomine/org.gnome.gnomine.gschema.xml.in
-gnomine/minefield.c
+gnomine/data/gnomine.desktop.in.in
+gnomine/data/org.gnome.gnomine.gschema.xml.in
+gnomine/src/gnomine.c
+gnomine/src/minefield.c
 gnotravex/gnotravex.c
 gnotravex/gnotravex.desktop.in.in
 gnotravex/org.gnome.gnotravex.gschema.xml.in



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]