Intro... Window managers have a few ways in which they are significantly different from other applications. This file, combined with the code overview in doc/code-overview.txt, should hopefully provide a series of relatively quick pointers (hopefully only a few minutes each) to some of the places one can look to orient themselves and get started. Some of this will be general to window managers on X, much will be specific to Marco, and there's probably some information that's common to programs in general but is nonetheless useful. Overview Administrative issues Minimal Building/Testing Environment Relevant standards and X properties Debugging and testing Debugging logs Adding information to the log Valgrind Testing Utilities Technical gotchas to keep in mind Other important reading Extra reading Ideas for tasks to work on Administrative issues Don't commit substantive code in here without asking hp@redhat.com. Adding translations, no-brainer typo fixes, etc. is fine. The code could use cleanup in a lot of places, feel free to do so. See http://developer.gnome.org/dotplan/for_maintainers.html for information on how to make a release. The only difference from those instructions is that the minor version number of a Marco release should always be a number from the Fibonacci sequence. Minimal Building/Testing Environment You do not need to _install_ a development version of Marco to build, run and test it; you can run it from some temporary directory. Also, you do not need to build all of Mate in order to build a development version of Marco -- odds are, you may be able to build marco from GIT without building any other modules. As long as you have gtk+ >= 2.10 and GIO >= 2.25.10 with your distro (gtk+ >= 2.6 if you manually revert the change from bug 348633), you should be able to install your distro's development packages (e.g. gtk2-devel, glib-devel, startup-notification-devel on Fedora; also, remember to install the mate-common package which is needed for building git versions of Mate modules like Marco) as well as the standard development tools (gcc, autoconf, automake, pkg-config, intltool, and libtool) and be ready to build and test Marco. Steps to do so: $ git clone https://github.com/mate-desktop/marco.git $ cd marco $ ./autogen.sh --prefix /usr $ make $ ./src/marco --replace Again, note that you do not need to run 'make install'. Relevant standards and X properties There are two documents that describe some basics about how window managers should behave: the ICCCM (Inter-Client Communication Conventions Manual) and EWMH (Extended Window Manager Hints). You can find these at the following locations: ICCCM - http://tronche.com/gui/x/icccm/ EWMH - :pserver:anoncvs@pdx.freedesktop.org:/cvs The ICCCM is usually available in RPM or DEB format as well. There is actually an online version of the EWMH, but it is almost always woefully out of date. Just get it from cvs with these commands (the backslash means include the stuff from the next line): cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions login cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions \ checkout wm-spec DO NOT GO AND READ THOSE THINGS. THEY ARE REALLY, REALLY BORING. If you do, you'll probably end up catching up on your sleep instead of hacking on Marco. ;-) Instead, just look at the table of contents and glance at a page or two to get an idea of what's in there. Then only refer to it if you see something weird in the code and you don't know what it is but has some funny looking name like you see in one of those two documents. You can refer to the COMPLIANCE file for additional information on these specifications and Marco's compliance therewith. One of the major things those documents cover that are useful to learn about immediately are X properties. The right way to learn about those, though, is through hand on experimentation with the xprop command (and then look up things you find from xprop in those two manuals if you're curious enough). First, try running xprop in a terminal and click on one of the windows on your screen. That gives you the x properties for that window. Look through them and get a basic idea of what's there for kicks. Note that you can get rid of some of the verboseness by grepping out the _NET_WM_ICON stuff, i.e. xprop | grep -v _NET_WM_ICON Next, try running xprop -root in a terminal. There's all the properties of the root window (which you can think of as the "main" Xserver window). You can also manually specify individual windows that you want the properties of with xprop -id if you know the id of the window in question. You can get the id of a given window by either running xwininfo, e.g. xwininfo | grep "Window id" | cut -f 4 -d ' ' or by looking at the _NET_CLIENT_STACKING property of the root window. Finally, it can also be useful to add "-spy" (without the quotes) to the xprop command to get it to continually monitor that window and report any changes to you. Debugging information Trying to run a window manager under a typical debugger, such as gdb, unfortunately just doesn't work very well. So, we have to resort to other methods. Debugging logs First, note that you can start a new version of marco to replace the existing one by running marco --replace (which also comes in handy in the form "./src/marco --replace" when trying to quickly test a small change while hacking on marco without doing a full "make install", though I'm going off topic...) This will allow you to see any warnings printed at the terminal. Sometimes it's useful to have these directed to a logfile instead, which you can do by running MARCO_USE_LOGFILE=1 marco --replace The logfile it uses will be printed in the terminal. Sometimes, it's useful to get more information than just warnings. You can set MARCO_VERBOSE to do that, like so: MARCO_VERBOSE=1 MARCO_USE_LOGFILE=1 marco --replace (note that MARCO_VERBOSE=1 can be problematic without MARCO_USE_LOGFILE=1; avoid it unless running in from something that won't be managed by the new Marco--see bug 305091 for more details). There are also other flags, such as MARCO_DEBUG, most of which I haven't tried and don't know what they do. Go to the source code directory and run grep "MARCO_" * | grep getenv to find out what the other ones are. Adding information to the log Since we can't single step with a debugger, we often have to fall back to the primitive method of getting information we want to know: adding "print" statements. Marco has a fairly structured way to do this, using the functions meta_warning, meta_topic, and meta_verbose. All three have the same basic format as printf, except that meta_topic also takes a leading enumeration parameter to specify the type of message being shown (makes it easier for grepping in a verbose log). You'll find tons of examples in the source code if you need them; just do a quick grep or look in most any file. Note that meta_topic and meta_verbose messages only appear if verbosity is turned on. I tend to frequently add temporary meta_warning statements (or switch meta_topic or meta_verbose ones to meta_warning ones) and then undo the changes once I've learned the info that I needed. There is also a meta_print_backtrace (which again is only active if verbosity is turned on) that can also be useful if you want to learn how a particular line of code gets called. And, of course, there's always g_assert if you want to make sure some section isn't executed (or isn't executed under certain conditions). Valgrind Valgrind is awesome for finding memory leaks or corruption and uninitialized variables. But I also tend to use it in a non-traditional way as a partial substitute for a normal debugger: it can provide me with a stack trace of where marco is crashing if I made a change that caused it to do so, which is one of the major uses of debuggers. (And, what makes it cooler than a debugger is that there will also often be warnings pinpointing the cause of the crash from either some kind of simple memory corruption or an uninitialized variable). Sometimes, when I merely want to know what is calling a particular function I'll just throw in an "int i; printf("%d\n", i);" just because valgrind will give me a full stacktrace whenever it sees that uninitialized variable being used (yes, I could use meta_print_backtrace, but that means I have to turn verbosity on). To run marco under valgrind, use options typical for any Mate program, such as valgrind --log-file=marco.log --tool=memcheck --num-callers=48 \ --leak-check=yes --leak-resolution=high --show-reachable=yes \ ./src/marco --replace where, again, the backslashes mean to join all the stuff on the following line with the previous one. However, there is a downside. Things run a little bit slowly, and it appears that you'll need about 1.5GB of ram, which unfortunately prevents most people from trying this. Testing Utilities src/run-marco.sh The script src/run-marco.sh is useful to hack on the window manager. It runs marco in an Xnest. e.g.: CLIENTS=3 ./run-marco.sh or DEBUG=memprof ./run-marco.sh or DEBUG_TEST=1 ./run-marco-sh or whatever. marco-message The tool marco-message can be used as follows: marco-message reload-theme marco-message restart marco-message enable-keybindings marco-message disable-keybindings The first of these is useful for testing themes, the second is just another way (besides the --restart flag to marco itself) of restarting marco, and the third is useful for testing Marco when running it under an Xnest (typically, the Marco under the Xnest wouldn't get keybinding notifications--making keyboard navigation not work--but if you disable the keybindings for the global Marco then the Marco under the Xnest can then get those keybinding notifications). marco-window-demo marco-window-demo is good for trying behavior of various kinds of window without launching a full desktop. Technical gotchas to keep in mind Files that include gdk.h or gtk.h are not supposed to include display.h or window.h or other core files. Files in the core (display.[hc], window.[hc]) are not supposed to include gdk.h or gtk.h. Reasons: "Basically you don't want GDK most of the time. It adds abstractions that cause problems, because they aren't designed to be used in a WM where we do weird stuff (display grabs, and just being the WM). At best GDK adds inefficiency, at worst it breaks things in weird ways where you have to be a GDK guru to figure them out. Owen also told me that they didn't want to start adding a lot of hacks to GDK to let a WM use it; we both agreed back in the mists of time that marco would only use it for the "UI" bits as it does. Having the split in the source code contains and makes very clear the interface between the WM and GDK/GTK. This keeps people from introducing extra GDK/GTK usage when it isn't needed or appropriate. Also, it speeds up the compilation a bit, though this was perhaps more relevant 5 years ago than it is now. There was also a very old worry that the GDK stuff might have to be in a separate process to work right; that turned out to be untrue. Though who knows what issues the CM will introduce." Remember that strings stored in X properties are not in UTF-8, and they have to end up in UTF-8 before we try putting them through Pango. If you make any X request involving a client window, you have to meta_error_trap_push() around the call; this is not necessary for X requests on the frame windows. Remember that not all windows have frames, and window->frame can be NULL. Other important reading & where to get started Extra reading There are some other important things to read to get oriented as well. These are: http://pobox.com/~hp/features.html rationales.txt doc/code-overview.txt It pays to read http://pobox.com/~hp/features.html in order to understand the philosophy of Marco. The rationales.txt file has two things: (1) a list of design choices with links in the form of bugzilla bugs that discuss the issue, and (2) a list outstanding bug categories, each of which is tracked by a particular tracker bug in bugzilla from which you can find several closely related bug reports. doc/code-overview.txt provides a fairly good overview of the code, including coverage of the function of the various files, the main structures and their relationships, and places to start looking in the code tailored to general categories of tasks. Ideas for tasks to work on There are a variety of things you could work on in the code. You may have ideas of your own, but in case you don't, let me provide a list of ideas you could choose from: If you're ambitious, there's a list of things Havoc made that he'd really like to see tackled, which you can find at http://log.ometer.com/2004-05.html. Be sure to double check with someone to make sure the item is still relevant if you're interested in one of these. Another place to look for ideas, of course, is bugzilla. One can just do queries and look for things that look fixable. However, perhaps the best way of getting ideas of related tasks to work on, is to look at the second half of the rationales.txt file, which tries to group bugs by type.