How to switch xmonad workspace and notify the current workspace's tag or name under full screen without bar? - xmonad

I connfig the xmonad workspaces as follows
myWorkspaces = map show [1..20 :: Int]
[((mod4Mask .|. m, k), windows $ f i)
| (i, k) <- zip myWorkspaces ([xK_1 .. xK_9] ++ [xK_0] ++ [xK_F1 .. xK_F10])
, (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask), (copy, mod3Mask)]
]
And I want to use notify-send shell command to show the current workspace number when switch to a certain workspace.
So how to define a function to greedyView the workspace and show the notification?

ok, I solved the problem by myself.
[((mod4Mask .|. m, k), workspaceHint f i)
| (i, k) <- zip myWorkspaces ([xK_1 .. xK_9] ++ [xK_0] ++ [xK_F1 .. xK_F10])
, (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask), (copy, mod3Mask)]
]
notifyWSHint :: String -> X()
notifyWSHint index = spawn $ "notify-send -t 500 \"workspace: " ++ index ++ "\""
workspaceHint f i = do
windows $ f i
notifyWSHint i

Related

Use IO when creating Xmonad configuration (keymap depends on number of connected monitors)

I'm trying to set up different Xmonad key mappings depending on the number of connected monitors. The reason is that I use the same Xmonad config file on multiple systems (desktops, a laptop with different monitor configurations including 3 displays). Displays are listed in a different order on different systems, that's why I need to hardcode display indices when using a 3 monitor setup.
My current best try is something like that (everything that is not relevant has been removed):
import qualified Graphics.X11.Xlib as X11
import qualified Graphics.X11.Xinerama as X11
screenKeysFor2Monitors conf#(XConfig {XMonad.modMask = modMask}) = M.fromList $
[((m .|. mod4Mask, key), screenWorkspace sc >>= flip whenJust (windows . f)) -- Replace 'mod1Mask' with your mod key of choice.
| (key, sc) <- zip [xK_w, xK_e] [0, 1] -- Usual screen order
, (f, m) <- [(W.view, 0), (W.shift, shiftMask), (W.greedyView, mod1Mask)]]
screenKeysFor3Monitors conf#(XConfig {XMonad.modMask = modMask}) = M.fromList $
[((m .|. mod4Mask, key), screenWorkspace sc >>= flip whenJust (windows . f)) -- Replace 'mod1Mask' with your mod key of choice.
| (key, sc) <- zip [xK_w, xK_e, xK_q] [0, 2, 1] -- hardcoded according to laptop driver
, (f, m) <- [(W.view, 0), (W.shift, shiftMask), (W.greedyView, mod1Mask)]]
screenKeys x = do
numberOfScreens <- getScreens
keyConfig <- case numberOfScreens of
3 -> screenKeysFor3Monitors x
_ -> screenKeysFor2Monitors x
return keyConfig
-- | Get number of screens
getScreens = do
screens <- do
dpy <- X11.openDisplay ""
rects <- X11.getScreenInfo dpy
X11.closeDisplay dpy
return rects
pure $ length screens
xmonadConfig = ewmh xfceConfig{
modMask = mod4Mask
keys = MyKeys.screenKeys
}
I get this error
Error detected while loading xmonad configuration file: /home/me/.xmonad/xmonad.hs
lib/MyXMonad/Keys.hs:51:64: error:
* Couldn't match expected type `M.Map (KeyMask, KeySym) (X ())`
with actual type `IO (X ())`
* In the expression: (screenKeys x)
In the second argument of `($)`, namely
`[(myKeysToAdd x), (workspaceKeys x), (screenKeys x)]`
In the expression:
M.unions $ [(myKeysToAdd x), (workspaceKeys x), (screenKeys x)]
|
51 | keysToAdd x = M.unions $ [(myKeysToAdd x), (workspaceKeys x), (screenKeys x)]
| ^^^^^^^^^^^^
lib/MyXMonad/Keys.hs:242:30: error:
* Couldn't match type `M.Map (KeyMask, KeySym)` with `IO`
Expected type: IO (X ())
Actual type: M.Map (KeyMask, KeySym) (X ())
* In the expression: screenKeysFor3Monitors x
In a case alternative: 3 -> screenKeysFor3Monitors x
In a stmt of a 'do' block:
keyConfig <- case numberOfScreens of
3 -> screenKeysFor3Monitors x
_ -> screenKeysFor2Monitors x
|
242 | 3 -> screenKeysFor3Monitors x
| ^^^^^^^^^^^^^^^^^^^^^^^^
lib/MyXMonad/Keys.hs:243:30: error:
* Couldn't match type `M.Map (KeyMask, KeySym)` with `IO`
Expected type: IO (X ())
Actual type: M.Map (KeyMask, KeySym) (X ())
* In the expression: screenKeysFor2Monitors x
In a case alternative: _ -> screenKeysFor2Monitors x
In a stmt of a 'do' block:
keyConfig <- case numberOfScreens of
3 -> screenKeysFor3Monitors x
_ -> screenKeysFor2Monitors x
|
243 | _ -> screenKeysFor2Monitors x
| ^^^^^^^^^^^^^^^^^^^^^^^^
Please check the file for errors.
If I understand correctly, the problem here is that my code depends on side effects (working with monitor configuration uses IO monad) and becomes non-pure. I can convert IO monad to X monad using liftIO. But the X monad is accessible only inside key binding handlers. The code that creates key bindings for Xmonad configuration has to be pure, and X monad is not expected here.
In other words, if I get the situation right, it's not possible to define key bindings using non-pure functions (e.g. by looking on connected monitors). Maybe there is some workaround? I lack a decent understanding of Haskell and maybe I'm missing something obvious for regular Haskell programmers.
not too familiar with Xmonad but you can easily do the following I guess. create a pure function mkConfig which takes the number of screens and returns the desired key mapping. Then, in your main pass it to xmonad function. I haven't tried to compile any of this but probably you can modify it easily
mkConfig numberOfScreens = -- Notice that this is a pure function
case numberOfScreens of
3 -> screenKeysFor3Monitors x
_ -> screenKeysFor2Monitors x
main :: IO ()
main = do
numberOfScreens <- getScreens -- Retrive the number of screens from the system
let keyConfig = mkConfig numberOfScreens -- Makes a key mapping out of this
xmonadConfig = ewmh xfceConfig{ modMask = mod4Mask, keys = keyConfig } -- Creates a Xmonad configuration
xmonad xmonadConfig -- Launch Xmonad.

Updating visibility of dynamically created content

Duplicating this from github as per #HeinrichApfelmus's suggestion:
This may be just a usage error on my part, but I am noticing a strange phenomenon when trying to set up conditional visibility/layout for dynamically created UI elements (in WX of course). As somewhat of a toy-example, I tried to create a widget that created StaticText elements on the fly and allowed the user to "browse" through these elements through '<' '>' buttons.
The problem I am noting is that all labels are invisible until a new one is created, at which point the current widget in focus becomes visible. Whether this is a bug or just a paradigm I am misusing, or a subtlety with reactive frameworks, I am unsure as to how to resolve this. Here is the code I have at this point, which exhibits the problem:
{-# LANGUAGE RecursiveDo #-}
module Test.Adder where
import Reactive.Banana
import Reactive.Banana.WX
import Graphics.UI.WX.Attributes
import Graphics.UI.WX hiding (Event, newEvent, empty, Identity)
import Graphics.UI.WXCore hiding (Event, Timer, empty, Identity, newEvent)
import Graphics.UI.WXCore.Frame
-- | Combine Unit-Events
anyEvent :: [Event ()] -> Event ()
anyEvent = foldl1 (unionWith (\_ _ -> ()))
-- | Unsugared if-then-else function
if_ :: Bool -> a -> a -> a
if_ True x _ = x
if_ False _ y = y
-- | Apply a function to the value at an index, or return a default value
-- if the index is out of range
(!?) :: (a -> b) -> b -> Int -> ([a] -> b)
(f!? ~y) n xs
| n < 0 = y
| otherwise = case drop n xs of
x:_ -> f x
[] -> y
main :: IO ()
main = start test
create :: Window w -> Int -> Behavior Int -> Event Int -> Event () -> MomentIO (StaticText ())
create t i bi ei eRef = do
let tx = replicate i '\t' ++ show i
x <- liftIO $ staticText t [ text := tx ]
let beq = (==i) <$> bi
let eMe = filterE (==i) ei
sink x [ visible :== beq ]
reactimate (refresh x <$ anyEvent [ eRef, () <$ eMe ])
return x
test :: IO ()
test = do
f <- frame [text := "Test"]
add <- button f [ text := "+" ]
prv <- button f [ text := "<" ]
cur <- staticText f []
nxt <- button f [ text := ">" ]
tab <- panel f [ clientSize := sz 200 300 ]
deb <- staticText f []
ref <- button f [ text := "refresh" ]
let networkDescription :: MomentIO ()
networkDescription = mdo
eAdd <- event0 add command
eRef <- event0 ref command
let bNotFirst = (>0) <$> bCur
bNotLast = (<) <$> bCur <*> bNext
sink prv [ enabled :== bNotFirst ]
sink cur [ text :== show <$> bCur ]
sink nxt [ enabled :== bNotLast ]
ePrev <- event0 prv command
eNext <- event0 nxt command
let eDelta :: Enum n => Event (n -> n)
eDelta = unions [ pred <$ whenE bNotFirst ePrev
, succ <$ whenE bNotLast eNext ]
eChange = flip ($) <$> bCur <#> eDelta
bCur <- stepper 0 $ eChange
(eIndex, bCount) <- mapAccum 0 ((\x -> (x, succ x)) <$ eAdd)
let bView = (\n i -> if_ (n==0) (0) i) <$> bCount <*> bCur
bNext = pred <$> bCount
eCreate = (\n -> create tab n bView eChange $ anyEvent [eRef,eAdd]) <$> eIndex
reCreate <- execute eCreate
bItemer <- accumB id $ flip (.) . (:) <$> reCreate
let bItems = ($[]) <$> bItemer
bThis = (widget!?(nullLayouts!!0)) <$> bCur <*> bItems
sink tab [ layout :== bThis ]
liftIO $ set f [ layout := column 5 [ margin 10 $ row 5 [ widget add
, widget prv
, widget cur
, widget nxt
, widget ref
]
, fill $ widget tab
]
]
network <- compile networkDescription
actuate network
>

Managing memory usage with infinite lists

So I am trying to find ways to make the number 5 using the number 15
import Data.List
import Control.Monad
import Control.Monad.Omega
import System.IO
data Expr = X | Sub Expr Expr | Div Expr Expr | Pow Expr Expr
deriving Show
eval x X = x
eval x (Sub a b) = eval x a - eval x b
eval x (Div a b) = eval x a / eval x b
eval x (Pow a b) = eval x a ** eval x b
exprs | v <- each exprs
= (X:) . concat $ transpose
[ runOmega $ liftM2 Div v v
, runOmega $ liftM2 Sub v v
, runOmega $ liftM2 Pow v v
]
main = do
hSetBuffering stdout LineBuffering
mapM_ print $ filter ((==5).eval 15) exprs
However, the first result is the 118588079th element in the list, and Haskell runs out of memory long before getting there. How do I know the first one is 118588079? Because if I just calculate it and ask for the index instead, Haskell uses no memory at all:
run x | v <- each $ run x
= (x:) . concat $ transpose
[ runOmega $ liftM2 (/ ) v v
, runOmega $ liftM2 (- ) v v
, runOmega $ liftM2 (**) v v
]
main = print . map snd . filter ((==5).fst) $ zip (run 15) [0..]
Where exactly is my memory going in the first case, and how do I get around it?
A top level binding like
list = [1..1000000]
will lazily produce the list once, and keep it in memory for subsequent use.
A function, instead,
fun x = [1..1000000]
will allocate a new list at every call, recomputing it (lazily) from scratch every time. Because it's referred by a top level binding, it will never be garbage collected.
Note that this is not mandated by Haskell -- it's just GHC which works in this way.
For comparison, try this variant:
run x | v <- each $ run x
= (x:) . concat $ transpose
[ runOmega $ liftM2 (/ ) v v
, runOmega $ liftM2 (- ) v v
, runOmega $ liftM2 (**) v v
]
run15 = run 15
main = print . map snd . filter ((==5).fst) $ zip run15 [0..]
You should see a lot of memory being consumed, since no garbage collection can happen. Instead,
main = print . map snd . filter ((==5).fst) $ zip run15 [0..]
where
run15 = run 15
should allow for garbage collection and run in a small amount of memory.
(By the way, that use of a pattern binding instead of let/where puzzled me for a while.)
#chi is exactly right. A function with no arguments is not really a function, and will be kept in memory, regardless of how recursive it is, whether it produces an infinite datastructure or not. This will cause you to run out of memory:
run' | v <- each run'
= (15:) . concat $ transpose
[ runOmega $ liftM2 (/ ) v v
, runOmega $ liftM2 (- ) v v
, runOmega $ liftM2 (**) v v
]
main = print $ run' !! 1000000000
while the first run function will not. On the same note- despite looking silly- this will not run out of memory:
exprs' x | v <- each $ exprs' x
= (x:) . concat $ transpose
[ runOmega $ liftM2 Div v v
, runOmega $ liftM2 Sub v v
, runOmega $ liftM2 Pow v v
]
main = print $ exprs' X !! 1000000000
PS
If anyone is curious, the 118588079th element in the list was ((((x**x)/x)-(x**(x-(x/x))))-((x-x)-(x/x)))

Haskell - how to change the show to get the right output

I have defined these datatypes which I am trying to create and print now.
type TNonTerminal = String -- will be creating own ones where [A-Z] won't be enough
type TTerminals = Char
type TSymbols = String -- both terminals and nonterminals
data Rule = Rule
{ leftSide :: TNonTerminal
, rightSide :: [TSymbols]
} deriving (Eq)
data RightLinearGrammar = RLG
{ nonterminals :: [TNonTerminal]
, terminals :: [TTerminals]
, firstNonterminal :: TNonTerminal
, rules :: [Rule]
} deriving (Eq)
So I also created those Show instances
instance Show Rule where
show (Rule ls rs) = show ls ++ "->" ++ show rs ++ "\n"
instance Show RightLinearGrammar where
show (RLG n t fn r) = show n ++ "\n" ++ show t ++ "\n" ++ show fn ++ "\n" ++ show r ++ "\n"
And I get this output (for clarification I created the Type RightLinearGrammar and called putStr $ show rlg):
["A","B"] -- [TNonTerminal]
"abc" -- [TTerminals]
"A" -- TNonTerminal
["A"->["aaB"] --
,"A"->["ccB"]
,"B"->["bB"] -- [Rule]
,"B"->["#"]
] --
How should I change the code to get better output like this one?
A,B
a,b,c
A
A->aaB
A->ccB
B->bB
B->#
show is by default going to give you quotes around strings and brackets around lists. If you just go back to concatenating strings and joining lists with commas or newlines, you should get the output you're expecting:
import Data.List (intercalate)
instance Show Rule where
show (Rule ls rs) = ls ++ "->" ++ intercalate "," rs
instance Show RightLinearGrammar where
show (RLG n t fn r) = intercalate "," n ++ "\n" ++ t ++ "\n" ++ fn ++ "\n" ++ (intercalate "\n" $ map show r) ++ "\n"
You either need to replace your type synonyms with newtypes, and define show on them to do what you want, or more likely replace the calls to show in your instances with calls to a custom formatter function.
Note: show is really not the right function for what you're trying to do, since it usually produces output you could paste back into ghci and arguably should be limitted to that use. You could easily define your own function and use it like this:
formatRule :: Rule -> String
formatRule (Rule ls rs) = ls ++ "->" ++ concat (intersperse "," rs) ++ "\n"
formatRightLinearGrammar :: RightLinearGrammar -> String
formatRightLinearGrammar (RLG n t fn r) =
concat (intersperse "," n) ++ "\n"
++ intersperse ',' t ++ "\n"
++ fn ++ "\n"
++ concat (map formatRule r)
Note: this is going to be fairly inefficient for large grammars; you might want to consider re-writing it as
formatRule :: Rule -> String -> String
formatRule (Rule ls rs) = (ls++) . ("->"++) . concatDS (intersperse "," rs) . ("\n"++)
formatRightLinearGrammar :: RightLinearGrammar -> String
formatRightLinearGrammar (RLG n t fn r) =
concatDS (intersperse "," n) $ ("\n"++) $
(intersperse ',' t ++) $ ("\n"++) $
(fn++) $ ("\n"++) $
foldr formatRule "" r
concatDS ss s' = foldr (++) s' ss

How can I toggle between physical displays in a single keystroke?

The following lines bind mod-[wer] to going to displays 1, 2 and 3. Instead of this mechanism, I'd like to toggle between displays in a single keystroke, How can I do so?
Thanks.
[((m .|. modm, key), screenWorkspace sc >>= flip whenJust (windows . f))
| (key, sc) <- zip [xK_e, xK_w, xK_r] [0..]
, (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]
Have a look at:
http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Actions-CycleWS.html#1
Don't forget the import line import XMonad.Actions.CycleWS

Resources