Newt was originally designed for use in the install code for
Red Hat Linux. As this install code runs in an environment with limited
resources (most importantly limited filesystem space), newt's size
was immediately an issue. To help minimize its size, the following design
decisions were made early in it's implementation:
newt does not use an event-driven architecture.newt is written in C, not C++. While there has been interest
in contructing C++ wrapper classes around the newt API, nothing has
yet come of those ideas.newt windows behave as modal dialogs). This is probably
the greatest functionality restriction of newt.
While newt provides a complete API, it does not handle the low-level
screen drawing itself. Instead, newt is layered on top of the screen
management capabilities of John E. Davis's
S-Lang library.
newt applications
As newt is not event driven and forces modal windows (forcing window
order to behave like a stack), newt applications tend to look quite like
other text-mode programs. It is quite straightforward to convert a command
line program which uses simple user prompts into a newt application.
Some of the programs run as part of the Red Hat installation process
(such as Xconfigurator and mouseconfig) were originally written
as simple terminal mode programs which used line-oriented menus to get
input from the user and were later converted into newt applications
(through a process affectionately known as newtering). Such a conversion
does not require changes to the control flow of most applications.
Programming newt is dramatically different from writing programs for
most other windowing systems as newt's API is not event driven. This
means that newt applications look dramatically different from programs
written for event-driven architectures such as Motif, gtk, or even
Borland's old TurboVision libraries.
When your're desiging your newt program, keep this differentiation
in mind. As long as you plan your application to call a function to
get input and then continue (rather then having your program called
when input is ready), programming with the newt libraries should be
simple.
Displayable items in newt are known as components, which are
analagous to the widgets provided by most Unix widget sets. There are
two main types of components in newt, forms and everything else.
Forms logically group components into functional sets. When an application
is ready to get input frm a user, it ``runs a form'', which makes the
form active and lets the user enter information into the components the
form contains. A form may contain any other component, including other
forms. Using subforms in this manner lets the application change the details
of how the user tabs between components on the form, scroll regions of the
screen, and control background colors for portions of windows.
Every component is of type newtComponent, which is an opaque type. It's
guaranteed to be a pointer though, which lets applications move it through
void pointers if the need arises. Variables of type newtComponent should
never be directly manipulated -- they should only be passed to newt
functions. As newtComponent variables are pointers, remember that
they are always passed by value -- if you pass a newtComponent to
a function which manipulates it, that component is manipulated everywhere,
not just inside of that function (which is nearly always the behaviour
you want).
Newt uses a number of conventions to make it easier for programmers
to use.
newtComponent
for that form to be the first parameter.newt is loosely typed (forcing all of the components into
a single variable makes coding easier, but nullifies the value of type
checking), newt functions include the name of the type they are
manipulating. An example of this is newtFormAddComponent(), which
adds a component to a form. Note that the first parameter to this function
is a form, as the name would suggest.Newt uses callback functions to convey certain events to
the application. While callbacks differe slightly in their parameters, most
of them allow the application to speicfy an arbitrary argument to be passed
to the callback when the callback is invoked. This argument is always a
void *, which allows the application great flexibility.