예제 #1
0
파일: multiwin.c 프로젝트: chimara/Chimara
/* Print some text in both windows. This uses print_to_otherwin() to
    find the other window and prepare it for printing. */
static void verb_both(winid_t win)
{
    winid_t otherwin;

    glk_set_window(win);
    glk_put_string("Something happens in this window.\n");

    otherwin = print_to_otherwin(win);

    if (otherwin) {
        glk_set_window(otherwin);
        glk_put_string("Something happens in the other window.\n");
    }
}
예제 #2
0
파일: multiwin.c 프로젝트: chimara/Chimara
static void draw_statuswin(void)
{
    glui32 width, height;

    if (!statuswin) {
        /* It is possible that the window was not successfully
            created. If that's the case, don't try to draw it. */
        return;
    }

    glk_set_window(statuswin);
    glk_window_clear(statuswin);

    glk_window_get_size(statuswin, &width, &height);

    /* Draw a decorative compass rose in the center. */
    width = (width/2);
    if (width > 0)
        width--;
    height = (height/2);
    if (height > 0)
        height--;

    glk_window_move_cursor(statuswin, width, height+0);
    glk_put_string("\\|/");
    glk_window_move_cursor(statuswin, width, height+1);
    glk_put_string("-*-");
    glk_window_move_cursor(statuswin, width, height+2);
    glk_put_string("/|\\");

}
예제 #3
0
파일: multiwin.c 프로젝트: chimara/Chimara
static void verb_quit(winid_t win)
{
    glk_set_window(win);

    glk_put_string("Thanks for playing.\n");
    glk_exit();
    /* glk_exit() actually stops the process; it does not return. */
}
예제 #4
0
파일: glk.c 프로젝트: chimara/Chimara
/**
 * 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);
}
예제 #5
0
파일: multiwin.c 프로젝트: chimara/Chimara
/* Print thirty lines. */
static void verb_page(winid_t win)
{
    int ix;
    char buf[32];

    glk_set_window(win);
    for (ix=0; ix<30; ix++) {
        num_to_str(buf, ix);
        glk_put_string(buf);
        glk_put_char('\n');
    }
}
예제 #6
0
파일: multiwin.c 프로젝트: chimara/Chimara
static void verb_yada(winid_t win)
{
    /* This is a goofy (and overly ornate) way to print a long paragraph.
        It just shows off line wrapping in the Glk implementation. */
    #define NUMWORDS (13)
    static char *wordcaplist[NUMWORDS] = {
        "Ga", "Bo", "Wa", "Mu", "Bi", "Fo", "Za", "Mo", "Ra", "Po",
            "Ha", "Ni", "Na"
    };
    static char *wordlist[NUMWORDS] = {
        "figgle", "wob", "shim", "fleb", "moobosh", "fonk", "wabble",
            "gazoon", "ting", "floo", "zonk", "loof", "lob",
    };
    static int wcount1 = 0;
    static int wcount2 = 0;
    static int wstep = 1;
    static int jx = 0;
    int ix;
    int first = TRUE;

    glk_set_window(win);

    for (ix=0; ix<85; ix++) {
        if (ix > 0) {
            glk_put_string(" ");
        }

        if (first) {
            glk_put_string(wordcaplist[(ix / 17) % NUMWORDS]);
            first = FALSE;
        }

        glk_put_string(wordlist[jx]);
        jx = (jx + wstep) % NUMWORDS;
        wcount1++;
        if (wcount1 >= NUMWORDS) {
            wcount1 = 0;
            wstep++;
            wcount2++;
            if (wcount2 >= NUMWORDS-2) {
                wcount2 = 0;
                wstep = 1;
            }
        }

        if ((ix % 17) == 16) {
            glk_put_string(".");
            first = TRUE;
        }
    }

    glk_put_char('\n');
}
예제 #7
0
void banner_contents_display(contentid_t contents)
{
    if (!contents || !(contents->banner))
        return;

    winid_t win = contents->banner->win;
    glui32 len = contents->len;

    glk_set_window(win);

    if (contents->newline)
    {
        char ch = '\n';
        os_put_buffer(&ch, 1);
    }
    
    if (len && (contents->chars[len-1] == '\n'))
    {
        len --;
        contents->banner->newline = 1;
    }
    else
    {
        contents->banner->newline = 0;
    }

    if (contents->move)
    {
        glk_window_move_cursor(win, contents->x, contents->y);
        contents->banner->move = 0;
        contents->banner->x = 0;
        contents->banner->y = 0;
    }

    glk_set_style(contents->style);
    os_put_buffer(contents->chars, len);
    glk_set_window(mainwin);
    banner_contents_display(contents->next);
}
예제 #8
0
파일: multiwin.c 프로젝트: chimara/Chimara
/* Turn off the timer. */
static void verb_untimer(winid_t win)
{
    glk_set_window(win);

    if (!timer_on) {
        glk_put_string("The timer is not currently running.\n");
        return;
    }

    glk_put_string("The timer stops running.\n");
    glk_request_timer_events(0);
    timer_on = FALSE;
}
예제 #9
0
파일: heglk.c 프로젝트: BPaden/garglk
void hugo_getline(char *prmpt)
{
	event_t ev;
	char gotline = 0;

	/* Just in case we try to get line input from a Glk-illegal
	   window that hasn't been created, switch as a failsafe
	   to mainwin
	*/
	if (currentwin==NULL)
		glk_set_window(currentwin = mainwin);

	/* Print prompt */
	glk_put_string(prmpt);

	/* Request line input */
	glk_request_line_event(currentwin, buffer, MAXBUFFER, 0);

        while (!gotline)
	{
		/* Grab an event */
		glk_select(&ev);

		switch (ev.type)
		{
 			case evtype_LineInput:
				/* (Will always be currentwin, but anyway) */
				if (ev.win==currentwin)
				{
					gotline = true;
				}
				break;
		}
        }
        
	/* The line we have received in commandbuf is not null-terminated */
	buffer[ev.val1] = '\0';	/* i.e., the length */

	/* Copy the input to the script file (if open) */
	if (script)
	{
		/* This looks inefficient, but it's necessary because
		   of the way Glk functions are mapped by stdio
		*/
		fprintf(script, "%s", prmpt);
		fprintf(script, "%s", buffer);
		fprintf(script, "%s", "\n");
	}
}
예제 #10
0
파일: heglk.c 프로젝트: BPaden/garglk
void glk_main(void)
{
	/* Open the main window... */
	mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);

	/* ...and set it up for default output */
	glk_set_window(currentwin = mainwin);

	/* It's possible that the main window failed to open. There's
	   nothing we can do without it, so exit */
	if (!mainwin)
		return; 

	he_main(0, NULL);	/* no argc, argv */
}
예제 #11
0
파일: multiwin.c 프로젝트: chimara/Chimara
/* Print every character, or rather try to. */
static void verb_chars(winid_t win)
{
    int ix;
    char buf[16];

    glk_set_window(win);

    for (ix=0; ix<256; ix++) {
        num_to_str(buf, ix);
        glk_put_string(buf);
        glk_put_string(": ");
        glk_put_char(ix);
        glk_put_char('\n');
    }
}
예제 #12
0
파일: glkmisc.c 프로젝트: BPaden/garglk
void os_fatal (const char *s)
{
	char err[256];
	sprintf(err,"%s",s);

	if (!gos_lower)
		gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);

	glk_set_window(gos_lower);
	glk_set_style(style_Normal);
	glk_put_string("\n\nFatal error: ");
	glk_put_string(err);
	glk_put_string("\n");
	glk_exit();
}
예제 #13
0
void print_two_rows(winid_t win)
{
	glui32 width, height;
	glk_window_get_size(win, &width, &height);
	
	glk_set_window(win);
	glk_window_clear(win);

	glui32 x = (width >= 6)? width / 2 - 3 : 0;
	glui32 y = (height > 0)? (height - 1) / 2 : 0;

	glk_window_move_cursor(win, x, y);
	glk_put_string("C: 2");
	glk_window_move_cursor(win, x + 3, y + 1);
	glk_put_string("rows");
}
예제 #14
0
파일: multiwin.c 프로젝트: chimara/Chimara
/* React to a timer event. This just prints "Tick" in mainwin1, but it
    first has to cancel line input if any is pending. */
static void perform_timer()
{
    event_t ev;

    if (!mainwin1)
        return;

    if (inputpending1) {
        glk_cancel_line_event(mainwin1, &ev);
        if (ev.type == evtype_LineInput)
            already1 = ev.val1;
        inputpending1 = FALSE;
    }

    glk_set_window(mainwin1);
    glk_put_string("Tick.\n");
}
예제 #15
0
파일: multiwin.c 프로젝트: chimara/Chimara
/* Turn on the timer. The timer prints a tick in mainwin1 every three
    seconds. */
static void verb_timer(winid_t win)
{
    glk_set_window(win);

    if (timer_on) {
        glk_put_string("The timer is already running.\n");
        return;
    }

    if (glk_gestalt(gestalt_Timer, 0) == 0) {
        glk_put_string("Your Glk library does not support timer events.\n");
        return;
    }

    glk_put_string("A timer starts running in the upper window.\n");
    glk_request_timer_events(3000); /* Every three seconds. */
    timer_on = TRUE;
}
예제 #16
0
파일: multiwin.c 프로젝트: chimara/Chimara
static void verb_help(winid_t win)
{
    glk_set_window(win);

    glk_put_string("This model only understands the following commands:\n");
    glk_put_string("HELP: Display this list.\n");
    glk_put_string("JUMP: Print a short message.\n");
    glk_put_string("YADA: Print a long paragraph.\n");
    glk_put_string("BOTH: Print a short message in both main windows.\n");
    glk_put_string("CLEAR: Clear one window.\n");
    glk_put_string("PAGE: Print thirty lines, demonstrating paging.\n");
    glk_put_string("PAGEBOTH: Print thirty lines in each window.\n");
    glk_put_string("TIMER: Turn on a timer, which ticks in the upper ");
    glk_put_string("main window every three seconds.\n");
    glk_put_string("UNTIMER: Turns off the timer.\n");
    glk_put_string("CHARS: Prints the entire Latin-1 character set.\n");
    glk_put_string("QUIT: Quit and exit.\n");
}
예제 #17
0
void center_text(winid_t win, char *text)
{
	glui32 width, height;
	glk_window_get_size(win, &width, &height);
	
	glk_set_window(win);
	glk_window_clear(win);
	
	if(glk_window_get_type(win) == wintype_TextGrid) {
		glk_window_move_cursor(win, width / 2 - strlen(text) / 2, height / 2);
		glk_put_string(text);
	} else if(glk_window_get_type(win) == wintype_TextBuffer) {
		int count;
		for(count = 0; count < height / 2; count++)
			glk_put_char('\n');
		for(count = 0; 
			count < (int)(SPACE_FACTOR * (width / 2 - strlen(text) / 2)); 
			count++)
			glk_put_char(' ');
		glk_put_string(text);
	}
}
예제 #18
0
파일: multiwin.c 프로젝트: chimara/Chimara
/* This draws some corner decorations in *every* key window -- the
    one created at startup, and any later ones. It finds them all
    with glk_window_iterate. */
static void draw_keywins(void)
{
    winid_t win;
    glui32 rock;
    glui32 width, height;

    for (win = glk_window_iterate(NULL, &rock);
            win;
            win = glk_window_iterate(win, &rock)) {
        if (rock == KEYWINROCK) {
            glk_set_window(win);
            glk_window_clear(win);
            glk_window_get_size(win, &width, &height);
            glk_window_move_cursor(win, 0, 0);
            glk_put_char('O');
            glk_window_move_cursor(win, width-1, 0);
            glk_put_char('O');
            glk_window_move_cursor(win, 0, height-1);
            glk_put_char('O');
            glk_window_move_cursor(win, width-1, height-1);
            glk_put_char('O');
        }
    }
}
예제 #19
0
파일: heglk.c 프로젝트: BPaden/garglk
void hugo_clearwindow(void)
{
/* Clears the currently defined window, moving the cursor to the top-left
   corner of the window */

	/* If the engine thinks we're in a window, but Glk was
	   unable to comply, don't clear the window, because it's
	   not really a window
	*/
	if (inwindow && currentwin==mainwin) return;
	if (currentwin==NULL) return;

	glk_window_clear(currentwin);

	/* See hugo_print() for the need for this */
	if (currentwin==mainwin) mainwin_bgcolor = glk_bgcolor;

	/* If we're in a fixed-font (i.e., textgrid) auxiliary
	   window when we call for a clear, close auxwin and reset
	   the current window to mainwin
	*/
	if (auxwin)
	{
		stream_result_t sr;

		glk_window_close(auxwin, &sr);
		auxwin = NULL;
		glk_set_window(currentwin = mainwin);
	}

	/* Must be set: */
	currentpos = 0;
	currentline = 1;

	if (!inwindow) just_cleared_screen = true;
}
예제 #20
0
void GlkInterface::initialize() {
	uint width, height;

	/*
	 * Init glk stuff
	 */

	 // monor
	glk_stylehint_set(wintype_AllTypes, style_Preformatted, stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes, style_Preformatted, stylehint_Weight, 0);
	glk_stylehint_set(wintype_AllTypes, style_Preformatted, stylehint_Oblique, 0);

	// monob
	glk_stylehint_set(wintype_AllTypes, style_Subheader, stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes, style_Subheader, stylehint_Weight, 1);
	glk_stylehint_set(wintype_AllTypes, style_Subheader, stylehint_Oblique, 0);

	// monoi
	glk_stylehint_set(wintype_AllTypes, style_Alert, stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes, style_Alert, stylehint_Weight, 0);
	glk_stylehint_set(wintype_AllTypes, style_Alert, stylehint_Oblique, 1);

	// monoz
	glk_stylehint_set(wintype_AllTypes, style_BlockQuote, stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes, style_BlockQuote, stylehint_Weight, 1);
	glk_stylehint_set(wintype_AllTypes, style_BlockQuote, stylehint_Oblique, 1);

	// propr
	glk_stylehint_set(wintype_TextBuffer, style_Normal, stylehint_Proportional, 1);
	glk_stylehint_set(wintype_TextGrid, style_Normal, stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes, style_Normal, stylehint_Weight, 0);
	glk_stylehint_set(wintype_AllTypes, style_Normal, stylehint_Oblique, 0);

	// propb
	glk_stylehint_set(wintype_TextBuffer, style_Header, stylehint_Proportional, 1);
	glk_stylehint_set(wintype_TextGrid, style_Header, stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes, style_Header, stylehint_Weight, 1);
	glk_stylehint_set(wintype_AllTypes, style_Header, stylehint_Oblique, 0);

	// propi
	glk_stylehint_set(wintype_TextBuffer, style_Emphasized, stylehint_Proportional, 1);
	glk_stylehint_set(wintype_TextGrid, style_Emphasized, stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes, style_Emphasized, stylehint_Weight, 0);
	glk_stylehint_set(wintype_AllTypes, style_Emphasized, stylehint_Oblique, 1);

	// propi
	glk_stylehint_set(wintype_TextBuffer, style_Note, stylehint_Proportional, 1);
	glk_stylehint_set(wintype_TextGrid, style_Note, stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes, style_Note, stylehint_Weight, 1);
	glk_stylehint_set(wintype_AllTypes, style_Note, stylehint_Oblique, 1);

	/*
	 * Get the screen size
	 */

	gos_lower = glk_window_open(0, 0, 0, wintype_TextGrid, 0);
	if (!gos_lower)
		gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
	glk_window_get_size(gos_lower, &width, &height);
	glk_window_close(gos_lower, nullptr);

	gos_channel = nullptr;

	/*
	 * Icky magic bit setting
	 */

	if (h_version == V3 && _tandyBit)
		h_config |= CONFIG_TANDY;

	if (h_version == V3 && gos_upper)
		h_config |= CONFIG_SPLITSCREEN;

	if (h_version == V3 && !gos_upper)
		h_config |= CONFIG_NOSTATUSLINE;

	if (h_version >= V4)
		h_config |= CONFIG_BOLDFACE | CONFIG_EMPHASIS |
		CONFIG_FIXED | CONFIG_TIMEDINPUT | CONFIG_COLOUR;

	if (h_version >= V5)
		h_flags &= ~(GRAPHICS_FLAG | MOUSE_FLAG | MENU_FLAG);

	if ((h_version >= 5) && (h_flags & SOUND_FLAG))
		h_flags |= SOUND_FLAG;

	if ((h_version == 3) && (h_flags & OLD_SOUND_FLAG))
		h_flags |= OLD_SOUND_FLAG;

	if ((h_version == 6) && (_sound != 0))
		h_config |= CONFIG_SOUND;

	if (h_version >= V5 && (h_flags & UNDO_FLAG))
		if (_undo_slots == 0)
			h_flags &= ~UNDO_FLAG;

	h_screen_cols = width;
	h_screen_rows = height;

	h_screen_height = h_screen_rows;
	h_screen_width = h_screen_cols;

	h_font_width = 1;
	h_font_height = 1;

	// Must be after screen dimensions are computed
	if (g_conf->_graphics) {
		if (_blorb)
			// Blorb file containers allow graphics
			h_flags |= GRAPHICS_FLAG;
		else if ((h_version == V6 || _storyId == BEYOND_ZORK) && initPictures())
			// Earlier Infocom game with picture files
			h_flags |= GRAPHICS_FLAG;
	}

	// Use the ms-dos interpreter number for v6, because that's the
	// kind of graphics files we understand
	h_interpreter_number = h_version == 6 ? INTERP_MSDOS : INTERP_AMIGA;
	h_interpreter_version = 'F';

	// Set these per spec 8.3.2.
	h_default_foreground = WHITE_COLOUR;
	h_default_background = BLACK_COLOUR;
	if (h_flags & COLOUR_FLAG)
		h_flags &= ~COLOUR_FLAG;

	/*
	 * Open the windows
	 */
	if (_storyId == BEYOND_ZORK)
		showBeyondZorkTitle();

	gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
	gos_upper = glk_window_open(gos_lower,
		winmethod_Above | winmethod_Fixed,
		0,
		wintype_TextGrid, 0);

	glk_set_window(gos_lower);
	gos_curwin = gos_lower;

	// Set the screen colors
	garglk_set_zcolors(_defaultForeground, _defaultBackground);

	// Add any sound folder or zip
	addSound();
}
예제 #21
0
파일: glkmisc.c 프로젝트: BPaden/garglk
void os_init_screen(void)
{
	glui32 width, height;

	/*
	 * Init glk stuff
	 */

	/* monor */
	glk_stylehint_set(wintype_AllTypes,   style_Preformatted, stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Preformatted, stylehint_Weight, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Preformatted, stylehint_Oblique, 0);

	/* monob */
	glk_stylehint_set(wintype_AllTypes,   style_Subheader,    stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Subheader,    stylehint_Weight, 1);
	glk_stylehint_set(wintype_AllTypes,   style_Subheader,    stylehint_Oblique, 0);

	/* monoi */
	glk_stylehint_set(wintype_AllTypes,   style_Alert,        stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Alert,        stylehint_Weight, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Alert,        stylehint_Oblique, 1);

	/* monoz */
	glk_stylehint_set(wintype_AllTypes,   style_BlockQuote,   stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes,   style_BlockQuote,   stylehint_Weight, 1);
	glk_stylehint_set(wintype_AllTypes,   style_BlockQuote,   stylehint_Oblique, 1);

	/* propr */
	glk_stylehint_set(wintype_TextBuffer, style_Normal,       stylehint_Proportional, 1);
	glk_stylehint_set(wintype_TextGrid,   style_Normal,       stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Normal,       stylehint_Weight, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Normal,       stylehint_Oblique, 0);

	/* propb */
	glk_stylehint_set(wintype_TextBuffer, style_Header,       stylehint_Proportional, 1);
	glk_stylehint_set(wintype_TextGrid,   style_Header,       stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Header,       stylehint_Weight, 1);
	glk_stylehint_set(wintype_AllTypes,   style_Header,       stylehint_Oblique, 0);

	/* propi */
	glk_stylehint_set(wintype_TextBuffer, style_Emphasized,   stylehint_Proportional, 1);
	glk_stylehint_set(wintype_TextGrid,   style_Emphasized,   stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Emphasized,   stylehint_Weight, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Emphasized,   stylehint_Oblique, 1);

	/* propi */
	glk_stylehint_set(wintype_TextBuffer, style_Note,         stylehint_Proportional, 1);
	glk_stylehint_set(wintype_TextGrid,   style_Note,         stylehint_Proportional, 0);
	glk_stylehint_set(wintype_AllTypes,   style_Note,         stylehint_Weight, 1);
	glk_stylehint_set(wintype_AllTypes,   style_Note,         stylehint_Oblique, 1);

	gos_lower = glk_window_open(0, 0, 0, wintype_TextGrid, 0);
	if (!gos_lower)
		gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
	glk_window_get_size(gos_lower, &width, &height);
	glk_window_close(gos_lower, NULL);

	gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
	gos_upper = glk_window_open(gos_lower,
			winmethod_Above | winmethod_Fixed,
			0,
			wintype_TextGrid, 0);

	gos_channel = NULL;

	glk_set_window(gos_lower);
	gos_curwin = gos_lower;

	/*
	 * Icky magic bit setting
	 */

	if (h_version == V3 && user_tandy_bit)
		h_config |= CONFIG_TANDY;

	if (h_version == V3 && gos_upper)
		h_config |= CONFIG_SPLITSCREEN;

	if (h_version == V3 && !gos_upper)
		h_config |= CONFIG_NOSTATUSLINE;

	if (h_version >= V4)
		h_config |= CONFIG_BOLDFACE | CONFIG_EMPHASIS |
			CONFIG_FIXED | CONFIG_TIMEDINPUT | CONFIG_COLOUR;

	if (h_version >= V5)
		h_flags &= ~(GRAPHICS_FLAG | MOUSE_FLAG | MENU_FLAG);

	if ((h_version >= 5) && (h_flags & SOUND_FLAG))
		h_flags |= SOUND_FLAG;

	if ((h_version == 3) && (h_flags & OLD_SOUND_FLAG))
		h_flags |= OLD_SOUND_FLAG;

	if ((h_version == 6) && (option_sound != 0)) 
		h_config |= CONFIG_SOUND;

	if (h_version >= V5 && (h_flags & UNDO_FLAG))
		if (option_undo_slots == 0)
			h_flags &= ~UNDO_FLAG;

	h_screen_cols = width;
	h_screen_rows = height;

	h_screen_height = h_screen_rows;
	h_screen_width = h_screen_cols;

	h_font_width = 1;
	h_font_height = 1;

	/* Must be after screen dimensions are computed.  */
	if (h_version == V6) {
		h_flags &= ~GRAPHICS_FLAG;
	}

	/* Use the ms-dos interpreter number for v6, because that's the
	 * kind of graphics files we understand.  Otherwise, use DEC.  */
	h_interpreter_number = h_version == 6 ? INTERP_MSDOS : INTERP_DEC_20;
	h_interpreter_version = 'F';
	{
		/* Set these per spec 8.3.2. */
		h_default_foreground = WHITE_COLOUR;
		h_default_background = BLACK_COLOUR;
		if (h_flags & COLOUR_FLAG) h_flags &= ~COLOUR_FLAG;
	}
}
예제 #22
0
파일: glkmisc.c 프로젝트: BPaden/garglk
void os_process_arguments(int argc, char *argv[]) 
{
	int c;

#ifdef GARGLK
	garglk_set_program_name("Frotz " VERSION);
	garglk_set_program_info(
			"Glk Frotz " VERSION "\n"
			"Original Frotz by Stefan Jokisch\n"
			"Unix port by Jim Dunleavy and David Griffith\n"
			"Glk port by Tor Andersson\n");
#endif

	/* Parse the options */
	do {
		c = zgetopt(argc, argv, "aAioOPQs:S:tu:xZ:");
		switch (c)
		{
			case 'a': option_attribute_assignment = 1; break;
			case 'A': option_attribute_testing = 1; break;
			case 'i': option_ignore_errors = 1; break;
			case 'o': option_object_movement = 1; break;
			case 'O': option_object_locating = 1; break;
			case 'P': option_piracy = 1; break;
			case 'Q': option_save_quetzal = 0; break;
			case 's': user_random_seed = atoi(zoptarg); break;
			case 'S': option_script_cols = atoi(zoptarg); break;
			case 't': user_tandy_bit = 1; break;
			case 'u': option_undo_slots = atoi(zoptarg); break;
			case 'x': option_expand_abbreviations = 1; break;
			case 'Z': option_err_report_mode = atoi(zoptarg);
					  if ((option_err_report_mode < ERR_REPORT_NEVER) ||
							  (option_err_report_mode > ERR_REPORT_FATAL))
						  option_err_report_mode = ERR_DEFAULT_REPORT_MODE;
					  break;
		}
	} while (c != EOF);

	if (((argc - zoptind) != 1) && ((argc - zoptind) != 2))
	{
		winid_t win;
		char buf[256];
		win = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
		glk_set_window(win);
		glk_put_string("FROTZ V" VERSION " -- Glk 0.7.0 interface.\n");
		glk_put_string(INFORMATION);
		sprintf(buf,
				"    -Z # error checking mode (default = %d)\n"
				"         %d = don't report errors.  "
				"%d = report first error.\n"
				"         %d = report all errors.  "
				"%d = exit after any error.\n",
				ERR_DEFAULT_REPORT_MODE, ERR_REPORT_NEVER,
				ERR_REPORT_ONCE, ERR_REPORT_ALWAYS, ERR_REPORT_FATAL);
		glk_put_string(buf);
		glk_exit();
	}
	else
	{
		char *s;

		story_name = argv[zoptind++];
		if (zoptind < argc)
			graphics_filename = argv[zoptind++];

		#ifdef GARGLK
		s = strrchr(story_name, '\\');
		if (!s) s = strrchr(story_name, '/');
		garglk_set_story_name(s ? s + 1 : story_name);
		#endif
	}
}
예제 #23
0
파일: heglk.c 프로젝트: BPaden/garglk
void hugo_settextpos(int x, int y)
{
/* The top-left corner of the current active window is (1, 1). */

	if (currentwin==NULL) return;

	/* Try to determine if we're trying to position fixed-width
	   text in the main window, as in a menu, for example
	*/
	if (!just_cleared_screen && !inwindow &&
		!(glk_current_font & PROP_FONT)
		&& y!=1			/* not just cls */
		&& y < SCREENHEIGHT-0x0f)	/* 0x0f is arbitrary */
	{
		/* See if we're already in the auxiliary window */
		if (currentwin!=auxwin)
		{
			/* If not, create it, making it 100% of
			   mainwin's height
			*/
			if (auxwin==NULL)
			{
				auxwin = glk_window_open(mainwin,
					winmethod_Below | winmethod_Proportional,
					100,
					wintype_TextGrid,
					0);
			}
			else
				glk_window_clear(auxwin);

			glk_set_window(currentwin = auxwin);
		}
	}

	/* On the other hand, if we were in a textgrid window and
	   no longer need to be, get out
	*/
	else if (auxwin)
	{
		stream_result_t sr;

		/* Close auxwin */
		glk_window_close(auxwin, &sr);
		auxwin = NULL;

		/* Clear the screen (both windows) */
		glk_window_clear(mainwin);
		glk_window_clear(secondwin);

		glk_set_window(currentwin = mainwin);
	}

	just_cleared_screen = false;

	/* Can only move the Glk cursor in a textgrid window */
	if (currentwin!=mainwin)
		glk_window_move_cursor(currentwin, x-1, y-1);

	/* Must be set: */
	currentline = y;
	currentpos = (x-1)*CHARWIDTH;   /* Note:  zero-based */
}
예제 #24
0
파일: heglk.c 프로젝트: BPaden/garglk
void hugo_settextwindow(int left, int top, int right, int bottom)
{
	static int secondwin_bottom = 0;

	/* Hugo's arbitrarily positioned windows don't currently
	   mesh with what Glk has to offer, so we have to ignore any
	   non-Glk-ish Windows and just maintain the current
	   parameters
	*/
	if ((top!=1 || bottom>=physical_windowbottom/FIXEDLINEHEIGHT+1)
		/* Pre-v2.4 didn't support proper windowing */
		&& (game_version>=24 || !inwindow))
	{
		in_valid_window = false;
		
		/* Glk-illegal floating window; setting currentwin
		   to NULL will tell hugo_print() not to print in it:
		*/
		if (bottom<physical_windowbottom/FIXEDLINEHEIGHT+1)
		{
			currentwin = NULL;
			glk_set_window(mainwin);
			return;
		}
		else
			glk_set_window(currentwin = mainwin);
	}

	/* Otherwise this is a valid window (positioned along the
	   top of the screen a la a status window), so... */
	else
	{
		/* Arbitrary height of 4 lines for pre-v2.4 windows */
		if (game_version < 24) bottom = 4;

		/* ...either create a new window if none exists... */
		if (!secondwin)
		{
			glk_stylehint_set (wintype_TextGrid, style_Normal, stylehint_ReverseColor, 1);
			glk_stylehint_set (wintype_TextGrid, style_Subheader, stylehint_ReverseColor, 1);
			glk_stylehint_set (wintype_TextGrid, style_Emphasized, stylehint_ReverseColor, 1);

			winid_t p;

			p = glk_window_get_parent(mainwin);
			secondwin = glk_window_open(mainwin,//p,
				winmethod_Above | winmethod_Fixed,
				bottom,
				wintype_TextGrid,
				0);
		}

		/* ...or resize the existing one if necessary */
		else if (bottom!=secondwin_bottom)
		{
			winid_t p;

			p  = glk_window_get_parent(secondwin);
			glk_window_set_arrangement(p, 
				winmethod_Above | winmethod_Fixed,
				bottom,
				secondwin);
		}

		if (secondwin)
		{
			if (game_version < 24)
				glk_window_clear(secondwin);

			glk_set_window(currentwin = secondwin);
			in_valid_window = true;
			secondwin_bottom = bottom;
		}
		else
		{
			currentwin = NULL;
			glk_set_window(mainwin);
			secondwin_bottom = 0;
			return;
		}
	}

	physical_windowleft = (left-1)*FIXEDCHARWIDTH;
	physical_windowtop = (top-1)*FIXEDLINEHEIGHT;
	physical_windowright = right*FIXEDCHARWIDTH-1;
	physical_windowbottom = bottom*FIXEDLINEHEIGHT-1;
	physical_windowwidth = (right-left+1)*FIXEDCHARWIDTH;
	physical_windowheight = (bottom-top+1)*FIXEDLINEHEIGHT;
}
예제 #25
0
void glk_main(void)
{
	FILE *f;
	int vb,no;

	Bottom = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
	if(Bottom == NULL)
		glk_exit();
	glk_set_window(Bottom);

	if(game_file == NULL)
		Fatal("No game provided");

	f = fopen(game_file, "r");
	if(f==NULL)
		Fatal("Cannot open game");

	if (Options & TRS80_STYLE)
	{
		Width = 64;
		TopHeight = 11;
	}
	else
	{
		Width = 80;
		TopHeight = 10;
	}

	if(split_screen)
	{
		Top = glk_window_open(Bottom, winmethod_Above | winmethod_Fixed, TopHeight, wintype_TextGrid, 0);
		if(Top == NULL)
		{
			split_screen = 0;
			Top = Bottom;
		}
	}
	else
	{
		Top = Bottom;
	}

	Output("\
Scott Free, A Scott Adams game driver in C.\n\
Release 1.14, (c) 1993,1994,1995 Swansea University Computer Society.\n\
Distributed under the GNU software license\n\n");
	LoadDatabase(f,(Options&DEBUGGING)?1:0);
	fclose(f);
	srand(time(NULL));
	while(1)
	{
		glk_tick();

		PerformActions(0,0);

		Look();

		if(GetInput(&vb,&no) == -1)
			continue;
		switch(PerformActions(vb,no))
		{
			case -1:Output("I don't understand your command. ");
				break;
			case -2:Output("I can't do that yet. ");
				break;
		}
		/* Brian Howarth games seem to use -1 for forever */
		if(Items[LIGHT_SOURCE].Location/*==-1*/!=DESTROYED && GameHeader.LightTime!= -1)
		{
			GameHeader.LightTime--;
			if(GameHeader.LightTime<1)
			{
				BitFlags|=(1<<LIGHTOUTBIT);
				if(Items[LIGHT_SOURCE].Location==CARRIED ||
					Items[LIGHT_SOURCE].Location==MyLoc)
				{
					if(Options&SCOTTLIGHT)
						Output("Light has run out! ");
					else
						Output("Your light has run out. ");
				}
				if(Options&PREHISTORIC_LAMP)
					Items[LIGHT_SOURCE].Location=DESTROYED;
			}
			else if(GameHeader.LightTime<25)
			{
				if(Items[LIGHT_SOURCE].Location==CARRIED ||
					Items[LIGHT_SOURCE].Location==MyLoc)
				{

					if(Options&SCOTTLIGHT)
					{
						Output("Light runs out in ");
						OutputNumber(GameHeader.LightTime);
						Output(" turns. ");
					}
					else
					{
						if(GameHeader.LightTime%5==0)
							Output("Your light is growing dim. ");
					}
				}
			}
		}
	}
}
예제 #26
0
파일: t23run.cpp 프로젝트: BPaden/garglk
void glk_main(void)
{
    int stat;
    static const char *defexts[] = { "gam", "t3" };
    char prog_arg[OSFNMAX];
    char fname[OSFNMAX];
    int engine_ver;

    int argc = tads_argc;
    char **argv = tads_argv;

    winid_t mainwin;
    char buf[256];
    char copyright[512];
    char errorload[512];

#ifdef GARGLK
    garglk_set_program_name("TADS " TADS_RUNTIME_VERSION " / " T3VM_VSN_STRING);
    garglk_set_program_info(
                "TADS Interpreter by Michael J. Roberts\n"
                "TADS 2 VM version " TADS_RUNTIME_VERSION "\n"
                "T3 VM version " T3VM_VSN_STRING "\n"
                "Gargoyle port by Tor Andersson\n"
    );
#endif

    /* 
     *   if one of our special usage message arguments was given, show the
     *   usage 
     */
    if (argc == 2 && stricmp(argv[1], "-help2") == 0)
    {
        /* invoke the tads 2 main entrypoint with no arguments */
        main_t2(1, argv);
        
        /* that's all we need to do with this option */
        os_term(OSEXSUCC);
    }
    else if (argc == 2 && stricmp(argv[1], "-help3") == 0)
    {
        /* invoke the tads 3 main entrypoint with no arguments */
        main_t3(1, argv);
        
        /* that's all we need to do with this option */
        os_term(OSEXSUCC);
    }

    /* look at the arguments and try to find the program name */
    if (!vm_get_game_arg(argc, argv, prog_arg, sizeof(prog_arg), &engine_ver))
    {
        /* 
         *   there's no game file name specified or implied - show the
         *   generic combined v2/v3 usage message 
         */
        mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
        glk_set_window(mainwin);

         /* copyright-date-string */
        sprintf(copyright,
                "TADS Interpreter - "
                "Copyright (c) 1993, 2004 Michael J. Roberts\n"
                "TADS 2 VM version " TADS_RUNTIME_VERSION " / "
                "T3 VM version " T3VM_VSN_STRING "\n\n");
        glk_put_string(copyright);

        sprintf(errorload,
                "Error: you didn't specify a game file name on the command "
                "line, or the command "
                "options are incorrect. You must specify the name of "
                "the game file you would "
                "like to run.\n"
                "\n"
                "If you'd like a list of command-line options for TADS 2 "
                "games, specify -help2 "
                "instead of giving a game file name. Or, if you'd like a "
                "list of command-line "
                "options for TADS 3, specify -help3.\n");
        glk_put_string(errorload);

        /* pause (if desired by OS layer) and exit */
        os_expause();
        os_term(OSEXFAIL);
    }

    /* determine the type of the game we have */
    engine_ver = vm_get_game_type(prog_arg, fname, sizeof(fname),
                                  defexts,
                                  sizeof(defexts)/sizeof(defexts[0]));

    /* presume failure */
    stat = OSEXFAIL;

    /* see what we have */
    switch(engine_ver)
    {
        case VM_GGT_TADS2:
            /* run the game using the TADS 2 engine */
            stat = main_t2(argc, argv);
            break;

        case VM_GGT_TADS3:
            /* run the game using the TADS 3 engine */
            stat = main_t3(argc, argv);
            break;

        case VM_GGT_INVALID:
            /* invalid file type */
            sprintf(buf,
                    "The file you have selected (%s) is not a valid game file.\n",
                    fname);
            mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
            glk_set_window(mainwin);
            glk_put_string(buf);
            break;

        case VM_GGT_NOT_FOUND:
            /* file not found */
            sprintf(buf, "The game file (%s) cannot be found.\n", prog_arg);
            mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
            glk_set_window(mainwin);
            glk_put_string(buf);
            break;

        case VM_GGT_AMBIG:
            /* ambiguous file */
            sprintf(buf,"The game file (%s) cannot be found exactly as given, "
                        "but multiple game "
                        "files with this name and different default suffixes "
                        "(.gam, .t3) exist. "
                        "Please specify the full name of the file, including the "
                        "suffix, that you "
                        "wish to use.\n",
                   prog_arg);
            mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
            glk_set_window(mainwin);
            glk_put_string(buf);
            break;
    }

    /* pause (if desired by OS layer) and terminate with our status code */
    os_expause();
    os_term(stat);
}
예제 #27
0
파일: term.c 프로젝트: cspiegel/garglk
/*======================================================================*/
void statusline(void)
{
#ifdef HAVE_GLK
  glui32 glkWidth;
  char line[100];
  int pcol = col;

  if (!statusLineOption) return;
  if (glkStatusWin == NULL)
    return;

  glk_set_window(glkStatusWin);
  glk_window_clear(glkStatusWin);
  glk_window_get_size(glkStatusWin, &glkWidth, NULL);

#ifdef HAVE_GARGLK
  int i;
  glk_set_style(style_User1);
  for (i = 0; i < glkWidth; i++)
    glk_put_char(' ');
#endif

  onStatusLine = TRUE;
  col = 1;
  glk_window_move_cursor(glkStatusWin, 1, 0);
  sayInstance(where(HERO, TRUE));

  // TODO Add status message1  & 2 as author customizable messages
  if (header->maximumScore > 0)
    sprintf(line, "Score %d(%d)/%d moves", current.score, (int)header->maximumScore, current.tick);
  else
    sprintf(line, "%d moves", current.tick);
  glk_window_move_cursor(glkStatusWin, glkWidth-strlen(line)-1, 0);
  glk_put_string(line);
  needSpace = FALSE;

  col = pcol;
  onStatusLine = FALSE;

  glk_set_window(glkMainWin);
#else
#ifdef HAVE_ANSI
  char line[100];
  int i;
  int pcol = col;

  if (!statusLineOption) return;
  /* ansi_position(1,1); ansi_bold_on(); */
  printf("\x1b[1;1H");
  printf("\x1b[7m");

  onStatusLine = TRUE;
  col = 1;
  sayInstance(where(HERO, FALSE));

  if (header->maximumScore > 0)
    sprintf(line, "Score %d(%d)/%d moves", current.score, header->maximumScore, current.tick);
  else
    sprintf(line, "%ld moves", (long)current.tick);
  for (i=0; i < pageWidth - col - strlen(line); i++) putchar(' ');
  printf(line);
  printf("\x1b[m");
  printf("\x1b[%d;1H", pageLength);

  needSpace = FALSE;
  capitalize = TRUE;

  onStatusLine = FALSE;
  col = pcol;
#endif
#endif
}
예제 #28
0
파일: heglk.c 프로젝트: BPaden/garglk
int hugo_waitforkey(void)
{
	event_t ev;
	char gotchar = 0;

	/* Just in case we try to get key input from a Glk-illegal
	   window that hasn't been created, switch as a failsafe
	   to mainwin
	*/
	if (currentwin==NULL)
		glk_set_window(currentwin = mainwin);

#if defined (NO_KEYPRESS_CURSOR)
	if (currentwin!=mainwin)
	{
		glk_window_move_cursor(currentwin, currentpos/CHARWIDTH, currentline-1);
		hugo_print("*");
		glk_window_move_cursor(currentwin, currentpos/CHARWIDTH, currentline-1);
	}
#endif
	
	glk_request_char_event(currentwin);

        while (!gotchar)
	{
		/* Grab an event */
		glk_select(&ev);
            
		switch (ev.type)
		{
 			case evtype_CharInput:
				/* (Will always be mainwin, but anyway) */
				if (ev.win==currentwin)
				{
					gotchar = true;
				}
				break;
		}
        }

	/* Convert Glk special keycodes: */
	switch (ev.val1)
	{
		case keycode_Left:	ev.val1 = 8;	break;
		case keycode_Right:	ev.val1 = 21;	break;
		case keycode_Up:	ev.val1 = 11;	break;
		case keycode_Down:	ev.val1 = 10;	break;
		case keycode_Return:	ev.val1 = 13;	break;
		case keycode_Escape:	ev.val1 = 27;	break;
	}

#if defined (NO_KEYPRESS_CURSOR)
	if (currentwin!=mainwin)
	{
		glk_window_move_cursor(currentwin, currentpos/CHARWIDTH, currentline-1);
		hugo_print(" ");
		glk_window_move_cursor(currentwin, currentpos/CHARWIDTH, currentline-1);
	}
#endif

	return ev.val1;
}
예제 #29
0
파일: model.c 프로젝트: imclab/Chimara
void glk_main(void)
{
    /* Open the main window. */
    mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
    if (!mainwin) {
        /* It's possible that the main window failed to open. There's
            nothing we can do without it, so exit. */
        return; 
    }
	
    glui32 buffer[1024];
    int i;
    for(i = 0; i < 512; i++) {
    	buffer[i * 2] = i + 33;
		buffer[i * 2 + 1] = 32;
	}
    
/*    frefid_t f = glk_fileref_create_temp(fileusage_BinaryMode, 0);
    if(f) 
    {
		strid_t s = glk_stream_open_file(f, filemode_ReadWrite, 0);*/
		glui32 membuf[512];
		strid_t s = glk_stream_open_memory_uni(membuf, 512, filemode_ReadWrite, 0);
		glk_stream_set_current(s);
		
		glk_put_char_uni('X');
		glk_put_string("Philip en Marijn zijn vet goed.\n");
		glk_put_buffer_uni(buffer, 1024);

		glk_stream_set_position(s, 0, seekmode_Start);
		glk_set_window(mainwin);
		glk_put_char_uni( glk_get_char_stream_uni(s) );
		glk_put_char('\n');
		printf("Line read: %d\n", glk_get_line_stream_uni(s, buffer, 1024) );
		printf("string[5] = %X\n", buffer[5]);
		glk_put_string_uni(buffer);
		int count = glk_get_buffer_stream_uni(s, buffer, 1024);
		printf("Buffer read: %d\n", count);
		glk_put_string("\n---SOME CHARACTERS---\n");
		glk_put_buffer_uni(buffer, count);
		glk_put_string("\n---THE SAME CHARACTERS IN UPPERCASE---\n");
		int newcount = glk_buffer_to_upper_case_uni(buffer, 1024, 1024);
		glk_put_buffer_uni(buffer, newcount);
		
		stream_result_t result;
		glk_stream_close(s, &result);
		
		fprintf(stderr, "Read count: %d\nWrite count: %d\n", result.readcount, result.writecount);
/*		glk_fileref_destroy(f);
	}*/

	glk_set_interrupt_handler(&sayit);

	event_t ev;
	while(1) {
		glk_put_string("\nprompt> ");
		glk_request_line_event_uni(mainwin, buffer, 1024, 0);
		glk_select(&ev);
		switch(ev.type) {
			default:
				printf("Received event:\n");
				printf("Type: %d\n", ev.type);
				printf("Win: %d\n", glk_window_get_rock(ev.win) );
				printf("Var1: %d\n", ev.val1);
				printf("Var2: %d\n", ev.val2);
		}
	}
	
	/* Bye bye */
	glk_exit();
}
예제 #30
0
파일: multiwin.c 프로젝트: chimara/Chimara
/* The glk_main() function is called by the Glk system; it's the main entry
    point for your program. */
void glk_main(void)
{
    char commandbuf1[256]; /* For mainwin1 */
    char commandbuf2[256]; /* For mainwin2 */

    /* Open the main windows. */
    mainwin1 = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
    if (!mainwin1) {
        /* It's possible that the main window failed to open. There's
            nothing we can do without it, so exit. */
        return;
    }

    /* Open a second window: a text grid, above the main window, five
        lines high. It is possible that this will fail also, but we accept
        that. */
    statuswin = glk_window_open(mainwin1,
        winmethod_Above | winmethod_Fixed,
        5, wintype_TextGrid, 0);

    /* And a third window, a second story window below the main one. */
    mainwin2 = glk_window_open(mainwin1,
        winmethod_Below | winmethod_Proportional,
        50, wintype_TextBuffer, 0);

    /* We're going to be switching from one window to another all the
        time. So we'll be setting the output stream on a case-by-case
        basis. Every function that prints must set the output stream
        first. (Contrast model.c, where the output stream is always the
        main window, and every function that changes that must set it
        back afterwards.) */

    glk_set_window(mainwin1);
    glk_put_string("Multiwin\nAn Interactive Sample Glk Program\n");
    glk_put_string("By Andrew Plotkin.\nRelease 3.\n");
    glk_put_string("Type \"help\" for a list of commands.\n");

    glk_set_window(mainwin2);
    glk_put_string("Note that the upper left-hand window accepts character");
    glk_put_string(" input. Hit 'h' to split the window horizontally, 'v' to");
    glk_put_string(" split the window vertically, 'c' to close a window,");
    glk_put_string(" and any other key (including special keys) to display");
    glk_put_string(" key codes. All new windows accept these same keys as");
    glk_put_string(" well.\n\n");
    glk_put_string("This bottom window accepts normal line input.\n");

    if (statuswin) {
        /* For fun, let's open a fourth window now, splitting the status
            window. */
        winid_t keywin;
        keywin = glk_window_open(statuswin,
            winmethod_Left | winmethod_Proportional,
            66, wintype_TextGrid, KEYWINROCK);
        if (keywin) {
            glk_request_char_event(keywin);
        }
    }

    /* Draw the key window now, since we don't draw it every input (as
        we do the status window. */
    draw_keywins();

    inputpending1 = FALSE;
    inputpending2 = FALSE;
    already1 = 0;
    already2 = 0;

    while (1) {
        char *cx, *cmd;
        int doneloop, len;
        winid_t whichwin = NULL;
        event_t ev;

        draw_statuswin();
        /* We're not redrawing the key windows every command. */

        /* Either main window, or both, could already have line input
            pending. If so, leave that window alone. If there is no
            input pending on a window, set a line input request, but
            keep around any characters that were in the buffer already. */

        if (mainwin1 && !inputpending1) {
            glk_set_window(mainwin1);
            glk_put_string("\n>");
            /* We request up to 255 characters. The buffer can hold 256,
                but we are going to stick a null character at the end, so
                we have to leave room for that. Note that the Glk library
                does *not* put on that null character. */
            glk_request_line_event(mainwin1, commandbuf1, 255, already1);
            inputpending1 = TRUE;
        }

        if (mainwin2 && !inputpending2) {
            glk_set_window(mainwin2);
            glk_put_string("\n>");
            /* See above. */
            glk_request_line_event(mainwin2, commandbuf2, 255, already2);
            inputpending2 = TRUE;
        }

        doneloop = FALSE;
        while (!doneloop) {

            /* Grab an event. */
            glk_select(&ev);

            switch (ev.type) {

                case evtype_LineInput:
                    /* If the event comes from one main window or the other,
                        we mark that window as no longer having line input
                        pending. We also set commandbuf to point to the
                        appropriate buffer. Then we leave the event loop. */
                    if (mainwin1 && ev.win == mainwin1) {
                        whichwin = mainwin1;
                        inputpending1 = FALSE;
                        cmd = commandbuf1;
                        doneloop = TRUE;
                    }
                    else if (mainwin2 && ev.win == mainwin2) {
                        whichwin = mainwin2;
                        inputpending2 = FALSE;
                        cmd = commandbuf2;
                        doneloop = TRUE;
                    }
                    break;

                case evtype_CharInput:
                    /* It's a key event, from one of the keywins. We
                        call a subroutine rather than exiting the
                        event loop (although I could have done it
                        that way too.) */
                    perform_key(ev.win, ev.val1);
                    break;

                case evtype_Timer:
                    /* It's a timer event. This does exit from the event
                        loop, since we're going to interrupt input in
                        mainwin1 and then re-print the prompt. */
                    whichwin = NULL;
                    cmd = NULL;
                    doneloop = TRUE;
                    break;

                case evtype_Arrange:
                    /* Windows have changed size, so we have to redraw the
                        status window and key window. But we stay in the
                        event loop. */
                    draw_statuswin();
                    draw_keywins();
                    break;
            }
        }

        if (cmd == NULL) {
            /* It was a timer event. */
            perform_timer();
            continue;
        }

        /* It was a line input event. cmd now points at a line of input
            from one of the main windows. */

        /* The line we have received in commandbuf is not null-terminated.
            We handle that first. */
        len = ev.val1; /* Will be between 0 and 255, inclusive. */
        cmd[len] = '\0';

        /* Then squash to lower-case. */
        for (cx = cmd; *cx; cx++) {
            *cx = glk_char_to_lower(*cx);
        }

        /* Then trim whitespace before and after. */

        for (cx = cmd; *cx == ' '; cx++, len--) { };

        cmd = cx;

        for (cx = cmd+len-1; cx >= cmd && *cx == ' '; cx--) { };
        *(cx+1) = '\0';

        /* cmd now points to a nice null-terminated string. We'll do the
            simplest possible parsing. */
        if (str_eq(cmd, "")) {
            glk_set_window(whichwin);
            glk_put_string("Excuse me?\n");
        }
        else if (str_eq(cmd, "help")) {
            verb_help(whichwin);
        }
        else if (str_eq(cmd, "yada")) {
            verb_yada(whichwin);
        }
        else if (str_eq(cmd, "both")) {
            verb_both(whichwin);
        }
        else if (str_eq(cmd, "clear")) {
            verb_clear(whichwin);
        }
        else if (str_eq(cmd, "page")) {
            verb_page(whichwin);
        }
        else if (str_eq(cmd, "pageboth")) {
            verb_pageboth(whichwin);
        }
        else if (str_eq(cmd, "timer")) {
            verb_timer(whichwin);
        }
        else if (str_eq(cmd, "untimer")) {
            verb_untimer(whichwin);
        }
        else if (str_eq(cmd, "chars")) {
            verb_chars(whichwin);
        }
        else if (str_eq(cmd, "jump")) {
            verb_jump(whichwin);
        }
        else if (str_eq(cmd, "quit")) {
            verb_quit(whichwin);
        }
        else {
            glk_set_window(whichwin);
            glk_put_string("I don't understand the command \"");
            glk_put_string(cmd);
            glk_put_string("\".\n");
        }

        if (whichwin == mainwin1)
            already1 = 0;
        else if (whichwin == mainwin2)
            already2 = 0;
    }
}