diff --git a/README b/README index 6d1104b..79c40bd 100644 --- a/README +++ b/README @@ -1,16 +1,16 @@ Vicious ------- -Vicious is a modular widget library for the "awesome" window manager, -derived from the "Wicked" widget library. It has some of the old -Wicked widget types, a few of them rewritten, and a good number of new -ones: +Vicious is a modular widget library for window managers, but mostly +catering to users of the "awesome" window manager. It was derived from +the old "Wicked" widget library, and has some of the old Wicked widget +types, a few of them rewritten, and a good number of new ones: - http://git.sysphere.org/vicious/about/ -Vicious widget types are a framework for creating your own awesome +Vicious widget types are a framework for creating your own widgets. Vicious contains modules that gather data about your system, -and a few helper functions that make it easier to register timers, -suspend widgets and so on. +and a few "awesome" helper functions that make it easier to register +timers, suspend widgets and so on. For now Vicious doesn't depend on any third party Lua libraries, to make it easier to install and use. That means some system utilities @@ -24,8 +24,22 @@ are used instead, where available: Usage ----- -To use vicious move it to your awesome configuration directory in -$XDG_CONFIG_HOME (usually ~/.config): +When provided by an operating system package, or installed from source +into the Lua library path Vicious can be used as a regular Lua +library, to be used stand-alone or to feed widgets of any window +manager (ie. Ion, WMII). It is compatible with both Lua v5.1 and v5.2. + + $ lua + > widgets = require("vicious.widgets") + > print(widgets.volume(nil, "Master")[1]) + 100 + + +Usage within Awesome +-------------------- +To use Vicious with Awesome, install the package from your operating +system provider, or download the source code and move it to your +awesome configuration directory in $XDG_CONFIG_HOME (usually ~/.config): $ mv vicious $XDG_CONFIG_HOME/awesome/ @@ -373,7 +387,7 @@ file with their GPG key. Trough the GPG Passphrase Agent they could then decrypt the file transparently while their session is active. -Usage examples (for awesome v3.4) +Usage examples --------------------------------- Start with a simple widget, like date. Then build your setup from there, one widget at a time. Also remember that besides creating and @@ -381,14 +395,14 @@ registering widgets you have to add them to a wibox (statusbar) in order to actually display them. Date widget - datewidget = widget({ type = "textbox" }) + datewidget = wibox.widget.textbox() vicious.register(datewidget, vicious.widgets.date, "%b %d, %R") - updated every 2 seconds (the default interval), uses standard date sequences as the format string Memory widget - memwidget = widget({ type = "textbox" }) + memwidget = wibox.widget.textbox() vicious.cache(vicious.widgets.mem) vicious.register(memwidget, vicious.widgets.mem, "$1 ($2MB/$3MB)", 13) @@ -396,7 +410,7 @@ Memory widget values and enables caching of this widget type HDD temperature widget - hddtempwidget = widget({ type = "textbox" }) + hddtempwidget = wibox.widget.textbox() vicious.register(hddtempwidget, vicious.widgets.hddtemp, "${/dev/sda} °C", 19) - updated every 19 seconds, requests the temperature level of the @@ -404,7 +418,7 @@ HDD temperature widget not provide the port argument so default port is used Mbox widget - mboxwidget = widget({ type = "textbox" }) + mboxwidget = wibox.widget.textbox() vicious.register(mboxwidget, vicious.widgets.mbox, "$1", 5, "/home/user/mail/Inbox") - updated every 5 seconds, provides full path to the mbox as an @@ -417,8 +431,8 @@ Battery widget batwidget:set_vertical(true) batwidget:set_background_color("#494B4F") batwidget:set_border_color(nil) - batwidget:set_color("#AECF96") - batwidget:set_gradient_colors({ "#AECF96", "#88A175", "#FF5656" }) + batwidget:set_color({ type = "linear", from = { 0, 0 }, to = { 0, 10 }, + stops = { { 0, "#AECF96" }, { 0.5, "#88A175" }, { 1, "#FF5656" }}) vicious.register(batwidget, vicious.widgets.bat, "$2", 61, "BAT0") - updated every 61 seconds, requests the current battery charge @@ -429,8 +443,8 @@ CPU usage widget cpuwidget = awful.widget.graph() cpuwidget:set_width(50) cpuwidget:set_background_color("#494B4F") - cpuwidget:set_color("#FF5656") - cpuwidget:set_gradient_colors({ "#FF5656", "#88A175", "#AECF96" }) + cpuwidget:set_color({ type = "linear", from = { 0, 0 }, to = { 50, 0 }, + stops = { { 0, "#FF5656" }, { 0.5, "#88A175" }, { 1, "#AECF96" }}) vicious.register(cpuwidget, vicious.widgets.cpu, "$1", 3) - updated every 3 seconds, feeds the graph with total usage @@ -454,7 +468,7 @@ second argument, and will return the text/data to be used for the widget. Example - mpdwidget = widget({ type = "textbox" }) + mpdwidget = wibox.widget.textbox() vicious.register(mpdwidget, vicious.widgets.mpd, function (widget, args) if args["{state}"] == "Stop" then return "" @@ -467,7 +481,7 @@ Example seconds (the default interval) Example - uptimewidget = widget({ type = "textbox" }) + uptimewidget = wibox.widget.textbox() vicious.register(uptimewidget, vicious.widgets.uptime, function (widget, args) return string.format("Uptime: %2dd %02d:%02d ", args[1], args[2], args[3]) @@ -482,9 +496,10 @@ textbox widgets by changing their .width field (by default width is automatically adapted to text width). Example - uptimewidget = widget({ type = "textbox" }) - uptimewidget.width, uptimewidget.align = 50, "right" + uptimewidget = wibox.widget.textbox() + uptimewidget:set_align("right") vicious.register(uptimewidget, vicious.widgets.uptime, "$1 $2:$3", 61) + uptimewidget = wibox.layout.constraint(uptimewidget, "exact", 50, nil) - forces a fixed width of 50px to the uptime widget, and aligns its text to the right @@ -495,7 +510,7 @@ color index arguments elegantly. But they are not unusable, far from it. Example - ctext = widget({ type = "textbox"}) + ctext = wibox.widget.textbox() cgraph = awful.widget.graph() cgraph:set_width(100):set_height(20) cgraph:set_stack(true):set_max_value(100) @@ -516,7 +531,7 @@ A lot of users are not happy with default symbols used in volume, battery, cpufreq and other widget types. You can use your own symbols without any need to modify modules. - volumewidget = widget({ type = "textbox"}) + volumewidget = wibox.widget.textbox() vicious.register(volumewidget, vicious.widgets.volume, function(widget, args) local label = { ["♫"] = "O", ["♩"] = "M" } diff --git a/contrib/README b/contrib/README index 370b6e1..15998c4 100644 --- a/contrib/README +++ b/contrib/README @@ -1,14 +1,14 @@ Contrib ------- -Contrib widgets are extra widgets you can use. Some are for less -common hardware, and other were contributed by Vicious users. The -contrib directory also holds widget types that were obsoleted or -rewritten. Contrib widgets will not be imported by init unless you -explicitly enable it, or load them in your rc.lua. +Contrib libraries, or widget types, are extra snippets of code you can +use. Some are for less common hardware, and other were contributed by +Vicious users. The contrib directory also holds widget types that were +obsoleted or rewritten. Contrib widgets will not be imported by init +unless you explicitly enable it, or load them in your rc.lua. -Usage ------ +Usage within Awesome +-------------------- To use contrib widgets uncomment the line that loads them in init.lua. Or you can load them in your rc.lua after you require Vicious: @@ -36,6 +36,14 @@ vicious.contrib.ac - if AC is connected, $1 returns "On", if not it returns "Off", if AC doesn't exist, $1 is "N/A" +vicious.contrib.ati + - provides various info about ATI GPU status + - takes card ID as an argument, i.e. "card0" (and where possible, + uses debugfs to gather data on radeon power management) + - returns a table with string keys: {method}, {dpm_state}, + {dpm_perf_level}, {profile}, {engine_clock mhz}, {engine_clock khz}, + {memory_clock mhz}, {memory_clock khz}, {voltage v}, {voltage mv} + vicious.contrib.batacpi - @@ -62,6 +70,12 @@ vicious.contrib.netcfg vicious.contrib.net - +vicious.contrib.openweather + - provides weather information for a requested city + - takes OpenWeatherMap city ID as an argument, i.e. "1275339" + - returns a table with string keys: {city}, {wind deg}, {wind aim}, + {wind kmh}, {wind mps}, {sky}, {weather}, {temp c}, {humid}, {press} + vicious.contrib.ossvol - @@ -106,9 +120,11 @@ vicious.contrib.buildbot - colors: red - failed, green - successful, yellow - in progress - it depends on lua json parser (e.g. liblua5.1-json on Ubuntu 12.04) + Usage examples --------------- +--------------------------------- Pulse Audio widget + vol = wibox.widget.textbox() vicious.register(vol, vicious.contrib.pulse, " $1%", 2, "alsa_output.pci-0000_00_1b.0.analog-stereo") vol:buttons(awful.util.table.join( awful.button({ }, 1, function () awful.util.spawn("pavucontrol") end), @@ -117,7 +133,7 @@ Pulse Audio widget )) Buildbot widget - local buildbotwidget = widget({ type = "textbox" }) + buildbotwidget = wibox.widget.textbox() local buildbotwidget_warg = { {builder="coverage", url="http://buildbot.buildbot.net"}, {builder="tarball-slave", url="http://buildbot.buildbot.net"} diff --git a/contrib/ati.lua b/contrib/ati.lua new file mode 100644 index 0000000..fd9932c --- /dev/null +++ b/contrib/ati.lua @@ -0,0 +1,79 @@ +--------------------------------------------------- +-- Licensed under the GNU General Public License v2 +-- * (c) 2013, NormalRa +--------------------------------------------------- + +-- {{{ Grab environment +local tonumber = tonumber +local io = { open = io.open } +local setmetatable = setmetatable +local helpers = require("vicious.helpers") +local string = { + sub = string.sub, + match = string.match, + gmatch = string.gmatch +} +-- }}} + + +-- ATI: provides various info about ATI GPU status +-- vicious.widgets.ati +local ati = {} + + +-- {{{ Define variables +local _units = { clock = { ["khz"] = 1, ["mhz"] = 1000 }, + voltage = { ["v"] = 1, ["mv"] = 1000 } } +local _reps = { + ["sclk"] = { name = "engine_clock", units = _units.clock, mul = 10 }, + ["mclk"] = { name = "memory_clock", units = _units.clock, mul = 10 }, + ["vddc"] = { name = "voltage", units = _units.voltage }, + ["voltage"] = { name = "voltage", units = _units.voltage }, + ["current engine clock"] = { name = "engine_clock", units = _units.clock }, + ["current memory clock"] = { name = "memory_clock", units = _units.clock } +} +-- }}} + +-- {{{ ATI widget type +local function worker(format, warg) + if not warg then return end + + local pm = helpers.pathtotable("/sys/class/drm/"..warg.."/device") + local _data = {} + + -- Get power info + _data["{method}"] = + pm.power_method and string.sub(pm.power_method, 1, -2) or "N/A" + _data["{dpm_state}"] = + pm.power_dpm_state and string.sub(pm.power_dpm_state, 1, -2) or "N/A" + _data["{dpm_perf_level}"] = + pm.power_dpm_force_performance_level and + string.sub(pm.power_dpm_force_performance_level, 1, -2) or "N/A" + _data["{profile}"] = + pm.power_profile and string.sub(pm.power_profile, 1, -2) or "N/A" + + local f = io.open("/sys/kernel/debug/dri/64/radeon_pm_info", "r") + if f then -- Get ATI info from the debug filesystem + for line in f:lines() do + for k, unit in string.gmatch(line, "(%a+[%a%s]*):[%s]+([%d]+)") do + unit = tonumber(unit) + + _data["{dpm_power_level}"] = -- DPM active? + tonumber(string.match(line, "power level ([%d])")) or "N/A" + + if _reps[k] then + for u, v in pairs(_reps[k].units) do + _data["{".._reps[k].name.." "..u.."}"] = + (unit * (_reps[k].mul or 1)) / v + end + end + end + end + f:close() + end + + return _data +end +-- }}} + +return setmetatable(ati, { __call = function(_, ...) return worker(...) end }) diff --git a/contrib/openweather.lua b/contrib/openweather.lua new file mode 100644 index 0000000..d3d2ffd --- /dev/null +++ b/contrib/openweather.lua @@ -0,0 +1,94 @@ +--------------------------------------------------- +-- Licensed under the GNU General Public License v2 +-- * (c) 2013, NormalRa +--------------------------------------------------- + +-- {{{ Grab environment +local tonumber = tonumber +local io = { popen = io.popen } +local setmetatable = setmetatable +local string = { match = string.match } +local math = { + ceil = math.ceil, + floor = math.floor +} +-- }}} + + +-- Openweather: provides weather information for a requested station +-- vicious.widgets.openweather +local openweather = {} + + +-- Initialize function tables +local _wdirs = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "N" } +local _wdata = { + ["{city}"] = "N/A", + ["{wind deg}"] = "N/A", + ["{wind aim}"] = "N/A", + ["{wind mps}"] = "N/A", + ["{wind kmh}"] = "N/A", + ["{sky}"] = "N/A", + ["{weather}"] = "N/A", + ["{temp c}"] = "N/A", + ["{humid}"] = "N/A", + ["{press}"] = "N/A" +} + +-- {{{ Openweather widget type +local function worker(format, warg) + if not warg then return end + + -- Get weather forceast using the city ID code, from: + -- * OpenWeatherMap.org + local openweather = "http://api.openweathermap.org/data/2.5/weather?id="..warg.."&mode=json&units=metric" + local f = io.popen("curl --connect-timeout 1 -fsm 3 '"..openweather.."'") + local ws = f:read("*all") + f:close() + + -- Check if there was a timeout or a problem with the station + if ws == nil then return _wdata end + + _wdata["{city}"] = -- City name + string.match(ws, '"name":"([%a%s%-]+)"') or _wdata["{city}"] + _wdata["{wind deg}"] = -- Wind degrees + string.match(ws, '"deg":([%d]+)') or _wdata["{wind deg}"] + _wdata["{wind mps}"] = -- Wind speed in meters per second + string.match(ws, '"speed":([%d%.]+)') or _wdata["{wind mps}"] + _wdata["{sky}"] = -- Sky conditions + string.match(ws, '"main":"([%a]+)"') or _wdata["{sky}"] + _wdata["{weather}"] = -- Weather description + string.match(ws, '"description":"([%a%s]+)"') or _wdata["{weather}"] + _wdata["{temp c}"] = -- Temperature in celsius + string.match(ws, '"temp":([%-]?[%d%.]+)') or _wdata["{temp c}"] + _wdata["{humid}"] = -- Relative humidity in percent + string.match(ws, '"humidity":([%d]+)') or _wdata["{humid}"] + _wdata["{press}"] = -- Pressure in hPa + string.match(ws, '"pressure":([%d%.]+)') or _wdata["{press}"] + + -- Wind speed in km/h + if _wdata["{wind mps}"] ~= "N/A" then + _wdata["{wind mps}"] = math.floor(tonumber(_wdata["{wind mps}"]) + .5) + _wdata["{wind kmh}"] = math.ceil(_wdata["{wind mps}"] * 3.6) + end -- Temperature in °C + if _wdata["{temp c}"] ~= "N/A" then + _wdata["{temp c}"] = math.floor(tonumber(_wdata["{temp c}"]) + .5) + end -- Calculate wind direction + if _wdata["{wind deg}"] ~= "N/A" then + _wdata["{wind deg}"] = tonumber(_wdata["{wind deg}"]) + + -- Lua tables start at [1] + if (_wdata["{wind deg}"] / 45)%1 == 0 then + _wdata["{wind aim}"] = _wdirs[_wdata["{wind deg}"] / 45 + 1] + else + _wdata["{wind aim}"] = + _wdirs[math.ceil(_wdata["{wind deg}"] / 45) + 1].. + _wdirs[math.floor(_wdata["{wind deg}"] / 45) + 1] + end + end + + return _wdata +end +-- }}} + +return setmetatable(openweather, { __call = function(_, ...) return worker(...) end }) diff --git a/init.lua b/init.lua index e7b1457..f567546 100644 --- a/init.lua +++ b/init.lua @@ -115,18 +115,21 @@ local function regregister(reg) -- Start the timer if reg.timer > 0 then - timers[reg.update] = { - timer = capi.timer({ timeout = reg.timer }) - } - - local tm = timers[reg.update].timer + local tm = timers[reg.timer] and timers[reg.timer].timer + tm = tm or capi.timer({ timeout = reg.timer }) if tm.connect_signal then tm:connect_signal("timeout", reg.update) else tm:add_signal("timeout", reg.update) end - tm:start() - + if not timers[reg.timer] then + timers[reg.timer] = { timer = tm, refs = 1 } + else + timers[reg.timer].refs = timers[reg.timer].refs + 1 + end + if not tm.started then + tm:start() + end -- Initial update tm:emit_signal("timeout") end @@ -194,11 +197,23 @@ function vicious.unregister(widget, keep, reg) end end - -- Stop the timer - if timers[reg.update].timer.started then - timers[reg.update].timer:stop() + if not reg.running then + return reg + end + + -- Disconnect from timer + local tm = timers[reg.timer] + if tm.timer.disconnect_signal then + tm.timer:disconnect_signal("timeout", reg.update) + else + tm.timer:remove_signal("timeout", reg.update) end reg.running = false + -- Stop the timer + tm.refs = tm.refs - 1 + if tm.refs == 0 and tm.timer.started then + tm.timer:stop() + end return reg end diff --git a/widgets/mboxc.lua b/widgets/mboxc.lua index 3226917..a79d1f4 100644 --- a/widgets/mboxc.lua +++ b/widgets/mboxc.lua @@ -55,4 +55,4 @@ local function worker(format, warg) end -- }}} -return setmetatable(mbox, { __call = function(_, ...) return worker(...) end }) +return setmetatable(mboxc, { __call = function(_, ...) return worker(...) end }) diff --git a/widgets/pkg.lua b/widgets/pkg.lua index 9ec03c0..f552b9f 100644 --- a/widgets/pkg.lua +++ b/widgets/pkg.lua @@ -23,6 +23,7 @@ local function worker(format, warg) local updates = 0 local manager = { ["Arch"] = { cmd = "pacman -Qu" }, + ["Arch C"] = { cmd = "checkupdates" }, ["Arch S"] = { cmd = "yes | pacman -Sup", sub = 1 }, ["Debian"] = { cmd = "apt-show-versions -u -b" }, ["Ubuntu"] = { cmd = "aptitude search '~U'" },