netrik hacker's manual
[This file describes handling of terminal input/output, and color handling. See
hacking.txt or hacking.html for an overview of the manual.] #<a name="color"
For storing color values internally (in the _String_ structure in the layout,
see hacking-layout.html) and for passing to the color setting functions
(see _screen.c_ below), a one-byte color representation is used much like
the one of CGA/EGA/VGA cards:
|bright : |bright : |
|back- : background color |fore- : foreground color |
|ground : |ground : |
7 6 5 4 3 2 1 0
Background colors are presently only used for link highlighting, so setting
the original text color boils down to determining the foreground color.
The text colors of the text on the layouted page are determined when
storing the text while _Parsing Structure_ during the layouting process
The right color for each text part is determined by a facility named text
modes: For every kind of text on the page (normal text, emphasized text,
links, layout marks etc.) one constant exists in "enum Text_mode", and some
fixed color value corresponds to each one.
The assignement of color values to the text modes is done with the "color_map"
array, which is declared and initialized in colors.c. (See _Colors Schemes_
For the various kinds of layout/form/image markers the color is directly taken
from the map entry of the appropriate text type and passed to _add_string()_
(see hacking-layout.*). Text modes that affect normal text (content) added
during parsing (like links, emphasize), set the "state.text_mode" variable
instead; any normal text will be added in the mode currently stored in this
Bold text (strong emphasize) is presently handled in a different manner: The
"state.bold" flag is set, causing all text added inside the section to be added
with a negated brightness flag. (i.e. normal colors will become bright/bold,
while colors for text modes already having "bright" set in the color map will
be non-bright instead.)
Netrik allows using different color schemes, according to one's preferences and
terminal colors. However, the color schemes aren't fully customizable for now;
there are only two color schemes (defined in colors-dark.c and colors-bright.c)
that can be switched by "cfg.bright_background" (using --bright-background
This is chiefly because our preffered colors only look good on black background,
but are unusable on bright background, so different color schemes have to be
provided for those situations.
The handling is actually quite simple: Depending on the setting of
"cfg.bright_background", either "color_map_bright" (from colors-bright.c) or
"color_map_dark" (from colors-dark.c) is assigned to "color_map". This is done
in load_color_map(), which is called after reading the command line/config
file options in main().
Note that, unless explicitly overridden by --no-force-colors,
"cfg.force_colors" is automatically set if "cfg.bright_background" is not
set, so a black background will always be used with the dark color scheme,
even on a terminal normally having a bright background. This isn't done with
the bright color scheme; here, the terminal's default colors are kept.
Netrik now features an extremly crude monochrome mode, which is activated
by passing the --bw command line option, or automatically in init_curses(),
if the terminal definition lacks color switching capabilities.
The monochrome mode presently completely disables all color/attribute switching.
This is achieved by skipping all color initializations and making all color
setting functions nops. Thus, it needs handling only in screen.c (s.b.),
and is otherwise completely transparant.
screen.c contains a couple of helper functions for handling curses, both in
raw and in full screen mode.
init_curses() is responsible for initializing curses in raw mode, and getting
some control sequences for setting colors etc. If cfg.inverse_bold was not
specified by the user, this is also done here: If the terminal name contains
"xterm", cfg.inverse_bold is set, otherwise reset.
start_curses() initializes curses in full screen mode, and sets the
foreground/background color pairs. (This is necessary to change colors using
curses.) It also initializes several curses settings.
All 63 modifiable color pairs are initialized (pair 0 is hard-wired in curses),
in such a manner that every combination of the eight foreground and eight
background colors is covered. (Brightness is controled by extra flags, and not
coded in the color pairs.) The upper three bits of the six-bit pair number
specify the background, the lower 3 the foreground. While the background
colors are mapped directly, some magic is necessary for the foreground,
to ensure that color pair 0 (which is hard-wired to white on black) will
actually correspond to the right color in the color scheme. This is achieved
by rotating the foreground color space by one, so color 0 gets white, color
1 gets black etc., instead of color 0 being black and color 7 being white.
For color pairs having black background or white foreground, the respective
parts aren't set; the terminal default is used instead. (Unless --force-colors
is used.) This is to produce the expected results in most xterms (or other
terminals with bright background and black text).
set_color() sets the text attributes in full screen mode. The foreground
color is set, and the "bold" attribute if it is a light color.
If the background color is bright, the "blink" attribute is set, which works
on most terminals. (Sadly not all...)
As this doesn't work in xterm, another approach has to be used for those:
If cfg.inverse_bold was set (see above), the "blink" attribute is used in
conjuction with reverse video instead. Of course we have to swap foreground
and background colors to get the actually desired ones. (Note that this trick
doesn't work on linux console, so we can use it *only* when in an xterm!)
The drawback is that the foreground is always bold but dark in this mode --
we can neiter prevent it getting bold nor get it bright to distinguish between
bold and normal foreground as soon as a bright background is set...
set_color_raw() does the same in raw mode. As raw mode has no color pairs to be
set during initialization, handling of default colors for white foreground/black
background has to be done here. The respective parts simply aren't set at all,
thus keeping the terminal default colors.
reset_colors_raw() resets all text attributes to their default values.
Handling of the "winch" singnal (which is raised by the terminal each time the
text area changes, e.g. when resizing an xterm window) itself is quite simple,
as we use the default handler provided by ncurses. On SIGWINCH, ncurses will
adjust its own data structures, and also store the pseudo-key "KEY_RESIZE"
in the input queue, so we know there was a change.
Only thing we have to care of here is ensuring that ncurses won't resize its
data structures while we are making some changes to the screen contents, as
this might cause failure when we are outside the screen unexpectedly. This is
achieved by the two functions hold_winch() and enable_winch() from winch.c.
hold_winch() stops immediate delivery of the winch signal, bud does not
descard it; instead, it is put on hold. enable_winch() reenables delivery
of the singal. If there is a pending signal generated during the hold phase,
it is also delivered now.
To ensure that SIGWINCH arrives only in controlled circumstances, it is
put on hold before entering fullscreen mode at the beginning of _display()_
(see hacking-pager.*), and released only after switching to scroll mode again.
(Inside end_fullscreen(), which is located in screen.c.) Only for the time
of the getch() call (waiting for a keypress) it is enabled, as the resulting
KEY_RESIZE will be handled immediately, thus no problems with unexpected
changes can arise.
Of course, resizing the pager window is not enough; the page contents also
needs to be adapted to the new screen width. This is done by returning to
_main()_ (see hacking.*) with RET_WINCH, where _ressize()_ (described in
hacking-layout.*) is called before returning to the pager.