Красные Кнопочки (red_buttons) wrote,
Красные Кнопочки
red_buttons

  • Mood:

xmonad, xmobar, friends

Тут обнаружилось, что я пропустил на XMonad и XMonadContrib суммарно больше полутысячи патчей и мне как-то стрёмно стало на версиях из репозитариев сидеть при такой дичайшей активности. Потому переполз на свеженький релизинг 0.5. В дальнейшем можно будет переползти на дистрибутивные бинарики, но что-то они там тормозят. А ещё тут cyber_lyric хотел потыкать и инструкцию. Вот инструкция.

Предположим, что делаем все телодвижения в ~/dev. И ставим всё в пределах ~, не загаживая систему. Ещё предположим, что мы лепим связку из xmonad и xmobar, в пользу которого я отказываюсь от связки из моего самописного скрипта и пары dzen2. Остальные программы, которые тут будут тоже настоятельно рекомендуются.

Зависимости



Сначала ставим GHC и хидеры для иксовых библиотек. У меня уже это есть, но вообще было бы aptitude install ghc6 libx11-dev.

Теперь нам нужен свежий Cabal. Если бы мы использовали ghc 6.8, то там он уж был бы, но его пока не нашлось. Потому делаем весьма тривиальные штуки:
cd ~/dev
wget http://hackage.haskell.org/packages/archive/Cabal/1.2.3.0/Cabal-1.2.3.0.tar.gz
tar xfv Cabal-1.2.3.0.tar.gz
rm -f Cabal-1.2.3.0.tar.gz
cd Cabal-1.2.3.0
runhaskell Setup.lhs configure --user --prefix=$HOME
runhaskell Setup.lhs build
runhaskell Setup.lhs install --user

Пьём чай, курим, разглядываем порнографический комикс, пока оно соберётся. Поставится оно в ~/lib.

Далее нам нужны хаскелльные либы mtl, unix, X11. Первые две уже были довольно свеженьких версий, а последнюю пришлось обновить, но там всё аналогично Cabal'у и нет смысла повторяться. Берётся всё опять же с http://hackage.haskell.org

XMonad, XMonadContrib, xmobar


C xmonad по сути тоже самое. На всякий случай:
wget http://hackage.haskell.org/packages/archive/xmonad/0.5/xmonad-0.5.tar.gz
tar xfv xmonad-0.5.tar.gz
rm -f xmonad-0.5.tar.gz
cd xmonad-0.5
runhaskell Setup.lhs configure --user --prefix=$HOME
runhaskell Setup.lhs build
runhaskell Setup.lhs install --user

Бинарик положится в ~/bin/xmonad и ещё чуть-чуть в ~/lib.
Тут самое интересное то, что теперь конфиг вкомпиливать не надобно в бинарь.

Аналогично делаем с XMonadContrib, ибо голый xmonad весьма гол. Теперь мы имеем в ~/lib ещё и экстеншены.

Также нас интересует программа xmobar, которая берётся всё там же. Она нам будет показывать всякие мелькающие разноцветные циферки. Устанавливается аналогично вышеуказанным.

Склеиваем вместе


Бинари xmonad и xmobar у нас лежат в ~/bin, а потому нам полезно прописать эту директорию в $PATH. У меня, например, это строчка export PATH="/home/buttons/bin:${PATH}" в ~/.zhenv. GHC тоже должен быть в $PATH или конфиг всё же придётся самому компилировать, но он скорее всего там уже есть.

Создаём директорию ~/.xmonad и там в xmonad.hs будем писать свой конфиг. Можно подсматривать в стандартном из ~/dev/xmonad-5.0/XMonad/Config.hs, можно позаимствовать из вики, можно мой, который будет приведён ниже. Вообще, нам теперь не надо сочинять полноценный конфиг, а достаточно лишь писать то, что отличается от стандартного. Допустим, используется мой.

После правок можно проверять конфиг на синтаксическую и не только правильность при помощи команды ghci ~/.xmonad/xmonad.hs. Но вообще xmonad умеет через xmessage сообщать об ошибках компиляции. Перезапускать xmonad толком не надо для применения новых настроек. Обычно достаточно сказать mod-q (если не перенастроено) и новый конфиг будет скомпилирован, слинкован с xmonad и WM перезапустится, не теряя наши окошки.

Ну вот и мой конфиг:
import XMonad
import System.Exit
import qualified XMonad.StackSet as W
import qualified Data.Map        as M

-- Расширения
import XMonad.Actions.CycleWS
import qualified XMonad.Actions.FlexibleResize as Flex
import XMonad.Actions.SinkAll
import XMonad.Hooks.DynamicLog
import XMonad.Layout.Circle
import XMonad.Layout.NoBorders
import XMonad.Layout.Tabbed
import XMonad.Prompt
import XMonad.Prompt.Man
import XMonad.Prompt.Shell
import XMonad.Prompt.Ssh

-- Мой любимый эмулятор терминала
myTerminal = "urxvtc"

-- Мой шрифт для разных надписей
myFont = "-xos4-terminus-medium-r-normal--12-120-72-72-c-60-*-*"

-- Мои любимые цвета
myNormalBorderColor = "#333"
myFocusedBorderColor = "#fedb73"

-- Устанавливаем функциональной кнопкой "windows key".
myModMask = mod4Mask

-- Отступ от краёв экрана для показывания всяческих сайдбаров
-- У меня это 14 пикселов сверху
myDefaultGaps = [(14,0,0,0)]

-- Мои воркспейсы
myWorkspaces = ["1:im", "2:web", "3:music", "4:emacs"]
               ++ map show [5 .. 9]

-- Кейбиндинги
myKeys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
    -- Запуск терминала
    [ ((modMask .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf)
    -- Блокировка экрана
    , ((modMask,               xK_Pause ), spawn "slock")
    -- Скриншот
    , ((modMask,               xK_Print ), spawn "import -window root ~/tmp/screenshot-`date +%s`.png")
    -- Громкость +/-
    , ((modMask .|. shiftMask, xK_Up    ), spawn "amixer -q set Master 1+")
    , ((modMask .|. shiftMask, xK_Down    ), spawn "amixer -q set Master 1-")
    -- Убийства окна в фокусе
    , ((modMask .|. shiftMask, xK_c     ), kill)

    -- Схемы расположения окон
    -- Переключиться на следующую доступную
    , ((modMask,               xK_space ), sendMessage NextLayout)
     -- Сменить на стандартную
    , ((modMask .|. shiftMask, xK_space ), setLayout $ XMonad.layoutHook conf)

    -- Изменить размер видимых окон до корректного
    , ((modMask,               xK_n     ), refresh)

    -- Перемещение фокуса
    -- На следующее окно
    , ((modMask,               xK_Tab   ), windows W.focusDown)
    , ((modMask,               xK_j     ), windows W.focusDown)
    -- На предыдущее окно
    , ((modMask,               xK_k     ), windows W.focusUp  )
    -- Переместить фокус на мастер-окно
    , ((modMask,               xK_m     ), windows W.focusMaster  )

    -- Изменение расположения окон
    -- Поменять местами окно в фокусе и мастер-окно
    , ((modMask,               xK_Return), windows W.swapMaster)
    -- Поменять местами окно в фокусе со следующим
    , ((modMask .|. shiftMask, xK_j     ), windows W.swapDown  )
    -- Поменять местами окно в фокусе с предыдущим
    , ((modMask .|. shiftMask, xK_k     ), windows W.swapUp    )
    -- Уменьшить master area
    , ((modMask,               xK_h     ), sendMessage Shrink)
    -- Увеличить master area
    , ((modMask,               xK_l     ), sendMessage Expand)
    -- Вернуть окно в tiled-режим
    , ((modMask,               xK_t     ), withFocused $ windows . W.sink)
    -- Увеличить кол-во окон в master area
    , ((modMask              , xK_comma ), sendMessage (IncMasterN 1))
    -- Уменьшить кол-во окон в master area
    , ((modMask              , xK_period), sendMessage (IncMasterN (-1)))

    -- Переключить показ всяческих сайдбаров
    , ((modMask              , xK_b     ), modifyGap (\i n -> let x = (XMonad.defaultGaps conf ++ repeat (0,0,0,0)) !! i in if n == x then (0,0,0,0) else x))

    -- Выйти из WM
    , ((modMask .|. shiftMask, xK_q     ), io (exitWith ExitSuccess))

    -- Перезагрузить WM
    , ((modMask              , xK_q     ), broadcastMessage ReleaseResources >> restart (Just "xmonad") True)

    -- Кейбиндинги для расширений
    -- Вернуть все окна на воркспейсе в tiled-режим
    , ((modMask .|. shiftMask, xK_t     ), sinkAll)
    -- Переключение/перенос окна на следующий/предыдущий воркспейс
    , ((modMask,               xK_Right), nextWS)
    , ((modMask,               xK_Left),  prevWS)
    , ((modMask .|. shiftMask, xK_Right), shiftToNext >> nextWS)
    , ((modMask .|. shiftMask, xK_Left),  shiftToPrev >> prevWS)

    -- Просмотр man-ов
    , ((modMask,               xK_F1), manPrompt myXPConfig)
    -- Запуск какого-нибудь приложения
    , ((modMask,               xK_p), shellPrompt myXPConfig)
    -- Запуск какого-нибудь приложения в эмуляторе терминала
    , ((modMask .|. shiftMask, xK_p), prompt ("urxvtc" ++ " -e") myXPConfig)
    -- Подключение к какому-нибудь хосту по SSH
    , ((modMask,               xK_s), sshPrompt myXPConfig)

    ]
    ++

    -- mod-[1..9] -- переключение на воркспейс #N
    -- mod-shift-[1..9] -- перемещение окна на воркспейс #N
    [((m .|. modMask, k), windows $ f i)
        | (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9]
        , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]

-- Биндинги для мышки
myMouseBindings (XConfig {XMonad.modMask = modMask}) = M.fromList $
    -- Переключение окна в floating-режим и перемещение курсором
    [ ((modMask, button1), (\w -> focus w >> mouseMoveWindow w))
    -- Перемещение окна на верх "стопки"
    , ((modMask, button2), (\w -> focus w >> windows W.swapMaster))
    -- Переключение окна в floating-режим и улучшенное изменение размера
    , ((modMask, button3), (\w -> focus w >> Flex.mouseResizeWindow w))
    ]

-- Схемы расположения окон
-- Обычный tiled, ion3-like tabbed, полноэкранный без окантовки, круговой
myLayout = tiled ||| tabbed shrinkText myTabConfig ||| noBorders Full ||| Circle
  where
     -- В обычном tiled экран разделяется на две панели
     tiled   = Tall nmaster delta ratio
     -- В основном панели по умолчанию одно окно
     nmaster = 1
     -- Стандартная пропорция разделения экрана на панели
     ratio   = 1/2
     -- Шаг изменения пропорции
     delta   = 3/100

-- Правила для отдельных окон
-- Используем xprop | grep WM_CLASS для познания идентификатора окна
myManageHook = composeAll
    [ className =? "MPlayer"        --> doFloat
    , className =? "Gimp"           --> doFloat
    , className =? "psi"            --> doF (W.shift "1:im")
    , className =? "Firefox-bin"    --> doF (W.shift "2:web")
    , className =? "Opera"          --> doF (W.shift "2:web")
    , className =? "Amarokapp"      --> doF (W.shift "3:music")
    , className =? "Emacs"          --> doF (W.shift "4:emacs")]

-- Настройки логирования
myPP = defaultPP { ppCurrent = xmobarColor "yellow" "" . wrap "[" "]"
                 , ppTitle   = xmobarColor "green"  "" . shorten 40
                 , ppVisible = wrap "(" ")"
                 }

-- Настройки для схемы tabbed
myTabConfig = defaultTConf { activeColor         = myFocusedBorderColor
                           , inactiveColor       = myNormalBorderColor
                           , activeBorderColor   = myNormalBorderColor
                           , inactiveBorderColor = myFocusedBorderColor
                           , activeTextColor     = myNormalBorderColor
                           , inactiveTextColor   = myFocusedBorderColor
                           , fontName            = myFont
                           , tabSize             = 14
                           }

-- Настройки для промптов
myXPConfig = XPC { font              = myFont
                 , bgColor           = myNormalBorderColor
                 , fgColor           = myFocusedBorderColor
                 , fgHLight          = "#000000"
                 , bgHLight          = "#BBBBBB"
                 , borderColor       = myFocusedBorderColor
                 , promptBorderWidth = 1
                 , position          = Bottom
                 , height            = 14
                 , historySize       = 256
                 }

------------------------------------------------------------------------
-- Запускаем xmonad с настройками, что мы тут прописывали
main = xmonad defaults

defaults = defaultConfig {
      -- простые штуки
        terminal           = myTerminal,
        normalBorderColor  = myNormalBorderColor,
        focusedBorderColor = myFocusedBorderColor,
        modMask            = myModMask,
        defaultGaps        = myDefaultGaps,
        workspaces         = myWorkspaces,
      -- кейбиндинги
        keys               = myKeys,
        mouseBindings      = myMouseBindings,

      -- хуки, схемы
        layoutHook         = myLayout,
        manageHook         = myManageHook,
        logHook            = dynamicLogWithPP myPP
    }

Думаю, комментарии всё проясняют.

Теперь мы настроим xmobar. Для этого в ~/.xmobarrc пишем что-то вроде этого:
Config { font = "-xos4-terminus-medium-r-normal--12-120-72-72-c-60-*-*"
       , bgColor = "black"
       , fgColor = "grey"
       , position = Static { xpos = 0
                           , ypos = 0
                           , width = 1280
                           , height = 14
                           }
       , commands = [ Run Network "eth0" ["-L","10","-H","100","--normal","green","--high","red"] 10
                    , Run Cpu ["-L","3","-H","50","--normal","green","--high","red"] 10
                    , Run Memory ["-t","Mem: <usedratio>%"] 10
                    , Run Swap [] 10
                    , Run Date "%a %b %_d %Y %H:%M:%S" "date" 10
                    , Run PipeReader "/home/buttons/.xmonad/status" "xlog"
                    ]
       , sepChar = "%"
       , alignSep = "}{"
       , template = "%xlog% }{ | %cpu% | %memory% * %swap% | %eth0% | <fc=#ee9a00>%date%</fc>"
       }


Теперь скрипт, который связывает две программы. Основываемся на скрипте из XMonadContribs. Это будет ~/bin/run-xmonad.sh:
#!/bin/sh
# xmonad use with a pipe talking to an external program
PIPE=$HOME/.xmonad/status
rm -f $PIPE
PATH=${PATH}:/sbin mkfifo -m 600 $PIPE
[ -p $PIPE ] || exit

# status bar
xmobar &

# go for it
xmonad > $PIPE &

# wait for xmonad
wait $!

killall xmobar



Остаётся только дописать запуск этого дела в .xsession или .xinitrc (по вкусу). Например, у меня такой ~/.xsession:
xmodmap ~/.Xmodmap &
urxvtd -q -o -f &
unclutter -idle 1 &
/home/buttons/bin/run-xmonad.sh


Всё. Теперь всё должно работать. Можно смело выходить из своего уютного Гнома или что там.


Что надо сделать в будущем:
Заменить вывод в статусбар и другие места чем-то, что умеет юникоды. Заменить ввод Prompt.hs чем-то, что умеет юникоды.
Ещё надо сочинить нормальную расцветочку, т.к. из-за лени у меня полный вырви глаз получился.
Tags: window_managers, xmobar, xmonad
Subscribe
  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 34 comments
Previous
← Ctrl ← Alt
Next
Ctrl → Alt →
Previous
← Ctrl ← Alt
Next
Ctrl → Alt →