commit 98e26ee0436822b00d4a6e707d86cf33d24bc00f Author: Adrian C. (anrxc) Date: Wed Jul 29 17:59:32 2009 +0200 Import of vicious source tree. Vicious is a modular widget library for 'awesome' window manager, derived from the 'Wicked' widget library. Summary of changes: * Original wicked code modularized * Widgets ported from Wicked: - CPU, MEM, FS, NET, Date, Uptime, MPD * CPU widget rewritten, uses pattern matching * MEM widget rewritten, uses pattern matching - Swap widget merged with MEM widget type * FS widget rewritten, uses pattern matching - Also fixed padding in the process * NET widget rewritten, uses pattern matching * MPD widget rewritten, a bit more versatile * Removed deprecated helper functions * Widgets written for Vicious: - Thermal, Battery, Mbox, OrgMode, Volume, Entropy, Disk I/O, System Load, Wireless, Pacman, Maildir diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + 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. diff --git a/bat.lua b/bat.lua new file mode 100644 index 0000000..e6caacf --- /dev/null +++ b/bat.lua @@ -0,0 +1,44 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { popen = io.popen } +local table = { insert = table.insert } +-- }}} + + +-- Bat: provides state, charge, and remaining time for all batteries +module("vicious.bat") + + +-- {{{ Battery widget type +function worker(format) + -- Initialise tables + local battery_info = {} + local battery_state = { + ["charged"] = "+", + ["charging"] = "+", + ["discharging"] = "-" + } + + -- Get data from acpitool + local f = io.popen("acpitool -b") + + -- Format data + for line in f:lines() do + -- Check if the battery is present + if line:match("^[%s]+Battery.*") then + -- Store state and charge information + table.insert(battery_info, battery_state[line:match("([%a]*),")]) + table.insert(battery_info, line:match("([%d]?[%d]?[%d])%.")) + -- Store remaining time information if the battery supports it + table.insert(battery_info, (line:match("%%,%s(.*)") or "/")) + end + end + f:close() + + return battery_info +end +-- }}} diff --git a/cpu.lua b/cpu.lua new file mode 100644 index 0000000..5112253 --- /dev/null +++ b/cpu.lua @@ -0,0 +1,95 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local type = type +local pairs = pairs +local ipairs = ipairs +local io = { open = io.open } +local math = { floor = math.floor } +local table = { insert = table.insert } +local helpers = require("vicious.helpers") +-- }}} + + +-- Cpu: provides CPU usage for all available CPUs/cores +module("vicious.cpu") + + +-- Initialise function tables +local cpu_usage = {} +local cpu_total = {} +local cpu_active = {} + +-- {{{ CPU widget type +function worker(format, padding) + -- Get /proc/stat + local f = io.open("/proc/stat") + local cpu_lines = {} + + -- Format data + for line in f:lines() do + if line:find("^cpu") then + if #cpu_lines < 1 then cpuid = 1 + else cpuid = #cpu_lines + 1 end + + cpu_lines[cpuid] = {} + for match in line:gmatch("[%s]+([%d]+)") do + table.insert(cpu_lines[cpuid], match) + end + end + end + f: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 + local total_new = {} + local active_new = {} + local diff_total = {} + local diff_active = {} + + for i, v in ipairs(cpu_lines) do + -- Calculate totals + total_new[i] = 0 + for j = 1, #v do + total_new[i] = total_new[i] + v[j] + end + active_new[i] = v[1] + v[2] + v[3] + + -- 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] = helpers.padd(cpu_usage[k], p) + end + end + + return cpu_usage +end +-- }}} diff --git a/date.lua b/date.lua new file mode 100644 index 0000000..e6ea108 --- /dev/null +++ b/date.lua @@ -0,0 +1,24 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local os = { date = os.date } +-- }}} + + +-- Date: provides access to os.date with optional custom formatting +module("vicious.date") + + +-- {{{ Date widget type +function worker(format) + -- Get format + if format == nil then + return os.date() + else + return os.date(format) + end +end +-- }}} diff --git a/dio.lua b/dio.lua new file mode 100644 index 0000000..12a3961 --- /dev/null +++ b/dio.lua @@ -0,0 +1,73 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local type = type +local ipairs = ipairs +local io = { open = io.open } +local math = { floor = math.floor } +local table = { insert = table.insert } +-- }}} + + +-- Disk I/O: provides I/O statistics for requsted storage devices +module("vicious.dio") + + +-- Initialise function tables +local disk_usage = {} +local disk_total = {} + +-- {{{ Disk I/O widget type +function worker(format, disk) + -- Get /proc/diskstats + local f = io.open("/proc/diskstats") + local disk_lines = {} + + -- Format data + for line in f:lines() do + if line:match("("..disk..")%s") then + -- Todo: find a way to do this + --for stat in line:gmatch("%s([%d]+)") do + -- table.insert(disk_lines, stat) + --end + -- + -- Skip first two matches + local stat = line:gmatch("%s([%d]+)") + stat() + stat() + -- Store the rest + for i = 1, 11 do + table.insert(disk_lines, stat()) + end + end + end + f:close() + + -- Ensure tables are initialized correctly + while #disk_total < #disk_lines do + table.insert(disk_total, 0) + end + + -- Setup tables + local diff_total = {} + + for i, v in ipairs(disk_lines) do + -- Diskstats are absolute, substract our last reading + diff_total[i] = v - disk_total[i] + + -- Store totals + disk_total[i] = v + end + + -- Calculate I/O + disk_usage["{raw}"] = diff_total[7] + diff_total[3] + -- Divide "sectors read" by 2 and 1024 to get KB and MB + disk_usage["{kb}"] = math.floor(diff_total[7] + diff_total[3])/2 + disk_usage["{mb}"] = math.floor(diff_total[7] + diff_total[3])/1024 + + return disk_usage +end +-- }}} diff --git a/entropy.lua b/entropy.lua new file mode 100644 index 0000000..43bdb80 --- /dev/null +++ b/entropy.lua @@ -0,0 +1,37 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { open = io.open } +local math = { floor = math.floor } +local string = { format = string.format } +-- }}} + + +-- Entropy: provides available system entropy +module("vicious.entropy") + + +-- {{{ Entropy widget type +function worker(format, poolsize) + -- Don't waste time opening the poolsize, Linux 2.6 has a default + -- entropy pool of 4096-bits, if needed specify otherwise + if poolsize == nil then + poolsize = 4096 + end + + -- Get available entropy + local f = io.open("/proc/sys/kernel/random/entropy_avail") + local ent_avail = f:read() + f:close() + + -- Calculate percentage + ent_avail_percent = math.floor(ent_avail * 100 / poolsize) + -- This data is intended for a progressbar + ent_avail_percent = string.format("%0d", ent_avail_percent) + + return {ent_avail, ent_avail_percent} +end +-- }}} diff --git a/fs.lua b/fs.lua new file mode 100644 index 0000000..3afe801 --- /dev/null +++ b/fs.lua @@ -0,0 +1,56 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local type = type +local io = { popen = io.popen } +local helpers = require("vicious.helpers") +-- }}} + + +-- FS: provides usage statistics for requested mount points +module("vicious.fs") + + +-- {{{ Filesystem widget type +function worker(format, padding) + -- Get data from df + local f = io.popen("df -hP") + local args = {} + + -- Format data + for line in f:lines() do + if not line:match("^Filesystem.*") then + -- Format helper can't deal with matrices, so don't setup a + -- table for each mount point with gmatch + local size, used, avail, usep, mount = + -- Instead match all at once, including network file systems + line:match("^[%w/-:%.]+[%s]+([%d%.]+)[%a]?[%s]+([%d%.]+)[%a]?[%s]+([%d%.]+)[%a]?[%s]+([%d]+)%%[%s]+([-/%w]+)$") + + if padding then + if type(padding) == "table" then + size = helpers.padd(size, padding[1]) + used = helpers.padd(used, padding[2]) + avail = helpers.padd(avail, padding[3]) + usep = helpers.padd(usep, padding[4]) + else + size = helpers.padd(size, padding) + used = helpers.padd(used, padding) + avail = helpers.padd(avail, padding) + usep = helpers.padd(usep, padding) + end + end + + args["{"..mount.." size}"] = size + args["{"..mount.." used}"] = used + args["{"..mount.." avail}"] = avail + args["{"..mount.." usep}"] = usep + end + end + f:close() + + return args +end +-- }}} diff --git a/helpers.lua b/helpers.lua new file mode 100644 index 0000000..d2bfc9f --- /dev/null +++ b/helpers.lua @@ -0,0 +1,115 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local pairs = pairs +local tonumber = tonumber +local tostring = tostring +local table = { insert = table.insert } +local math = { + pow = math.pow, + floor = math.floor +} +local string = { + sub = string.sub, + gsub = string.gsub, + find = string.find +} +-- }}} + + +-- Helpers: provides helper functions for vicious widgets +module("vicious.helpers") + + +-- {{{ Helper functions +-- {{{ Format a string with args +function 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 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 bytes_to_string(bytes, sec, padding) + if bytes == nil or tonumber(bytes) == nil then + return "" + end + + bytes = tonumber(bytes) + + local 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 = 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 +-- }}} + +--{{{ Escape a string +function escape(text) + if text then + text = text:gsub("&", "&") + text = text:gsub("<", "<") + text = text:gsub(">", ">") + text = text:gsub("'", "'") + text = text:gsub("\"", """) + end + + return text +end +-- }}} +-- }}} diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..8c74560 --- /dev/null +++ b/init.lua @@ -0,0 +1,274 @@ +---------------------------------------------------------------- +-- Vicious widgets for the awesome window manager +-- * FAQ: http://sysphere.org/~anrxc/local/scr/sources/vicious +---------------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +-- +-- To view a human-readable summary of the license, visit: +-- * http://creativecommons.org/licenses/GPL/2.0/ +---------------------------------------------------------------- +-- Derived from Wicked, by Lucas de Vries +-- * Wicked is licensed under the WTFPL v2 +---------------------------------------------------------------- + +-- {{{ Grab environment +require("awful") +require("vicious.helpers") + +local type = type +local pairs = pairs +local awful = awful +local tonumber = tonumber +local os = { time = os.time } +local table = { + insert = table.insert, + remove = table.remove +} + +-- Grab C API +local capi = { + hooks = hooks, + widget = widget, + awesome = awesome, +} +-- }}} + + +-- {{{ Configure widgets +require("vicious.cpu") +require("vicious.thermal") +require("vicious.load") +require("vicious.uptime") +require("vicious.bat") +require("vicious.mem") +require("vicious.fs") +require("vicious.dio") +require("vicious.net") +require("vicious.wifi") +require("vicious.mbox") +require("vicious.mdir") +require("vicious.entropy") +require("vicious.org") +require("vicious.pacman") +require("vicious.mpd") +require("vicious.volume") +require("vicious.date") +-- }}} + +-- Vicious: widgets for the awesome window manager +module("vicious") + + +-- {{{ Initialise variables +local registered = {} +local widget_cache = {} + +-- Initialise the function table +widgets = {} +-- }}} + +-- {{{ Widget types +for w, i in pairs(_M) do + -- Ensure we don't call ourselves + if i and i ~= _M and type(i) == "table" then + -- Ignore the function table and helpers + if w ~= "widgets" and w ~= "helpers" then + -- Place functions in the namespace table + widgets[w] = i.worker + -- Enable caching for all widget types + widget_cache[i.worker] = {} + end + end +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 vicious, 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 vicious, 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 +-- }}} + +-- {{{ 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 = helpers.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 +-- }}} +-- }}} diff --git a/load.lua b/load.lua new file mode 100644 index 0000000..50e1a22 --- /dev/null +++ b/load.lua @@ -0,0 +1,28 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { open = io.open } +-- }}} + + +-- Load: provides system load averages for the past 1, 5, and 15 minutes +module("vicious.load") + + +-- {{{ Load widget type +function worker(format) + -- Get load averages + local f = io.open('/proc/loadavg') + local line = f:read() + f:close() + + -- Get load data + local avg1, avg5, avg15 = + line:match("([%d]*%.[%d]*)%s([%d]*%.[%d]*)%s([%d]*%.[%d]*)") + + return {avg1, avg5, avg15} +end +-- }}} diff --git a/mbox.lua b/mbox.lua new file mode 100644 index 0000000..fae3355 --- /dev/null +++ b/mbox.lua @@ -0,0 +1,45 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { open = io.open } +local string = { gfind = string.gfind } +local helpers = require("vicious.helpers") +-- }}} + + +-- Mbox: provides the subject of last e-mail in a mbox file +module("vicious.mbox") + + +-- {{{ Mailbox widget type +function worker(format, mbox) + local f = io.open(mbox) + -- mbox could be huge, get a 15kb chunk from EOF + -- * attachments could be much bigger than this + f:seek("end", -15360) + + -- Get data + local text = f:read("*all") + f:close() + + -- Find subject lines + for match in string.gfind(text, "Subject: ([^\n]*)") do + subject = match + end + + if subject then + -- Spam sanitize only the last subject + subject = helpers.escape(subject) + + -- Don't abuse the wibox, truncate + if subject:len() > 22 then + subject = subject:sub(1, 19) .. "..." + end + + return {subject} + end +end +-- }}} diff --git a/mdir.lua b/mdir.lua new file mode 100644 index 0000000..e0fe392 --- /dev/null +++ b/mdir.lua @@ -0,0 +1,41 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +-- * Derived from Maildir Biff Widget, by Fredrik Ax +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { popen = io.popen } +-- }}} + + +-- Mdir: provides a number of new and unread messages in a Maildir structure +module("vicious.mdir") + + +-- {{{ Maildir widget type +function worker(format, mdir) + -- Widgets like this one are not agressive like CPU or NET, so we + -- can keep it simple, find is OK with me if we execute every >60s + -- + -- Initialise counters + local newcount = 0 + local curcount = 0 + + -- Recursively find new messages + local fnew = io.popen("find " .. mdir .. " -type f -wholename '*/new/*'") + for line in fnew:lines() do + newcount = newcount + 1 + end + fnew:close() + + -- Recursively find "old" messages lacking the Seen flag + local fcur = io.popen("find " .. mdir .. " -type f -regex '.*/cur/.*2,[^S]*$'") + for line in fcur:lines() do + curcount = curcount + 1 + end + fcur:close() + + return {newcount, curcount} +end +-- }}} diff --git a/mem.lua b/mem.lua new file mode 100644 index 0000000..818e501 --- /dev/null +++ b/mem.lua @@ -0,0 +1,76 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local type = type +local tonumber = tonumber +local io = { open = io.open } +local math = { floor = math.floor } +local helpers = require("vicious.helpers") +-- }}} + + +-- Mem: provides RAM and Swap usage statistics +module("vicious.mem") + + +-- {{{ Memory widget type +function worker(format, padding) + -- Get meminfo + local f = io.open("/proc/meminfo") + + -- Get data + for line in f:lines() do + if line:match("^MemTotal.*") then + mem_total = math.floor(tonumber(line:match("([%d]+)")) / 1024) + elseif line:match("^MemFree.*") then + free = math.floor(tonumber(line:match("([%d]+)")) / 1024) + elseif line:match("^Buffers.*") then + buffers = math.floor(tonumber(line:match("([%d]+)")) / 1024) + elseif line:match("^Cached.*") then + cached = math.floor(tonumber(line:match("([%d]+)")) / 1024) + -- Get swap stats while we're at it + elseif line:match("^SwapTotal.*") then + swap_total = math.floor(tonumber(line:match("([%d]+)")) / 1024) + elseif line:match("^SwapFree.*") then + swap_free = math.floor(tonumber(line:match("([%d]+)")) / 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) + -- Calculate swap percentage + swap_inuse = swap_total - swap_free + swap_usepercent = math.floor(swap_inuse/swap_total*100) + + if padding then + if type(padding) == "table" then + mem_usepercent = helpers.padd(mem_usepercent, padding[1]) + mem_inuse = helpers.padd(mem_inuse, padding[2]) + mem_total = helpers.padd(mem_total, padding[3]) + mem_free = helpers.padd(mem_free, padding[4]) + swap_usepercent = helpers.padd(swap_usepercent, padding[1]) + swap_inuse = helpers.padd(swap_inuse, padding[2]) + swap_total = helpers.padd(swap_total, padding[3]) + swap_free = helpers.padd(swap_free, padding[4]) + else + mem_usepercent = helpers.padd(mem_usepercent, padding) + mem_inuse = helpers.padd(mem_inuse, padding) + mem_total = helpers.padd(mem_total, padding) + mem_free = helpers.padd(mem_free, padding) + swap_usepercent = helpers.padd(swap_usepercent, padding) + swap_inuse = helpers.padd(swap_inuse, padding) + swap_total = helpers.padd(swap_total, padding) + swap_free = helpers.padd(swap_free, padding) + end + end + + return {mem_usepercent, mem_inuse, mem_total, mem_free, + swap_usepercent, swap_inuse, swap_total, swap_free} +end +-- }}} diff --git a/mpd.lua b/mpd.lua new file mode 100644 index 0000000..2dc95f8 --- /dev/null +++ b/mpd.lua @@ -0,0 +1,42 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { popen = io.popen } +local helpers = require("vicious.helpers") +-- }}} + + +-- Mpd: provides the currently playing song in MPD +module("vicious.mpd") + + +-- {{{ MPD widget type +function worker() + -- This one is as simple as they come. Using sockets or expanding + -- it is a lost cause since there are already a few MPD Lua libs + -- written for awesome. Use them. + -- + -- Get data from mpc + local f = io.popen("mpc") + local np = f:read("*line") + f:close() + + -- Check if it's stopped, off or not installed + if np == nil or (np:find("MPD_HOST") or np:find("volume:")) then + return {"Stopped"} + end + + -- Sanitize the song name + nowplaying = helpers.escape(np) + + -- Don't abuse the wibox, truncate + if nowplaying:len() > 30 then + nowplaying = nowplaying:sub(1, 27) .. "..." + end + + return {nowplaying} +end +-- }}} diff --git a/net.lua b/net.lua new file mode 100644 index 0000000..9428c5d --- /dev/null +++ b/net.lua @@ -0,0 +1,115 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local tonumber = tonumber +local os = { time = os.time } +local io = { open = io.open } +local math = { floor = math.floor } +local helpers = require("vicious.helpers") +-- }}} + + +-- Net: provides usage statistics for all network interfaces +module("vicious.net") + + +-- Initialise function tables +local nets = {} + +-- {{{ Net widget type +function worker(format, padding) + -- Get /proc/net/dev + local f = io.open("/proc/net/dev") + local args = {} + + -- Format data + for line in f:lines() do + -- Match wmaster0 as well as rt0 (multiple leading spaces) + if line:match("^[%s]?[%s]?[%s]?[%s]?[%w]+:") then + name = line:match("^[%s]?[%s]?[%s]?[%s]?([%w]+):") + -- Received bytes, first value after the name + recv = tonumber(line:match(":[%s]*([%d]+)")) + -- Transmited bytes, 7 fields from end of the line + send = tonumber(line:match("([%d]+)%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d$")) + + if padding then + args["{"..name.." rx}"] = helpers.bytes_to_string(recv, nil, padding) + args["{"..name.." tx}"] = helpers.bytes_to_string(send, nil, padding) + else + args["{"..name.." rx}"] = helpers.bytes_to_string(recv) + args["{"..name.." tx}"] = helpers.bytes_to_string(send) + end + + args["{"..name.." rx_b}"] = math.floor(recv*10)/10 + args["{"..name.." tx_b}"] = math.floor(send*10)/10 + + args["{"..name.." rx_kb}"] = math.floor(recv/1024*10)/10 + args["{"..name.." tx_kb}"] = math.floor(send/1024*10)/10 + + args["{"..name.." rx_mb}"] = math.floor(recv/1024/1024*10)/10 + args["{"..name.." tx_mb}"] = math.floor(send/1024/1024*10)/10 + + args["{"..name.." rx_gb}"] = math.floor(recv/1024/1024/1024*10)/10 + args["{"..name.." tx_gb}"] = math.floor(send/1024/1024/1024*10)/10 + + if nets[name] == nil then + -- Default values on our first run + 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 + -- Net stats are absolute, substract our last reading + interval = os.time() - nets[name].time + nets[name].time = os.time() + + down = (recv - nets[name][1])/interval + up = (send - nets[name][2])/interval + + if padding then + args["{"..name.." down}"] = helpers.bytes_to_string(down, true, padding) + args["{"..name.." up}"] = helpers.bytes_to_string(up, true, padding) + else + args["{"..name.." down}"] = helpers.bytes_to_string(down, true) + args["{"..name.." up}"] = helpers.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 + + -- Store totals + nets[name][1] = recv + nets[name][2] = send + end + end + f:close() + + return args +end +-- }}} diff --git a/org.lua b/org.lua new file mode 100644 index 0000000..5632179 --- /dev/null +++ b/org.lua @@ -0,0 +1,70 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +-- * Derived from org-awesome, copyright of Damien Leone +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { open = io.open } +local string = { find = string.find } +local os = { + time = os.time, + date = os.date +} +-- }}} + + +-- Org: provides agenda statistics for Emacs org-mode +module("vicious.org") + + +-- {{{ OrgMode widget type +function worker(format, files) + -- 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 + + -- Initialise count table + local count = { + past = 0, + today = 0, + soon = 0, + future = 0 + } + + -- Get data from agenda files + for i=1, #files do + local f = io.open(files[i]) + + -- Parse the agenda + for line in f:lines() 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)") + + -- Enumerate agenda items + 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 + f:close() + end + + return {count.past, count.today, count.soon, count.future} +end +-- }}} diff --git a/pacman.lua b/pacman.lua new file mode 100644 index 0000000..0d8f80a --- /dev/null +++ b/pacman.lua @@ -0,0 +1,38 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local tonumber = tonumber +local io = { popen = io.popen } +-- }}} + + +-- Pacman: provides number of pending updates on Arch Linux +module("vicious.pacman") + + +-- {{{ Pacman widget type +function worker(format) + -- Check if updates are available + local f = io.popen("pacman -Qu") + + -- Initialise updates + local updates = nil + + -- Get data + for line in f:lines() do + -- If there are 'Targets:' then updates are available, + -- number is provided, we don't have to count packages + updates = line:match("^Targets[%s]%(([%d]+)%)") or 0 + -- If the count changed then break out of the loop + if tonumber(updates) > 0 then + break + end + end + f:close() + + return {updates} +end +-- }}} diff --git a/thermal.lua b/thermal.lua new file mode 100644 index 0000000..02b1f54 --- /dev/null +++ b/thermal.lua @@ -0,0 +1,27 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { open = io.open } +-- }}} + + +-- Thermal: provides temperature levels of ACPI thermal zones +module("vicious.thermal") + + +-- {{{ Thermal widget type +function worker(format, thermal_zone) + -- Get thermal zone + local f = io.open("/proc/acpi/thermal_zone/" .. thermal_zone .. "/temperature") + local line = f:read() + f:close() + + -- Get temperature data + local temperature = line:match("[%d]?[%d]?[%d]") + + return {temperature} +end +-- }}} diff --git a/uptime.lua b/uptime.lua new file mode 100644 index 0000000..eae1d35 --- /dev/null +++ b/uptime.lua @@ -0,0 +1,51 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local tonumber = tonumber +local io = { open = io.open } +local math = { floor = math.floor } +local helpers = require("vicious.helpers") +-- }}} + + +-- Uptime: provides system uptime information +module("vicious.uptime") + + +-- {{{ Uptime widget type +function worker(format, padding) + -- Get /proc/uptime + local f = io.open("/proc/uptime") + local line = f:read() + f:close() + + -- Format data + local total_uptime = math.floor(tonumber(line:match("[%d%.]+"))) + + local uptime_days = math.floor(total_uptime / (3600 * 24)) + local uptime_hours = math.floor((total_uptime % (3600 * 24)) / 3600) + local uptime_minutes = math.floor(((total_uptime % (3600 * 24)) % 3600) / 60) + local uptime_seconds = math.floor(((total_uptime % (3600 * 24)) % 3600) % 60) + + if padding then + if type(padding) == "table" then + total_uptime = helpers.padd(total_uptime, padding[1]) + uptime_days = helpers.padd(uptime_days, padding[2]) + uptime_hours = helpers.padd(uptime_hours, padding[3]) + uptime_minutes = helpers.padd(uptime_minutes, padding[4]) + uptime_seconds = helpers.padd(uptime_seconds, padding[5]) + else + total_uptime = helpers.padd(total_uptime, padding) + uptime_days = helpers.padd(uptime_days, padding) + uptime_hours = helpers.padd(uptime_hours, padding) + uptime_minutes = helpers.padd(uptime_minutes, padding) + uptime_seconds = helpers.padd(uptime_seconds, padding) + end + end + + return {total_uptime, uptime_days, uptime_hours, uptime_minutes, uptime_seconds} +end +-- }}} diff --git a/volume.lua b/volume.lua new file mode 100644 index 0000000..fd02b76 --- /dev/null +++ b/volume.lua @@ -0,0 +1,33 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { popen = io.popen } +local string = { match = string.match } +-- }}} + + +-- Volume: provides volume levels of requested ALSA mixers +module("vicious.volume") + + +-- {{{ Volume widget type +function worker(format, channel) + -- Get mixer data + local f = io.popen("amixer get " .. channel) + local mixer = f:read("*all") + f:close() + + -- Get volume level + local volume_level = string.match(mixer, "([%d]?[%d]?[%d])%%") + + -- Don't break progressbars + if volume_level == nil then + return {0} + end + + return {volume_level} +end +-- }}} diff --git a/wifi.lua b/wifi.lua new file mode 100644 index 0000000..35289dd --- /dev/null +++ b/wifi.lua @@ -0,0 +1,62 @@ +---------------------------------------------------------- +-- Licensed under the GNU General Public License version 2 +-- * Copyright (C) 2009 Adrian C. +---------------------------------------------------------- + +-- {{{ Grab environment +local io = { popen = io.popen } +local string = { + find = string.find, + match = string.match +} +-- }}} + + +-- Wifi: provides wireless information for a requested interface +module("vicious.wifi") + + +-- {{{ Wireless widget type +function worker(format, iface) + -- Get data from iwconfig, on distributions where it is executable + -- by users, and /sbin or /usr/sbin is in their path + local f = io.popen("iwconfig " .. iface) + local iw = f:read("*all") + f:close() + + -- Setup tables + local winfo = { + ["{ssid}"] = "N/A", + ["{mode}"] = "N/A", + ["{chan}"] = "N/A", + ["{rate}"] = "N/A", + ["{link}"] = "N/A", + ["{sign}"] = "N/A" + } + + -- Check if iwconfig wasn't found, can't be executed or the + -- interface is not a wireless one + if iw == nil or string.find(iw, "No such device") then + return winfo + else + -- The 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 + string.match(iw, 'ESSID[=:]"([%w]+[%s]*[%w]*]*)"') 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 + string.match(iw, "Channel[=:]([%d]+)") or winfo["{chan}"] + winfo["{rate}"] = -- Bitrate can start with a space and we want to display Mb/s + string.match(iw, "Bit Rate[=:]([%s]?[%d%.]*[%s][%/%a]+)") or winfo["{rate}"] +-- winfo["{link}"] = -- Link quality can contain a slash: 32/100 +-- string.match(iw, "Link Quality[=:]([%d]+[%/%d]*)") or winfo["{link}"] + winfo["{link}"] = -- * match only the first number, great data for a progressbar + string.match(iw, "Link Quality[=:]([%d]+)") or winfo["{link}"] + winfo["{sign}"] = -- Signal level can be a negative value, also display decibel notation + string.match(iw, "Signal level[=:]([%-%d]+[%s][%a]*)") or winfo["{sign}"] + end + + return winfo +end +-- }}}