123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- This document
- =============
- This document is a guide how to develop GNU Midnight Commander. It's
- quite incomplete, but may be worth reading anyway.
- The document was written by Miguel de Icaza and reworked by Pavel
- Roskin and later from Patrick Winnertz.
- Some parts were taken from the messages posted in the mailing
- lists.
- Compiling from GIT
- ==================
- The full list of requirements is listed in the INSTALL file.
- It is recommended that all those tools are installed with the same
- prefix. Make sure that the tools with the right version are first in
- PATH.
- Once you have the right tools, run `autogen.sh' - it will generate
- everything necessary for the build `configure'. Then run 'configure'
- and `make' as usually.
- The distribution tarball is created by the command `make distcheck'.
- This command can take a while.
- Currently snapshots are made on Debian unstable and use the versions of
- the tools from the unstable repository. Yes, the rpm packages are made
- on Debian too.
- Note that the version of gettext doesn't affect the snapshot because the
- distributed files are installed by gettext from archives for the version
- used in the AM_GNU_GETTEXT_VERSION macro, which is 0.18.2.
- Working with GNU Midnight Commander
- ===================================
- Please use the GIT version. It may be quite different from the released
- versions. A lot of cleanup is going on. The GIT version may be easier
- to understand, in addition to the obvious fact that the merging is
- easier with the GIT version.
- In order to compile GNU Midnight Commander from a clean GIT checkout you
- should use 'autogen.sh && ./configure' instead of 'configure'.
- GNU Midnight Commander uses Autoconf and Automake, with make it fairly
- portable. However, GNU Make is strongly recommended for development
- because other versions of make may not track dependencies properly.
- This is very important for correct compilation, especially if you change
- any header files.
- If you add or remove any files, please change Makefile.am in the same
- directory accordingly. When doing significant changes in the tree
- structure, "make distcheck" is strongly recommended.
- GNU Autoconf allows you to test several different configurations are
- once. To do so, use the so called out-of-tree (or VPATH) compilation.
- Create separate empty directories and run configure with full path from
- those directories, like this:
- cd /usr/local/src
- mkdir mc-slang
- mkdir mc-ncurses
- cd mc-slang
- /usr/local/src/mc/configure && make all
- cd ../mc-ncurses
- /usr/local/src/mc/configure --with-screen=ncurses && make all
- Please use the same indentation as other developers. To indent a block,
- select in the internal editor and use Shift-F9 to call the external
- indent. For historic reasons, GNU Midnight Commander used formatting
- that is not default for GNU Indent. Please put following text to your
- ~/.indent.pro file to make GNU Indent follow the style used in GNU
- Midnight Commander:
- --gnu-style
- --format-first-column-comments
- --indent-level4
- --brace-indent0
- --line-length100
- --no-tabs
- --blank-lines-after-procedures
- or in short notation:
- indent -gnu -fc1 -i4 -bli0 -nut -bap -l100
- It's OK to indent the whole function if you edit it. However, please
- refrain from it if you are posting your patch for review. In this case
- you would save time of other developers if you only include significant
- changes. The developer applying your patch can format the code for you.
- Please keep in mind that the VFS subsystem is licensed under LGPL, while
- the rest of the code uses GPL.
- Code structure - outline
- ========================
- The code is located in following directories.
- vfs - Virtual File System.
- This library provides filesystem-like access to various data, such are
- archives and remote filesystems. To use VFS, you should use wrappers
- around POSIX calls. The wrappers have names composed from "mc_" and the
- standard name of the function. For example, to open a file on VFS, use
- mc_open() instead.
- edit - the internal editor.
- This code has been contributed by Paul Sheer, the author of Cooledit.
- The internal editor shares some code with Cooledit, but now it's
- developed as part of GNU Midnight Commander.
- src - the main part of the code.
- This code includes the dialog manager written by Radek Doulik and source
- code of the main application.
- Code structure - details
- ========================
- GNU Midnight Commander uses extensively the dialog manager written by
- Radek Doulik. To understand how the dialog manager works, please read
- the dialog.c. You will find the basic widgets in the files widget.c.
- Some more high-level functions, e.g. to display a message box, are
- located in wtools.c. This file also contains the Quick Dialog code,
- which makes it easier to create complex dialogs.
- The files util.c and utilunix.c have a lot of utility functions. Get
- familiar with them, they are very simple.
- glib is used for memory allocation and for some utility functions, such
- as manipulation with lists and trees. gmodule (part of the glib
- distribution) is used to load some libraries dynamically at the run
- time.
- Thanks to glib, the code has almost no hardcoded limits, since there are
- many ways to avoid them. For example, when you want to concatenate
- strings, use the g_strconcat() function:
- new_text = g_strconcat (username, " ", password, (char *)0);
- This allocates new memory for the string, so you should use g_free() on
- the result.
- The parent of all dialogs is called midnight_dlg. Both panels are
- widgets in that dialog. Other widgets include the menu, the command
- line and the button bar.
- 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 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.
- Where to Find Bug Reports and Patches
- =====================================
- The official place for bug reports is:
- https://www.midnight-commander.org/
- There are various unofficial sources where bug reports and patches can
- be found (NOT maintained by the MC team).
- http://bugs.debian.org/mc
- The bug tracking system for Debian, a package collection mainly
- for GNU/Linux and the Hurd.
- http://bugzilla.redhat.com/bugzilla/buglist.cgi?component=mc
- Bugs reported in Redhat Linux.
- http://www.openbsd.org/cgi-bin/cvsweb/ports/misc/mc/patches/
- The patches that are applied for the OpenBSD version of MC.
- http://www.freebsd.org/cgi/cvsweb.cgi/ports/misc/mc/files/
- The patches that are applied for the FreeBSD version of MC.
- http://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/sysutils/mc/patches/
- The patches that are applied for the NetBSD version of MC.
- http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/app-misc/mc/files/?hideattic=1
- The patches that are applied for the Gentoo Linux version of MC.
- Programming Tips
- ================
- (This list should be sorted alphabetically.)
- ?: This operator has a precedence that is easy to use the wrong way. You
- might think that
- int right = 25 + have_frame() ? 1 : 0; /* WRONG */
- results in either 25 or 26. This is not the case. The C compiler
- sees this as:
- int right = (25 + have_frame()) ? 1 : 0; /* WRONG */
- To avoid this, put the ?: in parentheses, like this
- int right = 25 + (have_frame() ? 1 : 0); /* RIGHT */
- If the condition is more complicated, put it in additional
- parentheses:
- int right = 25 + ((have_frame()) ? 1 : 0); /* RIGHT */
- const: For every function taking a string argument, decide whether you
- (as a user of the function) would expect that the string is modi-
- fied by the function. If not, declare the string argument as
- "const char *". If your implementation needs to modify the string,
- use g_strdup to create a local copy.
- const_cast: Has been replaced by str_unconst.
- g_free: g_free handles NULL argument too, no need for the comparison.
- Bad way:
- if (old_dir) g_free (old_dir);
- Right way:
- g_free (old_dir);
- g_strdup: When you use g_strdup to create a local copy of a string, use
- the following pattern to keep the reference.
- char * const pathref = g_strdup(argument);
- /* ... */
- g_free (pathref);
- The "const" will make the pointer unmodifiable (pathref++
- is not possible), but you can still modify the string contents.
- NULL: When you pass NULL as an argument of a varargs function, cast the
- 0 to the appropriate data type. If a system #defines NULL to
- be 0 (at least NetBSD and OpenBSD do), and the sizes of int and
- a pointer are different, the argument will be passed as int 0,
- not as a pointer.
- This tip applies at least to catstrs (edit/edit.h), execl(3),
- execle(3), execlp(3), g_strconcat (glib), parent_call
- (src/background.h), parent_call_string (src/background.h).
- example:
- char *path = g_strconcat("dir", "/", "file", (char *)0);
- size_t: This data type is suitable for expressing sizes of memory or the
- length of strings. This type is unsigned, so you need not check
- if the value is >= 0.
- strncpy: Don't use this function in newly created code. It is slow, insecure
- and hard to use. A much better alternative is g_strlcpy (see there).
- str_unconst: We use many libraries that do not know about "const char *"
- and thus declare their functions to require "char *". If you
- know for sure that an external function does not modify the
- string, you can "unconst" a string using the function
- str_unconst(). If you are not sure whether the function modifies
- the string, you should use g_strdup() to pass a copy of a string
- to the function. Don't forget to call g_free() after work is done.
- unused: Unused arguments of a function can be marked like this:
- void do_nothing(int data)
- {
- (void) &data;
- }
- This tells the GNU C Compiler not to emit a warning, and has no
- side effects for other compilers.
|