/** * glk_exit: * * If you want to shut down your program in the middle of your `glk_main()` * function, you can call glk_exit(). * * This function does not return. * * If you print some text to a window and then shut down your program, you can * assume that the player will be able to read it. Most likely the Glk library * will give a “`Hit any key to exit`” prompt. * (There are other possiblities, however. * A terminal-window version of Glk might simply exit and leave the last screen * state visible in the terminal window.) * * <note><para> * You should only shut down your program with glk_exit() or by returning from * your <function>glk_main()</function> function. If you call the ANSI * <function>exit()</function> function, bad things may happen. Some versions of * the Glk library may be designed for multiple sessions, for example, and you * would be cutting off all the sessions instead of just yours. You would * probably also prevent final text from being visible to the player. * </para></note> * * > # Chimara # * > If there are any windows open at the time glk_exit() is called, then * > Chimara will leave them open. * > This way, the final text remains visible. * > Note that bad things most definitely <emphasis>will</emphasis> happen if * > you use the ANSI `exit()`. */ void glk_exit(void) { ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); shutdown_glk_pre(); /* Find the biggest text buffer window */ winid_t win, largewin = NULL; glui32 largearea = 0; for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL)) { if(win->type == wintype_TextBuffer) { glui32 w, h; if(!largewin) { largewin = win; glk_window_get_size(largewin, &w, &h); largearea = w * h; } else { glk_window_get_size(win, &w, &h); if(w * h > largearea) { largewin = win; largearea = w * h; } } } } if(largewin) { glk_set_window(largewin); glk_set_style(style_Alert); glk_put_string("\n"); glk_put_string(glk_data->final_message); glk_put_string("\n"); flush_window_buffer(largewin); } /* Wait for a keypress if any text grid or buffer windows are open */ gboolean should_wait = FALSE; g_mutex_lock(&glk_data->shutdown_lock); for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL)) { if(win->type == wintype_TextGrid || win->type == wintype_TextBuffer) { g_signal_handler_unblock(win->widget, win->shutdown_keypress_handler); should_wait = TRUE; } } if (should_wait) g_cond_wait(&glk_data->shutdown_key_pressed, &glk_data->shutdown_lock); g_mutex_unlock(&glk_data->shutdown_lock); shutdown_glk_post(); gdk_threads_add_idle((GSourceFunc)emit_stopped_signal, glk_data->self); g_thread_exit(NULL); }
/* Internal function: abort this Glk program, freeing resources and calling the user's interrupt handler. */ static void abort_glk(void) { ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); if(glk_data->interrupt_handler) (*(glk_data->interrupt_handler))(); shutdown_glk_pre(); shutdown_glk_post(); /* If program is terminated by g_thread_exit() instead of returning from the glk_main() function, then the line in glk_exit() where the "stopped" signal is emitted will not be reached. So we have to emit it here. */ if(!glk_data->in_startup) g_signal_emit_by_name(glk_data->self, "stopped"); g_thread_exit(NULL); }