Remove compatibility checks with GTK 2.x
[projects/chimara/chimara.git] / libchimara / chimara-glk.c
index 47c2b51b014b320d625bfabc3cf1147d004902af..8fd1a1e81b752a430537961253813191dd685ba4 100644 (file)
 #define CHIMARA_GLK_MIN_WIDTH 0
 #define CHIMARA_GLK_MIN_HEIGHT 0
 
-/* Substitute functions for compiling on iLiad */
-
-#if !GTK_CHECK_VERSION(2, 18, 0)
-#define gtk_widget_get_allocation(w, a) \
-       G_STMT_START { \
-               (a)->x = (w)->allocation.x; \
-               (a)->y = (w)->allocation.y; \
-               (a)->width = (w)->allocation.width; \
-               (a)->height = (w)->allocation.height; \
-       } G_STMT_END
-#define gtk_widget_set_allocation(w, a) \
-       G_STMT_START { (w)->allocation = *(a); } G_STMT_END
-#define gtk_widget_set_has_window(w, f) \
-       G_STMT_START { \
-               if(f) \
-                       GTK_WIDGET_UNSET_FLAGS((w), GTK_NO_WINDOW); \
-               else \
-                       GTK_WIDGET_SET_FLAGS((w), GTK_NO_WINDOW); \
-       } G_STMT_END
-#endif /* GTK 2.18 */
-
 /**
  * SECTION:chimara-glk
  * @short_description: Widget which executes a Glk program
@@ -148,7 +127,8 @@ enum {
        PROP_SPACING,
        PROP_PROGRAM_NAME,
        PROP_PROGRAM_INFO,
-       PROP_STORY_NAME
+       PROP_STORY_NAME,
+       PROP_RUNNING
 };
 
 enum {
@@ -170,6 +150,8 @@ G_DEFINE_TYPE(ChimaraGlk, chimara_glk, GTK_TYPE_CONTAINER);
 static void
 chimara_glk_init(ChimaraGlk *self)
 {
+       chimara_init(); /* This is a library entry point */
+
     gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);
 
     ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(self);
@@ -267,6 +249,9 @@ chimara_glk_get_property(GObject *object, guint prop_id, GValue *value, GParamSp
                case PROP_STORY_NAME:
                        g_value_set_string(value, priv->story_name);
                        break;
+               case PROP_RUNNING:
+                       g_value_set_boolean(value, priv->running);
+                       break;
                default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     }
@@ -403,7 +388,9 @@ request_recurse(winid_t win, GtkRequisition *requisition, guint spacing)
                gtk_widget_size_request(win->frame, requisition);
 }
 
-/* Overrides gtk_widget_size_request */
+/* Old GTK 2 functionality overriding gtk_widget_size_request();
+get_preferred_width() and get_preferred_height() are implemented in terms of
+this function. */
 static void
 chimara_glk_size_request(GtkWidget *widget, GtkRequisition *requisition)
 {
@@ -428,6 +415,36 @@ chimara_glk_size_request(GtkWidget *widget, GtkRequisition *requisition)
     }
 }
 
+/* Minimal implementation of width-for-height request, in terms of the old
+GTK 2 mechanism. FIXME: make this more efficient. */
+static void
+chimara_glk_get_preferred_width(GtkWidget *widget, int *minimal, int *natural)
+{
+    g_return_if_fail(widget || CHIMARA_IS_GLK(widget));
+    g_return_if_fail(minimal);
+    g_return_if_fail(natural);
+
+    GtkRequisition requisition;
+
+    chimara_glk_size_request(widget, &requisition);
+    *minimal = *natural = requisition.width;
+}
+
+/* Minimal implementation of height-for-width request, in terms of the old
+GTK 2 mechanism. FIXME: make this more efficient. */
+static void
+chimara_glk_get_preferred_height(GtkWidget *widget, int *minimal, int *natural)
+{
+    g_return_if_fail(widget || CHIMARA_IS_GLK(widget));
+    g_return_if_fail(minimal);
+    g_return_if_fail(natural);
+
+    GtkRequisition requisition;
+
+    chimara_glk_size_request(widget, &requisition);
+    *minimal = *natural = requisition.height;
+}
+
 /* Recursively give the Glk windows their allocated space. Returns a window
  containing all children of this window that must be redrawn, or NULL if there 
  are no children that require redrawing. */
@@ -729,18 +746,6 @@ chimara_glk_iliad_screen_update(ChimaraGlk *self, gboolean typing)
        /* Default signal handler */
 }
 
-/* COMPAT: G_PARAM_STATIC_STRINGS only appeared in GTK 2.13.0 */
-#ifndef G_PARAM_STATIC_STRINGS
-
-/* COMPAT: G_PARAM_STATIC_NAME and friends only appeared in GTK 2.8 */
-#if GTK_CHECK_VERSION(2,8,0)
-#define G_PARAM_STATIC_STRINGS (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
-#else
-#define G_PARAM_STATIC_STRINGS (0)
-#endif
-
-#endif
-
 static void
 chimara_glk_class_init(ChimaraGlkClass *klass)
 {
@@ -751,7 +756,8 @@ chimara_glk_class_init(ChimaraGlkClass *klass)
     object_class->finalize = chimara_glk_finalize;
     
     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
-    widget_class->size_request = chimara_glk_size_request;
+    widget_class->get_preferred_width = chimara_glk_get_preferred_width;
+    widget_class->get_preferred_height = chimara_glk_get_preferred_height;
     widget_class->size_allocate = chimara_glk_size_allocate;
 
     GtkContainerClass *container_class = GTK_CONTAINER_CLASS(klass);
@@ -947,6 +953,17 @@ chimara_glk_class_init(ChimaraGlkClass *klass)
                NULL,
                G_PARAM_READABLE | G_PARAM_STATIC_STRINGS) );
        
+       /**
+        * ChimaraGlk:running:
+        *
+        * Whether this Glk widget is currently running a game or not.
+        */
+       g_object_class_install_property(object_class, PROP_RUNNING,
+               g_param_spec_boolean("running", _("Running"),
+               _("Whether there is a program currently running"),
+               FALSE,
+               G_PARAM_READABLE | G_PARAM_STATIC_STRINGS) );
+
        /* Private data */
     g_type_class_add_private(klass, sizeof(ChimaraGlkPrivate));
 }
@@ -1257,8 +1274,7 @@ chimara_glk_run(ChimaraGlk *glk, const gchar *plugin, int argc, char *argv[], GE
     g_assert( g_module_supported() );
        /* If there is already a module loaded, free it first -- you see, we want to
         * keep modules loaded as long as possible to avoid crashes in stack unwinding */
-       if( priv->program && !g_module_close(priv->program) )
-               g_warning( "Error closing module :%s", g_module_error() );
+       chimara_glk_unload_plugin(glk);
        /* Open the module to run */
     priv->program = g_module_open(plugin, G_MODULE_BIND_LAZY);
     
@@ -1300,6 +1316,35 @@ chimara_glk_run(ChimaraGlk *glk, const gchar *plugin, int argc, char *argv[], GE
        return !(priv->thread == NULL);
 }
 
+/**
+ * chimara_glk_run_file:
+ * @self: a #ChimaraGlk widget
+ * @plugin_file: a #GFile pointing to a plugin module compiled with <filename
+ * class="header">glk.h</filename>
+ * @argc: Number of command line arguments in @argv
+ * @argv: Array of command line arguments to pass to the plugin
+ * @error: location to store a <link
+ * linkend="glib-Error-Reporting">GError</link>, or %NULL
+ *
+ * Opens a Glk program compiled as a plugin, from a #GFile. See
+ * chimara_glk_run() for details.
+ *
+ * Return value: %TRUE if the Glk program was started successfully.
+ */
+gboolean
+chimara_glk_run_file(ChimaraGlk *self, GFile *plugin_file, int argc, char *argv[], GError **error)
+{
+       g_return_val_if_fail(self || CHIMARA_IS_GLK(self), FALSE);
+       g_return_val_if_fail(plugin_file || G_IS_FILE(plugin_file), FALSE);
+       g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+       char *path = g_file_get_path(plugin_file);
+       gboolean retval = chimara_glk_run(self, path, argc, argv, error);
+       g_free(path);
+
+       return retval;
+}
+
 /**
  * chimara_glk_stop:
  * @glk: a #ChimaraGlk widget
@@ -1356,6 +1401,26 @@ chimara_glk_wait(ChimaraGlk *glk)
        gdk_threads_enter();
 }
 
+/**
+ * chimara_glk_unload_plugin:
+ * @glk: a #ChimaraGlk widget
+ *
+ * The plugin containing the Glk program is unloaded as late as possible before
+ * loading a new plugin, in order to prevent crashes while printing stack
+ * backtraces during debugging. Sometimes this behavior is not desirable. This
+ * function forces @glk to unload the plugin running in it.
+ *
+ * This function does nothing if there is no plugin loaded.
+ */
+void
+chimara_glk_unload_plugin(ChimaraGlk *glk)
+{
+       g_return_if_fail(glk || CHIMARA_IS_GLK(glk));
+    CHIMARA_GLK_USE_PRIVATE(glk, priv);
+       if( priv->program && !g_module_close(priv->program) )
+               g_warning( "Error closing module :%s", g_module_error() );
+}
+
 /**
  * chimara_glk_get_running:
  * @glk: a #ChimaraGlk widget