Merge branch 'master' into browser
authorPhilip Chimento <philip.chimento@gmail.com>
Sat, 16 Jul 2011 21:58:50 +0000 (23:58 +0200)
committerPhilip Chimento <philip.chimento@gmail.com>
Sat, 16 Jul 2011 21:58:50 +0000 (23:58 +0200)
25 files changed:
COPYING
configure.ac
libchimara/chimara-glk.c
libchimara/chimara-glk.h
libchimara/chimara-if.c
libchimara/chimara-if.h
player/Makefile.am
player/app.c [new file with mode: 0644]
player/app.h [new file with mode: 0644]
player/browser.c [new file with mode: 0644]
player/browser.h [new file with mode: 0644]
player/browser.menus [new file with mode: 0644]
player/callbacks.c [deleted file]
player/chimara.menus.in [deleted file]
player/chimara.ui
player/error.c
player/error.h
player/main.c
player/player.c [new file with mode: 0644]
player/player.h [new file with mode: 0644]
player/player.menus [new file with mode: 0644]
player/preferences.c
player/preferences.h
player/util.c [new file with mode: 0644]
player/util.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
index eb40986d6c1f08057d8ce1b83c5b56e5d9786634..d1353d4af227ea6bf4884c4e212c0c5ba33b43c6 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (C) 2010, Philip Chimento and Marijn van Vliet.
+Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
 All rights reserved.
 
 Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
index fa284e1051ccfc0ed7e6a23b9497f095833dbe43..24cd3f862a94d4196226bf5af0d7ac82f0c39019 100644 (file)
@@ -85,18 +85,6 @@ AC_ARG_ENABLE([iliad],
        [enable_iliad=no])
 AM_CONDITIONAL(TARGET_ILIAD, $TEST "x$enable_iliad" = xyes)
 
-### BUILD WITHOUT RECENT FILES MANAGER #########################################
-# (to work around a bug on OS X)
-AC_ARG_ENABLE([recent],
-       [AS_HELP_STRING([--disable-recent],
-               [Omit recent files menu (to work around a bug on OS X])],
-       [],
-       [enable_recent=yes])
-AS_IF([$TEST "x$enable_recent" = "xyes"],
-       [OPEN_RECENT_MENU_ITEM="<menuitem action=\"recent\"/>"],
-       [OPEN_RECENT_MENU_ITEM="<!--  <menuitem action=\"recent\"/>-->"])
-AC_SUBST(OPEN_RECENT_MENU_ITEM)
-
 ### RPM CONFIGURATION ##########################################################
 # --enable-rpm requires rpm and rpmbuild
 AC_PATH_PROG([RPMBUILD], [rpmbuild], [notfound])
@@ -190,7 +178,6 @@ interpreters/glulxe/Makefile
 interpreters/git/Makefile
 tests/Makefile
 player/Makefile
-player/chimara.menus
 docs/Makefile
 docs/reference/Makefile
 docs/reference/version.xml
index 1a8b2245143f22e725d4747a8c9aaf26d0f0bf7f..6e1067ec32ea488a4ce9fbc10029ed5d6be1e25e 100644 (file)
@@ -1502,17 +1502,17 @@ chimara_glk_get_tag(ChimaraGlk *glk, ChimaraGlkWindowType window, const gchar *n
 
 /**
  * chimara_glk_get_tag_names:
- * @glk: a #ChimaraGlk widget
  * @num_tags: Return location for the number of tag names retrieved.
  *
- * Retrieves the possible tag names to use in chimara_glk_get_tag().
+ * Class method. Retrieves the possible tag names to use in
+ * chimara_glk_get_tag().
  *
  * Returns: (transfer none) (array length=num_tags) (element-type utf8):
  * Array of strings containing the tag names. This array is owned by Chimara,
  * do not free it.
  */
 const gchar **
-chimara_glk_get_tag_names(ChimaraGlk *glk, unsigned int *num_tags)
+chimara_glk_get_tag_names(unsigned int *num_tags)
 {
        g_return_val_if_fail(num_tags != NULL, NULL);
 
index 37d2220fb8776665cf07e947257dc01601db4fe6..743fa84bbcdaf8812bc380a182984c209d6488ec 100644 (file)
@@ -130,7 +130,7 @@ void chimara_glk_feed_line_input(ChimaraGlk *glk, const gchar *text);
 gboolean chimara_glk_is_char_input_pending(ChimaraGlk *glk);
 gboolean chimara_glk_is_line_input_pending(ChimaraGlk *glk);
 GtkTextTag *chimara_glk_get_tag(ChimaraGlk *glk, ChimaraGlkWindowType window, const gchar *name);
-const gchar **chimara_glk_get_tag_names(ChimaraGlk *glk, unsigned int *num_tags);
+const gchar **chimara_glk_get_tag_names(unsigned int *num_tags);
 void chimara_glk_update_style(ChimaraGlk *glk);
 void chimara_glk_set_resource_load_callback(ChimaraGlk *glk, ChimaraResourceLoadFunc func, gpointer user_data, GDestroyNotify destroy_user_data);
 
index 3879a12c2d721fb3e66febffe1e226a0715c5f8f..9b5d629d98473a5bb6de58c278771dd785105523 100644 (file)
@@ -574,7 +574,7 @@ chimara_if_get_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format)
  * case @error is set.
  */
 gboolean
-chimara_if_run_game(ChimaraIF *self, gchar *gamefile, GError **error)
+chimara_if_run_game(ChimaraIF *self, const char *gamefile, GError **error)
 {
        g_return_val_if_fail(self && CHIMARA_IS_IF(self), FALSE);
        g_return_val_if_fail(gamefile, FALSE);
@@ -679,7 +679,7 @@ chimara_if_run_game(ChimaraIF *self, gchar *gamefile, GError **error)
        }
 
        /* Game file and external blorb file */
-       args = g_slist_prepend(args, gamefile);
+       args = g_slist_prepend(args, (gpointer)gamefile);
        if(priv->graphics_file
                && (interpreter == CHIMARA_IF_INTERPRETER_FROTZ || interpreter == CHIMARA_IF_INTERPRETER_NITFOL)
            && g_file_test(priv->graphics_file, G_FILE_TEST_EXISTS)) {
index deda6474e8e893f85645ee66f603ff2a31326a08..c0763ee600517d1fa8ee88e3cc2252477aead57e 100644 (file)
@@ -116,7 +116,7 @@ GType chimara_if_get_type(void) G_GNUC_CONST;
 GtkWidget *chimara_if_new(void);
 void chimara_if_set_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format, ChimaraIFInterpreter interpreter);
 ChimaraIFInterpreter chimara_if_get_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format);
-gboolean chimara_if_run_game(ChimaraIF *self, gchar *gamefile, GError **error);
+gboolean chimara_if_run_game(ChimaraIF *self, const char *gamefile, GError **error);
 ChimaraIFFormat chimara_if_get_format(ChimaraIF *self);
 ChimaraIFInterpreter chimara_if_get_interpreter(ChimaraIF *self);
 
index 588f18325395ffa69e5daa083f8acbe441bdc87d..f6379d6eaa68e5adf0670de76e58337287643dae 100644 (file)
@@ -13,10 +13,16 @@ bin_PROGRAMS = chimara_iliad
 
 else
 
-dist_pkgdata_DATA = chimara.ui chimara.menus style.css
+dist_pkgdata_DATA = chimara.ui browser.menus player.menus style.css
 bin_PROGRAMS = chimara
 
-chimara_SOURCES = main.c callbacks.c preferences.c preferences.h error.c error.h
+chimara_SOURCES = main.c \
+       preferences.c preferences.h \
+       error.c error.h \
+       player.c player.h \
+       app.c app.h \
+       browser.c browser.h \
+       util.c util.h
 chimara_CPPFLAGS = $(AM_CPPFLAGS) \
        -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
        -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
diff --git a/player/app.c b/player/app.c
new file mode 100644 (file)
index 0000000..bbd79b1
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+/* Use a custom GSettings backend for our preferences file */
+#define G_SETTINGS_ENABLE_BACKEND
+#include <gio/gsettingsbackend.h>
+
+#include <config.h>
+#include <libchimara/chimara-if.h>
+#include "app.h"
+#include "browser.h"
+#include "error.h"
+#include "player.h"
+#include "preferences.h"
+#include "util.h"
+
+typedef struct _ChimaraAppPrivate {
+       /* Action group containing "application actions" */
+       GtkActionGroup *action_group;
+       /* List of currently opened player windows */
+       GSList *window_list;
+} ChimaraAppPrivate;
+
+#define CHIMARA_APP_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), CHIMARA_TYPE_APP, ChimaraAppPrivate))
+#define CHIMARA_APP_USE_PRIVATE ChimaraAppPrivate *priv = CHIMARA_APP_PRIVATE(self)
+
+G_DEFINE_TYPE(ChimaraApp, chimara_app, G_TYPE_OBJECT);
+
+static void
+chimara_app_finalize(GObject *self)
+{
+       CHIMARA_APP_USE_PRIVATE;
+       g_object_unref(priv->action_group);
+       g_slist_free(priv->window_list);
+       
+       /* Chain up */
+       G_OBJECT_CLASS(chimara_app_parent_class)->finalize(self);
+}
+
+static void
+chimara_app_class_init(ChimaraAppClass *klass)
+{
+       /* Override methods of parent classes */
+       GObjectClass *object_class = G_OBJECT_CLASS(klass);
+       object_class->finalize = chimara_app_finalize;
+
+       /* Private data */
+       g_type_class_add_private(klass, sizeof(ChimaraAppPrivate));
+}
+
+static void
+chimara_app_init(ChimaraApp *self)
+{
+       CHIMARA_APP_USE_PRIVATE;
+
+       /* Create configuration dir ~/.chimara */
+       gchar *configdir = g_build_filename(g_get_home_dir(), ".chimara", NULL);
+       if(!g_file_test(configdir, G_FILE_TEST_IS_DIR)
+               && g_mkdir(configdir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
+               g_error(_("Cannot create configuration directory ~/.chimara"));
+       g_free(configdir);
+
+       /* Initialize settings file; it can be overridden by a "chimara-config" file
+        in the current directory */
+       gchar *keyfile;
+       if(g_file_test("chimara-config", G_FILE_TEST_IS_REGULAR))
+               keyfile = g_strdup("chimara-config");
+       else
+               keyfile = g_build_filename(g_get_home_dir(), ".chimara", "config", NULL);
+       GSettingsBackend *backend = g_keyfile_settings_backend_new(keyfile, "/org/chimara-if/player/", NULL);
+       self->prefs_settings = g_settings_new_with_backend("org.chimara-if.player.preferences", backend);
+       self->state_settings = g_settings_new_with_backend("org.chimara-if.player.state", backend);
+       g_free(keyfile);
+
+       /* Build user interface */
+       char *object_ids[] = {
+               "app_group",
+               "aboutwindow",
+               NULL
+       };
+       GtkBuilder *builder = new_builder_with_objects(object_ids);
+
+       self->aboutwindow = GTK_WIDGET(load_object(builder, "aboutwindow"));
+       priv->action_group = GTK_ACTION_GROUP(load_object(builder, "app_group"));
+       g_object_ref(priv->action_group);
+
+       const gchar **ptr;
+       GtkRecentFilter *filter = gtk_recent_filter_new();
+       /* TODO: Use mimetypes and construct the filter dynamically depending on 
+       what plugins are installed */
+       const gchar *patterns[] = {
+               "*.z[1-8]", "*.[zg]lb", "*.[zg]blorb", "*.ulx", "*.blb", "*.blorb", NULL
+       };
+
+       for(ptr = patterns; *ptr; ptr++)
+               gtk_recent_filter_add_pattern(filter, *ptr);
+       GtkRecentChooser *recent = GTK_RECENT_CHOOSER(load_object(builder, "recent"));
+       gtk_recent_chooser_add_filter(recent, filter);
+
+       gtk_builder_connect_signals(builder, self);
+
+       g_object_unref(builder);
+}
+
+/* PUBLIC FUNCTIONS */
+
+ChimaraApp *
+chimara_app_get(void)
+{
+    static ChimaraApp *theapp = NULL;
+
+    if(G_UNLIKELY(theapp == NULL)) {
+               theapp = CHIMARA_APP(g_object_new(CHIMARA_TYPE_APP, NULL));
+
+               /* Create one-per-application windows */
+               theapp->prefswindow = chimara_prefs_new();
+               theapp->browser_window = chimara_browser_new();
+       }
+
+       return theapp;
+}
+
+GtkActionGroup *
+chimara_app_get_action_group(ChimaraApp *self)
+{
+       CHIMARA_APP_USE_PRIVATE;
+       return priv->action_group;
+}
+
+/* Internal function: See if there is a corresponding graphics file. If so,
+return its path. If not, return NULL. */
+static char *
+search_for_graphics_file(const char *path)
+{
+       ChimaraApp *theapp = chimara_app_get();
+
+       /* First get the name of the story file */
+       char *scratch = g_path_get_basename(path);
+       *(strrchr(scratch, '.')) = '\0';
+
+       /* Check in the stored resource path, if set */
+       char *resource_path;
+       g_settings_get(theapp->prefs_settings, "resource-path", "ms", &resource_path);
+
+       /* Otherwise check in the current directory */
+       if(!resource_path)
+               resource_path = g_path_get_dirname(path);
+
+       char *blorbfile = g_strconcat(resource_path, "/", scratch, ".blb", NULL);
+       g_free(scratch);
+       g_free(resource_path);
+
+       if(g_file_test(blorbfile, G_FILE_TEST_EXISTS))
+               return blorbfile;
+
+       g_free(blorbfile);
+       return NULL;
+}
+
+/* Remove a deleted player window from the list of currently opened windows */
+static gboolean
+on_player_delete_event(GtkWidget *player, GdkEvent *event, ChimaraApp *self)
+{
+       CHIMARA_APP_USE_PRIVATE;
+       priv->window_list = g_slist_remove(priv->window_list, player);
+       return FALSE; /* don't block event */
+}
+
+ChimaraPlayer *
+chimara_app_open_game(ChimaraApp *self, const char *path)
+{
+       CHIMARA_APP_USE_PRIVATE;
+       GError *error = NULL;
+
+       /* Open a new player window */
+       ChimaraPlayer *player = CHIMARA_PLAYER(chimara_player_new());
+       gtk_widget_show_all(GTK_WIDGET(player));
+       gtk_window_present(GTK_WINDOW(player));
+
+       gchar *blorbfile = search_for_graphics_file(path);
+       if(blorbfile) {
+               g_object_set(player->glk, "graphics-file", blorbfile, NULL);
+               g_free(blorbfile);
+       }
+       if(!chimara_if_run_game(CHIMARA_IF(player->glk), path, &error)) {
+               error_dialog(GTK_WINDOW(player), error, _("Could not open game file '%s': "), path);
+               gtk_widget_destroy(GTK_WIDGET(player));
+               return NULL;
+       }
+
+       /* Add the opened game to the list of currently opened windows */
+       priv->window_list = g_slist_prepend(priv->window_list, player);
+       g_signal_connect_after(player, "delete-event", G_CALLBACK(on_player_delete_event), self);
+
+       return player;
+}
+
+void
+chimara_app_foreach_game_window(ChimaraApp *self, GFunc func, gpointer data)
+{
+       CHIMARA_APP_USE_PRIVATE;
+       g_slist_foreach(priv->window_list, func, data);
+}
+
+/* GLADE CALLBACKS */
+
+void
+on_open_activate(GtkAction *action, ChimaraApp *theapp)
+{
+       //if(!confirm_open_new_game(CHIMARA_GLK(player->glk)))
+       //      return;
+
+       GtkWidget *dialog = gtk_file_chooser_dialog_new(_("Open Game"),
+           GTK_WINDOW(theapp->browser_window),
+           GTK_FILE_CHOOSER_ACTION_OPEN,
+           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+           GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+           NULL);
+
+       /* Get last opened path */
+       gchar *path;
+       g_settings_get(theapp->state_settings, "last-open-path", "ms", &path);
+       if(path) {
+               gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
+               g_free(path);
+       }
+
+       if(gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT)
+               goto finally;
+
+       GError *error = NULL;
+       char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+
+       if(!chimara_app_open_game(theapp, filename))
+               goto finally2;
+
+       path = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
+       if(path) {
+               g_settings_set(theapp->state_settings, "last-open-path", "ms", path);
+               g_free(path);
+       }
+
+       /* Add file to recent files list */
+       GtkRecentManager *manager = gtk_recent_manager_get_default();
+       gchar *uri;
+
+       if(!(uri = g_filename_to_uri(filename, NULL, &error)))
+               g_warning(_("Could not convert filename '%s' to URI: %s"), filename, error->message);
+       else {
+               if(!gtk_recent_manager_add_item(manager, uri))
+                       g_warning(_("Could not add URI '%s' to recent files list."), uri);
+               g_free(uri);
+       }
+
+finally2:
+       g_free(filename);
+finally:
+       gtk_widget_destroy(dialog);
+}
+
+void
+on_recent_item_activated(GtkRecentChooser *chooser, ChimaraApp *theapp)
+{
+       GError *error = NULL;
+       gchar *uri = gtk_recent_chooser_get_current_uri(chooser);
+       gchar *filename;
+       if(!(filename = g_filename_from_uri(uri, NULL, &error))) {
+               error_dialog(GTK_WINDOW(theapp->browser_window), error, _("Could not open game file '%s': "), uri);
+               goto finally;
+       }
+       
+       //if(!confirm_open_new_game(CHIMARA_GLK(player->glk)))
+       //      goto finally2;
+
+       if(!chimara_app_open_game(theapp, filename))
+               goto finally2;
+       
+       /* Add file to recent files list again, this updates it to most recently used */
+       GtkRecentManager *manager = gtk_recent_manager_get_default();
+       if(!gtk_recent_manager_add_item(manager, uri))
+               g_warning(_("Could not add URI '%s' to recent files list."), uri);
+
+finally2:
+       g_free(filename);
+finally:
+       g_free(uri);
+}
+
+void 
+on_quit_chimara_activate(GtkAction *action, ChimaraApp *theapp)
+{
+       gtk_main_quit();
+}
+
+void
+on_preferences_activate(GtkAction *action, ChimaraApp *theapp)
+{
+       gtk_window_present(GTK_WINDOW(theapp->prefswindow));
+}
+
+void
+on_about_activate(GtkAction *action, ChimaraApp *theapp)
+{
+       gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(theapp->aboutwindow), PACKAGE_VERSION);
+       gtk_window_present(GTK_WINDOW(theapp->aboutwindow));
+}
+
diff --git a/player/app.h b/player/app.h
new file mode 100644 (file)
index 0000000..a28061f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __APP_H__
+#define __APP_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include "player.h"
+
+G_BEGIN_DECLS
+
+#define CHIMARA_TYPE_APP            (chimara_app_get_type())
+#define CHIMARA_APP(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), CHIMARA_TYPE_APP, ChimaraApp))
+#define CHIMARA_APP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), CHIMARA_TYPE_APP, ChimaraAppClass))
+#define CHIMARA_IS_APP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), CHIMARA_TYPE_APP))
+#define CHIMARA_IS_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), CHIMARA_TYPE_APP))
+#define CHIMARA_APP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), CHIMARA_TYPE_APP, ChimaraAppClass))
+
+typedef struct _ChimaraApp {
+       GObject parent_instance;
+       
+       /* Public pointers */
+       GtkWidget *browser_window;
+       GtkWidget *aboutwindow;
+       GtkWidget *prefswindow;
+       /* Public settings */
+       GSettings *prefs_settings;
+       GSettings *state_settings;
+} ChimaraApp;
+
+typedef struct _ChimaraAppClass {
+       GObjectClass parent_class;
+} ChimaraAppClass;
+
+GType chimara_app_get_type(void) G_GNUC_CONST;
+ChimaraApp *chimara_app_get(void);
+GtkActionGroup *chimara_app_get_action_group(ChimaraApp *self);
+ChimaraPlayer *chimara_app_open_game(ChimaraApp *self, const char *path);
+void chimara_app_foreach_game_window(ChimaraApp *self, GFunc func, gpointer data);
+
+G_END_DECLS
+
+#endif /* __APP_H__ */
diff --git a/player/browser.c b/player/browser.c
new file mode 100644 (file)
index 0000000..f63404d
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include "browser.h"
+#include "app.h"
+#include "util.h"
+
+typedef struct _ChimaraBrowserPrivate {
+       GtkActionGroup *action_group;
+} ChimaraBrowserPrivate;
+
+#define CHIMARA_BROWSER_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), CHIMARA_TYPE_BROWSER, ChimaraBrowserPrivate))
+#define CHIMARA_BROWSER_USE_PRIVATE ChimaraBrowserPrivate *priv = CHIMARA_BROWSER_PRIVATE(self)
+
+G_DEFINE_TYPE(ChimaraBrowser, chimara_browser, GTK_TYPE_WINDOW);
+
+/* CALLBACKS */
+
+static gboolean
+on_browser_delete_event(GtkWidget *browser, GdkEvent *event)
+{
+       gtk_main_quit();
+       return TRUE;
+}
+
+/* TYPE SYSTEM */
+
+static void
+chimara_browser_finalize(GObject *self)
+{
+       CHIMARA_BROWSER_USE_PRIVATE;
+       g_object_unref(priv->action_group);
+
+       /* Chain up */
+       G_OBJECT_CLASS(chimara_browser_parent_class)->finalize(self);
+}
+
+static void
+chimara_browser_class_init(ChimaraBrowserClass *klass)
+{
+       /* Override methods of parent classes */
+       GObjectClass *object_class = G_OBJECT_CLASS(klass);
+       object_class->finalize = chimara_browser_finalize;
+
+       /* Private data */
+       g_type_class_add_private(klass, sizeof(ChimaraBrowserPrivate));
+}
+
+static void
+chimara_browser_init(ChimaraBrowser *self)
+{
+       CHIMARA_BROWSER_USE_PRIVATE;
+       ChimaraApp *theapp = chimara_app_get();
+
+       /* Set own properties */
+       g_object_set(self,
+               "title", _("Chimara"),
+               NULL);
+
+       /* Build user interface */
+       char *object_ids[] = {
+               "browser_group",
+               NULL
+       };
+       GtkBuilder *builder = new_builder_with_objects(object_ids);
+
+       priv->action_group = GTK_ACTION_GROUP(load_object(builder, "browser_group"));
+       g_object_ref(priv->action_group);
+
+       GtkUIManager *uimanager = new_ui_manager("browser.menus");
+
+       gtk_ui_manager_insert_action_group(uimanager, priv->action_group, 0);
+       gtk_ui_manager_insert_action_group(uimanager, chimara_app_get_action_group(theapp), 1);
+       GtkWidget *menubar = gtk_ui_manager_get_widget(uimanager, "/browser_menu");
+       GtkWidget *toolbar = gtk_ui_manager_get_widget(uimanager, "/browser_toolbar");
+       GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
+       gtk_container_add(GTK_CONTAINER(self), vbox);
+       gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
+
+       g_signal_connect(self, "delete-event", G_CALLBACK(on_browser_delete_event), NULL);
+
+       g_object_unref(uimanager);
+       g_object_unref(builder);
+}
+
+/* PUBLIC FUNCTIONS */
+
+GtkWidget *
+chimara_browser_new(void)
+{
+       return GTK_WIDGET(g_object_new(CHIMARA_TYPE_BROWSER,
+               "type", GTK_WINDOW_TOPLEVEL,
+               NULL));
+}
+
+/* GLADE CALLBACKS */
+
+void
+action_add_file(GtkAction *action, ChimaraBrowser *browser)
+{
+}
+
+void
+action_add_watched_folder(GtkAction *action, ChimaraBrowser *browser)
+{
+}
+
+void
+action_remove_file(GtkAction *action, ChimaraBrowser *browser)
+{
+}
+
+void
+action_play(GtkAction *action, ChimaraBrowser *browser)
+{
+}
+
+void
+action_more_info(GtkAction *action, ChimaraBrowser *browser)
+{
+}
diff --git a/player/browser.h b/player/browser.h
new file mode 100644 (file)
index 0000000..a1392ed
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BROWSER_H__
+#define __BROWSER_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define CHIMARA_TYPE_BROWSER            (chimara_browser_get_type())
+#define CHIMARA_BROWSER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), CHIMARA_TYPE_BROWSER, ChimaraBrowser))
+#define CHIMARA_BROWSER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), CHIMARA_TYPE_BROWSER, ChimaraBrowserClass))
+#define CHIMARA_IS_BROWSER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), CHIMARA_TYPE_BROWSER))
+#define CHIMARA_IS_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), CHIMARA_TYPE_BROWSER))
+#define CHIMARA_BROWSER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), CHIMARA_TYPE_BROWSER, ChimaraBrowserClass))
+
+typedef struct _ChimaraBrowser {
+       GtkWindow parent_instance;
+       
+       /* Public pointers */
+} ChimaraBrowser;
+
+typedef struct _ChimaraBrowserClass {
+       GtkWindowClass parent_class;
+} ChimaraBrowserClass;
+
+GType chimara_browser_get_type(void) G_GNUC_CONST;
+GtkWidget *chimara_browser_new(void);
+
+G_END_DECLS
+
+#endif /* __BROWSER_H__ */
diff --git a/player/browser.menus b/player/browser.menus
new file mode 100644 (file)
index 0000000..fc2ccda
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<ui>
+  <menubar name="browser_menu">
+    <menu action="game">
+      <menuitem action="play"/>
+      <menuitem action="more_info"/>
+      <separator/>
+      <menuitem action="open"/>
+         <menuitem action="recent"/>
+      <separator/>
+      <menuitem action="quit_chimara"/>
+    </menu>
+    <menu action="edit">
+      <menuitem action="preferences"/>
+    </menu>
+    <menu action="library">
+      <menuitem action="add_file"/>
+      <menuitem action="add_watched_folder"/>
+      <menuitem action="remove_file"/>
+    </menu>
+    <menu action="help">
+      <menuitem action="about"/>
+    </menu>
+  </menubar>
+  <toolbar name="browser_toolbar">
+    <toolitem action="add_file"/>
+    <toolitem action="remove_file"/>
+    <separator/>
+    <toolitem action="play"/>
+    <toolitem action="more_info"/>
+  </toolbar>
+</ui>
diff --git a/player/callbacks.c b/player/callbacks.c
deleted file mode 100644 (file)
index a4cc173..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-/*
- * callbacks.c
- * Copyright (C) Philip en Marijn 2008 <>
- * 
- * callbacks.c is free software copyrighted by Philip en Marijn.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name ``Philip en Marijn'' nor the name of any other
- *    contributor may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- * 
- * callbacks.c IS PROVIDED BY Philip en Marijn ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL Philip en Marijn OR ANY OTHER CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gtk/gtk.h>
-#include <libchimara/chimara-glk.h>
-#include <libchimara/chimara-if.h>
-#include <config.h>
-#include "error.h"
-
-/* If a game is running in @glk, warn the user that they will quit the currently
-running game if they open a new one. Returns TRUE if no game was running.
-Returns FALSE if the user cancelled. Returns TRUE and shuts down the running
-game if the user wishes to continue. */
-static gboolean
-confirm_open_new_game(ChimaraGlk *glk)
-{
-       g_return_val_if_fail(glk && CHIMARA_IS_GLK(glk), FALSE);
-       
-       GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
-       
-       if(chimara_glk_get_running(glk)) {
-               GtkWidget *dialog = gtk_message_dialog_new(window,
-                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                   GTK_MESSAGE_WARNING,
-                   GTK_BUTTONS_CANCEL,
-                   _("Are you sure you want to open a new game?"));
-               gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
-                   _("If you open a new game, you will quit the one you are currently playing."));
-               gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OPEN, GTK_RESPONSE_OK);
-               gint response = gtk_dialog_run(GTK_DIALOG(dialog));
-               gtk_widget_destroy(dialog);
-               
-               if(response != GTK_RESPONSE_OK)
-                       return FALSE;
-
-               chimara_glk_stop(glk);
-               chimara_glk_wait(glk);
-       }
-       return TRUE;
-}
-
-/* Internal function: See if there is a corresponding graphics file */
-static void
-search_for_graphics_file(const char *filename, ChimaraIF *glk)
-{
-
-       extern GSettings *prefs_settings;
-
-       /* First get the name of the story file */
-       char *scratch = g_path_get_basename(filename);
-       *(strrchr(scratch, '.')) = '\0';
-
-       /* Check in the stored resource path, if set */
-       char *resource_path;
-       g_settings_get(prefs_settings, "resource-path", "ms", &resource_path);
-
-       /* Otherwise check in the current directory */
-       if(!resource_path)
-               resource_path = g_path_get_dirname(filename);
-
-       char *blorbfile = g_strconcat(resource_path, "/", scratch, ".blb", NULL);
-       if(g_file_test(blorbfile, G_FILE_TEST_EXISTS))
-               g_object_set(glk, "graphics-file", blorbfile, NULL);
-
-       g_free(blorbfile);
-       g_free(scratch);
-       g_free(resource_path);
-}
-
-void
-on_open_activate(GtkAction *action, ChimaraGlk *glk) 
-{
-       GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
-       
-       if(!confirm_open_new_game(glk))
-               return;
-
-       GtkWidget *dialog = gtk_file_chooser_dialog_new(_("Open Game"),
-           window,
-           GTK_FILE_CHOOSER_ACTION_OPEN,
-           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-           GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
-           NULL);
-
-       /* Get last opened path */
-       extern GSettings *state_settings;
-       gchar *path;
-       g_settings_get(state_settings, "last-open-path", "ms", &path);
-       if(path) {
-               gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
-               g_free(path);
-       }
-
-       if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
-               GError *error = NULL;
-               extern GSettings *prefs_settings;
-               char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
-
-               search_for_graphics_file(filename, CHIMARA_IF(glk));
-               if(!chimara_if_run_game(CHIMARA_IF(glk), filename, &error)) {
-                       error_dialog(window, error, _("Could not open game file '%s': "), filename);
-                       g_free(filename);
-                       gtk_widget_destroy(dialog);
-                       return;
-               }
-               
-               path = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
-               if(path) {
-                       g_settings_set(state_settings, "last-open-path", "ms", path);
-                       g_free(path);
-               }
-
-               /* Add file to recent files list */
-               GtkRecentManager *manager = gtk_recent_manager_get_default();
-               gchar *uri;
-               
-               if(!(uri = g_filename_to_uri(filename, NULL, &error)))
-                       g_warning(_("Could not convert filename '%s' to URI: %s"), filename, error->message);
-               else {
-                       if(!gtk_recent_manager_add_item(manager, uri))
-                               g_warning(_("Could not add URI '%s' to recent files list."), uri);
-                       g_free(uri);
-               }
-               g_free(filename);
-       }
-       gtk_widget_destroy(dialog);
-}
-
-void
-on_recent_item_activated(GtkRecentChooser *chooser, ChimaraGlk *glk)
-{
-       GError *error = NULL;
-       GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
-       gchar *uri = gtk_recent_chooser_get_current_uri(chooser);
-       gchar *filename;
-       if(!(filename = g_filename_from_uri(uri, NULL, &error))) {
-               error_dialog(window, error, _("Could not open game file '%s': "), uri);
-               goto finally;
-       }
-       
-       if(!confirm_open_new_game(glk))
-               goto finally2;
-       
-       search_for_graphics_file(filename, CHIMARA_IF(glk));
-       if(!chimara_if_run_game(CHIMARA_IF(glk), filename, &error)) {
-               error_dialog(window, error, _("Could not open game file '%s': "), filename);
-               goto finally2;
-       }
-       
-       /* Add file to recent files list again, this updates it to most recently used */
-       GtkRecentManager *manager = gtk_recent_manager_get_default();
-       if(!gtk_recent_manager_add_item(manager, uri))
-               g_warning(_("Could not add URI '%s' to recent files list."), uri);
-
-finally2:
-       g_free(filename);
-finally:
-       g_free(uri);
-}
-
-void
-on_stop_activate(GtkAction *action, ChimaraGlk *glk)
-{
-       chimara_glk_stop(glk);
-}
-
-void 
-on_quit_chimara_activate(GtkAction *action, ChimaraGlk *glk) 
-{
-       gtk_main_quit();
-}
-
-void
-on_copy_activate(GtkAction *action, ChimaraGlk *glk)
-{
-       GtkWindow *toplevel = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
-       GtkWidget *focus = gtk_window_get_focus(toplevel);
-       /* Call "copy clipboard" on any widget that defines it */
-       if(GTK_IS_LABEL(focus) || GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
-               g_signal_emit_by_name(focus, "copy-clipboard");
-}
-
-void
-on_paste_activate(GtkAction *action, ChimaraGlk *glk)
-{
-       GtkWindow *toplevel = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
-       GtkWidget *focus = gtk_window_get_focus(toplevel);
-       /* Call "paste clipboard" on any widget that defines it */
-       if(GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
-               g_signal_emit_by_name(focus, "paste-clipboard");
-}
-
-void
-on_preferences_activate(GtkAction *action, ChimaraGlk *glk)
-{
-       extern GtkWidget *prefswindow;
-       gtk_window_present(GTK_WINDOW(prefswindow));
-}
-
-void
-on_toolbar_toggled(GtkToggleAction *action, ChimaraGlk *glk)
-{
-       extern GtkWidget *toolbar;
-       
-       if(gtk_toggle_action_get_active(action))
-               gtk_widget_show(toolbar);
-       else
-               gtk_widget_hide(toolbar);
-}
-
-void
-on_undo_activate(GtkAction *action, ChimaraGlk *glk)
-{
-       chimara_glk_feed_line_input(glk, "undo");
-}
-
-void 
-on_save_activate(GtkAction *action, ChimaraGlk *glk) 
-{
-       chimara_glk_feed_line_input(glk, "save");
-}
-
-void 
-on_restore_activate(GtkAction *action, ChimaraGlk *glk) 
-{
-       chimara_glk_feed_line_input(glk, "restore");
-}
-
-void 
-on_restart_activate(GtkAction *action, ChimaraGlk *glk) 
-{
-       chimara_glk_feed_line_input(glk, "restart");
-}
-
-void 
-on_quit_activate(GtkAction *action, ChimaraGlk *glk) 
-{
-       chimara_glk_feed_line_input(glk, "quit");
-}
-
-void
-on_about_activate(GtkAction *action, ChimaraGlk *glk)
-{
-       extern GtkWidget *aboutwindow;
-       gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(aboutwindow), PACKAGE_VERSION);
-       gtk_window_present(GTK_WINDOW(aboutwindow));
-}
-
-gboolean 
-on_window_delete_event(GtkWidget *widget, GdkEvent *event, ChimaraGlk *glk) 
-{
-       gtk_main_quit();
-       return TRUE;
-}
diff --git a/player/chimara.menus.in b/player/chimara.menus.in
deleted file mode 100644 (file)
index cb383f7..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0"?>
-<ui>
-  <menubar>
-    <menu action="game">
-      <menuitem action="open"/>
-         @OPEN_RECENT_MENU_ITEM@
-      <separator/>
-      <menuitem action="stop"/>
-      <menuitem action="quit_chimara"/>
-    </menu>
-    <menu action="edit">
-      <menuitem action="copy"/>
-      <menuitem action="paste"/>
-      <separator/>
-      <menuitem action="preferences"/>
-    </menu>
-    <menu action="view">
-      <menuitem action="toolbar"/>
-    </menu>
-    <menu action="command">
-      <menuitem action="undo"/>
-      <menuitem action="save"/>
-      <menuitem action="restore"/>
-      <menuitem action="restart"/>
-      <menuitem action="quit"/>
-    </menu>
-    <menu action="help">
-      <menuitem action="about"/>
-    </menu>
-  </menubar>
-  <toolbar>
-    <toolitem action="open"/>
-    <separator/>
-    <toolitem action="restore"/>
-    <toolitem action="save"/>
-  </toolbar>
-</ui>
index 0a80104cb648c4494c3c7b95f801c4a6c884c67d..36669fd8eefff536f886e019731476eedfc44713 100644 (file)
@@ -1,24 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <requires lib="gtk+" version="2.16"/>
-  <!-- interface-naming-policy toplevel-contextual -->
+  <requires lib="gtk+" version="2.20"/>
   <object class="GtkActionGroup" id="actiongroup">
-    <child>
-      <object class="GtkAction" id="game">
-        <property name="label">_Game</property>
-        <property name="short_label" translatable="yes">_Game</property>
-      </object>
-    </child>
-    <child>
-      <object class="GtkAction" id="open">
-        <property name="label">_Open...</property>
-        <property name="short_label">_Open</property>
-        <property name="tooltip">Quit the current game and load a new one</property>
-        <property name="stock_id">gtk-media-play</property>
-        <signal name="activate" handler="on_open_activate" swapped="no"/>
-      </object>
-      <accelerator key="o" modifiers="GDK_CONTROL_MASK"/>
-    </child>
     <child>
       <object class="GtkAction" id="restore">
         <property name="label">_Restore...</property>
         <signal name="activate" handler="on_save_activate" swapped="no"/>
       </object>
     </child>
-    <child>
-      <object class="GtkAction" id="quit_chimara">
-        <property name="label">_Quit Chimara</property>
-        <property name="short_label" translatable="yes">_Quit Chimara</property>
-        <property name="tooltip">Leave the program</property>
-        <property name="stock_id">gtk-quit</property>
-        <signal name="activate" handler="on_quit_chimara_activate" swapped="no"/>
-      </object>
-    </child>
     <child>
       <object class="GtkAction" id="command">
         <property name="label">_Command</property>
         <property name="short_label" translatable="yes">_Command</property>
       </object>
     </child>
-    <child>
-      <object class="GtkAction" id="edit">
-        <property name="label">_Edit</property>
-        <property name="short_label" translatable="yes">_Edit</property>
-      </object>
-    </child>
     <child>
       <object class="GtkAction" id="stop">
         <property name="label">_Stop Game</property>
         <signal name="activate" handler="on_stop_activate" swapped="no"/>
       </object>
     </child>
-    <child>
-      <object class="GtkRecentAction" id="recent">
-        <property name="label">Open _Recent</property>
-        <property name="short_label" translatable="yes">Open _Recent</property>
-        <property name="limit">10</property>
-        <property name="sort_type">mru</property>
-        <signal name="item-activated" handler="on_recent_item_activated" swapped="no"/>
-      </object>
-    </child>
     <child>
       <object class="GtkAction" id="undo">
         <property name="label">_Undo</property>
         <signal name="activate" handler="on_paste_activate" swapped="no"/>
       </object>
     </child>
+    <child>
+      <object class="GtkAction" id="view">
+        <property name="label" translatable="yes">_View</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkToggleAction" id="toolbar">
+        <property name="label" translatable="yes">_Toolbar</property>
+        <property name="tooltip" translatable="yes">Show a toolbar at the top of the window</property>
+        <signal name="toggled" handler="on_toolbar_toggled" swapped="no"/>
+      </object>
+    </child>
+  </object>
+  <object class="GtkActionGroup" id="app_group">
+    <child>
+      <object class="GtkAction" id="game">
+        <property name="label">_Game</property>
+        <property name="short_label" translatable="yes">_Game</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkAction" id="open">
+        <property name="label">_Open...</property>
+        <property name="short_label">_Open</property>
+        <property name="tooltip">Quit the current game and load a new one</property>
+        <property name="stock_id">gtk-open</property>
+        <signal name="activate" handler="on_open_activate" swapped="no"/>
+      </object>
+      <accelerator key="o" modifiers="GDK_CONTROL_MASK"/>
+    </child>
+    <child>
+      <object class="GtkAction" id="quit_chimara">
+        <property name="label">_Quit Chimara</property>
+        <property name="short_label" translatable="yes">_Quit Chimara</property>
+        <property name="tooltip">Leave the program</property>
+        <property name="stock_id">gtk-quit</property>
+        <signal name="activate" handler="on_quit_chimara_activate" swapped="no"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkAction" id="edit">
+        <property name="label">_Edit</property>
+        <property name="short_label" translatable="yes">_Edit</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkRecentAction" id="recent">
+        <property name="label">Open _Recent</property>
+        <property name="short_label" translatable="yes">Open _Recent</property>
+        <property name="limit">10</property>
+        <property name="sort_type">mru</property>
+        <signal name="item-activated" handler="on_recent_item_activated" swapped="no"/>
+      </object>
+    </child>
     <child>
       <object class="GtkAction" id="preferences">
         <property name="label">P_references</property>
         <signal name="activate" handler="on_about_activate" swapped="no"/>
       </object>
     </child>
+  </object>
+  <object class="GtkActionGroup" id="browser_group">
     <child>
-      <object class="GtkAction" id="view">
-        <property name="label" translatable="yes">_View</property>
+      <object class="GtkAction" id="add_file">
+        <property name="label" translatable="yes">_Add file to library...</property>
+        <property name="short_label" translatable="yes">Add</property>
+        <property name="tooltip" translatable="yes">Add a single game file to your library</property>
+        <property name="stock_id">gtk-add</property>
+        <signal name="activate" handler="action_add_file" swapped="no"/>
       </object>
     </child>
     <child>
-      <object class="GtkToggleAction" id="toolbar">
-        <property name="label" translatable="yes">_Toolbar</property>
-        <property name="tooltip" translatable="yes">Show a toolbar at the top of the window</property>
-        <signal name="toggled" handler="on_toolbar_toggled" swapped="no"/>
+      <object class="GtkAction" id="add_watched_folder">
+        <property name="label" translatable="yes">Add watched _folder to library...</property>
+        <property name="short_label" translatable="yes">Add folder</property>
+        <property name="tooltip" translatable="yes">Add all the game files in a folder to your library, and keep monitoring the folder to see if any game files are added to it in the future</property>
+        <property name="stock_id">gtk-directory</property>
+        <signal name="activate" handler="action_add_watched_folder" swapped="no"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkAction" id="play">
+        <property name="label" translatable="yes">_Play</property>
+        <property name="short_label" translatable="yes">Play</property>
+        <property name="tooltip" translatable="yes">Play the game</property>
+        <property name="stock_id">gtk-media-play</property>
+        <signal name="activate" handler="action_play" swapped="no"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkAction" id="more_info">
+        <property name="label" translatable="yes">More _information...</property>
+        <property name="short_label" translatable="yes">Info</property>
+        <property name="tooltip" translatable="yes">View information about this game</property>
+        <property name="stock_id">gtk-info</property>
+        <signal name="activate" handler="action_more_info" swapped="no"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkAction" id="remove_file">
+        <property name="label" translatable="yes">_Remove file</property>
+        <property name="short_label" translatable="yes">Remove</property>
+        <property name="tooltip" translatable="yes">Remove this game file from your library</property>
+        <property name="stock_id">gtk-remove</property>
+        <signal name="activate" handler="action_remove_file" swapped="no"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkAction" id="library">
+        <property name="label" translatable="yes">_Library</property>
       </object>
     </child>
   </object>
@@ -199,15 +252,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 </property>
     <property name="authors">Marijn van Vliet
 Philip Chimento</property>
-    <signal name="response" handler="gtk_widget_hide" swapped="no"/>
     <signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
+    <signal name="response" handler="gtk_widget_hide" swapped="no"/>
     <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox1">
+      <object class="GtkBox" id="dialog-vbox1">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
         <property name="spacing">2</property>
         <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area1">
+          <object class="GtkButtonBox" id="dialog-action_area1">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="layout_style">end</property>
@@ -231,22 +285,6 @@ Philip Chimento</property>
       <column type="gchararray"/>
     </columns>
   </object>
-  <object class="GtkWindow" id="chimara">
-    <property name="can_focus">False</property>
-    <property name="title" translatable="yes">Chimara</property>
-    <property name="default_width">600</property>
-    <property name="default_height">800</property>
-    <signal name="delete-event" handler="on_window_delete_event" swapped="no"/>
-    <child>
-      <object class="GtkVBox" id="vbox">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <child>
-          <placeholder/>
-        </child>
-      </object>
-    </child>
-  </object>
   <object class="GtkListStore" id="interpreters">
     <columns>
       <!-- column-name Format -->
@@ -255,722 +293,677 @@ Philip Chimento</property>
       <column type="gchararray"/>
     </columns>
   </object>
-  <object class="GtkDialog" id="prefswindow">
+  <object class="GtkVBox" id="player-vbox">
+    <property name="visible">True</property>
     <property name="can_focus">False</property>
-    <property name="border_width">5</property>
-    <property name="title" translatable="yes">Chimara Preferences</property>
-    <property name="window_position">center</property>
-    <property name="type_hint">dialog</property>
-    <signal name="response" handler="gtk_widget_hide" swapped="no"/>
-    <signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox2">
+    <child>
+      <placeholder/>
+    </child>
+  </object>
+  <object class="GtkNotebook" id="prefs-notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">True</property>
+    <child>
+      <object class="GtkVBox" id="vbox5">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="spacing">9</property>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area2">
+        <property name="border_width">6</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkFrame" id="frame2">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="layout_style">end</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
             <child>
-              <object class="GtkButton" id="button-close">
-                <property name="label">gtk-close</property>
+              <object class="GtkAlignment" id="alignment2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <object class="GtkCheckButton" id="flep">
+                    <property name="label" translatable="yes">Turn on _flepping</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Whether to flep or not when gronking a bloop.</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label12">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_action_appearance">False</property>
-                <property name="use_stock">True</property>
-                <signal name="clicked" handler="gtk_widget_hide" object="prefswindow" swapped="yes"/>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">&lt;b&gt;General settings&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
             </child>
           </object>
           <packing>
             <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="pack_type">end</property>
+            <property name="fill">False</property>
             <property name="position">0</property>
           </packing>
         </child>
         <child>
-          <object class="GtkNotebook" id="notebook1">
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Environment</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="border_width">6</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkTable" id="table1">
             <property name="visible">True</property>
-            <property name="can_focus">True</property>
+            <property name="can_focus">False</property>
+            <property name="n_columns">2</property>
             <child>
-              <object class="GtkVBox" id="vbox5">
+              <object class="GtkLabel" id="label5">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="border_width">6</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkFrame" id="frame2">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="label_xalign">0</property>
-                    <property name="shadow_type">none</property>
-                    <child>
-                      <object class="GtkAlignment" id="alignment2">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="left_padding">12</property>
-                        <child>
-                          <object class="GtkCheckButton" id="flep">
-                            <property name="label" translatable="yes">Turn on _flepping</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="tooltip_text" translatable="yes">Whether to flep or not when gronking a bloop.</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="use_underline">True</property>
-                            <property name="draw_indicator">True</property>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                    <child type="label">
-                      <object class="GtkLabel" id="label12">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">&lt;b&gt;General settings&lt;/b&gt;</property>
-                        <property name="use_markup">True</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
+                <property name="xalign">1</property>
+                <property name="xpad">5</property>
+                <property name="label" translatable="yes">Load layout from this CSS file:</property>
               </object>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFileChooserButton" id="css-filechooser">
+                <property name="width_request">250</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="title" translatable="yes">Select A CSS File</property>
+                <signal name="file-set" handler="on_css_filechooser_file_set" swapped="no"/>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+              </packing>
             </child>
-            <child type="tab">
-              <object class="GtkLabel" id="label1">
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHSeparator" id="hseparator1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="padding">5</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox3">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkLabel" id="label9">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="label" translatable="yes">Environment</property>
+                <property name="xalign">0</property>
+                <property name="xpad">5</property>
+                <property name="label" translatable="yes">Select a style to edit:</property>
               </object>
               <packing>
-                <property name="tab_fill">False</property>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
               </packing>
             </child>
             <child>
-              <object class="GtkVBox" id="vbox1">
+              <object class="GtkHBox" id="hbox1">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="border_width">6</property>
-                <property name="spacing">6</property>
+                <property name="spacing">12</property>
                 <child>
-                  <object class="GtkTable" id="table1">
+                  <object class="GtkScrolledWindow" id="scrolledwindow1">
+                    <property name="width_request">163</property>
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="n_columns">2</property>
-                    <child>
-                      <object class="GtkLabel" id="label5">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">1</property>
-                        <property name="xpad">5</property>
-                        <property name="label" translatable="yes">Load layout from this CSS file:</property>
-                      </object>
-                      <packing>
-                        <property name="x_options">GTK_FILL</property>
-                      </packing>
-                    </child>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">never</property>
                     <child>
-                      <object class="GtkFileChooserButton" id="css-filechooser">
-                        <property name="width_request">250</property>
+                      <object class="GtkTreeView" id="style-treeview">
                         <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="title" translatable="yes">Select A CSS File</property>
-                        <signal name="file-set" handler="on_css_filechooser_file_set" swapped="no"/>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="model">style-list</property>
+                        <property name="headers_visible">False</property>
+                        <property name="headers_clickable">False</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection" id="treeview-selection1"/>
+                        </child>
+                        <child>
+                          <object class="GtkTreeViewColumn" id="style-name-column">
+                            <property name="title" translatable="yes">Style Name</property>
+                            <property name="expand">True</property>
+                            <child>
+                              <object class="GtkCellRendererText" id="style-name-renderer"/>
+                              <attributes>
+                                <attribute name="text">0</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                        </child>
                       </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="right_attach">2</property>
-                      </packing>
                     </child>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
+                    <property name="expand">True</property>
                     <property name="fill">True</property>
                     <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkHSeparator" id="hseparator1">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="padding">5</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkVBox" id="vbox3">
+                  <object class="GtkVBox" id="vbox4">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
+                    <property name="spacing">6</property>
                     <child>
-                      <object class="GtkLabel" id="label9">
+                      <object class="GtkTable" id="table2">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="xpad">5</property>
-                        <property name="label" translatable="yes">Select a style to edit:</property>
+                        <property name="n_rows">3</property>
+                        <property name="n_columns">2</property>
+                        <property name="column_spacing">6</property>
+                        <property name="row_spacing">6</property>
+                        <child>
+                          <object class="GtkLabel" id="label6">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Font:</property>
+                          </object>
+                          <packing>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFontButton" id="fontbutton1">
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="use_action_appearance">False</property>
+                            <signal name="font-set" handler="on_font_set" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="label7">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Foreground color:</property>
+                          </object>
+                          <packing>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkColorButton" id="colorbutton1">
+                            <property name="width_request">40</property>
+                            <property name="height_request">30</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="color">#000000000000</property>
+                            <signal name="color-set" handler="on_foreground_color_set" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="label8">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Background color:</property>
+                          </object>
+                          <packing>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkColorButton" id="colorbutton2">
+                            <property name="width_request">40</property>
+                            <property name="height_request">30</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="color">#ffffffffffff</property>
+                            <signal name="color-set" handler="on_background_color_set" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
                       </object>
                       <packing>
-                        <property name="expand">False</property>
+                        <property name="expand">True</property>
                         <property name="fill">True</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkHBox" id="hbox1">
+                      <object class="GtkHButtonBox" id="hbuttonbox1">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="spacing">12</property>
+                        <property name="spacing">6</property>
+                        <property name="layout_style">start</property>
                         <child>
-                          <object class="GtkScrolledWindow" id="scrolledwindow1">
-                            <property name="width_request">163</property>
+                          <object class="GtkRadioButton" id="left">
+                            <property name="label">gtk-justify-left</property>
                             <property name="visible">True</property>
+                            <property name="sensitive">False</property>
                             <property name="can_focus">True</property>
-                            <property name="hscrollbar_policy">never</property>
-                            <property name="vscrollbar_policy">automatic</property>
-                            <child>
-                              <object class="GtkTreeView" id="style-treeview">
-                                <property name="visible">True</property>
-                                <property name="sensitive">False</property>
-                                <property name="can_focus">True</property>
-                                <property name="model">style-list</property>
-                                <property name="headers_visible">False</property>
-                                <property name="headers_clickable">False</property>
-                                <child>
-                                  <object class="GtkTreeViewColumn" id="style-name-column">
-                                    <property name="title" translatable="yes">Style Name</property>
-                                    <property name="expand">True</property>
-                                    <child>
-                                      <object class="GtkCellRendererText" id="style-name-renderer"/>
-                                      <attributes>
-                                        <attribute name="text">0</attribute>
-                                      </attributes>
-                                    </child>
-                                  </object>
-                                </child>
-                              </object>
-                            </child>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="use_stock">True</property>
+                            <property name="image_position">top</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">False</property>
+                            <signal name="toggled" handler="on_toggle_left" swapped="no"/>
                           </object>
                           <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
                             <property name="position">0</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkVBox" id="vbox4">
+                          <object class="GtkRadioButton" id="center">
+                            <property name="label">gtk-justify-center</property>
                             <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="spacing">6</property>
-                            <child>
-                              <object class="GtkTable" id="table2">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="n_rows">3</property>
-                                <property name="n_columns">2</property>
-                                <property name="column_spacing">6</property>
-                                <property name="row_spacing">6</property>
-                                <child>
-                                  <object class="GtkLabel" id="label6">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="xalign">0</property>
-                                    <property name="label" translatable="yes">Font:</property>
-                                  </object>
-                                  <packing>
-                                    <property name="x_options">GTK_FILL</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkFontButton" id="fontbutton1">
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <signal name="font-set" handler="on_font_set" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="left_attach">1</property>
-                                    <property name="right_attach">2</property>
-                                    <property name="x_options">GTK_FILL</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkLabel" id="label7">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="xalign">0</property>
-                                    <property name="label" translatable="yes">Foreground color:</property>
-                                  </object>
-                                  <packing>
-                                    <property name="top_attach">1</property>
-                                    <property name="bottom_attach">2</property>
-                                    <property name="x_options">GTK_FILL</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkColorButton" id="colorbutton1">
-                                    <property name="width_request">40</property>
-                                    <property name="height_request">30</property>
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="color">#000000000000</property>
-                                    <signal name="color-set" handler="on_foreground_color_set" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="left_attach">1</property>
-                                    <property name="right_attach">2</property>
-                                    <property name="top_attach">1</property>
-                                    <property name="bottom_attach">2</property>
-                                    <property name="x_options">GTK_FILL</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkLabel" id="label8">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="xalign">0</property>
-                                    <property name="label" translatable="yes">Background color:</property>
-                                  </object>
-                                  <packing>
-                                    <property name="top_attach">2</property>
-                                    <property name="bottom_attach">3</property>
-                                    <property name="x_options">GTK_FILL</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkColorButton" id="colorbutton2">
-                                    <property name="width_request">40</property>
-                                    <property name="height_request">30</property>
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="color">#ffffffffffff</property>
-                                    <signal name="color-set" handler="on_background_color_set" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="left_attach">1</property>
-                                    <property name="right_attach">2</property>
-                                    <property name="top_attach">2</property>
-                                    <property name="bottom_attach">3</property>
-                                    <property name="x_options">GTK_FILL</property>
-                                  </packing>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="expand">True</property>
-                                <property name="fill">True</property>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkHButtonBox" id="hbuttonbox1">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="spacing">6</property>
-                                <property name="layout_style">start</property>
-                                <child>
-                                  <object class="GtkRadioButton" id="left">
-                                    <property name="label">gtk-justify-left</property>
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="image_position">top</property>
-                                    <property name="active">True</property>
-                                    <property name="draw_indicator">False</property>
-                                    <signal name="toggled" handler="on_toggle_left" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">0</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkRadioButton" id="center">
-                                    <property name="label">gtk-justify-center</property>
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="image_position">top</property>
-                                    <property name="draw_indicator">False</property>
-                                    <property name="group">left</property>
-                                    <signal name="toggled" handler="on_toggle_center" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkRadioButton" id="right">
-                                    <property name="label">gtk-justify-right</property>
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="image_position">top</property>
-                                    <property name="draw_indicator">False</property>
-                                    <property name="group">left</property>
-                                    <signal name="toggled" handler="on_toggle_right" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">2</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkRadioButton" id="justify">
-                                    <property name="label">gtk-justify-fill</property>
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="image_position">top</property>
-                                    <property name="draw_indicator">False</property>
-                                    <property name="group">left</property>
-                                    <signal name="toggled" handler="on_toggle_justify" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">3</property>
-                                  </packing>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="expand">True</property>
-                                <property name="fill">True</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkHButtonBox" id="hbuttonbox2">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="spacing">6</property>
-                                <property name="layout_style">start</property>
-                                <child>
-                                  <object class="GtkCheckButton" id="checkbutton1">
-                                    <property name="label">gtk-bold</property>
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="image_position">top</property>
-                                    <property name="draw_indicator">False</property>
-                                    <signal name="toggled" handler="on_toggle_bold" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">0</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkCheckButton" id="checkbutton2">
-                                    <property name="label">gtk-italic</property>
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="image_position">top</property>
-                                    <property name="draw_indicator">False</property>
-                                    <signal name="toggled" handler="on_toggle_italic" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkCheckButton" id="underline">
-                                    <property name="label">gtk-underline</property>
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="image_position">top</property>
-                                    <property name="draw_indicator">False</property>
-                                    <signal name="toggled" handler="on_toggle_underline" swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">2</property>
-                                  </packing>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="expand">True</property>
-                                <property name="fill">True</property>
-                                <property name="position">2</property>
-                              </packing>
-                            </child>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="use_stock">True</property>
+                            <property name="image_position">top</property>
+                            <property name="draw_indicator">False</property>
+                            <property name="group">left</property>
+                            <signal name="toggled" handler="on_toggle_center" swapped="no"/>
                           </object>
                           <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
                             <property name="position">1</property>
                           </packing>
                         </child>
+                        <child>
+                          <object class="GtkRadioButton" id="right">
+                            <property name="label">gtk-justify-right</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="use_stock">True</property>
+                            <property name="image_position">top</property>
+                            <property name="draw_indicator">False</property>
+                            <property name="group">left</property>
+                            <signal name="toggled" handler="on_toggle_right" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkRadioButton" id="justify">
+                            <property name="label">gtk-justify-fill</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="use_stock">True</property>
+                            <property name="image_position">top</property>
+                            <property name="draw_indicator">False</property>
+                            <property name="group">left</property>
+                            <signal name="toggled" handler="on_toggle_justify" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">3</property>
+                          </packing>
+                        </child>
                       </object>
                       <packing>
                         <property name="expand">True</property>
                         <property name="fill">True</property>
-                        <property name="padding">5</property>
                         <property name="position">1</property>
                       </packing>
                     </child>
+                    <child>
+                      <object class="GtkHButtonBox" id="hbuttonbox2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="spacing">6</property>
+                        <property name="layout_style">start</property>
+                        <child>
+                          <object class="GtkCheckButton" id="checkbutton1">
+                            <property name="label">gtk-bold</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="use_stock">True</property>
+                            <property name="image_position">top</property>
+                            <property name="draw_indicator">False</property>
+                            <signal name="toggled" handler="on_toggle_bold" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="checkbutton2">
+                            <property name="label">gtk-italic</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="use_stock">True</property>
+                            <property name="image_position">top</property>
+                            <property name="draw_indicator">False</property>
+                            <signal name="toggled" handler="on_toggle_italic" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="underline">
+                            <property name="label">gtk-underline</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="use_stock">True</property>
+                            <property name="image_position">top</property>
+                            <property name="draw_indicator">False</property>
+                            <signal name="toggled" handler="on_toggle_underline" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
                   </object>
                   <packing>
                     <property name="expand">True</property>
                     <property name="fill">True</property>
-                    <property name="padding">5</property>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkLabel" id="label4">
-                    <property name="height_request">30</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="xalign">0</property>
-                    <property name="yalign">1</property>
-                    <property name="xpad">5</property>
-                    <property name="label" translatable="yes">Example text:</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">3</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkTextView" id="example-textview">
-                    <property name="height_request">100</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="editable">False</property>
-                    <property name="wrap_mode">word-char</property>
-                    <property name="left_margin">10</property>
-                    <property name="right_margin">10</property>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">4</property>
+                    <property name="position">1</property>
                   </packing>
                 </child>
               </object>
               <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="padding">5</property>
                 <property name="position">1</property>
               </packing>
             </child>
-            <child type="tab">
-              <object class="GtkLabel" id="label2">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">Layout</property>
-              </object>
-              <packing>
-                <property name="position">1</property>
-                <property name="tab_fill">False</property>
-              </packing>
-            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="padding">5</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label4">
+            <property name="height_request">30</property>
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="yalign">1</property>
+            <property name="xpad">5</property>
+            <property name="label" translatable="yes">Example text:</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkTextView" id="example-textview">
+            <property name="height_request">100</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="editable">False</property>
+            <property name="wrap_mode">word-char</property>
+            <property name="left_margin">10</property>
+            <property name="right_margin">10</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Layout</property>
+      </object>
+      <packing>
+        <property name="position">1</property>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkVBox" id="vbox2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="border_width">6</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkFrame" id="frame1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
             <child>
-              <object class="GtkVBox" id="vbox2">
+              <object class="GtkAlignment" id="alignment1">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="border_width">6</property>
-                <property name="spacing">6</property>
+                <property name="left_padding">12</property>
                 <child>
-                  <object class="GtkFrame" id="frame1">
+                  <object class="GtkScrolledWindow" id="scrolledwindow2">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="label_xalign">0</property>
-                    <property name="shadow_type">none</property>
+                    <property name="can_focus">True</property>
                     <child>
-                      <object class="GtkAlignment" id="alignment1">
+                      <object class="GtkTreeView" id="interpreters_view">
                         <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="left_padding">12</property>
+                        <property name="can_focus">True</property>
+                        <property name="tooltip_text" translatable="yes">Which interpreter to use by default for each story format</property>
+                        <property name="model">interpreters</property>
+                        <property name="headers_clickable">False</property>
+                        <property name="rules_hint">True</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection" id="treeview-selection2"/>
+                        </child>
                         <child>
-                          <object class="GtkScrolledWindow" id="scrolledwindow2">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="hscrollbar_policy">automatic</property>
-                            <property name="vscrollbar_policy">automatic</property>
+                          <object class="GtkTreeViewColumn" id="format_column">
+                            <property name="title">Format</property>
+                            <child>
+                              <object class="GtkCellRendererText" id="format_renderer"/>
+                              <attributes>
+                                <attribute name="text">0</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkTreeViewColumn" id="interpreter_column">
+                            <property name="title">Interpreter</property>
                             <child>
-                              <object class="GtkTreeView" id="interpreters_view">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="tooltip_text" translatable="yes">Which interpreter to use by default for each story format</property>
-                                <property name="model">interpreters</property>
-                                <property name="headers_clickable">False</property>
-                                <property name="rules_hint">True</property>
-                                <child>
-                                  <object class="GtkTreeViewColumn" id="format_column">
-                                    <property name="title">Format</property>
-                                    <child>
-                                      <object class="GtkCellRendererText" id="format_renderer"/>
-                                      <attributes>
-                                        <attribute name="text">0</attribute>
-                                      </attributes>
-                                    </child>
-                                  </object>
-                                </child>
-                                <child>
-                                  <object class="GtkTreeViewColumn" id="interpreter_column">
-                                    <property name="title">Interpreter</property>
-                                    <child>
-                                      <object class="GtkCellRendererCombo" id="interpreter_renderer">
-                                        <property name="editable">True</property>
-                                        <property name="has_entry">False</property>
-                                        <property name="model">available_interpreters</property>
-                                        <property name="text_column">0</property>
-                                        <signal name="changed" handler="on_interpreter_cell_changed" swapped="no"/>
-                                      </object>
-                                      <attributes>
-                                        <attribute name="text">1</attribute>
-                                      </attributes>
-                                    </child>
-                                  </object>
-                                </child>
+                              <object class="GtkCellRendererCombo" id="interpreter_renderer">
+                                <property name="editable">True</property>
+                                <property name="has_entry">False</property>
+                                <property name="model">available_interpreters</property>
+                                <property name="text_column">0</property>
+                                <signal name="changed" handler="on_interpreter_cell_changed" swapped="no"/>
                               </object>
+                              <attributes>
+                                <attribute name="text">1</attribute>
+                              </attributes>
                             </child>
                           </object>
                         </child>
                       </object>
                     </child>
-                    <child type="label">
-                      <object class="GtkLabel" id="label10">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">&lt;b&gt;Preferred interpreters&lt;/b&gt;</property>
-                        <property name="use_markup">True</property>
-                      </object>
-                    </child>
                   </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkHBox" id="hbox3">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="spacing">6</property>
-                    <child>
-                      <object class="GtkLabel" id="label11">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">Look for _resource files in:</property>
-                        <property name="use_underline">True</property>
-                        <property name="mnemonic_widget">blorb_file_chooser</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkFileChooserButton" id="blorb_file_chooser">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="tooltip_text" translatable="yes">Where to look for Blorb resource files containing graphics and sound; normally, these are part of the story file itself, but they are provided as separate files in some older games.</property>
-                        <property name="action">select-folder</property>
-                        <signal name="file-set" handler="on_resource_file_set" swapped="no"/>
-                      </object>
-                      <packing>
-                        <property name="expand">True</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
               </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label10">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">&lt;b&gt;Preferred interpreters&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="hbox3">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkLabel" id="label11">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Look for _resource files in:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">blorb_file_chooser</property>
+              </object>
               <packing>
-                <property name="position">2</property>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
               </packing>
             </child>
-            <child type="tab">
-              <object class="GtkLabel" id="label3">
+            <child>
+              <object class="GtkFileChooserButton" id="blorb_file_chooser">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="label" translatable="yes">Interpreters</property>
+                <property name="tooltip_text" translatable="yes">Where to look for Blorb resource files containing graphics and sound; normally, these are part of the story file itself, but they are provided as separate files in some older games.</property>
+                <property name="action">select-folder</property>
+                <signal name="file-set" handler="on_resource_file_set" swapped="no"/>
               </object>
               <packing>
-                <property name="position">2</property>
-                <property name="tab_fill">False</property>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
               </packing>
             </child>
           </object>
           <packing>
-            <property name="expand">True</property>
-            <property name="fill">True</property>
-            <property name="position">2</property>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
           </packing>
         </child>
       </object>
+      <packing>
+        <property name="position">2</property>
+      </packing>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label3">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Interpreters</property>
+      </object>
+      <packing>
+        <property name="position">2</property>
+        <property name="tab_fill">False</property>
+      </packing>
     </child>
-    <action-widgets>
-      <action-widget response="0">button-close</action-widget>
-    </action-widgets>
   </object>
   <object class="GtkTreeStore" id="style-list">
     <columns>
index a2df145d4a269dc7a103d8728b405d42ad4dfafb..c5c971b01a9cc24250ad860917179999ccaea407 100644 (file)
@@ -1,40 +1,53 @@
-/*  Copyright 2006 P.F. Chimento
- *  This file is part of GNOME Inform 7.
- * 
- *  GNOME Inform 7 is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
  *
- *  GNOME Inform 7 is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with GNOME Inform 7; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
-#include <gtk/gtk.h>
-#include <stdarg.h>
 
+#include <stdarg.h>
+#include <glib.h>
+#include <gtk/gtk.h>
 #include "error.h"
 
 /* Create and display an error dialog box, with parent window parent, and
 message format string msg. If err is not NULL, tack the error message on to the
 end of the format string. */
 void 
-error_dialog(GtkWindow *parent, GError *err, const gchar *msg, ...) 
+error_dialog(GtkWindow *parent, GError *err, const char *msg, ...)
 {
     va_list ap;
     
     va_start(ap, msg);
-    gchar buffer[1024];
+    char buffer[1024];
     g_vsnprintf(buffer, 1024, msg, ap);
     va_end(ap);
     
-    gchar *message;
+    char *message;
     if(err) {
         message = g_strconcat(buffer, err->message, NULL);
         g_error_free(err);
index bb05fbeec8042b5a7ebf20de67774976fce82091..f9d7c7af7299e185f8ae4bb768b6b3fa3abfd139 100644 (file)
@@ -1,27 +1,45 @@
-/*  Copyright 2006 P.F. Chimento
- *  This file is part of GNOME Inform 7.
- * 
- *  GNOME Inform 7 is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
  *
- *  GNOME Inform 7 is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with GNOME Inform 7; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
-#ifndef ERROR_H
-#define ERROR_H
+
+#ifndef __ERROR_H__
+#define __ERROR_H__
 
 #include <stdarg.h>
+#include <glib.h>
 #include <gtk/gtk.h>
 
-void error_dialog(GtkWindow *parent, GError *err, const gchar *msg, ...);
+G_BEGIN_DECLS
+
+void error_dialog(GtkWindow *parent, GError *err, const char *msg, ...);
+
+G_END_DECLS
 
-#endif
+#endif /* __ERROR_H__ */
index bd007b4ee128b0a7966822a37c547ca98c7b7c85..36473d1697a2d08ffc3168bff0fb1cf364b4330d 100644 (file)
@@ -1,26 +1,26 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
- * main.c
- * Copyright (C) Philip en Marijn 2008 <>
- * 
- * main.c is free software copyrighted by Philip en Marijn.
- * 
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name ``Philip en Marijn'' nor the name of any other
- *    contributor may be used to endorse or promote products derived
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
  *    from this software without specific prior written permission.
- * 
- * main.c IS PROVIDED BY Philip en Marijn ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL Philip en Marijn OR ANY OTHER CONTRIBUTORS
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
 #include <glib.h>
-#include <glib/gi18n.h>
-#include <glib/gstdio.h>
 #include <gtk/gtk.h>
-
-/* Use a custom GSettings backend for our preferences file */
-#define G_SETTINGS_ENABLE_BACKEND
-#include <gio/gsettingsbackend.h>
-
-#include "error.h"
-#include <libchimara/chimara-glk.h>
-#include <libchimara/chimara-if.h>
-
-#include "preferences.h"
-
-/* Static global pointers to widgets */
-static GtkUIManager *uimanager = NULL;
-static GtkWidget *window = NULL;
-static GtkWidget *glk = NULL;
-
-/* Global global pointers */
-GtkBuilder *builder = NULL;
-GtkWidget *aboutwindow = NULL;
-GtkWidget *prefswindow = NULL;
-GtkWidget *toolbar = NULL;
-GSettings *prefs_settings = NULL;
-GSettings *state_settings = NULL;
-
-GObject *
-load_object(const gchar *name)
-{
-       GObject *retval;
-       if( (retval = gtk_builder_get_object(builder, name)) == NULL) {
-               error_dialog(NULL, NULL, "Error while getting object '%s'", name);
-               g_error("Error while getting object '%s'", name);
-       }
-       return retval;
-}
-
-static void
-change_window_title(ChimaraGlk *glk, GParamSpec *pspec, GtkWindow *window)
-{
-       gchar *program_name, *story_name, *title;
-       g_object_get(glk, "program-name", &program_name, "story-name", &story_name, NULL);
-       if(!program_name) {
-               gtk_window_set_title(window, "Chimara");
-               return;
-       }
-       else if(!story_name)
-               title = g_strdup_printf("%s - Chimara", program_name);
-       else
-               title = g_strdup_printf("%s - %s - Chimara", program_name, story_name);
-               
-       g_free(program_name);
-       g_free(story_name);
-       gtk_window_set_title(window, title);
-       g_free(title);
-}
-
-static void
-create_window(void)
-{
-       GError *error = NULL;
-
-       builder = gtk_builder_new();
-       if( !gtk_builder_add_from_file(builder, PACKAGE_DATA_DIR "/chimara.ui", &error) ) {
-#ifdef DEBUG
-               g_error_free(error);
-               error = NULL;
-               if( !gtk_builder_add_from_file(builder, PACKAGE_SRC_DIR "/chimara.ui", &error) ) {
-#endif /* DEBUG */
-                       error_dialog(NULL, error, "Error while building interface: ");  
-                       return;
-#ifdef DEBUG
-               }
-#endif /* DEBUG */
-       }
-
-       window = GTK_WIDGET(load_object("chimara"));
-       aboutwindow = GTK_WIDGET(load_object("aboutwindow"));
-       prefswindow = GTK_WIDGET(load_object("prefswindow"));
-       GtkActionGroup *actiongroup = GTK_ACTION_GROUP(load_object("actiongroup"));
-
-       /* Set the default value of the "View/Toolbar" menu item upon creation of a
-        new window to the "show-toolbar-default" setting, but bind the setting
-        one-way only - we don't want toolbars to disappear suddenly */
-       GtkToggleAction *toolbar_action = GTK_TOGGLE_ACTION(load_object("toolbar"));
-       gtk_toggle_action_set_active(toolbar_action, g_settings_get_boolean(state_settings, "show-toolbar-default"));
-       g_settings_bind(state_settings, "show-toolbar-default", toolbar_action, "active", G_SETTINGS_BIND_SET);
-
-       const gchar **ptr;
-       GtkRecentFilter *filter = gtk_recent_filter_new();
-       /* TODO: Use mimetypes and construct the filter dynamically depending on 
-       what plugins are installed */
-       const gchar *patterns[] = {
-               "*.z[1-8]", "*.[zg]lb", "*.[zg]blorb", "*.ulx", "*.blb", "*.blorb", NULL
-       };
-
-       for(ptr = patterns; *ptr; ptr++)
-               gtk_recent_filter_add_pattern(filter, *ptr);
-       GtkRecentChooser *recent = GTK_RECENT_CHOOSER(load_object("recent"));
-       gtk_recent_chooser_add_filter(recent, filter);
-
-       uimanager = gtk_ui_manager_new();
-       if( !gtk_ui_manager_add_ui_from_file(uimanager, PACKAGE_DATA_DIR "/chimara.menus", &error) ) {
-#ifdef DEBUG
-               g_error_free(error);
-               error = NULL;
-               if( !gtk_ui_manager_add_ui_from_file(uimanager, PACKAGE_SRC_DIR "/chimara.menus", &error) ) {
-#endif /* DEBUG */
-                       error_dialog(NULL, error, "Error while building interface: ");
-                       return;
-#ifdef DEBUG
-               }
-#endif /* DEBUG */
-       }
-
-       glk = chimara_if_new();
-       g_object_set(glk,
-           "ignore-errors", TRUE,
-           /*"interpreter-number", CHIMARA_IF_ZMACHINE_TANDY_COLOR,*/
-           NULL);
-       if( !chimara_glk_set_css_from_file(CHIMARA_GLK(glk), PACKAGE_DATA_DIR "/style.css", &error) ) {
-#ifdef DEBUG
-               g_error_free(error);
-               error = NULL;
-               if( !chimara_glk_set_css_from_file(CHIMARA_GLK(glk), PACKAGE_SRC_DIR "/style.css", &error) ) {
-#endif /* DEBUG */
-                       error_dialog(NULL, error, "Couldn't open CSS file: ");
-                       return;
-#ifdef DEBUG
-               }
-#endif /* DEBUG */
-       }
-       
-       /* DON'T UNCOMMENT THIS your eyes will burn
-        but it is a good test of programmatically altering just one style
-       chimara_glk_set_css_from_string(CHIMARA_GLK(glk),
-           "buffer.normal { font-family: 'Comic Sans MS'; }");*/
-       
-       GtkBox *vbox = GTK_BOX( gtk_builder_get_object(builder, "vbox") );                      
-       if(vbox == NULL)
-       {
-               error_dialog(NULL, NULL, "Could not find vbox");
-               return;
-       }
-
-       gtk_ui_manager_insert_action_group(uimanager, actiongroup, 0);
-       GtkWidget *menubar = gtk_ui_manager_get_widget(uimanager, "/menubar");
-       toolbar = gtk_ui_manager_get_widget(uimanager, "/toolbar");
-       gtk_widget_set_no_show_all(toolbar, TRUE);
-       if(gtk_toggle_action_get_active(toolbar_action))
-               gtk_widget_show(toolbar);
-       else
-               gtk_widget_hide(toolbar);
-
-       /* Connect the accelerators */
-       GtkAccelGroup *accels = gtk_ui_manager_get_accel_group(uimanager);
-       gtk_window_add_accel_group(GTK_WINDOW(window), accels);
-
-       gtk_box_pack_end(vbox, glk, TRUE, TRUE, 0);
-       gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0);
-       gtk_box_pack_start(vbox, toolbar, FALSE, FALSE, 0);
-       
-       gtk_builder_connect_signals(builder, glk);
-       g_signal_connect(glk, "notify::program-name", G_CALLBACK(change_window_title), window);
-       g_signal_connect(glk, "notify::story-name", G_CALLBACK(change_window_title), window);
-       
-       /* Create preferences window */
-       preferences_create(CHIMARA_GLK(glk));
-}
+#include "app.h"
 
 int
 main(int argc, char *argv[])
 {
-       GError *error = NULL;
-
 #ifdef ENABLE_NLS
        bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
        bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
@@ -224,48 +48,25 @@ main(int argc, char *argv[])
        gdk_threads_init();
        gtk_init(&argc, &argv);
 
-       /* Create configuration dir ~/.chimara */
-       gchar *configdir = g_build_filename(g_get_home_dir(), ".chimara", NULL);
-       if(!g_file_test(configdir, G_FILE_TEST_IS_DIR)
-               && g_mkdir(configdir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
-               g_error(_("Cannot create configuration directory ~/.chimara"));
-       g_free(configdir);
+       ChimaraApp *theapp = chimara_app_get();
 
-       /* Initialize settings file; it can be overridden by a "chimara-config" file
-        in the current directory */
-       gchar *keyfile;
-       if(g_file_test("chimara-config", G_FILE_TEST_IS_REGULAR))
-               keyfile = g_strdup("chimara-config");
-       else
-               keyfile = g_build_filename(g_get_home_dir(), ".chimara", "config", NULL);
-       GSettingsBackend *backend = g_keyfile_settings_backend_new(keyfile, "/org/chimara-if/player/", NULL);
-       prefs_settings = g_settings_new_with_backend("org.chimara-if.player.preferences", backend);
-       state_settings = g_settings_new_with_backend("org.chimara-if.player.state", backend);
-       g_free(keyfile);
+       //if(argc == 3) {
+       //      g_object_set(glk, "graphics-file", argv[2], NULL);
+       //}
+       //if(argc >= 2) {
+       //      if( !chimara_if_run_game(CHIMARA_IF(glk), argv[1], &error) ) {
+       //              error_dialog(GTK_WINDOW(window), error, "Error starting Glk library: ");
+       //              return 1;
+       //      }
+       //}
 
-       create_window();
-       gtk_widget_show_all(window);
-
-       g_object_unref( G_OBJECT(uimanager) );
-
-       if(argc == 3) {
-               g_object_set(glk, "graphics-file", argv[2], NULL);
-       }
-       if(argc >= 2) {
-               if( !chimara_if_run_game(CHIMARA_IF(glk), argv[1], &error) ) {
-                       error_dialog(GTK_WINDOW(window), error, "Error starting Glk library: ");
-                       return 1;
-               }
-       }
+       gtk_widget_show_all(theapp->browser_window);
 
     gdk_threads_enter();
        gtk_main();
        gdk_threads_leave();
 
-       chimara_glk_stop(CHIMARA_GLK(glk));
-       chimara_glk_wait(CHIMARA_GLK(glk));
-
-       g_object_unref( G_OBJECT(builder) );
+       g_object_unref(theapp);
 
        return 0;
 }
diff --git a/player/player.c b/player/player.c
new file mode 100644 (file)
index 0000000..10f45d5
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <libchimara/chimara-glk.h>
+#include <libchimara/chimara-if.h>
+#include "player.h"
+#include "app.h"
+#include "error.h"
+#include "util.h"
+
+typedef struct _ChimaraPlayerPrivate {
+       int dummy;
+} ChimaraPlayerPrivate;
+
+#define CHIMARA_PLAYER_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), CHIMARA_TYPE_PLAYER, ChimaraPlayerPrivate))
+#define CHIMARA_PLAYER_USE_PRIVATE ChimaraPlayerPrivate *priv = CHIMARA_PLAYER_PRIVATE(self)
+
+G_DEFINE_TYPE(ChimaraPlayer, chimara_player, GTK_TYPE_WINDOW);
+
+static void
+change_window_title(ChimaraGlk *glk, GParamSpec *pspec, GtkWindow *window)
+{
+       gchar *program_name, *story_name, *title;
+       g_object_get(glk, "program-name", &program_name, "story-name", &story_name, NULL);
+       if(!program_name) {
+               gtk_window_set_title(window, "Chimara");
+               return;
+       }
+       else if(!story_name)
+               title = g_strdup_printf("%s - Chimara", program_name);
+       else
+               title = g_strdup_printf("%s - %s - Chimara", program_name, story_name);
+       
+       g_free(program_name);
+       g_free(story_name);
+       gtk_window_set_title(window, title);
+       g_free(title);
+}
+
+static void
+on_css_changed(GSettings *prefs_settings, char *key, ChimaraPlayer *self)
+{
+       char *user_css;
+       g_settings_get(prefs_settings, "css-file", "ms", &user_css);
+       if(user_css) {
+               if(!chimara_glk_set_css_from_file(CHIMARA_GLK(self->glk), user_css, NULL)) {
+                       /* If the setting didn't point to a CSS file, fail silently and
+                        null the setting */
+                       g_settings_set(prefs_settings, "css-file", "ms", NULL);
+               }
+               g_free(user_css);
+       }
+}
+
+static void
+chimara_player_dispose(GObject *object)
+{
+       ChimaraPlayer *self = CHIMARA_PLAYER(object);
+       if(chimara_glk_get_running(CHIMARA_GLK(self->glk))) {
+               chimara_glk_stop(CHIMARA_GLK(self->glk));
+               chimara_glk_wait(CHIMARA_GLK(self->glk));
+       }
+       
+       /* Chain up */
+       G_OBJECT_CLASS(chimara_player_parent_class)->dispose(object);
+}
+
+static void
+chimara_player_finalize(GObject *object)
+{
+       g_object_unref(CHIMARA_PLAYER(object)->glk);
+       
+       /* Chain up */
+       G_OBJECT_CLASS(chimara_player_parent_class)->finalize(object);
+}
+
+static void
+chimara_player_class_init(ChimaraPlayerClass *klass)
+{
+       /* Override methods of parent classes */
+       GObjectClass *object_class = G_OBJECT_CLASS(klass);
+       object_class->dispose = chimara_player_dispose;
+       object_class->finalize = chimara_player_finalize;
+
+       /* Private data */
+       g_type_class_add_private(klass, sizeof(ChimaraPlayerPrivate));
+}
+
+static void
+chimara_player_init(ChimaraPlayer *self)
+{      
+       GError *error = NULL;
+       ChimaraApp *theapp = chimara_app_get();
+
+       /* Set parent properties */
+       g_object_set(self,
+               "title", _("Chimara"),
+               "default-width", 600,
+               "default-height", 800,
+               NULL);
+
+       /* Construct user interface */
+       char *object_ids[] = {
+               "actiongroup",
+               "player-vbox",
+               NULL
+       };
+       GtkBuilder *builder = new_builder_with_objects(object_ids);
+
+       GtkActionGroup *actiongroup = GTK_ACTION_GROUP(load_object(builder, "actiongroup"));
+
+       /* Set the default value of the "View/Toolbar" menu item upon creation of a
+        new window to the "show-toolbar-default" setting, but bind the setting
+        one-way only - we don't want toolbars to disappear suddenly */
+       GtkToggleAction *toolbar_action = GTK_TOGGLE_ACTION(load_object(builder, "toolbar"));
+       gtk_toggle_action_set_active(toolbar_action, g_settings_get_boolean(theapp->state_settings, "show-toolbar-default"));
+       g_settings_bind(theapp->state_settings, "show-toolbar-default", toolbar_action, "active", G_SETTINGS_BIND_SET);
+
+       self->glk = chimara_if_new();
+       g_object_set(self->glk,
+                                "ignore-errors", TRUE,
+                                /*"interpreter-number", CHIMARA_IF_ZMACHINE_TANDY_COLOR,*/
+                                NULL);
+
+       /* Set the CSS styles for the interpreter */
+       char *default_css = get_data_file_path("style.css");
+       if( !chimara_glk_set_css_from_file(CHIMARA_GLK(self->glk), default_css, &error) ) {
+               error_dialog(GTK_WINDOW(self), error, "Couldn't open default CSS file: ");
+       }
+       g_free(default_css);
+       on_css_changed(theapp->prefs_settings, "css-file", self);
+       
+       /* DON'T UNCOMMENT THIS your eyes will burn
+        but it is a good test of programmatically altering just one style
+        chimara_glk_set_css_from_string(CHIMARA_GLK(glk),
+        "buffer.normal { font-family: 'Comic Sans MS'; }");*/
+
+       GtkUIManager *uimanager = new_ui_manager("player.menus");
+       gtk_ui_manager_insert_action_group(uimanager, actiongroup, 0);
+       gtk_ui_manager_insert_action_group(uimanager, chimara_app_get_action_group(theapp), 1);
+       GtkWidget *menubar = gtk_ui_manager_get_widget(uimanager, "/player_menu");
+       self->toolbar = gtk_ui_manager_get_widget(uimanager, "/player_toolbar");
+       gtk_widget_set_no_show_all(self->toolbar, TRUE);
+       if(gtk_toggle_action_get_active(toolbar_action))
+               gtk_widget_show(self->toolbar);
+       else
+               gtk_widget_hide(self->toolbar);
+       
+       /* Connect the accelerators */
+       GtkAccelGroup *accels = gtk_ui_manager_get_accel_group(uimanager);
+       gtk_window_add_accel_group(GTK_WINDOW(self), accels);
+
+       GtkBox *vbox = GTK_BOX(load_object(builder, "player-vbox"));
+       gtk_box_pack_end(vbox, self->glk, TRUE, TRUE, 0);
+       g_object_ref(self->glk); /* add an extra reference to keep it alive while
+                                                         the Glk program shuts down */
+       gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0);
+       gtk_box_pack_start(vbox, self->toolbar, FALSE, FALSE, 0);
+       gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(vbox));
+       
+       gtk_builder_connect_signals(builder, self);
+       g_signal_connect(self->glk, "notify::program-name", G_CALLBACK(change_window_title), self);
+       g_signal_connect(self->glk, "notify::story-name", G_CALLBACK(change_window_title), self);
+       g_signal_connect(theapp->prefs_settings, "changed::css-file", G_CALLBACK(on_css_changed), self);
+
+       g_object_unref(builder);
+       g_object_unref(uimanager);
+}
+
+/* PUBLIC FUNCTIONS */
+
+GtkWidget *
+chimara_player_new(void)
+{
+    return GTK_WIDGET(g_object_new(CHIMARA_TYPE_PLAYER,
+               "type", GTK_WINDOW_TOPLEVEL,
+               NULL));
+}
+
+void
+chimara_player_set_user_css_file(ChimaraPlayer *self, const char *filename)
+{
+       chimara_glk_set_css_to_default(CHIMARA_GLK(self->glk));
+       chimara_glk_set_css_from_file(CHIMARA_GLK(self->glk), filename, NULL);
+}
+
+/* GLADE CALLBACKS */
+
+#if 0
+/* If a game is running in @glk, warn the user that they will quit the currently
+running game if they open a new one. Returns TRUE if no game was running.
+Returns FALSE if the user cancelled. Returns TRUE and shuts down the running
+game if the user wishes to continue. */
+static gboolean
+confirm_open_new_game(ChimaraGlk *glk)
+{
+       g_return_val_if_fail(glk && CHIMARA_IS_GLK(glk), FALSE);
+       
+       GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
+       
+       if(chimara_glk_get_running(glk)) {
+               GtkWidget *dialog = gtk_message_dialog_new(window,
+                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                   GTK_MESSAGE_WARNING,
+                   GTK_BUTTONS_CANCEL,
+                   _("Are you sure you want to open a new game?"));
+               gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
+                   _("If you open a new game, you will quit the one you are currently playing."));
+               gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OPEN, GTK_RESPONSE_OK);
+               gint response = gtk_dialog_run(GTK_DIALOG(dialog));
+               gtk_widget_destroy(dialog);
+               
+               if(response != GTK_RESPONSE_OK)
+                       return FALSE;
+
+               chimara_glk_stop(glk);
+               chimara_glk_wait(glk);
+       }
+       return TRUE;
+}
+#endif
+
+void
+on_stop_activate(GtkAction *action, ChimaraPlayer *player)
+{
+       chimara_glk_stop(CHIMARA_GLK(player->glk));
+}
+
+void
+on_copy_activate(GtkAction *action, ChimaraPlayer *player)
+{
+       GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(player));
+       /* Call "copy clipboard" on any widget that defines it */
+       if(GTK_IS_LABEL(focus) || GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
+               g_signal_emit_by_name(focus, "copy-clipboard");
+}
+
+void
+on_paste_activate(GtkAction *action, ChimaraPlayer *player)
+{
+       GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(player));
+       /* Call "paste clipboard" on any widget that defines it */
+       if(GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
+               g_signal_emit_by_name(focus, "paste-clipboard");
+}
+
+void
+on_toolbar_toggled(GtkToggleAction *action, ChimaraPlayer *player)
+{
+       if(gtk_toggle_action_get_active(action))
+               gtk_widget_show(player->toolbar);
+       else
+               gtk_widget_hide(player->toolbar);
+}
+
+void
+on_undo_activate(GtkAction *action, ChimaraPlayer *player)
+{
+       chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "undo");
+}
+
+void 
+on_save_activate(GtkAction *action, ChimaraPlayer *player)
+{
+       chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "save");
+}
+
+void 
+on_restore_activate(GtkAction *action, ChimaraPlayer *player)
+{
+       chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "restore");
+}
+
+void 
+on_restart_activate(GtkAction *action, ChimaraPlayer *player)
+{
+       chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "restart");
+}
+
+void 
+on_quit_activate(GtkAction *action, ChimaraPlayer *player)
+{
+       chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "quit");
+}
+
diff --git a/player/player.h b/player/player.h
new file mode 100644 (file)
index 0000000..f777b87
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLAYER_H__
+#define __PLAYER_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define CHIMARA_TYPE_PLAYER            (chimara_player_get_type())
+#define CHIMARA_PLAYER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), CHIMARA_TYPE_PLAYER, ChimaraPlayer))
+#define CHIMARA_PLAYER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), CHIMARA_TYPE_PLAYER, ChimaraPlayerClass))
+#define CHIMARA_IS_PLAYER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), CHIMARA_TYPE_PLAYER))
+#define CHIMARA_IS_PLAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), CHIMARA_TYPE_PLAYER))
+#define CHIMARA_PLAYER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), CHIMARA_TYPE_PLAYER, ChimaraPlayerClass))
+
+typedef struct _ChimaraPlayer {
+       GtkWindow parent_instance;
+       
+       /* Public pointers to widgets */
+       GtkWidget *glk, *toolbar;
+} ChimaraPlayer;
+
+typedef struct _ChimaraPlayerClass {
+       GtkWindowClass parent_class;
+} ChimaraPlayerClass;
+
+GType chimara_player_get_type(void) G_GNUC_CONST;
+GtkWidget *chimara_player_new(void);
+void chimara_player_set_user_css_file(ChimaraPlayer *player, const char *filename);
+
+G_END_DECLS
+
+#endif /* __PLAYER_H__ */
diff --git a/player/player.menus b/player/player.menus
new file mode 100644 (file)
index 0000000..3d80345
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<ui>
+  <menubar name="player_menu">
+    <menu action="game">
+      <menuitem action="stop"/>
+    </menu>
+    <menu action="edit">
+      <menuitem action="copy"/>
+      <menuitem action="paste"/>
+      <separator/>
+      <menuitem action="preferences"/>
+    </menu>
+    <menu action="view">
+      <menuitem action="toolbar"/>
+    </menu>
+    <menu action="command">
+      <menuitem action="undo"/>
+      <menuitem action="save"/>
+      <menuitem action="restore"/>
+      <menuitem action="restart"/>
+      <menuitem action="quit"/>
+    </menu>
+    <menu action="help">
+      <menuitem action="about"/>
+    </menu>
+  </menubar>
+  <toolbar name="player_toolbar">
+    <toolitem action="open"/>
+    <separator/>
+    <toolitem action="restore"/>
+    <toolitem action="save"/>
+  </toolbar>
+</ui>
index 9154f4e290a4299e221fe4211688e2d76cdba244..df1edc62789d17bcce9df607a90cf360dce6ebe7 100644 (file)
@@ -1,26 +1,26 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
- * callbacks.c
- * Copyright (C) Philip en Marijn 2008 <>
- * 
- * preferences.c is free software copyrighted by Philip en Marijn.
- * 
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name ``Philip en Marijn'' nor the name of any other
- *    contributor may be used to endorse or promote products derived
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
  *    from this software without specific prior written permission.
- * 
- * preferences.c IS PROVIDED BY Philip en Marijn ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL Philip en Marijn OR ANY OTHER CONTRIBUTORS
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stdlib.h>
 #include <glib.h>
+#include <glib-object.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <libchimara/chimara-glk.h>
 #include <libchimara/chimara-if.h>
-#include <config.h>
 #include "error.h"
+#include "app.h"
+#include "preferences.h"
+#include "util.h"
+
+typedef struct _ChimaraPrefsPrivate {
+       int dummy;
+} ChimaraPrefsPrivate;
+
+#define CHIMARA_PREFS_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), CHIMARA_TYPE_PREFS, ChimaraPrefsPrivate))
+#define CHIMARA_PREFS_USE_PRIVATE ChimaraPrefsPrivate *priv = CHIMARA_PREFS_PRIVATE(self)
+
+G_DEFINE_TYPE(ChimaraPrefs, chimara_prefs, GTK_TYPE_DIALOG);
 
-GObject *load_object(const gchar *name);
 static GtkTextTag *current_tag;
 static GtkListStore *preferred_list;
 
-static void style_tree_select_callback(GtkTreeSelection *selection, ChimaraGlk *glk);
+static void style_tree_select_callback(GtkTreeSelection *selection);
+
+static void
+chimara_prefs_finalize(GObject *self)
+{
+       /* Chain up */
+       G_OBJECT_CLASS(chimara_prefs_parent_class)->finalize(self);
+}
+
+static void
+chimara_prefs_class_init(ChimaraPrefsClass *klass)
+{
+       /* Override methods of parent classes */
+       GObjectClass *object_class = G_OBJECT_CLASS(klass);
+       object_class->finalize = chimara_prefs_finalize;
+
+       /* Private data */
+       g_type_class_add_private(klass, sizeof(ChimaraPrefsPrivate));
+}
 
 /* Internal functions to convert from human-readable names in the config file
 to enums and back. Later: replace with plugin functions. */
@@ -135,11 +163,38 @@ interpreter_to_display_string(ChimaraIFInterpreter interp)
 }
 
 /* Create the preferences dialog. */
-void
-preferences_create(ChimaraGlk *glk)
+static void
+chimara_prefs_init(ChimaraPrefs *self)
 {
+       ChimaraApp *theapp = chimara_app_get();
+
+       /* Set parent properties */
+       g_object_set(self,
+               "title", _("Chimara Preferences"),
+               "window-position", GTK_WIN_POS_CENTER,
+               "type-hint", GDK_WINDOW_TYPE_HINT_DIALOG,
+               "border-width", 6,
+               NULL);
+       gtk_dialog_add_buttons(GTK_DIALOG(self),
+               GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+               NULL);
+       
+       /* Build user interface */
+       char *object_ids[] = {
+               "prefs-notebook",
+               "available_interpreters",
+               "interpreters",
+               "style-list",
+               NULL
+       };
+       GtkBuilder *builder = new_builder_with_objects(object_ids);
+
+       GtkWidget *notebook = GTK_WIDGET( load_object(builder, "prefs-notebook") );
+       GtkWidget *content_area = gtk_dialog_get_content_area( GTK_DIALOG(self) );
+       gtk_container_add( GTK_CONTAINER(content_area), notebook );
+       
        /* Initialize the tree of style names */
-       GtkTreeStore *style_list = GTK_TREE_STORE( load_object("style-list") );
+       GtkTreeStore *style_list = GTK_TREE_STORE( load_object(builder, "style-list") );
        GtkTreeIter buffer, grid, buffer_child, grid_child;
 
        gtk_tree_store_append(style_list, &buffer, NULL);
@@ -149,7 +204,7 @@ preferences_create(ChimaraGlk *glk)
 
        int i;
        unsigned int num_tags;
-       const gchar **tag_names = chimara_glk_get_tag_names(glk, &num_tags);
+       const gchar **tag_names = chimara_glk_get_tag_names(&num_tags);
        for(i=0; i<num_tags; i++) {
                gtk_tree_store_append(style_list, &buffer_child, &buffer);
                gtk_tree_store_append(style_list, &grid_child, &grid);
@@ -158,37 +213,31 @@ preferences_create(ChimaraGlk *glk)
        }
 
        /* Set selection mode to single select */
-       GtkTreeView *view = GTK_TREE_VIEW( load_object("style-treeview") );
+       GtkTreeView *view = GTK_TREE_VIEW( load_object(builder, "style-treeview") );
        GtkTreeSelection *selection = gtk_tree_view_get_selection(view);
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
-       g_signal_connect(selection, "changed", G_CALLBACK(style_tree_select_callback), glk);
+       g_signal_connect(selection, "changed", G_CALLBACK(style_tree_select_callback), NULL);
 
        /* Bind the preferences to the entries in the preferences file */
-       extern GSettings *prefs_settings;
-       GObject *flep = G_OBJECT( load_object("flep") );
-       g_settings_bind(prefs_settings, "flep", flep, "active", G_SETTINGS_BIND_DEFAULT);
-       GtkFileChooser *blorb_chooser = GTK_FILE_CHOOSER( load_object("blorb_file_chooser") );
-       GtkFileChooser *css_chooser = GTK_FILE_CHOOSER( load_object("css-filechooser") );
+       GObject *flep = G_OBJECT( load_object(builder, "flep") );
+       g_settings_bind(theapp->prefs_settings, "flep", flep, "active", G_SETTINGS_BIND_DEFAULT);
+       GtkFileChooser *blorb_chooser = GTK_FILE_CHOOSER( load_object(builder, "blorb_file_chooser") );
+       GtkFileChooser *css_chooser = GTK_FILE_CHOOSER( load_object(builder, "css-filechooser") );
        char *filename;
-       g_settings_get(prefs_settings, "resource-path", "ms", &filename);
+       g_settings_get(theapp->prefs_settings, "resource-path", "ms", &filename);
        if(filename) {
                gtk_file_chooser_set_filename(blorb_chooser, filename);
                g_free(filename);
        }
-       g_settings_get(prefs_settings, "css-file", "ms", &filename);
+
+       g_settings_get(theapp->prefs_settings, "css-file", "ms", &filename);
        if(filename) {
-               if(!chimara_glk_set_css_from_file(glk, filename, NULL)) {
-                       /* If the setting didn't point to a CSS file, fail silently and
-                        null the setting */
-                       g_settings_set(prefs_settings, "css-file", "ms", NULL);
-               } else {
-                       gtk_file_chooser_set_filename(css_chooser, filename);
-               }
+               gtk_file_chooser_set_filename(css_chooser, filename);
                g_free(filename);
        }
 
        /* Populate the list of available interpreters */
-       GtkListStore *interp_list = GTK_LIST_STORE( load_object("available_interpreters") );
+       GtkListStore *interp_list = GTK_LIST_STORE( load_object(builder, "available_interpreters") );
        unsigned int count;
        GtkTreeIter tree_iter;
        for(count = 0; count < CHIMARA_IF_NUM_INTERPRETERS; count++) {
@@ -199,33 +248,51 @@ preferences_create(ChimaraGlk *glk)
        }
 
        /* Get the list of preferred interpreters from the preferences */
-       GVariantIter *iter;
-       char *format, *plugin;
-       g_settings_get(prefs_settings, "preferred-interpreters", "a{ss}", &iter);
-       while(g_variant_iter_loop(iter, "{ss}", &format, &plugin)) {
-               ChimaraIFFormat format_num = parse_format(format);
-               if(format_num == CHIMARA_IF_FORMAT_NONE)
-                       continue;
-               ChimaraIFInterpreter interp_num = parse_interpreter(plugin);
-               if(interp_num == CHIMARA_IF_INTERPRETER_NONE)
-                       continue;
-               chimara_if_set_preferred_interpreter(CHIMARA_IF(glk), format_num, interp_num);
-       }
-       g_variant_iter_free(iter);
+       //GVariantIter *iter;
+       //char *format, *plugin;
+       //g_settings_get(prefs_settings, "preferred-interpreters", "a{ss}", &iter);
+       //while(g_variant_iter_loop(iter, "{ss}", &format, &plugin)) {
+       //      ChimaraIFFormat format_num = parse_format(format);
+       //      if(format_num == CHIMARA_IF_FORMAT_NONE)
+       //              continue;
+       //      ChimaraIFInterpreter interp_num = parse_interpreter(plugin);
+       //      if(interp_num == CHIMARA_IF_INTERPRETER_NONE)
+       //              continue;
+       //      chimara_if_set_preferred_interpreter(CHIMARA_IF(glk), format_num, interp_num);
+       //}
+       //g_variant_iter_free(iter);
 
        /* Display it all in the list */
-       preferred_list = GTK_LIST_STORE( load_object("interpreters") );
-       for(count = 0; count < CHIMARA_IF_NUM_FORMATS; count++) {
-               gtk_list_store_append(preferred_list, &tree_iter);
-               gtk_list_store_set(preferred_list, &tree_iter,
-                       0, format_to_display_string(count),
-                       1, interpreter_to_display_string(chimara_if_get_preferred_interpreter(CHIMARA_IF(glk), count)),
-                       -1);
-       }
+       //preferred_list = GTK_LIST_STORE( load_object(builder, "interpreters") );
+       //for(count = 0; count < CHIMARA_IF_NUM_FORMATS; count++) {
+       //      gtk_list_store_append(preferred_list, &tree_iter);
+       //      gtk_list_store_set(preferred_list, &tree_iter,
+       //              0, format_to_display_string(count),
+       //              1, interpreter_to_display_string(chimara_if_get_preferred_interpreter(CHIMARA_IF(glk), count)),
+       //              -1);
+       //}
+
+       gtk_builder_connect_signals(builder, self);
+       g_object_unref(builder);
+
+       /* Connect own signals */
+       g_signal_connect(self, "response", G_CALLBACK(gtk_widget_hide), NULL);
+       g_signal_connect(self, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
 }
 
+/* PUBLIC FUNCTIONS */
+GtkWidget *
+chimara_prefs_new(void)
+{
+       return GTK_WIDGET(g_object_new(CHIMARA_TYPE_PREFS,
+               "type", GTK_WINDOW_TOPLEVEL,
+               NULL));
+}
+
+/* GLADE CALLBACKS */
+
 static void
-style_tree_select_callback(GtkTreeSelection *selection, ChimaraGlk *glk)
+style_tree_select_callback(GtkTreeSelection *selection)
 {
        GtkTreeIter child, parent;
        gchar *child_name, *parent_name;
@@ -240,10 +307,10 @@ style_tree_select_callback(GtkTreeSelection *selection, ChimaraGlk *glk)
                return;
 
        gtk_tree_model_get(model, &parent, 0, &parent_name, -1);
-       if( !strcmp(parent_name, "Text buffer") ) 
-               current_tag = chimara_glk_get_tag(glk, CHIMARA_GLK_TEXT_BUFFER, child_name);
-       else
-               current_tag = chimara_glk_get_tag(glk, CHIMARA_GLK_TEXT_GRID, child_name);
+       //if( !strcmp(parent_name, "Text buffer") )
+       //      current_tag = chimara_glk_get_tag(glk, CHIMARA_GLK_TEXT_BUFFER, child_name);
+       //else
+       //      current_tag = chimara_glk_get_tag(glk, CHIMARA_GLK_TEXT_GRID, child_name);
 }
 
 void
@@ -339,58 +406,52 @@ on_font_set(GtkFontButton *button, ChimaraGlk *glk)
 void
 on_css_filechooser_file_set(GtkFileChooserButton *button, ChimaraGlk *glk)
 {
-       GError *error = NULL;
-       extern GSettings *prefs_settings;
+       ChimaraApp *theapp = chimara_app_get();
        char *filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(button) );
-       if(!chimara_glk_set_css_from_file(glk, filename, &error)) {
-               error_dialog(NULL, error, "There was a problem reading the CSS file: ");
-               g_settings_set(prefs_settings, "css-file", "ms", NULL);
-       } else {
-               g_settings_set(prefs_settings, "css-file", "ms", filename);
-       }
+       g_settings_set(theapp->prefs_settings, "css-file", "ms", filename);
        g_free(filename);
 }
 
 void
 on_resource_file_set(GtkFileChooserButton *button, ChimaraGlk *glk)
 {
-       extern GSettings *prefs_settings;
+       ChimaraApp *theapp = chimara_app_get();
        char *filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(button) );
-       g_settings_set(prefs_settings, "resource-path", "ms", filename);
+       g_settings_set(theapp->prefs_settings, "resource-path", "ms", filename);
        g_free(filename);
 }
 
 void
 on_interpreter_cell_changed(GtkCellRendererCombo *combo, char *path_string, GtkTreeIter *new_iter, ChimaraGlk *glk)
 {
-       unsigned int format, interpreter;
-       format = (unsigned int)strtol(path_string, NULL, 10);
-       GtkTreeModel *combo_model;
-       g_object_get(combo, "model", &combo_model, NULL);
-       char *combo_string = gtk_tree_model_get_string_from_iter(combo_model, new_iter);
-       interpreter = (unsigned int)strtol(combo_string, NULL, 10);
-       g_free(combo_string);
+       //unsigned int format, interpreter;
+       //format = (unsigned int)strtol(path_string, NULL, 10);
+       //GtkTreeModel *combo_model;
+       //g_object_get(combo, "model", &combo_model, NULL);
+       //char *combo_string = gtk_tree_model_get_string_from_iter(combo_model, new_iter);
+       //interpreter = (unsigned int)strtol(combo_string, NULL, 10);
+       //g_free(combo_string);
 
-       chimara_if_set_preferred_interpreter(CHIMARA_IF(glk), format, interpreter);
+       //chimara_if_set_preferred_interpreter(CHIMARA_IF(glk), format, interpreter);
 
        /* Display the new setting in the list */
-       GtkTreeIter iter;
-       GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
-       gtk_tree_model_get_iter(GTK_TREE_MODEL(preferred_list), &iter, path);
-       gtk_tree_path_free(path);
-       gtk_list_store_set(preferred_list, &iter,
-               1, interpreter_to_display_string(interpreter),
-               -1);
+       //GtkTreeIter iter;
+       //GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
+       //gtk_tree_model_get_iter(GTK_TREE_MODEL(preferred_list), &iter, path);
+       //gtk_tree_path_free(path);
+       //gtk_list_store_set(preferred_list, &iter,
+       //      1, interpreter_to_display_string(interpreter),
+       //      -1);
 
        /* Save the new settings in the preferences file */
-       extern GSettings *prefs_settings;
-       GVariantBuilder *builder = g_variant_builder_new( G_VARIANT_TYPE("a{ss}") );
-       unsigned int count;
-       for(count = 0; count < CHIMARA_IF_NUM_FORMATS; count++) {
-               g_variant_builder_add(builder, "{ss}",
-                       format_to_string(count),
-                       interpreter_to_string(chimara_if_get_preferred_interpreter(CHIMARA_IF(glk), count)));
-       }
-       g_settings_set(prefs_settings, "preferred-interpreters", "a{ss}", builder);
-       g_variant_builder_unref(builder);
+       //ChimaraApp *theapp = chimara_app_get();
+       //GVariantBuilder *builder = g_variant_builder_new( G_VARIANT_TYPE("a{ss}") );
+       //unsigned int count;
+       //for(count = 0; count < CHIMARA_IF_NUM_FORMATS; count++) {
+       //      g_variant_builder_add(builder, "{ss}",
+       //              format_to_string(count),
+       //              interpreter_to_string(chimara_if_get_preferred_interpreter(CHIMARA_IF(glk), count)));
+       //}
+       //g_settings_set(theapp->prefs_settings, "preferred-interpreters", "a{ss}", builder);
+       //g_variant_builder_unref(builder);
 }
index 9a1fad0c59842b2f2935f5e38900c51d05299517..243de18ec9072c325e4161df7a8e77fcbeab4a28 100644 (file)
@@ -1,9 +1,62 @@
-#ifndef PREFERENCES_H
-#define PREFERENCES_H
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
+#ifndef __PREFERENCES_H__
+#define __PREFERENCES_H__
+
+#include <glib.h>
 #include <gtk/gtk.h>
-#include <libchimara/chimara-glk.h>
 
-G_GNUC_INTERNAL void preferences_create(ChimaraGlk *glk);
+G_BEGIN_DECLS
+
+#define CHIMARA_TYPE_PREFS            (chimara_prefs_get_type())
+#define CHIMARA_PREFS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), CHIMARA_TYPE_PREFS, ChimaraPrefs))
+#define CHIMARA_PREFS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), CHIMARA_TYPE_PREFS, ChimaraPrefsClass))
+#define CHIMARA_IS_PREFS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), CHIMARA_TYPE_PREFS))
+#define CHIMARA_IS_PREFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), CHIMARA_TYPE_PREFS))
+#define CHIMARA_PREFS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), CHIMARA_TYPE_PREFS, ChimaraPrefsClass))
+
+typedef struct _ChimaraPrefs {
+       GtkDialog parent_instance;
+       
+       /* Public pointers */
+} ChimaraPrefs;
+
+typedef struct _ChimaraPrefsClass {
+       GtkDialogClass parent_class;
+} ChimaraPrefsClass;
+
+GType chimara_prefs_get_type(void) G_GNUC_CONST;
+GtkWidget *chimara_prefs_new(void);
+
+G_END_DECLS
 
-#endif
+#endif /* __PREFERENCES_H__ */
diff --git a/player/util.c b/player/util.c
new file mode 100644 (file)
index 0000000..70d1ed5
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <config.h>
+#include "util.h"
+#include "error.h"
+
+char *
+get_data_file_path(const char *filename)
+{
+       char *path = g_build_filename(PACKAGE_DATA_DIR, filename, NULL);
+       if(g_file_test(path, G_FILE_TEST_EXISTS))
+               return path;
+#ifdef DEBUG
+       g_free(path);
+       path = g_build_filename(PACKAGE_SRC_DIR, filename, NULL);
+       if(g_file_test(path, G_FILE_TEST_EXISTS))
+               return path;
+#endif /* DEBUG */
+       g_error("Could not find data file: %s", filename);
+}
+
+GtkBuilder *
+new_builder_with_objects(char **object_ids)
+{
+       GError *error = NULL;
+       GtkBuilder *builder = gtk_builder_new();
+       
+       if( !gtk_builder_add_objects_from_file(builder, PACKAGE_DATA_DIR "/chimara.ui", object_ids, &error) ) {
+#ifdef DEBUG
+               g_error_free(error);
+               error = NULL;
+               if( !gtk_builder_add_objects_from_file(builder, PACKAGE_SRC_DIR "/chimara.ui", object_ids, &error) )
+#endif /* DEBUG */
+                       goto fail;
+       }
+       return builder;
+
+fail:
+       error_dialog(NULL, error, _("Error while building interface: "));
+       return NULL;
+}
+
+GObject *
+load_object(GtkBuilder *builder, const char *name)
+{
+       GObject *retval;
+       if( (retval = gtk_builder_get_object(builder, name)) == NULL) {
+               error_dialog(NULL, NULL, "Error while getting object '%s'", name);
+               g_error("Error while getting object '%s'", name);
+       }
+       return retval;
+}
+
+GtkUIManager *
+new_ui_manager(const char *filename)
+{
+       GError *error = NULL;
+       GtkUIManager *uimanager = gtk_ui_manager_new();
+       char *path = g_build_filename(PACKAGE_DATA_DIR, filename, NULL);
+       
+       if( !gtk_ui_manager_add_ui_from_file(uimanager, path, &error) ) {
+#ifdef DEBUG
+               g_free(path);
+               path = g_build_filename(PACKAGE_SRC_DIR, filename, NULL);
+               g_error_free(error);
+               error = NULL;
+               if( !gtk_ui_manager_add_ui_from_file(uimanager, path, &error) )
+#endif /* DEBUG */
+                       goto fail;
+       }
+       return uimanager;
+
+fail:
+       error_dialog(NULL, error, _("Error while building interface: "));
+       return NULL;
+}
+
diff --git a/player/util.h b/player/util.h
new file mode 100644 (file)
index 0000000..73bed8c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
+ * All rights reserved.
+ *
+ * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
+ *    any other contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+char *get_data_file_path(const char *filename);
+GtkBuilder *new_builder_with_objects(char **object_ids);
+GObject *load_object(GtkBuilder *builder, const char *name);
+GtkUIManager *new_ui_manager(const char *filename);
+
+G_END_DECLS
+
+#endif /* __UTIL_H__ */