6 #include "chimara-glk-private.h"
9 extern GPrivate glk_data_key;
12 * glk_set_interrupt_handler:
13 * @func: A pointer to an interrupt handler function.
15 * Sets @func to be the interrupt handler. @func should be a pointer to a
16 * function which takes no argument and returns no result. If Glk receives an
17 * interrupt, and you have set an interrupt handler, your handler will be
18 * called, before the process is shut down.
20 * Initially there is no interrupt handler. You can reset to not having any by
21 * calling <code>#glk_set_interrupt_handler(%NULL)</code>.
23 * If you call glk_set_interrupt_handler() with a new handler function while an
24 * older one is set, the new one replaces the old one. Glk does not try to queue
27 * You should not try to interact with the player in your interrupt handler. Do
28 * not call glk_select() or glk_select_poll(). Anything you print to a window
29 * may not be visible to the player.
32 glk_set_interrupt_handler(void (*func)(void))
34 ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
35 glk_data->interrupt_handler = func;
38 /* Internal function: abort this Glk program, freeing resources and calling the
39 user's interrupt handler. */
43 ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
44 if(glk_data->interrupt_handler)
45 (*(glk_data->interrupt_handler))();
48 /* If program is terminated by g_thread_exit() instead of returning from the
49 glk_main() function, then the line in glk_exit() where the "stopped"
50 signal is emitted will not be reached. So we have to emit it here. */
51 if(!glk_data->in_startup)
52 g_signal_emit_by_name(glk_data->self, "stopped");
56 /* Internal function: check if the Glk program has been interrupted. */
60 ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
61 g_mutex_lock(&glk_data->abort_lock);
62 if(glk_data->abort_signalled)
64 g_mutex_unlock(&glk_data->abort_lock);
67 g_mutex_unlock(&glk_data->abort_lock);
70 /* Internal function: shut down all requests and anything not necessary while
71 showing the last displayed configuration of windows. */
73 shutdown_glk_pre(void)
75 ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
78 glk_request_timer_events(0);
80 /* Cancel any pending input requests and flush all window buffers */
82 for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL))
84 switch(win->input_request_type)
86 case INPUT_REQUEST_CHARACTER:
87 case INPUT_REQUEST_CHARACTER_UNICODE:
88 glk_cancel_char_event(win);
90 case INPUT_REQUEST_LINE:
91 case INPUT_REQUEST_LINE_UNICODE:
92 glk_cancel_line_event(win, NULL);
94 case INPUT_REQUEST_NONE:
96 ; /* TODO: Handle mouse and hyperlink requests */
99 flush_window_buffer(win);
102 /* Close any open resource files */
103 if(glk_data->resource_map != NULL) {
104 giblorb_destroy_map(glk_data->resource_map);
105 glk_data->resource_map = NULL;
106 glk_stream_close(glk_data->resource_file, NULL);
109 /* Empty the input queues */
110 while(g_async_queue_try_pop(glk_data->char_input_queue))
112 while(g_async_queue_try_pop(glk_data->line_input_queue))
115 /* Wait for any pending window rearrange */
116 g_mutex_lock(&glk_data->arrange_lock);
117 if(glk_data->needs_rearrange)
118 g_cond_wait(&glk_data->rearranged, &glk_data->arrange_lock);
119 g_mutex_unlock(&glk_data->arrange_lock);
122 /* Internal function: do any Glk-thread cleanup for shutting down the Glk library. */
124 shutdown_glk_post(void)
126 ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
128 /* Free all opaque objects; can't iterate normally, because the objects are
129 being removed from the global iteration lists */
130 if(glk_data->root_window)
131 glk_window_close(glk_data->root_window->data, NULL);
132 g_assert(glk_data->root_window == NULL);
134 while( (str = glk_stream_iterate(NULL, NULL)) )
135 glk_stream_close(str, NULL);
137 while( (fref = glk_fileref_iterate(NULL, NULL)) )
138 glk_fileref_destroy(fref);
140 while( (sch = glk_schannel_iterate(NULL, NULL)) )
141 glk_schannel_destroy(sch);
143 /* Empty the event queue */
144 g_mutex_lock(&glk_data->event_lock);
145 g_queue_foreach(glk_data->event_queue, (GFunc)g_free, NULL);
146 g_queue_clear(glk_data->event_queue);
147 g_mutex_unlock(&glk_data->event_lock);
149 /* Reset the abort signaling mechanism */
150 g_mutex_lock(&glk_data->abort_lock);
151 glk_data->abort_signalled = FALSE;
152 g_mutex_unlock(&glk_data->abort_lock);
154 /* Reset arrangement mechanism */
155 g_mutex_lock(&glk_data->arrange_lock);
156 glk_data->needs_rearrange = FALSE;
157 glk_data->ignore_next_arrange_event = FALSE;
158 g_mutex_unlock(&glk_data->arrange_lock);
160 /* Unref input queues (they are not destroyed because the main thread stil holds a ref */
161 g_async_queue_unref(glk_data->char_input_queue);
162 g_async_queue_unref(glk_data->line_input_queue);
164 /* Reset other stuff */
165 glk_data->interrupt_handler = NULL;
166 g_free(glk_data->current_dir);
167 glk_data->current_dir = NULL;
168 /* Remove the dispatch callbacks */
169 glk_data->register_obj = NULL;
170 glk_data->unregister_obj = NULL;
171 glk_data->register_arr = NULL;
172 glk_data->unregister_arr = NULL;