diff options
author | Kristian Lyngstol <kristian@linpro.no> | 2008-11-30 21:23:07 +0100 |
---|---|---|
committer | Kristian Lyngstol <kristian@linpro.no> | 2008-11-30 21:23:07 +0100 |
commit | 8eef8aafdcaee74b76f78e794ed2e1055a6060ac (patch) | |
tree | f01b8af2f55d222d0499b6d3c75a7216e621a577 | |
parent | 2871e6f23e0a097d3450b2d85443a85481ccf340 (diff) | |
download | Documentation-8eef8aafdcaee74b76f78e794ed2e1055a6060ac.tar.gz Documentation-8eef8aafdcaee74b76f78e794ed2e1055a6060ac.tar.bz2 |
Add a PluginDevelopment first draft
-rw-r--r-- | PluginDevelopment | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/PluginDevelopment b/PluginDevelopment new file mode 100644 index 0000000..fef9246 --- /dev/null +++ b/PluginDevelopment @@ -0,0 +1,155 @@ +Plugin development for Compiz Fusion + +0. About this document +1. Plugin initialization and finalization +2. Dealing with options +3. Hooking into core +4. Debugging +5. Pitfalls + +0. About this document +====================== +This is meant to be a brief introduction to development. It applies to both +new plugins, and working on existing plugins. + +When talking about Compiz development, we talk about plugins and core. Core +is the part of Compiz that are running and not plugins. In other words, it's +Compiz. + +1. Plugin initialization and finalization +========================================= +Plugin initialization starts with a dlOpen, and the only data that core +reads is the vTable, and as such, the vTable is essential. + +The vTable is almost almost found at the bottom of all plugins, and the +content of the vTable changes from time to time. One thing remains the same, +however: The vTable contains the unique plugin-name and function pointers to +various initialization and finalization functions. + +Generally you never modify the vTable in a plugin except to track core +changes. When dealing with the vTable, bcop also comes into play. BCop is a +code generator used in most of Compiz Fusion, but not Compiz. It allows +generation of much of the option handling code, based on metadata. More on +bcop later. + +The vTable currently only contains getMetadata, which you should let bcop +handle, so just leave it as 0 (it simply returns a pointer to the metadata +structure, which bcop generates for us). The initPlugin and finiPlugin +functions are, respectively, the first and last functions to be executed by +the plugin. They should allocate your displayPrivateIndex, which is the only +variable that has to be stored in the plugin in file scope. It is an index +we will use later, to store private data in CompDisplay. You may wonder why +it's not allocated during display initialization; That's because there may +be multiple Displays, and we only want one index. The same applies to all +indexes, as you will see shortly. + +Next in the vTable we have initObject and finiObject. Previously, we had +{init|fini}{Screen|Display|Window} instead. Now we have {init|fini}Object +which returns a list of these functions. This was implemented in +anticipation of a more advanced object framework. + +initDisplay is called first, and you want to allocate your PluginDisplay +structure here if you need one, and wrap anything that takes place in +display-context. This generally means anything that has to do with input. +Also, allocate a screenPrivateIndex, and store it. Since Compiz, in theory, +can have multiple displays (though the author has no idea why or how), it is +considered good practice to store the screenPracticeIndex in your +PluginDisplay variable. + +initScreen is called for _each screen_ after this. It should do set up +the PluginScreen structure and wrap anything related to output. You should +probably read up on Multihead to understand how Compiz may or may not have +multiple CompScreen structures on mutlihead setups. The rule of thumb is +that you always do output in CompScreen context, and that if you have to +work on CompScreen in display-context, you have to iterate over all the +possible screens. + +Lastly, we have initWindow. This is run both when you load your plugin and +when new windows are created. You setup up window-private data here, similar +to initScreen. + +On unload, finiWindow will be called for all windows, followed by finiScreen +for all screens, then finiDisplay, then finiPlugin. On unload, you only need +to worry about disabeling all timeouts (that's why you store their handlers, +right?), UNWRAP anything you WRAP'ed in init*, then free () data and free +indexes you allocated in the same init*. + +2. Dealing with options +======================= +There are two ways to deal with options. It's the Compiz way, and the Compiz +Fusion way. In Compiz Fusion, we use bcop (Beryl/Compiz Option +generator, or something along those lines). It's from the days of Beryl, and +takes care of all the boring parts of option handling. To understand what it +does, we'll first look at how Compiz handles options. + +Options are stored in metadata files, typically xml. I won't go into details +on how CompizConfig and Compiz handles it, but the essential part is that +the data needs to be available from BOTH C and the XML-data. In Compiz, that +means you have the .xml files which contains descriptions used in gconf and +ccsm. In the C code, you have a metadata structure which essentially +duplicates this data. + +You also have to have functions set up to handle when an option change, to +store it in your PluginFoo-variable. As you can imagine, this is mostly +identical in all plugins. What bcop does is take your xml data and generate +the metadata structure from it, then it generates get/set functions and +modifies the relevant bindings to core. + +This means a few things: +1. No get/set code or option code at all in your plugin. +2. No direct access to the option-values, or "default" functions that are +called when an option change. + +bcop solves the lack of direct access by generating functions that take the +form of "pluginGetOptionName (foo)", where foo is the core structure of the +relevant scope. Convention in metadata is to use underscore for option +names, while Compiz uses camelCase, so bcop translates this for you. So +some_option in Display context can be accessed by calling +pluginGetSomeOption (d), assuming d is a CompDisplay. + +To watch for an option change, you can use pluginSetOptionNotify (foo, bar), +where foo is the context-variable (CompDisplay, for instance) and bar is a +function that will be executed. + +3. Hooking into core +==================== +So now you can start your plugin and even read, set and watch for option +changes. To make it actually do something meaningful, you need to hook into +core. For that, you need two macros, WRAP and UNWRAP. These are essentially +stack push/pop operators. The core structures has a number of wrappable +functions, for instance to paint an output device. To modify how an output +device (ie: your monitor) is drawn you tell core that whenever it's about +to update the output, run OUR function. This means you have to make sure you +actually run the core-version afterwards. In reality, plugins stack this on +top of each other, so when you wrap a function, you're most likely saying +"execute my function before this other plugins function". This is why load +order is essential when creating effects that persist through different +plugins, like the fade plugin which looks at the intended opacity for a +window paint and modifies it so instead of an instant change, we get a +smooth gradual change, regardless of wether it was an other plugin that +modified the opacity, or core. + +Unfortunately, there are far too many wrappables to explain them all here. +You will have to look at what other plugins do, or ask around. Hopefully, +more documentation will arrive. + +4. Debugging +============ +Debugging a compiz plugin is hard. You will be restarting compiz a lot. +Using gdb on compiz means that you STOP your window manager, and input and +output along with it. If you really want to use GDB, you need to do it +remotely. + +Luckily, we have a crashhandler plugin that runs gdb for you if compiz +crashes. If you are running compiz in a terminal (like you should), this +should give you what you need to debug crashes. Other than that, it's mostly +printf. + +Some might mention valgrind, but if you need valgrind, you're in deep water. + +5. Pitfalls +=========== + - Mixing up WRAP/UNWRAP order, specially on unload. + - Mixing up CompScreen and CompDisplay context. Read Documentation/Multihead. + - Not unloading properly. + - ? |