Started using thread-private data. Multisession still doesn't work, but regular opera...
[rodin/chimara.git] / libchimara / input.c
1 #include "charset.h"
2 #include "magic.h"
3 #include "input.h"
4
5 /* Forward declarations */
6 static int flush_text_buffer(winid_t win);
7 static int flush_text_grid(winid_t win);
8
9 /** 
10  * glk_request_char_event:
11  * @win: A window to request char events from.
12  *
13  * Request input of a Latin-1 character or special key. A window cannot have 
14  * requests for both character and line input at the same time. Nor can it have
15  * requests for character input of both types (Latin-1 and Unicode). It is
16  * illegal to call glk_request_char_event() if the window already has a pending
17  * request for either character or line input. 
18  */
19 void
20 glk_request_char_event(winid_t win)
21 {
22         VALID_WINDOW(win, return);
23         g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
24         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
25
26         win->input_request_type = INPUT_REQUEST_CHARACTER;
27         g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
28 }
29
30 /** 
31  * glk_request_char_event_uni:
32  * @win: A window to request char events from.
33  *
34  * Request input of a Unicode character or special key. See 
35  * glk_request_char_event().
36  */
37 void
38 glk_request_char_event_uni(winid_t win)
39 {
40         VALID_WINDOW(win, return);
41         g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
42         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
43
44         win->input_request_type = INPUT_REQUEST_CHARACTER_UNICODE;
45         g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
46 }
47
48 /**
49  * glk_cancel_char_event:
50  * @win: A window to cancel the latest char event request on.
51  *
52  * This cancels a pending request for character input. (Either Latin-1 or
53  * Unicode.) For convenience, it is legal to call glk_cancel_char_event() even
54  * if there is no charcter input request on that window. Glk will ignore the
55  * call in this case.
56  */
57 void
58 glk_cancel_char_event(winid_t win)
59 {
60         VALID_WINDOW(win, return);
61         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
62         
63         if(win->input_request_type == INPUT_REQUEST_CHARACTER || win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE)
64         {
65                 win->input_request_type = INPUT_REQUEST_NONE;
66                 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
67         }
68 }
69
70 /* Internal function: Request either latin-1 or unicode line input, in a text grid window. */
71 static void
72 text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gchar *inserttext)
73 {
74         gdk_threads_enter();
75         
76         GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
77
78     GtkTextMark *cursor = gtk_text_buffer_get_mark(buffer, "cursor_position");
79     GtkTextIter start_iter, end_iter;
80     gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, cursor);
81     
82     /* Determine the maximum length of the line input */
83     gint cursorpos = gtk_text_iter_get_line_offset(&start_iter);
84     /* Odd; the Glk spec says the maximum input length is
85     windowwidth - 1 - cursorposition. I say no, because if cursorposition is
86     zero, then the input should fill the whole line. FIXME??? */
87     win->input_length = MIN(win->width - cursorpos, win->line_input_buffer_max_len);
88     end_iter = start_iter;
89     gtk_text_iter_set_line_offset(&end_iter, cursorpos + win->input_length);
90     
91         /* If the buffer currently has a selection with one bound in the middle of
92         the input field, then deselect it. Otherwise the input field gets trashed */
93         GtkTextIter start_sel, end_sel;
94         if( gtk_text_buffer_get_selection_bounds(buffer, &start_sel, &end_sel) )
95         {
96                 if( gtk_text_iter_in_range(&start_sel, &start_iter, &end_iter) )
97                         gtk_text_buffer_place_cursor(buffer, &end_sel);
98                 if( gtk_text_iter_in_range(&end_sel, &start_iter, &end_iter) )
99                         gtk_text_buffer_place_cursor(buffer, &start_sel);
100         }
101         
102     /* Erase the text currently in the input field and replace it with a GtkEntry */
103     gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
104     win->input_anchor = gtk_text_buffer_create_child_anchor(buffer, &start_iter);
105     win->input_entry = gtk_entry_new();
106         /* Set the entry's font to match that of the window */
107     GtkRcStyle *style = gtk_widget_get_modifier_style(win->widget);     /* Don't free */
108         gtk_widget_modify_font(win->input_entry, style->font_desc);
109         /* Make the entry as small as possible to fit with the text */
110         gtk_entry_set_has_frame(GTK_ENTRY(win->input_entry), FALSE);
111         GtkBorder border = { 0, 0, 0, 0 };
112         gtk_entry_set_inner_border(GTK_ENTRY(win->input_entry), &border);
113     gtk_entry_set_max_length(GTK_ENTRY(win->input_entry), win->input_length);
114     gtk_entry_set_width_chars(GTK_ENTRY(win->input_entry), win->input_length);
115     
116     /* Insert pre-entered text if needed */
117     if(insert)
118         gtk_entry_set_text(GTK_ENTRY(win->input_entry), inserttext);
119     
120     /* Set background color of entry (TODO: implement as property) */
121     GdkColor background;
122         gdk_color_parse("grey", &background);
123     gtk_widget_modify_base(win->input_entry, GTK_STATE_NORMAL, &background);
124     
125     g_signal_connect(win->input_entry, "activate", G_CALLBACK(on_input_entry_activate), win);
126     
127     gtk_widget_show(win->input_entry);
128     gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(win->widget), win->input_entry, win->input_anchor);
129         
130         g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
131         
132         gdk_threads_leave();
133 }
134     
135 /* Internal function: Request either latin-1 or unicode line input, in a text buffer window. */
136 static void
137 text_buffer_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gchar *inserttext)
138 {
139         gdk_threads_enter();
140         
141         GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
142
143     /* Move the input_position mark to the end of the window_buffer */
144     GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position");
145     GtkTextIter end_iter;
146     gtk_text_buffer_get_end_iter(buffer, &end_iter);
147     gtk_text_buffer_move_mark(buffer, input_position, &end_iter);
148
149     /* Set the entire contents of the window_buffer as uneditable
150      * (so input can only be entered at the end) */
151     GtkTextIter start_iter;
152     gtk_text_buffer_get_start_iter(buffer, &start_iter);
153     gtk_text_buffer_remove_tag_by_name(buffer, "uneditable", &start_iter, &end_iter);
154     gtk_text_buffer_apply_tag_by_name(buffer, "uneditable", &start_iter, &end_iter);
155     
156     /* Insert pre-entered text if needed */
157     if(insert)
158         gtk_text_buffer_insert(buffer, &end_iter, inserttext, -1);
159     
160     /* Scroll to input point */
161     gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), input_position);
162     
163     gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), TRUE);
164     g_signal_handler_unblock(buffer, win->insert_text_handler);
165         
166         gdk_threads_leave();
167 }
168
169 /**
170  * glk_request_line_event:
171  * @win: A text buffer or text grid window to request line input on.
172  * @buf: A buffer of at least @maxlen bytes.
173  * @maxlen: Length of the buffer.
174  * @initlen: The number of characters in @buf to pre-enter.
175  *
176  * Requests input of a line of Latin-1 characters. A window cannot have requests
177  * for both character and line input at the same time. Nor can it have requests
178  * for line input of both types (Latin-1 and Unicode). It is illegal to call
179  * glk_request_line_event() if the window already has a pending request for
180  * either character or line input.
181  * 
182  * The @buf argument is a pointer to space where the line input will be stored.
183  * (This may not be %NULL.) @maxlen is the length of this space, in bytes; the
184  * library will not accept more characters than this. If @initlen is nonzero,
185  * then the first @initlen bytes of @buf will be entered as pre-existing input
186  * — just as if the player had typed them himself. (The player can continue
187  * composing after this pre-entered input, or delete it or edit as usual.)
188  * 
189  * The contents of the buffer are undefined until the input is completed (either
190  * by a line input event, or glk_cancel_line_event(). The library may or may not
191  * fill in the buffer as the player composes, while the input is still pending;
192  * it is illegal to change the contents of the buffer yourself. 
193  */
194 void
195 glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen)
196 {
197         VALID_WINDOW(win, return);
198         g_return_if_fail(buf);
199         g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
200         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
201         g_return_if_fail(initlen <= maxlen);
202
203         win->input_request_type = INPUT_REQUEST_LINE;
204         win->line_input_buffer = buf;
205         win->line_input_buffer_max_len = maxlen;
206
207         gchar *inserttext = (initlen > 0)? g_strndup(buf, initlen) : g_strdup("");
208         switch(win->type)
209         {
210             case wintype_TextBuffer:
211                 text_buffer_request_line_event_common(win, maxlen, (initlen > 0), inserttext);
212                 break;
213             case wintype_TextGrid:
214                 text_grid_request_line_event_common(win, maxlen, (initlen > 0), inserttext);
215                 break;
216     }
217         g_free(inserttext);
218 }
219
220 /**
221  * glk_request_line_event_uni:
222  * @win: A text buffer or text grid window to request line input on.
223  * @buf: A buffer of at least @maxlen characters.
224  * @maxlen: Length of the buffer.
225  * @initlen: The number of characters in @buf to pre-enter.
226  *
227  * Request input of a line of Unicode characters. This works the same as
228  * glk_request_line_event(), except the result is stored in an array of
229  * <type>glui32</type> values instead of an array of characters, and the values
230  * may be any valid Unicode code points.
231  * 
232  * The result will be in Unicode Normalization Form C. This basically means that
233  * composite characters will be single characters where possible, instead of
234  * sequences of base and combining marks. See 
235  * <ulink url="http://www.unicode.org/reports/tr15/">Unicode Standard Annex #15
236  * </ulink> for the details.
237  */
238 void
239 glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
240 {
241         VALID_WINDOW(win, return);
242         g_return_if_fail(buf);
243         g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
244         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
245         g_return_if_fail(initlen <= maxlen);
246
247         win->input_request_type = INPUT_REQUEST_LINE_UNICODE;
248         win->line_input_buffer_unicode = buf;
249         win->line_input_buffer_max_len = maxlen;
250
251         gchar *utf8;
252         if(initlen > 0) {
253                 utf8 = convert_ucs4_to_utf8(buf, initlen);
254                 if(utf8 == NULL)
255                         return;
256         }
257         else
258                 utf8 = g_strdup("");
259
260     switch(win->type)
261         {
262             case wintype_TextBuffer:
263                 text_buffer_request_line_event_common(win, maxlen, (initlen > 0), utf8);
264                 break;
265             case wintype_TextGrid:
266                 text_grid_request_line_event_common(win, maxlen, (initlen > 0), utf8);
267                 break;
268     }           
269         g_free(utf8);
270 }
271
272 /**
273  * glk_cancel_line_event:
274  * @win: A text buffer or text grid window to cancel line input on.
275  * @event: Will be filled in if the user had already input something.
276  *
277  * This cancels a pending request for line input. (Either Latin-1 or Unicode.)
278  *
279  * The event pointed to by the event argument will be filled in as if the
280  * player had hit <keycap>enter</keycap>, and the input composed so far will be stored in the
281  * buffer; see below. If you do not care about this information, pass %NULL as
282  * the @event argument. (The buffer will still be filled.) 
283  *
284  * For convenience, it is legal to call glk_cancel_line_event() even if there
285  * is no line input request on that window. The event type will be set to
286  * %evtype_None in this case.
287  */
288 void
289 glk_cancel_line_event(winid_t win, event_t *event)
290 {
291         VALID_WINDOW(win, return);
292         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
293
294         if(event != NULL) {
295                 event->type = evtype_None;
296                 event->win = win;
297                 event->val1 = 0;
298                 event->val2 = 0;
299         }
300
301         if(win->input_request_type != INPUT_REQUEST_LINE && win->input_request_type != INPUT_REQUEST_LINE_UNICODE)
302                 return;
303
304         g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
305
306         int chars_written = 0;
307
308         if(win->type == wintype_TextGrid) {
309                 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
310                 chars_written = flush_text_grid(win);
311         } else if(win->type == wintype_TextBuffer) {
312                 GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
313                 g_signal_handler_block(window_buffer, win->insert_text_handler);
314                 chars_written = flush_text_buffer(win);
315         }
316
317         if(event != NULL && chars_written > 0) {
318                 event->type = evtype_LineInput;
319                 event->val1 = chars_written;
320         }
321 }
322
323 /* Internal function: General callback for signal key-press-event on a text buffer or text grid window. Used in character input on both text buffers and grids, and also in line input on grids, to redirect keystrokes to the line input field. Blocked when not in use. */
324 gboolean
325 on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win)
326 {
327         /* If this is a text grid window, and line input is active, then redirect the key press to the line input GtkEntry */
328         if( win->type == wintype_TextGrid && (win->input_request_type == INPUT_REQUEST_LINE || win->input_request_type == INPUT_REQUEST_LINE_UNICODE) )
329         {
330                 if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up
331                     || event->keyval == GDK_Down || event->keyval == GDK_KP_Down
332                     || event->keyval == GDK_Left || event->keyval == GDK_KP_Left
333                     || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
334                     || event->keyval == GDK_Tab || event->keyval == GDK_KP_Tab
335                     || event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up
336                     || event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down
337                     || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
338                     || event->keyval == GDK_End || event->keyval == GDK_KP_End)
339                         return FALSE; /* Don't redirect these keys */
340                 gtk_widget_grab_focus(win->input_entry);
341                 gtk_editable_set_position(GTK_EDITABLE(win->input_entry), -1);
342                 gboolean retval = TRUE;
343                 g_signal_emit_by_name(win->input_entry, "key-press-event", event, &retval);
344                 return retval; /* Block this key event if the entry handled it */
345         }
346         if(win->input_request_type != INPUT_REQUEST_CHARACTER && 
347                 win->input_request_type != INPUT_REQUEST_CHARACTER_UNICODE)
348                 return FALSE;
349
350         int keycode;
351
352         switch(event->keyval) {
353                 case GDK_Up:
354                 case GDK_KP_Up: keycode = keycode_Up; break;
355                 case GDK_Down: 
356                 case GDK_KP_Down: keycode = keycode_Down; break;
357                 case GDK_Left:
358                 case GDK_KP_Left: keycode = keycode_Left; break;
359                 case GDK_Right:
360                 case GDK_KP_Right: keycode = keycode_Right; break;
361                 case GDK_Linefeed:
362                 case GDK_Return:
363                 case GDK_KP_Enter: keycode = keycode_Return; break;
364                 case GDK_Delete:
365                 case GDK_BackSpace:
366                 case GDK_KP_Delete: keycode = keycode_Delete; break;
367                 case GDK_Escape: keycode = keycode_Escape; break;
368                 case GDK_Tab: 
369                 case GDK_KP_Tab: keycode = keycode_Tab; break;
370                 case GDK_Page_Up:
371                 case GDK_KP_Page_Up: keycode = keycode_PageUp; break;
372                 case GDK_Page_Down:
373                 case GDK_KP_Page_Down: keycode = keycode_PageDown; break;
374                 case GDK_Home:
375                 case GDK_KP_Home: keycode = keycode_Home; break;
376                 case GDK_End:
377                 case GDK_KP_End: keycode = keycode_End; break;
378                 case GDK_F1: 
379                 case GDK_KP_F1: keycode = keycode_Func1; break;
380                 case GDK_F2: 
381                 case GDK_KP_F2: keycode = keycode_Func2; break;
382                 case GDK_F3: 
383                 case GDK_KP_F3: keycode = keycode_Func3; break;
384                 case GDK_F4: 
385                 case GDK_KP_F4: keycode = keycode_Func4; break;
386                 case GDK_F5: keycode = keycode_Func5; break;
387                 case GDK_F6: keycode = keycode_Func6; break;
388                 case GDK_F7: keycode = keycode_Func7; break;
389                 case GDK_F8: keycode = keycode_Func8; break;
390                 case GDK_F9: keycode = keycode_Func9; break;
391                 case GDK_F10: keycode = keycode_Func10; break;
392                 case GDK_F11: keycode = keycode_Func11; break;
393                 case GDK_F12: keycode = keycode_Func12; break;
394                 default:
395                         keycode = gdk_keyval_to_unicode(event->keyval);
396                         /* If keycode is 0, then keyval was not recognized; also return
397                         unknown if Latin-1 input was requested and the character is not in
398                         Latin-1 */
399                         if(keycode == 0 || (win->input_request_type == INPUT_REQUEST_CHARACTER && keycode > 255))
400                                 keycode = keycode_Unknown;      
401         }
402
403         event_throw(CHIMARA_GLK(gtk_widget_get_ancestor(widget, CHIMARA_TYPE_GLK)), evtype_CharInput, win, keycode, 0);
404         
405         /* Only one keypress will be handled */
406         win->input_request_type = INPUT_REQUEST_NONE;
407         g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
408
409         return TRUE;
410 }
411
412 /* Internal function: finish handling a line input request, for both text grid and text buffer windows. */
413 static int
414 write_to_window_buffer(winid_t win, const gchar *inserted_text)
415 {
416         int copycount = 0;
417
418     /* Convert the string from UTF-8 to Latin-1 or Unicode */
419     if(win->input_request_type == INPUT_REQUEST_LINE) 
420     {
421         gsize bytes_written;
422         gchar *latin1 = convert_utf8_to_latin1(inserted_text, &bytes_written);
423         
424         if(latin1 == NULL)
425             return 0;
426
427         /* Place input in the echo stream */
428         if(win->echo_stream != NULL) 
429             glk_put_string_stream(win->echo_stream, latin1);
430
431         /* Copy the string (bytes_written does not include the NULL at the end) */
432         copycount = MIN(win->line_input_buffer_max_len, bytes_written);
433         memcpy(win->line_input_buffer, latin1, copycount);
434         g_free(latin1);
435     }
436     else if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE) 
437     {
438         glong items_written;
439         gunichar *unicode = convert_utf8_to_ucs4(inserted_text, &items_written);
440         
441         if(unicode == NULL)
442             return 0;
443
444         /* Place input in the echo stream */
445         if(win->echo_stream != NULL) 
446             glk_put_string_stream_uni(win->echo_stream, unicode);
447
448         /* Copy the string (but not the NULL at the end) */
449         copycount = MIN(win->line_input_buffer_max_len, items_written);
450         memcpy(win->line_input_buffer_unicode, unicode, copycount * sizeof(gunichar));
451         g_free(unicode);
452     }
453     else 
454         WARNING("Wrong input request type");
455
456     win->input_request_type = INPUT_REQUEST_NONE;
457         return copycount;
458 }
459
460 /* Internal function: Retrieves the input of a TextBuffer window and stores it in the window buffer.
461  * Returns the number of characters written, suitable for inclusion in a line input event. */
462 static int
463 flush_text_buffer(winid_t win)
464 {
465         VALID_WINDOW(win, return 0);
466         g_return_val_if_fail(win->type == wintype_TextBuffer, 0);
467
468         GtkTextIter start_iter, end_iter, last_character;
469
470         GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
471         GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
472         gtk_text_buffer_get_iter_at_mark(window_buffer, &start_iter, input_position);
473         gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
474         gtk_text_buffer_get_end_iter(window_buffer, &last_character);
475         gtk_text_iter_backward_cursor_position(&last_character);
476
477         gchar* last_char = gtk_text_buffer_get_text(window_buffer, &last_character, &end_iter, FALSE);
478
479         if( strchr(last_char, '\n') != NULL )
480                 gtk_text_iter_backward_cursor_position(&end_iter);
481
482         gchar* inserted_text = gtk_text_buffer_get_text(window_buffer, &start_iter, &end_iter, FALSE);
483
484         int chars_written = write_to_window_buffer(win, inserted_text);
485         g_free(inserted_text);
486
487         return chars_written;
488 }
489
490 /* Internal function: Retrieves the input of a TextGrid window and stores it in the window buffer.
491  * Returns the number of characters written, suitable for inclusion in a line input event. */
492 static int
493 flush_text_grid(winid_t win)
494 {
495         VALID_WINDOW(win, return 0);
496         g_return_val_if_fail(win->type == wintype_TextBuffer, 0);
497
498         GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
499         
500         gchar *text = g_strdup( gtk_entry_get_text(GTK_ENTRY(win->input_entry)) );
501         /* Move the focus back into the text view */
502         gtk_widget_grab_focus(win->widget);
503         /* Remove entry widget from text view */
504         /* Should be ok even though this is the widget's own signal handler */
505         gtk_container_remove( GTK_CONTAINER(win->widget), GTK_WIDGET(win->input_entry) );
506         win->input_entry = NULL;
507         /* Delete the child anchor */
508         GtkTextIter start, end;
509         gtk_text_buffer_get_iter_at_child_anchor(buffer, &start, win->input_anchor);
510         end = start;
511         gtk_text_iter_forward_char(&end); /* Point after the child anchor */
512         gtk_text_buffer_delete(buffer, &start, &end);
513         win->input_anchor = NULL;
514         
515     gchar *spaces = g_strnfill(win->input_length - g_utf8_strlen(text, -1), ' ');
516     gchar *text_to_insert = g_strconcat(text, spaces, NULL);
517         g_free(spaces);
518     gtk_text_buffer_insert(buffer, &start, text_to_insert, -1);
519     g_free(text_to_insert);
520     
521     int chars_written = write_to_window_buffer(win, text);
522         g_free(text);
523
524         return chars_written;
525 }
526
527 /* Internal function: Callback for signal insert-text on a text buffer window.
528 Runs after the default handler has already inserted the text.
529 FIXME: This function assumes that newline was the last character typed into the
530 window. That assumption is wrong if, for example, text containing a newline was
531 pasted into the window. */
532 void
533 after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win) 
534 {
535         if( strchr(text, '\n') != NULL ) 
536         {
537                 /* Remove signal handlers */
538                 GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
539                 g_signal_handler_block(window_buffer, win->insert_text_handler);
540                 
541                 /* Make the window uneditable again and retrieve the text that was input */
542         gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
543
544         int chars_written = flush_text_buffer(win);
545                 event_throw(CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK)), evtype_LineInput, win, chars_written, 0);
546         }
547 }
548
549 /* Internal function: Callback for signal activate on the line input GtkEntry
550 in a text grid window. */
551 void
552 on_input_entry_activate(GtkEntry *input_entry, winid_t win)
553 {
554         g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
555
556         int chars_written = flush_text_grid(win);
557         event_throw(CHIMARA_GLK(gtk_widget_get_ancestor(GTK_WIDGET(input_entry), CHIMARA_TYPE_GLK)), evtype_LineInput, win, chars_written, 0);
558 }
559