home *** CD-ROM | disk | FTP | other *** search
- Introduction
-
- This file documents the support for various windowing systems in
- NetHack. The support is through a standard interface, separating the
- main NetHack code from window-system specific code. The implementation
- supports multiple window systems in the same binary. Even if you only
- wish to support one window-port on your port, you will need to follow
- the instructions in Section VII to get a compilable binary.
-
- Contents:
- I. Window Types and Terminology
- II. Interface Specification
- III. Global variables
- IV. New or respecified common, high level routines
- V. Game startup
- VI. Conventions
- VII. Implementation and Multi-window support
-
- I. Window Types and Terminology
-
- There are 5 basic window types, used to call create_nhwindow():
-
- NHW_MESSAGE (top line)
- NHW_STATUS (bottom lines)
- NHW_MAP (main dungeon)
- NHW_MENU (inventory or other "corner" windows)
- NHW_TEXT (help/text, full screen paged window)
-
- The tty window-port also uses NHW_BASE (the base display) internally.
-
- NHW_MENU windows can be used for either menu or text display. Their
- basic feature is that for the tty-port, if the window is small enough,
- it appears in the corner of the tty display instead of overwriting
- the whole screen. The first call to add information to the window
- will decide if it is going to be used to display a menu or text.
- If start_menu() is called, then it will be used as a menu. If
- putstr() is called, it will be used as text. Once decided, there
- is no turning back. For the tty-port, if the data is too large for
- a single screen then the data is paged (with --more--) between pages.
- Only NHW_MENU type windows can be used for menus.
-
- NHW_TEXT windows are used to display a large amount of textual data.
- This is the type of window one would use for displaying a help file,
- for example. In the tty window-port, windows of type NHW_TEXT can
- page using the DEF_PAGER, if DEF_PAGER is defined. There exists an
- assumption that the font for text windows is monospaced. The help
- files are all formatted accordingly.
-
- "window" is always of type winid. This is currently implemented as an
- integer, but doesn't necessarily have to be done that way. There are
- a few fixed window names that are known throughout the code:
-
- WIN_MESSAGE (top line)
- WIN_STATUS (bottom lines)
- WIN_MAP (main dungeon)
- WIN_INVEN (inventory)
-
- Other windows are created and destroyed as needed.
-
- "Port" in this document refers to a CPU/OS/hardware platform (UNIX, MSDOS
- TOS, etc.) "window-port" refers to the windowing platform. This is
- orthogonal (e.g. UNIX might use either a tty window-port or an X11
- window-port).
-
-
- II. Interface Specification
-
- All functions below are void unless otherwise noted.
-
- A. Low-level routines:
-
- raw_print(str) -- Print directly to a screen, or otherwise guarantee that
- the user sees str. raw_print() appends a newline to str.
- It need not recognize ASCII control characters. This is
- used during startup (before windowing system initialization
- -- maybe this means only error startup messages are raw),
- for error messages, and maybe other "msg" uses. E.g.
- updating status for micros (i.e, "saving").
- raw_print_bold(str)
- -- Like raw_print(), but prints in bold/standout (if possible).
- curs(window, x, y)
- -- Next output to window will start at (x,y), also moves
- displayable cursor to (x,y). For backward compatibility,
- 1 <= x < cols, 0 <= y < rows, where cols and rows are
- the size of window.
- -- For variable sized windows, like the status window, the
- behaviour when curs() is called outside the window's limits
- is unspecified. The mac port wraps to 0, with the status
- window being 2 lines high and 80 columns wide.
- -- Still used by curs_on_u(), status updates, screen locating
- (identify, teleport).
- -- NHW_MESSAGE, NHW_MENU and NHW_TEXT windows do not
- currently support curs in the tty window-port.
- putstr(window, attr, str)
- -- Print str on the window the given attribute. Only
- printable ASCII characters (040-0126) must be supported.
- Multiple putstr()s are output on separate lines. Attributes
- can be one of
- ATR_NONE (or 0)
- ATR_ULINE
- ATR_BOLD
- ATR_BLINK
- ATR_INVERSE
- If a window-port does not support all of these, it may map
- unsupported attributes to a supported one (e.g. map them
- all to ATR_INVERSE). putstr() may compress spaces out of
- str, break str, or truncate str, if necessary for the
- display. Where putstr() breaks a line, it has to clear
- to end-of-line.
- -- putstr should be implemented such that if two putstr()s
- are done consecutively that the user will see the first
- and the second. In the tty port, pline() achieves this
- by calling more() or displaying both on the same line.
- get_nh_event() -- Does window event processing (e.g. exposure events).
- A noop for the tty and X window-ports.
- int nhgetch() -- Returns a single character input from the user.
- -- In the tty window-port, nhgetch() assumes that tgetch()
- will be the routine the OS provides to read a character.
- Returned character _must_ be non-zero.
- int nh_poskey(int *x, int *y, int *mod)
- -- Returns a single character input from the user or a
- a positioning event (perhaps from a mouse). If the
- return value is non-zero, a character was typed, else,
- a position in the MAP window is returned in x, y and mod.
- mod may be one of
-
- CLICK_1 /* mouse click type 1 */
- CLICK_2 /* mouse click type 2 */
-
- The different click types can map to whatever the
- hardware supports. If no mouse is supported, this
- routine always returns a non-zero character.
-
- B. High-level routines:
-
- print_glyph(window, x, y, glyph)
- -- Print the glyph at (x,y) on the given window. Glyphs are
- integers at the interface, mapped to whatever the window-
- port wants (symbol, font, color, attributes, ...there's
- a 1-1 map between glyphs and distinct things on the map).
- char yn_function(const char *ques, const char *choices, char default)
- -- Print a prompt made up of ques, choices and default.
- Read a single character response that is contained in
- choices or default. If choices is NULL, all possible
- inputs are accepted and returned. This overrides
- everything else. The choices are expected to be in
- lower case. Entering ESC always maps to 'q', or 'n',
- in that order, if present in choices, otherwise it maps
- to default. Entering any other quit character (SPACE,
- RETURN, NEWLINE) maps to default.
- -- If the choices string contains a '#' then accept a count.
- Place this value in the global "yn_number" and return '#'.
- -- This uses the top line in the tty window-port, other
- ports might use a popup.
- getlin(const char *ques, char *input)
- -- Prints ques as a prompt and reads a single line of text,
- up to a newline. The string entered is returned without the
- newline. ESC is used to cancel, in which case the string
- "\033\000" is returned.
- -- getlin() must call flush_screen(1) before doing anything.
- -- This uses the top line in the tty window-port, other
- ports might use a popup.
- get_ext_cmd(char *input)
- -- This routine is only included if COM_COMPL is defined.
- Get the extended command in a special way (command
- completion on the tty window-port).
- ** I think it is pretty lame that this has an #ifdef
- ** on it. The #ifdef COM_COMPL should either be yanked
- ** inside this function or done away with. -dean
- player_selection()
- -- Do a window-port specific player type selection. If
- player_selection() offers a Quit option, it is its
- responsibility to clean up and terminate the process.
- display_file(str, boolean complain)
- -- Display the file named str. Complain about missing files
- iff complain is TRUE.
- update_inventory()
- -- Indicate to the window port that the inventory has been
- changed.
- -- Merely calls display_inventory() for window-ports that
- leave the window up, otherwise empty.
- doprev_message()
- -- Display previous messages. Used by the ^P command.
- -- On the tty-port this scrolls WIN_MESSAGE back one line.
-
- C. Window Utility Routines
-
- init_nhwindows()
- -- Initialize the windows used by NetHack. This can also
- create the standard windows listed at the top, but does
- not display them.
- -- When the message window is created, the variable
- flags.window_inited needs to be set to TRUE. Othewise
- all plines() will be done via raw_print().
- ** Why not have init_nhwindows() create all of the "standard"
- ** windows? Or at least all but WIN_INFO? -dean
- exit_nhwindows()
- -- Exits the window system. This should dismiss all windows,
- except the "window" used for raw_print().
- window = create_nhwindow(type)
- -- Create a window of type "type."
- clear_nhwindow(window)
- -- Clear the given window, when apropriate.
- display_nhwindow(window, boolean blocking)
- -- Display the window on the screen. If there is data
- pending for output in that window, it should be sent.
- If blocking is TRUE, display_nhwindow() will not
- return until the data has been displayed on the screen,
- and acknowledged by the user where appropriate.
- -- All calls are blocking in the tty window-port.
- -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
- --more--, if necessary, in the tty window-port.
- destroy_nhwindow(window)
- -- Destroy will dismiss the window if the window has not
- already been dismissed.
- start_menu(window)
- -- Start using window as a menu. You must call start_menu()
- before add_menu(). After calling start_menu() you may not
- putstr() to window. Only windows of type NHW_MENU may be
- used for menus.
- add_menu(window, ch, attr, str)
- -- Add a text line to the given menu window. If ch is 0,
- then the line cannot be selected (e.g. a title). Otherwise,
- ch is the response needed to select the line. The value
- attr is the same as in putstr().
- end_menu(window, ch, str, morestr)
- -- Stop adding entries to the menu and flushes the window
- to the screen (brings to front?). Str gives other valid
- (likely canceling) inputs (beyond any standard ones) and
- ch is the response to any of them. Morestr is a prompt
- to give the user. If morestr is NULL, no prompt will be
- printed unless the window-port requires one (e.g. --more--
- in the tty window-port).
- char select_menu(window)
- -- Returns a valid response from the given menu (user typing,
- mouse selection, whatever). You may select_menu() from a
- window multiple times -- the menu is saved until
- start_menu() or destroy_nhwindow() is called on the window.
- -- Note that NHW_MENU windows need not have select_menu
- called for them. There is no way of knowing whether
- select_menu() will be called for the window at
- create_nhwindow() time.
-
- D. Misc. Routines
-
- make_sound(???) -- To be determinded later. THIS IS CURRENTLY UN-IMPLEMENTED.
- nhbell() -- Beep at user. [This will exist at least until sounds are
- redone, since sounds aren't attributable to windows anyway.]
- mark_synch() -- Don't go beyond this point in I/O on any channel until
- all channels are caught up to here. Can be an empty call
- for the moment
- wait_synch() -- Wait until all pending output is complete (*flush*() for
- streams goes here).
- -- May also deal with exposure events etc. so that the
- display is OK when return from wait_synch().
- delay_output() -- Causes a visible delay of 50ms in the output.
- Conceptually, this is similar to wait_synch() followed
- by a nap(50ms), but allows asynchronous operation.
- askname() -- Ask the user for a player name.
- cliparound(x, y)-- Make sure that the user is more-or-less centered on the
- screen if the playing area is larger than the screen.
- -- This funciton is only defined if CLIPPING is defined.
- number_pad(state)
- -- Initialize the number pad to the given state.
- suspend_nhwindows(str)
- -- Prepare the window to be suspended.
- resume_nhwindows()
- -- Restore the windows after being suspended.
-
- start_screen() -- Only used on Unix tty ports, but must be declared for
- completeness. Sets up the tty to work in full-screen
- graphics mode. Look at win/tty/termcap.c for an
- example. If your window-port does not need this function
- just declare an empty function.
- end_screen() -- Only used on Unix tty ports, but must be declared for
- completeness. The complement of start_screen().
-
-
- III. Global variables
-
- The following global variables are defined in decl.c and must be used by
- the window interface to the rest of NetHack.
-
- char toplines[BUFSZ] Contains the last message printed to the WIN_MESSAGE
- window, used by Norep().
- winid WIN_MESSAGE, WIN_MAP, WIN_STATUS, WIN_INVEN
- The four standard windows.
- char *AE, *AS; Checked in options.c to see if we should switch
- to DEC_GRAPHICS. It is #ifdefed VMS and UNIX.
- int LI, CO; Set in sys/unix/ioctl.c.
-
- The following appears to be Unix specific. Other ports using the tty
- window-port should also declare this variable in one of your sys/*.c files.
-
- short ospeed; Set and declared in sys/unix/unixtty.c (don't
- know about other sys files).
-
- IV. New or respecified common, high level routines
-
- These are not part of the interface, but mentioned here for your information.
-
- char display_inventory(lets,show_cost)
- -- Calls a start_menu()/add_menu()/select_menu() sequence.
- It returns the item selected, or '\0' if none is selected.
- Returns '\033' if the menu was canceled.
- raw_printf(str, ...)
- -- Like raw_print(), but accepts arguments like printf(). This
- routine processes the arguments and then calls raw_print().
- -- The mac version #defines error raw_printf. I think this
- is a reasonable thing to do for most ports.
- pline(str, ...)
- -- Prints a string to WIN_MESSAGE using a printf() interface.
- It has the variants kludge(), You(), Your(), and Norep()
- which all use the same mechanism. pline() requires the
- variable "char toplines[]" be defined; Every putstr() on
- WIN_MESSAGE must copy str to toplines[] for use by Norep()
- and pline(). If the window system is not active
- (!flags.window_inited) pline() uses raw_print().
-
-
- V. Game startup
-
- The following is the general order in which calls from main() should be made,
- as they relate to the window system. The actual code may differ, but the
- order of the calls should be the same.
-
-
- choose_windows(DEFAULT_WINDOW_SYS) /* choose a default window system */
- initoptions() /* read the resource file */
- init_nhwindows() /* initialize the window system */
- process_options(argc, argv) /* process command line options or equiv */
- if(save file is present) {
- display_gamewindows() /* create & display the game windows */
- dorestore() /* restore old game; pline()s are OK */
- } else {
- player_selection() /* select a player type using a window */
- display_gamewindows() /* create & display the game windows */
- }
- pline("Hello, welcome...");
-
- Choose_windows() is a common routine, and calling it in main() is necessary
- to initialize the function pointer table to _something_ so that calls to
- raw_print() will not fail. Choose_windows() should be called almost
- immediately upon entering main(). Look at unixmain.c for an example.
-
- Display_gamewindows() is a common routine that displays the three standard
- game windows (WIN_MESSAGE, WIN_MAP, and WIN_STATUS). It is normally called
- just before the "Hello, welcome" message.
-
- Process_options() is currently still unique to each port. There may be need
- in the future to make it possible to replace this on a per window-port basis.
-
-
- VI. Conventions
-
- init_nhwindows() is expected to display a gee-whiz banner window, including
- the Copyright message.
-
- Ports (MSDOS, TOS, MAC, etc) _may_ use window-port specific routines in
- their port specific files, _AT_THEIR_OWN_RISK_. Since "port" and
- "window-port" are orthogonal, you make your "port" code less portable by
- using "window-port" specific routines. Every effort should be made to
- use window-port interface routines, unless there is something port
- specific that is better suited (e.g. msmsg() for MSDOS).
-
- The tty window-port is contained in win/tty, the X window port is contained
- in win/X11. The files in these directories contain _only_ window port code,
- and may be replaced completely by other window ports.
-
-
- VII. Implementation and Multi-window support
-
- NetHack 3.1 supports multiple window systems in the same binary. When
- writing a new window-port, you need to follow the following guidelines:
-
- 1) Pick a unique prefix to identify your window-port. For example, the tty
- window port uses "tty"; the X11 window-port uses "X11".
- 2) When declaring your interface function, preceed the function names with
- your unique prefix. E.g:
-
- void tty_init_nhwindows()
- {
- /* code for initializing windows in the tty port */
- }
-
- When calling window functions from within your port code, we suggest
- calling the prefixed version to avoid unnecessary overhead. However,
- you may safely call the non-prefixed version (e.g. putstr() rather than
- tty_putstr()) as long as you #include "hack.h". If you do not
- include hack.h and use the non-prefixed names, you will get compile
- or link-time errors.
-
- We also suggest declaring all functions and port-specific data with
- this prefix to avoid unexpected overlaps with other window-ports.
- The tty and X11 ports do not currently follow this suggestion, but do
- use separate non-overlapping convention for naming data and internal
- functions.
-
- 3) Declare a structure, "struct win_choices prefix_procs", (with your
- prefix instead of "prefix") and fill in names of all of your
- interface functions. The first entry in this structure in the name
- of your window-port, which should be the prefix. The other entries
- are the function addresses.
-
- Assuming that you followed the convention in (2), you can safely copy
- the structure definition from an existing window-port and just change
- the prefixes. That will guarantee that you get the order of your
- initializations correct (not all compilers will catch out-of-order
- function pointer declarations).
-
- 3) Add a #define to config.h identifying your window-port in the
- "Windowing systems" section. Follow the "prefix_GRAPHICS" convention
- for your window-port.
-
- 4) Add your prefix to the list of valid prefixes listed in the "Known
- systems are" comment.
-
- 5) Edit makedefs.c and add a string for your windowing system to window_opts
- inside an #ifdef prefix_GRAPHICS.
-
- 6) Edit windows.c and add an external reference to your prefix_procs inside
- an #ifdef prefix_GRAPHICS. Also add an entry to the winchoices
- structure for your window-port of the form:
-
- #ifdef prefix_GRAPHICS
- { &prefix_procs, prefix_init_function },
- #endif
-
- The init_function is necessary for some compilers and systems to force
- correct linking. If your system does not need such massaging, you
- may put a null pointer here.
-
- You should declare prefix_procs and prefix_init_function as extern's
- in your win*.h file, and #include that file at the beginning of
- windows.c, also inside an #ifdef prefix_GRAPHICS. Some win*.h files
- are rather sensitive, and you might have to duplicate your
- prefix_procs and prefix_init_function's instead of including win*.h.
- The tty port includes wintty.h, the X11 port duplicates the declarations.
-
- 7) If your port uses Makefile.src, add the .c and .o files and an
- appropriate comment in the section on "WINSRC" and "WINOBJ". See
- Makefile.src for the style to use. If you don't use Makefile.src,
- we suggest using a similar convention for the make-equivalent used
- on your system. Also add your new source and binaries to WINSRC and
- WINOBJ (if you want the NetHack binary to include them, that is).
-
- 8) Look at your port's portmain.c (the file containing main()) and make
- sure that all of the calls match the the requirements laid out in
- Section V.
-
- Now, proceed with compilation and installation as usual. Don't forget
- to edit Makefile.src (or its equivalent) and config.h to set the
- window-ports you want in your binary, the default window-port to use,
- and the .o's needed to build a valid game.
-
- One caveat. Unfortunately, if you incorrectly specify the
- DEFAULT_WINDOW_SYS, NetHack will dump core (or whatever) without
- printing any message, because raw_print() cannot function without first
- setting the window-port.
-