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