From 062bbb9e7322c8e3f5162f86fc2f93bfc587b830 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Sun, 29 Mar 2009 01:13:07 +0000 Subject: [PATCH] Got Gtk-Doc working. Now all the fancy /** comments before the functions actually mean something. To use gtk-doc, invoke configure like this: ./configure --enable-gtk-doc When you do this, configure will generate makefiles that rebuild the docs whenever the source is changed. Calling configure without that option generates makefiles that don't rebuild the docs. Building the docs takes some time so you probably want to disable it unless you're actively working on the docs. The documentation is output as HTML, which you can browse by pointing your browser to file:///path/to/chimara/docs/reference/html/index.html The really cool thing is that the docs are also built as a devhelp module, so when you make install, the devhelp module is installed and automatically shows up in Devhelp. The documentation consists of two sections: one is the API of our widget, the other is the Glk API specification which we have been working from. I have obtained permission from Andrew Plotkin to include and alter this spec. I have changed the order of things around a little bit so it makes more sense as a Gtk-Doc reference book. The API spec only contains the parts that we have implemented so far. I figure if we update the documentation for the Glk API functions as we implement them, then we'll be able to see at a glance how far we've gotten. One more change left to describe: the new file src/doc.c consists of only comments. These comments contain two things. One is the introductory descriptions of each Gtk-Doc section. I put these in here because they really bloated the regular C files. The other is the Gtk-Doc comments for constants and structures that are defined in glk.h. I put these in here because the spec says glk.h is supposed to be the same on every platform except for the typedefs of the 32-bit types. git-svn-id: http://lassie.dyndns-server.com/svn/gargoyle-gtk@33 ddfedd41-794f-dd11-ae45-00112f111e67 --- Makefile.am | 4 +- autogen.sh | 2 +- configure.ac | 3 + docs/.svnignore | 3 + docs/Makefile.am | 1 + docs/reference/.svnignore | 18 + docs/reference/Makefile.am | 101 ++ docs/reference/chimara-docs.sgml | 142 ++ docs/reference/chimara-sections.txt | 466 ++++++ docs/reference/chimara.types | 1 + docs/reference/glk-api-conventions.sgml | 36 + docs/reference/glk-character-encoding.sgml | 47 + docs/reference/glk-display-style.sgml | 33 + docs/reference/glk-front-matter.sgml | 25 + docs/reference/glk-introduction.sgml | 106 ++ docs/reference/glk-line-input.sgml | 33 + docs/reference/glk-main-function.sgml | 69 + docs/reference/glk-other-events.sgml | 46 + docs/reference/glk-output.sgml | 39 + docs/reference/glk-window-arrangement.sgml | 73 + docs/reference/glk-windows.sgml | 94 ++ docs/reference/version.xml.in | 1 + po/.ignore | 23 - src/Makefile.am | 4 +- src/abort.c | 11 +- src/case.c | 77 +- src/chimara-glk-private.h | 2 +- src/chimara-glk.c | 74 +- src/chimara-glk.h | 27 +- src/doc.c | 1737 ++++++++++++++++++++ src/event.c | 1 + src/fileref.c | 152 +- src/fileref.h | 7 + src/gestalt.c | 43 +- src/glk.c | 76 +- src/input.c | 7 +- src/stream.c | 80 +- src/stream.h | 7 + src/strio.c | 113 +- src/style.c | 14 +- src/window.c | 330 +++- src/window.h | 7 + 42 files changed, 3804 insertions(+), 331 deletions(-) create mode 100644 docs/.svnignore create mode 100644 docs/Makefile.am create mode 100644 docs/reference/.svnignore create mode 100644 docs/reference/Makefile.am create mode 100644 docs/reference/chimara-docs.sgml create mode 100644 docs/reference/chimara-sections.txt create mode 100644 docs/reference/chimara.types create mode 100644 docs/reference/glk-api-conventions.sgml create mode 100644 docs/reference/glk-character-encoding.sgml create mode 100644 docs/reference/glk-display-style.sgml create mode 100644 docs/reference/glk-front-matter.sgml create mode 100644 docs/reference/glk-introduction.sgml create mode 100644 docs/reference/glk-line-input.sgml create mode 100644 docs/reference/glk-main-function.sgml create mode 100644 docs/reference/glk-other-events.sgml create mode 100644 docs/reference/glk-output.sgml create mode 100644 docs/reference/glk-window-arrangement.sgml create mode 100644 docs/reference/glk-windows.sgml create mode 100644 docs/reference/version.xml.in delete mode 100755 po/.ignore create mode 100644 src/doc.c diff --git a/Makefile.am b/Makefile.am index d4c356b..4a87cfd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in ## Created by Anjuta -SUBDIRS = src po +SUBDIRS = src po docs chimaradocdir = ${prefix}/doc/chimara chimaradoc_DATA = \ @@ -24,3 +24,5 @@ dist-hook: done DISTCLEANFILES = intltool-extract intltool-merge intltool-update + +DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc diff --git a/autogen.sh b/autogen.sh index 02e7c89..49281e5 100755 --- a/autogen.sh +++ b/autogen.sh @@ -4,7 +4,7 @@ ### GTK-DOC ######################################################### # Run before autotools echo "Setting up Gtk-Doc" -gtkdocize || exit 1 +gtkdocize --flavour no-tmpl || exit 1 ### AUTOTOOLS ####################################################### # Runs autoconf, autoheader, aclocal, automake, autopoint, libtoolize diff --git a/configure.ac b/configure.ac index 855619a..f084467 100644 --- a/configure.ac +++ b/configure.ac @@ -61,6 +61,9 @@ AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([ Makefile src/Makefile +docs/Makefile +docs/reference/Makefile +docs/reference/version.xml po/Makefile.in ]) # Do it diff --git a/docs/.svnignore b/docs/.svnignore new file mode 100644 index 0000000..22a4e72 --- /dev/null +++ b/docs/.svnignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in + diff --git a/docs/Makefile.am b/docs/Makefile.am new file mode 100644 index 0000000..b68c774 --- /dev/null +++ b/docs/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=reference diff --git a/docs/reference/.svnignore b/docs/reference/.svnignore new file mode 100644 index 0000000..7da551f --- /dev/null +++ b/docs/reference/.svnignore @@ -0,0 +1,18 @@ +.libs +Makefile +Makefile.in +html +xml +*.stamp +version.xml +chimara.args +chimara.hierarchy +chimara.interfaces +chimara.signals +chimara.prerequisites +chimara-decl.txt +chimara-decl-list.txt +chimara-overrides.txt +chimara-undeclared.txt +chimara-undocumented.txt + diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am new file mode 100644 index 0000000..4e05bb9 --- /dev/null +++ b/docs/reference/Makefile.am @@ -0,0 +1,101 @@ +### Makefile.am for Gtk-Doc directory ######################################### +# Adapted from examples/Makefile.am in Gtk-Doc distribution + +# We require automake 1.6 at least. +AUTOMAKE_OPTIONS = 1.6 + +# The name of the module, e.g. 'glib'. +DOC_MODULE = chimara + +# Uncomment for versioned docs and specify the version of the module, e.g. '2'. +# DOC_MODULE_VERSION = 2 + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.sgml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +DOC_SOURCE_DIR = ../../src + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS = + +# Extra options to supply to gtkdoc-scan. +# DO NOT use --rebuild-types, because it will think glk_window_get_type() +# is a GObject type. That makes it segfault. +SCAN_OPTIONS = + +# Extra options to supply to gtkdoc-mkdb. +MKDB_OPTIONS = --sgml-mode --output-format=xml + +# Extra options to supply to gtkdoc-mktmpl +MKTMPL_OPTIONS = + +# Extra options to supply to gtkdoc-mkhtml +MKHTML_OPTIONS = + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +FIXXREF_OPTIONS = + +# Used for dependencies. The docs will be rebuilt if any of these change. +HFILE_GLOB = $(top_srcdir)/src/*.h +CFILE_GLOB = $(top_srcdir)/src/*.c + +# Extra headers to include when scanning, which are not under DOC_SOURCE_DIR +EXTRA_HFILES = + +# Header files to ignore when scanning. Use base file name, no paths +IGNORE_HFILES = chimara-glk-private.h \ + abort.h charset.h event.h input.h stream.h window.h \ + callbacks.h error.h + +# Images to copy into HTML directory. +HTML_IMAGES = + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +content_files = version.xml \ + glk-front-matter.sgml \ + glk-introduction.sgml \ + glk-main-function.sgml \ + glk-api-conventions.sgml \ + glk-character-encoding.sgml \ + glk-output.sgml \ + glk-line-input.sgml \ + glk-windows.sgml \ + glk-window-arrangement.sgml \ + glk-display-style.sgml \ + glk-other-events.sgml + +# SGML files where gtk-doc abbreviations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +expand_content_files = \ + glk-main-function.sgml \ + glk-api-conventions.sgml \ + glk-output.sgml \ + glk-line-input.sgml \ + glk-window-arrangement.sgml \ + glk-display-style.sgml \ + glk-other-events.sgml + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +GTKDOC_CFLAGS = -I$(top_srcdir) $(CHIMARA_CFLAGS) +GTKDOC_LIBS = $(top_builddir)/src/libchimara.la + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/gtk-doc.make + +# Other files to distribute +EXTRA_DIST += version.xml.in + +# Files not to distribute +# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types +# for --rebuild-sections in $(SCAN_OPTIONS), e.g. $(DOC_MODULE)-sections.txt +# DISTCLEANFILES += + +# Comment this out if you want your docs-status tested during 'make check' +# TESTS_ENVIRONMENT = cd $(srcsrc) +# TESTS = $(GTKDOC_CHECK) + diff --git a/docs/reference/chimara-docs.sgml b/docs/reference/chimara-docs.sgml new file mode 100644 index 0000000..d003476 --- /dev/null +++ b/docs/reference/chimara-docs.sgml @@ -0,0 +1,142 @@ + + +]> + + + Chimara Reference Manual + + for Chimara &version;. The latest version of this documentation can be + found on-line at http://[SERVER]/chimara/. + + + + + Chimara API Reference + + + + + Glk API Specification, version 0.7.0 + + + + + + + + Overall Structure + + + + + + + + + + + + + + Character Encoding + + + + + + + + + + Windows + + + + + + + + + + + + + Events + + + + + + + + + + Streams + + + + + + + + + + + + + File References + + + + + + + + + + + + + + + + + diff --git a/docs/reference/chimara-sections.txt b/docs/reference/chimara-sections.txt new file mode 100644 index 0000000..79094a6 --- /dev/null +++ b/docs/reference/chimara-sections.txt @@ -0,0 +1,466 @@ +
+chimara-glk +ChimaraGlk +ChimaraGlk +chimara_glk_new +chimara_glk_set_interactive +chimara_glk_get_interactive +chimara_glk_set_protect +chimara_glk_get_protect +chimara_glk_run +chimara_glk_stop +chimara_glk_wait + +ChimaraGlkClass +CHIMARA_GLK +CHIMARA_IS_GLK +CHIMARA_TYPE_GLK +chimara_glk_get_type +CHIMARA_GLK_CLASS +CHIMARA_IS_GLK_CLASS +CHIMARA_GLK_GET_CLASS +
+ +
+glk-exiting +Exiting Your Program +glk_exit + +glk_main +
+ +
+glk-interrupt +The Interrupt Handler +glk_set_interrupt_handler +
+ +
+glk-tick +The Tick Thing +glk_tick +
+ +
+glk-types +Basic Types +glui32 +glsi32 +
+ +
+glk-opaque-objects +Opaque Objects +winid_t +strid_t +frefid_t +schanid_t +
+ +
+glk-gestalt +The Gestalt System +glk_gestalt_ext +glk_gestalt + +gestalt_Version + +gestalt_Unicode +GLK_MODULE_UNICODE + +gestalt_CharOutput +gestalt_CharOutput_CannotPrint +gestalt_CharOutput_ApproxPrint +gestalt_CharOutput_ExactPrint + +gestalt_LineInput + +gestalt_CharInput + +gestalt_MouseInput +gestalt_Timer +gestalt_Graphics +gestalt_DrawImage +gestalt_Sound +gestalt_SoundVolume +gestalt_SoundNotify +gestalt_Hyperlinks +gestalt_HyperlinkInput +gestalt_SoundMusic +gestalt_GraphicsTransparency +
+ +
+glk-character-input +Character Input +keycode_Unknown +keycode_Left +keycode_Right +keycode_Up +keycode_Down +keycode_Return +keycode_Delete +keycode_Escape +keycode_Tab +keycode_PageUp +keycode_PageDown +keycode_Home +keycode_End +keycode_Func1 +keycode_Func2 +keycode_Func3 +keycode_Func4 +keycode_Func5 +keycode_Func6 +keycode_Func7 +keycode_Func8 +keycode_Func9 +keycode_Func10 +keycode_Func11 +keycode_Func12 +keycode_MAXVAL +
+ +
+glk-case +Upper and Lower Case +glk_char_to_lower +glk_char_to_upper +glk_buffer_to_lower_case_uni +glk_buffer_to_upper_case_uni +glk_buffer_to_title_case_uni +
+ +
+glk-window-opening +Window Opening, Closing, and Constraints +glk_window_open +winmethod_Left +winmethod_Right +winmethod_Above +winmethod_Below +winmethod_DirMask +winmethod_Fixed +winmethod_Proportional +winmethod_DivisionMask +glk_window_close +
+ +
+glk-window-constraints +Changing Window Constraints +glk_window_get_size +glk_window_set_arrangement +glk_window_get_arrangement +
+ +
+glk-window-types +The Types of Windows +wintype_Blank +wintype_Pair +wintype_TextBuffer +wintype_TextGrid +glk_window_move_cursor +wintype_Graphics +wintype_AllTypes +
+ +
+glk-echo-streams +Echo Streams +glk_window_set_echo_stream +glk_window_get_echo_stream +
+ +
+glk-window-other +Other Window Functions +glk_window_iterate +glk_window_get_rock +glk_window_get_type +glk_window_get_parent +glk_window_get_sibling +glk_window_get_root +glk_window_clear +glk_window_get_stream +glk_set_window +
+ +
+glk-events +Events +glk_select +event_t +glk_select_poll + +evtype_None +evtype_Timer +evtype_CharInput +evtype_LineInput +evtype_MouseInput +evtype_Arrange +evtype_Redraw +evtype_SoundNotify +evtype_Hyperlink +
+ +
+glk-character-input-events +Character Input Events +glk_request_char_event +glk_request_char_event_uni +glk_cancel_char_event +
+ +
+glk-line-input-events +Line Input Events +glk_request_line_event +glk_request_line_event_uni +glk_cancel_line_event +
+ +
+glk-mouse-events +Mouse Input Events +glk_request_mouse_event +glk_cancel_mouse_event +
+ +
+glk-timer-events +Timer Events +glk_request_timer_events +
+ +
+glk-streams +Streams +glk_stream_set_current +glk_stream_get_current + +filemode_Write +filemode_Read +filemode_ReadWrite +filemode_WriteAppend +
+ +
+glk-print +How to Print +glk_put_char +glk_put_string +glk_put_buffer +glk_put_char_stream +glk_put_string_stream +glk_put_buffer_stream +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-read +How to Read +glk_get_char_stream +glk_get_buffer_stream +glk_get_line_stream +glk_get_char_stream_uni +glk_get_buffer_stream_uni +glk_get_line_stream_uni +
+ +
+glk-closing-streams +Closing Streams +glk_stream_close +stream_result_t +
+ +
+glk-stream-positions +Stream Positions +glk_stream_set_position +glk_stream_get_position + +seekmode_Start +seekmode_Current +seekmode_End +
+ +
+glk-styles +Styles +glk_set_style +glk_set_style_stream + +glk_stylehint_set +glk_stylehint_clear + +glk_style_distinguish +glk_style_measure + +style_Normal +style_Emphasized +style_Preformatted +style_Header +style_Subheader +style_Alert +style_Note +style_BlockQuote +style_Input +style_User1 +style_User2 +style_NUMSTYLES +stylehint_Indentation +stylehint_ParaIndentation +stylehint_Justification +stylehint_Size +stylehint_Weight +stylehint_Oblique +stylehint_Proportional +stylehint_TextColor +stylehint_BackColor +stylehint_ReverseColor +stylehint_NUMHINTS +stylehint_just_LeftFlush +stylehint_just_LeftRight +stylehint_just_Centered +stylehint_just_RightFlush +
+ +
+glk-stream-types +The Types of Streams +glk_stream_open_memory +glk_stream_open_memory_uni +glk_stream_open_file +glk_stream_open_file_uni +
+ +
+glk-stream-other +Other Stream Functions +glk_stream_iterate +glk_stream_get_rock +
+ +
+glk-fileref +File References +fileusage_Data +fileusage_SavedGame +fileusage_Transcript +fileusage_InputRecord +fileusage_TypeMask +fileusage_TextMode +fileusage_BinaryMode +
+ +
+glk-fileref-types +The Types of File References +glk_fileref_create_temp +glk_fileref_create_by_prompt +glk_fileref_create_by_name +glk_fileref_create_from_fileref +
+ +
+glk-fileref-other +Other File Reference Functions +glk_fileref_destroy +glk_fileref_iterate +glk_fileref_get_rock +glk_fileref_delete_file +glk_fileref_does_file_exist +
+ +
+glk-image-resources +Image Resources +glk_image_get_info +glk_image_draw +glk_image_draw_scaled +
+ +
+glk-graphics-windows +Graphics in Graphics Windows +glk_window_set_background_color +glk_window_fill_rect +glk_window_erase_rect +
+ +
+glk-graphics-text +Graphics in Text Buffer Windows +glk_window_flow_break + +imagealign_InlineUp +imagealign_InlineDown +imagealign_InlineCenter +imagealign_MarginLeft +imagealign_MarginRight +
+ +
+glk-graphics-testing +Testing for Graphics Capabilities +GLK_MODULE_IMAGE +
+ +
+glk-sound-channels +Creating and Destroying Sound Channels +glk_schannel_create +glk_schannel_destroy +
+ +
+glk-playing-sounds +Playing Sounds +glk_schannel_play +glk_schannel_play_ext +glk_schannel_stop +glk_schannel_set_volume +glk_sound_load_hint +
+ +
+glk-sound-other +Other Sound Channel Functions +glk_schannel_iterate +glk_schannel_get_rock +
+ +
+glk-sound-testing +Testing for Sound Capabilities +GLK_MODULE_SOUND +
+ +
+glk-creating-hyperlinks +Creating Hyperlinks +glk_set_hyperlink +glk_set_hyperlink_stream +
+ +
+glk-accepting-hyperlinks +Accepting Hyperlink Events +glk_request_hyperlink_event +glk_cancel_hyperlink_event +
+ +
+glk-hyperlinks-testing +Testing for Hyperlink Capabilities +GLK_MODULE_HYPERLINKS +
+ diff --git a/docs/reference/chimara.types b/docs/reference/chimara.types new file mode 100644 index 0000000..6d0bd57 --- /dev/null +++ b/docs/reference/chimara.types @@ -0,0 +1 @@ +chimara_glk_get_type diff --git a/docs/reference/glk-api-conventions.sgml b/docs/reference/glk-api-conventions.sgml new file mode 100644 index 0000000..e796e52 --- /dev/null +++ b/docs/reference/glk-api-conventions.sgml @@ -0,0 +1,36 @@ + + + + +Other API Conventions +3 +CHIMARA Library + + +Other API Conventions +General information about the Glk API + + +Description + +The glk.h header file is the same on all platforms, with the sole exception of the typedef of #glui32 and #glsi32. These will always be defined as 32-bit unsigned and signed integer types, which may be long or int or some other C definition. + + +Note that all constants are #defines, and all functions are actual function declarations (as opposed to macros.) + + +There are a few places where macros would be more efficient — glk_gestalt() and glk_gestalt_ext(), for example — but they are not likely to be CPU bottlenecks, and clarity seems more important. + + +%FALSE is 0; %TRUE is 1. %NULL is also 0. + + +As stated above, it is illegal to pass %NULL to a function which is expecting a valid object reference, unless the function definition says otherwise. + + +Some functions have pointer arguments, acting as variable or reference arguments; the function's intent is to return some value in the space pointed to by the argument. Unless the function says otherwise, it is legal to pass a %NULL pointer to indicate that you do not care about that value. + + + diff --git a/docs/reference/glk-character-encoding.sgml b/docs/reference/glk-character-encoding.sgml new file mode 100644 index 0000000..dec86f6 --- /dev/null +++ b/docs/reference/glk-character-encoding.sgml @@ -0,0 +1,47 @@ + + + + +Character Encoding +3 +CHIMARA Library + + +Character Encoding +Latin-1 and Unicode characters + + +Description + +Glk has two separate, but parallel, APIs for managing text input and output. The basic functions deal entirely in 8-bit characters; their arguments are arrays of bytes (octets). These functions all assume the Latin-1 character encoding. Equivalently, they may be said to use code points U+00..U+FF of Unicode. + + +Latin-1 is an 8-bit character encoding; it maps numeric codes in the range 0 to 255 into printed characters. The values from 32 to 126 are the standard printable ASCII characters (' ' to '~'). Values 0 to 31 and 127 to 159 are reserved for control characters, and have no printed equivalent. + + +Note that the basic Glk text API does not use UTF-8, or any other Unicode character form. Each character is represented by a single byte — even characters in the 128..255 range. + + +The extended, or Unicode, Glk functions deal entirely in 32-bit words. They take arrays of words, not bytes, as arguments. They can therefore cope with any Unicode code point. The extended functions have names ending in _uni. + + +Since these functions deal in arrays of 32-bit words, they can be said to use the UTF-32 character encoding form. (But not the UTF-32 character encoding scheme — that's a stream of bytes which must be interpreted in big-endian or little-endian mode. Glk Unicode functions operate on long integers, not bytes.) UTF-32 is also known as UCS-4, according to the Unicode spec (appendix C.2), modulo some semantic requirements which we will not deal with here. For practical purposes, we can ignore the whole encoding issue, and assume that we are dealing with sequences of numeric code points. + + +Why not UTF-8? It is a reasonable bare-bones compression algorithm for Unicode character streams; but IF systems typically have their own compression models for text. Compositing the two ideas causes more problems than it solves. The other advantage of UTF-8 is that 7-bit ASCII is automatically valid UTF-8; but this is not compelling for IF systems, in which the compiler can be tasked with generating consistent textual data. And UTF-8 is a variable-width encoding. Nobody ever wept at the prospect of avoiding that kettle of eels. + + + +What about bi-directional text? It's a good idea, and may show up in future versions of this document. It is not in this version because we want to get something simple implemented soon. For the moment, print out all text in reading order (not necessarily left-to-right) and hope for the best. Current suggestions include a stylehint_Direction, which the game can set to indicate that text in the given style should be laid out right-to-left. Top-to-bottom (or bottom-to-top) may be desirable too. The direction stylehints might only apply to full paragraphs (like justification stylehints); or they might apply to any text, thus requiring the library to lay out zig-zag blocks. The possibilities remain to be explored. Page layout is hard. + + +Another possibility is to let the library determine the directionality of text from the character set. This is not impossible — MacOSX text widgets do it. It may be too difficult. + + +In the meantime, it is worth noting that the Windows Glk library does not autodetect directionality, but the CheapGlk library running on MacOSX does. Therefore, there is no platform-independent way to handle right-to-left fonts at present. + + + + diff --git a/docs/reference/glk-display-style.sgml b/docs/reference/glk-display-style.sgml new file mode 100644 index 0000000..d119c24 --- /dev/null +++ b/docs/reference/glk-display-style.sgml @@ -0,0 +1,33 @@ + + + + +A Note on Display Style +3 +CHIMARA Library + + +A Note on Display Style +How windows may be displayed on different platforms + + +Description + +The way windows are displayed is, of course, entirely up to the Glk library; it depends on what is natural for the player's machine. The borders between windows may be black lines, 3-D bars, rows of # characters; there may even be no borders at all. + + +This is an important possibility to keep in mind. + + +There may be other decorations as well. A text buffer window will often have a scroll bar. The library (or player) may prefer wide margins around each text window. And so on. + + +The library is reponsible for handling these decorations, margins, spaces, and borders. You should never worry about them. You are guaranteed that if you request a fixed size of two rows, your text grid window will have room for two rows of characters — if there is enough total space. Any margins or borders will be allowed for already. If there isn't enough total space (as in stages 4 and 5 of this figure), you lose, of course. + + +How do you know when you're losing? You can call glk_window_get_size() to determine the window size you really got. Obviously, you should draw into your windows based on their real size, not the size you requested. If there's enough space, the requested size and the real size will be identical; but you should not rely on this. Call glk_window_get_size() and check. + + + diff --git a/docs/reference/glk-front-matter.sgml b/docs/reference/glk-front-matter.sgml new file mode 100644 index 0000000..2abdbc2 --- /dev/null +++ b/docs/reference/glk-front-matter.sgml @@ -0,0 +1,25 @@ + + + +Glk API Specification +API version 0.7.0 + + + Andrew + Plotkin + + erkyrath@eblong.com + + + 1998–2004 + Andrew Plotkin + + +You have permission to display, download, and print this document, provided that you do so for personal, non-commercial use only. You may not modify or distribute this document without the author's written permission. + + +The authors of the Chimara library have adapted this document to better fit the format of a GtkDoc reference manual. They have also added notes specific to Chimara's implementation of the Glk API. The original API specification and further Glk information can be found at: http://www.eblong.com/zarf/glk/ + + diff --git a/docs/reference/glk-introduction.sgml b/docs/reference/glk-introduction.sgml new file mode 100644 index 0000000..d7c317b --- /dev/null +++ b/docs/reference/glk-introduction.sgml @@ -0,0 +1,106 @@ + + +Introduction +What Glk Is + +Glk is an attempt to define a portable API (programming interface) for applications with text UIs (user interfaces.) + + +Rather than go into a detailed explanation of what that means, let me give examples from the world of text adventures. TADS and Infocom's Z-machine have nearly identical interface capabilities; each allows a program to... + + print an indefinite stream of text into an output buffer, with some style control + input a line of text + display a few lines of text in a small separate window + store information in a file, or read it in + +and so on. However, the implementation of these capabilities vary widely between platforms and operating systems. Furthermore, this variance is transparent to the program (the adventure game.) The game does not care whether output is displayed via a character terminal emulator or a GUI window; nor whether input uses Mac-style mouse editing or EMACS-style control key editing. + + +On the third hand, the user is likely to care deeply about these interface decisions. This is why there are Mac-native interpreters on Macintoshes, pen-controlled interpreters on Newtons and PalmOS PDAs, and so on — and (ultimately) why there Macintoshes and Palms and X-windows platforms in the first place. + + +On the fourth hand, TADS and Inform are not alone; there is historically a large number of text adventure systems. Most are obsolete or effectively dead; but it is inevitable that more will appear. Users want each living system ported to all the platforms in use. Users also prefer these ports to use the same interface, as much as possible. + + +This all adds up to a pain in the ass. + + +Glk tries to draw a line between the parts of the text adventure world which are identical on all IF systems, and different on different operating systems, from the parts which are unique to each IF system but identical in all OSs. The border between these two worlds is the Glk API. + + +My hope is that a new IF system, or existing ones which are less-supported (Hugo, AGT, etc) can be written using Glk for all input and output function. The IF system would then be in truly portable C. On the other side of the line, there would be a Glk library for each operating system and interface (Macintosh, X-windows, curses-terminal, etc.) Porting the IF system to every platform would be trivial; compile the system, and link in the library. + + +Glk can also serve as a nice interface for applications other than games — data manglers, quick hacks, or anything else which would normally lack niceties such as editable input, macros, scrolling, or whatever is native to your machine's interface idiom. + + +What About the Virtual Machine? + +You can think of Glk as an IF virtual machine, without the virtual machine part. The machine is just portable C code. + + +An IF virtual machine has been designed specifically to go along with Glk. This VM, called Glulx, uses Glk as its interface; each Glk call corresponds to an input/output opcode of the VM. + + +For more discussion of this approach, see Glk and the Virtual Machine. Glulx is documented at http://www.eblong.com/zarf/glulx. + + +Of course, Glk can be used with other IF systems. The advantage of Glulx is that it provides the game author with direct and complete access to the Glk API. Other IF systems typically have an built-in abstract I/O API, which maps only partially onto Glk. For these systems, Glk tends to be a least-common-denominator interface: highly portable, but not necessarily featureful. (Even if Glk has a feature, it may not be available through the layers of abstraction.) + + +What Does Glk Not Do? + +Glk does not handle the things which should be handled by the program (or the IF system, or the virtual machine) which is linked to Glk. This means that Glk does not address + + parsing + game object storage + computation + text compression + + + +Conventions of This Document + +This document defines the Glk API. I have tried to specify exactly what everything does, what is legal, what is illegal, and why. + + +Sections labeled like this are notes. They do not define anything; they clarify or explain what has already been defined. If there seems to be a conflict, ignore the note and follow the definition. + +WORK + +Notes with the label WORK are things which I have not yet fully resolved. Your comments requested and welcome. + +Chimara + +Notes labeled Chimara are specific to Chimara's implementation of the Glk API and are not part of the original Glk API specification. + + +This document is written for the point of view of the game programmer — the person who wants to use the Glk library to print text, input text, and so on. By saying what the Glk library does, of course, this document also defines the task of the Glk programmer — the person who wants to port the Glk library to a new platform or operating system. If the Glk library guarantees something, the game programmer can rely on it, and the Glk programmer is required to support it. Contrariwise, if the library does not guarantee something, the Glk programmer may handle it however he likes, and the game programmer must not rely on it. If something is illegal, the game programmer must not do it, and the Glk programmer is not required to worry about it. + + +It is preferable, but not required, that the Glk library detect illegal requests and display error messages. The Glk library may simply crash when the game program does something illegal. This is why the game programmer must not do it. Right? + +Chimara + +Wherever possible, Chimara checks for anything defined as illegal, and prints a +warning message to standard error. It tries to recover as gracefully as possible +so that the program can continue. + + +Hereafter, Glk or the library refers to the Glk library, and the program is the game program (or whatever) which is using the Glk library to print text, input text, or whatever. You are the person writing the program. The player is the person who will use the program/Glk library combination to actually play a game. Or whatever. + + +The Glk API is declared in a C header file called glk.h. Please refer to that file when reading this one. + + +Credits + +Glk has been a work of many years and many people. If I tried to list everyone who has offered comments and suggestions, I would immediately go blank, forget everyone's name, and become a mute hermit-like creature living in a train tunnel under Oakland. But I must thank those people who have written Glk libraries and linking systems: Matt Kimball, Ross Raszewski, David Kinder, John Elliott, Joe Mason, Stark Springs, and, er, anyone I missed. Look! A train! + + +Evin Robertson wrote the original proposal for the Glk Unicode functions, which I imported nearly verbatim into this document. Thank you. + + + diff --git a/docs/reference/glk-line-input.sgml b/docs/reference/glk-line-input.sgml new file mode 100644 index 0000000..f88692c --- /dev/null +++ b/docs/reference/glk-line-input.sgml @@ -0,0 +1,33 @@ + + + + +Line Input +3 +CHIMARA Library + + +Line Input +Reading lines of text + + +Description + +You can request that the player enter a line of text. See Line Input Events. + + +This text will be placed in a buffer of your choice. There is no length field or null terminator in the buffer. (The length of the text is returned as part of the line-input event.) + + +If you use the basic text API, the buffer will contain only printable Latin-1 characters (32 to 126, 160 to 255). + + +A particular implementation of Glk may not be able to accept all Latin-1 printable characters as input. It is guaranteed to be able to accept the ASCII characters (32 to 126.) + + +You can test for this by using the #gestalt_LineInput selector. + + + diff --git a/docs/reference/glk-main-function.sgml b/docs/reference/glk-main-function.sgml new file mode 100644 index 0000000..e6f33e7 --- /dev/null +++ b/docs/reference/glk-main-function.sgml @@ -0,0 +1,69 @@ + + + + +Your Program's Main Function +3 +CHIMARA Library + + +Your Program's Main Function +How Glk starts your program + + +Description + +The top level of the program — the main() function in C, for example — belongs to Glk. + + +This means that Glk isn't really a library. In a sense, you are writing a library, which is linked into Glk. This is bizarre to think about, so forget it. + +Chimara + +In Chimara, the arrangement is even more bizarre. Chimara is a library, and it runs your Glk program from within a GTK+ graphical application (the host program). Chimara treats your program as a plugin, or shared library, and it executes your program in its own thread, displaying windows and output in the GTK+ program. + + +This makes absolutely no difference to you, the Glk programmer; if your program works correctly with a regular Glk library, it will also work properly with Chimara. The only difference is in compiling your Glk program. + + +You define a function called glk_main(), which the library calls to begin running your program. glk_main() should run until your program is finished, and then return. + + +Glk does all its user-interface work in a function called glk_select(). This function waits for an event — typically the player's input — and returns an structure representing that event. This means that your program must have an event loop. In the very simplest case, you could write + + + +void glk_main() +{ + #event_t ev; + while (1) { + #glk_select(&ev); + switch (ev.type) { + default: + /* do nothing */ + break; + } + } +} + + + +This is a legal Glk-compatible program. As you might expect, it doesn't do anything. The player will see an empty window, which he can only stare at, or destroy in a platform-defined standard manner. + + +Commandperiod on the Macintosh; a kill-window menu option in an X window manager; controlC in a curses terminal window. + +Chimara + +In Chimara, there is no standard way; the program will stop when the host program calls chimara_glk_stop(). The host program might have a Stop button which does this, for example, but it will also generally happen when the #ChimaraGlk widget is destroyed or when the host program ends. + + +However, this program does not spin wildly and burn CPU time. The glk_select() function waits for an event it can return. Since it only returns events which you have requested, it will wait forever, and grant CPU time to other processes if that's meaningful on the player's machine. + + +Actually, there are some events which are always reported. More may be defined in future versions of the Glk API. This is why the default response to an event is to do nothing. If you don't recognize the event, ignore it. + + + diff --git a/docs/reference/glk-other-events.sgml b/docs/reference/glk-other-events.sgml new file mode 100644 index 0000000..b60a33f --- /dev/null +++ b/docs/reference/glk-other-events.sgml @@ -0,0 +1,46 @@ + + + + +Other Events +3 +CHIMARA Library + + +Other Events +Events in future versions of Glk + + + +There are currently no other event types defined by Glk. (The #evtype_None constant is a placeholder, and is never returned by glk_select().) + + +It is possible that new event types will be defined in the future. + +For example, if video or animation capabilities are added to Glk, there would probably be some sort of completion event for them. + + +This is also why you must put calls to glk_select() in loops. If you tried to read a character by simply writing + +#glk_request_char_event(win); +#glk_select(&ev); + +you might not get a CharInput event back. You could get some not-yet-defined event which happened to occur before the player hit a key. Or, for that matter, a window arrangement event. + + +It is not generally necessary to put a call to glk_select_poll() in a loop. You usually call glk_select_poll() to update the display or test if an event is available, not to wait for a particular event. However, if you are using sound notification events, and several sounds are playing, it might be important to make sure you knew about all sounds completed at any particular time. You would do this with + +#glk_select_poll(&ev); +while (ev.type != #evtype_None) { + /* handle event */ + #glk_select_poll(&ev); +} + + + +Once glk_select_poll() returns #evtype_None, you should not call it again immediately. Do some work first. If you want to wait for an event, use glk_select(), not a loop of glk_select_poll(). + + + diff --git a/docs/reference/glk-output.sgml b/docs/reference/glk-output.sgml new file mode 100644 index 0000000..c0d8a5d --- /dev/null +++ b/docs/reference/glk-output.sgml @@ -0,0 +1,39 @@ + + + + +Output +3 +CHIMARA Library + + +Output +Printing basics + + +Description + +When you are sending text to a window, or to a file open in text mode, you can print any of the printable Latin-1 characters: 32 to 126, 160 to 255. You can also print the newline character (linefeed, controlJ, decimal 10, hex 0x0A.) + + +It is not legal to print any other control characters (0 to 9, 11 to 31, 127 to 159). You may not print even common formatting characters such as tab (controlI), carriage return (controlM), or page break (controlL). + + +As usual, the behavior of the library when you print an illegal character is undefined. It is preferable that the library display a numeric code, such as \177 or 0x7F, to warn the user that something illegal has occurred. The library may skip illegal characters entirely; but you should not rely on this. + + +Printing Unicode characters above 255 is a more complicated matter — too complicated to be covered precisely by this specification. Refer to the Unicode specification, and good luck to you. + + +Unicode combining characters are a particular nuisance. Printing a combining character may alter the appearance of the previous character printed. The library should be prepared to cope with this — even if the characters are printed by two separate glk_put_char_uni() calls. + + +Note that when you are sending data to a file open in binary mode, you can print any byte value, without restriction. See File Streams. + + +A particular implementation of Glk may not be able to display all the printable characters. It is guaranteed to be able to display the ASCII characters (32 to 126, and the newline 10.) Other characters may be printed correctly, printed as multi-character combinations (such as ae for the æ ligature), or printed as some placeholder character (such as a bullet or question mark, or even an octal code.) You can test for this using #gestalt_CharOutput. + + + diff --git a/docs/reference/glk-window-arrangement.sgml b/docs/reference/glk-window-arrangement.sgml new file mode 100644 index 0000000..9926d81 --- /dev/null +++ b/docs/reference/glk-window-arrangement.sgml @@ -0,0 +1,73 @@ + + +]> + + +Window Arrangement +3 +CHIMARA Library + + +Window Arrangement +The Way of Window Arrangement + + +Description + +The Way of Window Arrangement is fairly complicated. I'll try to explain it coherently. + +If you are reading this document to get an overview of Glk, by all means skip forward to The Types of Windows. Come back here later. + + +Originally, there are no windows. You can create a window, which will take up the entire available screen area. You can then split this window in two. One of the halves is the original window; the other half is new, and can be of any type you want. You can control whether the new window is left, right, above, or below the original one. You can also control how the split occurs. It can be 50-50, or 70-30, or any other percentage split. Or, you can give a fixed width to the new window, and allow the old one to take up the rest of the available space. Or you can give a fixed width to the old window, and let the new one take up the rest of the space. + + +Now you have two windows. In exactly the same way, you can split either of them — the original window, or the one you just created. Whichever one you split becomes two, which together take up the same space that the one did before. + + +You can repeat this as often as you want. Every time you split a window, one new window is created. Therefore, the call that does this is called glk_window_open(). + + +It might have been less confusing to call it glk_split_window() — or it might have been more confusing. I picked one. + + +It is important to remember that the order of splitting matters. If you split twice, you don't have a trio of windows; you have a pair with another pair on one side. Mathematically, the window structure is a binary tree. + + +Example time. Say you do two splits, each a 50-50 percentage split. You start with the original window A, and split that into A and B; then you split B into B and C. +Screen shot 1 +Or, you could split A into A and B, and then split A again into A and C. +Screen shot 2 +I'm using the simplest possible splits in the examples above. Every split is 50-50, and the new window of the pair is always below the original one (the one that gets split.) You can get fancier than that. Here are three more ways to perform the first example; all of them have the same tree structure, but look different on the screen. +Screen shot 3 +On the left, we turn the second split (B into B/C) upside down; we put the new window (C) above the old window (B). + + +In the center, we mess with the percentages. The first split (A into A/B) is a 25-75 split, which makes B three times the size of A. The second (B into B/C) is a 33-66 split, which makes C twice the size of B. This looks rather like the second example above, but has a different internal structure. + + +On the right, the second split (B into B/C) is vertical instead of horizontal, with the new window (C) on the left of the old one. + + +The visible windows on the Glk screen are leaf nodes of the binary tree; they hang off the ends of the branches in the diagram. There are also the internal nodes, the ones at the forks, which are marked as O. These are the mysterious pair windows. + + +You don't create pair windows directly; they are created as a consequence of window splits. Whenever you create a new window, a new pair window is also created automatically. In the following two-split process, you can see that when a window is split, it is replaced by a new pair window, and moves down to become one of that O's two children. +Screen shot 4 + + +You can't draw into a pair window. It's completely filled up with the two windows it contains. They're what you should be drawing into. + + +Why have pair windows in the system at all? They're convenient for certain operations. For example, you can close any window at any time; but sometimes you want to close an entire nest of windows at once. In the third stage shown, if you close the lower pair window, it blows away all its descendents — both B and C — and leaves just a single window, A, which is what you started with. + + +I'm using some math terminology already, so I'll explain it briefly. The root of the tree is the top (math trees, like family trees, grow upside down.) If there's only one window, it's the root; otherwise the root is the topmost O. Every pair window has exactly two children. Other kinds of windows are leaves on the tree, and have no children. A window's descendants, obviously, are its children and grandchildren and great-grandchildren and so on. The parent and ancestors of a window are exactly what you'd expect. So the root window is the ancestor of every other window. + + +There are Glk functions to determine the root window, and to determine the parent of any given window. Note that every window's parent is a pair window. (Except for the root window, which has no parent.) + + + diff --git a/docs/reference/glk-windows.sgml b/docs/reference/glk-windows.sgml new file mode 100644 index 0000000..60f3615 --- /dev/null +++ b/docs/reference/glk-windows.sgml @@ -0,0 +1,94 @@ + + +]> + + +Windows +3 +CHIMARA Library + + +Windows +Introduction to Glk windows + + +Description + +On most platforms, the program/library combination will appear to the player in a window — either a window which covers the entire screen, or one which shares screen space with other windows in a multi-programming environment. Obviously your program does not have worry about the details of this. The Glk screen space is a rectangle, which you can divide into panels for various purposes. It is these panels which I will refer to as windows hereafter. + + +You refer to a window using an opaque C structure pointer. See Opaque Objects. + + +A window has a type. Currently there are four window types: + + + Text buffer windows + + A stream of text. + + The story window of an Infocom game. + + + You can only print at the end of the stream, and input a line of text at the end of the stream. + + + + Text grid windows + + A grid of characters in a fixed-width font. + + The status window of an Infocom game. + + + You can print anywhere in the grid. + + + + Graphics windows + + A grid of colored pixels. Graphics windows do not support text input or output, but there are image commands to draw in them. + + This is an optional capability; not all Glk libraries support graphics. See Testing for Graphics Capabilities. + + + + Blank windows + A blank window. Blank windows support neither input nor output. + + They exist mostly to be an example of a generic window. You are unlikely to want to use them. + + + + + +As Glk is an expanding system, more window types may be added in the future. Therefore, it is important to remember that not all window types will necessarily be available under all Glk libraries. + + +There is one other special type of window, the pair window. Pair windows are created by Glk as part of the system of window arrangement. You cannot create them yourself. See Pair Windows. + + +Every window has a rock. This is a value you provide when the window is created; you can use it however you want. See Rocks. + + +When Glk starts up, there are no windows. + + +When I say there are no windows, I mean there are no Glk windows. In a multiprogramming environment, such as X or MacOS, there may be an application window visible; this is the screen space that will contain all the Glk windows that you create. But at first, this screen space is empty and unused. + + +Without a window, you cannot do any kind of input or output; so the first thing you'll want to do is create one. See Window Opening, Closing, and Constraints. + + +You can create as many windows as you want, of any types. You control their arrangement and sizes through a fairly flexible system of calls. See Window Arrangement. + + +You can close any windows you want. You can even close all the windows, which returns you to the original startup state. + + +You can request input from any or all windows. Input can be mouse input (on platforms which support a mouse), single-character input, or input of an entire line of text. It is legal to request input from several windows at the same time. The library will have some interface mechanism for the player to control which window he is typing in. + + + diff --git a/docs/reference/version.xml.in b/docs/reference/version.xml.in new file mode 100644 index 0000000..a24f987 --- /dev/null +++ b/docs/reference/version.xml.in @@ -0,0 +1 @@ +@PACKAGE_VERSION@ diff --git a/po/.ignore b/po/.ignore deleted file mode 100755 index e69b061..0000000 --- a/po/.ignore +++ /dev/null @@ -1,23 +0,0 @@ -.libs -.deps -.*swp -.nautilus-metafile.xml -*.autosave -*.gmo -*.mo -*.pot -*~ -#*# -*.bak -*.o -*.lo -*.la -cat-id-tbl.c -stamp-cat-id -messages -missing -POTFILES -Makefile -Makefile.in -Makefile.in.in -translations.xml diff --git a/src/Makefile.am b/src/Makefile.am index e34db8b..b504287 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -37,11 +37,11 @@ libchimara_la_SOURCES = \ window.c window.h libchimara_la_LIBADD = @CHIMARA_LIBS@ -libchimara_la_LDFLAGS = -no-undefined -export-symbols-regex "^chimara_glk_.*|^glk_.*" +libchimara_la_LDFLAGS = -no-undefined -export-symbols-regex "^chimara_glk_|^glk_" libchimara_includedir = $(includedir)/chimara/chimara libchimara_include_HEADERS = chimara-glk.h -PLUGIN_LDFLAGS = -module -shared -avoid-version -export-symbols-regex "glk_main" +PLUGIN_LDFLAGS = -module -shared -avoid-version -export-symbols-regex "^glk_main$$" pkglib_LTLIBRARIES = first.la model.la gridtest.la splittest.la first_la_SOURCES = first.c first_la_LDFLAGS = $(PLUGIN_LDFLAGS) diff --git a/src/abort.c b/src/abort.c index 4580c0f..4ae157a 100644 --- a/src/abort.c +++ b/src/abort.c @@ -8,14 +8,15 @@ extern ChimaraGlkPrivate *glk_data; /** * glk_set_interrupt_handler: - * @func: A pointer to a function which takes no argument and returns no result. + * @func: A pointer to an interrupt handler function. * - * Specifies an interrupt handler function for cleaning up critical resources. - * If Glk receives an interrupt, and you have set an interrupt handler, your - * handler will be called, before the process is shut down. + * Sets @func to be the interrupt handler. @func should be a pointer to a + * function which takes no argument and returns no result. If Glk receives an + * interrupt, and you have set an interrupt handler, your handler will be + * called, before the process is shut down. * * Initially there is no interrupt handler. You can reset to not having any by - * calling glk_set_interrupt_handler(%NULL). + * calling #glk_set_interrupt_handler(%NULL). * * If you call glk_set_interrupt_handler() with a new handler function while an * older one is set, the new one replaces the old one. Glk does not try to queue diff --git a/src/case.c b/src/case.c index 9e73de1..47086e1 100644 --- a/src/case.c +++ b/src/case.c @@ -5,8 +5,21 @@ * glk_char_to_lower: * @ch: A Latin-1 character. * - * If @ch is an uppercase character in the Latin-1 character set, converts it - * to lowercase. Otherwise, leaves it unchanged. + * You can convert Latin-1 characters between upper and lower case with two Glk + * utility functions, glk_char_to_lower() and glk_char_to_upper(). These have a + * few advantages over the standard ANSI tolower() and + * toupper() macros. They work for the entire Latin-1 + * character set, including accented letters; they behave consistently on all + * platforms, since they're part of the Glk library; and they are safe for all + * characters. That is, if you call glk_char_to_lower() on a lower-case + * character, or a character which is not a letter, you'll get the argument + * back unchanged. + * + * The case-sensitive characters in Latin-1 are the ranges 0x41..0x5A, + * 0xC0..0xD6, 0xD8..0xDE (upper case) and the ranges 0x61..0x7A, 0xE0..0xF6, + * 0xF8..0xFE (lower case). These are arranged in parallel; so + * glk_char_to_lower() will add 0x20 to values in the upper-case ranges, and + * glk_char_to_upper() will subtract 0x20 from values in the lower-case ranges. * * Returns: A lowercase or non-letter Latin-1 character. */ @@ -23,7 +36,7 @@ glk_char_to_lower(unsigned char ch) * @ch: A Latin-1 character. * * If @ch is a lowercase character in the Latin-1 character set, converts it to - * uppercase. Otherwise, leaves it unchanged. + * uppercase. Otherwise, leaves it unchanged. See glk_char_to_lower(). * * Returns: An uppercase or non-letter Latin-1 character. */ @@ -41,18 +54,39 @@ glk_char_to_upper(unsigned char ch) * @len: Available length of @buf. * @numchars: Number of characters in @buf. * - * Converts the first @numchars characters of @buf to their lowercase - * equivalents, if there is such a thing. These functions provide two length - * arguments because a string of Unicode characters may expand when its case - * changes. The @len argument is the available length of the buffer; @numchars - * is the number of characters in the buffer initially. (So @numchars must be - * less than or equal to @len. The contents of the buffer after @numchars do - * not affect the operation.) + * Unicode character conversion is trickier, and must be applied to character + * arrays, not single characters. These functions + * (glk_buffer_to_lower_case_uni(), glk_buffer_to_upper_case_uni(), and + * glk_buffer_to_title_case_uni()) provide two length arguments because a + * string of Unicode characters may expand when its case changes. The @len + * argument is the available length of the buffer; @numchars is the number of + * characters in the buffer initially. (So @numchars must be less than or equal + * to @len. The contents of the buffer after @numchars do not affect the + * operation.) * - * Returns: The number of characters after conversion. If this is greater than - * @len, the characters in the array will be safely truncated at len, but the - * true count will be returned. (The contents of the buffer after the returned - * count are undefined.) + * The functions return the number of characters after conversion. If this is + * greater than @len, the characters in the array will be safely truncated at + * @len, but the true count will be returned. (The contents of the buffer after + * the returned count are undefined.) + * + * The lower_case and upper_case functions do what + * you'd expect: they convert every character in the buffer (the first @numchars + * of them) to its upper or lower-case equivalent, if there is such a thing. + * + * See the Unicode spec (chapter 3.13, chapter 4.2, etc) for the exact + * definitions of upper, lower, and title-case mapping. + * + * + * Unicode has some strange case cases. For example, a combined character + * that looks like ss might properly be upper-cased into + * two characters S. Title-casing is even + * stranger; ss (at the beginning of a word) might be + * title-cased into a different combined character that looks like + * Ss. The glk_buffer_to_title_case_uni() function is actually + * title-casing the first character of the buffer. If it makes a difference. + * + * + * Returns: The number of characters after conversion. */ glui32 glk_buffer_to_lower_case_uni(glui32 *buf, glui32 len, glui32 numchars) @@ -105,10 +139,19 @@ glk_buffer_to_upper_case_uni(glui32 *buf, glui32 len, glui32 numchars) * @lowerrest: %TRUE if the rest of @buf should be lowercased, %FALSE * otherwise. * - * Converts the first character of @buf to uppercase, if there is such a thing. - * See glk_buffer_to_lower_case_uni(). If @lowerrest is %TRUE, then the - * remainder of @buf is lowercased. + * See glk_buffer_to_lower_case_uni(). The title_case function has + * an additional (boolean) flag. Its basic function is to change the first + * character of the buffer to upper-case, and leave the rest of the buffer + * unchanged. If @lowerrest is true, it changes all the non-first characters to + * lower-case (instead of leaving them alone.) * + * + * Earlier drafts of this spec had a separate function which title-cased the + * first character of every word in the buffer. I took + * this out after reading Unicode Standard Annex #29, which explains how + * to divide a string into words. If you want it, feel free to implement it. + * + * * Returns: The number of characters after conversion. */ glui32 diff --git a/src/chimara-glk-private.h b/src/chimara-glk-private.h index dea8999..9395b40 100644 --- a/src/chimara-glk-private.h +++ b/src/chimara-glk-private.h @@ -46,4 +46,4 @@ struct _ChimaraGlkPrivate { G_END_DECLS -#endif /* __CHIMARA_GLK_PRIVATE_H__ */ \ No newline at end of file +#endif /* __CHIMARA_GLK_PRIVATE_H__ */ diff --git a/src/chimara-glk.c b/src/chimara-glk.c index 5a62517..4bc1c15 100644 --- a/src/chimara-glk.c +++ b/src/chimara-glk.c @@ -12,6 +12,31 @@ #define CHIMARA_GLK_MIN_WIDTH 0 #define CHIMARA_GLK_MIN_HEIGHT 0 +/** + * SECTION:chimara-glk + * @short_description: Widget which executes a Glk program + * @stability: Unstable + * @include: chimara/chimara-glk.h + * + * The ChimaraGlk widget opens and runs a Glk program. The program must be + * compiled as a plugin module, with a function glk_main() + * that the Glk library can hook into. + * + * On Linux systems, this is a file with a name like + * plugin.so. For portability, you can use libtool and + * automake: + * + * pkglib_LTLIBRARIES = plugin.la + * plugin_la_SOURCES = plugin.c foo.c bar.c + * plugin_la_LDFLAGS = -module -shared -avoid-version -export-symbols-regex "^glk_main$$" + * + * This will produce plugin.la which is a text file + * containing the correct plugin file to open (see the relevant section of the + * + * Libtool manual). + */ + typedef void (* glk_main_t) (void); enum { @@ -206,10 +231,24 @@ chimara_glk_class_init(ChimaraGlkClass *klass) /* Signals */ klass->stopped = chimara_glk_stopped; klass->started = chimara_glk_started; + /** + * ChimaraGlk::stopped: + * @glk: The widget that received the signal + * + * The ::stopped signal is emitted when the a Glk program finishes + * executing in the widget, whether it ended normally, or was interrupted. + */ chimara_glk_signals[STOPPED] = g_signal_new("stopped", G_OBJECT_CLASS_TYPE(klass), 0, G_STRUCT_OFFSET(ChimaraGlkClass, stopped), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + /** + * ChimaraGlk::started: + * @glk: The widget that received the signal + * + * The ::started signal is emitted when a Glk program starts executing in + * the widget. + */ chimara_glk_signals[STARTED] = g_signal_new ("started", G_OBJECT_CLASS_TYPE (klass), 0, G_STRUCT_OFFSET(ChimaraGlkClass, started), NULL, NULL, @@ -222,12 +261,28 @@ chimara_glk_class_init(ChimaraGlkClass *klass) TRUE, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_LAX_VALIDATION | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); + /** + * ChimaraGlk:interactive: + * + * Sets whether the widget is interactive. A Glk widget is normally + * interactive, but in non-interactive mode, keyboard and mouse input are + * ignored and the Glk program is controlled by chimara_glk_feed_text(). + * "More" prompts when a lot of text is printed to a text buffer are also + * disabled. This is typically used when you wish to control an interpreter + * program by feeding it a predefined list of commands. + */ g_object_class_install_property(object_class, PROP_INTERACTIVE, pspec); pspec = g_param_spec_boolean("protect", _("Protected"), _("Whether the Glk program is barred from doing file operations"), FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_LAX_VALIDATION | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); + /** + * ChimaraGlk:protect: + * + * Sets whether the Glk program is allowed to do file operations. In protect + * mode, all file operations will fail. + */ g_object_class_install_property(object_class, PROP_PROTECT, pspec); /* Private data */ @@ -263,12 +318,7 @@ chimara_glk_new(void) * @glk: a #ChimaraGlk widget * @interactive: whether the widget should expect user input * - * Sets the #ChimaraGlk:interactive property of @glk. A Glk widget is normally - * interactive, but in non-interactive mode, keyboard and mouse input is ignored - * and the Glk program is controlled by chimara_glk_feed_text(). "More" prompts - * when a lot of text is printed to a text buffer are also disabled. This is - * typically used when you wish to control an interpreter program by feeding it - * a predefined list of commands. + * Sets the #ChimaraGlk:interactive property of @glk. */ void chimara_glk_set_interactive(ChimaraGlk *glk, gboolean interactive) @@ -284,7 +334,7 @@ chimara_glk_set_interactive(ChimaraGlk *glk, gboolean interactive) * @glk: a #ChimaraGlk widget * * Returns whether @glk is interactive (expecting user input). See - * chimara_glk_set_interactive(). + * #ChimaraGlk:interactive. * * Return value: %TRUE if @glk is interactive. */ @@ -320,7 +370,7 @@ chimara_glk_set_protect(ChimaraGlk *glk, gboolean protect) * @glk: a #ChimaraGlk widget * * Returns whether @glk is in protect mode (banned from doing file operations). - * See chimara_glk_set_protect(). + * See #ChimaraGlk:protect. * * Return value: %TRUE if @glk is in protect mode. */ @@ -347,8 +397,10 @@ glk_enter(gpointer glk_main) /** * chimara_glk_run: * @glk: a #ChimaraGlk widget - * @plugin: path to a plugin module compiled with glk.h - * @error: location to store a #GError, or %NULL + * @plugin: path to a plugin module compiled with glk.h + * @error: location to store a GError, or + * %NULL * * Opens a Glk program compiled as a plugin and runs its glk_main() function in * a separate thread. On failure, returns %FALSE and sets @error. @@ -420,4 +472,4 @@ chimara_glk_wait(ChimaraGlk *glk) ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(glk); g_thread_join(priv->thread); -} \ No newline at end of file +} diff --git a/src/chimara-glk.h b/src/chimara-glk.h index 2f41972..94ee6c5 100644 --- a/src/chimara-glk.h +++ b/src/chimara-glk.h @@ -20,22 +20,23 @@ G_BEGIN_DECLS #define CHIMARA_GLK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ CHIMARA_TYPE_GLK, ChimaraGlkClass)) -typedef struct _ChimaraGlk ChimaraGlk; -typedef struct _ChimaraGlkClass ChimaraGlkClass; - -struct _ChimaraGlk { - GtkContainer parent_instance; +/** + * ChimaraGlk: + * + * This structure contains no public members. + */ +typedef struct _ChimaraGlk { + GtkContainer parent_instance; - /* Public members */ -}; + /*< public >*/ +} ChimaraGlk; -struct _ChimaraGlkClass { - GtkContainerClass parent_class; - - /* Signals */ +typedef struct _ChimaraGlkClass { + GtkContainerClass parent_class; + /* Signals */ void(* stopped) (ChimaraGlk *self); void(* started) (ChimaraGlk *self); -}; +} ChimaraGlkClass; GType chimara_glk_get_type(void) G_GNUC_CONST; GtkWidget *chimara_glk_new(void); @@ -49,4 +50,4 @@ void chimara_glk_wait(ChimaraGlk *glk); G_END_DECLS -#endif /* __CHIMARA_GLK_H__ */ \ No newline at end of file +#endif /* __CHIMARA_GLK_H__ */ diff --git a/src/doc.c b/src/doc.c new file mode 100644 index 0000000..5881072 --- /dev/null +++ b/src/doc.c @@ -0,0 +1,1737 @@ +/* + * doc.c - Contains the short and long descriptions of all the documentation + * sections in the Glk spec, as well as the GtkDoc comments for symbols + * defined only in glk.h. + */ + +/** + * SECTION:glk-exiting + * @short_description: How to terminate a Glk program cleanly + * @include: glk.h + * + * A Glk program usually ends when the end of the glk_main() function is + * reached. You can also terminate it earlier. + */ + +/** + * SECTION:glk-interrupt + * @short_description: Specifying an interrupt handler for cleaning up critical + * resources + * @include: glk.h + * + * Most platforms have some provision for interrupting a program — + * command + * period on the Macintosh, controlC + * in Unix, possibly a window manager item, or other possibilities. + * This can happen at any time, including while execution is nested inside one + * of your own functions, or inside a Glk library function. + * + * If you need to clean up critical resources, you can specify an interrupt + * handler function. + */ + +/** + * SECTION:glk-tick + * @short_description: Yielding time to the operating system + * @include: glk.h + * + * Many platforms have some annoying thing that has to be done every so often, + * or the gnurrs come from the voodvork out and eat your computer. + * + * Well, not really. But you should call glk_tick() every so often, just in + * case. It may be necessary to yield time to other applications in a + * cooperative-multitasking OS, or to check for player interrupts in an infinite + * loop. + */ + +/** + * SECTION:glk-types + * @short_description: Basic types used in Glk + * @include: glk.h + * + * For simplicity, all the arguments used in Glk calls are of a very few types. + * + * + * 32-bit unsigned integer + * Unsigned integers are used wherever possible, which is + * nearly everywhere. This type is called #glui32. + * + * + * 32-bit signed integer + * This type is called #glsi32. Rarely used. + * + * + * + * References to library objects + * These are pointers to opaque C structures; each library + * will use different structures, so you can not and should not try to + * manipulate their contents. See Opaque Objects. + * + * + * Pointer to one of the above types + * Pointer to a structure which consists entirely of the + * above types. + * + * + * unsigned char + * This is used only for Latin-1 text characters; see + * Character Encoding. + * + * + * + * Pointer to char + * Sometimes this means a null-terminated string; sometimes + * an unterminated buffer, with length as a separate #glui32 argument. The + * documentation says which. + * + * + * Pointer to void + * When nothing else will do. + * + * + */ + +/** + * SECTION:glk-opaque-objects + * @short_description: Complex objects in Glk + * @include: glk.h + * + * Glk keeps track of a few classes of special objects. These are opaque to your + * program; you always refer to them using pointers to opaque C structures. + * + * Currently, these classes are: + * + * + * Windows + * Screen panels, used to input or output information. + * + * + * + * Streams + * Data streams, to which you can input or output text. + * + * There are file streams and window streams, since you can + * output data to windows or files. + * + * + * + * File references + * Pointers to files in permanent storage. + * In Unix a file reference is a pathname; on the Mac, an + * FSSpec. Actually there's a little more information included, + * such as file type and whether it is a text or binary file. + * + * + * + * Sound channels + * Audio output channels. + * Not all Glk libraries support sound. + * + * + * + * + * + * Note that there may be more object classes in future versions of the Glk API. + * + * + * When you create one of these objects, it is always possible that the creation + * will fail (due to lack of memory, or some other OS error.) When this happens, + * the allocation function will return %NULL (0) instead of a valid pointer. You + * should always test for this possibility. + * + * %NULL is never the identifier of any object (window, stream, file reference, + * or sound channel). The value %NULL is often used to indicate no + * object or nothing, but it is not a valid reference. If + * a Glk function takes an object reference as an argument, it is illegal to + * pass in %NULL unless the function definition says otherwise. + * + * The glk.h file defines types + * #winid_t, #strid_t, #frefid_t, #schanid_t to store references. These are + * pointers to struct #glk_window_struct, #glk_stream_struct, + * #glk_fileref_struct, and #glk_schannel_struct respectively. It is, of course, + * illegal to pass one kind of pointer to a function which expects another. + * + * + * This is how you deal with opaque objects from a C program. If you are using + * Glk through a virtual machine, matters will probably be different. Opaque + * objects may be represented as integers, or as VM objects of some sort. + * + * + * Rocks + * + * Every one of these objects (window, stream, file reference, or sound channel) + * has a rock value. This is simply a 32-bit integer value which + * you provide, for your own purposes, when you create the object. + * + * The library — so to speak — stuffs this value under a + * rock for safe-keeping, and gives it back to you when you ask for it. + * + * If you don't know what to use the rocks for, provide 0 and forget + * about it. + * + * + * Iteration Through Opaque Objects + * + * For each class of opaque objects, there is an iterate function, which you can + * use to obtain a list of all existing objects of that class. It takes the form + * + * CLASSid_t glk_CLASS_iterate(CLASSid_t obj, #glui32 *rockptr); + * + * ...where CLASS represents one of the + * opaque object classes. + * + * + * So, at the current time, these are the functions glk_window_iterate(), + * glk_stream_iterate(), glk_fileref_iterate(), and glk_schannel_iterate(). + * There may be more classes in future versions of the spec; they all behave + * the same. + * + * + * Calling glk_CLASS_iterate(%NULL, r) + * returns the first object; calling + * glk_CLASS_iterate(obj, r) returns + * the next object, until there aren't any more, at which time it returns %NULL. + * + * + * The @rockptr argument is a pointer to a location; whenever + * glk_CLASS_iterate() returns an + * object, the object's rock is stored in the location (*@rockptr). + * If you don't want the rocks to be returned, you may set @rockptr to %NULL. + * + * + * You usually use this as follows: + * + * obj = glk_CLASS_iterate(NULL, NULL); + * while (obj) { + * /* ...do something with obj... */ + * obj = glk_CLASS_iterate(obj, NULL); + * } + * + * + * + * If you create or destroy objects inside this loop, obviously, the results are + * unpredictable. However it is always legal to call + * glk_CLASS_iterate(obj, r) as long as + * @obj is a valid object id, or %NULL. + * + * + * The order in which objects are returned is entirely arbitrary. The library + * may even rearrange the order every time you create or destroy an object of + * the given class. As long as you do not create or destroy any object, the rule + * is that glk_CLASS_iterate(obj, r) has + * a fixed result, and iterating through the results as above will list every + * object exactly once. + * + * + */ + +/** + * SECTION:glk-gestalt + * @short_description: Testing Glk's capabilities + * @include: glk.h + * + * 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. + */ + +/** + * SECTION:glk-character-input + * @short_description: Waiting for a single keystroke + * @include: glk.h + * + * You can request that the player hit a single key. See Character Input Events. + * + * If you use the basic text API, the character code which is returned can be + * any value from 0 to 255. The printable character codes have already been + * described. The remaining codes are typically control codes: control + * A to controlZ and a few + * others. + * + * There are also a number of special codes, representing special keyboard + * keys, which can be returned from a char-input event. These are represented + * as 32-bit integers, starting with 4294967295 (0xFFFFFFFF) and working down. + * The special key codes are defined in the glk.h file. They include one code for return or enter, + * one for delete or backspace, twelve function keys, and one code + * for any key which has no Latin-1 or special code. The full list of key codes + * is included below. + * + * Various implementations of Glk will vary widely in which characters the + * player can enter. The most obvious limitation is that some characters are + * mapped to others. For example, most keyboards return a controlI + * code when the tab key is + * pressed. The Glk library, if it can recognize this at all, will generate a + * #keycode_Tab event (value 0xFFFFFFF7) when this occurs. + * Therefore, for these keyboards, no keyboard key will generate a controlI + * event (value 9.) The Glk library will probably map many of the + * control codes to the other special keycodes. + * + * + * On the other hand, the library may be very clever and discriminate between + * tab and controlI. This is + * legal. The idea is, however, that if your program asks the player to + * press the tab + * key, you should check for a + * #keycode_Tab event as opposed to a control + * I event. + * + * + * Some characters may not be enterable simply because they do not exist. + * + * + * Not all keyboards have a home or end key. A pen-based platform may not recognize + * any control characters at all. + * + * + * Some characters may not be enterable because they are reserved for the + * purposes of the interface. For example, the Mac Glk library reserves the + * tab key for switching between different Glk + * windows. Therefore, on the Mac, the library will never generate a + * #keycode_Tab event or a + * controlI + * event. + * + * + * Note that the linefeed or controlJ + * character, which is the only printable control character, is probably not + * typable. This is because, in most libraries, it will be converted to + * #keycode_Return. Again, you should check for + * #keycode_Return if your program asks the player to + * press the return + * key. + * + * + * + * The delete and backspace keys are merged into a single + * keycode because they have such an astonishing history of being confused in + * the first place... this spec formally waives any desire to define the + * difference. Of course, a library is free to distinguish delete and backspace during line input. This is when it + * matters most; conflating the two during character input should not be a + * large problem. + * + * + * You can test for this by using the #gestalt_CharInput selector. + * + * + * Glk porters take note: it is not a goal to be able to generate every + * single possible key event. If the library says that it can generate a + * particular keycode, then game programmers will assume that it is + * available, and ask players to use it. If a #keycode_Home + * event can only be generated by typing escapecontrolA + * , and the player does not know this, the player will be lost + * when the game says Press the home key to see the next + * hint. It is better for the library to say that it + * cannot generate a #keycode_Home event; that way the game + * can detect the situation and ask the user to type H + * instead. + * + * + * Of course, it is better not to rely on obscure keys in any case. The arrow + * keys and return are nearly certain to be + * available; the others are of gradually decreasing reliability, and you + * (the game programmer) should not depend on them. You must be certain to + * check for the ones you want to use, including the arrow keys and return, and be prepared to use different keys in + * your interface if #gestalt_CharInput says they are not available. + * + */ + +/** + * SECTION:glk-case + * @short_description: Changing the case of strings + * @include: glk.h + * + * Glk has functions to manipulate the case of both Latin-1 and Unicode strings. + * One Latin-1 lowercase character corresponds to one uppercase character, and + * vice versa, so the Latin-1 functions act on single characters. The Unicode + * functions act on whole strings, since the length of the string may change. + */ + +/** + * SECTION:glk-window-opening + * @short_description: Creating new windows and closing them + * @include: glk.h + * + * You can open a new window using glk_window_open() and close it again using + * glk_window_close(). + */ + +/** + * SECTION:glk-window-constraints + * @short_description: Manipulating the size of a window + * @include: glk.h + * + * There are library functions to change and to measure the size of a window. + */ + +/** + * SECTION:glk-window-types + * @short_description: Blank, pair, text grid, text buffer, and graphics windows + * @include: glk.h + * + * A technical description of all the window types, and exactly how they behave. + */ + +/** + * SECTION:glk-echo-streams + * @short_description: Creating a copy of a window's output + * @include: glk.h + * + * Every window has an associated window stream; you print to the window by + * printing to this stream. However, it is possible to attach a second stream to + * a window. Any text printed to the window is also echoed to this second + * stream, which is called the window's echo stream. + * + * Effectively, any call to glk_put_char() (or the other output commands) which + * is directed to the window's window stream, is replicated to the window's echo + * stream. This also goes for the style commands such as glk_set_style(). + * + * Note that the echoing is one-way. You can still print text directly to the + * echo stream, and it will go wherever the stream is bound, but it does not + * back up and appear in the window. + * + * An echo stream can be of any type, even another window's window stream. + * + * + * This would be somewhat silly, since it would mean that any text printed to + * the window would be duplicated in another window. More commonly, you would + * set a window's echo stream to be a file stream, in order to create a + * transcript file from that window. + * + * + * A window can only have one echo stream. But a single stream can be the echo + * stream of any number of windows, sequentially or simultaneously. + * + * If a window is closed, its echo stream remains open; it is not automatically + * closed. + * + * + * Do not confuse the window's window stream with its echo stream. The window + * stream is owned by the window, and dies with it. The echo + * stream is merely temporarily associated with the window. + * + * + * If a stream is closed, and it is the echo stream of one or more windows, + * those windows are reset to not echo anymore. (So then calling + * glk_window_get_echo_stream() on them will return %NULL.) + */ + +/** + * SECTION:glk-window-other + * @short_description: Miscellaneous functions for windows + * @include: glk.h + * + * This section contains functions for windows that don't fit anywhere else. + */ + +/** + * SECTION:glk-events + * @short_description: Waiting for events + * @include: glk.h + * + * As described in Your + * Program's Main Function, all player input is handed to your program by + * the glk_select() call, in the form of events. You should write at least one + * event loop to retrieve these events. + */ + +/** + * SECTION:glk-character-input-events + * @short_description: Events representing a single keystroke + * @include: glk.h + * + * You can request character input from text buffer and text grid windows. See + * #evtype_CharInput. There are separate functions for requesting Latin-1 input + * and Unicode input; see #gestalt_Unicode. + */ + +/** + * SECTION:glk-line-input-events + * @short_description: Events representing a line of user input + * @include: glk.h + * + * You can request line input from text buffer and text grid windows. See + * #evtype_LineInput. There are separate functions for requesting Latin-1 input + * and Unicode input; see #gestalt_Unicode. + */ + +/** + * SECTION:glk-streams + * @short_description: Input and output abstractions + * @include: glk.h + * + * All character output in Glk is done through streams. Every window has an + * output stream associated with it. You can also write to files on disk; every + * open file is represented by an output stream as well. + * + * There are also input streams; these are used for reading from files on disk. + * It is possible for a stream to be both an input and an output stream. + * + * + * Player input is done through line and character input events, not streams. + * This is a small inelegance in theory. In practice, player input is slow and + * things can interrupt it, whereas file input is immediate. If a network + * extension to Glk were proposed, it would probably use events and not + * streams, since network communication is not immediate. + * + * + * It is also possible to create a stream that reads or writes to a buffer in + * memory. + * + * Finally, there may be platform-specific types of streams, which are created + * before your program starts running. + * + * + * For example, a program running under Unix may have access to standard input + * as a stream, even though there is no Glk call to explicitly open standard + * input. On the Mac, data in a Mac resource may be available through a + * resource-reading stream. + * + * + * You do not need to worry about the origin of such streams; just read or write + * them as usual. For information about how platform-specific streams come to + * be, see Startup Options. + * + * A stream is opened with a particular file mode, see the + * filemode_ constants below. + * + * For information on opening streams, see the discussion of each specific type + * of stream in The Types of + * Streams. Remember that it is always possible that opening a stream + * will fail, in which case the creation function will return %NULL. + * + * Each stream remembers two character counts, the number of characters printed + * to and read from that stream. The write-count is exactly one per + * glk_put_char() call; it is figured before any platform-dependent character + * cookery. + * + * + * For example, if a newline character is converted to + * linefeed-plus-carriage-return, the stream's count still only goes up by + * one; similarly if an accented character is displayed as two characters. + * + * + * The read-count is exactly one per glk_get_char_stream() call, as long as the + * call returns an actual character (as opposed to an end-of-file token.) + * + * Glk has a notion of the current (output) stream. If you print + * text without specifying a stream, it goes to the current output stream. The + * current output stream may be %NULL, meaning that there isn't one. It is + * illegal to print text to stream %NULL, or to print to the current stream when + * there isn't one. + * + * If the stream which is the current stream is closed, the current stream + * becomes %NULL. + */ + +/** + * SECTION:glk-print + * @short_description: Printing to streams + * @include: glk.h + * + * You can print Latin-1 and Unicode characters, null-terminated strings, or + * buffers to any stream. The characters will be converted into the appropriate + * format for that stream. + */ + +/** + * SECTION:glk-read + * @short_description: Reading from streams + * @include: glk.h + * + * You can read Latin-1 or Unicode characters, buffers, or whole lines from any + * stream. The characters will be converted into the form in which you request + * them. + */ + +/** + * SECTION:glk-closing-streams + * @short_description: Closing streams and retrieving their character counts + * @include: glk.h + * + * When you close a Glk stream, you have the opportunity to examine the + * character counts — the number of characters written to or read from the + * stream. + */ + +/** + * SECTION:glk-stream-positions + * @short_description: Moving the read/write mark + * @include: glk.h + * + * You can set the position of the read/write mark in a stream. + * + * + * Which makes one wonder why they're called streams in the + * first place. Oh well. + * + */ + +/** + * SECTION:glk-stream-types + * @short_description: Window, memory, and file streams + * @include: glk.h + * + * Window Streams + * + * Every window has an output stream associated with it. This is created + * automatically, with #filemode_Write, when you open the window. You get it + * with glk_window_get_stream(). + * + * A window stream cannot be closed with glk_stream_close(). It is closed + * automatically when you close its window with glk_window_close(). + * + * Only printable characters (including newline) may be printed to a window + * stream. See Character + * Encoding. + * + * + * Memory Streams + * + * You can open a stream which reads from or writes to a space in memory. See + * glk_stream_open_memory() and glk_stream_open_memory_uni(). When opening a + * memory stream, you specify a buffer to which the stream's output will be + * written, and its length @buflen. + * + * When outputting, if more than @buflen characters are written to the stream, + * all of them beyond the buffer length will be thrown away, so as not to + * overwrite the buffer. (The character count of the stream will still be + * maintained correctly. That is, it will count the number of characters written + * into the stream, not the number that fit into the buffer.) + * + * If the buffer is %NULL, or for that matter if @buflen is zero, then + * everything written to the stream is thrown away. This + * may be useful if you are interested in the character count. + * + * When inputting, if more than @buflen characters are read from the stream, the + * stream will start returning -1 (signalling end-of-file.) If the buffer is + * %NULL, the stream will always return end-of-file. + * + * The data is written to the buffer exactly as it was passed to the printing + * functions (glk_put_char(), etc.); input functions will read the data exactly + * as it exists in memory. No platform-dependent cookery will be done on it. + * + * + * You can write a disk file in text mode, but a memory stream is effectively + * always in binary mode. + * + * + * Whether reading or writing, the contents of the buffer are undefined until + * the stream is closed. The library may store the data there as it is written, + * or deposit it all in a lump when the stream is closed. It is illegal to + * change the contents of the buffer while the stream is open. + * + * + * File Streams + * + * You can open a stream which reads from or writes to a disk file. See + * glk_stream_open_file() and glk_stream_open_file_uni(). + * + * The file may be written in text or binary mode; this is determined by the + * file reference you open the stream with. Similarly, platform-dependent + * attributes such as file type are determined by the file reference. See File References. + * + * + */ + +/** + * SECTION:glk-stream-other + * @short_description: Miscellaneous functions for streams + * @include: glk.h + * + * This section includes functions for streams that don't fit anywhere else. + */ + +/** + * SECTION:glk-fileref + * @short_description: A platform-independent way to refer to disk files + * @include: glk.h + * + * You deal with disk files using file references. Each fileref is an opaque C + * structure pointer; see Opaque + * Objects. + * + * A file reference contains platform-specific information about the name and + * location of the file, and possibly its type, if the platform has a notion of + * file type. It also includes a flag indication whether the file is a text file + * or binary file. + * + * + * Note that this is different from the standard C I/O library, in which you + * specify text or binary mode when the file is opened. + * + * + * A fileref does not have to refer to a file which actually exists. You can + * create a fileref for a nonexistent file, and then open it in write mode to + * create a new file. + * + * You always provide a usage argument when you create a fileref. The usage is a + * mask of constants (see below) to indicate the file type and the mode (text or + * binary.) These values are used when you create a new file, and also to filter + * file lists when the player is selecting a file to load. + * + * In general, you should use text mode if the player expects to read the file + * with a platform-native text editor; you should use binary mode if the file is + * to be read back by your program, or if the data must be stored exactly. Text + * mode is appropriate for #fileusage_Transcript; binary mode is appropriate for + * #fileusage_SavedGame and probably for #fileusage_InputRecord. #fileusage_Data + * files may be text or binary, depending on what you use them for. + */ + +/** + * SECTION:glk-fileref-types + * @short_description: Four different ways to create a file reference + * @include: glk.h + * + * There are four different functions for creating a fileref, depending on how + * you wish to specify it. Remember that it is always possible that a fileref + * creation will fail and return %NULL. + */ + +/** + * SECTION:glk-fileref-other + * @short_description: Miscellaneous functions for file references + * @include: glk.h + * + * This section includes functions for file references that don't fit anywhere + * else. + */ + +/*---------------- TYPES AND CONSTANTS FROM GLK.H ----------------------------*/ + +/** + * glui32: + * + * A 32-bit unsigned integer type, used wherever possible in Glk. + */ + +/** + * glsi32: + * + * A 32-bit signed integer type, rarely used. + */ + +/** + * GLK_MODULE_UNICODE: + * + * If this preprocessor symbol is defined, so are all the Unicode functions and + * constants (see #gestalt_Unicode). If not, not. + */ + +/** + * winid_t: + * + * Opaque structure representing a Glk window. It has no user-accessible + * members. + */ + +/** + * strid_t: + * + * Opaque structure representing an input or output stream. It has no + * user-accessible members. + */ + +/** + * frefid_t: + * + * Opaque structure representing a file reference. It has no user-accessible + * members. + */ + +/** + * gestalt_Version: + * + * For an example of the gestalt mechanism, consider the selector + * #gestalt_Version. If you do + * + * #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.0, so this selector will return + * 0x00000700. + * + * + * #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. + */ + +/** + * gestalt_CharInput: + * + * If you set ch to a character code, or a special code (from + * 0xFFFFFFFF down), and call + * + * #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. + */ + +/** + * gestalt_LineInput: + * + * If you set ch to a character code, and call + * + * #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. + */ + +/** + * gestalt_CharOutput: + * + * If you set ch to a character code (Latin-1 or higher), and call + * + * #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 + * char variable ch to 0xFE, the + * small-thorn character (þ), and then call + * + * 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 + * + * 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. + * + */ + +/** + * gestalt_CharOutput_CannotPrint: + * + * 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. + */ + +/** + * gestalt_CharOutput_ApproxPrint: + * + * 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 (¦).) + */ + +/** + * gestalt_CharOutput_ExactPrint: + * + * When the #gestalt_CharOutput selector returns this for a character, the + * character will be printed exactly as defined. + */ + +/** + * gestalt_Unicode: + * + * 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 following gestalt selector: + * + * glui32 res; + * res = #glk_gestalt(#gestalt_Unicode, 0); + * + * + * This returns 1 if the 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. + */ + +/** + * evtype_None: + * + * No event. This is a placeholder, and glk_select() never returns it. + */ + +/** + * evtype_Timer: + * + * An event that repeats at fixed intervals. See Timer Events. + */ + +/** + * evtype_CharInput: + * + * A keystroke event in a window. See Character Input Events. + * + * If a window has a pending request for character input, and the player hits a + * key in that window, glk_select() will return an event whose type is + * #evtype_CharInput. Once this happens, the request is complete; it is no + * longer pending. You must call glk_request_char_event() or + * glk_request_char_event_uni() if you want another character from that window. + * + * In the event structure, @win tells what window the event came from. @val1 + * tells what character was entered; this will be a character code, or a special + * keycode. (See Character + * Input.) If you called glk_request_char_event(), @val1 will be in + * 0..255, or else a special keycode. In any case, @val2 will be 0. + */ + +/** + * evtype_LineInput: + * + * A full line of input completed in a window. See Line Input Events. + * + * If a window has a pending request for line input, and the player hits + * enter in that window (or whatever action is appropriate to + * enter his input), glk_select() will return an event whose type is + * #evtype_LineInput. Once this happens, the request is complete; it is no + * longer pending. You must call glk_request_line_event() if you want another + * line of text from that window. + * + * In the event structure, @win tells what window the event came from. @val1 + * tells how many characters were entered. @val2 will be 0. The characters + * themselves are stored in the buffer specified in the original + * glk_request_line_event() or glk_request_line_event_uni() call. + * + * There is no null terminator stored in the buffer. + * + * It is illegal to print anything to a window which has line input pending. + * + * + * This is because the window may be displaying and editing the player's + * input, and printing anything would make life unnecessarily complicated for + * the library. + * + */ + +/** + * evtype_MouseInput: + * + * A mouse click in a window. See Mouse Input Events. + */ + +/** + * evtype_Arrange: + * + * An event signalling that the sizes of some windows have changed. + * + * Some platforms allow the player to resize the Glk window during play. This + * will naturally change the sizes of your windows. If this occurs, then + * immediately after all the rearrangement, glk_select() will return an event + * whose type is #evtype_Arrange. You can use this notification to redisplay the + * contents of a graphics or text grid window whose size has changed. + * + * + * The display of a text buffer window is entirely up to the library, so you + * don't need to worry about those. + * + * + * In the event structure, @win will be %NULL if all windows are affected. If + * only some windows are affected, @win will refer to a window which contains + * all the affected windows. @val1 and @val2 will be 0. + * + * + * You can always play it safe, ignore @win, and redraw every graphics and + * text grid window. + * + * + * An arrangement event is guaranteed to occur whenever the player causes any + * window to change size, as measured by its own metric. + * + * + * Size changes caused by you — for example, if you open, close, or + * resize a window — do not trigger arrangement events. You must be + * aware of the effects of your window management, and redraw the windows that + * you affect. + * + * + * + * It is possible that several different player actions can cause windows to + * change size. For example, if the player changes the screen resolution, an + * arrangement event might be triggered. This might also happen if the player + * changes his display font to a different size; the windows would then be + * different sizes in the metric of rows and columns, which is + * the important metric and the only one you have access to. + * + * + * Arrangement events, like timer events, can be returned by glk_select_poll(). + * But this will not occur on all platforms. You must be ready to receive an + * arrangement event when you call glk_select_poll(), but it is possible that it + * will not arrive until the next time you call glk_select(). + * + * + * This is because on some platforms, window resizing is handled as part of + * player input; on others, it can be triggered by an external process such as + * a window manager. + * + */ + +/** + * evtype_Redraw: + * + * An event signalling that graphics windows must be redrawn. + * + * On platforms that support graphics, it is possible that the contents of a + * graphics window will be lost, and have to be redrawn from scratch. If this + * occurs, then glk_select() will return an event whose type is #evtype_Redraw. + * + * In the event structure, @win will be %NULL if all windows are affected. If + * only some windows are affected, @win will refer to a window which contains + * all the affected windows. @val1 and @val2 will be 0. + * + * + * You can always play it safe, ignore @win, and redraw every graphics window. + * + * + * Affected windows are already cleared to their background color when you + * receive the redraw event. + * + * Redraw events can be returned by glk_select_poll(). But, like arrangement + * events, this is platform-dependent. See #evtype_Arrange. + * + * For more about redraw events and how they affect graphics windows, see Graphics Windows. + */ + +/** + * evtype_SoundNotify: + * + * On platforms that support sound, you can request to receive an + * #evtype_SoundNotify event when a sound finishes playing. See Playing Sounds. + */ + +/** + * evtype_Hyperlink: + * + * On platforms that support hyperlinks, you can request to receive an + * #evtype_Hyperlink event when the player selects a link. See Accepting Hyperlink + * Events. + */ + +/** + * event_t: + * @type: the event type + * @win: the window that spawned the event, or %NULL + * @val1: information, the meaning of which depends on the type of event + * @val2: more information, the meaning of which depends on the type of event + * + * The event structure is self-explanatory. @type is the event type. The window + * that spawned the event, if relevant, is in @win. The remaining fields contain + * more information specific to the event. + * + * The event types are described below. Note that #evtype_None is zero, and the + * other values are positive. Negative event types (0x80000000 to 0xFFFFFFFF) + * are reserved for implementation-defined events. + */ + +/** + * keycode_Unknown: + * + * Represents any key that has no Latin-1 or special code. + */ + +/** + * keycode_Left: + * + * Represents the left arrow key. + */ + +/** + * keycode_Right: + * + * Represents the right arrow key. + */ + +/** + * keycode_Up: + * + * Represents the up arrow key. + */ + +/** + * keycode_Down: + * + * Represents the down arrow key. + */ + +/** + * keycode_Return: + * + * Represents the return or enter keys. + */ + +/** + * keycode_Delete: + * + * Represents the delete or backspace keys. + */ + +/** + * keycode_Escape: + * + * Represents the escape key. + */ + +/** + * keycode_Tab: + * + * Represents the tab key. + */ + +/** + * keycode_PageUp: + * + * Represents the page up key. + */ + +/** + * keycode_PageDown: + * + * Represents the page down key. + */ + +/** + * keycode_Home: + * + * Represents the home key. + */ + +/** + * keycode_End: + * + * Represents the end key. + */ + +/** + * keycode_Func1: + * + * Represents the F1 key. + */ + +/** + * keycode_Func2: + * + * Represents the F2 key. + */ + +/** + * keycode_Func3: + * + * Represents the F3 key. + */ + +/** + * keycode_Func4: + * + * Represents the F4 key. + */ + +/** + * keycode_Func5: + * + * Represents the F5 key. + */ + +/** + * keycode_Func6: + * + * Represents the F6 key. + */ + +/** + * keycode_Func7: + * + * Represents the F7 key. + */ + +/** + * keycode_Func8: + * + * Represents the F8 key. + */ + +/** + * keycode_Func9: + * + * Represents the F9 key. + */ + +/** + * keycode_Func10: + * + * Represents the F10 key. + */ + +/** + * keycode_Func11: + * + * Represents the F11 key. + */ + +/** + * keycode_Func12: + * + * Represents the F12 key. + */ + +/** + * keycode_MAXVAL: + * + * This value is equal to the number of special keycodes. The last keycode is + * The last keycode is always + * + * (0x100000000 - keycode_MAXVAL) + * (0x100000000 - keycode_MAXVAL) + * + * . + */ + +/** + * stream_result_t: + * @readcount: Number of characters read from the stream. + * @writecount: Number of characters printed to the stream, including ones that + * were thrown away. + * + * If you are interested in the character counts of a stream (see Streams), then you can pass a pointer to + * #stream_result_t as an argument of glk_stream_close() or glk_window_close(). + * The structure will be filled with the stream's final character counts. + */ + +/** + * wintype_AllTypes: + * + * A constant representing all window types, which may be used as the @wintype + * argument in glk_stylehint_set(). + */ + +/** + * wintype_Pair: + * + * A pair window is completely filled by the two windows it contains. It + * supports no input and no output, and it has no size. + * + * You cannot directly create a pair window; one is automatically created + * every time you split a window with glk_window_open(). Pair windows are + * always created with a rock value of 0. + * + * You can close a pair window with glk_window_close(); this also closes every + * window contained within the pair window. + * + * It is legal to split a pair window when you call glk_window_open(). + */ + +/** + * wintype_Blank: + * + * A blank window is always blank. It supports no input and no output. (You + * can call glk_window_get_stream() on it, as you can with any window, but + * printing to the resulting stream has no effect.) A blank window has no + * size; glk_window_get_size() will return (0,0), and it is illegal to set a + * window split with a fixed size in the measurement system of a blank window. + * + * + * A blank window is not the same as there being no windows. When Glk starts + * up, there are no windows at all, not even a window of the blank type. + * + */ + +/** + * wintype_TextBuffer: + * + * A text buffer window contains a linear stream of text. It supports output; + * when you print to it, the new text is added to the end. There is no way for + * you to affect text which has already been printed. There are no guarantees + * about how much text the window keeps; old text may be stored forever, so + * that the user can scroll back to it, or it may be thrown away as soon as it + * scrolls out of the window. + * + * + * Therefore, there may or may not be a player-controllable scroll bar or + * other scrolling widget. + * + * + * The display of the text in a text buffer is up to the library. Lines will + * probably not be broken in the middles of words — but if they are, the + * library is not doing anything illegal, only ugly. Text selection and copying + * to a clipboard, if available, are handled however is best on the player's + * machine. Paragraphs (as defined by newline characters in the output) may be + * indented. + * + * + * You should not, in general, fake this by printing spaces before each + * paragraph of prose text. Let the library and player preferences handle + * that. Special cases (like indented lists) are of course up to you. + * + * + * When a text buffer is cleared (with glk_window_clear()), the library will do + * something appropriate; the details may vary. It may clear the window, with + * later text appearing at the top — or the bottom. It may simply print + * enough blank lines to scroll the current text out of the window. It may + * display a distinctive page-break symbol or divider. + * + * The size of a text buffer window is necessarily imprecise. Calling + * glk_window_get_size() will return the number of rows and columns that would + * be available if the window was filled with + * 0 (zero) characters in the normal font. + * However, the window may use a non-fixed-width font, so that number of + * characters in a line could vary. The window might even support + * variable-height text (say, if the player is using large text for emphasis); + * that would make the number of lines in the window vary as well. + * + * Similarly, when you set a fixed-size split in the measurement system of a + * text buffer, you are setting a window which can handle a fixed number of rows + * (or columns) of 0 characters. The number of rows (or + * characters) that will actually be displayed depends on font variances. + * + * A text buffer window supports both character and line input, but not mouse + * input. + * + * In character input, there will be some visible signal that the window is + * waiting for a keystroke. (Typically, a cursor at the end of the text.) When + * the player hits a key in that window, an event is generated, but the key is + * not printed in the window. + * + * In line input, again, there will be some visible signal. It is most common + * for the player to compose input in the window itself, at the end of the text. + * (This is how IF story input usually looks.) But it's not strictly required. + * An alternative approach is the way MUD clients usually work: there is a + * dedicated one-line input window, outside of Glk's window space, and the user + * composes input there. + * + * + * If this approach is used, there will still be some way to handle input from + * two windows at once. It is the library's responsibility to make this + * available to the player. You only need request line input and wait for the + * result. + * + * + * When the player finishes his line of input, the library will display the + * input text at the end of the buffer text (if it wasn't there already.) It + * will be followed by a newline, so that the next text you print will start a + * new line (paragraph) after the input. + * + * If you call glk_cancel_line_event(), the same thing happens; whatever text + * the user was composing is visible at the end of the buffer text, followed by + * a newline. + */ + +/** + * wintype_TextGrid: + * + * A text grid contains a rectangular array of characters, in a fixed-width + * font. Its size is the number of columns and rows of the array. + * + * A text grid window supports output. It maintains knowledge of an output + * cursor position. When the window is opened, it is filled with blanks (space + * characters), and the output cursor starts in the top left corner — + * character (0,0). If the window is cleared with glk_window_clear(), the window + * is filled with blanks again, and the cursor returns to the top left corner. + * + * When you print, the characters of the output are laid into the array in + * order, left to right and top to bottom. When the cursor reaches the end of a + * line, it goes to the beginning of the next line. The library makes no attempt + * to wrap lines at word breaks. + * + * + * Note that printing fancy characters may cause the cursor to advance more + * than one position per character. (For example, the æ + * ligature may print as two characters.) See Output, for how to test this situation. + * + * + * You can set the cursor position with glk_window_move_cursor(). + * + * When a text grid window is resized smaller, the bottom or right area is + * thrown away, but the remaining area stays unchanged. When it is resized + * larger, the new bottom or right area is filled with blanks. + * + * + * You may wish to watch for #evtype_Arrange events, and clear-and-redraw your + * text grid windows when you see them change size. + * + * + * Text grid window support character and line input, as well as mouse input (if + * a mouse is available.) + * + * Mouse input returns the position of the character that was touched, from + * (0,0) to + * + * (width-1,height-1) + * (width - 1, height - 1) + * + * . + * + * Character input is as described in the previous section. + * + * Line input is slightly different; it is guaranteed to take place in the + * window, at the output cursor position. The player can compose input only to + * the right edge of the window; therefore, the maximum input length is + * + * (windowwidth - 1 - cursorposition) + * (windowwidth - 1 - cursorposition) + * + * . If the maxlen argument of glk_request_line_event() is smaller than this, + * the library will not allow the input cursor to go more than maxlen characters + * past its start point. + * + * + * This allows you to enter text in a fixed-width field, without the player + * being able to overwrite other parts of the window. + * + * + * When the player finishes his line of input, it will remain visible in the + * window, and the output cursor will be positioned at the beginning of the + * next row. Again, if you glk_cancel_line_event(), the + * same thing happens. + */ + +/** + * wintype_Graphics: + * + * A graphics window contains a rectangular array of pixels. Its size is the + * number of columns and rows of the array. + * + * Each graphics window has a background color, which is initially white. You + * can change this; see Graphics in Graphics + * Windows. + * + * When a text grid window is resized smaller, the bottom or right area is + * thrown away, but the remaining area stays unchanged. When it is resized + * larger, the new bottom or right area is filled with the background color. + * + * + * You may wish to watch for #evtype_Arrange events, and clear-and-redraw your + * graphics windows when you see them change size. + * + * + * In some libraries, you can receive a graphics-redraw event (#evtype_Redraw) + * at any time. This signifies that the window in question has been cleared to + * its background color, and must be redrawn. If you create any graphics + * windows, you must handle these events. + * + * + * Redraw events can be triggered when a Glk window is uncovered or made + * visible by the platform's window manager. On the other hand, some Glk + * libraries handle these problem automatically — for example, with a + * backing store — and do not send you redraw events. On the third hand, + * the backing store may be discarded if memory is low, or for other reasons + * — perhaps the screen's color depth has changed. So redraw events are + * always a possibility, even in clever libraries. This is why you must be + * prepared to handle them. + * + * However, you will not receive a redraw event when you create a graphics + * window. It is assumed that you will do the initial drawing of your own + * accord. You also do not get redraw events when a graphics window is + * enlarged. If you ordered the enlargement, you already know about it; if the + * player is responsible, you receive a window-arrangement event, which covers + * the situation. + * + * + * For a description of the drawing functions that apply to graphics windows, + * see Graphics in Graphics + * Windows. + * + * Graphics windows support no text input or output. + * + * Not all libraries support graphics windows. You can test whether Glk graphics + * are available using the gestalt system. In a C program, you can also test + * whether the graphics functions are defined at compile-time. See Testing for Graphics + * Capabilities. + * + * + * As with all windows, you should also test for %NULL when you create a + * graphics window. + * + */ + +/** + * winmethod_Left: + * + * When calling glk_window_open() with this @method, the new window will be + * to the left of the old one which was split. + */ + +/** + * winmethod_Right: + * + * When calling glk_window_open() with this @method, the new window will be + * to the right of the old one which was split. + */ + +/** + * winmethod_Above: + * + * When calling glk_window_open() with this @method, the new window will be + * above the old one which was split. + */ + +/** + * winmethod_Below: + * + * When calling glk_window_open() with this @method, the new window will be + * below the old one which was split. + */ + +/** + * winmethod_DirMask: + * + * Bitwise AND this value with a window splitting method argument to find + * whether the split is #winmethod_Left, #winmethod_Right, #winmethod_Above, or + * #winmethod_Below. + */ + +/** + * winmethod_Fixed: + * + * When calling glk_window_open() with this @method, the new window will be + * a fixed size. (See glk_window_open()). + */ + +/** + * winmethod_Proportional: + * + * When calling glk_window_open() with this @method, the new window will be + * a given proportion of the old window's size. (See glk_window_open()). + */ + +/** + * winmethod_DivisionMask: + * + * Bitwise AND this value with a window splitting method argument to find + * whether the new window has #winmethod_Fixed or #winmethod_Proportional. + */ + +/** + * fileusage_Data: + * + * Any other kind of file (preferences, statistics, arbitrary data.) + */ + +/** + * fileusage_SavedGame: + * + * A file which stores game state. + */ + +/** + * fileusage_Transcript: + * + * A file which contains a stream of text from the game (often an echo stream + * from a window.) + */ + +/** + * fileusage_InputRecord: + * + * A file which records player input. + */ + +/** + * fileusage_TextMode: + * + * The file contents will be transformed to a platform-native text file as they + * are written out. Newlines may be converted to linefeeds or + * linefeed-plus-carriage-return combinations; Latin-1 characters may be + * converted to native character codes. When reading a file in text mode, native + * line breaks will be converted back to newline (0x0A) characters, and native + * character codes may be converted to Latin-1. + * + * + * Line breaks will always be converted; other conversions are more + * questionable. If you write out a file in text mode, and then read it back + * in text mode, high-bit characters (128 to 255) may be transformed or lost. + * + * Chimara + * + * Text mode files in Chimara are in UTF-8, which is GTK+'s native file + * encoding. + * + */ + +/** + * fileusage_BinaryMode: + * + * The file contents will be stored exactly as they are written, and read back + * in the same way. The resulting file may not be viewable on platform-native + * text file viewers. + */ + +/** + * fileusage_TypeMask: + * + * Bitwise AND this value with a file usage argument to find whether the file + * type is #fileusage_SavedGame, #fileusage_Transcript, #fileusage_InputRecord, + * or #fileusage_Data. + */ + +/** + * filemode_Write: + * + * An output stream. + * + * + * Corresponds to mode "w" in the stdio library, using fopen(). + * + */ + +/** + * filemode_Read: + * + * An input stream. + * + * + * Corresponds to mode "r" in the stdio library, using fopen(). + * + */ + +/** + * filemode_ReadWrite: + * + * Both an input and an output stream. + * + * + * Corresponds to mode "r+" in the stdio library, using fopen(). + * + */ + +/** + * filemode_WriteAppend: + * + * An output stream, but the data will added to the end of whatever already + * existed in the destination, instead of replacing it. + * + * + * Corresponds to mode "a" in the stdio library, using fopen(). + * + */ + +/** + * seekmode_Start: + * + * In glk_stream_set_position(), signifies that @pos is counted in characters + * after the beginning of the file. + */ + +/** + * seekmode_Current: + * + * In glk_stream_set_position(), signifies that @pos is counted in characters + * after the current position (moving backwards if @pos is negative.) + */ + +/** + * seekmode_End: + * + * In glk_stream_set_position(), signifies that @pos is counted in characters + * after the end of the file. (@pos should always be zero or negative, so that + * this will move backwards to a position within the file. + */ + diff --git a/src/event.c b/src/event.c index a6837b1..8f34f6f 100644 --- a/src/event.c +++ b/src/event.c @@ -90,3 +90,4 @@ glk_select(event_t *event) /* If an abort event was generated, the thread should have exited by now */ g_assert(event->type != evtype_Abort); } + diff --git a/src/fileref.c b/src/fileref.c index be4f23f..1486e14 100644 --- a/src/fileref.c +++ b/src/fileref.c @@ -9,20 +9,14 @@ extern ChimaraGlkPrivate *glk_data; /** * glk_fileref_iterate: - * @fref: A file reference, or #NULL. - * @rockptr: Return location for the next window's rock, or #NULL. + * @fref: A file reference, or %NULL. + * @rockptr: Return location for the next fileref's rock, or %NULL. * - * Iterates over the list of file references; if @fref is #NULL, it returns the - * first file reference, otherwise the next file reference after @fref. If - * there are no more, it returns #NULL. The file reference's rock is stored in - * @rockptr. If you don't want the rocks to be returned, you may set @rockptr - * to #NULL. + * Iterates through all the existing filerefs. See Iterating Through Opaque + * Objects. * - * The order in which file references are returned is arbitrary. The order may - * change every time you create or destroy a file reference, invalidating the - * iteration. - * - * Returns: the next file reference, or #NULL if there are no more. + * Returns: the next file reference, or %NULL if there are no more. */ frefid_t glk_fileref_iterate(frefid_t fref, glui32 *rockptr) @@ -46,7 +40,8 @@ glk_fileref_iterate(frefid_t fref, glui32 *rockptr) * glk_fileref_get_rock: * @fref: A file reference. * - * Returns the file reference @fref's rock value. + * Retrieves the file reference @fref's rock value. See Rocks. * * Returns: A rock value. */ @@ -78,13 +73,17 @@ fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode) /** * glk_fileref_create_temp: - * @usage: Bitfield with one or more of the #fileusage_ constants. + * @usage: Bitfield with one or more of the fileusage_ constants. * @rock: The new fileref's rock value. * * Creates a reference to a temporary file. It is always a new file (one which * does not yet exist). The file (once created) will be somewhere out of the * player's way. * + * + * This is why no name is specified; the player will never need to know it. + * + * * A temporary file should never be used for long-term storage. It may be * deleted automatically when the program exits, or at some later time, say * when the machine is turned off or rebooted. You do not have to worry about @@ -121,18 +120,54 @@ glk_fileref_create_temp(glui32 usage, glui32 rock) /** * glk_fileref_create_by_prompt: - * @usage: Bitfield with one or more of the #fileusage_ constants. + * @usage: Bitfield with one or more of the fileusage_ constants. * @fmode: File mode, contolling the dialog's behavior. * @rock: The new fileref's rock value. * - * Creates a reference to a file by opening a file chooser dialog. If @fmode is - * #filemode_Read, then the file must already exist and the user will be asked - * to select from existing files. If @fmode is #filemode_Write, then the file - * should not exist; if the user selects an existing file, he or she will be - * warned that it will be replaced. If @fmode is #filemode_ReadWrite, then the - * file may or may not exist; if it already exists, the user will be warned - * that it will be modified. The @fmode argument should generally match the - * @fmode which will be used to open the file. + * Creates a reference to a file by asking the player to locate it. The library + * may simply prompt the player to type a name, or may use a platform-native + * file navigation tool. (The prompt, if any, is inferred from the usage + * argument.) + * + * Chimara + * + * Chimara uses a GtkFileChooserDialog. + * + * + * @fmode must be one of these values: + * + * + * #filemode_Read + * The file must already exist; and the player will be asked + * to select from existing files which match the usage. + * + * + * #filemode_Write + * The file should not exist; if the player selects an + * existing file, he will be warned that it will be replaced. + * + * + * + * #filemode_ReadWrite + * The file may or may not exist; if it already exists, the + * player will be warned that it will be modified. + * + * + * #filemode_WriteAppend + * Same behavior as #filemode_ReadWrite. + * + * + * + * The @fmode argument should generally match the @fmode which will be used to + * open the file. + * + * + * It is possible that the prompt or file tool will have a + * cancel option. If the player chooses this, + * glk_fileref_create_by_prompt() will return %NULL. This is a major reason + * why you should make sure the return value is valid before you use it. + * * * Returns: A new fileref, or #NULL if the fileref creation failed or the * dialog was canceled. @@ -202,14 +237,42 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) /** * glk_fileref_create_by_name: - * @usage: Bitfield with one or more of the #fileusage_ constants. + * @usage: Bitfield with one or more of the fileusage_ constants. * @name: A filename. * @rock: The new fileref's rock value. * * This creates a reference to a file with a specific name. The file will be - * in the same directory as your program, and visible to the player. + * in a fixed location relevant to your program, and visible to the player. + * + * + * This usually means in the same directory as your program. + * + * Chimara + * + * In Chimara, the file is created in the current working directory. + * * - * Returns: A new fileref, or #NULL if the fileref creation failed. + * Since filenames are highly platform-specific, you should use + * glk_fileref_create_by_name() with care. It is legal to pass any string in the + * name argument. However, the library may have to mangle, transform, or + * truncate the string to make it a legal native filename. + * + * + * For example, if you create two filerefs with the names File + * and FILE, they may wind up pointing to the same file; the + * platform may not support case distinctions in file names. Another example: + * on a platform where file type is specified by filename suffix, the library + * will add an appropriate suffix based on the usage; any suffix in the string + * will be overwritten or added to. For that matter, remember that the period + * is not a legal character in Acorn filenames... + * + * + * The most conservative approach is to pass a string of no more than 8 + * characters, consisting entirely of upper-case letters and numbers, starting + * with a letter. You can then be reasonably sure that the resulting filename + * will display all the characters you specify — in some form. + * + * Returns: A new fileref, or %NULL if the fileref creation failed. */ frefid_t glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) @@ -242,17 +305,34 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) /** * glk_fileref_create_from_fileref: - * @usage: Bitfield with one or more of the #fileusage_ constants. + * @usage: Bitfield with one or more of the fileusage_ constants. * @fref: Fileref to copy. * @rock: The new fileref's rock value. * * This copies an existing file reference @fref, but changes the usage. (The - * original @fref is not modified.) + * original fileref is not modified.) + * + * The use of this function can be tricky. If you change the type of the fileref + * (#fileusage_Data, #fileusage_SavedGame, etc), the new reference may or may + * not point to the same actual disk file. * - * If you write to a file in text mode and then read from it in binary mode, - * the results are platform-dependent. + * + * This generally depends on whether the platform uses suffixes to indicate + * file type. + * + * + * If you do this, and open both file references for writing, the results are + * unpredictable. It is safest to change the type of a fileref only if it refers + * to a nonexistent file. + * + * If you change the mode of a fileref (#fileusage_TextMode, + * #fileusage_BinaryMode), but leave the rest of the type unchanged, the new + * fileref will definitely point to the same disk file as the old one. + * + * Obviously, if you write to a file in text mode and then read from it in + * binary mode, the results are platform-dependent. * - * Returns: A new fileref, or #NULL if the fileref creation failed. + * Returns: A new fileref, or %NULL if the fileref creation failed. */ frefid_t glk_fileref_create_from_fileref(glui32 usage, frefid_t fref, glui32 rock) @@ -264,8 +344,9 @@ glk_fileref_create_from_fileref(glui32 usage, frefid_t fref, glui32 rock) * glk_fileref_destroy: * @fref: Fileref to destroy. * - * Destroys a fileref which you have created. This does not affect the disk - * file. + * Destroys a fileref which you have created. This does not + * affect the disk file; it just reclaims the resources allocated by the + * glk_fileref_create... function. * * It is legal to destroy a fileref after opening a file with it (while the * file is still open.) The fileref is only used for the opening operation, @@ -284,7 +365,7 @@ glk_fileref_destroy(frefid_t fref) * glk_fileref_delete_file: * @fref: A refrence to the file to delete. * - * Deletes the file referred to by @fref. Does not destroy @fref itself. + * Deletes the file referred to by @fref. It does not destroy @fref itself. */ void glk_fileref_delete_file(frefid_t fref) @@ -300,7 +381,8 @@ glk_fileref_delete_file(frefid_t fref) * * Checks whether the file referred to by @fref exists. * - * Returns: #TRUE (1) if @fref refers to an existing file, #FALSE (0) if not. + * Returns: %TRUE (1) if @fref refers to an existing file, and %FALSE (0) if + * not. */ glui32 glk_fileref_does_file_exist(frefid_t fref) diff --git a/src/fileref.h b/src/fileref.h index 6dcefed..0ee0c47 100644 --- a/src/fileref.h +++ b/src/fileref.h @@ -4,8 +4,15 @@ #include #include "glk.h" +/** + * glk_fileref_struct: + * + * This is an opaque structure (see + * Opaque Structures and should not be accessed directly. + */ struct glk_fileref_struct { + /*< private >*/ glui32 rock; /* Pointer to the list node in the global fileref list that contains this fileref */ diff --git a/src/gestalt.c b/src/gestalt.c index 0c3d27b..4b3b19c 100644 --- a/src/gestalt.c +++ b/src/gestalt.c @@ -33,32 +33,31 @@ glk_gestalt(glui32 sel, glui32 val) * 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 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). + * 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. + * @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. - * + * (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. - * + * (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.) * * Returns: an integer, depending on what selector was called. */ diff --git a/src/glk.c b/src/glk.c index 97673ac..6077dd5 100644 --- a/src/glk.c +++ b/src/glk.c @@ -10,18 +10,32 @@ ChimaraGlkPrivate *glk_data = NULL; /** * glk_exit: * - * Shuts down the Glk program. This function does not return. + * 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. + * 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.) * * - * You should only shut down your program with glk_exit() or by returning from - * your glk_main() function. If you call the ANSI exit() - * function, bad things may happen. This Glk library is designed for multiple - * sessions, for example, and you would be cutting off all the sessions instead - * of just yours. You would also prevent final text from being visible to the - * player. + * You should only shut down your program with glk_exit() or by returning from + * your glk_main() function. If you call the ANSI + * exit() 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. + * + * 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 will happen if you use the ANSI + * exit(). * */ void @@ -35,26 +49,39 @@ glk_exit(void) /** * glk_tick: * - * Many platforms have some annoying thing that has to be done every so often, - * or the gnurrs come from the voodvork out and eat your computer. - * - * Well, not really. But you should call glk_tick() every so often, just in - * case. It may be necessary to yield time to other applications in a - * cooperative-multitasking OS, or to check for player interrupts in an infinite - * loop. - * - * This call is fast; in fact, on average, it does nothing at all. So you can - * call it often. (In a virtual machine interpreter, once per opcode is - * appropriate. In a program with lots of computation, pick a comparable rate.) + * Carries out platform-dependent actions such as yielding time to the operating + * system and checking for interrupts. glk_tick() should be called every so + * often when there is a long interval between calls of glk_select() or + * glk_select_poll(). This call is fast; in fact, on average, it does nothing at + * all. So you can call it often. + * + * + * In a virtual machine interpreter, once per opcode is appropriate. In a + * program with lots of computation, pick a comparable rate. + * * * glk_tick() does not try to update the screen, or check for player input, or * any other interface task. For that, you should call glk_select() or - * glk_select_poll(). + * glk_select_poll(). See Events. * - * Basically, you must ensure there's some fixed upper bound on the amount of - * computation that can occur before a glk_tick() (or glk_select()) occurs. In a - * VM interpreter, where the VM code might contain an infinite loop, this is - * critical. In a C program, you can often eyeball it. + * + * Captious critics have pointed out that in the sample program + * model.c, I do not call glk_tick() at all. This is + * because model.c has no heavy loops. It does a bit of + * work for each command, and then cycles back to the top of the event loop. + * The glk_select() call, of course, blocks waiting for input, so it does all + * the yielding and interrupt-checking one could imagine. + * + * Basically, you must ensure there's some fixed upper bound on the + * amount of computation that can occur before a glk_tick() (or glk_select()) + * occurs. In a VM interpreter, where the VM code might contain an infinite + * loop, this is critical. In a C program, you can often eyeball it. + * + * But the next version of model.c will have a + * glk_tick() in the ornate printing loop of verb_yada(). + * Just to make the point. + * + * */ void glk_tick() @@ -67,3 +94,4 @@ glk_tick() gtk_main_iteration(); gdk_threads_leave(); } + diff --git a/src/input.c b/src/input.c index 8956c2c..c9775fc 100644 --- a/src/input.c +++ b/src/input.c @@ -1,7 +1,8 @@ #include "charset.h" #include "input.h" -/** glk_request_char_event: +/** + * glk_request_char_event: * @win: A window to request char events from. * * Request input of a Latin-1 character or special key. A window cannot have @@ -21,7 +22,8 @@ glk_request_char_event(winid_t win) g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler ); } -/** glk_request_char_event_uni: +/** + * glk_request_char_event_uni: * @win: A window to request char events from. * * Request input of a Unicode character or special key. See @@ -431,3 +433,4 @@ on_input_entry_activate(GtkEntry *input_entry, winid_t win) end_line_input_request(win, text); g_free(text); } + diff --git a/src/stream.c b/src/stream.c index 7e61dc9..bab5b5a 100644 --- a/src/stream.c +++ b/src/stream.c @@ -28,13 +28,9 @@ window_stream_new(winid_t window) * @str: A stream, or %NULL. * @rockptr: Return location for the next window's rock, or %NULL. * - * Iterates over the list of streams; if @str is %NULL, it returns the first - * stream, otherwise the next stream after @str. If there are no more, it - * returns %NULL. The stream's rock is stored in @rockptr. If you don't want - * the rocks to be returned, you may set @rockptr to %NULL. - * - * The order in which streams are returned is arbitrary. The order may change - * every time you create or destroy a stream, invalidating the iteration. + * Iterates through all the existing streams. See Iterating Through Opaque + * Objects. * * Returns: the next stream, or %NULL if there are no more. */ @@ -60,7 +56,8 @@ glk_stream_iterate(strid_t str, glui32 *rockptr) * glk_stream_get_rock: * @str: A stream. * - * Returns the stream @str's rock value. + * Retrieves the stream @str's rock value. See Rocks. * * Returns: A rock value. */ @@ -96,7 +93,7 @@ glk_stream_set_current(strid_t str) * * Returns the current stream, or %NULL if there is none. * - * Returns: A stream. + * Returns: A stream, or %NULL. */ strid_t glk_stream_get_current() @@ -109,7 +106,8 @@ glk_stream_get_current() * @ch: A character in Latin-1 encoding. * * Prints one character to the current stream. As with all basic functions, the - * character is assumed to be in the Latin-1 character encoding. + * character is assumed to be in the Latin-1 character encoding. See Character Encoding. */ void glk_put_char(unsigned char ch) @@ -123,7 +121,8 @@ glk_put_char(unsigned char ch) * @ch: A Unicode code point. * * Prints one character to the current stream. The character is assumed to be a - * Unicode code point. + * Unicode code point. See Character + * Encoding. */ void glk_put_char_uni(glui32 ch) @@ -137,10 +136,10 @@ glk_put_char_uni(glui32 ch) * @s: A null-terminated string in Latin-1 encoding. * * Prints a null-terminated string to the current stream. It is exactly - * equivalent to: + * equivalent to * - * for (ptr = s; *ptr; ptr++) - * glk_put_char(*ptr); + * for (ptr = @s; *ptr; ptr++) + * #glk_put_char(*ptr); * * However, it may be more efficient. */ @@ -174,8 +173,8 @@ glk_put_string_uni(glui32 *s) * Prints a block of characters to the current stream. It is exactly equivalent * to: * - * for (i = 0; i < len; i++) - * glk_put_char(buf[i]); + * for (i = 0; i < @len; i++) + * #glk_put_char(@buf[i]); * * However, it may be more efficient. */ @@ -213,33 +212,10 @@ glk_put_buffer_uni(glui32 *buf, glui32 len) * to the buffer where output will be read from or written to. @buflen is the * length of the buffer. * - * When outputting, if more than @buflen characters are written to the stream, - * all of them beyond the buffer length will be thrown away, so as not to - * overwrite the buffer. (The character count of the stream will still be - * maintained correctly. That is, it will count the number of characters written - * into the stream, not the number that fit into the buffer.) - * - * If @buf is %NULL, or for that matter if @buflen is zero, then - * everything written to the stream is thrown away. This may be - * useful if you are interested in the character count. - * - * When inputting, if more than @buflen characters are read from the stream, the - * stream will start returning -1 (signalling end-of-file.) If @buf is %NULL, - * the stream will always return end-of-file. - * - * The data is written to the buffer exactly as it was passed to the printing - * functions (glk_put_char(), etc.); input functions will read the data exactly - * as it exists in memory. No platform-dependent cookery will be done on it. - * (You can write a disk file in text mode, but a memory stream is effectively - * always in binary mode.) - * * Unicode values (characters greater than 255) cannot be written to the buffer. - * If you try, they will be stored as 0x3F ("?") characters. + * If you try, they will be stored as 0x3F ("?") characters. * - * Whether reading or writing, the contents of the buffer are undefined until - * the stream is closed. The library may store the data there as it is written, - * or deposit it all in a lump when the stream is closed. It is illegal to - * change the contents of the buffer while the stream is open. + * Returns: the new stream, or %NULL on error. */ strid_t glk_stream_open_memory(char *buf, glui32 buflen, glui32 fmode, glui32 rock) @@ -274,6 +250,8 @@ glk_stream_open_memory(char *buf, glui32 buflen, glui32 fmode, glui32 rock) * of 32-bit words, instead of bytes. This allows you to write and read any * Unicode character. The @buflen is the number of words, not the number of * bytes. + * + * Returns: the new stream, or %NULL on error. */ strid_t glk_stream_open_memory_uni(glui32 *buf, glui32 buflen, glui32 fmode, glui32 rock) @@ -389,14 +367,12 @@ file_stream_new(frefid_t fileref, glui32 fmode, glui32 rock, gboolean unicode) * already exists, it is truncated down to zero length (an empty file). If * @fmode is #filemode_WriteAppend, the file mark is set to the end of the * file. - * - * The file may be written in text or binary mode; this is determined by the - * @fileref argument. Similarly, platform-dependent attributes such as file - * type are determined by @fileref. * * When writing in binary mode, Unicode values (characters greater than 255) - * cannot be written to the file. If you try, they will be stored as 0x3F ("?") - * characters. In text mode, Unicode values are stored in UTF-8. + * cannot be written to the file. If you try, they will be stored as 0x3F + * ("?") characters. In text mode, Unicode values may be stored + * exactly, approximated, or abbreviated, depending on what the platform's text + * files support. * * Returns: A new stream, or %NULL if the file operation failed. */ @@ -417,7 +393,11 @@ glk_stream_open_file(frefid_t fileref, glui32 fmode, glui32 rock) * characters are written and read as four-byte (big-endian) values. This * allows you to write any Unicode character. * - * In text mode, the file is written and read in UTF-8. + * In text mode, the file is written and read in a platform-dependent way, which + * may or may not handle all Unicode characters. A text-mode file created with + * glk_stream_open_file_uni() may have the same format as a text-mode file + * created with glk_stream_open_file(); or it may use a more Unicode-friendly + * format. * * Returns: A new stream, or %NULL if the file operation failed. */ @@ -439,7 +419,9 @@ glk_stream_open_file_uni(frefid_t fileref, glui32 fmode, glui32 rock) * If @str is the current output stream, the current output stream is set to * %NULL. * - * You cannot close window streams; use glk_window_close() instead. + * You cannot close window streams; use glk_window_close() instead. See Window Opening, + * Closing, and Constraints. */ void glk_stream_close(strid_t str, stream_result_t *result) diff --git a/src/stream.h b/src/stream.h index 04134f5..25c052e 100644 --- a/src/stream.h +++ b/src/stream.h @@ -12,8 +12,15 @@ enum StreamType STREAM_TYPE_FILE }; +/** + * glk_stream_struct: + * + * This is an opaque structure (see + * Opaque Structures and should not be accessed directly. + */ struct glk_stream_struct { + /*< private >*/ glui32 rock; /* Pointer to the list node in the global stream list that contains this stream */ diff --git a/src/strio.c b/src/strio.c index 98140ad..5fa395e 100644 --- a/src/strio.c +++ b/src/strio.c @@ -279,8 +279,9 @@ write_buffer_to_stream_uni(strid_t str, glui32 *buf, glui32 len) * @str: An output stream. * @ch: A character in Latin-1 encoding. * - * Prints one character @ch to the stream @str. It is illegal for @str to be - * %NULL, or an input-only stream. + * The same as glk_put_char(), except that you specify a stream @str to print + * to, instead of using the current stream. It is illegal for @str to be %NULL, + * or an input-only stream. */ void glk_put_char_stream(strid_t str, unsigned char ch) @@ -296,7 +297,8 @@ glk_put_char_stream(strid_t str, unsigned char ch) * @str: An output stream. * @ch: A Unicode code point. * - * Prints one character @ch to the stream @str. It is illegal for @str to be + * The same as glk_put_char_uni(), except that you specify a stream @str to + * print to, instead of using the current stream. It is illegal for @str to be * %NULL, or an input-only stream. */ void @@ -313,8 +315,9 @@ glk_put_char_stream_uni(strid_t str, glui32 ch) * @str: An output stream. * @s: A null-terminated string in Latin-1 encoding. * - * Prints @s to the stream @str. It is illegal for @str to be %NULL, or an - * input-only stream. + * The same as glk_put_string(), except that you specify a stream @str to print + * to, instead of using the current stream. It is illegal for @str to be %NULL, + * or an input-only stream. */ void glk_put_string_stream(strid_t str, char *s) @@ -330,8 +333,9 @@ glk_put_string_stream(strid_t str, char *s) * @str: An output stream. * @s: A null-terminated array of Unicode code points. * - * Prints @s to the stream @str. It is illegal for @str to be %NULL, or an - * input-only stream. + * The same as glk_put_string_uni(), except that you specify a stream @str to + * print to, instead of using the current stream. It is illegal for @str to be + * %NULL, or an input-only stream. */ void glk_put_string_stream_uni(strid_t str, glui32 *s) @@ -353,8 +357,9 @@ glk_put_string_stream_uni(strid_t str, glui32 *s) * @buf: An array of characters in Latin-1 encoding. * @len: Length of @buf. * - * Prints @buf to the stream @str. It is illegal for @str to be %NULL, or an - * input-only stream. + * The same as glk_put_buffer(), except that you specify a stream @str to print + * to, instead of using the current stream. It is illegal for @str to be %NULL, + * or an input-only stream. */ void glk_put_buffer_stream(strid_t str, char *buf, glui32 len) @@ -371,8 +376,9 @@ glk_put_buffer_stream(strid_t str, char *buf, glui32 len) * @buf: An array of Unicode code points. * @len: Length of @buf. * - * Prints @buf to the stream @str. It is illegal for @str to be %NULL, or an - * input-only stream. + * The same as glk_put_buffer_uni(), except that you specify a stream @str to + * print to, instead of using the current stream. It is illegal for @str to be + * %NULL, or an input-only stream. */ void glk_put_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len) @@ -514,18 +520,27 @@ get_char_stream_common(strid_t str) * glk_get_char_stream: * @str: An input stream. * - * Reads one character from the stream @str. (There is no notion of a ``current - * input stream.'') It is illegal for @str to be %NULL, or an output-only - * stream. + * Reads one character from the stream @str. (There is no notion of a + * current input stream.) It is illegal for @str to be %NULL, or + * an output-only stream. * * The result will be between 0 and 255. As with all basic text functions, Glk - * assumes the Latin-1 encoding. If the end of the stream has been reached, the - * result will be -1. Note that high-bit characters (128..255) are - * not returned as negative numbers. + * assumes the Latin-1 encoding. See Character Encoding. If the end + * of the stream has been reached, the result will be -1. + * + * + * Note that high-bit characters (128..255) are not + * returned as negative numbers. + * * - * If the stream contains Unicode data --- for example, if it was created with - * glk_stream_open_file_uni() or glk_stream_open_memory_uni() --- then - * characters beyond 255 will be returned as 0x3F ("?"). + * If the stream contains Unicode data — for example, if it was created + * with glk_stream_open_file_uni() or glk_stream_open_memory_uni() — then + * characters beyond 255 will be returned as 0x3F ("?"). + * + * It is usually more efficient to read several characters at once with + * glk_get_buffer_stream() or glk_get_line_stream(), as opposed to calling + * glk_get_char_stream() several times. * * Returns: A character value between 0 and 255, or -1 on end of stream. */ @@ -546,7 +561,7 @@ glk_get_char_stream(strid_t str) * Reads one character from the stream @str. The result will be between 0 and * 0x7FFFFFFF. If the end of the stream has been reached, the result will be -1. * - * Returns: A character value between 0 and 255, or -1 on end of stream. + * Returns: A value between 0 and 0x7FFFFFFF, or -1 on end of stream. */ glsi32 glk_get_char_stream_uni(strid_t str) @@ -759,15 +774,16 @@ glk_get_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len) * @buf: A buffer with space for at least @len characters. * @len: The number of characters to read, plus one. * - * Reads characters from @str, until either @len - 1 characters have been read - * or a newline has been read. It then puts a terminal null ('\0') aracter on + * Reads characters from @str, until either + * + * @len - 1 + * @len - 1 + * + * characters have been read or a newline has been read. It then puts a + * terminal null ('\0') aracter on * the end. It returns the number of characters actually read, including the * newline (if there is one) but not including the terminal null. * - * It is usually more efficient to read several characters at once with - * glk_get_buffer_stream() or glk_get_line_stream(), as opposed to calling - * glk_get_char_stream() several times. - * * Returns: The number of characters actually read. */ glui32 @@ -890,9 +906,13 @@ glk_get_line_stream(strid_t str, char *buf, glui32 len) * @buf: A buffer with space for at least @len Unicode code points. * @len: The number of characters to read, plus one. * - * Reads Unicode characters from @str, until either @len - 1 Unicode characters - * have been read or a newline has been read. It then puts a terminal null (a - * zero value) on the end. + * Reads Unicode characters from @str, until either + * + * @len - 1 + * @len - 1 + * + * Unicode characters have been read or a newline has been read. It then puts a + * terminal null (a zero value) on the end. * * Returns: The number of characters actually read, including the newline (if * there is one) but not including the terminal null. @@ -1046,6 +1066,11 @@ glk_get_line_stream_uni(strid_t str, glui32 *buf, glui32 len) * a 32-bit word. So in a binary Unicode file, positions are multiples of four * bytes. * + * + * If this bothers you, don't use binary Unicode files. I don't think they're + * good for much anyhow. + * + * * Returns: position of the read/write mark in @str. */ glui32 @@ -1073,27 +1098,21 @@ glk_stream_get_position(strid_t str) * @seekmode: One of #seekmode_Start, #seekmode_Current, or #seekmode_End. * * Sets the position of the read/write mark in @str. The position is controlled - * by @pos, and the meaning of @pos is controlled by @seekmode: - * - * #seekmode_Start: @pos characters after the beginning of the file. - * - * #seekmode_Current: @pos characters after the current position - * (moving backwards if @pos is negative.) - * #seekmode_End: @pos characters after the end of the file. (@pos - * should always be zero or negative, so that this will move backwards to a - * position within the file. - * + * by @pos, and the meaning of @pos is controlled by @seekmode. See the + * seekmode_ constants below. + * * It is illegal to specify a position before the beginning or after the end of * the file. * - * In binary files, the mark position is exact --- it corresponds with the + * In binary files, the mark position is exact — it corresponds with the * number of characters you have read or written. In text files, this mapping * can vary, because of linefeed conventions or other character-set - * approximations. glk_stream_set_position() and glk_stream_get_position() - * measure positions in the platform's native encoding --- after character - * cookery. Therefore, in a text stream, it is safest to use - * glk_stream_set_position() only to move to the beginning or end of a file, or - * to a position determined by glk_stream_get_position(). + * approximations. See Streams. + * glk_stream_set_position() and glk_stream_get_position() measure positions in + * the platform's native encoding — after character cookery. Therefore, + * in a text stream, it is safest to use glk_stream_set_position() only to move + * to the beginning or end of a file, or to a position determined by + * glk_stream_get_position(). * * Again, in Latin-1 streams, characters are bytes. In Unicode streams, * characters are 32-bit words, or four bytes each. @@ -1138,4 +1157,4 @@ glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekmode) return; } } - + diff --git a/src/style.c b/src/style.c index 54b8aa2..bce1516 100644 --- a/src/style.c +++ b/src/style.c @@ -1,19 +1,7 @@ #include "glk.h" -/** - * glk_set_style: - * @val: A style. - * - * Changes the style of the current output stream. @val should be one of - * #style_Normal, #style_Emphasized, #style_Preformatted, #style_Header, - * #style_Subheader, #style_Alert, #style_Note, #style_BlockQuote, #style_Input, - * #style_User1, or #style_User2. However, any value is actually legal; if the - * library does not recognize the style value, it will treat it as - * #style_Normal. (This policy allows for the future definition of styles - * without breaking old Glk libraries.) - */ void -glk_set_style(glui32 val) +glk_set_style(glui32 styl) { /* No nothing yet */ return; diff --git a/src/window.c b/src/window.c index 204daa5..f533cc7 100644 --- a/src/window.c +++ b/src/window.c @@ -8,14 +8,14 @@ extern ChimaraGlkPrivate *glk_data; * @win: A window, or %NULL. * @rockptr: Return location for the next window's rock, or %NULL. * - * Iterates over the list of windows; if @win is %NULL, it returns the first - * window, otherwise the next window after @win. If there are no more, it - * returns #NULL. The window's rock is stored in @rockptr. If you don't want - * the rocks to be returned, you may set @rockptr to %NULL. + * This function can be used to iterate through the list of all open windows + * (including pair windows.) See Iterating Through Opaque + * Objects. * - * The order in which windows are returned is arbitrary. The root window is - * not necessarily first, nor is it necessarily last. The order may change - * every time you create or destroy a window, invalidating the iteration. + * As that section describes, the order in which windows are returned is + * arbitrary. The root window is not necessarily first, nor is it necessarily + * last. * * Returns: the next window, or %NULL if there are no more. */ @@ -55,7 +55,7 @@ glk_window_iterate(winid_t win, glui32 *rockptr) * @win: A window. * * Returns @win's rock value. Pair windows always have rock 0; all other windows - * have the rock value you created them with. + * return whatever rock value you created them with. * * Returns: A rock value. */ @@ -86,9 +86,10 @@ glk_window_get_type(winid_t win) * glk_window_get_parent: * @win: A window. * - * Returns the window @win's parent window. If @win is the root window, this - * returns %NULL, since the root window has no parent. Remember that the parent - * of every window is a pair window; other window types are always childless. + * Returns the window which is the parent of @win. If @win is the root window, + * this returns %NULL, since the root window has no parent. Remember that the + * parent of every window is a pair window; other window types are always + * childless. * * Returns: A window, or %NULL. */ @@ -104,8 +105,8 @@ glk_window_get_parent(winid_t win) * glk_window_get_sibling: * @win: A window. * - * Returns the other child of the window @win's parent. If @win is the - * root window, this returns %NULL. + * Returns the other child of @win's parent. If @win is the root window, this + * returns %NULL. * * Returns: A window, or %NULL. */ @@ -161,10 +162,169 @@ text_window_get_char_size(GtkWidget *textview, int *width, int *height) * #wintype_TextBuffer, or #wintype_Graphics. * @rock: The new window's rock value. * - * If there are no windows, create a new root window. @split must be 0, and - * @method and @size are ignored. Otherwise, split window @split into two, with - * position, size, and type specified by @method, @size, and @wintype. See the - * Glk documentation for the window placement algorithm. + * Creates a new window. If there are no windows, the first three arguments are + * meaningless. @split must be 0, and @method and @size + * are ignored. @wintype is the type of window you're creating, and @rock is + * the rock (see Rocks). + * + * If any windows exist, new windows must be created by splitting existing + * ones. @split is the window you want to split; this must + * not be zero. @method is a mask of constants to specify the + * direction and the split method (see below). @size is the size of the split. + * @wintype is the type of window you're creating, and @rock is the rock. + * + * Remember that it is possible that the library will be unable to create a new + * window, in which case glk_window_open() will return %NULL. + * + * + * It is acceptable to gracefully exit, if the window you are creating is an + * important one — such as your first window. But you should not try to + * perform any window operation on the id until you have tested to make sure + * it is non-zero. + * + * + * The examples we've seen so far have the simplest kind of size control. (Yes, + * this is below.) Every pair is a percentage split, with + * + * X + * X + * + * percent going to one side, and + * + * (100-X) + * (100 - X) + * + * percent going to the other side. If the player resizes the window, the whole + * mess expands, contracts, or stretches in a uniform way. + * + * As I said above, you can also make fixed-size splits. This is a little more + * complicated, because you have to know how this fixed size is measured. + * + * Sizes are measured in a way which is different for each window type. For + * example, a text grid window is measured by the size of its fixed-width font. + * You can make a text grid window which is fixed at a height of four rows, or + * ten columns. A text buffer window is measured by the size of its font. + * + * + * Remember that different windows may use different size fonts. Even two + * text grid windows may use fixed-size fonts of different sizes. + * + * + * Graphics windows are measured in pixels, not characters. Blank windows + * aren't measured at all; there's no meaningful way to measure them, and + * therefore you can't create a blank window of a fixed size, only of a + * proportional (percentage) size. + * + * So to create a text buffer window which takes the top 40% of the original + * window's space, you would execute + * + * newwin = #glk_window_open(win, #winmethod_Above | #winmethod_Proportional, 40, #wintype_TextBuffer, 0); + * + * + * To create a text grid which is always five lines high, at the bottom of the + * original window, you would do + * + * newwin = #glk_window_open(win, #winmethod_Below | #winmethod_Fixed, 5, #wintype_TextGrid, 0); + * + * + * Note that the meaning of the @size argument depends on the @method argument. + * If the method is #winmethod_Fixed, it also depends on the @wintype argument. + * The new window is then called the key window of this split, + * because its window type determines how the split size is computed. + * + * + * For #winmethod_Proportional splits, you can still call the new window the + * key window. But the key window is not important for + * proportional splits, because the size will always be computed as a simple + * ratio of the available space, not a fixed size of one child window. + * + * + * This system is more or less peachy as long as all the constraints work out. + * What happens when there is a conflict? The rules are simple. Size control + * always flows down the tree, and the player is at the top. Let's bring out an + * example: + * Screen shot 5 + * + * + * First we split A into A and B, with a 50% proportional split. Then we split + * A into A and C, with C above, C being a text grid window, and C gets a fixed + * size of two rows (as measured in its own font size). A gets whatever remains + * of the 50% it had before. + * + * Now the player stretches the window vertically. + * Screen shot 6 + * + * + * The library figures: the topmost split, the original A/B split, is 50-50. So + * B gets half the screen space, and the pair window next to it (the lower + * O) gets the other half. Then it looks at the lower + * O. C gets two rows; A gets the rest. All done. + * + * Then the user maliciously starts squeezing the window down, in stages: + * + * Screen shot 7 + * + * The logic remains the same. B always gets half the space. At stage 3, + * there's no room left for A, so it winds up with zero height. Nothing + * displayed in A will be visible. At stage 4, there isn't even room in the + * upper 50% to give C its two rows; so it only gets one. Finally, C is + * squashed out of existence as well. + * + * When a window winds up undersized, it remembers what size it should be. In + * the example above, A remembers that it should be two rows; if the user + * expands the window to the original size, it would return to the original + * layout. + * + * The downward flow of control is a bit harsh. After all, in stage 4, there's + * room for C to have its two rows if only B would give up some of its 50%. But + * this does not happen. + * + * + * This makes life much easier for the Glk library. To determine the + * configuration of a window, it only needs to look at the window's + * ancestors, never at its descendants. So window layout is a simple + * recursive algorithm, no backtracking. + * + * + * What happens when you split a fixed-size window? The resulting pair window + * — that is, the two new parts together — retain the same size + * constraint as the original window that was split. The key window for the + * original split is still the key window for that split, even though it's now + * a grandchild instead of a child. + * + * The easy, and correct, way to think about this is that the size constraint + * is stored by a window's parent, not the window itself; and a constraint + * consists of a pointer to a key window plus a size value. + * + * Screen shot 8 + * + * After the first split, the new pair window (O1, which covers the whole + * screen) knows that its first child (A) is above the second, and gets 50% of + * its own area. (A is the key window for this split, but a proportional split + * doesn't care about key windows.) + * + * After the second split, all this remains true; O1 knows that its first child + * gets 50% of its space, and A is O1's key window. But now O1's first child is + * O2 instead of A. The newer pair window (O2) knows that its first child (C) + * is above the second, and gets a fixed size of two rows. (As measured in C's + * font, because C is O2's key window.) + * + * If we split C, now, the resulting pair will still be two C-font rows high + * — that is, tall enough for two lines of whatever font C displays. For + * the sake of example, we'll do this vertically. + * Screen shot 9 + * + * + * O3 now knows that its children have a 50-50 left-right split. O2 is still + * committed to giving its upper child, O3, two C-font rows. Again, this is + * because C is O2's key window. + * + * + * This turns out to be a good idea, because it means that C, the text grid + * window, is still two rows high. If O3 had been a upper-lower split, things + * wouldn't work out so neatly. But the rules would still apply. If you don't + * like this, don't do it. + * * * Returns: the new window, or %NULL on error. */ @@ -416,7 +576,39 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, * the same thing.) * * The @result argument is filled with the output character count of the window - * stream. + * stream. See Streams and Closing Streams. + * + * When you close a window (and it is not the root window), the other window + * in its pair takes over all the freed-up area. Let's close D, in the current + * example: + * Screen shot 10 + * + * + * Notice what has happened. D is gone. O3 is gone, and its 50-50 left-right + * split has gone with it. The other size constraints are unchanged; O2 is + * still committed to giving its upper child two rows, as measured in the font + * of O2's key window, which is C. Conveniently, O2's upper child is C, just as + * it was before we created D. In fact, now that D is gone, everything is back + * to the way it was before we created D. + * + * But what if we had closed C instead of D? We would have gotten this: + * Screen shot 11 + * + * + * Again, O3 is gone. But D has collapsed to zero height. This is because its + * height is controlled by O2, and O2's key window was C, and C is now gone. O2 + * no longer has a key window at all, so it cannot compute a height for its + * upper child, so it defaults to zero. + * + * + * This may seem to be an inconvenient choice. That is deliberate. You should + * not leave a pair window with no key, and the zero-height default reminds + * you not to. You can use glk_window_set_arrangement() to set a new split + * measurement and key window. See Changing Window + * Constraints. + * */ void glk_window_close(winid_t win, stream_result_t *result) @@ -490,26 +682,36 @@ glk_window_close(winid_t win, stream_result_t *result) * glk_window_clear: * @win: A window. * - * Erases the window @win. The meaning of this depends on the window type. - * - * - * - * Text buffer: This may do any number of things, such as delete all text in - * the window, or print enough blank lines to scroll all text beyond - * visibility, or insert a page-break marker which is treated specially by the - * display part of the library. - * + * Erases @win. The meaning of this depends on the window type. + * + * + * Text buffer * - * Text grid: This will clear the window, filling all positions with blanks. - * The window cursor is moved to the top left corner (position 0,0). + * This may do any number of things, such as delete all text in the window, or + * print enough blank lines to scroll all text beyond visibility, or insert a + * page-break marker which is treated specially by the display part of the + * library. * + * + * + * Text grid * - * Graphics: Clears the entire window to its current background color. + * This will clear the window, filling all positions with blanks. The window + * cursor is moved to the top left corner (position 0,0). * + * + * + * Graphics * - * Other window types: No effect. + * Clears the entire window to its current background color. See Graphics Windows. * - * + * + * + * Other window types + * No effect. + * + * * * It is illegal to erase a window which has line input pending. */ @@ -578,9 +780,7 @@ glk_window_clear(winid_t win) * @win: A window. * * Sets the current stream to @win's window stream. It is exactly equivalent to - * - * glk_stream_set_current(glk_window_get_stream(win)) - * + * #glk_stream_set_current(#glk_window_get_stream(@win)). */ void glk_set_window(winid_t win) @@ -592,11 +792,16 @@ glk_set_window(winid_t win) * glk_window_get_stream: * @win: A window. * - * Returns the stream which is associated with @win. Every window has a stream - * which can be printed to, but this may not be useful, depending on the window - * type. (For example, printing to a blank window's stream has no effect.) + * Returns the stream which is associated with @win. (See Window Streams.) Every window has a + * stream which can be printed to, but this may not be useful, depending on the + * window type. + * + * + * For example, printing to a blank window's stream has no effect. + * * - * Returns: The window stream. + * Returns: A window stream. */ strid_t glk_window_get_stream(winid_t win) { @@ -609,23 +814,14 @@ strid_t glk_window_get_stream(winid_t win) * @win: A window. * @str: A stream to attach to the window, or %NULL. * - * Attaches the stream @str to @win as a second stream. Any text printed to the - * window is also echoed to this second stream, which is called the window's - * "echo stream." - * - * Effectively, any call to glk_put_char() (or the other output commands) which - * is directed to @win's window stream, is replicated to @win's echo stream. - * This also goes for the style commands such as glk_set_style(). - * - * Note that the echoing is one-way. You can still print text directly to the - * echo stream, and it will go wherever the stream is bound, but it does not - * back up and appear in the window. - * - * It is illegal to set a window's echo stream to be its own window stream, - * which would create an infinite loop. It is similarly illegal to create a - * longer loop (two or more windows echoing to each other.) + * Sets @win's echo stream to @str, which can be any valid output stream. You + * can reset a window to stop echoing by calling + * #glk_window_set_echo_stream(@win, %NULL). * - * You can reset a window to stop echoing by setting @str to %NULL. + * It is illegal to set a window's echo stream to be its + * own window stream. That would create an infinite loop, + * and is nearly certain to crash the Glk library. It is similarly illegal to + * create a longer loop (two or more windows echoing to each other.) */ void glk_window_set_echo_stream(winid_t win, strid_t str) @@ -651,8 +847,8 @@ glk_window_set_echo_stream(winid_t win, strid_t str) * glk_window_get_echo_stream: * @win: A window. * - * Returns the echo stream of window @win. If the window has no echo stream (as - * is initially the case) then this returns %NULL. + * Returns the echo stream of window @win. Initially, a window has no echo + * stream, so #glk_window_get_echo_stream(@win) will return %NULL. * * Returns: A stream, or %NULL. */ @@ -670,8 +866,11 @@ glk_window_get_echo_stream(winid_t win) * @heightptr: Pointer to a location to store the window's height, or %NULL. * * Simply returns the actual size of the window, in its measurement system. - * Either @widthptr or @heightptr can be %NULL, if you only want one - * measurement. (Or, in fact, both, if you want to waste time.) + * As described in Other API + * Conventions, either @widthptr or @heightptr can be %NULL, if you + * only want one measurement. + * + * Or, in fact, both, if you want to waste time. */ void glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) @@ -727,7 +926,7 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) g_warning("glk_window_get_size: Unsupported window type"); } } - + /** * glk_window_move_cursor: * @win: A text grid window. @@ -739,9 +938,9 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) * beginning of the next line. * * If you move the cursor below the last line, or when the cursor reaches the - * end of the last line, it goes "off the screen" and further output has no - * effect. You must call glk_window_move_cursor() or glk_window_clear() to move - * the cursor back into the visible region. + * end of the last line, it goes off the screen and further + * output has no effect. You must call glk_window_move_cursor() or + * glk_window_clear() to move the cursor back into the visible region. * * * Note that the arguments of glk_window_move_cursor() are unsigned @@ -754,8 +953,8 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) * Also note that the output cursor is not necessarily visible. In particular, * when you are requesting line or character input in a grid window, you cannot * rely on the cursor position to prompt the player where input is indicated. - * You should print some character prompt at that spot -- a ">" character, for - * example. + * You should print some character prompt at that spot — a + * > character, for example. * */ void @@ -787,3 +986,4 @@ glk_window_move_cursor(winid_t win, glui32 xpos, glui32 ypos) gdk_threads_leave(); } + diff --git a/src/window.h b/src/window.h index 7a14099..30fe53d 100644 --- a/src/window.h +++ b/src/window.h @@ -18,8 +18,15 @@ enum InputRequestType INPUT_REQUEST_LINE_UNICODE }; +/** + * glk_window_struct: + * + * This is an opaque structure (see + * Opaque Structures and should not be accessed directly. + */ struct glk_window_struct { + /*< private >*/ glui32 rock; /* Pointer to the node in the global tree that contains this window */ GNode *window_node; -- 2.30.2