| ||||||||
| ||||||||
| ||||||||
Description | ||||||||
This module gives a brief overview of the xmonad internals. It is intended for advanced users who are curious about the xmonad source code and want an brief overview. This document may also be helpful for the beginner/intermediate Haskell programmer who is motivated to write an xmonad extension as a way to deepen her understanding of this powerful functional language; however, there is not space here to go into much detail. For a more comprehensive document covering some of the same material in more depth, see the guided tour of the xmonad source on the xmonad wiki: http://haskell.org/haskellwiki/Xmonad/Guided_tour_of_the_xmonad_source. If you write an extension module and think it may be useful for others, consider releasing it. Coding guidelines and licensing policies are covered at the end of this document, and must be followed if you want your code to be included in the official repositories. For a basic tutorial on the nuts and bolts of developing a new extension for xmonad, see the tutorial on the wiki: http://haskell.org/haskellwiki/Xmonad/xmonad_development_tutorial. | ||||||||
Synopsis | ||||||||
Writing new extensions | ||||||||
Libraries for writing window managers | ||||||||
Starting with version 0.5, xmonad and xmonad-contrib are packaged and distributed as libraries, instead of components which must be compiled by the user into a binary (as they were prior to version 0.5). This way of distributing xmonad has many advantages, since it allows packaging by GNU/Linux distributions while still allowing the user to customize the window manager to fit her needs. Basically, xmonad and the xmonad-contrib libraries let users write their own window manager in just a few lines of code. While ~/.xmonad/xmonad.hs at first seems to be simply a configuration file, it is actually a complete Haskell program which uses the xmonad and xmonad-contrib libraries to create a custom window manager. This makes it possible not only to edit the default xmonad configuration, as we have seen in the XMonad.Doc.Extending document, but to use the Haskell programming language to extend the window manager you are writing in any way you see fit. | ||||||||
xmonad internals | ||||||||
The main entry point | ||||||||
xmonad installs a binary, xmonad, which must be executed by the Xsession starting script. This binary, whose code can be read in Main.hs of the xmonad source tree, will use recompile to run ghc in order to build a binary from ~/.xmonad/xmonad.hs. If this compilation process fails, for any reason, a default main entry point will be used, which calls the xmonad function with a default configuration. Thus, the real main entry point, the one that even the users' custom window manager application in ~/.xmonad/xmonad.hs must call, is the xmonad function. This function takes a configuration as its only argument, whose type (XConfig) is defined in XMonad.Core. xmonad takes care of opening the connection with the X server, initializing the state (or deserializing it when restarted) and the configuration, and calling the event handler (handle) that goes into an infinite loop (using forever) waiting for events and acting accordingly. | ||||||||
The X monad and the internal state | ||||||||
The event loop which calls handle to react to events is run within the X monad, which is a StateT transformer over IO, encapsulated within a ReaderT transformer. The StateT transformer encapsulates the (read/writable) state of the window manager (of type XState), whereas the ReaderT transformer encapsulates the (read-only) configuration (of type XConf). Thanks to GHC's newtype deriving feature, the instance of the MonadState class parametrized over XState and the instance of the MonadReader class parametrized over XConf are automatically derived for the X monad. This way we can use get, gets and modify for the XState, and ask and asks for reading the XConf. XState is where all the sensitive information about window management is stored. The most important field of the XState is the windowset, whose type (WindowSet) is a synonym for a StackSet parametrized over a WorkspaceID (a String), a layout type wrapped inside the Layout existential data type, the Window type, the ScreenID and the ScreenDetails. What a StackSet is and how it can be manipulated with pure functions is described in the Haddock documentation of the XMonad.StackSet module. The StackSet (WindowSet) has four fields:
The Workspace type is made of a tag, a layout and a (possibly empty) stack of windows. XMonad.StackSet (which should usually be imported qualified, to avoid name clashes with Prelude functions such as delete and filter) provides many pure functions to manipulate the StackSet. These functions are most commonly used as an argument to windows, which takes a pure function to manipulate the WindowSet and does all the needed operations to refresh the screen and save the modified XState. During each windows call, the layout field of the current and visible Workspaces are used to physically arrange the stack of windows on each workspace. The possibility of manipulating the StackSet (WindowSet) with pure functions makes it possible to test all the properties of those functions with QuickCheck, providing greater reliability of the core code. Every change to the XMonad.StackSet module must be accompanied by appropriate QuickCheck properties before being applied. | ||||||||
Event handling and messages | ||||||||
Event handling is the core activity of xmonad. Events generated by the X server are most important, but there may also be events generated by layouts or the user. XMonad.Core defines a class that generalizes the concept of events, Message, constrained to types with a Typeable instance definition (which can be automatically derived by ghc). Messages are wrapped within an existential type SomeMessage. The Typeable constraint allows for the definition of a fromMessage function that can unwrap the message with cast. X Events are instances of this class, along with any messages used by xmonad itself or by extension modules. Using the Typeable class for any kind of Messages and events allows us to define polymorphic functions for processing messages or unhandled events. This is precisely what happens with X events: xmonad passes them to handle. If the main event handling function doesn't have anything to do with the event, the event is sent to all visible layouts by broadcastMessage. This messaging system allows the user to create new message types, simply declare an instance of the Typeable and use sendMessage to send commands to layouts. And, finally, layouts may handle X events and other messages within the same function... miracles of polymorphism. | ||||||||
The LayoutClass | ||||||||
to do | ||||||||
Coding style | ||||||||
These are the coding guidelines for contributing to xmonad and the xmonad contributed extensions.
For examples of Haddock documentation syntax, have a look at other extensions. Important points are:
To generate and view the Haddock documentation for your extension, run runhaskell Setup haddock and then point your browser to /path/to/XMonadContrib/dist/doc/html/xmonad-contrib/index.html. For more information, see the Haddock documentation: http://www.haskell.org/haddock/haddock-html-0.8/index.html. For more information on the nuts and bolts of how to develop your own extension, see the tutorial on the wiki: http://haskell.org/haskellwiki/Xmonad/xmonad_development_tutorial. | ||||||||
Licensing policy | ||||||||
New modules should identify the author, and be submitted under the same license as xmonad (BSD3 license or freer). | ||||||||
Produced by Haddock version 0.8 |