[Xmonad] Constrained dynamically extensible layout events: a patch
Donald Bruce Stewart
dons at cse.unsw.edu.au
Fri May 4 04:21:07 EDT 2007
dons:
> dons:
> > David, Spencer et al, are there any problems with restricting layoutMsg
> > arguments to being members of the (open) Message class? I'd (strongly)
> > prefer this over just Dynamic, since it restores most of the static
> > checking we'd need.
>
> Oh, I forgot an example. This is why Dynamic-only is scary:
>
> , ((modMask, xK_h ), layoutMsg "hey Joe!")
> , ((modMask, xK_l ), layoutMsg Expand)
>
> is well typed. Under the new system, it becomes a static error:
>
> Config.hs:157:43:
> No instance for (Message [Char])
> arising from use of `sendMessage' at Config.hs:157:43-65
>
> -- Don
Ah, and a version that actually applies, given Spencer's last changes.
-- Don
-------------- next part --------------
New patches:
[Constrain layout messages to be members of a Message class
Don Stewart <dons at cse.unsw.edu.au>**20070504081649
Using Typeables as the only constraint on layout messages is a bit
scary, as a user can send arbitrary values to layoutMsg, whether they
make sense or not: there's basically no type feedback on the values you
supply to layoutMsg.
Folloing Simon Marlow's dynamically extensible exceptions paper, we use
an existential type, and a Message type class, to constrain valid
arguments to layoutMsg to be valid members of Message.
That is, a user writes some data type for messages their layout
algorithm accepts:
data MyLayoutEvent = Zoom
| Explode
| Flaming3DGlassEffect
deriving (Typeable)
and they then add this to the set of valid message types:
instance Message MyLayoutEvent
Done. We also reimplement the dynamic type check while we're here, to
just directly use 'cast', rather than expose a raw fromDynamic/toDyn.
With this, I'm much happier about out dynamically extensible layout
event subsystem.
] {
hunk ./Config.hs 157
- , ((modMask, xK_h ), layoutMsg Shrink)
- , ((modMask, xK_l ), layoutMsg Expand)
+ , ((modMask, xK_h ), sendMessage Shrink)
+ , ((modMask, xK_l ), sendMessage Expand)
hunk ./Operations.hs 19
-import Data.Dynamic ( Typeable, toDyn, fromDynamic )
hunk ./Operations.hs 75
-switchLayout = layout (\(x, xs) -> let xs' = xs ++ [x]
- in (head xs', tail xs'))
+switchLayout = layout (\(x, xs) -> let xs' = xs ++ [x] in (head xs', tail xs'))
hunk ./Operations.hs 77
+-- | Throw an (extensible) message value to the current Layout scheme,
+-- possibly modifying how we layout the windows, then refresh.
hunk ./Operations.hs 80
--- TODO, using Typeable for extensible stuff is a bit gunky. Check --
--- 'extensible exceptions' paper for other ideas.
+-- TODO, this will refresh on Nothing.
hunk ./Operations.hs 82
--- Basically this thing specifies the basic operations that vary between
--- layouts.
---
-data ShrinkOrExpand = Shrink | Expand deriving (Typeable, Eq)
-
-layoutMsg :: Typeable a => a -> X () -- FIXME: The below shouldn't refresh on Nothing
-layoutMsg a = layout $ \x@(l, ls) -> maybe x (flip (,) ls) (modifyLayout l (toDyn a))
+sendMessage :: Message a => a -> X ()
+sendMessage a = layout $ \x@(l, ls) -> maybe x (flip (,) ls) (modifyLayout l (SomeMessage a))
hunk ./Operations.hs 85
+------------------------------------------------------------------------
hunk ./Operations.hs 87
--- Standard layout algorithms:
+-- Builtin layout algorithms:
hunk ./Operations.hs 92
+--
+-- The latter algorithms support the following operations:
hunk ./Operations.hs 95
-full :: Layout
-tall, wide :: Rational -> Rational -> Layout
+-- Shrink
+-- Expand
+--
+
+data Resize = Shrink | Expand deriving (Typeable, Show)
+instance Message Resize
hunk ./Operations.hs 102
-full = Layout { doLayout = \sc ws -> [ (w,sc) | w <- ws ]
- , modifyLayout = const Nothing }
+full :: Layout
+full = Layout { doLayout = \sc ws -> [ (w,sc) | w <- ws ]
+ , modifyLayout = const Nothing } -- no changes
hunk ./Operations.hs 106
+tall, wide :: Rational -> Rational -> Layout
hunk ./Operations.hs 110
- , modifyLayout = fmap f . fromDynamic }
+ , modifyLayout = fmap handler . fromMessage }
hunk ./Operations.hs 112
- where f s = tall delta ((op s) frac delta)
- op Shrink = (-) ; op Expand = (+)
+ where handler s = tall delta $ (case s of
+ Shrink -> (-)
+ Expand -> (+)) frac delta
hunk ./XMonad.hs 20
+ Typeable, Message, SomeMessage(..), fromMessage,
hunk ./XMonad.hs 32
-import Data.Dynamic ( Dynamic )
+import Data.Typeable
hunk ./XMonad.hs 40
- , layouts :: !(M.Map WorkspaceId (Layout, [Layout]))
- -- ^ mapping of workspaces
- -- to descriptions of their layouts
- }
+ , layouts :: !(M.Map WorkspaceId (Layout, [Layout])) }
+ -- ^ mapping of workspaces to descriptions of their layouts
hunk ./XMonad.hs 54
- , focusedBorder :: !Color -- ^ border color of the focused window
- }
+ , focusedBorder :: !Color } -- ^ border color of the focused window
hunk ./XMonad.hs 96
--- 'doLayout', a pure function to layout a Window set
--- 'modifyLayout',
+-- 'doLayout', a pure function to layout a Window set 'modifyLayout',
+-- 'modifyLayout' can be considered a branch of an exception handler.
+--
hunk ./XMonad.hs 100
- , modifyLayout :: Dynamic -> Maybe Layout }
+ , modifyLayout :: SomeMessage -> Maybe Layout }
+
+-- Based on ideas in /An Extensible Dynamically-Typed Hierarchy of Exceptions/,
+-- Simon Marlow, 2006. Use extensible messages to the modifyLayout handler.
+--
+-- User-extensible messages must be a member of this class:
+--
+class (Typeable a, Show a) => Message a
+
+--
+-- A wrapped value of some type in the Message class.
+--
+data SomeMessage = forall a. Message a => SomeMessage a
+
+--
+-- And now, unwrap a given, unknown Message type, performing a (dynamic)
+-- type check on the result.
+--
+fromMessage :: Message m => SomeMessage -> Maybe m
+fromMessage (SomeMessage m) = cast m
}
Context:
[Handle empty layout lists
Spencer Janssen <sjanssen at cse.unl.edu>**20070504045644]
[refactoring, style, comments on new layout code
Don Stewart <dons at cse.unsw.edu.au>**20070504023618]
[use anyKey constant instead of magic number
Jason Creighton <jcreigh at gmail.com>**20070504015043]
[added mirrorLayout to mirror arbitrary layouts
Jason Creighton <jcreigh at gmail.com>**20070504014653]
[Fix layout switching order
Spencer Janssen <sjanssen at cse.unl.edu>**20070503235632]
[More Config.hs bugs
Spencer Janssen <sjanssen at cse.unl.edu>**20070503234607]
[Revert accidental change to Config.hs
Spencer Janssen <sjanssen at cse.unl.edu>**20070503233148]
[Add -fglasgow-exts for pattern guards. Properties.hs doesn't complain anymore
Spencer Janssen <sjanssen at cse.unl.edu>**20070503214221]
[Avoid the unsafe pattern match, in case Config.hs has no layouts
Spencer Janssen <sjanssen at cse.unl.edu>**20070503214007]
[add support for extensible layouts.
David Roundy <droundy at darcs.net>**20070503144750]
[comments. and stop tracing events to stderr
Don Stewart <dons at cse.unsw.edu.au>**20070503075821]
[-Wall police
Don Stewart <dons at cse.unsw.edu.au>**20070503074937]
[elaborate documentation in Config.hs
Don Stewart <dons at cse.unsw.edu.au>**20070503074843]
[Use updated refreshKeyboardMapping. Requires latest X11-extras
Spencer Janssen <sjanssen at cse.unl.edu>**20070503032040]
[run QC tests in addition to LOC test
Jason Creighton <jcreigh at gmail.com>**20070503003202]
[Add 'mod-n': refreshes current layout
Spencer Janssen <sjanssen at cse.unl.edu>**20070503002252]
[Fix tests after StackSet changes
Spencer Janssen <sjanssen at cse.unl.edu>**20070502201622]
[First steps to adding floating layer
Spencer Janssen <sjanssen at cse.unl.edu>**20070502195917]
[update motivational text using xmonad.org
Don Stewart <dons at cse.unsw.edu.au>**20070502061859]
[Sort dependencies in installation order
Spencer Janssen <sjanssen at cse.unl.edu>**20070501204249]
[Recommend X11-extras 0.1
Spencer Janssen <sjanssen at cse.unl.edu>**20070501204121]
[elaborate description in .cabal
Don Stewart <dons at cse.unsw.edu.au>**20070501035414]
[use -fasm by default. Much faster
Don Stewart <dons at cse.unsw.edu.au>**20070501031220]
[Make border width configurable
Spencer Janssen <sjanssen at cse.unl.edu>**20070430163515]
[Add Config.hs-boot, remove defaultLayoutDesc from XConf
Spencer Janssen <sjanssen at cse.unl.edu>**20070430162647]
[Comment only
Spencer Janssen <sjanssen at cse.unl.edu>**20070430161635]
[Comment only
Spencer Janssen <sjanssen at cse.unl.edu>**20070430161511]
[check we never generate invalid stack sets
Don Stewart <dons at cse.unsw.edu.au>**20070430065946]
[view n . shift n . view i . shift i) x == x --> shift + view is invertible
Don Stewart <dons at cse.unsw.edu.au>**20070430062901]
[add rotate all and view idempotency tests
Don Stewart <dons at cse.unsw.edu.au>**20070430055751]
[Add XConf for values that don't change.
Spencer Janssen <sjanssen at cse.unl.edu>**20070430054715]
[Control.Arrow is suspicious, add an explicit import
Spencer Janssen <sjanssen at cse.unl.edu>**20070430053623]
[push is idempotent
Don Stewart <dons at cse.unsw.edu.au>**20070430054345]
[add two properties relating to empty window managers
Don Stewart <dons at cse.unsw.edu.au>**20070430051016]
[configurable border colors
Jason Creighton <jcreigh at gmail.com>**20070430043859
This also fixes a bug where xmonad was assuming a 24-bit display, and just
using, eg, 0xff0000 as an index into a colormap without querying the X server
to determine the proper pixel value for "red".
]
[new QC property: opening a window only affects the current screen
Don Stewart <dons at cse.unsw.edu.au>**20070430050133]
[a bit more precise about building non-empty stacksets for one test
Don Stewart <dons at cse.unsw.edu.au>**20070430035729]
[remove redundant call to 'delete' in 'shift'
Don Stewart <dons at cse.unsw.edu.au>**20070430031151]
[clean 'delete' a little
Don Stewart <dons at cse.unsw.edu.au>**20070430025319]
[shrink 'swap'
Don Stewart <dons at cse.unsw.edu.au>**20070430024813]
[shrink 'rotate' a little
Don Stewart <dons at cse.unsw.edu.au>**20070430024525]
[move size into Properties.hs
Don Stewart <dons at cse.unsw.edu.au>**20070430021758]
[don't need 'size' operation on StackSet
Don Stewart <dons at cse.unsw.edu.au>**20070430015927]
[avoid grabbing all keys when a keysym is undefined
Jason Creighton <jcreigh at gmail.com>**20070428180046
XKeysymToKeycode() returns zero if the keysym is undefined. Zero also happens
to be the value of AnyKey.
]
[add homepage: field to .cabal file
Don Stewart <dons at cse.unsw.edu.au>**20070429041011]
[add fromList to Properties.hs
Don Stewart <dons at cse.unsw.edu.au>**20070429035823]
[move fromList into Properties.hs, -17 loc
Don Stewart <dons at cse.unsw.edu.au>**20070429035804]
[Further refactoring
Spencer Janssen <sjanssen at cse.unl.edu>**20070426212257]
[Refactor in Config.hs (no real changes)
Spencer Janssen <sjanssen at cse.unl.edu>**20070426211407]
[Add the manpage to extra-source-files
Spencer Janssen <sjanssen at cse.unl.edu>**20070426014105]
[add xmonad manpage
David Lazar <davidlazar at styso.com>**20070426010812]
[Remove toList
Spencer Janssen <sjanssen at cse.unl.edu>**20070426005713]
[Ignore numlock and capslock in keybindings
Jason Creighton <jcreigh at gmail.com>**20070424013357]
[Clear numlock bit
Spencer Janssen <sjanssen at cse.unl.edu>**20070424010352]
[force window border to 1px
Jason Creighton <jcreigh at gmail.com>**20070423050824]
[s/creigh//
Don Stewart <dons at cse.unsw.edu.au>**20070423024026]
[some other things to do
Don Stewart <dons at cse.unsw.edu.au>**20070423023151]
[Start TODOs for 0.2
Spencer Janssen <sjanssen at cse.unl.edu>**20070423021526]
[update readme
Don Stewart <dons at cse.unsw.edu.au>**20070422090507]
[TAG 0.1
Spencer Janssen <sjanssen at cse.unl.edu>**20070422083033]
Patch bundle hash:
28177163852c07f1fc191ac89148c43e45866f30
More information about the Xmonad
mailing list