mc/doc/DEVEL

168 lines
6.0 KiB
Plaintext

-*-outline-*-
This is the developers' hint guide.
Some parts are based on mail messages.
Please feel free to add your name to this list:
by Miguel de Icaza
* Working with the Midnight Commander
If you plan on working on the Midnight Commander, here are some
tips on how to make your development easier and my job of merging
your code easier, I find them useful.
o Run make depend if you modify the source code structure (e.g. you
add/remove include files). This is very important, it will help you
to get an accurate compilation.
o It's recommended that you use GNU Make (if you want to use the
depend feature).
o I work with the tags feature of GNU emacs. Run the make tags
command to get an updated TAGS file. The command Alt-. will take
you to any function or variable definition.
o Try to keep the indenting style as it is currently. Normally if you
just created a new file with a different coding style, run the GNU
indent program on it (remember to make a backup copy first) like
this: indent -kr -i4 -psl -pcs filename.c
o This code is distributed under the GNU General Public License and
Keep this in mind when adding code to the program.
* Code structure.
The program uses extensively the dialog manager written by Radek
Doulik. To understand how the dialog manager works, please read the
dialog.c and dialog.h. You will find the basic widgets in the files
widget.c and widget.h. If you understand these files, you are done.
The files option.c and boxes.c contain some examples of how the
dialog manager functions are used. For a more complete example, take
a look at the main.c file.
The file util.c has a lot of utility functions. Get familiar with
them, they are very simple.
The code has almost no hardcoded limits, there are a lot of ways of
avoiding them. For example, when you want to concatenate strings,
use the g_strconcat functions, it is used like this:
new_text = g_strconcat (username, " ", password, NULL);
This mallocs the required area, so it still needs to be freed.
* Upcoming changes.
* Panels
* Input handling
The routines for input handling on the Midnight Commander are:
getch, get_key_code, mi_getch and get_event.
getch is an interface to the low level system input mechanism. It
does not deal with the mouse.
In the case of ncurses, this is a function implemented in the
ncurses library that translates key sequences to key codes (\E[A to
something like KEY_UP and so on).
In the case of S-Lang there is no such conversion, that's why we
load a set of extra definitions.
The get_key_code routine converts the data from getch to the
constants the Midnight Commander uses.
In the case of S-Lang, it will actually do all the jobs that getch
does for curses. In the case of curses it patches a couple of
sequences that are not available on some terminal databases. This
routine is the one you want to use if you want a character without
the mouse support.
get_event is the routine you want to use if you want to handle mouse
events, it will return 0 on a mouse event, -1 if no input is available
or a key code if there is some input available. This routine in turn
uses get_key_code to decode the input stream and convert it to useful
constants.
mi_getch is just a wrapper around get_event that ignores all the mouse
events. It's used only in a couple of places, this routine may return
-1 if no input is available (if you have set the nodelay option of
ncurses or S-Lang with nodelay) or a character code if no such option is
available.
* Mouse support.
The mouse support in the Midnight Commander is based on the get_event
routine. The core of the mouse event dispatching is in the
dlg.c:run_dlg routine.
* ncurses
Although S-Lang is now used by default, we still support it ncurses. We
basically are using a small subset of ncurses because we want to be
compatible with Slang.
* The Dialog manager and the Widgets
The Dialog manager and the Widget structure are implemented in
src/dialog.c. Everything shown on screen is a dialog. Dialogs contain
widgets, but not everything on screen is a widget. Dialogs can draw
themselves.
Dialogs are connected into a singly linked list using "parent" field.
Currently active dialog is saved in current_dlg variable. The toplevel
dialog has parent NULL. Usually it's midnight_dlg.
parent parent
current_dlg ------->another dialog-- ... -->midnight_dlg
When the screen needs to be refreshed, every dialog asks its parent to
refresh first, and then refreshes itself.
A dialog is created by create_dlg(). Then it's populated by widgets
using add_widget(). Then the dialog is run by calling run_dlg(), which
returns the id of the button selected by the user. Finally, the dialog
is destroyed by calling destroy_dlg().
Widgets are placed to a doubly linked circular list. Each widget has
previous and next widget.
prev next prev next
widget1 <---------> widget2 <---------> widget3
^ ^
-----------------------------------------
next prev
Pressing Tab moves focus to the "next" widget, pressing Shift-Tab moves
focus to "prev". The tab order is equal to the add order except some
old code that use the reverse order by setting DLG_REVERSE flag in
create_dlg() call. Please don't use reverse order in the new code.
The initial widget to get focus can be selected by calling
dlg_select_widget().
When creating a dialog, you may want to use a callback that would
intercept some dialog events. However, many widgets will do the right
thing by default, so some dialogs can work just fine without callbacks.
There are also widget events, which are sent by the dialog to individual
widgets. Some widgets also have user callbacks.
To create your own widget, use init_widget(). In this case, you must
provide a callback function. Please note that it's not the same as the
user callback in some widgets.
** Button widget
** Check box widget
** Radio widget
** Input widget
** Listbox widget