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.