Анатомия Awesome WM

Поскольку заметок прибавилось, вперемешку с обсуждением их, решено навести порядок в блоге. Пост про автозагрузку перенесен вниз, вместо него добавлено

ОГЛАВЛЕНИЕ

1. Awesome WM: разбор rc.lua "по косточкам"
2. Awesome WM: анимированный виджет на рабочем столе: аналоговые часы
3. Список автозагрузки средствами Awesome
4. Отображение браузерного видео в полноэкранном режиме
5. Создание всплывающего guake-like терминала (Haron_Prime)

Так я думаю будет удобнее ориентироваться в блоге
Да пребудет с нами Сила...!
CPU Intel Core i9 10900-KF/RAM DDR4 128 Gb/NVidia GForce GTX 1080 Ti Turbo 11Gb/SSD M2 512 Gb/HDD Seagate SATA3 2 Tb/HDD Toshiba 3Tb/HDD Toshiba 6Tb
http://rusrailsim.org
А зачем использовать awesome для автозагрузки? Я понимаю, что он почти как DE, в нем можно реализовать практически все. Но не проще ли использовать для этого более подходящие способы. Самый простой, xinitrc, при этом программы при перезапуске дублироваться не будут. В конце концов можно использовать пользовательскую сессию systemd, оно как раз для этого предназначено.

Но это конечно ваше дело, и наверняка кому то пригодится. А в целом я только рад, что на форуме появится блог про awesome)
Awesome WM: разбор rc.lua "по косточкам"

Переходя на awesome, я мотивировался возможностью воспользоваться преимуществами тайлинга, предоставляемого данным WM, при сохранении привычного функционала из Openbox.

Под тайлингом (англ. tiling) подразумевается способность менеджера окон управлять ими так, что при открытии каждого окна, оно не перекрывает предыдущие и располагается "встык" с ранее открытыми окнами. Собственно ради этой возможности и был затеян мой переход на awesome.

После установки данного WM из коробки доступен базовый функционал и несколько тем оформления. Большая часть настройки awesome осуществляется путем редактирования файла ~/.config/awesome/rc.lua. При открытии конфига, идущего искаропки, волосы становятся дыбом от обилия непонятного кода на Lua. Собственно этот код позволяет задать весь необходимый Вам функционал Вашей рабочей среды, и хочется того или нет, с ним лучше хорошенько разобраться. С этого начал и я, переписав конфиг заново, в той или иной степени разобрав каждую его часть и откомментил на русском языке. Результаты всего этого излагаю в данной статье.

Awesome WM написан на C/C++, а вот его настройка выполняется с помощью скриптов на языке Lua, причем имеется Lua API, документация по которому есть на сайте разработчика, и честно говоря не блещет подробностью.

Первое что надо сделать - скопировать содержимое каталога /usr/share/awesome/ в каталог ~/.config/awesome для того чтобы использовать идущие в комплекте скрипты тем, картинки иконок для последующей модификации. Мною для издевательств была выбрана тема Zeburn, от которой нам понадобится файл ~/.config/awesome/themes/zeburn/theme.lua

1. Начало

Результат моих потуг изображен на скриншоте


Разберу теперь детально какая часть конфига rc.lua за что тут отвечает

Начинается всё с подключения необходимых библиотек

-------------------------------------------------------------------------------
--	Стандартные библиотеки
-------------------------------------------------------------------------------

local gears = require("gears")
local awful = require("awful")
local vicious = require("vicious")

awful.rules = require("awful.rules")

require("awful.autofocus")

local wibox = require("wibox")

local beautiful = require("beautiful")

local naughty = require("naughty")

local menubar = require("menubar")

При первом запуске Awesome удивляют часы на английском языке, исправляем эту ситуацию


-------------------------------------------------------------------------------
--	Устанавливаем системную локаль (русскую)
-------------------------------------------------------------------------------
os.setlocale(os.getenv("LANG"))

Задаем тему оформления, которую будем использовать

-------------------------------------------------------------------------------
--	Устанавливаем тему
-------------------------------------------------------------------------------
beautiful.init("/home/maisvendoo/.config/awesome/themes/zenburn/theme.lua")

Задаем используемые по умолчанию приложения

-------------------------------------------------------------------------------
--	Устанавливаем приложения по умолчанию
-------------------------------------------------------------------------------
terminal = "urxvt" -- Терминал по умолчанию
browser = "firefox" -- Браузер по умолчанию
editor = os.getenv("EDITOR") or "nano" -- Консольный редактор по умолчанию
editor_cmd = terminal .. " -e" .. editor -- Команда запуска редактора

Определяем главную клавишу-модификатор, от которой пляшут все клавиатурные комбинации. В стандартном конфиге в качестве такой клавиши выбрана Mod4, она же клавиша "Windows" нафиг не нужная в линуксе. Тем же путем пошел и я, хотя есть идея сменить её на Alt, из-за того что виртуальные машины под виндой отбирают клавишу Win на вызов своего меню :(. Собственно делаем это так


-------------------------------------------------------------------------------
--	Клавиша-модификатор
-------------------------------------------------------------------------------
modkey = "Mod4"

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

$ xev | grep 'button'

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


-------------------------------------------------------------------------------
--	Кнопки мыши
-------------------------------------------------------------------------------
left_button = 1
right_button = 3
wheel_button = 2
plus_button = 9
minus_button = 8

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

$ xev | grep 'keycode'

жмем клавиши и заполняем глобальные определения для клавиатуры


-------------------------------------------------------------------------------
--	Скан-коды клавиш
-------------------------------------------------------------------------------
key_J = "#44"
key_K = "#45"
key_N = "#57"
key_M = "#58"
key_F = "#41"
key_R = "#27"
key_L = "#46"
key_C = "#54"
key_W = "#25"
key_Q = "#24"
key_H = "#43"
key_Tab = "#23"
key_Tilda = "#49"
key_U = "#30"
key_I = "#31"
key_T = "#28"
key_P = "#33"
key_O = "#32"
key_Return = "#36"
key_Left = "#113"
key_Right = "#114"
key_Esc = "#9"
key_PrtScn = "#107"

2. Режимы тайлинга

Теперь зададим layouts - макеты расположения окон на экране, которые собираемся использовать. Они задаются в виде массива-таблицы


-------------------------------------------------------------------------------
--	Layouts - способы расположения окон на экране
-------------------------------------------------------------------------------
local layuots =
{
  awful.layout.suit.tile,		-- Главное окно слева, справа второстепенные (мелкие)
  awful.layout.suit.tile.left,		-- Слева второстепенные окна
  awful.layout.suit.tile.bottom,	-- Внизу второстепенные окна
  awful.layout.suit.tile.top		-- Второстепенные окна вверху
}

Я выбрал только тайлинговые макеты, а те окна которые необходимо сделать плавающими настраиваются таковыми принудительно дальше.



Кладем обои на рабочий стол

-------------------------------------------------------------------------------
--	Обои рабочего стола
-------------------------------------------------------------------------------

-- Если в теме заданы обои
if beautiful.wallpaper then

  -- Перебираем все экраны
  for s = 1, screen.count() do

    -- На каждый экран кладем обои (можно в принципе на каждый экран свои)
    gears.wallpaper.maximized(beautiful.wallpaper, s, true)

  end

end

Переменная beautiful.wallpaper задается в конфиге темы, и являет собой путь к файлу с обоями

~/.config/awesome/themes/zeburn/theme.lua

-------------------------------------------------------------------------------
--	Обои
-------------------------------------------------------------------------------
theme.wallpaper = "/home/maisvendoo/admin/desktop/0001.jpg"

3. Тэги - виртуальные рабочие столы и не только

Дальше создаем массив тэгов - аналог виртуальных рабочих столов в любой другой DE, отличие тэгов от рабочих столов заключается в возножности одновременного отображения нескольких тегов


-------------------------------------------------------------------------------
--	Тэги - виртуальные рабочие столы
-------------------------------------------------------------------------------

-- Список тэгов
tags = {}

-- Перебираем все экраны
for s = 1, screen.count() do

  -- На каждом создаем список тэгов, устанавливая 1й макет отображения окон
  tags[s] = awful.tag({1, 2, 3, 4, 5, 6, 7, 8, 9}, s, layuots[1])

end

4. Главное меню

Теперь создаем главное меню. В Openbox оно мне было в принципе без надобности, только затем чтобы добраться до перезагрузки/выключения/логаута. Ну а для кого-то наличие такого менб будет необходимо ещё для чего-нибудь
Для начала создаем подменю. Они выполняются в виде Lua-таблицы, элементами которой являются таблицы, содержащие строки с названием пункта меню, команды, выполняемой при выборе этого пункта, и пути к иконке, отображаемой в данном пункте подменю


-------------------------------------------------------------------------------
--	Интернет-приложения
-------------------------------------------------------------------------------
internet_menu =
{
    -- Формат описания пункта меню
    --
    -- {<Назавание пункта меню>, <Команда запуска>, <Иконка>}

    {"Firefox", "firefox", beautiful.firefox_icon},
    {"Opera", "opera", beautiful.opera_icon},
    {"Kopete", "kopete", beautiful.kopete_icon}

}

-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
editors_menu =
{

  {"Kate", "kate"},
  {"GVim", "gvim"}

}

-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
office_menu = {

  {"Текстовый процессор", "libreoffice --writer"},
  {"Электронные таблицы", "libreoffice --calc"}

}

Теперь можно делать основное меню, содержащее обычные пункты и подменю


-------------------------------------------------------------------------------
--	Главное меню
-------------------------------------------------------------------------------
main_menu = awful.menu({

  -- Таблица пунктов главного меню
  items = {

      { " Интернет", internet_menu}, 	-- Подменю
      { " Редакторы", editors_menu},	-- Подменю
      { " LibreOffice", office_menu},	-- Подменю
      { " "},				-- Пустое место

      -- Обычные пункты меню

      { " Выход", awesome.quit, beautiful.logout_icon},
      { " Перезагрузка", function()  awful.util.spawn_with_shell("systemctl reboot") end, beautiful.reboot_icon},
      { " Выключение", function()  awful.util.spawn_with_shell("systemctl poweroff") end, beautiful.poweroff_icon}
  }

})

Очень кстати здесь пришлись безрутовые команды systemd по перезагрузке и выключению компа.

Должно получится нечто похожее на это


Пути к иконкам приложений, используемым в меню, необходимо прописать в теме

~/.config/awesome/themes/zeburn/theme.lua

-- Иконки приложений
theme.firefox_icon	     = "/usr/share/icons/hicolor/128x128/apps/firefox.png"
theme.netbeans_icon	     = "/usr/local/netbeans-7.3/nb/netbeans.png"
theme.vbox_icon		     = "/usr/share/icons/hicolor/64x64/mimetypes/virtualbox.png"
theme.fm_icon		     = "/home/maisvendoo/icons/fm.png"
theme.maple_icon	     = "/home/maisvendoo/maple16/bin/Maple16.png"
theme.doublecmd_icon         = "/usr/share/icons/hicolor/128x128/apps/krusader_user.png"
theme.opera_icon	     = "/usr/share/icons/hicolor/128x128/apps/opera-browser.png"
theme.kopete_icon	     = "/usr/share/icons/hicolor/48x48/apps/kopete.png"

-- Иконки элементов меню
theme.poweroff_icon         = "/home/maisvendoo/icons/PowerOff.png"
theme.logout_icon           = "/home/maisvendoo/icons/logout.png"
theme.reboot_icon           = "/home/maisvendoo/icons/reboot.png"

В дальнейшем эти же иконки мы используем для создания кнопок быстрого запуска приложений.

Теперь создаем кнопку-лаунчер, и вешаем на неё меню


-------------------------------------------------------------------------------
--	Лаунчер - та кнопка что на панели слева
--	(кнопка старт нафиг как виндовсе :)
-------------------------------------------------------------------------------

launcher = awful.widget.launcher({ image = beautiful.archlinux_icon, menu = main_menu })

Вместо стандартного авесомовского логотипа повесил патриотичный лого арча, предварительно прописав путь к изображению в теме

~/.config/awesome/themes/zeburn/theme.lua

theme.archlinux_icon	     = "/home/maisvendoo/icons/arch.png"

5. Кнопки быстрого запуска приложений

Наличие таковых оказалось принципиальным, в Openbox они реализовывались на tint2-svn, и я, и моя девушка к ним уже привыкли, и реализация таковой же функции в awesome стала одним из условий перехода.

Кнопки приложений можно создать с помощью виджета button, например таким образом

-------------------------------------------------------------------------------
--	Кнопки приложений на панели задач
-------------------------------------------------------------------------------

-- Firefox --------------------------------------------------------------------
-- Создаем виджет кнопки с необходимой иконкой
firefox_button = awful.widget.button({image = beautiful.firefox_icon})

-- Программируем реакцию кнопки на нажатие левой кнопки мыши
firefox_button:buttons( awful.util.table.join(

  awful.button({ }, left_button, function() awful.util.spawn_with_shell("firefox") end)

))

-- Netbeans -------------------------------------------------------------------
netbeans_button = awful.widget.button({image = beautiful.netbeans_icon})

netbeans_button:buttons( awful.util.table.join(

  awful.button({ }, left_button, function() awful.util.spawn_with_shell("netbeans") end)

))

6. Текстовые часы

С этим всё ок, данный виджет является стандартным, и создается просто


-------------------------------------------------------------------------------
--	Текстовые часы-календарь
-------------------------------------------------------------------------------
text_clock = awful.widget.textclock()

При нормально настроенной локализации часы будут отображаться по-русски.

7. Список тэгов

Список тегов - панель, отображающая значки тегов, и обеспечивающая возможность переключения между тэгами, перебрасывание клиентов с тега на тэг с помощью мыши. Создается она использованием виджета taglist


-- Декларируем список тэгов
tag_list = {}

-- Задаем обработку кнопок мыши для списка тегов
tag_list.buttons = awful.util.table.join(

  -- Отобразить тэг
  awful.button( { }, left_button, awful.tag.viewonly ),
  -- Переместить клиент на данный тэг
  awful.button( { modkey }, left_button, awful.client.movetotag ),
  -- Отобразить выбранный тэг вместе с текущим
  awful.button( { }, right_button, awful.tag.viewtoggle ),
  -- Отобразить текущий клиент в текущем и выбранном тэге
  awful.button( { modkey }, right_button, awful.client.toggletag ),
  -- Следующий тэг
  awful.button( { }, plus_button, function(t) awful.tag.viewnext(awful.tag.getscreen(t)) end ),
   -- Предыдущий тэг
  awful.button( { }, minus_button, function(t) awful.tag.viewprev(awful.tag.getscreen(t)) end )

)

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

8. Список задач

Список задач - это набор прямоугольных кнопок на панели задач, обозначающих запущенные приложения (как-то так)

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


-- Декларируем список задач
task_list = {}

-- Задаем обработку кнопок мыши для списка задач
task_list.buttons = awful.util.table.join(

  -- Левая кнопка
  awful.button( { }, left_button,

  function(c)

    -- Если клиент имеет фокус - свернуть его
    if c == client.focus then

      c.minimized = true

    else -- Иначе, передать фокус на клиент не сворачивая

      c.minimized = false

      -- и ещё вот эта хрень, назначение которой мне пока не ясно
      if not c:isvisible() then

	awful.tag.viewonly(c: tags()[1])

      end

      client.focus = c
      c:raise()

    end

  end),

  -- Щелчок правой кнопкой - закрыть окно, как в Openbox c tint2
  awful.button( { }, right_button,

  function(c)

    c:kill()

  end),

  -- Сместить фокус на следующее окно
  awful.button( { }, plus_button,

  function()

    awful.client.focus.byidx(1)

    if client.focus then client.focus:raise() end

  end),

  -- Сместить фокус на предыдущее окно
  awful.button( { }, minus_button,

  function()

    awful.client.focus.byidx(-1)
    if client.focus then client.focus.raise() end

  end)
)

9. Собираем всё вместе

Настал момент когда можно собрать то что будет выполнять в нашем WM роль панели задач. Стандартный конфиг подразумевает использование и нескольких мониторов, поэтому имеется цикл, перебирающий все экраны и выполняющий действия по созданию панельки на каждом из них


-------------------------------------------------------------------------------
--	Создаем для каждого экрана нижнюю панель задач
-------------------------------------------------------------------------------

-- Цикл, перебирающий все экраны
for s = 1, screen.count() do

  -- Командная строка - виджет реализующий комендную строку на панели задач
  prompt_box[s] = awful.widget.prompt()

  -- Кнопка переключения макетов расположения окон
  layout_box[s] = awful.widget.layoutbox(s)

  -- декларируем для неё назначения кнопок мыши
  layout_box[s]:buttons(

    awful.util.table.join(

       -- Переключить на макет вперед
      awful.button( { }, left_button,	function() awful.layout.inc(layuots, 1)		end ),
      -- Переключить на макет назад
      awful.button( { }, right_button,	function() awful.layout.inc(layuots, -1)	end ),
      -- То же самое для боковых кнопок
      awful.button( { }, plus_button,	function() awful.layout.inc(layuots, 1)		end ),
      awful.button( { }, minus_button,	function() awful.layout.inc(layuots, -1)	end )

    )
  )

  -- Список тэгов: передаем номер экрана, и назначения кнопок мыши
  tag_list[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, tag_list.buttons)

  -- Список запущенных задач: передаем номер экрана, и назначения кнопок мыши
  task_list[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, task_list.buttons)

  -- Контейнер для всех виджетов - наша панель задач
  -- расположенная внизу экрана номер s и шириной в 27 px
  main_wibox[s] = awful.wibox({ position = "bottom", height = "27", screen = s })

  -- Создаем виджеты расположенные слева  (левый блок виджетов)
  local left_layout = wibox.layout.fixed.horizontal()

  -- Добавляем на левый блок виджетов последовательно
  left_layout:add(launcher) -- лаунчер (кнопка главного меню)
  left_layout:add(tag_list[s]) -- список тэгов
  left_layout:add(prompt_box[s]) -- командную строку

  -- Кнопки приложений
  left_layout:add(firefox_button)
  left_layout:add(kopete_button)
  left_layout:add(vbox_button)
  left_layout:add(doublecmd_button)
  left_layout:add(maple_button)
  left_layout:add(netbeans_button)
  left_layout:add(fm_button)

  -- Создаем виджеты расположенные справа
  local right_layout = wibox.layout.fixed.horizontal()

  -- Системный трей делаем почему-то только на первом экране, взято из стандартного конфига
  if s == 1 then right_layout:add(wibox.widget.systray()) end

  -- Добавляем
  right_layout:add(text_clock) -- Текстовые часы
  right_layout:add(layout_box[s]) -- Кнопку переключения макетов

  -- Создаем контейнер для всей панели задач
  local layout = wibox.layout.align.horizontal()

  layout:set_left(left_layout)
  layout:set_middle(task_list[s])
  layout:set_right(right_layout)

  main_wibox[s]:set_widget(layout)

end

После добавления в конфиг данного кода панель появится на экране и будет функциональна.

10. Оживляем рабочую среду: программируем мышь и клавиатуру

Необходимо определить назначения мыши для всей среды, горячие клавиши для всей среды, а так же назначения для клиентов - окон приложений

Глобальных назначений мыши не так много оказалось в стандартном конфиге, их шерстить я не стал. Единственное что было добевлено - номера кнопок мыши поменялись на определенные выше глобальные переменные


-------------------------------------------------------------------------------
--	Назначения мыши
-------------------------------------------------------------------------------

root.buttons(

 awful.util.table.join(

   -- Правая кнопка - вызов меню
   awful.button( { }, right_button, function() main_menu:toggle() end ),
   -- Боковые кнопки - переключение тэгов по порядку
   awful.button( { }, plus_button, awful.tag.viewnext ),
   awful.button( { }, minus_button, awful.tag.viewprev )

 )

А вот назначений клавиш гораздо больше. Каждая комбинация добавляется вызовом

awful.key({ <клавиша-модификатор1>, <клавиша-модификатор2>, <функция-обработчик>)

Таблица назначений клавиш формируется как результат выполнения функции

<имя таблицы> = awful.util.table.join( комбинация 1, комбинация 2,..., комбинация n)

Кроме того, для себя заменил обозначения буквенных клавиш со строк латиницы на сканкоды, глобально определив их в переменных в начале конфига. Так удобнее.


-------------------------------------------------------------------------------
--	Назначения клавиатуры
-------------------------------------------------------------------------------

-- Глобальные назначения клавиш

globalkeys = awful.util.table.join(

  -- Переключение рабочих столов
  awful.key( { modkey,			}, key_Left, awful.tag.viewprev ),
  awful.key( { modkey,			}, key_Right, awful.tag.viewnext ),
  awful.key( { modkey,			}, key_Esc, awful.tag.history.restore ),

  -- Переключение фокуса клиентских окон

  awful.key( { modkey,			}, key_J,

  function()

      awful.client.focus.byidx(1)

      if client.focus then client.focus.raise() end

  end),

  awful.key( { modkey,			}, key_K,

  function()

      awful.client.focus.byidx(-1)

      if client.focus then client.focus.raise() end

  end),

  awful.key( { modkey,			}, key_W, function() main_menu:show() end ),

  -- Манипуляция областями экрана (перестановка клиентов)

  awful.key( { modkey,	"Shift"		}, key_J, function() awful.client.swap.byidx(1) end ),
  awful.key( { modkey,	"Shift"		}, key_K, function() awful.client.swap.byidx(-1) end ),
  awful.key( { modkey,	"Control"	}, key_J, function() awful.screen.focus_relative(1) end ),
  awful.key( { modkey,	"Control"	}, key_K, function() awful.screen.focus_relative(-1) end ),
  awful.key( { modkey,			}, key_U, awful.client.urgent.jumpto ),
  awful.key( { modkey,			}, key_Tab,

  function()

    awful.client.focus.history.previous()

    if client.focus then client.focus:raise() end

  end ),

  -- Запуск стандартных программ

  -- Терминал
  awful.key( { modkey,			}, key_Return, function() awful.util.spawn(terminal) end ),

  -- Командная строка
  awful.key( { modkey,			}, key_R, function() prompt_box[mouse.screen]:run() end ),

  awful.key( { modkey,			}, key_E, function() awful.util.spawn_with_shell("kate /home/maisvendoo/.config/awesome/rc.lua") end ),
  awful.key( { modkey,			}, key_I, function() awful.util.spawn_with_shell("firefox") end ),

  -- Перезапуск awesome
  awful.key( { modkey,	"Control"	}, key_R,

  function()

    -- Грохаем весь автозапуск
    for i = 0, num_cmd - 1 do

      local cmd = string.match(autostart_list[i], "%a+")

      awful.util.spawn_with_shell("killall " .. cmd)

    end

    -- Перезапускаем awesome
    awful.util.restart()

  end ),

  -- Утилита для изготовления скриншотов от KDE
  awful.key( { 				}, key_PrtScn,

  function()

    awful.util.spawn_with_shell("ksnapshot")

  end )
)

Аналогично определяем клавиатурные комбинации для клиентских окон


-- Клиентские назначения клавиш

clientkeys = awful.util.table.join(

  -- РАзвернуть на весь экран
  awful.key( { modkey,			}, key_F, 	function(c) c.fullscreen = not c.fullscreen end ),
  -- Закрыть окно
  awful.key( { modkey,	"Shift"		}, key_C, 	function(c) c:kill() end ),
  -- Перевести окно  в плавающий режим
  awful.key( { modkey,	"Control"	}, key_Space, 	awful.client.floating.toggle ),
  -- Сделать данной клиентское окно главным
  awful.key( { modkey,	"Control"	}, key_Return, 	function(c) c:swap( awful.client.getmaster() ) end ),
  -- Переместить окно на другой экран???
  awful.key( { modkey,			}, key_O, 	awful.client.movetoscreen ),
  -- Поместить окно поверх всех
  awful.key( { modkey,			}, key_T, 	function(c) c.ontop = not c.ontop end ),
  -- Минимизировать окно
  awful.key( { modkey,			}, key_N,

  function(c)

    c.minimized = true

  end ),

  -- Максимизировать окно
  awful.key( { modkey,			}, key_M,

  function(c)

    c.maximized_horizontal = not c.maximized_horizontal
    c.maximized_vertical = not c.maximized_vertical

  end )

)

Кроме того, к глобальным назначениям добавляются комбинации Mod4 + <цифровая клавиша>, путем перебора в цикле сканкодов цифровых клавиш и добавления в таблицу globalkeys


-------------------------------------------------------------------------------
--	Переключение тэгов и операции с клиентами и тэгами на каждом из экранов
-------------------------------------------------------------------------------

for i = 1, 9 do

  -- modkey + <номер тэга>
  -- Переключиться в выбранный тэг
  globalkeys = awful.util.table.join( globalkeys,

    awful.key({ modkey }, "#" .. i + 9,

    function()
	local screen = mouse.screen
	local tag = awful.tag.gettags(screen)[i]

	if tag then

	  awful.tag.viewonly(tag)

	end
    end),

    -- modkey + Ctrl + <номер тэга>
    -- Совместить выбранный тэг с текущим
    awful.key({ modkey, "Control" }, "#" .. i + 9,

    function()
	local screen = mouse.screen
	local tag = awful.tag.gettags(screen)[i]

	if tag then

	  awful.tag.viewtoggle(tag)

	end
    end),

    -- modkey + <номер тэга>
    -- Переместить клиент в фокусе на выьранный тэг
    awful.key({ modkey, "Shift" }, "#" .. i + 9,

    function()

	local tag = awful.tag.gettags(client.focus.screen)[i]

	if client.focus and tag then

	  awful.client.movetotag(tag)

	end
    end),

    -- modkey + <номер тэга>
    -- Переместить клиент в фокусе на выбранный тэг, оставив его и в текущем тэге
    awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,

    function()

	local tag = awful.tag.gettags(client.focus.screen)[i]

	if client.focus and tag then

	  awful.client.toggletag(tag)

	end
    end)

  )

end

Ну и наконец мышиные назначения для клиентских окон


-------------------------------------------------------------------------------
--	Назначение кнопок мыши для каждого клиента
-------------------------------------------------------------------------------

clientbuttons = awful.util.table.join(

  -- Переключить фокус
  awful.button( { }, left_button, function(c) client.focus = c; c:raise() end),
  -- Переместить
  awful.button( { modkey }, left_button, awful.mouse.client.move),
  -- Изменить размер
  awful.button( { modkey }, right_button, awful.mouse.client.resize)

)

Далее просто активируем глобальные клавиатурные комбинации


-- Задать глобальные клавиши
root.keys(globalkeys)

Чтобы активировать клиентские назначения необходимо....

11. Назначение ролей приложениям

Роли приложений определяют как каждое из них будет себя вести при запуске в awesome. В моем конфиге роли назначены так


-------------------------------------------------------------------------------
--	Роли приложений
-------------------------------------------------------------------------------

awful.rules.rules = {

  { -- Главная роль для всех приложений
    rule = { },

    properties = { border_width = beautiful.border_width,
		   border_color = beautiful.border_normal,
		   focus = awful.client.focus.filter,
		   keys = clientkeys,
		   buttons = clientbuttons}
  },

  -- Для "копыта": быть в плавающем режиме, сохранять размеры полученные перед закрытием
  --
  {

    rule = { instance = "kopete" },
    properties = { floating = true, maximized_horizontal = false, maximized_vertical = false }
  },

  -- Запуск терминалов - только на 9м тэге
  {

    rule = { class = "URxvt"},
    properties = { tag = tags[1][9]}

  },

  -- Скриншотница: без рамки, плавающее окно, сохранять размеры
  {

    rule = { class = "Ksnapshot"},
    properties = { border_width = 0,
		   floating = true,
		   maximized_horizontal = false,
		   maximized_vertical = false }

  },

  -- "Коньки": без рамки и плавать
  {

    rule = { class = "Conky"},
    properties = { border_width = 0, floating = true }

  }
}

У всех приложений должна быть одна быть прописана общая роль, определяющая поведение всех окон, и задающая клиентам назначения горячих клавиш и реакцию на мышь


{ -- Главная роль для всех приложений
    rule = { },

    properties = { border_width = beautiful.border_width, -- задается толщина рамки окна
		   border_color = beautiful.border_normal, -- цвет рамки окна не в фокусе
		   focus = awful.client.focus.filter, -- это что не знаю :(
		   keys = clientkeys, -- горячие клавиши
		   buttons = clientbuttons} -- кнопки мыши
  }

После добавления этой роли среда оживает, окна открываются, реагируют на заданные нажатия клавиш и мышь.

Однако возникает необходимость для конкретного приложения определить особое поведение, скажем ICQ-клиент не совсем удобно запускать в тайлинге, равно как и некоторые другие приложения. Для каких-то приложений может понадобится запуск только в одном или нескольких выбранных тегах. Все это делается настройкой ролей для каждого приложения одновременно. Для этого необходимо указать в роли класс приложения, который можно получить так

$ xprop | grep 'CLASS'

и далее щелкнув курсором мыши по нужному окну, в консольном выводе получим например такое


WM_CLASS(STRING) = "urxvt", "URxvt"

Вторая строка URxvt это и есть искомый класс окна, а первое - свойство под название instance (не помню что это, чесло... :( )

Теперь можно определить роль для терминалов быть только в 9м тэге


-- Запуск терминалов - только на 9м тэге
  {

    rule = { class = "URxvt"},
    properties = { tag = tags[1][9]}

  }

для ICQ-клиента быть плавающим окном с без максимизации окна


{

    rule = { instance = "kopete" },
    properties = { floating = true, maximized_horizontal = false, maximized_vertical = false }
  }

12. Сигналы

Определив роли перейдем к последнему - сигналам, определяющим поведение окна например при переводе фокуса на него, или при перемещении на него курсора мыши, и т.д.

Для начала я ограничился действиями при переводе фокуса на окно и уводе фокуса с него

Когда окно в фокусе перекрашиваем рамку и добавляем полоску заголовка окна с кнопками управления

-- У окон в фокусе
client.connect_signal("focus",

   function(c)

    -- Раскрасить рамку соответствеено
    c.border_color = beautiful.border_focus

    -- Нарисовать заголовок окна

    -- Виджет слева от заголовка окна
    local left_layout = wibox.layout.fixed.horizontal()
    left_layout:add(awful.titlebar.widget.iconwidget(c))

    -- Виджеты в правой части заголовка окна
    local right_layout = wibox.layout.fixed.horizontal()
    right_layout:add(awful.titlebar.widget.floatingbutton(c))
    right_layout:add(awful.titlebar.widget.maximizedbutton(c))
    right_layout:add(awful.titlebar.widget.stickybutton(c))
    right_layout:add(awful.titlebar.widget.ontopbutton(c))
    right_layout:add(awful.titlebar.widget.closebutton(c))

    -- Заголовок окна
    local middle_layout = wibox.layout.flex.horizontal()
    local title = awful.titlebar.widget.titlewidget(c)
    title:set_align("center")
    middle_layout:add(title)

    -- Расставляем блоки виджетов по местам
    local layout = wibox.layout.align.horizontal()
    layout:set_left(left_layout)
    layout:set_right(right_layout)
    layout:set_middle(middle_layout)

    -- Добавляем их на заголовок окна
    awful.titlebar(c):set_widget(layout)
    -- Задаем размер заголовка окна
    awful.titlebar(c, {size = 15})

   end)

У окон не в фокусе - перекрашиваю рамку и убираю заголовок


client.connect_signal("unfocus",

   function(c)

    c.border_color = beautiful.border_normal
    awful.titlebar(c, {size = 0})

   end)
Заключение

Выполнив всё это можно получить вполне работоспособную среду Awesome а заодно разобраться с основными механизмами настройки. На этом затянувшийся разбор завершаю :)
Да пребудет с нами Сила...!
CPU Intel Core i9 10900-KF/RAM DDR4 128 Gb/NVidia GForce GTX 1080 Ti Turbo 11Gb/SSD M2 512 Gb/HDD Seagate SATA3 2 Tb/HDD Toshiba 3Tb/HDD Toshiba 6Tb
http://rusrailsim.org
serkhay
Но не проще ли использовать для этого более подходящие способы
Проще, хотелось поупражнятся с Lua и заставить среду выполнять то что я хочу :)

Но первый пост переозаглавил.
Да пребудет с нами Сила...!
CPU Intel Core i9 10900-KF/RAM DDR4 128 Gb/NVidia GForce GTX 1080 Ti Turbo 11Gb/SSD M2 512 Gb/HDD Seagate SATA3 2 Tb/HDD Toshiba 3Tb/HDD Toshiba 6Tb
http://rusrailsim.org
вот чего хочу добиться, есть 3 приложения они стартуют вместе c системой, так вот надо сделать так что бы они располагались на одном теге, в котором кроме них ничего не будет, и надо что бы они располагались в определенном месте в самом теге. не подскажите как такое реализовать? И да рад что есть тема обсуждения awesome
kdeneur: https://github.com/brestows/kdeNeur
awesome WM 3.5
brestows, что вы имеете в виду под определенным местом? Одно из этих трех окон можно с помощью правил сделать главным, и тогда в обычном тайловом режиме оно будет слева, а два остальных окна будут делить оставшееся место
нет я хочу именно сделать так например что одно конкретное приложение располагалось справа и имело фиксированный размер например 100% по высоте и 25% по ширине, два остальных занимали бы по 50% по высоте и 100% из 75% оставшихся по ширине. Проблема в том что при запуске awesome Делить рабочее пространство между окнами по полам, и не удобно каждый раз изменять размер окон, пусть и горячими клавишами...
kdeneur: https://github.com/brestows/kdeNeur
awesome WM 3.5
Размер главного окна можно задать так в rc.lua
awful.tag.setproperty(tags[1][1], "mwfact", 0.25)
Соответственно на первом таге первого экрана главное окно и будет занимать 100% высоты и 25% ширины.
serkhay, спасибо! Буду дальше ковырять сей прекрасный WM
kdeneur: https://github.com/brestows/kdeNeur
awesome WM 3.5
Дописал пост про rc.lua. Продолжу по мере расковыривания информации :)

serkhay
Самый простой, xinitrc, при этом программы при перезапуске дублироваться не будут.

При перезапуске awesome они просто вырубаются, если из добавить в .xinitrc. Может я что неверно сделал?

compton &
urxvt -e mc &
urxvt -e htop &
urxvt &
guake &
sbxkb &
conky -c ~/.conky/.conkyrc &
conky -c ~/.conky/.conkyrc_lua_clock &
conky -c ~/.conky/.conkyrc_updates &
exec ck-launch-session dbus-launch awesome &

И ещё один глобальный вопрос.

При переключении раскладке на русскую дефолтный awesome не реагирует ни на мышь ни на клавиатурные комбинации. С клавиатурой решилось логичным образом - сменил латинские строки в конфиге на скан-коды. А вот мышь при русской раскладке не работает никак с элементами интерфейса - не жмет кнопки, не закрывает окна. Стоит вернуть юэс инглиш - снова всё работает! Это баг или фича?

P.S.: Нарыл решение

Проблема решается комментированием соответствующих строк в /usr/share/X11/xkb/compat/basic (комманда выше давалась именно для этого):

group 2 = AltGr;
group 3 = AltGr;
group 4 = AltGr;

Вообще говоря, этот баг и есть костыль, подробности тут: https://bugs.freedesktop.org/show_bug.cgi?id=50611#c6

и, собсна такой вид указанного фйла

[maisvendoo@arch-host ~]$ cat /usr/share/X11/xkb/compat/basic
// Minimal set of symbol interpretations to provide
// reasonable default behavior (Num lock, shift and
// caps lock and mode switch) and set up the
// automatic updating of common keyboard LEDs.
default xkb_compatibility "basic"  {
    virtual_modifiers NumLock,AltGr;
    interpret.repeat= False;
    setMods.clearLocks= True;
    latchMods.clearLocks= True;
    latchMods.latchToLock= True;
    interpret Shift_Lock+AnyOf(Shift+Lock) {
	action= LockMods(modifiers=Shift);
    };
    interpret Any+Lock {
	action= LockMods(modifiers=Lock);
    };
    interpret Num_Lock+Any {
	virtualModifier= NumLock;
	action= LockMods(modifiers=NumLock);
    };
    interpret Mode_switch {
	useModMapMods= level1;
	virtualModifier= AltGr;
	action= SetGroup(group=+1);
    };
    interpret Any + Any {
	action= SetMods(modifiers=modMapMods);
    };
    //group 2 = AltGr;
    //group 3 = AltGr;
    //group 4 = AltGr;
    include "ledcaps"
    include "lednum"
    indicator "Shift Lock" {
	!allowExplicit;
	whichModState= Locked;
	modifiers= Shift;
    };
};

решает проблему
Да пребудет с нами Сила...!
CPU Intel Core i9 10900-KF/RAM DDR4 128 Gb/NVidia GForce GTX 1080 Ti Turbo 11Gb/SSD M2 512 Gb/HDD Seagate SATA3 2 Tb/HDD Toshiba 3Tb/HDD Toshiba 6Tb
http://rusrailsim.org
 
Зарегистрироваться или войдите чтобы оставить сообщение.