X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Fhyperlink.c;h=4545f9993a02b45a5e928aa1bd007129577893b6;hb=1e0dc5378f314f555e3b923c6d95f5017abd528b;hp=e58f9818f8d58c8310ff2b000cd533ea630e76d0;hpb=1f983431c87bfc86307c790f519409672f2d0e5a;p=projects%2Fchimara%2Fchimara.git diff --git a/libchimara/hyperlink.c b/libchimara/hyperlink.c index e58f981..4545f99 100644 --- a/libchimara/hyperlink.c +++ b/libchimara/hyperlink.c @@ -1,25 +1,22 @@ +#include +#include #include "hyperlink.h" #include "chimara-glk-private.h" #include "magic.h" -extern GPrivate *glk_data_key; +extern GPrivate glk_data_key; /** * glk_set_hyperlink: * @linkval: Set to nonzero to initiate hyperlink mode. Set to zero to disengage. * - * Use this function to create hyperlinks in a textbuffer. It sets the current stream - * to hyperlink mode, after which text will become a hyperlink until hyperlink mode - * is turned off. If the current stream does not write to a textbuffer window, this function - * does nothing. - * - * You can request hyperlink events with glk_request_hyperlink_event() to react - * to clicks on the link. + * This call sets the current link value in the current output stream. See + * glk_set_hyperlink_stream(). */ void glk_set_hyperlink(glui32 linkval) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); g_return_if_fail(glk_data->current_stream != NULL); glk_set_hyperlink_stream(glk_data->current_stream, linkval); } @@ -27,22 +24,41 @@ glk_set_hyperlink(glui32 linkval) /** * glk_set_hyperlink_stream: * @str: The stream to set the hyperlink mode on. - * @linkval: Set to nonzero to initiate hyperlink mode. Set to zero to disengage. + * @linkval: Set to non-zero to initiate hyperlink mode. Set to zero to + * disengage. + * + * This call sets the current link value on the specified output stream. A link + * value is any non-zero integer; zero indicates no link. Subsequent text output + * is considered to make up the body of the link, which continues until the link + * value is changed (or set to zero). * - * Use this function to create hyperlinks in a textbuffer. It sets a stream to a textbuffer - * window to hyperlink mode, after which text will become a hyperlink until hyperlink mode - * is turned off. Calling this function on a stream that does not write to a textbuffer does - * nothing. + * Note that it is almost certainly useless to change the link value of a stream + * twice with no intervening text. The result will be a zero-length link, which + * the player probably cannot see or select; the library may optimize it out + * entirely. * - * You can request hyperlink events with glk_request_hyperlink_event() to react - * to clicks on the link. + * Setting the link value of a stream to the value it already has, has no + * effect. + * + * If the library supports images, they take on the current link value as they + * are output, just as text does. The player can select an image in a link just + * as he does text. (This includes margin-aligned images, which can lead to some + * peculiar situations, since a right-margin image may not appear directly + * adjacent to the text it was output with.) + * + * The library will attempt to display links in some distinctive way (and it + * will do this whether or not hyperlink input has actually been requested for + * the window). Naturally, blue underlined text is most likely. Link images may + * not be distinguished from non-link images, so it is best not to use a + * particular image both ways. */ void glk_set_hyperlink_stream(strid_t str, glui32 linkval) { g_return_if_fail(str != NULL); + g_return_if_fail(str->type == STREAM_TYPE_WINDOW); g_return_if_fail(str->window != NULL); - g_return_if_fail(str->window->type == wintype_TextBuffer); + g_return_if_fail(str->window->type == wintype_TextBuffer || str->window->type == wintype_TextGrid); flush_window_buffer(str->window); @@ -61,7 +77,8 @@ glk_set_hyperlink_stream(strid_t str, glui32 linkval) new_hyperlink->value = linkval; new_hyperlink->tag = gtk_text_tag_new(NULL); new_hyperlink->event_handler = g_signal_connect( new_hyperlink->tag, "event", G_CALLBACK(on_hyperlink_clicked), new_hyperlink ); - g_signal_handler_block(new_hyperlink->tag, new_hyperlink->event_handler); + if(!str->window->hyperlink_event_requested) + g_signal_handler_block(new_hyperlink->tag, new_hyperlink->event_handler); new_hyperlink->window = str->window; /* Add the new tag to the tag table of the textbuffer */ @@ -69,8 +86,6 @@ glk_set_hyperlink_stream(strid_t str, glui32 linkval) GtkTextTagTable *tags = gtk_text_buffer_get_tag_table(textbuffer); gtk_text_tag_table_add(tags, new_hyperlink->tag); - printf("inserting link %d\n", linkval); - gint *linkval_pointer = g_new0(gint, 1); *linkval_pointer = linkval; g_hash_table_insert(str->window->hyperlinks, linkval_pointer, new_hyperlink); @@ -86,7 +101,6 @@ hyperlink_unblock_event_handler(gpointer key, gpointer value, gpointer user_data { hyperlink_t *link = (hyperlink_t *) value; g_signal_handler_unblock(link->tag, link->event_handler); - printf("unblocking link %d\n", link->value); } /* Internal function used to iterate over all the hyperlinks, blocking the event handler */ @@ -97,24 +111,65 @@ hyperlink_block_event_handler(gpointer key, gpointer value, gpointer user_data) g_signal_handler_block(link->tag, link->event_handler); } +/** + * glk_request_hyperlink_event: + * @win: The window to request a hyperlink event on. + * + * This call works like glk_request_char_event(), glk_request_line_event() and + * glk_request_mouse_event(). A pending request on a window remains pending + * until the player selects a link, or the request is cancelled. + * + * A window can have hyperlink input and mouse, character, or line input pending + * at the same time. However, if hyperlink and mouse input are requested at the + * same time, the library may not provide an intuitive way for the player to + * distingish which a mouse click represents. Therefore, this combination should + * be avoided. + * + * When a link is selected in a window with a pending request, glk_select() will + * return an event of type %evtype_Hyperlink. In the event structure, @win tells + * what window the event came from, and @val1 gives the (non-zero) link value. + * + * If no hyperlink request is pending in a window, the library will ignore + * attempts to select a link. No %evtype_Hyperlink event will be generated + * unless it has been requested. + */ void glk_request_hyperlink_event(winid_t win) { VALID_WINDOW(win, return); g_return_if_fail(win != NULL); - g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid); + g_return_if_fail(win->type == wintype_TextBuffer || win->type == wintype_TextGrid); + if(win->hyperlink_event_requested) { + WARNING(_("Tried to request a hyperlink event on a window that already had a hyperlink request")); + return; + } + + win->hyperlink_event_requested = TRUE; g_hash_table_foreach(win->hyperlinks, hyperlink_unblock_event_handler, NULL); } +/** + * glk_cancel_hyperlink_event: + * @win: The window in which to cancel the hyperlink event request. + * + * This call works like glk_cancel_char_event(), glk_cancel_line_event(), and + * glk_cancel_mouse_event(). See glk_request_hyperlink_event(). + */ void glk_cancel_hyperlink_event(winid_t win) { VALID_WINDOW(win, return); g_return_if_fail(win != NULL); - g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid); + g_return_if_fail(win->type == wintype_TextBuffer || win->type == wintype_TextGrid); + + if(!win->hyperlink_event_requested) { + WARNING(_("Tried to cancel a nonexistent hyperlink request")); + return; + } + win->hyperlink_event_requested = FALSE; g_hash_table_foreach(win->hyperlinks, hyperlink_block_event_handler, NULL); } @@ -125,6 +180,8 @@ on_hyperlink_clicked(GtkTextTag *tag, GObject *object, GdkEvent *event, GtkTextI g_assert(glk); if(event->type == GDK_BUTTON_PRESS) { + link->window->hyperlink_event_requested = FALSE; + g_hash_table_foreach(link->window->hyperlinks, hyperlink_block_event_handler, NULL); event_throw(glk, evtype_Hyperlink, link->window, link->value, 0); }