first commit
|
@ -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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
|
@ -0,0 +1,419 @@
|
|||
VAin agaIN
|
||||
==========
|
||||
|
||||
Author: Luke Bonham <dada [at] archlinux [dot] info>
|
||||
|
||||
Source: https://github.com/copycat-killer/vain
|
||||
|
||||
Version: 1.9.9
|
||||
|
||||
Release version: 2.0
|
||||
|
||||
**Please note**: until release version, this documentation will be not updated.
|
||||
|
||||
Foreword
|
||||
--------
|
||||
|
||||
Based on a port of [awesome-vain](https://github.com/vain/awesome-vain), this
|
||||
costantly evolving module provides new layouts, a set of widgets and
|
||||
utility functions in order to improve Awesome usability and configurability.
|
||||
|
||||
This work is licensed under [GNU GPLv2 License](http://www.gnu.org/licenses/gpl-2.0.html).
|
||||
Installation
|
||||
============
|
||||
|
||||
Simply clone this repository into your Awesome directory.
|
||||
|
||||
Widgets
|
||||
=======
|
||||
|
||||
systemload
|
||||
----------
|
||||
|
||||
Show the current system load in a textbox. Read it directly from
|
||||
`/proc/loadavg`.
|
||||
|
||||
mysysload = vain.widgets.systemload()
|
||||
|
||||
A click on the widget will call `htop` in your `terminal`.
|
||||
|
||||
The function takes a table as an optional argument. That table may
|
||||
contain:
|
||||
|
||||
* `.refresh_timeout`: Default to 10 seconds.
|
||||
* `.show_all`: Show all three values (`true`) or only the first one (`false`). Default to `false`.
|
||||
* `.color`: Default to beautiful.bg_normal or "#FFFFFF".
|
||||
|
||||
cpu
|
||||
--------
|
||||
|
||||
Shows the average CPU usage percent for a given amount of time.
|
||||
|
||||
mycpuusage = vain.widgets.cpu()
|
||||
|
||||
A click on the widget will call `htop` in your `terminal`.
|
||||
|
||||
The function takes a table as optional argument, which can contain:
|
||||
|
||||
Variable | Meaning | Type | Default
|
||||
--- | --- | --- | ---
|
||||
`refresh_timeout` | Refresh timeout seconds | int | 10
|
||||
`header` | Text to show before value | string | " Vol "
|
||||
`header_color` | Header color | string | `beautiful.fg_normal` or "#FFFFFF"
|
||||
`color` | Value color | string | `beautiful.fg_focus` or "#FFFFFF"
|
||||
`footer` | Text to show after value | string | "%"
|
||||
|
||||
**Note**: `footer` color is `color`.
|
||||
|
||||
memusage
|
||||
--------
|
||||
|
||||
Show used memory and total memory in MiB.
|
||||
|
||||
mymem = vain.widgets.mem()
|
||||
|
||||
|
||||
The function takes a table as an optional argument. That table may
|
||||
contain:
|
||||
|
||||
Variable | Meaning | Type | Default
|
||||
--- | --- | --- | ---
|
||||
`refresh_timeout` | Refresh timeout seconds | int | 10
|
||||
`show_swap` | Show amount of used swap space? | boolean | false
|
||||
`show_total` | Show amout of total memory? | boolean | false
|
||||
`header` | Text to show before value | string | " Vol "
|
||||
`header_color` | Header color | string | `beautiful.fg_normal` or "#FFFFFF"
|
||||
`color` | Value color | string | `beautiful.fg_focus` or "#FFFFFF"
|
||||
`footer` | Text to show after value | string | "MB"
|
||||
|
||||
**Note**: `footer` color is `color`.
|
||||
|
||||
mailcheck
|
||||
---------
|
||||
Checks maildirs and shows the result in a textbox.
|
||||
Maildirs are structured as follows:
|
||||
|
||||
~/Mail
|
||||
.
|
||||
|-- arch
|
||||
| |-- cur
|
||||
| |-- new
|
||||
| `-- tmp
|
||||
|-- gmail
|
||||
| |-- cur
|
||||
| |-- new
|
||||
| `-- tmp
|
||||
.
|
||||
.
|
||||
.
|
||||
|
||||
therefore `mailcheck` checks whether there are files in the `new`
|
||||
directories. To do so, it calls `find`. If there's new mail, the textbox
|
||||
will say something like "mail: bugs(3), system(1)", otherwise it says
|
||||
"no mail".
|
||||
|
||||
mymailcheck = vain.widgets.mailcheck("/path/to/my/maildir")
|
||||
|
||||
The function takes a table as an optional argument. That table may
|
||||
contain:
|
||||
|
||||
* `.mailprogram`: Your favourite mail program. Clicking on the widget will
|
||||
spawn it. Default is `mutt`.
|
||||
* `.refresh_timeout`: Default to 60 seconds.
|
||||
* `.mailpath`: Path to your maildir, default is `~/Mail`.
|
||||
* `.ignore_boxes`: Another table which lists boxes (just the last part,
|
||||
like `lists`) to ignore. Default to an empty table.
|
||||
* `.initial_update`: Check for mail when starting Awesome (`true`) or
|
||||
wait for the first refresh timeout (`false`)? Default to `false`.
|
||||
* `.header_text`: Text to show along with output, default is "Mail".
|
||||
* `.header_text_color`: Default to "#9E9E9E".
|
||||
* `.color_newmail`: Default to "#D4D4D4".
|
||||
* `.color_nomail`: Default to "#9E9E9E".
|
||||
* `.shadow`: Hides widget when there are no mails. Default is `false`.
|
||||
|
||||
imapcheck
|
||||
---------
|
||||
|
||||
Check new mails over imap protocol.
|
||||
|
||||
Dependencies:
|
||||
|
||||
* Python3
|
||||
|
||||
Since [luasec](https://github.com/brunoos/luasec/) is still not officially
|
||||
supported in lua 5.2, writing a pure lua solution would have meant too many
|
||||
hacks and dependencies, resulting in a very big and not efficient-proven submodule.
|
||||
|
||||
That's why I chose Python.
|
||||
|
||||
Python offers [imaplib](http://docs.python.org/2/library/imaplib.html), a simple yet powerful IMAP4 client library which provides encrypted communication over SSL sockets.
|
||||
|
||||
Basically, `imapcheck` calls ``vain/scripts/checkmail`` and parse its output in a widget. New mails are also notified through Naughty, with a popup like this:
|
||||
|
||||
+---------------------------------------------------+
|
||||
| +---+ |
|
||||
| |\ /| donald@disney.org has 3 new messages |
|
||||
| +---+ |
|
||||
| Latest From: Mickey Mouse <boss@disney.org> |
|
||||
| Subject: Re: Vacation Day |
|
||||
| |
|
||||
| Not after what you did yesterday. |
|
||||
| Daisy told me everything [...] |
|
||||
| |
|
||||
+---------------------------------------------------+
|
||||
|
||||
Text will be cut if the mail is too long.
|
||||
|
||||
myimapcheck = vain.widgets.mailcheck(args)
|
||||
|
||||
The function takes a table as argument. Required table parameters are:
|
||||
|
||||
* `.server`: You email server. Example: `imap.gmail.com`.
|
||||
* `.mail`: Your email.
|
||||
* `.password`: Your email password.
|
||||
|
||||
while the optional are:
|
||||
|
||||
* `.port`: Imap port. Default is `993`.
|
||||
* `.refresh_timeout`: Default to 60 seconds.
|
||||
* `.notify_timeout`: Notification timeout. Default to 8 seconds.
|
||||
* `.notify_position`: Notification position. Default is "top_left". Check
|
||||
[Naughty position parameter](http://awesome.naquadah.org/doc/api/modules/naughty.html) for a list of other possible values.
|
||||
* `.mailprogram`: Your favourite mail program. Clicking on the widget will
|
||||
spawn it. Default is `mutt`.
|
||||
* `.mail_encoding`: If you wish to set an encoding. Default is `nil`.
|
||||
* `.initial_update`: Check for mail when starting Awesome (`true`) or
|
||||
wait for the first refresh timeout (`false`)? Default to `false`.
|
||||
* `.header_text`: Text to show along with output, default is "Mail".
|
||||
* `.header_text_color`: Default to "#9E9E9E".
|
||||
* `.color_newmail`: Default to "#D4D4D4".
|
||||
* `.color_nomail`: Default to "#9E9E9E".
|
||||
* `.shadow`: Hides widget when there are no mails. Default is `false`.
|
||||
* `.maxlen`: Maximum mail length. If mail is longer, it will be cut. Default is
|
||||
`100`.
|
||||
* `.is_plain`: Define whether `.password` field is a plain password (`true`) or a function that retrieves it (`false`). Default to `false`.
|
||||
|
||||
Let's focus better on `.is_plain` parameter.
|
||||
|
||||
You can just easily set your password like this:
|
||||
|
||||
args.is_plain = false
|
||||
args.password = "mypassword"
|
||||
|
||||
and you'll have the same security provided by `~/.netrc`. (In this case, it's
|
||||
better to set your `rc.lua` permissions to 700 or 600)
|
||||
|
||||
**Or**, you can use a keyring, like gnome's:
|
||||
|
||||
args.password = "gnome-keyring-query get password"
|
||||
|
||||
(`gnome-keyring-query` is not in gnome-keyring pkg, you have to download it
|
||||
separately)
|
||||
|
||||
or the very light [python keyring](https://pypi.python.org/pypi/keyring).
|
||||
|
||||
When `.is_plain` is `false`, it *executes* `.password` before using it, so you can also use whatever password fetching solution you want.
|
||||
|
||||
You can also define your icon for the naughty notification. Just set `vain_mail_notify` into your ``theme.lua``.
|
||||
|
||||
|
||||
|
||||
mpd
|
||||
---
|
||||
|
||||
Provides a `table` with 2 elements:
|
||||
|
||||
* `table["widget"]` is a textbox displaying current song in play.
|
||||
|
||||
* `table["force"]` is a function to *force* the widget to update, exactly
|
||||
like `vicious.force()`.
|
||||
|
||||
Also, a notification is shown when a new song is playing.
|
||||
|
||||
Dependencies:
|
||||
|
||||
* libnotify
|
||||
* imagemagick
|
||||
|
||||
|
||||
mpdwidget = vain.widgets.mpd()
|
||||
...
|
||||
right_layout:add(mpdwidget["widget"])
|
||||
|
||||
The function takes a table as an optional argument. That table may
|
||||
contain:
|
||||
|
||||
* `.password`: Mpd password. Default is unset.
|
||||
* `.host`: Mpd host. Default is "127.0.0.1" (localhost).
|
||||
* `.port`: Mpd port. Default is "6600".
|
||||
* `.music_dir`: Your music directory. Default is "~/Music". If you have to
|
||||
change this, be sure to write the absolute path.
|
||||
* `.refresh_timeout`: Widget refresh timeout. Default is `1`.
|
||||
* `.notify_timeout`: Notification timeout. Default is `5`.
|
||||
* `.color_artist`: Artist name color. Default is `#9E9E9E`.
|
||||
* `.color_song`: Song name color. Default is `#EBEBFF`.
|
||||
* `.musicplr`: Your favourite music player. Clicking on the widget will spawn
|
||||
it. Default is `ncmpcpp`.
|
||||
* `.shadow`: Hides widget when no song is playing. Default is `false`.
|
||||
|
||||
You can use `table["force"]` to make your mpd keybindings immediate.
|
||||
Example usage:
|
||||
|
||||
globalkeys = awful.util.table.join(
|
||||
...
|
||||
-- Music control
|
||||
awful.key({ altkey, "Control" }, "Up", function ()
|
||||
awful.util.spawn_with_shell( "mpc toggle || ncmpcpp toggle || ncmpc toggle || pms toggle", false )
|
||||
mpdwidget["force"]()
|
||||
end),
|
||||
awful.key({ altkey, "Control" }, "Down", function ()
|
||||
awful.util.spawn_with_shell( "mpc stop || ncmpcpp stop || ncmpc stop || pms stop", false )
|
||||
mpdwidget["force"]()
|
||||
end ),
|
||||
awful.key({ altkey, "Control" }, "Left", function ()
|
||||
awful.util.spawn_with_shell( "mpc prev || ncmpcpp prev || ncmpc prev || pms prev", false )
|
||||
mpdwidget["force"]()
|
||||
end ),
|
||||
awful.key({ altkey, "Control" }, "Right", function ()
|
||||
awful.util.spawn_with_shell( "mpc next || ncmpcpp next || ncmpc next || pms next", false )
|
||||
mpdwidget["force"]()
|
||||
end ),
|
||||
|
||||
net
|
||||
---
|
||||
|
||||
Monitors network interfaces and shows current traffic in a textbox. If
|
||||
the interface is not present or if there's not enough data yet, you'll
|
||||
see `wlan0: -` or similar. Otherwise, the current traffic is shown in
|
||||
kilobytes per second as `eth0: ↑(00,010.2), ↓(01,037.8)` or similar.
|
||||
|
||||
neteth0 = vain.widgets.net()
|
||||
|
||||
The function takes a table as an optional argument. That table may
|
||||
contain:
|
||||
|
||||
* `.iface`: Default to `eth0`.
|
||||
* `.refresh_timeout`: Default to 2 seconds.
|
||||
* `.color`: Default to beautiful.bg_normal or "#FFFFFF".
|
||||
|
||||
gitodo
|
||||
------
|
||||
|
||||
This is an integration of [gitodo](https://github.com/vain/gitodo) into
|
||||
Awesome.
|
||||
|
||||
todolist = vain.widgets.gitodo()
|
||||
|
||||
The function takes a table as an optional argument. That table may
|
||||
contain:
|
||||
|
||||
* `.refresh_timeout`: Default to 120 seconds.
|
||||
* `.initial_update`: Check for todo items when starting Awesome (`true`)
|
||||
or wait for the first refresh timeout (`false`)? Default to `true`.
|
||||
|
||||
`beautiful.gitodo_normal` is used as the color for non-outdated items,
|
||||
`beautiful.gitodo_warning` for those items close to their deadline and
|
||||
`beautiful.gitodo_outdated` is the color of outdated items.
|
||||
|
||||
|
||||
|
||||
Utility functions
|
||||
=================
|
||||
|
||||
I'll only explain the more complex functions. See the source code for
|
||||
the others.
|
||||
|
||||
menu\_clients\_current\_tags
|
||||
----------------------------
|
||||
|
||||
Similar to `awful.menu.clients()`, but this menu only shows the clients
|
||||
of currently visible tags. Use it like this:
|
||||
|
||||
globalkeys = awful.util.table.join(
|
||||
...
|
||||
awful.key({ "Mod1" }, "Tab", function()
|
||||
awful.menu.menu_keys.down = { "Down", "Alt_L", "Tab", "j" }
|
||||
awful.menu.menu_keys.up = { "Up", "k" }
|
||||
vain.util.menu_clients_current_tags({ width = 350 }, { keygrabber = true })
|
||||
end),
|
||||
...
|
||||
)
|
||||
|
||||
magnify\_client
|
||||
---------------
|
||||
|
||||
Set a client to floating and resize it in the same way the "magnifier"
|
||||
layout does it. Place it on the "current" screen (derived from the mouse
|
||||
position). This allows you to magnify any client you wish, regardless of
|
||||
the currently used layout. Use it with a client keybinding like this:
|
||||
|
||||
clientkeys = awful.util.table.join(
|
||||
...
|
||||
awful.key({ modkey, "Control" }, "m", vain.util.magnify_client),
|
||||
...
|
||||
)
|
||||
|
||||
If you want to "de-magnify" it, just reset the clients floating state to
|
||||
`false` (hit `Mod4`+`CTRL`+`Space`, for example).
|
||||
|
||||
niceborder\_{focus, unfocus}
|
||||
----------------------------
|
||||
|
||||
By default, your `rc.lua` contains something like this:
|
||||
|
||||
client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
|
||||
client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
|
||||
|
||||
You can change it to this:
|
||||
|
||||
client.connect_signal("focus", vain.util.niceborder_focus(c))
|
||||
client.connect_signal("unfocus", vain.util.niceborder_unfocus(c))
|
||||
|
||||
Now, when a client is focused or unfocused, Awesome will look up its
|
||||
nice value in `/proc/<pid>/stat`. If it's less than 0, the client is
|
||||
classified as "high priority"; if it's greater than 0, the client is
|
||||
classified as "low priority". If it's equal to 0, nothing special
|
||||
happens.
|
||||
|
||||
This requires to define additional colors in your `theme.lua`. For example:
|
||||
|
||||
theme.border_focus_highprio = "#FF0000"
|
||||
theme.border_normal_highprio = "#A03333"
|
||||
|
||||
theme.border_focus_lowprio = "#3333FF"
|
||||
theme.border_normal_lowprio = "#333366"
|
||||
|
||||
tag\_view\_nonempty
|
||||
------------------------------
|
||||
|
||||
This function lets you jump to the next/previous non-empty tag.
|
||||
It takes two arguments:
|
||||
|
||||
* `direction`: `1` for next non-empty tag, `-1` for previous.
|
||||
* `sc`: Screen in which the taglist is. Default is `mouse.screen` or `1`. This
|
||||
argument is optional.
|
||||
|
||||
Usage example:
|
||||
|
||||
globalkeys = awful.util.table.join(
|
||||
...
|
||||
-- Non-empty tag browsing
|
||||
awful.key({ altkey }, "Left", function () vain.util.tag_view_nonempty(-1)
|
||||
end),
|
||||
awful.key({ altkey }, "Right", function () vain.util.tag_view_nonempty(1) end),
|
||||
...
|
||||
|
||||
prompt\_rename\_tag
|
||||
-------------------
|
||||
|
||||
This function enables you to dynamically rename the current tag you have
|
||||
focused.
|
||||
Usage example:
|
||||
|
||||
globalkeys = awful.util.table.join(
|
||||
..
|
||||
-- Dynamic tag renaming
|
||||
awful.key({ modkey, "Shift" }, "r", function () vain.util.prompt_rename_tag(mypromptbox) end),
|
||||
...
|
||||
|
||||
Credits goes to [minism](https://bbs.archlinux.org/viewtopic.php?pid=1315135#p1315135).
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
* (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
|
||||
--]]
|
||||
|
||||
local awful = require("awful")
|
||||
local debug = require("debug")
|
||||
local pairs = pairs
|
||||
local rawget = rawget
|
||||
|
||||
-- Lain helper functions for internal use
|
||||
-- lain.helpers
|
||||
local helpers = {}
|
||||
|
||||
helpers.lain_dir = debug.getinfo(1, 'S').source:match[[^@(.*/).*$]]
|
||||
helpers.icons_dir = helpers.lain_dir .. 'icons/'
|
||||
helpers.scripts_dir = helpers.lain_dir .. 'scripts/'
|
||||
|
||||
-- {{{ Modules loader
|
||||
|
||||
function helpers.wrequire(table, key)
|
||||
local module = rawget(table, key)
|
||||
return module or require(table._NAME .. '.' .. key)
|
||||
end
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{
|
||||
-- If lain.terminal is a string, e.g. "xterm", then "xterm -e " .. cmd is
|
||||
-- run. But if lain.terminal is a function, then terminal(cmd) is run.
|
||||
|
||||
function helpers.run_in_terminal(cmd)
|
||||
if type(terminal) == "function"
|
||||
then
|
||||
terminal(cmd)
|
||||
elseif type(terminal) == "string"
|
||||
then
|
||||
awful.util.spawn(terminal .. ' -e ' .. cmd)
|
||||
end
|
||||
end
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ Format units to one decimal point
|
||||
|
||||
function helpers.uformat(array, key, value, unit)
|
||||
for u, v in pairs(unit) do
|
||||
array["{"..key.."_"..u.."}"] = string.format("%.1f", value/v)
|
||||
end
|
||||
return array
|
||||
end
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ Read the first line of a file or return nil.
|
||||
|
||||
function helpers.first_line(f)
|
||||
local fp = io.open(f)
|
||||
if not fp
|
||||
then
|
||||
return nil
|
||||
end
|
||||
|
||||
local content = fp:read("*l")
|
||||
fp:close()
|
||||
return content
|
||||
end
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ A map utility
|
||||
|
||||
helpers.map_table = {}
|
||||
|
||||
function helpers.set_map(element, value)
|
||||
helpers.map_table[element] = value
|
||||
end
|
||||
|
||||
function helpers.get_map(element)
|
||||
return helpers.map_table[element]
|
||||
end
|
||||
|
||||
-- }}}
|
||||
|
||||
return helpers
|
After Width: | Height: | Size: 888 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 233 B |
After Width: | Height: | Size: 235 B |
After Width: | Height: | Size: 235 B |
After Width: | Height: | Size: 233 B |
After Width: | Height: | Size: 258 B |
After Width: | Height: | Size: 277 B |
After Width: | Height: | Size: 289 B |
After Width: | Height: | Size: 289 B |
After Width: | Height: | Size: 191 B |
After Width: | Height: | Size: 191 B |
After Width: | Height: | Size: 269 B |
After Width: | Height: | Size: 299 B |
After Width: | Height: | Size: 290 B |
After Width: | Height: | Size: 252 B |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 289 B |
After Width: | Height: | Size: 634 B |
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,20 @@
|
|||
|
||||
--[[
|
||||
|
||||
Lain
|
||||
Layouts, widgets and utilities for Awesome WM
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local lain =
|
||||
{
|
||||
layout = require("lain.layout"),
|
||||
util = require("lain.util"),
|
||||
widgets = require("lain.widgets")
|
||||
}
|
||||
|
||||
return lain
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local tag = require("awful.tag")
|
||||
|
||||
local cascade =
|
||||
{
|
||||
name = "cascade",
|
||||
nmaster = 0,
|
||||
offset_x = 32,
|
||||
offset_y = 8
|
||||
}
|
||||
|
||||
function cascade.arrange(p)
|
||||
|
||||
-- Cascade windows.
|
||||
|
||||
-- Screen.
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
|
||||
-- Opening a new window will usually force all existing windows to
|
||||
-- get resized. This wastes a lot of CPU time. So let's set a lower
|
||||
-- bound to "how_many": This wastes a little screen space but you'll
|
||||
-- get a much better user experience.
|
||||
local t = tag.selected(p.screen)
|
||||
local num_c
|
||||
if cascade.nmaster > 0
|
||||
then
|
||||
num_c = cascade.nmaster
|
||||
else
|
||||
num_c = tag.getnmaster(t)
|
||||
end
|
||||
|
||||
local how_many = #cls
|
||||
if how_many < num_c
|
||||
then
|
||||
how_many = num_c
|
||||
end
|
||||
|
||||
local current_offset_x = cascade.offset_x * (how_many - 1)
|
||||
local current_offset_y = cascade.offset_y * (how_many - 1)
|
||||
|
||||
-- Iterate.
|
||||
for i = 1,#cls,1
|
||||
do
|
||||
local c = cls[i]
|
||||
local g = {}
|
||||
|
||||
g.x = wa.x + (how_many - i) * cascade.offset_x
|
||||
g.y = wa.y + (i - 1) * cascade.offset_y
|
||||
g.width = wa.width - current_offset_x
|
||||
g.height = wa.height - current_offset_y
|
||||
|
||||
c:geometry(g)
|
||||
end
|
||||
end
|
||||
|
||||
return cascade
|
|
@ -0,0 +1,159 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local tag = require("awful.tag")
|
||||
local beautiful = require("beautiful")
|
||||
local tonumber = tonumber
|
||||
|
||||
local cascadetile =
|
||||
{
|
||||
name = "cascadetile",
|
||||
nmaster = 0,
|
||||
ncol = 0,
|
||||
mwfact = 0,
|
||||
offset_x = 5,
|
||||
offset_y = 32,
|
||||
extra_padding = 0
|
||||
}
|
||||
|
||||
function cascadetile.arrange(p)
|
||||
|
||||
-- Layout with one fixed column meant for a master window. Its
|
||||
-- width is calculated according to mwfact. Other clients are
|
||||
-- cascaded or "tabbed" in a slave column on the right.
|
||||
|
||||
-- It's a bit hard to demonstrate the behaviour with ASCII-images...
|
||||
--
|
||||
-- (1) (2) (3) (4)
|
||||
-- +-----+---+ +-----+---+ +-----+---+ +-----+---+
|
||||
-- | | | | | | | | | | | 4 |
|
||||
-- | | | | | 2 | | | 3 | | | |
|
||||
-- | 1 | | -> | 1 | | -> | 1 | | -> | 1 +---+
|
||||
-- | | | | +---+ | +---+ | | 3 |
|
||||
-- | | | | | | | | 2 | | |---|
|
||||
-- | | | | | | | |---| | | 2 |
|
||||
-- | | | | | | | | | | |---|
|
||||
-- +-----+---+ +-----+---+ +-----+---+ +-----+---+
|
||||
|
||||
-- A useless gap (like the dwm patch) can be defined with
|
||||
-- beautiful.useless_gap_width.
|
||||
local useless_gap = tonumber(beautiful.useless_gap_width)
|
||||
if useless_gap == nil
|
||||
then
|
||||
useless_gap = 0
|
||||
end
|
||||
|
||||
-- Screen.
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
|
||||
-- Width of main column?
|
||||
local t = tag.selected(p.screen)
|
||||
local mwfact
|
||||
if cascadetile.mwfact > 0
|
||||
then
|
||||
mwfact = cascadetile.mwfact
|
||||
else
|
||||
mwfact = tag.getmwfact(t)
|
||||
end
|
||||
|
||||
-- Make slave windows overlap main window? Do this if ncol is 1.
|
||||
local overlap_main
|
||||
if cascadetile.ncol > 0
|
||||
then
|
||||
overlap_main = cascadetile.ncol
|
||||
else
|
||||
overlap_main = tag.getncol(t)
|
||||
end
|
||||
|
||||
-- Minimum space for slave windows? See cascade.lua.
|
||||
local num_c
|
||||
if cascadetile.nmaster > 0
|
||||
then
|
||||
num_c = cascadetile.nmaster
|
||||
else
|
||||
num_c = tag.getnmaster(t)
|
||||
end
|
||||
|
||||
local how_many = #cls - 1
|
||||
if how_many < num_c
|
||||
then
|
||||
how_many = num_c
|
||||
end
|
||||
local current_offset_x = cascadetile.offset_x * (how_many - 1)
|
||||
local current_offset_y = cascadetile.offset_y * (how_many - 1)
|
||||
|
||||
if #cls > 0
|
||||
then
|
||||
-- Main column, fixed width and height.
|
||||
local c = cls[#cls]
|
||||
local g = {}
|
||||
local mainwid = wa.width * mwfact
|
||||
local slavewid = wa.width - mainwid
|
||||
|
||||
if overlap_main == 1
|
||||
then
|
||||
g.width = wa.width
|
||||
|
||||
-- The size of the main window may be reduced a little bit.
|
||||
-- This allows you to see if there are any windows below the
|
||||
-- main window.
|
||||
-- This only makes sense, though, if the main window is
|
||||
-- overlapping everything else.
|
||||
g.width = g.width - cascadetile.extra_padding
|
||||
else
|
||||
g.width = mainwid
|
||||
end
|
||||
|
||||
g.height = wa.height
|
||||
g.x = wa.x
|
||||
g.y = wa.y
|
||||
if useless_gap > 0
|
||||
then
|
||||
-- Reduce width once and move window to the right. Reduce
|
||||
-- height twice, however.
|
||||
g.width = g.width - useless_gap
|
||||
g.height = g.height - 2 * useless_gap
|
||||
g.x = g.x + useless_gap
|
||||
g.y = g.y + useless_gap
|
||||
|
||||
-- When there's no window to the right, add an additional
|
||||
-- gap.
|
||||
if overlap_main == 1
|
||||
then
|
||||
g.width = g.width - useless_gap
|
||||
end
|
||||
end
|
||||
c:geometry(g)
|
||||
|
||||
-- Remaining clients stacked in slave column, new ones on top.
|
||||
if #cls > 1
|
||||
then
|
||||
for i = (#cls - 1),1,-1
|
||||
do
|
||||
c = cls[i]
|
||||
g = {}
|
||||
g.width = slavewid - current_offset_x
|
||||
g.height = wa.height - current_offset_y
|
||||
g.x = wa.x + mainwid + (how_many - i) * cascadetile.offset_x
|
||||
g.y = wa.y + (i - 1) * cascadetile.offset_y
|
||||
if useless_gap > 0
|
||||
then
|
||||
g.width = g.width - 2 * useless_gap
|
||||
g.height = g.height - 2 * useless_gap
|
||||
g.x = g.x + useless_gap
|
||||
g.y = g.y + useless_gap
|
||||
end
|
||||
c:geometry(g)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return cascadetile
|
|
@ -0,0 +1,122 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local tonumber = tonumber
|
||||
local math = { floor = math.floor }
|
||||
|
||||
local centerwork =
|
||||
{
|
||||
name = "centerwork",
|
||||
top_left = 0,
|
||||
top_right = 1,
|
||||
bottom_left = 2,
|
||||
bottom_right = 3
|
||||
}
|
||||
|
||||
function centerwork.arrange(p)
|
||||
-- A useless gap (like the dwm patch) can be defined with
|
||||
-- beautiful.useless_gap_width .
|
||||
local useless_gap = tonumber(beautiful.useless_gap_width)
|
||||
if useless_gap == nil
|
||||
then
|
||||
useless_gap = 0
|
||||
end
|
||||
|
||||
-- Screen.
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
|
||||
-- Width of main column?
|
||||
local t = awful.tag.selected(p.screen)
|
||||
local mwfact = awful.tag.getmwfact(t)
|
||||
|
||||
if #cls > 0
|
||||
then
|
||||
-- Main column, fixed width and height.
|
||||
local c = cls[#cls]
|
||||
local g = {}
|
||||
local mainwid = math.floor(wa.width * mwfact)
|
||||
local slavewid = wa.width - mainwid
|
||||
local slaveLwid = math.floor(slavewid / 2)
|
||||
local slaveRwid = slavewid - slaveLwid
|
||||
local slaveThei = math.floor(wa.height / 2)
|
||||
local slaveBhei = wa.height - slaveThei
|
||||
|
||||
g.height = wa.height - 2 * useless_gap
|
||||
g.width = mainwid
|
||||
g.x = wa.x + slaveLwid
|
||||
g.y = wa.y + useless_gap
|
||||
|
||||
c:geometry(g)
|
||||
|
||||
-- Auxiliary windows.
|
||||
if #cls > 1
|
||||
then
|
||||
local at = 0
|
||||
for i = (#cls - 1),1,-1
|
||||
do
|
||||
-- It's all fixed. If there are more than 5 clients,
|
||||
-- those additional clients will float. This is
|
||||
-- intentional.
|
||||
if at == 4
|
||||
then
|
||||
break
|
||||
end
|
||||
|
||||
c = cls[i]
|
||||
g = {}
|
||||
|
||||
if at == centerwork.top_left
|
||||
then
|
||||
-- top left
|
||||
g.x = wa.x + useless_gap
|
||||
g.y = wa.y + useless_gap
|
||||
g.width = slaveLwid - 2 * useless_gap
|
||||
g.height = slaveThei - useless_gap
|
||||
elseif at == centerwork.top_right
|
||||
then
|
||||
-- top right
|
||||
g.x = wa.x + slaveLwid + mainwid + useless_gap
|
||||
g.y = wa.y + useless_gap
|
||||
g.width = slaveRwid - 2 * useless_gap
|
||||
g.height = slaveThei - useless_gap
|
||||
elseif at == centerwork.bottom_left
|
||||
then
|
||||
-- bottom left
|
||||
g.x = wa.x + useless_gap
|
||||
g.y = wa.y + slaveThei + useless_gap
|
||||
g.width = slaveLwid - 2 * useless_gap
|
||||
g.height = slaveBhei - 2 * useless_gap
|
||||
elseif at == centerwork.bottom_right
|
||||
then
|
||||
-- bottom right
|
||||
g.x = wa.x + slaveLwid + mainwid + useless_gap
|
||||
g.y = wa.y + slaveThei + useless_gap
|
||||
g.width = slaveRwid - 2 * useless_gap
|
||||
g.height = slaveBhei - 2 * useless_gap
|
||||
end
|
||||
|
||||
c:geometry(g)
|
||||
|
||||
at = at + 1
|
||||
end
|
||||
|
||||
-- Set remaining clients to floating.
|
||||
for i = (#cls - 1 - 4),1,-1
|
||||
do
|
||||
c = cls[i]
|
||||
awful.client.floating.set(c, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return centerwork
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
--[[
|
||||
|
||||
Lain
|
||||
Layouts, widgets and utilities for Awesome WM
|
||||
|
||||
Layouts section
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local wrequire = require("lain.helpers").wrequire
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local layout = { _NAME = "lain.layout" }
|
||||
|
||||
return setmetatable(layout, { __index = wrequire })
|
|
@ -0,0 +1,160 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local tag = require("awful.tag")
|
||||
local beautiful = require("beautiful")
|
||||
local math = { ceil = math.ceil,
|
||||
floor = math.floor,
|
||||
max = math.max }
|
||||
local tonumber = tonumber
|
||||
|
||||
local termfair =
|
||||
{
|
||||
name = "termfair",
|
||||
|
||||
-- You can set the number of columns and rows,
|
||||
-- -- otherwise they are read from awful.tag
|
||||
nmaster = 0, -- columns
|
||||
ncol = 0 -- rows
|
||||
}
|
||||
|
||||
function termfair.arrange(p)
|
||||
-- Layout with fixed number of vertical columns (read from nmaster).
|
||||
-- New windows align from left to right. When a row is full, a now
|
||||
-- one above it is created. Like this:
|
||||
|
||||
-- (1) (2) (3)
|
||||
-- +---+---+---+ +---+---+---+ +---+---+---+
|
||||
-- | | | | | | | | | | | |
|
||||
-- | 1 | | | -> | 2 | 1 | | -> | 3 | 2 | 1 | ->
|
||||
-- | | | | | | | | | | | |
|
||||
-- +---+---+---+ +---+---+---+ +---+---+---+
|
||||
|
||||
-- (4) (5) (6)
|
||||
-- +---+---+---+ +---+---+---+ +---+---+---+
|
||||
-- | 4 | | | | 5 | 4 | | | 6 | 5 | 4 |
|
||||
-- +---+---+---+ -> +---+---+---+ -> +---+---+---+
|
||||
-- | 3 | 2 | 1 | | 3 | 2 | 1 | | 3 | 2 | 1 |
|
||||
-- +---+---+---+ +---+---+---+ +---+---+---+
|
||||
|
||||
-- A useless gap (like the dwm patch) can be defined with
|
||||
-- beautiful.useless_gap_width.
|
||||
local useless_gap = tonumber(beautiful.useless_gap_width)
|
||||
if useless_gap == nil
|
||||
then
|
||||
useless_gap = 0
|
||||
end
|
||||
|
||||
-- Screen.
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
|
||||
-- How many vertical columns?
|
||||
local t = tag.selected(p.screen)
|
||||
local num_x
|
||||
if termfair.nmaster ~= 0
|
||||
then
|
||||
num_x = termfair.nmaster
|
||||
else
|
||||
num_x = tag.getnmaster(t)
|
||||
end
|
||||
|
||||
-- Do at least "desired_y" rows.
|
||||
local desired_y
|
||||
if termfair.ncol ~= 0
|
||||
then
|
||||
desired_y = termfair.ncol
|
||||
else
|
||||
desired_y = tag.getncol(t)
|
||||
end
|
||||
|
||||
if #cls > 0
|
||||
then
|
||||
local num_y = math.max(math.ceil(#cls / num_x), desired_y)
|
||||
local cur_num_x = num_x
|
||||
local at_x = 0
|
||||
local at_y = 0
|
||||
local remaining_clients = #cls
|
||||
local width = math.floor(wa.width / num_x)
|
||||
local height = math.floor(wa.height / num_y)
|
||||
|
||||
-- We start the first row. Left-align by limiting the number of
|
||||
-- available slots.
|
||||
if remaining_clients < num_x
|
||||
then
|
||||
cur_num_x = remaining_clients
|
||||
end
|
||||
|
||||
-- Iterate in reversed order.
|
||||
for i = #cls,1,-1
|
||||
do
|
||||
-- Get x and y position.
|
||||
local c = cls[i]
|
||||
local this_x = cur_num_x - at_x - 1
|
||||
local this_y = num_y - at_y - 1
|
||||
|
||||
-- Calc geometry.
|
||||
local g = {}
|
||||
if this_x == (num_x - 1)
|
||||
then
|
||||
g.width = wa.width - (num_x - 1) * width
|
||||
else
|
||||
g.width = width
|
||||
end
|
||||
if this_y == (num_y - 1)
|
||||
then
|
||||
g.height = wa.height - (num_y - 1) * height
|
||||
else
|
||||
g.height = height
|
||||
end
|
||||
g.x = wa.x + this_x * width
|
||||
g.y = wa.y + this_y * height
|
||||
if useless_gap > 0
|
||||
then
|
||||
-- Top and left clients are shrinked by two steps and
|
||||
-- get moved away from the border. Other clients just
|
||||
-- get shrinked in one direction.
|
||||
if this_x == 0
|
||||
then
|
||||
g.width = g.width - 2 * useless_gap
|
||||
g.x = g.x + useless_gap
|
||||
else
|
||||
g.width = g.width - useless_gap
|
||||
end
|
||||
|
||||
if this_y == 0
|
||||
then
|
||||
g.height = g.height - 2 * useless_gap
|
||||
g.y = g.y + useless_gap
|
||||
else
|
||||
g.height = g.height - useless_gap
|
||||
end
|
||||
end
|
||||
c:geometry(g)
|
||||
remaining_clients = remaining_clients - 1
|
||||
|
||||
-- Next grid position.
|
||||
at_x = at_x + 1
|
||||
if at_x == num_x
|
||||
then
|
||||
-- Row full, create a new one above it.
|
||||
at_x = 0
|
||||
at_y = at_y + 1
|
||||
|
||||
-- We start a new row. Left-align.
|
||||
if remaining_clients < num_x
|
||||
then
|
||||
cur_num_x = remaining_clients
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return termfair
|
|
@ -0,0 +1,122 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2012, Josh Komoroske
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local beautiful = require("beautiful")
|
||||
local ipairs = ipairs
|
||||
local math = { ceil = math.ceil, sqrt = math.sqrt }
|
||||
local tonumber = tonumber
|
||||
|
||||
local uselessfair = {}
|
||||
|
||||
local function fair(p, orientation)
|
||||
-- A useless gap (like the dwm patch) can be defined with
|
||||
-- beautiful.useless_gap_width.
|
||||
local useless_gap = tonumber(beautiful.useless_gap_width)
|
||||
if useless_gap == nil
|
||||
then
|
||||
useless_gap = 0
|
||||
end
|
||||
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
|
||||
if #cls > 0 then
|
||||
local cells = math.ceil(math.sqrt(#cls))
|
||||
local strips = math.ceil(#cls / cells)
|
||||
|
||||
local cell = 0
|
||||
local strip = 0
|
||||
for k, c in ipairs(cls) do
|
||||
local g = {}
|
||||
-- Save actual grid index for use in the useless_gap
|
||||
-- routine.
|
||||
local this_x = 0
|
||||
local this_y = 0
|
||||
if ( orientation == "east" and #cls > 2 )
|
||||
or ( orientation == "south" and #cls <= 2 ) then
|
||||
if #cls < (strips * cells) and strip == strips - 1 then
|
||||
g.width = wa.width / (cells - ((strips * cells) - #cls))
|
||||
else
|
||||
g.width = wa.width / cells
|
||||
end
|
||||
g.height = wa.height / strips
|
||||
|
||||
this_x = cell
|
||||
this_y = strip
|
||||
|
||||
g.x = wa.x + cell * g.width
|
||||
g.y = wa.y + strip * g.height
|
||||
|
||||
else
|
||||
if #cls < (strips * cells) and strip == strips - 1 then
|
||||
g.height = wa.height / (cells - ((strips * cells) - #cls))
|
||||
else
|
||||
g.height = wa.height / cells
|
||||
end
|
||||
g.width = wa.width / strips
|
||||
|
||||
this_x = strip
|
||||
this_y = cell
|
||||
|
||||
g.x = wa.x + strip * g.width
|
||||
g.y = wa.y + cell * g.height
|
||||
end
|
||||
|
||||
-- Useless gap.
|
||||
if useless_gap > 0
|
||||
then
|
||||
-- Top and left clients are shrinked by two steps and
|
||||
-- get moved away from the border. Other clients just
|
||||
-- get shrinked in one direction.
|
||||
if this_x == 0
|
||||
then
|
||||
g.width = g.width - 2 * useless_gap
|
||||
g.x = g.x + useless_gap
|
||||
else
|
||||
g.width = g.width - useless_gap
|
||||
end
|
||||
|
||||
if this_y == 0
|
||||
then
|
||||
g.height = g.height - 2 * useless_gap
|
||||
g.y = g.y + useless_gap
|
||||
else
|
||||
g.height = g.height - useless_gap
|
||||
end
|
||||
end
|
||||
-- End of useless gap.
|
||||
|
||||
c:geometry(g)
|
||||
|
||||
cell = cell + 1
|
||||
if cell == cells then
|
||||
cell = 0
|
||||
strip = strip + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Horizontal fair layout.
|
||||
-- @param screen The screen to arrange.
|
||||
uselessfair.horizontal = {}
|
||||
uselessfair.horizontal.name = "uselessfairh"
|
||||
function uselessfair.horizontal.arrange(p)
|
||||
return fair(p, "east")
|
||||
end
|
||||
|
||||
-- Vertical fair layout.
|
||||
-- @param screen The screen to arrange.
|
||||
uselessfair.name = "uselessfair"
|
||||
function uselessfair.arrange(p)
|
||||
return fair(p, "south")
|
||||
end
|
||||
|
||||
return uselessfair
|
|
@ -0,0 +1,112 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2009 Uli Schlachter
|
||||
* (c) 2008 Julien Danjolu
|
||||
|
||||
--]]
|
||||
|
||||
local beautiful = require("beautiful")
|
||||
local ipairs = ipairs
|
||||
local tonumber = tonumber
|
||||
|
||||
local uselesspiral = {}
|
||||
|
||||
local function spiral(p, spiral)
|
||||
-- A useless gap (like the dwm patch) can be defined with
|
||||
-- beautiful.useless_gap_width.
|
||||
local useless_gap = tonumber(beautiful.useless_gap_width)
|
||||
if useless_gap == nil
|
||||
then
|
||||
useless_gap = 0
|
||||
end
|
||||
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
local n = #cls
|
||||
|
||||
local static_wa = wa
|
||||
|
||||
for k, c in ipairs(cls) do
|
||||
if k < n then
|
||||
if k % 2 == 0 then
|
||||
wa.height = wa.height / 2
|
||||
else
|
||||
wa.width = wa.width / 2
|
||||
end
|
||||
end
|
||||
|
||||
if k % 4 == 0 and spiral then
|
||||
wa.x = wa.x - wa.width
|
||||
elseif k % 2 == 0 or
|
||||
(k % 4 == 3 and k < n and spiral) then
|
||||
wa.x = wa.x + wa.width
|
||||
end
|
||||
|
||||
if k % 4 == 1 and k ~= 1 and spiral then
|
||||
wa.y = wa.y - wa.height
|
||||
elseif k % 2 == 1 and k ~= 1 or
|
||||
(k % 4 == 0 and k < n and spiral) then
|
||||
wa.y = wa.y + wa.height
|
||||
end
|
||||
|
||||
local wa2 = {}
|
||||
wa2.x = wa.x
|
||||
wa2.y = wa.y
|
||||
wa2.height = wa.height
|
||||
wa2.width = wa.width
|
||||
|
||||
-- Useless gap.
|
||||
if useless_gap > 0
|
||||
then
|
||||
-- Top and left clients are shrinked by two steps and
|
||||
-- get moved away from the border. Other clients just
|
||||
-- get shrinked in one direction.
|
||||
|
||||
top = false
|
||||
left = false
|
||||
|
||||
if wa2.y == static_wa.y then
|
||||
top = true
|
||||
end
|
||||
|
||||
if wa2.x == static_wa.x then
|
||||
left = true
|
||||
end
|
||||
|
||||
if top then
|
||||
wa2.height = wa2.height - 2 * useless_gap
|
||||
wa2.y = wa2.y + useless_gap
|
||||
else
|
||||
wa2.height = wa2.height - useless_gap
|
||||
end
|
||||
|
||||
if left then
|
||||
wa2.width = wa2.width - 2 * useless_gap
|
||||
wa2.x = wa2.x + useless_gap
|
||||
else
|
||||
wa2.width = wa2.width - useless_gap
|
||||
end
|
||||
end
|
||||
-- End of useless gap.
|
||||
|
||||
c:geometry(wa2)
|
||||
end
|
||||
end
|
||||
|
||||
--- Dwindle layout
|
||||
uselesspiral.dwindle = {}
|
||||
uselesspiral.dwindle.name = "uselessdwindle"
|
||||
function uselesspiral.dwindle.arrange(p)
|
||||
return spiral(p, false)
|
||||
end
|
||||
|
||||
--- Spiral layout
|
||||
uselesspiral.name = "uselesspiral"
|
||||
function uselesspiral.arrange(p)
|
||||
return spiral(p, true)
|
||||
end
|
||||
|
||||
return uselesspiral
|
|
@ -0,0 +1,232 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2009 Donald Ephraim Curtis
|
||||
* (c) 2008 Julien Danjolu
|
||||
|
||||
--]]
|
||||
|
||||
local tag = require("awful.tag")
|
||||
local beautiful = require("beautiful")
|
||||
local ipairs = ipairs
|
||||
local math = { floor = math.floor,
|
||||
max = math.max,
|
||||
min = math.min }
|
||||
local tonumber = tonumber
|
||||
|
||||
local uselesstile = {}
|
||||
|
||||
local function tile_group(cls, wa, orientation, fact, group)
|
||||
-- A useless gap (like the dwm patch) can be defined with
|
||||
-- beautiful.useless_gap_width .
|
||||
local useless_gap = tonumber(beautiful.useless_gap_width)
|
||||
if useless_gap == nil
|
||||
then
|
||||
useless_gap = 0
|
||||
end
|
||||
|
||||
-- get our orientation right
|
||||
local height = "height"
|
||||
local width = "width"
|
||||
local x = "x"
|
||||
local y = "y"
|
||||
if orientation == "top" or orientation == "bottom" then
|
||||
height = "width"
|
||||
width = "height"
|
||||
x = "y"
|
||||
y = "x"
|
||||
end
|
||||
|
||||
-- make this more generic (not just width)
|
||||
available = wa[width] - (group.coord - wa[x])
|
||||
|
||||
-- find our total values
|
||||
local total_fact = 0
|
||||
local min_fact = 1
|
||||
local size = group.size
|
||||
for c = group.first,group.last do
|
||||
-- determine the width/height based on the size_hint
|
||||
local i = c - group.first +1
|
||||
local size_hints = cls[c].size_hints
|
||||
local size_hint = size_hints["min_"..width] or size_hints["base_"..width] or 0
|
||||
size_hint = size_hint + cls[c].border_width*2
|
||||
size = math.max(size_hint, size)
|
||||
|
||||
-- calculate the height
|
||||
if not fact[i] then
|
||||
fact[i] = min_fact
|
||||
else
|
||||
min_fact = math.min(fact[i],min_fact)
|
||||
end
|
||||
total_fact = total_fact + fact[i]
|
||||
end
|
||||
size = math.min(size, available)
|
||||
|
||||
local coord = wa[y]
|
||||
local geom = {}
|
||||
local used_size = 0
|
||||
local unused = wa[height]
|
||||
local stat_coord = wa[x]
|
||||
--stat_coord = size
|
||||
for c = group.first,group.last do
|
||||
local i = c - group.first +1
|
||||
geom[width] = size
|
||||
geom[height] = math.floor(unused * fact[i] / total_fact)
|
||||
geom[x] = group.coord
|
||||
geom[y] = coord
|
||||
|
||||
coord = coord + geom[height]
|
||||
unused = unused - geom[height]
|
||||
total_fact = total_fact - fact[i]
|
||||
used_size = math.max(used_size, geom[width])
|
||||
|
||||
-- Useless gap
|
||||
if useless_gap > 0
|
||||
then
|
||||
-- Top and left clients are shrinked by two steps and
|
||||
-- get moved away from the border. Other clients just
|
||||
-- get shrinked in one direction.
|
||||
|
||||
top = false
|
||||
left = false
|
||||
|
||||
if geom[y] == wa[y] then
|
||||
top = true
|
||||
end
|
||||
|
||||
if geom[x] == 0 or geom[x] == wa[x] then
|
||||
left = true
|
||||
end
|
||||
|
||||
if top then
|
||||
geom[height] = geom[height] - 2 * useless_gap
|
||||
geom[y] = geom[y] + useless_gap
|
||||
else
|
||||
geom[height] = geom[height] - useless_gap
|
||||
end
|
||||
|
||||
if left then
|
||||
geom[width] = geom[width] - 2 * useless_gap
|
||||
geom[x] = geom[x] + useless_gap
|
||||
else
|
||||
geom[width] = geom[width] - useless_gap
|
||||
end
|
||||
end
|
||||
-- End of useless gap.
|
||||
|
||||
geom = cls[c]:geometry(geom)
|
||||
end
|
||||
|
||||
return used_size
|
||||
end
|
||||
|
||||
local function tile(param, orientation)
|
||||
local t = tag.selected(param.screen)
|
||||
orientation = orientation or "right"
|
||||
|
||||
-- this handles are different orientations
|
||||
local height = "height"
|
||||
local width = "width"
|
||||
local x = "x"
|
||||
local y = "y"
|
||||
if orientation == "top" or orientation == "bottom" then
|
||||
height = "width"
|
||||
width = "height"
|
||||
x = "y"
|
||||
y = "x"
|
||||
end
|
||||
|
||||
local cls = param.clients
|
||||
local nmaster = math.min(tag.getnmaster(t), #cls)
|
||||
local nother = math.max(#cls - nmaster,0)
|
||||
|
||||
local mwfact = tag.getmwfact(t)
|
||||
local wa = param.workarea
|
||||
local ncol = tag.getncol(t)
|
||||
|
||||
local data = tag.getdata(t).windowfact
|
||||
|
||||
if not data then
|
||||
data = {}
|
||||
tag.getdata(t).windowfact = data
|
||||
end
|
||||
|
||||
local coord = wa[x]
|
||||
local place_master = true
|
||||
if orientation == "left" or orientation == "top" then
|
||||
-- if we are on the left or top we need to render the other windows first
|
||||
place_master = false
|
||||
end
|
||||
|
||||
-- this was easier than writing functions because there is a lot of data we need
|
||||
for d = 1,2 do
|
||||
if place_master and nmaster > 0 then
|
||||
local size = wa[width]
|
||||
if nother > 0 then
|
||||
size = math.min(wa[width] * mwfact, wa[width] - (coord - wa[x]))
|
||||
end
|
||||
if not data[0] then
|
||||
data[0] = {}
|
||||
end
|
||||
coord = coord + tile_group(cls, wa, orientation, data[0], {first=1, last=nmaster, coord = coord, size = size})
|
||||
end
|
||||
|
||||
if not place_master and nother > 0 then
|
||||
local last = nmaster
|
||||
|
||||
-- we have to modify the work area size to consider left and top views
|
||||
local wasize = wa[width]
|
||||
if nmaster > 0 and (orientation == "left" or orientation == "top") then
|
||||
wasize = wa[width] - wa[width]*mwfact
|
||||
end
|
||||
for i = 1,ncol do
|
||||
-- Try to get equal width among remaining columns
|
||||
local size = math.min( (wasize - (coord - wa[x])) / (ncol - i + 1) )
|
||||
local first = last + 1
|
||||
last = last + math.floor((#cls - last)/(ncol - i + 1))
|
||||
-- tile the column and update our current x coordinate
|
||||
if not data[i] then
|
||||
data[i] = {}
|
||||
end
|
||||
coord = coord + tile_group(cls, wa, orientation, data[i], { first = first, last = last, coord = coord, size = size })
|
||||
end
|
||||
end
|
||||
place_master = not place_master
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
uselesstile.right = {}
|
||||
uselesstile.right.name = "uselesstile"
|
||||
uselesstile.right.arrange = tile
|
||||
|
||||
--- The main tile algo, on left.
|
||||
-- @param screen The screen number to tile.
|
||||
uselesstile.left = {}
|
||||
uselesstile.left.name = "uselesstileleft"
|
||||
function uselesstile.left.arrange(p)
|
||||
return tile(p, "left")
|
||||
end
|
||||
|
||||
--- The main tile algo, on bottom.
|
||||
-- @param screen The screen number to tile.
|
||||
uselesstile.bottom = {}
|
||||
uselesstile.bottom.name = "uselesstilebottom"
|
||||
function uselesstile.bottom.arrange(p)
|
||||
return tile(p, "bottom")
|
||||
end
|
||||
|
||||
--- The main tile algo, on top.
|
||||
-- @param screen The screen number to tile.
|
||||
uselesstile.top = {}
|
||||
uselesstile.top.name = "uselesstiletop"
|
||||
function uselesstile.top.arrange(p)
|
||||
return tile(p, "top")
|
||||
end
|
||||
|
||||
uselesstile.arrange = uselesstile.right.arrange
|
||||
uselesstile.name = uselesstile.right.name
|
||||
|
||||
return uselesstile
|
|
@ -0,0 +1,104 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Simple email checker
|
||||
#
|
||||
# Wrote by copycat-killer on a rainy day of august 2013
|
||||
# to be used in Lain.
|
||||
#
|
||||
# https://github.com/copycat-killer/lain
|
||||
|
||||
import sys, getopt, locale, imaplib
|
||||
|
||||
def main(argv):
|
||||
usage = "usage: checkmail -s <imapserver> -u <usermail> -p <password> [--port <port>] [--encoding <encoding>] [--cut]"
|
||||
server = ""
|
||||
user = ""
|
||||
password = ""
|
||||
port = 993
|
||||
cut = False
|
||||
encoding = locale.getdefaultlocale()[1]
|
||||
output = ""
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, "hs:u:p:", ["port=", "encoding=", "cut"])
|
||||
except getopt.GetoptError:
|
||||
print(usage)
|
||||
sys.exit(2)
|
||||
|
||||
if len(argv) == 0:
|
||||
print(usage)
|
||||
sys.exit()
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt == "-h":
|
||||
print(usage)
|
||||
sys.exit()
|
||||
elif opt == "-s":
|
||||
server = arg
|
||||
elif opt == "-u":
|
||||
user = arg
|
||||
elif opt == "-p":
|
||||
password = arg
|
||||
elif opt == "--port":
|
||||
port = int(arg)
|
||||
elif opt == "--cut":
|
||||
cut = True
|
||||
elif opt == "--encoding":
|
||||
encoding = arg
|
||||
|
||||
try:
|
||||
mail = imaplib.IMAP4_SSL(server, port)
|
||||
mail.login(user, password)
|
||||
except imaplib.IMAP4.error:
|
||||
print("CheckMailError: invalid credentials")
|
||||
sys.exit(2)
|
||||
|
||||
status, counts = mail.status("Inbox","(MESSAGES UNSEEN)")
|
||||
|
||||
unread = int(counts[0].split()[4][:-1])
|
||||
|
||||
if status == "OK" and unread:
|
||||
mail.select("Inbox", readonly = 1)
|
||||
ret, messages = mail.uid("search", None, "(UNSEEN)")
|
||||
|
||||
if ret == "OK":
|
||||
latest_email_uid = messages[0].split()[-1]
|
||||
|
||||
ret_header, new_mail_header = mail.uid("fetch", latest_email_uid,
|
||||
"(BODY.PEEK[HEADER.FIELDS (SUBJECT FROM)])")
|
||||
ret_text, new_mail_text = mail.uid("fetch", latest_email_uid, "(BODY[TEXT])")
|
||||
|
||||
if ret_header == "OK" and ret_text == "OK":
|
||||
try: # not all the servers like this, that's why we try
|
||||
mail.store(latest_email_uid, "-FLAGS", "\\Seen")
|
||||
except imaplib.IMAP4.error:
|
||||
# this simply means the server refused to
|
||||
# toggle Seen flag from mail
|
||||
print("[+Seen]\n")
|
||||
|
||||
nm_header = new_mail_header[0][1].decode(encoding, "replace").strip()
|
||||
nm_text = new_mail_text[0][1].decode(encoding, "replace").strip()
|
||||
|
||||
if unread == 1:
|
||||
print(user, "has 1 new message\n")
|
||||
else:
|
||||
print(user, "has", unread, "new messages\n")
|
||||
nm_header.replace("From:", "Latest from:", 1)
|
||||
|
||||
print(nm_header, "\n")
|
||||
|
||||
if cut:
|
||||
if len(nm_text) <= 100:
|
||||
print(nm_text)
|
||||
else:
|
||||
print(nm_text[0:100])
|
||||
print("[...]")
|
||||
else:
|
||||
print(nm_text)
|
||||
else:
|
||||
print("No new messages")
|
||||
|
||||
mail.logout()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
|
@ -0,0 +1,385 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Adapted from Eridan's "fs" (cleanup, enhancements and switch to bash/Linux)
|
||||
# JM, 10/12/2004
|
||||
#
|
||||
# Integrated into Lain in september 2013
|
||||
# https://github.com/copycat-killer/lain
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Decoding options
|
||||
# -------------------------------------------------------------------------
|
||||
USAGE="Usage: $0 [-h(elp)] | [-n(arrow mode)] | [-w(eb output)]"
|
||||
|
||||
NARROW_MODE=0
|
||||
WEB_OUTPUT=0
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
"-h" )
|
||||
echo $USAGE
|
||||
exit
|
||||
;;
|
||||
"-d" )
|
||||
DEBUG=1
|
||||
;;
|
||||
"-n" )
|
||||
NARROW_MODE=1
|
||||
;;
|
||||
"-w" )
|
||||
WEB_OUTPUT=1
|
||||
;;
|
||||
* )
|
||||
echo $USAGE
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Preparations
|
||||
# -------------------------------------------------------------------------
|
||||
SYSTEM=`uname -s`
|
||||
PATTERN="/"
|
||||
|
||||
case "$SYSTEM" in
|
||||
"Linux" )
|
||||
DF_COMMAND="/usr/bin/env df -k"
|
||||
SORT_COMMAND="/usr/bin/env sort -k6"
|
||||
AWK_COMMAND="/usr/bin/env awk"
|
||||
;;
|
||||
* )
|
||||
DF_COMMAND="/bin/df -k"
|
||||
SORT_COMMAND="/usr/bin/sort -k6"
|
||||
AWK_COMMAND="/usr/bin/env gawk"
|
||||
;;
|
||||
esac
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Grabbing "df" result
|
||||
# -------------------------------------------------------------------------
|
||||
DF_RESULT=`$DF_COMMAND`
|
||||
if [ ! -z $DEBUG ]; then
|
||||
echo "--> DF_RESULT:"
|
||||
echo "$DF_RESULT"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Preprocessing "df" result, to join split logical lines
|
||||
# -------------------------------------------------------------------------
|
||||
PREPROCESSING_RESULT=` \
|
||||
echo "$DF_RESULT" | $AWK_COMMAND -v PATTERN=$PATTERN \
|
||||
'
|
||||
NF == 1 {
|
||||
printf ("%s", $0)
|
||||
}
|
||||
|
||||
NF == 5 {
|
||||
printf ("%s\n", $0)
|
||||
}
|
||||
|
||||
NF > 6 {
|
||||
}
|
||||
|
||||
NF == 6 {
|
||||
printf ("%s\n", $0)
|
||||
}'
|
||||
`
|
||||
if [ ! -z $DEBUG ]; then
|
||||
echo "--> PREPROCESSING_RESULT:"
|
||||
echo "$PREPROCESSING_RESULT"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
SORTED_FILE_SYSTEMS_INFO=`echo "$PREPROCESSING_RESULT" | $SORT_COMMAND`
|
||||
|
||||
if [ ! -z $DEBUG ]; then
|
||||
echo "--> SORTED_FILE_SYSTEMS_INFO:"
|
||||
echo "$SORTED_FILE_SYSTEMS_INFO"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Computing mount point max length
|
||||
# -------------------------------------------------------------------------
|
||||
MOUNT_POINT_MAX_LENGTH=` \
|
||||
echo $SORTED_FILE_SYSTEMS_INFO | $AWK_COMMAND -v PATTERN=$PATTERN \
|
||||
'
|
||||
BEGIN {
|
||||
mount_point_length_max = 15;
|
||||
}
|
||||
|
||||
END {
|
||||
printf ("%d", mount_point_length_max);
|
||||
}
|
||||
|
||||
$0 ~ PATTERN {
|
||||
# printf ("$6 = %s\n", $6);
|
||||
|
||||
mount_point = $6;
|
||||
# printf ("mount_point = %s\n", mount_point);
|
||||
|
||||
mount_point_length = length (mount_point);
|
||||
# printf ("mount_point_length = %d\n", mount_point_length);
|
||||
|
||||
if (mount_point_length > mount_point_length_max)
|
||||
mount_point_length_max = mount_point_length;
|
||||
}'
|
||||
`
|
||||
if [ ! -z $DEBUG ]; then
|
||||
echo "MOUNT_POINT_MAX_LENGTH: $MOUNT_POINT_MAX_LENGTH"
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Computing mount point data max size
|
||||
# -------------------------------------------------------------------------
|
||||
MOUNT_POINT_MAX_SIZE=` \
|
||||
echo "$SORTED_FILE_SYSTEMS_INFO" | $AWK_COMMAND -v PATTERN=$PATTERN \
|
||||
'
|
||||
BEGIN {
|
||||
mount_point_size_max = 0;
|
||||
}
|
||||
|
||||
END {
|
||||
printf ("%d", mount_point_size_max);
|
||||
}
|
||||
|
||||
$0 ~ PATTERN {
|
||||
# df -k shows k_bytes!
|
||||
# printf ("$2 = %s\n", $2);
|
||||
|
||||
mount_point_size = $2 * 1024;
|
||||
# printf ("mount_point_size = %d\n", mount_point_size);
|
||||
|
||||
if (mount_point_size > mount_point_size_max)
|
||||
mount_point_size_max = mount_point_size;
|
||||
}'
|
||||
`
|
||||
if [ ! -z $DEBUG ]; then
|
||||
echo "MOUNT_POINT_MAX_SIZE: $MOUNT_POINT_MAX_SIZE"
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Let's go!
|
||||
# -------------------------------------------------------------------------
|
||||
echo "$SORTED_FILE_SYSTEMS_INFO" | $AWK_COMMAND -v DEBUG=$DEBUG -v PATTERN=$PATTERN -v NARROW_MODE=$NARROW_MODE -v LEFT_COLUMN=$MOUNT_POINT_MAX_LENGTH -v MAX_SIZE=$MOUNT_POINT_MAX_SIZE -v SCALE=$SCALE -v WEB_OUTPUT=$WEB_OUTPUT \
|
||||
'
|
||||
# {printf ("$0 = %s\n", $0);}
|
||||
# {printf ("$1 = %s\n", $1);}
|
||||
# {printf ("PATTERN = %s\n", PATTERN);}
|
||||
# {printf ("LEFT_COLUMN = %s\n", LEFT_COLUMN);}
|
||||
|
||||
BEGIN {
|
||||
k_bytes = 1024.0;
|
||||
m_bytes = 1024.0 * k_bytes;
|
||||
g_bytes = 1024.0 * m_bytes;
|
||||
t_bytes = 1024.0 * g_bytes;
|
||||
|
||||
if (WEB_OUTPUT)
|
||||
{
|
||||
all_stars = "**************************************************";
|
||||
current_date = strftime ("%d-%m-%Y @ %H:%M:%S", localtime (systime ()));
|
||||
free_threshold = 10; # %
|
||||
|
||||
printf ("<!-- DEBUT CONTENU -->\n");
|
||||
|
||||
printf ( \
|
||||
"<A NAME=\"top\"></A>\n" \
|
||||
"<P ALIGN=CENTER><SPAN CLASS=\"titleblue\">%s</SPAN><SPAN CLASS=\"textbold\"> -- STATUS OF <SPAN CLASS=\"titlered\">ALCOR</SPAN> FILE SYSTEMS</SPAN></P><BR>\n",
|
||||
current_date )
|
||||
|
||||
printf ("<TABLE WIDTH=\"100%%\" BORDER=1>\n");
|
||||
|
||||
printf ( \
|
||||
"<TR>\n" \
|
||||
"<TD ALIGN=LEFT><STRONG>Mount point</STRONG></TD>\n" \
|
||||
"<TD ALIGN=CENTER><STRONG>%% Usato (<SPAN CLASS=\"titleblue\">*</SPAN>)" \
|
||||
" - %% Free (<SPAN CLASS=\"titlegreen\">*</SPAN>)</STRONG></TD>\n" \
|
||||
"<TD ALIGN=CENTER><STRONG>%% Usato</STRONG></TD>\n" \
|
||||
"<TD ALIGN=CENTER><STRONG>Spazio libero</STRONG></TD>\n" \
|
||||
"<TD ALIGN=CENTER><STRONG>Spazio totale</STRONG></TD>\n" \
|
||||
"</TR>\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
narrow_margin = " ";
|
||||
# printf ("%-*s", LEFT_COLUMN + 2, "Mount point");
|
||||
if (NARROW_MODE)
|
||||
printf ("\n%s", narrow_margin);
|
||||
else
|
||||
printf ("%-*s", LEFT_COLUMN + 2, "");
|
||||
print " Used Free Total ";
|
||||
if (! NARROW_MODE)
|
||||
print "";
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
if (WEB_OUTPUT)
|
||||
{
|
||||
printf ("</TABLE>\n");
|
||||
|
||||
printf ("<!-- FIN CONTENU -->\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NARROW_MODE)
|
||||
printf ("%s", narrow_margin);
|
||||
else
|
||||
printf ("%-*s", LEFT_COLUMN + 2, "");
|
||||
print "|----|----|----|----|----|----|----|----|----|----|"
|
||||
if (NARROW_MODE)
|
||||
printf ("\n%s", narrow_margin);
|
||||
else
|
||||
printf ("%-*s", LEFT_COLUMN + 2, "");
|
||||
print "0 10 20 30 40 50 60 70 80 90 100";
|
||||
print "";
|
||||
}
|
||||
}
|
||||
|
||||
$0 ~ PATTERN {
|
||||
|
||||
if (index ($0, "members") == 0 && index ($0, "Download") == 0 && index ($0, "admin") == 0)
|
||||
{
|
||||
# df -k shows k_bytes!
|
||||
|
||||
total_size = $2 * k_bytes;
|
||||
free_size = $4 * k_bytes;
|
||||
percentage_occupied = substr($5, 0, 3);
|
||||
mount_point = $6;
|
||||
|
||||
percentage_free = int (100 - percentage_occupied);
|
||||
|
||||
# reduction_factor: 2
|
||||
stars_number = int (percentage_occupied / 2);
|
||||
|
||||
if (WEB_OUTPUT)
|
||||
{
|
||||
posGroup = index (mount_point, "scratch");
|
||||
if (posGroup == 0)
|
||||
posGroup = index (mount_point, "u1");
|
||||
if (posGroup == 0)
|
||||
posGroup = index (mount_point, "u2");
|
||||
if (posGroup == 0)
|
||||
posGroup = index (mount_point, "u4");
|
||||
if (posGroup == 0)
|
||||
posGroup = index (mount_point, "u5");
|
||||
|
||||
printf ("<TR>\n");
|
||||
|
||||
if (posGroup > 0 || percentage_free < free_threshold)
|
||||
{
|
||||
if (percentage_free < free_threshold)
|
||||
{
|
||||
class = "titlered";
|
||||
if (posGroup == 0)
|
||||
posGroup = 1; # to display the whole mount_point in this color anyway
|
||||
}
|
||||
else if ((index (mount_point, "scratch") != 0) || (index (mount_point, "u1") != 0) || (index (mount_point, "u2") != 0))
|
||||
{
|
||||
class = "titleorange";
|
||||
posGroup = 1; # to display the whole mount_point in this color
|
||||
}
|
||||
else if ((index (mount_point, "u4") != 0) || (index (mount_point, "u5") != 0))
|
||||
{
|
||||
class = "titlebrown";
|
||||
posGroup = 1; # to display the whole mount_point in this color
|
||||
}
|
||||
|
||||
printf ( \
|
||||
"<TD ALIGN=LEFT>%s<SPAN CLASS=\"%s\">%s</SPAN></TD>\n",
|
||||
substr (mount_point, 1, posGroup - 1),
|
||||
class,
|
||||
substr (mount_point, posGroup) );
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("<TD ALIGN=LEFT>%s</TD>\n", mount_point);
|
||||
}
|
||||
|
||||
printf ( \
|
||||
"<TD ALIGN=CENTER><SPAN CLASS=\"titleblue\">%s</SPAN><SPAN CLASS=\"titlegreen\">%s</SPAN></TD>\n",
|
||||
substr (all_stars, 1, stars_number), substr (all_stars, stars_number + 1, 49) );
|
||||
|
||||
if (percentage_free < free_threshold)
|
||||
{
|
||||
color_beginning = "<SPAN CLASS=\"titlered\">";
|
||||
color_end = "</SPAN>"
|
||||
}
|
||||
else
|
||||
{
|
||||
color_beginning = "";
|
||||
color_end = ""
|
||||
}
|
||||
|
||||
if (total_size > 1 * t_bytes)
|
||||
printf ( \
|
||||
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Tb</TD><TD ALIGN=RIGHT>%5.1f Tb</TD>\n", \
|
||||
color_beginning, percentage_occupied, color_end, free_size / t_bytes, total_size / t_bytes \
|
||||
);
|
||||
else if (total_size > 1 * g_bytes)
|
||||
printf ( \
|
||||
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Gb</TD><TD ALIGN=RIGHT>%5.1f Gb</TD>\n", \
|
||||
color_beginning, percentage_occupied, color_end, free_size / g_bytes, total_size / g_bytes \
|
||||
);
|
||||
else if (total_size > 1 * m_byptes)
|
||||
printf ( \
|
||||
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Mb</TD><TD ALIGN=RIGHT>%5.1f Mb</TD>\n", \
|
||||
color_beginning, percentage_occupied, color_end, free_size / m_bytes, total_size / m_bytes \
|
||||
);
|
||||
else
|
||||
printf ( \
|
||||
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Kb</TD><TD ALIGN=RIGHT>%5.1f Kb</TD>\n", \
|
||||
color_beginning, percentage_occupied, color_end, free_size / k_bytes, total_size / k_bytes \
|
||||
);
|
||||
|
||||
printf ("</TR>\n");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
# printf ("percentage_occupied = %d\n", percentage_occupied);
|
||||
# printf ("percentage_free = %d\n", percentage_free);
|
||||
|
||||
printf ("%-*s", LEFT_COLUMN + 2, mount_point);
|
||||
if (NARROW_MODE)
|
||||
printf ("\n%s", narrow_margin);
|
||||
|
||||
# printf ("stars_number = %d\n", stars_number);
|
||||
|
||||
printf ("|");
|
||||
for (i = 1; i <= stars_number; i++)
|
||||
{
|
||||
printf ("%s", "*");
|
||||
}
|
||||
for (i = stars_number + 1; i <= 49; i++)
|
||||
{
|
||||
printf ("%s", "-");
|
||||
}
|
||||
|
||||
|
||||
if (total_size > 1 * t_bytes)
|
||||
printf ( \
|
||||
"| %3d%% %5.1f %5.1f Tb\n", \
|
||||
percentage_occupied, free_size / t_bytes, total_size / t_bytes \
|
||||
);
|
||||
else if (total_size > 1 * g_bytes)
|
||||
printf ( \
|
||||
"| %3d%% %5.1f %5.1f Gb\n", \
|
||||
percentage_occupied, free_size / g_bytes, total_size / g_bytes \
|
||||
);
|
||||
else if (total_size > 1 * m_byptes)
|
||||
printf ( \
|
||||
"| %3d%% %5.1f %5.1f Mb\n", \
|
||||
percentage_occupied, free_size / m_bytes, total_size / m_bytes \
|
||||
);
|
||||
else
|
||||
printf ( \
|
||||
"| %3d%% %5.1f %5.1f Kb\n", \
|
||||
percentage_occupied, free_size / k_bytes, total_size / k_bytes \
|
||||
);
|
||||
}
|
||||
} # if
|
||||
}'
|
|
@ -0,0 +1,64 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# A simple cover fetcher script for current playing song on mpd.
|
||||
#
|
||||
# Author : Wolfgang Mueller
|
||||
#
|
||||
# Adapted for Lain internal use.
|
||||
# https://github.com/copycat-killer/lain
|
||||
#
|
||||
# You can use, edit and redistribute this script in any way you like.
|
||||
#
|
||||
# Dependencies: imagemagick.
|
||||
#
|
||||
# Usage: mpdcover <music_directory> <song_file> <default_art>
|
||||
|
||||
# Configuration-------------------------------------------------------
|
||||
|
||||
# Music directory
|
||||
MUSIC_DIR=$1
|
||||
|
||||
# Song file
|
||||
file=$2
|
||||
|
||||
# The default cover to use (optional)
|
||||
DEFAULT_ART=$3
|
||||
|
||||
# Regex expression used for image search
|
||||
IMG_REG="(front|cover|art|Folder|folder)\.(jpg|jpeg|png|gif)$"
|
||||
|
||||
# Path of temporary resized cover
|
||||
TEMP_PATH="/tmp/mpdcover.png"
|
||||
|
||||
# Resize cover
|
||||
COVER_RESIZE="100x100"
|
||||
|
||||
# Thumbnail background (transparent)
|
||||
COVER_BACKGROUND="none"
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
# check if anything is playing at all
|
||||
[[ -z $file ]] && exit 1
|
||||
|
||||
# Art directory
|
||||
art="$MUSIC_DIR/${file%/*}"
|
||||
|
||||
# find every file that matches IMG_REG set the first matching file to be the
|
||||
# cover.
|
||||
cover="$(find "$art/" -maxdepth 1 -type f | egrep -i -m1 "$IMG_REG")"
|
||||
|
||||
# when no cover is found, use DEFAULT_ART as cover
|
||||
cover="${cover:=$DEFAULT_ART}"
|
||||
|
||||
# check if art is available
|
||||
if [[ -n $cover ]]; then
|
||||
if [[ -n $COVER_RESIZE ]]; then
|
||||
convert "$cover" -thumbnail $COVER_RESIZE -gravity center -background "$COVER_BACKGROUND" -extent $COVER_RESIZE "$TEMP_PATH"
|
||||
cover="$TEMP_PATH"
|
||||
fi
|
||||
else
|
||||
rm $TEMP_PATH
|
||||
fi
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,174 @@
|
|||
|
||||
--[[
|
||||
|
||||
Lain
|
||||
Layouts, widgets and utilities for Awesome WM
|
||||
|
||||
Utilities section
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local math = { sqrt = math.sqrt }
|
||||
local mouse = mouse
|
||||
local pairs = pairs
|
||||
local string = string
|
||||
local client = client
|
||||
local screen = screen
|
||||
local tonumber = tonumber
|
||||
|
||||
local wrequire = require("lain.helpers").wrequire
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Lain utilities submodule
|
||||
-- lain.util
|
||||
local util = { _NAME = "lain.util" }
|
||||
|
||||
-- Like awful.menu.clients, but only show clients of currently selected
|
||||
-- tags.
|
||||
function util.menu_clients_current_tags(menu, args)
|
||||
-- List of currently selected tags.
|
||||
local cls_tags = awful.tag.selectedlist(mouse.screen)
|
||||
|
||||
-- Final list of menu items.
|
||||
local cls_t = {}
|
||||
|
||||
if cls_tags == nil
|
||||
then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- For each selected tag get all clients of that tag and add them to
|
||||
-- the menu. A click on a menu item will raise that client.
|
||||
for i = 1,#cls_tags
|
||||
do
|
||||
local t = cls_tags[i]
|
||||
local cls = t:clients()
|
||||
|
||||
for k, c in pairs(cls)
|
||||
do
|
||||
cls_t[#cls_t + 1] = { awful.util.escape(c.name) or "",
|
||||
function ()
|
||||
c.minimized = false
|
||||
client.focus = c
|
||||
c:raise()
|
||||
end,
|
||||
c.icon }
|
||||
end
|
||||
end
|
||||
|
||||
-- No clients? Then quit.
|
||||
if #cls_t <= 0
|
||||
then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- menu may contain some predefined values, otherwise start with a
|
||||
-- fresh menu.
|
||||
if not menu
|
||||
then
|
||||
menu = {}
|
||||
end
|
||||
|
||||
-- Set the list of items and show the menu.
|
||||
menu.items = cls_t
|
||||
local m = awful.menu.new(menu)
|
||||
m:show(args)
|
||||
return m
|
||||
end
|
||||
|
||||
-- Magnify a client: Set it to "float" and resize it.
|
||||
function util.magnify_client(c)
|
||||
awful.client.floating.set(c, true)
|
||||
|
||||
local mg = screen[mouse.screen].geometry
|
||||
local tag = awful.tag.selected(mouse.screen)
|
||||
local mwfact = awful.tag.getmwfact(tag)
|
||||
local g = {}
|
||||
g.width = math.sqrt(mwfact) * mg.width
|
||||
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)
|
||||
end
|
||||
|
||||
-- Read the nice value of pid from /proc.
|
||||
local function get_nice_value(pid)
|
||||
local n = first_line('/proc/' .. pid .. '/stat')
|
||||
if n == nil
|
||||
then
|
||||
-- This should not happen. But I don't want to crash, either.
|
||||
return 0
|
||||
end
|
||||
|
||||
-- Remove pid and tcomm. This is necessary because tcomm may contain
|
||||
-- nasty stuff such as whitespace or additional parentheses...
|
||||
n = string.gsub(n, '.*%) ', '')
|
||||
|
||||
-- Field number 17 now is the nice value.
|
||||
fields = split(n, ' ')
|
||||
return tonumber(fields[17])
|
||||
end
|
||||
|
||||
-- To be used as a signal handler for "focus"
|
||||
-- This requires beautiful.border_focus{,_highprio,_lowprio}.
|
||||
function util.niceborder_focus(c)
|
||||
local n = get_nice_value(c.pid)
|
||||
if n == 0
|
||||
then
|
||||
c.border_color = beautiful.border_focus
|
||||
elseif n < 0
|
||||
then
|
||||
c.border_color = beautiful.border_focus_highprio
|
||||
else
|
||||
c.border_color = beautiful.border_focus_lowprio
|
||||
end
|
||||
end
|
||||
|
||||
-- To be used as a signal handler for "unfocus"
|
||||
-- This requires beautiful.border_normal{,_highprio,_lowprio}.
|
||||
function util.niceborder_unfocus(c)
|
||||
local n = get_nice_value(c.pid)
|
||||
if n == 0
|
||||
then
|
||||
c.border_color = beautiful.border_normal
|
||||
elseif n < 0
|
||||
then
|
||||
c.border_color = beautiful.border_normal_highprio
|
||||
else
|
||||
c.border_color = beautiful.border_normal_lowprio
|
||||
end
|
||||
end
|
||||
|
||||
-- Non-empty tag browsing
|
||||
-- direction in {-1, 1} <-> {previous, next} non-empty tag
|
||||
function util.tag_view_nonempty(direction, sc)
|
||||
local s = sc or mouse.screen or 1
|
||||
local scr = screen[s]
|
||||
|
||||
for i = 1, #tags[s] do
|
||||
awful.tag.viewidx(direction,s)
|
||||
if #awful.client.visible(s) > 0 then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Dynamically rename the current tag you have focused.
|
||||
function util.prompt_rename_tag(mypromptbox)
|
||||
local tag = awful.tag.selected(mouse.screen)
|
||||
awful.prompt.run({prompt="Rename tag: "}, mypromptbox[mouse.screen].widget,
|
||||
function(text)
|
||||
if text:len() > 0 then
|
||||
tag.name = text
|
||||
tag:emit_signal("property::name")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return setmetatable(util, { __index = wrequire })
|
|
@ -0,0 +1,102 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under MIT License
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2009, Uli Schlachter
|
||||
* (c) 2009, Majic
|
||||
|
||||
--]]
|
||||
|
||||
local beautiful = require("beautiful")
|
||||
local tostring = tostring
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Lain markup util submodule
|
||||
-- lain.util.markup
|
||||
local markup = {}
|
||||
|
||||
local fg = {}
|
||||
local bg = {}
|
||||
|
||||
--[[ clean this as soon as you document it
|
||||
|
||||
+-- markup
|
||||
|
|
||||
|`-- bold() Set bold.
|
||||
|`-- italic() Set italicized text.
|
||||
|`-- strike() Set strikethrough text.
|
||||
|`-- underline() Set underlined text.
|
||||
|`-- monospace() Set monospaced text.
|
||||
|`-- big() Set bigger text.
|
||||
|`-- small() Set smaller text.
|
||||
|`-- font() Set the font of the text.
|
||||
|
|
||||
|`--+ bg
|
||||
| |
|
||||
| |`-- color() Set background color.
|
||||
| |`-- focus() Set focus background color.
|
||||
| |`-- normal() Set normal background color.
|
||||
| `-- urgent() Set urgent background color.
|
||||
|
|
||||
|`--+ fg
|
||||
| |
|
||||
| |`-- color() Set foreground color.
|
||||
| |`-- focus() Set focus foreground color.
|
||||
| |`-- normal() Set normal foreground color.
|
||||
| `-- urgent() Set urgent foreground color.
|
||||
|
|
||||
|`-- focus() Set both foreground and background focus colors.
|
||||
|`-- normal() Set both foreground and background normal colors.
|
||||
`-- urgent() Set both foreground and background urgent colors.
|
||||
|
||||
]]
|
||||
|
||||
-- Convenience tags.
|
||||
function markup.bold(text) return '<b>' .. tostring(text) .. '</b>' end
|
||||
function markup.italic(text) return '<i>' .. tostring(text) .. '</i>' end
|
||||
function markup.strike(text) return '<s>' .. tostring(text) .. '</s>' end
|
||||
function markup.underline(text) return '<u>' .. tostring(text) .. '</u>' end
|
||||
function markup.monospace(text) return '<tt>' .. tostring(text) .. '</tt>' end
|
||||
function markup.big(text) return '<big>' .. tostring(text) .. '</big>' end
|
||||
function markup.small(text) return '<small>' .. tostring(text) .. '</small>' end
|
||||
|
||||
-- Set the font.
|
||||
function markup.font(font, text)
|
||||
return '<span font="' .. tostring(font) .. '">' .. tostring(text) ..'</span>'
|
||||
end
|
||||
|
||||
-- Set the foreground.
|
||||
function fg.color(color, text)
|
||||
return '<span foreground="' .. tostring(color) .. '">' .. tostring(text) .. '</span>'
|
||||
end
|
||||
|
||||
-- Set the background.
|
||||
function bg.color(color, text)
|
||||
return '<span background="' .. tostring(color) .. '">' .. tostring(text) .. '</span>'
|
||||
end
|
||||
|
||||
-- Context: focus
|
||||
function fg.focus(text) return fg.color(beautiful.fg_focus, text) end
|
||||
function bg.focus(text) return bg.color(beautiful.bg_focus, text) end
|
||||
function markup.focus(text) return bg.focus(fg.focus(text)) end
|
||||
|
||||
-- Context: normal
|
||||
function fg.normal(text) return fg.color(beautiful.fg_normal, text) end
|
||||
function bg.normal(text) return bg.color(beautiful.bg_normal, text) end
|
||||
function markup.normal(text) return bg.normal(fg.normal(text)) end
|
||||
|
||||
-- Context: urgent
|
||||
function fg.urgent(text) return fg.color(beautiful.fg_urgent, text) end
|
||||
function bg.urgent(text) return bg.color(beautiful.bg_urgent, text) end
|
||||
function markup.urgent(text) return bg.urgent(fg.urgent(text)) end
|
||||
|
||||
markup.fg = fg
|
||||
markup.bg = bg
|
||||
|
||||
-- link markup.{fg,bg}(...) calls to markup.{fg,bg}.color(...)
|
||||
setmetatable(markup.fg, { __call = function(_, ...) return markup.fg.color(...) end })
|
||||
setmetatable(markup.bg, { __call = function(_, ...) return markup.bg.color(...) end })
|
||||
|
||||
-- link markup(...) calls to markup.fg.color(...)
|
||||
return setmetatable(markup, { __call = function(_, ...) return markup.fg.color(...) end })
|
|
@ -0,0 +1,103 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
* (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local run_in_terminal = require("lain.helpers").run_in_terminal
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local io = io
|
||||
local string = { format = string.format,
|
||||
match = string.match }
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- ALSA volume infos
|
||||
-- nain.widgets.alsa
|
||||
local alsa = {
|
||||
volume = 0,
|
||||
mute = false,
|
||||
}
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local channel = args.channel or "Master"
|
||||
local step = args.step or "1%"
|
||||
local header = args.header or " Vol "
|
||||
local header_color = args.header_color or beautiful.fg_normal or "#FFFFFF"
|
||||
local color = args.color or beautiful.fg_focus or "#FFFFFF"
|
||||
|
||||
local myvolume = wibox.widget.textbox()
|
||||
local myvolumeupdate = function()
|
||||
local f = io.popen('amixer get ' .. channel)
|
||||
local mixer = f:read("*all")
|
||||
f:close()
|
||||
|
||||
local volume, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
|
||||
|
||||
if volume == nil
|
||||
then
|
||||
alsa.volume = 0
|
||||
else
|
||||
alsa.volume = volume
|
||||
end
|
||||
|
||||
if mute == nil or mute == 'on'
|
||||
then
|
||||
alsa.mute = true
|
||||
mute = ''
|
||||
else
|
||||
alsa.mute = false
|
||||
mute = 'M'
|
||||
end
|
||||
|
||||
local ret = markup(color, string.format("%d%s", volume, mute))
|
||||
myvolume:set_markup(markup(header_color, header) .. ret .. " ")
|
||||
end
|
||||
|
||||
local myvolumetimer = timer({ timeout = 5 })
|
||||
myvolumetimer:connect_signal("timeout", myvolumeupdate)
|
||||
myvolumetimer:start()
|
||||
myvolumetimer:emit_signal("timeout")
|
||||
|
||||
myvolume:buttons(awful.util.table.join(
|
||||
awful.button({}, 1,
|
||||
function()
|
||||
run_in_terminal('alsamixer')
|
||||
end),
|
||||
awful.button({}, 3,
|
||||
function()
|
||||
awful.util.spawn('amixer sset ' .. channel ' toggle')
|
||||
end),
|
||||
|
||||
awful.button({}, 4,
|
||||
function()
|
||||
awful.util.spawn('amixer sset ' .. channel .. ' ' .. step '+')
|
||||
myvolumeupdate()
|
||||
end),
|
||||
|
||||
awful.button({}, 5,
|
||||
function()
|
||||
awful.util.spawn('amixer sset ' .. channel .. ' ' .. step '-')
|
||||
myvolumeupdate()
|
||||
end)
|
||||
))
|
||||
|
||||
alsa.widget = myvolume
|
||||
alsa.channel = channel
|
||||
alsa.step = step
|
||||
alsa.notify = myvolumeupdate
|
||||
|
||||
return setmetatable(alsa, { __index = alsa.widget })
|
||||
end
|
||||
|
||||
return setmetatable(alsa, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,164 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2013, Rman
|
||||
--]]
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local naughty = require("naughty")
|
||||
|
||||
local io = io
|
||||
local math = { modf = math.modf }
|
||||
local string = { match = string.match,
|
||||
rep = string.rep }
|
||||
local tonumber = tonumber
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- ALSA volume bar
|
||||
-- lain.widgets.alsabar
|
||||
local alsabar =
|
||||
{
|
||||
channel = "Master",
|
||||
step = "5%",
|
||||
|
||||
colors =
|
||||
{
|
||||
background = beautiful.bg_normal,
|
||||
mute = "#EB8F8F",
|
||||
unmute = "#A4CE8A"
|
||||
},
|
||||
|
||||
mixer = terminal .. " -e alsamixer",
|
||||
|
||||
notifications =
|
||||
{
|
||||
font = beautiful.font:sub(beautiful.font:find(""), beautiful.font:find(" ")),
|
||||
font_size = "11",
|
||||
bar_size = 18 -- Awesome default
|
||||
},
|
||||
|
||||
_current_level = 0,
|
||||
_muted = false
|
||||
}
|
||||
|
||||
function alsabar:notify()
|
||||
local preset =
|
||||
{
|
||||
title = "", text = "",
|
||||
timeout = 3,
|
||||
font = alsabar.notifications.font .. " " .. alsabar.notifications.font_size,
|
||||
fg = beautiful.fg_focus
|
||||
}
|
||||
|
||||
if alsabar._muted then
|
||||
preset.title = alsabar.channel .. " - Muted"
|
||||
else
|
||||
preset.title = alsabar.channel .. " - " .. alsabar._current_level * 100 .. "%"
|
||||
end
|
||||
|
||||
local int = math.modf(alsabar._current_level * alsabar.notifications.bar_size)
|
||||
preset.text = "[" .. string.rep("|", int)
|
||||
.. string.rep(" ", alsabar.notifications.bar_size - int) .. "]"
|
||||
|
||||
if alsabar._notify ~= nil then
|
||||
alsabar._notify = naughty.notify ({ replaces_id = alsabar._notify.id,
|
||||
preset = preset })
|
||||
else
|
||||
alsabar._notify = naughty.notify ({ preset = preset })
|
||||
end
|
||||
end
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local width = args.width or 63
|
||||
local height = args.heigth or 1
|
||||
local ticks = args.ticks or true
|
||||
local ticks_size = args.ticks_size or 7
|
||||
local vertical = args.vertical or false
|
||||
alsabar.channel = args.channel or alsabar.channel
|
||||
alsabar.step = args.step or alsabar.step
|
||||
alsabar.colors = args.colors or alsabar.colors
|
||||
alsabar.notifications = args.notifications or alsabar.notifications
|
||||
|
||||
alsabar.bar = awful.widget.progressbar()
|
||||
alsabar.bar:set_background_color(alsabar.colors.background)
|
||||
alsabar.bar:set_color(alsabar.colors.unmute)
|
||||
alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } })
|
||||
alsabar.bar:set_width(width)
|
||||
alsabar.bar:set_height(height)
|
||||
alsabar.bar:set_ticks(ticks)
|
||||
alsabar.bar:set_ticks_size(ticks_size)
|
||||
|
||||
if vertical then
|
||||
alsabar.bar:set_vertical(true)
|
||||
end
|
||||
|
||||
local myvolumebarupdate = function()
|
||||
-- Get mixer control contents
|
||||
local f = io.popen("amixer get " .. alsabar.channel)
|
||||
local mixer = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Capture mixer control state: [5%] ... ... [on]
|
||||
local volu, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
|
||||
-- Handle mixers without data
|
||||
if volu == nil then
|
||||
volu = 0
|
||||
mute = "off"
|
||||
end
|
||||
|
||||
alsabar._current_level = tonumber(volu) / 100
|
||||
alsabar.bar:set_value(alsabar._current_level)
|
||||
|
||||
if mute == "" and volu == "0" or mute == "off"
|
||||
then
|
||||
alsabar._muted = true
|
||||
alsabar.tooltip:set_text (" [Muted] ")
|
||||
alsabar.bar:set_color(alsabar.colors.mute)
|
||||
else
|
||||
alsabar._muted = false
|
||||
alsabar.tooltip:set_text(" " .. alsabar.channel .. ": " .. volu .. "% ")
|
||||
alsabar.bar:set_color(alsabar.colors.unmute)
|
||||
end
|
||||
end
|
||||
|
||||
local myvolumebartimer = timer({ timeout = 5 })
|
||||
myvolumebartimer:connect_signal("timeout", myvolumebarupdate)
|
||||
myvolumebartimer:start()
|
||||
myvolumebartimer:emit_signal("timeout")
|
||||
|
||||
alsabar.bar:buttons (awful.util.table.join (
|
||||
awful.button ({}, 1, function()
|
||||
awful.util.spawn(alsabar.mixer)
|
||||
end),
|
||||
awful.button ({}, 3, function()
|
||||
awful.util.spawn("amixer sset " .. alsabar.channel .. " toggle")
|
||||
myvolumebarupdate()
|
||||
end),
|
||||
awful.button ({}, 4, function()
|
||||
awful.util.spawn("amixer sset " .. alsabar.channel .. " "
|
||||
.. alsabar.step .. "+")
|
||||
myvolumebarupdate()
|
||||
end),
|
||||
awful.button ({}, 5, function()
|
||||
awful.util.spawn("amixer sset " .. alsabar.channel .. " "
|
||||
.. alsabar.step .. "-")
|
||||
myvolumebarupdate()
|
||||
end)
|
||||
))
|
||||
|
||||
return { widget = alsabar.bar,
|
||||
channel = alsabar.channel,
|
||||
step = alsabar.step,
|
||||
notify = function()
|
||||
myvolumebarupdate()
|
||||
alsabar.notify()
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
return setmetatable(alsabar, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,147 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local first_line = require("lain.helpers").first_line
|
||||
|
||||
local beautiful = require("beautiful")
|
||||
local naughty = require("naughty")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local math = { floor = math.floor }
|
||||
local string = { format = string.format }
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Battery infos
|
||||
-- lain.widgets.bat
|
||||
local bat = {
|
||||
status = "not present",
|
||||
perc = "N/A",
|
||||
time = "N/A",
|
||||
}
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local battery = args.battery or "BAT0"
|
||||
local show_all = args.show_all or false
|
||||
local refresh_timeout = args.refresh_timeout or 30
|
||||
local header = args.header or " Bat "
|
||||
local header_color = args.header_color or beautiful.fg_normal or "#FFFFFF"
|
||||
local color = args.color or beautiful.fg_focus or "#FFFFFF"
|
||||
local shadow = args.shadow or false
|
||||
|
||||
local mybattery = wibox.widget.textbox()
|
||||
|
||||
local mybatteryupdate = function()
|
||||
local present = first_line("/sys/class/power_supply/"
|
||||
.. battery
|
||||
.. "/present")
|
||||
|
||||
if present == "1"
|
||||
then
|
||||
local rate = first_line("/sys/class/power_supply/"
|
||||
.. battery ..
|
||||
"/power_now")
|
||||
local ratev = first_line("/sys/class/power_supply/"
|
||||
.. battery ..
|
||||
"/voltage_now")
|
||||
local rem = first_line("/sys/class/power_supply/"
|
||||
.. battery ..
|
||||
"/energy_now")
|
||||
local tot = first_line("/sys/class/power_supply/"
|
||||
.. battery ..
|
||||
"/energy_full")
|
||||
bat.status = first_line("/sys/class/power_supply/"
|
||||
.. battery ..
|
||||
"/status")
|
||||
|
||||
local time_rat = 0
|
||||
if bat.status == "Charging"
|
||||
then
|
||||
status = "(+)"
|
||||
time_rat = (tot - rem) / rate
|
||||
elseif bat.status == "Discharging"
|
||||
then
|
||||
status = "(-)"
|
||||
time_rat = rem / rate
|
||||
else
|
||||
status = "(.)"
|
||||
end
|
||||
|
||||
local hrs = math.floor(time_rat)
|
||||
local min = (time_rat - hrs) * 60
|
||||
bat.time = string.format("%02d:%02d", hrs, min)
|
||||
|
||||
local amount = (rem / tot) * 100
|
||||
|
||||
if shadow
|
||||
then
|
||||
bat.perc = string.format("%d", amount)
|
||||
else
|
||||
bat.perc = string.format("%d%%", amount)
|
||||
end
|
||||
|
||||
local watt = string.format("%.2fW", (rate * ratev) / 1e12)
|
||||
|
||||
if show_all
|
||||
then
|
||||
text = watt .. " " .. bat.perc .. " " .. bat.time .. " " .. bat.status
|
||||
else
|
||||
text = bat.perc
|
||||
end
|
||||
|
||||
-- notifications for low and critical states
|
||||
if amount <= 5
|
||||
then
|
||||
naughty.notify{
|
||||
text = "shutdown imminent",
|
||||
title = "battery nearly exhausted",
|
||||
position = "top_right",
|
||||
timeout = 15,
|
||||
fg="#000000",
|
||||
bg="#ffffff",
|
||||
ontop = true
|
||||
}
|
||||
elseif amount <= 15
|
||||
then
|
||||
old_id = naughty.notify{
|
||||
text = "plug the cable",
|
||||
title = "battery low",
|
||||
position = "top_right",
|
||||
timeout = 5,
|
||||
fg="#202020",
|
||||
bg="#cdcdcd",
|
||||
ontop = true
|
||||
}
|
||||
end
|
||||
else
|
||||
text = "none"
|
||||
end
|
||||
|
||||
if shadow
|
||||
then
|
||||
mybattery:set_text('')
|
||||
else
|
||||
mybattery:set_markup(markup(header_color, header)
|
||||
.. markup(color, text) .. " ")
|
||||
end
|
||||
end
|
||||
|
||||
local mybatterytimer = timer({ timeout = refresh_timeout })
|
||||
mybatterytimer:connect_signal("timeout", mybatteryupdate)
|
||||
mybatterytimer:start()
|
||||
mybatterytimer:emit_signal("timeout")
|
||||
|
||||
bat.widget = mybattery
|
||||
|
||||
return setmetatable(bat, { __index = bat.widget })
|
||||
end
|
||||
|
||||
return setmetatable(bat, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local wibox = require("awful.wibox")
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Creates a thin wibox at a position relative to another wibox
|
||||
-- lain.widgets.borderbox
|
||||
local borderbox = {}
|
||||
|
||||
local function worker(relbox, s, args)
|
||||
local where = args.position or 'above'
|
||||
local color = args.color or '#FFFFFF'
|
||||
local size = args.size or 1
|
||||
local box = nil
|
||||
local wiboxarg = {
|
||||
position = nil,
|
||||
bg = color
|
||||
}
|
||||
|
||||
if where == 'above'
|
||||
then
|
||||
wiboxarg.width = relbox.width
|
||||
wiboxarg.height = size
|
||||
box = wibox(wiboxarg)
|
||||
box.x = relbox.x
|
||||
box.y = relbox.y - size
|
||||
elseif where == 'below'
|
||||
then
|
||||
wiboxarg.width = relbox.width
|
||||
wiboxarg.height = size
|
||||
box = wibox(wiboxarg)
|
||||
box.x = relbox.x
|
||||
box.y = relbox.y + relbox.height
|
||||
elseif where == 'left'
|
||||
then
|
||||
wiboxarg.width = size
|
||||
wiboxarg.height = relbox.height
|
||||
box = wibox(wiboxarg)
|
||||
box.x = relbox.x - size
|
||||
box.y = relbox.y
|
||||
elseif where == 'right'
|
||||
then
|
||||
wiboxarg.width = size
|
||||
wiboxarg.height = relbox.height
|
||||
box = wibox(wiboxarg)
|
||||
box.x = relbox.x + relbox.width
|
||||
box.y = relbox.y
|
||||
end
|
||||
|
||||
box.screen = s
|
||||
return box
|
||||
end
|
||||
|
||||
return setmetatable(borderbox, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,124 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
|
||||
--]]
|
||||
|
||||
local icons_dir = require("lain.helpers").icons_dir
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local naughty = require("naughty")
|
||||
|
||||
local io = io
|
||||
local os = { date = os.date }
|
||||
local tonumber = tonumber
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Calendar notification
|
||||
-- lain.widgets.calendar
|
||||
local calendar = {}
|
||||
local notification = nil
|
||||
|
||||
local function create(background, foreground)
|
||||
calendar.offset = 0
|
||||
calendar.icons_dir = icons_dir .. "cal/white/" -- default
|
||||
calendar.notify_icon = nil
|
||||
calendar.font_size = 12
|
||||
calendar.bg = background or beautiful.bg_normal or "#FFFFFF"
|
||||
calendar.fg = foreground or beautiful.fg_normal or "#FFFFFF"
|
||||
end
|
||||
|
||||
function calendar:hide()
|
||||
if notification ~= nil then
|
||||
naughty.destroy(notification)
|
||||
notification = nil
|
||||
end
|
||||
end
|
||||
|
||||
function calendar:show(t_out, inc_offset)
|
||||
calendar:hide()
|
||||
|
||||
local offs = inc_offset or 0
|
||||
local tims = t_out or 0
|
||||
local f, c_text
|
||||
local today = tonumber(os.date('%d'))
|
||||
local init_t = '/usr/bin/cal | sed -r -e "s/(^| )( '
|
||||
-- let's take font only, font size is set in calendar table
|
||||
local font = beautiful.font:sub(beautiful.font:find(""),
|
||||
beautiful.font:find(" "))
|
||||
|
||||
if offs == 0
|
||||
then -- current month showing, today highlighted
|
||||
if today >= 10
|
||||
then
|
||||
init_t = '/usr/bin/cal | sed -r -e "s/(^| )('
|
||||
end
|
||||
|
||||
calendar.offset = 0
|
||||
calendar.notify_icon = calendar.icons_dir .. today .. ".png"
|
||||
|
||||
-- bg and fg inverted to highlight today
|
||||
f = io.popen( init_t .. today ..
|
||||
')($| )/\\1<b><span foreground=\\"'
|
||||
.. calendar.bg ..
|
||||
'\\" background=\\"'
|
||||
.. calendar.fg ..
|
||||
'\\">\\2<\\/span><\\/b>\\3/"' )
|
||||
|
||||
else -- no current month showing, no day to highlight
|
||||
local month = tonumber(os.date('%m'))
|
||||
local year = tonumber(os.date('%Y'))
|
||||
|
||||
calendar.offset = calendar.offset + offs
|
||||
month = month + calendar.offset
|
||||
|
||||
if month > 12 then
|
||||
month = month % 12
|
||||
year = year + 1
|
||||
if month <= 0 then
|
||||
month = 12
|
||||
end
|
||||
elseif month < 1 then
|
||||
month = month + 12
|
||||
year = year - 1
|
||||
if month <= 0 then
|
||||
month = 1
|
||||
end
|
||||
end
|
||||
|
||||
calendar.notify_icon = nil
|
||||
|
||||
f = io.popen('/usr/bin/cal ' .. month .. ' ' .. year)
|
||||
end
|
||||
|
||||
|
||||
c_text = "<tt><span font='" .. font .. " "
|
||||
.. calendar.font_size .. "'><b>"
|
||||
.. f:read() .. "</b>\n\n"
|
||||
.. f:read() .. "\n"
|
||||
.. f:read("*all"):gsub("\n*$", "")
|
||||
.. "</span></tt>"
|
||||
f:close()
|
||||
|
||||
notification = naughty.notify({ text = c_text,
|
||||
icon = calendar.notify_icon,
|
||||
fg = calendar.fg,
|
||||
bg = calendar.bg,
|
||||
timeout = tims })
|
||||
end
|
||||
|
||||
function calendar:attach(widget, background, foreground)
|
||||
create(background, foreground)
|
||||
widget:connect_signal("mouse::enter", function () calendar:show() end)
|
||||
widget:connect_signal("mouse::leave", function () calendar:hide() end)
|
||||
widget:buttons(awful.util.table.join( awful.button({ }, 1, function ()
|
||||
calendar:show(0, -1) end),
|
||||
awful.button({ }, 3, function ()
|
||||
calendar:show(0, 1) end) ))
|
||||
end
|
||||
|
||||
return setmetatable(calendar, { __call = function(_, ...) return create(...) end })
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local first_line = require("lain.helpers").first_line
|
||||
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local math = { ceil = math.ceil }
|
||||
local string = { format = string.format,
|
||||
gmatch = string.gmatch }
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- CPU usage
|
||||
-- lain.widgets.cpu
|
||||
local cpu = {
|
||||
last_total = 0,
|
||||
last_active = 0
|
||||
}
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local refresh_timeout = args.refresh_timeout or 5
|
||||
local header = args.header or " Cpu "
|
||||
local header_color = args.header or beautiful.fg_normal or "#FFFFFF"
|
||||
local color = args.color or beautiful.fg_focus or "#FFFFFF"
|
||||
local footer = args.footer or "%"
|
||||
|
||||
local w = wibox.widget.textbox()
|
||||
|
||||
local cpuusageupdate = function()
|
||||
-- Read the amount of time the CPUs have spent performing
|
||||
-- different kinds of work. Read the first line of /proc/stat
|
||||
-- which is the sum of all CPUs.
|
||||
local times = first_line("/proc/stat")
|
||||
local at = 1
|
||||
local idle = 0
|
||||
local total = 0
|
||||
for field in string.gmatch(times, "[%s]+([^%s]+)")
|
||||
do
|
||||
-- 3 = idle, 4 = ioWait. Essentially, the CPUs have done
|
||||
-- nothing during these times.
|
||||
if at == 3 or at == 4
|
||||
then
|
||||
idle = idle + field
|
||||
end
|
||||
total = total + field
|
||||
at = at + 1
|
||||
end
|
||||
local active = total - idle
|
||||
|
||||
-- Read current data and calculate relative values.
|
||||
local dactive = active - cpu.last_active
|
||||
local dtotal = total - cpu.last_total
|
||||
local dta = math.ceil((dactive / dtotal) * 100)
|
||||
|
||||
w:set_markup(markup(header_color, header) .. markup(color, dta .. footer) .. " ")
|
||||
|
||||
-- Save current data for the next run.
|
||||
cpu.last_active = active
|
||||
cpu.last_total = total
|
||||
end
|
||||
|
||||
local cpuusagetimer = timer({ timeout = refresh_timeout })
|
||||
cpuusagetimer:connect_signal("timeout", cpuusageupdate)
|
||||
cpuusagetimer:start()
|
||||
cpuusagetimer:emit_signal("timeout")
|
||||
|
||||
return w
|
||||
end
|
||||
|
||||
return setmetatable(cpu, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,134 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
* (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local helpers = require("lain.helpers")
|
||||
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
local naughty = require("naughty")
|
||||
|
||||
local io = io
|
||||
local string = { match = string.match }
|
||||
local tonumber = tonumber
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- File system disk space usage
|
||||
-- lain.widgets.fs
|
||||
local fs = {}
|
||||
local notification = nil
|
||||
|
||||
function fs:hide()
|
||||
if notification ~= nil then
|
||||
naughty.destroy(notification)
|
||||
notification = nil
|
||||
end
|
||||
end
|
||||
|
||||
function fs:show(t_out)
|
||||
fs:hide()
|
||||
|
||||
local f = io.popen(helpers.scripts_dir .. "dfs")
|
||||
ws = f:read("*all"):gsub("\n*$", "")
|
||||
f:close()
|
||||
|
||||
notification = naughty.notify({
|
||||
text = ws,
|
||||
timeout = t_out,
|
||||
fg = beautiful.fg_focus,
|
||||
})
|
||||
end
|
||||
|
||||
-- Variable definitions
|
||||
local unit = { ["mb"] = 1024, ["gb"] = 1024^2 }
|
||||
|
||||
local function worker(args)
|
||||
local args = args or {}
|
||||
local partition = args.partition or "/"
|
||||
local refresh_timeout = args.refresh_timeout or 600
|
||||
local header = args.header or " Hdd "
|
||||
local header_color = args.header_color or beautiful.fg_normal or "#FFFFFF"
|
||||
local color = args.color or beautiful.fg_focus or "#FFFFFF"
|
||||
local footer = args.header or ""
|
||||
local shadow = args.shadow or false
|
||||
|
||||
local myfs = wibox.widget.textbox()
|
||||
|
||||
helpers.set_map("fs", false)
|
||||
|
||||
local fsupdate = function()
|
||||
local fs_info = {} -- Get data from df
|
||||
local f = io.popen("LC_ALL=C df -kP")
|
||||
|
||||
local function set_text()
|
||||
local info = fs_info['{' .. partition .. ' used_p}']
|
||||
myfs:set_markup(markup(header_color, header)
|
||||
.. markup(color, info .. footer) .. " ")
|
||||
end
|
||||
|
||||
for line in f:lines() do -- Match: (size) (used)(avail)(use%) (mount)
|
||||
local s = string.match(line, "^.-[%s]([%d]+)")
|
||||
local u,a,p = string.match(line, "([%d]+)[%D]+([%d]+)[%D]+([%d]+)%%")
|
||||
local m = string.match(line, "%%[%s]([%p%w]+)")
|
||||
|
||||
if u and m then -- Handle 1st line and broken regexp
|
||||
helpers.uformat(fs_info, m .. " used", u, unit)
|
||||
fs_info["{" .. m .. " used_p}"] = tonumber(p)
|
||||
end
|
||||
end
|
||||
|
||||
f:close()
|
||||
|
||||
if shadow
|
||||
then
|
||||
myfs:set_text('')
|
||||
else
|
||||
set_text()
|
||||
end
|
||||
|
||||
local part = fs_info['{' .. partition .. ' used_p}']
|
||||
|
||||
if part >= 90 then
|
||||
if part >= 99 and not helpers.get_map("fs") then
|
||||
naughty.notify({ title = "warning",
|
||||
text = partition .. " ran out!\n"
|
||||
.. "make some room",
|
||||
timeout = 8,
|
||||
position = "top_right",
|
||||
fg = beautiful.fg_urgent,
|
||||
bg = beautiful.bg_urgent })
|
||||
helpers.set_map("fs", true)
|
||||
end
|
||||
if shadow then set_text() end
|
||||
end
|
||||
end
|
||||
|
||||
local fstimer = timer({ timeout = refresh_timeout })
|
||||
fstimer:connect_signal("timeout", fsupdate)
|
||||
fstimer:start()
|
||||
fstimer:emit_signal("timeout")
|
||||
|
||||
myfs:connect_signal('mouse::enter', function () fs:show(0) end)
|
||||
myfs:connect_signal('mouse::leave', function () fs:hide() end)
|
||||
|
||||
local fs_out =
|
||||
{
|
||||
widget = myfs,
|
||||
show = function(t_out)
|
||||
fsupdate()
|
||||
fs:show(t_out)
|
||||
end
|
||||
}
|
||||
|
||||
return setmetatable(fs_out, { __index = fs_out.widget })
|
||||
end
|
||||
|
||||
return setmetatable(fs, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,166 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local helpers = require("lain.helpers")
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local naughty = require("naughty")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local io = io
|
||||
local tonumber = tonumber
|
||||
local string = string
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Mail imap check
|
||||
-- lain.widgets.imap
|
||||
local imap = {}
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
|
||||
local server = args.server
|
||||
local mail = args.mail
|
||||
local password = args.password
|
||||
|
||||
local port = args.port or "993"
|
||||
local refresh_timeout = args.refresh_timeout or 60
|
||||
local header = args.header or " Mail "
|
||||
local header_color = args.header_color or beautiful.fg_normal or "#FFFFFF"
|
||||
local color_newmail = args.color_newmail or beautiful.fg_focus or "#FFFFFF"
|
||||
local color_nomail = args.color_nomail or beautiful.fg_normal or "#FFFFFF"
|
||||
local mail_encoding = args.mail_encoding or nil
|
||||
local maxlen = args.maxlen or 200
|
||||
local app = args.app or "mutt"
|
||||
local is_plain = args.is_plain or false
|
||||
local shadow = args.shadow or false
|
||||
|
||||
helpers.set_map(mail, true)
|
||||
helpers.set_map(mail .. " count", "0")
|
||||
|
||||
local checkmail = helpers.scripts_dir .. "checkmail"
|
||||
|
||||
if not is_plain
|
||||
then
|
||||
local f = io.popen(password)
|
||||
password = f:read("*all"):gsub("\n", ""):gsub("\r", "")
|
||||
f:close()
|
||||
end
|
||||
|
||||
local myimapcheck = wibox.widget.textbox()
|
||||
|
||||
local myimapcheckupdate = function()
|
||||
function set_nomail()
|
||||
if shadow
|
||||
then
|
||||
myimapcheck:set_text('')
|
||||
else
|
||||
myimapcheck:set_markup(markup(color_nomail, " no mail "))
|
||||
end
|
||||
end
|
||||
|
||||
conn = io.popen("ip link show")
|
||||
check_conn = conn:read("*all")
|
||||
conn:close()
|
||||
|
||||
if not check_conn:find("state UP") then
|
||||
set_nomail()
|
||||
return
|
||||
end
|
||||
|
||||
to_execute = checkmail .. ' -s ' .. server ..
|
||||
' -u ' .. mail .. ' -p ' .. password
|
||||
.. ' --port ' .. port
|
||||
|
||||
if mail_encoding ~= nil
|
||||
then
|
||||
to_execute = to_execute .. ' --encoding '
|
||||
.. mail_encoding
|
||||
end
|
||||
|
||||
f = io.popen(to_execute)
|
||||
ws = f:read("*all")
|
||||
f:close()
|
||||
|
||||
if ws:find("No new messages") ~= nil
|
||||
then
|
||||
helpers.set_map(mail, true)
|
||||
set_nomail()
|
||||
elseif ws:find("CheckMailError: invalid credentials") ~= nil
|
||||
then
|
||||
helpers.set_map(mail, true)
|
||||
myimapcheck.set_markup(markup(header_color, header) ..
|
||||
markup(color_newmail, "invalid credentials "))
|
||||
else
|
||||
mailcount = ws:match("%d") or "?"
|
||||
|
||||
if helpers.get_map(mail .. " count") ~= mailcount and mailcount ~= "?"
|
||||
then
|
||||
helpers.set_map(mail, true)
|
||||
helpers.set_map(mail .. " count", mailcount)
|
||||
end
|
||||
|
||||
myimapcheck:set_markup(markup(header_color, header) ..
|
||||
markup(color_newmail, mailcount) .. " ")
|
||||
|
||||
if helpers.get_map(mail)
|
||||
then
|
||||
if mailcount == "?"
|
||||
-- May happens sometimes using keyrings or other password fetchers.
|
||||
-- Since this should be automatically fixed in short times, we threat
|
||||
-- this exception delaying the update to the next timeout.
|
||||
then
|
||||
set_nomail()
|
||||
return
|
||||
elseif tonumber(mailcount) >= 1
|
||||
then
|
||||
notify_title = ws:match(mail .. " has %d new message.?")
|
||||
ws = ws:gsub(notify_title, "", 1):gsub("\n", "", 2)
|
||||
|
||||
ws = ws:gsub("--Content.%S+.-\n", "")
|
||||
ws = ws:gsub("--%d+.-\n", "")
|
||||
|
||||
if string.len(ws) > maxlen
|
||||
then
|
||||
ws = ws:sub(1, maxlen) .. "[...]"
|
||||
end
|
||||
|
||||
notify_title = notify_title:gsub("\n", "")
|
||||
end
|
||||
|
||||
naughty.notify({ title = notify_title,
|
||||
fg = color_newmail,
|
||||
text = ws,
|
||||
icon = beautiful.lain_mail_notify or
|
||||
helpers.icons_dir .. "mail.png",
|
||||
timeout = 8,
|
||||
position = "top_left" })
|
||||
|
||||
helpers.set_map(mail, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local myimapchecktimer = timer({ timeout = refresh_timeout })
|
||||
myimapchecktimer:connect_signal("timeout", myimapcheckupdate)
|
||||
myimapchecktimer:start()
|
||||
myimapcheck:buttons(awful.util.table.join(
|
||||
awful.button({}, 0,
|
||||
|
||||
function()
|
||||
helpers.run_in_terminal(app)
|
||||
end)
|
||||
))
|
||||
|
||||
return myimapcheck
|
||||
end
|
||||
|
||||
return setmetatable(imap, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
--[[
|
||||
|
||||
Lain
|
||||
Layouts, widgets and utilities for Awesome WM
|
||||
|
||||
Widgets section
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local wrequire = require("lain.helpers").wrequire
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local widgets =
|
||||
{
|
||||
_NAME = "lain.widgets",
|
||||
terminal = "xterm" -- X default
|
||||
}
|
||||
|
||||
return setmetatable(widgets, { __index = wrequire })
|
|
@ -0,0 +1,129 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local run_in_terminal = require("lain.helpers").run_in_terminal
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local io = io
|
||||
local os = { getenv = os.getenv }
|
||||
local pairs = pairs
|
||||
local string = { len = string.len,
|
||||
match = string.match }
|
||||
local table = { sort = table.sort }
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Maildir check
|
||||
-- lain.widgets.maildir
|
||||
local maildir = {}
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local mailpath = args.mailpath or os.getenv("HOME") .. "/Mail"
|
||||
local ignore_boxes = args.ignore_boxes or {}
|
||||
local refresh_timeout = args.refresh_timeout or 60
|
||||
local header = args.header or " Mail "
|
||||
local header_color = args.header_color or beautiful.fg_normal or "#FFFFFF"
|
||||
local color_newmail = args.color_newmail or beautiful.fg_focus or "#FFFFFF"
|
||||
local color_nomail = args.color_nomail or beautiful.fg_normal or "#FFFFFF"
|
||||
local app = args.app or "mutt"
|
||||
local shadow = args.shadow or false
|
||||
|
||||
local mymailcheck = wibox.widget.textbox()
|
||||
local mymailcheckupdate = function()
|
||||
-- Find pathes to mailboxes.
|
||||
local p = io.popen("find " .. mailpath ..
|
||||
" -mindepth 1 -maxdepth 1 -type d" ..
|
||||
" -not -name .git")
|
||||
local boxes = {}
|
||||
local line = ""
|
||||
repeat
|
||||
line = p:read("*l")
|
||||
if line ~= nil
|
||||
then
|
||||
-- Find all files in the "new" subdirectory. For each
|
||||
-- file, print a single character (no newline). Don't
|
||||
-- match files that begin with a dot.
|
||||
-- Afterwards the length of this string is the number of
|
||||
-- new mails in that box.
|
||||
local np = io.popen("find " .. line ..
|
||||
"/new -mindepth 1 -type f " ..
|
||||
"-not -name '.*' -printf a")
|
||||
local mailstring = np:read("*all")
|
||||
|
||||
-- Strip off leading mailpath.
|
||||
local box = string.match(line, mailpath .. "/*([^/]+)")
|
||||
local nummails = string.len(mailstring)
|
||||
if nummails > 0
|
||||
then
|
||||
boxes[box] = nummails
|
||||
end
|
||||
end
|
||||
until line == nil
|
||||
|
||||
table.sort(boxes)
|
||||
|
||||
local newmail = ""
|
||||
local count = 0
|
||||
for box, number in pairs(boxes)
|
||||
do
|
||||
count = count + 1
|
||||
-- Add this box only if it's not to be ignored.
|
||||
if not util.element_in_table(box, ignore_boxes)
|
||||
then
|
||||
if newmail == ""
|
||||
then
|
||||
newmail = box .. "(" .. number .. ")"
|
||||
else
|
||||
newmail = newmail .. ", " ..
|
||||
box .. "(" .. number .. ")"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if count == 1 then
|
||||
-- it will be only executed once
|
||||
for box, number in pairs(boxes)
|
||||
do -- it's useless to show only INBOX(x)
|
||||
if box == "INBOX" then newmail = number end
|
||||
end
|
||||
end
|
||||
|
||||
if newmail == ""
|
||||
then
|
||||
if shadow
|
||||
then
|
||||
mymailcheck:set_text('')
|
||||
else
|
||||
myimapcheck:set_markup(markup(color_nomail, " no mail "))
|
||||
end
|
||||
else
|
||||
myimapcheck:set_markup(markup(header_color, header) ..
|
||||
markup(color_newmail, newmail) .. " ")
|
||||
end
|
||||
end
|
||||
|
||||
local mymailchecktimer = timer({ timeout = refresh_timeout })
|
||||
mymailchecktimer:connect_signal("timeout", mymailcheckupdate)
|
||||
mymailchecktimer:start()
|
||||
mymailcheck:buttons(awful.util.table.join(
|
||||
awful.button({}, 0,
|
||||
function()
|
||||
run_in_terminal(app)
|
||||
end)
|
||||
))
|
||||
|
||||
return mymailcheck
|
||||
end
|
||||
|
||||
return setmetatable(maildir, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
* (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
* (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local run_in_terminal = require("lain.helpers").run_in_terminal
|
||||
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local io = { lines = io.lines }
|
||||
local math = { floor = math.floor }
|
||||
local string = { format = string.format,
|
||||
gmatch = string.gmatch,
|
||||
len = string.len }
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Memory usage (ignoring caches)
|
||||
-- lain.widgets.mem
|
||||
local mem = {}
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local refresh_timeout = args.refresh_timeout or 10
|
||||
local show_swap = args.show_swap or false
|
||||
local show_total = args.show_total or false
|
||||
local header = args.header or " Mem "
|
||||
local header_color = args.header or beautiful.fg_normal or "#FFFFFF"
|
||||
local color = args.color or beautiful.fg_focus or "#FFFFFF"
|
||||
local footer = args.footer or "MB"
|
||||
|
||||
local widg = wibox.widget.textbox()
|
||||
|
||||
local upd = function()
|
||||
local mem = {}
|
||||
for line in io.lines("/proc/meminfo")
|
||||
do
|
||||
for k, v in string.gmatch(line, "([%a]+):[%s]+([%d]+).+")
|
||||
do
|
||||
if k == "MemTotal" then mem.total = math.floor(v / 1024)
|
||||
elseif k == "MemFree" then mem.free = math.floor(v / 1024)
|
||||
elseif k == "Buffers" then mem.buf = math.floor(v / 1024)
|
||||
elseif k == "Cached" then mem.cache = math.floor(v / 1024)
|
||||
elseif k == "SwapTotal" then mem.swap = math.floor(v / 1024)
|
||||
elseif k == "SwapFree" then mem.swapf = math.floor(v / 1024)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
used = mem.total - (mem.free + mem.buf + mem.cache)
|
||||
swapused = mem.swap - mem.swapf
|
||||
|
||||
if show_total
|
||||
then
|
||||
local fmt = "%" .. string.len(mem.total) .. ".0f/%.0f"
|
||||
widg:set_markup(markup(header_color, header) ..
|
||||
markup(color, string.format(fmt, used, mem.total) .. footer .. " "))
|
||||
else
|
||||
widg:set_markup(markup(header_color, header) ..
|
||||
markup(color, used .. footer .. " "))
|
||||
end
|
||||
|
||||
if show_swap
|
||||
then
|
||||
widg:set_markup(widg._layout.text .. ' ('
|
||||
.. string.format('%.0f '.. footer, swapused)
|
||||
.. ') ')
|
||||
end
|
||||
end
|
||||
|
||||
local tmr = timer({ timeout = refresh_timeout })
|
||||
tmr:connect_signal("timeout", upd)
|
||||
tmr:start()
|
||||
tmr:emit_signal("timeout")
|
||||
|
||||
return widg
|
||||
end
|
||||
|
||||
return setmetatable(mem, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local helpers = require("lain.helpers")
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local naughty = require("naughty")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local io = io
|
||||
local os = { execute = os.execute,
|
||||
getenv = os.getenv }
|
||||
local string = { gmatch = string.gmatch }
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- MPD infos
|
||||
-- lain.widgets.mpd
|
||||
local mpd = { id = nil }
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local password = args.password or ""
|
||||
local host = args.host or "127.0.0.1"
|
||||
local port = args.port or "6600"
|
||||
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music"
|
||||
local refresh_timeout = args.refresh_timeout or 1
|
||||
local notify_timeout = args.notify_timeout or 5
|
||||
local color_artist = args.color_artist or beautiful.fg_normal or "#FFFFFF"
|
||||
local color_song = args.color_song or beautiful.fg_focus or "#FFFFFF"
|
||||
local spr = args.spr or ""
|
||||
local musicplr = args.musicplr or "ncmpcpp"
|
||||
local shadow = args.shadow or false
|
||||
|
||||
local mpdcover = helpers.scripts_dir .. "mpdcover"
|
||||
local mpdh = "telnet://"..host..":"..port
|
||||
local echo = "echo 'password "..password.."\nstatus\ncurrentsong\nclose'"
|
||||
|
||||
local mympd = wibox.widget.textbox()
|
||||
|
||||
helpers.set_map("current mpd track", nil)
|
||||
|
||||
local mympdupdate = function()
|
||||
local function set_nompd()
|
||||
if shadow
|
||||
then
|
||||
mympd:set_text('')
|
||||
else
|
||||
mympd:set_markup(markup(color_artist, " mpd "), markup(color_song , "off "))
|
||||
end
|
||||
end
|
||||
|
||||
local mpd_state = {
|
||||
["{state}"] = "N/A",
|
||||
["{file}"] = "N/A",
|
||||
["{Artist}"] = "N/A",
|
||||
["{Title}"] = "N/A",
|
||||
["{Album}"] = "N/A",
|
||||
["{Date}"] = "N/A"
|
||||
}
|
||||
|
||||
-- Get data from MPD server
|
||||
local f = io.popen(echo .. " | curl --connect-timeout 1 -fsm 3 " .. mpdh)
|
||||
|
||||
for line in f:lines() do
|
||||
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
|
||||
if k == "state" then mpd_state["{"..k.."}"] = v
|
||||
elseif k == "file" then mpd_state["{"..k.."}"] = v
|
||||
elseif k == "Artist" then mpd_state["{"..k.."}"] = awful.util.escape(v)
|
||||
elseif k == "Title" then mpd_state["{"..k.."}"] = awful.util.escape(v)
|
||||
elseif k == "Album" then mpd_state["{"..k.."}"] = awful.util.escape(v)
|
||||
elseif k == "Date" then mpd_state["{"..k.."}"] = awful.util.escape(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
f:close()
|
||||
|
||||
if mpd_state["{state}"] == "play"
|
||||
then
|
||||
if mpd_state["{Title}"] ~= helpers.get_map("current mpd track")
|
||||
then
|
||||
helpers.set_map("current mpd track", mpd_state["{Title}"])
|
||||
os.execute(mpdcover .. " '" .. music_dir .. "' '"
|
||||
.. mpd_state["{file}"] .. "'")
|
||||
mpd.id = naughty.notify({
|
||||
title = "Now playing",
|
||||
text = mpd_state["{Artist}"] .. " (" ..
|
||||
mpd_state["{Album}"] .. ") - " ..
|
||||
mpd_state["{Date}"] .. "\n" ..
|
||||
mpd_state["{Title}"],
|
||||
icon = "/tmp/mpdcover.png",
|
||||
fg = beautiful.fg_focus or "#FFFFFF",
|
||||
bg = beautiful.bg_normal or "#000000" ,
|
||||
timeout = notify_timeout,
|
||||
replaces_id = mpd.id
|
||||
}).id
|
||||
end
|
||||
mympd:set_markup(markup(color_artist, " " .. mpd_state["{Artist}"])
|
||||
.. spr ..
|
||||
markup(color_song, " " .. mpd_state["{Title}"] .. " "))
|
||||
elseif mpd_state["{state}"] == "pause"
|
||||
then
|
||||
mympd:set_markup(markup(color_artist, " mpd")
|
||||
.. spr ..
|
||||
markup(color_song, " paused "))
|
||||
else
|
||||
helpers.set_map("current mpd track", nil)
|
||||
set_nompd()
|
||||
end
|
||||
end
|
||||
|
||||
local mympdtimer = timer({ timeout = refresh_timeout })
|
||||
mympdtimer:connect_signal("timeout", mympdupdate)
|
||||
mympdtimer:start()
|
||||
mympdtimer:emit_signal("timeout")
|
||||
|
||||
mympd:buttons(awful.util.table.join(
|
||||
awful.button({}, 0,
|
||||
function()
|
||||
helpers.run_in_terminal(musicplr)
|
||||
end)
|
||||
))
|
||||
|
||||
local mpd_out = { widget = mympd, notify = mympdupdate }
|
||||
|
||||
return setmetatable(mpd_out, { __index = mpd_out.widget })
|
||||
end
|
||||
|
||||
return setmetatable(mpd, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,153 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local helpers = require("lain.helpers")
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local io = io
|
||||
local tostring = tostring
|
||||
local string = { format = string.format }
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Network infos
|
||||
-- lain.widgets.net
|
||||
local net = {
|
||||
send = "0",
|
||||
recv = "0",
|
||||
last_t = {},
|
||||
last_r = {}
|
||||
}
|
||||
|
||||
local unit = {
|
||||
["b"] = 1,
|
||||
["kb"] = 1024,
|
||||
["mb"] = 1024^2,
|
||||
["gb"] = 1024^3
|
||||
}
|
||||
|
||||
function net.get_device()
|
||||
f = io.popen("ip link show | cut -d' ' -f2,9")
|
||||
ws = f:read("*all")
|
||||
f:close()
|
||||
ws = ws:match("%w+: UP")
|
||||
if ws ~= nil then
|
||||
return ws:gsub(": UP", "")
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local iface = args.iface or net.get_device()
|
||||
local delta = args.refresh_timeout or 2
|
||||
local unit = args.unit or unit["kb"]
|
||||
local spr = args.spr or " "
|
||||
local header = args.header or iface
|
||||
local header_color = args.header_color or beautiful.fg_normal or "#FFFFFF"
|
||||
local color_up = args.color_up or beautiful.fg_focus or header_color
|
||||
local color_down = args.color_down or beautiful.fg_focus or header_color
|
||||
local app = args.app or "sudo wifi-menu"
|
||||
|
||||
helpers.set_map(iface, true)
|
||||
helpers.set_map("carrier", 0)
|
||||
|
||||
local mynet = wibox.widget.textbox()
|
||||
|
||||
local mynetupdate = function()
|
||||
if iface == "" then
|
||||
iface = net.get_device()
|
||||
header = iface
|
||||
end
|
||||
|
||||
local carrier = helpers.first_line('/sys/class/net/' .. iface ..
|
||||
'/carrier') or ""
|
||||
local state = helpers.first_line('/sys/class/net/' .. iface ..
|
||||
'/operstate')
|
||||
local now_t = helpers.first_line('/sys/class/net/' .. iface ..
|
||||
'/statistics/tx_bytes')
|
||||
local now_r = helpers.first_line('/sys/class/net/' .. iface ..
|
||||
'/statistics/rx_bytes')
|
||||
local text = '<span color="' .. header_color .. '">' .. header .. '</span> '
|
||||
|
||||
if carrier ~= "1"
|
||||
then
|
||||
if helpers.get_map(iface)
|
||||
then
|
||||
n_title = iface
|
||||
if n_title == "" then
|
||||
n_title = "network"
|
||||
header = "Net"
|
||||
end
|
||||
naughty.notify({ title = n_title, text = "no carrier",
|
||||
timeout = 7,
|
||||
position = "top_left",
|
||||
icon = beautiful.lain_no_net_notify or
|
||||
helpers.icons_dir .. "no_net.png",
|
||||
fg = beautiful.fg_focus or "#FFFFFF" })
|
||||
|
||||
mynet:set_markup(markup(header_color, header) .. markup(color_up, " Off"))
|
||||
helpers.set_map(iface, false)
|
||||
end
|
||||
return
|
||||
else
|
||||
helpers.set_map(iface, true)
|
||||
end
|
||||
|
||||
if state == 'down' or not now_t or not now_r
|
||||
then
|
||||
mynet:set_markup(' ' .. text .. '-' .. ' ')
|
||||
return
|
||||
end
|
||||
|
||||
if net.last_t[iface] and net.last_t[iface]
|
||||
then
|
||||
net.send = tostring((now_t - net.last_t[iface]) / delta / unit)
|
||||
net.recv = tostring((now_r - net.last_r[iface]) / delta / unit)
|
||||
|
||||
text = text
|
||||
.. '<span color="' .. color_up .. '">'
|
||||
.. string.format('%.1f', net.send)
|
||||
.. '</span>'
|
||||
.. spr
|
||||
.. '<span color="' .. color_down .. '">'
|
||||
.. string.format('%.1f', net.recv)
|
||||
.. '</span>'
|
||||
|
||||
mynet:set_markup(' ' .. text .. ' ')
|
||||
else
|
||||
mynet:set_markup(' ' .. text .. '-' .. ' ')
|
||||
end
|
||||
|
||||
net.last_t[iface] = now_t
|
||||
net.last_r[iface] = now_r
|
||||
end
|
||||
|
||||
local mynettimer = timer({ timeout = delta })
|
||||
mynettimer:connect_signal("timeout", mynetupdate)
|
||||
mynettimer:start()
|
||||
mynettimer:emit_signal("timeout")
|
||||
|
||||
mynet:buttons(awful.util.table.join(
|
||||
awful.button({}, 0, function()
|
||||
helpers.run_in_terminal(app)
|
||||
mynetupdate()
|
||||
end)))
|
||||
|
||||
net.widget = mynet
|
||||
|
||||
return setmetatable(net, { __index = net.widget })
|
||||
end
|
||||
|
||||
return setmetatable(net, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
* (c) 2010-2012, Peter Hofmann
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
local helpers = require("lain.helpers")
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local io = io
|
||||
local string = { format = string.format,
|
||||
match = string.match }
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- System load
|
||||
-- lain.widgets.sysload
|
||||
local sysload = {}
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local refresh_timeout = args.refresh_timeout or 5
|
||||
local show_all = args.show_all or false
|
||||
local header = args.header or " Load "
|
||||
local header_color = args.header_color or beautiful.fg_normal or "#FFFFFF"
|
||||
local color = args.color or beautiful.fg_focus or header_color
|
||||
local app = args.app or "top"
|
||||
|
||||
local mysysload = wibox.widget.textbox()
|
||||
|
||||
local mysysloadupdate = function()
|
||||
local f = io.open("/proc/loadavg")
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
|
||||
if show_all
|
||||
then
|
||||
local a, b, c = string.match(ret, "([^%s]+) ([^%s]+) ([^%s]+)")
|
||||
mysysload:set_text(string.format("%s %s %s", a, b, c))
|
||||
else
|
||||
local a = string.match(ret, "([^%s]+) ")
|
||||
mysysload:set_text(string.format("%s", a))
|
||||
end
|
||||
mysysload:set_markup(markup(header_color, header) ..
|
||||
markup(color, mysysload._layout.text .. " "))
|
||||
end
|
||||
|
||||
local mysysloadtimer = timer({ timeout = refresh_timeout })
|
||||
mysysloadtimer:connect_signal("timeout", mysysloadupdate)
|
||||
mysysloadtimer:start()
|
||||
mysysloadtimer:emit_signal("timeout")
|
||||
|
||||
mysysload:buttons(awful.util.table.join(
|
||||
awful.button({}, 0,
|
||||
function()
|
||||
helpers.run_in_terminal(app)
|
||||
end)
|
||||
))
|
||||
|
||||
return mysysload
|
||||
end
|
||||
|
||||
return setmetatable(sysload, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
--[[
|
||||
|
||||
Licensed under GNU General Public License v2
|
||||
* (c) 2013, Luke Bonham
|
||||
|
||||
--]]
|
||||
|
||||
local markup = require("lain.util.markup")
|
||||
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local io = io
|
||||
local tonumber = tonumber
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- coretemp
|
||||
-- lain.widgets.temp
|
||||
local temp = {}
|
||||
|
||||
function worker(args)
|
||||
local args = args or {}
|
||||
local refresh_timeout = args.refresh_timeout or 5
|
||||
local header = args.header or " Temp "
|
||||
local header_color = args.header_color or beautiful.fg_normal or "#FFFFFF"
|
||||
local color = args.color or beautiful.fg_focus or header_color
|
||||
local footer = args.footer or "C "
|
||||
|
||||
local mytemp = wibox.widget.textbox()
|
||||
|
||||
local mytempupdate = function()
|
||||
local f = io.open("/sys/class/thermal/thermal_zone0/temp")
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
|
||||
ret = tonumber(ret) / 1000
|
||||
|
||||
mytemp:set_markup(markup(header_color, header) ..
|
||||
markup(color, ret .. footer))
|
||||
end
|
||||
|
||||
local mytemptimer = timer({ timeout = refresh_timeout })
|
||||
mytemptimer:connect_signal("timeout", mytempupdate)
|
||||
mytemptimer:start()
|
||||
mytemptimer:emit_signal("timeout")
|
||||
|
||||
return mytemp
|
||||
end
|
||||
|
||||
return setmetatable(temp, { __call = function(_, ...) return worker(...) end })
|
|
@ -0,0 +1,133 @@
|
|||
=========================================
|
||||
Yahoo's Awesome (WM) Weather Notification
|
||||
=========================================
|
||||
|
||||
----------------
|
||||
Lain integration
|
||||
----------------
|
||||
|
||||
:Author: Luke Bonham <dada [at] archlinux [dot] info>
|
||||
:License: WTFPLv2_
|
||||
:Version: 2.0-git
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Yawn is a module for Awesome WM providing brief and compact
|
||||
weather notification via Naughty and Yahoo! Weather API.
|
||||
|
||||
Originally a port of perceptive_, it became a completely new module after various improvements and style changes.
|
||||
|
||||
-----
|
||||
Usage
|
||||
-----
|
||||
|
||||
You can ``register`` Yawn to get a set of widgets, or ``attach`` it to
|
||||
an existent widget.
|
||||
|
||||
register
|
||||
^^^^^^^^
|
||||
|
||||
Call: ::
|
||||
|
||||
lain.widgets.yawn(id, args)
|
||||
|
||||
Arguments:
|
||||
|
||||
``id``
|
||||
An integer that defines the WOEID code of your city.
|
||||
To obtain it you can google 'yahoo weather %CITYNAME%' and follow the first link.
|
||||
It will look like::
|
||||
|
||||
http://weather.yahoo.com/united-states/california/san-diego-2487889/
|
||||
|
||||
and the last number in that link will be the ID you need.
|
||||
``args``
|
||||
An optional table which can contain the following settings:
|
||||
``u``
|
||||
Units. Type: string. Possible values: "c" (Celsius), "f" (Fahrenheit). Default: "c".
|
||||
|
||||
``toshow``
|
||||
What to show. Type: string. Possible values: "units", "forecast", "both".
|
||||
Default: "forecast".
|
||||
|
||||
``units_color``
|
||||
Color of units text. Type: string. Possible values: hexadecimal color
|
||||
codes.
|
||||
|
||||
``forecast_color``
|
||||
Color of forecast text. Type: string. Possible values: hexadecimal color
|
||||
codes.
|
||||
|
||||
``notification_color``
|
||||
Color of notification text. Type: string. Possible values: hexadecimal color
|
||||
codes.
|
||||
|
||||
``spr``
|
||||
A separator. Type: string. You can define it when ``toshow`` is set to "both".
|
||||
|
||||
``footer``
|
||||
A footer. Type: string. You can define it when ``toshow`` is set to
|
||||
"both".
|
||||
|
||||
The function creates an imagebox icon and a textbox widget. Add them to you wibox like this: ::
|
||||
|
||||
right_layout:add(lain.widgets.yawn.icon)
|
||||
right_layout:add(lain.widgets.yawn.widget)
|
||||
|
||||
Hovering over ``yawn.icon`` will display the notification.
|
||||
|
||||
attach
|
||||
^^^^^^
|
||||
|
||||
Call: ::
|
||||
|
||||
lain.widgets.yawn.attach(widget, id, args)
|
||||
|
||||
Arguments:
|
||||
|
||||
``widget``
|
||||
The widget which you want to attach yawn to.
|
||||
``id``
|
||||
same as in ``register``
|
||||
``args``
|
||||
same as in ``register``
|
||||
|
||||
Hovering over ``widget`` will display the notification.
|
||||
|
||||
--------------
|
||||
Popup shortcut
|
||||
--------------
|
||||
|
||||
You can also create a keybinding for the weather popup like this: ::
|
||||
|
||||
globalkeys = awful.util.table.join(
|
||||
...
|
||||
awful.key( { "Mod1" }, "w", function () lain.widgets.yawn.show(5) end )
|
||||
...
|
||||
|
||||
where ``show`` argument is an integer defining timeout seconds.
|
||||
|
||||
------------
|
||||
Localization
|
||||
------------
|
||||
|
||||
Default language is English, but Yawn can be localized.
|
||||
Move to ``localizations`` subdirectory and fill ``localization_template``.
|
||||
|
||||
Once you're done, rename it like your locale id. In my case: ::
|
||||
|
||||
$ lua
|
||||
Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
|
||||
> print(os.getenv("LANG"):match("(%S*$*)[.]"))
|
||||
it_IT
|
||||
>
|
||||
|
||||
hence I named my file "it_IT" (Italian localization).
|
||||
|
||||
**NOTE:** If you create a localization, feel free to send me! I will add it.
|
||||
|
||||
.. _WTFPLv2: http://www.wtfpl.net
|
||||
.. _perceptive: https://github.com/ioga/perceptive
|
||||
.. _Tamsyn: http://www.fial.com/~scott/tamsyn-font/
|
||||
.. _Rainbow: https://github.com/copycat-killer/awesome-copycats>
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 6.9 KiB |