mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 03:20:21 -07:00
279 lines
9.6 KiB
Haskell
279 lines
9.6 KiB
Haskell
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Doc.Developing
|
|
-- Copyright : (C) 2007 Andrea Rossato
|
|
-- License : BSD3
|
|
--
|
|
-- Maintainer : andrea.rossato@unibz.it
|
|
-- Stability : unstable
|
|
-- Portability : portable
|
|
--
|
|
-- This module documents the xmonad internals.
|
|
--
|
|
-- It is intended for the advanced users who are curious about the
|
|
-- 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
|
|
-- consider about releasing it.
|
|
--
|
|
-- Coding guidelines and licencing policies must be followed if you
|
|
-- want your code to be included in the official repositories.
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Doc.Developing
|
|
(
|
|
-- -- * Writing new extensions
|
|
-- -- $writing
|
|
|
|
-- * Libraries for writing window managers
|
|
-- $xmonad-libs
|
|
|
|
-- * xmonad internals
|
|
-- $internals
|
|
|
|
-- ** The @main@ entry point
|
|
-- $main
|
|
|
|
-- ** The X monad and the internal state
|
|
-- $internalState
|
|
|
|
-- ** Event handling and messages
|
|
-- $events
|
|
|
|
-- ** The 'LayoutClass'
|
|
-- $layoutClass
|
|
|
|
-- * Coding style
|
|
-- $style
|
|
|
|
-- * Licensing policy
|
|
-- $license
|
|
) where
|
|
|
|
--------------------------------------------------------------------------------
|
|
--
|
|
-- Writing Extensions
|
|
--
|
|
--------------------------------------------------------------------------------
|
|
|
|
{- $writing
|
|
-}
|
|
|
|
{- $xmonad-libs
|
|
|
|
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.
|
|
|
|
Basically, xmonad and the xmonad-contrib libraries let users write
|
|
their own window manager in a matter of a few lines of code.
|
|
|
|
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.
|
|
|
|
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
|
|
-}
|
|
|
|
{- $main
|
|
#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 '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
|
|
|
|
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
|
|
|
|
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#
|
|
to do
|
|
-}
|
|
|
|
{- $style
|
|
|
|
These are the coding guidelines for contributing to xmonad and the
|
|
xmonad contributed extensions.
|
|
|
|
* Comment every top level function (particularly exported funtions), and
|
|
provide a type signature.
|
|
|
|
* Use Haddock syntax in the comments.
|
|
|
|
* Follow the coding style of the other modules.
|
|
|
|
* Code should be compilable with -Wall -Werror. There should be no warnings.
|
|
|
|
* Partial functions should be avoided: the window manager should not
|
|
crash, so do not call 'error' or 'undefined'
|
|
|
|
* Tabs are /illegal/. Use 4 spaces for indenting.
|
|
|
|
* Any pure function added to the core should have QuickCheck properties
|
|
precisely defining its behaviour.
|
|
|
|
-}
|
|
|
|
{- $license
|
|
|
|
New modules should identify the author, and be submitted under the
|
|
same license as xmonad (BSD3 license or freer).
|
|
|
|
-}
|