Top |
#define | gestalt_Version |
#define | gestalt_Unicode |
#define | GLK_MODULE_UNICODE |
#define | gestalt_UnicodeNorm |
#define | GLK_MODULE_UNICODE_NORM |
#define | gestalt_CharOutput |
#define | gestalt_CharOutput_CannotPrint |
#define | gestalt_CharOutput_ApproxPrint |
#define | gestalt_CharOutput_ExactPrint |
#define | gestalt_LineInput |
#define | gestalt_LineInputEcho |
#define | GLK_MODULE_LINE_ECHO |
#define | gestalt_LineTerminators |
#define | GLK_MODULE_LINE_TERMINATORS |
#define | gestalt_LineTerminatorKey |
#define | gestalt_CharInput |
#define | gestalt_MouseInput |
#define | gestalt_Timer |
#define | gestalt_Graphics |
#define | gestalt_DrawImage |
#define | gestalt_Sound2 |
#define | gestalt_Sound |
#define | gestalt_SoundVolume |
#define | gestalt_SoundNotify |
#define | gestalt_Hyperlinks |
#define | gestalt_HyperlinkInput |
#define | gestalt_SoundMusic |
#define | gestalt_GraphicsTransparency |
#define | gestalt_DateTime |
#define | gestalt_ResourceStream |
#define | GLK_MODULE_RESOURCE_STREAM |
The “gestalt” mechanism (cheerfully stolen from the Mac OS) is a system by which the Glk API can be upgraded without making your life impossible. New capabilities (graphics, sound, or so on) can be added without changing the basic specification. The system also allows for “optional” capabilities — those which not all Glk library implementations will support — and allows you to check for their presence without trying to infer them from a version number.
The basic idea is that you can request information about the capabilities of the API, by calling the gestalt functions.
glui32 glk_gestalt_ext (glui32 sel
,glui32 val
,glui32 *arr
,glui32 arrlen
);
Calls the gestalt system to request information about the capabilities of the
API. The selector sel
tells which capability you are requesting information
about; the other three arguments are additional information, which may or may
not be meaningful. The arr
and arrlen
arguments of glk_gestalt_ext()
are
always optional; you may always pass NULL
and 0, if you do not want whatever
information they represent. glk_gestalt()
is simply a shortcut for this;
glk_gestalt(x, y)
is exactly the same as glk_gestalt_ext(x, y, NULL, 0)
.
The critical point is that if the Glk library has never heard of the selector
sel
, it will return 0. It is always safe to call
glk_gestalt(x, y)
(or glk_gestalt_ext(x, y, NULL, 0)
).
Even if you are using an old library, which was compiled before
the given capability was imagined, you can test for the capability by calling
glk_gestalt()
; the library will correctly indicate that it does not support
it, by returning 0.
(It is also safe to call glk_gestalt_ext(x, y, z, zlen)
for an unknown
selector x
, where z
is not NULL
, as long as z
points at an array of at
least zlen
elements.
The selector will be careful not to write beyond that point in the array, if
it writes to the array at all.)
(If a selector does not use the second argument, you should always pass 0; do not assume that the second argument is simply ignored. This is because the selector may be extended in the future. You will continue to get the current behavior if you pass 0 as the second argument, but other values may produce other behavior.)
glui32 glk_gestalt (glui32 sel
,glui32 val
);
Calls the gestalt system to request information about selector sel
, without
passing an array to store extra information in (see glk_gestalt_ext()
).
#define gestalt_Version (0)
For an example of the gestalt mechanism, consider the selector
gestalt_Version
. If you do
1 2 |
glui32 res; res = glk_gestalt(gestalt_Version, 0); |
res
will be set to a 32-bit number which encodes the version of the Glk
spec which the library implements.
The upper 16 bits stores the major version number; the next 8 bits stores the
minor version number; the low 8 bits stores an even more minor version
number, if any.
So the version number 78.2.11 would be encoded as 0x004E020B.
The current Glk specification version is 0.7.4, so this selector will return 0x00000704.
1 2 |
glui32 res; res = glk_gestalt_ext(gestalt_Version, 0, NULL, 0); |
does exactly the same thing. Note that, in either case, the second argument is not used; so you should always pass 0 to avoid future surprises.
#define gestalt_Unicode (15)
The basic text functions will be available in every Glk library. The Unicode
functions may or may not be available. Before calling them, you should use
the gestalt_Unicode
and gestalt_UnicodeNorm
gestalt selectors.
1 2 |
glui32 res; res = glk_gestalt(gestalt_Unicode, 0); |
This returns 1 if the core Unicode functions are available. If it returns 0,
you should not try to call them. They may print nothing, print gibberish, or
cause a run-time error. The Unicode functions include
glk_buffer_to_lower_case_uni()
, glk_buffer_to_upper_case_uni()
,
glk_buffer_to_title_case_uni()
, glk_put_char_uni()
, glk_put_string_uni()
,
glk_put_buffer_uni()
, glk_put_char_stream_uni()
, glk_put_string_stream_uni()
,
glk_put_buffer_stream_uni()
, glk_get_char_stream_uni()
,
glk_get_buffer_stream_uni()
, glk_get_line_stream_uni()
,
glk_request_char_event_uni()
, glk_request_line_event_uni()
,
glk_stream_open_file_uni()
, glk_stream_open_memory_uni()
.
If you are writing a C program, there is an additional complication. A
library which does not support Unicode may not implement the Unicode
functions at all. Even if you put gestalt tests around your Unicode calls,
you may get link-time errors.
If the glk.h
file is so old that it does not declare the Unicode functions
and constants, you may even get compile-time errors.
To avoid this, you can perform a preprocessor test for the existence of
GLK_MODULE_UNICODE
.
#define GLK_MODULE_UNICODE
If this preprocessor symbol is defined, so are the core Unicode functions and
constants (see gestalt_Unicode
). If not, not.
#define gestalt_UnicodeNorm (16)
1 2 |
glui32 res; res = glk_gestalt(gestalt_UnicodeNorm, 0); |
This code returns 1 if the Unicode normalization functions are available. If
it returns 0, you should not try to call them. The Unicode normalization
functions include glk_buffer_canon_decompose_uni()
and
glk_buffer_canon_normalize_uni()
.
The equivalent preprocessor test for these functions is
GLK_MODULE_UNICODE_NORM
.
#define GLK_MODULE_UNICODE_NORM
If this preprocessor symbol is defined, so are the Unicode normalization
functions (see gestalt_UnicodeNorm
). If not, not.
#define gestalt_CharOutput (3)
If you set ch
to a character code (Latin-1 or higher), and call
1 2 |
glui32 res, len; res = glk_gestalt_ext(gestalt_CharOutput, ch, &len, 1); |
then res
will be one of gestalt_CharOutput_CannotPrint
,
gestalt_CharOutput_ExactPrint
, or gestalt_CharOutput_ApproxPrint
(see
below.)
In all cases, len
(the glui32 value pointed at by the third argument) will
be the number of actual glyphs which will be used to represent the character.
In the case of gestalt_CharOutput_ExactPrint
, this will always be 1; for
gestalt_CharOutput_CannotPrint
, it may be 0 (nothing printed) or higher; for
gestalt_CharOutput_ApproxPrint
, it may be 1 or higher.
This information may be useful when printing text in a fixed-width font.
As described in Other API
Conventions, you may skip this information by passing NULL
as the
third argument in glk_gestalt_ext()
, or by calling glk_gestalt()
instead.
This selector will always return gestalt_CharOutput_CannotPrint
if ch
is
an unprintable eight-bit character (0 to 9, 11 to 31, 127 to 159.)
Make sure you do not get confused by signed byte values. If you set a
“signed char” variable ch
to 0xFE, the
small-thorn character (þ), it will wind up as -2.
(The same is true of a “char” variable, if your compiler
treats “char” as signed!)
If you then call
1 |
res = glk_gestalt(gestalt_CharOutput, ch); |
then (by the definition of C/C++) ch
will be sign-extended to
0xFFFFFFFE, which is not a legitimate character, even in Unicode. You
should write
1 |
res = glk_gestalt(gestalt_CharOutput, (unsigned char)ch); |
instead.
Unicode includes the concept of non-spacing or combining characters, which
do not represent glyphs; and double-width characters, whose glyphs take up
two spaces in a fixed-width font. Future versions of this spec may
recognize these concepts by returning a len
of 0 or 2 when
gestalt_CharOutput_ExactPrint
is used. For the moment, we are adhering to
a policy of “simple stuff first”.
#define gestalt_CharOutput_CannotPrint (0)
When the gestalt_CharOutput
selector returns this for a character, the
character cannot be meaningfully printed. If you try, the player may see
nothing, or may see a placeholder.
#define gestalt_CharOutput_ApproxPrint (1)
When the gestalt_CharOutput
selector returns this for a character, the
library will print some approximation of the character. It will be more or
less right, but it may not be precise, and it may not be distinguishable from
other, similar characters.
(Examples: “ae
” for the one-character “æ” ligature, “e
” for
“è”, “|
” for a broken vertical bar (¦).)
#define gestalt_CharOutput_ExactPrint (2)
When the gestalt_CharOutput
selector returns this for a character, the
character will be printed exactly as defined.
#define gestalt_LineInput (2)
If you set ch
to a character code, and call
1 2 |
glui32 res; res = glk_gestalt(gestalt_LineInput, ch); |
then res
will be TRUE
(1) if that character can be typed by the player in
line input, and FALSE
(0) if not.
Note that if ch
is a nonprintable Latin-1 character (0 to 31, 127 to 159),
then this is guaranteed to return FALSE
.
See Line Input.
#define gestalt_LineInputEcho (17)
1 |
res = glk_gestalt(gestalt_LineInputEcho, 0); |
This returns 1 if glk_set_echo_line_event()
is supported, and 0 if it is not.
Remember that if it is not supported, the behavior is always the default, which is line echoing enabled.
#define GLK_MODULE_LINE_ECHO
If this preprocessor symbol is defined, so is glk_set_echo_line_event()
. If
not, not.
#define gestalt_LineTerminators (18)
1 |
res = glk_gestalt(gestalt_LineTerminators, 0); |
This returns 1 if glk_set_terminators_line_event()
is supported, and 0 if it
is not.
#define GLK_MODULE_LINE_TERMINATORS
If this preprocessor symbol is defined, so is
glk_set_terminators_line_event()
. If not, not.
#define gestalt_LineTerminatorKey (19)
1 |
res = glk_gestalt(gestalt_LineTerminatorKey, ch); |
This returns 1 if the keycode ch
can be passed to
glk_set_terminators_line_event()
. If it returns 0, that keycode will be
ignored as a line terminator. Printable characters and keycode_Return
will
always return 0.
#define gestalt_CharInput (1)
If you set ch
to a character code, or a special code (from 0xFFFFFFFF
down), and call
1 2 |
glui32 res; res = glk_gestalt(gestalt_CharInput, ch); |
then res
will be TRUE
(1) if that character can be typed by the player in
character input, and FALSE
(0) if not.
See Character Input.
#define gestalt_MouseInput (4)
You can test whether mouse input is supported with the gestalt_MouseInput
selector.
1 |
res = glk_gestalt(gestalt_MouseInput, windowtype); |
This will return TRUE
(1) if windows of the given type support mouse input.
If this returns FALSE
(0), it is still legal to call
glk_request_mouse_event()
, but it will have no effect, and you will never get
mouse events.
#define gestalt_Timer (5)
You can test whether the library supports timer events:
1 |
res = glk_gestalt(gestalt_Timer, 0); |
This returns TRUE
(1) if timer events are supported, and FALSE
(0) if they
are not.
#define gestalt_Graphics (6)
Before calling Glk graphics functions, you should use the following gestalt selector:
1 2 |
glui32 res; res = glk_gestalt(gestalt_Graphics, 0); |
This returns 1 if the overall suite of graphics functions is available. This
includes glk_image_draw()
, glk_image_draw_scaled()
, glk_image_get_info()
,
glk_window_erase_rect()
, glk_window_fill_rect()
,
glk_window_set_background_color()
, and glk_window_flow_break()
. It also
includes the capability to create graphics windows.
If this selector returns 0, you should not try to call these functions. They
may have no effect, or they may cause a run-time error. If you try to create
a graphics window, you will get NULL
.
#define gestalt_DrawImage (7)
This selector returns 1 if images can be drawn in windows of the given type.
If it returns 0, glk_image_draw()
will fail and return FALSE
(0). You should
test wintype_Graphics
and wintype_TextBuffer
separately, since libraries
may implement both, neither, or only one.
#define gestalt_Sound2 (21)
You can test whether the library supports sound:
1 2 |
glui32 res; res = glk_gestalt(gestalt_Sound2, 0); |
This returns 1 if the overall suite of sound functions is available. This
includes all the functions defined in this chapter.
It also includes the capabilities described below under gestalt_SoundMusic
,
gestalt_SoundVolume
, and gestalt_SoundNotify
.
#define gestalt_Sound (8)
1 2 |
glui32 res; res = glk_gestalt(gestalt_Sound, 0); |
This returns 1 if the overall suite of sound functions is available. This
includes glk_schannel_create()
, glk_schannel_destroy()
,
glk_schannel_iterate()
, glk_schannel_get_rock()
, glk_schannel_play()
,
glk_schannel_play_ext()
, glk_schannel_stop()
, glk_schannel_set_volume()
, and
glk_sound_load_hint()
.
If this selector returns 0, you should not try to call these functions. They may have no effect, or they may cause a run-time error.
This selector is guaranteed to return 1 if gestalt_Sound2
does.
#define gestalt_SoundVolume (9)
You can test whether the library supports setting the volume of sound channels:
1 |
res = glk_gestalt(gestalt_SoundVolume, 0); |
This selector returns 1 if the glk_schannel_set_volume()
function works. If
it returns zero, glk_schannel_set_volume()
has no effect.
This selector is guaranteed to return 1 if gestalt_Sound2
does.
#define gestalt_SoundNotify (10)
You can test whether the library supports sound notification events:
1 |
res = glk_gestalt(gestalt_SoundNotify, 0); |
This selector returns 1 if the library supports sound notification events. If it returns zero, you will never get such events.
This selector is guaranteed to return 1 if gestalt_Sound2
does.
#define gestalt_Hyperlinks (11)
You can test whether the library supports hyperlinks:
1 2 |
glui32 res; res = glk_gestalt(gestalt_Hyperlinks, 0); |
This returns 1 if the overall suite of hyperlinks functions is available.
This includes glk_set_hyperlink()
, glk_set_hyperlink_stream()
,
glk_request_hyperlink_event()
, glk_cancel_hyperlink_event()
.
If this selector returns 0, you should not try to call these functions. They may have no effect, or they may cause a run-time error.
#define gestalt_HyperlinkInput (12)
You can test whether hyperlinks are supported with the
gestalt_HyperlinkInput
selector:
1 |
res = glk_gestalt(gestalt_HyperlinkInput, windowtype); |
This will return TRUE
(1) if windows of the given type support hyperlinks.
If this returns FALSE
(0), it is still legal to call glk_set_hyperlink()
and
glk_request_hyperlink_event()
, but they will have no effect, and you will
never get hyperlink events.
#define gestalt_SoundMusic (13)
You can test whether music resources are supported:
1 |
res = glk_gestalt(gestalt_SoundMusic, 0); |
This returns 1 if the library is capable of playing music sound resources. If it returns 0, only sampled sounds can be played.
“Music sound resources” means MOD songs — the only music format that Blorb currently supports. The presence of this selector is, of course, an ugly hack. It is a concession to the current state of the Glk libraries, some of which can handle AIFF but not MOD sounds.
This selector is guaranteed to return 1 if gestalt_Sound2
does.
#define gestalt_GraphicsTransparency (14)
This returns 1 if images with alpha channels can actually be drawn with the appropriate degree of transparency. If it returns 0, the alpha channel is ignored; fully transparent areas will be drawn in an implementation-defined color.
The JPEG format does not support transparency or alpha channels; the PNG format does.
#define gestalt_DateTime (20)
1 |
res = glk_gestalt(gestalt_DateTime, 0); |
This returns 1 if the overall suite of system clock functions, as described in this chapter, is available.
If this selector returns 0, you should not try to call these functions. They may have no effect, or they may cause a run-time error.
Glk timer events are covered by a different selector. See gestalt_Timer
.
#define gestalt_ResourceStream (22)
1 |
res = glk_gestalt(gestalt_ResourceStream, 0); |
This returns 1 if the glk_stream_open_resource()
and
glk_stream_open_resource_uni()
functions are available. If it returns 0, you
should not call them.
#define GLK_MODULE_RESOURCE_STREAM
If this preprocessor symbol is defined, so are glk_stream_open_resource()
and
glk_stream_open_resource_uni()
.
If not, not.