awesome-extra/0000755000000000000000000000000011765367721010544 5ustar awesome-extra/debian/0000755000000000000000000000000011765367723011770 5ustar awesome-extra/debian/compat0000644000000000000000000000000211651220275013146 0ustar 7 awesome-extra/debian/awesome-extra.examples0000644000000000000000000000002511651221247016266 0ustar shifty/example.rc.luaawesome-extra/debian/source/0000755000000000000000000000000011734356306013257 5ustar awesome-extra/debian/source/format0000644000000000000000000000001511734356306014466 0ustar 3.0 (native) awesome-extra/debian/changelog0000644000000000000000000000771211765367711013646 0ustar awesome-extra (2012061101) unstable; urgency=low * Update revelation * Update vicious -- Julien Danjou Mon, 11 Jun 2012 15:16:43 +0200 awesome-extra (2012032702) unstable; urgency=low * Add missing copyright information -- Julien Danjou Tue, 27 Mar 2012 17:34:34 +0200 awesome-extra (2012032701) unstable; urgency=low * Update revelation * Update shifty * Update vicious * Update wicked * Add bashets * Bump standard version * Add flaw * Use 3.0 source format (Closes: #606945) -- Julien Danjou Tue, 27 Mar 2012 17:28:35 +0200 awesome-extra (2011120501) unstable; urgency=low * Update shifty + This version has the fix for renaming (Closes: #619635) * Update vicious * Update wicked * Add dependency on curl for vivious hddtemp.lua (Closes: #651011) * Add revelation in long description * Do not install LICENSE file (Closes: #582215) -- Julien Danjou Mon, 05 Dec 2011 09:41:40 +0100 awesome-extra (2011103101) unstable; urgency=low * Update shifty * Fix missing revelation files (Closes: #647005) -- Julien Danjou Mon, 31 Oct 2011 09:33:22 +0100 awesome-extra (2011102401) unstable; urgency=low * Add revelation * Update shifty * Update vicious * Switch to dh in rules * Bump standard version -- Julien Danjou Mon, 24 Oct 2011 10:29:42 +0200 awesome-extra (2011011701) unstable; urgency=low * Update vicious * Update obvious * Bump standard version -- Julien Danjou Mon, 17 Jan 2011 15:31:17 +0100 awesome-extra (2010090201) unstable; urgency=low * Revert obvious to 3.4.7 version (Closes: #595235, #595233) -- Julien Danjou Thu, 02 Sep 2010 13:01:32 +0200 awesome-extra (2010083101) unstable; urgency=low * Update obvious * Update vicious -- Julien Danjou Tue, 31 Aug 2010 22:00:42 +0200 awesome-extra (2010071402) unstable; urgency=low * Rebuild with vicious (Closes: #589058) -- Julien Danjou Wed, 14 Jul 2010 18:25:55 +0200 awesome-extra (2010071401) unstable; urgency=low * Update obvious * Update wicked * Bump standard version -- Julien Danjou Wed, 14 Jul 2010 08:56:00 +0200 awesome-extra (2010051701) unstable; urgency=low * Update wicked * Update obvious * Update vicious * Add vicious in description * Bump standard version -- Julien Danjou Mon, 17 May 2010 12:21:11 +0200 awesome-extra (2010011901) unstable; urgency=low * Update wicked * Add vicious (Closes: #563814) * Update obvious * Update shifty * Bump standard version * Use 3.0 source format -- Julien Danjou Tue, 19 Jan 2010 14:13:42 +0100 awesome-extra (2009072701) unstable; urgency=low * Add obvious -- Julien Danjou Mon, 27 Jul 2009 16:24:00 +0200 awesome-extra (2009062201) unstable; urgency=low * Update wicked * Update shifty * Bump standard version -- Julien Danjou Mon, 22 Jun 2009 09:59:31 +0200 awesome-extra (2009050201) unstable; urgency=low * Fix typo in description. (Closes: #524627) -- Julien Danjou Sat, 02 May 2009 11:03:11 +0200 awesome-extra (2009050101) unstable; urgency=low * Update shifty and wicked. -- Julien Danjou Fri, 01 May 2009 19:27:19 +0200 awesome-extra (2009040601) unstable; urgency=low * Update shifty. -- Julien Danjou Mon, 06 Apr 2009 18:28:00 +0200 awesome-extra (2009040201) unstable; urgency=low * Add link to GPL-2 in copyright file. -- Julien Danjou Thu, 02 Apr 2009 10:19:24 +0200 awesome-extra (2009033101) unstable; urgency=low * Add shifty. -- Julien Danjou Tue, 31 Mar 2009 17:39:05 +0200 awesome-extra (2009033001) unstable; urgency=low * Initial Release. (Closes: #521427) -- Julien Danjou Mon, 30 Mar 2009 17:04:01 +0200 awesome-extra/debian/install0000644000000000000000000000034611734355755013362 0ustar wicked/wicked.lua usr/share/awesome/lib shifty usr/share/awesome/lib obvious usr/share/awesome/lib vicious usr/share/awesome/lib revelation usr/share/awesome/lib bashets/bashets.lua usr/share/awesome/lib flaw usr/share/awesome/libawesome-extra/debian/copyright0000644000000000000000000000502111734356775013722 0ustar This package was debianized by: Julien Danjou on Mon, 30 Mar 2009 17:04:01 +0200 It was downloaded from: Wicked: Shifty: Vicious: Obvious: Upstream Authors: Wicked: Lucas de Vries Shifty: koniu Vicious: Adrian C. Lucas de Vries Obvious: Gregor Best Revelation: Perry Hargrave resixian@gmail.com Espen Wiborg espenhw@grumblesmurf.org Julien Danjou julien@danjou.info Bashets: Anton Lobov Flaw: David Soulayrol Copyright: Wicked: Copyright 2008-2009 (C) Lucas de Vries Shifty: Copyright 2009 (C) koniu Vicious: Copyright 2010 (C) Adrian C. Copyright 2009 (C) Lucas de Vries Obvious: Copyright 2009 (C) Gregor Best Revelation: Copyright 2008 (C) Espen Wiborg, Julien Danjou Bashets: Copyright 2010 (C) Anton Lobov Flaw: Copyright 2009-2011 (C) David Soulayrol License: Wicked: DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar 14 rue de Plaisance, 75014 Paris, France Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. Shifty: Licensed under the GPL version 2. See /usr/share/common-licenses/GPL-2. Vicious: Licensed under the GPL version 2. See /usr/share/common-licenses/GPL-2. Revelation: Licensed under the GPL version 2. See /usr/share/common-licenses/GPL-2. Bashets: Licensed under the GPL version 3. See /usr/share/common-licenses/GPL-3 Flaw: Licensed under the GPL version 3. See /usr/share/common-licenses/GPL-3 The Debian packaging is: Copyright (C) 2009 Julien Danjou and is licensed under the GPL version 3. See /usr/share/common-licenses/GPL-3. awesome-extra/debian/rules0000755000000000000000000000056011734356437013045 0ustar #!/usr/bin/make -f # -*- makefile -*- %: dh $@ override_dh_auto_build: asciidoc -d manpage -b docbook -o wicked/wicked.7.xml wicked/wicked.7.txt xmlto man -o wicked wicked/wicked.7.xml override_dh_auto_clean: rm -f wicked/wicked.7.xml wicked/wicked.7 rm -f build-stamp configure-stamp dh_auto_clean override_dh_install: dh_install -X.git -XLICENSE -XCOPYING awesome-extra/debian/control0000644000000000000000000000164011734355720013362 0ustar Source: awesome-extra Section: x11 Priority: extra Maintainer: Julien Danjou Build-Depends: debhelper (>= 7.0.50~), asciidoc, xmlto Standards-Version: 3.9.3 Package: awesome-extra Architecture: all Recommends: awesome Depends: ${misc:Depends}, curl Description: additional modules for awesome This is a set of additional modules for the awesome window manager. . It contains: * wicked, a widget manager which can fill them with various system information (CPU or memory usage, network bandwidth, etc); * shifty, an extension implementing dynamic tagging; * obvious, a set of several widgets (WiFi link quality, battery usage, etc), superseding wicked; * vicious, a widget manager; * revelation, expose like functionality; * bashets, use your shell scripts as content providers for widgets; * flaw, object oriented library providing a thin abstraction layer above awesome widgets. awesome-extra/debian/dirs0000644000000000000000000000002611651220275012632 0ustar usr/share/awesome/lib awesome-extra/debian/manpages0000644000000000000000000000003411734355761013476 0ustar wicked/wicked.7 flaw/flaw.7 awesome-extra/bashets/0000755000000000000000000000000011734355302012161 5ustar awesome-extra/bashets/bashets.previous0000755000000000000000000002542011734355302015416 0ustar ------------------------------------------------------------------------ -- Bashets - use your shellscript's output in Awesome3 widgets -- -- @author Anton Lobov <ahmad200512@yandex.ru> -- @copyright 2010 Anton Lobov -- @license GPLv2 -- @release 0.3.1 for Awesome 3.4 -- @todo Implement better timer scheduling if possible. ----------------------------------------------------------------------- -- Grab only needed enviroment local awful = require("awful") local string = string local io = io local table = table local pairs = pairs local timer = timer local type = type --- Bashets module module("bashets") -- Default paths local script_path = "/usr/share/awesome/bashets/" local tmp_folder = "/tmp/" -- Utility functions table local util = {} -- Timer data local timerdata = {} local timers = {} -- Some default values local defaults = {} defaults.update_time = 1 defaults.file_update_time = 2 defaults.format_string = "$1" defaults.separator = " " defaults.field = "text" widget_field = defaults.field -- State variable local is_running = false -- # Utility functions --- Split string by separator into table -- @param str String to split -- @param sep Separator to use function util.split(str, sep) local parts = {} --parts array local first = 1 local ostart, oend = string.find(str, sep, first, true) --regexp disabled search while ostart do local part = string.sub(str, first, ostart - 1) table.insert(parts, part) first = oend + 1 ostart, oend = string.find(str, sep, first, true) end local part = string.sub(str, first) table.insert(parts, part) return parts end function util.tmpname(script) -- Replace all slashes with empty string so that /home/user1/script.sh -- and /home/user2/script.sh will have different temporary files local tmpname = string.gsub(script, '/', '') -- Replace all spaces with dots so that "script.sh arg1" -- and "script.sh arg2" will have different temporary files tmpname = string.gsub(tmpname, '%s+', '.') -- Generated script-parameter unique temporary file path local file = tmp_folder .. tmpname .. '.bashets.out' return file end function util.fullpath(script) if string.find(script, '^/') == nil then script = script_path .. script end return script end --- Execute a command and write it's output to temporary file -- @param script Script to execute -- @param file File for script output function util.execfile(script, file) -- Spawn command and redirect it's output to file awful.util.spawn_with_shell(script .. " > " .. file) end --- Read temporary file to a table or string -- @param file File to be read -- @param israw If true, return raw string, not table function util.readfile(file, sep) local fh = io.input(file) local str = fh:read("*all"); io.close(fh) if sep == nil then return str else parts = util.split(str, sep); return parts end end --- Read script output to a table or string -- @param script Script to execute -- @param israw If true, return raw string, not table function util.readshell(script, sep) local str = awful.util.pread(script) if sep == nil then return str else parts = util.split(str, sep); return parts end end --- Format script output with user defined format string -- @param output sep-separated string of values -- @param format Format string -- @param sep Separator of values in string function util.format(parts, format, sep) -- For each part with number "k" replace corresponding "$k" variable in format string for k,part in pairs(parts) do local part = string.gsub(part, "%%", "%1%1") --percent fix for next gsub (bug found in Wicked) part = awful.util.escape(part) --escape XML entities for correct Pango markup format = string.gsub(format, "$" .. k, part) end return format end --- Add function to corresponding timer object (Awesome >= 3.4 timer API) -- @param updtime Update time for widget, also dispatch time for timer -- @param func Function to dispatch function util.add_to_timings(updtime, func, force_new) local found = false -- Search for an existing timer at the same period for k,tmr in pairs(timerdata) do if tmr[1] == updtime and (force_new == nil or force_new == false) then table.insert(timerdata[k][2], func) found = true end end -- Add a new timer for period if not found if not found then table.insert(timerdata, {updtime, {func}}) end end --- Create timer table to define timers for multiple widget updates function util.create_timers_table() -- Parse table with timer data for _,tmr in pairs(timerdata) do -- Create timer for the period local t = timer {timeout = tmr[1]} -- Function to call all dispatched functions local f = function() for _, func in pairs(tmr[2]) do func() end end t:add_signal("timeout", f) table.insert(timers, t) end end --- Update widget from values function util.update_widget(widget, values, format, field) field = field or "text" if type(widget) == "table" or type(format) == "table" then if #widget ~= #format then io.stderr:write("E: bashets: widget table must have the same length with format string table") return end for k, widg in pairs(widget) do if widg ~= nil then if type(values) == "table" then pvalues = util.format(values, format[k]) else pvalues = values end if field == "image" then pvalues = image(pvalues) end if type(field) == "table" then if #widget ~= #field then io.stderr:write("E: bashets: fields table must have the same length with widget table"); return end widg[field[k]] = pvalues else widg[field] = pvalues end end end else if widget ~= nil then if type(values) == "table" then pvalues = util.format(values, format) else pvalues = values end if field == "image" then pvalues = image(util.format(values, format)) end widget[field] = pvalues end end end -- # Setter functions --- Set path for scripts -- @param path Path to set function set_script_path(path) script_path = path end --- Set path for temporary files -- @param path Path to set function set_temporary_path(path) tmp_folder = path end --- Set default values -- @param defs Table with defaults function set_defaults(defs) if type(defs) == "table" then if defs.update_time ~= nil then defaults.update_time = defs.update_time end if defs.file_update_time ~= nil then defaults.file_update_time = defs.file_update_time end if defs.format_string ~= nil then defaults.format_string = defs.format_string end defaults.separator = defs.separator --now could be nil if defs.widget_field ~= nil then defaults.field = defs.widget_field end end end --- Set widget field for updates -- @param fieldstr String representing widget field function set_widget_field(fieldstr) widget_field = fieldstr end -- # Acting functions --- Start widget updates function start() -- Create timers table if not initialized or empty if (not timers) or table.maxn(timers) == 0 then util.create_timers_table() end -- Start all timers for _, tmr in pairs(timers) do tmr:start() end is_running = true end --- Stop widget updates function stop() -- Stop all timers for _, tmr in pairs(timers) do tmr:stop() end is_running = false end --- Check whether updates are running function get_running() return is_running end --- Toggle updates function toggle() if is_running then start() else stop() end end --- Shedule function for timed execution -- @param func Function to run -- @param updatime Update time (optional) function schedule(func, updtime) updtime = updtime or defaults.update_time if func ~= nil then util.add_to_timings(updtime, func) end end -- # Widget registration functions --- Register script for text widget -- @param widget Widget to update -- @param script Script to use it's output -- @param format User-defined format string (optional) -- @param updtime Update time in seconds (optional) -- @param sep Output separator (optional) function register(widget, script, format, updtime, sep, field) -- Set optional variables updtime = updtime or defaults.update_time format = format or defaults.format_string sep = sep or defaults.separator script = util.fullpath(script) -- Do it first time local data = util.readshell(script) util.update_widget(widget, data, format, field) -- Schedule it for timed execution schedule(function() local data = util.readshell(script, sep) util.update_widget(widget, data, format, field) end, updtime) end --- Register script for widget's widget_field throughout the temporary file -- @param widget Widget to update -- @param script Script to use it's output -- @param format User-defined format string (optional) -- @param time1 File update time in seconds (optional) -- @param time2 Widget update time in seconds (optional) -- @param sep Output separator (optional) function register_async(widget, script, format, time1, time2, sep, field) -- Set optional variables time1 = time1 or defaults.file_update_time time2 = time2 or defaults.update_time format = format or defaults.format_string sep = sep or defaults.separator script = util.fullpath(script) local tmpfile = util.tmpname(script) -- Create temporary file if not exists fl = io.open(tmpfile, "w") io.close(fl) -- Do it first time util.execfile(script, tmpfile) local data = util.readfile(tmpfile) util.update_widget(widget, data, format, field) -- Schedule it for timed execution schedule(function() util.execfile(script, tmpfile) end, time1) schedule(function() local data = util.readfile(tmpfile, sep) util.update_widget(widget, data, format, field) end, time2) end --- Register text file for text widget -- @param widget Widget to update -- @param file File to use as data source -- @param format Format string (optional) -- @param time Update time (optional) -- @param sep Separator (optional) function register_file(widget, file, format, time, sep, field) -- Set optional variables time = time or defaults.update_time format = format or defaults.format_string sep = sep or defaults.separator -- Do it first time local data = util.readfile(file, sep) util.update_widget(widget, data, format, field) -- Schedule it for timed execution schedule(function() local data = util.readfile(file, sep) util.update_widget(widget, data, format, field) end, time) end --- Register Lua function for text widget -- @param widget Widget to update -- @param func Function to return variables table -- @param format Format string (optional) -- @param time Update time (optional) function register_lua(widget, func, format, time) -- Set optional variables time = time or defaults.update_time format = format or defaults.format_string sep = sep or defaults.separator -- Do it first time local data = func() util.update_widget(widget, data, format, field) -- Schedule it for timed execution schedule(function() local data = func() util.update_widget(widget, data, format, field) end, time) end awesome-extra/bashets/bashets.lua.prev0000644000000000000000000001454311734355302015277 0ustar ------------------------------------------------------------------ -- Bashets - use your shellscript's output in Awesome3 widgets -- -- @author Anton Lobov <ahmad200512@yandex.ru> -- @copyright 2009 Anton Lobov -- @license GPLv2 -- @release 0.1aw3 -- @todo Non-text widget support: progressbar and graph ------------------------------------------------------------------ -- Grab only needed enviroment local awful = require("awful") local string = string local io = io local table = table local pairs = pairs local coroutine = coroutine --- Bashets module module("bashets") -- Default paths (could be altered by 'configure' script) local script_path = "/usr/share/awesome/bashets/" local tmp_folder = "/tmp/" -- Utility functions table local util = {} --- Split string by separator into table -- @param str String to split -- @param sep Separator to use function util.split(str, sep) parts = {} --parts array first = 1 ostart, oend = string.find(str, sep, first, true) --regexp disabled search while ostart do part = string.sub(str, first, ostart - 1) table.insert(parts, part) first = oend + 1 ostart, oend = string.find(str, sep, first, true) end part = string.sub(str, first) table.insert(parts, part) return parts end --- Execute a command and return it's output -- @param script Script to execute function util.exec(script) local fh = io.popen(script) local str = "" -- Newlines are replaced with spaces for i in fh:lines() do str = str .. " " .. i end io.close(fh) return str end --- Execute a command and write it's output to temporary file -- @param script Script to execute -- @param file File for script output function util.exectmp(script, file) -- Maybe there is a more elegant way to correctly execute commands -- and do not hang Awesome? --io.popen(script .. " > " .. file) awful.util.spawn_with_shell(script .. " > " .. file) end --- Read temporary file to a single line -- @param file File to be read function util.readfile(file) local fh = io.input(file) local str = "" -- Newlines are replaced with spaces for i in fh:lines() do str = str .. " " .. i end io.close(fh) return str end --- Format script output with user defined format string -- @param output sep-separated string of values -- @param format Format string -- @param sep Separator of values in string function util.format(output, format, sep) -- Delete leading space symbols output = string.gsub(output, "^%s+", "") -- Split script output local parts = util.split(output, sep) -- For each part with number "k" replace corresponding "$k" variable in format string for k,part in pairs(parts) do part = string.gsub(part, "%%", "%1%1") --percent fix for next gsub (bug found in Wicked) format = string.gsub(format, "$" .. k, part) end return format end --- Format script output -- @param script Script to execute -- @param format Format string -- @param sep Separator of values in string function util.update(script, format, sep) -- Execute script and format it's output local output = util.exec(script) output = util.format(output, format, sep) return output end --- Format file contents (for async variant) -- @param file File to format it's content -- @param format Format string -- @param sep Separator of values in string function util.update_async(file, format, sep) -- Read file and format it's contents local output = util.readfile(file) if string.len(output) > 0 then output = util.format(output, format, sep) end return output end --- Register script for text widget -- @param widget Widget to update -- @param script Script to use it's output -- @param format User-defined format string (optional) -- @param updtime Update time in seconds (optional) -- @param sep Output separator (optional) function register(widget, script, format, updtime, sep) -- Set optional variables if updtime == nil then updtime = 2 -- Default update time = 2 seconds end if format == nil then format = "$1" -- Default format is the first word in script output end if sep == nil then sep = ' ' -- Default separator is the space symbol end -- Append script_path to relative script path if string.find(script, '^/') == nil then script = script_path .. script end -- User don't want to wait first 'updtime' interval to see the value =) widget.text = util.update(script, format, sep) -- Register timer to update widget every 'updtime' seconds awful.hooks.timer.register(updtime, function() widget.text = util.update(script, format, sep) end) end --- Register script for text widget throughout the temporary file -- @param widget Widget to update -- @param script Script to use it's output -- @param format User-defined format string (optional) -- @param time1 File update time in seconds (optional) -- @param time2 Widget update time in seconds (optional) -- @param sep Output separator (optional) function register_async(widget, script, format, time1, time2, sep) -- Set optional variables if time1 == nil then time1 = 2 -- Default file update time is 2 seconds end if time2 == nil then time2 = 1 -- Default widget update time is 1 second end if format == nil then format = "$1" -- Default format is the first word in script output end if sep == nil then sep = ' ' -- Default separator is the space symbol end -- Replace all slashes with empty string so that /home/user1/script.sh -- and /home/user2/script.sh will have different temporary files local tmpname = string.gsub(script, '/', '') -- Replace all spaces with points so that "script.sh arg1" -- and "script.sh arg2" will have different temporary files tmpname = string.gsub(tmpname, '%s+', '.') -- Text while updating widget first time - it could take a while widget.text = '...' -- Generated script-parameter-unique temporary file path local file = tmp_folder .. tmpname .. '.bashets.out' -- Append script_path to relative script path if string.find(script, '^/') == nil then script = script_path .. script end -- Create temporary file awful.util.spawn_with_shell('touch ' .. file) -- Do it first time util.exectmp(script, file) widget.text = util.update_async(file, format, sep) -- Register timers to update file every 'time1' seconds and widget every 'time2' seconds awful.hooks.timer.register(time1, function() util.exectmp(script, file) end) awful.hooks.timer.register(time2, function() local txt = util.update_async(file, format, sep) if string.len(txt) > 0 then widget.text = txt end end) end awesome-extra/bashets/userscripts/0000755000000000000000000000000011734355302014547 5ustar awesome-extra/bashets/userscripts/battery.sh0000755000000000000000000000040511734355302016557 0ustar #!/bin/bash STATUS=$( acpi | awk '{print $3}' ) if [ "$STATUS" = "Discharging," ] then STATUS="A" else STATUS="AC" fi PERCENT=$( acpi | awk '{print $4}' ) PERCENT=${PERCENT%%"%,"} PERCENT=${PERCENT%%"%"} #PERCENT=${PERCENT%%","} echo -n "$STATUS $PERCENT" awesome-extra/bashets/userscripts/ps.sh0000755000000000000000000000006411734355302015530 0ustar ps axk -%cpu,-%mem o pid,comm,%cpu,%mem | head -n 6 awesome-extra/bashets/userscripts/xkb.sh0000755000000000000000000000032311734355302015670 0ustar #!/bin/bash # you need either getxkblayout script ot xkblayout-state app to use this script #echo -n `getxkblayout` | tr '[:lower:]' '[:upper:]' echo -n `xkblayout-state print %e` | tr '[:lower:]' '[:upper:]' awesome-extra/bashets/userscripts/runner.sh0000755000000000000000000000020611734355302016415 0ustar #!/bin/sh while true; do echo "bashets.external_w(\"`$1 | sed '{:q;N;s/\n/\\\n/g;t q}'`\", \"$2\")" | awesome-client sleep $3 done awesome-extra/bashets/userscripts/mpd.awk0000755000000000000000000000042511734355302016037 0ustar #!/bin/awk -f BEGIN { MPD_CMD = "mpc"; # mpd MPD_CMD | getline; MPD_CMD | getline; mpd_state = $1; close(MPD_CMD); if ( mpd_state == "[playing]" ) print "▶"; else { if ( mpd_state == "[paused]" ) print "❚❚"; else { print "■"; } } } awesome-extra/bashets/userscripts/filesys.sh0000755000000000000000000000007311734355302016564 0ustar FSU=`df -h $1 | awk '{print $5}' | tail -n 1` echo -n $FSU awesome-extra/bashets/userscripts/mem.sh0000755000000000000000000000021211734355302015657 0ustar #!/bin/bash TOTAL=`free | grep Mem | awk '{print $2}'` USED=`free | grep - | awk '{print $3}'` let PERCC=$USED*100/$TOTAL echo -n $PERCC awesome-extra/bashets/userscripts/date.sh0000755000000000000000000000016111734355302016021 0ustar #!/bin/sh DAY=`date +%a` DAY=${DAY:0:2} #OTHER=`date +"%e %b, %H:%M"` #echo "$DAY $OTHER" echo -n `date +%H:%M` awesome-extra/bashets/userscripts/cpu.sh0000755000000000000000000000217311734355302015700 0ustar #!/bin/bash # by Paul Colby (http://colby.id.au), no rights reserved ;) # change this with your temporary files TMP1="/dev/shm/tmp/cpuusage.total" TMP2="/dev/shm/tmp/cpuusage.idle" if [ ! -s "$TMP1" ]; then touch "$TMP1" echo 0 > "$TMP1" fi if [ ! -s "$TMP2" ]; then touch "$TMP2" echo 0 > "$TMP2" fi #PREV_TOTAL=0 #PREV_IDLE=0 #while true; do PREV_TOTAL=`cat ${TMP1}` PREV_IDLE=`cat ${TMP2}` CPU=(`cat /proc/stat | grep '^cpu '`) # Get the total CPU statistics. unset CPU[0] # Discard the "cpu" prefix. IDLE=${CPU[4]} # Get the idle CPU time. # Calculate the total CPU time. TOTAL=0 for VALUE in "${CPU[@]}"; do let "TOTAL=$TOTAL+$VALUE" done # Calculate the CPU usage since we last checked. let "DIFF_IDLE=$IDLE-$PREV_IDLE" let "DIFF_TOTAL=$TOTAL-$PREV_TOTAL" let "DIFF_USAGE=(1000*($DIFF_TOTAL-$DIFF_IDLE)/$DIFF_TOTAL+5)/10" echo -n "$DIFF_USAGE" # Remember the total and idle CPU times for the next check. #PREV_TOTAL="$TOTAL" #PREV_IDLE="$IDLE" echo $TOTAL > "$TMP1" echo $IDLE > "$TMP2" # Wait before checking again. # sleep 1 #done awesome-extra/bashets/userscripts/forecast.sh0000755000000000000000000000046511734355302016721 0ustar #!/bin/bash # you need conkyForecast script to use this one LOCATION=RSXX0091 ICON=`conkyForecast --location=$LOCATION --datatype=WF | tail -n 1` TEMP=`conkyForecast --location=$LOCATION --datatype=HT | tail -n 1` if echo "$ICON" | grep -q "No"; then echo -n "e N/A" else echo -n "$ICON $TEMP" fi awesome-extra/bashets/userscripts/mpd.sh0000755000000000000000000000024711734355302015671 0ustar #!/bin/sh STATUS=`/usr/share/awesome/bashets/mpd.awk` TITLE=`mpc | head -n 1` MTIME=`mpc | head -n 2 | tail -n 1 | awk '{print $3}'` echo -n "$STATUS|$TITLE|$MTIME" awesome-extra/bashets/userscripts/vollevel.sh0000755000000000000000000000043411734355302016737 0ustar #!/bin/bash # #amixer get Master | grep "Front Left:" | awk '{print $5}' > /tmp/vollevel.out #RES=$( cat /tmp/vollevel.out ) RES=$( amixer get $1 | grep "Front Left:" | awk '{print $5}' ) #echo -e $RES #RES="[30%]" RES=${RES##"["} RES=${RES%%"%]"} echo -n $RES #> /tmp/vollevel.out awesome-extra/bashets/bashets.lua0000644000000000000000000003426011734355302014322 0ustar ------------------------------------------------------------------------ -- Bashets - use your shellscript's output in Awesome3 widgets -- -- @author Anton Lobov <ahmad200512@yandex.ru> -- @copyright 2010 Anton Lobov -- @license GPLv3 -- @release 0.6.1 (meant to be backwards compatible with older versions) ------------------------------------------------------------------------ -- Grab only needed enviroment local awful = require("awful") local string = string local io = io local table = table local pairs = pairs local timer = timer local type = type local image = image local capi = {oocairo = oocairo, timer = timer, dbus = dbus} local tonumber = tonumber local print = print local error = error --- Bashets module module("bashets") -- Default paths local script_path = "/usr/share/awesome/bashets/" local tmp_folder = "/tmp/" -- Utility functions table local util = {} -- Timer data local timerdata = {} local timers = {} -- External mode data local ewidgets = {} -- Some default values local defaults = {} defaults.update_time = 1 defaults.file_update_time = 2 defaults.format_string = "$1" defaults.separator = " " defaults.updater = "runner.sh" -- State variable local is_running = false -- # Utility functions --- Split string by separator into table -- @param str String to split -- @param sep Separator to use function util.split(str, sep) if sep == nil then return {str} end local parts = {} --parts array local first = 1 local ostart, oend = string.find(str, sep, first, true) --regexp disabled search while ostart do local part = string.sub(str, first, ostart - 1) table.insert(parts, part) first = oend + 1 ostart, oend = string.find(str, sep, first, true) end local part = string.sub(str, first) table.insert(parts, part) return parts end function util.tmpkey(script) -- Replace all slashes with empty string so that /home/user1/script.sh -- and /home/user2/script.sh will have different temporary files local tmpname = string.gsub(script, '/', '') -- Replace all spaces with dots so that "script.sh arg1" -- and "script.sh arg2" will have different temporary files tmpname = string.gsub(tmpname, '%s+', '.') return tmpname end function util.tmpname(script) -- Generated script-parameter unique temporary file path local file = tmp_folder .. util.tmpkey(script) .. '.bashets.out' return file end function util.fullpath(script) if string.find(script, '^/') == nil then script = script_path .. script end return script end --- Execute a command and write it's output to temporary file -- @param script Script to execute -- @param file File for script output function util.execfile(script, file) -- Spawn command and redirect it's output to file awful.util.spawn_with_shell(script .. " > " .. file) end function util.readstring(str, sep) if sep == nil then return str else parts = util.split(str, sep); return parts end end --- Read temporary file to a table or string -- @param file File to be read -- @param israw If true, return raw string, not table function util.readfile(file, sep) local fh = io.input(file) local str = fh:read("*all"); io.close(fh) return util.readstring(str, sep) end --- Read script output to a table or string -- @param script Script to execute -- @param israw If true, return raw string, not table function util.readshell(script, sep) local str = awful.util.pread(script) return util.readstring(str, sep) end --- Format script output with user defined format string -- @param output sep-separated string of values -- @param format Format string -- @param sep Separator of values in string function util.format(parts, format, sep) -- For each part with number "k" replace corresponding "$k" variable in format string for k,part in pairs(parts) do local part = string.gsub(part, "%%", "%1%1") --percent fix for next gsub (bug found in Wicked) part = awful.util.escape(part) --escape XML entities for correct Pango markup format = string.gsub(format, "$" .. k, part) end return format end --- Add function to corresponding timer object (Awesome >= 3.4 timer API) -- @param updtime Update time for widget, also dispatch time for timer -- @param func Function to dispatch function util.add_to_timings(updtime, func, force_new) local found = false -- Search for an existing timer at the same period for k,tmr in pairs(timerdata) do if tmr[1] == updtime and (force_new == nil or force_new == false) then table.insert(timerdata[k][2], func) found = true end end -- Add a new timer for period if not found if not found then table.insert(timerdata, {updtime, {func}}) end end --- Create timer table to define timers for multiple widget updates function util.create_timers_table() -- Parse table with timer data for _,tmr in pairs(timerdata) do -- Create timer for the period local t if capi.timer ~= nil then t = capi.timer {timeout = tmr[1]} else t = timer {timeout = tmr[1]} end -- Function to call all dispatched functions local f = function() for _, func in pairs(tmr[2]) do func() end end if t.add_signal ~= nil then t:add_signal("timeout", f) else t:connect_signal("timeout", f) end table.insert(timers, t) end end function util.update_widget_field(widget, valuess) -- print(widget.type) if widget.type == "imagebox" then --imagebox (old API) widget["image"] = image(valuess) elseif widget.set_image ~= nil then --imagebox (new API) --widget["image"] = capi.oocairo.image_surface_create_from_png(valuess) --widget:set_image(capi.oocairo.image_surface_create_from_png(valuess)) widget:set_image(valuess) elseif widget.type == "textbox" then --textbox (old API) widget["text"] = valuess elseif widget.set_markup ~= nil then --textbox (new API) widget:set_markup(valuess) --elseif widget["widget"] ~= nil then elseif widget.set_value ~= nil then --progressbar widget:set_value(tonumber(valuess)) elseif widget.add_value ~= nil then --graph widget:add_value(tonumber(valuess)) end --end end --- Update widget from values function util.update_widget(widget, values, format) if widget ~= nil then if type(values) == "table" then util.update_widget_field(widget, util.format(values, format)) else util.update_widget_field(widget, values) end end end -- # Setter functions --- Set path for scripts -- @param path Path to set function set_script_path(path) script_path = path end --- Set path for temporary files -- @param path Path to set function set_temporary_path(path) tmp_folder = path end --- Set default values -- @param defs Table with defaults function set_defaults(defs) if type(defs) == "table" then if defs.update_time ~= nil then defaults.update_time = defs.update_time end if defs.file_update_time ~= nil then defaults.file_update_time = defs.file_update_time end if defs.format_string ~= nil then defaults.format_string = defs.format_string end if defs.updater ~= nil then defaults.updater = defs.updater end defaults.separator = defs.separator --now could be nil end end -- # Acting functions --- Start widget updates function start() -- Create timers table if not initialized or empty if (not timers) or table.maxn(timers) == 0 then util.create_timers_table() end -- Start all timers for _, tmr in pairs(timers) do tmr:start() end -- Kill all externals (if some were here from previous launch) --awful.util.spawn_with_shell('killall ' .. defaults.updater) -- Run all externals for _, wgt in pairs(ewidgets) do awful.util.spawn_with_shell(wgt.cmd) end is_running = true end --- Stop widget updates function stop() -- Stop all timers for _, tmr in pairs(timers) do tmr:stop() end -- Kill all externals awful.util.spawn_with_shell('killall ' .. defaults.updater) is_running = false end --- Check whether updates are running function get_running() return is_running end --- Toggle updates function toggle() if is_running then start() else stop() end end --- Shedule function for timed execution -- @param func Function to run -- @param updatime Update time (optional) function schedule(func, updtime) updtime = updtime or defaults.update_time if func ~= nil then util.add_to_timings(updtime, func) end end -- # Widget registration functions --- General widget-callback registration function. For internal use, but if you need it, feel free to call it :) -- @param data_provider Function that returns table of values -- @param widget Widget to update, if null, nothing is updated -- @param callback Callback to call after the update of values, if null, nothing is called -- @param format Format string for widget //N.B.: it is not checked for null function schedule_w(data_provider, widget, callback, format, updtime) if callback ~= nil and type(callback) == "function" then if widget ~= nil then schedule(function() local data = data_provider() util.update_widget(widget, data, format) callback(data) end, updtime) else schedule(function() local data = data_provider() callback(data) end, updtime) end elseif widget ~= nil then schedule(function() local data = data_provider() util.update_widget(widget, data, format) end, updtime) end end --- External script registration. Script will pass data by calling external_w through dbus function schedule_e(script, widget, callback, format, updtime, sep) local ascript = util.fullpath(script) local key = util.tmpkey(ascript) ewidgets[key] = {} ewidgets[key].widget = widget ewidgets[key].callback = callback ewidgets[key].format = format ewidgets[key].separator = sep ewidgets[key].cmd = util.fullpath(defaults.updater) .. " \"" .. ascript .. "\" " .. key .. " " ..updtime --print(ewidgets[key].cmd) -- awful.util.spawn_with_shell() end function external_w(raw_data, key) local callback = ewidgets[key].callback or nil local widget = ewidgets[key].widget or nil local format = ewidgets[key].format or defaults.format_string local data = util.readstring(raw_data, ewidgets[key].separator) if callback ~= nil and type(callback) == "function" then if widget ~= nil then util.update_widget(widget, data, format) callback(data) else callback(data) end elseif widget ~= nil then util.update_widget(widget, data, format) end end function register_d(bus, iface, widget, callback, format) if capi.dbus then bus = bus or "session" capi.dbus.add_match(bus, "interface='" .. iface .. "'") capi.dbus.connect_signal(iface, function (...) local argums = {...} local data = {} for _,v in pairs(argums) do if type(v) == "table" then for _,iv in pairs(v) do table.insert(data, iv) end else table.insert(data, v) end end if callback ~= nil and type(callback) == "function" then if widget ~= nil then util.update_widget(widget, data, format) callback(data) else callback(data) end elseif widget ~= nil then util.update_widget(widget, data, format) end end) else error("bashets: You are trying to employ dbus, but no dbus api detected in your build of awesome") end end --- Register script for text widget -- @param object Object to be a data provider (function or string with a path to file/shellscript) -- @param options Options table with following content (all fields are optional): -- -- widget Widget to update -- callback Function to execute after the update (should have a single parameter which represents table with data) -- NOTE: you can use the widget without a callback, the callback without a widget, or both -- -- update_time Widget update time (in seconds) -- separator Output separator (string, could be null) -- format User-defined format string (any valid Pango markup with variables) -- -- async Perform script execution through a temporary file (true/false) -- file_update_time Temporary file content update time (in seconds) -- -- read_file Read file instead of executing it function register(object, options) -- Set optional variables options = options or {} local updtime = options.update_time or defaults.update_time local fltime = options.file_update_time or defaults.file_update_time local format = options.format or defaults.format_string local sep = options.separator or defaults.separator local callback = options.callback local async = options.async or false local isdbus = options.dbus or false local busname = options.busname or "session" local readfile = options.read_file or false local widget = options.widget local external = options.external or false if type(object) == "function" then --We have a function as a data provider -- Do it first time local data = func() util.update_widget(widget, data, format) -- Schedule it for timed execution schedule_w(func, widget, callback, format, updtime) elseif readfile then --We have a text file as a data provider -- Do it first time local data = util.readfile(object, sep) util.update_widget(widget, data, format) -- Schedule it for timed execution schedule_w(function() return util.readfile(object, sep) end, widget, callback, format, updtime) elseif async then --Script could hang Awesome, we need to run it local script = util.fullpath(object) --through a temporary file local tmpfile = util.tmpname(script) -- Create temporary file if not exists fl = io.open(tmpfile, "w") io.close(fl) -- Do it first time util.execfile(script, tmpfile) local data = util.readfile(tmpfile) util.update_widget(widget, data, format) -- Schedule it for timed execution schedule(function() util.execfile(script, tmpfile) end, fltime) schedule_w(function() return util.readfile(tmpfile, sep) end, widget, callback, format, updtime) elseif external then -- Script provides external data through dbus local script = util.fullpath(object) schedule_e(script, widget, callback, format, updtime, sep) elseif isdbus then -- Data is fetched through a message bus register_d(busname, object, widget, callback, format) --print("registered with bus name \"" .. busname .. "\" and object \"" .. object .. "\"") else -- Fast script that can be read through pread local script = util.fullpath(object) -- Do it first time local data = util.readshell(script) util.update_widget(widget, data, format) -- Schedule it for timed execution schedule_w(function() return util.readshell(script, sep) end, widget, callback, format, updtime) end end awesome-extra/obvious/0000755000000000000000000000000011651220754012216 5ustar awesome-extra/obvious/clock/0000755000000000000000000000000011653456453013322 5ustar awesome-extra/obvious/clock/init.lua0000644000000000000000000001336211653456453014775 0ustar -------------------------------- -- Author: Gregor Best -- -- Copyright 2009 Gregor Best -- -------------------------------- local pairs = pairs local print = print local setmetatable = setmetatable local tonumber = tonumber local type = type local os = { date = os.date, getenv = os.getenv } local io = { lines = io.lines } local string = { match = string.match } local table = { insert = table.insert } local capi = { widget = widget, mouse = mouse, screen = screen } local awful = require("awful") local beautiful = require("beautiful") local naughty = require("naughty") local lib = { hooks = require("obvious.lib.hooks"), markup = require("obvious.lib.markup") } module("obvious.clock") local initialized = false local defaults = { } defaults.shorttimeformat = "%T" defaults.longtimeformat = "%T %D" defaults.editor = nil defaults.shorttimer = 60 defaults.longtimer = 120 local settings = { } for key, value in pairs(defaults) do settings[key] = value end local menu local function edit(file) if not settings.editor then naughty.notify({ text="Obvious Clock: You need to configure your" .. " editor. See readme.", timeout=0 }) else awful.util.spawn(settings.editor .. " " .. file) end end local alarmfile = awful.util.getdir("config").."/alarms" local fulldate = false local alarms = { } local widget = capi.widget({ type = "textbox", name = "clock", align = "right" }) widget:buttons(awful.util.table.join( awful.button({ }, 3, function () menu:toggle() end), awful.button({ }, 1, function () if #alarms > 0 then for _, v in pairs(alarms) do naughty.notify({ text = v[2], title = v[1], screen = capi.mouse.screen }) end alarms = { } widget.bg = beautiful.bg_normal else naughty.notify({ text = lib.markup.font("monospace", awful.util.pread("cal"): gsub("([^0-9])(" .. tonumber(os.date("%d")) .. ")([^0-9])", "%1%2%3"):gsub("\n+$", "")), screen = capi.mouse.screen }) end end) )) local function read_alarms(file) local rv = { } local date = nil if not awful.util.file_readable(file) then return { } end for line in io.lines(file) do line = line:gsub("\\n", "\n") if not date then date = line else rv[date] = line date = nil end end return rv end local function update (trigger_alarms) if trigger_alarms == nil then trigger_alarms = true end local date if fulldate then if type(settings.longtimeformat) == "string" then date = os.date(settings.longtimeformat) elseif type(settings.longtimeformat) == "function" then date = os.date(settings.longtimeformat()) end if not date then date = os.date(defaults.longtimeformat) end else if type(settings.shorttimeformat) == "string" then date = os.date(settings.shorttimeformat) elseif type(settings.shorttimeformat) == "function" then date = os.date(settings.shorttimeformat()) end if not date then date = os.date(defaults.shorttimeformat) end end if #alarms > 0 then date = lib.markup.fg.color(beautiful.fg_focus, date) widget.bg = beautiful.bg_focus else widget.bg = beautiful.bg_normal end widget.text = date if trigger_alarms then local data = read_alarms(alarmfile) local currentdate = os.date("%a-%d-%m-%Y:%H:%M") for date, message in pairs(data) do if currentdate:match(date) then naughty.notify({ text = message, title = currentdate, screen = capi.screen.count() }) local add = true for _, v in pairs(alarms) do if v[1] == date and v[2] == message then add = false break end end if add then table.insert(alarms, { currentdate, message }) end end end update(false) end end widget:add_signal("mouse::enter", function () fulldate = true update(false) end) widget:add_signal("mouse::leave", function () fulldate = false update(false) end) function set_editor(e) settings.editor = e or defaults.editor end function set_longformat(strOrFn) settings.longtimeformat = strOrFn or defaults.longtimeformat update(false) end function set_shortformat(strOrFn) settings.shorttimeformat = strOrFn or defaults.shorttimeformat update(false) end function set_shorttimer(delay) settings.shorttimer = delay or defaults.shorttimer end function set_longtimer(delay) settings.longtimer = delay or defaults.longtimer end setmetatable(_M, { __call = function () update() if not initialized then lib.hooks.timer.register(settings.shorttimer, settings.longtimer, update) lib.hooks.timer.start(update) menu = awful.menu.new({ id = "clock", items = { { "Edit Todo", function () edit(os.getenv("HOME") .. "/todo") end }, { "Edit Alarms", function () edit(alarmfile) end } } }) initialized = true end return widget end }) awesome-extra/obvious/clock/readme.md0000644000000000000000000000403711651220325015066 0ustar Clock Widget ============ This widget is a powerful clock. It has a normal view, a roll-over view, and configurable, time-based alarms. When an alarm is shown, the clock will change its colour to indicate that. If you then click on it, all alarms since the last click are shown. Settings Available: ------------------- * `set_editor("xterm -e vim")`: Set which editor to use. There is no default, so this is needed. * `set_shortformat("%a %b %d")`: Set the format of the short display. You may specify either a string which has a format that os.date() can understand (man date has the formats), or a function that returns the usable format. * `set_longformat(function () return "%T %a %b %d %Y" end)`: Set the format of the long display. You may specify either a string which has a format that `os.date()` can understand (`man date` has the formats), or a function that returns the usable format. * `set_shorttimer(n)`: Set the delay between updates to `n` * `set_longtimer(n)`: Set the long delay between updates to `n`, this is used when obvious is suspended. To set one of these settings, simply do something like: obvious.clock.set_editor("xterm -e vim") Implementation: --------------- To use it, include it into your rc.lua by inserting this line: require("obvious.clock") Then configure at least the editor setting (see Settings Available). To finish your rc.lua changes, add the clock widget to your wibox's widget list by adding: obvious.clock() Finally, you want to create the alarm file. The alarm file is contained in `${XDG_CONFIG_DIR}/awesome/alarms`. In most cases this would be `~/.config/awesome/alarms`. The alarm file has a format like: 14:30 get pizza from oven These alarms (each consisting of two lines) are shown with naughty. The first line of each entry is a Lua regular expression to match against the time in strftime format `%a-%d-%m-%Y:%H:%M`, which looks like this: Tue-26-05-2009:22:01 The second line contains the message to show. You can use `\n` inside the message body if you want a newline. awesome-extra/obvious/AUTHORS0000644000000000000000000000207611651220325013265 0ustar Below is a list of authors and contributors to Obvious, along with their email addresses. Should you be listed here and want your listing removed or altered (i.e. change or remove the email adress), or if you think you should appear in this file, please drop a line to gbe@ring0.de. Authors: 2009 Gregor "farhaven" Best 2009 Andrei "Garoth" Thorp 2009 Uli "psychon" Schlachter Contributors: 2009 Evan McClain 2009 Alexandre "kAworu" Perrin 2009 Jacob Winther 2009 Sébastien Gross 2009 Marco Candrian 2009 Eligio Becerra 2010 Philip Paeps 2010 Kristof Provost 2010 Tadeusz Sośnierz 2010 Christian Kuka awesome-extra/obvious/net/0000755000000000000000000000000011651220325012776 5ustar awesome-extra/obvious/net/init.lua0000644000000000000000000000342311651220325014446 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- ----------------------------------- local setmetatable = setmetatable local io = io local tonumber = tonumber local lib = { widget = require("obvious.lib.widget") } module("obvious.net") -- Returns the total traffic send/received on some interface local function netinfo(interface) local net = io.open("/proc/net/dev") local ret = { } -- Init in case we don't find any matches ret.recv = 0 ret.send = 0 for line in net:lines() do if line:match("^%s+" .. interface) then ret.recv = tonumber(line:match(":%s*(%d+)")) ret.send = tonumber(line:match("(%d+)%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+$")) end end net:close() return ret end local function get_data(object) local last = object.last local cur = netinfo(object.device) object.last = cur local ret = { } if last then ret.recv = cur.recv - last.recv ret.send = cur.send - last.send else ret.recv = 0 ret.send = 0 end -- This can happen e.g. when an interface is brought down and up again -- or when some counter overflows if ret.recv < 0 then ret.recv = 0 end if ret.send < 0 then ret.send = 0 end return ret end local function data(device, key) local device = device or "eth0" local ret = {} ret.device = device ret.get = function(obj) return get_data(obj)[key] end return lib.widget.from_data_source(ret) end function recv(device) return data(device, "recv") end function send(device) return data(device, "send") end -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/loadavg/0000755000000000000000000000000011653456453013644 5ustar awesome-extra/obvious/loadavg/readme0000644000000000000000000000213611651220325015007 0ustar Loadavg Widget ============== This widget provides the loadavg date as a text box. For details on the numbers, may read: http://www.teamquest.com/resources/gunther/display/5/index.htm Settings Available (with default values): ----------------------------------------- - set_shorttimer(5): Sets the update interval of the widget. (Fast than each 5 seconds may makes no sense since the data itself does not update more quickly in /prov/loadavg - set_command("xterm -e htop"): Set what command to issue on Button1 press. - set_prefix(""): Sets some text before the loadavg info. May use 'Pango Text Markup': http://library.gnome.org/devel/pango/stable/PangoMarkupFormat.html - set_suffix(""): Sets the text after the loadavg info. Implementation: --------------- To use it, include it into your rc.lua by inserting this line: require("obvious.loadavg") Then may configure it like this: obvious.loadavg.set_shorttimer(10) obvious.loadavg.set_command("urxvt -e htop") obvious.loadavg.set_prefix('') obvious.loadavg.set_suffix("") awesome-extra/obvious/loadavg/init.lua0000644000000000000000000000406111653456453015313 0ustar ------------------------------------ -- Author: Marco Candrian -- -- Copyright 2009 Marco Candrian -- ------------------------------------ local io = io local pairs = pairs local print = print local setmetatable = setmetatable local tonumber = tonumber local type = type local os = { date = os.date, getenv = os.getenv } local capi = { widget = widget, mouse = mouse, screen = screen } local awful = require("awful") local beautiful = require("beautiful") local naughty = require("naughty") local lib = { hooks = require("obvious.lib.hooks"), markup = require("obvious.lib.markup") } module("obvious.loadavg") local initialized = false local defaults = { } defaults.shorttimer = 5 -- loadavg won't change faster it seems anyway defaults.longtimer = 60 defaults.prefix = "" defaults.suffix = "" defaults.command = "xterm -e top" local settings = { } for key, value in pairs(defaults) do settings[key] = value end local widget = capi.widget({ type = "textbox", name = "loadavg", align = "right" }) widget:buttons(awful.util.table.join( awful.button({ }, 1, function () awful.util.spawn(settings.command) end) )) -- update interval function set_shorttimer(e) settings.shorttimer = e or defaults.shorttimer end -- command to issue on Button1 click function set_command(e) settings.command = e or defaults.command end -- prefix to the data - e.g. using pango 'text markup language' function set_prefix(e) settings.prefix = e or defaults.prefix end -- suffix to the data function set_suffix(e) settings.suffix = e or defaults.suffix end local function update () local f = io.open("/proc/loadavg") local loadavg loadavg = f:read(14) f:close() widget.text = settings.prefix .. loadavg .. settings.suffix end setmetatable(_M, { __call = function () update() if not initialized then lib.hooks.timer.register(settings.shorttimer, settings.longtimer, update) lib.hooks.timer.start(update) initialized = true end return widget end }) awesome-extra/obvious/lib/0000755000000000000000000000000011653456453012775 5ustar awesome-extra/obvious/lib/wlan.lua0000644000000000000000000000200511653456453014436 0ustar -------------------------------- -- Author: Gregor Best -- -- Copyright 2009 Gregor Best -- -------------------------------- local tonumber = tonumber local setmetatable = setmetatable local io = { open = io.open, popen = io.popen } local math = { floor = math.floor } module("obvious.lib.wlan") local function get_data(device) local link = 0 local fd = io.open("/proc/net/wireless") if not fd then return end for line in fd:lines() do if line:match("^ "..device) then link = tonumber(line:match(" (%d?%d?%d)")) break end end fd:close() fd = io.popen("iwconfig " .. device) if fd then local scale = 100 for line in fd:lines() do if line:match("Link Quality=") then scale = tonumber(line:match("=%d+/(%d+)")) end end link = math.floor((link / scale) * 100) end return link end setmetatable(_M, { __call = function (_, ...) return get_data(...) end }) awesome-extra/obvious/lib/init.lua0000644000000000000000000000066411651220325014432 0ustar ------------------------------------------ -- Author: Andrei "Garoth" Thorp -- -- Copyright 2009 Andrei "Garoth" Thorp -- ------------------------------------------ require("obvious.lib.hooks") require("obvious.lib.markup") require("obvious.lib.mpd") require("obvious.lib.widget") require("obvious.lib.wlan") module("obvious.lib") -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/lib/hooks/0000755000000000000000000000000011653456453014120 5ustar awesome-extra/obvious/lib/hooks/init.lua0000644000000000000000000001146511653456453015575 0ustar ------------------------------------------ -- Author: Andrei "Garoth" Thorp -- -- Copyright 2009 Andrei "Garoth" Thorp -- ------------------------------------------ -- Awful Timer Wrapper With Speed Controls local pairs = pairs local capi = { timer = timer } module("obvious.lib.hooks") local registry = {} timer = {} -- Register a timer just as you would with awful.hooks.timer.register, but -- with one slight twist: you set your regular speed, your slow -- speed, and then your function. -- @param reg_time Regular speed for the widget -- @param slow_time (Optional) Slow time for the widget -- @param fn The function that the timer should call -- @param descr (Optional) The description of this function function timer.register(reg_time, slow_time, fn, descr) if not slow_time then slow_time = reg_time * 4 end registry[fn] = { regular=reg_time, slow=slow_time, speed="regular", description=descr or "Undescribed timer", timer=capi.timer({ timeout = 600 }) } registry[fn].timer:add_signal("timeout", fn) -- set_speed() will :stop() again and start with the real timeout registry[fn].timer:start() timer.set_speed(registry[fn].speed, fn) end -- Unregister the timer altogether -- Note: It's possible to pause the timer with timer.stop() instead. -- @param fn The function you want to unregister. function timer.unregister(fn) if registry[fn].timer.started then registry[fn].timer:stop() end registry[fn] = nil end -- Switch timers between "slow" and "regular" speeds. -- @param speed The speed at which you want the function(s) to run: one of -- "regular" or "slow" -- @param fn (Optional) Function that you want to set to some speed. If not -- not specified, set all timers to the given speed. function timer.set_speed(speed, fn) if fn then local obj = registry[fn] obj.speed = speed if not registry[fn].timer.started then return end obj.timer:stop() local timeout = nil if speed == "regular" then timeout = obj.regular elseif speed == "slow" then timeout = obj.slow end if timeout then obj.timer.timeout = timeout obj.timer:start() end else for key, value in pairs(registry) do timer.set_speed(speed, key) end end end -- Edit a function's speeds. -- @param reg_time Regular speed for the function -- @param slow_time Slow speed for the function -- @param fn Function that you want to alter the speed of function timer.set_speeds(reg_time, slow_time, fn) registry[fn] = { regular=reg_time, slow=slow_time, speed=registry[fn].speed, timer=registry[fn].timer, } timer.set_speed(registry[fn].speed, fn) end -- Returns the speeds for the timer(s). -- @param fn (Optional) Function that you want to know the data for. If not -- specified, this returns a table of all registered timers with their data. -- @return A table with the regular speed, the slow speed, the currently used -- speed, whether the timer is running or not, and the description. -- Note: This function returns a copy of the internal registry, so assigning to -- it doesn't work. function timer.get_speeds(fn) copy = {} if fn then for key, value in pairs(registry[fn]) do copy[key] = value end else for key, value in pairs(registry) do subcopy = {} for subkey, subvalue in pairs(registry[key]) do subcopy[subkey] = subvalue end copy[key] = subcopy end end return copy end -- Pause timer(s) -- @param fn (Optional) Function to pause the timer for. If none is specified, -- this pauses all registered timers. function timer.stop(fn) if fn then registry[fn].timer:stop() else for key, value in pairs(registry) do registry[fn].timer:stop() end end end -- Start timer(s) -- @param fn (Optional) Function to start the timer for. If none is specified, -- this starts all registered timers. function timer.start(fn) if fn then if not registry[fn].timer.started then registry[fn].timer:start() end timer.set_speed(registry[fn].speed, fn) else for key, value in pairs(registry) do if not registry[fn].timer.started then registry[fn].timer:start() end timer.set_speed(registry[key].speed, fn) end end end -- Checks whether the given function is registered -- @return boolean true/false of whether the function is registered function timer.has(fn) if registry[fn] then return true else return false end end -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/lib/mpd/0000755000000000000000000000000011651220325013536 5ustar awesome-extra/obvious/lib/mpd/init.lua0000644000000000000000000001562411651220325015214 0ustar -- -- _ _ -- | |_ _ __ _ _ __ ___ _ __ __| | -- | | | | |/ _` |_____| '_ ` _ \| '_ \ / _` | -- | | |_| | (_| |_____| | | | | | |_) | (_| | -- |_|\__,_|\__,_| |_| |_| |_| .__/ \__,_| -- |_| -- -- Small interface to MusicPD -- use luasocket, with a persistant connection to the MPD server. -- -- based on a netcat version from Steve Jothen -- (see http://modeemi.fi/~tuomov/repos/ion-scripts-3/scripts/mpd.lua) -- -- -- Copyright (c) 2008-2009, Alexandre Perrin -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- 4. Neither the name of the author nor the names of its contributors -- may be used to endorse or promote products derived from this software -- without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- SUCH DAMAGE. -- Grab env local have_socket, socket = pcall(function() return require("socket") end) local string = string local tonumber = tonumber local setmetatable = setmetatable local os = os -- Music Player Daemon Lua library. module("obvious.lib.mpd") MPD = { } MPD_mt = { __index = MPD } -- create and return a new mpd client. -- the settings argument is a table with theses keys: -- hostname: the MPD's host (default localhost) -- port: MPD's port to connect to (default 6600) -- desc: server's description (default hostname) -- password: the server's password (default nil, no password) -- timeout: time in sec to wait for connect() and receive() (default 1) -- retry: time in sec to wait before reconnect if error (default 60) function new(settings) local client = {} if settings == nil then settings = {} end client.hostname = settings.hostname or "localhost" client.port = settings.port or 6600 client.desc = settings.desc or client.hostname client.password = settings.password client.timeout = settings.timeout or 1 client.retry = settings.retry or 60 setmetatable(client, MPD_mt) return client end -- calls the action and returns the server's response. -- Example: if the server's response to "status" action is: -- volume: 20 -- repeat: 0 -- random: 0 -- playlist: 599 -- ... -- then the returned table is: -- { volume = 20, repeat = 0, random = 0, playlist = 599, ... } -- -- if an error arise (bad password, connection failed etc.), a table with only -- the errormsg field is returned. -- Example: if there is no server running on host/port, then the returned -- table is: -- { errormsg = "could not connect" } -- function MPD:send(action) local command = string.format("%s\n", action) local values = {} if not have_socket then return { errormsg = "could not require(\"socket\")" } end -- connect to MPD server if not already done. if not self.connected then local now = os.time(); if not self.last_try or (now - self.last_try) > self.retry then self.socket = socket.tcp() self.socket:settimeout(self.timeout, 't') self.last_try = os.time() self.connected = self.socket:connect(self.hostname, self.port) if not self.connected then return { errormsg = "could not connect" } end -- Read the server's hello message local line = self.socket:receive("*l") if not line:match("^OK MPD") then -- Invalid hello message? self.connected = false return { errormsg = string.format("invalid hello message: %s", line) } end -- send the password if needed if self.password then local rsp = self:send(string.format("password %s", self.password)) if rsp.errormsg then return rsp end end else local retry_sec = self.retry - (now - self.last_try) return { errormsg = string.format("retrying connection in %d sec", retry_sec) } end end self.socket:send(command) local line = "" while not line:match("^OK$") do line = self.socket:receive("*l") if not line then -- closed,timeout (mpd killed?) self.connected = false return self:send(action) end if line:match("^ACK") then return { errormsg = line } end local _, _, key, value = string.find(line, "([^:]+):%s(.+)") if key then values[string.lower(key)] = value end end return values end function MPD:next() return self:send("next") end function MPD:previous() return self:send("previous") end function MPD:stop() return self:send("stop") end -- no need to check the new value, mpd will set the volume in [0,100] function MPD:volume_up(delta) local stats = self:send("status") local new_volume = tonumber(stats.volume) + delta return self:send(string.format("setvol %d", new_volume)) end function MPD:volume_down(delta) return self:volume_up(-delta) end function MPD:toggle_random() local stats = self:send("status") if tonumber(stats.random) == 0 then return self:send("random 1") else return self:send("random 0") end end function MPD:toggle_repeat() local stats = self:send("status") if tonumber(stats["repeat"]) == 0 then return self:send("repeat 1") else return self:send("repeat 0") end end function MPD:toggle_play() if self:send("status").state == "stop" then return self:send("play") else return self:send("pause") end end -- vim:filetype=lua:tabstop=8:shiftwidth=4:expandtab: awesome-extra/obvious/lib/widget/0000755000000000000000000000000011653456453014260 5ustar awesome-extra/obvious/lib/widget/init.lua0000644000000000000000000000556211653456453015736 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- ----------------------------------- require("obvious.lib.widget.graph") require("obvious.lib.widget.progressbar") require("obvious.lib.widget.textbox") local setmetatable = setmetatable local getmetatable = getmetatable local pairs = pairs local type = type local lib = { hooks = require("obvious.lib.hooks") } local layout = require("awful.widget.layout.horizontal") module("obvious.lib.widget") local defaults = { } set_default_layout = function(lay) defaults.layout = lay or layouts.leftright end set_default_margin = function(marg) defaults.margin = marg or { left = 5 } end -- The functions each object from from_data_source will get local funcs = { } funcs.set_type = function (obj, widget_type) local widget_type = _M[widget_type] if not widget_type or not widget_type.create then return end local meta = getmetatable(obj) local widget = widget_type.create(meta.data, defaults.layout) obj[1] = widget obj.update() obj:set_margin(defaults.margin) return obj end funcs.set_layout = function (obj, layout) obj[1].layout = layout obj.layout = layout obj:set_margin(defaults.margin) return obj end funcs.set_margin = function (obj, margin) obj[1]:set_margin(margin) return obj end function from_data_source(data) local ret = { } for k, v in pairs(funcs) do ret[k] = v end -- We default to graph since progressbars can't handle sources without an -- upper bound on their value ret[1] = _M.graph.create(data) ret.layout = nil ret.update = function() -- because this uses ret, if ret[1] is changed this automatically -- picks up the new widget ret[1]:update() end -- Fire up the timer which keeps this widget up-to-date lib.hooks.timer.register(10, 60, ret.update) lib.hooks.timer.start(ret.update) ret.update() local meta = { } meta.data = data -- This is called when an unexesting key is accessed meta.__index = function (obj, key) local ret = obj[1][key] if key ~= "layout" and type(ret) == "function" then -- Ugly hack: this function wants to be called on the right object return function(_, ...) -- Ugly hack: this function wants to be called on the right object ret(obj[1], ...) -- Ugly hack 2: We force obj to be returned again and discard -- the function's return value return obj end end return ret end -- Default layout is leftright, users can override this if they want to ret:set_layout(defaults.layout) setmetatable(ret, meta) return ret end -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/lib/widget/graph.lua0000644000000000000000000000321411653456453016064 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- ----------------------------------- local beautiful = require("beautiful") local awful = { widget = require("awful.widget") } local margins = awful.widget.layout.margins local setmetatable = setmetatable module("obvious.lib.widget.graph") function graph(layout, scale) local theme = beautiful.get() local color = theme.graph_fg_color or theme.widget_fg_color or theme.fg_normal local back = theme.graph_bg_color or theme.widget_bg_color or theme.bg_normal local border= theme.graph_border or theme.widget_border or theme.border_normal local width = theme.graph_width or theme.widget_width local widget = awful.widget.graph({ layout = layout }) widget:set_color(color) widget:set_border_color(border) widget:set_background_color(back) if width then widget:set_width(width) end if scale then widget:set_scale(true) end return widget end function create(data, layout) local scale = true if data.max then scale = false end local widget = graph(layout, scale) widget.update = function(widget) local max = widget.data.max or 1 local val = widget.data:get() or max widget:add_value(val / max) end widget.data = data widget.set_margin = function(widget, margin) margins[widget.widget] = margin return widget end return widget end setmetatable(_M, { __call = function (_, ...) return graph(...) end }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/lib/widget/progressbar.lua0000644000000000000000000000317711653456453017324 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- ----------------------------------- local beautiful = require("beautiful") local awful = { widget = require("awful.widget") } local margins = awful.widget.layout.margins local setmetatable = setmetatable module("obvious.lib.widget.progressbar") function progressbar(layout) local theme = beautiful.get() local width = theme.progressbar_width or theme.widget_width or 8 local color = theme.progressbar_fg_color or theme.widget_fg_color or theme.fg_normal local back = theme.progressbar_bg_color or theme.widget_bg_color or theme.bg_normal local border= theme.progressbar_border or theme.widget_border or theme.border_normal local widget = awful.widget.progressbar({ layout = layout }) widget:set_vertical(true) widget:set_width(width) widget:set_color(color) widget:set_background_color(back) widget:set_border_color(border) return widget end function create(data, layout) local widget = progressbar(layout) widget.update = function(widget) -- TODO: We don't support data sources without a fixed upper bound local max = widget.data.max or 1 local val = widget.data:get() or max widget:set_value(val / max) end widget.set_margin = function(widget, margin) margins[widget.widget] = margin return widget end widget.data = data return widget end setmetatable(_M, { __call = function (_, ...) return progressbar(...) end }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/lib/widget/textbox.lua0000644000000000000000000000223711653456453016464 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- ----------------------------------- local type = type local margins = awful.widget.layout.margins local capi = { widget = widget } local string = { format = string.format } module("obvious.lib.widget.textbox") function create(data, layout) local obj = { } obj.data = data obj.widget = capi.widget({ type = "textbox" }) obj.format = "%3d%%" obj.layout = layout obj.update = function(obj) local max = obj.data.max or 1 local val = obj.data:get() or max local perc = val / max * 100 if type(obj.format) == "function" then obj.widget.text = obj.format(perc) else obj.widget.text = string.format(obj.format, perc) end end obj.set_format = function(obj, format) obj.format = format obj:update() return obj end obj.set_margin = function(obj, margin) margins[obj.widget] = margin return obj end return obj end -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/lib/markup.lua0000644000000000000000000000565511651220325014773 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- -- Copyright 2009 Majic -- ----------------------------------- local beautiful = require("beautiful") local tostring = tostring module('obvious.lib.markup') fg = {} bg = {} --[[ -- Little map of how I -- organized this for usage. +-- markup | |`-- bold() Set bold. |`-- italic() Set italicized text. |`-- strike() Set strikethrough text. |`-- underline() Set underlined text. |`-- big() Set bigger text. |`-- small() Set smaller text. |`-- font() Set the font of the text. | |`--+ bg | | | |`-- color() Set background color. | |`-- focus() Set focus background color. | |`-- normal() Set normal background color. | `-- urgent() Set urgent background color. | |`--+ fg | | | |`-- color() Set foreground color. | |`-- focus() Set focus foreground color. | |`-- normal() Set normal foreground color. | `-- urgent() Set urgent foreground color. | |`-- focus() Set both foreground and background focus colors. |`-- normal() Set both foreground and background normal colors. `-- urgent() Set both foreground and background urgent colors. ]] -- Basic stuff... function bold(text) return '' .. tostring(text) .. '' end function italic(text) return '' .. tostring(text) .. '' end function strike(text) return '' .. tostring(text) .. '' end function underline(text) return '' .. tostring(text) .. '' end function big(text) return '' .. tostring(text) .. '' end function small(text) return '' .. tostring(text) .. '' end function font(font, text) return '' .. tostring(text) ..'' end -- Set the foreground. function fg.color(color, text) return '' .. tostring(text) .. '' end -- Set the background. function bg.color(color, text) return '' .. tostring(text) .. '' end -- Context: focus function fg.focus(text) return fg.color(beautiful.fg_focus, text) end function bg.focus(text) return bg.color(beautiful.bg_focus, text) end function focus(text) return bg.focus(fg.focus(text)) end -- Context: normal function fg.normal(text) return fg.color(beautiful.fg_normal, text) end function bg.normal(text) return bg.color(beautiful.bg_normal, text) end function normal(text) return bg.normal(fg.normal(text)) end -- Context: urgent function fg.urgent(text) return fg.color(beautiful.fg_urgent, text) end function bg.urgent(text) return bg.color(beautiful.bg_urgent, text) end function urgent(text) return bg.urgent(fg.urgent(text)) end -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/CONTRIBUTING.md0000644000000000000000000001334211651220325014444 0ustar Contributing Obvious Widgets ============================ So, you want to contribute to the Obvious project? Well of course you do! I guess that's pretty clear. I mean, anyone could tell, right? Obviously. ... So lets get started. Patching An Existing Widget --------------------------- If you want to just improve our existing widgets by adding settings and features, it's pretty easy. Some things to watch out for: - Style! Make sure that the code you write fits with the general style of the widget. In particular, you should use the same indentation pattern that the code uses. Also, trailing whitespace is bad. Try to avoid adding space at the ends of lines. This wastes bytes and is considered poor form. Anyway, you probably get the idea. - Clarity. Your code should be easy to understand, maintainable, and modularized. You should also avoid code duplication wherever possible by adding functions. If something is unclear, and you can't write it in such a way that it will be clear, explain it with a comment. - Regressions. Please _test_ your changes before submitting to make sure that not only they work, but have not broken other parts of the widget! - Options. If you add or remove options, make sure the top-level README file reflects the changes. See "Adding A New Widget"'s section on this. Adding A New Widget ------------------- It's also understandable that people want to add their own widgets to the Obvious repository. That's fantastic. Adding your useful widgets to Obvious makes them available for everyone. However, there are a few things that you need to know about the structure of Obvious. Note that a lot of the stuff from the section "Patching An Existing Widget" also apply here. ### File Structure obvious | |-- init.lua | |-- battery | | | |-- init.lua | `-- readme . In general, Obvious widgets are laid as above. The main file, obvious/init.lua has the definition of the Obvious module in general. When adding a new widget, you want to also add it to this file. The name that you want to add is the same as the folder you'll be making. Then, you want to make that folder. In the example above, that is "battery". Inside the folder, you want to have at least "init.lua" and "readme". The init.lua file will be run first, the readme explains to the user what your module does and how to implement it, as well as any settings. Feel free to add more .lua files in the folder if you need them. ### Your init.lua This is your main file for your widget. Add other files if necessary for the sake of organization, but this is all you really need. Refer to other modules and documentation for how to write this kind of file. In general, the structure is: * Get variables and modules from the rc.lua and Awesome * Declare your module * Write your code using the variables defined * Write your public settings interface (see below) ### Your settings For settings, we have the standard that your module must have a collection of functions named `set_`. These are the access to the module's settings and can otherwise be whatever you want. These then are used from the rc.lua like: obvious.module.set_something(foo) And that should be all it takes for the user. ### Your data If the widget gathers nontrivial data (i.e. wlan signal strength, battery charge, but _not_ the current time, as that's just one function call away), you should supply a function called `get_data()` which returns nil on failure and a hashtable with the collected data otherwise. This is so other people can build on your work (the true spirit of open source, right? :P) and create different ways of visualizing the data gathered by your widget without duplicating code (which is why your widget should also use the `get_data()` function). ### Top-level init file If someone does `require("obvious")`, the behaviour is to import all widgets. The way this is accomplished is by making an "obvious" module that requires all of the sub-modules. In short, if you've created a new sub-module, you should add your sub-module to the list of things that is required by the init.lua in the root folder. ### Top-level README The top-level README is an overview of what features each widget sub-module supports and provides. It is a listing of the options available and what views it supports (like text-only, progress bar, etc.). When creating a new widget, you should add your overview to the top-level README. ### Your readme Your "readme" is the explanation for the user. As such, it has a rough layout: * Widget Name * Description of widget. * Explanation of available settings. * Explanation of how to integrate it into your rc.lua. The exact way you do this doesn't matter, but please try to stick to this kind of ordering/layout. Submitting Your Changes ----------------------- Once you've written a tidy, well-fitting, clear patch with no bugs, you should submit it. We'd seriously love to have it. Some ways: * Commit it and use git-format-branch to create a patch-email. Then send this e-mail to one of the developers of obvious if you can find their e-mails, or to one of the awesome mailing lists which we tend to read. We then can take it, read it, possibly reply to it with suggestions for improvement, or apply it to the obvious project. * You can put your changes into your own personal git repo on the web and request a pull. Use the command git request-pull for this. This makes a bit of formatted text that tells us what changes you've made and where to get it. Again, e-mail this text up to us somewhere. * Also, we're generally pretty laid back. If we know you, trust you to write decent code, and know that you want to help regularly, we can probably just agree to give you commit access to the main Obvious repo. awesome-extra/obvious/bluetooth/0000755000000000000000000000000011651220325014215 5ustar awesome-extra/obvious/bluetooth/readme0000644000000000000000000000042111651220325015372 0ustar * Bluetooth widget This widget list currently available bluetooth devices. ** Usage Include the following line into your rc.lua : require("obvious.bluetooth") Add it to your wibox's widgets list: obvious.bluetooth() Christian Kuka [christian@kuka.cc] awesome-extra/obvious/bluetooth/init.lua0000644000000000000000000000420011651220325015657 0ustar ----------------------------------------------------- -- Bluetooth widget for the awesome window manager -- ----------------------------------------------------- -- Author: Christian Kuka chritian@kuka.cc -- -- Copyright 2010 Christian Kuka -- -- Licensed under GPLv2 -- ----------------------------------------------------- local assert = assert local string = string local setmetatable = setmetatable local table = table local io = { popen = io.popen } local capi = { widget = widget, mouse = mouse } local naughty = require("naughty") local awful = require("awful") local lib = { hooks = require("obvious.lib.hooks"), markup = require("obvious.lib.markup") } module("obvious.bluetooth") widget = capi.widget({ type = "textbox", name = "tb_gps", align = "right" }) widget.text = "⋊" -- Major device classes local classes = { x00 = "Misc", x01 = "Computer", x02 = "Phone", x03 = "Network", x04 = "Audio", x05 = "Peripheral", x06 = "Imaging", x1f = "Uncategorized" } -- Return device list devices = {} function get_data() return devices end -- Update device list local function update() devices = {} local fd = io.popen("hcitool inq") if not fd then return end -- Inquery takes 10.5s for addr, cl in string.gfind(fd:read("*all"),"%s+([a-zA-Z0-9:]+)%s+clock offset: [a-z0-9]+%s+class: ([a-z0-9]+)") do local dev = { address = addr, class = classes[cl:sub(2,4)] or "Uncategorized" } table.insert(devices, dev) end end -- Show address and major device class local function detail() local d = "Bluetooth Devices:" table.foreach(devices, function(i,dev) d = d.."\n"..dev.address.."\t"..dev.class end) naughty.notify({ text = d, screen = capi.mouse.screen }) end widget:buttons(awful.util.table.join( awful.button({ }, 1, detail) )) lib.hooks.timer.register(60, 300, update) lib.hooks.timer.start(update) setmetatable(_M, { __call = function () return widget end }) awesome-extra/obvious/keymap_switch/0000755000000000000000000000000011653456453015076 5ustar awesome-extra/obvious/keymap_switch/init.lua0000644000000000000000000000671611653456453016556 0ustar --------------------------------- -- Author: Andrei Thorp -- -- Copyright 2010 Andrei Thorp -- --------------------------------- -- Dependencies: setxkbmap (shell command) -- Ideas: -- * user specified rewrite table: convert us(dvorak) to "Dvorak" -- * use formatting system to allow people to format their text widgets -- * allow the user to override the text widget with some other widget -- * filter out the current layout from the menu that appears on click -- * let user configure the quick update delay (1 second) in case their -- computer is unusually slow or quick or something local setmetatable = setmetatable local pairs = pairs local ipairs = ipairs local widget = widget local io = { popen = io.popen } local awful = require("awful") local lib = { hooks = require("obvious.lib.hooks"), markup = require("obvious.lib.markup") } local defaults = {} defaults.layouts = {} defaults.menu = nil defaults.widget = widget({ type = "textbox" }) defaults.widget.text = "..." -- Clone the defaults to the used settings local settings = {} for key, value in pairs(defaults) do settings[key] = value end module("obvious.keymap_switch") -- Updates once after a short delay and then unregisters its timer local function delayed_update_once(start) if start == true then lib.hooks.timer.register(1, 1, delayed_update_once, "One-off update for keymap widget") lib.hooks.timer.start(delayed_update_once) else update() lib.hooks.timer.unregister(delayed_update_once) end end setup_done = false local function init_once() if setup_done then return end lib.hooks.timer.register(5, 60, update, "Update for the keymap widget") lib.hooks.timer.start(update) delayed_update_once(true) setup_done = true end local function init(widget) init_once() -- Use the default widget if not specified if widget then settings.widget = widget end -- Reconfigure the menu immediately set_layouts(settings.layouts) -- Set up the on-click menu event settings.widget:buttons(awful.util.table.join( awful.button({ }, 1, function() settings.menu:toggle() end) )) return settings.widget end -- Returns the current keymap, as discovered from setxkbmap local function get_current_keymap() local fd = io.popen("setxkbmap -print") if not fd then return end for line in fd:lines() do if line:match("xkb_symbols") then local keymap = line:match("\+.*\+") fd:close() if not keymap then return "unknown layout" else return keymap:sub(2, -2) end end end fd:close() return "unknown layout" end local function switch_keymap(layout_string) awful.util.spawn("setxkbmap \"" .. layout_string .. "\"") delayed_update_once(true) end function set_layouts(layouts_table) settings.layouts = layouts_table or settings.layouts newitems = {} for index, value in ipairs(settings.layouts) do newitems[index] = { value, function() switch_keymap(value) end } end settings.menu = awful.menu.new({ id = "keymap_switch", items = newitems }) end function update() settings.widget.text = get_current_keymap() end setmetatable(_M, { __call = function() return init(settings.widget) end }) -- TODO let the user specify widget here -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/keymap_switch/readme.md0000644000000000000000000000106511651220325016640 0ustar Keymap Widget ============= This widget shows the current keyboard layout. To add this widget to your configuration, insert require("obvious.keymap_switch") into the top of your rc.lua and add `obvious.keymap_switch()` to your wibox. This widget provides some options: * `obvious.keymap_switch.set_layouts(layouts_table)` where `layouts_table` is a simple table of input strings to setxkbmap. For example, to allow the widget to switch between Qwerty and Dvorak, the call would look like: obvious.keymap_switch.set_layouts({ "us", "us(dvorak)" }) awesome-extra/obvious/init.lua0000644000000000000000000000122111651220325013652 0ustar ------------------------------------------- -- Author: Gregor "farhaven" Best" -- -- Copyright 2009 Gregor Best -- ------------------------------------------- require("obvious.basic_mpd") require("obvious.battery") require("obvious.clock") require("obvious.cpu") require("obvious.fs_usage") require("obvious.io") require("obvious.lib") require("obvious.loadavg") require("obvious.mem") require("obvious.net") require("obvious.popup_run_prompt") require("obvious.umts") require("obvious.volume_alsa") require("obvious.volume_freebsd") require("obvious.wlan") require("obvious.temp_info") require("obvious.keymap_switch") module("obvious") awesome-extra/obvious/temp_info/0000755000000000000000000000000011653456453014207 5ustar awesome-extra/obvious/temp_info/readme0000644000000000000000000000054311651220325015352 0ustar Temperature Zone widget This widget is a temperature monitor. It gets its information from ACPI, to make it as correct as possible. Implementation: --------------- To use it, include it into your rc.lua by inserting this line (near the top preferably): require("obvious.temp_info") Then add it to your wibox's widgets list: obvious.temp_info() awesome-extra/obvious/temp_info/init.lua0000644000000000000000000000255611653456453015665 0ustar ----------------------------------- -- Author: Eligio Becerra -- -- Copyright 2009 Eligio Becerra -- ----------------------------------- local awful = require("awful") local setmetatable = setmetatable local tonumber = tonumber local table = { insert = table.insert } local capi = { widget = widget } local lib = { markup = require("obvious.lib.markup"), hooks = require("obvious.lib.hooks") } module("obvious.temp_info") local widget = capi.widget({ type = "textbox" }) local colors = { ["normal"] = "#009000", ["warm"] = "#909000", ["hot"] = "#900000" } local function update() local d = awful.util.pread("acpi -t") local temp = { } for t in d:gmatch("Thermal %d+: %w+, (%d+.?%d*) degrees") do table.insert(temp, t) end local color = colors["hot"] if not temp[1] then widget.text = "no data" return end if tonumber(temp[1]) < 50 then color = colors["normal"] elseif tonumber(temp[1]) >= 50 and tonumber(temp[1]) < 60 then color = colors["warm"] end widget.text = temp[1] .. " " .. lib.markup.fg.color(color, "C") end update() lib.hooks.timer.register(5, 30, update) lib.hooks.timer.stop(update) setmetatable(_M, { __call = function () lib.hooks.timer.start(update) return widget end }) -- vim: filetype=lua:expandtab:shiftwidth=3:tabstop=3:softtabstop=3:encoding=utf-8:textwidth=80 awesome-extra/obvious/README0000644000000000000000000000367611651220325013104 0ustar Readme for Obvious -- Widget data sources -- cpu() -- Widgets -- textbox -- graph -- progressbar -- fs_usage(path) -- Widgets -- textbox -- graph -- progressbar -- Parameters -- path the mountpoint to watch, / by default -- io(device) -- Widgets -- textbox -- graph -- progressbar -- Parameters -- device the harddisk to monitor, sda by default -- mem() -- Widgets -- textbox -- graph -- progressbar -- net.send(device) / net.recv(device) -- Widgets -- textbox -- graph -- progressbar -- Parameters -- device the network device to monitor -- wlan(device) -- Widgets -- textbox -- graph -- progressbar -- Parameters -- device the wlan device to monitor -- basic_mpd() -- Widgets -- textbox -- battery() -- Widgets -- textbox -- clock() -- Widgets -- textbox -- temp_info() -- Widgets -- textbox -- keymap_switch() -- Widgets -- textbox -- Widget types -- "textbox" -- Functions -- set_format() -- "graph" -- Functions -- set_height() -- set_width() -- set_border_color() -- set_gradient_colors() -- set_gradient_angle() -- set_color() -- set_background_color() -- "progressbar" -- Functions -- set_height() -- set_width() -- set_border_color() -- set_gradient_colors() -- set_color() -- set_background_color() -- set_vertical() -- all -- Functions -- set_type() -- set_layout() -- set_margin() -- Global functions -- set_default_margin() -- set_default_layout() awesome-extra/obvious/io/0000755000000000000000000000000011651220325012617 5ustar awesome-extra/obvious/io/init.lua0000644000000000000000000000427411651220325014274 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- ----------------------------------- local io = io local setmetatable = setmetatable local tonumber = tonumber local pairs = pairs local lib = { widget = require("obvious.lib.widget") } module("obvious.io") local function info(dev) local f = io.open("/proc/diskstats") local line if f == nil then return ret end line = f:read() while line and not line:match(dev) do line = f:read() end f:close() if not line then return nil end local ret = { } -- each time matches() is called it returns the next number from line local matches = line:gmatch("%d+") -- First two are device numbers, skip them matches() matches() ret.reads_completed = tonumber(matches()) ret.reads_merged = tonumber(matches()) ret.reads_sectors = tonumber(matches()) ret.reads_time_ms = tonumber(matches()) ret.writes_completed = tonumber(matches()) ret.writes_merged = tonumber(matches()) ret.writes_sectors = tonumber(matches()) ret.writes_time_ms = tonumber(matches()) ret.in_progress = tonumber(matches()) ret.time_ms = tonumber(matches()) ret.time_ms_weight = tonumber(matches()) return ret end local function get_increase(data) local last = data.last local cur = info(data.device) if not cur then return nil end data.last = cur -- Fake for starting if last == nil then last = cur end local ret = { } for k, v in pairs(cur) do ret[k] = cur[k] - last[k] end return ret end local function get(data) local val = get_increase(data) if not val then return end return val.writes_sectors + val.reads_sectors end local function get_data_source(device) local device = device or "sda" local ret = {} ret.get = get ret.device = device return lib.widget.from_data_source(ret) end setmetatable(_M, { __call = function (_, ...) return get_data_source(...) end }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/wlan/0000755000000000000000000000000011653456453013170 5ustar awesome-extra/obvious/wlan/readme0000644000000000000000000000114611651220325014333 0ustar WLAN widget This widget monitors your WLAN's signal strength. To set the device it monitors, use obvious.wlan.set_device(dev) The default is "wlan0". To add it to your rc.lua, include require("obvious.wlan") in the top of your rc.lua and add obvious.wlan() to your wibox If you want to use the data gathered by this widget, you can use the function obvious.wlan.get_data(). It returns nil on failure, otherwise it returns a table with the field 'link' as its only content. That field contains a number the range of which depends on the wlan driver and firmware used which describes the signal strength. awesome-extra/obvious/wlan/init.lua0000644000000000000000000000235611653456453014644 0ustar -------------------------------- -- Author: Gregor Best -- -- Copyright 2009 Gregor Best -- -------------------------------- local string = { format = string.format } local setmetatable = setmetatable local lib = { widget = require("obvious.lib.widget"), markup = require("obvious.lib.markup"), wlan = require("obvious.lib.wlan") } module("obvious.wlan") local function format(link) local color = "#009000" if link < 50 and link > 10 then color = "#909000" elseif link <= 10 then color = "#900000" end return lib.markup.fg.color(color,"☢") .. string.format(" %03d%%", link) end local function get_data_source(device) local device = device or "wlan0" local data = {} data.device = device data.max = 100 data.get = function (obj) return lib.wlan(obj.device) end local ret = lib.widget.from_data_source(data) -- Due to historic reasons, this widget defaults to a textbox with -- a "special" format. ret:set_type("textbox") ret:set_format(format) return ret end setmetatable(_M, { __call = function (_, ...) return get_data_source(...) end }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/gps/0000755000000000000000000000000011651220325013001 5ustar awesome-extra/obvious/gps/readme0000644000000000000000000000137711651220325014171 0ustar * GPS widget This widget allows you to display position information from your GPS-receiver. It also can display the position on openstreetmap and perform reverse geocoding through geonames.org ** Available settings - set_browser: Sets the path to the www-browser. If no browser is set the default is /usr/bin/uzbl - set_device: Sets the GPS device ie. /dev/rfcomm0 if you have a bluetooth GPS receiver. Default is /dev/rfcomm0 ** Usage Include the following line into your rc.lua : require("obvious.gps") Then set the device and the browser: obvious.gps.set_device("/dev/rfcomm0") obvious.gps.set_browser("/usr/bin/uzbl") And add it to your wibox's widgets list: obvious.gps() Christian Kuka [christian@kuka.cc] awesome-extra/obvious/gps/init.lua0000644000000000000000000001275711651220325014463 0ustar ----------------------------------------------- -- GPS widget for the awesome window manager -- ----------------------------------------------- -- Author: Christian Kuka chritian@kuka.cc -- -- Copyright 2010 Christian Kuka -- -- Licensed under GPLv2 -- ----------------------------------------------- local assert = assert local string = string local tonumber = tonumber local math = math local setmetatable = setmetatable local table = table local io = { open = io.open } local capi = { widget = widget, mouse = mouse } local naughty = require("naughty") local awful = require("awful") local http = require("socket.http") local ltn12 = require("ltn12") local json = require("json") local lib = { hooks = require("obvious.lib.hooks"), markup = require("obvious.lib.markup") } module("obvious.gps") widget = capi.widget({ type = "textbox", name = "tb_gps", align = "right" }) position = { date = 0, time = 0, latitude = 0.0, longitude = 0.0, quality = 0, altitude = 0.0, satellites = 0, satellitesData = {}, dilution = 0.0, height = 0.0, status = "V", speed = 0.0, course = 0.0, variation = 0.0, node = "" } -- Set the local device for NMEA data local device = "/dev/rfcomm0" function set_device(dev) device = dev end -- Set the browser for opening openstreetmap local browser = "/usr/bin/uzbl" function set_browser(path) browser = path end -- Returns the position struct function get_data() return position end -- Parse the NMEA messages (GGA, RMC, GSV) local fh = nil function parse_nmea(line) local msg = string.sub(line,0,6) if (msg == "$GPGGA") then -- Match GGA message local time, latitude, longitude, quality, satellites, dilution, altitude, height, checksum = line:match("^\$GPGGA,([0-9.]+),([0-9.]+),[NS],([0-9.]+),[EW],([0-8]?),([0-9]+),([0-9.]*),([0-9.-]+),M,([0-9.]+),M,,\*(.*)") latitude = tonumber(latitude) longitude = tonumber(longitude) local dd dd,_ = math.modf(latitude / 100) position.latitude = dd + (latitude - dd * 100) / 60 dd,_ = math.modf(longitude / 100) position.longitude = dd + (longitude - dd * 100) / 60 position.time = time position.quality = tonumber(quality) position.satellites = tonumber(satellites) position.dilution = tonumber(dilution) position.altitude = tonumber(altitude) position.height = tonumber(height) elseif (msg == "$GPRMC") then -- Match RMC message local time, status, latitude, longitude, speed, course, date, variation, node, checksum = line:match("^\$GPRMC,([0-9.]+),[AV],([0-9.]+),[NS],([0-9.]+),[EW],([0-9.]+),([0-9.]+),([0-9]+),([0-9.]*),[EW]?,([NADE])\*(.*)") latitude = tonumber(latitude) longitude = tonumber(longitude) local dd dd,_ = math.modf(latitude / 100) position.latitude = dd + (latitude - dd * 100) / 60 dd,_ = math.modf(longitude / 100) position.longitude = dd + (longitude - dd * 100) / 60 position.time = time position.date = date position.status = status position.speed = tonumber(speed) position.course = tonumber(course) position.variation = tonumber(variation) position.node = node elseif (msg == "$GPGSV") then -- TODO is satellite data needed? -- Match GSV message --local total, count, satellites, satellites, checksum = line:match("^\$GPGSV,([1-3]+),([1-3]+),([0-9]+),([0-9,]*)\*(.*)") -- Match satellites data -- local id, elevation, azimuth, snr = satellites:match("([0-9]{1,2}),([0-9]+),([0-9]+),([0-9]*)") end end -- Reverse geocode a position using geonames.org function reverse_geocode() local c, err, h = http.request("http://ws.geonames.org/findNearbyPlaceNameJSON?lat="..position.latitude.."&lng="..position.longitude) if c then c = json.decode(c) return c.geonames[1] end return nil end -- Update position data local function update() fh = io.open(device) if fh then local line = fh:read("*l") local maxlines = 3 local l = 0 while line and l < maxlines do parse_nmea(line) l = l + 1 end fh:close() end widget.text = string.format("%f,%f", position.latitude, position.longitude) end -- Show detail information about current position local function detail() local d = string.format("Latitude:\t%f\nLongitude:\t%f\nAltitude:\t%f\nDilution:\t%f", position.latitude, position.longitude, position.altitude, position.dilution) naughty.notify({ text = d, screen = capi.mouse.screen }) end -- Show reverse geocode position information local function lookup() local geodata = reverse_geocode() if geodata then local d = string.format("Country:\t%s\nName:\t%s", geodata.countryName, geodata.name) naughty.notify({ text = d, screen = capi.mouse.screen }) end end -- Open openstreetmap with current position local function openmap() local link = "http://www.openstreetmap.org/?lat="..position.latitude.."&lon="..position.longitude.."&zoom=14&layers=B00FTF" awful.util.spawn(browser .. " " .. link) end widget:buttons(awful.util.table.join( awful.button({ }, 1, detail), awful.button({ }, 2, openmap), awful.button({ }, 3, lookup) )) update() lib.hooks.timer.register(60, 300, update) lib.hooks.timer.start(update) setmetatable(_M, { __call = function () return widget end }) awesome-extra/obvious/mem/0000755000000000000000000000000011651220325012766 5ustar awesome-extra/obvious/mem/init.lua0000644000000000000000000000452411651220325014441 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- ----------------------------------- local io = io local tonumber = tonumber local setmetatable = setmetatable local lib = { widget = require("obvious.lib.widget") } module("obvious.mem") local function mem_usage() local f = io.open("/proc/meminfo") local ret = { } for line in f:lines() do if line:match('^MemTotal:') then ret.total = tonumber(line:match('(%d+)')) elseif line:match('^MemFree:') then ret.free = tonumber(line:match('(%d+)')) elseif line:match('^Buffers:') then ret.bufs = tonumber(line:match('(%d+)')) elseif line:match('^Cached:') then ret.cached = tonumber(line:match('(%d+)')) elseif line:match('^SwapTotal:') then ret.swap_total = tonumber(line:match('(%d+)')) elseif line:match('^SwapFree:') then ret.swap_free = tonumber(line:match('(%d+)')) end end f:close() ret.avail = ret.free + ret.bufs + ret.cached ret.used = ret.total - ret.avail ret.perc = (100 / ret.total) * ret.used ret.perc_not_free = (100 / ret.total) * (ret.total - ret.free) ret.swap_used = ret.swap_total - ret.swap_free ret.swap_perc = (100 / ret.swap_total) * ret.swap_used -- The following values are returned: -- * total Total Memory -- * free Total free memory -- * bufs Memory used for buffers -- * cached Memory used for caches -- * avail Memory not used by user space -- * used Memory used by user space -- * perc Percentage of memory used by user space -- * perc_not_free Percentage of memory which is not free (different from 100 - perc!) -- * swap_total Total swap space -- * swap_free Free swap space -- * swap_used Used swap space -- * swap_perc Percentage of swap space used return ret end local function get() return mem_usage().perc end local function get_data_source() local ret = {} ret.max = 100 ret.get = get return lib.widget.from_data_source(ret) end setmetatable(_M, { __call = function (_, ...) return get_data_source(...) end }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/volume_freebsd/0000755000000000000000000000000011651220325015211 5ustar awesome-extra/obvious/volume_freebsd/init.lua0000644000000000000000000000634511651220325016667 0ustar -------------------------------- -- Author: Gregor Best -- -- Copyright 2009 Gregor Best -- -------------------------------- local setmetatable = setmetatable local tonumber = tonumber local pairs = pairs local io = { popen = io.popen } local string = { match = string.match, find = string.find, format = string.format } local table = { insert = table.insert } local capi = { widget = widget, } local awful = require("awful") local lib = { hooks = require("obvious.lib.hooks"), markup = require("obvious.lib.markup") } module("obvious.volume_freebsd") local objects = { } function get_data(channel) local rv = { } local fd = io.popen("mixer " .. channel) if not fd then return end local status = fd:read("*all") fd:close() rv.volume = tonumber(status:match(" +(%d?%d?%d)")) rv.mute = false local fd = io.popen("sysctl dev.acpi_ibm.0.mute") if fd then if tonumber(fd:read("*all"):match(": (%d)")) == 1 then rv.mute = true end end return rv end local function update(obj) local status = get_data(obj.channel) or { volume = 0, mute = true } local color = "#009000" if status.mute then color = "#900000" end obj.widget.text = lib.markup.fg.color(color, "☊") .. string.format(" %03d%%", status.volume) end local function update_by_values(channel) for i, v in pairs(objects) do if v.channel == channel then update(v) end end end function raise(channel, v) v = v or 1 awful.util.spawn("mixer " .. channel .. " +" .. v, false) update_by_values(channel) end function lower(channel, v) v = v or 1 awful.util.spawn("mixer " .. channel .. " -" .. v, false) update_by_values(channel) end local function create(_, channel) local channel = channel or "vol" local obj = { channel = channel } local widget = capi.widget({ type = "textbox" }) obj.widget = widget obj[1] = widget obj.update = function() update(obj) end widget:buttons(awful.util.table.join( awful.button({ }, 4, function () raise(obj.channel, 1) obj.update() end), awful.button({ }, 5, function () lower(obj.channel, 1) obj.update() end), awful.button({ "Shift" }, 4, function () raise(obj.channel, 10) obj.update() end), awful.button({ "Shift" }, 5, function () lower(obj.channel, 10) obj.update() end), awful.button({ "Control" }, 4, function () raise(obj.channel, 5) obj.update() end), awful.button({ "Control" }, 5, function () lower(obj.channel, 5) obj.update() end) )) obj.set_layout = function(obj, layout) obj.layout = layout return obj end obj.set_channel = function(obj, id) obj.channel = id obj.update() return obj end obj.raise = function(obj, v) raise(obj.channel, v) return obj end obj.lower = function(obj, v) lower(obj.channel, v) return obj end obj.update() lib.hooks.timer.register(10, 30, obj.update, "Update for the volume widget") lib.hooks.timer.start(obj.update) table.insert(objects, obj) return obj end setmetatable(_M, { __call = create }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/volume_freebsd/readme.md0000644000000000000000000000246211651220325016774 0ustar BSD volume widget ================= This widget uses mixer to get and set the current volume level and it also exports functions you can use in keybindings to change the volume of your soundcard. To add this widget to your configuration, insert require("obvious.volume_freebsd") into the top of your rc.lua and add `obvious.volume_freebsd()` to your wibox. Optionally you can specify the channel to be controlled like this: obvious.volume_alsa(channel) the default channel is "vol", you might need to set it to "pcm". The following functions can be used to raise/lower the volume of a soundcard and to mute it: * `obvious.volume_freebsd.raise(channel, v)` where `v` is optional and the value to raise the volume by (1 is the default) * `obvious.volume_freebsd.lower(channel, v)` where `v` is optional and the value to lower the volume by (1 is the default) Scrolling up and down on a widget changes the volume by 1. If you hold the `Control` key while scrolling, the volume is changed by 5 and if you hold `Shift`, it is changed by 10. If you want to use the data gathered by this widget, you can use the function obvous.volume_freebsd.get_data(channel) It returns nil on failure, otherwise it returns a table with the following fields: * `volume`: a number representing the current volume from 0 to 100 awesome-extra/obvious/popup_run_prompt/0000755000000000000000000000000011651220325015640 5ustar awesome-extra/obvious/popup_run_prompt/readme0000644000000000000000000000367411651220325017032 0ustar Pop-Up Run Prompt ================= This widget's purpose is to give you a pop-up run prompt. This widget requires that you bind it. If the bind is pressed, a wibox appears at the bottom of the current screen with a run prompt. Once you type the command you want or cancel, the wibox vanishes. This Obvious feature is inspired by ion3's similar run prompt that some users like because of the space-saving style it provides. Settings available: ------------------- - set_opacity: 0-1. Set the opacity of the popping up wibox. Use this if you have xcompmgr running and want real transparency. - set_prompt_string: The string that is used instead of the default " Run~ " for prompting the user to type. - set_prompt_font: Sets the font that the user types in. Uses pango markup. - set_slide: true/false. False by default. If this setting is on, rather than just having the wibox appear and disappear at the bottom of the screen, it slides on and off. - set_width: 0-1. Percentage width of screen edge. - set_height: number. Height of the run prompt, in pixels. - set_border_width: number: Width of border in pixels. - set_move_speed: number (in seconds): how fast each step of movement happens when the wibox is sliding up/down. - set_move_amount: number (in pixels): how many pixels the wibox moves per step (set by move_speed) - run_function: function: this function gets the input data as its argument, default is awful.util.spawn - completion_function: function: this function is used for completion, default is awful.completion.shell To set one of these settings, simply do something like: obvious.popup_run_prompt.set_opacity(0.7) Implementation: --------------- To use it, include it into your rc.lua by inserting this line: require("obvious.popup_run_prompt") Then add a bind to pop up the run prompt in your binds. Bind syntax changes, but it is roughly: awful.key({ modkey }, "r", obvious.popup_run_prompt.run_prompt), awesome-extra/obvious/popup_run_prompt/init.lua0000644000000000000000000001546011651220325017314 0ustar ------------------------------------------ -- Author: Andrei "Garoth" Thorp -- -- Copyright 2009 Andrei "Garoth" Thorp -- ------------------------------------------ local mouse = mouse local awful = require("awful") local widget = widget local screen = screen local ipairs = ipairs local pairs = pairs local io = io local beautiful = require("beautiful") local lib = { hooks = require("obvious.lib.hooks") } local capi = { wibox = wibox } module("obvious.popup_run_prompt") defaults = {} -- Default is 1 for people without compositing defaults.opacity = 1.0 defaults.prompt_string = " Run~ " defaults.prompt_font = nil -- Whether or not the bar should slide up or just pop up defaults.slide = false -- Bar will be percentage of screen width defaults.width = 0.6 -- Bar will be this high in pixels defaults.height = 22 defaults.border_width = 1 -- When sliding, it'll move this often (in seconds) defaults.move_speed = 0.02 -- When sliding, it'll move this many pixels per move defaults.move_amount = 3 -- Default run function defaults.run_function = awful.util.spawn -- Default completion function defaults.completion_function = awful.completion.shell -- Default cache defaults.cache = "/history" -- Default position defaults.position = "top" -- Clone the defaults for the used settings settings = {} for key, value in pairs(defaults) do settings[key] = value end runwibox = {} mypromptbox = {} inited = false -- We want to "lazy init" so that in case beautiful inits late or something, -- this is still likely to work. function ensure_init() if inited then return end inited = true for s = 1, screen.count() do mypromptbox[s] = widget({ type = "textbox", name = "mypromptbox" .. s, align = "left" }) runwibox[s] = capi.wibox({ fg = beautiful.fg_normal, bg = beautiful.bg_normal, border_width = settings.border_width, border_color = beautiful.bg_focus, }) set_default(s) runwibox[s].opacity = settings.opacity runwibox[s].visible = false runwibox[s].screen = s runwibox[s].ontop = true -- Widgets for prompt wibox runwibox[s].widgets = { mypromptbox[s], layout = awful.widget.layout.vertical.center } end end function set_default(s) runwibox[s]:geometry({ width = screen[s].geometry.width * settings.width, height = settings.height, x = screen[s].geometry.x + screen[s].geometry.width * ((1 - settings.width) / 2), y = screen[s].geometry.y + screen[s].geometry.height - settings.height, }) end function do_slide_up() local s = mouse.screen startgeom = runwibox[s]:geometry() runwibox[s]:geometry({ y = startgeom.y - settings.move_amount }) if runwibox[s]:geometry().y <= screen[s].geometry.y + screen[s].geometry.height - startgeom.height then set_default(s) lib.hooks.timer.stop(do_slide_up) end end function show_wibox(s) runwibox.screen = s if settings.slide == true then startgeom = runwibox[s]:geometry() -- changing visible property would reset wibox geometry to its defaults -- Might be 0 if position is set to "top" -- Thus the wibox has to be shown before setting its original slide up -- position. As a side effect, the top bar might blink if position is set -- to "top". runwibox[s].visible = true runwibox[s]:geometry({ y = screen[s].geometry.y + screen[s].geometry.height, }) if lib.hooks.timer.has(do_slide_up) then lib.hooks.timer.start(do_slide_up) else lib.hooks.timer.register(settings.move_speed, settings.move_speed*3, do_slide_up, "popup_run_prompt slide up") end else set_default(s) runwibox[s].visible = true end end function do_slide_down() local s = runwibox.screen startgeom = runwibox[s]:geometry() runwibox[s]:geometry({ y = startgeom.y + settings.move_amount, }) if runwibox[s]:geometry().y >= screen[s].geometry.y + screen[s].geometry.height then runwibox[s].visible = false lib.hooks.timer.stop(do_slide_down) end end function hide_wibox() local s = runwibox.screen or mouse.screen if settings.slide == true then runwibox[s].visible = true set_default(s) if lib.hooks.timer.has(do_slide_down) then lib.hooks.timer.start(do_slide_down) else lib.hooks.timer.register(settings.move_speed, settings.move_speed*3, do_slide_down, "popup_run_prompt slide down") end else set_default(s) runwibox[s].visible = false end end function run_prompt_callback() hide_wibox() end function run_prompt() ensure_init() show_wibox(mouse.screen) awful.prompt.run({ prompt = settings.prompt_string, font = settings.prompt_font }, mypromptbox[mouse.screen], settings.run_function, settings.completion_function, awful.util.getdir("cache") .. settings.cache, 100, run_prompt_callback ) end -- SETTINGS function set_opacity(amount) settings.opacity = amount or defaults.opacity update_settings() end function set_prompt_string(string) settings.prompt_string = string or defaults.prompt_string end function set_prompt_font(font_string) settings.prompt_font = font_string or defaults.prompt_font end function set_slide(tf) settings.slide = tf or defaults.slide end function set_width(amount) settings.width = amount or defaults.width update_settings() end function set_height(amount) settings.height = amount or defaults.height update_settings() end function set_border_width(amount) settings.border_width = amount or defaults.border_width update_settings() end function set_move_speed(amount) settings.move_speed = amount or defaults.move_speed end function set_move_amount(amount) settings.move_amount = amount or defaults.move_amount end function set_run_function(fn) settings.run_function = fn or defaults.run_function end function set_completion_function(fn) settings.completion_function = fn or defaults.completion_function end function set_position(p) settings.position = p end function update_settings() for s, value in ipairs(runwibox) do value.border_width = settings.border_width set_default(s) runwibox[s].opacity = settings.opacity end end function set_cache(c) settings.cache = c or defaults.cache end awesome-extra/obvious/basic_mpd/0000755000000000000000000000000011653456453014150 5ustar awesome-extra/obvious/basic_mpd/readme0000644000000000000000000000666211651220325015323 0ustar Basic MPD ========= This widget's purpose is to provide a simple interface to MPD, the Music Player Daemon. The widget will output track/album/artist information, formatted according to your wishes. Note, because Basic MPD runs on top of Obvious' MPD library, you do have access to features like pause/next/previous and everything else. However, this is done through the library directly rather than through Basic MPD. Note, because Basic MPD runs on top of Obvious' MPD library, access to advanced features is done using calls to the library via Basic MPD's connection to the MPD server. Settings available: ------------------- - set_format: Takes a string/function to use to format the Basic MPD display output. If a function is given, then a table with keys "artist", "album", and "title" will be given to this function, and whatever string it returns will be displayed. If a string is given to set_format, then it will be displayed with substitutions done on it. The format understands "$artist", "$album" and "$title" to do the replacement. For example, you could have a format string like: "$artist//$album//$title". The slashes are literal slashes, and the special variables will be replaced. If you're using a format string, the length is respected. If you're using a function, handling length is up to you. See set_length documentation about how it handles length. - set_length: Setting length only works for when using a format string for set_format (this is the default if you never call set_format). It would be somewhat silly to have the length just cut off the end of the string. This could land you in a situation where you know the title and album but not the artist, for example. Instead, what happens is that the formatter tries to shorten the longest components of format first and even out the lengths of the fields. So for example, imagine you have the output "Matisse The Cat - Jesse Cook - Frontiers" in your widget, but want this to be cut down to 32 characters max. The system would reformat this as "Matisse T - Jesse Coo - Frontiers". - set_unknown: If some metadata is not available, this is the string that should be displayed in that metadata's place. So for example, if you don't know the album, it might be "Matisse The Cat - Jesse Cook - (Unknown)". To set one of these settings, simply do something like: obvious.basic_mpd.set_format("MPD: $title") Implementation: --------------- To use it, include it into your rc.lua by inserting this line (near the top preferably): require("obvious.basic_mpd") Then add it to your wibox's widgets list: obvious.basic_mpd() It's also possible to create binds to control MPD via Obvious' MPD library: -- mod-p to pause/play. awful.key({ modkey }, "p", function() obvious.basic_mpd.connection:toggle_play() end), -- mod-plus/minus to decrease and increase volume by increments of 5. awful.key({ modkey, "Shift" }, "=", function () obvious.basic_mpd.connection:volume_up(5) end), awful.key({ modkey }, "-", function () obvious.basic_mpd.connection:volume_down(5) end), -- mod-> and mod-< to go forward/backward a song. bind({ modkey, "Shift" }, ",", function () obvious.basic_mpd.connection:previous() obvious.basic_mpd.update() end) bind({ modkey, "Shift" }, ".", function () obvious.basic_mpd.connection:next() obvious.basic_mpd.update() end) awesome-extra/obvious/basic_mpd/init.lua0000644000000000000000000001302311653456453015615 0ustar ------------------------------------------ -- Author: Andrei "Garoth" Thorp -- -- Copyright 2009 Andrei "Garoth" Thorp -- ------------------------------------------ local setmetatable = setmetatable local pairs = pairs local type = type local widget = widget local string = string local awful = require("awful") local naughty = require("naughty") local lib = { mpd = require("obvious.lib.mpd"), markup = require("obvious.lib.markup"), hooks = require("obvious.lib.hooks"), } module("obvious.basic_mpd") local defaults = { format = "$title - $album - $artist", length = 75, unknown = "(unknown)", } local settings = {} for key, value in pairs(defaults) do settings[key] = value end local widget = widget({ type = "textbox", name = "mpd-playing", align = "left" }) connection = lib.mpd.new() -- Utility function to handle the text for MPD -- @param songinfo: a table with fields "artist", "album", "title" in text -- @return formatted (settings.format) string to display on the widget. This -- respects settings.length and tries to make fields as close to the same -- lenghths as possible if shortening is required. local function format_metadata(songinfo) format = settings.format or defaults.format if (settings.length or defaults.length) <= 0 then return "" end used_keys = {} local start, stop start = 1 stop = 1 while start do local key start, stop = string.find(format, "%$%w+", stop) key = string.match(format, "%$(%w+)", stop) if key then if songinfo[key] then used_keys[key] = songinfo[key] else used_keys[key] = settings.unknown or defaults.unknown end end end retval = "" while true do retval = string.gsub(format, "%$(%w+)", used_keys) if #retval > (settings.length or defaults.length) then longest_key = nil longest_value = "" for key, value in pairs(used_keys) do if #value > #longest_value then longest_key = key longest_value = value end end if longest_key then -- shorten the longest by 1 used_keys[longest_key] = string.sub( used_keys[longest_key], 1, #longest_value - 1) else -- Seems like the format itself's too long err = "obvious.basic_mpd: impossible to fit " .. "output into " .. (settings.length or defaults.length) .. " characters.\n" .. "Widget paused." naughty.notify({ text = err, timeout = 0 }) lib.hooks.timer.stop(update) return "" end else -- All good! break end end return awful.util.escape(retval) end -- Updates the widget's display function update() local status = connection:send("status") local now_playing, songstats if not status.state then now_playing = "Music Off" now_playing = lib.markup.fg.color("yellow", now_playing) elseif status.state == "stop" then now_playing = "Music Stopped" else songstats = connection:send("playlistid " .. status.songid) format = settings.format or defaults.format if type(format) == "string" then now_playing = format_metadata(songstats) elseif type(format) == "function" then now_playing = format(songstats) else naughty.notify({ text = "obvious.basic_mpd: Invalid " .. "display format. Widget " .. "paused." }) lib.hooks.timer.stop(update) end end widget.text = now_playing end update() lib.hooks.timer.register(1, 30, update, "basic_mpd widget refresh rate") -- SETTINGS -- Set the format string -- @param format The format string function set_format(format) settings.format = format or defaults.format update() end -- Set the widget's text max length -- @param format The max length (in characters) of the widget's text function set_length(length) settings.length = length or defaults.length update() end -- Set the string to use for unknown metadata -- @param format The string to use for unknown metadata function set_unknown(unknown) settings.unknown = unknown or defaults.unknown update() end setmetatable(_M, { __call = function () return widget end }) -- vim: filetype=lua:expandtab:shiftwidth=8:tabstop=8:softtabstop=8:encoding=utf-8:textwidth=80 awesome-extra/obvious/battery/0000755000000000000000000000000011653456453013701 5ustar awesome-extra/obvious/battery/init.lua0000644000000000000000000001141711653456453015353 0ustar -------------------------------- -- Author: Gregor Best -- -- Copyright 2009 Gregor Best -- -------------------------------- local tonumber = tonumber local tostring = tostring local setmetatable = setmetatable local io = { popen = io.popen } local os = { execute = os.execute } local capi = { widget = widget, mouse = mouse } local naughty = require("naughty") local awful = require("awful") local lib = { hooks = require("obvious.lib.hooks"), markup = require("obvious.lib.markup") } module("obvious.battery") widget = capi.widget({ type = "textbox", name = "tb_battery", align = "right" }) status = { ["charged"] = "↯", ["full"] = "↯", ["high"] = "↯", ["discharging"] = "▼", ["charging"] = "▲", ["unknown"] = "⌁" } local backend = "acpi" get_data = nil local function init() local rv = os.execute("acpiconf") if rv == 0 then backend = "acpiconf" return end local rv = os.execute("acpitool") if rv == 0 then backend = "acpitool" return end rv = os.execute("acpi") if rv == 0 then backend = "acpi" return end rv = os.execute("apm") if rv == 0 then backend = "apm" return end backend = "none" end function get_data() local rv = { } rv.state = "unknown" rv.charge = nil rv.time = "00:00" if backend == "acpiconf" then local fd = io.popen("acpiconf -i0") for l in fd:lines() do if l:match("^Remaining capacity") then rv.charge = tonumber(l:match("\t(%d?%d?%d)")) elseif l:match("^Remaining time") then rv.time = l:match("\t(%S+)") if rv.time == "unknown" then rv.time = "" end elseif l:match("^State") then rv.state = l:match("\t(%S+)") end end fd:close() elseif backend == "acpi" or backend == "acpitool" then local fd = io.popen(backend .. " -b") if not fd then return end local line = fd:read("*l") while line do local data = line:match("Battery #?[0-9] *: ([^\n]*)") rv.state = data:match("([%a]*),.*"):lower() rv.charge = tonumber(data:match(".*, ([%d]?[%d]?[%d]%.?[%d]?[%d]?)%%")) rv.time = data:match(".*, ([%d]?[%d]?:?[%d][%d]:[%d][%d])") if not rv.state:match("unknown") then break end line = fd:read("*l") end fd:close() return rv elseif backend == "apm" then local fd = io.popen("apm") if not fd then return end local data = fd:read("*all") if not data then return end rv.state = data:match("battery ([a-z]+):") rv.charge = tonumber(data:match(".*, .*: (%d?%d?%d)%%")) rv.time = data:match("%((.*)%)$") return rv end return rv end local function update() local battery_status = "" local bat = get_data() if not bat then widget.text = "no data" return end local color = "#900000" if not bat.charge then widget.text = lib.markup.fg.color("#009000", status.charged) .. " A/C" return elseif bat.charge > 35 and bat.charge < 60 then color = "#909000" elseif bat.charge >= 40 then color = "#009000" end local state = bat.state if not status[state] then state = "unknown" end state = status[state] battery_status = lib.markup.fg.color(color, state) .. " " .. awful.util.escape(tostring(bat.charge)) .. "%" if bat.time then battery_status = battery_status .. " " .. awful.util.escape(bat.time) end widget.text = battery_status end local function detail () local fd = nil if backend == "acpiconf" then local str = "" fd = io.popen("sysctl hw.acpi.thermal") for l in fd:lines() do if l:match("tz%d%.temperature") then str = str .. "\n" .. l end end fd:close() naughty.notify({ text = str:gsub("^\n", ""), screen = capi.mouse.screen }) return elseif backend == "acpi" then fd = io.popen("acpi -bta") elseif backend == "acpitool" then fd = io.popen("acpitool") elseif backend == "apm" then fd = io.popen("apm") else naughty.notify({ text = "unknown backend: " .. backend }) end local d = fd:read("*all"):gsub("\n+$", "") fd:close() naughty.notify({ text = d, screen = capi.mouse.screen }) update() end widget:buttons(awful.util.table.join( awful.button({ }, 1, detail) )) init() update() lib.hooks.timer.register(60, 300, update) lib.hooks.timer.start(update) setmetatable(_M, { __call = function () return widget end }) awesome-extra/obvious/battery/readme.md0000644000000000000000000000267011651220325015446 0ustar Battery widget ============== This widget is a battery monitor. It gets its information from `acpi`, `acpitool` or from `apm`, to be as uniquely usable as possible. With `apm` as the backend, some information might not be available, such as whether the battery is currently charged or whether it is discharging. Charge is displayed with either backends. If you click on the widget, additional information is displayed. Currently, only the first battery is monitored on the widget box, but information about all other attached batteries is still visible if you click the widget. To use it, include it into your rc.lua by inserting this line: require("obvious.battery") into the top of your rc.lua. Then add the widget to your wibox. It's called obvious.battery() If you want to use the data gathered by this widget to create your own, use the function `obvious.battery.get_data()`. It returns nil on failure and it returns a table on success. The table has the following fields: * `state`: a string which describes the batteries' state as one element of the set `["charged", "full", "discharging", "charging"]` (most likely, some acpi implementations might output different values) * `charge`: a number representing the current battery charge as a number between 0 and 100 * `time`: a string describing the time left to full charge or complete discharge (the format and whether this field is filled at all depends on the acpi implementation) awesome-extra/obvious/LICENSE0000644000000000000000000000246711651220325013226 0ustar Obvious and its modules are licensed under the MIT license (the text of which follows below), unless explicitly stated in the module header. Unless stated explicitly in the file header, files belonging to Obvious are copyrighted by the people listed as "Authors" in the file AUTHORS. Text of the MIT license: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. awesome-extra/obvious/TODO0000644000000000000000000000233311651220325012701 0ustar Todo list / informal bug tracker Clock: alarms file should be created if doesn't exist ================================================================================ Clock: needs more beautiful theming? ================================================================================ Clock: raises error on menu ================================================================================ W: awesome: luaA_dofunction:317: error running function: /usr/local/share/awesome/lib/awful/menu.lua:48: bad argument #3 to '?' (string expected, got nil) This causes the menu to stick open. temp_info: doesn't conform to widget types and it should ================================================================================ temp_info: very littly flexibility ================================================================================ temp_info: use beautiful colours, perhaps ================================================================================ loadavg: doesn't conform to widget types and it should ================================================================================ loadavg: not in the README overview file at top-level ================================================================================ awesome-extra/obvious/fs_usage/0000755000000000000000000000000011651220325014004 5ustar awesome-extra/obvious/fs_usage/init.lua0000644000000000000000000000235611651220325015460 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- ----------------------------------- local io = io local setmetatable = setmetatable local pairs = pairs local lib = { widget = require("obvious.lib.widget") } module("obvious.fs_usage") -- This returns the percentage of used space on the given mountpoint function fs(path) local df = io.popen("LC_ALL=C df -hP " .. path) local key local ret = nil if not df then return nil end for line in df:lines() do local mountpoint = line:match("%% ([-/%w]+)$") local dev = line:match("^[%w/-]+") local perc = line:match("(%d+)%%") if perc ~= nil and mountpoint ~= nil and dev ~= nil then ret = perc end end df:close() return ret end local function get(data) return fs(data.path) end local function get_data_source(path) local path = path or "/" local ret = {} ret.max = 100 ret.get = get ret.path = path return lib.widget.from_data_source(ret) end setmetatable(_M, { __call = function (_, ...) return get_data_source(...) end }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/umts/0000755000000000000000000000000011653456453013217 5ustar awesome-extra/obvious/umts/readme0000644000000000000000000000054711651220325014366 0ustar UMTS (Ericsson F3705) widget This widget is a very quick&dirty hack to get data from the Ericsson F3707 UMTS card found in a number of ThinkPad and Dell notebooks. It gets the operator name and the signal strength. Possibly, this should be changed to be a progressbar rather than a textbox, but ... it works for me. - Philip [philip@paeps.cx, 20100216] awesome-extra/obvious/umts/init.lua0000644000000000000000000000470011653456453014666 0ustar -- -- Track indicators from F3705 gadget. -- ------------------------------------------------------------------------------ -- "THE BEER-WARE LICENSE" (Revision 42): -- wrote this file. As long as you retain this notice you -- can do whatever you want with this stuff. If we meet some day, and you -- think this stuff is worth it, you can buy me a beer in return. -- - Philip Paeps ------------------------------------------------------------------------------ local assert = assert local setmetatable = setmetatable local io = { open = io.open } local capi = { widget = widget, mouse = mouse } local naughty = require("naughty") local awful = require("awful") local lib = { hooks = require("obvious.lib.hooks"), markup = require("obvious.lib.markup") } module("obvious.umts") widget = capi.widget({ type = "textbox", name = "tb_umts", align = "right" }) local fh = nil local cops = {} local cind = {} function wait_for_data(input) fh:write(input) local data = "" local lastline repeat lastline = assert(fh:read()) data = data .. lastline .. "\n" until lastline:match("OK") return data end function get_indicators() local cind = wait_for_data("AT+CIND?\r\n") local rv = {} rv.signal = cind:match("+CIND: %d,(%d)") rv.service = cind:match("+CIND: %d,%d,%d,%d,(%d)") rv.roaming = cind:match("+CIND: %d,%d,%d,%d,%d,%d,%d,(%d)") return rv end function get_operator() wait_for_data("AT+COPS=3,0\r\n") local cops = wait_for_data("AT+COPS?\r\n") local rv = {} rv.mode = cops:match("+COPS: (%d)") rv.format = cops:match("+COPS: %d,(%d)") rv.oper = cops:match("+COPS: %d,%d,\"(%a*)\"") rv.act = cops:match("+COPS: %d,%d,\"%a*\",(%d)") return rv end local function update() fh = io.open("/dev/ttyACM1", "r+") if not fh then cops = {} cind = {} widget.text = "" return end cops = get_operator() cind = get_indicators() widget.text = " " .. cops.oper fh:close() end local function detail() if not cops.oper then return end naughty.notify({ text = "Mobile operator: " .. cops.oper .. "\nSignal strength: " .. cind.signal .. "/5" .. "\nRoaming: " .. cind.roaming, screen = capi.mouse.screen }) end widget:buttons(awful.util.table.join( awful.button({ }, 1, detail) )) update() lib.hooks.timer.register(60, 300, update) lib.hooks.timer.start(update) setmetatable(_M, { __call = function () return widget end }) awesome-extra/obvious/volume_alsa/0000755000000000000000000000000011653456453014536 5ustar awesome-extra/obvious/volume_alsa/init.lua0000644000000000000000000001062211653456453016205 0ustar -------------------------------- -- Author: Gregor Best -- -- Copyright 2009 Gregor Best -- -------------------------------- local setmetatable = setmetatable local tonumber = tonumber local pairs = pairs local io = { popen = io.popen } local string = { match = string.match, find = string.find, format = string.format } local table = { insert = table.insert } local capi = { widget = widget, } local awful = require("awful") local lib = { hooks = require("obvious.lib.hooks"), markup = require("obvious.lib.markup") } module("obvious.volume_alsa") local objects = { } function get_data(cardid, channel) local rv = { } local fd = io.popen("amixer -c " .. cardid .. " -- sget " .. channel) if not fd then return end local status = fd:read("*all") fd:close() rv.volume = tonumber(string.match(status, "(%d?%d?%d)%%")) if not rv.volume then return end status = string.match(status, "%[(o[^%]]*)%]") if not status then status = "on" end if string.find(status, "on", 1, true) then rv.mute = false else rv.mute = true end return rv end local function update(obj) local status = get_data(obj.cardid, obj.channel) or { mute = true, volume = 0 } local color = "#900000" if not status.mute then color = "#009000" end obj.widget.text = lib.markup.fg.color(color, "☊") .. string.format(" %03d%%", status.volume) end local function update_by_values(cardid, channel) for i, v in pairs(objects) do if v.channel == channel and v.cardid == cardid then update(v) end end end function raise(cardid, channel, v) v = v or 1 awful.util.spawn("amixer -q -c " .. cardid .. " sset " .. channel .. " " .. v .. "+", false) update_by_values(cardid, channel) end function lower(cardid, channel, v) v = v or 1 awful.util.spawn("amixer -q -c " .. cardid .. " sset " .. channel .. " " .. v .. "-", false) update_by_values(cardid, channel) end function mute(cardid, channel) awful.util.spawn("amixer -c " .. cardid .. " sset " .. channel .. " toggle", false) update_by_values(cardid, channel) end function mixer(term, cardid) awful.util.spawn(term .. " -e 'alsamixer -c " .. cardid .. "'") end local function create(_, cardid, channel) local cardid = cardid or 0 local channel = channel or "Master" local obj = { cardid = cardid, channel = channel, term = "x-terminal-emulator -T Mixer" } local widget = capi.widget({ type = "textbox" }) obj.widget = widget obj[1] = widget obj.update = function() update(obj) end widget:buttons(awful.util.table.join( awful.button({ }, 4, function () raise(obj.cardid, obj.channel, 1) obj.update() end), awful.button({ }, 5, function () lower(obj.cardid, obj.channel, 1) obj.update() end), awful.button({ "Shift" }, 4, function () raise(obj.cardid, obj.channel, 10) obj.update() end), awful.button({ "Shift" }, 5, function () lower(obj.cardid, obj.channel, 10) obj.update() end), awful.button({ "Control" }, 4, function () raise(obj.cardid, obj.channel, 5) obj.update() end), awful.button({ "Control" }, 5, function () lower(obj.cardid, obj.channel, 5) obj.update() end), awful.button({ }, 1, function () mute(obj.cardid, obj.channel) obj.update() end), awful.button({ }, 3, function () mixer(obj.term, obj.cardid) obj.update() end) )) obj.set_layout = function(obj, layout) obj.layout = layout return obj end obj.set_cardid = function(obj, id) obj.cardid = id obj.update() return obj end obj.set_channel = function(obj, id) obj.channel = id obj.update() return obj end obj.set_term = function(obj, term) obj.term = term return obj end obj.raise = function(obj, v) raise(obj.cardid, obj.channel, v) return obj end obj.lower = function(obj, v) lower(obj.cardid, obj.channel, v) return obj end obj.mute = function(obj, v) mute(obj.cardid, obj.channel, v) return obj end obj.update() lib.hooks.timer.register(10, 30, obj.update, "Update for the volume widget") lib.hooks.timer.start(obj.update) table.insert(objects, obj) return obj end setmetatable(_M, { __call = create }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/obvious/volume_alsa/readme.md0000644000000000000000000000344711651220325016306 0ustar ALSA volume widget ================== This widget uses amixer to get and set the current volume level and it also exports functions you can use in keybindings to change the volume and mute/unmute your soundcard. To add this widget to your configuration, insert require("obvious.volume_alsa") into the top of your rc.lua and add `obvious.volume_alsa()` to your wibox. Optionally you can specify the cardid and channel to be controlled like this: obvious.volume_alsa(cardid, channel) the default channel is "Master", you might need to set it to "PCM". The following functions can be used to raise/lower the volume of a soundcard and to mute it: * `obvious.volume_alsa.raise(cardid, channel, v)` where `v` is optional and the value to raise the volume by (1 is the default) * `obvious.volume_alsa.lower(cardid, channel, v)` where `v` is optional and the value to lower the volume by (1 is the default) * `obvious.volume_alsa.mute(cardid, channel)` If you left-click on a volume widget, the card is muted/unmuted. Right-clicking opens a terminal with `alsamixer` in it. The terminal can be set with `:set_term(t)` appended to the widget in the wibox. Changing it to `xterm` would look like this: w.widgets = { obvious.volume_alsa(0, "PCM"):set_term("xterm") } Scrolling up and down on a widget changes the volume by 1. If you hold the `Control` key while scrolling, the volume is changed by 5 and if you hold `Shift`, it is changed by 10. If you want to use the data gathered by this widget, you can use the function obvous.volume_alsa.get_data(cardid, channel). It returns nil on failure, otherwise it returns a table with the following fields: * `volume`: a number representing the current volume from 0 to 100 * `mute` : a boolean value describing whether the channel is muted or not awesome-extra/obvious/cpu/0000755000000000000000000000000011651220325012777 5ustar awesome-extra/obvious/cpu/init.lua0000644000000000000000000000444411651220325014453 0ustar ----------------------------------- -- Author: Uli Schlachter -- -- Copyright 2009 Uli Schlachter -- ----------------------------------- local io = io local tonumber = tonumber local pairs = pairs local setmetatable = setmetatable local lib = { widget = require("obvious.lib.widget") } module("obvious.cpu") local function cpu_info() local f = io.open("/proc/stat") local line = f:read() local ret = { } local matches = line:gmatch("%d+") f:close() -- each time matches() is called it returns the next number from line ret.user = tonumber(matches()) ret.nice = tonumber(matches()) ret.system = tonumber(matches()) ret.idle = tonumber(matches()) ret.iowait = tonumber(matches()) ret.irq = tonumber(matches()) ret.softirq = tonumber(matches()) -- The returned array contains numbers which describe the time in number of -- jiffies since this box was started return ret end local function cpu_usage(object) local last = object.cpu_last local cur = cpu_info() object.cpu_last = cur -- Fake for starting if last == nil then last = cur end local ret = { } for k, v in pairs(cur) do ret[k] = cur[k] - last[k] end -- Calculate the cpu usage in percent -- Ignore iowait (dunno...) local t = ret.user + ret.nice + ret.system + ret.irq + ret.softirq if (t + ret.idle) == 0 then ret.perc = 0 else ret.perc = 100 * t / (t + ret.idle) end -- This array now got the following keys (time is in jiffies!): -- * user user cpu time -- * nice cpu time for nice'd processes -- * system cpu time spent in syscalls -- * idle cpu time spent idlying -- * iowait cpu time spent waiting for I/O -- * irq cpu time spent in irq handlers -- * softirq cpu time spent in soft irq handlers -- * perc percentage of time spent doing stuff return ret end local function get_data_source() local ret = {} ret.max = 100 ret.get = function(obj) return cpu_usage(obj).perc end return lib.widget.from_data_source(ret) end setmetatable(_M, { __call = function (_, ...) return get_data_source(...) end }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:encoding=utf-8:textwidth=80 awesome-extra/wicked/0000755000000000000000000000000011765367653012016 5ustar awesome-extra/wicked/wicked.7.gz0000644000000000000000000000673011651220352013753 0ustar Jwicked.7ZmoF_|TKjc/Qȥ5ee}ኒ^\4rwvgf.KT*k.׉82crYjvMoG_i)xs\~ӝC6~LG5"p}[.qS$߱LD?3b? wid'Mwgy efL@P:fd|)**OWo._\?M]2k&5'lY˦%ʄm'zŒZF*تLYK>(2U7ibjUf!XhNLڈd.bZjªaZZf|0f7$QjRmm,*'Faf8f Q sLjk1is(;1/.iDFnmp{?RVnm&Eu ИQkf+7mzޢ/uAVQ#u Œb+^>NfY[&Q@6xՍ*mqBb´0z>kvz8t o T`BD75@`K܆Lv';/&Ib\ jQ<1(r "t bTwPT%lGj}4adt6%X+ى)` iӢFM1VMlu* E֥kjP1ܻGE!orh0ުRtT{l5S֐RKBY 8A!Tdahw #l9]`jڢ8Ӡټmj5#K.Gc5y-9"+5=?ڢ"7lBq Q, q3`:@[+zҜ_ |ik(pB!KYEy*^ZV0J`kD` bMБNᐴ.@2 MKjx}Eo VR 8wpR߀Tt[U8VL4<Yv֔TwŴIm :}QAܛiF`Sbdn8sd%p-qJQ"{&;spb8fﰈ}Lh D iĘЭ^s*/=a+l׊愛v<ҫJӍ7|g ]axCH?Y& "b!89`&-EW98)ZՎ }4ӔĶsi~eM7ŽHք_4Q$w0Q&t4W9|4cH㮟:WPANRPl7b# = \Bew8lvL`ҥ*|fVpW@0ًMgc\kR t@'@1Ax% rzdK}BYdڍү7XQ|n3ƺכƊkƞlsx6yq6[!}>mk|bӮ 3-U wo7~{ՙ } 00czدZ|ϰkaF?4˶C_o`o hQeꖞ؞{lO~7UO}Һ:=e'%Now Playing: '..args[1] else return '' end end) -------------------------------------- USAGE EXAMPLES -------------- Put these snippets into your rc.lua (usually located at ~/.config/awesome/rc.lua) to see what they do, don't forget to add the widgets to your statusbar. **A simple \'Now Playing' widget** -------------------------------------- mpdwidget = widget({ type = 'textbox', name = 'mpdwidget' }) wicked.register(mpdwidget, wicked.widgets.mpd, ' Now Playing: $1') -------------------------------------- **A memory usage monitor, with padding** -------------------------------------- memwidget = widget({ type = 'textbox', name = 'memwidget' }) wicked.register(memwidget, wicked.widgets.mem, ' Memory: $1 ($2Mb/$3Mb)', {2, 4, 4}) --------------------------------------- **A filesystem usage indicator** --------------------------------------- fswidget = widget({ type = 'textbox', name = 'fswidget' }) wicked.register(fswidget, wicked.widgets.fs, ' FS: ${/ used}/${/ size} (${/ usep} used)', 120) --------------------------------------- **A network interface monitor (for eth0)** --------------------------------------- netwidget = widget({ type = 'textbox', name = 'netwidget' }) wicked.register(netwidget, wicked.widgets.net, ' NET: ${eth0 down} / ${eth0 up} [ ${eth0 rx} // ${eth0 tx} ]') --------------------------------------- SEE ALSO -------- awesome(1) awesomerc(5) AUTHORS ------- Lucas de Vries awesome-extra/wicked/wicked.lua0000644000000000000000000005253611651220352013754 0ustar --------------------------------------------------------------------------- -- Wicked widgets for the awesome window manager --------------------------------------------------------------------------- -- Lucas de Vries -- Licensed under the WTFPL -- Version: v1.0pre-awe3.0rc4 --------------------------------------------------------------------------- -- Require libs require("awful") ---- {{{ Grab environment local ipairs = ipairs local pairs = pairs local print = print local type = type local tonumber = tonumber local tostring = tostring local math = math local table = table local awful = awful local os = os local io = io local string = string -- Grab C API local capi = { awesome = awesome, screen = screen, client = client, mouse = mouse, button = button, titlebar = titlebar, widget = widget, hooks = hooks, keygrabber = keygrabber } -- }}} -- Wicked: Widgets for the awesome window manager module("wicked") ---- {{{ Initialise variables local registered = {} local widget_cache = {} -- Initialise function tables widgets = {} helper = {} local nets = {} local cpu_total = {} local cpu_active = {} local cpu_usage = {} -- }}} ---- {{{ Helper functions ----{{{ Max width function helper.max_width(str, width) l = str:len() if l > width then r = math.floor(width/2) a = str:sub(1,r) b = str:sub(l-r, l) str = a .. "..." .. b end return str end ----}}} ----{{{ Force a fixed width on a string with spaces function helper.fixed_width(str, width) l = str:len() n = width-l if n >= 0 then for i = 1, n do str = str.." " end else str = str:sub(0, l+n) end return str end ----}}} ---- {{{ Format a string with args function helper.format(format, args) -- TODO: Find a more efficient way to do this -- Format a string for var,val in pairs(args) do format = string.gsub(format, '$'..var, val) end -- Return formatted string return format end -- }}} ---- {{{ Padd a number to a minimum amount of digits function helper.padd(number, padding) s = tostring(number) if padding == nil then return s end for i=1,padding do if math.floor(number/math.pow(10,(i-1))) == 0 then s = "0"..s end end if number == 0 then s = s:sub(2) end return s end -- }}} ---- {{{ Convert amount of bytes to string function helper.bytes_to_string(bytes, sec, padding) if bytes == nil or tonumber(bytes) == nil then return '' end bytes = tonumber(bytes) signs = {} signs[1] = ' b' signs[2] = 'KiB' signs[3] = 'MiB' signs[4] = 'GiB' signs[5] = 'TiB' sign = 1 while bytes/1024 > 1 and signs[sign+1] ~= nil do bytes = bytes/1024 sign = sign+1 end bytes = bytes*10 bytes = math.floor(bytes)/10 if padding then bytes = helper.padd(bytes*10, padding+1) bytes = bytes:sub(1, bytes:len()-1).."."..bytes:sub(bytes:len()) end if sec then return tostring(bytes)..signs[sign]..'ps' else return tostring(bytes)..signs[sign] end end -- }}} ---- {{{ Split by whitespace function helper.splitbywhitespace(str) values = {} start = 1 splitstart, splitend = string.find(str, ' ', start) while splitstart do m = string.sub(str, start, splitstart-1) if m:gsub(' ','') ~= '' then table.insert(values, m) end start = splitend+1 splitstart, splitend = string.find(str, ' ', start) end m = string.sub(str, start) if m:gsub(' ','') ~= '' then table.insert(values, m) end return values end -- }}} --{{{ Escape a string function helper.escape(text) if text then text = text:gsub("&", "&") text = text:gsub("<", "<") text = text:gsub(">", ">") text = text:gsub("'", "'") text = text:gsub("\"", """) end return text end -- }}} -- }}} ---- {{{ Widget types ---- {{{ MPD widget type function widgets.mpd() ---- Get data from mpc local nowplaying_file = io.popen('mpc') local nowplaying = nowplaying_file:read() -- Close the command nowplaying_file:close() -- Check that it's not nil if nowplaying == nil then return {''} end -- Escape nowplaying = helper.escape(nowplaying) -- Return it return {nowplaying} end widget_cache[widgets.mpd] = {} -- }}} ---- {{{ MOCP widget type function widgets.mocp(format, max_width) local playing = '' ---- Get data from mocp local info = io.popen('mocp -i') local state = info:read() state = state.gsub(state, 'State: ', '') if (state == "PLAY") then local file = info:read() file = file.gsub(file, 'File: ', '') local title = info:read() title = title.gsub(title, 'Title: ', '') local artist = info:read() artist = artist.gsub(artist, 'Artist: ', '') local songtitle = info:read() songtitle = songtitle.gsub(songtitle, 'SongTitle: ', '') local album = info:read() album = album.gsub(album, 'Album: ', '') -- Try artist - (song)title if (artist:len() > 0) then playing = artist .. ' - ' .. (songtitle ~= '' and songtitle or title) -- Else try title or songtitle elseif (artist:len() == 0 and (title:len() > 0 or songtitle:len() > 0)) then playing = (title ~= '' and title or songtitle) -- Else use the filename else file = string.reverse(file) i = string.find(file, '/') if (i ~= nil) then file = string.sub(file, 0, i-1) end playing = string.reverse(file) end else playing = state end -- Close file info:close() -- Apply maximum width if (max_width ~= nil) then playing = helper.max_width(playing, max_width) end playing = helper.escape(playing) -- Return it return {playing} end widget_cache[widgets.mocp] = {} -- }}} ---- {{{ CPU widget type function widgets.cpu(format, padding) -- Calculate CPU usage for all available CPUs / cores and return the -- usage -- Perform a new measurement ---- Get /proc/stat local cpu_lines = {} local cpu_usage_file = io.open('/proc/stat') for line in cpu_usage_file:lines() do if string.sub(line, 1, 3) == 'cpu' then table.insert(cpu_lines, helper.splitbywhitespace(line)) end end cpu_usage_file:close() ---- Ensure tables are initialized correctly while #cpu_total < #cpu_lines do table.insert(cpu_total, 0) end while #cpu_active < #cpu_lines do table.insert(cpu_active, 0) end while #cpu_usage < #cpu_lines do table.insert(cpu_usage, 0) end ---- Setup tables total_new = {} active_new = {} diff_total = {} diff_active = {} for i,v in ipairs(cpu_lines) do ---- Calculate totals total_new[i] = 0 for j = 2, #v do total_new[i] = total_new[i] + v[j] end active_new[i] = v[2] + v[3] + v[4] ---- Calculate percentage diff_total[i] = total_new[i] - cpu_total[i] diff_active[i] = active_new[i] - cpu_active[i] cpu_usage[i] = math.floor(diff_active[i] / diff_total[i] * 100) ---- Store totals cpu_total[i] = total_new[i] cpu_active[i] = active_new[i] end if padding ~= nil then for k,v in pairs(cpu_usage) do if type(padding) == "table" then p = padding[k] else p = padding end cpu_usage[k] = helper.padd(cpu_usage[k], p) end end return cpu_usage end widget_cache[widgets.cpu] = {} -- }}} ---- {{{ Memory widget type function widgets.mem(format, padding) -- Return MEM usage values local f = io.open('/proc/meminfo') ---- Get data for line in f:lines() do line = helper.splitbywhitespace(line) if line[1] == 'MemTotal:' then mem_total = math.floor(line[2]/1024) elseif line[1] == 'MemFree:' then free = math.floor(line[2]/1024) elseif line[1] == 'Buffers:' then buffers = math.floor(line[2]/1024) elseif line[1] == 'Cached:' then cached = math.floor(line[2]/1024) end end f:close() ---- Calculate percentage mem_free=free+buffers+cached mem_inuse=mem_total-mem_free mem_usepercent = math.floor(mem_inuse/mem_total*100) if padding then if type(padding) == "table" then mem_usepercent = helper.padd(mem_usepercent, padding[1]) mem_inuse = helper.padd(mem_inuse, padding[2]) mem_total = helper.padd(mem_total, padding[3]) mem_free = helper.padd(mem_free, padding[4]) else mem_usepercent = helper.padd(mem_usepercent, padding) mem_inuse = helper.padd(mem_inuse, padding) mem_total = helper.padd(mem_total, padding) mem_free = helper.padd(mem_free, padding) end end return {mem_usepercent, mem_inuse, mem_total, mem_free} end widget_cache[widgets.mem] = {} -- }}} ---- {{{ Swap widget type function widgets.swap(format, padding) -- Return SWAP usage values local f = io.open('/proc/meminfo') ---- Get data for line in f:lines() do line = helper.splitbywhitespace(line) if line[1] == 'SwapTotal:' then swap_total = math.floor(line[2]/1024) elseif line[1] == 'SwapFree:' then free = math.floor(line[2]/1024) elseif line[1] == 'SwapCached:' then cached = math.floor(line[2]/1024) end end f:close() ---- Calculate percentage swap_free=free+cached swap_inuse=swap_total-swap_free swap_usepercent = math.floor(swap_inuse/swap_total*100) if padding then if type(padding) == "table" then swap_usepercent = helper.padd(swap_usepercent, padding[1]) swap_inuse = helper.padd(swap_inuse, padding[2]) swap_total = helper.padd(swap_total, padding[3]) swap_free = helper.padd(swap_free, padding[4]) else swap_usepercent = helper.padd(swap_usepercent, padding) swap_inuse = helper.padd(swap_inuse, padding) swap_total = helper.padd(swap_total, padding) swap_free = helper.padd(swap_free, padding) end end return {swap_usepercent, swap_inuse, swap_total, swap_free} end widget_cache[widgets.swap] = {} -- }}} ---- {{{ Date widget type function widgets.date(format) -- Get format if format == nil then return os.date() else return os.date(format) end end -- }}} ---- {{{ Filesystem widget type function widgets.fs(format, padding) local f = io.popen('df -hP') local args = {} for line in f:lines() do vars = helper.splitbywhitespace(line) if vars[1] ~= 'Filesystem' and #vars == 6 then vars[5] = vars[5]:gsub('%%','') if padding then if type(padding) == "table" then vars[2] = helper.padd(vars[2], padding[1]) vars[3] = helper.padd(vars[3], padding[2]) vars[4] = helper.padd(vars[4], padding[3]) vars[5] = helper.padd(vars[5], padding[4]) else vars[2] = helper.padd(vars[2], padding) vars[3] = helper.padd(vars[3], padding) vars[4] = helper.padd(vars[4], padding) vars[5] = helper.padd(vars[5], padding) end end args['{'..vars[6]..' size}'] = vars[2] args['{'..vars[6]..' used}'] = vars[3] args['{'..vars[6]..' avail}'] = vars[4] args['{'..vars[6]..' usep}'] = vars[5] end end f:close() return args end -- }}} ---- {{{ Net widget type function widgets.net(format, padding) local f = io.open('/proc/net/dev') args = {} for line in f:lines() do line = helper.splitbywhitespace(line) local p = line[1]:find(':') if p ~= nil then name = line[1]:sub(0,p-1) line[1] = line[1]:sub(p+1) if tonumber(line[1]) == nil then line[1] = line[2] line[9] = line[10] end if padding then args['{'..name..' rx}'] = helper.bytes_to_string(line[1], nil, padding) args['{'..name..' tx}'] = helper.bytes_to_string(line[9], nil, padding) else args['{'..name..' rx}'] = helper.bytes_to_string(line[1]) args['{'..name..' tx}'] = helper.bytes_to_string(line[9]) end args['{'..name..' rx_b}'] = math.floor(line[1]*10)/10 args['{'..name..' tx_b}'] = math.floor(line[9]*10)/10 args['{'..name..' rx_kb}'] = math.floor(line[1]/1024*10)/10 args['{'..name..' tx_kb}'] = math.floor(line[9]/1024*10)/10 args['{'..name..' rx_mb}'] = math.floor(line[1]/1024/1024*10)/10 args['{'..name..' tx_mb}'] = math.floor(line[9]/1024/1024*10)/10 args['{'..name..' rx_gb}'] = math.floor(line[1]/1024/1024/1024*10)/10 args['{'..name..' tx_gb}'] = math.floor(line[9]/1024/1024/1024*10)/10 if nets[name] == nil then nets[name] = {} args['{'..name..' down}'] = 'n/a' args['{'..name..' up}'] = 'n/a' args['{'..name..' down_b}'] = 0 args['{'..name..' up_b}'] = 0 args['{'..name..' down_kb}'] = 0 args['{'..name..' up_kb}'] = 0 args['{'..name..' down_mb}'] = 0 args['{'..name..' up_mb}'] = 0 args['{'..name..' down_gb}'] = 0 args['{'..name..' up_gb}'] = 0 nets[name].time = os.time() else interval = os.time()-nets[name].time nets[name].time = os.time() down = (line[1]-nets[name][1])/interval up = (line[9]-nets[name][2])/interval if padding then args['{'..name..' down}'] = helper.bytes_to_string(down, true, padding) args['{'..name..' up}'] = helper.bytes_to_string(up, true, padding) else args['{'..name..' down}'] = helper.bytes_to_string(down, true) args['{'..name..' up}'] = helper.bytes_to_string(up, true) end args['{'..name..' down_b}'] = math.floor(down*10)/10 args['{'..name..' up_b}'] = math.floor(up*10)/10 args['{'..name..' down_kb}'] = math.floor(down/1024*10)/10 args['{'..name..' up_kb}'] = math.floor(up/1024*10)/10 args['{'..name..' down_mb}'] = math.floor(down/1024/1024*10)/10 args['{'..name..' up_mb}'] = math.floor(up/1024/1024*10)/10 args['{'..name..' down_gb}'] = math.floor(down/1024/1024/1024*10)/10 args['{'..name..' up_gb}'] = math.floor(up/1024/1024/1024*10)/10 end nets[name][1] = line[1] nets[name][2] = line[9] end end f:close() return args end widget_cache[widgets.net] = {} -- }}} ---- {{{ Uptime widget type function widgets.uptime(format, padding) --Get uptime from /proc/uptime local f = io.open("/proc/uptime") uptime_line = f:read() f:close() args = {} --/proc/uptime has the format " " if uptime_line:find(" ") ~= nil then pend = uptime_line:find(" ",0,true) uptime_line_part = uptime_line:sub(0,pend-1) total_uptime = math.floor( tonumber(uptime_line_part) ) uptime_days = math.floor( total_uptime / (3600 * 24) ) uptime_hours = math.floor( ( total_uptime % (3600 * 24) ) / 3600 ) uptime_minutes = math.floor( ( ( total_uptime % (3600 * 24) ) % 3600 ) / 60 ) uptime_seconds = math.floor( ( ( total_uptime % (3600 * 24) ) % 3600) % 60 ) if padding then if type(padding) == "table" then total_uptime = helper.padd(total_uptime , padding[1]) uptime_days = helper.padd(uptime_days , padding[2]) uptime_hours = helper.padd(uptime_hours , padding[3]) uptime_minutes = helper.padd(uptime_minutes , padding[4]) uptime_seconds = helper.padd(uptime_seconds , padding[5]) else total_uptime = helper.padd(total_uptime , padding) uptime_days = helper.padd(uptime_days , padding) uptime_hours = helper.padd(uptime_hours , padding) uptime_minutes = helper.padd(uptime_minutes , padding) uptime_seconds = helper.padd(uptime_seconds , padding) end end end return {total_uptime, uptime_days, uptime_hours, uptime_minutes, uptime_seconds} end widget_cache[widgets.uptime] = {} -- }}} -- For backwards compatibility: custom function widgets["function"] = function () return {} end -- }}} ---- {{{ Main functions ---- {{{ Register widget function register(widget, wtype, format, timer, field, padd) local reg = {} local widget = widget -- Set properties reg.type = wtype reg.format = format reg.timer = timer reg.field = field reg.padd = padd reg.widget = widget -- Update function reg.update = function () update(widget, reg) end -- Default to timer=1 if reg.timer == nil then reg.timer = 1 end -- Allow using a string widget type if type(reg.type) == "string" then reg.type = widgets[reg.type] end -- Register reg object regregister(reg) -- Return reg object for reuse return reg end -- }}} -- {{{ Register from reg object function regregister(reg) if not reg.running then -- Put widget in table if registered[reg.widget] == nil then registered[reg.widget] = {} table.insert(registered[reg.widget], reg) else already = false for w, i in pairs(registered) do if w == reg.widget then for k,v in pairs(i) do if v == reg then already = true break end end if already then break end end end if not already then table.insert(registered[reg.widget], reg) end end -- Start timer if reg.timer > 0 then awful.hooks.timer.register(reg.timer, reg.update) end -- Initial update reg.update() -- Set running reg.running = true end end -- }}} -- {{{ Unregister widget function unregister(widget, keep, reg) if reg == nil then for w, i in pairs(registered) do if w == widget then for k,v in pairs(i) do reg = unregister(w, keep, v) end end end return reg end if not keep then for w, i in pairs(registered) do if w == widget then for k,v in pairs(i) do if v == reg then table.remove(registered[w], k) end end end end end awful.hooks.timer.unregister(reg.update) reg.running = false return reg end -- }}} -- {{{ Suspend wicked, halt all widget updates function suspend() for w, i in pairs(registered) do for k,v in pairs(i) do unregister(w, true, v) end end end -- }}} -- {{{ Activate wicked, restart all widget updates function activate(widget) for w, i in pairs(registered) do if widget == nil or w == widget then for k,v in pairs(i) do regregister(v) end end end end -- }}} -- {{{ Enable caching for a widget type function enable_caching(widget) if widget_cache[widget] == nil then widget_cache[widget] = {} end end -- }}} ---- {{{ Update widget function update(widget, reg, disablecache) -- Check if there are any equal widgets if reg == nil then for w, i in pairs(registered) do if w == widget then for k,v in pairs(i) do update(w, v, disablecache) end end end return end local t = os.time() local data = {} -- Check if we have output chached for this widget, -- newer than last widget update. if widget_cache[reg.type] ~= nil then local c = widget_cache[reg.type] if c.time == nil or c.time <= t-reg.timer or disablecache then c.time = t c.data = reg.type(reg.format, reg.padd) end data = c.data else data = reg.type(reg.format, reg.padd) end if type(data) == "table" then if type(reg.format) == "string" then data = helper.format(reg.format, data) elseif type(reg.format) == "function" then data = reg.format(widget, data) end end if reg.field == nil then widget.text = data elseif widget.plot_data_add ~= nil then widget:plot_data_add(reg.field, tonumber(data)) elseif widget.bar_data_add ~= nil then widget:bar_data_add(reg.field, tonumber(data)) end return data end -- }}} -- }}} -- vim: set filetype=lua fdm=marker tabstop=4 shiftwidth=4 nu: awesome-extra/revelation/0000755000000000000000000000000011765367511012711 5ustar awesome-extra/revelation/init.lua0000644000000000000000000001203211734355103014343 0ustar -- revelation.lua -- -- Library that implements Expose like behavior. -- -- @author Perry Hargrave resixian@gmail.com -- @author Espen Wiborg espenhw@grumblesmurf.org -- @author Julien Danjou julien@danjou.info -- -- @copyright 2008 Espen Wiborg, Julien Danjou -- local awful = require('awful') local aw_rules = require('awful.rules') local pairs = pairs local setmetatable = setmetatable local table = table local capi = { tag = tag, client = client, keygrabber = keygrabber, mousegrabber = mousegrabber, mouse = mouse, screen = screen } local clientData = {} -- table that holds the positions and sizes of floating clients module("revelation") config = { -- Name of expose tag. tag_name = "Revelation", -- Match function can be defined by user. -- Must accept a `rule` and `client` and return `boolean`. -- The rule forms follow `awful.rules` syntax except we also check the -- special `rule.any` key. If its true, then we use the `match.any` function -- for comparison. match = { exact = aw_rules.match, any = aw_rules.match_any }, } -- Executed when user selects a client from expose view. -- -- @param restore Function to reset the current tags view. function selectfn(restore) return function(c) restore() -- Pop to client tag awful.tag.viewonly(c:tags()[1], c.screen) -- Focus and raise capi.client.focus = c c:raise() end end -- Tags all matching clients with tag t -- @param rule The rule. Conforms to awful.rules syntax. -- @param clients A table of clients to check. -- @param t The tag to give matching clients. function match_clients(rule, clients, t) local mf = rule.any and config.match.any or config.match.exact for _, c in pairs(clients) do if mf(c, rule) then -- Store geometry before setting their tags if awful.client.floating.get(c) then clientData[c] = c:geometry() awful.client.floating.set(c, false) end awful.client.toggletag(t, c) c.minimized = false end end return clients end -- Arrow keys and 'hjkl' move focus, Return selects, Escape cancels. Ignores -- modifiers. -- -- @param restore a function to call if the user presses escape -- @return keyboardhandler function keyboardhandler (restore) return function (mod, key, event) if event ~= "press" then return true end -- translate vim-style home keys to directions if key == "j" or key == "k" or key == "h" or key == "l" then if key == "j" then key = "Down" elseif key == "k" then key = "Up" elseif key == "h" then key = "Left" elseif key == "l" then key = "Right" end end -- if key == "Escape" then restore() return false elseif key == "Return" then selectfn(restore)(capi.client.focus) return false elseif key == "Left" or key == "Right" or key == "Up" or key == "Down" then awful.client.focus.bydirection(key:lower()) end return true end end -- Implement Exposé (ala Mac OS X). -- -- @param rule A table with key and value to match. [{class=""}] -- @param s The screen to consider clients of. [mouse.screen]. function expose(rule, s) local rule = rule or {class=""} local scr = s or capi.mouse.screen local t = awful.tag.new({config.tag_name}, scr, awful.layout.suit.fair)[1] awful.tag.viewonly(t, t.screen) match_clients(rule, capi.client.get(scr), t) local function restore() awful.tag.history.restore() t.screen = nil capi.keygrabber.stop() capi.mousegrabber.stop() for _, c in pairs(capi.client.get(src)) do if clientData[c] then c:geometry(clientData[c]) -- Restore positions and sizes awful.client.floating.set(c, true) end end end capi.keygrabber.run(keyboardhandler(restore)) local pressedMiddle = false capi.mousegrabber.run(function(mouse) local c = awful.mouse.client_under_pointer() if mouse.buttons[1] == true then selectfn(restore)(c) return false elseif mouse.buttons[2] == true and pressedMiddle == false and c ~= nil then -- is true whenever the button is down. pressedMiddle = true -- extra variable needed to prevent script from spam-closing windows c:kill() return true elseif mouse.buttons[2] == false and pressedMiddle == true then pressedMiddle = false end return true --Strange but on my machine only fleur worked as a string. --stole it from --https://github.com/Elv13/awesome-configs/blob/master/widgets/layout/desktopLayout.lua#L175 end,"fleur") end setmetatable(_M, { __call = function(_, ...) return expose(...) end }) awesome-extra/revelation/README.md0000644000000000000000000000561611765367511014200 0ustar # revelation.lua Provides Mac OSX like 'Expose' view of all clients. ## Use ### Installation (From user's awesome configuration directory, usually ~/.config/awesome) 1. Clone repository: git clone https://github.com/bioe007/awesome-revelation.git 2. put near the top of your rc.lua `require("revelation")` 3. Make a global keybinding (ModKey + e) for revelation in your rc.lua: globalkeys = awful.util.table.join( awful.key({ modkey, }, "Left", awful.tag.viewprev ), awful.key({ modkey, }, "Right", awful.tag.viewnext ), awful.key({ modkey, }, "Escape", awful.tag.history.restore), awful.key({ modkey}, "e", revelation), -- Insert this line awful.key({ modkey, }, "j", function () awful.client.focus.byidx( 1) if client.focus then client.focus:raise() end end), **NOTE:** Always double check this key binding syntax against the version of Awesome that you are using. 4. Reload rc.lua and try the keybinding __Modkey + e__ It should bring all clients to the current tag and set the layout to fair. You can focus clients with __cursor__ or __hjkl__ keys then press __Enter__ or press the mouse right button to select or __Escape__ to abort. This is a modification of the original awesome library that implemented expose like behavior. ### Configuration Revelation's configuration is done through direct access to the module's `config` table. There are two basic settings, shown with default values: -- The name of the tag created for the 'exposed' view revelation.config.tag_name = 'Revelation' -- A table of matcher functions (used in client filtering) revelation.match.exact = awful.rules.match revelation.match.any = awful.rules.match_any The rule matching functions must conform to `awful.rules.match` prototypes. For client matching rules, we follow the same syntax as awful.rules with one perk; if `rule.any == true`, then we call the `config.match.any` function. ### Examples All clients: awful.key({modkey}, "e", revelation) To match all urxvt terminals: awful.key({modkey}, "e", function() revelation({class="URxvt"}) end) To match clients with class 'foo' or 'bar': awful.key({modkey}, "e", function() revelation({ class={"foo", "bar"}, any=true }) end) ## Credits ### Maintenance * Perry Hargrave ### Contributions, many thanks! * Nikola Petrov ### Original authors * Espen Wiborg * Julien Danjou ## License Revelation is released under the GNU General Public License, version 3. (c) 2009-12 Perry Hargrave (c) 2008 Espen Wiborg, Julien Danjou awesome-extra/revelation/LICENSE0000644000000000000000000001674311765367511013731 0ustar GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. awesome-extra/vicious/0000755000000000000000000000000011765367633012227 5ustar awesome-extra/vicious/CHANGES0000644000000000000000000003543011765367633013227 0ustar --------------------------------------------------- Full changelog is available online: http://git.sysphere.org/vicious/log/?showmsg=1 --------------------------------------------------- f972955 README: update thermal documentation 5605030 thermal: change coretemp default, allow file as widget argument 7a3699c division by zero, if battery is full charged b11bb78 hddtemp: fix curl hang in version 7.24.0 73db82b README: add format function example for overriding symbols 7e81bb8 cpufreq: differentiate between ondemand and conservative 6f42ee5 README: update wtype argument explanation 45c6eba bat: fix time calculation, bug introduced in 350e924 cd4b04d thermal: remove unnecessary read 350e924 bat: another workaround for broken ACPI implementations eeb27a2 [cpu] fix division by zero 059442d net: sanitize time computation to avoid division by zero 25b375b [pulse] round volume to integer 18e1823 vicious: cleanup tabs and bad intendation cf996f2 [net] calculate time in a more clean way f1844de Allocate reg table with all values in one shot b11d251 README: provide multigraph usage example 44aea37 bat: better fix for missing rate in 31d7b2f e01a8eb vicious: document mem.bcuse 1384b69 mem: provide mem.bcuse for Gabriel 324563e Next release, tag 2.0.3 dcc2b60 vicious: load widget modules only when needed 06e8f7c mpd: allow named keys or positional arguments 729ceb7 dio: import string.match() c2f7fbc dio: provide stats for all devices, rewritten by Joerg 6522f58 cpu: another 10 percent optimization from Joerg 753ce61 cpu: calculation and optimization fixes by Joerg f85d944 gmail: fixed misleading comment 31d7b2f bat: fixed "no such device" for current and power d385843 helpers: properly handle magic characters 6ddad31 bat: added power_now support fd0718e contrib: added a README with pulse.lua documented 9f4302c contrib: rewrite pulse module 5160cfe Next release, tag 2.0.2 add54f8 README: added missing register() documentation fe2e432 TODO: fix contrib/sensors for Ian 7625933 wifi: proper fix for SSID regexp 7f7a94d gmail: inbox is now default 82eb67b wifi: removed spurious bracket from SSID regexp 304fa33 wifi: properly handle disconnects 32a7be1 wifi: provide link quality in percent c532c0b contrib: fixed email of pulse widget author 49b0913 wifi: improved SSID regular expression 932bd8d init: emit timeout instead of forced update fbd2af7 init: add set_markup support e51d8ac date: turn time widget argument into an offset c6085ee date: accept time as a widget argument a9d6ea2 init: add connect_signal support, patch by Uli 86a1394 README: update contrib information fbfcc49 init: comment connect_signal for users of awesome master 1d7f646 pkg: description updated 88c3d0c contrib: use pcall for luasocket in pop b200a80 contrib: dont import pop - requires luasocket 0350ec9 TODO: document contrib widgets f8a8696 contrib: imported POP3 widget from Boris 1a443cd init: import contrib widgets, commented 26b0395 contrib: imported contrib widgets 0d6333e Next release, tag 2.0.1 1534951 mpd: added some optional stats, commented 4113d37 pkg: include FreeBSD support fc46e7a TODO: solid multigraph support needed d912663 net: add operational state support 8674c91 dio: add partition support d6faae1 TODO: remove org-mode extension 6171734 TODO: added the carrier detection todo 6d6e98a TODO: included the todo file to encourage contribution ca1d8d7 README: cut on the security crap fdae848 raid: removed permanent stats storage 3e12875 pkg: include Mandriva support 64e5426 uptime: simplified system load regexp 448275a widgets: reuse existing datasets where appropriate a9347ec raid: import raid state widget type by Hagen 9af29ce pkg: aptitude alternative to apt-show-versions 94a60fb bat: fixed module description 338a2ee Next release, tag 2.0.0 0299c15 widgets: minor cleanup before a tag in cpuinf, fs, mbox... 4fc6dff wifi: return 0 not N/A when channel is unavailable f50ad21 thermal: function argument is already local 4f86e28 os: merge with entropy widget type 49b1b09 helpers: index subdirectories in pathtotable() 7cbf987 bat: fix battery detection a4bd307 README: updated link to contrib 4dad2e3 API: missing warg should not break awesome 237470c API: transform widgets namespace table to a directory 9a82d41 init: never pass string to awful.widget widgets 3ac4fcf init: missing widget type should not break awesome febc91d hddtemp: minor style changes 9338cb9 cpuinf: rewritten and optimized 96a8e55 Make use of io.lines() where appropriate 6441db0 README: added a list of needed utilities 06a455a README: add contributors to Authors section 178a7eb README: added contrib and vicious-fbsd information 0dd5b72 README: standardize quotes 8482b54 mpd: rewritten and now uses curl not mpc dda51b1 net: remove redudant string.match call 1abb451 Next release, tag 1.0.26 6898d4a dio: add I/O scheduler support 71f21f3 fs: use -l not --local for portability edb4619 os: import operating system information widget de15934 fs: further improve the regexp 3178068 mem: rewrite and simplify 77d1a0b gmail: switch to ~/.netrc for login storage 1c0ceff gmail: don't break on non-escaped chars, quote login abacd77 fs: include available space in percent, requested by Jon 94e7ed1 fs: rewritten, less prone to error fa40e40 init: never pass nil into awful.widget widgets 6f79227 Next release, tag 1.0.25 f34bfaf fs: fix the bug reported by Alex Tergeland 5f41c7a init: do not use keyword type for user data ee64644 API: added force() function to force update widgets 95e9a77 API: regregister() and update() are not exposed ff050a0 README: link to the "Widgets in awesome" document 5226d10 API: function enable_caching() is now cache() 9371839 volume: added real mute support dbd6c7b weather: capitalize weather and sky stats 2c6b969 weather: calculate degree Celsius from Fahrenheit ad14818 helpers: import capitalize 0ab8311 wifi: properly handle iwconfig PATH differences 4fa87fa wifi: properly handle non-existant interface 9eef646 git: ignore file removed 4664bee mdir: fix module description 57004c0 Next release, tag 1.0.24 b96cb98 bat: added a note about Apple PMU and ACPI/procfs 23d09f0 README: added the Security section e29ea62 helpers: uformat helper replaces formatting done by widgets f4cd746 pkg: solve interactive pacman prompt patch from tdy 5e1d1e0 volume: suggest appending card ID or other options 24f23fa gmail: reworked feed handling and changed username format 6c34e85 thermal: added support for procfs and coretemp 355c838 Next release, tag 1.0.23 0f3123e README: added textbox fixed width example 3095ffb pkg: added apt and yum to pkg managers table 91925e6 pkg: pacman moved to generic packages module 71566e0 dio: further improved support for multiple devices 8fe4cf4 net: sanitize time computation to avoid division by zero d2a00d7 Next release, tag 1.0.22 15dd6ea vicious: update copyright 9e37225 pacman: remove 3.2 example, add ignores+deps example cedf171 wifi: return numbers without notations fba4db6 weather: fix parsing of negative temperatures 2100ea1 Next release, tag 1.0.21 9b5efc7 cpu: simplified table initialization 9150063 dio: preliminary support for multiple devices b4031d2 dio: return separated read and write statistics 2c900fa README: minor changes in Format functions c870691 fs: switched to 1K blocks and new keys 5cbd759 net: move formatting out of the worker 14d69f6 net: minor coding style change db82c2a Next release, tag 1.0.20 3834caa hddtemp: fixed support for multiple devices 1790abb hddtemp: adapt regex to match disks like /dev/sg0 2492945 fs: minor coding style change f5b47dc mdir: support for multiple directories 1d0cfd3 Cleanup widgets that use pathtotable helper 76942d1 helpers: simplify pathtotable, patch by filmor 26c1f07 Next release, tag 1.0.19 2e9b811 README: document new truncate and scroll usage d0aa48a entropy: widget rewritten, poolsize no longer an argument 493150c uptime: merged with load widget type 7be560b bat: widget rewritten for sysfs a99c1cf cpufreq: widget rewritten, governor symbols enabled 5f9818f dio: widget type rewritten 92be5fb thermal: widget rewritten for sysfs 46d52fa helpers: import pathtotable eb661f6 batsys: add note about other charge/rate sources 6fadee6 batsys: don't return 0 if only rate is missing 8e21d26 batat: widget type removed, now available in the contrib branch e66e507 batsys: import battery widget that uses sysfs 896df4d De-obfuscate e-mail address 94cf0b7 Minor changes in mboxc and org 44d943d gmail: add scrolling support and truncate control 9e91408 mbox: add scrolling support and truncate control 5ff8927 mpd: add scrolling support and truncate control 589feb1 helpers: import scroll from Remy Clouard 0d73f6d Ensure returned numbers are of type number b105ae2 README: updated net description 3dc7c5e net: unit formatting delegated to a function 5c6f544 README: more information in Power section 40d7881 Adapt to awful.widget.graph max_value of 1 25ce79e batat: better returns when handling insufficient data baa3612 Next release, tag 1.0.18 97d2ecb bat: better returns when handling insufficient data 4d1af1e bat: better fix for ACPI, from bioe007 2cfdd5a bat: quick fix for broken BAT/ACPI implementations 64464ef README: removed obsolete widget names 11985f6 README: added padding example feca5da mem: tonumber is redudant 7f3d31e uptime: fixed problem discovered by jabbas 65e57fa README: document tables returned by widget types 893a85c README: caching documentation improved 00e7b2d README: fixed disk i/o warg documentation 0eea1a1 cpu: simplified CPU identification e252fd9 Next release, tag 1.0.17 a2b9de4 mem: widget type rewritten c84f515 mbox: read a 30kb chunk by default 4602ca2 Lots of coding style changes af4e85f bat: added a handler for incompetent users fcf1027 cpufreq: use string library for find/match b4e028b Removed some useless else statements b65d509 Reworked counters in mboxc, mdir, org b185e96 mbox: don't hide when there is no mail 724366c Reworked some variables in entropy, load, mpd, net, init 643ecb0 date: function simplified 3d97d44 cpuinf: prepend 'cpu' to CPU ID in table keys 0d5f07b README: included 'Other uses' section 9d518b8 volume: added mute support ddf9646 thermal: added some comments 0e863a5 bat: coding style changes 44f95c3 cpufreq: widget type rewritten aed9245 README: fixed some typos f933566 README: updated gmail information f99a74b gmail: count all unread messages 5dac6a4 mboxc: support for multiple mbox files 32fe770 README: fixes from git-diff --check b0f737e Rewrote all headers 8e544fd Next release, tag 1.0.16 b8f288b README: clarified caching usage 46a7241 README: added more caching information eadf0c9 Caching is controlled by users 0945724 README: minor fix in mem widget example 51d5255 README: include pbar/graph properties in examples c9fba4e Widgets derived from wicked include a notice ba6dfae Next release, tag 1.0.15 1707bc6 README: rewritten and now includes the "Power" section e205d66 CHANGES: changelog update 9ca9e2f Next release, tag 1.0.14 68b30a3 init: Default to 2s timer bc3cf45 README: mpd format function simplified 7410bc0 Entropy widget cleaned up 549c8bc Remote file systems in fs widget are optional 2a5126f General cleanup 4f3599d README: fixed CPU widget example 1603b5f Curl connect timeout 1s, max time 3s a950bd9 Next release, tag 1.0.13 161607e Gmail widget included e5c980e CHANGES file switched to 'oneline' short format fbc3f14 Updated links in the README 13527a3 Match all punctuation chars in fs partitions and mount points. 0ca1fd3 Match punctuation characters in wifi SSID. cb36f74 Next release, tag 1.0.12. 11b433c README updated in preparation for release 1.0.12. 2cc4e97 Removed deprecated data field. e7c2e2c Updated graphs and pbars for the upcoming awesome 3.4 853fafc Updated timers for the upcoming awesome 3.4 53b2799 Next release, tag 1.0.11. c283edc Updated link to wicked home. 0067dca Removed emtpy lines from mpd.lua 5e3b953 Link to wicked and add Joerg as contributor. 4330375 Next release, tag 1.0.10. 44cd53f Updated the CHANGES file in preparation for a new tag. 7ad474b Use of LANG=C and improved matching in fs.lua. f8eb93a Mention ICAO as the wanted code in the weather widget. 376591e Added laptop-mode note to the README. e5181cc Next release, tag 1.0.9. 03693e7 Renamed unused loop identifiers to _ 9f75b0d Spurious folds removed from helpers. 41d4acb Truncate helper, txtlen is local. 3b3e0dc CHANGES file updated. Will probably switch to shortlog. d4595bb All worker functions are local. 8b38567 Added missing poolsize info to the README + minor change in fs.lua 798036e Changed fs widget type description. 8d59a01 Next release, tag 1.0.8. d2d244f CPU Information widget included. cbd9a53 Next release, tag 1.0.7. 013dd08 HDD Temperature widget included. 515cc0d Weather widget switched to curl. 477b8d2 CHANGES file updated before the next push. f14280b Pacman widget updated for pacman 3.3. b46278a Lower the wget timeout to 3s in weather.lua eaf8470 Cleaned up sample widgets in the README 44aea40 Remove a spurious comment from helpers.lua 3c76e0d Introduced the truncate helper. 2d0cbf5 Fixed the weather widget, wind km/h was broken. 4c74de7 Padding removed, along with deprecated helper functions. 2d4efa6 Minor cleanup in init.lua 22033ba Disallow using a string widget type. 756215f Next release, tag 1.0.6. 5909d9e Updated the CHANGES file in preparation for tag v1.0.6. cef569b CPU frequency widget included. 3fe67d4 Coding style changes in entropy, load, thermal, uptime. 09fda0a Rewrite of the escape helper. 047dba0 Next release, version/tag 1.0.5. cad950a Updated the CHANGES file in preparation for tag v1.0.5. 418151f Make all widgets return their worker functions when called. 1630b78 Added wind speed in km/h to the weather widget. f841c54 Updated the CHANGES file. 3f851ff Added a note about weather symbols to the weather widget. 1b99061 Use utf symbols for some bat states. Mention LuaFileSystem in mdir.lua f00558c Next release, version 1.0.4. 475da04 Mbox mail count widget included. dad393b Updated the CHANGES file. bc63706 Coding style fixes in battery widgets. 052748a Fix the key reference to custom keys in the README 9c973a5 Updated the CHANGES file. 51770fe Fixed README and moved the ChangeLog to CHANGES. 2ab90de Updated the ChangeLog file, for v1.0.3. 0471c6a Next release, version 1.0.3. a8dc5c6 Added basic documentation as a README file. b06a5b6 Make git ignore org-mode files and archives. 87d895f Next release, version 1.0.2. 5ff480d Updated the ChangeLog file in preparation for a new version. 2921200 Added handlers to batat and fixed the battery_state table. e2d503e Added a new, standalone, battery widget. 19ca7b5 Replaced TODO with Todo in helpers. 9cd250b Fixed batat module name and expanded bat states and symbols. b331cb1 Updated the ChangeLog file. 76b8978 Battery widget moved to batat.lua in preparation for a new bat widget. 9da374d Updated the ChangeLog file. 1f31527 Next release, version 1.0.1. 11baa09 Added the ChangeLog file. 3eefddf Weather widget written and included, by request. 95dd8de Make git ignore backup files and lua binaries. 98e26ee Import of vicious source tree. awesome-extra/vicious/widgets/0000755000000000000000000000000011765367633013675 5ustar awesome-extra/vicious/widgets/mem.lua0000644000000000000000000000341011651220736015136 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) 2009, Lucas de Vries --------------------------------------------------- -- {{{ Grab environment local io = { lines = io.lines } local setmetatable = setmetatable local math = { floor = math.floor } local string = { gmatch = string.gmatch } -- }}} -- Mem: provides RAM and Swap usage statistics module("vicious.widgets.mem") -- {{{ Memory widget type local function worker(format) local mem = { buf = {}, swp = {} } -- Get MEM info for line in io.lines("/proc/meminfo") do for k, v in string.gmatch(line, "([%a]+):[%s]+([%d]+).+") do if k == "MemTotal" then mem.total = math.floor(v/1024) elseif k == "MemFree" then mem.buf.f = math.floor(v/1024) elseif k == "Buffers" then mem.buf.b = math.floor(v/1024) elseif k == "Cached" then mem.buf.c = math.floor(v/1024) elseif k == "SwapTotal" then mem.swp.t = math.floor(v/1024) elseif k == "SwapFree" then mem.swp.f = math.floor(v/1024) end end end -- Calculate memory percentage mem.free = mem.buf.f + mem.buf.b + mem.buf.c mem.inuse = mem.total - mem.free mem.bcuse = mem.total - mem.buf.f mem.usep = math.floor(mem.inuse / mem.total * 100) -- Calculate swap percentage mem.swp.inuse = mem.swp.t - mem.swp.f mem.swp.usep = math.floor(mem.swp.inuse / mem.swp.t * 100) return {mem.usep, mem.inuse, mem.total, mem.free, mem.swp.usep, mem.swp.inuse, mem.swp.t, mem.swp.f, mem.bcuse } end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/org.lua0000644000000000000000000000367011651220347015155 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) org-awesome, Damien Leone --------------------------------------------------- -- {{{ Grab environment local io = { lines = io.lines } local setmetatable = setmetatable local string = { find = string.find } local os = { time = os.time, date = os.date } -- }}} -- Org: provides agenda statistics for Emacs org-mode module("vicious.widgets.org") -- {{{ OrgMode widget type local function worker(format, warg) if not warg then return end -- Compute delays local today = os.time{ year=os.date("%Y"), month=os.date("%m"), day=os.date("%d") } local soon = today + 24 * 3600 * 3 -- 3 days ahead is close local future = today + 24 * 3600 * 7 -- 7 days ahead is maximum -- Initialize counters local count = { past = 0, today = 0, soon = 0, future = 0 } -- Get data from agenda files for i=1, #warg do for line in io.lines(warg[i]) do local scheduled = string.find(line, "SCHEDULED:") local closed = string.find(line, "CLOSED:") local deadline = string.find(line, "DEADLINE:") if (scheduled and not closed) or (deadline and not closed) then local b, e, y, m, d = string.find(line, "(%d%d%d%d)-(%d%d)-(%d%d)") if b then local t = os.time{ year = y, month = m, day = d } if t < today then count.past = count.past + 1 elseif t == today then count.today = count.today + 1 elseif t <= soon then count.soon = count.soon + 1 elseif t <= future then count.future = count.future + 1 end end end end end return {count.past, count.today, count.soon, count.future} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/date.lua0000644000000000000000000000125511651220347015300 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) 2009, Lucas de Vries --------------------------------------------------- -- {{{ Grab environment local setmetatable = setmetatable local os = { date = os.date, time = os.time } -- }}} -- Date: provides access to os.date with optional time formatting module("vicious.widgets.date") -- {{{ Date widget type local function worker(format, warg) return os.date(format or nil, warg and os.time()+warg or nil) end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/net.lua0000644000000000000000000000517611651220736015161 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) 2009, Lucas de Vries --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local os = { time = os.time } local io = { lines = io.lines } local setmetatable = setmetatable local string = { match = string.match } local helpers = require("vicious.helpers") -- }}} -- Net: provides state and usage statistics of all network interfaces module("vicious.widgets.net") -- Initialize function tables local nets = {} -- Variable definitions local unit = { ["b"] = 1, ["kb"] = 1024, ["mb"] = 1024^2, ["gb"] = 1024^3 } -- {{{ Net widget type local function worker(format) local args = {} -- Get NET stats for line in io.lines("/proc/net/dev") do -- Match wmaster0 as well as rt0 (multiple leading spaces) local name = string.match(line, "^[%s]?[%s]?[%s]?[%s]?([%w]+):") if name ~= nil then -- Received bytes, first value after the name local recv = tonumber(string.match(line, ":[%s]*([%d]+)")) -- Transmited bytes, 7 fields from end of the line local send = tonumber(string.match(line, "([%d]+)%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d$")) helpers.uformat(args, name .. " rx", recv, unit) helpers.uformat(args, name .. " tx", send, unit) -- Operational state and carrier detection local sysnet = helpers.pathtotable("/sys/class/net/" .. name) args["{"..name.." carrier}"] = tonumber(sysnet.carrier) or 0 local now = os.time() if nets[name] == nil then -- Default values on the first run nets[name] = {} helpers.uformat(args, name .. " down", 0, unit) helpers.uformat(args, name .. " up", 0, unit) else -- Net stats are absolute, substract our last reading local interval = now - nets[name].time if interval <= 0 then interval = 1 end local down = (recv - nets[name][1]) / interval local up = (send - nets[name][2]) / interval helpers.uformat(args, name .. " down", down, unit) helpers.uformat(args, name .. " up", up, unit) end nets[name].time = now -- Store totals nets[name][1] = recv nets[name][2] = send end end return args end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/init.lua0000644000000000000000000000110611651220736015323 0ustar --------------------------------------------------- -- Vicious widgets for the awesome window manager --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Setup environment local setmetatable = setmetatable local wrequire = require("vicious.helpers").wrequire -- Vicious: widgets for the awesome window manager module("vicious.widgets") -- }}} -- Load modules at runtime as needed setmetatable(_M, { __index = wrequire }) awesome-extra/vicious/widgets/cpufreq.lua0000644000000000000000000000345711765367633016056 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local setmetatable = setmetatable local string = { match = string.match } local helpers = require("vicious.helpers") -- }}} -- Cpufreq: provides freq, voltage and governor info for a requested CPU module("vicious.widgets.cpufreq") -- {{{ CPU frequency widget type local function worker(format, warg) if not warg then return end local cpufreq = helpers.pathtotable("/sys/devices/system/cpu/"..warg.."/cpufreq") local governor_state = { ["ondemand\n"] = "↯", ["powersave\n"] = "⌁", ["userspace\n"] = "¤", ["performance\n"] = "⚡", ["conservative\n"] = "⊚" } -- Default frequency and voltage values local freqv = { ["mhz"] = "N/A", ["ghz"] = "N/A", ["v"] = "N/A", ["mv"] = "N/A", } -- Get the current frequency local freq = tonumber(cpufreq.scaling_cur_freq) -- Calculate MHz and GHz if freq then freqv.mhz = freq / 1000 freqv.ghz = freqv.mhz / 1000 -- Get the current voltage if cpufreq.scaling_voltages then freqv.mv = tonumber(string.match(cpufreq.scaling_voltages, freq.."[%s]([%d]+)")) -- Calculate voltage from mV freqv.v = freqv.mv / 1000 end end -- Get the current governor local governor = cpufreq.scaling_governor -- Represent the governor as a symbol governor = governor_state[governor] or governor or "N/A" return {freqv.mhz, freqv.ghz, freqv.mv, freqv.v, governor} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/mdir.lua0000644000000000000000000000226311651220347015316 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) Maildir Biff Widget, Fredrik Ax --------------------------------------------------- -- {{{ Grab environment local io = { popen = io.popen } local setmetatable = setmetatable -- }}} -- Mdir: provides the number of new and unread messages in Maildir structures/dirs module("vicious.widgets.mdir") -- {{{ Maildir widget type local function worker(format, warg) if not warg then return end -- Initialize counters local count = { new = 0, cur = 0 } for i=1, #warg do -- Recursively find new messages local f = io.popen("find "..warg[i].." -type f -wholename '*/new/*'") for line in f:lines() do count.new = count.new + 1 end f:close() -- Recursively find "old" messages lacking the Seen flag local f = io.popen("find "..warg[i].." -type f -regex '.*/cur/.*2,[^S]*$'") for line in f:lines() do count.cur = count.cur + 1 end f:close() end return {count.new, count.cur} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/cpu.lua0000644000000000000000000000372611651220736015161 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2011, Adrian C. -- * (c) 2009, Lucas de Vries -- * (c) 2011, Jörg Thalheim --------------------------------------------------- -- {{{ Grab environment local ipairs = ipairs local io = { lines = io.lines } local setmetatable = setmetatable local math = { floor = math.floor } local table = { insert = table.insert } local string = { sub = string.sub, gmatch = string.gmatch } -- }}} -- Cpu: provides CPU usage for all available CPUs/cores module("vicious.widgets.cpu") -- Initialize function tables local cpu_usage = {} local cpu_total = {} local cpu_active = {} -- {{{ CPU widget type local function worker(format) local cpu_lines = {} -- Get CPU stats for line in io.lines("/proc/stat") do if string.sub(line, 1, 3) ~= "cpu" then break end cpu_lines[#cpu_lines+1] = {} for i in string.gmatch(line, "[%s]+([^%s]+)") do table.insert(cpu_lines[#cpu_lines], i) end end -- Ensure tables are initialized correctly for i = #cpu_total + 1, #cpu_lines do cpu_total[i] = 0 cpu_usage[i] = 0 cpu_active[i] = 0 end for i, v in ipairs(cpu_lines) do -- Calculate totals local total_new = 0 for j = 1, #v do total_new = total_new + v[j] end local active_new = total_new - (v[4] + v[5]) -- Calculate percentage local diff_total = total_new - cpu_total[i] local diff_active = active_new - cpu_active[i] if diff_total == 0 then diff_total = 1E-6 end cpu_usage[i] = math.floor((diff_active / diff_total) * 100) -- Store totals cpu_total[i] = total_new cpu_active[i] = active_new end return cpu_usage end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/cpuinf.lua0000644000000000000000000000247611651220347015655 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { lines = io.lines } local setmetatable = setmetatable local string = { gmatch = string.gmatch } -- }}} -- Cpuinf: provides speed and cache information for all available CPUs/cores module("vicious.widgets.cpuinf") -- {{{ CPU Information widget type local function worker(format) local id = nil local cpu_info = {} -- Get CPU info for line in io.lines("/proc/cpuinfo") do for k, v in string.gmatch(line, "([%a%s]+)[%s]+:[%s]([%d]+).-$") do if k == "processor" then id = v elseif k == "cpu MHz\t" or k == "cpu MHz" then local speed = tonumber(v) cpu_info["{cpu"..id.." mhz}"] = speed cpu_info["{cpu"..id.." ghz}"] = speed / 1000 elseif k == "cache size" then local cache = tonumber(v) cpu_info["{cpu"..id.." kb}"] = cache cpu_info["{cpu"..id.." mb}"] = cache / 1024 end end end return cpu_info end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/mpd.lua0000644000000000000000000000423511651220736015146 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local string = { gmatch = string.gmatch } local helpers = require("vicious.helpers") -- }}} -- Mpd: provides Music Player Daemon information module("vicious.widgets.mpd") -- {{{ MPD widget type local function worker(format, warg) local mpd_state = { ["{volume}"] = 0, ["{state}"] = "N/A", ["{Artist}"] = "N/A", ["{Title}"] = "N/A", ["{Album}"] = "N/A", ["{Genre}"] = "N/A", --["{Name}"] = "N/A", --["{file}"] = "N/A", } -- Fallback to MPD defaults local pass = warg and (warg.password or warg[1]) or "\"\"" local host = warg and (warg.host or warg[2]) or "127.0.0.1" local port = warg and (warg.port or warg[3]) or "6600" -- Construct MPD client options local mpdh = "telnet://"..host..":"..port local echo = "echo 'password "..pass.."\nstatus\ncurrentsong\nclose'" -- Get data from MPD server local f = io.popen(echo.." | curl --connect-timeout 1 -fsm 3 "..mpdh) for line in f:lines() do for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do if k == "volume" then mpd_state["{"..k.."}"] = v and tonumber(v) elseif k == "state" then mpd_state["{"..k.."}"] = helpers.capitalize(v) elseif k == "Artist" then mpd_state["{"..k.."}"] = helpers.escape(v) elseif k == "Title" then mpd_state["{"..k.."}"] = helpers.escape(v) elseif k == "Album" then mpd_state["{"..k.."}"] = helpers.escape(v) elseif k == "Genre" then mpd_state["{"..k.."}"] = helpers.escape(v) --elseif k == "Name" then mpd_state["{"..k.."}"] = helpers.escape(v) --elseif k == "file" then mpd_state["{"..k.."}"] = helpers.escape(v) end end end f:close() return mpd_state end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/volume.lua0000644000000000000000000000251611651220347015673 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local string = { match = string.match } -- }}} -- Volume: provides volume levels and state of requested ALSA mixers module("vicious.widgets.volume") -- {{{ Volume widget type local function worker(format, warg) if not warg then return end local mixer_state = { ["on"] = "♫", -- "", ["off"] = "♩" -- "M" } -- Get mixer control contents local f = io.popen("amixer get " .. warg) local mixer = f:read("*all") f:close() -- Capture mixer control state: [5%] ... ... [on] local volu, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)") -- Handle mixers without data if volu == nil then return {0, mixer_state["off"]} end -- Handle mixers without mute if mute == "" and volu == "0" -- Handle mixers that are muted or mute == "off" then mute = mixer_state["off"] else mute = mixer_state["on"] end return {tonumber(volu), mute} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/wifi.lua0000644000000000000000000000520711651220347015322 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local math = { ceil = math.ceil } local setmetatable = setmetatable local helpers = require("vicious.helpers") local io = { open = io.open, popen = io.popen } local string = { find = string.find, match = string.match } -- }}} -- Wifi: provides wireless information for a requested interface module("vicious.widgets.wifi") -- {{{ Wireless widget type local function worker(format, warg) if not warg then return end -- Default values local winfo = { ["{ssid}"] = "N/A", ["{mode}"] = "N/A", ["{chan}"] = 0, ["{rate}"] = 0, ["{link}"] = 0, ["{linp}"] = 0, ["{sign}"] = 0 } -- Get data from iwconfig where available local iwconfig = "/sbin/iwconfig" local f = io.open(iwconfig, "rb") if not f then iwconfig = "/usr/sbin/iwconfig" else f:close() end local f = io.popen(iwconfig .." ".. warg .. " 2>&1") local iw = f:read("*all") f:close() -- iwconfig wasn't found, isn't executable, or non-wireless interface if iw == nil or string.find(iw, "No such device") then return winfo end -- Output differs from system to system, some stats can be -- separated by =, and not all drivers report all stats winfo["{ssid}"] = -- SSID can have almost anything in it helpers.escape(string.match(iw, 'ESSID[=:]"(.-)"') or winfo["{ssid}"]) winfo["{mode}"] = -- Modes are simple, but also match the "-" in Ad-Hoc string.match(iw, "Mode[=:]([%w%-]*)") or winfo["{mode}"] winfo["{chan}"] = -- Channels are plain digits tonumber(string.match(iw, "Channel[=:]([%d]+)") or winfo["{chan}"]) winfo["{rate}"] = -- Bitrate can start with a space, we don't want to display Mb/s tonumber(string.match(iw, "Bit Rate[=:]([%s]?[%d%.]*)") or winfo["{rate}"]) winfo["{link}"] = -- Link quality can contain a slash (32/70), match only the first number tonumber(string.match(iw, "Link Quality[=:]([%d]+)") or winfo["{link}"]) winfo["{sign}"] = -- Signal level can be a negative value, don't display decibel notation tonumber(string.match(iw, "Signal level[=:]([%-]?[%d]+)") or winfo["{sign}"]) -- Link quality percentage if quality was available if winfo["{link}"] ~= 0 then winfo["{linp}"] = math.ceil(winfo["{link}"] / 0.7) end return winfo end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/os.lua0000644000000000000000000000411711651220347015004 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local pairs = pairs local tonumber = tonumber local io = { popen = io.popen } local os = { getenv = os.getenv } local math = { ceil = math.ceil } local setmetatable = setmetatable local helpers = require("vicious.helpers") local string = { gsub = string.gsub, match = string.match } -- }}} -- OS: provides operating system information module("vicious.widgets.os") -- {{{ Operating system widget type local function worker(format) local system = { ["ostype"] = "N/A", ["hostname"] = "N/A", ["osrelease"] = "N/A", ["username"] = "N/A", ["entropy"] = "N/A", ["entropy_p"] = "N/A" } -- Linux manual page: uname(2) local kernel = helpers.pathtotable("/proc/sys/kernel") for k, v in pairs(system) do if kernel[k] then system[k] = string.gsub(kernel[k], "[%s]*$", "") end end -- BSD manual page: uname(1) if system["ostype"] == "N/A" then local f = io.popen("uname -snr") local uname = f:read("*line") f:close() system["ostype"], system["hostname"], system["osrelease"] = string.match(uname, "([%w]+)[%s]([%w%p]+)[%s]([%w%p]+)") end -- Linux manual page: random(4) if kernel.random then -- Linux 2.6 default entropy pool is 4096-bits local poolsize = tonumber(kernel.random.poolsize) -- Get available entropy and calculate percentage system["entropy"] = tonumber(kernel.random.entropy_avail) system["entropy_p"] = math.ceil(system["entropy"] * 100 / poolsize) end -- Get user from the environment system["username"] = os.getenv("USER") return {system["ostype"], system["osrelease"], system["username"], system["hostname"], system["entropy"], system["entropy_p"]} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/mbox.lua0000644000000000000000000000260011651220347015323 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local type = type local io = { open = io.open } local setmetatable = setmetatable local string = { gfind = string.gfind } local helpers = require("vicious.helpers") -- }}} -- Mbox: provides the subject of last e-mail in a mbox file module("vicious.widgets.mbox") -- Initialize variables local subject = "N/A" -- {{{ Mailbox widget type local function worker(format, warg) if not warg then return end -- mbox could be huge, get a 30kb chunk from EOF if type(warg) ~= "table" then mbox = warg end -- * attachment could be much bigger than 30kb local f = io.open(mbox or warg[1]) f:seek("end", -30720) local txt = f:read("*all") f:close() -- Find all Subject lines for i in string.gfind(txt, "Subject: ([^\n]*)") do subject = i end -- Check if we should scroll, or maybe truncate if type(warg) == "table" then if warg[3] ~= nil then subject = helpers.scroll(subject, warg[2], warg[3]) else subject = helpers.truncate(subject, warg[2]) end end return {helpers.escape(subject)} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/raid.lua0000644000000000000000000000274611651220347015310 0ustar ----------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Hagen Schink ----------------------------------------------------- -- {{{ Grab environment local io = { lines = io.lines } local setmetatable = setmetatable local string = { len = string.len, sub = string.sub, match = string.match, gmatch = string.gmatch } -- }}} -- Raid: provides state information for a requested RAID array module("vicious.widgets.raid") -- Initialize function tables local mddev = {} -- {{{ RAID widget type local function worker(format, warg) if not warg then return end mddev[warg] = { ["found"] = false, ["active"] = 0, ["assigned"] = 0 } -- Linux manual page: md(4) for line in io.lines("/proc/mdstat") do if mddev[warg]["found"] then local updev = string.match(line, "%[[_U]+%]") for i in string.gmatch(updev, "U") do mddev[warg]["active"] = mddev[warg]["active"] + 1 end break elseif string.sub(line, 1, string.len(warg)) == warg then mddev[warg]["found"] = true for i in string.gmatch(line, "%[[%d]%]") do mddev[warg]["assigned"] = mddev[warg]["assigned"] + 1 end end end return {mddev[warg]["assigned"], mddev[warg]["active"]} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/gmail.lua0000644000000000000000000000432611651220736015460 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local type = type local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local helpers = require("vicious.helpers") local string = { find = string.find, match = string.match } -- }}} -- Gmail: provides count of new and subject of last e-mail on Gmail module("vicious.widgets.gmail") -- {{{ Variable definitions local rss = { inbox = { "https://mail.google.com/mail/feed/atom", "Gmail %- Inbox" }, unread = { "https://mail.google.com/mail/feed/atom/unread", "Gmail %- Label" }, --labelname = { -- "https://mail.google.com/mail/feed/atom/labelname", -- "Gmail %- Label" --}, } -- Default is just Inbox local feed = rss.inbox local mail = { ["{count}"] = 0, ["{subject}"] = "N/A" } -- }}} -- {{{ Gmail widget type local function worker(format, warg) -- Get info from the Gmail atom feed local f = io.popen("curl --connect-timeout 1 -m 3 -fsn " .. feed[1]) -- Could be huge don't read it all at once, info we are after is at the top for line in f:lines() do mail["{count}"] = -- Count comes before messages and matches at least 0 tonumber(string.match(line, "([%d]+)")) or mail["{count}"] -- Find subject tags local title = string.match(line, "(.*)") -- If the subject changed then break out of the loop if title ~= nil and not string.find(title, feed[2]) then -- Check if we should scroll, or maybe truncate if warg then if type(warg) == "table" then title = helpers.scroll(title, warg[1], warg[2]) else title = helpers.truncate(title, warg) end end -- Spam sanitize the subject and store mail["{subject}"] = helpers.escape(title) break end end f:close() return mail end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/thermal.lua0000644000000000000000000000273411765367633016042 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local type = type local tonumber = tonumber local setmetatable = setmetatable local string = { match = string.match } local helpers = require("vicious.helpers") -- }}} -- Thermal: provides temperature levels of ACPI and coretemp thermal zones module("vicious.widgets.thermal") -- {{{ Thermal widget type local function worker(format, warg) if not warg then return end local zone = { -- Known temperature data sources ["sys"] = {"/sys/class/thermal/", file = "temp", div = 1000}, ["core"] = {"/sys/devices/platform/", file = "temp2_input",div = 1000}, ["proc"] = {"/proc/acpi/thermal_zone/",file = "temperature"} } -- Default to /sys/class/thermal warg = type(warg) == "table" and warg or { warg, "sys" } -- Get temperature from thermal zone local thermal = helpers.pathtotable(zone[warg[2]][1] .. warg[1]) local data = warg[3] and thermal[warg[3]] or thermal[zone[warg[2]].file] if data then if zone[warg[2]].div then return {data / zone[warg[2]].div} else -- /proc/acpi "temperature: N C" return {tonumber(string.match(data, "[%d]+"))} end end return {0} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/weather.lua0000644000000000000000000000640711651220347016026 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local math = { ceil = math.ceil } local string = { match = string.match } local helpers = require("vicious.helpers") -- }}} -- Weather: provides weather information for a requested station module("vicious.widgets.weather") -- Initialize function tables local weather = { ["{city}"] = "N/A", ["{wind}"] = "N/A", ["{windmph}"] = "N/A", ["{windkmh}"] = "N/A", ["{sky}"] = "N/A", ["{weather}"] = "N/A", ["{tempf}"] = "N/A", ["{tempc}"] = "N/A", ["{humid}"] = "N/A", ["{press}"] = "N/A" } -- {{{ Weather widget type local function worker(format, warg) if not warg then return end -- Get weather forceast by the station ICAO code, from: -- * US National Oceanic and Atmospheric Administration local noaa = "http://weather.noaa.gov/pub/data/observations/metar/decoded/" local f = io.popen("curl --connect-timeout 1 -fsm 3 "..noaa..warg..".TXT") local ws = f:read("*all") f:close() -- Check if there was a timeout or a problem with the station if ws == nil then return weather end weather["{city}"] = -- City and/or area string.match(ws, "^(.+)%,.*%([%u]+%)") or weather["{city}"] weather["{wind}"] = -- Wind direction and degrees if available string.match(ws, "Wind:[%s][%a]+[%s][%a]+[%s](.+)[%s]at.+$") or weather["{wind}"] weather["{windmph}"] = -- Wind speed in MPH if available string.match(ws, "Wind:[%s].+[%s]at[%s]([%d]+)[%s]MPH") or weather["{windmph}"] weather["{sky}"] = -- Sky conditions if available string.match(ws, "Sky[%s]conditions:[%s](.-)[%c]") or weather["{sky}"] weather["{weather}"] = -- Weather conditions if available string.match(ws, "Weather:[%s](.-)[%c]") or weather["{weather}"] weather["{tempf}"] = -- Temperature in fahrenheit string.match(ws, "Temperature:[%s]([%-]?[%d%.]+).*[%c]") or weather["{tempf}"] weather["{humid}"] = -- Relative humidity in percent string.match(ws, "Relative[%s]Humidity:[%s]([%d]+)%%") or weather["{humid}"] weather["{press}"] = -- Pressure in hPa string.match(ws, "Pressure[%s].+%((.+)[%s]hPa%)") or weather["{press}"] -- Wind speed in km/h if MPH was available if weather["{windmph}"] ~= "N/A" then weather["{windmph}"] = tonumber(weather["{windmph}"]) weather["{windkmh}"] = math.ceil(weather["{windmph}"] * 1.6) end -- Temperature in °C if °F was available if weather["{tempf}"] ~= "N/A" then weather["{tempf}"] = tonumber(weather["{tempf}"]) weather["{tempc}"] = math.ceil((weather["{tempf}"] - 32) * 5/9) end -- Capitalize some stats so they don't look so out of place if weather["{sky}"] ~= "N/A" then weather["{sky}"] = helpers.capitalize(weather["{sky}"]) end if weather["{weather}"] ~= "N/A" then weather["{weather}"] = helpers.capitalize(weather["{weather}"]) end return weather end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/uptime.lua0000644000000000000000000000222111651220347015660 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) 2009, Lucas de Vries --------------------------------------------------- -- {{{ Grab environment local setmetatable = setmetatable local math = { floor = math.floor } local string = { match = string.match } local helpers = require("vicious.helpers") -- }}} -- Uptime: provides system uptime and load information module("vicious.widgets.uptime") -- {{{ Uptime widget type local function worker(format) local proc = helpers.pathtotable("/proc") -- Get system uptime local up_t = math.floor(string.match(proc.uptime, "[%d]+")) local up_d = math.floor(up_t / (3600 * 24)) local up_h = math.floor((up_t % (3600 * 24)) / 3600) local up_m = math.floor(((up_t % (3600 * 24)) % 3600) / 60) local l1, l5, l15 = -- Get load averages for past 1, 5 and 15 minutes string.match(proc.loadavg, "([%d%.]+)[%s]([%d%.]+)[%s]([%d%.]+)") return {up_d, up_h, up_m, l1, l5, l15} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/hddtemp.lua0000644000000000000000000000206111734355016016010 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local string = { gmatch = string.gmatch } -- }}} -- Hddtemp: provides hard drive temperatures using the hddtemp daemon module("vicious.widgets.hddtemp") -- {{{ HDD Temperature widget type local function worker(format, warg) -- Fallback to default hddtemp port if warg == nil then warg = 7634 end local hdd_temp = {} -- Get info from the hddtemp daemon local f = io.popen("echo | curl --connect-timeout 1 -fsm 3 telnet://127.0.0.1:"..warg) for line in f:lines() do for d, t in string.gmatch(line, "|([%/%a%d]+)|.-|([%d]+)|[CF]+|") do hdd_temp["{"..d.."}"] = tonumber(t) end end f:close() return hdd_temp end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/dio.lua0000644000000000000000000000427411651220736015144 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2011, Jörg T. --------------------------------------------------- -- {{{ Grab environment local pairs = pairs local io = { lines = io.lines } local setmetatable = setmetatable local string = { match = string.match } local helpers = require("vicious.helpers") local os = { time = os.time, difftime = os.difftime } -- }}} -- Disk I/O: provides I/O statistics for requested storage devices module("vicious.widgets.dio") -- Initialize function tables local disk_usage = {} local disk_stats = {} local disk_time = 0 -- Constant definitions local unit = { ["s"] = 1, ["kb"] = 2, ["mb"] = 2048 } -- {{{ Disk I/O widget type local function worker(format) local disk_lines = {} for line in io.lines("/proc/diskstats") do local device, read, write = -- Linux kernel documentation: Documentation/iostats.txt string.match(line, "([^%s]+) %d+ %d+ (%d+) %d+ %d+ %d+ (%d+)") disk_lines[device] = { read, write } end local time = os.time() local interval = os.difftime(time, disk_time) if interval == 0 then interval = 1 end for device, stats in pairs(disk_lines) do -- Avoid insane values on startup local last_stats = disk_stats[device] or stats -- Check for overflows and counter resets (> 2^32) if stats[1] < last_stats[1] or stats[2] < last_stats[2] then last_stats[1], last_stats[2] = stats[1], stats[2] end -- Diskstats are absolute, substract our last reading -- * divide by timediff because we don't know the timer value local read = (stats[1] - last_stats[1]) / interval local write = (stats[2] - last_stats[2]) / interval -- Calculate and store I/O helpers.uformat(disk_usage, device.." read", read, unit) helpers.uformat(disk_usage, device.." write", write, unit) helpers.uformat(disk_usage, device.." total", read + write, unit) end disk_time = time disk_stats = disk_lines return disk_usage end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/mboxc.lua0000644000000000000000000000343511651220347015475 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local io = { open = io.open } local setmetatable = setmetatable local string = { find = string.find } -- }}} -- Mboxc: provides the count of total, old and new messages in mbox files module("vicious.widgets.mboxc") -- {{{ Mbox count widget type local function worker(format, warg) if not warg then return end -- Initialize counters local count = { old = 0, total = 0, new = 0 } -- Get data from mbox files for i=1, #warg do local f = io.open(warg[i]) while true do -- Read the mbox line by line, if we are going to read -- some *HUGE* folders then switch to reading chunks local lines = f:read("*line") if not lines then break end -- Find all messages -- * http://www.jwz.org/doc/content-length.html local _, from = string.find(lines, "^From[%s]") if from ~= nil then count.total = count.total + 1 end -- Read messages have the Status header local _, status = string.find(lines, "^Status:[%s]RO$") if status ~= nil then count.old = count.old + 1 end -- Skip the folder internal data local _, int = string.find(lines, "^Subject:[%s].*FOLDER[%s]INTERNAL[%s]DATA") if int ~= nil then count.total = count.total - 1 end end f:close() end -- Substract total from old to get the new count count.new = count.total - count.old return {count.total, count.old, count.new} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/pkg.lua0000644000000000000000000000245011765367633015162 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local io = { popen = io.popen } local math = { max = math.max } local setmetatable = setmetatable -- }}} -- Pkg: provides number of pending updates on UNIX systems module("vicious.widgets.pkg") -- {{{ Packages widget type local function worker(format, warg) if not warg then return end -- Initialize counters local updates = 0 local manager = { ["Arch"] = { cmd = "pacman -Qu" }, ["Arch S"] = { cmd = "yes | pacman -Sup", sub = 1 }, ["Debian"] = { cmd = "apt-show-versions -u -b" }, ["Ubuntu"] = { cmd = "aptitude search '~U'" }, ["Fedora"] = { cmd = "yum list updates", sub = 3 }, ["FreeBSD"] ={ cmd = "pkg_version -I -l '<'" }, ["Mandriva"]={ cmd = "urpmq --auto-select" } } -- Check if updates are available local pkg = manager[warg] local f = io.popen(pkg.cmd) for line in f:lines() do updates = updates + 1 end f:close() return {pkg.sub and math.max(updates-pkg.sub, 0) or updates} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/fs.lua0000644000000000000000000000315611651220347014775 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) 2009, Lucas de Vries --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local string = { match = string.match } local helpers = require("vicious.helpers") -- }}} -- FS: provides file system disk space usage module("vicious.widgets.fs") -- Variable definitions local unit = { ["mb"] = 1024, ["gb"] = 1024^2 } -- {{{ Filesystem widget type local function worker(format, warg) -- Fallback to listing local filesystems if warg then warg = "" else warg = "-l" end local fs_info = {} -- Get data from df local f = io.popen("LC_ALL=C df -kP " .. warg) for line in f:lines() do -- Match: (size) (used)(avail)(use%) (mount) local s = string.match(line, "^.-[%s]([%d]+)") local u,a,p = string.match(line, "([%d]+)[%D]+([%d]+)[%D]+([%d]+)%%") local m = string.match(line, "%%[%s]([%p%w]+)") if u and m then -- Handle 1st line and broken regexp helpers.uformat(fs_info, m .. " size", s, unit) helpers.uformat(fs_info, m .. " used", u, unit) helpers.uformat(fs_info, m .. " avail", a, unit) fs_info["{" .. m .. " used_p}"] = tonumber(p) fs_info["{" .. m .. " avail_p}"] = 100 - tonumber(p) end end f:close() return fs_info end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/widgets/bat.lua0000644000000000000000000000505711734355016015141 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local setmetatable = setmetatable local string = { format = string.format } local helpers = require("vicious.helpers") local math = { min = math.min, floor = math.floor } -- }}} -- Bat: provides state, charge, and remaining time for a requested battery module("vicious.widgets.bat") -- {{{ Battery widget type local function worker(format, warg) if not warg then return end local battery = helpers.pathtotable("/sys/class/power_supply/"..warg) local battery_state = { ["Full\n"] = "↯", ["Unknown\n"] = "⌁", ["Charged\n"] = "↯", ["Charging\n"] = "+", ["Discharging\n"] = "-" } -- Check if the battery is present if battery.present ~= "1\n" then return {battery_state["Unknown\n"], 0, "N/A"} end -- Get state information local state = battery_state[battery.status] or battery_state["Unknown\n"] -- Get capacity information if battery.charge_now then remaining, capacity = battery.charge_now, battery.charge_full elseif battery.energy_now then remaining, capacity = battery.energy_now, battery.energy_full else return {battery_state["Unknown\n"], 0, "N/A"} end -- Calculate percentage (but work around broken BAT/ACPI implementations) local percent = math.min(math.floor(remaining / capacity * 100), 100) -- Get charge information if battery.current_now then rate = tonumber(battery.current_now) elseif battery.power_now then rate = tonumber(battery.power_now) else return {state, percent, "N/A"} end -- Calculate remaining (charging or discharging) time local time = "N/A" if rate ~= nil and rate ~= 0 then if state == "+" then timeleft = (tonumber(capacity) - tonumber(remaining)) / tonumber(rate) elseif state == "-" then timeleft = tonumber(remaining) / tonumber(rate) else return {state, percent, time} end -- Calculate time local hoursleft = math.floor(timeleft) local minutesleft = math.floor((timeleft - hoursleft) * 60 ) time = string.format("%02d:%02d", hoursleft, minutesleft) end return {state, percent, time} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/0000755000000000000000000000000011651220736013651 5ustar awesome-extra/vicious/contrib/mpc.lua0000644000000000000000000000234211651220347015132 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) 2009, Lucas de Vries --------------------------------------------------- -- {{{ Grab environment local type = type local io = { popen = io.popen } local setmetatable = setmetatable local string = { find = string.find } local helpers = require("vicious.helpers") -- }}} -- Mpc: provides the currently playing song in MPD module("vicious.contrib.mpc") -- {{{ MPC widget type local function worker(format, warg) -- Get data from mpd local f = io.popen("mpc") local np = f:read("*line") f:close() -- Not installed, if np == nil or -- off or stoppped. (string.find(np, "MPD_HOST") or string.find(np, "volume:")) then return {"Stopped"} end -- Check if we should scroll, or maybe truncate if warg then if type(warg) == "table" then np = helpers.scroll(np, warg[1], warg[2]) else np = helpers.truncate(np, warg) end end return {helpers.escape(np)} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/ossvol.lua0000644000000000000000000000253411651220347015703 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local string = { match = string.match } -- }}} -- Ossvol: provides volume levels of requested OSS mixers module("vicious.contrib.ossvol") -- {{{ Volume widget type local function worker(format, warg) if not warg then return end local mixer_state = { ["on"] = "♫", -- "", ["off"] = "♩" -- "M" } -- Get mixer control contents local f = io.popen("ossmix -c") local mixer = f:read("*all") f:close() -- Capture mixer control state local volu = tonumber(string.match(mixer, warg .. "[%s]([%d%.]+)"))/0.25 local mute = string.match(mixer, "vol%.mute[%s]([%a]+)") -- Handle mixers without data if volu == nil then return {0, mixer_state["off"]} end -- Handle mixers without mute if mute == "OFF" and volu == "0" -- Handle mixers that are muted or mute == "ON" then mute = mixer_state["off"] else mute = mixer_state["on"] end return {volu, mute} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/batpmu.lua0000644000000000000000000000450011651220347015641 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { open = io.open } local setmetatable = setmetatable local math = { min = math.min, floor = math.floor } local string = { find = string.find, match = string.match, format = string.format } -- }}} -- Batpmu: provides state, charge and remaining time for a requested battery using PMU module("vicious.contrib.batpmu") -- {{{ Battery widget type local function worker(format, batid) local battery_state = { ["full"] = "↯", ["unknown"] = "⌁", ["00000013"] = "+", ["00000011"] = "-" } -- Get /proc/pmu/battery* state local f = io.open("/proc/pmu/" .. batid) -- Handler for incompetent users if not f then return {battery_state["unknown"], 0, "N/A"} end local statefile = f:read("*all") f:close() -- Get /proc/pmu/info data local f = io.open("/proc/pmu/info") local infofile = f:read("*all") f:close() -- Check if the battery is present if infofile == nil or string.find(infofile, "Battery count[%s]+:[%s]0") then return {battery_state["unknown"], 0, "N/A"} end -- Get capacity and charge information local capacity = string.match(statefile, "max_charge[%s]+:[%s]([%d]+).*") local remaining = string.match(statefile, "charge[%s]+:[%s]([%d]+).*") -- Calculate percentage local percent = math.min(math.floor(remaining / capacity * 100), 100) -- Get timer information local timer = string.match(statefile, "time rem%.[%s]+:[%s]([%d]+).*") if timer == "0" then return {battery_state["full"], percent, "N/A"} end -- Get state information local state = string.match(statefile, "flags[%s]+:[%s]([%d]+).*") local state = battery_state[state] or battery_state["unknown"] -- Calculate remaining (charging or discharging) time local hoursleft = math.floor(tonumber(timer) / 3600) local minutesleft = math.floor((tonumber(timer) / 60) % 60) local time = string.format("%02d:%02d", hoursleft, minutesleft) return {state, percent, time} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/net.lua0000644000000000000000000001065311651220347015145 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) 2009, Henning Glawe -- * (c) 2009, Lucas de Vries --------------------------------------------------- -- {{{ Grab environment local pairs = pairs local tonumber = tonumber local os = { time = os.time } local io = { lines = io.lines } local setmetatable = setmetatable local string = { match = string.match } local helpers = require("vicious.helpers") -- }}} -- Net: provides usage statistics for all network interfaces module("vicious.contrib.net") -- Initialise function tables local nets = {} -- Variable definitions local unit = { ["b"] = 1, ["kb"] = 1024, ["mb"] = 1024^2, ["gb"] = 1024^3 } -- {{{ Net widget type local function worker(format, tignorelist) local args = {} local tignore = {} local total_rx = 0 local total_tx = 0 local any_up = 0 if not tignorelist then tignorelist = {"lo", "wmaster0"} end for k, i in pairs(tignorelist) do tignore[i] = true end -- Get NET stats for line in io.lines("/proc/net/dev") do -- Match wmaster0 as well as rt0 (multiple leading spaces) local name = string.match(line, "^[%s]?[%s]?[%s]?[%s]?([%w]+):") if name ~= nil then -- Received bytes, first value after the name local recv = tonumber(string.match(line, ":[%s]*([%d]+)")) -- Transmited bytes, 7 fields from end of the line local send = tonumber(string.match(line, "([%d]+)%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d$")) if not tignore[name] then total_rx = total_rx + recv total_tx = total_tx + send end helpers.uformat(args, name .. " rx", recv, unit) helpers.uformat(args, name .. " tx", send, unit) if nets[name] == nil then -- Default values on the first run nets[name] = {} helpers.uformat(args, name .. " down", 0, unit) helpers.uformat(args, name .. " up", 0, unit) args["{"..name.." carrier}"] = 0 nets[name].time = os.time() else -- Net stats are absolute, substract our last reading local interval = os.time() - nets[name].time > 0 and os.time() - nets[name].time or 1 nets[name].time = os.time() local down = (recv - nets[name][1]) / interval local up = (send - nets[name][2]) / interval helpers.uformat(args, name .. " down", down, unit) helpers.uformat(args, name .. " up", up, unit) -- Carrier detection sysnet = helpers.pathtotable("/sys/class/net/" .. name) if sysnet.carrier then ccarrier = tonumber(sysnet.carrier) args["{"..name.." carrier}"] = ccarrier if ccarrier ~= 0 and not tignore[name] then any_up = 1 end else args["{"..name.." carrier}"] = 0 end end -- Store totals nets[name][1] = recv nets[name][2] = send end end helpers.uformat(args, "total rx", total_rx, unit) helpers.uformat(args, "total tx", total_tx, unit) if nets["total"] == nil then -- Default values on the first run nets["total"] = {} helpers.uformat(args, "total down", 0, unit) helpers.uformat(args, "total up", 0, unit) args["{total carrier}"] = 0 nets["total"].time = os.time() else -- Net stats are absolute, substract our last reading local interval = os.time() - nets["total"].time > 0 and os.time() - nets["total"].time or 1 nets["total"].time = os.time() local down = (total_rx - nets["total"][1]) / interval local up = (total_tx - nets["total"][2]) / interval helpers.uformat(args, "total down", down, unit) helpers.uformat(args, "total up", up, unit) args["{total carrier}"] = any_up end -- Store totals nets["total"][1] = total_rx nets["total"][2] = total_tx return args end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/init.lua0000644000000000000000000000110611651220736015315 0ustar --------------------------------------------------- -- Vicious widgets for the awesome window manager --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Setup environment local setmetatable = setmetatable local wrequire = require("vicious.helpers").wrequire -- Vicious: widgets for the awesome window manager module("vicious.contrib") -- }}} -- Load modules at runtime as needed setmetatable(_M, { __index = wrequire }) awesome-extra/vicious/contrib/README0000644000000000000000000000542211651220736014534 0ustar 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. Widget types ------------ Most widget types consist of worker functions that take the "format" argument given to vicious.register as the first argument, "warg" as the second, and return a table of values to insert in the format string. But we have not insisted on this coding style in contrib. So widgets like PulseAudio have emerged that are different. These widgets could also depend on Lua libraries that are not distributed with the core Lua distribution. Ease of installation and use does not necessarily have to apply to contributed widgets. vicious.contrib.batacpi - vicious.contrib.batpmu - vicious.contrib.batproc - vicious.contrib.dio - provides I/O statistics for requested storage devices - takes the disk as an argument, i.e. "sda" (or a specific partition, i.e. "sda/sda2") - returns a table with string keys: {total_s}, {total_kb}, {total_mb}, {read_s}, {read_kb}, {read_mb}, {write_s}, {write_kb}, {write_mb} and {sched} vicious.contrib.mpc - vicious.contrib.netcfg - vicious.contrib.net - vicious.contrib.ossvol - vicious.contrib.pop - vicious.contrib.pulse - provides volume levels of requested pulseaudio sinks and functions to manipulate them - takes the name of a sink as an optional argument. a number will be interpret as an index, if no argument is given, it will take the first-best - to get a list of available sinks use the command: pacmd list-sinks | grep 'name:' - returns 1st value as the volume level - vicious.contrib.pulse.add(percent, sink) - @percent is a number, which increments or decrements the volume level by its value in percent - @sink optional, same usage as in vicious.contrib.pulse - returns the exit status of pacmd - vicious.contrib.pulse.toggle(sink) - inverts the volume state (mute -> unmute; unmute -> mute) - @sink optional, same usage as in vicious.contrib.pulse - returns the exit status of pacmd vicious.contrib.rss - vicious.contrib.sensors - Usage examples -------------- Pulse Audio widget 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), awful.button({ }, 4, function () vicious.contrib.pulse.add(5,"alsa_output.pci-0000_00_1b.0.analog-stereo") end), awful.button({ }, 5, function () vicious.contrib.pulse.add(-5,"alsa_output.pci-0000_00_1b.0.analog-stereo") end) )) awesome-extra/vicious/contrib/rss.lua0000644000000000000000000000327511651220347015170 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2009, olcc -- -- This is now a standalone RSS reader for awesome: -- * http://github.com/olcc/aware --------------------------------------------------- -- {{{ Grab environment local pairs = pairs local io = { popen = io.popen } local setmetatable = setmetatable -- }}} -- RSS: provides latest world news module("vicious.contrib.rss") -- {{{ RSS widget type local function worker(format, input) -- input: * feed - feed url -- * object - entity to look for (typically: 'item') -- * fields - fields to read (example: 'link', 'title', 'description') -- output: * count - number of entities found -- * one table for each field, containing wanted values local feed = input.feed local object = input.object local fields = input.fields -- Initialise tables local out = {} for _, v in pairs(fields) do out[v] = {} end -- Initialise variables local ob = nil local i,j,k = 1, 1, 0 local curl = "curl -A 'Mozilla/4.0' -fsm 5 --connect-timeout 3 " -- Get the feed local f = io.popen(curl .. '"' .. feed .. '"') local feed = f:read("*all") f:close() while true do i, j, ob = feed.find(feed, "<" .. object .. ">(.-)", i) if not ob then break end for _, v in pairs(fields) do out[v][k] = ob:match("<" .. v .. ">(.*)") end k = k+1 i = j+1 end -- Update the entity count out.count = k return out end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/pulse.lua0000644000000000000000000000567111651220736015515 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, MrMagne -- * (c) 2010, Mic92 --------------------------------------------------- -- {{{ Grab environment local type = type local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local os = { execute = os.execute } local table = { insert = table.insert } local string = { find = string.find, match = string.match, format = string.format, gmatch = string.gmatch } local math = { floor = math.floor } -- }}} -- Pulse: provides volume levels of requested pulseaudio sinks and methods to change them module("vicious.contrib.pulse") -- {{{ Helper function local function pacmd(args) local f = io.popen("pacmd "..args) local line = f:read("*all") f:close() return line end local function escape(text) local special_chars = { ["."] = "%.", ["-"] = "%-" } return text:gsub("[%.%-]", special_chars) end local cached_sinks = {} local function get_sink_name(sink) if type(sink) == "string" then return sink end -- avoid nil keys local key = sink or 1 -- Cache requests if not cached_sinks[key] then local line = pacmd("list-sinks") for s in string.gmatch(line, "name: <(.-)>") do table.insert(cached_sinks, s) end end return cached_sinks[key] end -- }}} -- {{{ Pulseaudio widget type local function worker(format, sink) sink = get_sink_name(sink) if sink == nil then return {0, "unknown"} end -- Get sink data local data = pacmd("dump") -- If mute return 0 (not "Mute") so we don't break progressbars if string.find(data,"set%-sink%-mute "..escape(sink).." yes") then return {0, "off"} end local vol = tonumber(string.match(data, "set%-sink%-volume "..escape(sink).." (0x[%x]+)")) if vol == nil then vol = 0 end return { math.floor(vol/0x10000*100), "on"} end -- }}} -- {{{ Volume control helper function add(percent, sink) sink = get_sink_name(sink) if sink == nil then return end local data = pacmd("dump") local pattern = "set%-sink%-volume "..escape(sink).." (0x[%x]+)" local initial_vol = tonumber(string.match(data, pattern)) local vol = initial_vol + percent/100*0x10000 if vol > 0x10000 then vol = 0x10000 end if vol < 0 then vol = 0 end local cmd = string.format("pacmd set-sink-volume %s 0x%x >/dev/null", sink, vol) return os.execute(cmd) end function toggle(sink) sink = get_sink_name(sink) if sink == nil then return end local data = pacmd("dump") local pattern = "set%-sink%-mute "..escape(sink).." (%a%a%a?)" local mute = string.match(data, pattern) -- 0 to enable a sink or 1 to mute it. local state = { yes = 0, no = 1} local cmd = string.format("pacmd set-sink-mute %s %d", sink, state[mute]) return os.execute(cmd) end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/sensors.lua0000644000000000000000000000331411651220347016047 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Greg D. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local table = { insert = table.insert } local string = { gsub = string.gsub, match = string.match } -- }}} -- Sensors: provides access to lm_sensors data module("vicious.contrib.sensors") -- {{{ Split helper function local function datasplit(str) -- Splitting strings into associative array -- with some magic to get the values right. str = string.gsub(str, "\n", ":") local tbl = {} string.gsub(str, "([^:]*)", function (v) if string.match(v, ".") then table.insert(tbl, v) end end) local assoc = {} for c = 1, #tbl, 2 do local k = string.gsub(tbl[c], ".*_", "") local v = tonumber(string.match(tbl[c+1], "[%d]+")) assoc[k] = v end return assoc end -- }}} -- {{{ Sensors widget type local function worker(format, warg) -- Get data from all sensors local f = io.popen("LANG=C sensors -uA") local lm_sensors = f:read("*all") f:close() local sensor_data = string.gsub( string.match(lm_sensors, warg..":\n(%s%s.-)\n[^ ]"), " ", "") -- One of: crit, max local divisor = "crit" local s_data = datasplit(sensor_data) if s_data[divisor] and s_data[divisor] > 0 then s_data.percent = s_data.input / s_data[divisor] * 100 end return {s_data.input, tonumber(s_data.percent)} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/netcfg.lua0000644000000000000000000000150111651220347015615 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Radu A. --------------------------------------------------- -- {{{ Grab environment local io = { popen = io.popen } local setmetatable = setmetatable local table = { insert = table.insert } -- }}} -- Netcfg: provides active netcfg network profiles module("vicious.contrib.netcfg") -- {{{ Netcfg widget type local function worker(format) -- Initialize counters local profiles = {} local f = io.popen("ls -1 /var/run/network/profiles") for line in f:lines() do if line ~= nil then table.insert(profiles, line) end end f:close() return profiles end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/pop.lua0000644000000000000000000000257611651220347015162 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Boris Bolgradov <> -- -- This widget type depends on luasocket. -- -- Widget arguments are host, port, username and -- password, i.e.: -- {"mail.myhost.com", 110, "John", "132435"} --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local setmetatable = setmetatable local sock_avail, socket = pcall(function() return require("socket") end) -- }}} -- POP: provides the count of new messages in a POP3 mailbox module("vicious.contrib.pop") -- {{{ POP3 count widget type local function worker(format, warg) if not sock_avail or (not warg or #warg ~= 4) then return {"N/A"} end local host, port = warg[1], tonumber(warg[2]) local user, pass = warg[3], warg[4] local client = socket.tcp() client:settimeout(3) client:connect(host, port) client:receive("*l") client:send("USER " .. user .. "\r\n") client:receive("*l") client:send("PASS " .. pass .. "\r\n") client:receive("*l") client:send("STAT" .. "\r\n") local response = client:receive("*l") client:close() if response:find("%+OK") then response = response:match("%+OK (%d+)") end return {response} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/batproc.lua0000644000000000000000000000513011651220347016003 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { open = io.open } local setmetatable = setmetatable local math = { min = math.min, floor = math.floor } local string = { find = string.find, match = string.match, format = string.format } -- }}} -- Batproc: provides state, charge, and remaining time for a requested battery using procfs module("vicious.contrib.batproc") -- {{{ Battery widget type local function worker(format, batid) local battery_state = { ["full"] = "↯", ["unknown"] = "⌁", ["charged"] = "↯", ["charging"] = "+", ["discharging"] = "-" } -- Get /proc/acpi/battery info local f = io.open("/proc/acpi/battery/"..batid.."/info") -- Handler for incompetent users if not f then return {battery_state["unknown"], 0, "N/A"} end local infofile = f:read("*all") f:close() -- Check if the battery is present if infofile == nil or string.find(infofile, "present:[%s]+no") then return {battery_state["unknown"], 0, "N/A"} end -- Get capacity information local capacity = string.match(infofile, "last full capacity:[%s]+([%d]+).*") -- Get /proc/acpi/battery state local f = io.open("/proc/acpi/battery/"..batid.."/state") local statefile = f:read("*all") f:close() -- Get state information local state = string.match(statefile, "charging state:[%s]+([%a]+).*") local state = battery_state[state] or battery_state["unknown"] -- Get charge information local rate = string.match(statefile, "present rate:[%s]+([%d]+).*") local remaining = string.match(statefile, "remaining capacity:[%s]+([%d]+).*") -- Calculate percentage (but work around broken BAT/ACPI implementations) local percent = math.min(math.floor(remaining / capacity * 100), 100) -- Calculate remaining (charging or discharging) time if state == "+" then timeleft = (tonumber(capacity) - tonumber(remaining)) / tonumber(rate) elseif state == "-" then timeleft = tonumber(remaining) / tonumber(rate) else return {state, percent, "N/A"} end local hoursleft = math.floor(timeleft) local minutesleft = math.floor((timeleft - hoursleft) * 60 ) local time = string.format("%02d:%02d", hoursleft, minutesleft) return {state, percent, time} end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/dio.lua0000644000000000000000000000422211651220736015127 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local ipairs = ipairs local setmetatable = setmetatable local table = { insert = table.insert } local string = { gmatch = string.gmatch } local helpers = require("vicious.helpers") -- }}} -- Disk I/O: provides I/O statistics for requested storage devices module("vicious.contrib.dio") -- Initialize function tables local disk_usage = {} local disk_total = {} -- Variable definitions local unit = { ["s"] = 1, ["kb"] = 2, ["mb"] = 2048 } -- {{{ Disk I/O widget type local function worker(format, disk) if not disk then return end local disk_lines = { [disk] = {} } local disk_stats = helpers.pathtotable("/sys/block/" .. disk) if disk_stats.stat then local match = string.gmatch(disk_stats.stat, "[%s]+([%d]+)") for i = 1, 11 do -- Store disk stats table.insert(disk_lines[disk], match()) end end -- Ensure tables are initialized correctly local diff_total = { [disk] = {} } if not disk_total[disk] then disk_usage[disk] = {} disk_total[disk] = {} while #disk_total[disk] < #disk_lines[disk] do table.insert(disk_total[disk], 0) end end for i, v in ipairs(disk_lines[disk]) do -- Diskstats are absolute, substract our last reading diff_total[disk][i] = v - disk_total[disk][i] -- Store totals disk_total[disk][i] = v end -- Calculate and store I/O helpers.uformat(disk_usage[disk], "read", diff_total[disk][3], unit) helpers.uformat(disk_usage[disk], "write", diff_total[disk][7], unit) helpers.uformat(disk_usage[disk], "total", diff_total[disk][7] + diff_total[disk][3], unit) -- Store I/O scheduler if disk_stats.queue and disk_stats.queue.scheduler then disk_usage[disk]["{sched}"] = string.gmatch(disk_stats.queue.scheduler, "%[([%a]+)%]") end return disk_usage[disk] end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/contrib/batacpi.lua0000644000000000000000000000305611651220347015761 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. --------------------------------------------------- -- {{{ Grab environment local tonumber = tonumber local io = { popen = io.popen } local setmetatable = setmetatable local table = { insert = table.insert } local string = { match = string.match } -- }}} -- Batacpi: provides state, charge, and remaining time for all batteries using acpitool module("vicious.contrib.batacpi") -- {{{ Battery widget type local function worker(format) local battery_info = {} local battery_state = { ["full"] = "↯", ["unknown"] = "⌁", ["charged"] = "↯", ["charging"] = "+", ["discharging"] = "-" } -- Get data from acpitool local f = io.popen("acpitool -b") for line in f:lines() do -- Check if the battery is present if string.match(line, "^[%s]+Battery.*") then -- Store state and charge information table.insert(battery_info, (battery_state[string.match(line, "([%a]*),") or "unknown"])) table.insert(battery_info, (tonumber(string.match(line, "([%d]?[%d]?[%d])%.")) or 0)) -- Store remaining time information table.insert(battery_info, (string.match(line, "%%,%s(.*)") or "N/A")) else return {battery_state["unknown"], 0, "N/A"} end end f:close() return battery_info end -- }}} setmetatable(_M, { __call = function(_, ...) return worker(...) end }) awesome-extra/vicious/init.lua0000644000000000000000000001340211651220736013657 0ustar --------------------------------------------------- -- Vicious widgets for the awesome window manager --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) 2009, Lucas de Vries --------------------------------------------------- -- {{{ Setup environment local type = type local pairs = pairs local tonumber = tonumber local capi = { timer = timer } local os = { time = os.time } local table = { insert = table.insert, remove = table.remove } require("vicious.helpers") require("vicious.widgets") --require("vicious.contrib") -- Vicious: widgets for the awesome window manager module("vicious") -- Initialize tables local timers = {} local registered = {} local widget_cache = {} -- }}} -- {{{ Local functions -- {{{ Update a widget local function update(widget, reg, disablecache) -- Check if there are any equal widgets if reg == nil then for w, i in pairs(registered) do if w == widget then for _, r in pairs(i) do update(w, r, disablecache) end end end return end local t = os.time() local data = {} -- Check for chached output newer than the last update if widget_cache[reg.wtype] ~= nil then local c = widget_cache[reg.wtype] if (c.time == nil or c.time <= t-reg.timer) or disablecache then c.time, c.data = t, reg.wtype(reg.format, reg.warg) end data = c.data else data = reg.wtype and reg.wtype(reg.format, reg.warg) end if type(data) == "table" then if type(reg.format) == "string" then data = helpers.format(reg.format, data) elseif type(reg.format) == "function" then data = reg.format(widget, data) end end if widget.add_value ~= nil then widget:add_value(tonumber(data) and tonumber(data)/100) elseif widget.set_value ~= nil then widget:set_value(tonumber(data) and tonumber(data)/100) elseif widget.set_markup ~= nil then widget:set_markup(data) else widget.text = data end return data end -- }}} -- {{{ Register from reg object local function regregister(reg) if not reg.running then if registered[reg.widget] == nil then registered[reg.widget] = {} table.insert(registered[reg.widget], reg) else local already = false for w, i in pairs(registered) do if w == reg.widget then for _, v in pairs(i) do if v == reg then already = true break end end if already then break end end end if not already then table.insert(registered[reg.widget], reg) end end -- Start the timer if reg.timer > 0 then timers[reg.update] = { timer = capi.timer({ timeout = reg.timer }) } local tm = timers[reg.update].timer if tm.connect_signal then tm:connect_signal("timeout", reg.update) else tm:add_signal("timeout", reg.update) end tm:start() -- Initial update tm:emit_signal("timeout") end reg.running = true end end -- }}} -- }}} -- {{{ Global functions -- {{{ Register a widget function register(widget, wtype, format, timer, warg) local widget = widget local reg = { -- Set properties wtype = wtype, format = format, timer = timer, warg = warg, widget = widget, -- Update function update = function () update(widget, reg) end, } -- Default to 2s timer if reg.timer == nil then reg.timer = 2 end -- Register a reg object regregister(reg) -- Return a reg object for reuse return reg end -- }}} -- {{{ Unregister a widget function unregister(widget, keep, reg) if reg == nil then for w, i in pairs(registered) do if w == widget then for _, v in pairs(i) do reg = unregister(w, keep, v) end end end return reg end if not keep then for w, i in pairs(registered) do if w == widget then for k, v in pairs(i) do if v == reg then table.remove(registered[w], k) end end end end end -- Stop the timer if timers[reg.update].timer.started then timers[reg.update].timer:stop() end reg.running = false return reg end -- }}} -- {{{ Enable caching of a widget type function cache(wtype) if wtype ~= nil then if widget_cache[wtype] == nil then widget_cache[wtype] = {} end end end -- }}} -- {{{ Force update of widgets function force(wtable) if type(wtable) == "table" then for _, w in pairs(wtable) do update(w, nil, true) end end end -- }}} -- {{{ Suspend all widgets function suspend() for w, i in pairs(registered) do for _, v in pairs(i) do unregister(w, true, v) end end end -- }}} -- {{{ Activate a widget function activate(widget) for w, i in pairs(registered) do if widget == nil or w == widget then for _, v in pairs(i) do regregister(v) end end end end -- }}} -- }}} awesome-extra/vicious/README0000644000000000000000000005310011765367633013106 0ustar 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: - http://git.sysphere.org/vicious/about/ Vicious widget types are a framework for creating your own awesome 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. 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 are used instead, where available: - hddtemp for the HDD Temperature widget type - alsa-utils for the Volume widget type - wireless_tools for the Wireless widget type - curl for widget types accessing network resources Usage ----- To use vicious move it to your awesome configuration directory in $XDG_CONFIG_HOME (usually ~/.config): $ mv vicious $XDG_CONFIG_HOME/awesome/ Vicious will only load modules for widget types you intend to use in your awesome configuration, to avoid having useless modules sitting in your memory. Then add the following to the top of your rc.lua: require("vicious") Once you create a widget (a textbox, graph or a progressbar) call vicious.register() to register it with Vicious: vicious.register(widget, wtype, format, interval, warg) widget - widget created with widget() or awful.widget() (in case of a graph or a progressbar) wtype - widget type or a function - any of the available (default, or custom) widget types can be used here, see below for a list of those provided by Vicious - function - custom functions from your own "awesome" configuration can be registered as widget types, see the "Custom widget types" section format - string argument or a function - $1, $2, $3... will be replaced by their respective value returned by the widget type, some widget types return tables with string keys, in that case use: ${key} - function - function(widget, args) can be used to manipulate data returned by the widget type, more about this below interval - number of seconds between updates of the widget, 2s by default, also read the "Power" section below warg - some widget types require an argument to be passed, for example the battery ID Other functions --------------- Unregister a widget: vicious.unregister(widget, keep) - if keep is true widget will be suspended, waiting to be activated Suspend all widgets: vicious.suspend() - example automation script for the "laptop-mode-tools" start-stop module: http://sysphere.org/~anrxc/local/sources/lmt-vicious.sh Restart suspended widgets: vicious.activate(widget) - if widget is provided only that widget will be activated Enable caching of a widget type: vicious.cache(wtype) - enable caching of values returned by a widget type Force update of widgets: vicious.force({ widget, }) - widget argument is a table with one or more widgets that will be updated Widget types ------------ Widget types consist of worker functions that take the "format" argument given to vicious.register as the first argument, "warg" as the second, and return a table of values to insert in the format string. vicious.widgets.cpu - provides CPU usage for all available CPUs/cores - returns 1st value as usage of all CPUs/cores, 2nd as usage of first CPU/core, 3rd as usage of second CPU/core etc. vicious.widgets.cpuinf - provides speed and cache information for all available CPUs/cores - returns a table with string keys, using CPU ID as a base: {cpu0 mhz}, {cpu0 ghz}, {cpu0 kb}, {cpu0 mb}, {cpu1 mhz} etc. vicious.widgets.cpufreq - provides freq, voltage and governor info for a requested CPU - takes the CPU ID as an argument, i.e. "cpu0" - returns 1st value as frequency of requested CPU in MHz, 2nd in GHz, 3rd as voltage in mV, 4th as voltage in V and 5th as the governor state vicious.widgets.thermal - provides temperature levels of ACPI and coretemp thermal zones - takes the thermal zone as an argument, i.e. "thermal_zone0", or a table with 1st field as thermal zone, 2nd as data source - available data sources are "proc", "core" and "sys" (which is the default when only the zone is provided) and 3rd optional argument as a temperature input file to read - returns 1st value as temperature of requested thermal zone vicious.widgets.uptime - provides system uptime and load information - returns 1st value as uptime in days, 2nd as uptime in hours, 3rd as uptime in minutes, 4th as load average for past 1 minute, 5th for 5 minutes and 6th for 15 minutes vicious.widgets.bat - provides state, charge, and remaining time for a requested battery - takes battery ID as an argument, i.e. "BAT0" - returns 1st value as state of requested battery, 2nd as charge level in percent and 3rd as remaining (charging or discharging) time vicious.widgets.mem - provides RAM and Swap usage statistics - returns 1st value as memory usage in percent, 2nd as memory usage, 3rd as total system memory, 4th as free memory, 5th as swap usage in percent, 6th as swap usage, 7th as total system swap, 8th as free swap and 9th as memory usage with buffers and cache vicious.widgets.os - provides operating system information - returns 1st value as the operating system in use, 2nd as the release version, 3rd as your username, 4th the hostname, 5th as available system entropy and 6th value as available entropy in percent vicious.widgets.fs - provides file system disk space usage - takes an (optional) argument which, if true, includes remote file systems, only local file systems are included by default - returns a table with string keys, using mount points as a base: {/ size_mb}, {/ size_gb}, {/ used_mb}, {/ used_gb}, {/ used_p}, {/ avail_mb}, {/ avail_gb}, {/ avail_p}, {/home size_mb} etc. vicious.widgets.dio - provides I/O statistics for all available storage devices - returns a table with string keys: {sda total_s}, {sda total_kb}, {sda total_mb}, {sda read_s}, {sda read_kb}, {sda read_mb}, {sda write_s}, {sda write_kb}, {sda write_mb}, {sdb1 total_s} etc. vicious.widgets.raid - provides state information for a requested RAID array - takes the RAID array ID as an argument - returns 1st value as the number of assigned, and 2nd as active, devices in the array vicious.widgets.hddtemp - provides hard drive temperatures using the hddtemp daemon - takes the hddtemp listening port as an argument, or defaults to port 7634 - returns a table with string keys, using hard drives as a base: {/dev/sda} and {/dev/sdc} for example vicious.widgets.net - provides state and usage statistics of all network interfaces - returns a table with string keys, using net interfaces as a base: {eth0 carrier}, {eth0 rx_b}, {eth0 tx_b}, {eth0 rx_kb}, {eth0 tx_kb}, {eth0 rx_mb}, {eth0 tx_mb}, {eth0 rx_gb}, {eth0 tx_gb}, {eth0 down_b}, {eth0 up_b}, {eth0 down_kb}, {eth0 up_kb}, {eth0 down_mb}, {eth0 up_mb}, {eth0 down_gb}, {eth0 up_gb}, {eth1 rx_b} etc. vicious.widgets.wifi - provides wireless information for a requested interface - takes the network interface as an argument, i.e. "wlan0" - returns a table with string keys: {ssid}, {mode}, {chan}, {rate}, {link}, {linp} and {sign} vicious.widgets.mbox - provides the subject of last e-mail in a mbox file - takes the full path to the mbox as an argument, or a table with 1st field as path, 2nd as maximum lenght and 3rd (optional) as widget name - if 3rd field is present scrolling will be used - returns 1st value as the subject of the last e-mail vicious.widgets.mboxc - provides the count of total, old and new messages in mbox files - takes a table with full paths to mbox files as an argument - returns 1st value as the total count of messages, 2nd as the count of old messages and 3rd as the count of new messages vicious.widgets.mdir - provides the number of new and unread messages in Maildir structures/directories - takes a table with full paths to Maildir structures as an argument - returns 1st value as the count of new messages and 2nd as the count of "old" messages lacking the Seen flag vicious.widgets.gmail - provides count of new and subject of last e-mail on Gmail - takes an (optional) argument, if it's a number subject will be truncated, if a table, with 1st field as maximum lenght and 2nd the widget name (i.e. "gmailwidget"), scrolling will be used - keeps login information in the ~/.netrc file, example: machine mail.google.com login user password pass - returns a table with string keys: {count} and {subject} vicious.widgets.org - provides agenda statistics for Emacs org-mode - takes a table with full paths to agenda files, that will be parsed, as an argument - returns 1st value as count of tasks you forgot to do, 2nd as count of tasks for today, 3rd as count of tasks for the next 3 days and 4th as count of tasks to do in the week vicious.widgets.pkg - provides number of pending updates on UNIX systems - takes the distribution name as an argument, i.e. "Arch" - returns 1st value as the count of available updates vicious.widgets.mpd - provides Music Player Daemon information - takes a table as an argument, 1st field should be the password (or nil), 2nd the hostname (or nil) and 3rd port (or nil) - if no argument is provided connection attempt will be made to localhost port 6600 with no password - returns a table with string keys: {volume}, {state}, {Artist}, {Title}, {Album}, {Genre} and optionally {Name} and {file} vicious.widgets.volume - provides volume levels and state of requested ALSA mixers - takes the ALSA mixer control as an argument, i.e. "Master", optionally append the card ID or other options, i.e. "PCM -c 0" - returns 1st value as the volume level and 2nd as the mute state of the requested channel vicious.widgets.weather - provides weather information for a requested station - takes the ICAO station code as an argument, i.e. "LDRI" - returns a table with string keys: {city}, {wind}, {windmph}, {windkmh}, {sky}, {weather}, {tempf}, {tempc}, {humid}, {press} vicious.widgets.date - provides access to os.date, with optional time formatting provided as the format string - using regular date sequences - takes optional time offset, in seconds, as an argument for example to calculate time zone differences, otherwise current time is formatted - returns the output of os.date, formatted by provided sequences Custom widget types ------------------- Use any of the existing widget types as a starting point for your own. Write a quick worker function that does the work and plug it in. How data will be formatted, will it be red or blue, should be defined in rc.lua (or somewhere else, outside the actual module). Before writing a widget type you should check if there is already one in the contrib directory of Vicious. The contrib directory contains 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. Richard Kolkovich, a FreeBSD user, published his vicious-fbsd branch. If you are also a BSD user you can find his work here: - http://git.sigil.org/vicious-fbsd/ Some users would like to avoid writing new modules. For them Vicious kept the old Wicked functionality, possibility to register their own functions as widget types. By providing them as the second argument to vicious.register. Your function can accept "format" and "warg" arguments, just like workers. Power and Caching ----------------- When a lot of widgets are in use they, and awesome, can generate a lot of wake-ups and also be very expensive for system resources. This is especially important when running on battery power. It was a big problem with awesome v2 and widgets that used shell scripts to gather data, and with widget libraries written in languages like Ruby. Lua is an extremely fast and efficient programming language, and Vicious takes advantage of that. But suspending Vicious widgets is one way to prevent them from draining your battery, despite that. Update intervals also play a big role, and you can save a lot of power with a smart approach. Don't use intervals like: 5, 10, 30, 60... to avoid harmonics. If you take the 60-second mark as an example, all of your widgets would be executed at that point. Instead think about using only prime numbers, in that case you will have only a few widgets executed at any given time interval. When choosing intervals also consider what a widget actually does. Some widget types read files that reside in memory, others call external utilities and some, like the mbox widget, read big files. Vicious can also cache values returned by widget types. Caching enables you to have multiple widgets using the same widget type. With caching its worker function gets executed only once - which is also great for saving power. - Some widget types keep internal data and if you call one multiple times without caching, the widget that executes it first would modify stored values. This can lead to problems and give you inconsistent data. Remember it for widget types like CPU and Network usage, which compare the old set of data with the new one to calculate current usage. - Widget types that require a widget argument to be passed should be handled carefully. If you are requesting information for different devices then caching should not be used, because you could get inconsistent data. Security -------- At the moment only one widget type (Gmail) requires auth. information in order to get to the data. In the future there could be more, and you should give some thought to the issue of protecting your data. The Gmail widget type by default stores login information in the ~/.netrc file, and you are advised to make sure that file is only readable by the owner. Other than that we can not force all users to conform to one standard, one way of keeping it secure, like in some keyring. First let's clear why we simply don't encrypt the login information and store it in ciphertext. By exposing the algorithm anyone can reverse the encryption steps. Some claim even that's better than plaintext but it's just security trough obscurity. Here are some ideas actually worth your time. Users that have KDE (or parts of it) installed could store their login information into the Kwallet service and request it via DBus from the widget type. It can be done with tools like "dbus-send" and "qdbus". The Gnome keyring should support the same, so those with parts of Gnome installed could use that keyring. Users of GnuPG (and its agent) could consider encrypting the netrc file with their GPG key. Trough the GPG Passphrase Agent they could then decrypt the file transparently while their session is active. 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 registering widgets you have to add them to a wibox (statusbar) in order to actually display them. Date widget datewidget = widget({ type = "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" }) vicious.cache(vicious.widgets.mem) vicious.register(memwidget, vicious.widgets.mem, "$1 ($2MB/$3MB)", 13) - updated every 13 seconds, appends "MB" to 2nd and 3rd returned values and enables caching of this widget type HDD temperature widget hddtempwidget = widget({ type = "textbox" }) vicious.register(hddtempwidget, vicious.widgets.hddtemp, "${/dev/sda} °C", 19) - updated every 19 seconds, requests the temperature level of the {/dev/sda} key/disk and appends "°C" to the returned value, does not provide the port argument so default port is used Mbox widget mboxwidget = widget({ type = "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 argument Battery widget batwidget = awful.widget.progressbar() batwidget:set_width(8) batwidget:set_height(10) 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" }) vicious.register(batwidget, vicious.widgets.bat, "$2", 61, "BAT0") - updated every 61 seconds, requests the current battery charge level and displays a progressbar, provides "BAT0" battery ID as an argument 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" }) vicious.register(cpuwidget, vicious.widgets.cpu, "$1", 3) - updated every 3 seconds, feeds the graph with total usage percentage of all CPUs/cores Format functions ---------------- You can use a function instead of a string as the format parameter. Then you are able to check the value returned by the widget type and change it or perform some action. You can change the color of the battery widget when it goes below a certain point, hide widgets when they return a certain value or maybe use string.format for padding. - Do not confuse this with just coloring the widget, in those cases standard pango markup can be inserted into the format string. The format function will get the widget as its first argument, table with the values otherwise inserted into the format string as its second argument, and will return the text/data to be used for the widget. Example mpdwidget = widget({ type = "textbox" }) vicious.register(mpdwidget, vicious.widgets.mpd, function (widget, args) if args["{state}"] == "Stop" then return "" else return 'MPD: '.. args["{Artist}"]..' - '.. args["{Title}"] end end) - hides the mpd widget when no song is playing, updated every 2 seconds (the default interval) Example uptimewidget = widget({ type = "textbox" }) vicious.register(uptimewidget, vicious.widgets.uptime, function (widget, args) return string.format("Uptime: %2dd %02d:%02d ", args[1], args[2], args[3]) end, 61) - uses string.format for padding uptime values to a minimum amount of digits, updated every 61 seconds When it comes to padding it is also useful to mention how a widget can be configured to have a fixed width. You can set a fixed width on your 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" vicious.register(uptimewidget, vicious.widgets.uptime, "$1 $2:$3", 61) - forces a fixed width of 50px to the uptime widget, and aligns its text to the right Another use case are stacked graphs (aka multigraphs) which Vicious does not handle on its own at the moment, as it's hard to pass on color index arguments elegantly. But they are not unusable, far from it. Example ctext = widget({ type = "textbox"}) cgraph = awful.widget.graph() cgraph:set_width(100):set_height(20) cgraph:set_stack(true):set_max_value(100) cgraph:set_background_color("#494B4F") cgraph:set_stack_colors({ "#FF5656", "#88A175", "#AECF96" }) vicious.register(ctext, vicious.widgets.cpu, function (widget, args) cgraph:add_value(args[2], 1) -- Core 1, color 1 cgraph:add_value(args[3], 2) -- Core 2, color 2 cgraph:add_value(args[4], 3) -- Core 3, color 3 end, 3) - enables graph stacking/multigraph and plots usage of all three CPU cores on a single graph, the textbox "ctext" is just an empty placeholder, graph is updated every 3 seconds 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"}) vicious.register(volumewidget, vicious.widgets.volume, function(widget, args) local label = { ["♫"] = "O", ["♩"] = "M" } return "Volume: " .. args[1] .. "% State: " .. label[args[2]] end, 2, "PCM") - uses a custom table map to modify symbols representing the mixer state; on or off/mute Other ----- Read "awesome" manual pages: - awesome(1) awesomerc(5) Awesome widgets explained: - http://awesome.naquadah.org/wiki/Widgets_in_awesome Example "awesome" configuration: - http://git.sysphere.org/awesome-configs/ Authors ------- Wicked written by: - Lucas de Vries Vicious written by: - Adrian C. (anrxc) Vicious contributors: - Michael Unterkalmsteiner - Martin Striz - Benedikt Sauer - Greg D. - Henning Glawe - Rémy C. - Hiltjo Posthuma - Hagen Schink - Jörg Thalheim awesome-extra/vicious/LICENSE0000644000000000000000000004310311651220347013215 0ustar GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. awesome-extra/vicious/helpers.lua0000644000000000000000000000665511651220736014372 0ustar --------------------------------------------------- -- Licensed under the GNU General Public License v2 -- * (c) 2010, Adrian C. -- * (c) 2009, Rémy C. -- * (c) 2009, Benedikt Sauer -- * (c) 2009, Henning Glawe -- * (c) 2009, Lucas de Vries --------------------------------------------------- -- {{{ Grab environment local pairs = pairs local rawget = rawget local require = require local tonumber = tonumber local io = { open = io.open } local setmetatable = setmetatable local getmetatable = getmetatable local string = { upper = string.upper, format = string.format } -- }}} -- Helpers: provides helper functions for vicious widgets module("vicious.helpers") -- {{{ Variable definitions local scroller = {} -- }}} -- {{{ Helper functions -- {{{ Loader of vicious modules function wrequire(table, key) local module = rawget(table, key) return module or require(table._NAME .. "." .. key) end -- }}} -- {{{ Expose path as a Lua table function pathtotable(dir) return setmetatable({ _path = dir }, { __index = function(table, index) local path = table._path .. '/' .. index local f = io.open(path) if f then local s = f:read("*all") f:close() if s then return s else local o = { _path = path } setmetatable(o, getmetatable(table)) return o end end end }) end -- }}} -- {{{ Format a string with args function format(format, args) for var, val in pairs(args) do format = format:gsub("$" .. (tonumber(var) and var or var:gsub("[-+?*]", function(i) return "%"..i end)), val) end return format end -- }}} -- {{{ Format units to one decimal point function uformat(array, key, value, unit) for u, v in pairs(unit) do array["{"..key.."_"..u.."}"] = string.format("%.1f", value/v) end return array end -- }}} -- {{{ Escape a string function escape(text) local xml_entities = { ["\""] = """, ["&"] = "&", ["'"] = "'", ["<"] = "<", [">"] = ">" } return text and text:gsub("[\"&'<>]", xml_entities) end -- }}} -- {{{ Capitalize a string function capitalize(text) return text and text:gsub("([%w])([%w]*)", function(c, s) return string.upper(c) .. s end) end -- }}} -- {{{ Truncate a string function truncate(text, maxlen) local txtlen = text:len() if txtlen > maxlen then text = text:sub(1, maxlen - 3) .. "..." end return text end -- }}} -- {{{ Scroll through a string function scroll(text, maxlen, widget) if not scroller[widget] then scroller[widget] = { i = 1, d = true } end local txtlen = text:len() local state = scroller[widget] if txtlen > maxlen then if state.d then text = text:sub(state.i, state.i + maxlen) .. "..." state.i = state.i + 3 if maxlen + state.i >= txtlen then state.d = false end else text = "..." .. text:sub(state.i, state.i + maxlen) state.i = state.i - 3 if state.i <= 1 then state.d = true end end end return text end -- }}} -- }}} awesome-extra/vicious/TODO0000644000000000000000000000257511651220736012712 0ustar #-*- mode: org -*- #+TYP_TODO: TODO MAYBE CANCEL WAITING NEXT NOTE DONE #+STARTUP: showall #+STARTUP: hidestars * Vicious ** TODO Implement intelligent multigraph support ** TODO Expand raid to grab data for all available devices ** TODO Consider commiting power drain support to bat.lua ** TODO Document contrib widgets in contrib/README ** TODO Complete the hddtemp fix - In certain setups regexp does not match all devices - The regexp catches the first device name, but last stats - Shortening the match introduced new problems IIRC ** TODO Add fan speed to thermal.lua ** TODO Fix contrib/sensors for Ian - > it does work and provides the lm_sensors > information but only for one cpu core. ** TODO Return values of type number in NET and FS - Note: tonumber() strips decimal points ** MAYBE Simplify scrolling using negative margins + fixed width ** TODO Try to simplify truncating with a fixed width ** NOTE Changelog header --------------------------------------------------- Full changelog is available online: http://git.sysphere.org/vicious/log/?showmsg=1 --------------------------------------------------- * Git ** DONE Git hook post-update not executed on git push ** DONE Git post-update hook does not leave info/refs with correct permissions ** DONE Git persmission are incorrect since 1.6.5, does not honor umask ** TODO Git smart http transport with cgit awesome-extra/flaw/0000755000000000000000000000000011734355656011475 5ustar awesome-extra/flaw/tests/0000755000000000000000000000000011734355656012637 5ustar awesome-extra/flaw/tests/start_in_xephyr.sh0000755000000000000000000000077111734355656016425 0ustar #!/bin/bash # Run Awesome in a nested server for tests [ $# -ne 1 ] && { echo "`basename $0` rc_file"; exit 0; } [ -f $1 ] || { echo "\"$1\" does not exist"; exit 0; } RC_FILE=$1 AWESOME=`which awesome` XEPHYR=`which Xephyr` test -x $AWESOME || { echo "Please install Awesome"; exit 1; } test -x $XEPHYR || { echo "Please install Xephyr"; exit 1; } echo "Starting $XEPHYR" $XEPHYR -ac -br -noreset -screen 800x600 :1 & sleep 1 echo "Starting $AWESOME with $RC_FILE" DISPLAY=:1.0 $AWESOME -c $RC_FILE awesome-extra/flaw/tests/rc.lua0000644000000000000000000003735011734355656013756 0ustar -- Standard awesome library require("awful") require("awful.autofocus") require("awful.rules") -- Theme handling library require("beautiful") -- Notification library require("naughty") -- Flaw Tests require("flaw") -- {{{ Variable definitions -- Themes define colours, icons, and wallpapers beautiful.init("/usr/share/awesome/themes/default/theme.lua") -- Gadgets population. local gadgets = {} -- Calendar gadgets.calendar = flaw.gadget.text.calendar( '', { clock_format = ' | %a %d %B - %H:%M' }) -- Client title gadgets.title = flaw.gadget.text.title( '', { pattern = ' | $title' }) -- GMail gadgets.gmail = flaw.gadget.text.gmail( '', { pattern = ' | GMail: $count ' }) gadgets.gmail:set_tooltip('Unread messages at $timestamp:\n$mails') -- ALSA -- gadgets.alsa_icon = flaw.gadget.AlsaIcon( -- 'alsa', {}, { image = image(beautiful.icon_cpu) }) gadgets.alsa = flaw.gadget.text.alsa('0', { pattern = ' | Vol.:$s_volume% ' }) gadgets.alsa_bar = flaw.gadget.bar.alsa('0') gadgets.alsa_bar.hull:set_vertical(true) gadgets.alsa_bar.hull:set_height(18) gadgets.alsa_bar.hull:set_width(12) -- gadgets.alsa_bar.hull:set_ticks(true) -- gadgets.alsa_bar.hull:set_ticks_size(2) gadgets.alsa_bar.hull:set_background_color(beautiful.bg_normal) gadgets.alsa_bar.hull:set_gradient_colors( { beautiful.fg_normal, beautiful.fg_focus, beautiful.fg_urgent}) -- Create CPU, CPUfreq monitor -- gadgets.cpu_icon = flaw.gadget.CPUIcon( -- 'cpu', {}, { image = image(beautiful.icon_cpu) }) gadgets.cpu_graph = flaw.gadget.graph.cpu( 'cpu', {}, { width = 60, height = 18 }) gadgets.cpu_graph.hull:set_color(beautiful.fg_normal) gadgets.cpu_graph.hull:set_border_color(beautiful.fg_normal) gadgets.cpu_graph.hull:set_background_color(beautiful.bg_normal) -- Create network monitor -- gadgets.net_icon = flaw.gadget.NetIcon( -- 'eth0', {}, { image = image(beautiful.icon_net) }) gadgets.net_graph = flaw.gadget.graph.network( 'eth0', {}, { width = 60, height = 18 }) gadgets.net_graph.hull:set_color(beautiful.fg_normal) gadgets.net_graph.hull:set_border_color(beautiful.fg_normal) gadgets.net_graph.hull:set_background_color(beautiful.bg_normal) -- gadgets.memory_box = flaw.gadget.new('flaw.memory.textbox', '') -- Create battery monitor if flaw.battery ~= nil then gadgets.battery_icon = flaw.gadget.icon.battery( 'BAT0', { my_icons = { image(beautiful.icon_battery_low), image(beautiful.icon_battery_mid), image(beautiful.icon_battery_full) }, my_load_icon = image(beautiful.icon_battery_plugged), my_update = function(self) if self.provider.data.st_symbol == flaw.battery.STATUS_CHARGING then self.widget.image = self.my_load_icon else self.widget.image = self.my_icons[math.floor(self.provider.data.load / 30) + 1] end end }, { image = image(beautiful.icon_battery_full) } ) gadgets.battery_icon:add_event( flaw.event.EdgeTrigger:new{ condition = function(d) return d.load < 60 end }, function (g) g:my_update() end ) gadgets.battery_icon:add_event( flaw.event.EdgeTrigger:new{ condition = function(d) return d.load < 30 end }, function (g) g:my_update() end ) gadgets.battery_icon:add_event( flaw.event.EdgeTrigger:new{ condition = function(d) return d.st_symbol == flaw.battery.STATUS_CHARGING end }, function (g) g:my_update() end ) gadgets.battery_icon:add_event( flaw.event.LatchTrigger:new{condition = function(d) return d.load < 10 end }, function(g) naughty.notify{ title = "Battery Warning", text = "Battery low! " .. g.provider.data.load .. "% left!", timeout = 10, position = "top_right", fg = beautiful.fg_focus, bg = beautiful.bg_focus} end ) gadgets.battery_box = flaw.gadget.text.battery( 'BAT0', { pattern = '$load% $time' } ) gadgets.battery_box:add_event( flaw.event.LatchTrigger:new{condition = function(d) return d.load < 60 end }, function(g) g.pattern = '$load%' end ) gadgets.battery_box:add_event( flaw.event.LatchTrigger:new{condition = function(d) return d.load < 30 end }, function(g) g.pattern = '$load%' end ) end -- Create wifi monitor -- local w_wifi_widget = wifi.widget_new('wlan0') -- Create sound monitor -- local w_sound_widget = sound.widget_new() -- This is used later as the default terminal and editor to run. terminal = "x-terminal-emulator" editor = os.getenv("EDITOR") or "editor" editor_cmd = terminal .. " -e " .. editor -- Default modkey. -- Usually, Mod4 is the key with a logo between Control and Alt. -- If you do not like this or do not have such a key, -- I suggest you to remap Mod4 to another key using xmodmap or other tools. -- However, you can use another modifier like Mod1, but it may interact with others. modkey = "Mod4" -- Table of layouts to cover with awful.layout.inc, order matters. layouts = { awful.layout.suit.floating, awful.layout.suit.tile, awful.layout.suit.tile.left, awful.layout.suit.tile.bottom, awful.layout.suit.tile.top, awful.layout.suit.fair, awful.layout.suit.fair.horizontal, awful.layout.suit.spiral, awful.layout.suit.spiral.dwindle, awful.layout.suit.max, awful.layout.suit.max.fullscreen, awful.layout.suit.magnifier } -- }}} -- {{{ Tags -- Define a tag table which hold all screen tags. tags = {} for s = 1, screen.count() do -- Each screen has its own tag table. tags[s] = awful.tag({ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s, layouts[1]) end -- }}} -- {{{ Menu -- Create a laucher widget and a main menu myawesomemenu = { { "manual", terminal .. " -e man awesome" }, { "edit config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua" }, { "restart", awesome.restart }, { "quit", awesome.quit } } mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon }, { "open terminal", terminal } } }) mylauncher = awful.widget.launcher({ image = image(beautiful.awesome_icon), menu = mymainmenu }) -- }}} -- {{{ Wibox -- Create a wibox for each screen and add it mywibox = {} mylayoutbox = {} mytaglist = {} mytaglist.buttons = awful.util.table.join( awful.button({ }, 1, awful.tag.viewonly), awful.button({ modkey }, 1, awful.client.movetotag), awful.button({ }, 3, awful.tag.viewtoggle), awful.button({ modkey }, 3, awful.client.toggletag), awful.button({ }, 4, awful.tag.viewnext), awful.button({ }, 5, awful.tag.viewprev) ) for s = 1, screen.count() do -- Create an imagebox widget which will contains an icon indicating which layout we're using. -- We need one layoutbox per screen. mylayoutbox[s] = awful.widget.layoutbox(s) mylayoutbox[s]:buttons(awful.util.table.join( awful.button({ }, 1, function () awful.layout.inc(layouts, 1) end), awful.button({ }, 3, function () awful.layout.inc(layouts, -1) end), awful.button({ }, 4, function () awful.layout.inc(layouts, 1) end), awful.button({ }, 5, function () awful.layout.inc(layouts, -1) end))) -- Create a taglist widget mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.label.all, mytaglist.buttons) -- Create the wibox mywibox[s] = awful.wibox({ position = "top", screen = s }) -- Add widgets to the wibox - order matters mywibox[s].widgets = { { mylauncher, mytaglist[s], gadgets.calendar.widget, gadgets.gmail.widget, gadgets.alsa.widget, gadgets.alsa_bar.widget, -- gadgets.cpu_icon.widget or nil, gadgets.cpu_graph.widget or nil, -- gadgets.net_icon.widget or nil, gadgets.net_graph.widget or nil, gadgets.battery_box and gadgets.battery_box.widget or nil, gadgets.battery_icon and gadgets.battery_icon.widget or nil, gadgets.title.widget, layout = awful.widget.layout.horizontal.leftright }, mylayoutbox[s], layout = awful.widget.layout.horizontal.rightleft } end -- }}} -- {{{ Mouse bindings root.buttons(awful.util.table.join( awful.button({ }, 3, function () mymainmenu:toggle() end), awful.button({ }, 4, awful.tag.viewnext), awful.button({ }, 5, awful.tag.viewprev) )) -- }}} -- {{{ Key bindings globalkeys = awful.util.table.join( awful.key({ modkey, }, "Left", awful.tag.viewprev ), awful.key({ modkey, }, "Right", awful.tag.viewnext ), awful.key({ modkey, }, "Escape", awful.tag.history.restore), awful.key({ modkey, }, "j", function () awful.client.focus.byidx( 1) if client.focus then client.focus:raise() end end), awful.key({ modkey, }, "k", function () awful.client.focus.byidx(-1) if client.focus then client.focus:raise() end end), awful.key({ modkey, }, "w", function () mymainmenu:show(true) end), -- Layout manipulation awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end), awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end), awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end), awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end), awful.key({ modkey, }, "u", awful.client.urgent.jumpto), awful.key({ modkey, }, "Tab", function () awful.client.focus.history.previous() if client.focus then client.focus:raise() end end), -- Standard program awful.key({ modkey, }, "Return", function () awful.util.spawn(terminal) end), awful.key({ modkey, "Control" }, "r", awesome.restart), awful.key({ modkey, "Shift" }, "q", awesome.quit), awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end), awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end), awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1) end), awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end), awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1) end), awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end), awful.key({ modkey, }, "space", function () awful.layout.inc(layouts, 1) end), awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end) ) clientkeys = awful.util.table.join( awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end), awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end), awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ), awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end), awful.key({ modkey, }, "o", awful.client.movetoscreen ), awful.key({ modkey, "Shift" }, "r", function (c) c:redraw() end), awful.key({ modkey, }, "n", function (c) c.minimized = not c.minimized end), awful.key({ modkey, }, "m", function (c) c.maximized_horizontal = not c.maximized_horizontal c.maximized_vertical = not c.maximized_vertical end) ) -- Compute the maximum number of digit we need, limited to 9 keynumber = 0 for s = 1, screen.count() do keynumber = math.min(9, math.max(#tags[s], keynumber)); end -- Bind all key numbers to tags. -- Be careful: we use keycodes to make it works on any keyboard layout. -- This should map on the top row of your keyboard, usually 1 to 9. for i = 1, keynumber do globalkeys = awful.util.table.join(globalkeys, awful.key({ modkey }, "#" .. i + 9, function () local screen = mouse.screen if tags[screen][i] then awful.tag.viewonly(tags[screen][i]) end end), awful.key({ modkey, "Control" }, "#" .. i + 9, function () local screen = mouse.screen if tags[screen][i] then awful.tag.viewtoggle(tags[screen][i]) end end), awful.key({ modkey, "Shift" }, "#" .. i + 9, function () if client.focus and tags[client.focus.screen][i] then awful.client.movetotag(tags[client.focus.screen][i]) end end), awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9, function () if client.focus and tags[client.focus.screen][i] then awful.client.toggletag(tags[client.focus.screen][i]) end end)) end clientbuttons = awful.util.table.join( awful.button({ }, 1, function (c) client.focus = c; c:raise() end), awful.button({ modkey }, 1, awful.mouse.client.move), awful.button({ modkey }, 3, awful.mouse.client.resize)) -- Set keys root.keys(globalkeys) -- }}} -- {{{ Rules awful.rules.rules = { -- All clients will match this rule. { rule = { }, properties = { border_width = beautiful.border_width, border_color = beautiful.border_normal, focus = true, keys = clientkeys, buttons = clientbuttons } }, { rule = { class = "MPlayer" }, properties = { floating = true } }, { rule = { class = "pinentry" }, properties = { floating = true } }, { rule = { class = "gimp" }, properties = { floating = true } }, -- Set Firefox to always map on tags number 2 of screen 1. -- { rule = { class = "Firefox" }, -- properties = { tag = tags[1][2] } }, } -- }}} -- {{{ Signals -- Signal function to execute when a new client appears. client.add_signal("manage", function (c, startup) -- Add a titlebar -- awful.titlebar.add(c, { modkey = modkey }) -- Enable sloppy focus c:add_signal("mouse::enter", function(c) if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier and awful.client.focus.filter(c) then client.focus = c end end) if not startup then -- Set the windows at the slave, -- i.e. put it at the end of others instead of setting it master. -- awful.client.setslave(c) -- Put windows in a smart way, only if they does not set an initial position. if not c.size_hints.user_position and not c.size_hints.program_position then awful.placement.no_overlap(c) awful.placement.no_offscreen(c) end end end) client.add_signal("focus", function(c) c.border_color = beautiful.border_focus end) client.add_signal("unfocus", function(c) c.border_color = beautiful.border_normal end) -- }}} flaw.check_modules() awesome-extra/flaw/alsa.lua0000644000000000000000000002034711734355656013126 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local io = io local math = math local os = os local string = string local tonumber = tonumber local beautiful = require('beautiful') local naughty = require('naughty') local awful = { button = require("awful.button"), util = require("awful.util"), } local flaw = { helper = require('flaw.helper'), gadget = require('flaw.gadget'), provider = require('flaw.provider') } --- ALSA control gadgets and provider. -- --

This module contains a provider for ALSA information and two -- gadgets: a text gadget and an icon gadget.

-- --

Gadgets

-- --

The ID of the gadgets designates the identifier of the audio -- card to control. ALSA gadgets provide no custom parameters. See the -- gadget module documentation to learn -- about standard gadgets parameters.

-- --

All ALSA gadgets specialize their standard counterpart to allow -- you to control the volume from the Master channel of the monitored -- card. The buttons 4 and 5 of the mouse - which should normally be -- bound to the wheel up and down movements - allow you to change the -- sound level, whereas the left click mutes the channel.

-- --

Icon Gadget

-- --

The ALSA icon gadget can be instantiated by indexing the gadget -- module with icon.alsa. Here is an exemple which -- assumes the card identifier is 0, and the path of the icon to -- display is stored in a beautiful property.

-- --
-- g = flaw.gadget.icon.alsa(
--    '0', {}, { image = image(beautiful.sound_icon) })
--
-- --

Text Gadget

-- --

The ALSA text gadget can be instantiated by indexing the gadget -- module with text.alsa. By default, the gadget pattern -- is '$volume%'. See the provider's documentation below -- to learn about the available variables.

-- --
-- g = flaw.gadget.text.alsa('0') --
-- --

Provider

-- --

The ALSA provider relies on the amixer program to -- get the master channel status as well as to modify to sound -- level

-- --

The ALSA provider data is composed of the following fields.

-- --
    -- --
  • volume -- --

    The sound level in percent on the Master channel on the monitored card, -- as a number.

  • -- --
  • s_volume -- --

    A string which represents the current sound level in percent of -- the Master channel on the monitored card, with a visual hint when -- it is muted. The string is 3 characters long, padded by the -- left.

  • -- --
-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2010,2011 David Soulayrol module('flaw.alsa') CHANNEL = 'Master' --- The ALSA provider prototype. -- --

The ALSA provider type is set to alsa._NAME.

-- -- @class table -- @name ALSAProvider ALSAProvider = flaw.provider.CyclicProvider:new{ type = _NAME } --- Callback for provider refresh. function ALSAProvider:do_refresh() local f = io.popen("amixer -c " .. self.id .. " -- sget " .. CHANNEL) -- The following is shamelessly ripped of the Obvious lib. -- TODO: In the future, it would be nice to analyse the different -- playback channels (see the amix output). if f ~= nil then local status = f:read('*all') if status ~=nil then self.data.s_volume = flaw.helper.strings.pad_left( string.match(status, '(%d?%d?%d)%%'), 3) self.data.volume = tonumber(self.data.s_volume) or 0 status = string.match(status, '%[(o[^%]]*)%]') if status == nil or string.find(status, 'off', 1, true) then self.data.s_volume = '---' end end f:close() end end --- Raise the sound level on the Master channel from the monitored --- card. -- -- @param offset the value to add to the current sound level. This -- value is one if the paramenter is nil. function ALSAProvider:raise(offset) awful.util.spawn('amixer -q -c ' .. self.id .. ' sset ' .. CHANNEL .. ' ' .. (offset or 1) .. '+', false) self:do_refresh() self:refresh_gadgets(true) end --- Lower the sound level on the Master channel from the monitored --- card. -- -- @param offset the value to remove from the current sound -- level. This value is one if the paramenter is -- nil. function ALSAProvider:lower(offset) awful.util.spawn('amixer -q -c ' .. self.id .. ' sset ' .. CHANNEL .. ' ' .. (offset or 1) .. '-', false) self:do_refresh() self:refresh_gadgets(true) end --- Mute the Master channel from the monitored card. function ALSAProvider:mute() awful.util.spawn('amixer -q -c ' .. self.id .. ' sset ' .. CHANNEL .. ' toggle', false) self:do_refresh() self:refresh_gadgets(true) end --- A factory for ALSA providers. -- --

Only one provider is built for a card ID. Created providers are -- stored in the global provider cache.

-- -- @param id the identifier of the card for which the new -- provider should gather information -- @return a brand new ALSA provider, or an existing one if the -- given ID was already used to create one. function provider_factory(id) local p = flaw.provider.get(_NAME, id) -- Create the provider if necessary. if p == nil then p = ALSAProvider:new{ id = id, data = { volume = 0, s_volume = '---'} } flaw.provider.add(p) end return p end -- A Text gadget prototype for ALSA status display. ALSATextGadget = flaw.gadget.TextGadget:new{} -- Create the wrapped gadget. function ALSATextGadget:create(wopt) flaw.gadget.TextGadget.create(self, wopt) self.widget:buttons( awful.util.table.join( awful.button({ }, 4, function() self.provider:raise() end), awful.button({ }, 5, function() self.provider:lower() end), awful.button({ }, 1, function() self.provider:mute() end))) end -- A progress bar gadget prototype for ALSA status display. ALSABarGadget = flaw.gadget.BarGadget:new{} -- Create the wrapped gadget. function ALSABarGadget:create(wopt) flaw.gadget.BarGadget.create(self, wopt) self.widget:buttons( awful.util.table.join( awful.button({ }, 4, function() self.provider:raise() end), awful.button({ }, 5, function() self.provider:lower() end), awful.button({ }, 1, function() self.provider:mute() end))) end -- An icon gadget prototype for ALSA status display. ALSAIconGadget = flaw.gadget.IconGadget:new{} -- Create the wrapped gadget. function ALSAIconGadget:create(wopt) flaw.gadget.TextGadget.create(self, wopt) self.widget:buttons( awful.util.table.join( awful.button({ }, 4, function() self.provider:raise() end), awful.button({ }, 5, function() self.provider:lower() end), awful.button({ }, 1, function() self.provider:mute() end))) end --- Module initialization routine. -- --

This method tests the available information on the system. If -- alsa data can be found, if registers gadgets and returns the -- module; otherwise it simply returns nil.

-- -- @return return this module if it can be used on the system, -- false otherwise. function init() -- TODO: test alsa. flaw.gadget.register.bar( _M, { delay = 1, value = 'volume' }, {}, ALSABarGadget) flaw.gadget.register.text( _M, { delay = 1, pattern = '$s_volume%' }, {}, ALSATextGadget) flaw.gadget.register.icon(_M, { delay = 1 }, {}, ALSAIconGadget) return _M end awesome-extra/flaw/luadoc/0000755000000000000000000000000011734355656012744 5ustar awesome-extra/flaw/luadoc/doclet/0000755000000000000000000000000011734355656014216 5ustar awesome-extra/flaw/luadoc/doclet/html/0000755000000000000000000000000011734355656015162 5ustar awesome-extra/flaw/luadoc/doclet/html/table.lp0000644000000000000000000000063111734355656016606 0ustar
<%=tab.name%>
<%=tab.description:match('^[%a%d%s]*%. (.*)$') or tab.description%> <%if type(tab.field) == "table" and #tab.field > 0 then%> Fields
    <%for p = 1, #tab.field do%>
  • <%=tab.field[p]%>: <%=tab.field[tab.field[p]] or ""%>
  • <%end%>
<%end%>
awesome-extra/flaw/luadoc/doclet/html/function.lp0000644000000000000000000000273211734355656017350 0ustar <% if module_doc then from = "modules/"..module_doc.name elseif file_doc then from = "files/.."..file_doc.name else from = "" end %>
<%=func.private and "local " or ""%><%=func.name%> (<%=table.concat(func.param, ", ")%>)
<%=func.description:match("^[ \t]*(.-)[ \t]*$"):match('^[%a%d%s]*%. (.*)$') or '

' .. func.description .. '

'%> <%if type(func.param) == "table" and #func.param > 0 then%>

Parameters

    <%for p = 1, #func.param do%>
  • <%=func.param[p]%>: <%=func.param[func.param[p]] or ""%>
  • <%end%>
<%end%> <%if type(func.usage) == "string" then%>

Usage:

<%=func.usage%> <%elseif type(func.usage) == "table" then%>

Usage

    <%for _, usage in ipairs(func.usage) do%>
  • <%= usage %> <%end%>
<%end%> <%if type(func.ret) == "string" then%>

Return value:

<%=func.ret%> <%elseif type(func.ret) == "table" then%>

Return values:

    <%for _, ret in ipairs(func.ret) do%>
  1. <%= ret %> <%end%>
<%end%> <%if type(func.see) == "string" then %>

See also:

<%=func.see%> <%elseif type(func.see) == "table" and #func.see > 0 then %>

See also:

<%end%>
awesome-extra/flaw/luadoc/doclet/html/module.lp0000644000000000000000000000702511734355656017010 0ustar Flaw Reference Manual: <%=module_doc.name%>

Module <%=module_doc.name%>

<%if module_doc.copyright then%>

Copyright© <%=module_doc.copyright%>

<%end%> <%if module_doc.author then%>

<%= #module_doc.author>1 and "Authors" or "Author" %>:

<%for _, author in ipairs(module_doc.author) do%>

   <%= author %>

<%end%> <%end%> <%if module_doc.release then%>

Release: <%=module_doc.release%>

<%end%>
<%=module_doc.description:match('^[%a%d%s]*%. (.*)$') or module_doc.description%> <%if #module_doc.functions > 0 then%>

Functions

<%for _, func_name in ipairs(module_doc.functions) do local func_data = module_doc.functions[func_name]%> <%end%>
<%=func_data.private and "local " or ""%><%=func_name%> (<%=table.concat(module_doc.functions[func_name].param, ", ")%>) <%=module_doc.functions[func_name].summary%>
<%end%> <%if #module_doc.tables > 0 then%>

Tables

<%for _, tab_name in ipairs(module_doc.tables) do%> <%end%>
<%=tab_name%> <%=module_doc.tables[tab_name].summary%>
<%end%>

<%if #module_doc.functions > 0 then%>

Functions

<%for _, func_name in ipairs(module_doc.functions) do%> <%=luadoc.doclet.html.include("function.lp", { doc=doc, module_doc=module_doc, func=module_doc.functions[func_name] })%> <%end%>
<%end%> <%if #module_doc.tables > 0 then%>

Tables

<%for _, tab_name in ipairs(module_doc.tables) do%> <%=luadoc.doclet.html.include("table.lp", { doc=doc, module_doc=module_doc, tab=module_doc.tables[tab_name] })%> <%end%>
<%end%>
awesome-extra/flaw/luadoc/doclet/html/header.lp0000644000000000000000000000055611734355656016755 0ustar <% if module_doc then from = "modules/"..module_doc.name elseif file_doc then from = "files/.."..file_doc.name else from = "" end %>
A Lua OO management framework for Awesome WM widgets.
awesome-extra/flaw/luadoc/doclet/html/luadoc.css0000644000000000000000000001273511734355656017153 0ustar body { margin-left: 1em; margin-right: 1em; font-family: arial, helvetica, geneva, sans-serif; background-color:#ffffff; margin:0px; } code { font-family: "Andale Mono", monospace; } tt { font-family: "Andale Mono", monospace; } body, td, th { font-size: 11pt; } h1, h2, h3, h4 { margin-left: 0em; } textarea, pre, tt { font-size:10pt; } body, td, th { color:#000000; } small { font-size:0.85em; } h1 { font-size:2em; } h2 { font-size:1.5em; } h3 { font-size:1.15em; } h4 { font-size:1.06em; } a:link { font-weight:bold; color: #004080; text-decoration: none; } a:visited { font-weight:bold; color: #006699; text-decoration: none; } a:link:hover { text-decoration: underline; } hr { color:#cccccc } img { border-width: 0px; } h3 { padding-top: 1em; } p { margin-left: 1em; } p.name { font-family: "Andale Mono", monospace; padding-top: 1em; margin-left: 0em; } blockquote { margin-left: 3em; } div.meta { color: #aa2222; padding: .2em; font-size: .7em; line-height: 50%; } div.example { background-color: #f0f0f0; border: 1px solid silver; padding: .5em; margin-left: 2em; margin-right: 1em; font-family: "Andale Mono", monospace; font-size: smaller; } hr { margin-left: 0em; background: #00007f; border: 0px; height: 1px; } ul { list-style-type: disc; } table.index { border: 1px #00007f; } table.index td { text-align: left; vertical-align: top; } table.index ul { padding-top: 0em; margin-top: 0em; } table { border: 1px solid black; border-collapse: collapse; margin-left: auto; margin-right: auto; } th { border: 1px solid black; padding: 0.5em; } td { border: 1px solid black; padding: 0.5em; } div.header, div.footer { margin-left: 0em; } #container { width: 80%; margin-left: auto; margin-right: auto; } #header { color:#000000; background-color: #ffffff; text-align: right; } #product_logo { } #product_name { font-size: 2em; } #product_description { font-style: italic; } #main { } #navigation { float: right; width: 16em; margin: 1em; vertical-align: top; background-color: #f0f0f0; border: 2px solid #cccccc; overflow: hidden; } #navigation h1 { background-color:#e7e7e7; font-size:1.1em; color:#000000; text-align:left; margin:0px; padding:0.2em; border-top:1px solid #dddddd; border-bottom:1px solid #dddddd; } #navigation ul { font-size:1em; list-style-type: none; padding: 0; margin: 1px; } #navigation li { text-indent: -1em; margin: 0em 0em 0em 0.5em; display: block; padding: 3px 0px 0px 12px; } #navigation li li a { padding: 0px 3px 0px -1em; } #content { padding: 1em; background-color: #ffffff; } #footer { clear: both; margin: 0; padding: 5px; border-top: 2px solid #cccccc; background-color: #ffffff; } @media print { body { font: 12pt "Times New Roman", "TimeNR", Times, serif; } a { font-weight:bold; color: #004080; text-decoration: underline; } #main { background-color: #ffffff; border-left: 0px; } #container { margin-left: 2%; margin-right: 2%; background-color: #ffffff; } #content { margin-left: 0px; padding: 1em; border-left: 0px; border-right: 0px; background-color: #ffffff; } #navigation { display: none; } #footer { display: none; } div.example { font-family: "Andale Mono", monospace; font-size: 10pt; page-break-inside: avoid; } } table.module_list { margin-left: 2em; margin-right: 1em; } table.module_list td { border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; } table.module_list td.name { background-color: #f0f0f0; } table.module_list td.summary { width: 100%; } table.module_list th { background-color: #e7e7e7; border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; } table.file_list { margin-left: 2em; margin-right: 1em; border-width: 1px; border-style: solid; border-color: #cccccc; border-collapse: collapse; } table.file_list td { border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; } table.file_list td.name { background-color: #f0f0f0; } table.file_list td.summary { width: 100%; } table.function_list { margin-left: 2em; margin-right: 1em; border-width: 1px; border-style: solid; border-color: #cccccc; border-collapse: collapse; } table.function_list td { border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; } table.function_list td.name { background-color: #f0f0f0; } table.function_list td.summary { width: 100%; } table.table_list { margin-left: 2em; margin-right: 1em; border-width: 1px; border-style: solid; border-color: #cccccc; border-collapse: collapse; } table.table_list td { border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; } table.table_list td.name { background-color: #f0f0f0; } table.table_list td.summary { width: 100%; } dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} dl.function dd {padding-bottom: 1em;} dl.function h3 {padding: 0; margin: 0; font-size: medium;} dl.table dt {border-top: 1px solid #ccc; padding-top: 1em;} dl.table dd {padding-bottom: 1em;} dl.table h3 {padding: 0; margin: 0; font-size: medium;} #TODO: make module_list, file_list, function_list, table_list inherit from a list awesome-extra/flaw/luadoc/doclet/html/index.lp0000644000000000000000000001014411734355656016626 0ustar Flaw Reference Manual " type="text/css" />

Introduction

flaw is a Lua object oriented package providing mechanisms to easily handle the configuration and the management of awesome widgets. flaw is aimed at being simple and resources efficient. To achieve these goals, it minimises system resources access and provides asynchronous events capabilities. The core flaw concepts are detailed in the gadget, provider and event modules.

flaw provides many gadgets for common system information (like CPU or memory activity). It also proposes a simple API to extend all core objects, allowing you to write new system resources interfaces or to automate the configuration of new widgets.

Installation

The source code of flaw is hosted on GitHub and can be browsed here. There is neither archive nor stable release at this time.

The only dependency of flaw, besides the need to run it inside awesome of course, is the lua-filesystem package which can be found at LuaForge.net.

<%if not options.nomodules and #doc.modules > 0 then%>

Documentation

<%for _, modulename in ipairs(doc.modules) do%> <%end%>
Modules
<%=modulename%> <%=doc.modules[modulename].summary%>
<%end%>

Credits and License

The awesome wiki proposes a lot of more common Lua extensions. Though their design and target differ, all of them provide similar information like CPU or network status and share some algorithms. Thus, the core functions of many modules developped in flaw come from wicked or vicious. Many thanks to all the contributors to these Lua extensions.

flaw is licensed under the GNU General Public License v3.

awesome-extra/flaw/luadoc/doclet/html/menu.lp0000644000000000000000000000103611734355656016463 0ustar <% if module_doc then from = "modules/"..module_doc.name elseif file_doc then from = "files/.."..file_doc.name else from = "" end %> <%if not options.nomodules and #doc.modules > 0 then%>

Modules

    <%for _, modulename in ipairs(doc.modules) do if module_doc and module_doc.name == modulename then%>
  • <%=modulename%>
  • <%else%>
  • <%=modulename%>
  • <%end%> <%end%>
<%end%> awesome-extra/flaw/luadoc/doclet/html/footer.lp0000644000000000000000000000026111734355656017014 0ustar

Valid XHTML 1.0

awesome-extra/flaw/gadget.lua0000644000000000000000000005442111734355656013441 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2009,2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local ipairs = ipairs local pairs = pairs local setmetatable = setmetatable local string = string local tonumber = tonumber local awful = { widget = require('awful.widget'), tooltip = require('awful.tooltip'), util = require('awful.util'), } local capi = { widget = widget, } local flaw = { helper = require('flaw.helper'), } --- Core gadgets factory and handling. -- --

To add functionality to awesome widgets, flaw defines -- gadget objects, which are a wrapper around a widget. Gadgets have -- properties, events, a refresh mechanism and a data provider. Even -- though gadgets could wrap any awesome widget type, -- flaw is focused on the most commonly used to report -- information: text boxes, image boxes, graphs or progress -- bars. These gadgets are TextGadget, GraphGadget, BarGadget and IconGadget which embed a text -- box, a graph, a progress bar and an image box -- respectively.

-- --

flaw provides many gadgets for common system information -- (like battery, CPU or memory activity) in different modules. This -- one contains the core gadget prototypes and functions.

-- --

Instantiation, Initialization Parameters

-- --

The following is the complete pattern to instantiate a -- gadget:

-- --
-- g = flaw.gadget.<type>.<name>(<id>, <gopts>, <wopts>) --
-- --

A gadget is first identified by its type and its -- name. The type is what identifies the -- gadget kind and can be Text, Icon, -- Graph and Bar. The name is -- usually the name of the module which defines it (eg. the battery -- module defines battery gadgets).

-- --

Whatever the gadget, up to three parameters can be passed at -- creation time, only the first being mandatory.

-- --
    -- --
  • id -- --

    This first and most important parameter is the gadget -- identifier, or ID. It is altogether the gadget unique name and a -- string that can be used by this gadget provider to identify a -- resource (eg. the CPU to monitor or the id of the battery). Whether -- the provider needs an ID or not is described in service modules -- pages, but this parameter must always be non-null.

  • -- --
  • gopts -- --

    The next parameter is a table providing properties for the -- gadget to create. Again, modules documentation will provide -- information on the available properties. This table can also be -- used to store user data which will be available in the event -- triggering functions for example.

  • -- --
  • wopts -- --

    The last parameter is another table providing properties for the -- wrapped awful widget. The acceptable options are detailed in -- the awesome documentation.

  • -- --
-- --

All created gadgets are kept in a global store from which they can be -- retrieved anytime. This store knows not only about gadgets -- instances, but also about their prototype, their provider, and -- defaults properties.

-- --

Usage in awesome configuration

-- --

Gadgets are meant to be displayed in wiboxes, like any -- other awful widget. Actually, it is the wrapped widget that -- will be added to the wibox. To achieve this, every gadget -- exposes its underlying widget with the widget -- member.

-- --

Types Details

-- --

Icon Gadgets

-- --

Icon gadgets wrap the awful imagebox widget. They -- can display an image and that is all, which makes them the simpler -- gadget provided by flaw. What's interesting about them -- though is that like any other gadget they rely on one provider and -- can make use of events.

-- --

Assuming the beautiful property battery_icon is the -- path to a default battery icon path, the following statement -- creates a new battery status icon gadget. Note the -- image widget property which is explained in -- awful documentation.

-- --
-- g = flaw.gadget.icon.battery(
--    'BAT0', {}, { image = image(beautiful.battery_icon) })
--
-- --

Text Gadgets

-- --

Text gadgets allow you to display any textual information. What -- makes them really interesting is that the display can be used to -- format information returned by the provider associated to the -- gadget.

-- --

All text gadgets provide a default content related to the -- information they gather from the provider (percents of available -- memory, or of battery load for example). The pattern -- gadget option allows every text gadget to be customized.

-- --
-- g = flaw.gadget.text.alsa('0',
--    { pattern = '<span color="#ffffff"> -- $volume</span>%($mute)' }) --
-- --

The variables to be formatted must be prefixed by a dollar -- sign. The available variables are detailed in the providers -- documentations.

-- --

Graph Gadgets

-- --

Graph gadgets are an interesting way to represent data variation -- in the time. As of text gadgets, all graph gadgets provide default -- content to be drawn. This content can be customized uing the -- values gadget option.

-- --
-- g = flaw.gadget.graph.memory('', { values = {'free'} }, {
--    width = '35',
--    height = '0.8',
--    grow = 'right',
--    bg = beautiful.bg_normal,
--    fg = beautiful.fg_normal,
--    max_value = '100',
-- }) --
-- --

Bar Gadgets

-- --

FIXME

-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2009,2010,2011 David Soulayrol module('flaw.gadget') --- Types store. -- --

This table indexes the available gadget types and their default -- implementation.

-- --

This table is private to the gadget module. It is -- mainly used as a reference for registering gadget prototypes.

-- -- @class table -- @name _gadgets_types local _gadgets_types = {} --- Global gadgets store. -- --

This table stores all the registered prototypes as well as all -- the gagdet instances. The store behaves like a dictionnary where -- the keys are prototype types and entries a table which -- contains:

-- --
    --
  • The prototype itself.
  • --
  • A factory for the provider used by the prototype.
  • --
  • A table of instances.
  • --
  • A table of default values to be set on each new instance.
  • --
-- --

This table is private to the gadget module. It can -- be accessed using the get and register functions of this -- module.

-- -- @class table -- @name _gadgets_cache local _gadgets_cache = {} --- Store a gadget prototype. -- --

This function creates a new entry in the global store. This -- entry retains the given prototype, provider factory and defaults -- tables and associates a gadget instance table to them.

-- --

The function fails if the given prototype is nil or has a nil -- type.

-- --

Note that unless you create your own gadget prototype, you do -- not have to call this function. Also note that the current -- implementation silently overwrites the previous entry if it -- existed.

-- -- @param t the type of prototype to register. -- @param n the name of prototype to register. -- @param p the prototype to register. -- @param pf the provider factory to use when creating a new gadget -- using this new prototype. -- @param gopt the default prototype options. -- @param wopt the default options for the wrapped widget. function register_prototype(t, n, p, pf, gopt, wopt) if t == nil or n == nil or p == nil or pf == nil then flaw.helper.debug.error('flaw.gadget.register_prototype: invalid arguments.') return end if _gadgets_cache[t] == nil then flaw.helper.debug.error('flaw.gadget.register_prototype: invalid type: ' .. t) return end -- Keep only the latest part of a dotted notation in name. n = n:gsub('^%w*%.', '') _gadgets_cache[t][n] = { prototype = p, provider_factory = pf, instances = {}, defaults = { gadget = gopt or {}, widget = wopt or {} } } end --- Store a gadget instance. -- --

This function stores the given instance in the global gadgets -- store. It fails if the instance is invalid, that is if it is nil or -- if its type or its ID is nil. It also fails if the store has no -- entry for this gadget type.

-- --

You normally do not have to call this function since it is -- silently invoked each time you call the gadget factory new function.

-- -- @param t the type of gadget to store. -- @param g the gadget to store. -- @return The gadget stored, or nil if the given gadget could not be stored. function add(t, n, g) if t == nil or n == nil or g == nil or g.id == nil then flaw.helper.debug.error('flaw.gadget.add: invalid gadget.') else if _gadgets_cache[t] == nil or _gadgets_cache[t][n] == nil then flaw.helper.debug.error('flaw.gadget.add: unknown gadget class: ' .. g.type) end _gadgets_cache[t][n].instances[g.id] = g return g end return nil end --- Retrieve a gadget instance. -- --

This function returns the gadget matching the given -- information. It immediately fails if the given type or identifier -- is nil. It also fails if no gadget in the store matches the given -- parameters.

-- -- @param t the type of the gadget to retrieve. -- @param id the uniquer identifier of the gadget to retrieve. -- @return The matching gadget instance, or nil if information was -- incomplete or if there is no such gadget. function get(t, n, id) if t ~= nil and n ~= nil and id ~= nil then return _gadgets_cache[t] and _gadgets_cache[t][n] ~= nil and _gadgets_cache[t].instances[id] end flaw.helper.debug.error('flaw.gadget.get: invalid information.') return nil end --- Create a new gadget. -- --

This function is the only gadget factory and the main -- flaw interface for a user to populate its wibox with -- gadgets. However, it is not necessary to call it directly since the -- module provides intelligent indexation to hide it.

-- --

It immediately fails if given type or identifier is nil, or if -- no such type was registered in the store. If it was, the gadget is -- created from the data available in the matching store entry.

-- --

If a matching entry is found in the store, the function first -- completes the given options tables with the defaults found in the -- entry. Then it creates the gadget using the found prototype and -- provider factory, and applies the options tables to the gadget and -- the wrapped widget respectively. At last, it starts the gadget -- monitoring with the delay gadget option and stores it -- in the store entry instances table.

-- -- @param t the type of the gadget to create. -- @param id the uniquer identifier of the gadget to create. -- @param gopt the options to pass to the created gadget. -- @param wopt the options to pass to the created wrapped widget. -- @return A brand new gadget instance, or nil it was not successfully -- created. Note that the returned widget is present in the -- gadget store and can be retrieved with the get function from now on. function new(t, n, id, gopt, wopt) if t == nil or n == nil or id == nil then flaw.helper.debug.error('flaw.gadget.new: invalid information.') return nil end local e = _gadgets_cache[t][n] if e == nil then flaw.helper.debug.error('flaw.gadget.new: unknown gadget class: ' .. t .. '.' .. n) return nil end -- Load default parameters. gopt = gopt or {} wopt = wopt or {} for k in pairs(e.defaults.gadget) do gopt[k] = gopt[k] or e.defaults.gadget[k] end for k in pairs(e.defaults.widget) do wopt[k] = wopt[k] or e.defaults.widget[k] end -- Create the widget. local g = e.prototype:new{ id = id, provider = e.provider_factory(id) } -- Configure the gadget. for k in pairs(gopt) do g[k] = gopt[k] end if g.create ~= nil then g:create(wopt) for k in pairs(wopt) do g.widget[k] = wopt[k] end end -- Start monitoring. g:register(gopt.delay) return add(t, n, g) end --- The Gadget prototype. -- --

This is the root prototype of all gadgets. It provides common -- methods for events and refresh handling.

-- -- @class table -- @name Gadget Gadget = {} --- Gadget constructor. -- --

Note that this constructor is only used internally, or to create -- new gadget prototypes. To create gadget instances, you should use -- the gadget factory new -- function.

-- -- @param o a table with default values. -- @return The brand new gadget. function Gadget:new(o) o = o or {} o.events = {} setmetatable(o, self) self.__index = self return o end --- Hook the gadget to clock events. -- --

This method is called automatically by the new function, with the -- delay argument of its gopt options -- table. The delay will be considered or not by the -- provider depending on its kind.

-- -- @param delay the delay between gadget updates in seconds. It can be -- nil if the underlying provider is not a CyclicProvider. function Gadget:register(delay) -- Subscribe this gadget to the provider. if self.provider ~= nil then self.provider:subscribe(self, delay) end end --- Register an event to the gadget. -- -- @param t the event trigger. -- @param a the action taken upon the event occurrence. function Gadget:add_event(t, a) if t == nil or a == nil then flaw.helper.debug.error('flaw.gadget.Gadget:add_event: invalid event') else self.events[t] = a end end --- Sets the tooltip for this gadget. -- -- @param pattern the pattern to use for the tooltip content. This -- pattern will be parsed like a TextGadget pattern. function Gadget:set_tooltip(pattern) if pattern == nil then flaw.helper.debug.error('flaw.gadget.Gadget:set_tooltip: invalid pattern.') return nil end self.tooltip = { widget = awful.tooltip({ objects = { self.widget }, }), pattern = pattern } if self.provider ~= nil and self.provider.data ~= nil then self.tooltip.widget:set_text( flaw.helper.strings.format( pattern, self.provider.data[self.id] or self.provider.data)) else flaw.helper.debug.warn('flaw.gadget.Gadget:set_tooltip: useless tooltip.') end end --- Callback for gadget update. -- --

This function is called by awful if the gadget has been -- registered to awful time events. It first asks the gadget provider -- to refresh itself, and then applies any triggered event. At last, -- it calls its own redraw function, if defined.

function Gadget:update() if self.provider ~= nil then for c, a in pairs(self.events) do if c:test(self.provider.data) then a(self, t) end end if self.redraw then self:redraw() end end end --- The text boxes wrapper gadget. -- --

This specialised gadget relies on a pattern property which is -- used to format the text output. The provider data are used when -- parsing the pattern. See helper.strings.format -- to understand how the pattern is used to build the output.

-- -- @class table -- @name TextGadget TextGadget = Gadget:new{} -- Create the wrapped gadget. function TextGadget:create(wopt) self.widget = capi.widget( awful.util.table.join(wopt, { type = 'textbox', name = self.id })) end --- Specialised callback for text gadget update. -- --

This implementation support two data models. First, it can apply -- the gadget pattern directly on the provider data table. But if the -- gadget identifier is a key of the provider data, then the gadget -- pattern is applied using the content of this entry only in the -- provider data set.

function TextGadget:redraw() local data_set = {} if self.provider ~= nil and self.provider.data ~= nil then data_set = self.provider.data[self.id] or self.provider.data end if self.pattern ~= nil then self.widget.text = flaw.helper.strings.format(self.pattern, data_set) end if self.tooltip ~= nil then self.tooltip.widget:set_text( flaw.helper.strings.format(self.tooltip.pattern, data_set)) end end _gadgets_types.text = TextGadget _gadgets_cache.text = {} --- The graphs wrapper gadget. -- --

This specialised gadget proposes a list of data values to track -- from the provider data and to plot.

-- -- @class table -- @name GraphGadget GraphGadget = Gadget:new{} --- Specialised callback for graph gadget update. -- --

This implementation support two data models. First, it can -- search the gadget values directly on the provider data table. But -- if the gadget identifier is a key of the provider data, then the -- gadget values is searched using the content of this entry only in -- the provider data set.

function GraphGadget:redraw() if self.provider ~= nil and self.provider.data ~= nil then local data_set = self.provider.data[self.id] or self.provider.data for i, v in ipairs(self.values) do self.hull:add_value(tonumber(data_set[v]) / 100) end end end -- Create the wrapped gadget. -- -- In this case, the raw widget is still stored in -- widget, but the awful.widget.graph is -- stored in the hull one. function GraphGadget:create(wopt) self.hull = awful.widget.graph( awful.util.table.join(wopt, {name = self.id})) self.widget = self.hull.widget end _gadgets_types.graph = GraphGadget _gadgets_cache.graph = {} --- The progress bar wrapper gadget. -- -- The progress bar represents a numeric value using a horizontal or -- vertical gauge. The gadget value field is the name of -- the provider property to be represented. -- -- @class table -- @name BarGadget BarGadget = Gadget:new{} --- Specialised callback for progress gadget update. -- --

This implementation supports two data models. First, it can -- search the gadget value field directly in the provider -- data table. But if the gadget identifier is a key of the provider -- data table, then the gadget value field is searched in -- the provider's data[id] table.

function BarGadget:redraw() if self.provider ~= nil and self.provider.data ~= nil then local data_set = self.provider.data[self.id] or self.provider.data self.hull:set_value(tonumber(data_set[self.value]) / 100) end end -- Create the wrapped gadget. -- -- In this case, the raw widget is still stored in -- widget, but the awful.widget.progressbar -- is stored in the hull one. To configure the -- hull, see -- . function BarGadget:create(wopt) self.hull = awful.widget.progressbar( awful.util.table.join(wopt, {name = self.id})) self.widget = self.hull.widget end _gadgets_types.bar = BarGadget _gadgets_cache.bar = {} --- The image boxes wrapper gadget. -- --

This specialised gadget is a placeholder for specific icon -- treatments. For now, it brings nothing. Interesting stuff can be -- handled using the events mechanism.

-- -- @class table -- @name IconGadget IconGadget = Gadget:new{ type = 'unknown.imagebox' } _gadgets_types.icon = IconGadget _gadgets_cache.icon = {} -- TODO function IconGadget:create() self.widget = capi.widget({ type = 'imagebox', name = self.id }) end -- Below are nifty shortcuts to register or create new gadgets. register = {} setmetatable(register, { __index = function(_, t) return function(m, gopt, wopt, p) if m == nil or m._NAME == nil or m.provider_factory == nil then flaw.helper.debug.error( 'flaw.gadget.register.' .. t .. ': invalid module.') return end register_prototype(t, m._NAME, p or _gadgets_types[t], m.provider_factory, gopt, wopt) end end }) setmetatable(_M, { __index = function(_, t) _t = {} _mt = { __index = function(_, n) return function(id, gopt, wopt) return new(t, n, id, gopt, wopt) end end } setmetatable(_t, _mt) return _t end }) awesome-extra/flaw/flaw.70000644000000000000000000000527011734355656012522 0ustar .\" Process this file with .\" groff -t -mandoc -Tascii flaw.7 | less .\" .TH flaw 7 "FEBRUARY 2009" .SH NAME flaw \- a Lua OO management framework for awesome WM widgets .SH DESCRIPTION .B flaw stands for Fully Loaded AWesome. It is a LUA object oriented library providing a thin abstraction layer above awesome widgets. It is aimed at being simple and resources efficient. .sp To achieve these goals, .B flaw provides the following concepts. .IP gadgets To add functionality to awesome widgets, .B flaw defines gadget objects, which are a wrapper around a widget. All gadgets have properties, events, a refresh mechanism and a data provider (see below). Gadgets can wrap all awesome widget type, namely text boxes, image boxes, graphs or progress bars. .B flaw provides many gadgets for common system information (like CPU or memory activity). .IP provider .B flaw tries to minimise system access and data refresh. Since all information do not have the same expiration rate, all gadgets refresh independently. And since some gadgets can share information, all data is provided by providers which can be shared among gadgets. Providers maintain status data from the system and refreshes only when necessary (ie. when the gadget with the shortest refresh rate demands it). .IP events Events are a way for the user to modify the gadget behaviour or properties when some conditions are met. An event is composed of a trigger, which computes the condition, and an action. Event triggers are tested by the providers only when data changes. Both the condition and the action are provided by the user. .SH USAGE .B flaw depends on the .RB lua-filesystem package which can be found .IR http://luaforge.net/projects/luafilesystem . Once installed, the following statement must be inserted in awesome configuration before any .B flaw gadget or mechanism is used. .RS \f(CWrequire('flaw')\fP .RE .PP Using .B flaw consists in creating gadgets, passing them parameters to customize their display and events to add some behaviour to them, and then adding them in a wibox like any other awesome widget. .B flaw and awful gadgets can live together. The complete .B flaw documentation is available in Luadoc format. Enter the following command to generate it. .RS \f(CWLUA_PATH="path_toflaw/doclet/html/?;;" luadoc -d html --nofiles *.lua\fP .RE .SH DIAGNOSTICS .B flaw tries to recover upon bad invocations. When something wrong occurs, it outputs warning or error messages to stderr (for example, if awesome was started with xsession, output will be found in .I ~/.xsession-errors ). .SH BUGS Certainly a lot. .SH AUTHOR David Soulayrol .SH "SEE ALSO" .BR awesome (1), .BR awesome-client (1), .BR awesomerc (5) awesome-extra/flaw/calendar.lua0000644000000000000000000001540111734355656013752 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local math = math local os = os local string = string local table = table local tostring = tostring local capi = { client = client, mouse = mouse, wibox = wibox, widget = widget, } local awful = { button = require("awful.button"), placement = require("awful.placement"), util = require("awful.util"), widget = require("awful.widget"), } local flaw = { gadget = require('flaw.gadget'), provider = require('flaw.provider'), helper = require('flaw.helper'), } --- A Calendar. -- --

This module contains a text gadget and a provider to display a -- calendar. It was written thanks to the original calendar module -- proposed at http://awesome.naquadah.org/wiki/Calendar_widget.

-- --

Gadget

-- --

The calendar gadget can be instantiated by indexing the gadget -- module with text.calendar. The ID parameter has no -- meaning for the calendar gadget, and it takes no particular -- parameters. See the gadget -- module documentation to learn about standard gadgets -- parameters.

-- --
-- g = flaw.gadget.text.calendar('') --
-- --

When the mouse gets over the gadget, a floating -- wibox is displayed to present a month view. The -- buttons 4 and 5 of the mouse - which should normally be bound to -- the wheel up and down movements - allow you to change the displayed -- month. With the help of the shift key, the year is -- changed.

-- --

Provider

-- --

The provider makes no hardware or software access whatsoever. It -- simply builds a textual month view for the calendar gadget. This -- also means the delay parameter has no meaning for -- it.

-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2010,2011, David Soulayrol module('flaw.calendar') --- The calendar provider prototype. -- --

The calendar provider type is set to -- calendar._NAME.

-- -- @class table -- @name CalendarProvider CalendarProvider = flaw.provider.Provider:new{ type = _NAME } function CalendarProvider:subscribe(g) if flaw.provider.Provider.subscribe(self, g) then -- Initial update. g:update() return true end return false end function CalendarProvider:set_month(m) self.data.month = self.data.month + (m or 1) self:build_simple_view() end function CalendarProvider:build_simple_view() local t = os.time{ year = self.data.year, month = self.data.month + 1, day = 0 } local d = os.date('*t', t) local mthDays, stDay= d.day, (d.wday - d.day) % 7 local lines = {} for x = 0, 6 do lines[x+1] = os.date( "%a ", os.time{ year = 2006, month = 1, day = x + 1 }) end lines[8] = " " local writeLine = 1 while writeLine < (stDay + 1) do lines[writeLine] = lines[writeLine] .. " " writeLine = writeLine + 1 end for x = 1, mthDays do if writeLine == 8 then writeLine = 1 end if writeLine == 1 or x == 1 then lines[8] = lines[8] .. os.date( " %V",os.time{ year = self.data.year, month = self.data.month, day = x }) end if (#(tostring(x)) == 1) then x = " " .. x end lines[writeLine] = lines[writeLine] .. " " .. x writeLine = writeLine + 1 end local header = os.date( "%B %Y\n", os.time{ year = self.data.year, month = self.data.month, day = 1 }) header = string.rep( " ", math.floor((#(lines[1]) - #header) / 2 )) .. header self.data.v_simple = string.format( '%s', 'monospace', header .. table.concat(lines, '\n')) self:refresh_gadgets() end --- A factory for calendar providers. -- --

Only one provider is built.

-- -- @return a brand new calendar provider, or the existing one if the -- found in the providers cache. function provider_factory() local p = flaw.provider.get(_NAME, '') -- Create the provider if necessary. if p == nil then p = CalendarProvider:new{ id = '', data = { month = os.date('%m'), year = os.date('%Y'), v_simple = '', v_remind = '', v_events = '' } } p:build_simple_view() flaw.provider.add(p) end return p end --- A Gadget prototype for calendar display. -- -- @class table -- @name CalendarGadget CalendarGadget = flaw.gadget.Gadget:new{} -- Create the wrapped gadget. function CalendarGadget:create(wopt) self.widget = awful.widget.textclock( awful.util.table.join(wopt, { name = self.id }), self.clock_format) self.wibox = capi.wibox{} self.wibox.visible = false self.wibox.ontop = true self.wibox.widgets = { capi.widget{ type = "textbox", name = 'calendar' } } self.widget:add_signal("mouse::enter", function() self:popup() end) self.widget:add_signal("mouse::leave", function() self:collapse() end) self.wibox:add_signal("mouse::enter", function() self:collapse() end) self.widget:buttons( awful.util.table.join( awful.button({}, 4, function() self.provider:set_month(-1) end), awful.button({}, 5, function() self.provider:set_month(1) end), awful.button({ 'Shift' }, 4, function() self.provider:set_month(-12) end), awful.button({ 'Shift' }, 5, function() self.provider:set_month(12) end))) end function CalendarGadget:redraw() if self.provider ~= nil and self.provider.data ~= nil then self.wibox.widgets[1].text = self.provider.data.v_simple local size = self.wibox.widgets[1]:extents() self.wibox.width = size.width + 10 self.wibox.height = size.height + 10 end end function CalendarGadget:popup() if self.wibox.visible then return end self.wibox.screen = capi.mouse.screen awful.placement.under_mouse(self.wibox) awful.placement.no_offscreen(self.wibox) self.wibox.visible = true end function CalendarGadget:collapse() self.wibox.visible = false end flaw.gadget.register.text(_M, {}, {}, CalendarGadget) awesome-extra/flaw/init.lua0000644000000000000000000002336211734355656013151 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2009,2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local ipairs = ipairs local naughty = require('naughty') local table = require('table') local service_modules = { loaded = {}, dropped = {}, invalid = {} } local function load_flaw_component(name) local m = require('flaw.' .. name) if m then if m.init ~= nil then m = m.init() end if m ~= nil then table.insert(service_modules.loaded, name) else table.insert(service_modules.dropped, name) end else table.insert(service_modules.invalid, name) end return m end local function get_nb_modules(section) return # service_modules[section] end local function get_modules_names(section) local str = '' for _, v in ipairs(service_modules[section]) do str = str .. v .. ' ' end return str end -- Essential modules. require('flaw.gadget') require('flaw.provider') require('flaw.event') require('flaw.helper') -- Service modules. load_flaw_component('alsa') load_flaw_component('battery') load_flaw_component('calendar') load_flaw_component('cpu') load_flaw_component('gmail') load_flaw_component('memory') load_flaw_component('network') load_flaw_component('title') load_flaw_component('wifi') --- Introduction to the core concepts and mechanisms. -- --

The flaw package is composed of core modules which -- provide the raw mechanisms and utilities, and service modules which -- build upon this core to propose interesting gadgets with their -- associated information sources.

-- --

Hereafter are described the core concepts developed by -- flaw. Users also should have a look at the service modules -- they are interested in. Developers may read the core modules -- documentation before doing more complicated things.

-- --

Setup

-- --

The following statement must be inserted in the awesome -- configuration before any flaw gadget or mechanism can be -- used. Such a statement is usually written at the top of the -- configuration file, where naughty, beautiful or -- others modules are declared.

-- --
-- require('flaw')
--
-- --

When this statement is parsed at start up, each of the non-core -- modules referenced in flaw's init.lua are -- loaded and then register the gadgets they provide, and a factory -- for their associated provider. All this information is maintained -- in a table in the gadget core -- module, and is ready to be used to instantiate gadgets.

-- --

Gadgets

-- --

Gadgets are a wrapper around awful widgets that provide -- an automated way to react asynchronously on some hardware or -- software events. The gadget core -- module provides the main gadgets factory and management.

-- --

Gadgets are divided in types which are named after the kinds of -- widgets awesome provides: Text, -- Icon, Graph and ProgressBar -- (which is reduced to Bar in flaw). Thanks to -- some nifty tricks, creating a gadget is straight forward. As an -- example, the following statement instantiates a very simple gadget -- which displays the title of the focused window.

-- --
-- gtitle = flaw.gadget.text.title('') --
-- --

The gadget module is indexed -- first with the type of the desired gadget, and then with its -- name. title is actually one of the service modules -- which were loaded at start up, and which have registered a -- Text gadget. Note that the parameter is required, -- while not useful to this gadget (hence the empty string).

-- --

Here is a moderately complicated example which builds an -- awful 60x18 graph widget which is updated every 5 seconds -- with the current CPU activity.

-- --
-- gcpu = flaw.gadget.graph.cpu('cpu',
--    { delay = 5 }, { width = 60, height = 18 })
--
-- --

The gadget module is indexed -- first with the graph type, and then with the -- cpu gadget name. Indeed, the cpu module -- registers a Text, a Graph and an -- Icon gadget when loaded. Here the required first -- parameter designates the cpu to be monitored. The second and third -- parameters are respectively the gadget and the wrapped widget -- options.

-- --

Here is now how these two gadgets can be embedded in a -- wibox with a layout box and a tags list.

-- --
-- for s = 1, screen.count() do
--    mylayoutbox[s] = awful.widget.layoutbox(s)
--    mytaglist[s] = awful.widget.taglist(
--       s, awful.widget.taglist.label.all, mytaglist.buttons))
--    mywibox[s] = awful.wibox({ position = "top", screen = s })
--    
--    -- Add widgets to the wibox - order matters
--    mywibox[s].widgets = {
--       {
--       mytaglist[s],
--       gcpu.widget,
--       gtitle.widget,
--       layout = awful.widget.layout.horizontal.leftright
--       },
--    mylayoutbox[s],
--    layout = awful.widget.layout.horizontal.rightleft
--    }
-- end
--
-- --

Providers

-- --

Providers are the objects that gather data to feed a gadget. The -- provider core module provides the -- roots of the data mining objects.

-- --

Creating a gadget automatically registers itself to a provider -- so that the displayed information is refreshed at the requested -- pace. Providers can be shared among gadgets, and only refresh their -- data according to the smallest gadget refresh rate.

-- --

No user action is required for this mechanism. However, the -- refresh rate of a gadget can be tuned using the delay -- gadget option. As seen in the gadgets description above, it -- defaults to 10 seconds.

-- --

Events

-- --

The automated and efficient refresh loop of flaw is the -- core of its design. It provides cyclic data updates to gadgets -- which display it in accordance with their type. Events were -- introduced to provide the capability to react to some data values, -- and to do something else than just displaying them. This mechanism -- is available to all of gadgets and is implemented in the event core module.

-- --

Events are made of a trigger and an action. The trigger's -- condition takes the provider's data and is tested each time a -- refresh is called. If it returns true, the event's action is then -- fired, with the gadget as parameter. It can do absolutely anything, -- and its return value has no meaning for flaw.

-- --

Here is an example assuming g is a battery icon -- gadget and battery_low_icon a beautiful property -- holding the path to an explicit low battery icon. This snippet -- changes of the gadget when the battery load gets really low.

-- --
-- g.add_event(
--    flaw.event.LatchTriger:new{ -- condition = function(d) return d.load < 9 end },
--    function(g) g.widget.image = -- image(beautiful.battery_low_icon) end) --
-- --

Writing a new service module

-- --

FIXME

-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2009,2010,2011, David Soulayrol module("flaw") --- Notify the dropped service modules to the user. -- --

This function pops up a notification displaying a list of -- modules which were not loaded. These checked modules are those -- which depend on hardware or sources that can be absent from some -- system, like the battery.

-- --

This function can typically be called at the end of the -- configuration file, or on demand to check the flaw library status.

function check_modules() if get_nb_modules('dropped') ~= 0 then naughty.notify{ title = "Flaw", text = "The following modules are absent from your system:\n" .. get_modules_names('dropped'), timeout = 12, position = "top_right"} end end --- Check the availability of a service module. -- -- @param m the name of the service module to check. -- @return true if the module was loaded, false otherwise. Note that -- loaded means here that the module was correctly parsed and -- has registered the provider or the gadgets it contains. function check_module(m) for _, v in ipairs(service_modules['loaded']) do if m == v then return true end end return false end awesome-extra/flaw/README0000644000000000000000000000130211734355656012351 0ustar Flaw is a LUA object oriented library providing a thin abstraction layer above awesome widgets. It is aimed at being simple and resources efficient. See . Flaw requires luafilesystem. To learn more, please read the provided flaw(7) man page. You can read it without installing it on the system using one of the following commands: man -l flaw.7 groff -t -mandoc -Tascii flaw.7 | less Flaw also comes with inline documentation. If you have Luadoc installed, you can use the following command to extract HTML documentation pages. LUA_PATH="path_toflaw/doclet/html/?;;" luadoc -d html --nofiles *.lua -- David Soulayrol awesome-extra/flaw/cpu.lua0000644000000000000000000001523611734355656012776 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2009,2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local io = io local string = string local beautiful = require('beautiful') local naughty = require('naughty') local flaw = { helper = require('flaw.helper'), gadget = require('flaw.gadget'), provider = require('flaw.provider') } --- Cpu information. -- --

This module contains a provider for cpu information and three -- gadgets: a text gadget, an icon gadget and a graph gadget.

-- --

Gadgets

-- --

The ID of the gadgets designates the CPU slot to be monitored, -- in the /proc/stat file, as indicated in the provider's -- documentation below. CPU gadgets provide no custom parameters. See -- the gadget module documentation to -- learn about standard gadgets parameters.

-- --

Icon Gadget

-- --

The CPU icon gadget can be instantiated by indexing the gadget -- module with icon.cpu. Here is an exemple which assumes -- the CPU icon path is stored in a beautiful property.

-- --
-- g = flaw.gadget.icon.cpu(
--    'cpu', {}, { image = image(beautiful.cpu_icon) })
--
-- --

Text Gadget

-- --

The CPU text gadget can be instantiated by indexing the gadget -- module with text.cpu. By default, the gadget pattern -- is $load_user/$load_sum. See the provider's -- documentation below to learn about the available variables.

-- --
-- g = flaw.gadget.text.cpu('cpu') --
-- --

Graph Gadget

-- --

The CPU graph gadget can be instantiated by indexing the gadget -- module with graph.cpu. By default, the chart displayed -- by the gadget shows the evolution of load_sum. See the -- provider's documentation below to learn about the available -- variables.

-- --
-- g = flaw.gadget.graph.cpu(
--    'cpu', {}, { width = 60, height = 18 }) --
-- --

Provider

-- --

The cpu provider loads its information from -- /proc/stat/ and considers the line beginning with -- cpu. On multi-core machines, multiple -- cpuNN lines follow the one which begins with only -- cpu. The complete file format is explained at http://www.linuxhowtos.org/System/procstat.htm

-- --

The cpu provider computed data is composed of the following -- fields.

-- --
    -- --
  • load_user -- --

    The percentage of time the CPU has spent performing normal -- processing in user mode.

  • -- --
  • load_nice -- --

    The percentage of time the CPU has spent performing niced -- processing in user mode.

  • -- --
  • load_sum -- --

    The percentage of time the CPU has spent performing any task in -- any mode.

  • -- --
-- -- The provider data also stores the raw values read from the lines -- parsed in /proc/stat. This information can be found in -- raw_sum, raw_user, raw_nice, -- raw_idle, and is used to compute percentage values. -- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2009,2010,2011 David Soulayrol module('flaw.cpu') --- The cpu provider prototype. -- --

The CPU provider type is set to -- cpu._NAME.

-- -- @class table -- @name CPUProvider CPUProvider = flaw.provider.CyclicProvider:new{ type = _NAME, data = {} } --- Callback for provider refresh. function CPUProvider:do_refresh() local file = io.open('/proc/stat') local line = '' local id, user, nice, system, idle, diff while line ~= nil do line = file:read() if line ~=nil then id, user, nice, system, idle = string.match( line, '(%w+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)') if id ~=nil and string.find(id, 'cpu') ~= nil then if self.data[id] == nil then self.data[id] = { raw_user = 0, raw_nice = 0, raw_idle = 0, raw_sum = 0, load_user = 0, load_nice = 0, load_sum = 0 } end local cpu_sum = user + nice + system + idle diff = cpu_sum - self.data[id].raw_sum -- The diff should always be positive. If it is not the case, -- the load is too heavy for the system to refresh data. In -- this case, keep a 100 USER_HZ default value. self.data[id].load_user = 100 self.data[id].load_nice = 100 self.data[id].load_sum = 100 if diff > 0 then self.data[id].load_user = 100 * (user - self.data[id].raw_user) / diff self.data[id].load_nice = 100 * (nice - self.data[id].raw_nice) / diff self.data[id].load_sum = 100 - 100 * (idle - self.data[id].raw_idle) / diff end self.data[id].raw_sum = cpu_sum self.data[id].raw_user = user self.data[id].raw_nice = nice self.data[id].raw_idle = idle end end end io.close(file); end --- A factory for CPU provider. -- --

Only one provider is built to store all the CPU information. Its -- data is a map indexed by CPU slot.

-- -- @return a brand new CPU provider, or the existing one if found in -- the providers cache. function provider_factory() local p = flaw.provider.get(_NAME, '') -- Create the provider if necessary. if p == nil then p = CPUProvider:new{ id = '' } flaw.provider.add(p) end return p end -- A Text gadget for cpu status display. flaw.gadget.register.text(_M, { delay = 1, pattern = '$load_user/$load_sum' }) -- A graph gadget for cpu load display. flaw.gadget.register.graph(_M, { delay = 1, values = { 'load_sum' } }) -- An icon gadget for cpu status display. flaw.gadget.register.icon(_M) awesome-extra/flaw/helper.lua0000644000000000000000000002307311734355656013464 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2009,2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local io = io local os = os local math = math local pairs = pairs local string = string local tostring = tostring local table = require('table') local naughty = require('naughty') local beautiful = require('beautiful') --- Utilities. -- --

This module mainly contains utilities borrowed and improved from -- wicked and other scripts found on the awesome wiki. Many -- thanks to all the wiki contributors.

-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2009,2010,2011 David Soulayrol module('flaw.helper') local unities = { 'b', 'Kb', 'Mb', 'Gb', 'Tb' } --- File related tools. -- -- @class table -- @name file file = {} --- Append the given string to a temporary log file. -- -- @param line the line to write down. function file.log(line) if line ~= nil then local log = io.open('/tmp/awesome_rc.log', 'a') log:write(os.date('%c\t') .. tostring(line) .. '\n') log:close() end end --- Load a file with lines formatted as "name: value". -- --

For each line "k:v" read in the file f, the given table is -- completed with v for the key "f_k" (everything in lower -- case). Spaces in k are replaces with underscores.

-- -- @param path the file path. -- @param name the filename. -- @param t the table which will hold the parsed values. -- @return the number of lines parsed, or -1 if the file could not be opened. function file.load_state_file(path, name, t) local f = io.open(path .. '/' .. name) local r = -1 if f ~= nil then local prefix = name:lower() .. '_' local line = nil r = 0 repeat line = f:read() if line then n, v = line:match('([%a%d ]+):%s+([%w%.- ]+)') if n ~= nil and v ~= nil then t[prefix .. n:gsub(' ', '_'):lower()] = v:lower() r = r + 1 end end until line == nil f:close() end return r end --- Text formatting related functions. -- --

This family of functions returns the given text formatted with -- special attributes.

-- -- @class table -- @name format format = {} --- Return the string with a background color. -- -- @param color the color to apply in background. -- @param text the text to format. -- @return The formatted text. function format.set_bg(color, text) return ''..text end --- Return the string with the given color. -- -- @param color the color to apply on the text. -- @param text the text to format. -- @return The formatted text. function format.set_fg(color, text) return ''..text..'' end --- Return the string with background and foreground color. -- -- @param bgcolor the color to apply in background. -- @param fgcolor the color to apply on the text. -- @param text the text to format. -- @return The formatted text. function format.set_bg_fg(bgcolor, fgcolor, text) return ''..text..'' end --- Return the string with a defined font. -- -- @param font the font to apply on the text. -- @param text the text to format. -- @return The formatted text. function format.set_font(font, text) return ''..text..'' end --- String related functions. -- -- @class table -- @name strings strings = {} --- Split the given string by whitespaces. -- -- @param str the string to split. -- @return a table with the string tokens. function strings.split(str) str = str or '' values = {} local start = 1 while true do local splitstart, splitend = string.find(str, ' ', start) local token = string.sub(str, start, splitstart and splitstart - 1 or nil) if token:gsub(' ','') ~= '' then table.insert(values, token) end if splitstart == nil then break end start = splitend+1 splitstart, splitend = string.find(str, ' ', start) end return values end --- Crop the given string to the given maximum width. -- --

If string is too large, the right-most part is replaced by an -- ellipsis.

-- -- @param str the string to crop. -- @param width the maximum result width. -- @return the resulting string. function strings.crop(str, width) str = str or '' local len = str:len() width = width or len if width < 3 then str = '' elseif len > width then str = str:sub(1, width - 3) .. '...' end return str end --- Force a fixed width on the given string. -- --

If the string is too short, it is padded with spaces on the -- left. If too long, it is cropped without an ellipsis.

-- -- @param str the string to handle. -- @param width the width to apply. -- @return the resulting string. function strings.pad_left(str, width) str = str or '' local len = str:len() width = width or len if width > len then for i = 1, width - len do str = ' ' .. str end else str = str:sub(0, width) end return str end --- Force a fixed width on the given string. -- --

If the string is too short, it is padded with spaces on the -- right. If too long, it is cropped without an ellipsis.

-- -- @param str the string to handle. -- @param width the width to apply. -- @return the resulting string. function strings.pad_right(str, width) str = str or '' local len = str:len() width = width or len if width > len then for i = 1, width - len do str = str .. ' ' end else str = str:sub(0, width) end return str end --- Pad a number to a minimum amount of digits. -- --

Caveat: the result is wrong for numbers between 0 and 1.

-- -- @param str number the number to handle as a string. -- @param padding the number of digits to add if necessary. -- @return the resulting string. function strings.pad_number(number, padding) number = number or 0 local str = tostring(number) or '' padding = padding or str:len() for i = 1, padding do if math.floor(number / math.pow(10, (i - 1))) == 0 then str = '0' .. str end end if number == 0 then str = str:sub(2) end return str end --- Fill in a string with given arguments. -- --

This method replaces the $key patterns in the given string with -- value got by indexing the given table with key.

-- -- @param pattern the string to translate. -- @param args the values table. -- @return the resulting string. function strings.format(pattern, args) pattern = pattern or '' args = args or {} for key, value in pairs(args) do if key ~= nil and value ~= nil then pattern = string.gsub(pattern, '$' .. key, value) end end return pattern end -- Convert amount of bytes to string. function strings.format_bytes(bytes, padding) bytes = bytes and tonumber(bytes) or '' padding = padding local sign = 1 while bytes / 1024 > 1 and unities[sign + 1] ~= nil do bytes = bytes / 1024 sign = sign + 1 end bytes = math.floor(bytes * 10)/10 if padding then bytes = pad_number(bytes * 10, padding + 1) bytes = bytes:sub(1, bytes:len() - 1) .. '.' .. bytes:sub(bytes:len()) end return tostring(bytes) .. unities[sign] end --- Strip left spaces on a string. -- -- @param str the string to handle. -- @return the resulting string. function strings.lstrip(str) return str:match("^[ \t]*(.*)$") end --- Strip spaces on a string. -- -- @param str the string to handle. -- @return the resulting string. function strings.strip(str) return str:match("^[ \t]*(.-)[ \t]*$") end --- Strip right spaces on a string. -- -- @param str the string to handle. -- @return the resulting string. function strings.rstrip(str) return str:match("^(.-)[ \t]*$") end --- Escape a string -- --

This method replaces common URL-forbidden characters by their -- HTML entity.

-- -- @param text the string to handle. -- @return the resulting string. function strings.escape(text) local xml_entities = { ["\""] = """, ["&"] = "&", ["'"] = "'", ["<"] = "<", [">"] = ">" } return text and text:gsub("[\"&'<>]", xml_entities) end function round(n, p) local m = 10^(p or 0) return math.floor(m*n + 0.5)/m end --- Debug related tools. -- -- @class table -- @name debug debug = {} --- Display a message using a naughty notification. -- -- @param message the message to display. function debug.display(message) naughty.notify{ title = "DEBUG", text = tostring(message), timeout = 5 } end --- Output a warning on error output. -- -- @param message the message to log. function debug.warn(message) io.stderr:write(os.date('%A %d %B %H:%M:%S') .. ' WARNING: ' .. tostring(message) .. '\n') end --- Output an error on error output. -- -- @param message the message to log. function debug.error(message) io.stderr:write(os.date('%A %d %B %H:%M:%S') .. ' ERROR: ' .. tostring(message) .. '\n') end awesome-extra/flaw/provider.lua0000644000000000000000000002405711734355656014042 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2009,2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local pairs = pairs local os = os local setmetatable = setmetatable local capi = { timer = timer, } local flaw = { helper = require('flaw.helper'), } --- Providers core mechanisms. -- --

In flaw, all data is gathered by provider objects which, -- in an attempt to minimize resources usage, can be shared among -- gadgets. The providers can poll disks or memory at a given rate for -- their information, or can be updated by scripts or direct -- Lua invocation, like awful callbacks. When updated, -- providers notify the gadgets that have subscribed to them.

-- --

Providers are normally handled automatically when a gadget is -- created. You only have to take care of them when you are writing -- your own gadget, or if you want to create a new provider, or extend -- an existing one. flaw already implements many providers for -- common system information. The existing providers are usually -- defined in the module of the widget type they serve.

-- --

A provider is identified by its type and an identifier, which -- must remain unique for one type. The provider type usually -- represents the module of this provider and can be composed of any -- character. Thus, it is common to create a new provider prototype -- this way:

-- --
-- flaw.provider.Provider:new{ type = _NAME } --
-- --

All created providers are kept in a global store from which they can be -- retrieved anytime. Note that this store has normally no use for the -- user, but allows gadgets to share providers.

-- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2009,2010,2011 David Soulayrol module('flaw.provider') --- Global providers store. -- --

This table stores all the registered provider -- instances. Providers are sorted by their type first, and then by -- their ID. The store is private to the provider -- module. It can be accessed using its get, and add functions.

-- -- @class table -- @name _providers_cache local _providers_cache = {} --- Store a provider instance. -- --

This function stores the given provider in the global providers -- store. It fails if the instance is invalid, that is if it is nil or -- if its type is nil.

-- --

You normally do not have to call this function since it is -- silently invoked each time a gadget instantiates its provider.

-- -- @param p the provider prototype to store. function add(p) if p == nil or p.id == nil then flaw.helper.debug.error('flaw.provider.provider_add: invalid provider.') else if _providers_cache[p.type] == nil then _providers_cache[p.type] = {} end _providers_cache[p.type][p.id] = p end end --- Retrieve a provider instance. -- --

This function returns the provider matching the given -- information. It immediately fails if the given type or identifier -- is nil. It also fails if no instance in the store matches the given -- parameters.

-- -- @param type the type of the provider to retrieve. -- @param id the uniquer identifier of the provider to retrieve. -- @return The matching provider instance, or nil if information was -- incomplete or if there is no such provider. function get(type, id) if type == nil or id == nil then flaw.helper.debug.error('flaw.provider.provider_get: invalid information.') else return _providers_cache[type] ~= nil and _providers_cache[type][id] or nil end end --- The Provider prototype. -- --

This is the root prototype of all providers. It defines nothing -- but the prototype's type and a method for gadgets subscription.

-- -- @class table -- @name Provider Provider = { type = 'unknown' } --- Provider constructor. -- --

Remember that providers are normally handled automatically when -- a gadget is created. This constructor is only used internally, or -- to create new gadget prototypes.

-- -- @param o a table with default values. -- @return The brand new provider. function Provider:new(o) o = o or {} o.data = o.data or {} o.subscribers = o.subscribers or {} setmetatable(o, self) self.__index = self return o end --- Subscribe a gadget to this provider. -- --

This is the method a gadget automatically uses, when created by -- the gadget factory, to register itself to its provider. The root -- provider does strictly nothing with this subscription, but any -- active provider uses the subscribers list to update its -- gadgets.

-- --

This method immediately fails if the given gadget is nil. On -- success, the gadget is stored in the provider internal subscribers -- list.

-- -- @param g the gadget subscriber. -- @return True if the subscriber was correctly stored, False otherwise. function Provider:subscribe(g) if g == nil then flaw.helper.debug.error('flaw.provider.Provider:subscribe: invalid gadget') return false end self.subscribers[g] = { timestamp = os.time() } return true end --- Refresh gadgets subscribed to this provider. -- --

This method is a facility for providers to invoke all the -- gadgets refresh when they are done with data gathering.

function Provider:refresh_gadgets() for g, props in pairs(self.subscribers) do props['timestamp'] = self.timestamp g:update() end end --- The Cyclic Provider prototype. -- --

This specialized provider is the root of all the providers -- needing to provide cyclic information, based on files, network and -- so on, rather than on events. Cyclic providers poll resources -- status from system only when necessary (ie. when the gadget with -- the shortest refresh rate demands it).

-- --

The CyclicProvider relies on a C API timer. The timer timeout -- value defaults to 60 seconds but is updated each time a gadget -- starts to use the provider, if its own rate is shorter. Note that -- the higher rate demand only will be served in time, all others will -- be refreshed using a comparison between their timestamp and the -- refresh date. For example, if a provider is asked to refresh every -- 10 seconds and then every 3 seconds, its timer will be set to 3 -- seconds. The second gadget will be refreshed exactly in time, -- whereas the first will be refreshed at 12 seconds, 21 seconds, 30 -- seconds, and so on.

-- --

All CyclicProvider also define a timestamp value -- which can be used in specific treatments to know the last refresh -- date.

-- -- @class table -- @name CyclicProvider CyclicProvider = Provider:new{ type = 'unknown.cyclic', timestamp = 0, timer = nil } --- Subscribe a gadget to this provider. -- --

The CyclicProvider specialised method adds the poll timer -- handling to the parent method. It also requires the gadget's rate -- as second argument (which defaults to 60s).

-- --

This method immediately fails if the given gadget is nil. On -- success, the gadget is stored in the provider internal subscribers -- list.

-- -- @param g the gadget subscriber. -- @param rate the new poll interval asked by the gadget. -- @return True if the subscriber was correctly stored and the timer -- correctly started or reconfigured (if necessary), False otherwise. function CyclicProvider:subscribe(g, rate) rate = rate or 60 if Provider.subscribe(self, g) then self.subscribers[g].rate = rate local start = false if self.timer == nil then self.timer = capi.timer{ timeout = 60 } self.timer:add_signal('timeout', function() self:refresh() end, true) start = true end if rate < self.timer.timeout then self.timer.timeout = rate end if start then self.timer:start() end -- Initial refresh. self:refresh(g) return true end return false end --- Refresh the provider status. -- --

This callback is invoked by the provider timer, which timeouts -- at the highest asked rate. The actual refresh process is dedicated -- to the do_refresh method, which is called with no -- argument. This definition depends on the provider role, and should -- be defined in all derived prototypes.

-- --

After refresh is done, the gadgets are redrawn.

-- -- @param g if provided, this gadget only is refreshed. -- @return True is the provider did refresh its data set since the -- given gadget last asked for the refresh. function CyclicProvider:refresh(g) if self.do_refresh then self:do_refresh() if g ~= nil then self.subscribers[g].timestamp = self.timestamp g:update() else self:refresh_gadgets() end else flaw.helper.debug.warn( 'CyclicProvider ' .. self.type .. '.' .. self.id .. ' misses do_refresh()') end end --- Refresh gadgets subscribed to this provider. -- --

Redefined here to handle the rate required by the different -- gadgets. All child providers should rely on the -- refresh method which calls directly this one.

function CyclicProvider:refresh_gadgets(force) local force = force or false self.timestamp = os.time() for g, props in pairs(self.subscribers) do if force or props['timestamp'] + props['rate'] <= self.timestamp then props['timestamp'] = self.timestamp g:update() end end end awesome-extra/flaw/memory.lua0000644000000000000000000001165611734355656013521 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2009,2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local io = io local string = string local beautiful = require('beautiful') local naughty = require('naughty') local flaw = { helper = require('flaw.helper'), gadget = require('flaw.gadget'), provider = require('flaw.provider') } --- Memory information. -- --

This module contains a provider for memory status and two -- gadgets: a text gadget and a graph gadget.

-- --

Gadgets

-- --

The ID parameter has no meaning for the memory gadgets. Memory -- gadgets provide no custom parameters. See the gadget module documentation to learn -- about standard gadgets parameters.

-- --

Text Gadget

-- --

The memory text gadget can be instantiated by indexing the -- gadget module with text.memory. By default, the gadget -- pattern is $ratio%. See the provider's documentation -- below to learn about the available variables.

-- --
-- g = flaw.gadget.text.memory('') --
-- --

Graph Gadget

-- --

The memory graph gadget can be instantiated by indexing the -- gadget module with graph.memory. By default, the chart -- displayed by the gadget shows the evolution of -- ratio. See the provider's documentation below to learn -- about the available variables.

-- --
-- g = flaw.gadget.graph.memory(
--    '', {}, { width = 60, height = 18 }) --
-- --

Provider

-- --

The memory provider loads its information from -- /proc/meminfo/. This file format is explained, among -- other places, at http://www.redhat.com/advice/tips/meminfo.html

-- --

The memory provider computed data is composed of the following -- field.

-- --
    -- --
  • ratio -- --

    The percentage of memory currently used.

  • -- --
-- --

The provider data also stores the raw values read from the -- /proc/meminfo file. This information can be found in -- proc and is composed of the following fields.

-- --
    -- --
  • proc.meminfo_memtotal -- --

    The memory available on the system.

  • -- --
  • proc.meminfo_cached -- --

    The memory affected to cached data.

  • -- --
  • proc.meminfo_buffers -- --

    The memory affected to application buffers data.

  • -- --
  • proc.meminfo_memfree -- --

    The free memory.

  • -- --
-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2009,2010,2011 David Soulayrol module('flaw.memory') --- The memory provider prototype. -- --

The memory provider type is set to -- memory._NAME.

-- -- @class table -- @name MemoryProvider MemoryProvider = flaw.provider.CyclicProvider:new{ type = _NAME, data = {} } --- Callback for provider refresh. function MemoryProvider:do_refresh() local p = self.data.proc local r = flaw.helper.file.load_state_file('/proc', 'meminfo', p) self.data.ratio = 0 if r > 0 then -- Adapt values. local total = p.meminfo_memtotal:match('(%d+).*') or 0 local free = p.meminfo_memfree:match('(%d+).*') or 0 local buffers = p.meminfo_buffers:match('(%d+).*') or 0 local cached = p.meminfo_cached:match('(%d+).*') or 0 if total ~= 0 then self.data.ratio = flaw.helper.round( 100 * (total - free - buffers - cached) / total, 2) end end end --- A factory for memory providers. -- --

Only one provider is built.

-- -- @return a brand new memory provider, or the existing one if found -- in the providers cache. function provider_factory() local p = flaw.provider.get(_NAME, '') -- Create the provider if necessary. if p == nil then p = MemoryProvider:new{ id = '', data = { ratio = 0, proc = {} } } flaw.provider.add(p) end return p end -- A Text gadget for memory status display. flaw.gadget.register.text(_M, { pattern = '$ratio%' }) -- A graph gadget for memory status history. flaw.gadget.register.graph(_M, { delay = 1, values = { 'ratio' } }) awesome-extra/flaw/wifi.lua0000644000000000000000000001520211734355656013136 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local io = io local string = string local tonumber = tonumber local lfs = require('lfs') local flaw = { gadget = require('flaw.gadget'), helper = require('flaw.helper'), provider = require('flaw.provider') } --- Wifi information. -- --

This module contains a provider for wifi information and two -- gadgets: a text gadget and an icon gadget.

-- --

Gadgets

-- --

The ID of the gadgets designates the network device to be -- monitored. Wifi gadgets provide no custom parameters. See the gadget module documentation to learn -- about standard gadgets parameters.

-- --

Icon Gadget

-- --

The wifi icon gadget can be instantiated by indexing the -- gadget module with icon.wifi. Here is an exemple -- which assumes the icon path is stored in a beautiful -- property.

-- --
-- g = flaw.gadget.icon.wifi(
--    'wlan0', {}, { image = image(beautiful.wifi_icon) })
--
-- --

Text Gadget

-- --

The wifi text gadget can be instantiated by indexing the -- gadget module with text.wifi. By default, the -- gadget pattern is $essid: $rate Mb/s. See the -- provider's documentation below to learn about the available -- variables.

-- --
-- g = flaw.gadget.text.wifi('wlan1') --
-- --

Provider

-- --

The wifi provider loads its information from -- iwconfig output (generally from the wireless-tools -- package). The use of iwconfig was prefered to -- iwgetid (which output if far simpler to parse) because -- it returns all data at once and so limits the number of processes -- to launch.

-- --

The wifi provider stores the data for each configured wireless -- device at once. Data is composed of the following fields.

-- --
    -- --
  • essid -- --

    The name of the network the device is connected to (or -- N/A).

  • -- --
  • mode -- --

    The mode of the wireless connection (generally -- Managed or Ad-Hoc).

  • -- --
  • channel -- --

    The channel used by the wireless connection, as a -- number

  • -- --
  • freq -- --

    The frequency used by the wireless adapter as a number in -- MHz.

  • -- --
  • ap -- --

    The wireless access-point MAC address.

  • -- --
  • rate -- --

    The connection bit rate, as a number in Mb/s.

  • -- --
  • quality -- --

    The link quality as returned by iwconfig, in its -- fraction format.

  • -- --
  • level -- --

    Ths signal level as a number.

  • -- --
-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2011, David Soulayrol module('flaw.wifi') --- The wifi provider prototype. -- --

The wifi provider type is set to wifi._NAME.

-- -- @class table -- @name WifiProvider WifiProvider = flaw.provider.CyclicProvider:new{ type = _NAME } --- Parse one entry from iwconfig output. -- -- @param bloc the text representing information for one device. The -- first characters of this bloc are the name of the device -- which is analysed. function WifiProvider:parse_adapter_info(bloc) local adapter = string.match(bloc, '([%w%d]+)') self.data[adapter] = {} self.data[adapter].essid = string.match(bloc, 'ESSID[=:]"(.-)"') or 'N/A' self.data[adapter].ap = string.match(bloc, 'Access Point[=:] ([%w%d%:]+)') or 'No Access-Point' self.data[adapter].mode = string.match(bloc, "Mode[=:]([%w%-]*)") or '' self.data[adapter].freq = tonumber(string.match(bloc, "Frequency[=:]([%d%.]+)")) or 0 self.data[adapter].channel = tonumber(string.match(bloc, "Channel[=:]([%d]+)")) or 0 self.data[adapter].rate = tonumber(string.match(bloc, "Bit Rate[=:]([%s]*[%d%.]*)")) or 0 self.data[adapter].quality = string.match(bloc, "Link Quality[=:]([%d]+/[%d]+)") or 'N/A' self.data[adapter].level = tonumber(string.match(bloc, "Signal level[=:]([%-]?[%d]+)")) or 0 end --- Callback for provider refresh. function WifiProvider:do_refresh() local file = io.popen('/sbin/iwconfig 2> /dev/null', 'r') local content = '' local line = false if file then while line ~= nil do line = file:read() if line == '' then self:parse_adapter_info(content) elseif line ~= nil then content = content .. line end end file:close() end end --- A factory for wifi providers. -- --

Only one provider is built for all wireless adapters. Its data -- is a map indexed by the name of the wireless device.

-- -- @return a brand new wireless provider, or the existing one if found -- in the providers cache. function provider_factory() local p = flaw.provider.get(_NAME, '') -- Create the provider if necessary. if p == nil then p = WifiProvider:new{ id = '', data = {} } flaw.provider.add(p) end return p end --- Module initialization routine. -- --

This method tests the available information on the system. If -- wireless devices can can be found, it registers gadgets and returns -- the module; otherwise it simply returns nil.

-- -- @return return this module if it can be used on the system, -- false otherwise. function init() local file = '/proc/net/wireless' if lfs.attributes(file, 'mode') == 'file' then local t = {} if flaw.helper.file.load_state_file('', file, t) > 0 then -- An icon gadget prototype for wifi status display. flaw.gadget.register.icon(_M) -- A Text gadget prototype for wifi status display. flaw.gadget.register.text(_M, { pattern = '$essid: $rate Mb/s' }) return _M end end end awesome-extra/flaw/event.lua0000644000000000000000000002305611734355656013327 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2009,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local setmetatable = setmetatable --- Core events objects. -- --

Events are a way for the user to modify the gadget behaviour or -- properties when certain conditions are met. An event is composed of -- a trigger, which computes the condition, and an action.

-- --

Trigger and Action

-- --

The trigger is an object which takes a condition and provides -- some status depending of its type. The trigger is tested each time -- the gadget's provider refreshes its data, and the action called if -- the event fires. There are three kind of triggers; the simple Trigger, the LatchTrigger and the EdgeTrigger described -- below. All depend on the condition function but fire the event -- differently, depending on their previous status.

-- --

The condition function takes one parameter which is the data -- table updated by the provider. This table layout depends on the -- provider and is detailed in the provider documentation. The -- condition function shall return true if its conditions are met, or -- false otherwise. The event will then fire depending on its -- type.

-- --

The action function takes the gadget as parameter. It can do -- absolutely anything, and its return value has no meaning for -- flaw.

-- --

Usage

-- --

Condition and action are written by the user. Events must be -- registered to a gadget, which in turn registers the trigger to its -- provider.

-- --
-- t = flaw.event.LatchTrigger:new{
--    condition = function(d) return d.load < 25 end },
-- a = function(g) g.pattern = '<bg color="#ff6565"/>$load%' end
-- gadget:add_event(e, a)
--
-- --

Assuming g is a battery icon gadget created as -- above and battery_low_icon a beautiful property -- holding the path to an explicit low battery icon, here is a short -- snippet to change the icon in a gadget when the battery load gets -- really low.

-- --
-- g.add_event(
--    flaw.event.LatchTriger:new{ -- condition = function(d) return d.load < 9 end },
--    function(g) g.widget.image = -- image(beautiful.battery_low_icon) end) --
-- --

It is important to carefully choose the correct trigger for the -- event to be raised. The LatchTrigger object used here -- will make the event happen only at the moment the load gets under 9 -- percents. If the percentage of load remains under 9, the event will -- not be triggered again. If a raw Trigger object had been used, the -- event would be triggered again at each provider's refresh.

-- --

If a repeated refresh can be considered as a minor optimisation -- issue here, it can become a really annoying problem, like in the -- following sample where naughty is used to be notified if the -- same situation.

-- --
-- g.add_event(
--    flaw.event.LatchTriger:new{ -- condition = function(d) return d.load < 9 end },
--    function(g) naughty.notify{
--       title = "Battery Warning",
--       text = "Battery low! " .. g.provider.data.load .. "% left!",
--       timeout = 5,
--       position = "top_right",
--       fg = beautiful.fg_focus,
--       bg = beautiful.bg_focus} end) --
-- --

Here is another example which introduces the EdgeTrigger. This trigger is -- activated when the condition's state change, that is if it becomes -- true or if it becomes false. Since Lua objects can be -- extended at will, the following snippet also moves the refresh -- action content into a my_update object's member. This -- way, behaviour which is common to multiple events can be written -- only once.

-- --
-- bg = flaw.gadget.icon.battery('BAT0',
--    {
--       my_icons = {
--          image( -- beautiful.icon_battery_low ),
--          image( -- beautiful.icon_battery_mid ),
--          image( -- beautiful.icon_battery_full )
--       },
--       my_load_icon = image( -- beautiful.icon_battery_plugged ),
--       my_update = function(self)
--          if -- self.provider.data.st_symbol == flaw.battery.STATUS_CHARGING then
--             self.widget.image -- = self.my_load_icon
--          else
--             self.widget.image -- = self.my_icons[math.floor(self.provider.data.load / 30) + 1]
--          end
--       end
--    }, {
--       image -- = image(beautiful.icon_battery_full)
--    } )
--
bg:add_event(
--    flaw.event.EdgeTrigger:new{ -- condition = function(d) return d.load < 60 end },
--    function (g) g:my_update() end )
-- bg:add_event(
--    flaw.event.EdgeTrigger:new{ -- condition = function(d) return d.load < 30 end },
--    function (g) g:my_update() end )
-- bg:add_event(
--    flaw.event.EdgeTrigger:new{
--       condition -- = function(d) return d.st_symbol == flaw.battery.STATUS_CHARGING end },
--    function (g) g:my_update() end )
--
-- --

This module provides the different Trigger prototypes.

-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2009,2011 David Soulayrol module('flaw.event') --- The simple trigger prototype. -- --

The simple trigger starts the event it belongs to each time the -- condition is successfully checked.

-- -- @class table -- @name Trigger -- @field condition the boolean computing routine, normally provided -- by the user, which decides if the event should be started. Trigger = { condition = function() return true end } --- The simple trigger constructor. -- -- @param o a table, which should at least contain the condition -- function at the index condition. -- @return the fresh new trigger. function Trigger:new(o) o = o or {} setmetatable(o, self) self.__index = self return o end --- Event trigger using the raw condition. -- -- @param data the provider data. function Trigger:test(data) return self.condition(data) end --- The latch trigger prototype. -- --

The latch trigger starts the event it belongs to only when the -- condition becomes true. That is, while the condition remains true, -- the event is started exactly once. It will be started again only if -- the condition becomes false again and then true.

-- -- @class table -- @name LatchTrigger -- @field condition the boolean computing routine, normally provided -- by the user, which decides if the event should be started. -- @field status the trigger memory. LatchTrigger = Trigger:new{ status = false } --- Event trigger using a bistable mechanism around the raw condition. -- -- @param data the provider data. function LatchTrigger:test(data) local old_status = self.status self.status = self.condition(data) return not old_status and self.status end --- The edge trigger prototype. -- --

The edge trigger starts the event it belongs to only when the -- condition result changes. That is, the event is started each time -- the condition becomes true or becomes false.

-- -- @class table -- @name EdgeTrigger -- @field condition the boolean computing routine, normally provided -- by the user, which decides if the event should be started. -- @field status the trigger memory. EdgeTrigger = Trigger:new{ status = false } --- Event trigger using edge detection of the raw condition results. -- -- @param data the provider data. function EdgeTrigger:test(data) local old_status = self.status self.status = self.condition(data) return old_status and not self.status or not old_status and self.status end awesome-extra/flaw/network.lua0000644000000000000000000001632311734355656013676 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2009,2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local io = io local math = math local tonumber = tonumber local os = os local string = string local beautiful = require('beautiful') local naughty = require('naughty') local flaw = { helper = require('flaw.helper'), gadget = require('flaw.gadget'), provider = require('flaw.provider') } --- Network activity. -- --

This module contains a provider for network status and activity -- and three gadgets: a text gadget, an icon gadget and a graph -- gadget.

-- --

Gadgets

-- --

The ID of the gadgets designates the network device to be -- monitored, in the /proc/net/dev file, as indicated in -- the provider's documentation below. Network gadgets provide no -- custom parameters. See the gadget -- module documentation to learn about standard gadgets -- parameters.

-- --

Icon Gadget

-- --

The network icon gadget can be instantiated by indexing the -- gadget module with icon.network. Here is an exemple -- which assumes the icon path is stored in a beautiful -- property.

-- --
-- g = flaw.gadget.icon.network(
--    'eth0', {}, { image = image(beautiful.net_icon) })
--
-- --

Text Gadget

-- --

The network text gadget can be instantiated by indexing the -- gadget module with text.network. By default, the -- gadget pattern is in:$net_in out:$net_out. See the -- provider's documentation below to learn about the available -- variables.

-- --
-- g = flaw.gadget.text.network('wlan0') --
-- --

Graph Gadget

-- --

The network graph gadget can be instantiated by indexing the -- gadget module with graph.network. By default, the -- chart displayed by the gadget shows the evolution of -- percents_in. See the provider's documentation below to -- learn about the available variables.

-- --
-- g = flaw.gadget.graph.network(
--    'eth1', {}, { width = 60, height = 18 }) --
-- --

Provider

-- --

The network provider loads its information from -- /proc/net/dev. It stores the data for each line, which -- represent the network devices of the machine. The file format is -- explained in the proc manual page (for example at http://linux.die.net/man/5/proc

-- --

The network provider computed data is composed of the following -- fields.

-- --
    -- --
  • net_in -- --

    The number of packets received by the monitored interface -- between two updates of the provider.

  • -- --
  • net_out -- --

    The number of packets emitted by the monitored interface -- between two updates of the provider.

  • -- --
  • all_net_in -- --

    The total number of packets received by the monitored interface -- since the machine start up.

  • -- --
  • all_net_out -- --

    The total number of packets emitted by the monitored interface -- since the machine start up.

  • -- --
  • percents_in -- --

    The incoming data load in percents on the monitored -- interface. This value is for now computed with a hard-coded maximum -- value of 256000 (in DL_BANDWIDTH).

  • -- --
  • percents_out -- --

    The ougoing data load in percents on the monitored -- interface. This value is for now computed with a hard-coded maximum -- value of 64000 (in UP_BANDWIDTH).

  • -- --
-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2009,2010,2011 David Soulayrol module('flaw.network') -- Bandwidth in bytes. -- TODO: should become a parameter for the provider. DL_BANDWIDTH = 256000 UP_BANDWIDTH = 64000 --- The network provider prototype. -- --

The network provider type is set to -- network._NAME.

-- -- @class table -- @name NetworkProvider NetworkProvider = flaw.provider.CyclicProvider:new{ type = _NAME } --- Callback for provider refresh. function NetworkProvider:do_refresh() local file = io.open('/proc/net/dev') local sep local adapter local line = '' local input, output while line ~= nil do line = file:read() if line ~= nil then -- Skip the adapter prefix. sep = string.find (line, ':') if sep ~= nil then adapter = flaw.helper.strings.lstrip(string.sub(line, 0, sep - 1)) if adapter ~= nil then if self.data[adapter] == nil then self.data[adapter] = { all_net_in = 0, all_net_out = 0, net_in = 0, net_out = 0 } end -- First decimal number are total bytes local split_line = flaw.helper.strings.split( string.sub(line, sep + 1)) local interval = os.time() - self.timestamp input = tonumber(split_line[1]) output = tonumber(split_line[9]) self.data[adapter].net_in = (input - self.data[adapter].all_net_in) / interval self.data[adapter].net_out = (output - self.data[adapter].all_net_out) / interval self.data[adapter].percents_in = (self.data[adapter].net_in / DL_BANDWIDTH) * 100 self.data[adapter].percents_out = (self.data[adapter].net_out / UP_BANDWIDTH) * 100 self.data[adapter].all_net_in = input self.data[adapter].all_net_out = output end end end end io.close(file); end --- A factory for network providers. -- --

Only one provider is built for all network adapters. Its data is -- a map indexed by the name of the interface.

-- -- @return a brand new network provider, or the existing one if found -- in the providers cache. function provider_factory() local p = flaw.provider.get(_NAME, '') -- Create the provider if necessary. if p == nil then p = NetworkProvider:new{ id = '', data = {} } flaw.provider.add(p) end return p end -- An icon gadget for network status display. flaw.gadget.register.icon(_M) -- A Text gadget for network status display. flaw.gadget.register.text(_M, { delay = 1, pattern = 'in:$net_in out:$net_out' }) -- A graph gadget for network load display. flaw.gadget.register.graph(_M, { delay = 1, values = { 'percents_in' } }) awesome-extra/flaw/COPYING0000644000000000000000000010437411734355656012541 0ustar GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . awesome-extra/flaw/gmail.lua0000644000000000000000000001437711734355656013305 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local io = io local os = os local awful = { button = require("awful.button"), util = require("awful.util"), } local flaw = { helper = require('flaw.helper'), gadget = require('flaw.gadget'), provider = require('flaw.provider') } --- GMail report gadget and provider. -- --

This module contains a provider for GMail contents and a text -- gadget.

-- --

Gadget

-- --

The gmail gadget can be instantiated by indexing the gadget -- module with text.gmail. The ID parameter has no -- meaning for this gadget, and it takes no particular parameters. By -- default, the gadget pattern is '$count messages'. See -- the gadget module documentation to -- learn about standard gadgets parameters.

-- --
-- g = flaw.gadget.text.gmail() --
-- --

The gmail gadget is updated every delay seconds, -- like any other gadget. However, clicking on the gadget triggers -- immediate mail check.

-- --

Provider

-- --

The gmail provider gets it information by downloading with -- curl the feed at -- https://mail.google.com/mail/feed/atom/unread. Of -- course, this URL needs authentication, so the file -- $HOME/.netrc should at least have a line with the -- following format:

-- --
-- machine mail.google.com login my_login password my_password --
-- --

This file is read by curl to proceed to -- authentication when asked. Since it keeps unobfuscated passwords, -- this file shall be readable only by the user.

-- --

The gmail provider data is composed of the following fields.

-- --
    -- --
  • timestamp -- --

    The date of the last check.

  • -- --
  • count -- --

    The current number of unread messages.

  • -- --
  • mails -- --

    The unread threads. This text block is intended to be used in a -- notification popup or a tooltip, like this:

    -- --
    -- gmail_gadget:set_tooltip('Unread threads at $timestamp\n$mails') --
  • -- --
-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2010, David Soulayrol module('flaw.gmail') --- The gmail provider prototype. -- --

The gmail provider type is set to gmail._NAME.

-- -- @class table -- @name GMailProvider GMailProvider = flaw.provider.CyclicProvider:new{ type = _NAME } --- Callback for provider refresh. function GMailProvider:do_refresh() local states = { ROOT = 0, ENTRY = 1, AUTHOR = 2 } local depth = states.ROOT local current = '' local pattern = '' local feed = 'https://mail.google.com/mail/feed/atom/unread' local f = io.popen("curl --connect-timeout 1 -m 3 -fsn " .. feed) if 0 ~= f:seek("end") then self.data.timestamp = os.date('%H:%M') self.data.count = '0' self.data.mails = '' f:seek("set") for line in f:lines() do if depth == states.AUTHOR then if line:match("") ~= nil then depth = states.ENTRY else pattern = line:match("(.*)") if pattern ~= nil then current = current .. ' (' .. flaw.helper.strings.escape(pattern) .. ')' end end elseif depth == states.ENTRY then if line:match("") ~= nil then self.data.mails = self.data.mails .. current .. "\n" depth = states.ROOT elseif line:match("") ~= nil then depth = states.AUTHOR else pattern = line:match("(.*)") if pattern ~= nil then current = flaw.helper.strings.crop( flaw.helper.strings.escape(pattern), 42) -- Remove HTML entities that would be now truncated. local i = current:find("&") if i ~= nil and current:find(";") == nil then current = current:sub(0, i - 1) .. "..." end current = "" .. current .. "" end end elseif depth == states.ROOT then if line:match("") ~= nil then depth = states.ENTRY else self.data.count = line:match("([%d]+)") or self.data.count end end end end f:close() end --- A factory for GMail provider. -- --

Only one provider is built. It is stored in the global provider -- cache.

-- -- @return a brand new gmail provider, or the existing one if found in -- the providers cache. function provider_factory() local p = flaw.provider.get(_NAME, '') -- Create the provider if necessary. if p == nil then p = GMailProvider:new{ id = '', data = { timestamp = 'N/A', count = "0", mails = '' } } flaw.provider.add(p) end return p end -- A Text gadget prototype for GMail status display. GMailTextGadget = flaw.gadget.TextGadget:new{} -- Create the wrapped gadget. function GMailTextGadget:create(wopt) flaw.gadget.TextGadget.create(self, wopt) self.widget:buttons( awful.util.table.join( awful.button({ }, 1, function() self.provider:refresh(self) end))) end -- A Text gadget prototype for GMail summary display. flaw.gadget.register.text( _M, { delay = 300, pattern = '$count messages' }, {}, GMailTextGadget) awesome-extra/flaw/title.lua0000644000000000000000000000702011734355656013320 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local capi = { client = client, } local awful = { util = require("awful.util"), } local flaw = { gadget = require('flaw.gadget'), provider = require('flaw.provider'), helper = require('flaw.helper'), } --- Clients title display. -- --

This module contains a simple text gadget which displays the -- title of the active client, and its provider. This is a convenient -- way to see the window title displayed, even if the window bar is -- not displayed.

-- --

Gadget

-- --

The title gadget can be instantiated by indexing the gadget -- module with text.title. The ID parameter has no -- meaning for the calendar gadget, and it takes no particular -- parameters. See the gadget module -- documentation to learn about standard gadgets parameters.

-- --
-- g = flaw.gadget.text.title('') --
-- --

Provider

-- --

The provider makes no hardware or software access whatsoever. It -- simply plugs its update method on the -- focus, unfocus and -- property::name signals. This also means the -- delay parameter has no meaning for it.

-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2010,2011 David Soulayrol module('flaw.title') --- The client events provider prototype. -- --

The client title provider type is set to -- title._NAME.

-- -- @class table -- @name ClientProvider ClientProvider = flaw.provider.Provider:new{ type = _NAME } --- Display the new client title. function ClientProvider:update(c) if c and c.name and capi.client.focus == c then self.data.title = awful.util.escape(c.name) self:refresh_gadgets() end end --- Erase the client title. function ClientProvider:reset(c) if c then self.data.title = '' self:refresh_gadgets() end end --- A factory for client providers. -- -- @return a brand new client provider. function provider_factory() local p = flaw.provider.get(_NAME, '') -- Create the provider if necessary. if p == nil then p = ClientProvider:new{ id = '', data = { title = '' } } flaw.provider.add(p) -- Init signals once for the provider. capi.client.add_signal( 'manage', function (c, startup) c:add_signal('property::name', function(c) p:update(c) end) end) capi.client.add_signal('focus', function(c) p:update(c) end) capi.client.add_signal('unfocus', function(c) p:reset(c) end) end return p end -- A Text gadget prototype for clients title display. flaw.gadget.register.text(_M, { pattern = '$title' }) awesome-extra/flaw/battery.lua0000644000000000000000000002070311734355656013654 0ustar -- flaw, a Lua OO management framework for Awesome WM widgets. -- Copyright (C) 2009,2010,2011 David Soulayrol -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- Grab environment. local io = io local lfs = require('lfs') local math = math local os = os local beautiful = require('beautiful') local naughty = require('naughty') local flaw = { helper = require('flaw.helper'), gadget = require('flaw.gadget'), provider = require('flaw.provider') } -- Provider sources. local SRC_PROC_DIR = '/proc/acpi/battery/' local SRC_SYSFS_DIR = '/sys/class/power_supply/' -- Helper tools for environment settings. local function has_proc_information() return lfs.attributes(SRC_PROC_DIR, 'mode') == 'directory' end local function has_sysfs_information() local path = SRC_SYSFS_DIR local r = false for file in lfs.dir(path) do if file ~= "." and file ~= ".." then local f = io.open(path .. '/' .. file .. '/type') if f ~= nil then if f:read() == 'Battery' then r = true end f:close() end end if r ~= false then break end end return r end --- Battery information gadgets and provider. -- --

This module contains a provider for battery information and two -- gadgets: a text gadget and an icon gadget.

-- --

Gadgets

-- --

The ID of the gadget designates the battery slot to be -- monitored. Battery gadgets provide no custom parameters. See the gadget module documentation to learn -- about standard gadgets parameters.

-- --

Icon Gadget

-- --

The battery icon gadget can be instantiated by indexing the -- gadget module with icon.battery. Here is an exemple -- which assumes the battery icon path is stored in a beautiful -- property.

-- --
-- g = flaw.gadget.icon.battery(
--    'BAT0', {}, { image = image(beautiful.battery_icon) })
--
-- --

Text Gadget

-- --

The battery text gadget can be instantiated by indexing the -- gadget module with text.battery. By default, the -- gadget pattern is '$load% $status'. See the provider's -- documentation below to learn about the available variables.

-- --
-- g = flaw.gadget.text.battery('BAT0') --
-- --

Provider

-- --

The battery provider loads its information from -- /proc/acpi/battery/<ID>/ and -- /sys/class/power_supply/<ID>/ if they exist.

-- --

The battery provider data is composed of the following fields.

-- --
    -- --
  • load -- --

    The current battery load in percents.

  • -- --
  • st_symbol -- --

    The current power supply utilisation. It is set to the value of -- battery.STATUS_PLUGGED if AC adaptor is in use and -- there is no activity on the battery, -- battery.STATUS_CHARGING if the battery is in charge, -- or battery.STATUS_DISCHARGING if the battery is -- currently the only power supply. At last, the symbol -- battery.STATUS_UNKNOWN is used when the provider has -- no information on the battery slot.

  • -- --
  • seconds -- --

    The number of seconds until the battery is empty or loaded, -- whether its status is discharging or charging. This information is -- currently only available if the -- /proc/acpi/battery/<ID>/ path is -- available

  • -- --
  • time -- --

    The seconds information, formatted as a date.

  • -- --
-- -- -- @author David Soulayrol <david.soulayrol AT gmail DOT com> -- @copyright 2009,2010,2011 David Soulayrol module('flaw.battery') -- Battery statuses. STATUS_UNKNOWN = '=' STATUS_PLUGGED = '(A/C)' STATUS_CHARGING = '^' STATUS_DISCHARGING = 'v' --- The battery provider prototype. -- --

The battery provider type is set to -- battery._NAME.

-- -- @class table -- @name BatteryProvider BatteryProvider = flaw.provider.CyclicProvider:new{ type = _NAME } --- Load state information from --- /proc/acpi/battery/<ID>/ if it exists. function BatteryProvider:load_from_procfs() local p = self.data.proc local r1 = flaw.helper.file.load_state_file( SRC_PROC_DIR .. self.id:upper(), 'state', p) local r2 = flaw.helper.file.load_state_file( SRC_PROC_DIR .. self.id:upper(), 'info', p) if r1 > 0 or r2 > 0 then -- Adapt values. local state = p.state_charging_state or '' local r_capacity = p.state_remaining_capacity:match('(%d+).*') or 0 local rate = p.state_present_rate:match('(%d+).*') or 1 if rate ~= nil and rate ~= 0 then if state == 'discharging' then -- remaining seconds. self.data.seconds = 3600 * r_capacity / rate self.data.time = os.date('!remaining %X', self.data.seconds) elseif state == 'charging' then -- seconds until charged. local l_capacity = p.info_last_full_capacity:match('(%d+).*') or 0 self.data.seconds = 3600 * (l_capacity - r_capacity) / rate self.data.time = os.date('!full in %X', self.data.seconds) end end end end --- Load state information from --- /sys/class/power_supply/<ID>/ if it exists. function BatteryProvider:load_from_sysfs() local f = nil -- Load raw values. local f = io.open(SRC_SYSFS_DIR .. self.id .. "/charge_now") if f ~= nil then self.data.sys.charge_now = f:read() f:close() end f = io.open(SRC_SYSFS_DIR .. self.id .. "/charge_full") if f ~= nil then self.data.sys.charge_full = f:read() f:close() end f = io.open(SRC_SYSFS_DIR .. self.id .. "/status") if f ~= nil then self.data.sys.status = f:read() f:close() end -- Compute interesting values. self.data.load = math.floor(self.data.sys.charge_now * 100 / self.data.sys.charge_full) if self.data.load > 100 then self.data.load = 100 end self.data.st_symbol = STATUS_PLUGGED if self.data.sys.status:match("Charging") then self.data.st_symbol = STATUS_CHARGING elseif self.data.sys.status:match("Discharging") then self.data.st_symbol = STATUS_DISCHARGING end end --- Callback for provider refresh. function BatteryProvider:do_refresh() if has_proc_information() then self:load_from_procfs() end self:load_from_sysfs() end --- A factory for battery providers. -- --

Only one provider is built for a slot. Created providers are -- stored in the global provider cache.

-- -- @param slot the identifier of the battery for which the new -- provider should gather information. -- @return a brand new battery provider, or an existing one if the -- given slot was already used to create one. function provider_factory(slot) local p = flaw.provider.get(_NAME, slot) -- Create the provider if necessary. if p == nil then p = BatteryProvider:new{ id = slot, data = { load = 0, st_symbol = '', seconds = 0, time = '', sys = {}, proc = {} } } flaw.provider.add(p) end return p end --- Module initialization routine. -- --

This method tests the available information on the system. If -- battery data can be found, it registers gadgets and returns the -- module; otherwise it simply returns nil.

-- -- @return return this module if it can be used on the system, -- false otherwise. function init() if has_proc_information() or has_sysfs_information() then -- A Text gadget prototype for battery status display. flaw.gadget.register.text(_M, { pattern = '$load% $status' }) -- An icon gadget prototype for battery status display. flaw.gadget.register.icon(_M, { status = STATUS_UNKNOWN }) return _M end end awesome-extra/shifty/0000755000000000000000000000000011765367624012054 5ustar awesome-extra/shifty/init.lua0000644000000000000000000010216511734355121013510 0ustar --- Shifty: Dynamic tagging library for awesome3-git -- @author koniu <gkusnierz@gmail.com> -- @author resixian (aka bioe007) <resixian@gmail.com> -- -- http://awesome.naquadah.org/wiki/index.php?title=Shifty -- environment local type = type local ipairs = ipairs local table = table local string = string local beautiful = require("beautiful") local awful = require("awful") local pairs = pairs local io = io local tonumber = tonumber local dbg= dbg local capi = { client = client, tag = tag, image = image, screen = screen, button = button, mouse = mouse, root = root, timer = timer } module("shifty") -- variables config = {} config.tags = {} config.apps = {} config.defaults = {} config.float_bars = false config.guess_name = true config.guess_position = true config.remember_index = true config.sloppy = true config.default_name = "new" config.clientkeys = {} config.globalkeys = nil config.layouts = {} config.prompt_sources = { "config_tags", "config_apps", "existing", "history" } config.prompt_matchers = { "^", ":", "" } local matchp = "" local index_cache = {} for i = 1, capi.screen.count() do index_cache[i] = {} end --name2tags: matches string 'name' to tag objects -- @param name : tag name to find -- @param scr : screen to look for tags on -- @return table of tag objects or nil function name2tags(name, scr) local ret = {} local a, b = scr or 1, scr or capi.screen.count() for s = a, b do for i, t in ipairs(capi.screen[s]:tags()) do if name == t.name then table.insert(ret, t) end end end if #ret > 0 then return ret end end function name2tag(name, scr, idx) local ts = name2tags(name, scr) if ts then return ts[idx or 1] end end --tag2index: finds index of a tag object -- @param scr : screen number to look for tag on -- @param tag : the tag object to find -- @return the index [or zero] or end of the list function tag2index(scr, tag) for i, t in ipairs(capi.screen[scr]:tags()) do if t == tag then return i end end end --rename --@param tag: tag object to be renamed --@param prefix: if any prefix is to be added --@param no_selectall: function rename(tag, prefix, no_selectall) local theme = beautiful.get() local t = tag or awful.tag.selected(capi.mouse.screen) local scr = t.screen local bg = nil local fg = nil local text = prefix or t.name local before = t.name if t == awful.tag.selected(scr) then bg = theme.bg_focus or '#535d6c' fg = theme.fg_urgent or '#ffffff' else bg = theme.bg_normal or '#222222' fg = theme.fg_urgent or '#ffffff' end awful.prompt.run({ fg_cursor = fg, bg_cursor = bg, ul_cursor = "single", text = text, selectall = not no_selectall}, taglist[scr][tag2index(scr, t) * 2], function (name) if name:len() > 0 then t.name = name; end end, completion, awful.util.getdir("cache") .. "/history_tags", nil, function () if t.name == before then if awful.tag.getproperty(t, "initial") then del(t) end else awful.tag.setproperty(t, "initial", true) set(t) end tagkeys(capi.screen[scr]) t:emit_signal("property::name") end ) end --send: moves client to tag[idx] -- maybe this isn't needed here in shifty? -- @param idx the tag number to send a client to function send(idx) local scr = capi.client.focus.screen or capi.mouse.screen local sel = awful.tag.selected(scr) local sel_idx = tag2index(scr, sel) local tags = capi.screen[scr]:tags() local target = awful.util.cycle(#tags, sel_idx + idx) awful.client.movetotag(tags[target], capi.client.focus) awful.tag.viewonly(tags[target]) end function send_next() send(1) end function send_prev() send(-1) end --pos2idx: translate shifty position to tag index --@param pos: position (an integer) --@param scr: screen number function pos2idx(pos, scr) local v = 1 if pos and scr then for i = #capi.screen[scr]:tags() , 1, -1 do local t = capi.screen[scr]:tags()[i] if awful.tag.getproperty(t, "position") and awful.tag.getproperty(t, "position") <= pos then v = i + 1 break end end end return v end --select : helper function chooses the first non-nil argument --@param args - table of arguments function select(args) for i, a in pairs(args) do if a ~= nil then return a end end end --tagtoscr : move an entire tag to another screen -- --@param scr : the screen to move tag to --@param t : the tag to be moved [awful.tag.selected()] --@return the tag function tagtoscr(scr, t) -- break if called with an invalid screen number if not scr or scr < 1 or scr > capi.screen.count() then return end -- tag to move local otag = t or awful.tag.selected() otag.screen = scr -- set screen and then reset tag to order properly if #otag:clients() > 0 then for _ , c in ipairs(otag:clients()) do if not c.sticky then c.screen = scr c:tags({otag}) else awful.client.toggletag(otag, c) end end end return otag end --set : set a tags properties --@param t: the tag --@param args : a table of optional (?) tag properties --@return t - the tag object function set(t, args) if not t then return end if not args then args = {} end -- set the name t.name = args.name or t.name -- attempt to load preset on initial run local preset = (awful.tag.getproperty(t, "initial") and config.tags[t.name]) or {} -- pick screen and get its tag table local scr = args.screen or (not t.screen and preset.screen) or t.screen or capi.mouse.screen local clientstomove = nil if scr > capi.screen.count() then scr = capi.screen.count() end if t.screen and scr ~= t.screen then tagtoscr(scr, t) t.screen = nil end local tags = capi.screen[scr]:tags() -- try to guess position from the name local guessed_position = nil if not (args.position or preset.position) and config.guess_position then local num = t.name:find('^[1-9]') if num then guessed_position = tonumber(t.name:sub(1, 1)) end end -- allow preset.layout to be a table to provide a different layout per -- screen for a given tag local preset_layout = preset.layout if preset_layout and preset_layout[scr] then preset_layout = preset.layout[scr] end -- select from args, preset, getproperty, -- config.defaults.configs or defaults local props = { layout = select{args.layout, preset_layout, awful.tag.getproperty(t, "layout"), config.defaults.layout, awful.layout.suit.tile}, mwfact = select{args.mwfact, preset.mwfact, awful.tag.getproperty(t, "mwfact"), config.defaults.mwfact, 0.55}, nmaster = select{args.nmaster, preset.nmaster, awful.tag.getproperty(t, "nmaster"), config.defaults.nmaster, 1}, ncol = select{args.ncol, preset.ncol, awful.tag.getproperty(t, "ncol"), config.defaults.ncol, 1}, matched = select{args.matched, awful.tag.getproperty(t, "matched")}, exclusive = select{args.exclusive, preset.exclusive, awful.tag.getproperty(t, "exclusive"), config.defaults.exclusive}, persist = select{args.persist, preset.persist, awful.tag.getproperty(t, "persist"), config.defaults.persist}, nopopup = select{args.nopopup, preset.nopopup, awful.tag.getproperty(t, "nopopup"), config.defaults.nopopup}, leave_kills = select{args.leave_kills, preset.leave_kills, awful.tag.getproperty(t, "leave_kills"), config.defaults.leave_kills}, max_clients = select{args.max_clients, preset.max_clients, awful.tag.getproperty(t, "max_clients"), config.defaults.max_clients}, position = select{args.position, preset.position, guessed_position, awful.tag.getproperty(t, "position")}, icon = select{args.icon and capi.image(args.icon), preset.icon and capi.image(preset.icon), awful.tag.getproperty(t, "icon"), config.defaults.icon and capi.image(config.defaults.icon)}, icon_only = select{args.icon_only, preset.icon_only, awful.tag.getproperty(t, "icon_only"), config.defaults.icon_only}, sweep_delay = select{args.sweep_delay, preset.sweep_delay, awful.tag.getproperty(t, "sweep_delay"), config.defaults.sweep_delay}, overload_keys = select{args.overload_keys, preset.overload_keys, awful.tag.getproperty(t, "overload_keys"), config.defaults.overload_keys}, } -- get layout by name if given as string if type(props.layout) == "string" then props.layout = getlayout(props.layout) end -- set keys if args.keys or preset.keys then local keys = awful.util.table.join(config.globalkeys, args.keys or preset.keys) if props.overload_keys then props.keys = keys else props.keys = squash_keys(keys) end end -- calculate desired taglist index local index = args.index or preset.index or config.defaults.index local rel_index = args.rel_index or preset.rel_index or config.defaults.rel_index local sel = awful.tag.selected(scr) --TODO: what happens with rel_idx if no tags selected local sel_idx = (sel and tag2index(scr, sel)) or 0 local t_idx = tag2index(scr, t) local limit = (not t_idx and #tags + 1) or #tags local idx = nil if rel_index then idx = awful.util.cycle(limit, (t_idx or sel_idx) + rel_index) elseif index then idx = awful.util.cycle(limit, index) elseif props.position then idx = pos2idx(props.position, scr) if t_idx and t_idx < idx then idx = idx - 1 end elseif config.remember_index and index_cache[scr][t.name] then idx = index_cache[scr][t.name] elseif not t_idx then idx = #tags + 1 end -- if we have a new index, remove from old index and insert if idx then if t_idx then table.remove(tags, t_idx) end table.insert(tags, idx, t) index_cache[scr][t.name] = idx end -- set tag properties and push the new tag table capi.screen[scr]:tags(tags) for prop, val in pairs(props) do awful.tag.setproperty(t, prop, val) end -- execute run/spawn if awful.tag.getproperty(t, "initial") then local spawn = args.spawn or preset.spawn or config.defaults.spawn local run = args.run or preset.run or config.defaults.run if spawn and args.matched ~= true then awful.util.spawn_with_shell(spawn, scr) end if run then run(t) end awful.tag.setproperty(t, "initial", nil) end return t end function shift_next() set(awful.tag.selected(), {rel_index = 1}) end function shift_prev() set(awful.tag.selected(), {rel_index = -1}) end --add : adds a tag --@param args: table of optional arguments function add(args) if not args then args = {} end local name = args.name or " " -- initialize a new tag object and its data structure local t = capi.tag{name = name} -- tell set() that this is the first time awful.tag.setproperty(t, "initial", true) -- apply tag settings set(t, args) -- unless forbidden or if first tag on the screen, show the tag if not (awful.tag.getproperty(t, "nopopup") or args.noswitch) or #capi.screen[t.screen]:tags() == 1 then awful.tag.viewonly(t) end -- get the name or rename if args.name then t.name = args.name else -- FIXME: hack to delay rename for un-named tags for -- tackling taglist refresh which disabled prompt -- from being rendered until input awful.tag.setproperty(t, "initial", true) local f if args.position then f = function() rename(t, args.rename, true); tmr:stop() end else f = function() rename(t); tmr:stop() end end tmr = capi.timer({timeout = 0.01}) tmr:add_signal("timeout", f) tmr:start() end return t end --del : delete a tag --@param tag : the tag to be deleted [current tag] function del(tag) local scr = (tag and tag.screen) or capi.mouse.screen or 1 local tags = capi.screen[scr]:tags() local sel = awful.tag.selected(scr) local t = tag or sel local idx = tag2index(scr, t) -- return if tag not empty (except sticky) local clients = t:clients() local sticky = 0 for i, c in ipairs(clients) do if c.sticky then sticky = sticky + 1 end end if #clients > sticky then return end -- store index for later index_cache[scr][t.name] = idx -- remove tag t.screen = nil -- if the current tag is being deleted, restore from history if t == sel and #tags > 1 then awful.tag.history.restore(scr, 1) -- this is supposed to cycle if history is invalid? -- e.g. if many tags are deleted in a row if not awful.tag.selected(scr) then awful.tag.viewonly(tags[awful.util.cycle(#tags, idx - 1)]) end end -- FIXME: what is this for?? if capi.client.focus then capi.client.focus:raise() end end --is_client_tagged : replicate behavior in tag.c - returns true if the --given client is tagged with the given tag function is_client_tagged(tag, client) for i, c in ipairs(tag:clients()) do if c == client then return true end end return false end --match : handles app->tag matching, a replacement for the manage hook in -- rc.lua --@param c : client to be matched function match(c, startup) local nopopup, intrusive, nofocus, run, slave local wfact, struts, geom, float local target_tag_names, target_tags = {}, {} local typ = c.type local cls = c.class local inst = c.instance local role = c.role local name = c.name local keys = config.clientkeys or c:keys() or {} local target_screen = capi.mouse.screen c.border_color = beautiful.border_normal c.border_width = beautiful.border_width -- try matching client to config.apps for i, a in ipairs(config.apps) do if a.match then local matched = false -- match only class if not matched and cls and a.match.class then for k, w in ipairs(a.match.class) do matched = cls:find(w) if matched then break end end end -- match only instance if not matched and inst and a.match.instance then for k, w in ipairs(a.match.instance) do matched = inst:find(w) if matched then break end end end -- match only name if not matched and name and a.match.name then for k, w in ipairs(a.match.name) do matched = name:find(w) if matched then break end end end -- match only role if not matched and role and a.match.role then for k, w in ipairs(a.match.role) do matched = role:find(w) if matched then break end end end -- match only type if not matched and typ and a.match.type then for k, w in ipairs(a.match.type) do matched = typ:find(w) if matched then break end end end -- check everything else against all attributes if not matched then for k, w in ipairs(a.match) do matched = (cls and cls:find(w)) or (inst and inst:find(w)) or (name and name:find(w)) or (role and role:find(w)) or (typ and typ:find(w)) if matched then break end end end -- set attributes if matched then if a.screen then target_screen = a.screen end if a.tag then if type(a.tag) == "string" then target_tag_names = {a.tag} else target_tag_names = a.tag end end if a.startup and startup then a = awful.util.table.join(a, a.startup) end if a.geometry ~=nil then geom = {x = a.geometry[1], y = a.geometry[2], width = a.geometry[3], height = a.geometry[4]} end if a.float ~= nil then float = a.float end if a.slave ~=nil then slave = a.slave end if a.border_width ~= nil then c.border_width = a.border_width end if a.nopopup ~=nil then nopopup = a.nopopup end if a.intrusive ~=nil then intrusive = a.intrusive end if a.fullscreen ~=nil then c.fullscreen = a.fullscreen end if a.honorsizehints ~=nil then c.size_hints_honor = a.honorsizehints end if a.kill ~=nil then c:kill(); return end if a.ontop ~= nil then c.ontop = a.ontop end if a.above ~= nil then c.above = a.above end if a.below ~= nil then c.below = a.below end if a.buttons ~= nil then c:buttons(a.buttons) end if a.nofocus ~= nil then nofocus = a.nofocus end if a.keys ~= nil then keys = awful.util.table.join(keys, a.keys) end if a.hidden ~= nil then c.hidden = a.hidden end if a.minimized ~= nil then c.minimized = a.minimized end if a.dockable ~= nil then awful.client.dockable.set(c, a.dockable) end if a.urgent ~= nil then c.urgent = a.urgent end if a.opacity ~= nil then c.opacity = a.opacity end if a.run ~= nil then run = a.run end if a.sticky ~= nil then c.sticky = a.sticky end if a.wfact ~= nil then wfact = a.wfact end if a.struts then struts = a.struts end if a.skip_taskbar ~= nil then c.skip_taskbar = a.skip_taskbar end if a.props then for kk, vv in pairs(a.props) do awful.client.property.set(c, kk, vv) end end end end end -- set key bindings c:keys(keys) -- Add titlebars to all clients when the float, remove when they are -- tiled. if config.float_bars then c:add_signal("property::floating", function(c) if awful.client.floating.get(c) then awful.titlebar.add(c, {modkey=modkey}) else awful.titlebar.remove(c) end awful.placement.no_offscreen(c) end) end -- set properties of floating clients if float ~= nil then awful.client.floating.set(c, float) awful.placement.no_offscreen(c) end local sel = awful.tag.selectedlist(target_screen) if not target_tag_names or #target_tag_names == 0 then -- if not matched to some names try putting -- client in c.transient_for or current tags if c.transient_for then target_tags = c.transient_for:tags() elseif #sel > 0 then for i, t in ipairs(sel) do local mc = awful.tag.getproperty(t, "max_clients") if intrusive or not (awful.tag.getproperty(t, "exclusive") or (mc and mc >= #t:clients())) then table.insert(target_tags, t) end end end end if (not target_tag_names or #target_tag_names == 0) and (not target_tags or #target_tags == 0) then -- if we still don't know any target names/tags guess -- name from class or use default if config.guess_name and cls then target_tag_names = {cls:lower()} else target_tag_names = {config.default_name} end end if #target_tag_names > 0 and #target_tags == 0 then -- translate target names to tag objects, creating -- missing ones for i, tn in ipairs(target_tag_names) do local res = {} for j, t in ipairs(name2tags(tn, target_screen) or name2tags(tn) or {}) do local mc = awful.tag.getproperty(t, "max_clients") local tagged = is_client_tagged(t, c) if intrusive or not (mc and (((#t:clients() >= mc) and not tagged) or (#t:clients() > mc))) or intrusive then table.insert(res, t) end end if #res == 0 then table.insert(target_tags, add({name = tn, noswitch = true, matched = true})) else target_tags = awful.util.table.join(target_tags, res) end end end -- set client's screen/tag if needed target_screen = target_tags[1].screen or target_screen if c.screen ~= target_screen then c.screen = target_screen end if slave then awful.client.setslave(c) end c:tags(target_tags) if wfact then awful.client.setwfact(wfact, c) end if geom then c:geometry(geom) end if struts then c:struts(struts) end local showtags = {} local u = nil if #target_tags > 0 and not startup then -- switch or highlight for i, t in ipairs(target_tags) do if not (nopopup or awful.tag.getproperty(t, "nopopup")) then table.insert(showtags, t) elseif not startup then c.urgent = true end end if #showtags > 0 then local ident = false -- iterate selected tags and and see if any targets -- currently selected for kk, vv in pairs(showtags) do for _, tag in pairs(sel) do if tag == vv then ident = true end end end if not ident then awful.tag.viewmore(showtags, c.screen) end end end if not (nofocus or c.hidden or c.minimized) then --focus and raise accordingly or lower if supressed if (target and target ~= sel) and (awful.tag.getproperty(target, "nopopup") or nopopup) then awful.client.focus.history.add(c) else capi.client.focus = c end c:raise() else c:lower() end if config.sloppy then -- Enable sloppy focus c:add_signal("mouse::enter", function(c) if awful.client.focus.filter(c) and awful.layout.get(c.screen) ~= awful.layout.suit.magnifier then capi.client.focus = c end end) end -- execute run function if specified if run then run(c, target) end end --sweep : hook function that marks tags as used, visited, --deserted also handles deleting used and empty tags function sweep() for s = 1, capi.screen.count() do for i, t in ipairs(capi.screen[s]:tags()) do local clients = t:clients() local sticky = 0 for i, c in ipairs(clients) do if c.sticky then sticky = sticky + 1 end end if #clients == sticky then if awful.tag.getproperty(t, "used") and not awful.tag.getproperty(t, "persist") then if awful.tag.getproperty(t, "deserted") or not awful.tag.getproperty(t, "leave_kills") then local delay = awful.tag.getproperty(t, "sweep_delay") if delay then local f = function() del(t); tmr:stop() end tmr = capi.timer({timeout = delay}) tmr:add_signal("timeout", f) tmr:start() else del(t) end else if awful.tag.getproperty(t, "visited") and not t.selected then awful.tag.setproperty(t, "deserted", true) end end end else awful.tag.setproperty(t, "used", true) end if t.selected then awful.tag.setproperty(t, "visited", true) end end end end --getpos : returns a tag to match position -- @param pos : the index to find -- @return v : the tag (found or created) at position == 'pos' function getpos(pos, scr_arg) local v = nil local existing = {} local selected = nil local scr = scr_arg or capi.mouse.screen or 1 -- search for existing tag assigned to pos for i = 1, capi.screen.count() do for j, t in ipairs(capi.screen[i]:tags()) do if awful.tag.getproperty(t, "position") == pos then table.insert(existing, t) if t.selected and i == scr then selected = #existing end end end end if #existing > 0 then -- if making another of an existing tag, return the end of -- the list the optional 2nd argument decides if we return -- only if scr_arg ~= nil then for _, tag in pairs(existing) do if tag.screen == scr_arg then return tag end end -- no tag with a position and scr_arg match found, clear -- v and allow the subseqeunt conditions to be evaluated v = nil else v = (selected and existing[awful.util.cycle(#existing, selected + 1)]) or existing[1] end end if not v then -- search for preconf with 'pos' and create it for i, j in pairs(config.tags) do if j.position == pos then v = add({name = i, position = pos, noswitch = not switch}) end end end if not v then -- not existing, not preconfigured v = add({position = pos, rename = pos .. ':', no_selectall = true, noswitch = not switch}) end return v end --init : search shifty.config.tags for initial set of --tags to open function init() local numscr = capi.screen.count() for i, j in pairs(config.tags) do local scr = j.screen or {1} if type(scr) ~= 'table' then scr = {scr} end for _, s in pairs(scr) do if j.init and (s <= numscr) then add({name = i, persist = true, screen = s, layout = j.layout, mwfact = j.mwfact}) end end end end --count : utility function returns the index of a table element --FIXME: this is currently used only in remove_dup, so is it really --necessary? function count(table, element) local v = 0 for i, e in pairs(table) do if element == e then v = v + 1 end end return v end --remove_dup : used by shifty.completion when more than one --tag at a position exists function remove_dup(table) local v = {} for i, entry in ipairs(table) do if count(v, entry) == 0 then v[#v+ 1] = entry end end return v end --completion : prompt completion -- function completion(cmd, cur_pos, ncomp, sources, matchers) -- get sources and matches tables sources = sources or config.prompt_sources matchers = matchers or config.prompt_matchers local get_source = { -- gather names from config.tags config_tags = function() local ret = {} for n, p in pairs(config.tags) do table.insert(ret, n) end return ret end, -- gather names from config.apps config_apps = function() local ret = {} for i, p in pairs(config.apps) do if p.tag then if type(p.tag) == "string" then table.insert(ret, p.tag) else ret = awful.util.table.join(ret, p.tag) end end end return ret end, -- gather names from existing tags, starting with the -- current screen existing = function() local ret = {} for i = 1, capi.screen.count() do local s = awful.util.cycle(capi.screen.count(), capi.mouse.screen + i - 1) local tags = capi.screen[s]:tags() for j, t in pairs(tags) do table.insert(ret, t.name) end end return ret end, -- gather names from history history = function() local ret = {} local f = io.open(awful.util.getdir("cache") .. "/history_tags") for name in f:lines() do table.insert(ret, name) end f:close() return ret end, } -- if empty, match all if #cmd == 0 or cmd == " " then cmd = "" end -- match all up to the cursor if moved or no matchphrase if matchp == "" or cmd:sub(cur_pos, cur_pos+#matchp) ~= matchp then matchp = cmd:sub(1, cur_pos) end -- find matching commands local matches = {} for i, src in ipairs(sources) do local source = get_source[src]() for j, matcher in ipairs(matchers) do for k, name in ipairs(source) do if name:find(matcher .. matchp) then table.insert(matches, name) end end end end -- no matches if #matches == 0 then return cmd, cur_pos end -- remove duplicates matches = remove_dup(matches) -- cycle while ncomp > #matches do ncomp = ncomp - #matches end -- put cursor at the end of the matched phrase if #matches == 1 then cur_pos = #matches[ncomp] + 1 else cur_pos = matches[ncomp]:find(matchp) + #matchp end -- return match and position return matches[ncomp], cur_pos end -- tagkeys : hook function that sets keybindings per tag function tagkeys(s) local sel = awful.tag.selected(s.index) local keys = awful.tag.getproperty(sel, "keys") or config.globalkeys if keys and sel.selected then capi.root.keys(keys) end end -- squash_keys: helper function which removes duplicate -- keybindings by picking only the last one to be listed in keys -- table arg function squash_keys(keys) local squashed = {} local ret = {} for i, k in ipairs(keys) do squashed[table.concat(k.modifiers) .. k.key] = k end for i, k in pairs(squashed) do table.insert(ret, k) end return ret end -- getlayout: returns a layout by name function getlayout(name) for _, layout in ipairs(config.layouts) do if awful.layout.getname(layout) == name then return layout end end end -- signals capi.client.add_signal("manage", match) capi.client.add_signal("unmanage", sweep) capi.client.remove_signal("manage", awful.tag.withcurrent) for s = 1, capi.screen.count() do awful.tag.attached_add_signal(s, "property::selected", sweep) awful.tag.attached_add_signal(s, "tagged", sweep) capi.screen[s]:add_signal("tag::history::update", tagkeys) end awesome-extra/shifty/README.md0000644000000000000000000000476711651220454013330 0ustar # shifty [Shifty](https://awesome.naquadah.org/wiki/Shifty) is an Awesome 3 extension that implements dynamic tagging. It also implements fine client matching configuration allowing _you_ to be the master of _your_ desktop. Here are a few ways of how shifty makes awesome awesomer: * on-the-fly tag creation and disposal * advanced client matching * easy moving of clients between tags * tag add/rename prompt in taglist (with completion) * reordering tags and configurable positioning * tag name guessing, automagic no-config client grouping * customizable keybindings per client and tag * simple yet powerful configuration ## Use 0. Go to configuration directory, usually `~/.config/awesome` 1. Clone repository: `git clone https://bioe007@github.com/bioe007/awesome-shifty.git shifty` 2. Move the example `rc.lua` file into your configuration directory. `cp shifty/example.rc.lua rc.lua` 3. Restart awesome and enjoy. There are many configuration options for shifty, the `example.rc.lua` is provided merely as a starting point. The most important variables are the tables: * `shifty.config.tags = {}` - Sets predefined tags, which are not necessarily initialized. * `shifty.config.apps = {}` - How to handle certain applications. * `shifty.config.defaults = {}` - Fallback values used when a preset is not found in the first two configuration tables. But for each of these there are _tons_ of shifty variables and settings, its easiest to check out the wiki page or the module itself. In the `example.rc.lua` searching for `shifty` in your editor can also help to make sense of these. ## Help Help is best found in this order: 1. Web search, e.g. [Google](http://www.google.com) is your friend... 2. `#awesome` on irc.oftc.net is good for immediate aid, especially with configuration questions and such. 3. The [awesome users mailing list](mailto:awesome@naquadah.org) 4. Messaging through github 5. Directly e-mailing the [author](mailto:resixian@gmail.com) - _Please_ use this as a last resort, not that I mind, but the other formats allow others to benefit as well. ## Development Report bugs at the [github repo](https://github.com/bioe007/awesome-shifty/issues). Please include at least the current versions of awesome and shifty, as well as distribution. ## Credits * [Perry Hargrave](mailto:resixian@gmail.com) - Current maintainer and point of contact. * [koniu](mailto:gkusnierz@gmail.com) - Original author ## License Current awesome wm license or if thats not defined, GPLv2. awesome-extra/shifty/example.rc.lua0000644000000000000000000003415511734355121014606 0ustar -- default rc.lua for shifty -- -- Standard awesome library require("awful") require("awful.autofocus") -- Theme handling library require("beautiful") -- Notification library require("naughty") -- shifty - dynamic tagging library require("shifty") -- useful for debugging, marks the beginning of rc.lua exec print("Entered rc.lua: " .. os.time()) -- Variable definitions -- Themes define colours, icons, and wallpapers -- The default is a dark theme theme_path = "/usr/share/awesome/themes/default/theme.lua" -- Uncommment this for a lighter theme -- theme_path = "/usr/share/awesome/themes/sky/theme" -- Actually load theme beautiful.init(theme_path) -- This is used later as the default terminal and editor to run. browser = "firefox" mail = "thunderbird" terminal = "xterm" editor = os.getenv("EDITOR") or "nano" editor_cmd = terminal .. " -e " .. editor -- Default modkey. -- Usually, Mod4 is the key with a logo between Control and Alt. -- If you do not like this or do not have such a key, I suggest you to remap -- Mod4 to another key using xmodmap or other tools. However, you can use -- another modifier like Mod1, but it may interact with others. modkey = "Mod4" -- Table of layouts to cover with awful.layout.inc, order matters. layouts = { awful.layout.suit.tile, awful.layout.suit.tile.left, awful.layout.suit.tile.bottom, awful.layout.suit.tile.top, awful.layout.suit.fair, awful.layout.suit.fair.horizontal, awful.layout.suit.max, awful.layout.suit.max.fullscreen, awful.layout.suit.magnifier, awful.layout.suit.floating } -- Define if we want to use titlebar on all applications. use_titlebar = false -- Shifty configured tags. shifty.config.tags = { w1 = { layout = awful.layout.suit.max, mwfact = 0.60, exclusive = false, position = 1, init = true, screen = 1, slave = true, }, web = { layout = awful.layout.suit.tile.bottom, mwfact = 0.65, exclusive = true, max_clients = 1, position = 4, spawn = browser, }, mail = { layout = awful.layout.suit.tile, mwfact = 0.55, exclusive = false, position = 5, spawn = mail, slave = true }, media = { layout = awful.layout.suit.float, exclusive = false, position = 8, }, office = { layout = awful.layout.suit.tile, position = 9, }, } -- SHIFTY: application matching rules -- order here matters, early rules will be applied first shifty.config.apps = { { match = { "Navigator", "Vimperator", "Gran Paradiso", }, tag = "web", }, { match = { "Shredder.*", "Thunderbird", "mutt", }, tag = "mail", }, { match = { "pcmanfm", }, slave = true }, { match = { "OpenOffice.*", "Abiword", "Gnumeric", }, tag = "office", }, { match = { "Mplayer.*", "Mirage", "gimp", "gtkpod", "Ufraw", "easytag", }, tag = "media", nopopup = true, }, { match = { "MPlayer", "Gnuplot", "galculator", }, float = true, }, { match = { terminal, }, honorsizehints = false, slave = true, }, { match = {""}, buttons = awful.util.table.join( awful.button({}, 1, function (c) client.focus = c; c:raise() end), awful.button({modkey}, 1, function(c) client.focus = c c:raise() awful.mouse.client.move(c) end), awful.button({modkey}, 3, awful.mouse.client.resize) ) }, } -- SHIFTY: default tag creation rules -- parameter description -- * floatBars : if floating clients should always have a titlebar -- * guess_name : should shifty try and guess tag names when creating -- new (unconfigured) tags? -- * guess_position: as above, but for position parameter -- * run : function to exec when shifty creates a new tag -- * all other parameters (e.g. layout, mwfact) follow awesome's tag API shifty.config.defaults = { layout = awful.layout.suit.tile.bottom, ncol = 1, mwfact = 0.60, floatBars = true, guess_name = true, guess_position = true, } -- Wibox -- Create a textbox widget mytextclock = awful.widget.textclock({align = "right"}) -- Create a laucher widget and a main menu myawesomemenu = { {"manual", terminal .. " -e man awesome"}, {"edit config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua"}, {"restart", awesome.restart}, {"quit", awesome.quit} } mymainmenu = awful.menu( { items = { {"awesome", myawesomemenu, beautiful.awesome_icon}, {"open terminal", terminal}} }) mylauncher = awful.widget.launcher({image = image(beautiful.awesome_icon), menu = mymainmenu}) -- Create a systray mysystray = widget({type = "systray", align = "right"}) -- Create a wibox for each screen and add it mywibox = {} mypromptbox = {} mylayoutbox = {} mytaglist = {} mytaglist.buttons = awful.util.table.join( awful.button({}, 1, awful.tag.viewonly), awful.button({modkey}, 1, awful.client.movetotag), awful.button({}, 3, function(tag) tag.selected = not tag.selected end), awful.button({modkey}, 3, awful.client.toggletag), awful.button({}, 4, awful.tag.viewnext), awful.button({}, 5, awful.tag.viewprev) ) mytasklist = {} mytasklist.buttons = awful.util.table.join( awful.button({}, 1, function(c) if not c:isvisible() then awful.tag.viewonly(c:tags()[1]) end client.focus = c c:raise() end), awful.button({}, 3, function() if instance then instance:hide() instance = nil else instance = awful.menu.clients({width=250}) end end), awful.button({}, 4, function() awful.client.focus.byidx(1) if client.focus then client.focus:raise() end end), awful.button({}, 5, function() awful.client.focus.byidx(-1) if client.focus then client.focus:raise() end end)) for s = 1, screen.count() do -- Create a promptbox for each screen mypromptbox[s] = awful.widget.prompt({layout = awful.widget.layout.leftright}) -- Create an imagebox widget which will contains an icon indicating which -- layout we're using. We need one layoutbox per screen. mylayoutbox[s] = awful.widget.layoutbox(s) mylayoutbox[s]:buttons(awful.util.table.join( awful.button({}, 1, function() awful.layout.inc(layouts, 1) end), awful.button({}, 3, function() awful.layout.inc(layouts, -1) end), awful.button({}, 4, function() awful.layout.inc(layouts, 1) end), awful.button({}, 5, function() awful.layout.inc(layouts, -1) end))) -- Create a taglist widget mytaglist[s] = awful.widget.taglist.new(s, awful.widget.taglist.label.all, mytaglist.buttons) -- Create a tasklist widget mytasklist[s] = awful.widget.tasklist.new(function(c) return awful.widget.tasklist.label.currenttags(c, s) end, mytasklist.buttons) -- Create the wibox mywibox[s] = awful.wibox({position = "top", screen = s}) -- Add widgets to the wibox - order matters mywibox[s].widgets = { { mylauncher, mytaglist[s], mypromptbox[s], layout = awful.widget.layout.horizontal.leftright }, mylayoutbox[s], mytextclock, s == 1 and mysystray or nil, mytasklist[s], layout = awful.widget.layout.horizontal.rightleft } mywibox[s].screen = s end -- SHIFTY: initialize shifty -- the assignment of shifty.taglist must always be after its actually -- initialized with awful.widget.taglist.new() shifty.taglist = mytaglist shifty.init() -- Mouse bindings root.buttons(awful.util.table.join( awful.button({}, 3, function() mymainmenu:toggle() end), awful.button({}, 4, awful.tag.viewnext), awful.button({}, 5, awful.tag.viewprev) )) -- Key bindings globalkeys = awful.util.table.join( -- Tags awful.key({modkey,}, "Left", awful.tag.viewprev), awful.key({modkey,}, "Right", awful.tag.viewnext), awful.key({modkey,}, "Escape", awful.tag.history.restore), -- Shifty: keybindings specific to shifty awful.key({modkey, "Shift"}, "d", shifty.del), -- delete a tag awful.key({modkey, "Shift"}, "n", shifty.send_prev), -- client to prev tag awful.key({modkey}, "n", shifty.send_next), -- client to next tag awful.key({modkey, "Control"}, "n", function() local t = awful.tag.selected() local s = awful.util.cycle(screen.count(), t.screen + 1) awful.tag.history.restore() t = shifty.tagtoscr(s, t) awful.tag.viewonly(t) end), awful.key({modkey}, "a", shifty.add), -- creat a new tag awful.key({modkey,}, "r", shifty.rename), -- rename a tag awful.key({modkey, "Shift"}, "a", -- nopopup new tag function() shifty.add({nopopup = true}) end), awful.key({modkey,}, "j", function() awful.client.focus.byidx(1) if client.focus then client.focus:raise() end end), awful.key({modkey,}, "k", function() awful.client.focus.byidx(-1) if client.focus then client.focus:raise() end end), awful.key({modkey,}, "w", function() mymainmenu:show(true) end), -- Layout manipulation awful.key({modkey, "Shift"}, "j", function() awful.client.swap.byidx(1) end), awful.key({modkey, "Shift"}, "k", function() awful.client.swap.byidx(-1) end), awful.key({modkey, "Control"}, "j", function() awful.screen.focus(1) end), awful.key({modkey, "Control"}, "k", function() awful.screen.focus(-1) end), awful.key({modkey,}, "u", awful.client.urgent.jumpto), awful.key({modkey,}, "Tab", function() awful.client.focus.history.previous() if client.focus then client.focus:raise() end end), -- Standard program awful.key({modkey,}, "Return", function() awful.util.spawn(terminal) end), awful.key({modkey, "Control"}, "r", awesome.restart), awful.key({modkey, "Shift"}, "q", awesome.quit), awful.key({modkey,}, "l", function() awful.tag.incmwfact(0.05) end), awful.key({modkey,}, "h", function() awful.tag.incmwfact(-0.05) end), awful.key({modkey, "Shift"}, "h", function() awful.tag.incnmaster(1) end), awful.key({modkey, "Shift"}, "l", function() awful.tag.incnmaster(-1) end), awful.key({modkey, "Control"}, "h", function() awful.tag.incncol(1) end), awful.key({modkey, "Control"}, "l", function() awful.tag.incncol(-1) end), awful.key({modkey,}, "space", function() awful.layout.inc(layouts, 1) end), awful.key({modkey, "Shift"}, "space", function() awful.layout.inc(layouts, -1) end), -- Prompt awful.key({modkey}, "F1", function() awful.prompt.run({prompt = "Run: "}, mypromptbox[mouse.screen].widget, awful.util.spawn, awful.completion.shell, awful.util.getdir("cache") .. "/history") end), awful.key({modkey}, "F4", function() awful.prompt.run({prompt = "Run Lua code: "}, mypromptbox[mouse.screen].widget, awful.util.eval, nil, awful.util.getdir("cache") .. "/history_eval") end) ) -- Client awful tagging: this is useful to tag some clients and then do stuff -- like move to tag on them clientkeys = awful.util.table.join( awful.key({modkey,}, "f", function(c) c.fullscreen = not c.fullscreen end), awful.key({modkey, "Shift"}, "c", function(c) c:kill() end), awful.key({modkey, "Control"}, "space", awful.client.floating.toggle), awful.key({modkey, "Control"}, "Return", function(c) c:swap(awful.client.getmaster()) end), awful.key({modkey,}, "o", awful.client.movetoscreen), awful.key({modkey, "Shift"}, "r", function(c) c:redraw() end), awful.key({modkey}, "t", awful.client.togglemarked), awful.key({modkey,}, "m", function(c) c.maximized_horizontal = not c.maximized_horizontal c.maximized_vertical = not c.maximized_vertical end) ) -- SHIFTY: assign client keys to shifty for use in -- match() function(manage hook) shifty.config.clientkeys = clientkeys shifty.config.modkey = modkey -- Compute the maximum number of digit we need, limited to 9 for i = 1, (shifty.config.maxtags or 9) do globalkeys = awful.util.table.join(globalkeys, awful.key({modkey}, i, function() local t = awful.tag.viewonly(shifty.getpos(i)) end), awful.key({modkey, "Control"}, i, function() local t = shifty.getpos(i) t.selected = not t.selected end), awful.key({modkey, "Control", "Shift"}, i, function() if client.focus then awful.client.toggletag(shifty.getpos(i)) end end), -- move clients to other tags awful.key({modkey, "Shift"}, i, function() if client.focus then t = shifty.getpos(i) awful.client.movetotag(t) awful.tag.viewonly(t) end end)) end -- Set keys root.keys(globalkeys) -- Hook function to execute when focusing a client. client.add_signal("focus", function(c) if not awful.client.ismarked(c) then c.border_color = beautiful.border_focus end end) -- Hook function to execute when unfocusing a client. client.add_signal("unfocus", function(c) if not awful.client.ismarked(c) then c.border_color = beautiful.border_normal end end)