Как я дошел до жизни такой
Все началось с перехода на новое место работы. Хотя, нет… Все началось
Главным событием стала смена работы, и последовавшая вместе с ней смена 17-дюймового монитора на 23-дюймовый. После пары недель работы стало абсолютно ясно, что используемый мной уже не один год Gnome не позволяет полноценно использовать все доступное мне пространство рабочего стола (1920*1080, это ж и подумать было страшно о таком разрешении на мониторе еще лет 10 назад). Фигурно расставлять окна довольно неудобно, а специфика работы системного администратора в моей организации подразумевает одновременное открытие и параллельное использование как минимум консоли, браузера, мессенджера, а так же еще кучи меняющихся в зависимости от контекста деятельности приложений, таких как rdesktop или vncviewer.
Как раз в этот момент я в очередной раз наткнулся на упоминание о тайловых менеджерах рабочего стола, и решил испробовать данный способ организации рабочего пространства. И о чудо — это оказалось весьма удобно. Испробовав несколько WM, я остановил свой выбор на Awesome. Через пару дней использования, я уверился в мысли о том, что именно такой тип WM как нельзя лучше подходит мне для работы, а awesome является достойным представителем данного типа, и принялся изучать возможность кастомизации своего рабочего стола. На мое счастье, Awesome начиная с третьей версии использует скрипт на языке Lua для конфигурации, что позволяет писать виджеты прямо в конфиге. Изучая доступные на сайте Awesome виджеты от пользователей, я наткнулся на виджет аналоговых часов, и беглый просмотр кода этого виджета показал мне отличную возможность реализовать давно интересующую меня вещь — бинарные часы, вместо стандартных для awesome текстовых. Все, что необходимо для этого — возможность рисовать изображение средствами самого Awesome, так что виджет не зависит от внешних компонентов.
image:draw_rectangle(x,y,w,h)
Конечно, язык Lua я до этого ни разу не использовал, но задача представлялась весьма тривиальной, так что я принялся за работу.
Итак, поехали
Открываем в текстовом редакторе нужный нам файл:
$vim ~/.config/awesome/rc.lua
Ищем имеющееся объявление виджета текстовых часов
mytextclock = awful.widget.textclock({ align = "right" })
И начинаем «творить»:
binaryclock = {}
binaryclock.widget = widget({type = "imagebox"})
binaryclock.w = 51 --width
binaryclock.h = 24 --height (better to be a multiple of 6)
--dont forget that awesome resizes our image with clocks to fit wibox's height
binaryclock.show_sec = true --must we show seconds?
binaryclock.color_active = beautiful.bg_focus --active dot color
binaryclock.color_bg = beautiful.bg_normal --background color
binaryclock.color_inactive = beautiful.fg_focus --inactive dot color
binaryclock.dotsize = math.floor(binaryclock.h / 6) --dot size
binaryclock.step = math.floor(binaryclock.dotsize / 2) --whitespace between dots
binaryclock.widget.image = image.argb32(binaryclock.w, binaryclock.h, nil) --create image
if (binaryclock.show_sec) then binaryclock.timeout = 1 else binaryclock.timeout = 20 end --we don't need to update often when we don't show seconds
Как вы видите, все настройки виджета задаются здесь, и все основные расчеты размеров проводятся тут же.
Дальше я использовал уже готовое решение для языка Lua, позволяющее переводить числа в десятичной системе исчисления в любую другую:
binaryclock.DEC_BIN = function(IN) --thanx to Lostgallifreyan (http://lua-users.org/lists/lua-l/2004-09/msg00054.html)
local B,K,OUT,I,D=2,"01","",0
while IN>0 do
I=I+1
IN,D=math.floor(IN/B),math.mod(IN,B)+1
OUT=string.sub(K,D,D)..OUT
end
return OUT
end
Теперь объявим функцию, рисующую точки-«диоды» часов, соответственно самому числу
binaryclock.paintdot = function(val,shift,limit) --paint number as dots with shift from left side
local binval = binaryclock.DEC_BIN(val)
local l = string.len(binval)
local height = 0 --height adjustment, if you need to lift dots up
if (l < limit) then
for i=1,limit - l do binval = "0" .. binval end
end
for i=0,limit-1 do
if (string.sub(binval,limit-i,limit-i) == "1") then
binaryclock.widget.image:draw_rectangle(shift, binaryclock.h - binaryclock.dotsize - height, binaryclock.dotsize, binaryclock.dotsize, true, binaryclock.color_active)
else
binaryclock.widget.image:draw_rectangle(shift, binaryclock.h - binaryclock.dotsize - height, binaryclock.dotsize,binaryclock.dotsize, true, binaryclock.color_inactive)
end
height = height + binaryclock.dotsize + binaryclock.step
end
end
Ну и наконец главная функция, рисующая наши часики:
binaryclock.drawclock = function () --get time and send digits to paintdot()
binaryclock.widget.image:draw_rectangle(0, 0, binaryclock.w, binaryclock.h, true, binaryclock.color_bg) --fill background
local t = os.date("*t")
local hour = t.hour
if (string.len(hour) == 1) then
hour = "0" .. t.hour
end
local min = t.min
if (string.len(min) == 1) then
min = "0" .. t.min
end
local sec = t.sec
if (string.len(sec) == 1) then
sec = "0" .. t.sec
end
local col_count = 6
if (not binaryclock.show_sec) then col_count = 4 end
local step = math.floor((binaryclock.w - col_count * binaryclock.dotsize) / 8) --calc horizontal whitespace between cols
binaryclock.paintdot(0 + string.sub(hour, 1, 1), step, 2)
binaryclock.paintdot(0 + string.sub(hour, 2, 2), binaryclock.dotsize + 2 * step, 4)
binaryclock.paintdot(0 + string.sub(min, 1, 1),binaryclock.dotsize * 2 + 4 * step, 3)
binaryclock.paintdot(0 + string.sub(min, 2, 2),binaryclock.dotsize * 3 + 5 * step, 4)
if (binaryclock.show_sec) then
binaryclock.paintdot(0 + string.sub(sec, 1, 1), binaryclock.dotsize * 4 + 7 * step, 3)
binaryclock.paintdot(0 + string.sub(sec, 2, 2), binaryclock.dotsize * 5 + 8 * step, 4)
end
binaryclock.widget.image = binaryclock.widget.image
end
Конечно, не самое элегантное решение, но работает.
Нам осталось только установить таймер обновления:
binarytimer = timer { timeout = binaryclock.timeout } --register timer
binarytimer:add_signal("timeout", function()
binaryclock.drawclock()
end)
binarytimer:start()--start timer
и разместить наш виджет на панели (вибоксе):
mywibox[s].widgets = {
--widgets
binaryclock.widget,
--widgets again
layout = awful.widget.layout.horizontal.rightleft
}
Хотя для пущей красоты (и нормального размера часов на Full-HD экране), мне пришлось еще изменить высоту панели:
mywibox[s] = awful.wibox({ position = "top", screen = s, height = "22" })
Пусть вас не удивляет высота панели в 22px, при высоте виджета в 24. Awesome масштабирует изображения в панели, но почему-то при высоте панели 24px иконка Pidgin в трее ведет себя очень склочно, мигает, и вообще капризничает.
Работа закончена, можно оценить результат, перезапустив Awesome чудесным комбо Mod4+Ctrl+r.
И что же в итоге?
Результат моего труда вы можете оценить на скриншоте:

Пара дней написания кода в обеденный перерыв — и бинарные часы благополучно замигали, показывая время в панели awesome, а я обогатился знаниями о языке Lua, и украсил свое виртуальное рабочее пространство. Awesome, кстати, так же показал свою пригодность к использованию и на моем 11-дюймовом ноутбуке, позволив мне почти полностью отказаться от использования тачпада/трекпада, и увеличить общую отзывчивость ноутбука.
P.S. Код виджета