HACKING ======= If you want to contribute to herbstluftwm, this file is for you! Contributing ------------ Beside writing code you can help herbstluftwm by testing, reporting bugs, writing/fixing documentation (e.g. by fixing spelling mistakes) or packaging it for distributions. Coding style ------------ The coding style is similar to the Linux-kernel style with some changes: - Use 4 spaces instead of tabs. - Do not add any trailing spaces at the end of a line. - Data type names are CamelCase - Globals must be prefixed with g_ - If a function returns success or failure, then encode it in a bool (from stdbool.h). Only use main()-like exit codes (0 = success, non zero = failure) for commands. - Always typedef struct, e.g.: typedef struct { int first_member; long long other_member; } MyStruct; Build system ------------ The build system mainly is one Makefile. To check which source files depend on which header files it uses dependency files src/*.d and ipc-client/*.d (one for each C source file) which are generated by default. Note: If you switch a branch, the dependency files are not marked as dirty! This may cause unresolvable dependencies e.g. if you switch from a branch with a new header file to a branch without it. So after switching the branch, you always should remove dependency files by running: make cleandeps Alternate build system: CMake ----------------------------- CMake has been included as an alternative build-system, that has some advantages including: - Project file generation for IDEs. - Flexible configuration. - Multiple _out of source_ builds (debug, release... etc). You can use CMake with the following commands (assuming you're in the herbstluftwm repository root): mkdir build cd build cmake .. make make install The choice of 'build' here is arbitrary, you can put your build directory(s) wherever you like. Note that CMake support is currently experimental. Sending patches --------------- You can use git to make commits and create patches from them via the command git format-patch. Always specify your full name and a valid e-mail address in the author field. The commit description must consist two parts, separated by an empty line: - A mandatory short description in imperative form, e.g.: "Do things in this or that way". The description must not exceed 50 characters. - An optional longer description consisting of full sentences. This is only needed if the commit introduces non-trivial changes. When introducing new features, always - add documentation for it in doc/herbstluftwm.txt (or doc/herbstclient.txt). - document the change (e.g. "new command ...") in the NEWS file. You can send those patches to the mailing list[1] or via the irc[2]. [1] hlwm@lists.herbstluftwm.org + [2] #herbstluftwm on irc.freenode.net Mailing list ------------ The main mailing list for general development, discussion, release announcements is: hlwm@lists.herbstluftwm.org You can subscribe by sending a mail with subscribe in the subject to hlwm-request@lists.herbstluftwm.org or by using the web interface at: https://lists.schokokeks.org/mailman/listinfo.cgi/hlwm Debugging with valgrind ----------------------- If you use tools like valgrind, then it is needed to turn of the memory optimization settings for glib. So export this before running herbstluftwm within valgrind: export G_SLICE=always-malloc export G_DEBUG=gc-friendly valgrind --leak-check=full ./herbstluftwm -c share/autostart Internal structure ------------------ The main modules (i.e. source file + header file) communicate like this if a key is pressed or if a command is called via herbstclient: X11 | V +--------+ key +-----+ call +---------+ | main |------>| key |------>| command | +--------+ event +-----+ +---------+ \ output / ^ IPC-Call\ +------------+<----' / Execute -Window `---->| ipc-server |-------' IPC-Call -Event +------------+ | V X11 herbstclient is rather simple: Command-Line- +------+ Arguments --->| main |----. | | X11 stdout <----| |<---' +------+ Objects ------- There is one tree of objects in herbstluftwm to provide an easy access for the user to many options. The usage is similar to kobjects known from the Linux kernel. The most important functions are: - HSObject* hsobject_create_and_link(HSObject* parent, char* name): Create a new child object under parent. If name already exists it will be replaced. - void hsobject_unlink_and_destroy(HSObject* parent, HSObject* child): Remove all child entries at the parent object and destroys the object afterwards. - HSObject* hsobject_root(): Return the root node of the object tree. - void hsobject_set_attributes(HSObject* obj, HSAttribute* attributes): Set the attributes of an object, attributes is an array terminated by ATTRIBUTE_LAST. For a full list see src/object.h. Each object has a certain set of attributes. Each attribute has a type, which is defined by the according constructor: - ATTRIBUTE_BOOL(N, V, CHANGE): accords to bool - ATTRIBUTE_INT(N, V, CHANGE): accords to int - ATTRIBUTE_UINT(N, V, CHANGE): accords to unsigned int - ATTRIBUTE_STRING(N, V, CHANGE): accords to GString* - ATTRIBUTE_CUSTOM(N, V, CHANGE): accords to HSAttributeCustom - ATTRIBUTE_CUSTOM_INT(N, V, CHANGE): accords to HSAttributeCustomInt N is the name of the attribute as displayed to the user, V is the value in the struct; the macro automatically prepends a '&' to it to get the pointer. To check if attributes are changed properly (or to do certain actions after a change), the callback CHANGE is definied: GString* (*on_change) (struct HSAttribute* attr); It is called after the attribute is changed by the user. If this function returns something != NULL, this string is put as an error message to the user and the original value is restored. To mark a attribute as read-only for the user, give ATTR_READ_ONLY as CHANGE. The "custom" attributes do not give a pointer to a variable but give a function that returns the variable. HSAttributeCustom returns a GString, HSAttributeCustomInt an int. typedef void (*HSAttributeCustom)(void* data, GString* output); typedef int (*HSAttributeCustomInt)(void* data); They both get a data-pointer, it is exactly the data-pointer you can give as the data-member of the HSObject struct. For an example see, add_tag(char*) in src/tag.c, it covers most cases. // vim: nowrap ft=asciidoc tw=80