4031221206657fb15218a82b9cb2bdc0ad612507
[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 
175  * continue composing after this pre-entered input, or delete it or edit as 
176  * usual.)
177  * 
178  * The contents of the buffer are undefined until the input is completed (either
179  * by a line input event, or glk_cancel_line_event(). The library may or may not
180  * fill in the buffer as the player composes, while the input is still pending;
181  * it is illegal to change the contents of the buffer yourself. 
182  */
183 void
184 glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen)
185 {
186         VALID_WINDOW(win, return);
187         g_return_if_fail(buf);
188         g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
189         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
190         g_return_if_fail(initlen <= maxlen);
191
192         win->input_request_type = INPUT_REQUEST_LINE;
193         win->line_input_buffer = buf;
194         win->line_input_buffer_max_len = maxlen;
195
196         gchar *inserttext = (initlen > 0)? g_strndup(buf, initlen) : g_strdup("");
197         switch(win->type)
198         {
199             case wintype_TextBuffer:
200                 text_buffer_request_line_event_common(win, maxlen, (initlen > 0), inserttext);
201                 break;
202             case wintype_TextGrid:
203                 text_grid_request_line_event_common(win, maxlen, (initlen > 0), inserttext);
204                 break;
205     }
206         g_free(inserttext);
207 }
208
209 /**
210  * glk_request_line_event_uni:
211  * @win: A text buffer or text grid window to request line input on.
212  * @buf: A buffer of at least @maxlen characters.
213  * @maxlen: Length of the buffer.
214  * @initlen: The number of characters in @buf to pre-enter.
215  *
216  * Request input of a line of Unicode characters. This works the same as
217  * glk_request_line_event(), except the result is stored in an array of
218  * <type>glui32</type> values instead of an array of characters, and the values
219  * may be any valid Unicode code points.
220  * 
221  * The result will be in Unicode Normalization Form C. This basically means that
222  * composite characters will be single characters where possible, instead of
223  * sequences of base and combining marks. See 
224  * <ulink url="http://www.unicode.org/reports/tr15/">Unicode Standard Annex #15
225  * </ulink> for the details.
226  */
227 void
228 glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
229 {
230         VALID_WINDOW(win, return);
231         g_return_if_fail(buf);
232         g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
233         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
234         g_return_if_fail(initlen <= maxlen);
235
236         win->input_request_type = INPUT_REQUEST_LINE_UNICODE;
237         win->line_input_buffer_unicode = buf;
238         win->line_input_buffer_max_len = maxlen;
239
240         gchar *utf8;
241         if(initlen > 0) {
242                 utf8 = convert_ucs4_to_utf8(buf, initlen);
243                 if(utf8 == NULL)
244                         return;
245         }
246         else
247                 utf8 = g_strdup("");
248
249     switch(win->type)
250         {
251             case wintype_TextBuffer:
252                 text_buffer_request_line_event_common(win, maxlen, (initlen > 0), utf8);
253                 break;
254             case wintype_TextGrid:
255                 text_grid_request_line_event_common(win, maxlen, (initlen > 0), utf8);
256                 break;
257     }           
258         g_free(utf8);
259 }
260
261 /* Internal function: cancel a line input request, for both text grid and text buffer windows. */
262 static void
263 cancel_line_input_request(winid_t win, const gchar *inserted_text, event_t *event)
264 {
265         if(event)
266         {
267                 event->type = evtype_LineInput;
268                 event->win = win;
269                 event->val1 = event->val2 = 0;
270         }
271         
272     /* Convert the string from UTF-8 to Latin-1 or Unicode */
273     if(win->input_request_type == INPUT_REQUEST_LINE) 
274     {
275             win->input_request_type = INPUT_REQUEST_NONE;
276                 
277         gsize bytes_written;
278         gchar *latin1 = convert_utf8_to_latin1(inserted_text, &bytes_written);
279         
280         if(latin1 == NULL)
281             return;
282
283         /* Place input in the echo stream */
284         if(win->echo_stream != NULL) 
285             glk_put_string_stream(win->echo_stream, latin1);
286
287         /* Copy the string (bytes_written does not include the NULL at the end) */
288         int copycount = MIN(win->line_input_buffer_max_len, bytes_written);
289         memcpy(win->line_input_buffer, latin1, copycount);
290         g_free(latin1);
291         if(event)
292                         event->val1 = copycount;
293     }
294     else if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE) 
295     {
296         glong items_written;
297         gunichar *unicode = convert_utf8_to_ucs4(inserted_text, &items_written);
298         
299         if(unicode == NULL)
300             return;
301
302         /* Place input in the echo stream */
303         if(win->echo_stream != NULL) 
304             glk_put_string_stream_uni(win->echo_stream, unicode);
305
306         /* Copy the string (but not the NULL at the end) */
307         int copycount = MIN(win->line_input_buffer_max_len, items_written);
308         memcpy(win->line_input_buffer_unicode, unicode, copycount * sizeof(gunichar));
309         g_free(unicode);
310         if(event)
311                         event->val1 = copycount;
312     }
313     else 
314         WARNING("Wrong input request type");
315 }
316
317 /**
318  * glk_cancel_line_event:
319  * @win: A text buffer or text grid window to cancel line input on.
320  * @event: Will be filled in if the user had already input something.
321  *
322  * This cancels a pending request for line input. (Either Latin-1 or Unicode.)
323  *
324  * The event pointed to by the @event argument will be filled in as if the
325  * player had hit <keycap>enter</keycap>, and the input composed so far will be 
326  * stored in the buffer; see below. If you do not care about this information, 
327  * pass %NULL as the @event argument. (The buffer will still be filled.) 
328  *
329  * For convenience, it is legal to call glk_cancel_line_event() even if there
330  * is no line input request on that window. The event type will be set to
331  * #evtype_None in this case.
332  */
333 void
334 glk_cancel_line_event(winid_t win, event_t *event)
335 {
336         VALID_WINDOW(win, return);
337         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
338
339         if(win->input_request_type == INPUT_REQUEST_LINE || win->input_request_type == INPUT_REQUEST_LINE_UNICODE)
340         {
341                 if(win->type == wintype_TextBuffer)
342                 {
343                         /* Remove signal handlers */
344                         GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
345                         g_signal_handler_block(window_buffer, win->insert_text_handler);
346                 
347                         /* Make the window uneditable again and retrieve the text that was input */
348                         gchar *inserted_text;
349                         GtkTextIter start_iter, end_iter;
350
351                     gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
352                     GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
353                     gtk_text_buffer_get_iter_at_mark(window_buffer, &start_iter, input_position);
354                     gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
355                         gtk_text_iter_backward_cursor_position(&end_iter); /* don't include \n */
356                     
357                     inserted_text = gtk_text_buffer_get_text(window_buffer, &start_iter, &end_iter, FALSE);
358
359                     cancel_line_input_request(win, inserted_text, event);
360                     g_free(inserted_text);
361                 }
362                 else if(win->type == wintype_TextGrid)
363                 {
364                         GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
365         
366                         gchar *text = g_strdup( gtk_entry_get_text( GTK_ENTRY(win->input_entry) ) );
367                         /* Move the focus back into the text view */
368                         gtk_widget_grab_focus(win->widget);
369                         /* Remove entry widget from text view */
370                         gtk_container_remove(GTK_CONTAINER(win->widget), win->input_entry);
371                         win->input_entry = NULL;
372                         /* Delete the child anchor */
373                         GtkTextIter start, end;
374                         gtk_text_buffer_get_iter_at_child_anchor(buffer, &start, win->input_anchor);
375                         end = start;
376                         gtk_text_iter_forward_char(&end); /* Point after the child anchor */
377                         gtk_text_buffer_delete(buffer, &start, &end);
378                         win->input_anchor = NULL;
379         
380                         gchar *spaces = g_strnfill(win->input_length - g_utf8_strlen(text, -1), ' ');
381                         gchar *text_to_insert = g_strconcat(text, spaces, NULL);
382                         g_free(spaces);
383                         gtk_text_buffer_insert(buffer, &start, text_to_insert, -1);
384                         g_free(text_to_insert);
385                 
386                         g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
387         
388                         cancel_line_input_request(win, text, event);
389                         g_free(text);
390                 }
391         }
392         else
393                 if(event)
394                         event->type = evtype_None;
395 }
396
397 /* 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. */
398 gboolean
399 on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win)
400 {
401         /* If this is a text grid window, and line input is active, then redirect the key press to the line input GtkEntry */
402         if( win->type == wintype_TextGrid && (win->input_request_type == INPUT_REQUEST_LINE || win->input_request_type == INPUT_REQUEST_LINE_UNICODE) )
403         {
404                 if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up
405                     || event->keyval == GDK_Down || event->keyval == GDK_KP_Down
406                     || event->keyval == GDK_Left || event->keyval == GDK_KP_Left
407                     || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
408                     || event->keyval == GDK_Tab || event->keyval == GDK_KP_Tab
409                     || event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up
410                     || event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down
411                     || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
412                     || event->keyval == GDK_End || event->keyval == GDK_KP_End)
413                         return FALSE; /* Don't redirect these keys */
414                 gtk_widget_grab_focus(win->input_entry);
415                 gtk_editable_set_position(GTK_EDITABLE(win->input_entry), -1);
416                 gboolean retval = TRUE;
417                 g_signal_emit_by_name(win->input_entry, "key-press-event", event, &retval);
418                 return retval; /* Block this key event if the entry handled it */
419         }
420         if(win->input_request_type != INPUT_REQUEST_CHARACTER && 
421                 win->input_request_type != INPUT_REQUEST_CHARACTER_UNICODE)
422                 return FALSE;
423
424         int keycode;
425
426         switch(event->keyval) {
427                 case GDK_Up:
428                 case GDK_KP_Up: keycode = keycode_Up; break;
429                 case GDK_Down: 
430                 case GDK_KP_Down: keycode = keycode_Down; break;
431                 case GDK_Left:
432                 case GDK_KP_Left: keycode = keycode_Left; break;
433                 case GDK_Right:
434                 case GDK_KP_Right: keycode = keycode_Right; break;
435                 case GDK_Linefeed:
436                 case GDK_Return:
437                 case GDK_KP_Enter: keycode = keycode_Return; break;
438                 case GDK_Delete:
439                 case GDK_BackSpace:
440                 case GDK_KP_Delete: keycode = keycode_Delete; break;
441                 case GDK_Escape: keycode = keycode_Escape; break;
442                 case GDK_Tab: 
443                 case GDK_KP_Tab: keycode = keycode_Tab; break;
444                 case GDK_Page_Up:
445                 case GDK_KP_Page_Up: keycode = keycode_PageUp; break;
446                 case GDK_Page_Down:
447                 case GDK_KP_Page_Down: keycode = keycode_PageDown; break;
448                 case GDK_Home:
449                 case GDK_KP_Home: keycode = keycode_Home; break;
450                 case GDK_End:
451                 case GDK_KP_End: keycode = keycode_End; break;
452                 case GDK_F1: 
453                 case GDK_KP_F1: keycode = keycode_Func1; break;
454                 case GDK_F2: 
455                 case GDK_KP_F2: keycode = keycode_Func2; break;
456                 case GDK_F3: 
457                 case GDK_KP_F3: keycode = keycode_Func3; break;
458                 case GDK_F4: 
459                 case GDK_KP_F4: keycode = keycode_Func4; break;
460                 case GDK_F5: keycode = keycode_Func5; break;
461                 case GDK_F6: keycode = keycode_Func6; break;
462                 case GDK_F7: keycode = keycode_Func7; break;
463                 case GDK_F8: keycode = keycode_Func8; break;
464                 case GDK_F9: keycode = keycode_Func9; break;
465                 case GDK_F10: keycode = keycode_Func10; break;
466                 case GDK_F11: keycode = keycode_Func11; break;
467                 case GDK_F12: keycode = keycode_Func12; break;
468                 default:
469                         keycode = gdk_keyval_to_unicode(event->keyval);
470                         /* If keycode is 0, then keyval was not recognized; also return
471                         unknown if Latin-1 input was requested and the character is not in
472                         Latin-1 */
473                         if(keycode == 0 || (win->input_request_type == INPUT_REQUEST_CHARACTER && keycode > 255))
474                                 keycode = keycode_Unknown;      
475         }
476
477         event_throw(evtype_CharInput, win, keycode, 0);
478         
479         /* Only one keypress will be handled */
480         win->input_request_type = INPUT_REQUEST_NONE;
481         g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
482
483         return TRUE;
484 }
485
486 /* Internal function: finish handling a line input request, for both text grid and text buffer windows. */
487 static void
488 end_line_input_request(winid_t win, const gchar *inserted_text)
489 {
490     /* Convert the string from UTF-8 to Latin-1 or Unicode */
491     if(win->input_request_type == INPUT_REQUEST_LINE) 
492     {
493                 win->input_request_type = INPUT_REQUEST_NONE;
494                 
495         gsize bytes_written;
496         gchar *latin1 = convert_utf8_to_latin1(inserted_text, &bytes_written);
497         
498         if(latin1 == NULL)
499         {
500             event_throw(evtype_LineInput, win, 0, 0);
501             return;
502         }
503
504         /* Place input in the echo stream */
505         if(win->echo_stream != NULL) 
506             glk_put_string_stream(win->echo_stream, latin1);
507
508         /* Copy the string (bytes_written does not include the NULL at the end) */
509         int copycount = MIN(win->line_input_buffer_max_len, bytes_written);
510         memcpy(win->line_input_buffer, latin1, copycount);
511         g_free(latin1);
512         event_throw(evtype_LineInput, win, copycount, 0);
513     }
514     else if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE) 
515     {
516                 win->input_request_type = INPUT_REQUEST_NONE;
517                 
518         glong items_written;
519         gunichar *unicode = convert_utf8_to_ucs4(inserted_text, &items_written);
520         
521         if(unicode == NULL)
522         {
523             event_throw(evtype_LineInput, win, 0, 0);
524             return;
525         }
526
527         /* Place input in the echo stream */
528         if(win->echo_stream != NULL) 
529             glk_put_string_stream_uni(win->echo_stream, unicode);
530
531         /* Copy the string (but not the NULL at the end) */
532         int copycount = MIN(win->line_input_buffer_max_len, items_written);
533         memcpy(win->line_input_buffer_unicode, unicode, copycount * sizeof(gunichar));
534         g_free(unicode);
535         event_throw(evtype_LineInput, win, copycount, 0);
536     }
537     else 
538         WARNING("Wrong input request type");
539 }
540
541 /* Internal function: Callback for signal insert-text on a text buffer window.
542 Runs after the default handler has already inserted the text.
543 FIXME: This function assumes that newline was the last character typed into the
544 window. That assumption is wrong if, for example, text containing a newline was
545 pasted into the window. */
546 void
547 after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win) 
548 {
549         if( strchr(text, '\n') != NULL ) 
550         {
551                 /* Remove signal handlers */
552                 GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
553                 g_signal_handler_block(window_buffer, win->insert_text_handler);
554                 
555                 /* Make the window uneditable again and retrieve the text that was input */
556                 gchar *inserted_text;
557                 GtkTextIter start_iter, end_iter;
558
559         gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
560         GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
561         gtk_text_buffer_get_iter_at_mark(window_buffer, &start_iter, input_position);
562         gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
563                 gtk_text_iter_backward_cursor_position(&end_iter); /* don't include \n */
564         
565         inserted_text = gtk_text_buffer_get_text(window_buffer, &start_iter, &end_iter, FALSE);
566
567         end_line_input_request(win, inserted_text);
568         g_free(inserted_text);
569         }
570 }
571
572 /* Internal function: Callback for signal activate on the line input GtkEntry
573 in a text grid window. */
574 void
575 on_input_entry_activate(GtkEntry *input_entry, winid_t win)
576 {
577         GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
578         
579         gchar *text = g_strdup(gtk_entry_get_text(input_entry));
580         /* Move the focus back into the text view */
581         gtk_widget_grab_focus(win->widget);
582         /* Remove entry widget from text view */
583         /* Should be ok even though this is the widget's own signal handler */
584         gtk_container_remove( GTK_CONTAINER(win->widget), GTK_WIDGET(input_entry) );
585         win->input_entry = NULL;
586         /* Delete the child anchor */
587         GtkTextIter start, end;
588         gtk_text_buffer_get_iter_at_child_anchor(buffer, &start, win->input_anchor);
589         end = start;
590         gtk_text_iter_forward_char(&end); /* Point after the child anchor */
591         gtk_text_buffer_delete(buffer, &start, &end);
592         win->input_anchor = NULL;
593         
594     gchar *spaces = g_strnfill(win->input_length - g_utf8_strlen(text, -1), ' ');
595     gchar *text_to_insert = g_strconcat(text, spaces, NULL);
596         g_free(spaces);
597     gtk_text_buffer_insert(buffer, &start, text_to_insert, -1);
598     g_free(text_to_insert);
599     
600         g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
601         
602     end_line_input_request(win, text);
603         g_free(text);
604 }
605