Musca -- немного лирики


        _   _     ___  ___   _______     ____      __                  ,
       / \ / \    | |  | |  /  _____|   / __ \    /  \         *    .   
      /   |   \   | |  | |  \___ \__   | /  \/   / /\ \          *      
     /  /\_/\  \  |  \_/  \ ____\_  \  | \__/\  / /__\ \      .         
    |___/   \___|  \___/|_| |_______/   \____/ |__/  \__|          `    
_______________________________________________________________         
_______________________________________________________________         
Месяц был в оффлайн. За это время накропал обзор Musca. Писал по-немногу в свободное время, которого, увы, совсем немного. Так что не обессудьте за непоследовательность изложения ;-)

Итак, пришло время написать об оконном менеджере Musca (названного в честь созвездия южного неба). Открыв для себя POSIX-мир менее полугода назад, я искренне недоумевал тому, почему консоль (в “недрах” которой кроется вся мощь никсов) так сильно отмежована от иксов, в которых и проводят пользователи этих систем свой досуг.
Как и многие другие, вдоволь наигравшись гномом и копизом, потискав KDE, я обратил свой взгляд по ту сторону DE – а что там? А там – преимущественно, мир WM. А их, оконных менеджеров, существуют тысячи. И приглянулся среди прочих мне Ion. Так я открыл мир тайлингов. Но ион конфигурировался на Lua. Этот язык я не знаю, и учить как-то не тянет. Это одна из причин, почему он у меня не прижился. Но отступать было поздно. После иона попробовал боксы (FluxBox и PekWM), подкупившие меня своими табами в заголовках окон, наподобии ион. Но они были не так эффективны, и небыло в них какой-то хакерской красоты, что-ли. А тайлинговые WM всё тянули меня. Потыкал Ratpoison и StumpWM, но как-то не пошло, слишком они мне показались негибкими и сковывающими. Динамические вроде dwm и его потомков я сразу отбросил – мне не понравилась идея полностью автоватического (не ручного) управления окнами. Правда потестил ScrotWM – довольно приятный и очень минималистичный динамический WM, но сыроватый, и как динамический, лично мне он не подходил. Начал было уже заглядываться на Xmonad, смирившись с мыслью учить Haskell, чтобы настроить его под себя, но тут и прочитал о Musca. Почитав отзывы и статьи, я понял – на это стоит потратить время.
Итак, MUSCA – динамический оконный менеджер с ручным управлением. Создан он на основе идей Ratpoison и dwm. Поначалу это насторожило, но потом я понял, что он вобрал действительно лучшее, и добавил много своего. Динамичность его, наверно, заключается в отсутствии рабочих столов. вместо них есть группы. Сначала это показалось неудобным, пока я не понял логику. Группы переключаются, как рабочие столы, но окна, входящие в групу вовсе не обязательно отображаются. Рабочее пространство гуппы поделено на фреймы, и окна открываются в этих фреймах. Внутри любого фрейма можно переключать все окна данной группы, также можно перетаскивать окна между фреймами. Группу можно сохранить в файл и загрузить из файла. Деление на фреймы осуществляется хоткеями. Также группа может занимать не весь экран, оставляя место панелям, апплетам и т. п. . Порадовали очень удобные (легко запоминающиеся и неконфликтующие с приложениями) комбинации клавиш.
В качестве главного меню выступает dmenu. Мне оно показалось не очень удобным, но, думаю, это решается (установкой и настройкой его оболочки Yeganesh, или написанием собственных скриптов).
Через dmenu можно вызвать (и запустить) список окон, список групп, shell, и команды musca. Последние заслуживают отдельного внимания и похвалы. Все действия осуществляются командами, у команд есть аргументы (напр., в каком отношении делить фрейм), команды можно привязывать к хоткеям, писать скрипты, запускать из консоли, обьединять, образуя новые команды, в последующих версиях обещают также поддержку событий иксов. Вобщем, человекочитаемость скриптов, простота настройки, и реализация в хороших традициях никсов (использование потоков для управления) меня заворожили.

Также у фреймов есть три режима.

catchall flip – один фрейм в группе выбирается для открытия в нём всех последующих открываемых (упс, повторяюсь:) окон (по умолчанию, в зависимости от настройки, открываемые окна занимают позицию текущего или пустого, если есть такой, фрейма);

dedicate flip – фрейм помечается как занятый и новые открываемые окна его не занимают (можно использовать при запуске многооконных приложений);

stack flip – режим плавающих окон (распростроняется на всю группу, так же может быть использован многооконными приложениями). Musca поддерживает основные манипуляции с окнами следующим образом: перетаскивание окон осуществляется левой кнопкой мыша с зажатой super (или другой используемой Вами как основная модулирующая клавиша); изменение размера – правой клавишей с той же кноповкой.

Помимо того, отдельные окна можно помечать как не обрабатываемые (напр., панели) – чтобы избежать помещения во фрейм.
Настройка осуществляется присваиванием командой set значения параметрам (цвета, имя конфигурационного файла запуска, команда запуска главного меню и приложения для вывода сообщений и т. д.). Т.е. конфигурировать можно прямо во время работы, более того, можно посто запустить на выполнение файл, содержащий список команд. С полным списком команд и переменных можно ознакомиться на официальном сайте http://aerosuidae.net/musca/Musca_Window_Manager.
А теперь, собственно, критика и пожелания. По мере обнаружения. Первое – жаль, что хоткеями фреймы делятся только пополам (оч. нехватает комбинации вроде EMACSовского C-u для задания параметров, если кто подскажет рецепт – пишите) ; далее – по dmenu – нет так полюбившегося мне по zsh перебора TABом и автодополнения ключей и параметров (в т.ч. и пути к файлам) (надеюсь, что это настраиваемо). Также я не нашел, как раскидывать окна по группам при старте (внутри одной группы по фреймам они встают при загрузке файла-дампа этой группы) – окна запускаются с разной задержкой и все норовят влезть в текущую группу.
Еще, кажется, обнаружил пару небольших багов. Первый – делим группу на 4 равных фрейма, левый нижний, например, растягиваем немного вправо, правый верхний делим горизонтально, нижнюю часть – вертикально, нижний правый фрейм удаляем. По идеи, теперь фреймы должны заполнить пустое пространство, но вместо этого только правый нижний кусок правого верхнего изначального фрейма заполняет часть пространства, левый нижний же (изначальный) не изменился, и осталась незаполненная область. Теперь удаляем левую нижнюю часть правого верхнего изначального фрейма – опять только пустая, незаполняемая фреймами область! Удаляем оставшуюся верхнюю часть изначального левого верхнего фрейма – его оставшаяся правая нижняя часть заполняет часть пространства, но между ним и оставшимися левыми изначальными фреймами – пустая область, и переключиться теперь между фреймами штатными хоткеями не выйдет. Пути два – тыкать мышем, или ресайзить оставшиеся фреймы, чтобы те опять “сцепились”. Но это не есть нормально, и если кто знает лекарство от этого – буду очень благодарен. Если нет – пишите багрепорт, ибо ваш скромный слуга на буржуйском интернациональном не писатель. Второй баг также незначителен, но может доставлять некоторое неудобство. Пример – делим группу на 3 фрейма, 2 помечаем как dedicate и catchall соответственно, переходим на третий. Теперь переходим в stack режим и обратно. Все фреймы рисуются по умолчанию, без подсветки режима. Это может ввести в заблуждение, т. к. режимы по-прежниму включены – чтобы удостовериться, достаточно переключить фокус на неактивные фреймы – и те вновь подсветятся соответственно режимам. Думаю, об этом также стоит упомянуть в багрэпорте.
Ну, и, на последок, немного помечтаем. Во-первых, я не знаю, какое средство вывода информации сюда подойдёт (умолчательно все сообщения выводятся просто в stdout). Если есть идеи и варианты – буду рад услышать. Интересно было бы попробовать прикрутить conky или dzen как системный монитор, но отображать его только по нажатию соответствующего хоткея тонкой строчкой вверху или внизу – выводить дату/время, системный мониторинг, сюда же прикрутить какой-нибудь трэер (trayer или stalonetray) и средство визуализации раскиданных по группам окон. Обычно его называют пейджером и реализовывают в виде маленькой модели окошек в квадратиках воркспейсов. И правда, для пимпочкотыкательных интерфейсов что-то лучше того же ipager придумать сложно. Но я представляю себе это средство визуализации несколько иначе, благо это полность походит к musca. Хотелось бы видеть монитор в текстовом режиме, отображающий информацию примерно в следующем виде:
		*/term
		    +urxvt
		    -mirage
		   *+emacs
		 /work
		    +evince
		    -tkabber
		 /music
		    +snd
где / –перечисленые группы, в группах – окна, плюсами отмечены видимые во фреймах, * – означает текущее. Выводить можно в несколько строк во всплывающем меню, либо в ту же строку, экономя место, либо, для удобства восприятия – в отдельную строку (а по-хорошему, это должно задаваться опционально). Если бы это был еще и активный управляющий элемент (переименовывать группы, перетаскивать окна между ними, менять текущее и отображаемое) – было бы вообще здорово. Помимо того можно добавить сюда же следующий функционал – при при выборе одной из групп по нажатии ввода (или, как альтернативный вариант, тыканью мышем) – загружается и открывается для редактирования дамп текущей группы, по окончании редактирования, сделать возможность загрузить в musca сохранённый дамп, скорректировав текущую группу. Думаю, благодаря командной реализации musca, реалезовать всё это будет несложно, даже написанием простого скрипта. А вывести можно в тот же системный монитор или dmenu.

Также мне кажется неправильной связка с dmenu. Например, совместив функционал родного средства запуска программ dmemu shell с DmenFM (файловый менеджер – скрипт, работающий через dmenu), можно получить автодополнение/перебор имён файлов, как аргументов запускаемых программ – то, чего мне так не хватает после Ion3. Но переменная строки запуска dmenu инкапсулирована, и приходится настраивать такой запуск приложений независимо от Musca, отдельно настраивая параметры dmenu. Это не очень хорошо, и, надеюсь, этот архетектурный недочёт исправят.

И еще – уже просто пожелание – хотелось бы, чтобы указатель мыша следовал за фокусом окон, как в Ion3, а также исчезал при неактивности мыши, т. к. при работе только с клавиатуры – приходится изредка тянуться за мышем, чтобы только подвинуть его курсор :-)
И напоследок (опять повторяюсь?) приведу свой стартовый конфиг с комментариями, ибо лучше 1 раз увидеть, чем 128 раз услышать…

[~/.musca_start]
----------------------------------------------------------------
# Цветовая схема -- как я её себе представляю -- советую при настройке посмотреть man colors или showrgb | grep <нужный цвет>
set border_focus LimeGreen
set border_unfocus ForestGreen
set border_dedicate_focus #3283CD
set border_dedicate_unfocus #225888
set border_catchall_focus #CD327F
set border_catchall_unfocus #882255
# навешиваем команды на кейбиндинги
# стандартный терминал -- хотя нужно ли запускать больше одного экземпляра?
bind on Mod4+t exec urxvt
# хоткеем можно запустить скрипт dmenfm, создающий из dmenu минималистичный файловый менеджер. Жаль, что для него необходимо отдельно настраивать dmenu -- средств для более плотнойинтеграции я не нашел. Впрочем, создавать интегрированную среду из оконного и файлого менеджера -- это уже путь DE (Desktop environments -- рабочих столов). Чуть подправленный мной скрипт привожу в конце статьи
bind on Mod4+z exec dmenfm
bind on Mod4+Shift+z exec dmenfm
# деление фрейма хоткеями пополам -- горизонтально и вертикально, соответственно
bind on Mod4+Shift+h hsplit 1/2
bind on Mod4+Shift+v vsplit 1/2
# удаление фрейма
bind on Mod4+Shift+r remove
# удаление всех фреймов в группе кроме текущего, последний занимает место всей группы
bind on Mod4+Shift+o only
# аварийное завершение работы текущего окна
bind on Mod4+Shift+k kill
bind on Mod1+F4 kill
# переключение между окнами текущей группы в текущем фрейме; local переключает во фрейме только те окна, которые в нём ранее открывались
bind on Mod4+c cycle local next
bind on Mod4+Shift+c cycle local prev
# bind on Mod1+Shif+Tab cycle prev почему-то не работает :-\
bind on Control+Tab cycle prev
bind on Mod1+Shif+Tab cycle prev
# выбор текущего фрейма в группе
bind on Mod4+Left focus left
bind on Mod4+Right focus right
bind on Mod4+Up focus up
bind on Mod4+Down focus down
# Super+PgDn и Super+PgUp -- переключение между группами
bind on Mod4+Next use (next)
bind on Mod4+Prior use (prev)
# не знаю :) переписал на всякий случай. Возможно это нужно для поддержки работы нескольких экранов (но у меня только 1 монитор)
bind on Mod4+Tab screen (next)
# вызов dmenu с перечнем всех окон
bind on Mod4+Shift+w switch window
# вызов dmenu с перечнем всех групп
bind on Mod4+Shift+g switch group
#запуск dmenu с перечнем всех установленных программ -- штатное средство запуска программ
bind on Mod4+x shell
# Вызывает меню команд musca через dmenu, то же происходит по нажатию Super+M
bind on Mod4+Shift+x command
# пометить фрейм как занятый для открывающихся окон
bind on Mod4+Shift+d dedicate flip
# пометить фрейм для размещения в нём всех новых окон
bind on Mod4+Shift+a catchall flip
# отмена последней манипуляции с musca (!)
bind on Mod4+Shift+u undo
# переключение в режим плавающих окон
bind on Mod4+Shift+s stack flip
# перетаскивания окна между фреймами
bind on Mod4+Shift+Left swap left
bind on Mod4+Shift+Right swap right
bind on Mod4+Shift+Up swap up
bind on Mod4+Shift+Down swap down
# изменение размеров текущего фрейма
bind on Mod4+Control+Left resize left
bind on Mod4+Control+Right resize right
bind on Mod4+Control+Up resize up
bind on Mod4+Control+Down resize down
# выход из musca ;)
bind on Mod4+Shift+q quit
# вот примерно так осуществляются отдельные нефреймовые окна
#manage off stalonetray
#manage off Conky
# настройка переменных musca
# по умолчанию новое окно открывается в пустом фрейме, если такой есть, а не в текущем
set window_open_frame empty
# на вкус и цвет фломастеры разные -- я запускаю dmenu так
set dmenu dmenu -i -b -fn -*-ProggyClean-medium-r-normal-*-*-*-*-*-*-*-* -nb ForestGreen -nf black -sb LimeGreen -sf black
# а тут неплохо бы указать штатное средство вывода вербальной информации. Наверно, это всё-же будет dzen2, когда его освою :)
#set notify echo `cat` 
# размеры рабочей части группы -- можно ограничить при использовании панелей и прочих апплетов-котлетов -- я не использую
#pad 0 0 0 16
# место для приготовления котлетов
#exec stalonetray
#exec conky
# загружаю конфигурацию текущей группы, сохранённую ранее командой dump
load .musca_dump/term
# автозапуск всяких окон
exec emacs ~/.musca_start 
exec urxvt
# можно создать сколько-то групп для работы. я обычно создаю их в процессе работы. Впрочем, можно это дело также повесить на хоткеи. Т. к. я не знаю, как при запуске окно отправлять в конкретную группу -- при старте, чтобы окна не путались, использую только одну группу
# перерисовка текущего окна -- бывает, что некоторые окна болезненно реагируют на изменения размеров
bind on Mod4+f refresh
# создание группы с именем someone
bind on Mod4+Insert add someone
# удаление текущей или ближайшей из следующих группы с именем someone, все открытые в ней окна отправляются в следующую группу. Делаю так, потому, что не знаю, как удалять просто текущую группу без указания имени оной
bind on Mod4+Delete drop someone
# а вот так можно убрать рамку вокруг текущего фрейма, например. при просмотре фильма. Только я на знаю, как повесить переключатель включить/выключить рамку на 1 комбинацию, потому мспользую пару
bind on Mod4+b border on
bind on Mod4+Shift+b border off
# И, наконец, пример обьединения комманд. Данная строчка, если её раскоментировать, добавит в команду создания новой группы вызов команды, ограничивающей рабочую область, оставляя внизу полосу в 26 пикселей, напр., для панели
# hook ^add pad 0 0 0 26
# неудавшаяся попытка раскидывать окна по группам :-(
#load .musca_dump/work
#exec kazehakase file:///home/archer/Desktop/na_zapis_Uriel/Settings%20-%20Musca.htm
#exec kazehakase file:///home/archer/Desktop/na_zapis_Uriel/Commands%20-%20Musca.htm
----------------------------------------------------------------

За основу взят конфиг из ArchWiki на http://wiki.archlinux.org/index.php/Musca.
И обещанный мною скрипт :D

dmenfm
----------------------------------------------------------------
#!/bin/bash
about="Dmen File Manager\nversion 0.1.2.1\nby Scott Garrett\n<wintervenom [(a)] archlinux.us>\nre-edition\nby Yuriy Pitometsu\n<Pitometsu [(a)] gmail.com>"
### Changelog #####################################################
# 0.1.0   # * Initial version                                     #
# 0.1.1   # + Option 'Open last used dir'                         #
#         # + Options 'Always open dirs' and 'Always open files'  #
# 0.1.2   # + Config moved to $XDG_CONFIG_HOME                    #
#         # + Options for dmenu styling                           #
#         # + Option to change executor                           #
#         # + Option to open file manager in current directory    #
#         # + Plugins support                                     #
# 0.1.2.1 # + Font option for dmenu                               #
###################################################################
# TODO: UTF-8
function defaults {
    show_hidden=0
    show_backup=0
    always_open_files=0
    always_open_dirs=0
    open_last=1
    dmenu_caseinsens=1
    dmenu_onbottom=1
    dmenu_font='-*-ProggyClean-medium-r-normal-*-*-*-*-*-*-*-*'
    dmenu_bg='#228822'
    dmenu_fg='#000000'
    dmenu_sbg='#32CD32'
    dmenu_sfg='#000000'
    executor='exo-open'
    editor='geany'
    filemanager='thunar'
}
# initialization defaults
d_dmenu_font="$dmenu_font"
d_dmenu_bg="$dmenu_bg"
d_dmenu_fg="$dmenu_fg"
d_dmenu_sbg="$dmenu_sbg"
d_dmenu_sfg="$dmenu_sfg"
d_editor="$editor"
d_executor="$executor"
d_filemanager="$filemanager"
function saveconfig {
    echo "show_hidden=$show_hidden
show_backup=$show_backup
always_open_dirs=$always_open_dirs
always_open_files=$always_open_files
open_last=$open_last
dmenu_caseinsens=$dmenu_caseinsens
dmenu_onbottom=$dmenu_onbottom
dmenu_font=\"$dmenu_font\"
dmenu_bg='$dmenu_bg'
dmenu_fg='$dmenu_fg'
dmenu_sbg='$dmenu_sbg'
dmenu_sfg='$dmenu_sfg'
editor=\"$editor\"
executor=\"$executor\"
filemanager=\"$filemanager\"
last_dir=\"$(pwd)\"
" > "$config"
}
function setmenu {
    menu="$menu $([ "$dmenu_caseinsens" == '1' ] && echo '-i') $([ "$dmenu_onbottom" == '1' ] && echo '-b') -fn $dmenu_font -nb $dmenu_bg -nf $dmenu_fg -sb $dmenu_sbg -sf $dmenu_sfg"
}
file=1
config_file="preferences"
config_dir="$XDG_CONFIG_HOME/dmenfm"
config="$config_dir/$config_file"
plugins_dir="$XDG_CONFIG_HOME/dmenfm/plugins"
menu='dmenu'
[ ! -d "$config_dir" ] && mkdir "$config_dir"
[ ! -d "$plugins_dir" ] && mkdir "$plugins_dir"
[ ! -d "$plugins_dir/browser" ] && mkdir "$plugins_dir/browser"
[ ! -d "$plugins_dir/operations" ] && mkdir "$plugins_dir/operations"
[ ! -d "$plugins_dir/preferences" ] && mkdir "$plugins_dir/preferences"
[ -e "$HOME/.dmanfs" ] && mv "$HOME/.dmanfs" "$config"
defaults
touch "$config"
source "$config"
setmenu
[[ "$last_dir" && "$open_last" == 1 ]] && cd "$last_dir"
while [ "$file" ]; do
    file=$((echo -e '..\n.'; ls $([[ "$show_hidden" == '1' ]] && echo '-A') $([[ "$show_backup" == '1' ]] && echo '-B'); echo -e "[Preferences]\n[Open in $filemanager]"; ls -B "$plugins_dir/browser") | $menu -p "$(basename $(pwd))")
    if [ "$file" ]; then
        if [ -e "$file" ]; then
            if $([ -d "$file" ] && [[ "$always_open_dirs" != '1' && "$file" != "." && "$file" != ".." ]]) || $([ -f "$file" ] && [[ "$always_open_files" != '1' ]]); then
                owd=$(pwd)
                opt=$((echo 'Open'; ([ -f "$file" ] && echo 'Edit'); echo -e 'Copy\nMove\nRename\nDelete'; ls -B "$plugins_dir/operations") | $menu -p "<$file>")
            else
                opt='Open'
            fi
            case "$opt" in
                'Open')
                    if [ -d "$file" ]; then
                        cd "$file"
                    else
                        if [ "$executor" ] && which "$executor" &> /dev/null; then
                            exec "$executor" "$owd/$file" &
                            unset file
                        elif which "$d_executor" &> /dev/null; then
                            "$d_executor" "$owd/$file"
                            unset file
                        else
                            echo -e "No executor found.\nSet one in [Preferences]." | $menu -p 'Error:'
                        fi
                    fi
                ;;
                'Edit')
                    if [ "$editor" ] && which "$editor" &> /dev/null; then
                        exec "$editor" "$owd/$file" &
                        unset file
                    elif which "$d_editor" &> /dev/null; then
                        exec "$d_editor" "$owd/$file"
                        unset file
                    else
                        echo -e "No editor found.\nSet one in [Preferences]." | $menu -p 'Error:'
                    fi
                ;;
                'Copy')
                    cdir=1
                    while [ "$cdir" ]; do
                        cdir=$((echo -e '..\n.'; ls $([[ "$show_hidden" == 1 ]] && echo "-A") $([[ "$show_backup" == 1 ]] && echo "-B") -d */) | $menu -p "Copy <$file> to:")
                        if [[ "$cdir" ]]; then
                            opt=$(echo -e 'Open\nCopy' | $menu -p "Copy <$file> to <$cdir>:")
                            if [[ "$opt" == "Open" ]]; then
                                cd "$cdir"
                            elif [[ "$opt" == "Copy" ]]; then
                                echo "$file"
                                [ -e "$cdir/$file" ] && opt=$(echo -e "No\nYes" | $menu -p "Replace existing <$file>?")
                                [[ "$opt" == "Copy" || "$opt" == "Yes" ]] && cp -af "$owd/$file" "$cdir/$file"
                                unset cdir
                            fi
                        fi
                    done
                ;;
                'Move')
                    cdir=1
                    while [ "$cdir" ]; do
                        cdir=$((echo -e '..\n.' && ls $([[ "$show_hidden" == 1 ]] && echo "-A") $([[ "$show_backup" == 1 ]] && echo "-B") -d */) | $menu -p "Move <$file> to:")
                        if [[ "$cdir" ]]; then
                            opt=$(echo -e 'Open\nMove' | $menu -p "Move <$file> to <$cdir>:")
                            if [[ "$opt" == "Open" ]]; then
                                cd "$cdir"
                            elif [[ "$opt" == "Move" ]]; then
                                echo "$file"
                                [ -e "$cdir/$file" ] && opt=$(echo -e "No\nYes" | $menu -p "Replace existing <$file>?")
                                [[ "$opt" == "Move" || "$opt" == "Yes" ]] && mv -f "$owd/$file" "$cdir/$file"
                                unset cdir
                            fi
                        fi
                    done
                ;;
                'Rename')
                    opt=$(echo "" | $menu -p "Rename <$file> to:")
                    [ "$opt" ] && mv -f "$file" "$opt"
                ;;
                'Delete')
                    opt=$(echo -e "No\nYes" | $menu -p "Really delete <$file>?")
                    [[ "$opt" == "Yes" ]] && rm -rf "$file"
                ;;
                *) [ "$opt" ] && [ -e "$plugins_dir/operations/$opt" ] && source "$plugins_dir/operations/$opt" ;;
            esac
        elif [[ "$file" =~ '[Open in' ]]; then
            which "$filemanager" &> /dev/null && exec "$filemanager" . &
            unset file
        elif [[ "$file" == '[Preferences]' ]]; then
            opt=1
            while [ "$opt" ]; do
                opt=$((echo "Show hidden files [$show_hidden]
Show backup files [$show_backup]
Always open dirs [$always_open_dirs]
Always open files [$always_open_files]
Open last used dir [$open_last]
Case-insensitive [$dmenu_caseinsens]
Display on bottom [$dmenu_onbottom]
Font [$dmenu_font]
Background [$dmenu_bg]
Foreground [$dmenu_fg]
Selected background [$dmenu_sbg]
Selected foreground [$dmenu_sfg]
Executor [$executor]
Editor [$editor]
File manager [$filemanager]
Set defaults
About"; ls -B "$plugins_dir/preferences") | $menu -p "Preferences")
                case "$opt" in
                    *"Show hidden files [$show_hidden]") (('show_hidden=!show_hidden')) ;;
                    *"Show backup files [$show_backup]") (('show_backup=!show_backup')) ;;
                    *"Always open dirs [$always_open_dirs]") (('always_open_dirs=!always_open_dirs')) ;;
                    *"Always open files [$always_open_files]") (('always_open_files=!always_open_files')) ;;
                    *"Open last used dir [$open_last]") (('open_last=!open_last')) ;;
                    *"Case-insensitive [$dmenu_caseinsens]") (('dmenu_caseinsens=!dmenu_caseinsens')) ;;
                    *"Display on bottom [$dmenu_onbottom]") (('dmenu_onbottom=!dmenu_onbottom')) ;;
                    *"Font [$dmenu_font]")
                        opt=$(echo -e "$dmenu_font\n[Default]" | $menu -p "Font:")
                        [[ "$opt" == '[Default]' ]] && opt="$d_dmenu_font"
                        [ "$opt" ] && dmenu_font="$opt"
                        dmenu_test=1
                    ;;
                    *"Background [$dmenu_bg]")
                        opt=$(echo -e "$dmenu_bg\n[Default]" | $menu -p "Background:")
                        [[ "$opt" == '[Default]' ]] && opt="$d_dmenu_bg"
                        [ "$opt" ] && dmenu_bg="$opt"
                        dmenu_test=1
                    ;;
                    *"Foreground [$dmenu_fg]")
                        opt=$(echo -e "$dmenu_fg\n[Default]" | $menu -p "Foreground:")
                        [[ "$opt" == '[Default]' ]] && opt="$d_dmenu_fg"
                        [ "$opt" ] && dmenu_fg="$opt"
                        dmenu_test=1
                    ;;
                    *"Selected background [$dmenu_sbg]")
                        opt=$(echo -e "$dmenu_sbg\n[Default]" | $menu -p "Selected background:")
                        [[ "$opt" == '[Default]' ]] && opt="$d_dmenu_sbg"
                        [ "$opt" ] && dmenu_sbg="$opt"
                        dmenu_test=1
                    ;;
                    *"Selected foreground [$dmenu_sfg]")
                        opt=$(echo -e "$dmenu_sfg\n[Default]" | $menu -p "Selected foreground:")
                        [[ "$opt" == '[Default]' ]] && opt="$d_dmenu_sfg"
                        [ "$opt" ] && dmenu_sfg="$opt"
                        dmenu_test=1
                    ;;
                    *"Executor [$executor]")
                        opt=$(echo -e "$executor\n[Default]" | $menu -p "Executor:")
                        [[ "$opt" == '[Default]' ]] && opt="$d_executor"
                        [ "$opt" ] && executor="$opt"
                    ;;
                    *"Editor [$editor]")
                        opt=$(echo -e "$editor\n[Default]" | $menu -p "Editor:")
                        [[ "$opt" == '[Default]' ]] && opt="$d_editor"
                        [ "$opt" ] && editor="$opt"
                    ;;
                    *"File manager [$filemanager]")
                        opt=$(echo -e "$filemanager\n[Default]" | $menu -p "File manager:")
                        [[ "$opt" == '[Default]' ]] && opt="$d_filemaneger"
                        [ "$opt" ] && filemanager="$opt"
                    ;;
                    *"Set defaults")
                        opt=$(echo -e "No\nYes" | $menu -p "Really set defaults?")
                        [[ "$opt" == "Yes" ]] && defaults
                    ;;
                    'About') echo -e "$about" | $menu -p "About:" ;;
                    *)
                        [ "$opt" ] && [ -e "$plugins_dir/preferences/$opt" ] && source "$plugins_dir/preferences/$opt"
                    ;;
                esac
            done
	    
            setmenu
            if [[ "$dmenu_test" == '1' ]]; then
                if [[ "OK" != "$(echo 'OK' | $menu -p 'Dmenu settings changed.')" ]]; then
                 defaults
                 source "$config"
                 setmenu
                 echo 'OK' | $menu -p 'Error in Dmenu settings.  Reverted.'
                fi
	    fi
            saveconfig
        elif [ -e "$plugins_dir/browser/$file" ]; then
            source "$plugins_dir/browser/$file"
        fi
    fi
    
done
saveconfig
----------------------------------------------------------------
Ну вот и всё, надеюсь, читающие нашли что-либо для себя интересное. :-D
П. С. :
А это в качестве бонуса :-) вписать в конфиг .musca_start
# Очень рекомендую установить rss-glx -- подборка замечательных хранителей экрана, которые использовать вместо фона рабочего стола намного веселее X-)
exec plasma_rss -r --resolution 56 --speed 16
Уважение за обзор :)
systemd должен умереть.
+1, хоть и не слезу с Awesome, но обзор в целом порадовал.
серьезный подход к делу!!! мое почтение!!!
Такие обзоры надо в блоги, вики, и, чуть-чуть переделав под инструкцию, опять же в вики, но уже в “настройки” ;) Респект.
 
Зарегистрироваться или войдите чтобы оставить сообщение.