-
Notifications
You must be signed in to change notification settings - Fork 3
Glk Multi Display Support
The Glk API assumes that the application is managing exactly one Glk game display at a time. This fits poorly with the modern desktop GUI, in which a game interpreter might want to display several windows with a different game in each.
Interpreter applications typically work around this by launching sub-processes, each of which manages one game in one window. This is adequate, but we would like a better solution.
This is a proposal for a Glk interface update which supports multiple displays within a single application, without breaking backwards compatibility.
(This deals only with the C header glk.h
and C library implementations. The Javascript [GlkOte.js][] implementation already supports multiple Glk displays in separate browser windows -- each browser window is a separate Javascript context, so we get that for free. It could be extended to support multiple Glk displays in a single browser window, but this is not very important.)
The glk.h
header should serve both old (single-display) libraries and new (multi-display) libraries. Therefore, we need some preprocessor abuse!
Function definitions will now look like:
/* extern void glk_put_char(unsigned char ch); */
GLK_DECLARE_FN1(void, put_char, unsigned char ch);
(GLK_DECLARE_FN1
means "declare Glk function with one argument". GLK_DECLARE_FN0
to GLK_DECLARE_FN6
will be available.)
If the symbol GLK_LIBRARY_MULTI
is not defined, this will compile to the old-style declaration, as shown in the comment. If GLK_LIBRARY_MULTI
is defined, it compiles to two declarations:
extern void glk_put_char(unsigned char ch);
extern void glkmd_put_char(glk_context *gcontext, unsigned char ch);
The library will maintain a global variable:
extern glk_context *glk_context_singleton;
A call to the old-style function will invoke the new-style function using this context. That is, glk_put_char(ch)
will be implemented as a call to glkmd_put_char(glk_context_singleton, ch)
. This allows old-style applications to compile with minimal change.
(These boilerplate old-style functions will live in a new file gi_multi.c
, which will be distributed along with gi_dispa.c
and gi_blorb.c
.)
Note that some functions, such as glk_char_to_lower()
, don't interact with the display state. For consistency, these will also get glkmd_XXX()
implementations, but they can ignore the context argument.
When GLK_LIBRARY_MULTI
is set, gidispatch_function_t
will contain pointers to both the glk_XXX()
and glkmd_XXX()
versions of each function. (This will entail more preprocessor abuse.)
The gidispatch_call()
entry point will remain, calling glk_XXX()
functions. Under GLK_LIBRARY_MULTI
, there will also be gidispatch_call_multi()
, with an additional context argument, which calls the glkmd_XXX()
functions. (I haven't decided what kind of evil I will use to accomplish this, but nobody else ever has to read gi_dispa.c
, so don't sweat it.)
An old-style library can import the new glk.h
header file, and not define GLK_LIBRARY_MULTI
. It will build the way it's always built, no changes needed.
To fully support multi-display Glk, a library will have to be refactored so that all Glk display state is contained in a glk_context
struct. (The library must define this struct type.) It will have to rename all its glk_XXX()
functions to glkmd_XXX()
, adding a glk_context *
as the first argument.
(CheapGlk and GlkTerm will remain as old-style, single-display libraries. RemGlk will become a multi-display library, although this is more of a proof of concept than a useful feature. A RemGlk interpreter can be launched with multiple games; input and output for each game will be tagged with a distinct session ID.)
XXX startup code XXX how to update an application