├── .gitignore ├── recipes ├── .luacheckrc ├── awesomewm-font.ttf ├── gpmdp.mdwn ├── xrandr.mdwn ├── awesome-taglist.mdwn ├── mic.mdwn ├── countdown.mdwn ├── wirelessStatus.mdwn ├── mpc.mdwn ├── gpmdp.lua ├── xrandr.lua ├── mic.lua ├── watch.mdwn ├── mpc.lua └── wirelessStatus.lua ├── images ├── bg_t.gif ├── bg_menu.gif ├── bullet.gif ├── screen.png ├── top_bg.gif ├── top_bg_.gif ├── 6mon.medium.png ├── 6mon.small.png ├── icons │ ├── aw_16.png │ ├── aw_22.png │ ├── aw_32.png │ ├── aw_48.png │ ├── aw_64.png │ ├── aw_64_shadow.png │ ├── moon.svg │ └── sun.svg ├── awesome-taglist.png ├── awesome-taglist-outline.png ├── website │ ├── aw-block_website-header-1.png │ ├── aw-block_website-header-2.png │ ├── aw-block_website-header-3.png │ ├── aw-block_website-header-4.png │ └── aw-block_website-banner-860-140px.png ├── arrow.svg ├── awesome-logo.svg ├── awesome2.svg ├── awesome3.svg ├── awesome1.svg ├── awesome-dark-2.svg ├── awesome-dark-1.svg └── awesome-15yrs-anniversary.svg ├── .gitmodules ├── README.for_webpage.md ├── screenshots.mdwn ├── doc.mdwn ├── css ├── light.css ├── dark.css ├── mode-switch.css └── local.css ├── script ├── dark-light-mode.js └── dark-light-mode-switch.js ├── Makefile ├── community.mdwn ├── doing_a_release.mdwn ├── recipes.mdwn ├── README.md ├── index.mdwn ├── download.mdwn ├── releases.mdwn ├── .github └── workflows │ └── www.yml └── templates └── page.tmpl /.gitignore: -------------------------------------------------------------------------------- 1 | html 2 | .ikiwiki 3 | -------------------------------------------------------------------------------- /recipes/.luacheckrc: -------------------------------------------------------------------------------- 1 | ../src/.luacheckrc -------------------------------------------------------------------------------- /images/bg_t.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/bg_t.gif -------------------------------------------------------------------------------- /images/bg_menu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/bg_menu.gif -------------------------------------------------------------------------------- /images/bullet.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/bullet.gif -------------------------------------------------------------------------------- /images/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/screen.png -------------------------------------------------------------------------------- /images/top_bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/top_bg.gif -------------------------------------------------------------------------------- /images/top_bg_.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/top_bg_.gif -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src"] 2 | path = src 3 | url = https://github.com/awesomeWM/awesome 4 | -------------------------------------------------------------------------------- /images/6mon.medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/6mon.medium.png -------------------------------------------------------------------------------- /images/6mon.small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/6mon.small.png -------------------------------------------------------------------------------- /images/icons/aw_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/icons/aw_16.png -------------------------------------------------------------------------------- /images/icons/aw_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/icons/aw_22.png -------------------------------------------------------------------------------- /images/icons/aw_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/icons/aw_32.png -------------------------------------------------------------------------------- /images/icons/aw_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/icons/aw_48.png -------------------------------------------------------------------------------- /images/icons/aw_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/icons/aw_64.png -------------------------------------------------------------------------------- /images/awesome-taglist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/awesome-taglist.png -------------------------------------------------------------------------------- /recipes/awesomewm-font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/recipes/awesomewm-font.ttf -------------------------------------------------------------------------------- /images/icons/aw_64_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/icons/aw_64_shadow.png -------------------------------------------------------------------------------- /images/awesome-taglist-outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/awesome-taglist-outline.png -------------------------------------------------------------------------------- /images/website/aw-block_website-header-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/website/aw-block_website-header-1.png -------------------------------------------------------------------------------- /images/website/aw-block_website-header-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/website/aw-block_website-header-2.png -------------------------------------------------------------------------------- /images/website/aw-block_website-header-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/website/aw-block_website-header-3.png -------------------------------------------------------------------------------- /images/website/aw-block_website-header-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/website/aw-block_website-header-4.png -------------------------------------------------------------------------------- /images/website/aw-block_website-banner-860-140px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awesomeWM/awesome-www/HEAD/images/website/aw-block_website-banner-860-140px.png -------------------------------------------------------------------------------- /images/icons/moon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /README.for_webpage.md: -------------------------------------------------------------------------------- 1 | # DO NOT EDIT 2 | 3 | This repository contains the generated version of the web page for the [awesome 4 | window manager](https://awesomewm.org/). All pull requests to this repository 5 | will be ignored. Instead, please send suggestions for changes to the 6 | [awesome-www repository](https://github.com/awesomeWM/awesome-www) instead. 7 | -------------------------------------------------------------------------------- /screenshots.mdwn: -------------------------------------------------------------------------------- 1 | # Screenshots 2 | 3 | Screenshots of different AwesomeWM configurations are available 4 | [at GitHub](https://github.com/awesomeWM/awesome/discussions/3813). 5 | Feel free to add your own screenshots in the thread along with configuration details. 6 | 7 | Alternatively you can browse these screenshots using the [AwesomeWM Screenshot Gallery](https://mipmip.github.io/awesomewm-screenshots/). 8 | -------------------------------------------------------------------------------- /doc.mdwn: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | * LUA API documentation built by [ldoc](http://stevedonovan.github.io/ldoc/) 4 | * [Lua API documentation for the stable release](api) 5 | * [Lua API documentation for Git master (development version)](../apidoc/) 6 | * [awesome(1) manpage](manpages/awesome.1.html) 7 | * [awesomerc(5) manpage](manpages/awesomerc.5.html) 8 | * [awesome-client(1) manpage](manpages/awesome-client.1.html) 9 | 10 | 11 | # Awesome 4.0 12 | 13 | * [News / breaking changes](https://awesomewm.org/apidoc/documentation/89-NEWS.md.html#v4) 14 | * [Configuration porting tips](https://awesomewm.org/apidoc/documentation/17-porting-tips.md.html#v4) 15 | -------------------------------------------------------------------------------- /recipes/gpmdp.mdwn: -------------------------------------------------------------------------------- 1 | # Google Play Music Desktop Player watcher 2 | 3 | This widget can be used to display the current track information and state of 4 | [Google Play Music Desktop Player](https://www.googleplaymusicdesktopplayer.com/). 5 | 6 | 1. Download `gpmdp.lua` [here](https://awesomewm.org/recipes/gpmdp.lua) 7 | 2. Add your customization to `gpmdp.lua` after `-- customize here` 8 | 3. Import `gpmdp.lua` into your `rc.lua` 9 | 10 | ```lua 11 | local gpmdp = require("path/to/gpmdp.lua") 12 | ``` 13 | 14 | 4. Add the widget to your wibar 15 | 16 | ```lua 17 | s.mywibox:setup { 18 | layout = wibox.layout.align.horizontal, 19 | { 20 | layout = wibox.layout.fixed.horizontal, 21 | gpmdp.widget, 22 | -- ... 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /recipes/xrandr.mdwn: -------------------------------------------------------------------------------- 1 | # Helper for multiple monitors (based on xrandr) 2 | 3 | The [[xrandr.lua|xrandr.lua]] script helps when dealing with multiple monitors. 4 | Using this snippet you can set a keybinding where you swap to all possible 5 | arrangements of monitors. 6 | 7 | The process of setting up this script is as follows: 8 | 9 | 1. Create a file called `xrandr.lua` in your file system (preferably in 10 | awesome's folder) with the [[script|xrandr.lua]] content. 11 | 12 | 2. Import the script in your `rc.lua` 13 | 14 | ```lua 15 | local xrandr = require("xrandr") 16 | ``` 17 | 18 | 3. Create a keybinding to the script in the `globalkeys` table 19 | 20 | Pressing this key binding will open a popup with a possible screen 21 | arrangement. 22 | Pressing the key again will replace this popup with the next possibility, 23 | eventually arriving at "keep the current configuration". 24 | 25 | If the key is not pressed again within four seconds, the configuration 26 | described in the current popup is applied. 27 | 28 | ```lua 29 | awful.key({}, "Some Key", function() xrandr.xrandr() end) 30 | ``` 31 | -------------------------------------------------------------------------------- /css/light.css: -------------------------------------------------------------------------------- 1 | /** 2 | * AWESOME THEME LIGHT 3 | * background: #ffffff 4 | * foreground: #000300 5 | * color0: #000300 6 | * color1: #b44631 7 | * color2: #6fc24e 8 | * color3: #cab14c 9 | * color4: #006194 10 | * color5: #926090 11 | * color6: #59929d 12 | * color7: #3c4847 13 | * color8: #3f5f47 14 | * color9: #c1605d 15 | * colorA: #a9c68e 16 | * colorB: #decf50 17 | * colorC: #a6bbcb 18 | * colorD: #ad79a2 19 | * colorE: #8aa1af 20 | * colorF: #fafafa 21 | * colorA: #4f5867 22 | */ 23 | 24 | :root { 25 | --background-color: #ffffff; 26 | --color: #000300; 27 | --link-color: #006194; 28 | --main-headline-color: #3c4847; 29 | --bullet-points-color: #3c4847; 30 | --accent-background-color: #006194; 31 | --accent-color: #fafafa; 32 | --warning-message: #b44631; 33 | --menu-hover-color: #000300; 34 | --screenshot-border-color: #347272; 35 | --button-background-color: #535d6c; 36 | --button-text-color: #fafafa; 37 | --button-hover-color: #000300; 38 | --nav-text-color: #006194; 39 | --nav-accent-color: #000300; 40 | } 41 | 42 | .darkmode { 43 | visibility: hidden; 44 | display: none; 45 | } 46 | -------------------------------------------------------------------------------- /css/dark.css: -------------------------------------------------------------------------------- 1 | /** 2 | * AWESOME THEME DARK 3 | * background: #222222 4 | * foreground: #c4c5c8 5 | * color0: #000300 6 | * color1: #b44631 7 | * color2: #6fc24e 8 | * color3: #cab14c 9 | * color4: #59929d 10 | * color5: #926090 11 | * color6: #668d96 12 | * color7: #728c8d 13 | * color8: #3f5f47 14 | * color9: #c1605d 15 | * colorA: #a9c68e 16 | * colorB: #decf50 17 | * colorC: #a6bbcb 18 | * colorD: #ad79a2 19 | * colorE: #8aa1af 20 | * colorF: #bababa 21 | * color10: #755cf2 22 | */ 23 | 24 | :root { 25 | --background-color: #222222; 26 | --color: #c4c5c8; 27 | --link-color: #59929d; 28 | --image-filter: grayscale(50%); 29 | --main-headline-color: #b44631; 30 | --bullet-points-color: #b44631; 31 | --accent-background-color: #00bcd4; 32 | --accent-color: #050505; 33 | --warning-message: #b44631; 34 | --menu-hover-color: #ad79a2; 35 | --screenshot-border-color: #347272; 36 | --button-background-color: #59929d; 37 | --button-text-color: #fafafa; 38 | --button-hover-color: #00bcd4; 39 | --nav-text-color: #59929d; 40 | --nav-accent-color: #c4c5c8; 41 | } 42 | 43 | img:not([src*=".svg"]) { 44 | filter: var(--image-filter); 45 | } 46 | 47 | .lightmode { 48 | visibility: hidden; 49 | display: none; 50 | } 51 | -------------------------------------------------------------------------------- /recipes/awesome-taglist.mdwn: -------------------------------------------------------------------------------- 1 | # Awesome taglist 2 | 3 | Here is nice-looking and super easy way to customize taglist. The idea is simple - literally write 'awesome' or 'awesomewm' (if you want to keep 9 tags) in the taglist using characters from the Awesome logo. 4 | 5 | To do it you need to install a font which was generated from the svg images of the letters from the logo. Download it from [here](../awesomewm-font.ttf) and place it under `~/.local/share/fonts`. Then name your tags in **rc.lua** using it. The font has two types of letters: uppercase are for the bold characters: 6 | 7 | awful.tag({ "A", "W", "E", "S", "O", "M", "E", "W", "M"}, 8 | 9 |
10 | [[!img images/awesome-taglist.png alt="awesome taglist screenshot"]] 11 |
12 | 13 | and lowercase for the outline characters: 14 | 15 | awful.tag({ "a", "w", "e", "s", "o", "m", "e", "w", "m"}, 16 | 17 |
18 | [[!img images/awesome-taglist-outline.png alt="awesome taglist screenshot"]] 19 |
20 | 21 | Almost done! The last step is to theme it, below is the config which is used for the screenshots above (add it to the **theme.lua**): 22 | 23 | theme.taglist_fg_focus = "#3992af" 24 | theme.taglist_fg_occupied = "#164b5d" 25 | theme.taglist_fg_urgent = "#ED7572" 26 | theme.taglist_fg_empty = "#828282" 27 | theme.taglist_spacing = 2 28 | theme.taglist_font = "awesomewm-font 13" 29 | -------------------------------------------------------------------------------- /recipes/mic.mdwn: -------------------------------------------------------------------------------- 1 | # Microphone state widget/watcher 2 | 3 | This widget can be used to display the current microphone status. 4 | 5 | ## Requirements 6 | 7 | - `amixer` - this command is used to get and toggle microphone state 8 | 9 | ## Usage 10 | 11 | - Download [mic.lua](https://awesomewm.org/recipes/mic.lua) file and put it into awesome's 12 | folder (like `~/.config/awesome/widgets/mic.lua`) 13 | 14 | - Add widget to `theme.lua`: 15 | 16 | ```lua 17 | local widgets = { 18 | mic = require("widgets/mic"), 19 | } 20 | theme.mic = widgets.mic({ 21 | timeout = 10, 22 | settings = function(self) 23 | if self.state == "muted" then 24 | self.widget:set_image(theme.widget_micMuted) 25 | else 26 | self.widget:set_image(theme.widget_micUnmuted) 27 | end 28 | end 29 | }) 30 | local widget_mic = wibox.widget { theme.mic.widget, layout = wibox.layout.align.horizontal } 31 | ``` 32 | 33 | - Create a shortcut to toggle microphone state (add to `rc.lua`): 34 | 35 | ```lua 36 | -- Toggle microphone state 37 | awful.key({ modkey, "Shift" }, "m", 38 | function () 39 | beautiful.mic:toggle() 40 | end, 41 | {description = "Toggle microphone (amixer)", group = "Hotkeys"} 42 | ), 43 | ``` 44 | 45 | - You can also add a command to mute the microphone state on boot. Add this to your `rc.lua`: 46 | 47 | ```lua 48 | -- Mute microphone on boot 49 | beautiful.mic:mute() 50 | ``` 51 | -------------------------------------------------------------------------------- /script/dark-light-mode.js: -------------------------------------------------------------------------------- 1 | var siteVars = new Array(); 2 | siteVars['theme_active'] = 'light'; 3 | siteVars['theme_forced'] = ''; 4 | 5 | // combine prefers color theme or custom selected user dark/light theme 6 | let themeForcedStored = localStorage.getItem('theme_forced'); 7 | if (themeForcedStored == 'light' || themeForcedStored == 'dark') { 8 | siteVars['theme_forced'] = themeForcedStored; 9 | } 10 | 11 | siteVars['theme_active'] = 'light'; 12 | if ((window.matchMedia && 13 | window.matchMedia('(prefers-color-scheme: dark)').matches) || 14 | siteVars['theme_forced'] == 'dark') { 15 | siteVars['theme_active'] = 'dark'; 16 | } 17 | 18 | if (siteVars['theme_forced'] != '') { 19 | siteVars['theme_active'] = siteVars['theme_forced']; 20 | } 21 | 22 | if (siteVars['theme_forced'] != '') { 23 | if (siteVars['theme_forced'] == 'dark') { 24 | document.getElementById('css-darkmode').setAttribute('media', 'all'); 25 | document.getElementById('css-darkmode').disabled = false; 26 | 27 | document.getElementById('css-lightmode').setAttribute('media', 'not all'); 28 | document.getElementById('css-lightmode').disabled = true; 29 | 30 | } else { 31 | document.getElementById('css-darkmode').setAttribute('media', 'not all'); 32 | document.getElementById('css-darkmode').disabled = true; 33 | 34 | document.getElementById('css-lightmode').setAttribute('media', 'all'); 35 | document.getElementById('css-lightmode').disabled = false; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Make git not use user's config. 2 | OLD_HOME:=$(HOME) 3 | HOME:=/dev/null 4 | 5 | all: output ldoc changelogs manpages 6 | 7 | output: 8 | ikiwiki $(CURDIR) html -v --wikiname about --plugin=goodstuff \ 9 | --templatedir=templates \ 10 | --exclude=html --exclude=Makefile --exclude=README.md \ 11 | --exclude=README.for_webpage.md 12 | echo awesomewm.org > html/CNAME 13 | cp README.for_webpage.md html/README.md 14 | 15 | ldoc: 16 | make -C src distclean 17 | HOME=$(OLD_HOME) make -C src cmake-build ldoc 18 | 19 | clean: 20 | rm -rf .ikiwiki html 21 | 22 | changelogs: 23 | test -d html/changelogs/short || mkdir -p html/changelogs/short 24 | git --git-dir=src/.git tag | grep -v rc | sort -n | \ 25 | (while read v; do \ 26 | test -z "$$pv" && pv="`git --git-dir=src/.git rev-list HEAD | tail -n1`" ; \ 27 | git --git-dir=src/.git shortlog --no-merges $$pv..$$v > html/changelogs/short/$$v.txt ; \ 28 | git --git-dir=src/.git log --no-merges $$pv..$$v > html/changelogs/$$v.txt ; \ 29 | pv=$$v; done) 30 | 31 | manpages: 32 | mkdir -p html/doc/manpages 33 | cd src/manpages; for manpage in *.?.txt; \ 34 | do asciidoc -a icons -b xhtml11 -o ../../html/doc/manpages/`basename $${manpage} .txt`.html $$manpage || exit 1; \ 35 | done 36 | 37 | build_for_gh_actions: all 38 | build_for_gh_actions: BUILD_WEB?=/tmp/awesome-build-web 39 | build_for_gh_actions: ASCIIDOC_ICONS_DIR?=/usr/share/asciidoc/icons 40 | build_for_gh_actions: 41 | test -d "$(ASCIIDOC_ICONS_DIR)" 42 | rsync -PaOvz --delete --exclude=.git --chmod=u=rwX,g=rwX,o=rX,Dg+s --exclude src html/ \ 43 | "$(BUILD_WEB)" 44 | rsync -PaOvz --delete --chmod=u=rwX,g=rwX,o=rX,Dg+s src/build/doc/ \ 45 | "$(BUILD_WEB)/doc/api" 46 | rsync -PaOvz --delete --chmod=u=rwX,g=rwX,o=rX,Dg+s $(ASCIIDOC_ICONS_DIR) \ 47 | "$(BUILD_WEB)/doc/manpages/icons" 48 | 49 | .PHONY: changelogs manpages 50 | -------------------------------------------------------------------------------- /css/mode-switch.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Dark/Light Theme Switcher build on Checkbox and UL/LI structure 3 | */ 4 | 5 | .mode-switch { 6 | display: flex; 7 | position: absolute; 8 | top: 0.5rem; 9 | right: 0.5rem; 10 | } 11 | 12 | .mode-switch>li { 13 | list-style: none; 14 | margin-right: 6px; 15 | } 16 | 17 | .mode-switch-icon { 18 | padding: 0px 0px 0px 32px; 19 | list-style: none; 20 | margin: 0; 21 | } 22 | 23 | .mode-switch-dark { 24 | background: url(../images/icons/moon.svg) no-repeat left top; 25 | background-size: 32px 32px; 26 | filter: invert(100%); 27 | } 28 | 29 | .mode-switch-light { 30 | background: url(../images/icons/sun.svg) no-repeat left top; 31 | background-size: 32px 32px; 32 | } 33 | 34 | .switch { 35 | position: relative; 36 | display: inline-block; 37 | width: 60px; 38 | height: 34px; 39 | } 40 | 41 | /* Hide default HTML checkbox */ 42 | .switch input { 43 | opacity: 0; 44 | width: 0; 45 | height: 0; 46 | } 47 | 48 | /* The slider */ 49 | .slider { 50 | position: absolute; 51 | cursor: pointer; 52 | top: 0; 53 | left: 0; 54 | right: 0; 55 | bottom: 0; 56 | background-color: #ccc; 57 | -webkit-transition: 0.4s; 58 | transition: 0.4s; 59 | } 60 | 61 | .slider:before { 62 | position: absolute; 63 | content: ""; 64 | height: 26px; 65 | width: 26px; 66 | left: 4px; 67 | bottom: 4px; 68 | background-color: #fafafa; 69 | -webkit-transition: 0.4s; 70 | transition: 0.4s; 71 | } 72 | 73 | input:checked+.slider { 74 | background-color: #59929d; 75 | } 76 | 77 | input:focus+.slider { 78 | box-shadow: 0 0 1px #59929d; 79 | } 80 | 81 | input:checked+.slider:before { 82 | -webkit-transform: translateX(26px); 83 | -ms-transform: translateX(26px); 84 | transform: translateX(26px); 85 | } 86 | 87 | /* Rounded sliders */ 88 | .slider.round { 89 | border-radius: 34px; 90 | } 91 | 92 | .slider.round:before { 93 | border-radius: 50%; 94 | } 95 | -------------------------------------------------------------------------------- /community.mdwn: -------------------------------------------------------------------------------- 1 | # Community 2 | 3 | **awesome** has an active and growing community. 4 | 5 | # IRC 6 | You can join us in the `#awesome` channel on the [`OFTC`](http://www.oftc.net) IRC network. 7 | 8 | [IRC Webchat](https://webchat.oftc.net/?channels=awesome) 9 | 10 | # Stack Overflow 11 | 12 | You can ask questions on 13 | [Stack Overflow](http://stackoverflow.com/questions/tagged/awesome-wm). 14 | 15 | # Discord 16 | 17 | You can join the (non official) awesome community on the discord server 18 | [invite](https://discord.gg/BPat4F87dg). 19 | 20 | # Reddit 21 | 22 | We also have an [awesomewm subreddit](https://www.reddit.com/r/awesomewm/) where 23 | you can share your work and ask questions. 24 | 25 | # GitHub 26 | 27 | Awesome is [developed on GitHub](https://github.com/awesomeWM/awesome/). 28 | You can follow (watch) us there, contribute to our decision making and help 29 | triage issues. Also pull requests and issues are welcome there. 30 | 31 | This web page also is [on GitHub](https://github.com/awesomeWM/awesome-www) and 32 | can be changed via pull requests. To locally test your changes, the web page can 33 | be built with `make`. For this, you need to have 34 | [ikiwiki](https://ikiwiki.info/) installed. 35 | 36 | You can also browse GitHub repositories tagged with 37 | [awesomewm](https://github.com/search?q=topic%3Aawesomewm). To find inspiration 38 | or snippets of code. Feel welcome to tag your own config so other users can 39 | discover it. 40 | 41 | # Old mailing list (now closed) 42 | 43 | * [The Mail Archive](http://www.mail-archive.com/awesome@naquadah.org/) 44 | * [Gmane archive](http://dir.gmane.org/gmane.comp.window-managers.awesome) 45 | * [Gmane developers list archive](http://dir.gmane.org/gmane.comp.window-managers.awesome.devel) 46 | * [The Mail Archive developers list](http://www.mail-archive.com/awesome-devel@naquadah.org/) 47 | 48 | # Old wiki 49 | 50 | The old wiki has been shut down, but can be still viewed at 51 | [archive.org](https://web.archive.org/web/20160701200046/https://awesome.naquadah.org/wiki/Main_Page). 52 | 53 | # Authors 54 | [See our GitHub page](https://github.com/awesomeWM/awesome/graphs/contributors) 55 | -------------------------------------------------------------------------------- /script/dark-light-mode-switch.js: -------------------------------------------------------------------------------- 1 | const checkbox = document.querySelector("input[type='checkbox']"); 2 | const mode_switch_icon = document.querySelector(".mode-switch-icon"); 3 | 4 | // configure and set correct state of theme checkbox 5 | checkbox.checked = siteVars['theme_active'] == 'dark' 6 | checkbox.addEventListener("click", () => { 7 | theme_switch(); 8 | set_theme_checkbox(); 9 | }); 10 | 11 | set_theme_checkbox(); 12 | 13 | // apply specific styling after page reload 14 | document.getElementById('navbar').classList.add("topBotomBordersOut"); 15 | 16 | // set correct state of dark/light theme mode 17 | function set_theme_checkbox() { 18 | if (checkbox.checked) { 19 | mode_switch_icon.classList.add("mode-switch-dark"); 20 | mode_switch_icon.classList.remove("mode-switch-light"); 21 | } else { 22 | mode_switch_icon.classList.add("mode-switch-light"); 23 | mode_switch_icon.classList.remove("mode-switch-dark"); 24 | } 25 | } 26 | 27 | // switch dark/light mode and store the state to local storage 28 | function theme_switch() { 29 | if (siteVars['theme_active'] == 'light') { 30 | siteVars['theme_active'] = siteVars['theme_forced'] = 'dark'; 31 | 32 | document.getElementById('css-darkmode').setAttribute('media', 'all'); 33 | document.getElementById('css-darkmode').disabled = false; 34 | 35 | document.getElementById('css-lightmode').setAttribute('media', 'not all'); 36 | document.getElementById('css-lightmode').disabled = true; 37 | } else { 38 | siteVars['theme_active'] = siteVars['theme_forced'] = 'light'; 39 | 40 | document.getElementById('css-darkmode').setAttribute('media', 'not all'); 41 | document.getElementById('css-darkmode').disabled = true; 42 | 43 | document.getElementById('css-lightmode').setAttribute('media', 'all'); 44 | document.getElementById('css-lightmode').disabled = false; 45 | } 46 | localStorage.setItem('theme_forced', siteVars['theme_active']); 47 | 48 | document.body.classList.add('expand'); 49 | document.body.offsetHeight; 50 | document.body.classList.remove('expand'); 51 | } 52 | -------------------------------------------------------------------------------- /doing_a_release.mdwn: -------------------------------------------------------------------------------- 1 | ## How to do a release 2 | 3 | ### Local preparations 4 | 5 | The following steps are done in a checkout of the *awesome* git repository. 6 | 7 | * The codename: 8 | * Pick some codename that is not already listed in [[Releases]]. 9 | * jd always picked a song title, you should do the same. 10 | * Edit `awesomeConfig.cmake` and change the argument in `set(CODENAME "Foo")`. 11 | * `git commit -sm 'change codename' awesomeConfig.cmake` 12 | * Git sign with `git tag -s vX.Y -m 'awesome vX.Y`' 13 | * Run `make dist` to create tarballs. You need to have GPG set up correctly, because the tarballs will be signed. 14 | * Copy the tarballs and the signatures into the awesome-releases repository and 15 | commit the result. 16 | 17 | The following steps are done in a checkout of the *awesome-www* git repository. 18 | 19 | * Create a release-branch via `git checkout -b release`. 20 | * Add the release version and date to [[Releases]]. 21 | * Update `download.mdwn` to add version information and links. 22 | * Go into the 'src' submodule, and update it to vX.Y with `git pull 23 | path/to/your/awesome/repo tag vX.Y && git checkout vX.Y`. 24 | * Commit `download.mdwn`, `releases.mdwn`, and `src` with `git commit -sm 'vX.Y' 25 | download.mdwn releases.mdwn src`. 26 | 27 | ### The final steps 28 | 29 | * Push the new commits 30 | * In the awesome-releases repository 31 | * In the awesome-www repository (push just the release branch!) 32 | * In the awesome repository (make sure the tag is also pushed!) 33 | * Create a pull request to the awesome-www repository for the release branch. 34 | This makes sure that the Github-Actions build will be successful when merging into the 35 | master branch. 36 | * Create the release on GitHub: 37 | * Go to the GitHub release page . 38 | * Enter `vX.Y` into the "Tag version"-field. GitHub should recognize this as 39 | an existing tag. 40 | * Enter `Awesome vX.Y` into the "Release title" field. 41 | * Come up with something good for the description field. A nice idea is to 42 | mention some highlights and to link to a porting document. 43 | * Attach the tarballs and signatures created by `make dist`. 44 | * Verify the pull request to the awesome-www repository built successful and 45 | merge it into the master branch. 46 | * Change the topic on IRC. 47 | * Check the links to the downloads on the webpage. 48 | -------------------------------------------------------------------------------- /recipes/countdown.mdwn: -------------------------------------------------------------------------------- 1 | # Countdown widget 2 | 3 | Add the following in your `rc.lua`: 4 | 5 | ```lua 6 | local countdown = { 7 | widget = wibox.widget.textbox(), 8 | checkbox = wibox.widget { 9 | checked = false, 10 | check_color = beautiful.fg_focus, -- customize 11 | border_color = beautiful.fg_normal, -- customize 12 | border_width = 2, -- customize 13 | shape = gears.shape.circle, 14 | widget = wibox.widget.checkbox 15 | } 16 | } 17 | 18 | function countdown.set() 19 | awful.prompt.run { 20 | prompt = "Countdown minutes: ", -- floats accepted 21 | textbox = awful.screen.focused().mypromptbox.widget, 22 | exe_callback = function(timeout) 23 | countdown.seconds = tonumber(timeout) 24 | if not countdown.seconds then return end 25 | countdown.checkbox.checked = false 26 | countdown.minute_t = countdown.seconds > 1 and "minutes" or "minute" 27 | countdown.seconds = countdown.seconds * 60 28 | countdown.timer = gears.timer({ timeout = 1 }) 29 | countdown.timer:connect_signal("timeout", function() 30 | if countdown.seconds > 0 then 31 | local minutes = math.floor(countdown.seconds / 60) 32 | local seconds = math.fmod(countdown.seconds, 60) 33 | countdown.widget:set_markup(string.format("%d:%02d", minutes, seconds)) 34 | countdown.seconds = countdown.seconds - 1 35 | else 36 | naughty.notify({ 37 | title = "Countdown", 38 | text = string.format("%s %s timeout", timeout, countdown.minute_t) 39 | }) 40 | countdown.widget:set_markup("") 41 | countdown.checkbox.checked = true 42 | countdown.timer:stop() 43 | end 44 | end) 45 | countdown.timer:start() 46 | end 47 | } 48 | end 49 | 50 | countdown.checkbox:buttons(awful.util.table.join( 51 | awful.button({}, 1, function() countdown.set() end), -- left click 52 | awful.button({}, 3, function() -- right click 53 | if countdown.timer and countdown.timer.started then 54 | countdown.widget:set_markup("") 55 | countdown.checkbox.checked = false 56 | countdown.timer:stop() 57 | naughty.notify({ title = "Countdown", text = "Timer stopped" }) 58 | end 59 | end) 60 | )) 61 | ``` 62 | 63 | then, add `countdown.widget` and `countdown.checkbox` to your favourite `wibox`. 64 | 65 | Left clicking on the `checkbox` will prompt for a countdown, right clicking will stop the timer. 66 | 67 | The `widget` will display the countdown. 68 | -------------------------------------------------------------------------------- /images/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 45 | -------------------------------------------------------------------------------- /recipes/wirelessStatus.mdwn: -------------------------------------------------------------------------------- 1 | # Wireless status widget/watcher 2 | 3 | Get wireless Quality link (converted to percentages) and wireless status. 4 | 5 | Data is taken from `/proc/net/wireless`. 6 | 7 | According to [this](https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Linux.Wireless.Extensions.html) 8 | website `/proc/net/wireless` has the following information: 9 | 10 | - Status: Its current state. This is a device dependent information. 11 | 12 | - Quality - link: general quality of the reception. 13 | 14 | - Quality - level: signal strength at the receiver. 15 | 16 | - Quality - noise: silence level (no packet) at the receiver. 17 | 18 | - Discarded - nwid: number of discarded packets due to invalid network id. 19 | 20 | - Discarded - crypt: number of packet unable to decrypt. 21 | 22 | - Discarded - misc: unused (for now). 23 | 24 | This widget uses `Quality - link` and converts it to percentages (`perc=Quality_link*10/7`). 25 | The above equation is taken from [this](https://superuser.com/a/1360447) forum answer. 26 | 27 | It also stores `Status` information (note that this is presumably device dependent). 28 | 29 | ## Requirements 30 | 31 | - `iw` 32 | 33 | ## Usage 34 | 35 | - Download [wirelessStatus.lua](https://awesomewm.org/recipes/wirelessStatus.lua) file and put it 36 | into awesome's folder (like `~/.config/awesome/widgets/wirelessStatus.lua`) 37 | 38 | - Add widget to `theme.lua`: 39 | 40 | ```lua 41 | local widgets = { 42 | wirelessStatus = require("widgets/wirelessStatus"), 43 | } 44 | -- Wireless status widget (`status` is presumably device dependent) 45 | theme.wirelessStatus = widgets.wirelessStatus({ 46 | notification_preset = { font = "Mononoki Nerd Font 10", fg = theme.fg_normal }, 47 | timeout = 10, 48 | settings = function(self) 49 | if self.status == "1" or self.status == "" then 50 | self.widget:set_image(theme.wifidisc) 51 | else 52 | if self.perc <= 5 then 53 | self.widget:set_image(theme.wifinone) 54 | elseif self.perc <= 25 then 55 | self.widget:set_image(theme.wifilow) 56 | elseif self.perc <= 50 then 57 | self.widget:set_image(theme.wifimed) 58 | elseif self.perc <= 75 then 59 | self.widget:set_image(theme.wifihigh) 60 | else 61 | self.widget:set_image(theme.wififull) 62 | end 63 | end 64 | end, 65 | }) 66 | local widget_wirelessStatus = wibox.widget { nil, theme.wirelessStatus.widget, layout = wibox.layout.align.horizontal } 67 | ``` 68 | 69 | - Set which application to run on widget press (add to `rc.lua`): 70 | 71 | ```lua 72 | -- wirelessStatus widget pressed function - open terminal and start `nmtui` 73 | beautiful.wirelessStatus.pressed = function(self, button) 74 | if button == 1 then -- left mouse click 75 | awful.spawn(terminal.." -e nmtui") 76 | end 77 | end 78 | ``` 79 | -------------------------------------------------------------------------------- /recipes.mdwn: -------------------------------------------------------------------------------- 1 | # Recipes 2 | 3 | The recipes section is where you can find useful snippets and tutorials on how 4 | to improve your Awesome setup. 5 | 6 | * [How to contribute to Recipes](https://github.com/awesomeWM/awesome-www#contributing-to-recipes-section) 7 | 8 | ## Setups 9 | 10 | * [My First Awesome Setup](https://awesomewm.org/apidoc/documentation/07-my-first-awesome.md.html#) 11 | * [A step by step Guide by Epsi](https://epsi-rns.github.io/desktop/2019/06/15/awesome-overview.html) (for Awesome 4.3) 12 | 13 | ## Widgets 14 | 15 | * [Lain](https://github.com/copycat-killer/lain) 16 | * [Vicious](https://github.com/vicious-widgets/vicious) 17 | * [[Countdown|recipes/countdown]] 18 | * [[MPD current song|recipes/mpc]] 19 | * [[Awesome "Watch" widget usage examples|recipes/watch]] 20 | * [PulseAudio](https://github.com/stefano-m/awesome-pulseaudio_widget) 21 | * [Connman (network manager)](https://github.com/stefano-m/awesome-connman_widget) 22 | * [Battery Indicator (UPower)](https://github.com/stefano-m/awesome-power_widget) 23 | * [[Google Play Music Desktop Player|recipes/gpmdp]] 24 | * [Set of simple widgets](https://github.com/streetturtle/awesome-wm-widgets) - widgets for battery, cpu, brightness, volume, email, etc. 25 | * [[Wireless status|recipes/wirelessStatus]] 26 | * [[Microphone state|recipes/mic]] 27 | * [Noobie](https://github.com/streetturtle/noobie) - create a wibar widget based on the output of a script. 28 | 29 | ## Libraries 30 | 31 | * [Radical menu framework](https://github.com/Elv13/radical) 32 | * [amh - Simultaneously spawn programs on multiple hosts](https://github.com/sim590/amh) 33 | 34 | ## Themes 35 | 36 | * [Aesthetic Night](https://github.com/rxyhn/dotfiles) 37 | - Full Animated Setup 38 | - Modern Bottom Panel, Dashboard Panel, Control Center, Notification Center 39 | - Music Player Widget, Weather Widget, Calendar Widget, Battery Widget, Network Widget 40 | - Word Clock Lockscreen, Minimalist Exitscreen 41 | 42 | * [awesome-copycats](https://github.com/copycat-killer/awesome-copycats) 43 | 44 | ## Window management 45 | 46 | * [Awesome-Revelation - Mac OSX like 'Expose' view of all clients](https://github.com/guotsuan/awesome-revelation) 47 | * [awesome-cyclefocus - sensible Alt-Tab behavior](https://github.com/blueyed/awesome-cyclefocus/) 48 | * [Collision geometric navigation keybindings](https://github.com/Elv13/collision) 49 | * [Tyrannical dynamic tag managment framework](https://github.com/Elv13/tyrannical) 50 | * [Repetitive dynamic keybindings and macros](https://github.com/Elv13/repetitive) 51 | * [layout-machi - a manual layout with interactive editing](https://github.com/xinhaoyuan/layout-machi) 52 | * [nice - macOS-like seamless window decorations](https://github.com/mut-ex/awesome-wm-nice) 53 | * [modalawesome - framework for modal, vi-like keybindings](https://github.com/potamides/modalawesome) 54 | 55 | ## Others 56 | 57 | * [[Swap Monitor Snippet|recipes/xrandr]] 58 | * [Poppin' - Pop over applications](https://github.com/raksooo/poppin) 59 | * [Awesome taglist](../recipes/awesome-taglist) 60 | * [Tag based screen rotation](https://github.com/raksooo/screenrotation) 61 | -------------------------------------------------------------------------------- /recipes/mpc.mdwn: -------------------------------------------------------------------------------- 1 | # MPD integration 2 | 3 | This page describes an integration with the [Music Player 4 | Daemon](https://www.musicpd.org/). This consists of two parts: A [[pure Lua 5 | library for talking to mpc|mpc.lua]] and an example on how to use this for a 6 | widget with awesome. 7 | 8 | ## The library 9 | 10 | The library provides a function `mpc.new` that creates a new object representing 11 | a connection to MPD. It can be used as follows: 12 | 13 | local connection = require("mpc").new(host, port, password, error_handler, idle_commands...) 14 | 15 | This will establish a TCP connection to the given host and port and, if a 16 | password is given, log in to the MPD server. Whenever an error happens (for 17 | example the connection is lost or the password is rejected), the given error 18 | handler function is called with the error as its argument. The next time the 19 | connection is used, an automatic reconnection is attempted. 20 | 21 | A description of the MPD protocol can be found 22 | [here](https://www.musicpd.org/doc/protocol/). This library only provides 23 | low-level access to the protocol. However, special support for the idle command 24 | is provided via extra arguments to the `new` function. This will be made clear 25 | in an example below. 26 | 27 | For example, to get information about the currently playing song: 28 | 29 | connection:send("currentsong", function(success, data) 30 | if not success then print("command failed") end 31 | print("Information about the current song:") 32 | require("gears.debug").dump(data) 33 | end) 34 | 35 | ## A sample widget 36 | 37 | The following keeps a textbox up-to-date with the MPD status. It automatically 38 | updates when the current MPD state changes. 39 | 40 | local mpc = require("mpc") 41 | local textbox = require("wibox.widget.textbox") 42 | local mpd_widget = textbox() 43 | local state, title, artist, file = "stop", "", "", "" 44 | local function update_widget() 45 | local text = "Current MPD status: " 46 | text = text .. tostring(artist or "") .. " - " .. tostring(title or "") 47 | if state == "pause" then 48 | text = text .. " (paused)" 49 | end 50 | if state == "stop" then 51 | text = text .. " (stopped)" 52 | end 53 | mpd_widget.text = text 54 | end 55 | 56 | local function error_handler(err) 57 | mpd_widget:set_text("Error: " .. tostring(err)) 58 | end 59 | 60 | local reconnect_interval = 1 -- negative to disable 61 | local connection 62 | connection = mpc.new(nil, nil, nil, error_handler, reconnect_interval, 63 | "status", function(_, result) 64 | state = result.state 65 | end, 66 | "currentsong", function(_, result) 67 | title, artist, file = result.title, result.artist, result.file 68 | pcall(update_widget) 69 | end) 70 | 71 | If you actually want to be able to control MPD's behaviour, you could for 72 | example do the following to pause/unpause when clicking on the widget: 73 | 74 | mpd_widget:buttons(awful.button({}, 1, function() connection:toggle_play() end)) 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Website for awesome WM 2 | 3 | [![Build Status](https://github.com/awesomeWM/awesome-www/actions/workflows/www.yml/badge.svg)](https://github.com/awesomeWM/awesome-www/actions/workflows/www.yml) 4 | 5 | This is the main source of the 6 | [website for the awesome window manager](https://awesomewm.org/). 7 | 8 | ## Requirements 9 | 10 | - [ikiwiki](https://ikiwiki.info/) 11 | - [PerlMagick](https://www.imagemagick.org/script/perl-magick.php) (optional, 12 | for images) 13 | 14 | ## Hacking 15 | 16 | You can build the web page locally by running `make`, which will generate the 17 | output in `html/`. 18 | 19 | To view it, open `html/index.html` in your web browser. 20 | 21 | You can simulate running a web server using Python, which will automatically 22 | open `index.html` when following a link to a directory: 23 | 24 | ``` 25 | cd html && python3 -m http.server -b localhost 8000 & 26 | ``` 27 | 28 | ## Contributing to the Screenshots Section 29 | 30 | To contribute with Screenshots: 31 | 32 | 1. Add your image to the folder images/screenshots with an appropriate name. 33 | 34 | 1. Add a new `
` tag in the bottom of *screenshots.mdwn*, 35 | 36 | 1. Inside the new tag, add the screenshots with a `` tag and use the 37 | `
` to add caption to the image, explaining what is being used on 38 | the screenshot. 39 | 40 | ## Contributing to Recipes Section 41 | 42 | Fork this repository and create a new branch with a name relevant to the 43 | information you will be adding to the site. If you have doubts in how to Fork 44 | and Branch, take a look in this cheat-sheet 45 | [here](https://www.git-tower.com/blog/git-cheat-sheet/) 46 | 47 | The process of editing files can be done inside GitHub's interface, more 48 | information [here](https://help.github.com/articles/github-flow/) 49 | 50 | ### With external Link 51 | 52 | Create a new link in markdown format `[Link Name](Real Link)` in the appropriate 53 | section in `recipes.mdwn` file. 54 | 55 | ### With internal Link (host in awesome site) 56 | 57 | 1. Create a new page with your tutorial/setup/widget/snippet in Markdown, with a 58 | relevant name, under the `recipes` folder. 59 | 60 | Example `recipes/xrandr-tutorial.mdwn` 61 | 62 | 1. Link your page to the right section in the `recipes.mdwn` page with Markdown 63 | syntax. 64 | 65 | Example `[[XrandR Tutorial|recipes/xrandr-tutorial]]` 66 | 67 | ### Seeing results and pulling your changes 68 | 69 | 1. Build the site as explained in the Hacking section in this same page to check 70 | how your changes will look like. 71 | 72 | 1. If everything is right and looks good, you're ready do make a Pull Request. 73 | 74 | ## Publishing 75 | 76 | The master branch gets built by 77 | [GH Actions](https://github.com/awesomeWM/awesome-www/actions), and is then published 78 | through 79 | [Github's Organization Pages](https://github.com/awesomeWM/awesomeWM.github.io). 80 | 81 | ## Other resources 82 | 83 | The API documentation for the master branch at 84 | [/apidoc](https://awesomewm.org/apidoc/) is viewable at [Github's Project 85 | Pages for the apidoc repo](https://github.com/awesomeWM/apidoc), where it gets 86 | pushed to from successful builds in [the awesome main 87 | repo](https://github.com/awesomeWM/awesome/). 88 | -------------------------------------------------------------------------------- /index.mdwn: -------------------------------------------------------------------------------- 1 | # What is this awesome window manager? 2 | 3 | **awesome** is a highly configurable, next generation framework window 4 | manager for X. It is very fast, extensible and licensed under the 5 | [GNU GPLv2 license](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html). 6 | 7 | It is primarily targeted at power users, developers and any people dealing with 8 | every day computing tasks and who want to have fine-grained control on their 9 | graphical environment. 10 | 11 | 18 | 19 |
20 | [[!img images/screen.png link="images/screen.png" alt="awesome screenshot"]] 21 |
22 | 23 | 24 | # Concepts 25 | 26 | A window manager is probably one of the most used software applications in 27 | your day-to-day tasks, along with your web browser, mail reader and text editor. 28 | Power users and programmers have a big range of choice between several tools 29 | for these day-to-day tasks. Some are heavily extensible and configurable. 30 | 31 | **awesome** tries to complete these tools with what we miss: an extensible, 32 | highly configurable window manager. 33 | 34 | To achieve this goal, **awesome** has been designed as a framework window 35 | manager. 36 | It's extremely fast, small, dynamic and heavily extensible using the 37 | [Lua](http://www.lua.org) programming language. 38 | 39 | We provide a documented API to configure and define the behavior of your 40 | window manager. 41 | 42 |
43 | [[!img images/6mon.small.png link="images/6mon.medium.png" alt="awesome running on 6 monitors"]] 44 |
45 | 46 | # Features and non-features 47 | 48 | * Very stable, fast and small codebase and footprint. 49 | * First window manager using the asynchronous [XCB](http://xcb.freedesktop.org) 50 | library instead of the old, synchronous 51 | [Xlib](http://en.wikipedia.org/wiki/Xlib), which makes **awesome** less 52 | subject to latency compared to other window managers. 53 | * Documented source code and API. 54 | * No mouse needed: everything can be performed with the keyboard. 55 | * Real multihead support (XRandR) with per screen desktops (tags). 56 | * Implements many [Freedesktop](http://www.freedesktop.org) standards: 57 | [EWMH](http://standards.freedesktop.org/wm-spec/wm-spec-latest.html), 58 | [XDG Base Directory](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html), 59 | [XEmbed](http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html), 60 | [Desktop Notification](http://www.galago-project.org/specs/notification/), 61 | [System Tray](http://standards.freedesktop.org/systemtray-spec/systemtray-spec-latest.html). 62 | * Does not distinguish between layers: there is no floating or tiled layer. 63 | * Uses tags instead of workspaces: allow to place clients on several tags, and 64 | display several tags at the same time. 65 | * A lot of Lua extensions to add features: dynamic tagging, widget feeding, 66 | tabs, layouts, … 67 | * [D-Bus](http://dbus.freedesktop.org) support. 68 | * And more. 69 | 70 | This is gonna be LEGEN... wait for it... DARY! 71 | -------------------------------------------------------------------------------- /recipes/gpmdp.lua: -------------------------------------------------------------------------------- 1 | 2 | --[[ 3 | 4 | Licensed under GNU General Public License v2 5 | * (c) 2017, Greg Flynn 6 | 7 | --]] 8 | local awful = require("awful") 9 | local naughty = require("naughty") 10 | local dpi = require("beautiful.xresources").apply_dpi 11 | local io, next, os, string, table = io, next, os, string, table 12 | 13 | -- Google Play Music Desktop Player widget 14 | -- requires: curl and dkjson or lain 15 | 16 | local gpmdp = { 17 | notify = "on", 18 | followtag = false, 19 | file_location = os.getenv("HOME") .. "/.config/Google Play Music Desktop Player/json_store/playback.json", 20 | notification_preset = { 21 | title = "Now playing", 22 | icon_size = dpi(128), 23 | timeout = 6 24 | }, 25 | notification = nil, 26 | current_track = nil, 27 | album_cover = "/tmp/gpmcover" 28 | } 29 | 30 | function gpmdp.notification_on() 31 | local gpm_now = gpmdp.latest 32 | gpmdp.current_track = gpm_now.title 33 | 34 | if gpmdp.followtag then gpmdp.notification_preset.screen = awful.screen.focused() end 35 | awful.spawn.easy_async({"curl", gpm_now.cover_url, "-o", gpmdp.album_cover}, function(stdout) 36 | local old_id = nil 37 | if gpmdp.notification then old_id = gpmdp.notification.id end 38 | 39 | gpmdp.notification = naughty.notify({ 40 | preset = gpmdp.notification_preset, 41 | icon = gpmdp.album_cover, 42 | replaces_id = old_id 43 | }) 44 | end) 45 | end 46 | 47 | function gpmdp.notification_off() 48 | if not gpmdp.notification then return end 49 | naughty.destroy(gpmdp.notification) 50 | gpmdp.notification = nil 51 | end 52 | 53 | function gpmdp.get_lines(file) 54 | local f = io.open(file) 55 | if not f then 56 | return 57 | else 58 | f:close() 59 | end 60 | 61 | local lines = {} 62 | for line in io.lines(file) do 63 | lines[#lines + 1] = line 64 | end 65 | return lines 66 | end 67 | 68 | gpmdp.widget = awful.widget.watch({"pidof", "Google Play Music Desktop Player"}, 2, function(widget, stdout) 69 | local filelines = gpmdp.get_lines(gpmdp.file_location) 70 | if not filelines then return end -- GPMDP not running? 71 | 72 | gpm_now = { running = stdout ~= '' } 73 | 74 | if not next(filelines) then 75 | gpm_now.running = false 76 | gpm_now.playing = false 77 | else 78 | dict, pos, err = require("dkjson").decode(table.concat(filelines), 1, nil) -- dkjson 79 | -- dict, pos, err = require("lain.util").dkjson.decode(table.concat(filelines), 1, nil) -- lain 80 | gpm_now.artist = dict.song.artist 81 | gpm_now.album = dict.song.album 82 | gpm_now.title = dict.song.title 83 | gpm_now.cover_url = dict.song.albumArt 84 | gpm_now.playing = dict.playing 85 | end 86 | gpmdp.latest = gpm_now 87 | 88 | -- customize here 89 | gpmdp.notification_preset.text = string.format("%s (%s) - %s", gpm_now.artist, gpm_now.album, gpm_now.title) 90 | widget:set_text(gpm_now.artist .. " - " .. gpm_now.title) 91 | 92 | if gpm_now.playing then 93 | if gpmdp.notify == "on" and gpm_now.title ~= gpmdp.current_track then 94 | gpmdp.notification_on() 95 | end 96 | elseif not gpm_now.running then 97 | gpmdp.current_track = nil 98 | end 99 | end) 100 | 101 | -- add mouse hover 102 | gpmdp.widget:connect_signal("mouse::enter", gpmdp.notification_on) 103 | gpmdp.widget:connect_signal("mouse::leave", gpmdp.notification_off) 104 | 105 | return gpmdp 106 | -------------------------------------------------------------------------------- /download.mdwn: -------------------------------------------------------------------------------- 1 | # Download 2 | 3 | ## Packages 4 | 5 | **awesome** is currently available in: 6 | 7 | * Arch Linux: 8 | * [stable](https://www.archlinux.org/packages/extra/x86_64/awesome/) 9 | * [awesome-git in AUR](https://aur.archlinux.org/packages/awesome-git) 10 | * [awesome-luajit-git in AUR](https://aur.archlinux.org/packages/awesome-luajit-git/) 11 | * [Debian](http://packages.debian.org/awesome) 12 | * [Ubuntu](http://packages.ubuntu.com/awesome) 13 | * [Fedora](https://packages.fedoraproject.org/pkgs/awesome/awesome/) 14 | * [FreeBSD](http://www.freshports.org/x11-wm/awesome/) 15 | * [Gentoo](http://packages.gentoo.org/package/x11-wm/awesome) 16 | * [OpenBSD](http://openports.se/x11/awesome) 17 | * [NetBSD](http://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/wm/awesome/) 18 | * [Source Mage GNU/Linux](http://codex.sourcemage.org/test/windowmanagers/awesome/) 19 | * [T2 SDE](http://t2-project.org/packages/awesome.html) 20 | * [CRUX](http://crux.nu/portdb/index.php?q=awesome&a=search&s=true) 21 | * [openSUSE](http://download.opensuse.org/repositories/X11:/windowmanagers/) 22 | * [Milis Linux](https://notabug.org/milislinux/milis/src/master/talimatname/genel/a/awesome) 23 | * [PLD Linux](http://pld-linux.org) 24 | * [Mageia](http://mageia.madb.org/package/show/application/0/name/awesome) 25 | * [OpenIndiana](http://pkg.openindiana.org/hipster/en/search.shtml?token=awesome&action=Search) 26 | 27 | Repology provides a [comprehensive overview](https://repology.org/metapackage/awesome/versions) of which version of **awesome** is included in which distribution. 28 | 29 | ### Distributions using Awesome as the default window manager 30 | 31 | * [GoboLinux](https://gobolinux.org) 32 | 33 | ## Building from Source 34 | 35 |

36 | We strongly recommend using the awesome package of your distribution. 37 |

38 | 39 | This is because many people who tried to build from source had problems. 40 | [LGI](https://github.com/pavouk/lgi), one of awesome's dependencies, currently 41 | hardcodes the package search path used by Lua 5.1. Part of the reason for this 42 | is that Lua upstream intends Lua to be embedded, which means that detecting an 43 | installed Lua version properly is not easy. 44 | 45 | After installing awesome, you can check if you are affected by this problem by 46 | running `awesome -v`. If an error message is displayed instead of LGI version's 47 | number, you are likely affected. 48 | 49 | ### Stable 50 | 51 | Latest stable version of **awesome** is version 4.3 (*Too long*) 52 | released on 28 January 2019. 53 | 54 | * [v4.3 changelog](../changelogs/v4.3.txt) ([short](../changelogs/short/v4.3.txt)) 55 | * [awesome-4.3.tar.bz2](https://github.com/awesomeWM/awesome-releases/raw/master/awesome-4.3.tar.bz2) ([GPG sig](https://github.com/awesomeWM/awesome-releases/raw/master/awesome-4.3.tar.bz2.asc)) 56 | * [awesome-4.3.tar.xz](https://github.com/awesomeWM/awesome-releases/raw/master/awesome-4.3.tar.xz) ([GPG sig](https://github.com/awesomeWM/awesome-releases/raw/master/awesome-4.3.tar.xz.asc)) 57 | 58 | ### Old stable 59 | 60 | This branch of **awesome** is deprecated. 61 | 62 | Latest old stable version of **awesome** is version 3.5.9 (*Mighty Ravendark*) 63 | released on 6 March 2016. 64 | 65 | * [v3.5.9 changelog](../changelogs/v3.5.9.txt) ([short](../changelogs/short/v3.5.9.txt)) 66 | * [awesome-3.5.9.tar.bz2](https://github.com/awesomeWM/awesome-releases/raw/master/awesome-3.5.9.tar.bz2) 67 | * [awesome-3.5.9.tar.xz](https://github.com/awesomeWM/awesome-releases/raw/master/awesome-3.5.9.tar.xz) 68 | 69 | ### Development 70 | 71 | The Git repository can be cloned from Github: 72 | 73 | `git clone https://github.com/awesomeWM/awesome.git` 74 | 75 | Alternatively, development versions can be downloaded as ZIP files through the 76 | [Github web interface](https://github.com/awesomeWM/awesome). 77 | 78 | ## History 79 | 80 | A list of of old releases [[is available here|releases]]. 81 | -------------------------------------------------------------------------------- /recipes/xrandr.lua: -------------------------------------------------------------------------------- 1 | --- Separating Multiple Monitor functions as a separeted module (taken from awesome wiki) 2 | 3 | local gtable = require("gears.table") 4 | local spawn = require("awful.spawn") 5 | local naughty = require("naughty") 6 | 7 | -- A path to a fancy icon 8 | local icon_path = "" 9 | 10 | -- Get active outputs 11 | local function outputs() 12 | local outputs = {} 13 | local xrandr = io.popen("xrandr -q --current") 14 | 15 | if xrandr then 16 | for line in xrandr:lines() do 17 | local output = line:match("^([%w-]+) connected ") 18 | if output then 19 | outputs[#outputs + 1] = output 20 | end 21 | end 22 | xrandr:close() 23 | end 24 | 25 | return outputs 26 | end 27 | 28 | local function arrange(out) 29 | -- We need to enumerate all permutations of horizontal outputs. 30 | 31 | local choices = {} 32 | local previous = { {} } 33 | for i = 1, #out do 34 | -- Find all permutation of length `i`: we take the permutation 35 | -- of length `i-1` and for each of them, we create new 36 | -- permutations by adding each output at the end of it if it is 37 | -- not already present. 38 | local new = {} 39 | for _, p in pairs(previous) do 40 | for _, o in pairs(out) do 41 | if not gtable.hasitem(p, o) then 42 | new[#new + 1] = gtable.join(p, {o}) 43 | end 44 | end 45 | end 46 | choices = gtable.join(choices, new) 47 | previous = new 48 | end 49 | 50 | return choices 51 | end 52 | 53 | -- Build available choices 54 | local function menu() 55 | local menu = {} 56 | local out = outputs() 57 | local choices = arrange(out) 58 | 59 | for _, choice in pairs(choices) do 60 | local cmd = "xrandr" 61 | -- Enabled outputs 62 | for i, o in pairs(choice) do 63 | cmd = cmd .. " --output " .. o .. " --auto" 64 | if i > 1 then 65 | cmd = cmd .. " --right-of " .. choice[i-1] 66 | end 67 | end 68 | -- Disabled outputs 69 | for _, o in pairs(out) do 70 | if not gtable.hasitem(choice, o) then 71 | cmd = cmd .. " --output " .. o .. " --off" 72 | end 73 | end 74 | 75 | local label = "" 76 | if #choice == 1 then 77 | label = 'Only ' .. choice[1] .. '' 78 | else 79 | for i, o in pairs(choice) do 80 | if i > 1 then label = label .. " + " end 81 | label = label .. '' .. o .. '' 82 | end 83 | end 84 | 85 | menu[#menu + 1] = { label, cmd } 86 | end 87 | 88 | return menu 89 | end 90 | 91 | -- Display xrandr notifications from choices 92 | local state = { cid = nil } 93 | 94 | local function naughty_destroy_callback(reason) 95 | if reason == naughty.notificationClosedReason.expired or 96 | reason == naughty.notificationClosedReason.dismissedByUser then 97 | local action = state.index and state.menu[state.index - 1][2] 98 | if action then 99 | spawn(action, false) 100 | state.index = nil 101 | end 102 | end 103 | end 104 | 105 | local function xrandr() 106 | -- Build the list of choices 107 | if not state.index then 108 | state.menu = menu() 109 | state.index = 1 110 | end 111 | 112 | -- Select one and display the appropriate notification 113 | local label, action 114 | local next = state.menu[state.index] 115 | state.index = state.index + 1 116 | 117 | if not next then 118 | label = "Keep the current configuration" 119 | state.index = nil 120 | else 121 | label, action = next[1], next[2] 122 | end 123 | state.cid = naughty.notify({ text = label, 124 | icon = icon_path, 125 | timeout = 4, 126 | screen = mouse.screen, 127 | replaces_id = state.cid, 128 | destroy = naughty_destroy_callback}).id 129 | end 130 | 131 | return { 132 | outputs = outputs, 133 | arrange = arrange, 134 | menu = menu, 135 | xrandr = xrandr 136 | } 137 | -------------------------------------------------------------------------------- /images/awesome-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 40 | 42 | 43 | 45 | image/svg+xml 46 | 48 | 49 | 50 | 51 | 52 | 54 | 59 | 64 | 69 | 74 | 79 | 84 | 89 | 94 | 99 | 104 | 109 | 114 | 115 | -------------------------------------------------------------------------------- /releases.mdwn: -------------------------------------------------------------------------------- 1 | # Releases 2 | 3 | This page provides an overview over all releases of awesome. 4 | 5 | ## Version 4 6 | 7 | [[!table data=""" 8 | Date |Version |Codename 9 | 28 January 2019 |awesome 4.3 |Too long 10 | 15 July 2017 |awesome 4.2 |Human after all 11 | 18 March 2017 |awesome 4.1 |Technologic 12 | **25 December 2016** |**awesome 4.0**|**Harder, Better, Faster, Stronger** 13 | """]] 14 | 15 | ## Version 3 16 | 17 | [[!table data=""" 18 | Date |Version |Codename 19 | 6 March 2016 |awesome 3.5.9 |Mighty Ravendark 20 | 30 January 2016 |awesome 3.5.8 |Major Tom 21 | 15 January 2016 |awesome 3.5.7 |Space Oddity 22 | 10 January 2015 |awesome 3.5.6 |For Those About To Rock 23 | 11 April 2014 |awesome 3.5.5 |Kansas City Shuffle 24 | 2 April 2014 |awesome 3.5.4 |Brown Paper Bag 25 | 29 March 2014 |awesome 3.5.3 |Crazy 26 | 12 Octover 2013 |awesome 3.5.2 |The Fox 27 | 1 April 2013 |awesome 3.5.1 |Ruby Tuesday 28 | **21 December 2012** |**awesome 3.5**|**Last Christmas** 29 | 14 December 2012 |awesome 3.5-rc2|I'll Kill Her 30 | 24 November 2012 |awesome 3.5-rc1|Dirty Magic 31 | 11 February 2013 |awesome 3.4.15 |Never Gonna Give You Up 32 | 24 December 2012 |awesome 3.4.14 |White Christmas 33 | 15 July 2012 |awesome 3.4.13 |Octoveropus 34 | 11 June 2012 |awesome 3.4.12 |Starlight 35 | 23 November 2011 |awesome 3.4.11 |Pickapart 36 | 16 May 2011 |awesome 3.4.10 |Exploder 37 | 17 January 2011 |awesome 3.4.9 |Smack 38 | 4 Octover 2010 |awesome 3.4.8 |Never Know 39 | 25 August 2010 |awesome 3.4.7 |Left Of Center 40 | 14 July 2010 |awesome 3.4.6 |Hootch 41 | 10 May 2010 |awesome 3.4.5 |Close To You 42 | 02 March 2010 |awesome 3.4.4 |Jet Sex 43 | 04 January 2010 |awesome 3.4.3 |Engines 44 | 26 November 2009 |awesome 3.4.2 |For The Restless 45 | 9 November 2009 |awesome 3.4.1 |Ego Rock 46 | **20 Octover 2009** |**awesome 3.4**|**Closing In** 47 | 9 Octover 2009 |awesome 3.4-rc3|Black Star 48 | 28 September 2009 |awesome 3.4-rc2|Piku 49 | 11 September 2009 |awesome 3.4-rc1|Uprising 50 | 7 September 2009 |awesome 3.3.4 |Mercury 51 | 25 August 2009 |awesome 3.3.3 |Firelight 52 | 27 July 2009 |awesome 3.3.2 |Half Moon 53 | 18 June 2009 |awesome 3.3.1 |Bionic 54 | **4 June 2009** |**awesome 3.3**|**Stellar** 55 | 26 May 2009 |awesome 3.3-rc4|Breath 56 | 18 May 2009 |awesome 3.3-rc3|Uniform 57 | 8 May 2009 |awesome 3.3-rc2|Bad Boyfriend 58 | 1 May 2009 |awesome 3.3-rc1|The Lightning Strike 59 | 4 April 2009 |awesome 3.2.1 |Complicated 60 | **13 March 2009** |**awesome 3.2**|**Accidental Babies** 61 | 27 February 2009 |awesome 3.2-rc4|Faith 62 | 20 February 2009 |awesome 3.2-rc3|Chocolate 63 | 13 February 2009 |awesome 3.2-rc2|Hunting For Witches 64 | 6 February 2009 |awesome 3.2-rc1|Candyman 65 | 5 February 2009 |awesome 3.1.2 |Nobody Came 66 | 8 January 2009 |awesome 3.1.1 |Ring My Bell 67 | **12 December 2008** |**awesome 3.1**|**Helicopter** 68 | 5 December 2008 |awesome 3.1-rc5|Face 69 | 28 November 2008 |awesome 3.1-rc4|Seven Nation Army 70 | 21 November 2008 |awesome 3.1-rc3|When Doves Cry 71 | 14 November 2008 |awesome 3.1-rc2|When She Believes 72 | 7 November 2008 |awesome 3.1-rc1|The Golden Floor 73 | **18 September 2008**|**awesome 3.0**|**Fake Plastic Trees** 74 | 5 September 2008 |awesome 3.0-rc6|Elect The Dead 75 | 29 August 2008 |awesome 3.0-rc5|Marchshals Are Dead 76 | 22 August 2008 |awesome 3.0-rc4|Scared Of Girls 77 | 15 August 2008 |awesome 3.0-rc3|Into The Groove 78 | 8 August 2008 |awesome 3.0-rc2|Wake Up Call 79 | 1 August 2008 |awesome 3.0-rc1|Time To Pretend 80 | """]] 81 | 82 | ## Version 2 83 | 84 | [[!table data=""" 85 | Date |Version |Codename 86 | 18 April 2009 |awesome 2.3.6 |Tomorrow Morning 87 | 2 January 2009 |awesome 2.3.5 |New Morning 88 | 24 August 2008 |awesome 2.3.4 |Morning Trouble 89 | 26 July 2008 |awesome 2.3.3 |Pure Morning 90 | 24 June 2008 |awesome 2.3.2 |Morning Yearning 91 | 2 June 2008 |awesome 2.3.1 |Morning Glory 92 | **6 May 2008** |**awesome 2.3**|**Morning View** 93 | 21 April 2008 |awesome 2.3-rc3|Dirty Boots 94 | 17 April 2008 |awesome 2.3-rc2|Better Than 95 | 7 April 2008 |awesome 2.3-rc1|Deep Inside 96 | **23 March 2008** |**awesome 2.2**|**Morning Lemon** 97 | 13 March 2008 |awesome 2.2-rc4|Wooden Horse 98 | 4 March 2008 |awesome 2.2-rc3|There There 99 | 25 Feburary 2008 |awesome 2.2-rc2|Broken Man 100 | 14 Feburary 2008 |awesome 2.2-rc1|Digital Love 101 | **21 January 2008**|**awesome 2.1**|**Morning Bell** 102 | 12 January 2008 |awesome 2.1-rc2|Blow out 103 | 9 January 2008 |awesome 2.1-rc1|Dracula Cowboy 104 | **11 December 2007**|**awesome 2.0**|**Fruit Fly** 105 | 29 November 2007 |awesome 2.0-rc2|Softened Lights 106 | 16 November 2007 |awesome 2.0-rc1|Bumping Toaster 107 | """]] 108 | 109 | 110 | ## Version 1 111 | 112 | [[!table data=""" 113 | Date |Version 114 | 5 October 2007 |awesome 1.3 115 | 26 September 2007 |awesome 1.2 116 | 20 September 2007 |awesome 1.1 117 | **19 September 2007**|**awesome 1.0** 118 | """]] 119 | -------------------------------------------------------------------------------- /images/icons/sun.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 40 | 42 | 44 | 48 | 52 | 56 | 60 | 64 | 68 | 72 | 76 | 80 | 81 | 82 | 84 | 85 | 87 | 88 | 90 | 91 | 93 | 94 | 96 | 97 | 99 | 100 | 102 | 103 | 105 | 106 | 108 | 109 | 111 | 112 | 114 | 115 | 117 | 118 | 120 | 121 | 123 | 124 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /recipes/mic.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | Licensed under GNU General Public License v2 4 | * (c) 2021, bzgec 5 | 6 | 7 | # Microphone state widget/watcher 8 | 9 | This widget can be used to display the current microphone status. 10 | 11 | ## Requirements 12 | 13 | - `amixer` - this command is used to get and toggle microphone state 14 | 15 | ## Usage 16 | 17 | - Download [mic.lua](https://awesomewm.org/recipes/mic.lua) file and put it into awesome's 18 | folder (like `~/.config/awesome/widgets/mic.lua`) 19 | 20 | - Add widget to `theme.lua`: 21 | 22 | ```lua 23 | local widgets = { 24 | mic = require("widgets/mic"), 25 | } 26 | theme.mic = widgets.mic({ 27 | timeout = 10, 28 | settings = function(self) 29 | if self.state == "muted" then 30 | self.widget:set_image(theme.widget_micMuted) 31 | else 32 | self.widget:set_image(theme.widget_micUnmuted) 33 | end 34 | end 35 | }) 36 | local widget_mic = wibox.widget { theme.mic.widget, layout = wibox.layout.align.horizontal } 37 | ``` 38 | 39 | - Create a shortcut to toggle microphone state (add to `rc.lua`): 40 | 41 | ```lua 42 | -- Toggle microphone state 43 | awful.key({ modkey, "Shift" }, "m", 44 | function () 45 | beautiful.mic:toggle() 46 | end, 47 | {description = "Toggle microphone (amixer)", group = "Hotkeys"} 48 | ), 49 | ``` 50 | 51 | - You can also add a command to mute the microphone state on boot. Add this to your `rc.lua`: 52 | 53 | ```lua 54 | -- Mute microphone on boot 55 | beautiful.mic:mute() 56 | ``` 57 | 58 | --]] 59 | 60 | 61 | local awful = require("awful") 62 | local naughty = require("naughty") 63 | local gears = require("gears") 64 | local wibox = require("wibox") 65 | 66 | local function factory(args) 67 | local args = args or {} 68 | 69 | local mic = { 70 | widget = args.widget or wibox.widget.imagebox(), 71 | settings = args.settings or function(self) end, 72 | timeout = args.timeout or 10, 73 | timer = gears.timer, 74 | state = "", 75 | } 76 | 77 | function mic:mute() 78 | awful.spawn.easy_async({"amixer", "set", "Capture", "nocap"}, 79 | function() 80 | self:update() 81 | end 82 | ) 83 | end 84 | 85 | function mic:unmute() 86 | awful.spawn.easy_async({"amixer", "set", "Capture", "cap"}, 87 | function() 88 | self:update() 89 | end 90 | ) 91 | end 92 | 93 | function mic:toggle() 94 | awful.spawn.easy_async({"amixer", "set", "Capture", "toggle"}, 95 | function() 96 | self:update() 97 | end 98 | ) 99 | end 100 | 101 | function mic:pressed(button) 102 | if button == 1 then 103 | self:toggle() 104 | end 105 | end 106 | 107 | function mic:update() 108 | -- Check that timer has started 109 | if self.timer.started then 110 | self.timer:emit_signal("timeout") 111 | end 112 | end 113 | 114 | -- Read `amixer get Capture` command and try to `grep` all "[on]" lines. 115 | -- - If there are lines with "[on]" then assume microphone is "unmuted". 116 | -- - If there are NO lines with "[on]" then assume microphone is "muted". 117 | mic, mic.timer = awful.widget.watch( 118 | {"bash", "-c", "amixer get Capture | grep '\\[on\\]'"}, 119 | mic.timeout, 120 | function(self, stdout, stderr, exitreason, exitcode) 121 | local current_micState = "error" 122 | 123 | if exitcode == 1 then 124 | -- Exit code 1 - no line selected 125 | current_micState = "muted" 126 | elseif exitcode == 0 then 127 | -- Exit code 0 - a line is selected 128 | current_micState = "unmuted" 129 | else 130 | -- Other exit code (2) - error occurred 131 | current_micState = "error" 132 | end 133 | 134 | -- Compare new and old state 135 | if current_micState ~= self.state then 136 | if current_micState == "muted" then 137 | naughty.notify({preset=naughty.config.presets.normal, 138 | title="mic widget info", 139 | text='muted'}) 140 | elseif current_micState == "unmuted" then 141 | naughty.notify({preset=naughty.config.presets.normal, 142 | title="mic widget info", 143 | text='unmuted'}) 144 | else 145 | naughty.notify({preset=naughty.config.presets.critical, 146 | title="mic widget error", 147 | text='Error on "amixer get Capture | grep \'\\[on\\]\'"'}) 148 | end 149 | 150 | -- Store new microphone state 151 | self.state = current_micState 152 | end 153 | 154 | -- Call user/theme defined function 155 | self:settings() 156 | end, 157 | mic -- base_widget (passed in callback function as first parameter) 158 | ) 159 | 160 | -- add mouse click 161 | mic.widget:connect_signal("button::press", function(c, _, _, button) 162 | mic:pressed(button) 163 | end) 164 | 165 | return mic 166 | end 167 | 168 | return factory 169 | -------------------------------------------------------------------------------- /.github/workflows/www.yml: -------------------------------------------------------------------------------- 1 | name: Build and publish awesomewm.org 2 | 3 | on: 4 | # Trigger on push to branche `master`. 5 | push: 6 | branches: [ master ] 7 | # Trigger on pull request events for PRs that have `master` as their target branch 8 | pull_request: 9 | branches: [ master ] 10 | 11 | # Allow running the workflow manually 12 | workflow_dispatch: 13 | 14 | defaults: 15 | run: 16 | # GitHub Actions adds `errexit` and `pipefail` by default, but we add `xtrace` 17 | # to improve debugging some of the longer scripts. 18 | shell: /bin/bash -o errexit -o pipefail -o xtrace {0} 19 | 20 | jobs: 21 | main: 22 | runs-on: ubuntu-20.04 23 | 24 | env: 25 | BUILD_WEB: "/tmp/build-web" 26 | 27 | steps: 28 | # Create a cache invalidation key based on the current year + week. 29 | # This way, packages will be checked for updates once every week. 30 | - name: Get Date 31 | id: get-date 32 | run: echo "::set-output name=date::$(/bin/date -u "+%Y%W")" 33 | 34 | - name: Cache apt packages 35 | id: cache-apt 36 | uses: actions/cache@v2 37 | with: 38 | path: /var/cache/apt/archives 39 | # The trailing number serves as a version flag that can be incremented 40 | # to invalidate the cache after changing the list of packages. 41 | key: ${{ github.workflow }}-${{ runner.os }}-${{ steps.get-date.outputs.date }}-apt-3 42 | 43 | - name: Download apt packages 44 | if: steps.cache-apt.outputs.cache-hit != 'true' 45 | run: | 46 | sudo apt-get update 47 | sudo apt-get install --download-only -y --no-install-recommends \ 48 | ikiwiki \ 49 | asciidoc \ 50 | imagemagick \ 51 | perlmagick \ 52 | luarocks \ 53 | cmake \ 54 | libxcb-cursor-dev \ 55 | libxcb-randr0-dev \ 56 | libxcb-xtest0-dev \ 57 | libxcb-xinerama0-dev \ 58 | libxcb-shape0-dev \ 59 | libxcb-util0-dev \ 60 | libxcb-keysyms1-dev \ 61 | libxcb-icccm4-dev \ 62 | libxcb-xrm-dev \ 63 | libxdg-basedir-dev \ 64 | libstartup-notification0-dev \ 65 | libxcb-xkb-dev \ 66 | libxkbcommon-dev \ 67 | libxkbcommon-x11-dev \ 68 | gir1.2-pango-1.0 \ 69 | xutils-dev \ 70 | libgirepository1.0-dev \ 71 | lua-discount 72 | 73 | - name: Install downloaded packages 74 | run: | 75 | sudo dpkg -i /var/cache/apt/archives/*.deb 76 | 77 | - name: Cache luarocks 78 | id: cache-luarocks 79 | uses: actions/cache@v2 80 | with: 81 | path: /tmp/luarocks 82 | key: ${{ github.workflow }}-${{ runner.os }}-luarocks-3.5.0 83 | 84 | - name: Install fresh Luarocks 85 | if: steps.cache-luarocks.outputs.cache-hit != 'true' 86 | run: | 87 | wget -O /tmp/luarocks.tar.gz https://github.com/luarocks/luarocks/archive/v3.5.0.tar.gz 88 | mkdir /tmp/luarocks 89 | tar -xf /tmp/luarocks.tar.gz -C /tmp/luarocks --strip-components=1 90 | cd /tmp/luarocks 91 | ./configure 92 | make build 93 | sudo make install 94 | 95 | - name: Install cached Luarocks 96 | if: steps.cache-luarocks.outputs.cache-hit == 'true' 97 | run: | 98 | cd /tmp/luarocks 99 | sudo make install 100 | 101 | - name: Install rocks 102 | run: | 103 | sudo -H luarocks install lgi 104 | sudo -H luarocks install ldoc 105 | 106 | - name: Install mdl 107 | run: | 108 | sudo gem install mdl -v 0.9.0 109 | 110 | - uses: actions/checkout@v2 111 | with: 112 | submodules: recursive 113 | 114 | - name: Get Awesome website target repo 115 | env: 116 | APIDOC_TOKEN: ${{ secrets.AWESOME_ROBOT_TOKEN || github.token }} 117 | run: | 118 | set -e 119 | git clone \ 120 | https://${APIDOC_TOKEN}@github.com/awesomeWM/awesomeWM.github.io \ 121 | "$BUILD_WEB" 2>&1 | sed "s/$APIDOC_TOKEN/APIDOC_TOKEN/g" 122 | if [ "${{ github.event_name }}" != 'pull_request' ]; then 123 | branch="${{ github.head_ref || github.ref_name }}" 124 | else 125 | branch="pr-${{ github.event.pull_request.number }}" 126 | fi 127 | if [ "$branch" != master ]; then 128 | cd "$BUILD_WEB" 129 | if ! git checkout -b "$branch" "origin/$branch"; then 130 | git checkout -b "$branch" 131 | fi 132 | cd - 133 | fi 134 | 135 | - name: Build website 136 | run: | 137 | cd "${{ github.workspace }}" 138 | PKG_CONFIG_PATH="$HOME/install/lib/pkgconfig" make build_for_gh_actions 139 | mdl --git-recurse . 140 | 141 | - name: Publish website 142 | if: github.event_name != 'pull_request' 143 | env: 144 | APIDOC_TOKEN: ${{ secrets.AWESOME_ROBOT_TOKEN || github.token }} 145 | CLOUDFLARE_ZONE: ${{ secrets.CLOUDFLARE_ZONE }} 146 | CLOUDFLARE_AUTH_EMAIL: ${{ secrets.CLOUDFLARE_AUTH_EMAIL }} 147 | CLOUDFLARE_AUTH_KEY: ${{ secrets.CLOUDFLARE_AUTH_KEY }} 148 | run: | 149 | set -e 150 | commit_hash=$(git rev-parse --short HEAD) 151 | cd "$BUILD_WEB" 152 | git config user.name "awesome-robot on GH Actions" 153 | git config user.email "awesome-robot@users.noreply.github.com" 154 | git add --all . 155 | NL=$'\n' 156 | git commit -m "Update from GH Actions for awesome-www@${commit_hash}${NL}${NL}Commits: ${{ github.event.pull_request.commits_url }}${NL}Build URL: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}" 157 | git --no-pager show --stat 158 | git push origin "$(git symbolic-ref --quiet HEAD)" 2>&1 | sed "s/$APIDOC_TOKEN/APIDOC_TOKEN/g" 159 | 160 | # Purge CloudFlare cache. 161 | curl -X DELETE "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE/purge_cache" \ 162 | -H "X-Auth-Email: $CLOUDFLARE_AUTH_EMAIL" \ 163 | -H "X-Auth-Key: $CLOUDFLARE_AUTH_KEY" \ 164 | -H "Content-Type: application/json" \ 165 | --data '{"purge_everything":true}' 166 | 167 | # vim: filetype=yaml:expandtab:shiftwidth=2:tabstop=2 168 | -------------------------------------------------------------------------------- /templates/page.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <TMPL_VAR TITLE> - awesome window manager 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 69 | 70 |
71 | 72 |
73 | 74 |
75 | 76 |
77 |
78 |
79 | 15years anniversary 81 |
82 |
83 | 15years anniversary 84 |
85 | 86 | 88 | 89 | 97 | 98 | 105 | 106 | 107 |
108 | 109 | License: 110 |
111 |
112 | 113 |
114 | Last edited 115 |
116 |
117 |
118 | 119 | 120 |
    121 |
  • 122 |
  • 123 |
124 | 125 | 126 | 140 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /recipes/watch.mdwn: -------------------------------------------------------------------------------- 1 | # [`awful.widget.watch`](https://awesomewm.org/doc/api/classes/awful.widget.watch.html) use case examples 2 | 3 | ## bitcoin 4 | 5 | Requires `curl` and [dkjson](https://github.com/LuaDist/dkjson) or [lain](https://github.com/copycat-killer/lain). 6 | 7 | ```lua 8 | local bitcoin = awful.widget.watch( 9 | "curl -m5 -s 'https://coinbase.com/api/v1/prices/buy'", 10 | 43200, -- half day 11 | function(widget, stdout) 12 | local btc, pos, err = require("dkjson").decode(stdout, 1, nil) -- dkjson 13 | --local btc, pos, err = require("lain.util").dkjson.decode(stdout, 1, nil) -- lain 14 | local btc_price = (not err and btc and btc["subtotal"]["amount"]) or "N/A" 15 | 16 | -- customize here 17 | widget:set_text(btc_price) 18 | end 19 | ) 20 | ``` 21 | 22 | ## brtfs 23 | 24 | ```lua 25 | -- btrfs root df 26 | local myrootfs = awful.widget.watch( 27 | "btrfs filesystem df -g /", 28 | 600, -- 10 minutes 29 | function(widget, stdout) 30 | local total, used = string.match(stdout, "Data.-total=(%d+%.%d+)GiB.-used=(%d+%.%d+)GiB") 31 | local percent_used = math.ceil((tonumber(used) / tonumber(total)) * 100) 32 | 33 | -- customize here 34 | widget:set_text(" [/: " .. percent_used .. "%] ") 35 | end 36 | ) 37 | ``` 38 | 39 | ## cmus 40 | 41 | ```lua 42 | -- cmus audio player 43 | local cmus, cmus_timer = awful.widget.watch( 44 | "cmus-remote -Q", 45 | 2, 46 | function(widget, stdout) 47 | local cmus_now = { 48 | state = "N/A", 49 | artist = "N/A", 50 | title = "N/A", 51 | album = "N/A" 52 | } 53 | 54 | for w in string.gmatch(stdout, "(.-)tag") do 55 | a, b = w:match("(%w+) (.-)\n") 56 | cmus_now[a] = b 57 | end 58 | 59 | -- customize here 60 | widget:set_text(cmus_now.artist .. " - " .. cmus_now.title) 61 | end 62 | ) 63 | ``` 64 | 65 | ## iostat 66 | 67 | ```lua 68 | -- disk I/O using iostat from sysstat utilities 69 | local iotable = {} 70 | local iostat = awful.widget.watch("iostat -dk", 2, -- in Kb, use -dm for Mb 71 | function(widget, stdout) 72 | for line in stdout:match("(sd.*)\n"):gmatch("(.-)\n") do 73 | local device, tps, read_s, wrtn_s, read, wrtn = 74 | line:match("(%w+)%s*(%d+,?%d*)%s*(%d+,?%d*)%s*(%d+,?%d*)%s*(%d+,?%d*)%s*(%d+,?%d*)") 75 | -- [1] [2] [3] [4] [5] 76 | iotable[device] = { tps, read_s, wrtn_s, read, wrtn } 77 | end 78 | 79 | -- customize here 80 | widget:set_text("sda: "..iotable["sda"][2].."/"..iotable["sda"][3]) -- read_s/wrtn_s 81 | end 82 | ) 83 | ``` 84 | 85 | ## maildir 86 | 87 | ```lua 88 | -- checks whether there are files in the "new" directories of a mail dirtree 89 | local mailpath = "~/Mail" 90 | local mymaildir = awful.widget.watch( 91 | { awful.util.shell, "-c", string.format("ls -1dr %s/*/new/*", mailpath) }, 92 | 60, 93 | function(widget, stdout) 94 | local inbox_now = { digest = "" } 95 | 96 | for dir in stdout:gmatch(".-/(%w+)/new") do 97 | inbox_now[dir] = 1 98 | for _ in stdout:gmatch(dir) do 99 | inbox_now[dir] = inbox_now[dir] + 1 100 | end 101 | if #inbox_now.digest > 0 then inbox_now.digest = inbox_now.digest .. ", " end 102 | inbox_now.digest = inbox_now.digest .. string.format("%s (%d)", dir, inbox_now[dir]) 103 | end 104 | 105 | -- customize here 106 | widget:set_text("mail: " .. inbox_now.digest) 107 | end 108 | ) 109 | ``` 110 | 111 | ## mpris 112 | 113 | ```lua 114 | -- infos from mpris clients such as spotify and VLC 115 | -- based on https://github.com/acrisci/playerctl 116 | local mpris, mpris_timer = awful.widget.watch( 117 | { awful.util.shell, "-c", "playerctl status && playerctl metadata" }, 118 | 2, 119 | function(widget, stdout) 120 | local escape_f = require("awful.util").escape 121 | local mpris_now = { 122 | state = "N/A", 123 | artist = "N/A", 124 | title = "N/A", 125 | art_url = "N/A", 126 | album = "N/A", 127 | album_artist = "N/A" 128 | } 129 | 130 | mpris_now.state = string.match(stdout, "Playing") or 131 | string.match(stdout, "Paused") or "N/A" 132 | 133 | for k, v in string.gmatch(stdout, "'[^:]+:([^']+)':[%s]<%[?'([^']+)'%]?>") 134 | do 135 | if k == "artUrl" then mpris_now.art_url = v 136 | elseif k == "artist" then mpris_now.artist = escape_f(v) 137 | elseif k == "title" then mpris_now.title = escape_f(v) 138 | elseif k == "album" then mpris_now.album = escape_f(v) 139 | elseif k == "albumArtist" then mpris_now.album_artist = escape_f(v) 140 | end 141 | end 142 | 143 | -- customize here 144 | widget:set_text(mpris_now.artist .. " - " .. mpris_now.title) 145 | end 146 | ) 147 | ``` 148 | 149 | ## pipewire 150 | 151 | ```lua 152 | -- pactl based volume widget for pure pipewire setups 153 | local volume = awful.widget.watch( 154 | "pactl get-sink-volume @DEFAULT_SINK@ | cut -s -d/ -f2,4; pactl get-sink-mute @DEFAULT_SINK@", 155 | 5, -- timeout 156 | function(widget, stdout) 157 | local volume = "Volume: " 158 | for v in stdout:gmatch("(%d+%%)") do volume = volume .. " " .. v end 159 | if #volume == 8 then volume = "N/A" end 160 | local mute = string.match(stdout, "Mute: (%S+)") or "N/A" 161 | 162 | -- customize here 163 | widget:set_markup(volume .. " " .. mute) 164 | end 165 | ) 166 | ``` 167 | 168 | ## upower 169 | 170 | ```lua 171 | -- battery infos from freedesktop upower 172 | local mybattery = awful.widget.watch( 173 | { awful.util.shell, "-c", "upower -i /org/freedesktop/UPower/devices/battery_BAT | sed -n '/present/,/icon-name/p'" }, 174 | 30, 175 | function(widget, stdout) 176 | local bat_now = { 177 | present = "N/A", 178 | state = "N/A", 179 | warninglevel = "N/A", 180 | energy = "N/A", 181 | energyfull = "N/A", 182 | energyrate = "N/A", 183 | voltage = "N/A", 184 | percentage = "N/A", 185 | capacity = "N/A", 186 | icon = "N/A" 187 | } 188 | 189 | for k, v in string.gmatch(stdout, '([%a]+[%a|-]+):%s*([%a|%d]+[,|%a|%d]-)') do 190 | if k == "present" then bat_now.present = v 191 | elseif k == "state" then bat_now.state = v 192 | elseif k == "warning-level" then bat_now.warninglevel = v 193 | elseif k == "energy" then bat_now.energy = string.gsub(v, ",", ".") -- Wh 194 | elseif k == "energy-full" then bat_now.energyfull = string.gsub(v, ",", ".") -- Wh 195 | elseif k == "energy-rate" then bat_now.energyrate = string.gsub(v, ",", ".") -- W 196 | elseif k == "voltage" then bat_now.voltage = string.gsub(v, ",", ".") -- V 197 | elseif k == "percentage" then bat_now.percentage = tonumber(v) -- % 198 | elseif k == "capacity" then bat_now.capacity = string.gsub(v, ",", ".") -- % 199 | elseif k == "icon-name" then bat_now.icon = v 200 | end 201 | end 202 | 203 | -- customize here 204 | widget:set_text("Bat: " .. bat_now.percentage .. " " .. bat_now.state) 205 | end 206 | ) 207 | ``` 208 | -------------------------------------------------------------------------------- /recipes/mpc.lua: -------------------------------------------------------------------------------- 1 | local lgi = require "lgi" 2 | local GLib = lgi.GLib 3 | local Gio = lgi.Gio 4 | 5 | local gears = require "gears" 6 | 7 | local mpc = {} 8 | 9 | local function parse_password(host) 10 | -- This function is based on mpd_parse_host_password() from libmpdclient 11 | local position = string.find(host, "@") 12 | if not position then 13 | return host 14 | end 15 | return string.sub(host, position + 1), string.sub(host, 1, position - 1) 16 | end 17 | 18 | function mpc.new(host, port, password, error_handler, reconnect_interval, ...) 19 | host = host or os.getenv("MPD_HOST") or "localhost" 20 | port = port or os.getenv("MPD_PORT") or 6600 21 | if not password then 22 | host, password = parse_password(host) 23 | end 24 | 25 | local self = setmetatable({ 26 | _host = host, 27 | _port = port, 28 | _password = password, 29 | _error_handler = error_handler or function() end, 30 | _connected = false, 31 | _idle_commands = { ... }, 32 | _conn = nil, 33 | _output = nil, 34 | _input = nil, 35 | _reconnect_timer = nil, 36 | _reconnect_interval = reconnect_interval, 37 | _try_reconnect = true 38 | }, { __index = mpc }) 39 | 40 | self:_connect() 41 | return self 42 | end 43 | 44 | function mpc:_error(err) 45 | self._error_handler(err, self) 46 | end 47 | 48 | function mpc:_reset() 49 | self._output = nil 50 | self._input = nil 51 | self._reply_handlers = {} 52 | self._pending_reply = {} 53 | self._idle_commands_pending = false 54 | self._idle = false 55 | self._connected = false 56 | end 57 | 58 | function mpc:_reconnect() 59 | if not self._reconnect_timer then 60 | self:_error("cannot reconnect") 61 | return 62 | end 63 | 64 | if not self._try_reconnect then 65 | return 66 | end 67 | 68 | self._reconnect_timer:again() 69 | end 70 | 71 | function mpc:_connect() 72 | if self._connected then return end 73 | -- Reset all of our state 74 | self:_reset() 75 | 76 | -- Set up a new connection 77 | local address 78 | if string.sub(self._host, 1, 1) == "/" then 79 | -- It's a unix socket 80 | address = Gio.UnixSocketAddress.new(self._host) 81 | else 82 | -- Do a TCP connection 83 | address = Gio.NetworkAddress.new(self._host, self._port) 84 | end 85 | local client = Gio.SocketClient() 86 | 87 | local conn 88 | if not self._conn then 89 | if not self._reconnect_timer and self._try_reconnect then 90 | -- timer requires positive value 91 | local interval = self._reconnect_interval >= 0 and self._reconnect_interval or 0 92 | self._reconnect_timer = gears.timer.start_new(interval, function() 93 | -- user disabled reconnect 94 | if self._reconnect_interval < 0 then 95 | self._try_reconnect = false 96 | end 97 | 98 | self:_reset() 99 | conn, err = client:connect(address) 100 | 101 | if not conn then 102 | self:_error(err) 103 | return true 104 | end 105 | 106 | self._connected = true 107 | 108 | local input, output = conn:get_input_stream(), conn:get_output_stream() 109 | self._conn, self._output, self._input = conn, output, Gio.DataInputStream.new(input) 110 | 111 | -- Read the welcome message 112 | self._input:read_line() 113 | 114 | if self._password and self._password ~= "" then 115 | self:_send("password " .. self._password) 116 | end 117 | 118 | return false 119 | end) 120 | else 121 | self:_reconnect() 122 | end 123 | end 124 | 125 | self._reconnect_timer:connect_signal("stop", function() 126 | self:do_read() 127 | -- To synchronize the state on startup, send the idle commands now. As a 128 | -- side effect, this will enable idle state. 129 | self:_send_idle_commands(true) 130 | end) 131 | end 132 | 133 | function mpc:do_read() 134 | -- Set up the reading loop. This will asynchronously read lines by 135 | -- calling itself. 136 | self._input:read_line_async(GLib.PRIORITY_DEFAULT, nil, function(obj, res) 137 | local line, err = obj:read_line_finish(res) 138 | -- Ugly API. On success we get string, length-of-string 139 | -- and on error we get nil, error. Other versions of lgi 140 | -- behave differently. 141 | if line == nil or tostring(line) == "" then 142 | err = "Connection closed" 143 | self:_error(err) 144 | self:_reconnect() 145 | return 146 | end 147 | 148 | if type(err) ~= "number" then 149 | self:_error(err) 150 | self:_reconnect() 151 | else 152 | self:do_read() 153 | line = tostring(line) 154 | if line == "OK" or line:match("^ACK ") then 155 | local success = line == "OK" 156 | local arg 157 | if success then 158 | arg = self._pending_reply 159 | else 160 | arg = { line } 161 | end 162 | local handler = self._reply_handlers[1] 163 | table.remove(self._reply_handlers, 1) 164 | self._pending_reply = {} 165 | handler(success, arg) 166 | else 167 | local _, _, key, value = string.find(line, "([^:]+):%s(.+)") 168 | if key then 169 | self._pending_reply[string.lower(key)] = value 170 | end 171 | end 172 | end 173 | end) 174 | end 175 | 176 | function mpc:_send_idle_commands(skip_stop_idle) 177 | -- We use a ping to unset this to make sure we never get into a busy 178 | -- loop sending idle / unidle commands. Next call to 179 | -- _send_idle_commands() might be ignored! 180 | if self._idle_commands_pending then 181 | return 182 | end 183 | if not skip_stop_idle then 184 | self:_stop_idle() 185 | end 186 | 187 | self._idle_commands_pending = true 188 | for i = 1, #self._idle_commands, 2 do 189 | self:_send(self._idle_commands[i], self._idle_commands[i+1]) 190 | end 191 | self:_send("ping", function() 192 | self._idle_commands_pending = false 193 | end) 194 | self:_start_idle() 195 | end 196 | 197 | function mpc:_start_idle() 198 | if self._idle then 199 | self:_error("still idle?!") 200 | error("Still idle?!") 201 | end 202 | self:_send("idle", function(success, reply) 203 | if reply.changed then 204 | -- idle mode was disabled by mpd 205 | self:_send_idle_commands() 206 | end 207 | end) 208 | self._idle = true 209 | end 210 | 211 | function mpc:_stop_idle() 212 | if not self._idle then 213 | self:_error("Not idle?!") 214 | error("Not idle?!") 215 | end 216 | self._output:write("noidle\n") 217 | self._idle = false 218 | end 219 | 220 | function mpc:_send(command, callback) 221 | if self._idle then 222 | self:_error("Still idle in send()?!") 223 | error("Still idle in send()?!") 224 | end 225 | self._output:write(command .. "\n") 226 | table.insert(self._reply_handlers, callback or function() end) 227 | end 228 | 229 | function mpc:send(...) 230 | if not self._conn then 231 | self:_reconnect() 232 | return 233 | end 234 | 235 | local args = { ... } 236 | if not self._idle then 237 | self:_error("Something is messed up, we should be idle here...") 238 | error("Something is messed up, we should be idle here...") 239 | end 240 | self:_stop_idle() 241 | for i = 1, #args, 2 do 242 | self:_send(args[i], args[i+1]) 243 | end 244 | self:_start_idle() 245 | end 246 | 247 | function mpc:toggle_play() 248 | self:send("status", function(success, status) 249 | if status.state == "stop" then 250 | self:send("play") 251 | else 252 | self:send("pause") 253 | end 254 | end) 255 | end 256 | 257 | --[[ 258 | 259 | -- Example on how to use this (standalone) 260 | -- set negative reconnect_interval to disable reconnect in case initial connection failed 261 | 262 | local host, port, password, reconnect_interval = nil, nil, nil, 0 263 | local m = mpc.new(host, port, password, error_handler, reconnect_interval 264 | "status", function(success, status) print("status is", status.state) end) 265 | 266 | GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, function() 267 | -- Test command submission 268 | m:send("status", function(_, s) print(s.state) end, 269 | "currentsong", function(_, s) print(s.title) end) 270 | m:send("status", function(_, s) print(s.state) end) 271 | -- Force a reconnect 272 | GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, function() 273 | m._conn:close() 274 | end) 275 | end) 276 | 277 | GLib.MainLoop():run() 278 | --]] 279 | 280 | return mpc 281 | -------------------------------------------------------------------------------- /recipes/wirelessStatus.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | Licensed under GNU General Public License v2 4 | * (c) 2021, bzgec 5 | 6 | 7 | # Wireless status widget/watcher 8 | 9 | Get wireless Quality link (converted to percentages) and wireless status. 10 | 11 | Data is taken from `/proc/net/wireless`. 12 | 13 | According to [this](https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Linux.Wireless.Extensions.html) 14 | website `/proc/net/wireless` has the following information: 15 | 16 | - Status: Its current state. This is a device dependent information. 17 | 18 | - Quality - link: general quality of the reception. 19 | 20 | - Quality - level: signal strength at the receiver. 21 | 22 | - Quality - noise: silence level (no packet) at the receiver. 23 | 24 | - Discarded - nwid: number of discarded packets due to invalid network id. 25 | 26 | - Discarded - crypt: number of packet unable to decrypt. 27 | 28 | - Discarded - misc: unused (for now). 29 | 30 | This widget uses `Quality - link` and converts it to percentages (`perc=Quality_link*10/7`). 31 | The above equation is taken from [this](https://superuser.com/a/1360447) forum answer. 32 | 33 | It also stores `Status` information (note that this is presumably device dependent). 34 | 35 | ## Requirements 36 | 37 | - `iw` 38 | 39 | ## Usage 40 | 41 | - Download [wirelessStatus.lua](https://awesomewm.org/recipes/wirelessStatus.lua) file and put it 42 | into awesome's folder (like `~/.config/awesome/widgets/wirelessStatus.lua`) 43 | 44 | - Add widget to `theme.lua`: 45 | 46 | ```lua 47 | local widgets = { 48 | wirelessStatus = require("widgets/wirelessStatus"), 49 | } 50 | -- Wireless status widget (`status` is presumably device dependent) 51 | theme.wirelessStatus = widgets.wirelessStatus({ 52 | notification_preset = { font = "Mononoki Nerd Font 10", fg = theme.fg_normal }, 53 | timeout = 10, 54 | settings = function(self) 55 | if self.status == "1" or self.status == "" then 56 | self.widget:set_image(theme.wifidisc) 57 | else 58 | if self.perc <= 5 then 59 | self.widget:set_image(theme.wifinone) 60 | elseif self.perc <= 25 then 61 | self.widget:set_image(theme.wifilow) 62 | elseif self.perc <= 50 then 63 | self.widget:set_image(theme.wifimed) 64 | elseif self.perc <= 75 then 65 | self.widget:set_image(theme.wifihigh) 66 | else 67 | self.widget:set_image(theme.wififull) 68 | end 69 | end 70 | end, 71 | }) 72 | local widget_wirelessStatus = wibox.widget { nil, theme.wirelessStatus.widget, layout = wibox.layout.align.horizontal } 73 | ``` 74 | 75 | - Set which application to run on widget press (add to `rc.lua`): 76 | 77 | ```lua 78 | -- wirelessStatus widget pressed function - open terminal and start `nmtui` 79 | beautiful.wirelessStatus.pressed = function(self, button) 80 | if button == 1 then -- left mouse click 81 | awful.spawn(terminal.." -e nmtui") 82 | end 83 | end 84 | ``` 85 | 86 | --]] 87 | 88 | 89 | local wibox = require("wibox") 90 | local naughty = require("naughty") 91 | local awful = require("awful") 92 | local gears = require("gears") 93 | 94 | local function factory(args) 95 | local args = args or {} 96 | 97 | local wirelessStatus = { 98 | widget = args.widget or wibox.widget.imagebox(), 99 | settings = args.settings or function(self) end, 100 | timeout = args.timeout or 10, 101 | pressed = args.pressed or function(self, button) end, 102 | followtag = args.followtag or false, 103 | notification_preset = args.notification_preset or {}, 104 | showpopup = args.showpopup or "on", -- Show notification popup while hovering above widget 105 | timer = gears.timer, 106 | interface = "", 107 | perc = 0, 108 | status = "", 109 | notification_text = "No connection", 110 | } 111 | 112 | -- Reset to default values 113 | function wirelessStatus:reset() 114 | wirelessStatus.interface = "" 115 | wirelessStatus.perc = 0 116 | wirelessStatus.status = "" 117 | wirelessStatus.notification_text = "No connection" 118 | end 119 | 120 | -- Show notification popup 121 | function wirelessStatus:show(seconds) 122 | self:hide() 123 | 124 | -- Update every time 125 | self:update() 126 | 127 | if self.followtag then 128 | self.notification_preset.screen = focused() 129 | end 130 | 131 | self.notification = naughty.notify { 132 | preset = self.notification_preset, 133 | text = self.notification_text, 134 | timeout = type(seconds) == "number" and seconds or self.notification_preset.timeout 135 | } 136 | end 137 | 138 | -- Hide notification popup 139 | function wirelessStatus:hide() 140 | if self.notification then 141 | naughty.destroy(self.notification) 142 | self.notification = nil 143 | end 144 | end 145 | 146 | function wirelessStatus:attach() 147 | self.widget:connect_signal("mouse::enter", function() 148 | self:show(0) 149 | end) 150 | self.widget:connect_signal("mouse::leave", function() 151 | self:hide() 152 | end) 153 | end 154 | 155 | -- Get name of wireless interface 156 | function wirelessStatus:getInterface() 157 | awful.spawn.easy_async_with_shell( 158 | "awk 'NR==3 {printf(\"%s\\n\", $1)}' /proc/net/wireless", 159 | function(stdout, exitcode) 160 | -- Store interface name 161 | -- Remove last character/s from string ("wlp4s0:"" -> "wlp4s0") 162 | self.interface = stdout:sub(0, -3) 163 | 164 | -- Check in case interface is now equal to "" (we don't want to cause recursive 165 | -- calls) 166 | if self.interface ~= "" then 167 | self:update() 168 | end 169 | end 170 | ) 171 | end 172 | 173 | function wirelessStatus:update() 174 | self.timer:emit_signal("timeout") 175 | end 176 | 177 | -- Get status and Quality link (convert quality link to percentages) 178 | wirelessStatus, wirelessStatus.timer = awful.widget.watch( 179 | { 'awk', 'NR==3 {printf("%d-%.0f\\n", $2, $3*10/7)}', '/proc/net/wireless' }, 180 | wirelessStatus.timeout, 181 | function(self, stdout, stderr, exitreason, exitcode) 182 | if stdout == "" then 183 | -- No output from command above -> reset internal values to default 184 | self:reset() 185 | else 186 | -- Status and Quality link received 187 | local status, perc = stdout:match("(%d)-(%d+)") 188 | perc = tonumber(perc) 189 | self.perc = perc 190 | self.status = status 191 | 192 | if self.interface == "" then 193 | -- Get interface name 194 | self:getInterface() 195 | else 196 | -- Get information about active connection 197 | local cmd_getInfo = "iw dev "..self.interface.." link" 198 | awful.spawn.easy_async_with_shell(cmd_getInfo, function(stdout, exitcode) 199 | self.notification_text = stdout 200 | end) 201 | end 202 | end 203 | 204 | -- Call user/theme defined function 205 | self:settings() 206 | end, 207 | wirelessStatus -- base_widget (passed in callback function as first parameter) 208 | ) 209 | 210 | -- Show notification popup while hovering above widget 211 | if wirelessStatus.showpopup == "on" then wirelessStatus:attach(wirelessStatus.widget) end 212 | 213 | wirelessStatus.widget:connect_signal("button::press", function(c, _, _, button) 214 | wirelessStatus:pressed(button) 215 | end) 216 | 217 | return wirelessStatus 218 | end 219 | 220 | return factory 221 | -------------------------------------------------------------------------------- /css/local.css: -------------------------------------------------------------------------------- 1 | /* Styles for https://awesomewm.org/ 2 | * Source: https://github.com/awesomeWM/awesome-www 3 | * Originally created by Devit Schizoper (01.12.2006) 4 | */ 5 | 6 | :root { 7 | color-scheme: dark light; 8 | supported-color-schemes: dark light; 9 | --duration: 0.5s; 10 | --timing: ease; 11 | } 12 | 13 | *, 14 | ::before, 15 | ::after { 16 | box-sizing: border-box; 17 | } 18 | 19 | html { 20 | font-family: Noto Sans, Verdana, Arial, sans-serif; 21 | font-size: 0.9rem; 22 | } 23 | 24 | body { 25 | margin: 0; 26 | width: 100%; 27 | height: 100%; 28 | background-color: var(--background-color); 29 | color: var(--color); 30 | } 31 | 32 | body.expand { 33 | transition: 34 | color var(--duration) var(--timing), 35 | background-color var(--duration) var(--timing); 36 | } 37 | 38 | .preload { 39 | transition: none !important; 40 | } 41 | 42 | :any-link { 43 | color: var(--link-color); 44 | } 45 | 46 | figure { 47 | margin: 1rem 0; 48 | } 49 | 50 | figcaption { 51 | margin: 0.5rem 0; 52 | } 53 | 54 | p { 55 | margin: 11px 0 10px 0; 56 | padding: 0; 57 | text-align: justify; 58 | line-height: 1.5; 59 | } 60 | 61 | ul { 62 | margin: 0; 63 | padding: 0; 64 | } 65 | 66 | li::marker { 67 | color: var(--bullet-points-color); 68 | } 69 | 70 | #arrow li { 71 | background: url(/images/arrow.svg) no-repeat left; 72 | background-size: 8px; 73 | padding: 3px 0px 3px 18px; 74 | list-style: none; 75 | margin: 0; 76 | } 77 | 78 | h1 { 79 | color: var(--main-headline-color); 80 | font-size: 1.9rem; 81 | line-height: 1; 82 | } 83 | 84 | a { 85 | color: var(--link-color); 86 | } 87 | 88 | a:hover { 89 | text-decoration: none; 90 | } 91 | 92 | blockquote { 93 | background: var(--background-color); 94 | color: var(--color); 95 | padding: 10px; 96 | } 97 | 98 | iframe { 99 | border: 5px solid var(--screenshot-border-color); 100 | } 101 | 102 | .align_center { 103 | text-align: center; 104 | } 105 | 106 | .align_right { 107 | display: block; 108 | text-align: right; 109 | } 110 | 111 | .screenshot img { 112 | border: 5px solid var(--screenshot-border-color); 113 | display: block; 114 | margin-left: auto; 115 | margin-right: auto; 116 | width: 80%; 117 | height: auto; 118 | max-width: 1024px; 119 | } 120 | 121 | .fork-me-banner { 122 | position: absolute; 123 | top: 0; 124 | left: 0; 125 | border: 0; 126 | } 127 | 128 | #justified-logo img { 129 | display: block; 130 | margin-left: auto; 131 | margin-right: auto; 132 | padding-top: 20px; 133 | width: 40%; 134 | max-width: 800px; 135 | } 136 | 137 | .standout { 138 | font-size: larger; 139 | font-weight: bold; 140 | color: var(--warning-message); 141 | } 142 | 143 | .standout a { 144 | color: var(--warning-message); 145 | } 146 | 147 | /**** header ***/ 148 | 149 | #pageheader { 150 | display: inline-block; 151 | font-family: Noto Sans, Verdana, Arial, sans-serif; 152 | font-size: 1.0em; 153 | margin-left: 0; 154 | overflow: hidden; 155 | width: 100%; 156 | } 157 | 158 | #pageheader h2 { 159 | display: block; 160 | float: left; 161 | font-size: 3.0em; 162 | font-weight: bold; 163 | letter-spacing: 3px; 164 | margin-right: 20px; 165 | position: relative; 166 | top: 5px; 167 | } 168 | 169 | #pageheader h2 a { 170 | text-decoration: none; 171 | } 172 | 173 | #pageheader h2 a:hover { 174 | color: var(--menu-hover-color); 175 | } 176 | 177 | /**** article ***/ 178 | 179 | #content { 180 | width: 100%; 181 | } 182 | 183 | #content h1 { 184 | margin: 0; 185 | padding: 20px 0 5px 0; 186 | } 187 | 188 | #content h2 { 189 | margin: 0; 190 | padding: 20px 0 5px 0; 191 | } 192 | 193 | #content ul { 194 | margin: 0; 195 | padding: 11px 0 15px 20px; 196 | } 197 | 198 | #content li { 199 | margin-bottom: 5px; 200 | padding-left: 3px; 201 | } 202 | 203 | #content { 204 | display: block; 205 | display: inline; 206 | float: left; 207 | margin-left: 20%; 208 | width: 60%; 209 | } 210 | 211 | /**** clear div ***/ 212 | 213 | #clear { 214 | clear: both; 215 | display: block; 216 | height: 1px; 217 | overflow: hidden; 218 | width: 100%; 219 | } 220 | 221 | /**** footer ***/ 222 | 223 | footer { 224 | border-top: dashed 1px gray; 225 | margin: 40px auto 0 auto; 226 | padding: 20px 0 20px 0; 227 | text-align: center; 228 | width: 70%; 229 | } 230 | 231 | footer p { 232 | margin: 0; 233 | padding: 0; 234 | } 235 | 236 | #pageinfo { 237 | border-top: 0; 238 | margin: 0 0; 239 | } 240 | 241 | #donate { 242 | margin: 1em 0; 243 | text-align: center; 244 | } 245 | 246 | #donate p, 247 | #donate div { 248 | text-align: center; 249 | } 250 | 251 | .aw-anniversary { 252 | margin-left: 65px; 253 | } 254 | 255 | /** buttons */ 256 | 257 | .flex-container { 258 | display: flex; 259 | height: 100%; 260 | padding: 0; 261 | margin: 20px; 262 | align-items: center; 263 | justify-content: center; 264 | } 265 | 266 | .row { 267 | width: auto; 268 | } 269 | 270 | .flex-href { 271 | display: flex; 272 | justify-content: center; 273 | } 274 | 275 | .btn { 276 | display: inline-block; 277 | background: #4E9CAF; 278 | border-radius: 5px; 279 | box-sizing: border-box; 280 | -webkit-appearance: none; 281 | -moz-appearance: none; 282 | appearance: none; 283 | background-color: transparent; 284 | border: 1px solid var(--button-background-color); 285 | border-color: var(--button-background-color); 286 | color: var(--button-background-color); 287 | cursor: pointer; 288 | display: -webkit-box; 289 | display: -webkit-flex; 290 | display: -ms-flexbox; 291 | display: flex; 292 | -webkit-align-self: center; 293 | -ms-flex-item-align: center; 294 | align-self: center; 295 | font-size: 1rem; 296 | font-weight: 900; 297 | line-height: 1.5; 298 | margin: 8px; 299 | padding: 1.2em 2.2em; 300 | text-decoration: none; 301 | text-align: center; 302 | text-transform: uppercase; 303 | } 304 | 305 | .btn:hover, 306 | .btn:focus { 307 | color: var(--button-hover-color); 308 | outline: 0; 309 | } 310 | 311 | .shine { 312 | border-color: var(--button-background-color); 313 | color: var(--button-text-color); 314 | box-shadow: 0 0 60px 60px var(--button-background-color) inset, 0 0 0 0 var(--button-background-color); 315 | -webkit-transition: all 150ms ease-in-out; 316 | transition: all 150ms ease-in-out; 317 | } 318 | 319 | .shine:hover { 320 | box-shadow: 0 0 1px 0 var(--button-background-color) inset, 0 0 1px 1px var(--button-background-color); 321 | } 322 | 323 | /**** navigation ***/ 324 | 325 | nav.container { 326 | font-family: Noto Sans; 327 | font-weight: bold; 328 | margin: 0 auto; 329 | padding: 1em 1em; 330 | text-align: center; 331 | } 332 | 333 | nav.container a { 334 | color: var(--link-color); 335 | text-decoration: none; 336 | font: 0.99em Noto Sans; 337 | font-weight: bold; 338 | margin: 0px 10px; 339 | padding: 5px 10px; 340 | position: relative; 341 | z-index: 0; 342 | cursor: pointer; 343 | } 344 | 345 | nav.container a:hover { 346 | color: var(--nav-accent-color); 347 | } 348 | 349 | /* effect top-bottom borders go out */ 350 | nav.topBotomBordersOut a:before, 351 | nav.topBotomBordersOut a:after { 352 | position: absolute; 353 | left: 0px; 354 | width: 100%; 355 | height: 2px; 356 | background: var(--nav-accent-color); 357 | content: ""; 358 | opacity: 0; 359 | transition: all 0.3s; 360 | } 361 | 362 | nav.topBotomBordersOut a:before { 363 | top: 0px; 364 | transform: translateY(10px); 365 | } 366 | 367 | nav.topBotomBordersOut a:after { 368 | bottom: 0px; 369 | transform: translateY(-10px); 370 | } 371 | 372 | nav.topBotomBordersOut a:hover:before, 373 | nav.topBotomBordersOut a:hover:after { 374 | opacity: 1; 375 | transform: translateY(0px); 376 | } 377 | 378 | /* selected menu item */ 379 | 380 | nav.active-menu-about a.menu-about, 381 | nav.active-menu-download a.menu-download, 382 | nav.active-menu-community a.menu-community, 383 | nav.active-menu-recipes a.menu-recipes, 384 | nav.active-menu-screenshots a.menu-screenshots, 385 | nav.active-menu-doc a.menu-doc { 386 | color: var(--nav-accent-color); 387 | text-decoration-line: underline; 388 | text-decoration-thickness: 1.7px; 389 | } 390 | 391 | /* vim: set sw=2 et: */ -------------------------------------------------------------------------------- /images/awesome2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 240 | -------------------------------------------------------------------------------- /images/awesome3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 240 | -------------------------------------------------------------------------------- /images/awesome1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 246 | -------------------------------------------------------------------------------- /images/awesome-dark-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 272 | -------------------------------------------------------------------------------- /images/awesome-dark-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 278 | -------------------------------------------------------------------------------- /images/awesome-15yrs-anniversary.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 155 | --------------------------------------------------------------------------------