[gnome-games: 2/3] gnomine: Port from C to Vala
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games: 2/3] gnomine: Port from C to Vala
- Date: Sun, 13 Nov 2011 07:00:37 +0000 (UTC)
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]