LaurVas

Оконный менеджер i3

   linux

Иногда хочется расположить окна таким образом, чтобы они не перекрывали друг друга, а стыковались. Типа такого:

 

Это становится особенно актуально на больших мониторах. Разумеется, при должном усердии можно аккуратно расставить окна руками. Но стоит открыть лишь ещё один терминал, и весь порядок рушится. Да, в типовых ситуациях выручали горячие клавиши. Но на все комбинации окон не напасёшься горячих клавиш. А ещё я перфекционист и заморачиваюсь по поводу рационального использования площади монитора. Я отключал заголовки окон и радовался выигранному пространству:

i3 подарил мне неожиданный прирост эффективности и стал одним из моих любимых инструментов. Почему я так тащусь от него?

  • Окна всегда занимают всю площадь экрана.
  • Окна не перекрывают друг друга.
  • В i3 я спокойно ориентируюсь в 20 открытых окнах. Раньше путался уже на 10.
  • Всё управление окнами осуществляется с клавиатуры.
  • Всё хорошо сразу, на дефолтном конфиге. Не возникает желания переделать дизайн по-своему.

К тайловому оконному менеджеру (сокращённо WM) надо привыкнуть. Это нормально. Linux тоже поначалу был непривычен, верно? Запаситесь терпением, и оно окупится.

Другие популярные тайловые WM

DWM. Аскетичный оконный менеджер от Suckless. Настраивается прямо в исходниках, в заголовочном файле. Маленький, быстрый и простой. Возможности тайлинга у него небогатые: конфигурация как на картинке выше ему уже не по зубам.

Xmonad. Написан на Haskell. Хаскеллисты гордятся и прокачивают свой скилл, допиливая этот WM. Интересен ли он остальным людям? Я не нашёл в нём ничего особенного.

Awesome. Нескромное название… Свой путь в тайлинг я начал с него. Не проникся, хотя на ЛОРе многие хвалят. Мне он показался излишне усложнённым. Имеет аж 12 вариантов компоновки окон (layouts), из которых реально нужных 2-3. Не понравилось, что при открытии нового окна всё перестраивается и какой-то он страшный по дефолту. Нашёл для вас неплохое демо на Youtube.

Установка i3

В Archlinux ставим пакеты i3-wm, i3status, dmenu. Если вы тру-арчевод и не используете графических логин-менеджеров (slim, lightdm, gdm, kdm), то для запуска i3 допишите в конец файла ~/.xinitrc строчку exec i3. Остальные exec надо закомментировать, иначе эффекта не будет.

В Ubuntu и Debian ставим мета-пакет i3, он подтянет за собой всё остальное.

При первом запуске i3 предложит создать конфиг-файл и спросит какую клавишу использовать в качестве модификатора: Win или Alt. Выбирайте Win, чтобы хоткеи управления окнами не конфликтовали с хоткеями приложений.

Организация работы в i3

У i3 нет главного меню типа “Пуск” или меню по правому клику, как в Openbox. Это может быть непривычно для новичков, но по-моему правильно: надо привыкать запускать приложения с клавиатуры. В дефолтной конфигурации для запуска приложений используется лончер на базе dmenu, он вызывается по Win + D. Терминал запускается сочетанием Win + Enter — дико удобно. Технически это сделано так: вместе с i3 идёт скрипт i3-sensible-terminal, который ищет установленные терминалы в системе и запускает первый попавшийся. Поэтому если i3 не угадал ваш любимый терминал, пропишите его явно в конфиге i3.

У i3 нет панели задач. Но она там и не нужна, т.к. все окна на виду — не потеряются. Зато доступно сразу 10 рабочих столов. В Awesome они называются тэгами, а в i3 — воркспэйсами (workspaces). Я же буду по-старинке называть их рабочими столами. Переключение между рабочими столами осуществляется комбинацией Win + цифра. Например, для переключения на третий надо нажать Win + 3.

Чтобы не путаться в рабочих столах, вы должны выработать стратегию что где запускать. Тут всё сильно зависит от ваших привычек и специфики работы. Могу дать только один очевидный совет: выделяйте отдельный рабочий стол приложению, которому нужен весь экран (IDE, браузер). Вот моё разделение:

  1. разные рабочие терминалы, обычно подключенные к серверам,
  2. код в редакторе, один-два терминала для работы с этим кодом,
  3. браузер,
  4. VirtualBox,
  5. музыкальный плеер,
  6. один-два рутовых терминала.

Остальные рабочие столы я использую редко и без какой-либо системы. На индикаторе в левом нижнем углу экрана отображаются только те рабочие столы, на которых есть открытые окна. Нет рабочего стола на индикаторе — значит и нет на нём ничего, пустой. Вроде бы мелочь, но фишка кайфовая!

Если очень хочется, можно дать рабочим столам имена вместо номеров. Не спрашивайте зачем. Я не знаю.

Как рулить окнами в i3

По своему опыту могу сказать, что главное при работе в i3 — понять как он представляет набор окон в виде дерева. Слева будет скриншот, справа — как i3 видит данную конфигурацию. Голубым отмечено активное окно.

Итак, i3 группирует окна в контейнеры. Всего есть 4 типа контейнеров:

Горизонтально разделённый контейнер (horizontal-split):

 

Вертикально разделённый контейнер (vertical-split):

 

Контейнер с табами (tabbed):

 

Стэковый контейнер (stacked):

 

Win + E переводит горизонтальный контейнер в вертикальный и наоборот,
Win + W переводит контейнер в табовый,
Win + S переводит контейнер в стэковый.

А теперь самое интересное: мы можем создать новый контейнер на месте активного окна:

Win + V создаёт вертикальный контейнер,
Win + H создаёт горизонтальный контейнер:

 

Новые окна будут открываться внутри нового контейнера:

 

И Win + E, Win + W, Win + S будут менять компоновку внутреннего контейнера, а не внешнего:

 

 

 

Вы сейчас спросите: а на кой чёрт засовывать один стэковый контейнер в другой? Сам не знаю. Я так и не делаю никогда. Сейчас исправим.

Поменять компоновку второго контейнера легко, а как поменять компоновку первого? Для этого надо подняться на уровень выше. Есть два способа:

  • Использовать мышь или Win + стрелка, чтобы переключиться на окно, принадлежащее первому контейнеру.
  • Выделить второй контейнер целиком сочетанием Win + A:

 

Жмём Win + E, чтобы превратить стэковый контейнер в горизонтально разделённый:

 

Благодаря рекурсивным контейнерам в i3 можно создавать сколь угодно сложную мозайку вообще без напряга. Вот пример рабочей компоновки для большого монитора:

 

Таких богатых возможностей я не встречал ни в одном оконном менеджере. Это же конструктор своих собственных IDE под любые задачи!

Для изменения размера активного окна надо перейти в соответствующий режим комбинацией Win + R и отрегулировать размер стрелками ( и уменьшают окно, и увеличивают). Чтобы понять логику работы стрелок, представьте, что вы двигаете правый нижний угол окна. При этом остальные окна того же рабочего стола будут пропорционально перерисовываться. Не забываем выйти из ресайза клавишей Enter или Esc. Также i3 позволяет двигать стыки между окнами мышью, но это вы и без меня догадаетесь.

Можно оторвать любое окно от плитки и сделать его плавающим (floating). Такое окно будет находиться поверх плитки в отдельном слое. Не знаю зачем это может понадобиться и не пользуюсь этой фичей. Диалоговые окна всегда плавающие, что логично.

Остальные комбинации клавиш:

Win + Shift + стрелка перемещает активное окно по плитке,
Win + Shift + цифра отправит окно на указанный рабочий стол,
Win + F разворачивает окно на весь экран и обратно,
Win + Shift + Q закрывает активное окно,
Win + Shift + пробел делает окно плавающим и возвращает обратно,
Win + пробел переводит фокус с тайлового окна на плавающее и обратно,
Win + мышь перемешает плавающее окно.

Вместо стрелок можно использовать вимовские HJKL, но смещённые на одну клавишу вправо, чтобы Win + H было мнемоникой для горизонтального разделения. Мне это показалось неудобным, и я сделал каноничные HJKL, а горизонтальное разделение сместил на Win + G. И ещё переназначил Alt + F4 на закрытие окна по старой привычке. В остальном дефолтные сочетания клавиш подобраны очень удачно.

Чтобы быстрее запомнить горячие клавиши, можете распечатать шпаргалку.

Настройка под себя

Чтобы работа была в удовольствие, а инструмент приносил радость, важно не только изучить как он работает, но и настроить под себя. С этим у i3 всё хорошо.

Я не нашёл графических утилит для настройки i3 и надеюсь что их действительно нет: править конфиг руками совсем не сложно. Все пользовательские настройки хранятся в ~/.config/i3/config. Не буду в деталях расписывать конфигурационный файл, потому что во-первых там всё просто, а во-вторых у i3 отличная документация. Расскажу преимущественно о своём опыте, а остальное вы всегда сможете подсмотреть в документации.

Как и Openbox, i3 не любит выполнять чужую работу. Обои, индикатор раскладки клавиатуры, блокировка экрана реализуются сторонними приложениями. Подходящие для этих целей утилиты я подробно описал в статье про Openbox. В i3 я по-прежнему сижу без обоев, использую sbxkb для индикации раскладки и slock для блокировки экрана.

Ресайз

i3 ресайзит тайловые окна в процентах относительно родительского контейнера и мне это не нравится: получается грубый ресайз в больших контейнерах и тонкий в маленьких. Вообще идея относительного ресайза концептуально интересна, вот только привязываться надо не к размеру контейнера, а к размеру окна. Но так i3 пока не умеет.

А может быть клавиатура в принципе плохо подходит для ресайза? Получается либо быстро, но грубо, либо точно, но медленно. У мышки такой проблемы нет. В i3 можно двигать стыки окон мышкой, но во-первых до неё слишком далеко тянуться, а во-вторых предварительно надо попасть курсором в стык, что тоже отнимает время.

К счастью, недавно разработчики запилили ресайз тайловых окон на фиксированную величину и 4 ноября эта фича попала в релиз (версия 4.16). По-моему так лучше. Я поигрался с настройками и в конце концов остановился на двух группах клавиш для изменения размеров окон: HJKL двигают грубо, а стрелочки — тонко:

~/.config/i3/config
mode "resize" {
        bindsym $left resize shrink width 40 px
        bindsym $down resize grow height 40 px
        bindsym $up resize shrink height 40 px
        bindsym $right resize grow width 40 px

        bindsym Left resize shrink width 10 px
        bindsym Down resize grow height 10 px
        bindsym Up resize shrink height 10 px
        bindsym Right resize grow width 10 px

        # back to normal: Enter or Escape
        bindsym Return mode "default"
        bindsym Escape mode "default"
}

Возможно со временем найдутся более удобные числа, а пока так. Кстати, никто не запрещает делать ресайз на разную величину по высоте и ширине или в разных направлениях (в плюс больше чем в минус или наоборот).

Автозапуск приложений

~/.config/i3/config
exec chromium
exec pidgin

Для приложений, которые не поддерживают механизм startup-notification, надо делать exec с ключом --no-startup-id. Как правило это либо древние (xterm), либо консольные. Если приложение уже запустилось, а курсор ещё выглядит как часы, значит нужен ключ --no-startup-id.

Если надо запустить процесс с аргументами, просто перечисляем их через пробел. i3 использует шелл для запуска, поэтому можно смело использовать возможности шелла (глоббинг, операторы). Если в команде нужны символы ; и ,, то команду следует заключить в кавычки.

Привязка приложений к рабочим столам

Разумеется, приложения должны стартовать не где попало, а на вполне конкретных рабочих столах. Это помогает не сбиваться с выбранной стратегии использования рабочих столов.

Нам понадобится утилита xprop, чтобы узнать свойства окна. В Archlinux она устанавливается из пакета xorg-xprop, в Debian и Ubuntu из пакета x11-utils. Вот пример для chromium:

$ xprop | grep "^WM_CLASS"
WM_CLASS(STRING) = "chromium", "Chromium"

Нам нужно второе значение. Обернём его крышкой и баксом для точного соответствия:

~/.config/i3/config
assign [class="^Chromium$"]3
assign [class="^VirtualBox$"]4
assign [class="^Pidgin$"]5

Таким образом приложение будет всегда открываться на строго определённом рабочем столе, в том числе при запуске через лончер или из терминала. В некоторых случаях это может быть нежелательным — когда я запускаю приложение через лончер, я ожидаю увидеть его здесь, а не где-то на пятом десктопе. Можно сделать привязку только для автозапуска. Немного костыльно, но работает:

~/.config/i3/config
exec --no-startup-id i3-msg 'workspace 3; exec firefox; workspace 1'

Обычный автозапуск работает как: “запусти firefox”. Этот автозапуск работает как “перейди на N-десктоп, запусти firefox, перейди на 1-й десктоп”. i3-msg является консольной командой и не поддерживает startup-notification, поэтому её надо вызывать с ключом --no-startup-id. А вот внутреннюю команду обязательно запускать без --no-startup-id, иначе переключение рабочего стола не даст эффекта.

Если вы пропишите в автозапуск несколько i3-msg, то возможно возникнет состояние гонки и все окна перепутаются. А может быть и нет, зависит от реализации i3-msg. Я бы засунул всё в один вызов, чтобы сократить накладные расходы.

Цвета, шрифт, рамки

Я пробовал менять цветовую палитру i3, но получалось только хуже. Стандартные цвета действительно удачно подобраны. Расскажу лучше про шрифты.

i3 поддерживает как растровые, так и векторные шрифты. Я поигрался с разными вариантами и остановился на растровом шрифте misc-fixed из пакета xorg-fonts-misc. По-моему он идеально вписывается в дизайн i3. Вы только взгляните на эти аккуратные циферки!

Чтобы узнать какие растровые шрифты есть в вашей системе и выбрать подходящий, используйте утилиту xfontsel (пакет xorg-xfontsel в Archlinux и x11-utils в Debian и Ubuntu).

У неё специфический интерфейс, но разобраться можно. Потыкав загадочные слова из верхней строчки, вы должны уточнять параметры шрифта до тех пор, пока они не станут однозначно идентифицировать шрифт (надпись “1 name matches” в правом верхнем углу). Нажимаем кнопку select, и название шрифта попадёт в буфер обмена, только не тот, который для Ctrl + C , Ctrl + V, а который вставляется нажатием на колёсико мыши или Shift + Insert. В конфиге i3 растровый шрифт указывается так:

~/.config/i3/config
font -misc-fixed-medium-r-normal-*-15-*-*-*-*-*-iso10646-*

На экранах с высоким разрешением пиксельный шрифт выглядит слишком мелким даже на максимальном размере. Значит расчехляем векторный шрифт. Для векторного шрифта нужно добавлять префикс pango:, например:

~/.config/i3/config
font pango:DejaVu Sans Mono Book 12

Можно настроить разные шрифты для заголовков окон и панели, если очень хочется.

Конечно же я отключил заголовки окон:

~/.config/i3/config
default_border pixel

В i3 они нужны ещё меньше, чем в Openbox’е. Заголовки табового и стэкового контейнеров при этом не пропали — удобно.

Да, чтобы работающий i3 перечитал конфиг, надо нажать Win + Shift + C.

Выделение активного окна

Когда отключены заголовки окон, то все окна выглядят одинаково и сходу непонятно какое из них сейчас активно. Есть лишь пара малозаметных признаков, по которым можно вычислить активное окно: мигающий курсор и тонкая однопиксельная рамка вокруг окна. Эффективно работать в таких условиях не получается. Вообще это проблема любого оконного менеджера, а не только i3. Я стал искать как сделать активное окно заметным.

Самое простое решение — увеличить толщину рамки:

~/.config/i3/config
for_window [tiling] border pixel 3

Стало лучше, но хочется большего. А что если затемнять неактивные окна? Вот так:

 

Для этих целей хорошо подходит композитный менеджер picom. Помимо затемнения он умеет полупрозрачность, тени и вертикальную синхронизацию (vsync). К сожалению picom вяло развивается начиная с 2016 года, и, в зависимости от видеокарты, может давать побочные эффекты вроде просадки частоты кадров (fps) или мерцания. У меня вообще в какой-то момент стал подвисать скролл в браузере. Но сейчас всё работает нормально, так что попробовать стоит.

Ставим пакет picom и сперва тестируем в консоли:

$ picom --inactive-dim 0.2 --no-fading-openclose --inactive-dim-fixed --config /dev/null

--inactive-dim 0.2 — степень затемнения неактивных окон (0…1), подбирается опытным путём.
--inactive-dim-fixed — не вычислять степень затемнения с учётом полупрозрачности. Возможно этот ключ лишний, если полупрозрачность не используется, но я его на всякий случай добавил.
--config /dev/null — не читать системный конфиг-файл. Без этого ключа picom рисует тени, а мне нужно только затемнение окон.

Если всё нравится и работает без нареканий, добавляем вызов этой команды в автозапуск i3. Если же возникли проблемы, надо разбираться. У picom’а куча низкоуровневых настроек, в которых я ничего не понимаю.

Почему-то picom меняет цвет заливки фона с чёрного на серый. В принципе можно оставить и так: фон виден только на пустых рабочих столах, а рабочие столы редко бывают пустыми. Но я настолько привык к чёрному фону, что захотел его вернуть. Для этого понадобится утилита yawa (ранее hsetroot). В Archlinux она находится в AUR, в Debian и Ubuntu в официальных репозиториях.

~/.config/i3/config
exec --no-startup-id yawa --solid='#000000'

Панель i3bar

Панель i3bar — это неотъемлемая часть i3. В принципе можно заменить её на что-то другое или даже отключить, но зачем?

В левой части панели расположены индикаторы рабочих столов, а остальное место отведено под статусную строку и трей. Тонкой настройки, как у Tint2, здесь нет. Здесь вообще настроек — раз-два и обчёлся: можно перенести панель наверх, если вы любите сверху, да отключить трей.

Самая интересная часть панели с точки зрения настройки под себя — это статусная строка. По сути это такая сильно упрощённая система мониторинга. Её формирует утилита i3status и вот что она умеет показывать:

  • IPv6 адрес,
  • свободное/занятое место на файловой системе,
  • состояние сервиса через pid-файл (работает/лежит),
  • наличие пути в файловой системе (есть/нет),
  • состояние проводного/беспроводного сетевого интерфейса,
  • состояние аккумулятора,
  • температуру процессора,
  • загрузку процессора в процентах и load average,
  • дату и время,
  • громкость канала PulseAudio или ALSA.

Формат вывода довольно гибко настраивается, но вывод всегда остаётся текстовым. Подробнее см. man i3status.

i3status специально сделана маленькой и простой, чтобы не тупила под высокой нагрузкой. В ней не предусмотрен запуск дочерних процессов, поэтому, например, выводить результат пинга на панель не получится. Для этих целей придётся мастерить свою обёртку или подбирать более мощный аналог, которых предостаточно.

Настраивается i3status через свой конфигурационный файл ~/.config/i3status/config. Результат можно смотреть прямо в консоли — удобно!

$ i3status
i3status: trying to auto-detect output_format setting
i3status: auto-detected "term"
no IPv6 | 4,2 GiB | W: down | E: 192.168.10.3 (1000 Mbit/s) | 0,88 | 2018-11-22 10:28:48

Scratchpad

Scratchpad — это такая нычка, куда можно спрятать окно, чтобы оно не мешалось, но в то же время было всегда под рукой. Если вам нравятся quake-like терминалы, то scratchpad скорее всего вам тоже понравится — по сути это то же самое.

В дефолтном конфиге нет горячих клавиш для scratchpad’а. Документация i3 рекомендует назначить его на (минус); мне же больше понравилось, когда я перенёс его на кавычку слева от 1 — сюда обычно назначают quake-like терминал и до неё ближе тянуться. Итак, добавим пару строк в конфиге:

~/.config/i3/config
bindsym $mod+Shift+grave move scratchpad
bindsym $mod+grave scratchpad show

Как я узнал что клавиша называется grave? С помощью утилиты xev. Запускаем её в терминале, нажимаем нужную клавишу и смотрим вывод после слова keysim:

KeyPress event, serial 34, synthetic NO, window 0x2c00001,
    root 0x1e2, subw 0x0, time 12447641, (399,-62), root:(402,2088),
    state 0x10, keycode 49 (keysym 0x60, grave), same_screen YES,
    XLookupString gives 1 bytes: (60) "`"
    XmbLookupString gives 1 bytes: (60) "`"
    XFilterEvent returns: False

KeyRelease event, serial 34, synthetic NO, window 0x2c00001,
    root 0x1e2, subw 0x0, time 12447705, (399,-62), root:(402,2088),
    state 0x10, keycode 49 (keysym 0x60, grave), same_screen YES,
    XLookupString gives 1 bytes: (60) "`"
    XFilterEvent returns: False

Чтобы изменения вступили в силу, заставим i3 перечитать конфиг комбинацией Win + Shift + C. Теперь Win + Shift + ` отправит активное окно в scratchpad, а Win + ` достанет его оттуда (и спрячет обратно по второму нажатию). Окно из scratchpad’а ведёт себя как обычное плавающее окно: его можно двигать мышкой с зажатой клавишей Win, а Win + пробел будет переключать фокус на плитку и обратно на плавающее окно.

i3 позволяет прятать в scratchpad несколько окон. Когда их там больше одного, Win + ` будет доставать и убирать окна по очереди. В реальной работе это неудобно уже на двух окнах, хочется иметь по отдельному хоткею на каждый scratchpad. В отличие от рабочих столов, у scratchpad’ов нет идентификаторов, поэтому нельзя дать команду вроде “спрятать это окно в первый scratchpad” или “показать второй scratchpad”. Но можно использовать свойства окон аналогично тому, как это делается для привязки к рабочим столам. Со временем я пришёл к такой конфигурации:

~/.config/i3/config
bindsym $mod+F1 [class="^TelegramDesktop$"] scratchpad show
bindsym $mod+F2 [class="^Keepassx$"] scratchpad show

Win + F1 отвечает за Telegram, а Win + F2 за менеджер паролей KeePassX. Получилось удобно. Если мне когда-нибудь захочется держать в scratchpad’е ещё одно приложение, я добавлю третью привязку. Не хватает только индикатора scratchpad’а на панели i3bar.

О чём я мог бы написать, но не написал

  • Как i3 переваривает несколько мониторов.
  • Сохранение и восстановление сессий.