2 #include "chimara-glk-private.h"
5 extern GPrivate *glk_data_key;
9 * @linkval: Set to nonzero to initiate hyperlink mode. Set to zero to disengage.
11 * This call sets the current link value in the current output stream. See
12 * glk_set_hyperlink_stream().
15 glk_set_hyperlink(glui32 linkval)
17 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
18 g_return_if_fail(glk_data->current_stream != NULL);
19 glk_set_hyperlink_stream(glk_data->current_stream, linkval);
23 * glk_set_hyperlink_stream:
24 * @str: The stream to set the hyperlink mode on.
25 * @linkval: Set to non-zero to initiate hyperlink mode. Set to zero to
28 * This call sets the current link value on the specified output stream. A link
29 * value is any non-zero integer; zero indicates no link. Subsequent text output
30 * is considered to make up the body of the link, which continues until the link
31 * value is changed (or set to zero).
33 * Note that it is almost certainly useless to change the link value of a stream
34 * twice with no intervening text. The result will be a zero-length link, which
35 * the player probably cannot see or select; the library may optimize it out
38 * Setting the link value of a stream to the value it already has, has no
41 * If the library supports images, they take on the current link value as they
42 * are output, just as text does. The player can select an image in a link just
43 * as he does text. (This includes margin-aligned images, which can lead to some
44 * peculiar situations, since a right-margin image may not appear directly
45 * adjacent to the text it was output with.)
47 * The library will attempt to display links in some distinctive way (and it
48 * will do this whether or not hyperlink input has actually been requested for
49 * the window). Naturally, blue underlined text is most likely. Link images may
50 * not be distinguished from non-link images, so it is best not to use a
51 * particular image both ways.
54 glk_set_hyperlink_stream(strid_t str, glui32 linkval)
56 g_return_if_fail(str != NULL);
57 g_return_if_fail(str->type == STREAM_TYPE_WINDOW);
58 g_return_if_fail(str->window != NULL);
59 g_return_if_fail(str->window->type == wintype_TextBuffer);
61 flush_window_buffer(str->window);
64 /* Turn off hyperlink mode */
65 str->hyperlink_mode = FALSE;
66 str->window->current_hyperlink = NULL;
70 /* Check whether a tag with the needed value already exists */
71 hyperlink_t *new_hyperlink = g_hash_table_lookup(str->window->hyperlinks, &linkval);
72 if(new_hyperlink == NULL) {
73 /* Create a new hyperlink with the requested value */
74 new_hyperlink = g_new0(struct hyperlink, 1);
75 new_hyperlink->value = linkval;
76 new_hyperlink->tag = gtk_text_tag_new(NULL);
77 new_hyperlink->event_handler = g_signal_connect( new_hyperlink->tag, "event", G_CALLBACK(on_hyperlink_clicked), new_hyperlink );
78 g_signal_handler_block(new_hyperlink->tag, new_hyperlink->event_handler);
79 new_hyperlink->window = str->window;
81 /* Add the new tag to the tag table of the textbuffer */
82 GtkTextBuffer *textbuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(str->window->widget) );
83 GtkTextTagTable *tags = gtk_text_buffer_get_tag_table(textbuffer);
84 gtk_text_tag_table_add(tags, new_hyperlink->tag);
86 printf("inserting link %d\n", linkval);
88 gint *linkval_pointer = g_new0(gint, 1);
89 *linkval_pointer = linkval;
90 g_hash_table_insert(str->window->hyperlinks, linkval_pointer, new_hyperlink);
93 str->hyperlink_mode = TRUE;
94 str->window->current_hyperlink = new_hyperlink;
97 /* Internal function used to iterate over all the hyperlinks, unblocking the event handler */
99 hyperlink_unblock_event_handler(gpointer key, gpointer value, gpointer user_data)
101 hyperlink_t *link = (hyperlink_t *) value;
102 g_signal_handler_unblock(link->tag, link->event_handler);
103 printf("unblocking link %d\n", link->value);
106 /* Internal function used to iterate over all the hyperlinks, blocking the event handler */
108 hyperlink_block_event_handler(gpointer key, gpointer value, gpointer user_data)
110 hyperlink_t *link = (hyperlink_t *) value;
111 g_signal_handler_block(link->tag, link->event_handler);
115 * glk_request_hyperlink_event:
116 * @win: The window to request a hyperlink event on.
118 * This call works like glk_request_char_event(), glk_request_line_event() and
119 * glk_request_mouse_event(). A pending request on a window remains pending
120 * until the player selects a link, or the request is cancelled.
122 * A window can have hyperlink input and mouse, character, or line input pending
123 * at the same time. However, if hyperlink and mouse input are requested at the
124 * same time, the library may not provide an intuitive way for the player to
125 * distingish which a mouse click represents. Therefore, this combination should
128 * When a link is selected in a window with a pending request, glk_select() will
129 * return an event of type %evtype_Hyperlink. In the event structure, @win tells
130 * what window the event came from, and @val1 gives the (non-zero) link value.
132 * If no hyperlink request is pending in a window, the library will ignore
133 * attempts to select a link. No %evtype_Hyperlink event will be generated
134 * unless it has been requested.
137 glk_request_hyperlink_event(winid_t win)
139 VALID_WINDOW(win, return);
140 g_return_if_fail(win != NULL);
141 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
143 g_hash_table_foreach(win->hyperlinks, hyperlink_unblock_event_handler, NULL);
148 * glk_cancel_hyperlink_event:
149 * @win: The window in which to cancel the hyperlink event request.
151 * This call works like glk_cancel_char_event(), glk_cancel_line_event(), and
152 * glk_cancel_mouse_event(). See glk_request_hyperlink_event().
155 glk_cancel_hyperlink_event(winid_t win)
157 VALID_WINDOW(win, return);
158 g_return_if_fail(win != NULL);
159 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
161 g_hash_table_foreach(win->hyperlinks, hyperlink_block_event_handler, NULL);
165 on_hyperlink_clicked(GtkTextTag *tag, GObject *object, GdkEvent *event, GtkTextIter *iter, hyperlink_t *link)
167 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(link->window->widget, CHIMARA_TYPE_GLK));
170 if(event->type == GDK_BUTTON_PRESS) {
171 event_throw(glk, evtype_Hyperlink, link->window, link->value, 0);