--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
+ 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.
+
+ {description}
+ Copyright (C) {year} {fullname}
+
+ 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.
+
+ {signature of Ty Coon}, 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.
.. _GNU-GPL2: http://www.gnu.org/licenses/gpl-2.0.html
.. _awesome-vain: https://github.com/vain/awesome-vain
-.. _Awesome: http://awesome.naquadah.org/
+.. _Awesome: https://github.com/awesomeWM/awesome
.. _wiki: https://github.com/copycat-killer/lain/wiki
id, formatted_command
)
- if type(awful.spawn) == 'table' then
+ if type(awful.spawn) == 'table' and awful.spawn.with_shell then
awful.spawn.with_shell(req)
else
awful.util.spawn_with_shell(req)
local debug = require("debug")
+local assert = assert
local capi = { timer = (type(timer) == 'table' and timer or require ("gears.timer")) }
local io = { open = io.open,
lines = io.lines,
function helpers.lines_match(regexp, file)
local lines = {}
for index,line in pairs(helpers.lines_from(file)) do
- if string.match(line, regexp) then
+ if string.match(line, regexp) then
lines[index] = line
- end
+ end
end
return lines
end
local name = timeout
if not helpers.timer_table[name] then
helpers.timer_table[name] = capi.timer({ timeout = timeout })
+ helpers.timer_table[name]:start()
end
helpers.timer_table[name]:connect_signal("timeout", fun)
- helpers.timer_table[name]:start()
if not nostart then
helpers.timer_table[name]:emit_signal("timeout")
end
-- {{{ Pipe operations
--- read the full output of a pipe (command)
+-- read the full output of a command output
function helpers.read_pipe(cmd)
local f = assert(io.popen(cmd))
local output = f:read("*all")
return output
end
+-- return line iterator of a command output
+function helpers.pipelines(...)
+ local f = assert(io.popen(...))
+ return function () -- iterator
+ local data = f:read()
+ if data == nil then f:close() end
+ return data
+ end
+end
+
-- }}}
-- {{{ A map utility
end
--}}}
+
return helpers
--- /dev/null
+package = "lain"
+version = "git"
+source = {
+ url = "https://github.com/copycat-killer/lain",
+ tag = "git"
+}
+description = {
+ summary = "Layout, widgets and utilities for Awesome WM",
+ detailed = [[
+ Successor of awesome-vain, this module provides new layouts, a set of widgets and utility functions, in order to improve Awesome usability and configurability.
+
+ Optional dependencies: alsa-utils (for alsamixer); curl; imagemagick.
+ ]],
+ homepage = "https://github.com/copycat-killer/lain",
+ license = "GPL v2"
+}
+dependencies = {
+ "lua >= 5.1",
+ "awesome >= 3.5",
+ "alsa-utils",
+ "curl",
+ "imagemagick"
+}
+supported_platforms = { "linux" }
+build = {
+ type = "builtin",
+ modules = { lain = "init.lua" }
+}
# -------------------------------------------------------------------------
# Decoding options
# -------------------------------------------------------------------------
-USAGE="Usage: $0 [-h(elp)] | [-n(arrow mode)] | [-w(eb output)]"
+USAGE="Usage: $0 [-h(elp)] | [-n(arrow mode)] | [-w(eb output) | --type=<fstype> | --exclude-type=<fstype>]"
NARROW_MODE=0
WEB_OUTPUT=0
+DF_OPTIONS=""
while [ $# -gt 0 ]; do
case "$1" in
"-w" )
WEB_OUTPUT=1
;;
+--type=*)
+DF_OPTIONS+=" $1"
+;;
+--exclude-type=*)
+DF_OPTIONS+=" $1"
+;;
* )
echo $USAGE
exit
;;
esac
+# Add additional df options
+DF_COMMAND+=$DF_OPTIONS
+
# -------------------------------------------------------------------------
# Grabbing "df" result
# -------------------------------------------------------------------------
g.height = math.sqrt(mwfact) * mg.height
g.x = mg.x + (mg.width - g.width) / 2
g.y = mg.y + (mg.height - g.height) / 2
- c:geometry(g)
+ if c then c:geometry(g) end -- if c is still a valid object
end
-- Read the nice value of pid from /proc.
--- /dev/null
+
+--[[
+
+ Licensed under GNU General Public License v2
+ * (c) 2016, Luke Bonham
+
+--]]
+
+local awful = require("awful")
+local capi = { client = client,
+ mouse = mouse,
+ screen = screen,
+ timer = timer }
+local string = string
+
+local pairs = pairs
+local setmetatable = setmetatable
+local tostring = tostring
+
+-- Quake-like Dropdown application spawn
+-- Original version: https://awesomewm.org/wiki/Drop-down_terminal#Another_solution
+local quake = {}
+
+-- If you have a rule like "awful.client.setslave" for your terminals,
+-- ensure you use an exception for QuakeDD. Otherwise, you may
+-- run into problems with focus.
+
+function quake:display()
+ -- First, we locate the client
+ local client = nil
+ local i = 0
+ for c in awful.client.iterate(function (c)
+ -- c.name may be changed!
+ return c.instance == self.name
+ end, nil, self.screen)
+ do
+ i = i + 1
+ if i == 1 then
+ client = c
+ else
+ -- Additional matching clients, let's remove the sticky bit
+ -- which may persist between awesome restarts. We don't close
+ -- them as they may be valuable. They will just turn into
+ -- normal clients.
+ c.sticky = false
+ c.ontop = false
+ c.above = false
+ end
+ end
+
+ if not client and not self.visible then return end
+
+ if not client then
+ -- The client does not exist, we spawn it
+ awful.util.spawn(string.format("%s %s %s", self.app,
+ string.format(self.argname, self.name), self.extra),
+ false, self.screen)
+ self.notexist = true
+ return
+ end
+
+ -- Resize
+ awful.client.floating.set(client, true)
+ client.border_width = self.border
+ client.size_hints_honor = false
+ if self.notexist then
+ client:geometry(self.geometry)
+ self.notexist = false
+ end
+
+ -- Not sticky and on top
+ client.ontop = true
+ client.above = true
+ client.skip_taskbar = true
+ client.sticky = false
+
+ -- Toggle display
+ if self.visible then
+ client.hidden = false
+ client:raise()
+ self.last_tag = tostring(awful.tag.selected(self.screen))
+ client:tags({awful.tag.selected(self.screen)})
+ capi.client.focus = client
+ else
+ client.hidden = true
+ local ctags = client:tags()
+ for i, t in pairs(ctags) do
+ ctags[i] = nil
+ end
+ client:tags(ctags)
+ end
+
+ return client
+end
+
+function quake:new(config)
+ local conf = config or {}
+
+ conf.app = conf.app or "xterm" -- application to spawn
+ conf.name = conf.name or "QuakeDD" -- window name
+ conf.argname = conf.argname or "-name %s" -- how to specify window name
+ conf.extra = conf.extra or "" -- extra arguments
+ conf.visible = conf.visible or false -- initially not visible
+ conf.screen = conf.screen or capi.mouse.screen
+ conf.border = conf.border or 1
+
+ -- If width or height <= 1 this is a proportion of the workspace
+ wibox_height = conf.wibox_height or 18 -- statusbar weight
+ height = conf.height or 0.25 -- height
+ width = conf.width or 1 -- width
+ vert = conf.vert or "top" -- top, bottom or center
+ horiz = conf.horiz or "center" -- left, right or center
+
+ -- Compute size
+ local geom = capi.screen[conf.screen].workarea
+ if width <= 1 then width = geom.width * width end
+ if height <= 1 then height = geom.height * height end
+ local x, y
+ if horiz == "left" then x = geom.x
+ elseif horiz == "right" then x = geom.width + geom.x - width
+ else x = geom.x + (geom.width - width)/2 end
+ if vert == "top" then y = geom.y
+ elseif vert == "bottom" then y = geom.height + geom.y - height
+ else y = geom.y + (geom.height - height)/2 end
+ conf.geometry = { x = x, y = y + wibox_height, width = width, height = height }
+
+ local console = setmetatable(conf, { __index = quake })
+ capi.client.connect_signal("manage", function(c)
+ if c.instance == console.name and c.screen == console.screen then
+ console:display()
+ end
+ end)
+ capi.client.connect_signal("unmanage", function(c)
+ if c.instance == console.name and c.screen == console.screen then
+ console.visible = false
+ end
+ end)
+
+ -- "Reattach" currently running quake application. This is in case awesome is restarted.
+ local reattach = capi.timer { timeout = 0 }
+ reattach:connect_signal("timeout", function()
+ reattach:stop()
+ console:display()
+ end)
+ reattach:start()
+
+ return console
+end
+
+function quake:toggle()
+ current_tag = awful.tag.selected(self.screen)
+ if self.last_tag ~= tostring(current_tag) and self.visible then
+ awful.client.movetotag(current_tag, self:display())
+ else
+ self.visible = not self.visible
+ self:display()
+ end
+end
+
+setmetatable(quake, { __call = function(_, ...) return quake:new(...) end })
+
+return quake
local timeout = args.timeout or 5
local settings = args.settings or function() end
- alsa.cmd = args.cmd or "amixer"
- alsa.channel = args.channel or "Master"
- alsa.widget = wibox.widget.textbox('')
+ alsa.cmd = args.cmd or "amixer"
+ alsa.channel = args.channel or "Master"
+ alsa.togglechannel = args.togglechannel
+ alsa.widget = wibox.widget.textbox('')
function alsa.update()
mixer = read_pipe(string.format("%s get %s", alsa.cmd, alsa.channel))
l,s = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
+ -- HDMIs can have a channel different from Master for toggling mute
+ if alsa.togglechannel then
+ s = string.match(read_pipe(string.format("%s get %s", alsa.cmd, alsa.togglechannel)), "%[(%a+)%]")
+ end
+
if alsa.last_level ~= l or alsa.last_status ~= s then
volume_now = { level = l, status = s }
alsa.last_level = l
-- lain.widgets.alsabar
local alsabar = {
channel = "Master",
- step = "2%",
+ step = "1%",
colors = {
background = beautiful.bg_normal,
alsabar.cmd = args.cmd or "amixer"
alsabar.channel = args.channel or alsabar.channel
+ alsabar.togglechannel = args.togglechannel
alsabar.step = args.step or alsabar.step
alsabar.colors = args.colors or alsabar.colors
alsabar.notifications = args.notifications or alsabar.notifications
-- Capture mixer control state: [5%] ... ... [on]
local volu, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
+ -- HDMIs can have a channel different from Master for toggling mute
+ if alsabar.togglechannel then
+ mute = string.match(read_pipe(string.format("%s get %s", alsabar.cmd, alsabar.togglechannel)), "%[(%a+)%]")
+ end
+
if (volu and tonumber(volu) ~= alsabar._current_level) or (mute and string.match(mute, "on") ~= alsabar._muted)
then
- alsabar._current_level = tonumber(volu)
+ alsabar._current_level = tonumber(volu) or alsabar._current_level
alsabar.bar:set_value(alsabar._current_level / 100)
if not mute and tonumber(volu) == 0 or mute == "off"
then
end
end
- alsabar.bar:buttons (awful.util.table.join (
- awful.button ({}, 1, function()
+ alsabar.bar:buttons(awful.util.table.join (
+ awful.button({}, 1, function()
awful.util.spawn(alsabar.mixer)
end),
- awful.button ({}, 3, function()
+ awful.button({}, 2, function()
+ awful.util.spawn(string.format("%s set %s 100%%", alsabar.cmd, alsabar.channel))
+ pulsebar.update()
+ end),
+ awful.button({}, 3, function()
awful.util.spawn(string.format("%s set %s toggle", alsabar.cmd, alsabar.channel))
alsabar.update()
end),
- awful.button ({}, 4, function()
+ awful.button({}, 4, function()
awful.util.spawn(string.format("%s set %s %s+", alsabar.cmd, alsabar.channel, alsabar.step))
alsabar.update()
end),
- awful.button ({}, 5, function()
+ awful.button({}, 5, function()
awful.util.spawn(string.format("%s set %s %s-", alsabar.cmd, alsabar.channel, alsabar.step))
alsabar.update()
end)
base.widget = wibox.widget.textbox('')
function base.update()
+ output = read_pipe(cmd)
if output ~= base.prev then
- output = read_pipe(cmd)
widget = base.widget
settings()
base.prev = output
local naughty = require("naughty")
local wibox = require("wibox")
-local math = { floor = math.floor, min = math.min }
+local math = { abs = math.abs,
+ floor = math.floor,
+ log10 = math.log10,
+ min = math.min }
local string = { format = string.format }
-local tonumber = tonumber
+local type = type
+local tonumber = tonumber
local setmetatable = setmetatable
-- Battery infos
}
bat_now = {
- status = "Not present",
+ status = "N/A",
ac_status = "N/A",
perc = "N/A",
time = "N/A",
}
bat_now.n_status = {}
+ bat_now.n_perc = {}
for i = 1, #batteries do
- bat_now.n_status[i] = "Not present"
+ bat_now.n_status[i] = "N/A"
+ bat_now.n_perc[i] = 0
end
- function update()
+ function bat.update()
local sum_rate_current = 0
local sum_rate_voltage = 0
- local sum_rate_power = 0
- local sum_energy_now = 0
- local sum_energy_full = 0
- local sum_energy_percentage = 0
+ local sum_rate_power = 0
+ local sum_rate_energy = 0
+ local sum_energy_now = 0
+ local sum_energy_full = 0
+ local pspath = "/sys/class/power_supply/"
for i, battery in ipairs(batteries) do
- local bstr = "/sys/class/power_supply/" .. battery
+ local bstr = pspath .. battery
local present = first_line(bstr .. "/present")
- if present == "1"
- then
+ if tonumber(present) == 1 then
-- current_now(I)[uA], voltage_now(U)[uV], power_now(P)[uW]
- local rate_current = tonumber(first_line(bstr .. "/current_now"))
- local rate_voltage = tonumber(first_line(bstr .. "/voltage_now"))
- local rate_power = tonumber(first_line(bstr .. "/power_now"))
+ local rate_current = tonumber(first_line(bstr .. "/current_now"))
+ local rate_voltage = tonumber(first_line(bstr .. "/voltage_now"))
+ local rate_power = tonumber(first_line(bstr .. "/power_now"))
-- energy_now(P)[uWh], charge_now(I)[uAh]
local energy_now = tonumber(first_line(bstr .. "/energy_now") or
local energy_percentage = tonumber(first_line(bstr .. "/capacity")) or
math.floor((energy_now / energy_full) * 100)
- if bat_now.n_status[i] ~= "Charging" and bat_now.n_status[i] ~= "Discharging"
- then
- bat_now.n_status[i] = first_line(bstr .. "/status") or "N/A"
- end
+ bat_now.n_status[i] = first_line(bstr .. "/status") or "N/A"
+ bat_now.n_perc[i] = energy_percentage or bat_now.n_perc[i]
- sum_rate_current = sum_rate_current + (rate_current or 0)
- sum_rate_voltage = sum_rate_voltage + rate_voltage
- sum_rate_power = sum_rate_power + (rate_power or ((rate_voltage * rate_current) / 1e6))
- sum_energy_now = sum_energy_now + energy_now
- sum_energy_full = sum_energy_full + energy_full
- sum_energy_percentage = sum_energy_percentage + energy_percentage
+ sum_rate_current = sum_rate_current + (rate_current or 0)
+ sum_rate_voltage = sum_rate_voltage + (rate_voltage or 0)
+ sum_rate_power = sum_rate_power + (rate_power or 0)
+ sum_rate_energy = sum_rate_energy + (rate_power or (((rate_voltage or 0) * (rate_current or 0)) / 1e6))
+ sum_energy_now = sum_energy_now + (energy_now or 0)
+ sum_energy_full = sum_energy_full + (energy_full or 0)
end
end
bat_now.status = bat_now.n_status[1]
- bat_now.ac_status = first_line(string.format("/sys/class/power_supply/%s/online", ac)) or "N/A"
+ bat_now.ac_status = tonumber(first_line(string.format("%s%s/online", pspath, ac))) or "N/A"
+
+ if bat_now.status ~= "N/A" then
+ -- update {perc,time,watt} iff battery not full and rate > 0
+ if bat_now.status ~= "Full" and (sum_rate_power > 0 or sum_rate_current > 0) then
+ local rate_time = 0
+ local div = (sum_rate_power > 0 and sum_rate_power) or sum_rate_current
+
+ if bat_now.status == "Charging" then
+ rate_time = (sum_energy_full - sum_energy_now) / div
+ else -- Discharging
+ rate_time = sum_energy_now / div
+ end
- -- update {perc,time,watt} iff rate > 0 and battery not full
- if (sum_rate_current > 0 or sum_rate_power > 0) and not (bat_now.status == "Full")
- then
- local rate_time = 0
+ if 0 < rate_time and rate_time < 0.01 then -- check for magnitude discrepancies (#199)
+ rate_time_magnitude = math.abs(math.floor(math.log10(rate_time)))
+ rate_time = rate_time * 10^(rate_time_magnitude - 2)
+ end
- if bat_now.status == "Charging" then
- rate_time = (sum_energy_full - sum_energy_now) / (sum_rate_power or sum_rate_current)
- elseif bat_now.status == "Discharging" then
- rate_time = sum_energy_now / (sum_rate_power or sum_rate_current)
+ local hours = math.floor(rate_time)
+ local minutes = math.floor((rate_time - hours) * 60)
+ bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
+ bat_now.time = string.format("%02d:%02d", hours, minutes)
+ bat_now.watt = tonumber(string.format("%.2f", sum_rate_energy / 1e6))
+ elseif bat_now.status ~= "Full" and sum_rate_power == 0 and bat_now.ac_status == 1 then
+ bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
+ bat_now.time = "00:00"
+ bat_now.watt = 0
+ elseif bat_now.status == "Full" then
+ bat_now.perc = 100
+ bat_now.time = "00:00"
+ bat_now.watt = 0
end
-
- local hours = math.floor(rate_time)
- local minutes = math.floor((rate_time - hours) * 60)
- local watt = sum_rate_power / 1e6
-
- bat_now.perc = string.format("%d", math.min(100, sum_energy_percentage / #batteries))
- bat_now.time = string.format("%02d:%02d", hours, minutes)
- bat_now.watt = string.format("%.2fW", watt)
end
widget = bat.widget
settings()
-- notifications for low and critical states
- if bat_now.status == "Discharging" and notify == "on" and bat_now.perc then
- local nperc = tonumber(bat_now.perc) or 100
- if nperc <= 5 then
+ if notify == "on" and type(bat_now.perc) == "number" and bat_now.status == "Discharging" then
+ if bat_now.perc <= 5 then
bat.id = naughty.notify({
preset = bat_notification_critical_preset,
- replaces_id = bat.id,
+ replaces_id = bat.id
}).id
- elseif nperc <= 15 then
+ elseif bat_now.perc <= 15 then
bat.id = naughty.notify({
preset = bat_notification_low_preset,
- replaces_id = bat.id,
+ replaces_id = bat.id
}).id
end
end
end
- newtimer(battery, timeout, update)
+ newtimer(battery, timeout, bat.update)
return setmetatable(bat, { __index = bat.widget })
end
local calendar = {}
local cal_notification = nil
-function calendar:hide()
+function calendar.hide()
if cal_notification ~= nil then
naughty.destroy(cal_notification)
cal_notification = nil
end
end
-function calendar:show(t_out, inc_offset, scr)
- calendar:hide()
+function calendar.show(t_out, inc_offset, scr)
+ calendar.hide()
local f, c_text
local offs = inc_offset or 0
})
end
-function calendar:attach(widget, args)
+function calendar.attach(widget, args)
local args = args or {}
calendar.cal = args.cal or "/usr/bin/cal"
calendar.offset = 0
calendar.notify_icon = nil
- widget:connect_signal("mouse::enter", function () calendar:show(0, 0, calendar.scr_pos) end)
- widget:connect_signal("mouse::leave", function () calendar:hide() end)
+ widget:connect_signal("mouse::enter", function () calendar.show(0, 0, calendar.scr_pos) end)
+ widget:connect_signal("mouse::leave", function () calendar.hide() end)
widget:buttons(awful.util.table.join(awful.button({ }, 1, function ()
- calendar:show(0, -1, calendar.scr_pos) end),
+ calendar.show(0, -1, calendar.scr_pos) end),
awful.button({ }, 3, function ()
- calendar:show(0, 1, calendar.scr_pos) end),
+ calendar.show(0, 1, calendar.scr_pos) end),
awful.button({ }, 4, function ()
- calendar:show(0, -1, calendar.scr_pos) end),
+ calendar.show(0, -1, calendar.scr_pos) end),
awful.button({ }, 5, function ()
- calendar:show(0, 1, calendar.scr_pos) end)))
+ calendar.show(0, 1, calendar.scr_pos) end)))
end
return setmetatable(calendar, { __call = function(_, ...) return create(...) end })
+++ /dev/null
-
---[[
-
- Licensed under GNU General Public License v2
- * (c) 2014, Aaron Lebo
-
---]]
-
-local newtimer = require("lain.helpers").newtimer
-local json = require("lain.util").dkjson
-
-local wibox = require("wibox")
-
-local string = { format = string.format }
-local tonumber = tonumber
-
--- Crypto currencies widget
--- lain.widgets.contrib.ccurr
-local ccurr = {}
-
--- Currently gets
--- * BTC/USD
--- * DOGE/USD
--- using Coinbase and Cryptsy APIs.
-
--- requires http://dkolf.de/src/dkjson-lua.fsl/home
--- based upon http://awesome.naquadah.org/wiki/Bitcoin_Price_Widget
-
-local function get(url)
- local f = io.popen('curl -m 5 -s "' .. url .. '"')
- if not f then
- return 0
- else
- local s = f:read("*all")
- f:close()
- return s
- end
-end
-
-local function parse(j)
- local obj, pos, err = json.decode(j, 1, nil)
- if err then
- return nil
- else
- return obj
- end
-end
-
-local function worker(args)
- local args = args or {}
- local timeout = args.timeout or 600
- local btc_url = args.btc_url or "https://coinbase.com/api/v1/prices/buy"
- local doge_url = args.doge_url or "http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=132"
- local settings = args.settings or function() end
-
- ccurr.widget = wibox.widget.textbox('')
-
- local function update()
- price_now = {
- btc = "N/A",
- doge = "N/A"
- }
-
- btc = parse(get(btc_url))
- doge = parse(get(doge_url))
-
- if btc and doge then
- price_now.btc = tonumber(btc["subtotal"]["amount"])
- price_now.doge = tonumber(doge["return"]["markets"]["DOGE"]["lasttradeprice"])
- price_now.doge = string.format("%.4f", price_now.btc * price_now.doge)
- end
-
- widget = ccurr.widget
- settings()
- end
-
- newtimer("ccurr", timeout, update)
-
- return ccurr.widget
-end
-
-return setmetatable(ccurr, { __call = function(_, ...) return worker(...) end })
--- /dev/null
+
+--[[
+
+ Licensed under GNU General Public License v2
+ * (c) 2016, Alexandre Terrien
+
+--]]
+
+local helpers = require("lain.helpers")
+local json = require("lain.util.dkjson")
+local pread = require("awful.util").pread
+local naughty = require("naughty")
+local wibox = require("wibox")
+local mouse = mouse
+local os = { getenv = os.getenv }
+
+local setmetatable = setmetatable
+
+-- Google Play Music Desktop infos
+-- lain.widget.contrib.gpmdp
+local gpmdp = {}
+
+local function worker(args)
+ local args = args or {}
+ local timeout = args.timeout or 2
+ local notify = args.notify or "off"
+ local followmouse = args.followmouse or false
+ local file_location = args.file_location or
+ os.getenv("HOME") .. "/.config/Google Play Music Desktop Player/json_store/playback.json"
+ local settings = args.settings or function() end
+
+ gpmdp.widget = wibox.widget.textbox('')
+
+ gpmdp_notification_preset = {
+ title = "Now playing",
+ timeout = 6
+ }
+
+ helpers.set_map("gpmdp_current", nil)
+
+ function gpmdp.update()
+ file, err = io.open(file_location, "r")
+ if not file
+ then
+ gpm_now = { running = false, playing = false }
+ else
+ dict, pos, err = json.decode(file:read "*a", 1, nil)
+ file:close()
+ gpm_now = {}
+ gpm_now.artist = dict.song.artist
+ gpm_now.album = dict.song.album
+ gpm_now.title = dict.song.title
+ gpm_now.cover_url = dict.song.albumArt
+ gpm_now.playing = dict.playing
+ end
+
+ if (pread("pidof 'Google Play Music Desktop Player'") ~= '') then
+ gpm_now.running = true
+ else
+ gpm_now.running = false
+ end
+
+ gpmdp_notification_preset.text = string.format("%s (%s) - %s", gpm_now.artist, gpm_now.album, gpm_now.title)
+ widget = gpmdp.widget
+ settings()
+
+ if gpm_now.playing
+ then
+ if notify == "on" and gpm_now.title ~= helpers.get_map("gpmdp_current")
+ then
+ helpers.set_map("gpmdp_current", gpm_now.title)
+ os.execute("curl " .. gpm_now.cover_url .. " -o /tmp/gpmcover.png")
+
+ if followmouse then
+ gpmdp_notification_preset.screen = mouse.screen
+ end
+
+ gpmdp.id = naughty.notify({
+ preset = gpmdp_notification_preset,
+ icon = "/tmp/gpmcover.png",
+ replaces_id = gpmdp.id,
+ }).id
+ end
+ elseif not gpm_now.running
+ then
+ helpers.set_map("gpmdp_current", nil)
+ end
+ end
+
+ helpers.newtimer("gpmdp", timeout, gpmdp.update)
+
+ return setmetatable(gpmdp, { __index = gpmdp.widget })
+end
+
+return setmetatable(gpmdp, { __call = function(_, ...) return worker(...) end })
-- Keyboard layout switcher
-- lain.widgets.contrib.kblayout
-local function worker (args)
+local function worker(args)
local kbdlayout = {}
kbdlayout.widget = wibox.widget.textbox('')
awful.button({ }, 1, function () kbdlayout.next() end),
awful.button({ }, 3, function () kbdlayout.prev() end)))
- local function run_settings (layout, variant)
+ local function run_settings(layout, variant)
widget = kbdlayout.widget
kbdlayout_now = { layout=string.match(layout, "[^,]+"), -- Make sure to match the primary layout only.
variant=variant }
settings()
end
- function kbdlayout.update ()
+ function kbdlayout.update()
local status = read_pipe('setxkbmap -query')
run_settings(string.match(status, "layout:%s*([^\n]*)"),
string.match(status, "variant:%s*([^\n]*)"))
end
- function kbdlayout.set (i)
+ function kbdlayout.set(i)
idx = ((i - 1) % #layouts) + 1 -- Make sure to wrap around as needed.
local to_execute = 'setxkbmap ' .. layouts[idx].layout
end
end
- function kbdlayout.next ()
+ function kbdlayout.next()
kbdlayout.set(idx + 1)
end
- function kbdlayout.prev ()
+ function kbdlayout.prev()
kbdlayout.set(idx - 1)
end
-- lain.widgets.contrib.redshift
local redshift = {}
-local attached = false -- true if attached to a widget
-local active = false -- true if redshift is active
-local running = false -- true if redshift was initialized
-local update_fnct = function() end -- Function that is run each time redshift is toggled. See redshift:attach().
-
+local attached = false -- true if attached to a widget
+local active = false -- true if redshift is active
+local running = false -- true if redshift was initialized
+local update_fnct = function() end -- Function that is run each time redshift is toggled. See redshift:attach().
local function init()
-- As there is no way to determine if redshift was previously
local task_notification = nil
-function task:hide()
+function findLast(haystack, needle)
+ local i=haystack:match(".*"..needle.."()")
+ if i==nil then return nil else return i-1 end
+end
+
+function task.hide()
if task_notification ~= nil then
naughty.destroy(task_notification)
task_notification = nil
end
end
-function task:show(scr_pos)
- task:hide()
+function task.show(scr_pos)
+ task.hide()
- local f, c_text
+ local f, c_text, scrp
if task.followmouse then
- local scrp = mouse.screen
+ scrp = mouse.screen
else
- local scrp = scr_pos or task.scr_pos
+ scrp = scr_pos or task.scr_pos
end
- f = io.popen('task')
+ f = io.popen('task ' .. task.cmdline)
c_text = "<span font='"
.. task.font .. " "
.. task.font_size .. "'>"
- .. f:read("*all"):gsub("\n*$", "")
+ .. awful.util.escape(f:read("*all"):gsub("\n*$", ""))
.. "</span>"
f:close()
})
end
-function task:prompt_add()
+function task.prompt_add()
awful.prompt.run({ prompt = "Add task: " },
mypromptbox[mouse.screen].widget,
function (...)
c_text = "\n<span font='"
.. task.font .. " "
.. task.font_size .. "'>"
- .. f:read("*all")
+ .. awful.util.escape(f:read("*all"))
.. "</span>"
f:close()
awful.util.getdir("cache") .. "/history_task_add")
end
-function task:prompt_search()
+function task.prompt_search()
awful.prompt.run({ prompt = "Search task: " },
mypromptbox[mouse.screen].widget,
function (...)
c_text = "<span font='"
.. task.font .. " "
.. task.font_size .. "'>"
- .. c_text
+ .. awful.util.escape(c_text)
.. "</span>"
end
awful.util.getdir("cache") .. "/history_task")
end
-function task:attach(widget, args)
+function task.attach(widget, args)
local args = args or {}
task.font_size = tonumber(args.font_size) or 12
- task.font = beautiful.font:sub(beautiful.font:find(""),
- beautiful.font:find(" "))
+ task.font = args.font or beautiful.font:sub(beautiful.font:find(""),
+ findLast(beautiful.font, " "))
task.fg = args.fg or beautiful.fg_normal or "#FFFFFF"
task.bg = args.bg or beautiful.bg_normal or "#FFFFFF"
task.position = args.position or "top_right"
task.timeout = args.timeout or 7
task.scr_pos = args.scr_pos or 1
task.followmouse = args.followmouse or false
+ task.cmdline = args.cmdline or "next"
task.notify_icon = icons_dir .. "/taskwarrior/task.png"
task.notify_icon_small = icons_dir .. "/taskwarrior/tasksmall.png"
- widget:connect_signal("mouse::enter", function () task:show(task.scr_pos) end)
- widget:connect_signal("mouse::leave", function () task:hide() end)
+ widget:connect_signal("mouse::enter", function () task.show(task.scr_pos) end)
+ widget:connect_signal("mouse::leave", function () task.hide() end)
end
return setmetatable(task, { __call = function(_, ...) return create(...) end })
local setmetatable = setmetatable
local smapi = {}
-
local apipath = "/sys/devices/platform/smapi"
-- Most are readable values, but some can be written to (not implemented, yet?)
local fs = {}
local fs_notification = nil
-function fs:hide()
+function fs.hide()
if fs_notification ~= nil then
naughty.destroy(fs_notification)
fs_notification = nil
end
end
-function fs:show(t_out)
- fs:hide()
+function fs.show(seconds, options, scr)
+ fs.hide()
- local ws = helpers.read_pipe(helpers.scripts_dir .. "dfs"):gsub("\n*$", "")
+ local cmd = (options and string.format("dfs %s", options)) or "dfs"
+ local ws = helpers.read_pipe(helpers.scripts_dir .. cmd):gsub("\n*$", "")
if fs.followmouse then
fs.notification_preset.screen = mouse.screen
+ elseif scr then
+ fs.notification_preset.screen = scr
end
fs_notification = naughty.notify({
preset = fs.notification_preset,
text = ws,
- timeout = t_out
+ timeout = seconds or 5
})
end
local args = args or {}
local timeout = args.timeout or 600
local partition = args.partition or "/"
+ local showpopup = args.showpopup or "on"
+ local notify = args.notify or "on"
local settings = args.settings or function() end
fs.followmouse = args.followmouse or false
fs_now.size_mb = tonumber(fs_info[partition .. " size_mb"]) or 0
fs_now.size_gb = tonumber(fs_info[partition .. " size_gb"]) or 0
+ notification_preset = fs.notification_preset
widget = fs.widget
settings()
- if fs_now.used >= 99 and not helpers.get_map(partition)
+ if notify == "on" and fs_now.used >= 99 and not helpers.get_map(partition)
then
naughty.notify({
title = "warning",
end
end
- fs.widget:connect_signal('mouse::enter', function () fs:show(0) end)
- fs.widget:connect_signal('mouse::leave', function () fs:hide() end)
+ if showpopup == "on" then
+ fs.widget:connect_signal('mouse::enter', function () fs:show(0) end)
+ fs.widget:connect_signal('mouse::leave', function () fs:hide() end)
+ end
helpers.newtimer(partition, timeout, update)
helpers.set_map(mail, 0)
- if not is_plain
- then
+ if not is_plain then
password = helpers.read_pipe(password):gsub("\n", "")
end
maildir.widget = wibox.widget.textbox('')
function update()
- if ext_mail_cmd ~= nil
- then
+ if ext_mail_cmd then
awful.util.spawn(ext_mail_cmd)
end
p:close()
newmail = "no mail"
+
-- Count the total number of mails irrespective of where it was found
total = 0
--]]
-local newtimer = require("lain.helpers").newtimer
+local newtimer = require("lain.helpers").newtimer
-local wibox = require("wibox")
+local wibox = require("wibox")
-local io = { lines = io.lines }
-local math = { floor = math.floor }
-local string = { gmatch = string.gmatch }
+local io = { lines = io.lines }
+local math = { floor = math.floor }
+local string = { gmatch = string.gmatch }
-local setmetatable = setmetatable
+local setmetatable = setmetatable
-- Memory usage (ignoring caches)
-- lain.widgets.mem
mem_now.used = mem_now.total - (mem_now.free + mem_now.buf + mem_now.cache)
mem_now.swapused = mem_now.swap - mem_now.swapf
+ mem_now.perc = math.floor(mem_now.used / mem_now.total * 100)
widget = mem.widget
settings()
local naughty = require("naughty")
local wibox = require("wibox")
-local os = { execute = os.execute,
- getenv = os.getenv }
-local math = { floor = math.floor }
+local os = { execute = os.execute,
+ getenv = os.getenv }
+local math = { floor = math.floor }
local mouse = mouse
-local string = { format = string.format,
- match = string.match,
- gmatch = string.gmatch }
+local string = { format = string.format,
+ match = string.match,
+ gmatch = string.gmatch }
local setmetatable = setmetatable
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music"
local cover_size = args.cover_size or 100
local default_art = args.default_art or ""
+ local notify = args.notify or "on"
local followmouse = args.followmouse or false
local echo_cmd = args.echo_cmd or "echo"
local settings = args.settings or function() end
function mpd.update()
async.request(echo .. " | curl --connect-timeout 1 -fsm 3 " .. mpdh, function (f)
mpd_now = {
- state = "N/A",
- file = "N/A",
- name = "N/A",
- artist = "N/A",
- title = "N/A",
- album = "N/A",
- date = "N/A",
- time = "N/A",
- elapsed = "N/A"
+ random_mode = false,
+ single_mode = false,
+ repeat_mode = false,
+ consume_mode = false,
+ pls_pos = "N/A",
+ pls_len = "N/A",
+ state = "N/A",
+ file = "N/A",
+ name = "N/A",
+ artist = "N/A",
+ title = "N/A",
+ album = "N/A",
+ date = "N/A",
+ time = "N/A",
+ elapsed = "N/A"
}
for line in string.gmatch(f, "[^\n]+") do
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
- if k == "state" then mpd_now.state = v
- elseif k == "file" then mpd_now.file = v
- elseif k == "Name" then mpd_now.name = escape_f(v)
- elseif k == "Artist" then mpd_now.artist = escape_f(v)
- elseif k == "Title" then mpd_now.title = escape_f(v)
- elseif k == "Album" then mpd_now.album = escape_f(v)
- elseif k == "Date" then mpd_now.date = escape_f(v)
- elseif k == "Time" then mpd_now.time = v
- elseif k == "elapsed" then mpd_now.elapsed = string.match(v, "%d+")
+ if k == "state" then mpd_now.state = v
+ elseif k == "file" then mpd_now.file = v
+ elseif k == "Name" then mpd_now.name = escape_f(v)
+ elseif k == "Artist" then mpd_now.artist = escape_f(v)
+ elseif k == "Title" then mpd_now.title = escape_f(v)
+ elseif k == "Album" then mpd_now.album = escape_f(v)
+ elseif k == "Date" then mpd_now.date = escape_f(v)
+ elseif k == "Time" then mpd_now.time = v
+ elseif k == "elapsed" then mpd_now.elapsed = string.match(v, "%d+")
+ elseif k == "song" then mpd_now.pls_pos = v
+ elseif k == "playlistlength" then mpd_now.pls_len = v
+ elseif k == "repeat" then mpd_now.repeat_mode = v ~= "0"
+ elseif k == "single" then mpd_now.single_mode = v ~= "0"
+ elseif k == "random" then mpd_now.random_mode = v ~= "0"
+ elseif k == "consume" then mpd_now.consume_mode = v ~= "0"
end
end
end
if mpd_now.state == "play"
then
- if mpd_now.title ~= helpers.get_map("current mpd track")
+ if notify == "on" and mpd_now.title ~= helpers.get_map("current mpd track")
then
helpers.set_map("current mpd track", mpd_now.title)
net_now.sent = string.gsub(string.format('%.1f', net_now.sent), ',', '.')
net_now.received = string.gsub(string.format('%.1f', net_now.received), ',', '.')
- widget = net.widget
- settings()
-
net.last_t = total_t
net.last_r = total_r
end
+
+ widget = net.widget
+ settings()
end
helpers.newtimer(iface, timeout, update)
--]]
-local read_pipe = require("lain.helpers").read_pipe
-local newtimer = require("lain.helpers").newtimer
-local wibox = require("wibox")
+local read_pipe = require("lain.helpers").read_pipe
+local newtimer = require("lain.helpers").newtimer
+local wibox = require("wibox")
-local string = { match = string.match,
- format = string.format }
+local string = { gmatch = string.gmatch,
+ match = string.match,
+ format = string.format }
-local setmetatable = setmetatable
+local setmetatable = setmetatable
-- PulseAudio volume
-- lain.widgets.pulseaudio
local settings = args.settings or function() end
local scallback = args.scallback
- pulseaudio.cmd = args.cmd or string.format("pacmd list-sinks | sed -n -e '0,/*/d' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p'")
+ pulseaudio.cmd = args.cmd or string.format("pacmd list-sinks | sed -n -e '0,/*/d' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'")
pulseaudio.widget = wibox.widget.textbox('')
function pulseaudio.update()
local s = read_pipe(pulseaudio.cmd)
volume_now = {}
- volume_now.left = tonumber(string.match(s, ":.-(%d+)%%"))
- volume_now.right = tonumber(string.match(s, ":.-(%d+)%%"))
- volume_now.muted = string.match(s, "muted: (%S+)")
+ volume_now.index = string.match(s, "index: (%S+)") or "N/A"
+ volume_now.sink = string.match(s, "device.string = \"(%S+)\"") or "N/A"
+ volume_now.muted = string.match(s, "muted: (%S+)") or "N/A"
+
+ local ch = 1
+ volume_now.channel = {}
+ for v in string.gmatch(s, ":.-(%d+)%%") do
+ volume_now.channel[ch] = v
+ ch = ch + 1
+ end
+
+ volume_now.left = volume_now.channel[1] or "N/A"
+ volume_now.right = volume_now.channel[2] or "N/A"
widget = pulseaudio.widget
settings()
-- lain.widgets.pulsebar
local pulsebar = {
sink = 0,
+ step = "1%",
colors = {
background = beautiful.bg_normal,
pulsebar.colors = args.colors or pulsebar.colors
pulsebar.notifications = args.notifications or pulsebar.notifications
pulsebar.sink = args.sink or 0
+ pulsebar.step = args.step or pulsebar.step
pulsebar.followmouse = args.followmouse or false
pulsebar.bar = awful.widget.progressbar()
end
end
- pulsebar.bar:buttons (awful.util.table.join (
- awful.button ({}, 1, function()
+ pulsebar.bar:buttons(awful.util.table.join (
+ awful.button({}, 1, function()
awful.util.spawn(pulsebar.mixer)
- end)
+ end),
+ awful.button({}, 2, function()
+ awful.util.spawn(string.format("pactl set-sink-volume %d 100%%", pulsebar.sink))
+ pulsebar.update()
+ end),
+ awful.button({}, 3, function()
+ awful.util.spawn(string.format("pactl set-sink-mute %d toggle", pulsebar.sink))
+ pulsebar.update()
+ end),
+ awful.button({}, 4, function()
+ awful.util.spawn(string.format("pactl set-sink-volume %d +%s", pulsebar.sink, pulsebar.step))
+ pulsebar.update()
+ end),
+ awful.button({}, 5, function()
+ awful.util.spawn(string.format("pactl set-sink-volume %d -%s", pulsebar.sink, pulsebar.step))
+ pulsebar.update()
+ end)
))
timer_id = string.format("pulsebar-%s", pulsebar.sink)
local pos, err
weather_now, pos, err = json.decode(f, 1, nil)
- if not err and weather_now and tonumber(weather_now["cod"]) == 200 then
+ if not err and type(weather_now) == "table" and tonumber(weather_now["cod"]) == 200 then
weather.notification_text = ''
for i = 1, weather_now["cnt"] do
weather.notification_text = weather.notification_text ..
local pos, err, icon
weather_now, pos, err = json.decode(f, 1, nil)
- if not err and weather_now and tonumber(weather_now["cod"]) == 200 then
+ if not err and type(weather_now) == "table" and tonumber(weather_now["cod"]) == 200 then
-- weather icon based on localtime
local now = os.time()
local sunrise = tonumber(weather_now["sys"]["sunrise"])
-Subproject commit 25dd1a2ec44da832d06ded29f393d716e4b54783
+Subproject commit d0df450d05655c5d8f724c42dc6b5d18b3676a60