X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Fgraphics.c;h=1ab5a359b68ba304bf3d0a1c5ec90d357bc13ff0;hb=cdb84c7c776f214f41ba1a509efb2494e7ed1baf;hp=abcab4a4a07e58344d54754c28d17ed5b6ef1078;hpb=43b334356e9e0003589d506ae74a8c85e5b9349d;p=projects%2Fchimara%2Fchimara.git diff --git a/libchimara/graphics.c b/libchimara/graphics.c index abcab4a..1ab5a35 100644 --- a/libchimara/graphics.c +++ b/libchimara/graphics.c @@ -13,21 +13,12 @@ static gboolean image_loaded; 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 */ - 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; @@ -71,24 +62,84 @@ load_image_in_cache(glui32 image, gint width, gint height) } g_mutex_unlock(glk_data->resource_lock); + info->pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); + g_object_ref(info->pixbuf); + + 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; + } + g_object_ref(info->pixbuf); + + 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); + } + + if(info == NULL) + return NULL; + /* Store the image in the cache */ gdk_threads_enter(); if( g_slist_length(glk_data->image_cache) >= IMAGE_CACHE_MAX_NUM ) { struct image_info *head = (struct image_info*) glk_data->image_cache->data; - gdk_pixbuf_unref(head->pixbuf); + g_object_unref(head->pixbuf); 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; } @@ -124,7 +175,7 @@ on_pixbuf_closed(GdkPixbufLoader *loader, gpointer data) void clear_image_cache(struct image_info *data, gpointer user_data) { - gdk_pixbuf_unref(data->pixbuf); + g_object_unref(data->pixbuf); g_free(data); } @@ -181,11 +232,11 @@ image_cache_find(struct image_info* to_find) * @height: Pointer to a location at which to store the image's height. * * This gets information about the image resource with the given identifier. It - * returns %TRUE if there is such an image, and %FALSE if not. You can also pass - * pointers to width and height variables; if the image exists, the variables - * will be filled in with the width and height of the image, in pixels. (You can - * pass %NULL for either width or height if you don't care about that - * information.) + * returns %TRUE (1) if there is such an image, and %FALSE (0) if not. You can + * also pass pointers to width and height variables; if the image exists, the + * variables will be filled in with the width and height of the image, in + * pixels. (You can pass %NULL for either width or height if you don't care + * about that information.) * * * You should always use this function to measure the size of images when you @@ -216,7 +267,7 @@ glk_image_get_info(glui32 image, glui32 *width, glui32 *height) if(width != NULL) *width = found->width; - if(width != NULL) + if(height != NULL) *height = found->height; return TRUE; } @@ -339,12 +390,13 @@ glk_image_draw_scaled(winid_t win, glui32 image, glsi32 val1, glsi32 val2, glui3 glui32 draw_image_common(winid_t win, GdkPixbuf *pixbuf, glsi32 val1, glsi32 val2) { - GdkPixmap *canvas; - gdk_threads_enter(); - switch(win->type) { case wintype_Graphics: { + GdkPixmap *canvas; + + gdk_threads_enter(); + gtk_image_get_pixmap( GTK_IMAGE(win->widget), &canvas, NULL ); if(canvas == NULL) { WARNING("Could not get pixmap"); @@ -355,18 +407,23 @@ draw_image_common(winid_t win, GdkPixbuf *pixbuf, glsi32 val1, glsi32 val2) /* Update the screen */ gtk_widget_queue_draw(win->widget); + + gdk_threads_leave(); } break; case wintype_TextBuffer: { + flush_window_buffer(win); + + gdk_threads_enter(); + GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) ); GtkTextIter end, start; gtk_text_buffer_get_end_iter(buffer, &end); - start = end; - flush_window_buffer(win); gtk_text_buffer_insert_pixbuf(buffer, &end, pixbuf); + start = end; gtk_text_iter_forward_char(&end); gint height = 0; @@ -386,12 +443,11 @@ draw_image_common(winid_t win, GdkPixbuf *pixbuf, glsi32 val1, glsi32 val2) GtkTextTag *tag = gtk_text_buffer_create_tag(buffer, NULL, "rise", PANGO_SCALE * (-height), NULL); gtk_text_buffer_apply_tag(buffer, tag, &start, &end); } + + gdk_threads_leave(); } break; - } - - gdk_threads_leave(); return TRUE; } @@ -481,8 +537,46 @@ glk_window_erase_rect(winid_t win, glsi32 left, glsi32 top, glui32 width, glui32 glk_window_fill_rect(win, win->background_color, left, top, width, height); } +/** + * glk_window_flow_break: + * @win: A window. + * + * You may wish to break the stream of text down below the + * current margin image. Since lines of text can be in any font and size, you + * cannot do this by counting newlines. Instead, use this function. + * + * If the current point in the text is indented around a margin-aligned image, + * this acts like the correct number of newlines to start a new line below the + * image. (If there are several margin-aligned images, it goes below all of + * them.) If the current point is not beside a margin-aligned image, this call + * has no effect. + * + * When a text buffer window is resized, a flow-break behaves cleverly; it may + * become active or inactive as necessary. You can consider this function to + * insert an invisible mark in the text stream. The mark works out how many + * newlines it needs to be whenever the text is formatted for display. + * + * An example of the use of glk_window_flow_break(): If you display a + * left-margin image at the start of every line, they can stack up in a strange + * diagonal way that eventually squeezes all the text off the screen. + * + * If you can't picture this, draw some diagrams. Make the margin images more + * than one line tall, so that each line starts already indented around the + * last image. + * + * To avoid this problem, call glk_window_flow_break() immediately before + * glk_image_draw() for every margin-aligned image. + * + * In all windows other than text buffers, glk_window_flow_break() has no + * effect. + * + * + * This function is not implemented yet. + * + */ void glk_window_flow_break(winid_t win) { + VALID_WINDOW(win, return); } /*** Called when the graphics window is resized. Resize the backing pixmap if necessary ***/