ymonad-0.1.0.0: src/YMonad/Core/Reduce.hs
module YMonad.Core.Reduce (
reduce,
relayoutRequests,
) where
import Data.List (partition)
import Data.Map.Strict qualified as M
import YMonad.Core.Layout
import YMonad.Core.StackSet
import YMonad.Core.Types
reduce :: RuntimeState -> YEvent -> Transition
reduce st ev = case ev of
EvViewMapped vid meta ->
let ws' = insertUp vid (rtWindowSet st)
st' = st {rtWindowSet = ws', rtViews = M.insert vid meta (rtViews st)}
in Transition st' (relayoutRequests st')
EvViewUnmapped vid ->
let ws' = delete vid (rtWindowSet st)
st' = st {rtWindowSet = ws', rtViews = M.delete vid (rtViews st)}
in Transition st' (ReqHideView vid : relayoutRequests st')
EvOutputAdded oid info ->
let currentScreen = current (rtWindowSet st)
ws' =
(rtWindowSet st)
{ current = currentScreen {screenRect = outputRect info}
}
st' = st {rtWindowSet = ws', rtOutputs = M.insert oid info (rtOutputs st)}
in Transition st' (relayoutRequests st')
EvOutputRemoved oid ->
let st' = st {rtOutputs = M.delete oid (rtOutputs st)}
in Transition st' []
EvFocusChanged Nothing -> Transition st [ReqFocusView Nothing, ReqCommit]
EvFocusChanged (Just vid) ->
let ws' = focusWindow vid (rtWindowSet st)
st' = st {rtWindowSet = ws'}
in Transition st' (relayoutRequests st')
EvUserCommand cmd -> reduceCommand st cmd
EvBackendFault fault -> Transition (st {rtLastFault = Just fault}) []
reduceCommand :: RuntimeState -> UserCommand -> Transition
reduceCommand st cmd = case cmd of
CmdFocusNext ->
let st' = st {rtWindowSet = focusUp (rtWindowSet st)}
in Transition st' (relayoutRequests st')
CmdFocusPrev ->
let st' = st {rtWindowSet = focusDown (rtWindowSet st)}
in Transition st' (relayoutRequests st')
CmdSwapNext ->
let st' = st {rtWindowSet = swapUp (rtWindowSet st)}
in Transition st' (relayoutRequests st')
CmdSwapPrev ->
let st' = st {rtWindowSet = swapDown (rtWindowSet st)}
in Transition st' (relayoutRequests st')
CmdKillFocused -> case peek (rtWindowSet st) of
Nothing -> Transition st []
Just vid -> Transition st [ReqCloseView vid, ReqCommit]
CmdViewWorkspace wid ->
let st' = st {rtWindowSet = view wid (rtWindowSet st)}
in Transition st' (relayoutRequests st')
CmdMoveFocusedTo wid ->
let st' = st {rtWindowSet = shift wid (rtWindowSet st)}
in Transition st' (relayoutRequests st')
CmdToggleFullscreen -> toggleCurrentWorkspaceFullscreen st
CmdCycleLayout -> applyCurrentLayoutMessage (MsgChangeLayout NextLayout) st
CmdShrink -> applyCurrentLayoutMessage (MsgResize Shrink) st
CmdExpand -> applyCurrentLayoutMessage (MsgResize Expand) st
CmdIncMasterN delta -> applyCurrentLayoutMessage (MsgIncMasterN (IncMasterN delta)) st
CmdExitSession -> Transition st [ReqExitSession]
applyCurrentLayoutMessage :: LayoutMessage -> RuntimeState -> Transition
applyCurrentLayoutMessage message st =
let ws' =
modifyCurrentWorkspace
( \workspace ->
let oldLayout = workspaceLayout workspace
newLayout = applyLayoutMessage message oldLayout
restoreLayout =
if description oldLayout == "Full" && description newLayout /= "Full"
then Nothing
else workspaceRestoreLayout workspace
in workspace
{ workspaceLayout = newLayout
, workspaceRestoreLayout = restoreLayout
}
)
(rtWindowSet st)
st' = st {rtWindowSet = ws'}
in Transition st' (relayoutRequests st')
relayoutRequests :: RuntimeState -> [BackendReq]
relayoutRequests st = map mkShow placementPairs ++ styleRequests ++ hideRequests ++ focusRequest ++ [ReqCommit]
where
currentScreen = current (rtWindowSet st)
currentWorkspace = screenWorkspace currentScreen
placements = layoutViews (workspaceLayout currentWorkspace) (screenRect currentScreen) (workspaceStack currentWorkspace)
placementPairs = focusFirst focusedView placements
active = map fst placementPairs
hideRequests = [ReqHideView vid | vid <- M.keys (rtViews st), vid `notElem` active]
focusRequest = case focusedView of
Nothing -> [ReqFocusView Nothing]
Just vid -> [ReqFocusView (Just vid)]
styleRequests = map mkStyle active
focusedView = peek (rtWindowSet st)
theme = rtTheme st
mkShow (vid, rect) = ReqSetViewRect vid rect
mkStyle vid =
ReqSetViewStyle
vid
ViewStyle
{ viewStyleTitleBarMode = themeTitleBarMode theme
, viewStyleBorderWidth = themeBorderWidth theme
, viewStyleBorderColor = if Just vid == focusedView then themeFocusedBorderColor theme else themeNormalBorderColor theme
}
toggleCurrentWorkspaceFullscreen :: RuntimeState -> Transition
toggleCurrentWorkspaceFullscreen st =
let ws' =
modifyCurrentWorkspace
( \workspace ->
let currentLayout = workspaceLayout workspace
in if description currentLayout == "Full"
then
workspace
{ workspaceLayout = fromMaybe currentLayout (workspaceRestoreLayout workspace)
, workspaceRestoreLayout = Nothing
}
else
workspace
{ workspaceLayout = applyLayoutMessage (MsgJumpToLayout "Full") currentLayout
, workspaceRestoreLayout = Just currentLayout
}
)
(rtWindowSet st)
st' = st {rtWindowSet = ws'}
in Transition st' (relayoutRequests st')
focusFirst :: (Eq a) => Maybe a -> [(a, b)] -> [(a, b)]
focusFirst Nothing xs = xs
focusFirst (Just focused) xs = focusedPairs ++ otherPairs
where
(focusedPairs, otherPairs) = partition ((== focused) . fst) xs