priv->resource_lock = g_mutex_new();
priv->resource_loaded = g_cond_new();
priv->resource_info_available = g_cond_new();
+ priv->resource_load_callback = NULL;
+ priv->resource_load_callback_data = NULL;
priv->image_cache = NULL;
priv->program_name = NULL;
priv->program_info = NULL;
g_mutex_unlock(priv->arrange_lock);
gtk_widget_queue_resize( GTK_WIDGET(priv->self) );
}
+
+/**
+ * chimara_glk_set_resource_load_callback:
+ * @glk: a #ChimaraGlk widget
+ * @func: a function to call for loading resources, or %NULL
+ * @user_data: user data to pass to @func, or %NULL
+ *
+ * Sometimes it is preferable to load image and sound resources from somewhere
+ * else than a Blorb file, for example while developing a game. Section 14 of
+ * the <ulink url="http://eblong.com/zarf/blorb/blorb.html#s14">Blorb
+ * specification</ulink> allows for this possibility. This function sets @func
+ * to be called when the Glk program requests loading an image or sound without
+ * a Blorb resource map having been loaded, optionally passing @user_data as an
+ * extra parameter.
+ *
+ * Note that @func is only called if no Blorb resource map has been set; having
+ * a resource map in place overrides this function.
+ *
+ * To deactivate the callback, call this function with @func set to %NULL.
+ */
+void
+chimara_glk_set_resource_load_callback(ChimaraGlk *glk, ChimaraResourceLoadFunc func, gpointer user_data)
+{
+ CHIMARA_GLK_USE_PRIVATE(glk, priv);
+ priv->resource_load_callback = func;
+ priv->resource_load_callback_data = user_data;
+}
CHIMARA_PLUGIN_ALREADY_RUNNING
} ChimaraError;
+/**
+ * ChimaraResourceType:
+ * @CHIMARA_RESOURCE_SOUND: A sound file.
+ * @CHIMARA_RESOURCE_IMAGE: An image file.
+ *
+ * The type of resource that the Glk program is requesting, passed to a
+ * #ChimaraResourceLoadFunc.
+ */
+typedef enum _ChimaraResourceType {
+ CHIMARA_RESOURCE_SOUND,
+ CHIMARA_RESOURCE_IMAGE
+} ChimaraResourceType;
+
+/**
+ * ChimaraResourceLoadFunc:
+ *
+ * The type of function passed to chimara_glk_set_resource_load_callback(). It
+ * takes a #ChimaraResourceType constant, @usage, to indicate what sort of
+ * resource to look for; @resnum is the resource number to look for, and
+ * @user_data is the user data provided along with the callback. The function
+ * must return an allocated string containing the filename where the resource
+ * can be found.
+ */
+typedef gchar * (*ChimaraResourceLoadFunc)(ChimaraResourceType usage, guint32 resnum, gpointer user_data);
+
/**
* CHIMARA_ERROR:
*
const gchar **chimara_glk_get_tag_names(ChimaraGlk *glk);
gint chimara_glk_get_num_tag_names(ChimaraGlk *glk);
void chimara_glk_update_style(ChimaraGlk *glk);
+void chimara_glk_set_resource_load_callback(ChimaraGlk *glk, ChimaraResourceLoadFunc func, gpointer user_data);
G_END_DECLS
static gboolean size_determined;
static struct image_info*
-load_image_in_cache(glui32 image, gint width, gint height)
+load_image_from_blorb(giblorb_result_t resource, glui32 image, gint width, gint height)
{
ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
- giblorb_err_t blorb_error = 0;
- giblorb_result_t resource;
GError *pixbuf_error = NULL;
guchar *buffer;
- /* Lookup the proper resource */
- if(!glk_data->resource_map) {
- WARNING("No resource map has been loaded yet.");
- return NULL;
- }
- blorb_error = giblorb_load_resource(glk_data->resource_map, giblorb_method_FilePos, &resource, giblorb_ID_Pict, image);
- if(blorb_error != giblorb_err_None) {
- WARNING_S( "Error loading resource", giblorb_get_error_message(blorb_error) );
- return NULL;
- }
-
struct image_info *info = g_new0(struct image_info, 1);
info->resource_number = image;
}
g_mutex_unlock(glk_data->resource_lock);
+ info->pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
+
+ g_object_unref(loader);
+ return info;
+}
+
+static struct image_info *
+load_image_from_file(const gchar *filename, glui32 image, gint width, gint height)
+{
+ GError *err = NULL;
+
+ struct image_info *info = g_new0(struct image_info, 1);
+ info->resource_number = image;
+
+ if(width > 0 && height > 0) {
+ info->scaled = TRUE;
+ info->pixbuf = gdk_pixbuf_new_from_file_at_size(filename, width, height, &err);
+ } else {
+ info->pixbuf = gdk_pixbuf_new_from_file(filename, &err);
+ }
+ if(!info->pixbuf) {
+ IO_WARNING("Error loading resource from alternative location", filename, err->message);
+ g_error_free(err);
+ g_free(info);
+ return NULL;
+ }
+
+ return info;
+}
+
+static struct image_info*
+load_image_in_cache(glui32 image, gint width, gint height)
+{
+ ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+ struct image_info *info = NULL;
+
+ /* Lookup the proper resource */
+ if(!glk_data->resource_map) {
+ if(!glk_data->resource_load_callback) {
+ WARNING("No resource map has been loaded yet.");
+ return NULL;
+ }
+ gchar *filename = glk_data->resource_load_callback(CHIMARA_RESOURCE_IMAGE, image, glk_data->resource_load_callback_data);
+ if(!filename) {
+ WARNING("Error loading resource from alternative location");
+ return NULL;
+ }
+ info = load_image_from_file(filename, image, width, height);
+ g_free(filename);
+ } else {
+ giblorb_result_t resource;
+ giblorb_err_t blorb_error = giblorb_load_resource(glk_data->resource_map, giblorb_method_FilePos, &resource, giblorb_ID_Pict, image);
+ if(blorb_error != giblorb_err_None) {
+ WARNING_S( "Error loading resource", giblorb_get_error_message(blorb_error) );
+ return NULL;
+ }
+ info = load_image_from_blorb(resource, image, width, height);
+ }
+
/* Store the image in the cache */
gdk_threads_enter();
g_free(head);
glk_data->image_cache = g_slist_remove_link(glk_data->image_cache, glk_data->image_cache);
}
- info->pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
gdk_pixbuf_ref(info->pixbuf);
info->width = gdk_pixbuf_get_width(info->pixbuf);
info->height = gdk_pixbuf_get_height(info->pixbuf);
glk_data->image_cache = g_slist_prepend(glk_data->image_cache, info);
gdk_threads_leave();
-
- g_object_unref(loader);
return info;
}