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