Xmonad и 2 монитора [решено]

Имею 2 монитора, все работает замечательно (проприетарные драйверы nvidia, Twinview, xcompmgr). Одна проблема - не могу заставить Xmonad на основном мониторе выводить одни рабочие столы с программами, а на дополнительном мониторе - другие. Нагуглил, что для этого надо бы использовать XMonad.Layout.IndependentScreens, включил, реально количество рабочих столов удвоилось, но как присвоить конкретному монитору конкретные рабочие столы - не понимаю. Xmonad их сам тасует как хочет. Отключил greedyView, заменил на просто view - без толку. Либо вообще ничего не уходить на второй монитор, либо уходит, и как-то странно. Xmonad (а также contrib и utils) из darcs.

Мой текущий конфиг:
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances, FlexibleContexts, NoMonomorphismRestriction #-}
import XMonad
import qualified XMonad.StackSet as W -- to shift and float windows
import Data.Ratio
import qualified Data.Map as M
import XMonad.Actions.CycleWS
import XMonad.Actions.WindowGo
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Hooks.FadeInactive
import XMonad.Hooks.DynamicLog
import XMonad.Layout.Grid
import XMonad.Layout.LayoutModifier
import XMonad.Layout.PerWorkspace
import XMonad.Layout.LayoutCombinators hiding ( (|||) )
import XMonad.Layout.IM
import XMonad.Layout.IndependentScreens
import XMonad.Layout.ShowWName
import XMonad.Util.EZConfig
import XMonad.Util.Run
import XMonad.Util.WindowProperties
import Control.Monad
import Graphics.X11.ExtraTypes.XF86
import Foreign.C.Types
-- Взять значение свойства окна
getProp :: Atom -> Window -> X (Maybe [CLong])
getProp a w = withDisplay $ \dpy -> io $ getWindowProperty32 dpy a w
-- Эта функция проверяет, выставлено ли свойство окна name в значение value
checkAtom name value = ask >>= \w -> liftX $ do
          a <- getAtom name
          val <- getAtom value
          mbr <- getProp a w
          case mbr of
            Just [r] -> return $ elem (fromIntegral r) [val]
            _ -> return False
-- Эта функция проверяет, является ли окно диалогом
checkDialog = checkAtom "_NET_WM_WINDOW_TYPE" "_NET_WM_WINDOW_TYPE_DIALOG"
-- Отрывающиеся (tear-off) меню
checkMenu = checkAtom "_NET_WM_WINDOW_TYPE" "_NET_WM_WINDOW_TYPE_MENU"
basicLayout = Mirror tiled where
    tiled = Tall nmaster delta ratio
    nmaster = 1
    delta   = 2/100
    ratio   = 3/7
basicALayout = avoidStruts $ basicLayout
tallLayout = Mirror basicLayout
tallALayout = avoidStruts $ Mirror basicLayout
imLayout = withIMs ratio rosters chatLayout where
    chatLayout      = Mirror Grid
    ratio           = 1%5
    rosters         = [skypeRoster, pidginRoster]
    pidginRoster    = (ClassName "Pidgin") `And` (Role "buddy_list")
    --skypeRoster     = (ClassName "Skype") `And` (Not (Title "Options")) `And` (Not (Role "Chats")) `And` (Not (Title "*чат")) `And` (Not (Role "CallWindowForm"))
    skypeRoster     = (Title "evvproffessorr - Skype™ (Beta)")
myLayoutHook = fullscreen $ iml $ normal where
    normal     = basicLayout ||| basicALayout ||| tallLayout ||| tallALayout ||| Full
    fullscreen = onWorkspace "0_music, 1_music, 0_video, 1_video" Full
    iml         = onWorkspace "1_im" imLayout
    --av         = onWorkspace "7, 9" basicALayout
manageMenus = checkMenu --> doFloat
manageDialogs = checkDialog --> doFloat
imManageHooks = composeAll . concat $
     [ [className =? "Firefox" --> moveTo "1_firefox"]
     , [title =? d --> doFloat | d <- myTFloats]
     , [className =? c --> doFloat | c <- myFloats]
     , [className =? a --> moveTo "1_im" | a <- myIMs]
     , [title =? "NCMPC" --> moveTo "4"]
     , [title =? "SMPlayer" --> moveTo "5"]
     , [className =? "Krusader" --> moveTo "1_main"]
     , [className =? "Wine" --> moveTo "1_wine"]
     , [title =? "Sun VirtualBox" --> moveTo "8"]
     , [className =? b --> doIgnore | b <- myIgnores]
     , [className =? "Basket" --> moveTo "9"]
     ,[isFullscreen --> (doF W.focusDown <+> doFullFloat)]
     ]
     where
       --moveTo = doF . W.shift
       moveTo = doShift
       myIMs = ["Pidgin", "Skype"]
       myIgnores = ["Qt-subapplication", "Plasma"]
       myFloats = ["KMix", "Gimp-2.6", "Wine"]
       myTFloats = ["Firefox Preferences", "Составление фильтра для Adblock Plus"]
myManageHook = imManageHooks <+> manageMenus <+> manageDialogs
myLogHook :: X ()
myLogHook = fadeInactiveLogHook fadeAmount
    where fadeAmount = 0x66666666
-- | Data type for LayoutModifier which converts given layout to IM-layout
-- (with dedicated space for the roster and original layout for chat windows)
data AddRosters a = AddRosters Rational [Property] deriving (Read, Show)
instance LayoutModifier AddRosters Window where
  modifyLayout (AddRosters ratio props) = applyIMs ratio props
  modifierDescription _                = "IMs"
-- | Modifier which converts given layout to IMs-layout (with dedicated
-- space for rosters and original layout for chat windows)
withIMs :: LayoutClass l a => Rational -> [Property] -> l a -> ModifiedLayout AddRosters l a
withIMs ratio props = ModifiedLayout $ AddRosters ratio props
-- | IM layout modifier applied to the Grid layout
gridIMs :: Rational -> [Property] -> ModifiedLayout AddRosters Grid a
gridIMs ratio props = withIMs ratio props Grid
hasAnyProperty :: [Property] -> Window -> X Bool
hasAnyProperty [] _ = return False
hasAnyProperty (p:ps) w = do
    b <- hasProperty p w
    if b then return True else hasAnyProperty ps w
-- | Internal function for placing the rosters specified by
-- the properties and running original layout for all chat windows
applyIMs :: (LayoutClass l Window) =>
               Rational
            -> [Property]
            -> W.Workspace WorkspaceId (l Window) Window
            -> Rectangle
            -> X ([(Window, Rectangle)], Maybe (l Window))
applyIMs ratio props wksp rect = do
    let stack = W.stack wksp
    let ws = W.integrate' $ stack
    rosters <- filterM (hasAnyProperty props) ws
    let n = fromIntegral $ length rosters
    let (rostersRect, chatsRect) = splitHorizontallyBy (n * ratio) rect
    let rosterRects = splitHorizontally n rostersRect
    let filteredStack = stack >>= W.filter (`notElem` rosters)
    wrs <- runLayout (wksp {W.stack = filteredStack}) chatsRect
    return ((zip rosters rosterRects) ++ fst wrs, snd wrs)
myMouseBindings (XConfig {XMonad.modMask = mod4Mask}) = M.fromList $
    [ ((0, 9), (\_ -> toggleWS)),
      ((mod4Mask, button1), (\w -> focus w >> mouseMoveWindow w)),
      ((mod4Mask, button3), (\w -> focus w >> mouseResizeWindow w))
    ]
--myWorkspaces =
  --withScreens 1 ["first"]["main","firefox","im","music","video","wine","virtualbox","smth","smth2"]
  --withScreens 2 ["second"]["info","chats","player","films"]
myWorkspaces = withScreens 2 ["main","firefox","im","music","video","wine","virtualbox","smth","smth2"]
main = do
  xmonad $ defaultConfig {
    modMask = mod4Mask
    , layoutHook = showWName myLayoutHook
    , manageHook = myManageHook
    , workspaces = myWorkspaces
    , borderWidth = 0
    , logHook = myLogHook
    , terminal = "urxvt"
    , mouseBindings = myMouseBindings
    }
    `additionalKeysP`
    [ ("M1-<F4>", kill)
	, ("M1-<Tab>", windows W.focusDown)
	, ("M1-S-<Tab>", windows W.focusUp)
     , ("<XF86Explorer>", spawn "urxvt")
     , ("<XF86Launch3>", spawn "urxvt --title NCMPC -e ncmpc -c -m -S")
     , ("<XF86Launch5>", spawn "~/.mpd/playlist.sh")
     , ("<XF86Launch6>", spawn "urxvt -e ssh -p 43434 [email protected]")
     , ("<XF86Launch7>", spawn "urxvt -e ssh -p 43434 [email protected]")
     , ("<XF86Launch9>", prevWS)
     , ("<XF86Mail>", toggleWS)
     , ("<XF86Favorites>", nextWS)
     , ("<XF86MenuKB>", windows $ W.view "3")
     , ("S-<XF86MenuKB>", (windows $ W.shift "3") >> (windows $ W.view "3"))
     , ("C-<XF86MenuKB>", windows $ W.view "6")
     , ("<XF86Sleep>", spawn "sudo pm-suspend")
     , ("<XF86AudioLowerVolume>", spawn "amixer -q set Master 1- unmute")
     , ("<XF86AudioRaiseVolume>", spawn "amixer -q set Master 1+ unmute")
     , ("<XF86MyComputer>", spawn "gmrun")
    ]

Вот тут: http://www.haskell.org/haskellwiki/Xmon … esktops.29 пишут, что еще надо горячие клавиши настроить. Но так, как там пишут, у меня не получается, Xmonad на myWorkspaces ругается, а если заменить на Xmonad.workspaces, то опять же ругается.
P.S. Где б этому хаскелю нормально научится? А то может я бы и сам догадался, где проблема, да не могу в самом языке разобраться еще :(
В конец конфига, после main, надо добавить:
    `additionalKeysP`
    [("M-" ++ m ++ show k, windows $ onCurrentScreen f i)
     | (i, k) <- zip (workspaces defaultConfig) [1..9]
     , (f, m) <- [(W.greedyView, ""), (W.shift, "S-")]]
вместо того, чтобы добавлять все эти команды (только “++” вместо “additionalKeysP”) прямо в конец списка горячих клавиш.
 
Зарегистрироваться или войдите чтобы оставить сообщение.