awesome-vain

[Discontinued] Layouts and widgets for AwesomeWM
git clone https://movq.de/git/awesome-vain.git
Log (Feed) - Files - Refs (Feed) - README

README (28564B)


      1                                                              _
      2     __ ___      _____  ___  ___  _ __ ___   ___  __   ____ _(_)_ __
      3    / _` \ \ /\ / / _ \/ __|/ _ \| '_ ` _ \ / _ \ \ \ / / _` | | '_ \
      4   | (_| |\ V  V /  __/\__ \ (_) | | | | | |  __/  \ V / (_| | | | | |
      5    \__,_| \_/\_/ \___||___/\___/|_| |_| |_|\___|   \_/ \__,_|_|_| |_|
      6   https://uninformativ.de/git/awesome-vain
      7   https://uninformativ.de/bugs.html
      8 
      9 
     10 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     11 
     12 
     13 Historical purposes only
     14 ========================
     15 
     16 This is very much outdated and will no longer work with current versions
     17 of Awesome. Please have a look at lcpz's work:
     18 
     19     https://github.com/lcpz/lain
     20     https://github.com/lcpz/vain-again
     21 
     22 
     23 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     24 
     25 
     26 This repository contains stuff I wrote for the [Awesome Window
     27 Manager](http://awesome.naquadah.org/). Essentially, it contains
     28 everything I use in my `rc.lua` that is not trivial: Widgets, layouts,
     29 utility functions. This means, the stuff in here is exceedingly
     30 customized to fit *my* needs. Thus, you shouldn't blindly use it. It's
     31 likely for things to get changed or removed or whatever. Rather than
     32 actually using it, read the code. :)
     33 
     34 All of this is [GPL3+](http://www.gnu.org/licenses/gpl-3.0.txt).
     35 
     36 Note: I'm using the 3.4 branch of Awesome. Thus, this module is likely
     37 to not work with the current git branch.
     38 
     39 
     40 Using it
     41 ========
     42 
     43 Basically, all you have to do is including the module:
     44 
     45 	require("vain")
     46 	vain.widgets.terminal = "xterm"
     47 
     48 Some widgets require a terminal, so you need to set that as well.
     49 `terminal` may also be a lua function that accepts one parameter.
     50 Something like this:
     51 
     52 	function footerm(cmd)
     53         awful.util.spawn("xterm -e " .. cmd)
     54 	end
     55 
     56 	vain.widgets.terminal = footerm
     57 
     58 While this particular is pretty useless, you may come up with something
     59 clever.
     60 
     61 Furthermore, the directory `vain` must be located in the same
     62 directory as your `rc.lua`.
     63 
     64 	$ pwd
     65 	/home/void/.config/awesome
     66 	$ tree -l
     67 	.
     68 	|-- rc.lua
     69 	|-- themes -> ../.awesome-themes/
     70 	|   |-- ...
     71 	|   `-- ...
     72 	`-- vain -> ../.awesome-vain/vain
     73 	    |-- init.lua
     74 	    |-- layout
     75 	    |   |-- browse.lua
     76 	    |   |-- gimp.lua
     77 	    |   |-- init.lua
     78 	    |   |-- termfair.lua
     79 	    |   `-- uselessfair.lua
     80 	    |-- util.lua
     81 	    `-- widgets.lua
     82 
     83 
     84 Layouts
     85 =======
     86 
     87 How do layouts work in general?
     88 -------------------------------
     89 
     90 A "layout" is simply a lua table or module that has an attribute `name`
     91 and a function called `arrange`. So the most simple layout could look
     92 like this:
     93 
     94 	mylayout = {}
     95 	mylayout.name = "hurz"
     96 	mylayout.arrange = function(p) end
     97 
     98 To use this layout on a tag, you have to write:
     99 
    100 	awful.layout.set(mylayout, tags[1][7])
    101 
    102 (Of course, you could just add it to the default table called
    103 `layouts`.)
    104 
    105 Now, the `arrange` function gets a parameter `p` which is another table.
    106 The most important elements of this table are `workarea` and `clients`.
    107 Thus, the table `p` looks similar to this:
    108 
    109 	p = {
    110 	    workarea = { x, y, width, height },
    111 	    clients = { ... },
    112 	    ...
    113 	}
    114 
    115 The job of the `arrange` function is to iterate over all clients and set
    116 their geometry. That is, for each client you have to call `geometry` on
    117 it:
    118 
    119 	mylayout.arrange = arrange(p)
    120 
    121 	    local wa = p.workarea
    122 	    local cls = p.clients
    123 
    124 	    for k, c in ipairs(cls)
    125 	    do
    126 	        local g = {}
    127 
    128 	        g.width = ...
    129 	        g.height = ...
    130 	        g.x = wa.x + ...
    131 	        g.y = wa.y + ...
    132 
    133 	        c:geometry(g)
    134 	    end
    135 	end
    136 
    137 That's it. Awesome handles all the nasty stuff like minimized clients,
    138 floating clients, order of clients, focus, drawing window borders etc.
    139 
    140 What about icons?
    141 -----------------
    142 
    143 Thanks to Nicolas Estibals (https://github.com/nestibal) for creating
    144 icons for Awesome's default theme!
    145 
    146 You have to extend your theme like this (let's say this file is called
    147 `~/.config/awesome/extended_default_theme.lua`):
    148 
    149 	dofile("/usr/share/awesome/themes/default/theme.lua")
    150 	...
    151 	theme.layout_termfair      = os.getenv("HOME") .. "/.config/awesome/vain/themes/default/layouts/termfairw.png"
    152 	theme.layout_browse        = os.getenv("HOME") .. "/.config/awesome/vain/themes/default/layouts/browsew.png"
    153 	theme.layout_gimp          = os.getenv("HOME") .. "/.config/awesome/vain/themes/default/layouts/gimpw.png"
    154 	theme.layout_cascade       = os.getenv("HOME") .. "/.config/awesome/vain/themes/default/layouts/cascadew.png"
    155 	theme.layout_cascadebrowse = os.getenv("HOME") .. "/.config/awesome/vain/themes/default/layouts/cascadebrowsew.png"
    156 	theme.layout_centerwork    = os.getenv("HOME") .. "/.config/awesome/vain/themes/default/layouts/centerworkw.png"
    157 	theme.layout_ppres         = os.getenv("HOME") .. "/.config/awesome/vain/themes/default/layouts/ppresw.png"
    158 	...
    159 	return theme
    160 
    161 Then, you can tell `beautiful` to use this extended theme:
    162 
    163 	beautiful.init(os.getenv("HOME") .. "/.config/awesome/extended_default_theme.lua")
    164 
    165 Icons for the default theme are available in black and white. There's
    166 also a set of icons for the "zenburn" theme (this is what I use).
    167 
    168 What do my layouts do?
    169 ----------------------
    170 
    171 ### termfair
    172 I do a lot of work on terminals. The common tiling algorithms usually
    173 maximize windows, so you'll end up with a terminal that has about 200
    174 columns or more. That's way too much. Have you ever read a manpage in a
    175 terminal of this size?
    176 
    177 This layout restricts the size of each window. Each window will have the
    178 same width but is variable in height. Furthermore, windows are
    179 left-aligned. The basic workflow is as follows (the number above the
    180 screen is the number of open windows, the number in a cell is the fixed
    181 number of a client):
    182 
    183 	     (1)                (2)                (3)
    184 	+---+---+---+      +---+---+---+      +---+---+---+
    185 	|   |   |   |      |   |   |   |      |   |   |   |
    186 	| 1 |   |   |  ->  | 2 | 1 |   |  ->  | 3 | 2 | 1 |  ->
    187 	|   |   |   |      |   |   |   |      |   |   |   |
    188 	+---+---+---+      +---+---+---+      +---+---+---+
    189 
    190 	     (4)                (5)                (6)
    191 	+---+---+---+      +---+---+---+      +---+---+---+
    192 	| 4 |   |   |      | 5 | 4 |   |      | 6 | 5 | 4 |
    193 	+---+---+---+  ->  +---+---+---+  ->  +---+---+---+
    194 	| 3 | 2 | 1 |      | 3 | 2 | 1 |      | 3 | 2 | 1 |
    195 	+---+---+---+      +---+---+---+      +---+---+---+
    196 
    197 The first client will be located in the left column. When opening
    198 another window, this new window will be placed in the left column while
    199 moving the first window into the middle column. Once a row is full,
    200 another row above it will be created.
    201 
    202 The number of columns is fixed and controlled by the value of `nmaster`
    203 of the tag. The number of rows is usually variable but you can set a
    204 minimum by setting `ncol` of the tag.
    205 
    206 This sets the `termfair` layout on tag 7 of screen 1 and sets it to 3
    207 columns and at least 2 rows:
    208 
    209 	awful.layout.set(vain.layout.termfair, tags[1][7])
    210 	awful.tag.setnmaster(3, tags[1][7])
    211 	awful.tag.setncol(2, tags[1][7])
    212 
    213 ### browse
    214 A very wide browser window is a pain. Some pages do restrict their width
    215 but others don't. The latter will be unreadable because your eye has to
    216 keep track of very long lines.
    217 
    218 The `browse` layout has a fixed column on the left which is meant for
    219 the browser. Its size is controlled by `mwfact` of the tag. Additional
    220 windows will be opened in another column right to your browser. New
    221 windows are placed above old windows.
    222 
    223 	    (1)              (2)              (3)              (4)
    224 	+-----+---+      +-----+---+      +-----+---+      +-----+---+
    225 	|     |   |      |     |   |      |     | 3 |      |     | 4 |
    226 	|     |   |      |     |   |      |     |   |      |     +---+
    227 	|  1  |   |  ->  |  1  | 2 |  ->  |  1  +---+  ->  |  1  | 3 |
    228 	|     |   |      |     |   |      |     | 2 |      |     +---+
    229 	|     |   |      |     |   |      |     |   |      |     | 2 |
    230 	+-----+---+      +-----+---+      +-----+---+      +-----+---+
    231 
    232 For my laptop, I place the right column *on top of* the browser column:
    233 Additional windows will overlap the browser window. This is unusual for
    234 a tiling layout but I need it: When browsing the web, I often want to
    235 open a terminal window (just for a few minutes, then I'll close it).
    236 Typically, the browser window would get resized and for most browsers
    237 this means that the current position in the web page is lost. Hence, I'd
    238 need to scroll the page to reach that point where I was before I opened
    239 the terminal. That's a mess.
    240 
    241 Whether the slave column is place on top of the browser window or not is
    242 controlled by the value of `ncol` of the tag. A value of 1 means
    243 "overlapping slave column" and anything else means "don't overlap
    244 windows".
    245 
    246 Thus, the following sets the `browse` layout on tag 7 of screen 1. The
    247 main column will have half of the screen width and there will be a
    248 separate column for slave windows.
    249 
    250 	awful.layout.set(vain.layout.browse, tags[1][7])
    251 	awful.tag.setmwfact(0.5, tags[1][2])
    252 	awful.tag.setncol(1, tags[1][7])
    253 	vain.layout.browse.extra_padding = 5
    254 
    255 `extra_padding` reduces the size of the main window if "overlapping
    256 slave column" is activated. This allows you to see if there are any
    257 windows in your slave column.
    258 
    259 ### gimp
    260 *Please note: Since Gimp 2.8, this layout is deprecated and no longer
    261 maintained. It may still work but I don't use it anymore. Gimp 2.8 has a
    262 "single window mode" which does all I need.*
    263 
    264 Gimp is something very special. A lot of people don't use Gimp because
    265 it has "so many windows". Using an own layout for Awesome, you can solve
    266 this "problem". (I don't consider it a problem, actually.)
    267 
    268 The `gimp` layout uses one big slot for Gimp's image window. To the
    269 right, there's one slot for each toolbox or dock. Windows that are *not*
    270 Gimp windows are set to floating mode.
    271 
    272 	+-------+---+---+
    273 	|       |   |   |
    274 	| Image | T | D |
    275 	|       |   |   |
    276 	+-------+---+---+
    277 
    278 By default (i.e., if `ncol` is 1), when opening another image window, it
    279 will be placed over the first window overlapping it. So usually, you
    280 only see one image window because that's the image you're working on.
    281 You can use an application switcher or hotkeys to switch to other image
    282 windows (see `menu_clients_current_tags` in the section "Utility
    283 functions").
    284 
    285 Sometimes, you may need to get a better overview. By setting the value
    286 of `ncol` to 2, you can switch to "cascade mode":
    287 
    288 	+-------------+---+---+
    289 	|     +-----+ |   |   |
    290 	|     |     | |   |   |
    291 	|   +-| Img | |   |   |
    292 	|   | |     | |   |   |
    293 	| +-| +-----+ | T | D |
    294 	| | |     |   |   |   |
    295 	| | +-----+   |   |   |
    296 	| |     |     |   |   |
    297 	| +-----+     |   |   |
    298 	+-------------+---+---|
    299 
    300 You can control the offset for each window by setting the global
    301 variable `vain.layout.gimp.cascade_offset`. The default value is 16
    302 pixels.
    303 
    304 When setting `ncol` to 2, all images will be stacked in the main slot:
    305 
    306 	+-------+---+---+
    307 	| Image |   |   |
    308 	+-------+   |   |
    309 	| Image | T | D |
    310 	+-------+   |   |
    311 	| Image |   |   |
    312 	+-------+---+---+
    313 
    314 Again, `mwfact` controls the width of the main slot. So, the following
    315 will use the `gimp` layout on tag 7 of screen 1, defaulting to "stacking
    316 mode" and the main slot will have a width of 75% of your screen:
    317 
    318 	awful.layout.set(vain.layout.gimp, tags[1][7])
    319 	awful.tag.setmwfact(0.75, tags[1][2])
    320 	awful.tag.setncol(3, tags[1][7])
    321 
    322 However, this is not enough. Default Awesome rules will set the
    323 toolboxes and docks to floating mode because they are *utility windows*.
    324 But: A layout doesn't manage floating windows. So we'll need a set of
    325 rules that set Gimp toolboxes back to normal mode. You have to merge
    326 this set of rules with your existing rules:
    327 
    328 	awful.rules.rules = awful.util.table.join(
    329 	    awful.rules.rules,
    330 	    vain.layout.gimp.rules
    331 	)
    332 
    333 You can still use your own rules, for example, to move Gimp windows to a
    334 specific tag.
    335 
    336 ### cascade
    337 Cascade all windows (see gimp layout) of a tag.
    338 
    339 Similarly, you can control the offsets by setting those two variables:
    340 
    341 	vain.layout.cascade.cascade_offset_x = 64
    342 	vain.layout.cascade.cascade_offset_y = 16
    343 
    344 The following reserves space for 5 windows:
    345 
    346 	awful.tag.setnmaster(5, tags[s][1])
    347 
    348 That is, no window will get resized upon the creation of a new window,
    349 unless there's more than 5 windows.
    350 
    351 ### cascadebrowse
    352 Similar to the regular `browse` layout, however, clients in the slave
    353 column are cascaded instead of tiled. Thus, there's a similar set of
    354 settings:
    355 
    356 	vain.layout.cascadebrowse.cascade_offset_x = 2
    357 	vain.layout.cascadebrowse.cascade_offset_y = 32
    358 	vain.layout.cascadebrowse.extra_padding = 5
    359 	awful.tag.setnmaster(5, tags[s][1])
    360 	awful.tag.setncol(1, tags[s][1])
    361 
    362 I recommend setting `cascade_offset_x` to a very small value or even 0
    363 to avoid wasting space.
    364 
    365 See the `browse` layout for an explanation of `extra_padding` and
    366 `ncol`.
    367 
    368 ### uselessfair
    369 This is a duplicate of the stock `fair` layouts. However, I added
    370 "useless gaps" (see below) to this layout. Use it like this:
    371 
    372 	awful.layout.set(vain.layout.uselessfair, tags[1][7])
    373 
    374 ### centerwork
    375 You start with one window, centered horizontally:
    376 
    377 	+--------------------------+
    378 	|       +----------+       |
    379 	|       |          |       |
    380 	|       |          |       |
    381 	|       |          |       |
    382 	|       |   MAIN   |       |
    383 	|       |          |       |
    384 	|       |          |       |
    385 	|       |          |       |
    386 	|       |          |       |
    387 	|       +----------+       |
    388 	+--------------------------+
    389 
    390 This is your main working window. You do most of the work right here.
    391 Sometimes, you may want to open up additional windows. They're put in
    392 the following four slots:
    393 
    394 	+--------------------------+
    395 	| +---+ +----------+ +---+ |
    396 	| |   | |          | |   | |
    397 	| | 0 | |          | | 1 | |
    398 	| |   | |          | |   | |
    399 	| +---+ |   MAIN   | +---+ |
    400 	| +---+ |          | +---+ |
    401 	| |   | |          | |   | |
    402 	| | 2 | |          | | 3 | |
    403 	| |   | |          | |   | |
    404 	| +---+ +----------+ +---+ |
    405 	+--------------------------+
    406 
    407 Yes, the number "four" is fixed. In total, you can only have five open
    408 windows with this layout. Additional windows are not managed and set to
    409 floating mode. This is intentional.
    410 
    411 Set the layout on one of your tags:
    412 
    413 	awful.layout.set(vain.layout.centerwork, tags[s][t])
    414 
    415 You can set the order of the four auxiliary windows. This is the default
    416 configuration:
    417 
    418 	vain.layout.centerwork.top_left = 0
    419 	vain.layout.centerwork.top_right = 1
    420 	vain.layout.centerwork.bottom_left = 2
    421 	vain.layout.centerwork.bottom_right = 3
    422 
    423 This means: The bottom left slot will be occupied by the third window
    424 (not counting the main window). Suppose you want your windows to appear
    425 in this order:
    426 
    427 	+--------------------------+
    428 	| +---+ +----------+ +---+ |
    429 	| |   | |          | |   | |
    430 	| | 3 | |          | | 0 | |
    431 	| |   | |          | |   | |
    432 	| +---+ |   MAIN   | +---+ |
    433 	| +---+ |          | +---+ |
    434 	| |   | |          | |   | |
    435 	| | 2 | |          | | 1 | |
    436 	| |   | |          | |   | |
    437 	| +---+ +----------+ +---+ |
    438 	+--------------------------+
    439 
    440 This would require you to use these settings:
    441 
    442 	vain.layout.centerwork.top_left = 3
    443 	vain.layout.centerwork.top_right = 0
    444 	vain.layout.centerwork.bottom_left = 2
    445 	vain.layout.centerwork.bottom_right = 1
    446 
    447 *Please note:* If you use Awesome's default configuration, navigation in
    448 this layout may be very confusing. How do you get from the main window
    449 to the window on the bottom left? This depends on the order in which the
    450 windows are opened! Thus, I suggest you use
    451 `awful.client.focus.bydirection()`:
    452 
    453 	globalkeys = awful.util.table.join(
    454 	    awful.key({ modkey }, "j",
    455 	        function()
    456 	            awful.client.focus.bydirection("down")
    457 	            if client.focus then client.focus:raise() end
    458 	        end),
    459 	    awful.key({ modkey }, "k",
    460 	        function()
    461 	            awful.client.focus.bydirection("up")
    462 	            if client.focus then client.focus:raise() end
    463 	        end),
    464 	    awful.key({ modkey }, "h",
    465 	        function()
    466 	            awful.client.focus.bydirection("left")
    467 	            if client.focus then client.focus:raise() end
    468 	        end),
    469 	    awful.key({ modkey }, "l",
    470 	        function()
    471 	            awful.client.focus.bydirection("right")
    472 	            if client.focus then client.focus:raise() end
    473 	        end),
    474 	    -- ...
    475 	)
    476 
    477 ### ppres
    478 [ppres](https://github.com/vain/ppres) is a toolchest for presenting
    479 PDFs. It uses multiple windows so it's the window manager's job to
    480 organize those windows.
    481 
    482 The layout is as follows:
    483 
    484 	+----------+  +----------+  +---------+
    485 	| Previous |  | Current  |  | Next    |
    486 	|    slide |  |    slide |  |   slide |
    487 	+----------+  +----------+  +---------+
    488 	+-------+ +-------+ +-------+ +-------+
    489 	| other | | other | | other | | other |
    490 	+-------+ +-------+ +-------+ +-------+
    491 
    492 There's a main column at the top and a slave column at the bottom.
    493 ppres windows have unique class and instance names and they're sorted
    494 according to them. ppres also has a "projector" window which is set to
    495 floating mode so you can easily move it around.
    496 
    497 All other windows are tiled in the slave column.
    498 
    499 Note: This layout has no support for useless gaps.
    500 
    501 Useless gaps
    502 ------------
    503 
    504 Useless gaps are gaps between windows. They are "useless" because they
    505 serve no special purpose despite increasing overview. I find it easier
    506 to recognize window boundaries if windows are set apart a little bit.
    507 
    508 The `uselessfair` layout, for example, looks like this:
    509 
    510 	+================+
    511 	#                #
    512 	#  +---+  +---+  #
    513 	#  | 1 |  |   |  #
    514 	#  +---+  |   |  #
    515 	#         | 3 |  #
    516 	#  +---+  |   |  #
    517 	#  | 2 |  |   |  #
    518 	#  +---+  +---+  #
    519 	#                #
    520 	+================+
    521 
    522 All of my layouts provide useless gaps. To set the width of the gap,
    523 you'll have to extend your `beautiful` theme. There must be an item
    524 called `useless_gap_width` in the `theme` table. If it doesn't exist,
    525 the width will default to 0.
    526 
    527 	...
    528 	theme.useless_gap_width = "5"
    529 	...
    530 
    531 
    532 Widgets
    533 =======
    534 
    535 Each function returns a widget that can be used in wiboxes. Most widgets
    536 are updated periodically; see the code for the default timer values.
    537 
    538 ## systemload
    539 Show the current system load in a textbox. Read it directly from
    540 `/proc/loadavg`.
    541 
    542 	mysysload = vain.widgets.systemload()
    543 
    544 A click on the widget will call `htop` in your `terminal`.
    545 
    546 The function takes a table as an optional argument. That table may
    547 contain:
    548 
    549 * `.refresh_timeout`: Defaults to 10 seconds.
    550 * `.show_all`: Show all three values (`true`) or only the first one
    551   (`false`)? Defaults to `false`.
    552 
    553 ## cpuusage
    554 Show the average CPU usage for a given amount of time. This is what
    555 `htop` does.
    556 
    557 	mycpuusage = vain.widgets.cpuusage()
    558 
    559 A click on the widget will call `htop` in your `terminal`.
    560 
    561 The function takes a table as an optional argument. That table may
    562 contain:
    563 
    564 * `.refresh_timeout`: Defaults to 10 seconds.
    565 
    566 ## memusage
    567 Show used memory and total memory in MiB. Read from `/proc/meminfo`.
    568 
    569 	mymemusage = vain.widgets.memusage()
    570 
    571 A click on the widget will call `htop` in your `terminal`.
    572 
    573 The function takes a table as an optional argument. That table may
    574 contain:
    575 
    576 * `.refresh_timeout`: Defaults to 10 seconds.
    577 * `.show_swap`: Show amount of used swap space? Defaults to `false`.
    578 
    579 ## mailcheck
    580 Check Maildirs and show the result in a textbox. For example, I have a
    581 set of Maildirs below `~/Mail`:
    582 
    583 	$ pwd
    584 	/home/void/Mail
    585 	$ tree -ad
    586 	.
    587 	|-- bugs
    588 	|   |-- cur
    589 	|   |-- new
    590 	|   `-- tmp
    591 	|-- lists
    592 	|   |-- cur
    593 	|   |-- new
    594 	|   `-- tmp
    595 	|-- system
    596 	|   |-- cur
    597 	|   |-- new
    598 	|   `-- tmp
    599 	.
    600 	.
    601 	.
    602 
    603 The `mailcheck` widget checks whether there are files in the `new`
    604 directories. To do so, it calls `find`. If there's new mail, the textbox
    605 will say something like "mail: bugs(3), system(1)", otherwise it says
    606 "no mail".
    607 
    608 	mymailcheck = vain.widgets.mailcheck()
    609 
    610 The function takes a table as an optional argument. That table may
    611 contain:
    612 
    613 * `.refresh_timeout`: Defaults to 30 seconds.
    614 * `.mailpath`: Path to your maildirs, defaults to `~/Mail`.
    615 * `.ignore_boxes`: Another table which lists boxes (just the last part,
    616   like `lists`) to ignore. Defaults to an empty table.
    617 * `.initial_update`: Check for mail when starting Awesome (`true`) or
    618   wait for the first refresh timeout (`false`)? Defaults to `true`.
    619 
    620 When clicking on the widget, the bash alias `smail` is called. That's a
    621 wrapper script for [mutt](http://www.mutt.org/) which I use: It
    622 automatically commits to a [git](http://git-scm.com/) repository after
    623 I've read mail.
    624 
    625 `beautiful.mailcheck_new` may contain a color. The new-mail-message is
    626 shown in this color. Uses red if undefined.
    627 
    628 ## battery
    629 Show the remaining time and capacity of your laptop battery, as well as
    630 the current wattage. Uses the `/sys` filesystem.
    631 
    632 	mybattery = vain.widgets.battery()
    633 
    634 The function takes a table as an optional argument. That table may
    635 contain:
    636 
    637 * `.refresh_timeout`: Defaults to 30 seconds.
    638 * `.battery`: Identifier of the battery to watch, defaults to `BAT0`.
    639 
    640 ## volume
    641 Show and control the current volume in a textbox. Periodically calls the
    642 `control_volume` script to get the current volume. That same script is
    643 used to set the volume. See below.
    644 
    645 * Left click: Mute/unmute.
    646 * Right click: Mute/unmute.
    647 * Middle click: Launch `alsamixer` in your `terminal`.
    648 * Scroll wheel: Increase/decrase volume.
    649 
    650 	myvolume = vain.widgets.volume()
    651 
    652 The function takes a table as an optional argument. That table may
    653 contain:
    654 
    655 * `.refresh_timeout`: Defaults to 2 seconds.
    656 * `.mixer_channel`: Defaults to `Master`.
    657 
    658 I currently use a script similar to the following as
    659 `control_volume`:
    660 
    661 	#!/bin/bash
    662 	channel=${2:-Master}
    663 	case $1 in
    664 		up)
    665 			mpc volume +2
    666 			;;
    667 		down)
    668 			mpc volume -2
    669 			;;
    670 		toggle)
    671 			amixer set $channel toggle
    672 			;;
    673 		get)
    674 			mpc volume | sed -r 's/^volume: ?([^%]+)%.*/\1/'
    675 
    676 			echo -n ' '
    677 
    678 			amixer get $channel |
    679 			sed -rn 's/.*\[([a-z]+)\]/\1/p' |
    680 			head -1
    681 			;;
    682 	esac
    683 
    684 That is, I get and set volume via
    685 [mpd](http://en.wikipedia.org/wiki/Music_Player_Daemon). I used to do
    686 all of that via `amixer` but this tool gets more and more broken. For
    687 example, once the volume reached 0%, `amixer` can't get it back.
    688 
    689 This is a very ugly solution. I decided to use a wrapper script so I
    690 don't need to touch my Awesome configuration once I find a better
    691 solution.
    692 
    693 ## mpd
    694 Provides a set of imageboxes to control a running instance of mpd on
    695 your local host. Also provides controls similiar to the volume widget.
    696 To control mpd, `mpc` is used.
    697 
    698 * Right click on any icon: Mute/unmute via `control_volume`. See above.
    699 * Middle click on any icon: Call `ncmpcpp` in your `terminal`.
    700 
    701 This function does not return one widget but a table of widgets. For
    702 now, you'll have to add them one for one to your wibox:
    703 
    704 	mpdtable = vain.widgets.mpd()
    705 	...
    706 	mywibox[s].widgets = {
    707 	    ...
    708 	    mpdtable[1],
    709 	    mpdtable[2],
    710 	    mpdtable[3],
    711 	    mpdtable[4],
    712 	    mpdtable[5],
    713 	    mpdtable[6],
    714 	    ...
    715 	}
    716 
    717 The function takes a table as an optional argument. That table may
    718 contain:
    719 
    720 * `.mixer_channel`: Defaults to `Master`.
    721 * `.show_label`: Determines whether `mpd:` is shown in front of the
    722   control icons. Defaults to `true`.
    723 
    724 ## net
    725 Monitors network interfaces and shows current traffic in a textbox. If
    726 the interface is not present or if there's not enough data yet, you'll
    727 see `wlan0: -` or similar.  Otherwise, the current traffic is shown in
    728 kilobytes per second as `eth0: ↑(00,010.2), ↓(01,037.8)` or similar.
    729 
    730 	neteth0 = vain.widgets.net()
    731 
    732 The function takes a table as an optional argument. That table may
    733 contain:
    734 
    735 * `.refresh_timeout`: Defaults to 2 seconds.
    736 * `.iface`: Defaults to `eth0`.
    737 
    738 ## gitodo
    739 This is an integration of [gitodo](https://github.com/vain/gitodo) into
    740 Awesome.
    741 
    742 	todolist = vain.widgets.gitodo()
    743 
    744 The function takes a table as an optional argument. That table may
    745 contain:
    746 
    747 * `.refresh_timeout`: Defaults to 120 seconds.
    748 * `.initial_update`: Check for todo items when starting Awesome (`true`)
    749   or wait for the first refresh timeout (`false`)? Defaults to `true`.
    750 
    751 `beautiful.gitodo_normal` is used as the color for non-outdated items,
    752 `beautiful.gitodo_warning` for those items close to their deadline and
    753 `beautiful.gitodo_outdated` is the color of outdated items.
    754 
    755 ## borderbox
    756 Creates a thin wibox at a position relative to another wibox. This
    757 allows you to create "separators" or "borders" for your wiboxes. For
    758 example, think of this as a wibox:
    759 
    760 	[======================]
    761 
    762 If `args.position = 'above'`, then you'll get an additional wibox below
    763 the existing one:
    764 
    765 	________________________
    766 	[======================]
    767 
    768 It'll match position and size of the existing wibox.
    769 
    770 If your main wiboxes are stored in a table called `mywibox` (one wibox
    771 for each screen) and are located at the bottom of your screen, then this
    772 adds a borderbox on top of them:
    773 
    774 	for s = 1, screen.count()
    775 	do
    776 	    -- Most likely, you'll want to do this as well:
    777 	    awful.screen.padding(screen[s], { bottom = 1 })
    778 
    779 	    -- Create the box and place it above the existing box.
    780 	    vain.widgets.borderbox(mywibox[s], s, { position = 'above' } )
    781 	end
    782 
    783 `borderbox()` is defined as follows:
    784 
    785 	function borderbox(relbox, s, args)
    786 
    787 `relbox` and `s` (a number) are required arguments, `args` is optional.
    788 `args` may contain:
    789 
    790 * `.position`: One of `above`, `below`, `left` and `right`. Defaults to
    791   `above`.
    792 * `.color`: The color of the additional box. Defaults to `#FFFFFF`.
    793 * `.size`: The size of the additional box, measured in pixels. Defaults
    794   to `1`.
    795 
    796 
    797 Utility functions
    798 =================
    799 
    800 I'll only explain the more complex functions. See the source code for
    801 the others.
    802 
    803 ## menu\_clients\_current\_tags
    804 Similar to `awful.menu.clients()`, but this menu only shows the clients
    805 of currently visible tags. Use it like this:
    806 
    807 	globalkeys = awful.util.table.join(
    808 	    ...
    809 	    awful.key({ "Mod1" }, "Tab", function()
    810 	        awful.menu.menu_keys.down = { "Down", "Alt_L", "Tab", "j" }
    811 	        awful.menu.menu_keys.up = { "Up", "k" }
    812 	        vain.util.menu_clients_current_tags({ width = 350 }, { keygrabber = true })
    813 	    end),
    814 	    ...
    815 	)
    816 
    817 ## magnify\_client
    818 Set a client to floating and resize it in the same way the "magnifier"
    819 layout does it. Place it on the "current" screen (derived from the mouse
    820 position). This allows you to magnify any client you wish, regardless of
    821 the currently used layout. Use it with a client keybinding like this:
    822 
    823 	clientkeys = awful.util.table.join(
    824 		...
    825 		awful.key({ modkey, "Control" }, "m", vain.util.magnify_client),
    826 		...
    827 	)
    828 
    829 If you want to "de-magnify" it, just reset the clients floating state to
    830 `false` (hit `Mod`+`CTRL`+`Space`, for example).
    831 
    832 ## Window borders colored according to nice values
    833 By default, your `rc.lua` contains something like this:
    834 
    835 	client.add_signal("focus", function(c) c.border_color = beautiful.border_focus end)
    836 	client.add_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
    837 
    838 You can change it to this:
    839 
    840 	client.add_signal("focus", vain.util.niceborder_focus)
    841 	client.add_signal("unfocus", vain.util.niceborder_unfocus)
    842 
    843 Now, when a client is focused or unfocused, Awesome will look up its
    844 nice value in `/proc/<pid>/stat`. If it's less than 0, this window is
    845 classified as "high priority"; if it's greater than 0, the window is
    846 classified as "low priority". If it's equal to 0, nothing special
    847 happens.
    848 
    849 This requires to define additional colors in your `theme.lua`. This is
    850 what I use:
    851 
    852 	theme.border_focus_highprio  = "#FF0000"
    853 	theme.border_normal_highprio = "#A03333"
    854 
    855 	theme.border_focus_lowprio   = "#3333FF"
    856 	theme.border_normal_lowprio  = "#333366"
    857 
    858 ## tag\_view{next,prev}\_nonempty
    859 Maybe you're using a taglist that shows only non-empty tags:
    860 
    861 	mytaglist = awful.widget.taglist(s, awful.widget.taglist.label.noempty, mytaglist.buttons)
    862 	--                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    863 
    864 Now, the default setup looks something like this:
    865 
    866 	globalkeys = awful.util.table.join(
    867 		-- Standard navigation
    868 		awful.key({ modkey }, "Left",   awful.tag.viewprev),
    869 		awful.key({ modkey }, "Right",  awful.tag.viewnext),
    870 		...
    871 
    872 So when pressing `modkey + right`, you jump to the next tag. However,
    873 when only showing non-empty tags, the target tag may be empty! I don't
    874 like that. I always want to jump to the next non-empty tag.
    875 
    876 `tag_viewnext_nonempty()` and `tag_viewprev_nonempty()` do exactly this.
    877 How to use them:
    878 
    879 	globalkeys = awful.util.table.join(
    880 		-- Standard navigation
    881 		awful.key({ modkey }, "Left",   vain.util.tag_viewprev_nonempty),
    882 		awful.key({ modkey }, "Right",  vain.util.tag_viewnext_nonempty),
    883 		...
    884 
    885 Note: To jump to an empty tag, you now must address it directly. That
    886 is, press `modkey + 4` or similar.