- Various other small fixes.
chimara_glk_stop
chimara_glk_wait
chimara_glk_get_running
+chimara_glk_feed_char_input
+chimara_glk_feed_line_input
<SUBSECTION Standard>
CHIMARA_GLK
CHIMARA_IS_GLK
+#include "abort.h"
#include "event.h"
#include <glib.h>
#include <gtk/gtk.h>
/* Internal function: abort this Glk program, freeing resources and calling the
user's interrupt handler. */
static void
-abort_glk()
+abort_glk(void)
{
ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
if(glk_data->interrupt_handler)
(*(glk_data->interrupt_handler))();
- g_signal_emit_by_name(glk_data->self, "stopped");
+ shutdown_glk();
g_thread_exit(NULL);
}
/* Internal function: check if the Glk program has been interrupted. */
void
-check_for_abort()
+check_for_abort(void)
{
ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
g_mutex_lock(glk_data->abort_lock);
}
g_mutex_unlock(glk_data->abort_lock);
}
+
+/* Internal function: do any cleanup for shutting down the Glk library. */
+void
+shutdown_glk(void)
+{
+ ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+
+ if(!glk_data->in_startup)
+ g_signal_emit_by_name(glk_data->self, "stopped");
+
+ /* Stop any timers */
+ glk_request_timer_events(0);
+
+ /* Close any open resource files */
+ if(glk_data->resource_map != NULL) {
+ giblorb_destroy_map(glk_data->resource_map);
+ glk_stream_close(glk_data->resource_file, NULL);
+ }
+
+ /* Unref the input queues */
+ g_async_queue_unref(glk_data->char_input_queue);
+ g_async_queue_unref(glk_data->line_input_queue);
+}
#ifndef ABORT_H
#define ABORT_H
-G_GNUC_INTERNAL void check_for_abort();
+#include <glib.h>
+
+G_GNUC_INTERNAL void check_for_abort(void);
+G_GNUC_INTERNAL void shutdown_glk(void);
#endif
GCond *rearranged;
gboolean needs_rearrange;
gboolean ignore_next_arrange_event;
+ /* Input queues */
+ GAsyncQueue *char_input_queue;
+ GAsyncQueue *line_input_queue;
/* *** Glk library data *** */
/* User-defined interrupt handler */
priv->rearranged = g_cond_new();
priv->needs_rearrange = FALSE;
priv->ignore_next_arrange_event = FALSE;
- priv->interrupt_handler = NULL;
+ priv->char_input_queue = g_async_queue_new();
+ priv->line_input_queue = g_async_queue_new();
+ /* Should be g_async_queue_new_full(g_free); but only in GTK >= 2.16 */
+ priv->interrupt_handler = NULL;
priv->root_window = NULL;
priv->fileref_list = NULL;
priv->current_stream = NULL;
g_mutex_free(priv->arrange_lock);
priv->arrange_lock = NULL;
+ /* Unref input queues */
+ g_async_queue_unref(priv->char_input_queue);
+ g_async_queue_unref(priv->line_input_queue);
+
/* Free private data */
pango_font_description_free(priv->default_font_desc);
pango_font_description_free(priv->monospace_font_desc);
extern GPrivate *glk_data_key;
g_private_set(glk_data_key, startup->glk_data);
+ g_async_queue_ref(startup->glk_data->char_input_queue);
+ g_async_queue_ref(startup->glk_data->line_input_queue);
+
/* Run startup function */
if(startup->glkunix_startup_code) {
startup->glk_data->in_startup = TRUE;
CHIMARA_GLK_USE_PRIVATE(glk, priv);
return priv->running;
}
+
+/**
+ * chimara_glk_feed_char_input:
+ * @glk: a #ChimaraGlk widget
+ * @keyval: a key symbol as defined in <filename
+ * class="headerfile">gdk/gdkkeysyms.h</filename>
+ *
+ * Pretend that a key was pressed in the Glk program as a response to a
+ * character input request. You can call this function even when no window has
+ * requested character input, in which case the key will be saved for the
+ * following window that requests character input. This has the disadvantage
+ * that if more than one window has requested character input, it is arbitrary
+ * which one gets the key press.
+ */
+void
+chimara_glk_feed_char_input(ChimaraGlk *glk, guint keyval)
+{
+ g_return_if_fail(glk || CHIMARA_IS_GLK(glk));
+ CHIMARA_GLK_USE_PRIVATE(glk, priv);
+ g_async_queue_push(priv->char_input_queue, GUINT_TO_POINTER(keyval));
+ event_throw(glk, evtype_ForcedCharInput, NULL, 0, 0);
+}
+
+/**
+ * chimara_glk_feed_line_input:
+ * @glk: a #ChimaraGlk widget
+ * @text: text to pass to the next line input request
+ *
+ * Pretend that @text was typed in the Glk program as a response to a line input
+ * request. @text does not need to end with a newline. You can call this
+ * function even when no window has requested line input, in which case the text
+ * will be saved for the following window that requests line input. This has the
+ * disadvantage that if more than one window has requested character input, it
+ * is arbitrary which one gets the text.
+ */
+void
+chimara_glk_feed_line_input(ChimaraGlk *glk, const gchar *text)
+{
+ g_return_if_fail(glk || CHIMARA_IS_GLK(glk));
+ g_return_if_fail(text);
+ CHIMARA_GLK_USE_PRIVATE(glk, priv);
+ g_async_queue_push(priv->line_input_queue, g_strdup(text));
+ event_throw(glk, evtype_ForcedLineInput, NULL, 0, 0);
+}
void chimara_glk_stop(ChimaraGlk *glk);
void chimara_glk_wait(ChimaraGlk *glk);
gboolean chimara_glk_get_running(ChimaraGlk *glk);
+void chimara_glk_feed_char_input(ChimaraGlk *glk, guint32 keycode);
+void chimara_glk_feed_line_input(ChimaraGlk *glk, const gchar *text);
G_END_DECLS
#include "magic.h"
#include "glk.h"
#include "window.h"
+#include "input.h"
#include <string.h>
#include "chimara-glk.h"
g_mutex_unlock(priv->event_lock);
}
+/* Helper function: Wait for an event in the event queue. If it is a forced
+ * input event, but no windows have an input request of that type, then wait
+ * for the next event and put the forced input event back on top of the queue.
+ */
+static void
+get_appropriate_event(event_t *event)
+{
+ ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+
+ g_mutex_lock(glk_data->event_lock);
+
+ event_t *retrieved_event = NULL;
+
+ /* Wait for an event */
+ if( g_queue_is_empty(glk_data->event_queue) )
+ g_cond_wait(glk_data->event_queue_not_empty, glk_data->event_lock);
+
+ retrieved_event = g_queue_pop_tail(glk_data->event_queue);
+
+ /* Signal that the event queue is no longer full */
+ g_cond_signal(glk_data->event_queue_not_full);
+
+ g_mutex_unlock(glk_data->event_lock);
+
+ if(retrieved_event->type == evtype_ForcedCharInput)
+ {
+ /* Check for forced character input in the queue */
+ winid_t win;
+ for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL))
+ if(win->input_request_type == INPUT_REQUEST_CHARACTER || win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE)
+ break;
+ if(win)
+ {
+ force_char_input_from_queue(win, event);
+ g_free(retrieved_event);
+ }
+ else
+ {
+ get_appropriate_event(event);
+ g_mutex_lock(glk_data->event_lock);
+ g_queue_push_tail(glk_data->event_queue, retrieved_event);
+ g_cond_signal(glk_data->event_queue_not_empty);
+ g_mutex_unlock(glk_data->event_lock);
+ }
+ }
+ else if(retrieved_event->type == evtype_ForcedLineInput)
+ {
+ /* Check for forced line input in the queue */
+ winid_t win;
+ for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL))
+ if(win->input_request_type == INPUT_REQUEST_LINE || win->input_request_type == INPUT_REQUEST_LINE_UNICODE)
+ break;
+ if(win)
+ {
+ force_line_input_from_queue(win, event);
+ g_free(retrieved_event);
+ }
+ else
+ {
+ get_appropriate_event(event);
+ g_mutex_lock(glk_data->event_lock);
+ g_queue_push_tail(glk_data->event_queue, retrieved_event);
+ g_cond_signal(glk_data->event_queue_not_empty);
+ g_mutex_unlock(glk_data->event_lock);
+ }
+ }
+ else
+ {
+ if(retrieved_event == NULL)
+ {
+ WARNING("Retrieved NULL event from non-empty event queue");
+ return;
+ }
+ memcpy(event, retrieved_event, sizeof(event_t));
+ g_free(retrieved_event);
+ }
+}
+
/**
* glk_select:
* @event: Pointer to an #event_t.
/* Emit the "waiting" signal to let listeners know we are ready for input */
g_signal_emit_by_name(glk_data->self, "waiting");
- g_mutex_lock(glk_data->event_lock);
+ get_appropriate_event(event);
- /* Wait for an event */
- if( g_queue_is_empty(glk_data->event_queue) )
- g_cond_wait(glk_data->event_queue_not_empty, glk_data->event_lock);
-
- event_t *retrieved_event = g_queue_pop_tail(glk_data->event_queue);
- if(retrieved_event == NULL)
- {
- g_mutex_unlock(glk_data->event_lock);
- WARNING("Retrieved NULL event from non-empty event queue");
- return;
- }
- memcpy(event, retrieved_event, sizeof(event_t));
- g_free(retrieved_event);
-
- /* Signal that the event queue is no longer full */
- g_cond_signal(glk_data->event_queue_not_full);
-
- g_mutex_unlock(glk_data->event_lock);
-
/* Check for interrupt */
glk_tick();
* intended for you to test conditions which may have occurred while you are
* computing, and not interfacing with the player. For example, time may pass
* during slow computations; you can use glk_select_poll() to see if a
- * %evtype_Timer event has occured. (See <link
+ * %evtype_Timer event has occurred. (See <link
* linkend="chimara-Timer-Events">Timer Events</link>.)
*
* At the moment, glk_select_poll() checks for %evtype_Timer, %evtype_Arrange,
#define EVENT_QUEUE_MAX_LENGTH (100)
#define evtype_Abort (-1)
+#define evtype_ForcedCharInput (-2)
+#define evtype_ForcedLineInput (-3)
G_GNUC_INTERNAL void event_throw(ChimaraGlk *glk, glui32 type, winid_t win, glui32 val1, glui32 val2);
void
glk_exit(void)
{
- ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
-
- if(!glk_data->in_startup)
- g_signal_emit_by_name(glk_data->self, "stopped");
-
- /* Stop any timers */
- glk_request_timer_events(0);
-
- /* Close any open resource files */
- if(glk_data->resource_map != NULL) {
- giblorb_destroy_map(glk_data->resource_map);
- glk_stream_close(glk_data->resource_file, NULL);
- }
-
+ shutdown_glk();
g_thread_exit(NULL);
}
* it is illegal to change the contents of the buffer yourself.
*/
void
-glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen)
+glk_request_line_event(winid_t win, char *buf, glui32 maxlen, glui32 initlen)
{
VALID_WINDOW(win, return);
g_return_if_fail(buf);
g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
g_return_if_fail(initlen <= maxlen);
- /* Register the buffer */
ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+
+ /* Register the buffer */
if(glk_data->register_arr)
win->buffer_rock = (*glk_data->register_arr)(buf, maxlen, "&+#!Cn");
* The result will be in Unicode Normalization Form C. This basically means that
* composite characters will be single characters where possible, instead of
* sequences of base and combining marks. See
- * <ulink url="http://www.unicode.org/reports/tr15/">Unicode Standard Annex #15
- * </ulink> for the details.
+ * <ulink url="http://www.unicode.org/reports/tr15/">Unicode Standard Annex
+ * #15</ulink> for the details.
*/
void
glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
g_return_if_fail(initlen <= maxlen);
- /* Register the buffer */
ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+
+ /* Register the buffer */
if(glk_data->register_arr)
win->buffer_rock = (*glk_data->register_arr)(buf, maxlen, "&+#!Iu");
* This cancels a pending request for line input. (Either Latin-1 or Unicode.)
*
* The event pointed to by the event argument will be filled in as if the
- * player had hit <keycap>enter</keycap>, and the input composed so far will be stored in the
- * buffer; see below. If you do not care about this information, pass %NULL as
- * the @event argument. (The buffer will still be filled.)
+ * player had hit <keycap>enter</keycap>, and the input composed so far will be
+ * stored in the buffer; see below. If you do not care about this information,
+ * pass %NULL as the @event argument. (The buffer will still be filled.)
*
* For convenience, it is legal to call glk_cancel_line_event() even if there
* is no line input request on that window. The event type will be set to
win->input_request_type != INPUT_REQUEST_CHARACTER_UNICODE)
return FALSE;
- int keycode;
-
- switch(event->keyval) {
- case GDK_Up:
- case GDK_KP_Up: keycode = keycode_Up; break;
- case GDK_Down:
- case GDK_KP_Down: keycode = keycode_Down; break;
- case GDK_Left:
- case GDK_KP_Left: keycode = keycode_Left; break;
- case GDK_Right:
- case GDK_KP_Right: keycode = keycode_Right; break;
- case GDK_Linefeed:
- case GDK_Return:
- case GDK_KP_Enter: keycode = keycode_Return; break;
- case GDK_Delete:
- case GDK_BackSpace:
- case GDK_KP_Delete: keycode = keycode_Delete; break;
- case GDK_Escape: keycode = keycode_Escape; break;
- case GDK_Tab:
- case GDK_KP_Tab: keycode = keycode_Tab; break;
- case GDK_Page_Up:
- case GDK_KP_Page_Up: keycode = keycode_PageUp; break;
- case GDK_Page_Down:
- case GDK_KP_Page_Down: keycode = keycode_PageDown; break;
- case GDK_Home:
- case GDK_KP_Home: keycode = keycode_Home; break;
- case GDK_End:
- case GDK_KP_End: keycode = keycode_End; break;
- case GDK_F1:
- case GDK_KP_F1: keycode = keycode_Func1; break;
- case GDK_F2:
- case GDK_KP_F2: keycode = keycode_Func2; break;
- case GDK_F3:
- case GDK_KP_F3: keycode = keycode_Func3; break;
- case GDK_F4:
- case GDK_KP_F4: keycode = keycode_Func4; break;
- case GDK_F5: keycode = keycode_Func5; break;
- case GDK_F6: keycode = keycode_Func6; break;
- case GDK_F7: keycode = keycode_Func7; break;
- case GDK_F8: keycode = keycode_Func8; break;
- case GDK_F9: keycode = keycode_Func9; break;
- case GDK_F10: keycode = keycode_Func10; break;
- case GDK_F11: keycode = keycode_Func11; break;
- case GDK_F12: keycode = keycode_Func12; break;
- default:
- keycode = gdk_keyval_to_unicode(event->keyval);
- /* If keycode is 0, then keyval was not recognized; also return
- unknown if Latin-1 input was requested and the character is not in
- Latin-1 */
- if(keycode == 0 || (win->input_request_type == INPUT_REQUEST_CHARACTER && keycode > 255))
- keycode = keycode_Unknown;
- }
+ glui32 keycode = keyval_to_glk_keycode(event->keyval, win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE);
ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(widget, CHIMARA_TYPE_GLK));
g_assert(glk);
void
on_input_entry_activate(GtkEntry *input_entry, winid_t win)
{
- g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
+ g_signal_handler_block(win->widget, win->keypress_handler);
int chars_written = finish_text_grid_line_input(win, TRUE);
- event_throw(CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK)), evtype_LineInput, win, chars_written, 0);
+ ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
+ event_throw(glk, evtype_LineInput, win, chars_written, 0);
}
+glui32
+keyval_to_glk_keycode(guint keyval, gboolean unicode)
+{
+ glui32 keycode;
+ switch(keyval) {
+ case GDK_Up:
+ case GDK_KP_Up: return keycode_Up;
+ case GDK_Down:
+ case GDK_KP_Down: return keycode_Down;
+ case GDK_Left:
+ case GDK_KP_Left: return keycode_Left;
+ case GDK_Right:
+ case GDK_KP_Right: return keycode_Right;
+ case GDK_Linefeed:
+ case GDK_Return:
+ case GDK_KP_Enter: return keycode_Return;
+ case GDK_Delete:
+ case GDK_BackSpace:
+ case GDK_KP_Delete: return keycode_Delete;
+ case GDK_Escape: return keycode_Escape;
+ case GDK_Tab:
+ case GDK_KP_Tab: return keycode_Tab;
+ case GDK_Page_Up:
+ case GDK_KP_Page_Up: return keycode_PageUp;
+ case GDK_Page_Down:
+ case GDK_KP_Page_Down: return keycode_PageDown;
+ case GDK_Home:
+ case GDK_KP_Home: return keycode_Home;
+ case GDK_End:
+ case GDK_KP_End: return keycode_End;
+ case GDK_F1:
+ case GDK_KP_F1: return keycode_Func1;
+ case GDK_F2:
+ case GDK_KP_F2: return keycode_Func2;
+ case GDK_F3:
+ case GDK_KP_F3: return keycode_Func3;
+ case GDK_F4:
+ case GDK_KP_F4: return keycode_Func4;
+ case GDK_F5: return keycode_Func5;
+ case GDK_F6: return keycode_Func6;
+ case GDK_F7: return keycode_Func7;
+ case GDK_F8: return keycode_Func8;
+ case GDK_F9: return keycode_Func9;
+ case GDK_F10: return keycode_Func10;
+ case GDK_F11: return keycode_Func11;
+ case GDK_F12: return keycode_Func12;
+ default:
+ keycode = gdk_keyval_to_unicode(keyval);
+ /* If keycode is 0, then keyval was not recognized; also return
+ unknown if Latin-1 input was requested and the character is not in
+ Latin-1 */
+ if(keycode == 0 || (!unicode && keycode > 255))
+ return keycode_Unknown;
+ return keycode;
+ }
+}
+
+void
+force_char_input_from_queue(winid_t win, event_t *event)
+{
+ ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+ guint keyval = GPOINTER_TO_UINT(g_async_queue_pop(glk_data->char_input_queue));
+
+ glk_cancel_char_event(win);
+
+ gdk_threads_enter();
+ ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
+ g_assert(glk);
+ g_signal_emit_by_name(glk, "char-input", win->rock, keyval);
+ gdk_threads_leave();
+
+ event->type = evtype_CharInput;
+ event->win = win;
+ event->val1 = keyval_to_glk_keycode(keyval, win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE);
+ event->val2 = 0;
+}
+
+void
+force_line_input_from_queue(winid_t win, event_t *event)
+{
+ ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+ const gchar *text = g_async_queue_pop(glk_data->line_input_queue);
+ glui32 chars_written = 0;
+
+ gdk_threads_enter();
+ if(win->type == wintype_TextBuffer)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
+ GtkTextIter start, end;
+
+ /* Remove signal handlers so the line input doesn't get picked up again */
+ g_signal_handler_block(buffer, win->insert_text_handler);
+
+ /* Erase any text that was already typed */
+ GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position");
+ gtk_text_buffer_get_iter_at_mark(buffer, &start, input_position);
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gtk_text_buffer_delete(buffer, &start, &end);
+
+ /* Make the window uneditable again */
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
+
+ /* Insert the forced input into the window */
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gchar *text_to_insert = g_strconcat(text, "\n", NULL);
+ gtk_text_buffer_insert_with_tags_by_name(buffer, &end, text_to_insert, -1, "input", NULL);
+ chars_written = finish_text_buffer_line_input(win, TRUE);
+ }
+ else if(win->type == wintype_TextGrid)
+ {
+ /* Remove signal handlers so the line input doesn't get picked up again */
+ g_signal_handler_block(win->widget, win->keypress_handler);
+
+ /* Insert the forced input into the window */
+ gtk_entry_set_text(GTK_ENTRY(win->input_entry), text);
+ chars_written = finish_text_grid_line_input(win, TRUE);
+ }
+ gdk_threads_leave();
+
+ event->type = evtype_LineInput;
+ event->win = win;
+ event->val1 = chars_written;
+ event->val2 = 0;
+}
G_GNUC_INTERNAL gboolean on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win);
G_GNUC_INTERNAL void after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win);
G_GNUC_INTERNAL void on_input_entry_activate(GtkEntry *input_entry, winid_t win);
+G_GNUC_INTERNAL glui32 keyval_to_glk_keycode(guint keyval, gboolean unicode);
+G_GNUC_INTERNAL void force_char_input_from_queue(winid_t win, event_t *event);
+G_GNUC_INTERNAL void force_line_input_from_queue(winid_t win, event_t *event);
#endif
noinst_PROGRAMS = test-chimara test-multisession
-test_chimara_SOURCES = main.c callbacks.c callbacks.h error.c error.h
+test_chimara_SOURCES = main.c callbacks.c error.c error.h
test_chimara_CPPFLAGS = $(AM_CPPFLAGS) \
-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
-DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "callbacks.h"
+#include <gdk/gdkkeysyms.h>
+#include <libchimara/chimara-glk.h>
#include "error.h"
-void on_save(GtkAction *action, gpointer user_data) {
+void on_save(GtkAction *action, ChimaraGlk *glk) {
GSList *widgets = gtk_action_get_proxies(action);
GtkWindow *top = GTK_WINDOW( gtk_widget_get_toplevel(widgets->data) );
error_dialog(top, NULL, "Not implemented yet");
}
-gboolean on_window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
+gboolean on_window_delete_event(GtkWidget *widget, GdkEvent *event, ChimaraGlk *glk) {
gtk_main_quit();
return TRUE;
}
-void on_quit(GtkAction *action, gpointer user_data) {
+void on_quit(GtkAction *action, ChimaraGlk *glk) {
gtk_main_quit();
}
+void on_hint(GtkAction *action, ChimaraGlk *glk) {
+ chimara_glk_feed_line_input(glk, "se");
+ chimara_glk_feed_line_input(glk, "push cans to window");
+ chimara_glk_feed_line_input(glk, "stand on cans");
+ chimara_glk_feed_line_input(glk, "open window");
+ chimara_glk_feed_line_input(glk, "enter window");
+}
+
+void on_press_r(GtkAction *action, ChimaraGlk *glk) {
+ chimara_glk_feed_char_input(glk, GDK_R);
+}
+
+void on_press_enter(GtkAction *action, ChimaraGlk *glk) {
+ chimara_glk_feed_char_input(glk, GDK_Return);
+ chimara_glk_feed_char_input(glk, GDK_Return);
+ chimara_glk_feed_char_input(glk, GDK_Return);
+}
+++ /dev/null
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-/*
- * callbacks.h
- * Copyright (C) Philip en Marijn 2008 <>
- *
- * callbacks.h is free software copyrighted by Philip en Marijn.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name ``Philip en Marijn'' nor the name of any other
- * contributor may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * callbacks.h IS PROVIDED BY Philip en Marijn ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL Philip en Marijn OR ANY OTHER CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <gtk/gtk.h>
-
-void on_save(GtkAction *action, gpointer user_data);
-gboolean on_window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data);
-void on_quit(GtkAction *action, gpointer user_data);
<menuitem action="open"/>
<menuitem action="save"/>
<separator/>
+ <menuitem action="hint"/>
+ <menuitem action="char_input"/>
+ <menuitem action="char_input2"/>
+ <separator/>
<menuitem action="quit"/>
</menu>
</menubar>
<toolbar>
<toolitem action="save"/>
<toolitem action="quit"/>
+ <separator/>
+ <toolitem action="hint"/>
+ <toolitem action="char_input"/>
+ <toolitem action="char_input2"/>
</toolbar>
</ui>
<property name="stock_id">gtk-quit</property>
<signal name="activate" handler="on_quit"/>
</object>
+ <object class="GtkAction" id="hint">
+ <property name="label">_Hint</property>
+ <property name="tooltip">Do the first few moves of the game</property>
+ <property name="stock_id">gtk-dialog-info</property>
+ <signal name="activate" handler="on_hint"/>
+ </object>
+ <object class="GtkAction" id="char_input">
+ <property name="label">Press _R</property>
+ <property name="stock_id">gtk-open</property>
+ <signal name="activate" handler="on_press_r"/>
+ </object>
+ <object class="GtkAction" id="char_input2">
+ <property name="label">3x _Enter</property>
+ <property name="stock_id">gtk-media-play</property>
+ <signal name="activate" handler="on_press_enter"/>
+ </object>
</interface>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
-#include "callbacks.h"
#include "error.h"
#include <libchimara/chimara-glk.h>
#include <libchimara/chimara-if.h>
static void
on_command(ChimaraGlk *glk, gchar *input, gchar *response)
{
- g_print("Command: %s\nResponse: %s\n", input, response);
+ gchar *ellipsized = g_strdelimit(g_strndup(response, 20), "\n", ' ');
+ g_print("%s - %s%s\n", input, ellipsized,
+ (strlen(ellipsized) < strlen(response))? "..." : "");
+ g_free(ellipsized);
}
static GObject *
"open", "<ctrl>F7",
"save", NULL, /* NULL means use stock accelerator */
"quit", NULL,
+ "hint", "",
+ "char_input", "",
+ "char_input2", "",
NULL
};
const gchar **ptr;
gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0);
gtk_box_pack_start(vbox, toolbar, FALSE, FALSE, 0);
- gtk_builder_connect_signals(builder, NULL);
+ gtk_builder_connect_signals(builder, glk);
}
int
}
buffer.input {
+ color: #0000aa;
+ font-style: italic;
}
buffer.user1 {