Моё знакомство с WM Awesome. Часть 1

от автора

Разговор пойдёт о моём первом знакомстве с таким оконным менеджером, как Awesome. Долгое время я использовал Gnome2, потом пробовал Gnome3, решил испробовать kde, но ничего из этого не удовлетворило меня. Да, к слову, у меня Gentoo. Да, статья ориентирована на таких же как и я новичков — дабы упростить жизнь.

В официальной ветке портажа стабильной является версия 3.4.15, но я решил поставить последнюю доступную — 3.5.2-r1, с USE флагом «dbus». В качество логин менеджера я выбрал SLiM. После сборки всех необходимых пакетов открываем /etc/conf.d/xdm и устанавливаем SLiM в качестве менеджера по умолчанию:

DISPLAYMANAGER="slim"

Далее необходимо сделать небольшие изменение я /etc/slim.conf

# login_cmd exec /bin/sh - ~/.xinitrc %session
login_cmd exec /bin/bash -login ~/.xinitrc %session
# login_cmd exec /bin/bash -login /usr/share/slim/Xsession %session

В этом конфиге также можете выбрать понравившуюся тему, которые лежат в /usr/share/slim/themes. Я обхожусь дефолтной. Так же там есть ещё пару интересных параметров, но я их не трогал — нет необходимости.

Терминал я решил использовать urxvt. У меня он собран:

rxvt USE="xgetdefaults"
rxvt-unicode USE="256-color focused-urgency font-styles mousewheel perl startup-notification vanilla xft"

Чтобы, собственно, запустился наш wm нужно вмести изменения в файл ~/.xinitrc (если его нету — то создать), ниже привожу свой:

urxvtd --quiet --opendisplay --fork &
pulseaudio --start &
exec ck-launch-session dbus-launch awesome

Первая строка — запускаю демон urxvt (в дальнейшем клиент вызывается urxvtc), ну, во второй понятно запускаем pulseaudio, и в последней запускаем сам awesome. Стоит отметить, что если у вас systemd, а не consolekit — то у вас вызов awesome вроде как отличается, но я не использую systemd, поэтому не берусь утверждать.

Запускаем xdm:
sudo /etc/init.d/xdm start

Логинимся и наблюдаем вот такую вот картину:

Я долго лазил по разным форумам в поисках красивых темок, конфигов, виджетов для awesome. Наткулся на такого пользователя unligic (у него много статей и интересных вещей на github)

И более новая версия его темы:

Меня это очень впечатлило и я решил поставить себе его тему — но это не увенчалось успехом. Тема просто не работало. При исправлении одной ошибки появлялась новая и т.д. Позже я увидел его пост, содержание примерно такое «ставить новичку не советую, так как там много костылей, потратите кучу времени и не факт, что заработает». Собственно так и получилось. Тогда я решил писать конфиг сам. Знаний в Lua у меня не было вообще, но гугл всегда помогает.

Конфигурационный файл лежит в /etc/xdg/awesome/rc.lua — но его я трогать не советую, просто скопируем его
cp /etc/xdg/awesome/rc.lua ~/.config/awesome/rc.lua
(У кого-то директории .config может не оказаться, не пугайтесь — просто создайте.
mkdir ~/.config
mkdir ~/.config/awesome

Начнём конфигурацию. (Да, я, пользуясь многими статьями, просто переписал его)

Тут мы перечисляем все подключаемые библиотеки

--------------------------------------------- --- Стандартные библиотеки --- --------------------------------------------- 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") local dbus = require("dbus") 

Вроде всё понятно 🙂

--------------------------------------------------------- --- Устанавливаем системную локаль --- --------------------------------------------------------- os.setlocale("ru_RU.UTF-8") 

Эту часть оставляем без изменений — это обработчик ошибок

-- {{{ Error handling -- Check if awesome encountered an error during startup and fell back to -- another config (This code will only ever execute for the fallback config) if awesome.startup_errors then     naughty.notify({ preset = naughty.config.presets.critical,                      title = "Oops, there were errors during startup!",                      text = awesome.startup_errors }) end  -- Handle runtime errors after startup do     local in_error = false     awesome.connect_signal("debug::error", function (err)         -- Make sure we don't go into an endless error loop         if in_error then return end         in_error = true          naughty.notify({ preset = naughty.config.presets.critical,                          title = "Oops, an error happened!",                          text = err })         in_error = false     end) end -- }}} 

Я взял за основу тему zenburn (лежит в /usr/share/awesome/themes/zenburn). И решил её немного поменять под себя (практически не значительно, пока что)

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

Параметр -nw в последней строчке позволяет запускать emacs в терминале

---------------------------------------------------------------------- --- Устанавливаем приложения по умолчанию --- ---------------------------------------------------------------------- terminal         = "urxvtc" -- Терминал по умолчанию browser         = "google-chrome-stable" -- Браузер по умолчанию editor              = os.getenv("EDITOR") or "emacs" -- Редактор по умолчанию editor_cmd    = terminal .. " -nw" .. editor -- Команда запуска консольного редактора 

Отступы ужасно съехали, но в редакторе оно всё красиво. Клавиша модификатор — её ещё называет супер, клавиша с логотипом шиндоуса. Чаще всего это Mod4, но может и отличаться. И далее коды кнопок мыши и нужных в конфиге клавиш. Для проверки кодов мыши:
xev | grep 'button'

Для клавиши модификатора и остальных клавиш:
xev | grep 'keycode'

Коды кнопок и клавиш

----------------------------------------- --- Клавиша-модификатор --- ----------------------------------------- modkey             = "Mod4"  --------------------------- --- Кнопки мыши --- --------------------------- left_button                  = 1 wheel_button            = 2 right_button               = 3 plus_button               = 4  minus_button           = 5 wheel_left_button    = 6 wheel_write_button = 7  ----------------------------------- --- Скан-коды клавиш --- ----------------------------------- key_V              = "#55" key_Z              = "#52" key_Y               = "#29" 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_X                = "#53" key_Q                = "#24" key_H                = "#43" key_Tab             = "#23" key_Tilda           = "#49" key_U                  = "#30" key_E                  = "#26" key_T                   = "#28" key_P                   = "#33" key_O                   = "#32" key_Return          = "#36" key_Left               = "#113" key_Right            = "#114" key_Esc               = "#9" key_Print              = "#107" key_Alt_R             = "#108" key_Alt_L              = "#64" key_Space           = "#65" key_Ctrl_R           = "#105" key_Ctrl_L            = "#37" key_Home            = "#110" key_F1                   = "#67" key_Mute               = "#121" key_Vol_Down     = "#122" key_Vol_Up          = "#123" 

Здесь я выбрал нужные мне разметки окон

------------------------------------------------------------------------------ --- Layouts - способы расположения окон на экране --- ----------------------------------------------------------------------------- local layouts = {     awful.layout.suit.floating,          -- 1       awful.layout.suit.tile,                  -- 2 Главное окно слева, справа второстепенные (мелкие)     --awful.layout.suit.tile.left,         -- * Слева второстепенные окна     awful.layout.suit.tile.bottom,    -- 3 Внизу второстепенные окна     --awful.layout.suit.tile.top,         -- * Второстепенные окна вверху     awful.layout.suit.fair,                  -- 4     --awful.layout.suit.fair.horizontal,     --awful.layout.suit.spiral,     awful.layout.suit.spiral.dwindle,    -- 5     awful.layout.suit.max,                      -- 6     --awful.layout.suit.max.fullscreen,     awful.layout.suit.magnifier             -- 7 } 

Тут всё ясно

-------------------------------------- --- Обои рабочего стола --- -------------------------------------- -- Если в теме заданы обои if beautiful.wallpaper then   -- Перебираем все экраны   for s = 1, screen.count() do     -- На каждый экран кладем обои (можно в принципе на каждый экран свои)     gears.wallpaper.maximized(beautiful.wallpaper, s, true)   end end 

Имена тегов могут быть абсолютно любыми — я выбрал греческие буквы — как на скрине unligic. Каждому отдельному тегу я присваиваю своё макет, которые мы определили выше.

Тэги

--------------------------------------------------------- --- Тэги - виртуальные рабочие столы --- --------------------------------------------------------- -- Список тэгов tags = {    -- Имена тэгов    names  = { "  α  ", "  β  ", "  ζ  ", "  Θ  ", "  Ξ  ", "  ς  ", "  ψ  "},    -- Макеты тэгов    layout = { layouts[1], layouts[2], layouts[3], layouts[4], layouts[5],               layouts[6],  layouts[7] }} -- Перебираем все экраны for s = 1, screen.count() do    -- На каждом создаем список тэгов, устанавливая макет отображения окон    tags[s] = awful.tag(tags.names, s, tags.layout) end 

Собираем менюшку (не знаю зачем она нужна, так ни разу и не использовал)

------------------------------ --- Главное меню --- ------------------------------ --- Интернет-приложения internet_menu = {     -- Формат описания пункта меню     -- {<Назавание пункта меню>, <Команда запуска>, <Иконка>}     {" Firefox", "firefox-bin", beautiful.firefox_icon},     {" Chrome", "google-chrome-stable", beautiful.chrome_icon},     {" Pidgin", "pidgin"} } ---  editors_menu = {   {" Eclipse", "eclipse-bin-4.2"},   {" Emacs", "emacs"} } ---  office_menu = {   {" Word", "libreoffice --writer"},   {" Exel", "libreoffice --calc"} }  main_menu = awful.menu({   -- Таблица пунктов главного меню   items = {       {" Интернет", internet_menu},       {" Редакторы", editors_menu},       {" LibreOffice", office_menu},       {" "},       {" Перезагрузка", "reboot", beautiful.reboot_icon},       {" Выключение", "halt", beautiful.poweroff_icon},       {" Выход", awesome.quit, beautiful.logout_icon}   } })  ------------------------------------------------------------------ --- Лаунчер - та кнопка что на панели слева ---  ------------------------------------------------------------------ launcher = awful.widget.launcher({ image = beautiful.gentoo_icon, menu = main_menu }) 

А вот это так и не понял для чего

-- Menubar configuration menubar.utils.terminal = terminal -- Set the terminal for applications that require it -- }}} 

Тут объявляем все виджеты, которые буду использоваться. Сразу стоит отметить баг — при нажатии клавиши «отключить звук» звук исчезает, при повторном нажатии — на виджете отображает, что звук включён, но его нету. Приходится прописывать команду вручную в консоли, странно. Пока не нашёл как его исправить. И ещё смущает отображаение громкости — 90% по факту ~70 единиц в alsamixer, надо бы исправить, но никак не дойдёт руки. Ну а остальное вроде как интуитивно понятно

Виджеты

--------------------- --- Виджеты --- --------------------- opening_brace = '<span foreground="white" font_desc="Ubuntu">[</span>' closing_brace = '<span foreground="white" font_desc="Ubuntu">] </span>' function enbrace(str)    return " "..opening_brace..str..closing_brace..' ' end  function colorify(str, color)    return '<span foreground="'..color..'">'..str..'</span>' end  function get_colorload(val)    local color = 'green'    if val > 85 then       color = 'red'    elseif val > 60 then       color = 'yellow'    end    return color end  function format_throughput(val)    if (val < 1000) then       return string.format('%3dKB/s', val)    elseif (val < 10240) then       return string.format('%.1fMB/s', val/1024)    else       return string.format('%3dMB/s', val/1024)    end end  one_sec_timer = timer{timeout = 1} ten_sec_timer = timer{timeout = 10}  spacer_big = wibox.widget.textbox()   spacer_big:set_text('     ') spacer_small = wibox.widget.textbox()   spacer_small:set_text('  ') volumecfg = {} volumecfg.cardid  = 0 volumecfg.channel = "Master" volumecfg.widget = wibox.widget.textbox() vol_color = {} -- command must start with a space! volumecfg.mixercommand = function (command)        local fd = io.popen("amixer -c " .. volumecfg.cardid .. command)        local status = fd:read("*all")        fd:close()         local volume = string.match(status, "(%d?%d?%d)%%")        volume = string.format("% 3d", volume)        status = string.match(status, "%[(o[^%]]*)%]")        if string.find(status, "on", 1, true) then                volume = volume .. "%" 	       vol_color="cyan"        else                volume = volume .. "×" 		vol_color = "red"        end        volumecfg.widget:set_markup(enbrace(colorify(volume, vol_color)))  end volumecfg.update = function ()        volumecfg.mixercommand(" sget " .. volumecfg.channel) end volumecfg.up = function ()        volumecfg.mixercommand(" sset " .. volumecfg.channel .. " 1%+") end volumecfg.down = function ()        volumecfg.mixercommand(" sset " .. volumecfg.channel .. " 1%-") end volumecfg.toggle = function ()        volumecfg.mixercommand(" sset " .. volumecfg.channel .. " toggle") end volumecfg.update()  client.connect_signal("manage", function (c, startup)     c.size_hints_honor = false end)  batterybox = wibox.widget.textbox()  function battery ()    local io_info = io.open("/proc/acpi/battery/BAT0/info")    local io_state  = io.open("/proc/acpi/battery/BAT0/state")    local str_info = io_info:read("*a")    local str_state = io_state:read("*a")    io.close(io_info)    io.close(io_state)     local capacity = str_info:match("last full capacity:%s+(%d+)")    local current  = str_state:match("remaining capacity:%s+(%d+)")    local state    = str_state:match("charging state:%s+(%a+)")    local rate     = str_state:match("present rate:%s+(%d+)")     local st_color = 'green'    if state == 'discharging' then       st_color = 'red'    elseif state == 'charging' then       st_color = 'yellow'    end     local remain_time_str = 'inf'    remain_chrg = ((current * 100) / capacity)    if (('discharging' == state) and (nil ~= rate) and (rate > '0')) then       remain_time = current/rate       remain_time_str = string.format('%dh %.2dm', remain_time, remain_time*60%60)    end    local rem_color = 'red'    if remain_chrg > 15 then       rem_color = 'yellow'    end    if remain_chrg > 60 then       rem_color = 'green'    end    batterybox:set_markup( enbrace(colorify('bat: ', 'orange')                            ..colorify(string.format("%d%%", remain_chrg), rem_color)                            ..', '                            ..colorify(remain_time_str, rem_color)                            ..', '                            ..colorify(state, st_color))) end  battery() ten_sec_timer:connect_signal("timeout", battery)   membox = wibox.widget.textbox() function memory()    local io_meminfo      = io.open("/proc/meminfo")    local str_meminfo     = io_meminfo:read("*a")    io.close(io_meminfo)     local total           = str_meminfo:match("MemTotal:%s+(%d+)")    local free            = str_meminfo:match("MemFree:%s+(%d+)")    local buffers         = str_meminfo:match("Buffers:%s+(%d+)")    local cached          = str_meminfo:match("Cached:%s+(%d+)")    local swap_total      = str_meminfo:match("SwapTotal:%s+(%d+)")    local swap_free       = str_meminfo:match("SwapFree:%s+(%d+)")    local swap_cached     = str_meminfo:match("SwapCached:%s+(%d+)")     local total_free      = free + buffers + cached    local total_swap_free = swap_free + swap_cached     local p_mem           = 100*(total - total_free)/total    local mem_color       = get_colorload(p_mem)    local sw_mem          = 100*(swap_total - total_swap_free)/swap_total    local sw_mem_color    = get_colorload(sw_mem)     local p_mem           = 100*(total - total_free)/total    local mem_color       = get_colorload(p_mem)    local sw_mem          = 100*(swap_total - total_swap_free)/swap_total    local sw_mem_color    = get_colorload(sw_mem)     membox:set_markup(enbrace(                              colorify('mem: ', 'orange')                              ..colorify(string.format('%2d%%', p_mem), mem_color)                              ..'('..colorify(string.format('%3dMb', (total - total_free)/1024), mem_color)                              ..colorify(string.format('/%3dMb', (total)/1024), 'white')                              ..')'                              ..' | '                              ..colorify('swap: ', 'orange')                              ..colorify(string.format('%2d%%', sw_mem), sw_mem_color)                              ..'('..colorify(string.format('%3dMb', (swap_total - total_swap_free)/1024), sw_mem_color)                              ..colorify(string.format('/%3dMb', (swap_total)/1024), 'white')                              ..')'                             )                      ) end memory() one_sec_timer:connect_signal("timeout", memory)  -- CPU usage widget cpugraph = awful.widget.graph() cpugraph:set_width(75) cpugraph:set_height(25) cpugraph:set_background_color("#494B4F") --cpugraph:set_color("#FF5656") cpugraph:set_color({ type = "horisontal", from = { 0, 0 }, to = { 0, 20 }, stops = { { 0, "#FF5656" }, { 0.5, "#88A175" }, { 1, "#AECF96" } }}) -- Register CPU widget vicious.register(cpugraph, vicious.widgets.cpu,                      function (widget, args)                         return args[1]                     end) cpubox = wibox.widget.textbox() cpubox_img = wibox.widget.imagebox() cpu_arr = {} cpu0_arr = {} cpu1_arr = {} for i = 0, 4 do    cpu_arr[i] = 0    cpu0_arr[i] = 0    cpu1_arr[i] = 0 end function parse_cpu(cpu, stat)    local cpu_new = {}    local ret = {}    cpu_new[0], cpu_new[1], cpu_new[2], cpu_new[3], cpu_new[4] = stat:match("cpu%d*%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)")     local idle   = (cpu_new[3] - cpu[3]) + (cpu_new[4] - cpu[4])    local user   = (cpu_new[1] - cpu[1]) + (cpu_new[0] - cpu[0])    local system = (cpu_new[2] - cpu[2])    local total  = idle + user + system    local busy   = user + system     ret['busy'] = busy*100/total    ret['sys'] = system*100/total    ret['user'] = user*100/total    ret['cpu'] = cpu_new     return ret end  function cpu()    local io_stat  = io.open("/proc/stat")    local str_stat = io_stat:read("*l")    io.close(io_stat)     local ret = parse_cpu(cpu_arr, str_stat)    cpu_arr = ret['cpu']       cpubox:set_markup (enbrace(colorify('cpu: ', 'orange')                        ..'('                        ..colorify(string.format('%3d%%', ret['busy']), get_colorload(ret['busy']))                        ..') | (u:'                        ..colorify(string.format('%3d%%', ret['user']), get_colorload(ret['user']))                        ..', s:'                        ..colorify(string.format('%3d%%', ret['sys']), get_colorload(ret['sys']))                        ..')')) end  cpu() one_sec_timer:connect_signal("timeout", cpu)  		     hddbox = wibox.widget.textbox() hdd_r = 0 hdd_w = 0 hddlist = {'/sys/block/sda/stat', '/sys/block/sdb/stat'}  function hdd()    local new_r = 0    local new_w = 0    for i = 1, 2 do       local io_stat = io.open(hddlist[i])       local str_stat = io_stat:read("*a")       io.close(io_stat)       local rd, wr = str_stat:match("%s+%d+%s+%d+%s+(%d+)%s+%d+%s+%d+%s+%d+%s+(%d+)")       new_w = new_w + wr       new_r = new_r + rd    end    local r = (new_r - hdd_r)/2    local w = (new_w - hdd_w)/2    hdd_w = new_w    hdd_r = new_r     hddbox:set_markup ( enbrace(colorify('i/o: ', 'orange')                        ..'(r: '                        ..colorify(format_throughput(r), 'green')                        ..', w:'                        ..colorify(format_throughput(w), 'green')                        ..')')) end -- RAM usage widget memwidget = awful.widget.progressbar() memwidget:set_width(30) memwidget:set_height(25) memwidget:set_vertical(true) memwidget:set_background_color('#494B4F') memwidget:set_color('#AECF96') cpugraph:set_color({ type = "linear", from = { 0, 0 }, to = { 0, 20 }, stops = { { 0, "#AECF96" }, { 0.5, "#88A175" }, { 1, "#FF5656" } }})  vicious.cache(vicious.widgets.mem) vicious.register(memwidget, vicious.widgets.mem,                 function (widget, args)                     return args[1]                  end, 1)                  --update every 13 seconds  hdd() one_sec_timer:connect_signal("timeout", hdd)   -- Start timers to update widgets one_sec_timer:start() ten_sec_timer:start() -- Часы и дата text_clock = awful.widget.textclock() -- Create a systray systray = wibox.widget.systray() 

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

ссылка на оригинал статьи http://habrahabr.ru/post/214411/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *