3 /* Global tree of all windows */
4 static GNode *root_window = NULL;
8 * @win: A window, or #NULL.
9 * @rockptr: Return location for the next window's rock, or #NULL.
11 * Iterates over the list of windows; if @win is #NULL, it returns the first
12 * window, otherwise the next window after @win. If there are no more, it
13 * returns #NULL. The window's rock is stored in @rockptr. If you don't want
14 * the rocks to be returned, you may set @rockptr to #NULL.
16 * The order in which windows are returned is arbitrary. The root window is
17 * not necessarily first, nor is it necessarily last. The order may change
18 * every time you create or destroy a window, invalidating the iteration.
20 * Returns: the next window, or #NULL if there are no more.
23 glk_window_iterate(winid_t win, glui32 *rockptr)
28 retnode = root_window;
31 GNode *node = win->window_node;
32 if( G_NODE_IS_LEAF(node) )
34 while(node && node->next == NULL)
42 retnode = g_node_first_child(node);
44 winid_t retval = retnode? (winid_t)retnode->data : NULL;
46 /* Store the window's rock in rockptr */
48 *rockptr = glk_window_get_rock(retval);
54 * glk_window_get_rock:
57 * Returns the window @win's rock value. Pair windows always have rock 0.
59 * Returns: A rock value.
62 glk_window_get_rock(winid_t win)
64 g_return_val_if_fail(win != NULL, 0);
69 * glk_window_get_type:
72 * Returns the window @win's type, one of #wintype_Blank, #wintype_Pair,
73 * #wintype_TextBuffer, #wintype_TextGrid, or #wintype_Graphics.
75 * Returns: The window's type.
78 glk_window_get_type(winid_t win)
80 g_return_val_if_fail(win != NULL, 0);
81 return win->window_type;
85 * glk_window_get_parent:
88 * Returns the window @win's parent window. If @win is the root window, this
89 * returns #NULL, since the root window has no parent. Remember that the parent
90 * of every window is a pair window; other window types are always childless.
95 glk_window_get_parent(winid_t win)
97 g_return_val_if_fail(win != NULL, NULL);
98 /* Value will also be NULL if win is the root window */
99 return (winid_t)win->window_node->parent->data;
103 * glk_window_get_sibling:
106 * Returns the other child of the window @win's parent. If @win is the
107 * root window, this returns #NULL.
109 * Returns: A window, or NULL.
112 glk_window_get_sibling(winid_t win)
114 g_return_val_if_fail(win != NULL, NULL);
116 if(G_NODE_IS_ROOT(win->window_node))
118 if(win->window_node->next)
119 return (winid_t)win->window_node->next;
120 return (winid_t)win->window_node->prev;
124 * glk_window_get_root:
126 * Returns the root window. If there are no windows, this returns #NULL.
128 * Returns: A window, or #NULL.
131 glk_window_get_root()
133 if(root_window == NULL)
135 return (winid_t)root_window->data;
140 * @split: The window to split to create the new window. Must be 0 if there
141 * are no windows yet.
142 * @method: Position of the new window and method of size computation. One of
143 * #winmethod_Above, #winmethod_Below, #winmethod_Left, or #winmethod_Right
144 * OR'ed with #winmethod_Fixed or #winmethod_Proportional. If @wintype is
145 * #wintype_Blank, then #winmethod_Fixed is not allowed.
146 * @size: Size of the new window, in percentage points if @method is
147 * #winmethod_Proportional, otherwise in characters if @wintype is
148 * #wintype_TextBuffer or #wintype_TextGrid, or pixels if @wintype is
150 * @wintype: Type of the new window. One of #wintype_Blank, #wintype_TextGrid,
151 * #wintype_TextBuffer, or #wintype_Graphics.
152 * @rock: The new window's rock value.
154 * If there are no windows, create a new root window. @split must be 0, and
155 * @method and @size are ignored. Otherwise, split window @split into two, with
156 * position, size, and type specified by @method, @size, and @wintype. See the
157 * Glk documentation for the window placement algorithm.
159 * Returns: the new window.
162 glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype,
165 extern GtkBuilder *builder;
169 g_warning("glk_window_open: splitting of windows not implemented");
173 if(root_window != NULL)
175 g_warning("glk_window_open: there is already a window");
178 /* We only create one window and don't support any more than that */
179 winid_t new_window = g_new0(struct glk_window_struct, 1);
180 root_window = g_node_new(new_window);
182 new_window->rock = rock;
183 new_window->window_type = wintype;
187 GtkBox *vbox = GTK_BOX( gtk_builder_get_object(builder, "vbox") );
190 error_dialog(NULL, NULL, "Could not find vbox");
199 /* A blank window will be a label without any text */
200 GtkWidget *window = gtk_label_new("");
201 gtk_box_pack_end(vbox, window, TRUE, TRUE, 0);
202 gtk_widget_show(window);
204 new_window->widget = window;
205 /* You can print to a blank window's stream, but it does nothing */
206 new_window->window_stream = window_stream_new(new_window);
207 new_window->echo_stream = NULL;
211 case wintype_TextBuffer:
213 GtkWidget *scroll_window = gtk_scrolled_window_new(NULL, NULL);
214 GtkWidget *window = gtk_text_view_new();
215 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(window) );
217 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(window), GTK_WRAP_WORD_CHAR );
218 gtk_text_view_set_editable( GTK_TEXT_VIEW(window), FALSE );
220 gtk_container_add( GTK_CONTAINER(scroll_window), window );
221 gtk_box_pack_end(vbox, scroll_window, TRUE, TRUE, 0);
222 gtk_widget_show_all(scroll_window);
224 new_window->widget = window;
225 new_window->window_stream = window_stream_new(new_window);
226 new_window->echo_stream = NULL;
227 new_window->input_request_type = INPUT_REQUEST_NONE;
228 new_window->line_input_buffer = NULL;
229 new_window->line_input_buffer_unicode = NULL;
231 /* Connect signal handlers */
232 new_window->keypress_handler = g_signal_connect( G_OBJECT(window), "key-press-event", G_CALLBACK(on_window_key_press_event), new_window );
233 g_signal_handler_block( G_OBJECT(window), new_window->keypress_handler );
235 new_window->insert_text_handler = g_signal_connect_after( G_OBJECT(buffer), "insert-text", G_CALLBACK(after_window_insert_text), new_window );
236 g_signal_handler_block( G_OBJECT(buffer), new_window->insert_text_handler );
238 /* Create an editable tag to indicate editable parts of the window (for line input) */
239 gtk_text_buffer_create_tag(buffer, "uneditable", "editable", FALSE, "editable-set", TRUE, NULL);
241 /* Mark the position where the user will input text */
242 GtkTextIter end_iter;
243 gtk_text_buffer_get_end_iter(buffer, &end_iter);
244 gtk_text_buffer_create_mark(buffer, "input_position", &end_iter, TRUE);
249 g_warning("glk_window_open: unsupported window type");
255 new_window->window_node = root_window;
263 glk_window_close(winid_t win, stream_result_t *result)
265 g_return_if_fail(win != NULL);
267 switch(win->window_type)
269 case wintype_TextBuffer:
270 gtk_widget_destroy( gtk_widget_get_parent(win->widget) );
271 /* TODO: Cancel all input requests */
275 gtk_widget_destroy(win->widget);
279 stream_close_common(win->window_stream, result);
281 g_node_destroy(win->window_node);
282 /* TODO: iterate over child windows, closing them */
291 * Erases the window @win.
294 glk_window_clear(winid_t win)
296 g_return_if_fail(win != NULL);
298 switch(win->window_type)
304 case wintype_TextBuffer:
305 /* delete all text in the window */
309 GtkTextBuffer *buffer =
310 gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
311 GtkTextIter start, end;
312 gtk_text_buffer_get_bounds(buffer, &start, &end);
313 gtk_text_buffer_delete(buffer, &start, &end);
320 g_warning("glk_window_clear: unsupported window type");
328 * Sets the current stream to @win's window stream.
331 glk_set_window(winid_t win)
333 glk_stream_set_current( glk_window_get_stream(win) );
337 * glk_window_get_stream:
340 * Gets the stream associated with @win.
342 * Returns: The window stream.
344 strid_t glk_window_get_stream(winid_t win)
346 g_return_val_if_fail(win != NULL, NULL);
347 return win->window_stream;
351 * glk_window_set_echo_stream:
353 * @str: A stream to attach to the window, or #NULL.
355 * Attaches the stream @str to @win as a second stream. Any text printed to the
356 * window is also echoed to this second stream, which is called the window's
359 * Effectively, any call to glk_put_char() (or the other output commands) which
360 * is directed to @win's window stream, is replicated to @win's echo stream.
361 * This also goes for the style commands such as glk_set_style().
363 * Note that the echoing is one-way. You can still print text directly to the
364 * echo stream, and it will go wherever the stream is bound, but it does not
365 * back up and appear in the window.
367 * It is illegal to set a window's echo stream to be its own window stream,
368 * which would create an infinite loop. It is similarly illegal to create a
369 * longer loop (two or more windows echoing to each other.)
371 * You can reset a window to stop echoing by setting @str to #NULL.
374 glk_window_set_echo_stream(winid_t win, strid_t str)
376 g_return_if_fail(win != NULL);
378 /* Test for an infinite loop */
381 next_str != NULL && next_str->stream_type == STREAM_TYPE_WINDOW;
382 next_str = next_str->window->echo_stream)
384 if(next_str == win->window_stream)
386 g_warning("glk_window_set_echo_stream: Infinite loop detected");
387 win->echo_stream = NULL;
392 win->echo_stream = str;
396 * glk_window_get_echo_stream:
399 * Returns the echo stream of window @win. If the window has no echo stream (as
400 * is initially the case) then this returns #NULL.
402 * Returns: A stream, or #NULL.
405 glk_window_get_echo_stream(winid_t win)
407 g_return_val_if_fail(win != NULL, NULL);
408 return win->echo_stream;
412 glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr)
414 g_return_if_fail(win != NULL);
416 if(widthptr != NULL) {
420 if(heightptr != NULL) {
426 glk_window_move_cursor(winid_t win, glui32 xpos, glui32 ypos)
428 g_return_if_fail(win != NULL);