You are not logged in.
I've been using xmonad for a week or so and am starting to dig further into Haskell as I continue to tweak my configuration (which is a modified version of this). What I would like to do is use a single ~/.xmonad directory on several machines (synced via Dropbox), with an xmonad.hs that will automatically load the right values (specifically the widths for multiple dzen2 bars that sit side by side) based on the hostname. I saw there is a haskell-hostname package in the AUR, and here is the documentation for the module it provides, but I'm tripping up on the syntax.
What I would like to do is something like this:
-- retrieve hostname
myHostName = getHostName
-- set host-specific options:
case myHostName of
"host1" -> myStatusBar = "dzen2 -w 1280 -ta l " ++ myDzenGenOpts
myConkyBar = "conky -c ~/.xmonad/conky_bar.host1 | dzen2 -x 1280 -w 400 -ta r " ++ myDzenGenOpts
"host2" -> myStatusBar = "dzen2 -w 584 -ta l " ++ myDzenGenOpts
myConkyBar = "conky -c ~/.xmonad/conky_bar.host2 | dzen2 -x 584 -w 440 -ta r " ++ myDzenGenOptsClearly I'm misunderstanding either the case statement syntax, or how to use the HostName module.
However, now that I think of it, since the xmonad.hs is recompiled when you launch xmonad, perhaps it isn't such a good idea to use a single .xmonad directory. Perhaps a local .xmonad directory on each box, with the xmonad.hs symlinked to my dropbox folder, would be a better idea. I would like to use the same config file on both machines, though.
Last edited by archtaku (2011-06-28 15:42:43)
Offline
This is one option, if you trust the hostname never to change / throw an error you'd like to recover elsewhere from:
import System.IO.Unsafe
{-# NOINLINE myHostName #-}
myHostName = unsafePerformIO getHostName
-- then define these myFoo separately like:
myStatusBar = case myHostName of
"host1" -> "dzen2 -w 1280 -ta l " ++ myDzenGenOpts
"host2" -> "dzen2 -w 584 -ta l " ++ myDzenGenOptsOr if the hostname is ok to be chosen at compile time:
{-# LANGUAGE TemplateHaskell #-} -- at the very top
import Language.Haskell.TH
[d| myHostName = $(stringE =<< runIO getHostName ) |]
-- use myHostName just like the unsafePerformIO option aboveOffline
Thanks for the reply. I've been reading up on Haskell and learning the syntax, and I was about to tackle this again. So, your reply is a big help. Will try this sometime soon.
Offline
Hello archtaku,
Did you get it working? Here's my setup in xmonad.hs:
...
import System.Posix.Unistd -- for getting hostname
...
main = do
hostname <- fmap nodeName getSystemID
xmonad $ ewmh defaultConfig
{ terminal = myTerminal
, focusFollowsMouse = myFocusFollowsMouse
, borderWidth = myBorderWidth
, modMask = myModMask
, numlockMask = myNumlockMask
, workspaces = myWorkspaces
, normalBorderColor = myNormalBorderColor
, focusedBorderColor = myFocusedBorderColor
, keys = myKeys hostname
, mouseBindings = myMouseBindings
, layoutHook = myLayout
, manageHook = myManageHook
, handleEventHook = myEventHook
, logHook = myLogHook
, startupHook = myStartupHook hostname
}
...
myStartupHook :: String -> X ()
myStartupHook hostname =
do {
; case hostname of
"foo" -> do { blah blah blah ...
; blah blah blah...
; blah blah blah...
}
"bar" -> do { blah blah blah...
}
_ -> return ()
}Those explicit braces and semicolons are from my early Haskell days (you don't need them if you have proper indentation). And if you want to customize your dzen stuff, I think this should work (I'm using the code from the link you provided):
import System.Posix.Unistd -- for getting hostname
...
main = do
hostname <- fmap nodeName getSystemID
myStatusBarPipe <- spawnPipe (myStatusBar hostname)
-- or, if you want to be more Haskell-ish: myStatusBarPipe <- spawnPipe $ myStatusBar hostname
conkyBar <- spawnPipe myConkyBar
xmonad $ myUrgencyHook $ defaultConfig
{ terminal = "urxvt"
, normalBorderColor = myInactiveBorderColor
, focusedBorderColor = myActiveBorderColor
, manageHook = manageDocks <+> myManageHook <+> manageHook defaultConfig
, layoutHook = avoidStruts $ myLayoutHook
, startupHook = setWMName "LG3D"
, logHook = dynamicLogWithPP $ myDzenPP myStatusBarPipe
, modMask = mod4Mask
, keys = myKeys
, workspaces = myWorkspaces
}
-- Status Bar
-- BTW, explicit typesignatures are a MUST if you're a beginner...
myStatusBar :: String -> String
myStatusBar theHostnameArgumentToThisFunction = case theHostnameArgumentToThisFunction of
"fooMachine" -> "dzen2 -w 665 -ta l " ++ myDzenGenOpts
"barMachine" -> "dzen2 -w 200 -ta l " ++ myDzenGenOpts
_ -> "dzen2 -w 665 -ta l " ++ myDzenGenOpts
-- here's a less repetitive version:
myStatusBar :: String -> String
myStatusBar theHostnameArgumentToThisFunction = "dzen2 -w " ++ width ++ " -ta l " ++ myDzenGenOpts
where
width = case theHostnameArgumentToThisFunction of
"fooMachine" -> "665"
"barMachine" -> "200"
_ -> "500"The key is to first do the IO stuff from the main function, then pass in the value (hostname) into those functions that need it (in this case, your myStatusBar function, which was just a function that returned a string, but now returns a string based on the input string). I named the input string "theHostnameArgumentToThisFunction" so that you get the idea. Refactoring/extending is ridiculously easy in Haskell...
EDIT: added a less repetitive version for myStatusBar
Last edited by listdata (2011-06-20 20:26:02)
Offline
Still haven't gotten the chance to work on it. Work has been hectic lately, and when I get a chance to have a weekend there's usually something going on then too. Hope to get a couple hours to myself by this upcoming weekend to do this.
Thanks to both of you for your recommendations. Given what I've seen here, I have no doubt I'll get it working. Was just a matter of getting the proper syntax. The problem I was having before, I think, was that I was treating Haskell as a procedural language instead of the functional language it is (which is, I'm guessing, a common mistake among Haskell n00bs).
Last edited by archtaku (2011-06-20 20:21:44)
Offline
Still haven't gotten the chance to work on it. Work has been hectic lately, and when I get a chance to have a weekend there's usually something going on then too. Hope to get a couple hours to myself by this upcoming weekend to do this.
Thanks to both of you for your recommendations. Given what I've seen here, I have no doubt I'll get it working. Was just a matter of getting the proper syntax. The problem I was having before, I think, was that I was treating Haskell as a procedural language instead of the functional language it is (which is, I'm guessing, a common mistake among Haskell n00bs).
Ah, I see. Well, I hope you get it all sorted out soon (more Haskell => better world).
As for the procedural vs. functional paradigms, yep, that's a common mistake (which is the same mistake from your original posted config). You need monads to take care of sequential computations (the "do" keyword block, in this case). And for some reason monads have a very bad reputation (it's just chained computations...).
Good luck on your Haskell journey!
Offline
OK, I believe I have it working! Will have to test this on the workstation in my office on Tuesday, but it's working on my netbook. Here's what I went with:
...
import System.Posix.Unistd
...
main = do
hostname <- fmap nodeName getSystemID
myStatusBarPipe <- spawnPipe $ myStatusBar hostname
conkyBar <- spawnPipe $ myConkyBar hostname
xmonad $ myUrgencyHook $ defaultConfig
{ terminal = "urxvt"
, normalBorderColor = myInactiveBorderColor
, focusedBorderColor = myActiveBorderColor
, manageHook = manageDocks <+> myManageHook <+> manageHook defaultConfig
, layoutHook = avoidStruts $ myLayoutHook
, startupHook = setWMName "ERIK"
, modMask = mod4Mask
, logHook = dynamicLogWithPP $ myDzenPP myStatusBarPipe
, keys = myKeys
, workspaces = myWorkspaces
}
...
-- Status Bar
myStatusBar :: String -> String
myStatusBar x = "dzen2 -w " ++ sb_width ++ " -ta l " ++ myDzenGenOpts
where
sb_width = case x of
"XXXXXXXXXXX" -> "1280"
"YYYYYY" -> "462"
_ -> "512"
-- Conky Bar
myConkyBar :: String -> String
myConkyBar x = "conky -c ~/.xmonad/conky/conky_bar." ++ x ++ " | dzen2 -x " ++ cb_indent ++ " -w " ++ cb_width ++ " -ta r " ++ myDzenGenOpts
where
cb_indent = case x of
"XXXXXXXXXXX" -> "1280"
"YYYYYY" -> "462"
_ -> "512"
cb_width = case x of
"XXXXXXXXXXX" -> "400"
"YYYYYY" -> "562"
_ -> "512"
...Will post back once I've had a chance to test this on another computer, but I'm pretty sure this will do what I want. I moved the location of the conky config files, and the new path is reflected in the instance of conky presently running on my netbook.
Thanks for nudging me in the right direction!
Last edited by archtaku (2011-06-27 04:09:33)
Offline
OK, I believe I have it working! Will have to test this on the workstation in my office on Tuesday, but it's working on my netbook. Here's what I went with:
... import System.Posix.Unistd ... main = do hostname <- fmap nodeName getSystemID myStatusBarPipe <- spawnPipe $ myStatusBar hostname conkyBar <- spawnPipe $ myConkyBar hostname xmonad $ myUrgencyHook $ defaultConfig { terminal = "urxvt" , normalBorderColor = myInactiveBorderColor , focusedBorderColor = myActiveBorderColor , manageHook = manageDocks <+> myManageHook <+> manageHook defaultConfig , layoutHook = avoidStruts $ myLayoutHook , startupHook = setWMName "ERIK" , modMask = mod4Mask , logHook = dynamicLogWithPP $ myDzenPP myStatusBarPipe , keys = myKeys , workspaces = myWorkspaces } ... -- Status Bar myStatusBar :: String -> String myStatusBar x = "dzen2 -w " ++ sb_width ++ " -ta l " ++ myDzenGenOpts where sb_width = case x of "XXXXXXXXXXX" -> "1280" "YYYYYY" -> "462" _ -> "512" -- Conky Bar myConkyBar :: String -> String myConkyBar x = "conky -c ~/.xmonad/conky/conky_bar." ++ x ++ " | dzen2 -x " ++ cb_indent ++ " -w " ++ cb_width ++ " -ta r " ++ myDzenGenOpts where cb_indent = case x of "XXXXXXXXXXX" -> "1280" "YYYYYY" -> "462" _ -> "512" cb_width = case x of "XXXXXXXXXXX" -> "400" "YYYYYY" -> "562" _ -> "512" ...Will post back once I've had a chance to test this on another computer, but I'm pretty sure this will do what I want. I moved the location of the conky config files, and the new path is reflected in the instance of conky presently running on my netbook.
Thanks for nudging me in the right direction!
Awesome! But next time, to avoid any xmonad errors, you should always try either:
ghci xmonad.hsor
xmonad --recompileto see that all of your types match/line up properly (if they don't, there will be a slew of error messages thrown at you; otherwise, it's fine). And, you can always do
xmonad --recompile; xmonad --restart to test everything in one go. ![]()
Offline
Yep, I learned to do this from the rebinded Mod-q in the xmonad.hs which I used as a starting point for my config, otherwise it wouldn't have occurred to me to try this from the terminal first.
-- Do not leave useless conky, dzen and xxkb after restart
, ((modm, xK_q), spawn "killall conky dzen2 xxkb; xmonad --recompile; xmonad --restart")Offline
Mark as solved? ![]()
Offline
Like I said earlier, I had to test this shared xmonad.hs on a 2nd computer to be 100% sure. Good news: it works. Marking as solved.
Offline