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