You are not logged in.

#1 2011-05-18 22:52:07

archtaku
Member
Registered: 2010-07-02
Posts: 84

[SOLVED] xmonad: different values for parameters depending on hostname

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 " ++ myDzenGenOpts

Clearly 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

#2 2011-06-07 23:01:47

vogt
Member
From: Toronto, Canada
Registered: 2006-11-25
Posts: 389

Re: [SOLVED] xmonad: different values for parameters depending on hostname

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 " ++ myDzenGenOpts

Or 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 above

Offline

#3 2011-06-07 23:05:24

archtaku
Member
Registered: 2010-07-02
Posts: 84

Re: [SOLVED] xmonad: different values for parameters depending on hostname

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

#4 2011-06-20 20:12:34

listdata
Member
Registered: 2008-12-23
Posts: 102
Website

Re: [SOLVED] xmonad: different values for parameters depending on hostname

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

#5 2011-06-20 20:21:18

archtaku
Member
Registered: 2010-07-02
Posts: 84

Re: [SOLVED] xmonad: different values for parameters depending on hostname

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

#6 2011-06-20 20:29:43

listdata
Member
Registered: 2008-12-23
Posts: 102
Website

Re: [SOLVED] xmonad: different values for parameters depending on hostname

archtaku wrote:

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

#7 2011-06-27 04:07:47

archtaku
Member
Registered: 2010-07-02
Posts: 84

Re: [SOLVED] xmonad: different values for parameters depending on hostname

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

#8 2011-06-27 14:39:08

listdata
Member
Registered: 2008-12-23
Posts: 102
Website

Re: [SOLVED] xmonad: different values for parameters depending on hostname

archtaku wrote:

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.hs

or

xmonad --recompile

to 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. wink

Offline

#9 2011-06-27 16:10:04

archtaku
Member
Registered: 2010-07-02
Posts: 84

Re: [SOLVED] xmonad: different values for parameters depending on hostname

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

#10 2011-06-28 04:44:13

listdata
Member
Registered: 2008-12-23
Posts: 102
Website

Re: [SOLVED] xmonad: different values for parameters depending on hostname

Mark as solved? wink

Offline

#11 2011-06-28 15:41:43

archtaku
Member
Registered: 2010-07-02
Posts: 84

Re: [SOLVED] xmonad: different values for parameters depending on hostname

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

Board footer

Powered by FluxBB