Exemplo n.º 1
0
/**
 * 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);
}
Exemplo n.º 2
0
/* Internal function: shut down all requests and anything not necessary while
 showing the last displayed configuration of windows. */
void
shutdown_glk_pre(void)
{
	ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);

	/* Stop any timers */
	glk_request_timer_events(0);
	
	/* Cancel any pending input requests and flush all window buffers */
	winid_t win;
	for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL))
	{
		switch(win->input_request_type)
		{
			case INPUT_REQUEST_CHARACTER:
			case INPUT_REQUEST_CHARACTER_UNICODE:
				glk_cancel_char_event(win);
				break;
			case INPUT_REQUEST_LINE:
			case INPUT_REQUEST_LINE_UNICODE:
				glk_cancel_line_event(win, NULL);
				break;
			case INPUT_REQUEST_NONE:
			default:
				; /* TODO: Handle mouse and hyperlink requests */
		}
		
		flush_window_buffer(win);
	}
	
	/* Close any open resource files */
	if(glk_data->resource_map != NULL) {
		giblorb_destroy_map(glk_data->resource_map);
		glk_data->resource_map = NULL;
		glk_stream_close(glk_data->resource_file, NULL);
	}
	
	/* Empty the input queues */
	while(g_async_queue_try_pop(glk_data->char_input_queue))
		;
	while(g_async_queue_try_pop(glk_data->line_input_queue))
		;
	
	/* Wait for any pending window rearrange */
	g_mutex_lock(&glk_data->arrange_lock);
	if(glk_data->needs_rearrange)
		g_cond_wait(&glk_data->rearranged, &glk_data->arrange_lock);
	g_mutex_unlock(&glk_data->arrange_lock);
}
Exemplo n.º 3
0
/* Internal function: write a Latin-1 buffer with length to a stream. */
static void
write_buffer_to_stream(strid_t str, gchar *buf, glui32 len)
{
	switch(str->type)
	{
		case STREAM_TYPE_WINDOW:
			/* Each window type has a different way of printing to it */
			switch(str->window->type)
			{
				/* Printing to these windows' streams does nothing */
				case wintype_Blank:
				case wintype_Pair:
				case wintype_Graphics:
					str->write_count += len;
					break;
					
			    /* Text grid/buffer windows */
			    case wintype_TextGrid:
				{
			        gchar *utf8 = convert_latin1_to_utf8(buf, len);
			        if(utf8 != NULL) {
						/* Deal with newlines */
						int i;
						gchar *line = utf8;
						for(i=0; i<len; i++) {
							if(utf8[i] == '\n') {
								utf8[i] = '\0';
								write_utf8_to_window_buffer(str->window, line);
								flush_window_buffer(str->window);

								/* Move cursor position forward to the next line */
								gdk_threads_enter();
								GtkTextIter cursor_pos;
								GtkTextView *textview = GTK_TEXT_VIEW(str->window->widget);
								GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview);
								GtkTextMark *cursor_mark = gtk_text_buffer_get_mark(buffer, "cursor_position");

							    gtk_text_buffer_get_iter_at_mark( buffer, &cursor_pos, cursor_mark);
								gtk_text_view_forward_display_line(textview, &cursor_pos);
								gtk_text_view_backward_display_line_start(textview, &cursor_pos);
								gtk_text_buffer_move_mark(buffer, cursor_mark, &cursor_pos);
								gdk_threads_leave();

								line = utf8 + (i < len-1 ? (i+1):(len-1));
							}
						}
								
						/* No more newlines left. */
						write_utf8_to_window_buffer(str->window, line);
						g_free(utf8);
					}

					str->write_count += len;
				}
					break;

				case wintype_TextBuffer:
			    {
			        gchar *utf8 = convert_latin1_to_utf8(buf, len);
			        if(utf8 != NULL) {
						write_utf8_to_window_buffer(str->window, utf8);
						g_free(utf8);
					}
				}	
					str->write_count += len;
					break;
				default:
					ILLEGAL_PARAM("Unknown window type: %u", str->window->type);
			}
			
			/* Now write the same buffer to the window's echo stream */
			if(str->window->echo_stream != NULL)
				write_buffer_to_stream(str->window->echo_stream, buf, len);
			
			break;
			
		case STREAM_TYPE_MEMORY:
			if(str->unicode && str->ubuffer)
			{
				int foo = 0;
				while(str->mark < str->buflen && foo < len)
					str->ubuffer[str->mark++] = (unsigned char)buf[foo++];
			}
			if(!str->unicode && str->buffer)
			{
				int copycount = MIN(len, str->buflen - str->mark);
				memmove(str->buffer + str->mark, buf, copycount);
				str->mark += copycount;
			}

			/* Move the EOF marker if we wrote past it */
			if(str->mark > str->endmark)
				str->endmark = str->mark;

			str->write_count += len;
			break;
			
		case STREAM_TYPE_FILE:
			if(str->binary) 
			{
				if(str->unicode) 
				{
					gchar *writebuffer = convert_latin1_to_ucs4be_string(buf, len);
					ensure_file_operation(str, filemode_Write);
					fwrite(writebuffer, sizeof(gchar), len * 4, str->file_pointer);
					g_free(writebuffer);
				} 
				else /* Regular file */
				{
					ensure_file_operation(str, filemode_Write);
					fwrite(buf, sizeof(gchar), len, str->file_pointer);
				}
			}
			else /* Text mode is the same for Unicode and regular files */
			{
				gchar *utf8 = convert_latin1_to_utf8(buf, len);
				if(utf8 != NULL)
				{
					ensure_file_operation(str, filemode_Write);
					g_fprintf(str->file_pointer, "%s", utf8);
					g_free(utf8);
				}
			}
			
			str->write_count += len;
			break;
		case STREAM_TYPE_RESOURCE:
			ILLEGAL(_("Writing to a resource stream is illegal."));
			break;
		default:
			ILLEGAL_PARAM("Unknown stream type: %u", str->type);
	}
}