Advertisement
Guest User

Untitled

a guest
Dec 31st, 2022
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE FlexibleContexts, TypeSynonymInstances, MultiParamTypeClasses, ScopedTypeVariables #-}
  2.  
  3. -- | A layout modifier, that "pops" the focused window, making it
  4. -- | larger and moving it somewhat towards the centre
  5. -- | This can be useful if your usual layout provides a good overview, but you
  6. -- | often find yourself full-screening windows are focussing them to get to the
  7. -- | details they contain.
  8. -- | If you switch focus, the previously focussed window will return to it's usual
  9. -- | size, and the newly focussed window will be popped instead.
  10. -- | The "strengh" parameter determines how much "pop" will be applied - the
  11. -- | larger this number the more of the screen the popped window will occupy.
  12. -- | As the strength paramater tends to infinity, the popped window becomes
  13. -- | full-screen.
  14. -- | I use this LayoutModifier in a MultiToggle group alongsize NBFULL, on
  15. -- | adjacent keys ("M-;" and "M-S-;") to give me quickly accessible options
  16. -- | around zooming a window.
  17.  
  18. module PopOnFocus where
  19.  
  20. import Data.Map (Map)
  21. import Data.Ratio
  22. import qualified Data.Map as Map
  23. import qualified Data.Set as Set
  24.  
  25. import XMonad
  26. import XMonad.Layout.MultiToggle
  27. import qualified XMonad.StackSet as S
  28. import XMonad.Layout.LayoutModifier
  29. import XMonad.Prelude ( partition )
  30.  
  31. data POPALL = POPALL deriving (Eq, Show, Read)
  32.  
  33. -- This transformer doesn't actually do anything - is just exists so we can query if it's on or off
  34. instance Transformer POPALL Window where
  35.     transform _ x k = k x id
  36.  
  37. data PopOnFocus a =
  38.   PopOnFocus
  39.     { globalPop :: !Bool
  40.     , defaultGlobalStrength :: !Int
  41.     , globalStrength :: !Int
  42.     , windowStrength :: !(Map Window Int)
  43.     } deriving ( Read, Show, Eq )
  44.  
  45. data PopOnFocusMessage = MakeBigger Window | MakeSmaller Window | MakeNormal Window
  46.  
  47. instance Message PopOnFocusMessage
  48.  
  49. popOnFocus :: LayoutClass l Window => Int -> l Window -> ModifiedLayout PopOnFocus l Window
  50. popOnFocus globalStrength
  51.   | globalStrength >= 1 = ModifiedLayout $ PopOnFocus False globalStrength globalStrength Map.empty
  52.  
  53. instance LayoutModifier PopOnFocus Window where
  54.     modifierDescription _ = "PopOnFocus"
  55.     pureModifier m rect (Just (S.Stack focused _ _)) wrs =
  56.       case if (globalPop m)
  57.              then Just (globalStrength m)
  58.              else Map.lookup focused (windowStrength m)
  59.         of Nothing -> (wrs, Nothing)
  60.            Just strength ->
  61.              let (toMax, rest) = partition (\(w, _) -> w == focused) wrs
  62.                  maxed = map (\(w, before) -> (w, embiggen strength before rect)) toMax
  63.               in (maxed ++ rest, Nothing)
  64.     pureModifier _ _ _ wrs = (wrs, Nothing)
  65.  
  66.     pureMess m@(PopOnFocus { globalPop = True })  mess =
  67.       case fromMessage mess
  68.         of Nothing -> Nothing
  69.            Just (MakeBigger w) -> Just (m { globalStrength = succ (globalStrength m)})
  70.            Just (MakeSmaller w) -> Just (m { globalStrength = max 1 (pred (globalStrength m))})
  71.            Just (MakeNormal w) -> Just (m { globalStrength = defaultGlobalStrength m})
  72.     pureMess m@(PopOnFocus { globalPop = False })  mess =
  73.       case fromMessage mess
  74.         of Nothing -> Nothing
  75.            Just (MakeBigger w) ->
  76.              let tagged' = Map.alter (\f -> case f
  77.                                             of Nothing -> Just 1
  78.                                                Just x -> Just (succ x))
  79.                             w (windowStrength m)
  80.              in Just (m { windowStrength = tagged'})
  81.            Just (MakeSmaller w) ->
  82.              let tagged' = Map.alter (\f -> case f
  83.                                             of Nothing -> Nothing
  84.                                                Just x ->
  85.                                                  if x == 1 then
  86.                                                    Nothing
  87.                                                else
  88.                                                    Just (pred x))
  89.                             w (windowStrength m)
  90.              in Just (m { windowStrength = tagged' })
  91.            Just (MakeNormal w) -> Just (m { windowStrength = Map.delete w (windowStrength m)})
  92.  
  93.     handleMess m0 mess | Just Hide <- fromMessage mess             = doUnhook
  94.                        | Just ReleaseResources <- fromMessage mess = doUnhook
  95.                        | otherwise =
  96.                           case pureMess m0 mess
  97.                             of Nothing -> return Nothing
  98.                                Just m1 -> withWindowSet (\ws -> return $ Just $ m1 { windowStrength =  removeDeadWindows ws (windowStrength m1)})
  99.       where
  100.         doUnhook = do unhook m0; return Nothing
  101.  
  102.         removeDeadWindows ws tagged = Map.filterWithKey (\w _ -> Set.member w ws') tagged
  103.            where
  104.                ws' = Set.fromList $ S.allWindows ws
  105.  
  106.     redoLayout m r ms wrs = do
  107.         m' <- updateFlag m
  108.        hook m'
  109.         case pureModifier m' r ms wrs
  110.          of (wrs, Nothing) -> return (wrs, Just m')
  111.              (wrs, Just m'') -> return (wrs, Just m'')
  112.  
  113.  
  114. updateFlag m = do
  115.   popAll <- withWindowSet (isToggleActive POPALL . S.workspace . S.current)
  116.   case popAll
  117.     of Nothing -> return m
  118.        Just popAll' -> return m { globalPop = popAll' }
  119.  
  120. embiggen :: Int -> Rectangle -> Rectangle -> Rectangle
  121. embiggen strength inner outter = fromCentreSpan icx' icy' icw' ich'
  122.   where
  123.     (icx, icy, iw, ih) = toCentreSpan inner
  124.     (ocx, ocy, ow, oh) = toCentreSpan outter
  125.     (icx', icw') = transformLineSegment strength icx iw ocx ow
  126.     (icy', ich') = transformLineSegment strength icy ih ocy oh
  127.  
  128. -- The function controls how we transform the windows.
  129. -- It's applied twice, once for each dimension.
  130. -- The inner segment is made more like the outter segment, depending on the strength parameter.
  131. -- Note that we move the centre of the segment a bit more aggressively than the
  132. -- length - this is so windows pop towards the centre, which gives a bit of a
  133. -- sense as to where in the layout they came from
  134. transformLineSegment :: Int -> Rational -> Rational -> Rational -> Rational -> (Rational, Rational)
  135. transformLineSegment strength ic il oc ol = ((f2'*ic)+(f2*oc), (f'*il)+(f*ol))
  136.   where
  137.     f = strengthToFrac strength
  138.     f2 = strengthToFrac (succ strength)
  139.     f' = 1 - f
  140.    f2' = 1 - f2
  141.  
  142. toCentreSpan :: Rectangle -> (Rational, Rational, Rational, Rational)
  143. toCentreSpan r = (x + (w/2), y+(h/2), w, h)
  144.   where
  145.     x = fromIntegral $ rect_x r
  146.     y = fromIntegral $ rect_y r
  147.     w = fromIntegral $ rect_width r
  148.     h =  fromIntegral $ rect_height r
  149.  
  150. fromCentreSpan :: Rational -> Rational -> Rational -> Rational -> Rectangle
  151. fromCentreSpan cx cy w h = Rectangle (floor (cx-(w/2))) (floor (cy-(h/2))) (ceiling w) (ceiling h)
  152.  
  153. strengthToFrac n
  154.   | n < 0 = error "strengthToFrac"
  155.   | otherwise = fromIntegral n % (succ (fromIntegral n))
  156.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement