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

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

Related

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

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

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.

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)))

Is it possible to clean some code using gtk2hs?

I'm starting a GUI with haskell and gtk2hs.
I've got a notebook widget and I want to switch pages with "F1, F2 ... F11" keys.
My working code is:
import Control.Monad.Trans (liftIO)
import Graphics.UI.Gtk
main = do
initGUI
builder <- builderNew
builderAddFromFile builder "M62.glade"
window <- builderGetObject builder castToWindow "window1"
notebook <- builderGetObject builder castToNotebook "notebook1"
window `on` keyPressEvent $ tryEvent $ do "F1" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 0
window `on` keyPressEvent $ tryEvent $ do "F2" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 1
window `on` keyPressEvent $ tryEvent $ do "F3" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 2
window `on` keyPressEvent $ tryEvent $ do "F4" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 3
window `on` keyPressEvent $ tryEvent $ do "F5" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 4
window `on` keyPressEvent $ tryEvent $ do "F6" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 5
window `on` keyPressEvent $ tryEvent $ do "F7" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 6
window `on` keyPressEvent $ tryEvent $ do "F8" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 7
window `on` keyPressEvent $ tryEvent $ do "F9" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 8
window `on` keyPressEvent $ tryEvent $ do "F10" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 9
window `on` keyPressEvent $ tryEvent $ do "F11" <- eventKeyName
liftIO $ notebookSetCurrentPage notebook 10
onDestroy window mainQuit
widgetShowAll window
mainGUI
Is there betters and/or concises ways to do it?
I've tried to handle it out of the 'main' but then only "F1" works.
I don't see how to manage this boilerplate.
I don't know much about gtk2hs, but using forM_ to loop over the key indices should go a long way. Also, it seems events are a MonadPlus, so pattern match failure can be favorably replaced with guard.
forM_ [0..10] $ \i -> do
let key = "F" ++ show (i + 1)
window `on` keyPressEvent $ tryEvent $ do
pressed <- eventKeyName
guard (pressed == key)
liftIO $ notebookSetCurrentPage notebook i
How about this:
window `on` keyPressEvent $ tryEvent $ do
'F':n_ <- eventKeyName
let (n, ""):_ = reads n_
liftIO . notebookSetCurrentPage notebook $ n - 1
This is hopelessly partial: there are two partial pattern matches that can throw an exception. But that's okay, because that's what tryEvent is for. At time of writing, all other answers involve registering many event handlers, whereas this one registers only one. This should have a (slight) performance advantage.
Try splitting the repeated part into a function, like this:
import Control.Monad
import Graphics.UI.Gtk
main = do
initGUI
builder <- builderNew
builderAddFromFile builder "M62.glade"
window <- builderGetObject builder castToWindow "window1"
notebook <- builderGetObject builder castToNotebook "notebook1"
-- Split the repeated code into a reusable function, like this
let registerKeyPressEvent n =
window `on` keyPressEvent $ tryEvent $ do
pressed <- eventKeyName
guard (pressed == ("F" ++ show (n + 1)))
liftIO $ notebookSetCurrentPage notebook n
-- Thanks to Tarmil for catching a bug in the code that used to be above.
-- Tarmil got it right, so I'm borrowing his/her version.
-- Then you can call it more than once
registerKeyPressEvent 0
registerKeyPressEvent 1
registerKeyPressEvent 2
registerKeyPressEvent 3
registerKeyPressEvent 4
registerKeyPressEvent 5
registerKeyPressEvent 6
registerKeyPressEvent 7
registerKeyPressEvent 8
registerKeyPressEvent 9
registerKeyPressEvent 10
-- But even that is too verbose.
-- You can shorten it even further like this:
mapM_ registerKeyPressEvent [0..10]
mapM is like map, except for monads. The type of map is:
map :: (a -> b) -> [a] -> [b]
meaning that it takes a function and applies it to every element of a list, returning the result. The type of mapM is:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
meaning that it takes a monadic function (such as registerKeyPressEvent, function in the IO monad that creates the side effect of registering a key press event). mapM then executes this function once for every element in the list, and not only collects the results into a list, but collects the monadic actions into the resulting monad, meaning that the side effects from running registerKeyPressEvent 11 times are performed in order.
The final piece of the puzzle is that you might get a type error if you use mapM, because it assumes you care about the resulting list, and therefore returns m [b]. However, in this case, the type of main is IO (), and () is not going to match up to [b]. You therefore want a slight variation on mapM that throws away the resulting list, only collecting the monadic actions:
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
This has the return type you're looking for.

XMobar is dying due to a problem in my Xmonad config, related to IO

This is a follow up to this question.
In pursuit of trying to find how many physical monitors I had, I came up with
screenCount :: X Int
screenCount = withDisplay (io.fmap length.getScreenInfo)
makeXMobars :: X [Handle] -- loads two xmobars per screen, one top & one bottom
makeXMobars = screenCount >>= (io.mapM spawnPipe.commandHandles )
where
commandHandles n = map ((\x -> "xmobar -x " ++ x).unwords) $ commandNames n
commandNames n = sequence [map show [0..n], map (\x -> "~/.xmobarrc" ++ x) ["Top", "Bottom"]]
myLogHook :: X ()
myLogHook = do
handles <- makeXMobars
dynamicLogWithPP $ defaultPP
{
ppOutput = \x -> mapM_ (`hPutStrLn` x) handles
}
myLogHook just drops in to the xmonad $ DefaultConfig. However, when I load XMonad the PipeReader for the top XMobars (on both screens) just shows updating for a little while, and then disappears, and refuses to come back when I reload. The bottom ones are perfectly happy.
Previously, I simply used for my ppOutput:
ppOutput = \x -> hPutStrLn xmobarTopScreen0 x >> hPutStrLn xmobarTopScreen1 x
which worked perfectly fine.
I assume I've made some error with my understanding of IO, rather than the code itself being bad per se, but I'm really not sure.
I suspect that you want to use map show [0 .. n-1] rather than map show [0 .. n]. I also suggest that you spawn the xmobar instances in main rather than in logHook, since the latter will spawn brand new copies of xmobar every time you do any xmonad action (like changing focus). As for screenCount, may I suggest countScreens from the IndependentScreens module?

Resources