From c6576d6dea5111710082d812a6d455f1e4957fbd Mon Sep 17 00:00:00 2001 From: Andrea Rossato Date: Sat, 24 Nov 2007 15:11:33 +0100 Subject: Developing: a start darcs-hash:20071124141133-32816-43c2c3233ef8cc6b5e6d2f50385ca6bc492839b7.gz --- XMonad/Doc/Developing.hs | 185 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 158 insertions(+), 27 deletions(-) (limited to 'XMonad/Doc/Developing.hs') diff --git a/XMonad/Doc/Developing.hs b/XMonad/Doc/Developing.hs index e23ce79..180fc8a 100644 --- a/XMonad/Doc/Developing.hs +++ b/XMonad/Doc/Developing.hs @@ -1,6 +1,6 @@ ----------------------------------------------------------------------------- -- | --- Module : Documentation +-- Module : XMonad.Doc.Developing -- Copyright : (C) 2007 Andrea Rossato -- License : BSD3 -- @@ -11,7 +11,12 @@ -- This module documents the xmonad internals. -- -- It is intended for the advanced users who are curious about the --- xmonad code and want an brief overview of it. +-- xmonad source code and want an brief overview of it. +-- +-- While some knowledge of Haskell is required, still this document is +-- also intended for the beginner\/intermediate Haskell programmer who +-- could find writing an xmonad extension a motivation for deepening +-- her understanding of this powerful functional language. -- -- It may be useful also for those who would like to extend xmonad. If -- you think your extension may be useful for other users too, you may @@ -24,8 +29,8 @@ module XMonad.Doc.Developing ( - -- * Writing new extensions - -- $writing + -- -- * Writing new extensions + -- -- $writing -- * Libraries for writing window managers -- $xmonad-libs @@ -59,60 +64,186 @@ module XMonad.Doc.Developing -------------------------------------------------------------------------------- {- $writing - -Writing Other Extensions - -} {- $xmonad-libs -xmonad and xmonad-contrib are just libraries for letting users write -their own window managers. This is what makes xmonad such a powerful -and still simple application. +Starting from version 0.5, xmonad and xmonad-contrib are packaged and +distributed as libraries. This way of distributing xmonad has many +advantages, since it allows the packaging by GNU\/Linux distributions +while letting the user have the possibility of greatly customizing the +window manager to fit her needs. -Give some examples: -arossato_vm -droundy_wm +Basically, xmonad and the xmonad-contrib libraries let users write +their own window manager in a matter of a few lines of code. -In the previous sections we show how simple it can be to write your -own window manager by using the core code (xmonad) and some of the -contributed code (xmonad-contrib). +In fact, what seems to be just a configuration file, +@~\/.xmonad\/xmonad.hs@ (whose presence is not necessary for running +the default configuration), is indeed a full Haskell program, with its +@main@ entry point. -In this section we will give you a brief overview of the programming -techniques that have been used in order to make writing new extensions -very simple. +This makes it possible, not only to edit the xmonad default +configuration, as we have seen the "XMonad.Doc.Extending" document, +but also to use the Haskell programming language to extend the tasks +performed by the window manager you are writing every time you write +your own @~\/.xmonad\/xmonad.hs@. + +This is obviously out of the scope of this document, which instead +will be focused on the xmonad internals, by describing, very briefly, +the programming techniques that have been employed in order to make +writing new extensions very simple. -} {- $internals - -TODO - -} {- $main #The_main_entry_point# -TODO +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 'XMonad.Core.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 'XMonad.Main.xmonad', from the +"XMonad.Main" module. + +So, the real @main@ entry point, the one that even users' application +in @~\/.xmonad\/xmonad.hs@ must call, is 'XMonad.Main.xmonad' + +'XMonad.Main.xmonad' takes the configuration as its only argument, +configuration whose type ('XMonad.Core.XConfig') is defined in +"XMonad.Core". + +'XMonad.Main.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 +('XMonad.Main.handle') that will 'Prelude.forever' loop waiting for +events and acting accordingly. -} {- $internalState -TODO +The event loop which calls 'XMonad.Main.handle' to react to events is +run within the 'XMonad.Core.X' monad, which is a +'Control.Monad.State.StateT' transformer over 'IO', encapsulated +within a 'Control.Monad.Reader.ReaderT' transformer. The +'Control.Monad.State.StateT' transformer encapsulates the (writable) +state of the window manager ('XMonad.Core.XState'), whereas the +'Control.Monad.Reader.ReaderT' transformer encapsulates the +(read-only) configuration ('XMonad.Core.XConf'). + +Thanks to the @newtype deriving@ clause the instance of the +'Control.Monad.State.MonadState' class parametrized over +'XMonad.Core.XState' and the instance of the +'Control.Monad.Reader.MonadReader' class parametrized over +'XMonad.Core.XConf' are automatically derived from us by ghc. This way +we can use 'Control.Monad.State.get', 'Control.Monad.State.gets' and +'Control.Monad.State.modify' for the 'XMonad.Core.XState', and +'Control.Monad.Reader.ask' and 'Control.Monad.Reader.asks' for +reading the 'XMonad.Core.XConf'. + +'XMonad.Core.XState' is where all the sensitive information about +windows managing is stored. And the main record of the +'XMonad.Core.XState' is the 'XMonad.Core.windowset', whose type +('XMonad.Core.WindowSet') is a type synonymous for a +'XMonad.StackSet.StackSet' parametrized over a +'XMonad.Core.WorkspaceID' (a 'String'), a layout type wrapped inside +the 'XMonad.Layout.Layout' existential data type, the +'Graphics.X11.Types.Window' type, the 'XMonad.Core.ScreenID' and the +'XMonad.Core.ScreenDetail's. + +What a 'XMonad.StackSet.StackSet' is and how it can be manipulated +with pure functions is perfectly described in the Haddock +documentation of the "XMonad.StackSet" module, and will not be repeated +here. + +The 'XMonad.StackSet.StackSet' ('XMonad.Core.WindowSet') has 4 +records: + +* 'XMonad.StackSet.current', for the current, focused workspace. This + is a 'XMonad.StackSet.Screen', composed by a + 'XMonad.StackSet.Workspace', and the screen information (for + Xinerama support). + +* 'XMonad.StackSet.visible', a list of 'XMonad.StackSet.Screen's for + the other visible (with Xinerama) workspaces. + +* 'XMonad.StackSet.hidden', the list of 'XMonad.StackSet.Screen's for + non visible workspaces. + +The 'XMonad.StackSet.Workspace' type is made of a +'XMonad.StackSet.tag', a 'XMonad.StackSet.layout' and +'XMonad.StackSet.stack', possibly empy, of windows. + +"XMonad.StackSet", to be imported qualified, provides many pure +functions to manipulate the 'XMonad.StackSet.StackSet'. These +functions are usually used as the argument of +'XMonad.Operations.windows', which indeed takes a pure function to +manipulate the 'XMonad.Core.WindowSet' and does all the needed +operations to refresh the screen and save the modified +'XMonad.Core.XState'. + +During 'XMonad.Operations.windows' calls the 'XMonad.StackSet.layout' +record of the 'XMonad.StackSet.current' and 'XMonad.StackSet.visible' +'XMonad.StackSet.Workspace's is used to arrange the +'XMonad.StackSet.stack' of windows of each workspace. + +The possibility of manipulating the 'XMonad.StackSet.StackSet' +('XMonad.Core.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 with +the set of property to be tested with QuickCheck before being applied. -} {- $events -TODO +Events and event handling are the main data and activity xmonad is +involved with. And X Events are one of the most important. + +Still there may be events that are generated by layouts, or by the +user, for sending commands to layouts, for instance. + +"XMonad.Core" defines a class that generalizes the concept of events, +'XMonad.Core.Message', constrained to types with a +'Data.Typeable.Typeable' instance definition (which can be +automatically derived by ghc). + +'XMonad.Core.Message's are wrapped within an existential type +'XMonad.Core.SomeMessage'. + +The 'Data.Typeable.Typeable' constraint allows us to define a +'XMonad.Core.fromMessage' function that can unwrap the message with +'Data.Typeable.cast'. + +X Events are instances of this class. + +By using the 'Data.Typeable.Typeable' class for any kind of +'XMonad.Core.Message's and events we can define polymorphic functions +and use them for processing messages or unhandled events. + +This is precisely what happens with X events: xmonad passes them to +'XMonad.Main.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 'XMonad.Operations.bradcastMessage'. + +This messaging system allows the user to create new message types, +simply declare an instance of the 'Data.Typeable.Typeable' and use +'XMonad.Operations.sendMessage' to send commands to layouts. + +And, finally, layouts may handle X events and other messages within the +same function... miracles of polymorphism. -} {- $layoutClass #The_LayoutClass# -TODO - +to do -} {- $style -- cgit v1.2.3