|
XMonad.StackSet | Portability | portable, Haskell 98 | Stability | experimental | Maintainer | dons@galois.com |
|
|
|
|
|
Description |
|
|
Synopsis |
|
data StackSet i l a sid sd = StackSet {} | | data Workspace i l a = Workspace {} | | data Screen i l a sid sd = Screen {} | | data Stack a = Stack {} | | data RationalRect = RationalRect Rational Rational Rational Rational | | new :: Integral s => l -> [i] -> [sd] -> StackSet i l a s sd | | view :: (Eq s, Eq i) => i -> StackSet i l a s sd -> StackSet i l a s sd | | greedyView :: (Eq s, Eq i) => i -> StackSet i l a s sd -> StackSet i l a s sd | | lookupWorkspace :: Eq s => s -> StackSet i l a s sd -> Maybe i | | screens :: StackSet i l a s sd -> [Screen i l a s sd] | | workspaces :: StackSet i l a s sd -> [Workspace i l a] | | allWindows :: Eq a => StackSet i l a s sd -> [a] | | peek :: StackSet i l a s sd -> Maybe a | | index :: StackSet i l a s sd -> [a] | | integrate :: Stack a -> [a] | | integrate' :: Maybe (Stack a) -> [a] | | differentiate :: [a] -> Maybe (Stack a) | | focusUp :: StackSet i l a s sd -> StackSet i l a s sd | | focusDown :: StackSet i l a s sd -> StackSet i l a s sd | | focusMaster :: StackSet i l a s sd -> StackSet i l a s sd | | focusWindow :: (Eq s, Eq a, Eq i) => a -> StackSet i l a s sd -> StackSet i l a s sd | | tagMember :: Eq i => i -> StackSet i l a s sd -> Bool | | renameTag :: Eq i => i -> i -> StackSet i l a s sd -> StackSet i l a s sd | | ensureTags :: Eq i => l -> [i] -> StackSet i l a s sd -> StackSet i l a s sd | | member :: Eq a => a -> StackSet i l a s sd -> Bool | | findTag :: Eq a => a -> StackSet i l a s sd -> Maybe i | | mapWorkspace :: (Workspace i l a -> Workspace i l a) -> StackSet i l a s sd -> StackSet i l a s sd | | mapLayout :: (l -> l') -> StackSet i l a s sd -> StackSet i l' a s sd | | insertUp :: Eq a => a -> StackSet i l a s sd -> StackSet i l a s sd | | delete :: (Ord a, Eq s) => a -> StackSet i l a s sd -> StackSet i l a s sd | | delete' :: (Eq a, Eq s) => a -> StackSet i l a s sd -> StackSet i l a s sd | | filter :: (a -> Bool) -> Stack a -> Maybe (Stack a) | | swapUp :: StackSet i l a s sd -> StackSet i l a s sd | | swapDown :: StackSet i l a s sd -> StackSet i l a s sd | | swapMaster :: StackSet i l a s sd -> StackSet i l a s sd | | modify :: Maybe (Stack a) -> (Stack a -> Maybe (Stack a)) -> StackSet i l a s sd -> StackSet i l a s sd | | modify' :: (Stack a -> Stack a) -> StackSet i l a s sd -> StackSet i l a s sd | | float :: Ord a => a -> RationalRect -> StackSet i l a s sd -> StackSet i l a s sd | | sink :: Ord a => a -> StackSet i l a s sd -> StackSet i l a s sd | | shift :: (Ord a, Eq s, Eq i) => i -> StackSet i l a s sd -> StackSet i l a s sd | | shiftWin :: (Ord a, Eq a, Eq s, Eq i) => i -> a -> StackSet i l a s sd -> StackSet i l a s sd | | abort :: String -> a |
|
|
|
Introduction
|
|
The StackSet data type encodes a window manager abstraction. The
window manager is a set of virtual workspaces. On each workspace is a
stack of windows. A given workspace is always current, and a given
window on each workspace has focus. The focused window on the current
workspace is the one which will take user input. It can be visualised
as follows:
Workspace { 0*} { 1 } { 2 } { 3 } { 4 }
Windows [1 [] [3* [6*] []
,2*] ,4
,5]
Note that workspaces are indexed from 0, windows are numbered
uniquely. A * indicates the window on each workspace that has
focus, and which workspace is current.
|
|
The Zipper
|
|
We encode all the focus tracking directly in the data structure, with a zipper:
A Zipper is essentially an updateable and yet pure functional
cursor into a data structure. Zipper is also a delimited
continuation reified as a data structure.
The Zipper lets us replace an item deep in a complex data
structure, e.g., a tree or a term, without an mutation. The
resulting data structure will share as much of its components with
the old structure as possible.
Oleg Kiselyov, 27 Apr 2005, haskell@, Zipper as a delimited continuation
We use the zipper to keep track of the focused workspace and the
focused window on each workspace, allowing us to have correct focus
by construction. We closely follow Huet's original implementation:
G. Huet, Functional Pearl: The Zipper,
1997, J. Functional Programming 75(5):549-554.
and:
R. Hinze and J. Jeuring, Functional Pearl: The Web.
and Conor McBride's zipper differentiation paper.
Another good reference is:
The Zipper, Haskell wikibook
|
|
Xinerama support
|
|
Xinerama in X11 lets us view multiple virtual workspaces
simultaneously. While only one will ever be in focus (i.e. will
receive keyboard events), other workspaces may be passively
viewable. We thus need to track which virtual workspaces are
associated (viewed) on which physical screens. To keep track of
this, StackSet keeps separate lists of visible but non-focused
workspaces, and non-visible workspaces.
|
|
Master and Focus
|
|
Each stack tracks a focused item, and for tiling purposes also tracks
a master position. The connection between master and focus
needs to be well defined, particularly in relation to insert and
delete.
|
|
data StackSet i l a sid sd | Source |
|
API changes from xmonad 0.1:
StackSet constructor arguments changed. StackSet workspace window screen
- new, -- was: empty
- view,
- index,
- peek, -- was: peek/peekStack
- focusUp, focusDown, -- was: rotate
- swapUp, swapDown
- focus -- was: raiseFocus
- insertUp, -- was: insert/push
- delete,
- swapMaster, -- was: promote/swap
- member,
- shift,
- lookupWorkspace, -- was: workspace
- visibleWorkspaces -- gone.
A cursor into a non-empty list of workspaces.
We puncture the workspace list, producing a hole in the structure
used to track the currently focused workspace. The two other lists
that are produced are used to track those workspaces visible as
Xinerama screens, and those workspaces not visible anywhere.
| Constructors | StackSet | | current :: !(Screen i l a sid sd) | currently focused workspace
| visible :: [Screen i l a sid sd] | non-focused workspaces, visible in xinerama
| hidden :: [Workspace i l a] | workspaces not visible anywhere
| floating :: Map a RationalRect | floating windows
|
|
| Instances | (Eq i, Eq l, Eq a, Eq sid, Eq sd) => Eq (StackSet i l a sid sd) | (Ord a, Read i, Read l, Read a, Read sid, Read sd) => Read (StackSet i l a sid sd) | (Show i, Show l, Show a, Show sid, Show sd) => Show (StackSet i l a sid sd) |
|
|
|
|
A workspace is just a tag - its index - and a stack
| Constructors | | Instances | |
|
|
data Screen i l a sid sd | Source |
|
Visible workspaces, and their Xinerama screens.
| Constructors | Screen | | workspace :: !(Workspace i l a) | | screen :: !sid | | screenDetail :: !sd | |
|
| Instances | (Eq i, Eq l, Eq a, Eq sid, Eq sd) => Eq (Screen i l a sid sd) | (Read i, Read l, Read a, Read sid, Read sd) => Read (Screen i l a sid sd) | (Show i, Show l, Show a, Show sid, Show sd) => Show (Screen i l a sid sd) |
|
|
|
|
A stack is a cursor onto a (possibly empty) window list.
The data structure tracks focus by construction, and
the master window is by convention the top-most item.
Focus operations will not reorder the list that results from
flattening the cursor. The structure can be envisaged as:
+-- master: < '7' >
up | [ '2' ]
+--------- [ '3' ]
focus: < '4' >
dn +----------- [ '8' ]
A Stack can be viewed as a list with a hole punched in it to make
the focused position. Under the zipper/calculus view of such
structures, it is the differentiation of a [a], and integrating it
back has a natural implementation used in index.
| Constructors | Stack | | focus :: !a | | up :: [a] | | down :: [a] | |
|
| Instances | |
|
|
|
A structure for window geometries
| Constructors | | Instances | |
|
|
Construction
|
|
|
|
|
O(n). Create a new stackset, of empty stacks, with given tags,
with physical screens whose descriptions are given by m. The
number of physical screens (length m) should be less than or
equal to the number of workspace tags. The first workspace in the
list will be current.
Xinerama: Virtual workspaces are assigned to physical screens, starting at 0.
|
|
|
O(w). Set focus to the workspace with index 'i'.
If the index is out of range, return the original StackSet.
Xinerama: If the workspace is not visible on any Xinerama screen, it
becomes the current screen. If it is in the visible list, it becomes
current.
|
|
|
Set focus to the given workspace. If that workspace does not exist
in the stackset, the original workspace is returned. If that workspace is
hidden, then display that workspace on the current screen, and move the
current workspace to hidden. If that workspace is visible on another
screen, the workspaces of the current screen and the other screen are
swapped.
|
|
Xinerama operations
|
|
Xinerama in X11 lets us view multiple virtual workspaces
simultaneously. While only one will ever be in focus (i.e. will
receive keyboard events), other workspaces may be passively
viewable. We thus need to track which virtual workspaces are
associated (viewed) on which physical screens. To keep track of
this, StackSet keeps separate lists of visible but non-focused
workspaces, and non-visible workspaces.
|
|
|
Find the tag of the workspace visible on Xinerama screen sc.
Nothing if screen is out of bounds.
|
|
|
Get a list of all screens in the StackSet.
|
|
|
Get a list of all workspaces in the StackSet.
|
|
|
Get a list of all windows in the StackSet in no particular order
|
|
Operations on the current stack
|
|
|
|
|
O(1). Extract the focused element of the current stack.
Return Just that element, or Nothing for an empty stack.
|
|
|
O(s). Extract the stack on the current workspace, as a list.
The order of the stack is determined by the master window -- it will be
the head of the list. The implementation is given by the natural
integration of a one-hole list cursor, back to a list.
|
|
|
O(n). Flatten a Stack into a list.
|
|
|
O(n) Flatten a possibly empty stack into a list.
|
|
|
O(n). Turn a list into a possibly empty stack (i.e., a zipper):
the first element of the list is current, and the rest of the list
is down.
|
|
|
|
|
O(1), O(w) on the wrapping case.
focusUp, focusDown. Move the window focus up or down the stack,
wrapping if we reach the end. The wrapping should model a cycle
on the current stack. The master window, and window order,
are unaffected by movement of focus.
swapUp, swapDown, swap the neighbour in the stack ordering, wrapping
if we reach the end. Again the wrapping model should cycle on
the current stack.
|
|
|
O(s). Set focus to the master window.
|
|
|
O(1) on current window, O(n) in general. Focus the window w,
and set its workspace as current.
|
|
|
Is the given tag present in the StackSet?
|
|
|
Rename a given tag if present in the StackSet.
|
|
|
Ensure that a given set of workspace tags is present by renaming
existing workspaces and/or creating new hidden workspaces as
necessary.
|
|
|
O(n). Is a window in the StackSet.
|
|
|
O(1) on current window, O(n) in general.
Return Just the workspace tag of the given window, or Nothing
if the window is not in the StackSet.
|
|
|
Map a function on all the workspaces in the StackSet.
|
|
|
Map a function on all the layouts in the StackSet.
|
|
Modifying the stackset
|
|
|
|
|
O(n). (Complexity due to duplicate check). Insert a new element
into the stack, above the currently focused element. The new
element is given focus; the previously focused element is moved
down.
If the element is already in the stackset, the original stackset is
returned unmodified.
Semantics in Huet's paper is that insert doesn't move the cursor.
However, we choose to insert above, and move the focus.
|
|
|
O(1) on current window, O(n) in general. Delete window w if it exists.
There are 4 cases to consider:
- delete on an Nothing workspace leaves it Nothing
* otherwise, try to move focus to the down
* otherwise, try to move focus to the up
* otherwise, you've got an empty workspace, becomes Nothing
Behaviour with respect to the master:
- deleting the master window resets it to the newly focused window
* otherwise, delete doesn't affect the master.
|
|
|
Only temporarily remove the window from the stack, thereby not destroying special
information saved in the Stackset
|
|
|
O(n). 'filter p s' returns the elements of s such that p evaluates to
True. Order is preserved, and focus moves as described for delete.
|
|
Setting the master window
|
|
|
|
|
|
|
|
|
O(s). Set the master window to the focused window.
The old master window is swapped in the tiling order with the focused window.
Focus stays with the item moved.
|
|
|
Apply a function, and a default value for Nothing, to modify the current stack.
|
|
|
Apply a function to modify the current stack if it isn't empty, and we don't
want to empty it.
|
|
|
Given a window, and its preferred rectangle, set it as floating
A floating window should already be managed by the StackSet.
|
|
|
Clear the floating status of a window
|
|
Composite operations
|
|
|
|
|
O(w). shift. Move the focused element of the current stack to stack
n, leaving it as the focused element on that stack. The item is
inserted above the currently focused element on that workspace.
The actual focused workspace doesn't change. If there is no
element on the current stack, the original stackSet is returned.
|
|
|
O(n). shiftWin. Searches for the specified window w on all workspaces
of the stackSet and moves it to stack n, leaving it as the focused
element on that stack. The item is inserted above the currently
focused element on that workspace.
The actual focused workspace doesn't change. If the window is not
found in the stackSet, the original stackSet is returned.
TODO how does this duplicate shifts behaviour?
|
|
|
this function indicates to catch that an error is expected
|
|
Produced by Haddock version 2.4.2 |