aboutsummaryrefslogtreecommitdiffstats
path: root/XMonad/Doc/Developing.hs
blob: 180fc8a89aae7008d5630095e70447271cccdc02 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
-----------------------------------------------------------------------------
-- |
-- 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).

-}