aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAbdus <abdus@abdus.net>2021-03-05 14:54:44 +0530
committerAbdus <abdus@abdus.net>2021-03-05 14:55:17 +0530
commitb1fe95c049f8582c0753a2ae8a974b68a993b920 (patch)
tree66dfb50c98ffa251779bdda8a4c2c063acb5af64
parent1eab9522d1b5cdec8ab8f62087d37b0eef6bf3fc (diff)
downloaddotfiles-b1fe95c049f8582c0753a2ae8a974b68a993b920.tar.bz2
dotfiles-b1fe95c049f8582c0753a2ae8a974b68a993b920.zip
awesomewm
-rw-r--r--awesome/autostart.lua41
-rw-r--r--awesome/bling/README.md338
-rw-r--r--awesome/bling/docs/.nojekyll0
-rw-r--r--awesome/bling/docs/_sidebar.md16
-rw-r--r--awesome/bling/docs/home.md34
-rw-r--r--awesome/bling/docs/index.html27
-rw-r--r--awesome/bling/docs/layouts/layout.md44
-rw-r--r--awesome/bling/docs/module/flash.md33
-rw-r--r--awesome/bling/docs/module/swal.md24
-rw-r--r--awesome/bling/docs/module/tabbed.md45
-rw-r--r--awesome/bling/docs/module/twall.md25
-rw-r--r--awesome/bling/docs/module/wall.md127
-rw-r--r--awesome/bling/docs/signals/pctl.md91
-rw-r--r--awesome/bling/docs/theme.md54
-rw-r--r--awesome/bling/helpers/client.lua34
-rw-r--r--awesome/bling/helpers/color.lua59
-rw-r--r--awesome/bling/helpers/filesystem.lua39
-rw-r--r--awesome/bling/helpers/init.lua7
-rw-r--r--awesome/bling/helpers/shape.lua23
-rw-r--r--awesome/bling/helpers/time.lua29
-rw-r--r--awesome/bling/icons/layouts/centered.pngbin0 -> 2638 bytes
-rw-r--r--awesome/bling/icons/layouts/horizontal.pngbin0 -> 768 bytes
-rw-r--r--awesome/bling/icons/layouts/mstab.pngbin0 -> 1706 bytes
-rw-r--r--awesome/bling/icons/layouts/vertical.pngbin0 -> 767 bytes
-rw-r--r--awesome/bling/init.lua9
-rw-r--r--awesome/bling/layout/centered.lua98
-rw-r--r--awesome/bling/layout/horizontal.lua72
-rw-r--r--awesome/bling/layout/init.lua22
-rw-r--r--awesome/bling/layout/mstab.lua217
-rw-r--r--awesome/bling/layout/vertical.lua72
-rw-r--r--awesome/bling/module/flash_focus.lua36
-rw-r--r--awesome/bling/module/init.lua7
-rw-r--r--awesome/bling/module/tabbed.lua202
-rw-r--r--awesome/bling/module/tiled_wallpaper.lua58
-rw-r--r--awesome/bling/module/wallpaper.lua293
-rw-r--r--awesome/bling/module/window_swallowing.lua97
-rw-r--r--awesome/bling/signal/init.lua1
-rw-r--r--awesome/bling/signal/playerctl.lua120
-rw-r--r--awesome/bling/theme-var-template.lua55
-rw-r--r--awesome/bling/widget/tabbar/boxes.lua54
-rw-r--r--awesome/bling/widget/tabbar/default.lua49
-rw-r--r--awesome/bling/widget/tabbar/modern.lua198
-rw-r--r--awesome/bloat/bar/init.lua1
-rw-r--r--awesome/bloat/bar/wibar.lua483
-rw-r--r--awesome/bloat/init.lua4
-rw-r--r--awesome/bloat/lockscreen/init.lua13
-rw-r--r--awesome/bloat/lockscreen/lockscreen.lua293
-rw-r--r--awesome/bloat/notifs/battery.lua37
-rw-r--r--awesome/bloat/notifs/brightness.lua93
-rw-r--r--awesome/bloat/notifs/init.lua202
-rw-r--r--awesome/bloat/notifs/notif-center/build-notifbox/empty-notifbox.lua42
-rw-r--r--awesome/bloat/notifs/notif-center/build-notifbox/init.lua58
-rw-r--r--awesome/bloat/notifs/notif-center/build-notifbox/notifbox.lua101
-rw-r--r--awesome/bloat/notifs/notif-center/clear-all/init.lua31
-rw-r--r--awesome/bloat/notifs/notif-center/icons/clear_all.svg91
-rw-r--r--awesome/bloat/notifs/notif-center/icons/delete.svg1
-rw-r--r--awesome/bloat/notifs/notif-center/icons/dont-disturb-mode.svg64
-rw-r--r--awesome/bloat/notifs/notif-center/icons/empty-notification.svg1
-rw-r--r--awesome/bloat/notifs/notif-center/icons/new-notif.svg15
-rw-r--r--awesome/bloat/notifs/notif-center/icons/notify-mode.svg91
-rw-r--r--awesome/bloat/notifs/notif-center/init.lua26
-rw-r--r--awesome/bloat/notifs/playerctl.lua6
-rw-r--r--awesome/bloat/notifs/volume.lua119
-rw-r--r--awesome/bloat/pop/dash.lua339
-rw-r--r--awesome/bloat/pop/exitscreen.lua170
-rw-r--r--awesome/bloat/pop/init.lua8
-rw-r--r--awesome/bloat/pop/notif.lua33
-rw-r--r--awesome/bloat/titlebars/init.lua51
-rw-r--r--awesome/bloat/titlebars/top.lua99
-rw-r--r--awesome/bloat/widgets/brightness_arc.lua28
-rw-r--r--awesome/bloat/widgets/brightness_bar.lua33
-rw-r--r--awesome/bloat/widgets/button.lua108
-rw-r--r--awesome/bloat/widgets/cpu_arc.lua26
-rw-r--r--awesome/bloat/widgets/cpu_bar.lua39
-rw-r--r--awesome/bloat/widgets/disk_arc.lua28
-rw-r--r--awesome/bloat/widgets/disk_bar.lua36
-rw-r--r--awesome/bloat/widgets/info.lua57
-rw-r--r--awesome/bloat/widgets/pacman_taglist.lua92
-rw-r--r--awesome/bloat/widgets/playerctl.lua171
-rw-r--r--awesome/bloat/widgets/ram_arc.lua29
-rw-r--r--awesome/bloat/widgets/ram_bar.lua56
-rw-r--r--awesome/bloat/widgets/temp_arc.lua33
-rw-r--r--awesome/bloat/widgets/temp_bar.lua34
-rw-r--r--awesome/bloat/widgets/volume_arc.lua34
-rw-r--r--awesome/bloat/widgets/volume_bar.lua48
-rw-r--r--awesome/bloat/widgets/weather.lua25
-rw-r--r--awesome/configs/picom.conf92
-rw-r--r--awesome/ears/battery.lua59
-rw-r--r--awesome/ears/brightness.lua38
-rw-r--r--awesome/ears/cpu.lua18
-rw-r--r--awesome/ears/disk.lua22
-rw-r--r--awesome/ears/init.lua14
-rw-r--r--awesome/ears/ram.lua23
-rw-r--r--awesome/ears/temp.lua15
-rw-r--r--awesome/ears/volume.lua53
-rw-r--r--awesome/ears/weather.lua32
-rw-r--r--awesome/helpers.lua444
-rw-r--r--awesome/icons/ghosts/awesome.pngbin0 -> 403 bytes
-rw-r--r--awesome/icons/ghosts/battery.pngbin0 -> 164837 bytes
-rw-r--r--awesome/icons/ghosts/battery_charging.pngbin0 -> 163374 bytes
-rw-r--r--awesome/icons/ghosts/dot.pngbin0 -> 519 bytes
-rw-r--r--awesome/icons/ghosts/dot.svg45
-rw-r--r--awesome/icons/ghosts/ghost.pngbin0 -> 508 bytes
-rw-r--r--awesome/icons/ghosts/ghost.svg45
-rw-r--r--awesome/icons/ghosts/pacman.pngbin0 -> 634 bytes
-rw-r--r--awesome/icons/ghosts/pacman.svg4
-rw-r--r--awesome/icons/ghosts/terminal.pngbin0 -> 6640 bytes
-rw-r--r--awesome/icons/notif-center/clear.pngbin0 -> 236 bytes
-rw-r--r--awesome/icons/notif-center/clear_grey.pngbin0 -> 2401 bytes
-rw-r--r--awesome/icons/notif-center/delete.pngbin0 -> 1057870 bytes
-rw-r--r--awesome/icons/notif-center/delete_grey.pngbin0 -> 1057709 bytes
-rw-r--r--awesome/icons/notif-center/notification.pngbin0 -> 1055650 bytes
-rw-r--r--awesome/images/bg.pngbin0 -> 20733355 bytes
-rw-r--r--awesome/images/default.pngbin0 -> 1054957 bytes
-rw-r--r--awesome/images/layout-machi_demo.gifbin0 -> 11630052 bytes
-rw-r--r--awesome/images/me.pngbin0 -> 1055033 bytes
-rw-r--r--awesome/images/rice.pngbin0 -> 2665262 bytes
-rw-r--r--awesome/images/round_shadow.pngbin0 -> 5448 bytes
-rw-r--r--awesome/images/round_transparent.pngbin0 -> 10695 bytes
-rw-r--r--awesome/keys.lua387
-rw-r--r--awesome/layout-machi/LICENSE13
-rw-r--r--awesome/layout-machi/README.md284
-rw-r--r--awesome/layout-machi/editor.lua992
-rw-r--r--awesome/layout-machi/icon.pngbin0 -> 988 bytes
-rw-r--r--awesome/layout-machi/init.lua39
-rw-r--r--awesome/layout-machi/layout.lua395
-rw-r--r--awesome/layout-machi/nested_layout_screenshot.pngbin0 -> 652163 bytes
-rw-r--r--awesome/layout-machi/rc.patch38
-rw-r--r--awesome/layout-machi/switcher.lua476
-rw-r--r--awesome/rc.lua664
-rwxr-xr-xawesome/scripts/jeff33
-rwxr-xr-xawesome/scripts/rofi-emoji134
-rwxr-xr-xawesome/scripts/shoot28
-rw-r--r--awesome/theme/ghosts/theme.lua276
-rw-r--r--awesome/utils/button.lua160
-rw-r--r--awesome/utils/init.lua4
-rw-r--r--awesome/utils/popupLib.lua62
-rw-r--r--awesome/window/better-resize.lua135
-rw-r--r--awesome/window/init.lua176
-rw-r--r--awesome/window/savefloats.lua55
140 files changed, 10836 insertions, 518 deletions
diff --git a/awesome/autostart.lua b/awesome/autostart.lua
new file mode 100644
index 0000000..97020cf
--- /dev/null
+++ b/awesome/autostart.lua
@@ -0,0 +1,41 @@
+-- autostart.lua
+-- Autostart Stuff Here
+local awful = require("awful")
+local gears = require("gears")
+
+local function run_once(cmd)
+ local findme = cmd
+ local firstspace = cmd:find(' ')
+ if firstspace then findme = cmd:sub(0, firstspace - 1) end
+ awful.spawn.easy_async_with_shell(string.format(
+ 'pgrep -u $USER -x %s > /dev/null || (%s)',
+ findme, cmd))
+end
+
+-- LuaFormatter off
+-- Add apps to autostart here
+autostart_apps = {
+ -- Network Manager Applet
+ "nm-applet",
+
+ -- Disable Bell
+ "xset -b",
+
+ -- Layout
+ "~/.screenlayout/layout.sh",
+
+ -- Bluetooth
+ "blueman-applet",
+
+ -- Compositor
+ "picom --experimental-backends --config " ..
+ gears.filesystem.get_configuration_dir() .. "configs/picom.conf",
+
+ -- Media controller daemon
+ "playerctld daemon"
+}
+-- LuaFormatter on
+
+for app = 1, #autostart_apps do run_once(autostart_apps[app]) end
+
+-- EOF ------------------------------------------------------------------------
diff --git a/awesome/bling/README.md b/awesome/bling/README.md
new file mode 100644
index 0000000..138b740
--- /dev/null
+++ b/awesome/bling/README.md
@@ -0,0 +1,338 @@
+# <center> 🌟 Bling - Utilities for the AwesomeWM 🌟 </center>
+
+For documentation, go [here](https://nooo37.github.io/bling). This readme is out of date.
+
+## ❓ Why
+
+AwesomeWM is literally that - an awesome window manager.
+
+It's unique selling point has always been the widget system allowing for fancy buttons, sliders, bars, dashboards and everything you can imagine. But that feature might also be a curse. Most modules focus on the widget side of things which left the actual window managing part of awesomeWM a little underdeveloped compared to for example xmonad even though it's probably just as powerfull in that regard.
+
+This module is trying to fix exactly that: Adding new layouts and modules that - while making use of the widget system - don't focus on it but on new window managing features.
+
+## 🧭 Installation and configuration
+- `git clone` this repo into your `~/.config/awesome` folder
+- Put ``local bling = require("bling")`` somewhere in your ``rc.lua`` (remember to put it under ``beautiful.init...``)
+
+##### 📎 Layouts
+
+Choose layouts from the list below and add them to to your `awful.layouts` list in your `rc.lua`.
+
+Everyone of them supports multiple master clients and master width factor making them as easily useable as the default layouts.
+```Lua
+bling.layout.mstab
+bling.layout.centered
+bling.layout.vertical
+bling.layout.horizontal
+```
+
+##### 😋 Window swallowing
+
+To activate and deactivate window swallowing there are the following functions. If you want to activate it, just call the `start` function once in your `rc.lua`.
+```lua
+bling.module.window_swallowing.start() -- activates window swallowing
+bling.module.window_swallowing.stop() -- deactivates window swallowing
+bling.module.window_swallowing.toggle() -- toggles window swallowing
+```
+
+##### 🏬 Tiled Wallpaper
+
+The function to set an automatically created tiled wallpaper can be called the follwing way (you don't need to set every option in the table of the last argument since there are reasonable defaults):
+```lua
+awful.screen.connect_for_each_screen(function(s) -- that way the wallpaper is applied to every screen
+ bling.module.tiled_wallpaper("x", s, { -- call the actual function ("x" is the string that will be tiled)
+ fg = "#ff0000", -- define the foreground color
+ bg = "#00ffff", -- define the background color
+ offset_y = 25, -- set a y offset
+ offset_x = 25, -- set a x offset
+ font = "Hack", -- set the font (without the size)
+ font_size = 14, -- set the font size
+ padding = 100, -- set padding (default is 100)
+ zickzack = true -- rectangular pattern or criss cross
+ })
+end)
+```
+
+##### 🎇 Wallpaper easy setup
+
+This is a simple-to-use, extensible, declarative wallpaper manager.
+
+###### Practical examples
+
+```lua
+-- A default Awesome wallpaper
+bling.module.wallpaper.setup()
+
+-- A slideshow with pictures from different sources changing every 30 minutes
+bling.module.wallpaper.setup {
+ wallpaper = {"/images/my_dog.jpg", "/images/my_cat.jpg"},
+ change_timer = 1800
+}
+
+-- A random wallpaper with images from multiple folders
+bling.module.wallpaper.setup {
+ set_function = bling.module.wallpaper.setters.random
+ wallpaper = {"/path/to/a/folder", "/path/to/another/folder"},
+ change_timer = 631, -- prime numbers are better for timers
+ position = "fit",
+ background = "#424242"
+}
+
+-- wallpapers based on a schedule, like awesome-glorious-widgets dynamic wallpaper
+-- https://github.com/manilarome/awesome-glorious-widgets/tree/master/dynamic-wallpaper
+bling.module.wallpaper.setup {
+ set_function = wallpaper.setters.simple_schedule,
+ wallpaper = {
+ ["06:22:00"] = "morning-wallpaper.jpg",
+ ["12:00:00"] = "noon-wallpaper.jpg",
+ ["17:58:00"] = "night-wallpaper.jpg",
+ ["24:00:00"] = "midnight-wallpaper.jpg",
+ },
+ position = "maximized",
+}
+
+-- random wallpapers, from different folder depending on time of the day
+bling.module.wallpaper.setup {
+ set_function = bling.module.wallpaper.setters.simple_schedule,
+ wallpaper = {
+ ["09:00:00"] = "~/Pictures/safe_for_work",
+ ["18:00:00"] = "~/Pictures/personal",
+ },
+ schedule_set_function = bling.module.wallpaper.setters.random
+ position = "maximized",
+ recursive = false,
+ change_timer = 600
+}
+```
+###### Details
+
+The setup function will do 2 things: call the set-function when awesome requests a wallpaper, and manage a timer to call `set_function` periodically.
+
+Its argument is a args table that is passed to ohter functions (setters and wallpaper functions), so you define everything with setup.
+
+The `set_function` is a function called every times a wallpaper is needed.
+
+The module provides some setters:
+
+* `bling.module.wallpaper.setters.awesome_wallpaper`: beautiful.theme_assets.wallpaper with defaults from beautiful.
+* `bling.module.wallpaper.setters.simple`: slideshow from the `wallpaper` argument.
+* `bling.module.wallpaper.setters.random`: same as simple but in a random way.
+* `bling.module.wallpaper.setters.simple_schedule`: takes a table of `["HH:MM:SS"] = wallpaper` arguments, where wallpaper is the `wallpaper` argument used by `schedule_set_function`.
+
+A wallpaper is one of the following elements:
+
+* a color
+* an image
+* a folder containing images
+* a function that sets a wallpaper
+* everything gears.wallpaper functions can manage (cairo surface, cairo pattern string)
+* a list containing any of the elements above
+```lua
+-- This is a valid wallpaper definition
+bling.module.wallpaper.setup {
+ wallpaper = { -- a list
+ "black", "#112233", -- colors
+ "wall1.jpg", "wall2.png", -- files
+ "/path/to/wallpapers", -- folders
+ -- cairo patterns
+ "radial:600,50,100:105,550,900:0,#2200ff:0.5,#00ff00:1,#101010",
+ -- or functions that set a wallpaper
+ function(args) bling.module.tiled_wallpaper("\\o/", args.screen) end,
+ bling.module.wallpaper.setters.awesome_wallpaper,
+ },
+ change_timer = 10,
+}
+```
+The provided setters `simple` and `random` will use 2 internal functions that you can use to write your own setter:
+
+* `bling.module.wallpaper.prepare_list`: return a list of wallpapers directly usable by `apply` (for now, it just explores folders)
+* `bling.module.wallpaper.apply`: a wrapper for gears.wallpaper functions, using the args table of setup
+
+Here are the defaults:
+```lua
+-- Default parameters
+bling.module.wallpaper.setup {
+ screen = nil, -- the screen to apply the wallpaper, as seen in gears.wallpaper functions
+ change_timer = nil, -- the timer in seconds. If set, call the set_function every change_timer seconds
+ set_function = nil, -- the setter function
+
+ -- parameters used by bling.module.wallpaper.prepare_list
+ wallpaper = nil, -- the wallpaper object, see simple or simple_schedule documentation
+ image_formats = {"jpg", "jpeg", "png", "bmp"}, -- when searching in folder, consider these files only
+ recursive = true, -- when searching in folder, search also in subfolders
+
+ -- parameters used by bling.module.wallpaper.apply
+ position = nil, -- use a function of gears.wallpaper when applicable ("centered", "fit", "maximized", "tiled")
+ background = beautiful.bg_normal or "black", -- see gears.wallpaper functions
+ ignore_aspect = false, -- see gears.wallpaper.maximized
+ offset = {x = 0, y = 0}, -- see gears.wallpaper functions
+ scale = 1, -- see gears.wallpaper.centered
+
+ -- parameters that only apply to bling.module.wallpaper.setter.awesome (as a setter or as a wallpaper function)
+ colors = { -- see beautiful.theme_assets.wallpaper
+ bg = beautiful.bg_color, -- the actual default is this color but darkened or lightned
+ fg = beautiful.fg_color,
+ alt_fg = beautiful.fg_focus
+ }
+}
+```
+
+Check documentation in [module/wallpaper.lua](module/wallpaper.lua) for more details.
+
+
+##### 🔦 Flash Focus
+
+There are two ways you can use this module. You can just enable it by calling the `enable()` function:
+```lua
+bling.module.flash_focus.enable()
+```
+This connects to the focus signal of a client, which means that the flash focus will activate however you focus the client.
+
+The other way is to call the function itself like this: `bling.module.flash_focus.flashfocus(someclient)`. This allows you to just activate on certain keybinds:
+```lua
+awful.key({modkey}, "Up",
+ function()
+ awful.client.focus.bydirection("up")
+ bling.module.flash_focus.flashfocus(client.focus)
+ end, {description = "focus up", group = "client"})
+```
+
+##### 📑 Tabbing
+
+You should bind these functions to keys in oder to use the tabbed module effectively:
+```lua
+bling.module.tabbed.pick() -- picks a client with your cursor to add to the tabbing group
+bling.module.tabbed.pop() -- removes the focused client from the tabbing group
+bling.module.tabbed.iter() -- iterates through the currently focused tabbing group
+bling.module.tabbed.pick_with_dmenu() -- picks a client with a dmenu application (defaults to rofi, other options can be set with a string parameter like "dmenu")
+```
+
+##### 🎵 Playerctl
+
+This is a signal module in which you can connect to certain bling signals to grab playerctl info. Currently, this is what it supports:
+
+- Song title and artist
+- Album art (the path this module downloaded the art to)
+- If playing or not
+- Position
+- Song length
+
+This module relies on `playerctl` and `curl`. If you have this module disabled, you won't need those programs.
+
+To enable: `bling.signal.playerctl.enable()`
+
+###### Signals
+
+```lua
+-- bling::playerctl::status -- first line is the signal
+-- playing (boolean) -- indented lines are function parameters
+-- bling::playerctl::title_artist_album
+-- title (string)
+-- artist (string)
+-- album_path (string)
+-- bling::playerctl::position
+-- interval_sec (number)
+-- length_sec (number)
+```
+
+###### Example Implementation
+
+```lua
+local art = wibox.widget {
+ image = "default_image.png",
+ resize = true,
+ forced_height = dpi(80),
+ forced_width = dpi(80),
+ widget = wibox.widget.imagebox
+}
+
+local title_widget = wibox.widget {
+ markup = 'Nothing Playing',
+ align = 'center',
+ valign = 'center',
+ widget = wibox.widget.textbox
+}
+
+local artist_widget = wibox.widget {
+ markup = 'Nothing Playing',
+ align = 'center',
+ valign = 'center',
+ widget = wibox.widget.textbox
+}
+
+-- Get Song Info
+awesome.connect_signal("bling::playerctl::title_artist_album",
+ function(title, artist, art_path)
+ -- Set art widget
+ art:set_image(gears.surface.load_uncached(art_path))
+
+ local my_title = "No Title"
+ local my_artist = "No Artist"
+
+ if title then
+ my_title = title
+ my_artist = artist
+ end
+
+ -- Set title and artist widgets
+ title_widget:set_markup_silently(my_title)
+ artist_widget:set_markup_silently(my_artist)
+end)
+```
+Thats all! You don't even have to worry about updating the widgets, the signals will handle that for you.
+
+
+
+### 🌈 Theme variables
+You will find a list of all theme variables that are used in bling and comments on what they do in the `theme-var-template.lua` file - ready for you to copy them into your `theme.lua`. Theme variables are not only used to change the appearance of some features but also to adjust the functionality of some modules. So it is worth it to take a look at them.
+
+## 😲 Preview
+
+### Tabbing
+![](https://imgur.com/08AlNhQ.png)
+
+screenshot by [javacafe](https://github.com/JavaCafe01)
+
+### Mstab (dynamic tabbing layout)
+![](https://imgur.com/HZRgApE.png)
+
+screenshot by [javacafe](https://github.com/JavaCafe01)
+
+### Centered
+![](https://media.discordapp.net/attachments/769673106842845194/780095998239834142/unknown.png)
+
+screenshot by [branwright](https://github.com/branwright1)
+
+### Tiled Wallpaper
+![](https://media.discordapp.net/attachments/702548913999314964/773887721294135296/tiled-wallpapers.png?width=1920&height=1080)
+
+screenshots by me
+
+### Flash Focus
+![](https://imgur.com/5txYrlV.gif)
+
+gif by [javacafe](https://github.com/JavaCafe01)
+
+### Wind swallowing
+![](https://media.discordapp.net/attachments/635625813143978012/769180910683684864/20-10-23-14-40-32.gif)
+
+gif by me :)
+
+### Playerctl Signals Implementation
+![](https://user-images.githubusercontent.com/33443763/107377569-fa807900-6a9f-11eb-93c1-174c58eb7bf1.png)
+
+screenshot by [javacafe](https://github.com/JavaCafe01)
+
+## TODO
+- [ ] Add external sources management for the wallpaper module (URLs, RSS feeds, NASA picture of the day, ...)
+- [ ] Scratchpad module
+- [x] Some more documentation on the tabbed module
+- [x] Add a cool alternative tabbar style
+- [x] Add another cool tabbar style (we need more styles)
+- [x] Make the mstab layout compatible with vertical tabbars (left and right)
+- [x] Add option to mstab layout to not shrink windows down when they are in the tabbed pane and unfocused (for example for people using transparent terminals)
+- [x] Keyboard based option to add windows to a tabbing object
+
+All naming credit goes to javacafe.
+
+Contributions are welcomed 💛
diff --git a/awesome/bling/docs/.nojekyll b/awesome/bling/docs/.nojekyll
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/awesome/bling/docs/.nojekyll
diff --git a/awesome/bling/docs/_sidebar.md b/awesome/bling/docs/_sidebar.md
new file mode 100644
index 0000000..4a0615c
--- /dev/null
+++ b/awesome/bling/docs/_sidebar.md
@@ -0,0 +1,16 @@
+- [Home](home.md)
+
+- [Layouts](layouts/layout.md)
+
+- Modules
+ - [Flash Focus](module/flash.md)
+ - [Tabbed](module/tabbed.md)
+ - [Tiled Wallpaper](module/twall.md)
+ - [Wallpaper Easy Setup](module/wall.md)
+ - [Window Swallowing](module/swal.md)
+
+- Signals
+ - [Playerctl](signals/pctl.md)
+
+- Extra
+ - [Theme Variable Template](theme.md)
diff --git a/awesome/bling/docs/home.md b/awesome/bling/docs/home.md
new file mode 100644
index 0000000..d5eed80
--- /dev/null
+++ b/awesome/bling/docs/home.md
@@ -0,0 +1,34 @@
+# <center> 🌟 Bling - Utilities for AwesomeWM 🌟 </center>
+
+## Why
+
+[AwesomeWM](https://awesomewm.org/) is literally what it stands for, an awesome window manager.
+
+Its unique selling point has always been the widget system, which allows for fancy buttons, sliders, bars, dashboards and anything you can imagine. But that feature can be a curse. Most modules focus on the widget side of things which leave the actual window managing part of AwesomeWM underdeveloped compared to, for example, [xmonad](https://xmonad.org/) even though it's probably just as powerfull in that area.
+
+This project focuses on that problem - adding new layouts and modules that make use of the widget system, but primarily focus on the new window managing features.
+
+## Installation
+- clone this repo into your `~/.config/awesome` folder
+ - `git clone https://github.com/Nooo37/bling.git ~/.config/awesome/bling`
+- require the module in your `rc.lua`, and make sure it's under the beautiful module initialization
+
+```lua
+-- other imports
+
+local beautiful = require("beautiful")
+
+-- other configuration stuff here
+
+beautiful.init("some_theme.lua")
+local bling = require("bling")
+```
+
+## Contributors
+A special thanks to all our contributors...
+
+<a href="https://github.com/Nooo37/bling/graphs/contributors">
+ <img src="https://contrib.rocks/image?repo=Nooo37/bling" />
+</a>
+
+Made with [contributors-img](https://contrib.rocks).
diff --git a/awesome/bling/docs/index.html b/awesome/bling/docs/index.html
new file mode 100644
index 0000000..7f0cae4
--- /dev/null
+++ b/awesome/bling/docs/index.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <title>Bling Docs</title>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+ <meta name="description" content="Description">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
+ <link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
+ </head>
+ <body>
+ <div id="app"></div>
+ <script>
+ window.$docsify = {
+ name: 'bling',
+ nameLink: '/',
+ repo: 'https://github.com/Nooo37/bling',
+ loadSidebar: true,
+ subMaxLevel: 3,
+ homepage: 'home.md'
+ }
+ </script>
+ <!-- Docsify v4 -->
+ <script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
+ <script src="//unpkg.com/prismjs/components/prism-lua.js"></script>
+ </body>
+</html>
diff --git a/awesome/bling/docs/layouts/layout.md b/awesome/bling/docs/layouts/layout.md
new file mode 100644
index 0000000..97c8ab6
--- /dev/null
+++ b/awesome/bling/docs/layouts/layout.md
@@ -0,0 +1,44 @@
+## 📎 Layouts <!-- {docsify-ignore} -->
+
+Choose layouts from the list below and add them to to your `awful.layouts` list in your `rc.lua`.
+
+Everyone of them supports multiple master clients and master width factor making them easy to use.
+
+The mstab layout uses the tab theme from the tabbed module.
+
+```Lua
+bling.layout.mstab
+bling.layout.centered
+bling.layout.vertical
+bling.layout.horizontal
+```
+
+### Theme Variables
+```lua
+-- mstab
+theme.mstab_bar_ontop = false -- whether you want to allow the bar to be ontop of clients
+theme.mstab_dont_resize_slaves = false -- whether the tabbed stack windows should be smaller than the
+ -- currently focused stack window (set it to true if you use
+ -- transparent terminals. False if you use shadows on solid ones
+theme.mstab_bar_padding = "default" -- how much padding there should be between clients and your tabbar
+ -- by default it will adjust based on your useless gaps.
+ -- If you want a custom value. Set it to the number of pixels (int)
+theme.mstab_border_radius = 0 -- border radius of the tabbar
+theme.mstab_bar_height = 40 -- height of the tabbar
+theme.mstab_tabbar_position = "top" -- position of the tabbar (mstab currently does not support left,right)
+theme.mstab_tabbar_style = "default" -- style of the tabbar ("default", "boxes" or "modern")
+ -- defaults to the tabbar_style so only change if you want a
+ -- different style for mstab and tabbed
+```
+
+### Previews
+
+#### Mstab (dynamic tabbing layout)
+![](https://imgur.com/HZRgApE.png)
+
+*screenshot by [javacafe](https://github.com/JavaCafe01)*
+
+#### Centered
+![](https://media.discordapp.net/attachments/769673106842845194/780095998239834142/unknown.png)
+
+*screenshot by [branwright](https://github.com/branwright1)*
diff --git a/awesome/bling/docs/module/flash.md b/awesome/bling/docs/module/flash.md
new file mode 100644
index 0000000..ed4fa42
--- /dev/null
+++ b/awesome/bling/docs/module/flash.md
@@ -0,0 +1,33 @@
+## 🔦 Flash Focus <!-- {docsify-ignore} -->
+
+Flash focus does an opacity animation effect on a client when it is focused.
+
+
+### Usage
+
+There are two ways in which you can use this module. You can enable it by calling the `enable()` function:
+```lua
+bling.module.flash_focus.enable()
+```
+This connects to the focus signal of a client, which means that the flash focus will activate however you focus the client.
+
+The other way is to call the function itself like this: `bling.module.flash_focus.flashfocus(someclient)`. This allows you to activate on certain keybinds like so:
+```lua
+awful.key({modkey}, "Up",
+ function()
+ awful.client.focus.bydirection("up")
+ bling.module.flash_focus.flashfocus(client.focus)
+ end, {description = "focus up", group = "client"})
+```
+
+### Theme Variables
+```lua
+theme.flash_focus_start_opacity = 0.6 -- the starting opacity
+theme.flash_focus_step = 0.01 -- the step of animation
+```
+
+### Preview
+
+![](https://imgur.com/5txYrlV.gif)
+
+*gif by [JavaCafe01](https://github.com/JavaCafe01)*
diff --git a/awesome/bling/docs/module/swal.md b/awesome/bling/docs/module/swal.md
new file mode 100644
index 0000000..ad40c0f
--- /dev/null
+++ b/awesome/bling/docs/module/swal.md
@@ -0,0 +1,24 @@
+## 😋 Window Swallowing <!-- {docsify-ignore} -->
+
+Can your window manager swallow? It probably can...
+
+### Usage
+
+To activate and deactivate window swallowing here are the following functions. If you want to activate it, just call the `start` function once in your `rc.lua`.
+```lua
+bling.module.window_swallowing.start() -- activates window swallowing
+bling.module.window_swallowing.stop() -- deactivates window swallowing
+bling.module.window_swallowing.toggle() -- toggles window swallowing
+```
+
+### Theme Variables
+```lua
+theme.dont_swallow_classname_list = {"firefox", "Gimp"} -- list of class names that should not be swallowed
+theme.dont_swallow_filter_activated = true -- whether the filter above should be active
+```
+
+### Preview
+
+![](https://media.discordapp.net/attachments/635625813143978012/769180910683684864/20-10-23-14-40-32.gif)
+
+*gif by [Nooo37](https://github.com/Nooo37)*
diff --git a/awesome/bling/docs/module/tabbed.md b/awesome/bling/docs/module/tabbed.md
new file mode 100644
index 0000000..1c82253
--- /dev/null
+++ b/awesome/bling/docs/module/tabbed.md
@@ -0,0 +1,45 @@
+## 📑 Tabbed <!-- {docsify-ignore} -->
+
+Tabbed implements a tab container. There are also different themes for the tabs.
+
+### Usage
+
+You should bind these functions to keys in order to use the tabbed module effectively:
+```lua
+bling.module.tabbed.pick() -- picks a client with your cursor to add to the tabbing group
+bling.module.tabbed.pop() -- removes the focused client from the tabbing group
+bling.module.tabbed.iter() -- iterates through the currently focused tabbing group
+bling.module.tabbed.pick_with_dmenu() -- picks a client with a dmenu application (defaults to rofi, other options can be set with a string parameter like "dmenu")
+```
+
+### Theme Variables
+
+```lua
+-- For tabbed only
+theme.tabbed_spawn_in_tab = false -- whether a new client should spawn into the focused tabbing container
+
+-- For tabbar in general
+theme.tabbar_ontop = false
+theme.tabbar_radius = 0 -- border radius of the tabbar
+theme.tabbar_style = "default" -- style of the tabbar ("default", "boxes" or "modern")
+theme.tabbar_font = "Sans 11" -- font of the tabbar
+theme.tabbar_size = 40 -- size of the tabbar
+theme.tabbar_position = "top" -- position of the tabbar
+theme.tabbar_bg_normal = "#000000" -- background color of the focused client on the tabbar
+theme.tabbar_fg_normal = "#ffffff" -- foreground color of the focused client on the tabbar
+theme.tabbar_bg_focus = "#1A2026" -- background color of unfocused clients on the tabbar
+theme.tabbar_fg_focus = "#ff0000" -- foreground color of unfocused clients on the tabbar
+
+-- the following variables are currently only for the "modern" tabbar style
+theme.tabbar_color_close = "#f9929b" -- chnges the color of the close button
+theme.tabbar_color_min = "#fbdf90" -- chnges the color of the minimize button
+theme.tabbar_color_float = "#ccaced" -- chnges the color of the float button
+```
+
+### Preview
+
+Modern theme:
+
+<img src="https://imgur.com/omowmIQ.png" width="600"/>
+
+*screenshot by [javacafe](https://github.com/JavaCafe01)*
diff --git a/awesome/bling/docs/module/twall.md b/awesome/bling/docs/module/twall.md
new file mode 100644
index 0000000..73ef4a3
--- /dev/null
+++ b/awesome/bling/docs/module/twall.md
@@ -0,0 +1,25 @@
+## 🏬 Tiled Wallpaper <!-- {docsify-ignore} -->
+
+### Usage
+
+The function to set an automatically created tiled wallpaper can be called the following way (you don't need to set every option in the table):
+```lua
+awful.screen.connect_for_each_screen(function(s) -- that way the wallpaper is applied to every screen
+ bling.module.tiled_wallpaper("x", s, { -- call the actual function ("x" is the string that will be tiled)
+ fg = "#ff0000", -- define the foreground color
+ bg = "#00ffff", -- define the background color
+ offset_y = 25, -- set a y offset
+ offset_x = 25, -- set a x offset
+ font = "Hack", -- set the font (without the size)
+ font_size = 14, -- set the font size
+ padding = 100, -- set padding (default is 100)
+ zickzack = true -- rectangular pattern or criss cross
+ })
+end)
+```
+
+### Preview
+
+![](https://media.discordapp.net/attachments/702548913999314964/773887721294135296/tiled-wallpapers.png?width=1920&height=1080)
+
+*screenshots by [Nooo37](https://github.com/Nooo37)*
diff --git a/awesome/bling/docs/module/wall.md b/awesome/bling/docs/module/wall.md
new file mode 100644
index 0000000..12a5e4d
--- /dev/null
+++ b/awesome/bling/docs/module/wall.md
@@ -0,0 +1,127 @@
+## 🎇 Wallpaper Easy Setup <!-- {docsify-ignore} -->
+
+This is a simple-to-use, extensible, declarative wallpaper manager.
+
+### Practical Examples
+
+```lua
+-- A default Awesome wallpaper
+bling.module.wallpaper.setup()
+
+-- A slideshow with pictures from different sources changing every 30 minutes
+bling.module.wallpaper.setup {
+ wallpaper = {"/images/my_dog.jpg", "/images/my_cat.jpg"},
+ change_timer = 1800
+}
+
+-- A random wallpaper with images from multiple folders
+bling.module.wallpaper.setup {
+ set_function = bling.module.wallpaper.setters.random
+ wallpaper = {"/path/to/a/folder", "/path/to/another/folder"},
+ change_timer = 631, -- prime numbers are better for timers
+ position = "fit",
+ background = "#424242"
+}
+
+-- wallpapers based on a schedule, like awesome-glorious-widgets dynamic wallpaper
+-- https://github.com/manilarome/awesome-glorious-widgets/tree/master/dynamic-wallpaper
+bling.module.wallpaper.setup {
+ set_function = wallpaper.setters.simple_schedule,
+ wallpaper = {
+ ["06:22:00"] = "morning-wallpaper.jpg",
+ ["12:00:00"] = "noon-wallpaper.jpg",
+ ["17:58:00"] = "night-wallpaper.jpg",
+ ["24:00:00"] = "midnight-wallpaper.jpg",
+ },
+ position = "maximized",
+}
+
+-- random wallpapers, from different folder depending on time of the day
+bling.module.wallpaper.setup {
+ set_function = bling.module.wallpaper.setters.simple_schedule,
+ wallpaper = {
+ ["09:00:00"] = "~/Pictures/safe_for_work",
+ ["18:00:00"] = "~/Pictures/personal",
+ },
+ schedule_set_function = bling.module.wallpaper.setters.random
+ position = "maximized",
+ recursive = false,
+ change_timer = 600
+}
+```
+### Details
+
+The setup function will do 2 things: call the set-function when awesome requests a wallpaper, and manage a timer to call `set_function` periodically.
+
+Its argument is a args table that is passed to ohter functions (setters and wallpaper functions), so you define everything with setup.
+
+The `set_function` is a function called every times a wallpaper is needed.
+
+The module provides some setters:
+
+* `bling.module.wallpaper.setters.awesome_wallpaper`: beautiful.theme_assets.wallpaper with defaults from beautiful.
+* `bling.module.wallpaper.setters.simple`: slideshow from the `wallpaper` argument.
+* `bling.module.wallpaper.setters.random`: same as simple but in a random way.
+* `bling.module.wallpaper.setters.simple_schedule`: takes a table of `["HH:MM:SS"] = wallpaper` arguments, where wallpaper is the `wallpaper` argument used by `schedule_set_function`.
+
+A wallpaper is one of the following elements:
+
+* a color
+* an image
+* a folder containing images
+* a function that sets a wallpaper
+* everything gears.wallpaper functions can manage (cairo surface, cairo pattern string)
+* a list containing any of the elements above
+
+```lua
+-- This is a valid wallpaper definition
+bling.module.wallpaper.setup {
+ wallpaper = { -- a list
+ "black", "#112233", -- colors
+ "wall1.jpg", "wall2.png", -- files
+ "/path/to/wallpapers", -- folders
+ -- cairo patterns
+ "radial:600,50,100:105,550,900:0,#2200ff:0.5,#00ff00:1,#101010",
+ -- or functions that set a wallpaper
+ function(args) bling.module.tiled_wallpaper("\\o/", args.screen) end,
+ bling.module.wallpaper.setters.awesome_wallpaper,
+ },
+ change_timer = 10,
+}
+```
+The provided setters `simple` and `random` will use 2 internal functions that you can use to write your own setter:
+
+* `bling.module.wallpaper.prepare_list`: return a list of wallpapers directly usable by `apply` (for now, it just explores folders)
+* `bling.module.wallpaper.apply`: a wrapper for gears.wallpaper functions, using the args table of setup
+
+Here are the defaults:
+
+```lua
+-- Default parameters
+bling.module.wallpaper.setup {
+ screen = nil, -- the screen to apply the wallpaper, as seen in gears.wallpaper functions
+ change_timer = nil, -- the timer in seconds. If set, call the set_function every change_timer seconds
+ set_function = nil, -- the setter function
+
+ -- parameters used by bling.module.wallpaper.prepare_list
+ wallpaper = nil, -- the wallpaper object, see simple or simple_schedule documentation
+ image_formats = {"jpg", "jpeg", "png", "bmp"}, -- when searching in folder, consider these files only
+ recursive = true, -- when searching in folder, search also in subfolders
+
+ -- parameters used by bling.module.wallpaper.apply
+ position = nil, -- use a function of gears.wallpaper when applicable ("centered", "fit", "maximized", "tiled")
+ background = beautiful.bg_normal or "black", -- see gears.wallpaper functions
+ ignore_aspect = false, -- see gears.wallpaper.maximized
+ offset = {x = 0, y = 0}, -- see gears.wallpaper functions
+ scale = 1, -- see gears.wallpaper.centered
+
+ -- parameters that only apply to bling.module.wallpaper.setter.awesome (as a setter or as a wallpaper function)
+ colors = { -- see beautiful.theme_assets.wallpaper
+ bg = beautiful.bg_color, -- the actual default is this color but darkened or lightned
+ fg = beautiful.fg_color,
+ alt_fg = beautiful.fg_focus
+ }
+}
+```
+
+Check documentation in [module/wallpaper.lua](module/wallpaper.lua) for more details.
diff --git a/awesome/bling/docs/signals/pctl.md b/awesome/bling/docs/signals/pctl.md
new file mode 100644
index 0000000..dd2ee48
--- /dev/null
+++ b/awesome/bling/docs/signals/pctl.md
@@ -0,0 +1,91 @@
+## 🎵 Playerctl <!-- {docsify-ignore} -->
+
+This is a signal module in which you can connect to certain bling signals to grab playerctl info. Currently, this is what it supports:
+
+- Song title and artist
+- Album art (the path this module downloaded the art to)
+- If playing or not
+- Position
+- Song length
+- If there are no players on
+
+This module relies on `playerctl` and `curl`. If you have this module disabled, you won't need those programs. With this module, you can create a widget like below without worrying about the backend.
+
+![](https://user-images.githubusercontent.com/33443763/107377569-fa807900-6a9f-11eb-93c1-174c58eb7bf1.png)
+
+*screenshot by [javacafe](https://github.com/JavaCafe01)*
+
+### Usage
+
+To enable: `bling.signal.playerctl.enable()`
+
+Here are the signals available:
+
+```lua
+-- bling::playerctl::status -- first line is the signal
+-- playing (boolean) -- indented lines are function parameters
+-- bling::playerctl::title_artist_album
+-- title (string)
+-- artist (string)
+-- album_path (string)
+-- bling::playerctl::position
+-- interval_sec (number)
+-- length_sec (number)
+-- bling::playerctl::player_stopped
+-- (No params)
+```
+
+### Example Implementation
+
+Lets say we have an imagebox. If I wanted to set the imagebox to show the album art, all I have to do is this:
+```lua
+local art = wibox.widget {
+ image = "default_image.png",
+ resize = true,
+ forced_height = dpi(80),
+ forced_width = dpi(80),
+ widget = wibox.widget.imagebox
+}
+
+local title_widget = wibox.widget {
+ markup = 'Nothing Playing',
+ align = 'center',
+ valign = 'center',
+ widget = wibox.widget.textbox
+}
+
+local artist_widget = wibox.widget {
+ markup = 'Nothing Playing',
+ align = 'center',
+ valign = 'center',
+ widget = wibox.widget.textbox
+}
+
+-- Get Song Info
+awesome.connect_signal("bling::playerctl::title_artist_album",
+ function(title, artist, art_path)
+ -- Set art widget
+ art:set_image(gears.surface.load_uncached(art_path))
+
+ -- Set title and artist widgets
+ title_widget:set_markup_silently(title)
+ artist_widget:set_markup_silently(artist)
+end)
+```
+Thats all! You don't even have to worry about updating the widgets, the signals will handle that for you.
+
+Here's another example in which you get a notification with the album art, title, and artist whenever the song changes.
+
+```lua
+local naughty = require("naughty")
+
+awesome.connect_signal("bling::playerctl::title_artist_album",
+ function(title, artist, art_path)
+ naughty.notify({title = title, text = artist, image = art_path})
+end)
+```
+
+### Theme Variables
+```lua
+theme.playerctl_position_update_interval = 1 -- the update interval for fetching the position from playerctl
+```
diff --git a/awesome/bling/docs/theme.md b/awesome/bling/docs/theme.md
new file mode 100644
index 0000000..5814a2e
--- /dev/null
+++ b/awesome/bling/docs/theme.md
@@ -0,0 +1,54 @@
+```lua
+--[[ Bling theme variables template
+This file has all theme variables of the bling module.
+Every variable has a small comment on what it does.
+You might just want to copy that whole part into your theme.lua and start adjusting from there.
+--]]
+
+
+-- window swallowing
+theme.dont_swallow_classname_list = {"firefox", "Gimp"} -- list of class names that should not be swallowed
+theme.dont_swallow_filter_activated = true -- whether the filter above should be active
+
+-- flash focus
+theme.flash_focus_start_opacity = 0.6 -- the starting opacity
+theme.flash_focus_step = 0.01 -- the step of animation
+
+-- playerctl signal
+theme.playerctl_position_update_interval = 1 -- the update interval for fetching the position from playerctl
+
+-- tabbed
+theme.tabbed_spawn_in_tab = false -- whether a new client should spawn into the focused tabbing container
+
+-- tabbar general
+theme.tabbar_ontop = false
+theme.tabbar_radius = 0 -- border radius of the tabbar
+theme.tabbar_style = "default" -- style of the tabbar ("default", "boxes" or "modern")
+theme.tabbar_font = "Sans 11" -- font of the tabbar
+theme.tabbar_size = 40 -- size of the tabbar
+theme.tabbar_position = "top" -- position of the tabbar
+theme.tabbar_bg_normal = "#000000" -- background color of the focused client on the tabbar
+theme.tabbar_fg_normal = "#ffffff" -- foreground color of the focused client on the tabbar
+theme.tabbar_bg_focus = "#1A2026" -- background color of unfocused clients on the tabbar
+theme.tabbar_fg_focus = "#ff0000" -- foreground color of unfocused clients on the tabbar
+
+-- mstab
+theme.mstab_bar_ontop = false -- whether you want to allow the bar to be ontop of clients
+theme.mstab_dont_resize_slaves = false -- whether the tabbed stack windows should be smaller than the
+ -- currently focused stack window (set it to true if you use
+ -- transparent terminals. False if you use shadows on solid ones
+theme.mstab_bar_padding = "default" -- how much padding there should be between clients and your tabbar
+ -- by default it will adjust based on your useless gaps.
+ -- If you want a custom value. Set it to the number of pixels (int)
+theme.mstab_border_radius = 0 -- border radius of the tabbar
+theme.mstab_bar_height = 40 -- height of the tabbar
+theme.mstab_tabbar_position = "top" -- position of the tabbar (mstab currently does not support left,right)
+theme.mstab_tabbar_style = "default" -- style of the tabbar ("default", "boxes" or "modern")
+ -- defaults to the tabbar_style so only change if you want a
+ -- different style for mstab and tabbed
+
+-- the following variables are currently only for the "modern" tabbar style
+theme.tabbar_color_close = "#f9929b" -- chnges the color of the close button
+theme.tabbar_color_min = "#fbdf90" -- chnges the color of the minimize button
+theme.tabbar_color_float = "#ccaced" -- chnges the color of the float button
+```
diff --git a/awesome/bling/helpers/client.lua b/awesome/bling/helpers/client.lua
new file mode 100644
index 0000000..67bacae
--- /dev/null
+++ b/awesome/bling/helpers/client.lua
@@ -0,0 +1,34 @@
+local awful = require("awful")
+
+local _client = {}
+
+--- Turn off passed client
+-- Remove current tag from window's tags
+--
+-- @param c a client
+function _client.turn_off(c)
+ local current_tag = awful.tag.selected(c.screen)
+ local ctags = {}
+ for k, tag in pairs(c:tags()) do
+ if tag ~= current_tag then table.insert(ctags, tag) end
+ end
+ c:tags(ctags)
+end
+
+--- Turn on passed client (add current tag to window's tags)
+--
+-- @param c A client
+function _client.turn_on(c)
+ local current_tag = awful.tag.selected(c.screen)
+ ctags = {current_tag}
+ for k, tag in pairs(c:tags()) do
+ if tag ~= current_tag then table.insert(ctags, tag) end
+ end
+ c:tags(ctags)
+ c:raise()
+ client.focus = c
+end
+
+
+
+return _client
diff --git a/awesome/bling/helpers/color.lua b/awesome/bling/helpers/color.lua
new file mode 100644
index 0000000..09e003b
--- /dev/null
+++ b/awesome/bling/helpers/color.lua
@@ -0,0 +1,59 @@
+
+
+local _color = {}
+
+
+
+--- Try to guess if a color is dark or light.
+--
+-- @string color The color with hexadecimal HTML format `"#RRGGBB"`.
+-- @treturn bool `true` if the color is dark, `false` if it is light.
+function _color.is_dark(color)
+ -- Try to determine if the color is dark or light
+ local numeric_value = 0;
+ for s in color:gmatch("[a-fA-F0-9][a-fA-F0-9]") do
+ numeric_value = numeric_value + tonumber("0x"..s);
+ end
+ return (numeric_value < 383)
+end
+
+
+--- Lighten a color.
+--
+-- @string color The color to lighten with hexadecimal HTML format `"#RRGGBB"`.
+-- @int[opt=26] amount How much light from 0 to 255. Default is around 10%.
+-- @treturn string The lighter color
+function _color.lighten(color, amount)
+ amount = amount or 26
+ local c = {
+ r = tonumber("0x"..color:sub(2,3)),
+ g = tonumber("0x"..color:sub(4,5)),
+ b = tonumber("0x"..color:sub(6,7)),
+ }
+
+ c.r = c.r + amount
+ c.r = c.r < 0 and 0 or c.r
+ c.r = c.r > 255 and 255 or c.r
+ c.g = c.g + amount
+ c.g = c.g < 0 and 0 or c.g
+ c.g = c.g > 255 and 255 or c.g
+ c.b = c.b + amount
+ c.b = c.b < 0 and 0 or c.b
+ c.b = c.b > 255 and 255 or c.b
+
+ return string.format('#%02x%02x%02x', c.r, c.g, c.b)
+end
+
+--- Darken a color.
+--
+-- @string color The color to darken with hexadecimal HTML format `"#RRGGBB"`.
+-- @int[opt=26] amount How much dark from 0 to 255. Default is around 10%.
+-- @treturn string The darker color
+function _color.darken(color, amount)
+ amount = amount or 26
+ return _color.lighten(color, -amount)
+end
+
+
+
+return _color
diff --git a/awesome/bling/helpers/filesystem.lua b/awesome/bling/helpers/filesystem.lua
new file mode 100644
index 0000000..0d8ed11
--- /dev/null
+++ b/awesome/bling/helpers/filesystem.lua
@@ -0,0 +1,39 @@
+local Gio = require("lgi").Gio
+
+local _filesystem = {}
+
+--- Get a list of files from a given directory.
+-- @string path The directory to search.
+-- @tparam[opt] table exts Specific extensions to limit the search to. eg:`{ "jpg", "png" }`
+-- If ommited, all files are considered.
+-- @bool[opt=false] recursive List files from subdirectories
+-- @staticfct bling.helpers.filesystem.get_random_file_from_dir
+function _filesystem.list_directory_files(path, exts, recursive)
+ recursive = recursive or false
+ local files, valid_exts = {}, {}
+
+ -- Transforms { "jpg", ... } into { [jpg] = #, ... }
+ if exts then for i, j in ipairs(exts) do valid_exts[j:lower()] = i end end
+
+ -- Build a table of files from the path with the required extensions
+ local file_list = Gio.File.new_for_path(path):enumerate_children("standard::*", 0)
+ if file_list then
+ for file in function() return file_list:next_file() end do
+ local file_type = file:get_file_type()
+ if file_type == "REGULAR" then
+ local file_name = file:get_display_name()
+ if not exts or valid_exts[file_name:lower():match(".+%.(.*)$") or ""] then
+ table.insert(files, file_name)
+ end
+ elseif recursive and file_type == "DIRECTORY" then
+ local file_name = file:get_display_name()
+ files = gears.table.join(files, list_directory_files(file_name, exts, recursive))
+ end
+ end
+ end
+
+ return files
+end
+
+
+return _filesystem
diff --git a/awesome/bling/helpers/init.lua b/awesome/bling/helpers/init.lua
new file mode 100644
index 0000000..41ac702
--- /dev/null
+++ b/awesome/bling/helpers/init.lua
@@ -0,0 +1,7 @@
+return {
+ client = require(... .. ".client"),
+ color = require(... .. ".color"),
+ filesystem = require(... .. ".filesystem"),
+ shape = require(... .. ".shape"),
+ time = require(... .. ".time")
+}
diff --git a/awesome/bling/helpers/shape.lua b/awesome/bling/helpers/shape.lua
new file mode 100644
index 0000000..31883aa
--- /dev/null
+++ b/awesome/bling/helpers/shape.lua
@@ -0,0 +1,23 @@
+local gears = require("gears")
+
+shape = {}
+
+-- Create rounded rectangle shape (in one line)
+
+function shape.rrect(radius)
+ return function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, radius)
+ end
+end
+
+-- Create partially rounded rect
+
+function shape.prrect(radius, tl, tr, br, bl)
+ return function(cr, width, height)
+ gears.shape.partially_rounded_rect(cr, width, height, tl, tr, br, bl,
+ radius)
+ end
+end
+
+
+return shape
diff --git a/awesome/bling/helpers/time.lua b/awesome/bling/helpers/time.lua
new file mode 100644
index 0000000..dc2a9d4
--- /dev/null
+++ b/awesome/bling/helpers/time.lua
@@ -0,0 +1,29 @@
+
+
+local time = {}
+
+
+--- Parse a time string to seconds (from midnight)
+--
+-- @string time The time (`HH:MM:SS`)
+-- @treturn int The number of seconds since 00:00:00
+function time.hhmmss_to_seconds(time)
+ hour_sec = tonumber(string.sub(time, 1, 2)) * 3600
+ min_sec = tonumber(string.sub(time, 4, 5)) * 60
+ get_sec = tonumber(string.sub(time, 7, 8))
+ return (hour_sec + min_sec + get_sec)
+end
+
+
+--- Get time difference in seconds.
+--
+-- @tparam string base The time to compare from (`HH:MM:SS`).
+-- @tparam string base The time to compare to (`HH:MM:SS`).
+-- @treturn int Number of seconds between the two times.
+function time.time_diff(base, compare)
+ local diff = time.hhmmss_to_seconds(base) - time.hhmmss_to_seconds(compare)
+ return diff
+end
+
+
+return time
diff --git a/awesome/bling/icons/layouts/centered.png b/awesome/bling/icons/layouts/centered.png
new file mode 100644
index 0000000..5e4d07f
--- /dev/null
+++ b/awesome/bling/icons/layouts/centered.png
Binary files differ
diff --git a/awesome/bling/icons/layouts/horizontal.png b/awesome/bling/icons/layouts/horizontal.png
new file mode 100644
index 0000000..217f4eb
--- /dev/null
+++ b/awesome/bling/icons/layouts/horizontal.png
Binary files differ
diff --git a/awesome/bling/icons/layouts/mstab.png b/awesome/bling/icons/layouts/mstab.png
new file mode 100644
index 0000000..4372846
--- /dev/null
+++ b/awesome/bling/icons/layouts/mstab.png
Binary files differ
diff --git a/awesome/bling/icons/layouts/vertical.png b/awesome/bling/icons/layouts/vertical.png
new file mode 100644
index 0000000..3561673
--- /dev/null
+++ b/awesome/bling/icons/layouts/vertical.png
Binary files differ
diff --git a/awesome/bling/init.lua b/awesome/bling/init.lua
new file mode 100644
index 0000000..0ac3478
--- /dev/null
+++ b/awesome/bling/init.lua
@@ -0,0 +1,9 @@
+--[[
+ Bling
+ Layouts, widgets and utilities for Awesome WM
+--]] return {
+ layout = require(... .. ".layout"),
+ module = require(... .. ".module"),
+ helpers = require(... .. ".helpers"),
+ signal = require(... .. ".signal")
+}
diff --git a/awesome/bling/layout/centered.lua b/awesome/bling/layout/centered.lua
new file mode 100644
index 0000000..e2203fd
--- /dev/null
+++ b/awesome/bling/layout/centered.lua
@@ -0,0 +1,98 @@
+local awful = require("awful")
+local gears = require("gears")
+local gcolor = require("gears.color")
+local beautiful = require("beautiful")
+local math = math
+
+local mylayout = {}
+
+mylayout.name = "centered"
+
+function mylayout.arrange(p)
+ local area = p.workarea
+ local t = p.tag or screen[p.screen].selected_tag
+ local mwfact = t.master_width_factor
+ local nmaster = math.min(t.master_count, #p.clients)
+ local nslaves = #p.clients - nmaster
+
+ local master_area_width = area.width * mwfact
+ local slave_area_width = area.width - master_area_width
+ local master_area_x = area.x + 0.5*slave_area_width
+
+ local number_of_left_sided_slaves =math.floor(nslaves/2)
+ local number_of_right_sided_slaves = nslaves - number_of_left_sided_slaves
+ local left_iterator = 0
+ local right_iterator = 0
+
+ -- Special case: no maters -> rrelapse into awesomes fair layout
+ if t.master_count == 0 then
+ awful.layout.suit.fair.arrange(p)
+ return
+ end
+
+ -- Special case: one slave -> relapse into awesomes masterstack tile layout
+ if nslaves == 1 then
+ awful.layout.suit.tile.right.arrange(p)
+ return
+ end
+
+ -- Special case: no slaves -> fullscreen master area
+ if nslaves < 1 then
+ master_area_width = area.width
+ master_area_x = area.x
+ end
+
+ -- iterate through masters
+ for idx=1,nmaster do
+ local c = p.clients[idx]
+ local g
+ g = {
+ x = master_area_x,
+ y = area.y + (nmaster-idx)*(area.height/nmaster),
+ width = master_area_width,
+ height = area.height/nmaster,
+ }
+ p.geometries[c] = g
+ end
+
+ -- iterate through slaves
+ for idx=1,nslaves do -- idx=nmaster+1,#p.clients do
+ local c = p.clients[idx+nmaster]
+ if idx % 2 == 0 then
+ g = {
+ x = area.x,
+ y = area.y + left_iterator * (area.height/number_of_left_sided_slaves),
+ width = slave_area_width/2,
+ height = area.height/number_of_left_sided_slaves,
+ }
+ left_iterator = left_iterator + 1
+ else
+ g = {
+ x = area.x + master_area_width + slave_area_width/2,
+ y = area.y + right_iterator * (area.height/number_of_right_sided_slaves),
+ width = slave_area_width/2,
+ height = area.height/number_of_right_sided_slaves,
+ }
+ right_iterator = right_iterator + 1
+
+ end
+ p.geometries[c] = g
+ end
+end
+
+local icon_raw = gears.filesystem.get_configuration_dir() .. tostring(...):match("^.*bling"):gsub("%.", "/") .. "/icons/layouts/centered.png"
+
+local function get_icon()
+ if icon_raw ~= nil then
+ return gcolor.recolor_image(icon_raw, beautiful.fg_normal)
+ else
+ return nil
+ end
+end
+
+
+return {
+ layout = mylayout,
+ icon_raw = icon_raw,
+ get_icon = get_icon,
+}
diff --git a/awesome/bling/layout/horizontal.lua b/awesome/bling/layout/horizontal.lua
new file mode 100644
index 0000000..ff768e7
--- /dev/null
+++ b/awesome/bling/layout/horizontal.lua
@@ -0,0 +1,72 @@
+local awful = require("awful")
+local gears = require("gears")
+local gcolor = require("gears.color")
+local beautiful = require("beautiful")
+local math = math
+
+local mylayout = {}
+
+mylayout.name = "horizontal"
+
+function mylayout.arrange(p)
+ local area = p.workarea
+ local t = p.tag or screen[p.screen].selected_tag
+ local mwfact = t.master_width_factor
+ local nmaster = math.min(t.master_count, #p.clients)
+ local nslaves = #p.clients - nmaster
+
+ local master_area_height = area.height * mwfact
+ local slave_area_height = area.height - master_area_height
+
+ -- Special case: no slaves
+ if nslaves == 0 then
+ master_area_height = area.height
+ slave_area_height = 0
+ end
+
+ -- Special case: no masters
+ if nmaster == 0 then
+ master_area_height = 0
+ slave_area_height = area.height
+ end
+
+ -- itearte through masters
+ for idx=1,nmaster do
+ local c = p.clients[idx]
+ local g = {
+ x = area.x + (idx-1)*(area.width/nmaster),
+ y = area.y,
+ width = area.width/nmaster,
+ height = master_area_height,
+ }
+ p.geometries[c] = g
+ end
+
+ -- iterate through slaves
+ for idx=1,nslaves do
+ local c = p.clients[idx+nmaster]
+ local g = {
+ x = area.x,
+ y = area.y + master_area_height + (idx-1)*(slave_area_height/nslaves),
+ width = area.width,
+ height = slave_area_height/nslaves,
+ }
+ p.geometries[c] = g
+ end
+end
+
+local icon_raw = gears.filesystem.get_configuration_dir() .. tostring(...):match("^.*bling"):gsub("%.", "/") .. "/icons/layouts/horizontal.png"
+
+local function get_icon()
+ if icon_raw ~= nil then
+ return gcolor.recolor_image(icon_raw, beautiful.fg_normal)
+ else
+ return nil
+ end
+end
+
+return {
+ layout = mylayout,
+ icon_raw = icon_raw,
+ get_icon = get_icon,
+}
diff --git a/awesome/bling/layout/init.lua b/awesome/bling/layout/init.lua
new file mode 100644
index 0000000..912d149
--- /dev/null
+++ b/awesome/bling/layout/init.lua
@@ -0,0 +1,22 @@
+local beautiful = require("beautiful")
+
+local mstab = require(... .. ".mstab")
+beautiful.layout_mstab = mstab.get_icon()
+
+local vertical = require(... .. ".vertical")
+beautiful.layout_vertical = vertical.get_icon()
+
+local horizontal = require(... .. ".horizontal")
+beautiful.layout_horizontal = horizontal.get_icon()
+
+local centered = require(... .. ".centered")
+beautiful.layout_centered = centered.get_icon()
+
+local layout = {
+ mstab = mstab.layout,
+ centered = centered.layout,
+ vertical = vertical.layout,
+ horizontal = horizontal.layout
+}
+
+return layout
diff --git a/awesome/bling/layout/mstab.lua b/awesome/bling/layout/mstab.lua
new file mode 100644
index 0000000..1ba0985
--- /dev/null
+++ b/awesome/bling/layout/mstab.lua
@@ -0,0 +1,217 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local gcolor = require("gears.color")
+local beautiful = require("beautiful")
+
+local mylayout = {}
+
+mylayout.name = "mstab"
+
+local tabbar_ontop = beautiful.mstab_bar_ontop or false
+local tabbar_padding = beautiful.mstab_bar_padding or "default"
+local border_radius = beautiful.mstab_border_radius or
+ beautiful.border_radius or 0
+local tabbar_position = beautiful.mstab_tabbar_position or
+ beautiful.tabbar_position or "top"
+
+local bar_style = beautiful.mstab_tabbar_style or beautiful.tabbar_style or
+ "default"
+local bar = require(tostring(...):match(".*bling") .. ".widget.tabbar." ..
+ bar_style)
+local tabbar_size = bar.size or beautiful.mstab_bar_height or beautiful.tabbar_size or 40
+local dont_resize_slaves = beautiful.mstab_dont_resize_slaves or false
+
+-- The top_idx is the idx of the slave clients (excluding all master clients)
+-- that should be on top of all other slave clients ("the focused slave")
+-- by creating a variable outside of the arrange function, this layout can "remember" that client
+-- by creating it as a new property of every tag, this layout can be active on different tags and
+-- still have different "focused slave clients"
+for idx, tag in ipairs(root.tags()) do tag.top_idx = 1 end
+
+-- Haven't found a signal that is emitted when a new tag is added. That should work though
+-- since you can't use a layout on a tag that you haven't selected previously
+tag.connect_signal("property::selected",
+ function(t) if not t.top_idx then t.top_idx = 1 end end)
+
+function update_tabbar(clients, t, top_idx, area, master_area_width,
+ slave_area_width)
+
+ local s = t.screen
+
+ -- create the list of clients for the tabbar
+ local clientlist = bar.layout()
+ for idx, c in ipairs(clients) do
+ -- focus with right click, kill with mid click, minimize with left click
+ local buttons = gears.table.join(
+ awful.button({}, 1, function()
+ c:raise()
+ client.focus = c
+ end),
+ awful.button({}, 2, function()
+ c:kill()
+ end),
+ awful.button({}, 3, function()
+ c.minimized = true
+ end))
+ local client_box = bar.create(c, (idx == top_idx), buttons)
+ clientlist:add(client_box)
+ end
+
+ -- if no tabbar exists, create one
+ if not s.tabbar then
+ s.tabbar = wibox {
+ ontop = tabbar_ontop,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, border_radius)
+ end,
+ bg = bar.bg_normal,
+ visible = true
+ }
+
+ -- Change visibility of the tab bar when layout, selected tag or number of clients (visible, master, slave) changes
+ local function adjust_visiblity(t)
+ s.tabbar.visible = (#t:clients() - t.master_count > 1) and
+ (t.layout.name == mylayout.name)
+ end
+
+ tag.connect_signal("property::selected",
+ function(t) adjust_visiblity(t) end)
+ tag.connect_signal("property::layout",
+ function(t, layout) adjust_visiblity(t) end)
+ tag.connect_signal("tagged", function(t, c) adjust_visiblity(t) end)
+ tag.connect_signal("untagged", function(t, c) adjust_visiblity(t) end)
+ tag.connect_signal("property::master_count",
+ function(t) adjust_visiblity(t) end)
+ client.connect_signal("property::minimized", function(c)
+ local t = c.first_tag
+ adjust_visiblity(t)
+ end)
+ end
+
+ -- update the tabbar size and position (to support gap size change on the fly)
+ if tabbar_position == "top" then
+ s.tabbar.x = area.x + master_area_width + t.gap
+ s.tabbar.y = area.y + t.gap
+ s.tabbar.width = slave_area_width - 2 * t.gap
+ s.tabbar.height = tabbar_size
+ elseif tabbar_position == "bottom" then
+ s.tabbar.x = area.x + master_area_width + t.gap
+ s.tabbar.y = area.y + area.height - tabbar_size - t.gap
+ s.tabbar.width = slave_area_width - 2 * t.gap
+ s.tabbar.height = tabbar_size
+ elseif tabbar_position == "left" then
+ s.tabbar.x = area.x + master_area_width + t.gap
+ s.tabbar.y = area.y + t.gap
+ s.tabbar.width = tabbar_size
+ s.tabbar.height = area.height - 2 * t.gap
+ elseif tabbar_position == "right" then
+ s.tabbar.x = area.x + master_area_width + slave_area_width - tabbar_size - t.gap
+ s.tabbar.y = area.y + t.gap
+ s.tabbar.width = tabbar_size
+ s.tabbar.height = area.height - 2 * t.gap
+ end
+
+ -- update clientlist
+ s.tabbar:setup{layout = wibox.layout.flex.horizontal, clientlist}
+
+end
+
+function mylayout.arrange(p)
+ local area = p.workarea
+ local t = p.tag or screen[p.screen].selected_tag
+ local s = t.screen
+ local mwfact = t.master_width_factor
+ local nmaster = math.min(t.master_count, #p.clients)
+ local nslaves = #p.clients - nmaster
+
+ local master_area_width = area.width * mwfact
+ local slave_area_width = area.width - master_area_width
+
+ -- "default" means that it uses standard useless gap size
+ if tabbar_padding == "default" then tabbar_padding = 2 * t.gap end
+
+ -- Special case: No masters -> full screen slave width
+ if nmaster == 0 then
+ master_area_width = 1
+ slave_area_width = area.width
+ end
+
+ -- Special case: One or zero slaves -> no tabbar (essentially tile right)
+ if nslaves <= 1 then
+ -- since update_tabbar isnt called that way we have to hide it manually
+ if s.tabbar then s.tabbar.visible = false end
+ -- otherwise just do tile right
+ awful.layout.suit.tile.right.arrange(p)
+ return
+ end
+
+ -- Iterate through masters
+ for idx = 1, nmaster do
+ local c = p.clients[idx]
+ local g = {
+ x = area.x,
+ y = area.y + (idx - 1) * (area.height / nmaster),
+ width = master_area_width,
+ height = area.height / nmaster
+ }
+ p.geometries[c] = g
+ end
+
+ local tabbar_size_change = 0
+ local tabbar_width_change = 0
+ local tabbar_y_change = 0
+ local tabbar_x_change = 0
+ if tabbar_position == "top" then
+ tabbar_size_change = tabbar_size + tabbar_padding
+ tabbar_y_change = tabbar_size + tabbar_padding
+ elseif tabbar_position == "bottom" then
+ tabbar_size_change = tabbar_size + tabbar_padding
+ elseif tabbar_position == "left" then
+ tabbar_width_change = tabbar_size + tabbar_padding
+ tabbar_x_change = tabbar_size + tabbar_padding
+ elseif tabbar_position == "right" then
+ tabbar_width_change = tabbar_size + tabbar_padding
+ end
+
+ -- Iterate through slaves
+ -- (also creates a list of all slave clients for update_tabbar)
+ local slave_clients = {}
+ for idx = 1, nslaves do
+ local c = p.clients[idx + nmaster]
+ slave_clients[#slave_clients + 1] = c
+ if c == client.focus then t.top_idx = #slave_clients end
+ local g = {
+ x = area.x + master_area_width + tabbar_x_change,
+ y = area.y + tabbar_y_change,
+ width = slave_area_width - tabbar_width_change,
+ height = area.height - tabbar_size_change
+ }
+ if not dont_resize_slaves and idx ~= t.top_idx then
+ g = {
+ x = area.x + master_area_width + slave_area_width / 4,
+ y = area.y + tabbar_size + area.height / 4,
+ width = slave_area_width / 2,
+ height = area.height / 4 - tabbar_size
+ }
+ end
+ p.geometries[c] = g
+ end
+
+ update_tabbar(slave_clients, t, t.top_idx, area, master_area_width,
+ slave_area_width)
+end
+
+local icon_raw = gears.filesystem.get_configuration_dir() ..
+ tostring(...):match("^.*bling"):gsub("%.", "/") ..
+ "/icons/layouts/mstab.png"
+
+local function get_icon()
+ if icon_raw ~= nil then
+ return gcolor.recolor_image(icon_raw, beautiful.fg_normal)
+ else
+ return nil
+ end
+end
+
+return {layout = mylayout, icon_raw = icon_raw, get_icon = get_icon}
diff --git a/awesome/bling/layout/vertical.lua b/awesome/bling/layout/vertical.lua
new file mode 100644
index 0000000..8789cb3
--- /dev/null
+++ b/awesome/bling/layout/vertical.lua
@@ -0,0 +1,72 @@
+local awful = require("awful")
+local gears = require("gears")
+local gcolor = require("gears.color")
+local beautiful = require("beautiful")
+local math = math
+
+local mylayout = {}
+
+mylayout.name = "vertical"
+
+function mylayout.arrange(p)
+ local area = p.workarea
+ local t = p.tag or screen[p.screen].selected_tag
+ local mwfact = t.master_width_factor
+ local nmaster = math.min(t.master_count, #p.clients)
+ local nslaves = #p.clients - nmaster
+
+ local master_area_width = area.width * mwfact
+ local slave_area_width = area.width - master_area_width
+
+ -- Special case: no slaves
+ if nslaves == 0 then
+ master_area_width = area.width
+ slave_area_width = 0
+ end
+
+ -- Special case: no masters
+ if nmaster == 0 then
+ master_area_width = 0
+ slave_area_width = area.width
+ end
+
+ -- iterate through masters
+ for idx=1,nmaster do
+ local c = p.clients[idx]
+ local g = {
+ x = area.x,
+ y = area.y + (idx-1)*(area.height/nmaster),
+ width = master_area_width,
+ height = area.height/nmaster,
+ }
+ p.geometries[c] = g
+ end
+
+ -- itearte through slaves
+ for idx=1,nslaves do
+ local c = p.clients[idx+nmaster]
+ local g = {
+ x = area.x + master_area_width + (idx-1)*(slave_area_width/nslaves),
+ y = area.y,
+ width = slave_area_width/nslaves,
+ height = area.height,
+ }
+ p.geometries[c] = g
+ end
+end
+
+local icon_raw = gears.filesystem.get_configuration_dir() .. tostring(...):match("^.*bling"):gsub("%.", "/") .. "/icons/layouts/vertical.png"
+
+local function get_icon()
+ if icon_raw ~= nil then
+ return gcolor.recolor_image(icon_raw, beautiful.fg_normal)
+ else
+ return nil
+ end
+end
+
+return {
+ layout = mylayout,
+ icon_raw = icon_raw,
+ get_icon = get_icon,
+}
diff --git a/awesome/bling/module/flash_focus.lua b/awesome/bling/module/flash_focus.lua
new file mode 100644
index 0000000..7c6ae2f
--- /dev/null
+++ b/awesome/bling/module/flash_focus.lua
@@ -0,0 +1,36 @@
+local gears = require("gears")
+local beautiful = require("beautiful")
+
+local op = beautiful.flash_focus_start_opacity or 0.6
+local stp = beautiful.flash_focus_step or 0.01
+
+local flashfocus = function(c)
+ if c then
+ c.opacity = op
+ local q = op
+ local g = gears.timer {
+ timeout = stp,
+ call_now = false,
+ autostart = true
+ }
+
+ g:connect_signal("timeout", function()
+ if not c.valid then return end
+ if q >= 1 then
+ c.opacity = 1
+ g:stop()
+ else
+ c.opacity = q
+ q = q + stp
+ end
+ end)
+ end
+
+ -- Bring the focused client to the top
+ if c then c:raise() end
+end
+
+local enable = function() client.connect_signal("focus", flashfocus) end
+local disable = function() client.disconnect_signal("focus", flashfocus) end
+
+return {enable = enable, disable = disable, flashfocus = flashfocus}
diff --git a/awesome/bling/module/init.lua b/awesome/bling/module/init.lua
new file mode 100644
index 0000000..953e24a
--- /dev/null
+++ b/awesome/bling/module/init.lua
@@ -0,0 +1,7 @@
+return {
+ window_swallowing = require(... .. ".window_swallowing"),
+ tiled_wallpaper = require(... .. ".tiled_wallpaper"),
+ wallpaper = require(... .. ".wallpaper"),
+ flash_focus = require(... .. ".flash_focus"),
+ tabbed = require(... .. ".tabbed")
+}
diff --git a/awesome/bling/module/tabbed.lua b/awesome/bling/module/tabbed.lua
new file mode 100644
index 0000000..b4e66a6
--- /dev/null
+++ b/awesome/bling/module/tabbed.lua
@@ -0,0 +1,202 @@
+--[[
+
+This module currently works by adding a new property to each client that is tabbed.
+That new property is called bling_tabbed.
+So each client in a tabbed state has the property "bling_tabbed" which is a table.
+Each client that is not tabbed doesn't have that property.
+In the function themselves, the same object is refered to as "tabobj" which is why
+you will often see something like: "local tabobj = some_client.bling_tabbed" at the beginning
+of a function.
+
+--]]
+
+local awful = require("awful")
+local wibox = require("wibox")
+local gears = require("gears")
+local beautiful = require("beautiful")
+local helpers = require(tostring(...):match(".*bling") .. ".helpers")
+
+local bar_style = beautiful.tabbar_style or "default"
+local bar = require(tostring(...):match(".*bling") .. ".widget.tabbar." ..
+ bar_style)
+
+local function copy_size(c, parent_client)
+ if not c or not parent_client then return end
+ if not c.valid or not parent_client.valid then return end
+ c.floating = parent_client.floating
+ c.x = parent_client.x
+ c.y = parent_client.y
+ c.width = parent_client.width
+ c.height = parent_client.height
+end
+
+tabbed = {}
+
+-- used to change focused tab relative to the currently focused one
+tabbed.iter = function(idx)
+ if not idx then idx = 1 end
+ if not client.focus or not client.focus.bling_tabbed then return end
+ local tabobj = client.focus.bling_tabbed
+ local new_idx = (tabobj.focused_idx + idx) % #tabobj.clients
+ if new_idx == 0 then new_idx = #tabobj.clients end
+ tabbed.switch_to(tabobj, new_idx)
+end
+
+-- removes a given client from its tab object
+tabbed.remove = function(c)
+ if not c or not c.bling_tabbed then return end
+ local tabobj = c.bling_tabbed
+ table.remove(tabobj.clients, tabobj.focused_idx)
+ awful.titlebar.hide(c, bar.position)
+ c.bling_tabbed = nil
+ tabbed.switch_to(tabobj, 1)
+end
+
+-- removes the currently focused client from the tab object
+tabbed.pop = function()
+ if not client.focus or not client.focus.bling_tabbed then return end
+ tabbed.remove(client.focus)
+end
+
+-- adds a client to a given tabobj
+tabbed.add = function(c, tabobj)
+ if c.bling_tabbed then return end
+ copy_size(c, tabobj.clients[tabobj.focused_idx])
+ tabobj.clients[#tabobj.clients + 1] = c
+ tabobj.focused_idx = #tabobj.clients
+ -- calls update even though switch_to calls update again
+ -- but the new client needs to have the tabobj property
+ -- before a clean switch can happen
+ tabbed.update(tabobj)
+ tabbed.switch_to(tabobj, #tabobj.clients)
+end
+
+-- use xprop to select one client and make it tab in the currently focused tab
+tabbed.pick = function()
+ if not client.focus then return end
+ if not client.focus.bling_tabbed then tabbed.init(client.focus) end
+ local tabobj = client.focus.bling_tabbed
+ -- this function uses xprop to grab a client pid which is then
+ -- compared to all other client process ids
+
+ local xprop_cmd = [[ xprop _NET_WM_PID | cut -d' ' -f3 ]]
+ awful.spawn.easy_async_with_shell(xprop_cmd, function(output)
+ for _, c in ipairs(client.get()) do
+ if tonumber(c.pid) == tonumber(output) then
+ tabbed.add(c, tabobj)
+ end
+ end
+ end)
+end
+
+-- use dmenu to select a client and make it tab in the currently focused tab
+tabbed.pick_with_dmenu = function(dmenu_command)
+ if not client.focus then return end
+ if not client.focus.bling_tabbed then tabbed.init(client.focus) end
+ local tabobj = client.focus.bling_tabbed
+
+ if not dmenu_command then dmenu_command = "rofi -dmenu -i" end
+
+ -- get all clients from the current tag
+ -- ignores the case where multiple tags are selected
+ local t = awful.screen.focused().selected_tag
+ local list_clients = {}
+ local list_clients_string = ""
+ for idx, c in ipairs(t:clients()) do
+ if not c.bling_tabbed then
+ list_clients[#list_clients + 1] = c
+ if #list_clients ~= 1 then
+ list_clients_string = list_clients_string .. "\\n"
+ end
+ list_clients_string = list_clients_string .. tostring(c.window) .. " " .. c.name
+ end
+ end
+
+ if #list_clients == 0 then return end
+
+ -- calls the actual dmenu
+ local xprop_cmd = [[ echo -e "]] .. list_clients_string .. [[" | ]] .. dmenu_command .. [[ | awk '{ print $1 }' ]]
+ awful.spawn.easy_async_with_shell(xprop_cmd, function(output)
+ for _, c in ipairs(list_clients) do
+ if tonumber(c.window) == tonumber(output) then
+ tabbed.add(c, tabobj)
+ end
+ end
+ end)
+end
+
+-- update everything about one tab object
+tabbed.update = function(tabobj)
+ local currently_focused_c = tabobj.clients[tabobj.focused_idx]
+ -- update tabobj of each client and other things
+ for idx, c in ipairs(tabobj.clients) do
+ if c.valid then
+ c.bling_tabbed = tabobj
+ copy_size(c, currently_focused_c)
+ -- the following handles killing a client while the client is tabbed
+ c:connect_signal("unmanage", function(c) tabbed.remove(c) end)
+ end
+ end
+
+ tabbed.update_tabbar(tabobj)
+end
+
+-- change docused tab by absolute index
+tabbed.switch_to = function(tabobj, new_idx)
+ local old_focused_c = tabobj.clients[tabobj.focused_idx]
+ tabobj.focused_idx = new_idx
+ for idx, c in ipairs(tabobj.clients) do
+ if idx ~= new_idx then
+ helpers.client.turn_off(c)
+ else
+ helpers.client.turn_on(c)
+ c:raise()
+ if old_focused_c and old_focused_c.valid then
+ c:swap(old_focused_c)
+ end
+ copy_size(c, old_focused_c)
+ end
+ end
+ tabbed.update(tabobj)
+end
+
+tabbed.update_tabbar = function(tabobj)
+ local flexlist = bar.layout()
+ -- itearte over all tabbed clients to create the widget tabbed list
+ for idx, c in ipairs(tabobj.clients) do
+ local buttons = gears.table.join(
+ awful.button({}, 1, function()
+ tabbed.switch_to(tabobj, idx)
+ end))
+ wid_temp = bar.create(c, (idx == tabobj.focused_idx), buttons)
+ flexlist:add(wid_temp)
+ end
+ -- add tabbar to each tabbed client (clients will be hided anyway)
+ for _, c in ipairs(tabobj.clients) do
+ local titlebar = awful.titlebar(c, {
+ bg = bar.bg_normal,
+ size = bar.size,
+ position = bar.position
+ })
+ titlebar:setup{layout = wibox.layout.flex.horizontal, flexlist}
+ end
+end
+
+tabbed.init = function(c)
+ local tabobj = {}
+ tabobj.clients = {c}
+ tabobj.focused_idx = 1
+ tabbed.update(tabobj)
+end
+
+if beautiful.tabbed_spawn_in_tab then
+ client.connect_signal("manage", function(c)
+ local s = awful.screen.focused()
+ local previous_client = awful.client.focus.history.get(s, 1)
+ if previous_client and previous_client.bling_tabbed then
+ tabbed.add(c, previous_client.bling_tabbed)
+ end
+ end)
+end
+
+return tabbed
diff --git a/awesome/bling/module/tiled_wallpaper.lua b/awesome/bling/module/tiled_wallpaper.lua
new file mode 100644
index 0000000..9594fe6
--- /dev/null
+++ b/awesome/bling/module/tiled_wallpaper.lua
@@ -0,0 +1,58 @@
+--[[
+ This module makes use of cairo surfaces
+ For documentation take a look at the C docs:
+ https://www.cairographics.org/
+ They can be applied to lua by changing the naming conventions
+ and adjusting for the missing namespaces (and classes)
+ for example:
+ cairo_rectangle(cr, 1, 1, 1, 1) in C would be written as
+ cr:rectangle(1, 1, 1, 1) in lua
+ and
+ cairo_fill(cr) in C would be written as
+ cr:fill() in lua
+--]]
+
+local cairo = require("lgi").cairo
+local gears = require("gears")
+
+function create_tiled_wallpaper(str, s, args_table)
+
+ -- user input
+ args_table = args_table or {}
+ local fg = args_table.fg or "#ff0000"
+ local bg = args_table.bg or "#00ffff"
+ local offset_x = args_table.offset_x
+ local offset_y = args_table.offset_y
+ local font = args_table.font or "Hack"
+ local font_size = tonumber(args_table.font_size) or 16
+ local zickzack_bool = args_table.zickzack or false
+ local padding = args_table.padding or 100
+
+ -- create cairo image wallpaper
+ local img = cairo.ImageSurface(cairo.Format.RGB24, padding, padding)
+ cr = cairo.Context(img)
+
+ cr:set_source(gears.color(bg))
+ cr:paint()
+
+ cr:set_source(gears.color(fg))
+
+ cr:set_font_size(font_size)
+ cr:select_font_face(font)
+
+ if zickzack_bool then
+ cr:set_source(gears.color(fg))
+ cr:move_to(padding/2 + font_size, padding/2 + font_size)
+ cr:show_text(str)
+ end
+
+ cr:set_source(gears.color(fg))
+ cr:move_to(font_size, font_size)
+ cr:show_text(str)
+
+ -- tile cairo image
+ gears.wallpaper.tiled(img, s, {x=offset_x, y=offset_y})
+end
+
+return create_tiled_wallpaper
+
diff --git a/awesome/bling/module/wallpaper.lua b/awesome/bling/module/wallpaper.lua
new file mode 100644
index 0000000..69a8147
--- /dev/null
+++ b/awesome/bling/module/wallpaper.lua
@@ -0,0 +1,293 @@
+---------------------------------------------------------------------------
+-- High-level declarative function for setting your wallpaper.
+--
+--
+-- An easy way to setup a complex wallpaper with slideshow, random, schedule, extensibility.
+--
+-- @usage
+-- local wallpaper = require("wallpaper")
+-- -- A silly example
+-- wallpaper.setup { -- I want a wallpaper
+-- change_timer = 500, -- changing every 5 minutes
+-- set_function = wallpaper.setters.random, -- in a random way
+-- wallpaper = {"#abcdef",
+-- "~/Pictures",
+-- wallpaper.setters.awesome}, -- from this list (a color, a directory with pictures and the Awesome wallpaper)
+-- recursive = false, -- do not read subfolders of "~/Pictures"
+-- position = "centered", -- center it on the screen (for pictures)
+-- scale = 2, -- 2 time bigger (for pictures)
+-- }
+--
+-- @author Grumph
+-- @copyright 2021 Grumph
+--
+---------------------------------------------------------------------------
+
+
+local beautiful = require("beautiful")
+local gears = require("gears")
+local helpers = require(tostring(...):match(".*bling") .. ".helpers")
+
+local setters = {}
+
+--- Apply a wallpaper.
+--
+-- This function is a helper that will apply a wallpaper_object,
+-- either using gears.wallpaper.set or gears.wallpaper.* higher level functions when applicable.
+-- @param wallpaper_object A wallpaper object, either
+-- a `pattern` (see `gears.wallpaper.set`)
+-- a `surf` (see `gears.wallpaper.centered`)
+-- a function that actually sets the wallpaper.
+-- @tparam table args The argument table containing any of the arguments below.
+-- @int[opt=nil] args.screen The screen to use (as used in `gears.wallpaper` functions)
+-- @string[opt=nil or "centered"] args.position The `gears.wallpaper` position function to use.
+-- Must be set when wallpaper is a file.
+-- It can be `"centered"`, `"fit"`, `"tiled"` or `"maximized"`.
+-- @string[opt=beautiful.bg_normal or "black"] args.background See `gears.wallpaper`.
+-- @bool[opt=false] args.ignore_aspect See `gears.wallpaper`.
+-- @tparam[opt={x=0,y=0}] table args.offset See `gears.wallpaper`.
+-- @int[opt=1] args.scale See `gears.wallpaper`.
+function apply(wallpaper_object, args)
+ args.background = args.background or beautiful.bg_normal or "black"
+ args.ignore_aspect = args.ignore_aspect or false -- false = keep aspect ratio
+ args.offset = args.offset or {x = 0, y = 0}
+ args.scale = args.scale or 1
+ local positions = {
+ ["centered"] = function() gears.wallpaper.centered(wallpaper_object, args.screen, args.background, args.scale) end,
+ ["tiled"] = function() gears.wallpaper.tiled(wallpaper_object, args.screen, args.offset) end,
+ ["maximized"] = function() gears.wallpaper.maximized(wallpaper_object, args.screen, args.ignore_aspect, args.offset) end,
+ ["fit"] = function() gears.wallpaper.fit(wallpaper_object, args.screen, args.background) end,
+ }
+ if type(wallpaper_object) == "string" and gears.filesystem.file_readable(wallpaper_object) then
+ -- path of an image file, we use a position function
+ local p = args.position or "centered"
+ positions[p]()
+ elseif type(wallpaper_object) == "function" then
+ -- function
+ wallpaper_object(args)
+ elseif (not gears.color.ensure_pango_color(wallpaper_object, nil)) and args.position then
+ -- if the user sets a position function, wallpaper_object should be a cairo surface
+ positions[args.position]()
+ else
+ gears.wallpaper.set(wallpaper_object)
+ end
+end
+
+--- Converts `args.wallpaper` to a list of `wallpaper_objects` readable by `apply` function).
+--
+-- @tparam table args The argument table containing the argument below.
+-- @param[opt=`beautiful.wallpaper_path` or `"black"`] args.wallpaper A wallpaper object.
+-- It can be a color or a cairo pattern (what `gears.wallpaper.set` understands),
+-- a cairo suface (set with gears.wallpaper.set if `args.position` is nil, or with
+-- `gears.wallpaper` position functions, see `args.position`),
+-- a function similar to args.set_function that will effectively set a wallpaper (usually
+-- with `gears.wallpaper` functions),
+-- a path to a file,
+-- path to a directory containing images,
+-- or a list with any of the previous choices.
+-- @tparam[opt=`{"jpg", "jpeg", "png", "bmp"}`] table args.image_formats A list of
+-- file extensions to filter when `args.wallpaper` is a directory.
+-- @bool[opt=true] args.recursive Either to recurse or not when `args.wallpaper` is a directory.
+-- @treturn table A list of `wallpaper_objects` (what `apply` can read).
+-- @see apply
+function prepare_list(args)
+ args.image_formats = args.image_formats or {"jpg", "jpeg", "png", "bmp"}
+ args.recursive = args.recursive or true
+
+ local wallpapers = (args.wallpaper
+ or beautiful.wallpaper_path
+ or "black")
+ local res = {}
+ if type(wallpapers) ~= "table" then
+ wallpapers = {wallpapers}
+ end
+ for _, w in ipairs(wallpapers) do
+ -- w is either:
+ -- - a directory path (string)
+ -- - an image path or a color (string)
+ -- - a cairo surface or a cairo pattern
+ -- - a function for setting the wallpaper
+ if type(w) == "string" and gears.filesystem.dir_readable(w) then
+ local file_list = helpers.filesystem.list_directory_files(w, args.image_formats, args.recursive)
+ for _, f in ipairs(file_list) do
+ res[#res + 1] = w .. "/" .. f
+ end
+ else
+ res[#res + 1] = w
+ end
+ end
+ return res
+end
+
+local simple_index = 0
+--- Set the next wallpaper in a list.
+--
+-- @tparam table args See `prepare_list` and `apply` arguments
+-- @see apply
+-- @see prepare_list
+function setters.simple(args)
+ local wallpapers = prepare_list(args)
+ simple_index = (simple_index % #wallpapers) + 1
+ apply(wallpapers[simple_index], args)
+end
+
+--- Set a random wallpaper from a list.
+--
+-- @tparam table args See `prepare_list` and `apply` arguments
+-- @see apply
+-- @see prepare_list
+function setters.random(args)
+ local wallpapers = prepare_list(args)
+ apply(wallpapers[math.random(#wallpapers)], args)
+end
+
+
+local simple_schedule_object = nil
+--- A schedule setter.
+--
+-- This simple schedule setter was freely inspired by [dynamic-wallpaper](https://github.com/manilarome/awesome-glorious-widgets/blob/master/dynamic-wallpaper/init.lua).
+-- @tparam table args The argument table containing any of the arguments below.
+-- @tparam table args.wallpaper The schedule table, with the form
+-- {
+-- ["HH:MM:SS"] = wallpaper,
+-- ["HH:MM:SS"] = wallpaper2,
+-- }
+-- The wallpapers definition can be anything the `schedule_set_function` can read
+-- (what you would place in `args.wallpaper` for this function),
+-- @tparam[opt=`setters.simple`] function args.wallpaper_set_function The set_function used by default
+function setters.simple_schedule(args)
+ local function update_wallpaper()
+ local fake_args = gears.table.join(args, {wallpaper = args.wallpaper[simple_schedule_object.closest_lower_time]})
+ simple_schedule_object.schedule_set_function(fake_args)
+ end
+ if not simple_schedule_object then
+ simple_schedule_object = {}
+ -- initialize the schedule object, so we don't do it for every call
+ simple_schedule_object.schedule_set_function = args.schedule_set_function or setters.simple
+ -- we get the sorted time keys
+ simple_schedule_object.times = {}
+ for k in pairs(args.wallpaper) do table.insert(simple_schedule_object.times, k) end
+ table.sort(simple_schedule_object.times)
+ -- now we get the closest time which is below current time (the current applicable period)
+ local function update_timer()
+ local current_time = os.date("%H:%M:%S")
+ local next_time = simple_schedule_object.times[1]
+ simple_schedule_object.closest_lower_time = simple_schedule_object.times[#(simple_schedule_object.times)]
+ for _, k in ipairs(simple_schedule_object.times) do
+ if k > current_time then
+ next_time = k
+ break
+ end
+ simple_schedule_object.closest_lower_time = k
+ end
+ simple_schedule_object.timer.timeout = helpers.time.time_diff(next_time, current_time)
+ if simple_schedule_object.timer.timeout < 0 then
+ -- the next_time is the day after, so we add 24 hours to the timer
+ simple_schedule_object.timer.timeout = simple_schedule_object.timer.timeout + 86400
+ end
+ simple_schedule_object.timer:again()
+ update_wallpaper()
+ end
+ simple_schedule_object.timer = gears.timer {
+ callback = update_timer,
+ }
+ update_timer()
+ else
+ -- if called again (usually when the change_timer is set), we just change the wallpaper depending on current parameters
+ update_wallpaper()
+ end
+end
+
+
+
+
+
+--- Set the AWESOME wallpaper.
+--
+-- @tparam table args The argument table containing the argument below.
+-- @param[opt=`beautiful.bg_normal`] args.colors.bg The bg color.
+-- If the default is used, the color is darkened if `beautiful.bg_normal` is light
+-- or lightned if `beautiful.bg_normal` is dark.
+-- @param[opt=`beautiful.fg_normal`] args.colors.fg The fg color.
+-- @param[opt=`beautiful.fg_focus`] args.colors.alt_fg The alt_fg color.
+--
+-- see beautiful.theme_assets.wallpaper
+function setters.awesome_wallpaper(args)
+ local colors = {bg = beautiful.bg_normal, fg = beautiful.fg_normal, alt_fg = beautiful.bg_focus }
+ colors.bg = helpers.color.is_dark(beautiful.bg_normal)
+ and helpers.color.lighten(colors.bg)
+ or helpers.color.darken(colors.bg)
+ if (type(args.colors) == "table") then
+ colors.bg = args.colors.bg or colors.bg
+ colors.fg = args.colors.fg or colors.fg
+ colors.alt_fg = args.colors.alt_fg or colors.alt_fg
+ end
+ -- Generate wallpaper:
+ if not args.screen then
+ for s in screen do
+ gears.wallpaper.set(
+ beautiful.theme_assets.wallpaper(colors.bg, colors.fg, colors.alt_fg, s)
+ )
+ end
+ else
+ gears.wallpaper.set(
+ beautiful.theme_assets.wallpaper(colors.bg, colors.fg, colors.alt_fg, args.screen)
+ )
+ end
+end
+
+
+
+--- Setup a wallpaper.
+--
+-- @tparam table args Parameters for the wallpaper. It may also contain all parameters your `args.set_function` needs
+-- @int[opt=nil] args.screen The screen to use (as used in `gears.wallpaper` functions)
+-- @int[opt=nil] args.change_timer Time in seconds for wallpaper changes
+-- @tparam[opt=`setters.awesome` or `setters.simple`] function args.set_function A function to set the wallpaper
+-- It takes args as parameter (the same args as the setup function).
+-- This function is called at `"request::wallpaper"` `screen` signals and at `args.change_timer` timeouts.
+-- There is no obligation, but for consistency, the function should use `args.wallpaper` as a feeder.
+-- If `args.wallpaper` is defined, the default function is `setters.simple`, else it will be `setters.awesome`.
+--
+-- @usage
+-- local wallpaper = require("wallpaper")
+-- wallpaper.setup {
+-- change_timer = 631, -- Prime number is better
+-- set_function = wallpaper.setters.random,
+-- -- parameters for the random setter
+-- wallpaper = '/data/pictures/wallpapers',
+-- position = "maximized",
+-- }
+--
+-- @see apply
+-- @see prepare_list
+-- @see setters.simple
+function setup(args)
+ local config = args or {}
+ config.set_function = config.set_function or (config.wallpaper and setters.simple or setters.awesome_wallpaper)
+ local function set_wallpaper(s)
+ config.screen = s or config.screen
+ config.set_function(config)
+ end
+
+ if config.change_timer and config.change_timer > 0 then
+ gears.timer {
+ timeout = config.change_timer,
+ call_now = false,
+ autostart = true,
+ callback = function() set_wallpaper() end
+ }
+ end
+
+ screen.connect_signal("request::wallpaper", set_wallpaper)
+end
+
+
+
+
+return {
+ setup = setup,
+ setters = setters,
+ apply = apply,
+ prepare_list = prepare_list,
+}
diff --git a/awesome/bling/module/window_swallowing.lua b/awesome/bling/module/window_swallowing.lua
new file mode 100644
index 0000000..1e4f3f7
--- /dev/null
+++ b/awesome/bling/module/window_swallowing.lua
@@ -0,0 +1,97 @@
+local awful = require("awful")
+local gears = require("gears")
+local beautiful = require("beautiful")
+
+local helpers = require(tostring(...):match(".*bling") .. ".helpers")
+
+-- It might actually swallow too much, that's why there is a filter option by classname
+-- without the don't-swallow-list it would also swallow for example
+-- file pickers or new firefox windows spawned by an already existing one
+
+local window_swallowing_activated = false
+
+-- you might want to add or remove applications here
+local dont_swallow_classname_list = beautiful.dont_swallow_classname_list or {"firefox", "Gimp", "Google-chrome"}
+local activate_dont_swallow_filter = beautiful.dont_swallow_filter_activated or true
+
+-- makes c the same size and position as parent_client
+local function copy_size(c, parent_client)
+ if not c or not parent_client then
+ return
+ end
+ if not c.valid or not parent_client.valid then
+ return
+ end
+ c.floating = parent_client.floating
+ c.x = parent_client.x;
+ c.y = parent_client.y;
+ c.width = parent_client.width;
+ c.height = parent_client.height;
+ -- TODO that function should also support "copying" the
+ -- index of the parent_client to the new c
+end
+
+-- checks if client classname matches with any entry of the dont-swallow-list
+local function check_if_swallow(c)
+ if not activate_dont_swallow_filter then
+ return true
+ end
+ for _, classname in ipairs(dont_swallow_classname_list) do
+ if classname == c.class then
+ return false
+ end
+ end
+ return true
+end
+
+-- the function that will be connected to / disconnected from the spawn client signal
+local function manage_clientspawn(c)
+ -- get the last focused window to check if it is a parent window
+ local parent_client=awful.client.focus.history.get(c.screen, 1)
+ if not parent_client then return end
+
+ -- io.popen is normally discouraged. Should probably be changed
+ local handle = io.popen([[pstree -T -p -a -s ]] .. tostring(c.pid) .. [[ | sed '2q;d' | grep -o '[0-9]*$' | tr -d '\n']])
+ local parent_pid = handle:read("*a")
+ handle:close()
+
+ if (tostring(parent_pid) == tostring(parent_client.pid)) and check_if_swallow(c) then
+
+ c:connect_signal("unmanage", function()
+ helpers.client.turn_on(parent_client)
+ copy_size(parent_client, c)
+ end)
+
+ copy_size(c, parent_client)
+ helpers.client.turn_off(parent_client)
+
+ end
+end
+
+-- without the following functions that module would be autoloaded by require("bling")
+-- a toggle window swallowing hotkey is also possible that way
+
+local function start()
+ client.connect_signal("manage", manage_clientspawn)
+ window_swallowing_activated = true
+end
+
+local function stop()
+ client.disconnect_signal("manage", manage_clientspawn)
+ window_swallowing_activated = false
+end
+
+local function toggle()
+ if window_swallowing_activated then
+ stop()
+ else
+ start()
+ end
+end
+
+return {
+ start = start,
+ stop = stop,
+ toggle = toggle
+}
+
diff --git a/awesome/bling/signal/init.lua b/awesome/bling/signal/init.lua
new file mode 100644
index 0000000..a4a2ad7
--- /dev/null
+++ b/awesome/bling/signal/init.lua
@@ -0,0 +1 @@
+return {playerctl = require(... .. ".playerctl")}
diff --git a/awesome/bling/signal/playerctl.lua b/awesome/bling/signal/playerctl.lua
new file mode 100644
index 0000000..21c6212
--- /dev/null
+++ b/awesome/bling/signal/playerctl.lua
@@ -0,0 +1,120 @@
+--
+-- Provides:
+-- bling::playerctl::status
+-- playing (boolean)
+-- bling::playerctl::title_artist_album
+-- title (string)
+-- artist (string)
+-- album_path (string)
+-- bling::playerctl::position
+-- interval_sec (number)
+-- length_sec (number)
+-- bling::playerctl::player_stopped
+--
+local awful = require("awful")
+local beautiful = require("beautiful")
+
+local interval = beautiful.playerctl_position_update_interval or 1
+
+local function emit_player_status()
+ local status_cmd = "playerctl status -F"
+
+ -- Follow status
+ awful.spawn.easy_async({
+ "pkill", "--full", "--uid", os.getenv("USER"), "^playerctl status"
+ }, function()
+ awful.spawn.with_line_callback(status_cmd, {
+ stdout = function(line)
+ local playing = false
+ if line:find("Playing") then
+ playing = true
+ else
+ playing = false
+ end
+ awesome.emit_signal("bling::playerctl::status", playing)
+ end
+ })
+ end)
+end
+
+local function emit_player_info()
+ local art_script = [[
+sh -c '
+
+tmp_dir="$XDG_CACHE_HOME/awesome/"
+
+if [ -z ${XDG_CACHE_HOME} ]; then
+ tmp_dir="$HOME/.cache/awesome/"
+fi
+
+tmp_cover_path=${tmp_dir}"cover.png"
+
+if [ ! -d $tmp_dir ]; then
+ mkdir -p $tmp_dir
+fi
+
+link="$(playerctl metadata mpris:artUrl)"
+
+curl -s "$link" --output $tmp_cover_path
+
+echo "$tmp_cover_path"
+']]
+
+ -- Command that lists artist and title in a format to find and follow
+ local song_follow_cmd =
+ "playerctl metadata --format 'artist_{{artist}}title_{{title}}' -F"
+
+ -- Progress Cmds
+ local prog_cmd = "playerctl position"
+ local length_cmd = "playerctl metadata mpris:length"
+
+ awful.widget.watch(prog_cmd, interval, function(_, interval)
+ awful.spawn.easy_async_with_shell(length_cmd, function(length)
+ local length_sec = tonumber(length) -- in microseconds
+ local interval_sec = tonumber(interval) -- in seconds
+ if length_sec and interval_sec then
+ if interval_sec >= 0 and length_sec > 0 then
+ awesome.emit_signal("bling::playerctl::position",
+ interval_sec, length_sec / 1000000)
+ end
+ end
+ end)
+ end)
+
+ -- Follow title
+ awful.spawn.easy_async({
+ "pkill", "--full", "--uid", os.getenv("USER"), "^playerctl metadata"
+ }, function()
+ awful.spawn.with_line_callback(song_follow_cmd, {
+ stdout = function(line)
+ local album_path = ""
+ awful.spawn.easy_async_with_shell(art_script, function(out)
+ -- Get album path
+ album_path = out:gsub('%\n', '')
+ -- Get title and artist
+ local artist = line:match('artist_(.*)title_')
+ local title = line:match('title_(.*)')
+ -- If the title is nil or empty then the players stopped
+ if title and title ~= "" then
+ awesome.emit_signal(
+ "bling::playerctl::title_artist_album", title,
+ artist, album_path)
+ else
+ awesome.emit_signal("bling::playerctl::player_stopped")
+ end
+ end)
+ end
+ })
+ end)
+end
+
+-- Emit info
+-- emit_player_status()
+-- emit_player_info()
+
+local enable = function()
+ emit_player_status()
+ emit_player_info()
+end
+
+return {enable = enable}
diff --git a/awesome/bling/theme-var-template.lua b/awesome/bling/theme-var-template.lua
new file mode 100644
index 0000000..ff1084d
--- /dev/null
+++ b/awesome/bling/theme-var-template.lua
@@ -0,0 +1,55 @@
+--[[ Bling theme variables template
+
+This file has all theme variables of the bling module.
+Every variable has a small comment on what it does.
+You might just want to copy that whole part into your theme.lua and start adjusting from there.
+
+--]]
+
+
+-- window swallowing
+theme.dont_swallow_classname_list = {"firefox", "Gimp"} -- list of class names that should not be swallowed
+theme.dont_swallow_filter_activated = true -- whether the filter above should be active
+
+-- flash focus
+theme.flash_focus_start_opacity = 0.6 -- the starting opacity
+theme.flash_focus_step = 0.01 -- the step of animation
+
+-- playerctl signal
+theme.playerctl_position_update_interval = 1 -- the update interval for fetching the position from playerctl
+
+-- tabbed
+theme.tabbed_spawn_in_tab = false -- whether a new client should spawn into the focused tabbing container
+
+-- tabbar general
+theme.tabbar_ontop = false
+theme.tabbar_radius = 0 -- border radius of the tabbar
+theme.tabbar_style = "default" -- style of the tabbar ("default", "boxes" or "modern")
+theme.tabbar_font = "Sans 11" -- font of the tabbar
+theme.tabbar_size = 40 -- size of the tabbar
+theme.tabbar_position = "top" -- position of the tabbar
+theme.tabbar_bg_normal = "#000000" -- background color of the focused client on the tabbar
+theme.tabbar_fg_normal = "#ffffff" -- foreground color of the focused client on the tabbar
+theme.tabbar_bg_focus = "#1A2026" -- background color of unfocused clients on the tabbar
+theme.tabbar_fg_focus = "#ff0000" -- foreground color of unfocused clients on the tabbar
+
+-- mstab
+theme.mstab_bar_ontop = false -- whether you want to allow the bar to be ontop of clients
+theme.mstab_dont_resize_slaves = false -- whether the tabbed stack windows should be smaller than the
+ -- currently focused stack window (set it to true if you use
+ -- transparent terminals. False if you use shadows on solid ones
+theme.mstab_bar_padding = "default" -- how much padding there should be between clients and your tabbar
+ -- by default it will adjust based on your useless gaps.
+ -- If you want a custom value. Set it to the number of pixels (int)
+theme.mstab_border_radius = 0 -- border radius of the tabbar
+theme.mstab_bar_height = 40 -- height of the tabbar
+theme.mstab_tabbar_position = "top" -- position of the tabbar (mstab currently does not support left,right)
+theme.mstab_tabbar_style = "default" -- style of the tabbar ("default", "boxes" or "modern")
+ -- defaults to the tabbar_style so only change if you want a
+ -- different style for mstab and tabbed
+
+-- the following variables are currently only for the "modern" tabbar style
+theme.tabbar_color_close = "#f9929b" -- chnges the color of the close button
+theme.tabbar_color_min = "#fbdf90" -- chnges the color of the minimize button
+theme.tabbar_color_float = "#ccaced" -- chnges the color of the float button
+
diff --git a/awesome/bling/widget/tabbar/boxes.lua b/awesome/bling/widget/tabbar/boxes.lua
new file mode 100644
index 0000000..8491dc8
--- /dev/null
+++ b/awesome/bling/widget/tabbar/boxes.lua
@@ -0,0 +1,54 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+
+local beautiful = require("beautiful")
+
+local bg_normal = beautiful.tabbar_bg_normal or beautiful.bg_normal or "#ffffff"
+local fg_normal = beautiful.tabbar_fg_normal or beautiful.fg_normal or "#000000"
+local bg_focus = beautiful.tabbar_bg_focus or beautiful.bg_focus or "#000000"
+local fg_focus = beautiful.tabbar_fg_focus or beautiful.fg_focus or "#ffffff"
+local font = beautiful.tabbar_font or beautiful.font or "Hack 15"
+local size = beautiful.tabbar_size or 40
+local position = beautiful.tabbar_position or "bottom"
+
+local function create(c, focused_bool, buttons)
+ local bg_temp = bg_normal
+ local fg_temp = fg_normal
+ if focused_bool then
+ bg_temp = bg_focus
+ fg_temp = fg_focus
+ end
+ local wid_temp = wibox.widget({
+ {
+ {
+ awful.widget.clienticon(c),
+ left = 10,
+ right = 10,
+ bottom= 10,
+ top= 10,
+ widget = wibox.container.margin()
+ },
+ widget = wibox.container.place()
+ },
+ buttons = buttons,
+ bg = bg_temp,
+ widget = wibox.container.background()
+ })
+ return wid_temp
+end
+
+local layout = wibox.layout.fixed.horizontal
+if position == "left" or position == "right" then
+ layout = wibox.layout.fixed.vertical
+end
+
+return {
+ layout = layout,
+ create = create,
+ position = position,
+ size = size,
+ bg_normal = bg_normal,
+ bg_focus = bg_normal
+}
+
diff --git a/awesome/bling/widget/tabbar/default.lua b/awesome/bling/widget/tabbar/default.lua
new file mode 100644
index 0000000..748cc04
--- /dev/null
+++ b/awesome/bling/widget/tabbar/default.lua
@@ -0,0 +1,49 @@
+local gears = require("gears")
+local wibox = require("wibox")
+
+local beautiful = require("beautiful")
+
+local bg_normal = beautiful.tabbar_bg_normal or beautiful.bg_normal or "#ffffff"
+local fg_normal = beautiful.tabbar_fg_normal or beautiful.fg_normal or "#000000"
+local bg_focus = beautiful.tabbar_bg_focus or beautiful.bg_focus or "#000000"
+local fg_focus = beautiful.tabbar_fg_focus or beautiful.fg_focus or "#ffffff"
+local font = beautiful.tabbar_font or beautiful.font or "Hack 15"
+local size = beautiful.tabbar_size or 20
+local position = beautiful.tabbar_position or "top"
+
+local function create(c, focused_bool, buttons)
+ local flexlist = wibox.layout.flex.horizontal()
+ local title_temp = c.name or c.class or "-"
+ local bg_temp = bg_normal
+ local fg_temp = fg_normal
+ if focused_bool then
+ bg_temp = bg_focus
+ fg_temp = fg_focus
+ end
+ local text_temp = wibox.widget.textbox()
+ text_temp.align = "center"
+ text_temp.valign = "center"
+ text_temp.font = font
+ text_temp.markup = "<span foreground='" .. fg_temp .. "'>" .. title_temp.. "</span>"
+ c:connect_signal("property::name", function(_)
+ local title_temp = c.name or c.class or "-"
+ text_temp.markup = "<span foreground='" .. fg_temp .. "'>" .. title_temp.. "</span>"
+ end)
+ local wid_temp = wibox.widget({
+ text_temp,
+ buttons = buttons,
+ bg = bg_temp,
+ widget = wibox.container.background()
+ })
+ return wid_temp
+end
+
+
+return {
+ layout = wibox.layout.flex.horizontal,
+ create = create,
+ position = "top",
+ size = size,
+ bg_normal = bg_normal,
+ bg_focus = bg_focus
+}
diff --git a/awesome/bling/widget/tabbar/modern.lua b/awesome/bling/widget/tabbar/modern.lua
new file mode 100644
index 0000000..4eb934a
--- /dev/null
+++ b/awesome/bling/widget/tabbar/modern.lua
@@ -0,0 +1,198 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+local helpers = require(tostring(...):match(".*bling") .. ".helpers")
+
+local bg_normal = beautiful.tabbar_bg_normal or beautiful.bg_normal or "#ffffff"
+local fg_normal = beautiful.tabbar_fg_normal or beautiful.fg_normal or "#000000"
+local bg_focus = beautiful.tabbar_bg_focus or beautiful.bg_focus or "#000000"
+local fg_focus = beautiful.tabbar_fg_focus or beautiful.fg_focus or "#ffffff"
+local font = beautiful.tabbar_font or beautiful.font or "Hack 15"
+local size = beautiful.tabbar_size or dpi(40)
+local border_radius =
+ beautiful.mstab_border_radius or beautiful.border_radius or 6
+local position = beautiful.tabbar_position or "top"
+local close_color = beautiful.tabbar_color_close or beautiful.xcolor1 or
+ "#f9929b"
+local min_color = beautiful.tabbar_color_min or beautiful.xcolor3 or "#fbdf90"
+local float_color = beautiful.tabbar_color_float or beautiful.xcolor5 or
+ "#ccaced"
+
+-- Helper to create buttons
+local function create_title_button(c, color_focus, color_unfocus)
+ local tb_color = wibox.widget {
+ wibox.widget.textbox(),
+ forced_width = dpi(8),
+ forced_height = dpi(8),
+ bg = color_focus,
+ shape = gears.shape.circle,
+ widget = wibox.container.background
+ }
+
+ local tb = wibox.widget {
+ tb_color,
+ width = dpi(25),
+ height = dpi(25),
+ strategy = "min",
+ layout = wibox.layout.constraint
+ }
+
+ local function update()
+ if client.focus == c then
+ tb_color.bg = color_focus
+ else
+ tb_color.bg = color_unfocus
+ end
+ end
+ update()
+ c:connect_signal("focus", update)
+ c:connect_signal("unfocus", update)
+
+ tb:connect_signal("mouse::enter",
+ function() tb_color.bg = color_focus .. "70" end)
+
+ tb:connect_signal("mouse::leave", function() tb_color.bg = color_focus end)
+
+ tb.visible = true
+ return tb
+end
+
+local function create(c, focused_bool, buttons)
+ -- local flexlist = wibox.layout.flex.horizontal()
+ local title_temp = c.name or c.class or "-"
+ local bg_temp = bg_normal
+ local fg_temp = fg_normal
+ if focused_bool then
+ bg_temp = bg_focus
+ fg_temp = fg_focus
+ end
+ local text_temp = wibox.widget.textbox()
+ text_temp.align = "center"
+ text_temp.valign = "center"
+ text_temp.font = font
+ text_temp.markup = "<span foreground='" .. fg_temp .. "'>" .. title_temp ..
+ "</span>"
+ c:connect_signal("property::name", function(_)
+ local title_temp = c.name or c.class or "-"
+ text_temp.markup =
+ "<span foreground='" .. fg_temp .. "'>" .. title_temp .. "</span>"
+ end)
+
+ local tab_content = wibox.widget {
+ {
+ awful.widget.clienticon(c),
+ top = dpi(10),
+ left = dpi(15),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+ },
+ text_temp,
+ nill,
+ expand = "none",
+ layout = wibox.layout.align.horizontal
+ }
+
+ if focused_bool then
+ tab_content = wibox.widget {
+ {
+ awful.widget.clienticon(c),
+ top = dpi(10),
+ left = dpi(15),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+ },
+ text_temp,
+ nil,
+ expand = "none",
+ layout = wibox.layout.align.horizontal
+ }
+ end
+
+ local main_content = nil
+ local left_shape = nil
+ local right_shape = nil
+
+ if position == "top" then
+ main_content = wibox.widget {
+ {
+ tab_content,
+ bg = bg_temp,
+ shape = helpers.shape.prrect(border_radius, true, true, false, false),
+ widget = wibox.container.background
+ },
+ top = dpi(8),
+ widget = wibox.container.margin
+ }
+
+ left_shape = helpers.shape.prrect(border_radius, false, false, true, false)
+ right_shape = helpers.shape.prrect(border_radius, false, false, false, true)
+ else
+ main_content = wibox.widget {
+ {
+ tab_content,
+ bg = bg_temp,
+ shape = helpers.shape.prrect(border_radius, false, false, true, true),
+ widget = wibox.container.background
+ },
+ bottom = dpi(8),
+ widget = wibox.container.margin
+ }
+
+ left_shape = helpers.shape.prrect(border_radius, false, true, false, false)
+ right_shape = helpers.shape.prrect(border_radius, true, false, false, false)
+ end
+
+ local wid_temp = wibox.widget({
+ buttons = buttons,
+ {
+ {
+ {
+ wibox.widget.textbox(),
+ bg = bg_normal,
+ shape = left_shape,
+ widget = wibox.container.background
+ },
+ bg = bg_temp,
+ shape = gears.rectangle,
+ widget = wibox.container.background
+ },
+ width = border_radius + (border_radius / 2),
+ height = size,
+ strategy = "exact",
+ layout = wibox.layout.constraint
+ },
+ main_content,
+ {
+ {
+ {
+ wibox.widget.textbox(),
+ bg = bg_normal,
+ shape = right_shape,
+ widget = wibox.container.background
+ },
+ bg = bg_temp,
+ shape = gears.rectangle,
+ widget = wibox.container.background
+ },
+ width = border_radius + (border_radius / 2),
+ height = size,
+ strategy = "exact",
+ layout = wibox.layout.constraint
+ },
+
+ layout = wibox.layout.align.horizontal
+ })
+ return wid_temp
+end
+
+return {
+ layout = wibox.layout.flex.horizontal,
+ create = create,
+ position = position,
+ size = size,
+ bg_normal = bg_normal,
+ bg_focus = bg_focus
+}
diff --git a/awesome/bloat/bar/init.lua b/awesome/bloat/bar/init.lua
new file mode 100644
index 0000000..473b4de
--- /dev/null
+++ b/awesome/bloat/bar/init.lua
@@ -0,0 +1 @@
+require("bloat.bar.wibar")
diff --git a/awesome/bloat/bar/wibar.lua b/awesome/bloat/bar/wibar.lua
new file mode 100644
index 0000000..5161125
--- /dev/null
+++ b/awesome/bloat/bar/wibar.lua
@@ -0,0 +1,483 @@
+-- wibar.lua
+-- Wibar (top bar)
+local awful = require("awful")
+local gears = require("gears")
+local gfs = require("gears.filesystem")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+local helpers = require("helpers")
+
+local systray_margin = (beautiful.wibar_height - beautiful.systray_icon_size) /
+ 2
+
+-- Helper function that changes the appearance of progress bars and their icons
+-- Create horizontal rounded bars
+local function format_progress_bar(bar)
+ bar.forced_width = dpi(100)
+ bar.shape = helpers.rrect(beautiful.border_radius - 3)
+ bar.bar_shape = helpers.rrect(beautiful.border_radius - 3)
+ bar.background_color = beautiful.xcolor0
+ return bar
+end
+
+-- Awesome Panel -----------------------------------------------------------
+
+local awesome_icon = wibox.widget {
+ {
+ {
+ widget = wibox.widget.imagebox,
+ image = gears.surface.load_uncached(
+ gfs.get_configuration_dir() .. "icons/ghosts/awesome.png"),
+ resize = true
+ },
+ margins = dpi(7),
+ widget = wibox.container.margin
+ },
+ bg = beautiful.xbackground,
+ widget = wibox.container.background
+}
+
+awesome_icon:buttons(gears.table.join(awful.button({}, 1, function()
+ awesome_icon.bg = beautiful.xcolor0
+end)))
+
+-- Notifs Panel ---------------------------------------------------------------
+
+local notifPop = require("bloat.pop.notif")
+local notif_icon = wibox.widget {
+ {
+ {
+ widget = wibox.widget.textbox,
+ font = beautiful.icon_font,
+ markup = "<span foreground='" .. beautiful.xcolor4 .. "'>" .. "" ..
+ "</span>",
+ resize = true
+ },
+ margins = dpi(4),
+ widget = wibox.container.margin
+ },
+ bg = beautiful.xbackground,
+ widget = wibox.container.background
+}
+
+-- notif_icon:connect_signal("mouse::enter", function() notifPop.visible = true end)
+-- notifPop:connect_signal("mouse::leave", function() notifPop.visible = false end)
+
+notif_icon:buttons(gears.table.join(awful.button({}, 1, function()
+ notifPop.visible = true
+ notif_icon.bg = beautiful.xcolor0
+end)))
+
+notifPop:connect_signal("mouse::leave", function()
+ notifPop.visible = false
+ notif_icon.bg = beautiful.xbackground
+end)
+
+-- Battery Bar Widget ---------------------------------------------------------
+
+local battery_bar = wibox.widget {
+ max_value = 100,
+ value = 50,
+ forced_width = dpi(200),
+ shape = helpers.rrect(beautiful.border_radius - 3),
+ bar_shape = helpers.rrect(beautiful.border_radius - 3),
+ color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {75, 20},
+ stops = {
+ {0, beautiful.xcolor9}, {0.5, beautiful.xcolor11},
+ {1, beautiful.xcolor10}
+ }
+ },
+ background_color = beautiful.xcolor0,
+ border_width = dpi(0),
+ border_color = beautiful.border_color,
+ widget = wibox.widget.progressbar
+}
+
+local battery_tooltip = awful.tooltip {}
+battery_tooltip.shape = helpers.prrect(beautiful.border_radius - 3, true, true,
+ false, false)
+battery_tooltip.preferred_alignments = {"middle", "front", "back"}
+battery_tooltip.mode = "outside"
+battery_tooltip:add_to_object(battery_bar)
+battery_tooltip.text = 'Not Updated'
+
+awesome.connect_signal("ears::battery", function(value)
+ battery_bar.value = value
+ battery_bar.color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {75 - (100 - value), 20},
+ stops = {
+ {1 + (value) / 100, beautiful.xcolor10},
+ {0.75 - (value / 100), beautiful.xcolor9},
+ {1 - (value) / 100, beautiful.xcolor10}
+ }
+ }
+
+ local bat_icon = ' '
+
+ if value >= 90 and value <= 100 then
+ bat_icon = ' '
+ elseif value >= 70 and value < 90 then
+ bat_icon = ' '
+ elseif value >= 60 and value < 70 then
+ bat_icon = ' '
+ elseif value >= 50 and value < 60 then
+ bat_icon = ' '
+ elseif value >= 30 and value < 50 then
+ bat_icon = ' '
+ elseif value >= 15 and value < 30 then
+ bat_icon = ' '
+ else
+ bat_icon = ' '
+ end
+
+ battery_tooltip.markup =
+ " " .. "<span foreground='" .. beautiful.xcolor12 .. "'>" .. bat_icon ..
+ "</span>" .. value .. '% '
+end)
+
+-- Timer for charging animation
+local q = 0
+local g = gears.timer {
+ timeout = 0.03,
+ call_now = false,
+ autostart = false,
+ callback = function()
+ if q >= 100 then q = 0 end
+ q = q + 1
+ battery_bar.value = q
+ battery_bar.color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {75 - (100 - q), 20},
+ stops = {
+ {1 + (q) / 100, beautiful.xcolor10},
+ {0.75 - (q / 100), beautiful.xcolor1},
+ {1 - (q) / 100, beautiful.xcolor10}
+ }
+ }
+ end
+}
+
+-- The charging animation
+local running = false
+awesome.connect_signal("ears::charger", function(plugged)
+ if plugged then
+ g:start()
+ running = true
+ else
+ if running then
+ g:stop()
+ running = false
+ end
+ end
+end)
+
+local battery = format_progress_bar(battery_bar)
+
+-- Systray Widget -------------------------------------------------------------
+
+local mysystray = wibox.widget.systray()
+mysystray:set_base_size(beautiful.systray_icon_size)
+
+local mysystray_container = {
+ mysystray,
+ left = dpi(8),
+ right = dpi(8),
+ widget = wibox.container.margin
+}
+
+-- Tasklist Buttons -----------------------------------------------------------
+
+local tasklist_buttons = gears.table.join(
+ awful.button({}, 1, function(c)
+ if c == client.focus then
+ c.minimized = true
+ else
+ c:emit_signal("request::activate", "tasklist", {raise = true})
+ end
+ end), awful.button({}, 3, function()
+ awful.menu.client_list({theme = {width = 250}})
+ end), awful.button({}, 4, function() awful.client.focus.byidx(1) end),
+ awful.button({}, 5, function()
+ awful.client.focus.byidx(-1)
+ end))
+
+-- Playerctl Bar Widget -------------------------------------------------------
+
+-- Title Widget
+local song_title = wibox.widget {
+ markup = 'Nothing Playing',
+ align = 'center',
+ valign = 'center',
+ widget = wibox.widget.textbox
+}
+
+local song_artist = wibox.widget {
+ markup = 'nothing playing',
+ align = 'center',
+ valign = 'center',
+ widget = wibox.widget.textbox
+}
+
+local song_logo = wibox.widget {
+ markup = '<span foreground="' .. beautiful.xcolor6 .. '"></span>',
+ font = beautiful.icon_font,
+ align = 'center',
+ valign = 'center',
+ widget = wibox.widget.textbox
+}
+
+local playerctl_bar = wibox.widget {
+ {
+ {
+ {
+ song_logo,
+ left = dpi(3),
+ right = dpi(10),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ song_title,
+ expand = "outside",
+ layout = wibox.layout.align.vertical
+ },
+ left = dpi(10),
+ right = dpi(10),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ song_artist,
+ expand = "outside",
+ layout = wibox.layout.align.vertical
+ },
+ left = dpi(10),
+ widget = wibox.container.margin
+ },
+ spacing = 1,
+ spacing_widget = {
+ bg = beautiful.xcolor8,
+ widget = wibox.container.background
+ },
+ layout = wibox.layout.fixed.horizontal
+ },
+ left = dpi(10),
+ right = dpi(10),
+ widget = wibox.container.margin
+ },
+
+ bg = beautiful.xcolor0,
+ shape = helpers.rrect(beautiful.border_radius - 3),
+ widget = wibox.container.background
+}
+
+playerctl_bar.visible = false
+
+awesome.connect_signal("bling::playerctl::player_stopped",
+ function() playerctl_bar.visible = false end)
+
+-- Get Title
+awesome.connect_signal("bling::playerctl::title_artist_album",
+ function(title, artist, _)
+
+ playerctl_bar.visible = true
+ song_title.markup = '<span foreground="' .. beautiful.xcolor5 .. '">' ..
+ title .. '</span>'
+
+ song_artist.markup = '<span foreground="' .. beautiful.xcolor4 .. '">' ..
+ artist .. '</span>'
+end)
+
+-- Create the Wibar -----------------------------------------------------------
+
+screen.connect_signal("request::desktop_decoration", function(s)
+ -- Create a promptbox for each screen
+ s.mypromptbox = awful.widget.prompt()
+
+ -- Create layoutbox widget
+ s.mylayoutbox = awful.widget.layoutbox(s)
+
+ if s.index == 1 then
+ mysystray_container.visible = true
+ else
+ mysystray_container.visible = false
+ end
+
+ -- Create the wibox
+ s.mywibox = awful.wibar({position = "bottom", screen = s})
+ s.mywibox:set_xproperty("WM_NAME", "panel")
+
+ -- Remove wibar on full screen
+ local function remove_wibar(c)
+ if c.fullscreen or c.maximized then
+ c.screen.mywibox.visible = false
+ else
+ c.screen.mywibox.visible = true
+ end
+ end
+
+ -- Remove wibar on full screen
+ local function add_wibar(c)
+ if c.fullscreen or c.maximized then
+ c.screen.mywibox.visible = true
+ end
+ end
+
+ -- Hide bar when a splash widget is visible
+ awesome.connect_signal("widgets::splash::visibility",
+ function(vis) s.mywibox.visible = not vis end)
+
+ client.connect_signal("property::fullscreen", remove_wibar)
+
+ client.connect_signal("request::unmanage", add_wibar)
+
+ -- Create the taglist widget
+ s.mytaglist = require("bloat.widgets.pacman_taglist")(s)
+
+ -- Create a tasklist widget
+ s.mytasklist = awful.widget.tasklist {
+ screen = s,
+ filter = awful.widget.tasklist.filter.currenttags,
+ buttons = tasklist_buttons,
+ bg = beautiful.xcolor0,
+ style = {bg = beautiful.xcolor0},
+ layout = {spacing = dpi(0), layout = wibox.layout.fixed.horizontal},
+ widget_template = {
+ {
+ {
+ nil,
+ awful.widget.clienticon,
+ nil,
+ layout = wibox.layout.fixed.horizontal
+ },
+ top = dpi(5),
+ bottom = dpi(5),
+ left = dpi(10),
+ right = dpi(10),
+ widget = wibox.container.margin
+ },
+ id = 'background_role',
+ widget = wibox.container.background
+ }
+ }
+
+ local final_systray = wibox.widget {
+ {mysystray_container, top = dpi(5), layout = wibox.container.margin},
+ bg = beautiful.xcolor0,
+ shape = helpers.rrect(beautiful.border_radius - 3),
+ widget = wibox.container.background
+ }
+
+ -- Add widgets to the wibox
+ s.mywibox:setup{
+ layout = wibox.layout.fixed.vertical,
+ {
+ widget = wibox.container.background,
+ bg = beautiful.xcolor0,
+ forced_height = dpi(1)
+ },
+ {
+ layout = wibox.layout.align.horizontal,
+ expand = "none",
+ {
+ layout = wibox.layout.fixed.horizontal,
+ {
+ awesome_icon,
+ top = dpi(0),
+ right = dpi(5),
+ left = dpi(10),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ s.mytaglist,
+ bg = beautiful.xcolor0,
+ shape = helpers.rrect(beautiful.border_radius - 3),
+ widget = wibox.container.background
+ },
+ margins = dpi(5),
+ widget = wibox.container.margin
+ },
+ s.mypromptbox,
+ {
+ playerctl_bar,
+ margins = dpi(5),
+ widget = wibox.container.margin
+ }
+ },
+ {
+ {
+ {
+ s.mytasklist,
+ bg = beautiful.xcolor0 .. "00",
+ shape = helpers.rrect(beautiful.border_radius - 3),
+ widget = wibox.container.background
+ },
+ margins = dpi(5),
+ widget = wibox.container.margin
+ },
+ widget = wibox.container.constraint
+ },
+ {
+ {
+ {
+ {
+ battery,
+ margins = dpi(5),
+ widget = wibox.container.margin
+ },
+ bg = beautiful.xcolor0,
+ shape = helpers.rrect(beautiful.border_radius - 3),
+ widget = wibox.container.background
+ },
+ margins = dpi(5),
+ widget = wibox.container.margin
+ },
+ nil,
+ nil,
+ {
+ awful.widget.only_on_screen(final_systray, screen[1]),
+ margins = dpi(5),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ {
+ s.mylayoutbox,
+ top = dpi(4),
+ bottom = dpi(4),
+ right = dpi(7),
+ left = dpi(7),
+ widget = wibox.container.margin
+ },
+ bg = beautiful.xcolor0,
+ shape = helpers.rrect(beautiful.border_radius - 3),
+ widget = wibox.container.background
+ },
+ margins = dpi(5),
+ widget = wibox.container.margin
+ },
+
+ {
+ notif_icon,
+ top = dpi(0),
+ right = dpi(10),
+ left = dpi(5),
+ widget = wibox.container.margin
+ },
+
+ layout = wibox.layout.fixed.horizontal
+ }
+ }
+ }
+end)
+
+-- EOF ------------------------------------------------------------------------
diff --git a/awesome/bloat/init.lua b/awesome/bloat/init.lua
new file mode 100644
index 0000000..941b734
--- /dev/null
+++ b/awesome/bloat/init.lua
@@ -0,0 +1,4 @@
+require("bloat.notifs")
+require("bloat.pop")
+require("bloat.bar")
+require("bloat.titlebars")
diff --git a/awesome/bloat/lockscreen/init.lua b/awesome/bloat/lockscreen/init.lua
new file mode 100644
index 0000000..81f397a
--- /dev/null
+++ b/awesome/bloat/lockscreen/init.lua
@@ -0,0 +1,13 @@
+local awful = require("awful")
+
+local lock_screen = {}
+
+lock_screen.init = function()
+ lock_screen.authenticate = function(password)
+ return password == "awesomewm"
+ end
+
+ require("bloat.lockscreen.lockscreen")
+end
+
+return lock_screen
diff --git a/awesome/bloat/lockscreen/lockscreen.lua b/awesome/bloat/lockscreen/lockscreen.lua
new file mode 100644
index 0000000..b6fe6f5
--- /dev/null
+++ b/awesome/bloat/lockscreen/lockscreen.lua
@@ -0,0 +1,293 @@
+-- TOTALLY NOT STOLEN FROM ELENAPAN
+-- https://github.com/elenapan/dotfiles/tree/master/config/awesome/elemental/lock_screen
+-- Disclaimer:
+-- This lock screen was not designed with security in mind. There is
+-- no guarantee that it will protect you against someone that wants to
+-- gain access to your computer.
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+local naughty = require("naughty")
+local helpers = require("helpers")
+local lock_screen = require("bloat.lockscreen")
+
+local lock_screen_symbol = ""
+local lock_screen_fail_symbol = ""
+local lock_animation_icon = wibox.widget {
+ -- Set forced size to prevent flickering when the icon rotates
+ forced_height = dpi(80),
+ forced_width = dpi(80),
+ font = "FiraCode Nerd Font 40",
+ align = "center",
+ valign = "center",
+ widget = wibox.widget.textbox(lock_screen_symbol)
+}
+
+-- A dummy textbox needed to get user input.
+-- It will not be visible anywhere.
+local some_textbox = wibox.widget.textbox()
+
+-- Create the lock screen wibox
+-- Set the type to "splash" and set all "splash" windows to be blurred in your
+-- compositor configuration file
+lock_screen_box = wibox({
+ visible = false,
+ ontop = true,
+ type = "splash",
+ screen = screen.primary
+})
+awful.placement.maximize(lock_screen_box)
+
+lock_screen_box.bg = beautiful.exit_screen_bg
+lock_screen_box.fg = beautiful.xforeground or "#FEFEFE"
+
+-- Add lockscreen to each screen
+awful.screen.connect_for_each_screen(function(s)
+ if s == screen.primary then
+ s.mylockscreen = lock_screen_box
+ else
+ s.mylockscreen = helpers.screen_mask(s, beautiful.exit_screen_bg or
+ beautiful.xbackground .. "80")
+ end
+end)
+
+local function set_visibility(v)
+ for s in screen do s.mylockscreen.visible = v end
+end
+
+-- Items
+local day_of_the_week = wibox.widget {
+ font = beautiful.font_name .. "80",
+ forced_width = dpi(1000),
+ align = "center",
+ valign = "center",
+ widget = wibox.widget.textclock(helpers.colorize_text("%A",
+ beautiful.xcolor4 ..
+ "70"))
+}
+
+local month = wibox.widget {
+ font = beautiful.font_name .. "100",
+ align = "center",
+ valign = "center",
+ widget = wibox.widget.textclock("%B %d")
+}
+
+local function update_month()
+ month.markup = helpers.colorize_text(month.text:upper(),
+ beautiful.xcolor6 .. "70")
+end
+
+update_month()
+month:connect_signal("widget::redraw_needed", function() update_month() end)
+
+local time = {
+ {font = "sans bold 16", widget = wibox.widget.textclock("%H")},
+ {font = "sans 16", widget = wibox.widget.textclock("%M")},
+ spacing = dpi(2),
+ layout = wibox.layout.fixed.horizontal
+}
+
+local me_pic = wibox.widget {
+ nil,
+ {
+ image = beautiful.me,
+ resize = true,
+ -- forced_height = dpi(35),
+ -- forced_width = dpi(35),
+ clip_shape = gears.shape.circle,
+ widget = wibox.widget.imagebox
+ },
+ nil,
+ expand = "none",
+ layout = wibox.layout.align.horizontal
+}
+
+-- Lock animation
+local lock_animation_widget_rotate = wibox.container.rotate()
+
+local arc = function()
+ return function(cr, width, height)
+ gears.shape.arc(cr, width, height, dpi(5), 0, math.pi / 2, true, true)
+ end
+end
+
+local lock_animation_arc = wibox.widget {
+ shape = arc(),
+ bg = "#00000000",
+ forced_width = dpi(100),
+ forced_height = dpi(100),
+ widget = wibox.container.background
+}
+
+local lock_animation_widget = {
+ {lock_animation_arc, widget = lock_animation_widget_rotate},
+ {me_pic, margins = dpi(10), widget = wibox.container.margin},
+ forced_height = dpi(200),
+ forced_width = dpi(200),
+
+ layout = wibox.layout.stack
+}
+
+-- Lock helper functions
+local characters_entered = 0
+local function reset()
+ characters_entered = 0;
+ lock_animation_icon.markup = helpers.colorize_text(lock_screen_symbol,
+ beautiful.xcolor7)
+ lock_animation_widget_rotate.direction = "north"
+ lock_animation_arc.bg = "#00000000"
+end
+
+local function fail()
+ characters_entered = 0;
+ lock_animation_icon.text = lock_screen_fail_symbol
+ lock_animation_widget_rotate.direction = "north"
+ lock_animation_arc.bg = "#00000000"
+end
+
+local animation_colors = {
+ -- Rainbow sequence =)
+ beautiful.xcolor1, beautiful.xcolor5, beautiful.xcolor4, beautiful.xcolor6,
+ beautiful.xcolor2, beautiful.xcolor3
+}
+
+local animation_directions = {"north", "west", "south", "east"}
+
+-- Function that "animates" every key press
+local function key_animation(char_inserted)
+ local color
+ local direction = animation_directions[(characters_entered % 4) + 1]
+ if char_inserted then
+ color = animation_colors[(characters_entered % 6) + 1]
+ lock_animation_icon.text = lock_screen_symbol
+ else
+ if characters_entered == 0 then
+ reset()
+ else
+ color = beautiful.xcolor7 .. "55"
+ end
+ end
+
+ lock_animation_arc.bg = color
+ lock_animation_widget_rotate.direction = direction
+end
+
+-- Get input from user
+local function grab_password()
+ awful.prompt.run {
+ hooks = {
+ -- Custom escape behaviour: Do not cancel input with Escape
+ -- Instead, this will just clear any input received so far.
+ {
+ {}, 'Escape', function(_)
+ reset()
+ grab_password()
+ end
+ }, -- Fix for Control+Delete crashing the keygrabber
+ {
+ {'Control'}, 'Delete', function()
+ reset()
+ grab_password()
+ end
+ }
+ },
+ keypressed_callback = function(mod, key, cmd)
+ -- Only count single character keys (thus preventing
+ -- "Shift", "Escape", etc from triggering the animation)
+ if #key == 1 then
+ characters_entered = characters_entered + 1
+ key_animation(true)
+ elseif key == "BackSpace" then
+ if characters_entered > 0 then
+ characters_entered = characters_entered - 1
+ end
+ key_animation(false)
+ end
+
+ -- Debug
+ -- naughty.notify { title = 'You pressed:', text = key }
+ end,
+ exe_callback = function(input)
+ -- Check input
+ if lock_screen.authenticate(input) then
+ -- YAY
+ reset()
+ set_visibility(false)
+ else
+ -- NAY
+ fail()
+ grab_password()
+ end
+ end,
+ textbox = some_textbox
+ }
+end
+
+function lock_screen_show()
+ set_visibility(true)
+ grab_password()
+end
+
+-- Item placement
+lock_screen_box:setup{
+ -- Horizontal centering
+ nil,
+ {
+ -- Vertical centering
+ nil,
+ {
+ {
+ {
+ {
+ lock_animation_widget,
+ month,
+ day_of_the_week,
+ layout = wibox.layout.align.vertical
+ },
+ {
+ nil,
+ {
+ -- Small circle
+ {
+ forced_height = dpi(5),
+ forced_width = dpi(5),
+ shape = gears.shape.star,
+ bg = beautiful.xcolor6,
+ widget = wibox.container.background
+ },
+ time,
+ -- Small circle
+ {
+ forced_height = dpi(5),
+ forced_width = dpi(5),
+ shape = gears.shape.star,
+ bg = beautiful.xcolor6,
+ widget = wibox.container.background
+ },
+ spacing = dpi(4),
+ layout = wibox.layout.fixed.horizontal
+ },
+ expand = "none",
+ layout = wibox.layout.align.horizontal
+ },
+ spacing = dpi(20),
+ -- spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ },
+ spacing = dpi(40),
+ layout = wibox.layout.fixed.vertical
+
+ },
+ bottom = dpi(60),
+ widget = wibox.container.margin
+ },
+ expand = "none",
+ layout = wibox.layout.align.vertical
+ },
+ expand = "none",
+ layout = wibox.layout.align.horizontal
+}
diff --git a/awesome/bloat/notifs/battery.lua b/awesome/bloat/notifs/battery.lua
new file mode 100644
index 0000000..2f0c5f4
--- /dev/null
+++ b/awesome/bloat/notifs/battery.lua
@@ -0,0 +1,37 @@
+local gfs = require("gears.filesystem")
+local naughty = require("naughty")
+
+local display = true
+
+awesome.connect_signal("ears::battery", function(value)
+ if value < 11 then
+ naughty.notification({
+ title = "Battery Status",
+ text = "Running low at " .. value .. "%",
+ image = gfs.get_configuration_dir() .. "icons/ghosts/battery.png"
+ })
+ end
+
+ if (value > 94 and display) then
+ naughty.notification({
+ title = "Battery Status",
+ text = "Running high at " .. value .. "%",
+ image = gfs.get_configuration_dir() .. "icons/ghosts/battery.png"
+
+ })
+ display = false
+ end
+end)
+
+awesome.connect_signal("ears::charger", function(plugged)
+ if plugged then
+ naughty.notification({
+ title = "Battery Status",
+ text = "Charging",
+ image = gfs.get_configuration_dir() ..
+ "icons/ghosts/battery_charging.png"
+ })
+ display = true
+ end
+
+end)
diff --git a/awesome/bloat/notifs/brightness.lua b/awesome/bloat/notifs/brightness.lua
new file mode 100644
index 0000000..c660535
--- /dev/null
+++ b/awesome/bloat/notifs/brightness.lua
@@ -0,0 +1,93 @@
+local wibox = require("wibox")
+local awful = require("awful")
+local gears = require("gears")
+local beautiful = require("beautiful")
+local helpers = require("helpers")
+local dpi = beautiful.xresources.apply_dpi
+
+local width = dpi(200)
+local height = dpi(200)
+local screen = awful.screen.focused()
+
+local active_color_1 = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor6}, {0.50, beautiful.xcolor4}}
+}
+
+local bright_icon = wibox.widget {
+ markup = "<span foreground='" .. beautiful.xcolor4 .. "'><b></b></span>",
+ align = 'center',
+ valign = 'center',
+ font = beautiful.font_name .. '70',
+ widget = wibox.widget.textbox
+}
+
+-- create the bright_adjust component
+local bright_adjust = wibox({
+ screen = screen.primary,
+ type = "notification",
+ x = screen.geometry.width / 2 - width / 2,
+ y = screen.geometry.height / 2 - height / 2 + 300,
+ width = width,
+ height = height,
+ visible = false,
+ ontop = true,
+ bg = beautiful.xbackground .. "00"
+})
+
+local bright_bar = wibox.widget {
+ widget = wibox.widget.progressbar,
+ shape = gears.shape.rounded_bar,
+ bar_shape = gears.shape.rounded_bar,
+ color = active_color_1,
+ background_color = beautiful.xcolor0,
+ max_value = 100,
+ value = 0
+}
+
+bright_adjust:setup{
+ {
+ layout = wibox.layout.align.vertical,
+ {
+ bright_icon,
+ top = dpi(15),
+ left = dpi(50),
+ right = dpi(50),
+ bottom = dpi(15),
+ widget = wibox.container.margin
+ },
+ {
+ bright_bar,
+ left = dpi(25),
+ right = dpi(25),
+ bottom = dpi(30),
+ widget = wibox.container.margin
+ }
+
+ },
+ shape = helpers.rrect(beautiful.client_radius),
+ bg = beautiful.xbackground,
+ border_width = beautiful.widget_border_width,
+ border_color = beautiful.widget_border_color,
+ widget = wibox.container.background
+}
+
+-- create a 3 second timer to hide the volume adjust
+-- component whenever the timer is started
+local hide_bright_adjust = gears.timer {
+ timeout = 3,
+ autostart = true,
+ callback = function() bright_adjust.visible = false end
+}
+
+awesome.connect_signal("ears::brightness", function(value)
+ bright_bar.value = value
+ if bright_adjust.visible then
+ hide_bright_adjust:again()
+ else
+ bright_adjust.visible = true
+ hide_bright_adjust:start()
+ end
+end)
diff --git a/awesome/bloat/notifs/init.lua b/awesome/bloat/notifs/init.lua
new file mode 100644
index 0000000..e25a768
--- /dev/null
+++ b/awesome/bloat/notifs/init.lua
@@ -0,0 +1,202 @@
+local naughty = require("naughty")
+local beautiful = require("beautiful")
+local gears = require("gears")
+local wibox = require("wibox")
+local awful = require("awful")
+local dpi = beautiful.xresources.apply_dpi
+local helpers = require("helpers")
+local ruled = require("ruled")
+
+require("bloat.notifs.brightness")
+require("bloat.notifs.playerctl")
+require("bloat.notifs.volume")
+require("bloat.notifs.battery")
+
+naughty.config.defaults.ontop = true
+-- naughty.config.defaults.icon_size = dpi(32)
+naughty.config.defaults.screen = awful.screen.focused()
+naughty.config.defaults.timeout = 3
+naughty.config.defaults.title = "System Notification"
+-- naughty.config.defaults.margin = dpi(20)
+-- naughty.config.defaults.border_width = 0
+-- naughty.config.defaults.border_color = beautiful.widget_border_color
+naughty.config.defaults.position = "bottom_left"
+-- naughty.config.defaults.shape = helpers.rrect(beautiful.client_radius)
+
+naughty.config.padding = dpi(10)
+naughty.config.spacing = dpi(5)
+naughty.config.icon_dirs = {
+ "/usr/share/icons/Papirus-Dark/24x24/apps/", "/usr/share/pixmaps/"
+}
+naughty.config.icon_formats = {"png", "svg"}
+
+-- Timeouts
+naughty.config.presets.low.timeout = 3
+naughty.config.presets.critical.timeout = 0
+
+naughty.config.presets.normal = {
+ font = beautiful.font,
+ fg = beautiful.fg_normal,
+ bg = beautiful.bg_normal
+}
+
+naughty.config.presets.low = {
+ font = beautiful.font,
+ fg = beautiful.fg_normal,
+ bg = beautiful.bg_normal
+}
+
+naughty.config.presets.critical = {
+ font = beautiful.font_name .. "10",
+ fg = beautiful.xcolor1,
+ bg = beautiful.bg_normal,
+ timeout = 0
+}
+
+naughty.config.presets.ok = naughty.config.presets.normal
+naughty.config.presets.info = naughty.config.presets.normal
+naughty.config.presets.warn = naughty.config.presets.critical
+
+ruled.notification.connect_signal('request::rules', function()
+ -- All notifications will match this rule.
+ ruled.notification.append_rule {
+ rule = {},
+ properties = {screen = awful.screen.preferred, implicit_timeout = 6}
+ }
+end)
+
+naughty.connect_signal("request::display", function(n)
+ local appicon = n.icon or n.app_icon
+ if not appicon then appicon = beautiful.notification_icon end
+
+ local action_widget = {
+ {
+ {
+ id = 'text_role',
+ align = "center",
+ valign = "center",
+ font = beautiful.font_name .. "8",
+ widget = wibox.widget.textbox
+ },
+ left = dpi(6),
+ right = dpi(6),
+ widget = wibox.container.margin
+ },
+ bg = beautiful.xcolor0,
+ forced_height = dpi(25),
+ forced_width = dpi(20),
+ shape = helpers.rrect(dpi(4)),
+ widget = wibox.container.background
+ }
+
+ local actions = wibox.widget {
+ notification = n,
+ base_layout = wibox.widget {
+ spacing = dpi(8),
+ layout = wibox.layout.flex.horizontal
+ },
+ widget_template = action_widget,
+ style = {underline_normal = false, underline_selected = true},
+ widget = naughty.list.actions
+ }
+
+ naughty.layout.box {
+ notification = n,
+ type = "notification",
+ bg = beautiful.xbackground .. "00",
+ widget_template = {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ image = appicon,
+ resize = true,
+ clip_shape = helpers.rrect(
+ beautiful.border_radius - 3),
+ widget = wibox.widget.imagebox
+ },
+ -- bg = beautiful.xcolor1,
+ strategy = 'max',
+ height = 40,
+ width = 40,
+ widget = wibox.container.constraint
+ },
+ layout = wibox.layout.align.vertical
+ },
+ top = dpi(10),
+ left = dpi(15),
+ right = dpi(15),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ nil,
+ {
+ {
+ step_function = wibox.container
+ .scroll.step_functions
+ .waiting_nonlinear_back_and_forth,
+ speed = 50,
+ {
+ markup = "<span weight='bold'>" ..
+ n.title .. "</span>",
+ font = beautiful.font,
+ align = "left",
+ visible = title_visible,
+ widget = wibox.widget.textbox
+ },
+ forced_width = dpi(204),
+ widget = wibox.container.scroll
+ .horizontal
+ },
+ {
+ {
+ markup = n.message,
+ align = "left",
+ font = beautiful.font,
+ widget = wibox.widget.textbox
+ },
+ right = 10,
+ widget = wibox.container.margin
+ },
+ {
+ actions,
+ visible = n.actions and #n.actions >
+ 0,
+ layout = wibox.layout.fixed.vertical,
+ forced_width = dpi(220)
+ },
+ spacing = dpi(3),
+ layout = wibox.layout.fixed.vertical
+ },
+ nil,
+ expand = "none",
+ layout = wibox.layout.align.vertical
+ },
+ margins = dpi(8),
+ widget = wibox.container.margin
+ },
+ layout = wibox.layout.fixed.horizontal
+ },
+ top = dpi(10),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+ },
+ bg = beautiful.xbackground,
+ shape = helpers.rrect(beautiful.border_radius),
+ widget = wibox.container.background
+ },
+ margins = beautiful.widget_border_width,
+ widget = wibox.container.margin
+ },
+ bg = beautiful.xcolor0,
+ shape = helpers.rrect(beautiful.border_radius + 2),
+ widget = wibox.container.background
+ }
+ }
+end)
diff --git a/awesome/bloat/notifs/notif-center/build-notifbox/empty-notifbox.lua b/awesome/bloat/notifs/notif-center/build-notifbox/empty-notifbox.lua
new file mode 100644
index 0000000..a5c6b8b
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/build-notifbox/empty-notifbox.lua
@@ -0,0 +1,42 @@
+local beautiful = require("beautiful")
+local wibox = require('wibox')
+
+local dpi = require('beautiful').xresources.apply_dpi
+
+local empty_notifbox = wibox.widget {
+ {
+ layout = wibox.layout.fixed.vertical,
+ spacing = dpi(5),
+ {
+ expand = 'none',
+ layout = wibox.layout.align.horizontal,
+ nil,
+ {
+ image = beautiful.notification_none_icon,
+ resize = true,
+ forced_height = dpi(35),
+ forced_width = dpi(35),
+ widget = wibox.widget.imagebox
+ },
+ nil
+ },
+ {
+ markup = 'You have no notifs!',
+ font = beautiful.font_name .. '10',
+ align = 'center',
+ valign = 'center',
+ widget = wibox.widget.textbox
+ }
+ },
+ margins = dpi(20),
+ widget = wibox.container.margin
+
+}
+
+local centered_empty_notifbox = wibox.widget {
+ layout = wibox.layout.fixed.vertical,
+ expand = 'none',
+ empty_notifbox
+}
+
+return centered_empty_notifbox
diff --git a/awesome/bloat/notifs/notif-center/build-notifbox/init.lua b/awesome/bloat/notifs/notif-center/build-notifbox/init.lua
new file mode 100644
index 0000000..07872af
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/build-notifbox/init.lua
@@ -0,0 +1,58 @@
+local awful = require('awful')
+local naughty = require('naughty')
+local wibox = require('wibox')
+local gears = require('gears')
+local beautiful = require('beautiful')
+
+local dpi = beautiful.xresources.apply_dpi
+local empty_notifbox = require(
+ 'bloat/notifs.notif-center.build-notifbox.empty-notifbox')
+
+local config_dir = gears.filesystem.get_configuration_dir()
+local widget_icon_dir = config_dir .. 'bloat/notifs/notif-center/icons/'
+
+local width = dpi(380)
+
+local remove_notifbox_empty = true
+
+local notifbox_layout = wibox.layout.fixed.vertical()
+
+notifbox_layout.spacing = dpi(7)
+notifbox_layout.forced_width = width
+
+reset_notifbox_layout = function()
+ notifbox_layout:reset(notifbox_layout)
+ notifbox_layout:insert(1, empty_notifbox)
+ remove_notifbox_empty = true
+end
+
+remove_notifbox = function(box)
+ notifbox_layout:remove_widgets(box)
+
+ if #notifbox_layout.children == 0 then
+ notifbox_layout:insert(1, empty_notifbox)
+ remove_notifbox_empty = true
+ end
+end
+
+notifbox_layout:insert(1, empty_notifbox)
+
+naughty.connect_signal("added", function(n)
+
+ if #notifbox_layout.children == 1 and remove_notifbox_empty then
+ notifbox_layout:reset(notifbox_layout)
+ remove_notifbox_empty = false
+ end
+
+ local notifbox_color = beautiful.groups_bg
+ if n.urgency == 'critical' then
+ notifbox_color = beautiful.xcolor1 .. '66'
+ end
+ local appicon = n.icon or n.app_icon
+ if not appicon then appicon = beautiful.notification_icon end
+
+ local box = require("bloat/notifs.notif-center.build-notifbox.notifbox")
+ notifbox_layout:insert(1, box.create(appicon, n.title, n.message, width))
+end)
+
+return notifbox_layout
diff --git a/awesome/bloat/notifs/notif-center/build-notifbox/notifbox.lua b/awesome/bloat/notifs/notif-center/build-notifbox/notifbox.lua
new file mode 100644
index 0000000..6714394
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/build-notifbox/notifbox.lua
@@ -0,0 +1,101 @@
+local awful = require("awful")
+local wibox = require("wibox")
+local gears = require("gears")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+local helpers = require("helpers")
+
+local button = require("bloat.widgets.button")
+
+local notifbox = {}
+
+notifbox.create = function(icon, title, message, width)
+ local time = os.date("%H:%M")
+ local box = {}
+
+ local dismiss = button.create_image_onclick(beautiful.delete_grey_icon,
+ beautiful.delete_icon,
+ function()
+ _G.remove_notifbox(box)
+ end)
+ dismiss.forced_height = dpi(24)
+ dismiss.forced_width = dpi(24)
+
+ -- icon.forced_height = dpi(24)
+ -- icon.forced_width = dpi(24)
+
+ local img_icon = wibox.widget {
+ image = icon,
+ forced_width = dpi(35),
+ forced_height = dpi(35),
+ resize = true,
+ clip_shape = function(cr)
+ gears.shape.rounded_rect(cr, dpi(35), dpi(35), dpi(6))
+ end,
+ widget = wibox.widget.imagebox
+ }
+
+ local center1 = wibox.container.margin(img_icon, 20, 0, 14, 0)
+
+ box = wibox.widget {
+ {
+ center1,
+ {
+ {
+ nil,
+ {
+ {
+ font = beautiful.font_name .. "10",
+ markup = title,
+ widget = wibox.widget.textbox
+ },
+ {
+ font = beautiful.font_name .. "8",
+ markup = message,
+ widget = wibox.widget.textbox
+ },
+ layout = wibox.layout.fixed.vertical
+ },
+ expand = "none",
+ layout = wibox.layout.align.vertical
+ },
+ left = dpi(20),
+ bottom = dpi(0),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ {
+ font = beautiful.font_name .. "8",
+ markup = time,
+ widget = wibox.widget.textbox
+ },
+ {
+ nil,
+ dismiss,
+ nil,
+ expand = "none",
+ layout = wibox.layout.align.horizontal
+ },
+ spacing = dpi(5),
+ layout = wibox.layout.fixed.vertical
+ },
+ margins = dpi(10),
+ widget = wibox.container.margin
+ },
+ spacing = dpi(20),
+ layout = wibox.layout.align.horizontal
+ },
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, beautiful.client_radius)
+ end,
+ bg = beautiful.xcolor0 .. "80",
+ forced_width = width,
+ widget = wibox.container.background
+ }
+
+ return box
+end
+
+return notifbox
diff --git a/awesome/bloat/notifs/notif-center/clear-all/init.lua b/awesome/bloat/notifs/notif-center/clear-all/init.lua
new file mode 100644
index 0000000..e4bf610
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/clear-all/init.lua
@@ -0,0 +1,31 @@
+local awful = require('awful')
+local wibox = require('wibox')
+local gears = require('gears')
+local beautiful = require('beautiful')
+
+local button = require("bloat.widgets.button")
+local dpi = require('beautiful').xresources.apply_dpi
+
+local config_dir = gears.filesystem.get_configuration_dir()
+local widget_icon_dir = config_dir .. 'notifs/notif-center/icons/'
+
+local delete_button = button.create_image_onclick(beautiful.clear_grey_icon,
+ beautiful.clear_icon,
+ function()
+ _G.reset_notifbox_layout()
+end)
+
+local delete_button_wrapped = wibox.widget {
+ nil,
+ {
+ delete_button,
+ widget = wibox.container.background,
+ forced_height = dpi(24),
+ forced_width = dpi(24)
+ },
+ nil,
+ expand = 'none',
+ layout = wibox.layout.align.vertical
+}
+
+return delete_button_wrapped
diff --git a/awesome/bloat/notifs/notif-center/icons/clear_all.svg b/awesome/bloat/notifs/notif-center/icons/clear_all.svg
new file mode 100644
index 0000000..3f5b9b4
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/icons/clear_all.svg
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="svg2"
+ width="240"
+ height="240"
+ viewBox="0 0 240 240"
+ sodipodi:docname="clear_all.svg"
+ inkscape:version="0.92.4 5da689c313, 2019-01-14">
+ <metadata
+ id="metadata8">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs6" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1321"
+ inkscape:window-height="740"
+ id="namedview4"
+ showgrid="false"
+ inkscape:pagecheckerboard="true"
+ inkscape:zoom="1.1346154"
+ inkscape:cx="-63.016949"
+ inkscape:cy="104"
+ inkscape:window-x="45"
+ inkscape:window-y="28"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg2" />
+ <image
+ width="200"
+ height="200"
+ preserveAspectRatio="none"
+ style="image-rendering:optimizeQuality"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJwAAACcCAYAAACKuMJNAAAC53pUWHRSYXcgcHJvZmlsZSB0eXBl
+IGV4aWYAAHja7ZdbktwgDEX/WUWWgCSExHIwmKrsIMvPBT+me2byquQnVW3KQAtZyPcA3R32b19H
++IKLSuaQ1DyXnCOuVFLhio7H4yqrpphWfZjaOUbP9nAPMEyCVo6PVk//Cru+PXDNQduzPfg5wn4G
+OgeugDJnZnT6Y5Kw82GndGW0H51c3B5T3fho2+m4UjlvsRX6DjI/h0dDMqjUFV7CvAtJXLUfGchx
+V9xy1PCj01ICmiR0ZgJBnl7vamN8FOhJ5KsX3qt/996Jz/W0yzst86kROp8OkH4u/pL4YWK5M+Ln
+AZMr1EeRx+g+xn68XU0ZiuZzRcVwqTOfgeMGyWU9llEMt6JvqxQUjzU2wOmxxQ2lUSGG4iNQok6V
+Bu2rbdSQYuKdDS1zY1k2F+PCTSanNAsNNinSxcGy8R6AMgnfudCat6z5Gjlm7gRXJgQjPPLDEn42
++CcljDE3G1H0WyvkxXPlIo1JbtbwAhAaJzddAl/lxB8f1g+WKgjqktnxgjVuR4hN6W1tyeIs8FO0
+x66gYP0MAIkwtyIZEhCImUQpUzRmI4KODkAVmbMk3kCAVLkjSU4iOI+MnefceMZo+bJy5mnG2QQQ
+KlkMbIpUwEpJsX4sOdZQVdGkqllNPWjRmiWnrDlny/OQqyaWTC2bmVux6uLJ1bObuxevhYvgDNSS
+ixUvpdTKoWKiilgV/hWWjTfZ0qZb3mzzrWy1Yfm01LTlZs1babVzl45joudu3Xvpdaew46TY0657
+3m33vex1YK0NGWnoyMOGjzLqTe2k+qH8ATU6qfEiNf3spgZrMLtC0DxOdDIDMU4E4jYJYEHzZBad
+UuJJbjKLhbEplJGkTjah0yQGhGkn1kE3uzdyv8UtqP8WN/4VuTDR/QtyAeg+cvuEWp/fc20RO3bh
+1DQKdh98KnvAHSOqv21fgV6BXoFegV6BXoFegf7/QDLw4wF/YsN33bGdtpmLXwIAAAGEaUNDUElD
+QyBwcm9maWxlAAB4nH2RPUjDQBiG3yZKVSoOdhBxyFCdLIiKOGoVilAh1AqtOphc+gdNDEmKi6Pg
+WnDwZ7Hq4OKsq4OrIAj+gDg5Oim6SInfJYUWMd5x3MN73/ty9x0g1CtMtzvGAN1wrHQyIWVzK1L4
+FSJNAd0QFWabs7KcQuD4ukeI73dxnhVc9+fo1fI2A0IS8QwzLYd4nXhq0zE57xNHWUnRiM+JRy26
+IPEj11Wf3zgXPRZ4ZtTKpOeIo8RSsY3VNmYlSyeeJI5pukH5QtZnjfMWZ71SZc178hdG8sbyEtdp
+DSGJBSxChgQVVZRRgYM47QYpNtJ0ngjwD3p+mVwqucpg5JjHBnQonh/8D3731i5MjPtJkQTQ+eK6
+H8NAeBdo1Fz3+9h1GyeA+AxcGS3/Rh2Y/iS91tJiR0DfNnBx3dLUPeByBxh4MhVL8SSRllAoAO9n
+9E05oP8W6Fn1+9Y8x+kDkKFepW6Ag0NgpEjZawHv7mrv2781zf79AJwYclGE5YZ3AAAABmJLR0QA
+AAAAAAD5Q7t/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5AMDAgkphODRQQAAAN1JREFU
+eNrt3DEKACEMRUGz979zbC3WSgwGZk4g+kr5YwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArOLVg2Vm
+ep7GYUX8tvW5GioJDsEhOBAcggPBITgEB4JDcCA4BAeCQ3AAAAAAAAAAAAAAvVzbh7Pv1jyMzb7b
+KT9+KSU4BIfgQHAIDgSH4BAcCA7BgeAQHAgOwQEAAAAAAAAAAAD0st0As+/W/GEv7bud8uMXwSE4
+EByCA8EhOAQHgkNwIDgEB4JDcAgOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABKTLHwDF4Sg/poAAAA
+AElFTkSuQmCC
+"
+ id="image10"
+ x="20"
+ y="20" />
+</svg>
diff --git a/awesome/bloat/notifs/notif-center/icons/delete.svg b/awesome/bloat/notifs/notif-center/icons/delete.svg
new file mode 100644
index 0000000..3f1f88c
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/icons/delete.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="240" height="240" viewBox="0 0 24 24"><path fill="#ffffff" d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" /></svg> \ No newline at end of file
diff --git a/awesome/bloat/notifs/notif-center/icons/dont-disturb-mode.svg b/awesome/bloat/notifs/notif-center/icons/dont-disturb-mode.svg
new file mode 100644
index 0000000..d5dc170
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/icons/dont-disturb-mode.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="512px"
+ viewBox="-12 0 448 448.04455"
+ width="512px"
+ version="1.1"
+ id="svg6"
+ sodipodi:docname="dont-disturb-mode.svg"
+ inkscape:version="0.92.4 5da689c313, 2019-01-14">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#252525"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1321"
+ inkscape:window-height="738"
+ id="namedview8"
+ showgrid="false"
+ inkscape:zoom="0.4609375"
+ inkscape:cx="264.67797"
+ inkscape:cy="247.32203"
+ inkscape:window-x="45"
+ inkscape:window-y="30"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg6" />
+ <g
+ id="g4"
+ transform="matrix(0.71799041,0,0,0.71799041,59.727137,63.17728)">
+ <path
+ d="m 224.02344,448.03125 c 85.71484,0.90234 164.01172,-48.48828 200.11718,-126.23047 -22.72265,9.91406 -47.33203,14.76953 -72.11718,14.23047 -97.15625,-0.10938 -175.89063,-78.84375 -176,-176 C 176.99609,94.3125 213.25781,34.199219 270.93359,2.679688 255.37891,0.699219 239.70312,-0.1875 224.02344,0.03125 c -123.71485,0 -224.0000025,100.28906 -224.0000025,224 0,123.71484 100.2851525,224 224.0000025,224 z m 0,0"
+ data-original="#000000"
+ class="active-path"
+ data-old_color="#000000"
+ style="fill:#ffffff"
+ data-darkreader-inline-fill=""
+ id="path2"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/awesome/bloat/notifs/notif-center/icons/empty-notification.svg b/awesome/bloat/notifs/notif-center/icons/empty-notification.svg
new file mode 100644
index 0000000..df4154c
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/icons/empty-notification.svg
@@ -0,0 +1 @@
+<svg height="512pt" viewBox="-17 0 511 512" width="512pt" xmlns="http://www.w3.org/2000/svg"><path d="m227.148438 446.128906c0 35.339844-27.96875 64.269532-62.9375 65.800782-.972657.050781-1.949219.070312-2.929688.070312-36.332031 0-65.882812-29.550781-65.882812-65.871094zm0 0" fill="#ff9a00"/><path d="m227.148438 446.128906c0 35.339844-27.96875 64.269532-62.9375 65.800782v-65.800782zm0 0" fill="#e67500"/><path d="m372.617188 150.859375h-84.328126l42.714844-76.324219h-35.386718v-30h86.554687l-42.714844 76.324219h33.160157zm0 0" fill="#6d76e7"/><path d="m468.285156 90.816406h-76.429687l34.035156-60.816406h-22.273437v-30h73.441406l-34.035156 60.816406h25.261718zm0 0" fill="#6d76e7"/><path d="m327.910156 450.921875-163.699218.238281-163.589844.238282-.109375-72.949219-.011719-7.167969 2.339844-3.679688c.109375-.179687 4.5-7.230468 10.171875-19.152343 9.238281-19.378907 21.878906-51.640625 25.007812-88.078125 7.058594-82.152344 52.902344-129.320313 125.769531-129.429688h.421876c38.738281.039063 69.640624 13.1875 91.867187 39.078125 18.871094 22 30.582031 53.109375 33.863281 89.96875 3.269532 36.710938 16.167969 69.140625 25.480469 88.460938 5.609375 11.628906 9.917969 18.511719 10.027344 18.679687l2.332031 3.671875.007812 4.359375.011719 3.289063zm0 0" fill="#ffdb2d"/><path d="m327.910156 450.921875-163.699218.238281v-320.21875c38.738281.039063 69.640624 13.1875 91.867187 39.078125 18.871094 22 30.582031 53.109375 33.863281 89.96875 3.269532 36.710938 16.167969 69.140625 25.480469 88.460938 5.609375 11.628906 9.917969 18.511719 10.027344 18.679687l2.332031 3.671875.007812 4.359375.011719 3.289063zm0 0" fill="#ffaa20"/><path d="m327.800781 378.449219h-327.289062l-.011719-7.167969 2.339844-3.679688c.109375-.179687 4.5-7.230468 10.171875-19.152343h302.410156c5.609375 11.628906 9.917969 18.511719 10.027344 18.679687l2.332031 3.671875.007812 4.359375zm0 0" fill="#fff5cb"/><path d="m327.800781 378.449219h-163.589843v-30h151.210937c5.609375 11.628906 9.917969 18.511719 10.027344 18.679687l2.332031 3.671875.007812 4.359375zm0 0" fill="#ffdba9"/></svg> \ No newline at end of file
diff --git a/awesome/bloat/notifs/notif-center/icons/new-notif.svg b/awesome/bloat/notifs/notif-center/icons/new-notif.svg
new file mode 100644
index 0000000..630b90a
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/icons/new-notif.svg
@@ -0,0 +1,15 @@
+<svg style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2" version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
+ <path d="m17.387 45.391l3.91-5.484h17.453s4.968 0.082 4.968-7.006v-22.292c-0.313-4.851-4.714-5.223-4.714-5.223h-29.298s-5.424 0.318-5.502 5.605v21.91c9e-3 6.902 5.502 7.006 5.502 7.006h2.578l3.523 5.463c0.767 0.894 0.778 0.777 1.58 0.021z" style="fill-opacity:.67"/>
+ <path d="m17.387 44.002l3.91-5.484h17.453s4.968 0.081 4.968-7.006v-22.293c-0.313-4.851-4.714-5.223-4.714-5.223h-29.298s-5.424 0.318-5.502 5.606v21.91c9e-3 6.902 5.502 7.006 5.502 7.006h2.578l3.523 5.462c0.767 0.895 0.778 0.778 1.58 0.022z" style="fill:url(#_Linear1)"/>
+ <circle cx="32.84" cy="6.821" r="5.728" style="fill:url(#_Linear2)"/>
+ <defs>
+ <linearGradient id="_Linear1" x2="1" gradientTransform="matrix(.799284 -39.6049 39.6049 .799284 498.134 53.5618)" gradientUnits="userSpaceOnUse">
+ <stop style="stop-color:#888" offset="0"/>
+ <stop style="stop-color:#fefeff" offset="1"/>
+ </linearGradient>
+ <linearGradient id="_Linear2" x2="1" gradientTransform="matrix(7.01453e-16,-11.4556,11.4556,7.01453e-16,87.5702,12.5494)" gradientUnits="userSpaceOnUse">
+ <stop style="stop-color:#05f" offset="0"/>
+ <stop style="stop-color:#00a0ff" offset="1"/>
+ </linearGradient>
+ </defs>
+</svg>
diff --git a/awesome/bloat/notifs/notif-center/icons/notify-mode.svg b/awesome/bloat/notifs/notif-center/icons/notify-mode.svg
new file mode 100644
index 0000000..92b960b
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/icons/notify-mode.svg
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="512px"
+ viewBox="-21 0 512 512"
+ width="512px"
+ version="1.1"
+ id="svg12"
+ sodipodi:docname="notify-mode.svg"
+ inkscape:version="0.92.4 5da689c313, 2019-01-14">
+ <metadata
+ id="metadata18">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs16" />
+ <sodipodi:namedview
+ pagecolor="#252525"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1321"
+ inkscape:window-height="738"
+ id="namedview14"
+ showgrid="false"
+ inkscape:zoom="0.4609375"
+ inkscape:cx="-98.711864"
+ inkscape:cy="256"
+ inkscape:window-x="45"
+ inkscape:window-y="30"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg12" />
+ <g
+ id="g10"
+ transform="matrix(0.75500702,0,0,0.75500702,57.825511,62.718203)">
+ <path
+ d="m 448,232.14844 c -11.77734,0 -21.33203,-9.55469 -21.33203,-21.33203 0,-59.83985 -23.29688,-116.074222 -65.60156,-158.402348 -8.33985,-8.339843 -8.33985,-21.820312 0,-30.164062 8.33984,-8.339844 21.82421,-8.339844 30.16406,0 50.37109,50.367188 78.10156,117.33594 78.10156,188.56641 0,11.77734 -9.55469,21.33203 -21.33203,21.33203 z m 0,0"
+ data-original="#000000"
+ class="active-path"
+ style="fill:#ffffff"
+ data-darkreader-inline-fill=""
+ data-old_color="#000000"
+ id="path2"
+ inkscape:connector-curvature="0" />
+ <path
+ d="M 21.332031,232.14844 C 9.558594,232.14844 0,222.59375 0,210.81641 0,139.58594 27.734375,72.617188 78.101562,22.25 c 8.339844,-8.339844 21.824219,-8.339844 30.164068,0 8.34375,8.34375 8.34375,21.824219 0,30.164062 C 65.960938,94.71875 42.667969,150.97656 42.667969,210.81641 c 0,11.77734 -9.558594,21.33203 -21.335938,21.33203 z m 0,0"
+ data-original="#000000"
+ class="active-path"
+ style="fill:#ffffff"
+ data-darkreader-inline-fill=""
+ data-old_color="#000000"
+ id="path4"
+ inkscape:connector-curvature="0" />
+ <path
+ d="M 434.75391,360.8125 C 402.49609,333.54687 384,293.69531 384,251.47656 V 192 C 384,116.92969 328.23437,54.785156 256,44.375 V 21.332031 C 256,9.535156 246.44141,0 234.66797,0 222.89062,0 213.33203,9.535156 213.33203,21.332031 V 44.375 C 141.07812,54.785156 85.332031,116.92969 85.332031,192 v 59.47656 c 0,42.21875 -18.496093,82.07031 -50.941406,109.50391 -8.300781,7.10547 -13.058594,17.42969 -13.058594,28.35156 0,20.58984 16.746094,37.33594 37.335938,37.33594 H 410.66797 c 20.58594,0 37.33203,-16.7461 37.33203,-37.33594 0,-10.92187 -4.75781,-21.24609 -13.24609,-28.51953 z m 0,0"
+ data-original="#000000"
+ class="active-path"
+ style="fill:#ffffff"
+ data-darkreader-inline-fill=""
+ data-old_color="#000000"
+ id="path6"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 234.66797,512 c 38.63281,0 70.95312,-27.54297 78.3789,-64 H 156.28906 c 7.42188,36.45703 39.74219,64 78.37891,64 z m 0,0"
+ data-original="#000000"
+ class="active-path"
+ style="fill:#ffffff"
+ data-darkreader-inline-fill=""
+ data-old_color="#000000"
+ id="path8"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/awesome/bloat/notifs/notif-center/init.lua b/awesome/bloat/notifs/notif-center/init.lua
new file mode 100644
index 0000000..ce872ed
--- /dev/null
+++ b/awesome/bloat/notifs/notif-center/init.lua
@@ -0,0 +1,26 @@
+local wibox = require('wibox')
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+local notif_header = wibox.widget {
+ markup = 'Notification Center',
+ font = beautiful.font_name .. "12",
+ align = 'center',
+ valign = 'center',
+ widget = wibox.widget.textbox
+}
+
+return wibox.widget {
+ {
+ notif_header,
+ nil,
+ require("bloat.notifs.notif-center.clear-all"),
+ expand = "none",
+ spacing = dpi(10),
+ layout = wibox.layout.align.horizontal
+ },
+ require('bloat.notifs.notif-center.build-notifbox'),
+
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+}
diff --git a/awesome/bloat/notifs/playerctl.lua b/awesome/bloat/notifs/playerctl.lua
new file mode 100644
index 0000000..1712488
--- /dev/null
+++ b/awesome/bloat/notifs/playerctl.lua
@@ -0,0 +1,6 @@
+local naughty = require("naughty")
+
+awesome.connect_signal("bling::playerctl::title_artist_album",
+ function(title, artist, art_path)
+ naughty.notification({title = title, text = artist, image = art_path})
+end)
diff --git a/awesome/bloat/notifs/volume.lua b/awesome/bloat/notifs/volume.lua
new file mode 100644
index 0000000..d156fce
--- /dev/null
+++ b/awesome/bloat/notifs/volume.lua
@@ -0,0 +1,119 @@
+local wibox = require("wibox")
+local awful = require("awful")
+local gears = require("gears")
+local beautiful = require("beautiful")
+local helpers = require("helpers")
+local dpi = beautiful.xresources.apply_dpi
+
+local width = dpi(200)
+local height = dpi(200)
+local screen = awful.screen.focused()
+
+local active_color_1 = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor6}, {0.50, beautiful.xcolor4}}
+}
+
+local volume_icon = wibox.widget {
+ markup = "<span foreground='" .. beautiful.xcolor4 .. "'><b></b></span>",
+ align = 'center',
+ valign = 'center',
+ font = beautiful.font_name .. '70',
+ widget = wibox.widget.textbox
+}
+
+local volume_adjust = wibox({
+ screen = screen.primary,
+ type = "notification",
+ x = screen.geometry.width / 2 - width / 2,
+ y = screen.geometry.height / 2 - height / 2 + 300,
+ width = width,
+ height = height,
+ visible = false,
+ ontop = true,
+ bg = beautiful.xbackground .. "00"
+})
+
+local volume_bar = wibox.widget {
+ widget = wibox.widget.progressbar,
+ shape = gears.shape.rounded_bar,
+ bar_shape = gears.shape.rounded_bar,
+ color = active_color_1,
+ background_color = beautiful.xcolor0,
+ max_value = 100,
+ value = 0
+}
+
+volume_adjust:setup{
+ {
+ layout = wibox.layout.align.vertical,
+ {
+ volume_icon,
+ top = dpi(15),
+ left = dpi(50),
+ right = dpi(50),
+ bottom = dpi(15),
+ widget = wibox.container.margin
+ },
+ {
+ volume_bar,
+ left = dpi(25),
+ right = dpi(25),
+ bottom = dpi(30),
+ widget = wibox.container.margin
+ }
+
+ },
+ shape = helpers.rrect(beautiful.client_radius),
+ bg = beautiful.xbackground,
+ border_width = beautiful.widget_border_width,
+ border_color = beautiful.widget_border_color,
+ widget = wibox.container.background
+}
+
+-- create a 3 second timer to hide the volume adjust
+-- component whenever the timer is started
+local hide_volume_adjust = gears.timer {
+ timeout = 3,
+ autostart = true,
+ callback = function() volume_adjust.visible = false end
+}
+
+awesome.connect_signal("ears::volume", function(vol, muted)
+ volume_bar.value = vol
+ if muted or vol == 0 then
+ volume_icon.markup = "<span foreground='" .. beautiful.xcolor4 ..
+ "'><b>ﳌ</b></span>"
+ else
+ volume_icon.markup = "<span foreground='" .. beautiful.xcolor4 ..
+ "'><b></b></span>"
+
+ end
+
+ if volume_adjust.visible then
+ hide_volume_adjust:again()
+ else
+ volume_adjust.visible = true
+ hide_volume_adjust:start()
+ end
+
+end)
+--[[
+-- show volume-adjust when "volume_change" signal is emitted
+awesome.connect_signal("ears::volume", function(volume, muted)
+ if muted then
+ volume_bar.value = 0
+ else
+ volume_bar.value = volume
+ end
+ -- make volume_adjust component visible
+ if volume_adjust.visible then
+ hide_volume_adjust:again()
+ else
+ volume_adjust.visible = true
+ hide_volume_adjust:start()
+ end
+end)
+]] --
diff --git a/awesome/bloat/pop/dash.lua b/awesome/bloat/pop/dash.lua
new file mode 100644
index 0000000..bf8d8d5
--- /dev/null
+++ b/awesome/bloat/pop/dash.lua
@@ -0,0 +1,339 @@
+-- panel.lua
+-- Panel Widget
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+local helpers = require("helpers")
+
+local popupLib = require("utils.popupLib")
+
+local box_radius = beautiful.client_radius
+local box_gap = dpi(8)
+
+local function create_boxed_widget(widget_to_be_boxed, width, height, bg_color)
+ local box_container = wibox.container.background()
+ box_container.bg = bg_color
+ box_container.forced_height = height
+ box_container.forced_width = width
+ box_container.shape = helpers.rrect(box_radius)
+ box_container.border_width = beautiful.widget_border_width
+ box_container.border_color = beautiful.widget_border_color
+
+ local boxed_widget = wibox.widget {
+ {
+ {
+ nil,
+ {
+ nil,
+ widget_to_be_boxed,
+ layout = wibox.layout.align.vertical,
+ expand = "none"
+ },
+ layout = wibox.layout.align.horizontal
+ },
+ widget = box_container
+ },
+ margins = box_gap,
+ color = "#FF000000",
+ widget = wibox.container.margin
+ }
+ return boxed_widget
+end
+
+-- Helper function that changes the appearance of progress bars and their icons
+-- Create horizontal rounded bars
+local function format_progress_bar(bar, markup)
+ local text = wibox.widget {
+ markup = markup,
+ align = 'center',
+ valign = 'center',
+ font = beautiful.font_name .. '25',
+ widget = wibox.widget.textbox
+ }
+ text.forced_height = dpi(36)
+ text.forced_width = dpi(36)
+ text.resize = true
+
+ local w = wibox.widget {text, bar, layout = wibox.layout.stack}
+ return w
+end
+
+--- {{{ Volume Widget
+
+local volume_bar = require("bloat.widgets.volume_arc")
+local volume = format_progress_bar(volume_bar, "<span foreground='" ..
+ beautiful.xcolor6 ..
+ "'><b></b></span>")
+
+awesome.connect_signal("ears::volume", function(vol, muted)
+ if muted or vol == 0 then
+ volume.children[1].markup = "<span foreground='" .. beautiful.xcolor6 ..
+ "'><b></b></span>"
+ else
+ if vol then
+ if vol > 50 then
+ volume.children[1].markup =
+ "<span foreground='" .. beautiful.xcolor6 ..
+ "'><b></b></span>"
+ else
+ volume.children[1].markup =
+ "<span foreground='" .. beautiful.xcolor6 ..
+ "'><b></b></span>"
+
+ end
+ end
+ end
+end)
+
+apps_volume = function()
+ helpers.run_or_raise({class = 'Pavucontrol'}, true, "pavucontrol")
+end
+
+volume:buttons(gears.table.join( -- Left click - Mute / Unmute
+ awful.button({}, 1, function() helpers.volume_control(0) end),
+ -- Scroll - Increase / Decrease volume
+ awful.button({}, 4, function() helpers.volume_control(5) end),
+ awful.button({}, 5, function() helpers.volume_control(-5) end)))
+
+-- }}}
+--
+--- {{{ Brightness Widget
+
+local brightness_bar = require("bloat.widgets.brightness_arc")
+local brightness = format_progress_bar(brightness_bar, "<span foreground='" ..
+ beautiful.xcolor5 ..
+ "'><b></b></span>")
+
+-- local brightness = require("bloat.widgets.brightness_arc")
+
+--- }}}
+
+--- {{{ Ram Widget
+
+-- local ram = require("bloat.widgets.ram_arc")
+
+local ram_bar = require("bloat.widgets.ram_arc")
+local ram = format_progress_bar(ram_bar, "<span foreground='" ..
+ beautiful.xcolor3 .. "'><b></b></span>")
+
+--- }}}
+
+--- {{{ Disk Widget
+
+local disk_bar = require("bloat.widgets.disk_arc")
+local disk = format_progress_bar(disk_bar, "<span foreground='" ..
+ beautiful.xcolor2 .. "'><b></b></span>")
+
+--- }}}
+
+--- {{{ Temp Widget
+
+local temp_bar = require("bloat.widgets.temp_arc")
+local temp = format_progress_bar(temp_bar, "<span foreground='" ..
+ beautiful.xcolor1 .. "'><b></b></span>")
+
+--- }}}
+
+--- {{{ Cpu Widget
+
+-- local cpu = require("bloat.widgets.cpu_arc")
+
+local cpu_bar = require("bloat.widgets.cpu_arc")
+local cpu = format_progress_bar(cpu_bar, "<span foreground='" ..
+ beautiful.xcolor4 .. "'><b></b></span>")
+
+--- }}}
+
+--- {{{ Clock
+
+local fancy_time_widget = wibox.widget.textclock("%H%M")
+fancy_time_widget.markup = fancy_time_widget.text:sub(1, 2) ..
+ "<span foreground='" .. beautiful.xcolor12 ..
+ "'>" .. fancy_time_widget.text:sub(3, 4) ..
+ "</span>"
+fancy_time_widget:connect_signal("widget::redraw_needed", function()
+ fancy_time_widget.markup = fancy_time_widget.text:sub(1, 2) ..
+ "<span foreground='" .. beautiful.xcolor12 ..
+ "'>" .. fancy_time_widget.text:sub(3, 4) ..
+ "</span>"
+end)
+fancy_time_widget.align = "center"
+fancy_time_widget.valign = "center"
+fancy_time_widget.font = beautiful.font_name .. "55"
+
+local fancy_time = {fancy_time_widget, layout = wibox.layout.fixed.vertical}
+
+local fancy_date_widget = wibox.widget.textclock("%m/%d/%Y")
+fancy_date_widget.markup = fancy_date_widget.text:sub(1, 3) ..
+ "<span foreground='" .. beautiful.xcolor12 ..
+ "'>" .. fancy_date_widget.text:sub(4, 6) ..
+ "</span>" .. "<span foreground='" ..
+ beautiful.xcolor6 .. "'>" ..
+ fancy_date_widget.text:sub(7, 10) .. "</span>"
+fancy_date_widget:connect_signal("widget::redraw_needed", function()
+ fancy_date_widget.markup = fancy_date_widget.text:sub(1, 3) ..
+ "<span foreground='" .. beautiful.xcolor12 ..
+ "'>" .. fancy_date_widget.text:sub(4, 6) ..
+ "</span>" .. "<span foreground='" ..
+ beautiful.xcolor6 .. "'>" ..
+ fancy_date_widget.text:sub(7, 10) ..
+ "</span>"
+
+end)
+fancy_date_widget.align = "center"
+fancy_date_widget.valign = "center"
+fancy_date_widget.font = beautiful.font_name .. "12"
+
+local fancy_date = {fancy_date_widget, layout = wibox.layout.fixed.vertical}
+
+---}}}
+
+-- {{{ Music Widget
+
+local playerctl = require("bloat.widgets.playerctl")
+local playerctl_box = create_boxed_widget(playerctl, 400, 145,
+ beautiful.xbackground)
+
+-- {{{ Info Widget
+
+local info = require("bloat.widgets.info")
+local info_box = create_boxed_widget(info, 400, 145, beautiful.xbackground)
+
+-- }}}
+
+-- {{ Weather
+
+local weather = require("bloat.widgets.weather")
+local weather_box =
+ create_boxed_widget(weather, 400, 100, beautiful.xbackground)
+
+-- }}
+
+local sys = wibox.widget {
+ {
+ cpu,
+ top = dpi(20),
+ bottom = dpi(0),
+ left = dpi(0),
+ right = dpi(0),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ volume,
+ top = dpi(0),
+ bottom = dpi(20),
+ left = dpi(10),
+ right = dpi(0),
+ widget = wibox.container.margin
+ },
+ {
+ brightness,
+ top = dpi(0),
+ bottom = dpi(20),
+ left = dpi(0),
+ right = dpi(10),
+ widget = wibox.container.margin
+ },
+ layout = wibox.layout.flex.horizontal
+ },
+ spacing = dpi(0),
+ layout = wibox.layout.flex.vertical
+}
+
+local sys2 = wibox.widget {
+ {
+ ram,
+ top = dpi(20),
+ bottom = dpi(0),
+ left = dpi(0),
+ right = dpi(0),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ disk,
+ top = dpi(0),
+ bottom = dpi(20),
+ left = dpi(10),
+ right = dpi(0),
+ widget = wibox.container.margin
+ },
+ {
+ temp,
+ top = dpi(0),
+ bottom = dpi(20),
+ left = dpi(0),
+ right = dpi(10),
+ widget = wibox.container.margin
+ },
+ layout = wibox.layout.flex.horizontal
+ },
+ spacing = dpi(0),
+ layout = wibox.layout.flex.vertical
+}
+
+-- local sys2 = wibox.widget {ram, disk, temp, layout = wibox.layout.flex.vertical}
+
+local sys_box = create_boxed_widget(sys, 400, 200, beautiful.xbackground)
+local sys_box2 = create_boxed_widget(sys2, 400, 200, beautiful.xbackground)
+
+local time = wibox.widget {
+ {fancy_time, fancy_date, layout = wibox.layout.align.vertical},
+ top = dpi(0),
+ left = dpi(20),
+ right = dpi(20),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+}
+
+local time_box = create_boxed_widget(time, 400, 159, beautiful.xbackground)
+
+local panelWidget = wibox.widget {
+ {info_box, sys_box, layout = wibox.layout.align.vertical},
+ {weather_box, time_box, layout = wibox.layout.align.vertical},
+ {playerctl_box, sys_box2, layout = wibox.layout.align.vertical},
+ layout = wibox.layout.flex.horizontal
+}
+
+local dash_manager = {}
+local dashboard = wibox({visible = false, ontop = true, type = "splash"})
+awful.placement.maximize(dashboard)
+
+dashboard.bg = beautiful.exit_screen_bg or "#111111"
+dashboard.fg = beautiful.exit_screen_fg or "#FEFEFE"
+
+local dash_grabber
+
+dash_manager.dash_hide = function()
+ awful.keygrabber.stop(dash_grabber)
+ dashboard.visible = false
+ awesome.emit_signal("widgets::splash::visibility", dashboard.visible)
+end
+
+dash_manager.dash_show = function()
+ dash_grabber = awful.keygrabber.run(function(_, key, event)
+ -- Ignore case
+ key = key:lower()
+ if event == "release" then return end
+ if key == 'escape' or key == 'q' or key == 'x' then
+ dash_manager.dash_hide()
+ end
+ end)
+ dashboard.visible = true
+ awesome.emit_signal("widgets::splash::visibility", dashboard.visible)
+end
+
+dashboard:setup{
+ nil,
+ {nil, panelWidget, expand = "none", layout = wibox.layout.align.horizontal},
+ expand = "none",
+ layout = wibox.layout.align.vertical
+}
+
+return dash_manager
+
+-- EOF ------------------------------------------------------------------------
diff --git a/awesome/bloat/pop/exitscreen.lua b/awesome/bloat/pop/exitscreen.lua
new file mode 100644
index 0000000..81753ae
--- /dev/null
+++ b/awesome/bloat/pop/exitscreen.lua
@@ -0,0 +1,170 @@
+-- exitscreen.lua
+-- Exit Screen Widget
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+local helpers = require("helpers")
+local pad = helpers.pad
+
+-- Appearance
+local icon_font = "Fira Code NerdFont Mono 45"
+local poweroff_text_icon = ""
+local reboot_text_icon = ""
+local suspend_text_icon = ""
+local exit_text_icon = ""
+local lock_text_icon = ""
+
+local button_bg = beautiful.xbackground
+local button_size = dpi(120)
+
+local lock_screen = require("bloat.lockscreen")
+lock_screen.init()
+
+-- Commands
+local poweroff_command =
+ function() awful.spawn.with_shell("systemctl poweroff") end
+local reboot_command = function() awful.spawn.with_shell("systemctl reboot") end
+local suspend_command = function()
+ lock_screen_show()
+ awful.spawn.with_shell("systemctl hibernate")
+end
+local exit_command = function() awesome.quit() end
+local lock_command = function() lock_screen_show() end
+
+-- Helper function that generates the clickable buttons
+local create_button = function(symbol, hover_color, text, command)
+ local icon = wibox.widget {
+ forced_height = button_size,
+ forced_width = button_size,
+ align = "center",
+ valign = "center",
+ font = icon_font,
+ text = symbol,
+ widget = wibox.widget.textbox()
+ }
+
+ local button = wibox.widget {
+ {nil, icon, expand = "none", layout = wibox.layout.align.horizontal},
+ forced_height = button_size,
+ forced_width = button_size,
+ shape = helpers.rrect(10),
+ bg = button_bg,
+ border_width = beautiful.widget_border_width,
+ border_color = beautiful.widget_border_color,
+ widget = wibox.container.background
+ }
+
+ -- Bind left click to run the command
+ button:buttons(gears.table.join(
+ awful.button({}, 1, function() command() end)))
+
+ -- Change color on hover
+ button:connect_signal("mouse::enter", function()
+ icon.markup = helpers.colorize_text(icon.text, hover_color)
+ button.border_color = hover_color
+ end)
+ button:connect_signal("mouse::leave", function()
+ icon.markup = helpers.colorize_text(icon.text, beautiful.xforeground)
+ button.border_color = beautiful.widget_border_color
+ end)
+
+ -- Use helper function to change the cursor on hover
+ helpers.add_hover_cursor(button, "hand1")
+
+ return button
+end
+
+-- Create the buttons
+local poweroff = create_button(poweroff_text_icon, beautiful.xcolor1,
+ "Poweroff", poweroff_command)
+local reboot = create_button(reboot_text_icon, beautiful.xcolor2, "Reboot",
+ reboot_command)
+local suspend = create_button(suspend_text_icon, beautiful.xcolor3, "Suspend",
+ suspend_command)
+local exit = create_button(exit_text_icon, beautiful.xcolor4, "Exit",
+ exit_command)
+local lock = create_button(lock_text_icon, beautiful.xcolor5, "Lock",
+ lock_command)
+
+local exit_manager = {}
+-- Create the exit screen wibox
+local exit_screen = wibox({visible = false, ontop = true, type = "splash"})
+awful.placement.maximize(exit_screen)
+
+exit_screen.bg = beautiful.exit_screen_bg or exitscreen_bg or "#111111"
+exit_screen.fg = beautiful.exit_screen_fg or beautiful.wibar_fg or "#FEFEFE"
+
+local exit_screen_grabber
+
+exit_manager.exit_screen_hide = function()
+ awful.keygrabber.stop(exit_screen_grabber)
+ exit_screen.visible = false
+ awesome.emit_signal("widgets::splash::visibility", exit_screen.visible)
+end
+
+exit_manager.exit_screen_show = function()
+ exit_screen_grabber = awful.keygrabber.run(
+ function(_, key, event)
+ -- Ignore case
+ key = key:lower()
+
+ if event == "release" then return end
+
+ if key == 's' then
+ suspend_command()
+ exit_manager.exit_screen_hide()
+ -- 'e' for exit
+ elseif key == 'e' then
+ exit_command()
+ elseif key == 'l' then
+ exit_manager.exit_screen_hide()
+ lock_command()
+ elseif key == 'p' then
+ poweroff_command()
+ elseif key == 'r' then
+ reboot_command()
+ elseif key == 'escape' or key == 'q' or key == 'x' then
+ exit_manager.exit_screen_hide()
+ end
+ end)
+ exit_screen.visible = true
+ awesome.emit_signal("widgets::splash::visibility", exit_screen.visible)
+end
+
+exit_screen:buttons(gears.table.join( -- Left click - Hide exit_screen
+ awful.button({}, 1, function()
+ exit_manager.exit_screen_hide()
+ end), -- Middle click - Hide exit_screen
+ awful.button({}, 2, function() exit_manager.exit_screen_hide() end),
+ -- Right click - Hide exit_screen
+ awful.button({}, 3, function()
+ exit_manager.exit_screen_hide()
+ end)))
+
+-- Item placement
+exit_screen:setup{
+ nil,
+ {
+ nil,
+ {
+ poweroff,
+ reboot,
+ suspend,
+ exit,
+ lock,
+ spacing = dpi(50),
+ layout = wibox.layout.fixed.horizontal
+ },
+ expand = "none",
+ layout = wibox.layout.align.horizontal
+ },
+ expand = "none",
+ layout = wibox.layout.align.vertical
+}
+
+return exit_manager
+
+-- EOF ------------------------------------------------------------------------
diff --git a/awesome/bloat/pop/init.lua b/awesome/bloat/pop/init.lua
new file mode 100644
index 0000000..a8e288d
--- /dev/null
+++ b/awesome/bloat/pop/init.lua
@@ -0,0 +1,8 @@
+local exit_manager = require(... .. ".exitscreen")
+local dash_manager = require(... .. ".dash")
+
+awesome.connect_signal("widgets::dashboard::show",
+ function() dash_manager.dash_show() end)
+
+awesome.connect_signal("widgets::exit_screen::show",
+ function() exit_manager.exit_screen_show() end)
diff --git a/awesome/bloat/pop/notif.lua b/awesome/bloat/pop/notif.lua
new file mode 100644
index 0000000..79f1155
--- /dev/null
+++ b/awesome/bloat/pop/notif.lua
@@ -0,0 +1,33 @@
+-- notif.lua
+-- Notification Popup Widget
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+
+local popupLib = require("utils.popupLib")
+
+local popupWidget = wibox.widget {
+ {
+ require("bloat.notifs.notif-center"),
+ margins = dpi(8),
+ widget = wibox.container.margin
+ },
+ expand = "none",
+ layout = wibox.layout.fixed.horizontal
+}
+
+local width = 400
+local margin = -1 * beautiful.widget_border_width
+
+local popup = popupLib.create(awful.screen.focused().geometry.width - width +
+ (-1 * margin), margin, nil, width,
+ popupWidget, dpi(25), false, false, false, true)
+
+popup:set_xproperty("WM_NAME", "panel")
+
+return popup
+
+-- EOF ------------------------------------------------------------------------
diff --git a/awesome/bloat/titlebars/init.lua b/awesome/bloat/titlebars/init.lua
new file mode 100644
index 0000000..6dd1ea4
--- /dev/null
+++ b/awesome/bloat/titlebars/init.lua
@@ -0,0 +1,51 @@
+local gears = require("gears")
+local awful = require("awful")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+local helpers = require("helpers")
+
+local tb_ops = {}
+
+local add_decorations = function(c) require("bloat.titlebars.top")(c) end
+
+tb_ops.enable_tb = function(c) add_decorations(c) end
+
+tb_ops.disable_tb = function(c) awful.titlebar.hide(c, "top") end
+
+client.connect_signal("request::titlebars", function(c)
+
+ client.connect_signal("property::floating", function(c)
+ local b = false;
+ if c.first_tag ~= nil then
+ b = c.first_tag.layout.name == "floating"
+ end
+ if c.floating or b then
+ tb_ops.enable_tb(c)
+ else
+ if not c.bling_tabbed then tb_ops.disable_tb(c) end
+ end
+ end)
+
+ client.connect_signal("manage", function(c)
+ if c.floating or c.first_tag.layout.name == "floating" then
+ tb_ops.enable_tb(c)
+ else
+ if not c.bling_tabbed then tb_ops.disable_tb(c) end
+ end
+ end)
+
+ tag.connect_signal("property::layout", function(t)
+ local clients = t:clients()
+ for k, c in pairs(clients) do
+ if c.floating or c.first_tag.layout.name == "floating" then
+ tb_ops.enable_tb(c)
+ else
+ if not c.bling_tabbed then tb_ops.disable_tb(c) end
+ end
+ end
+ end)
+
+end)
+
+return tb_ops
diff --git a/awesome/bloat/titlebars/top.lua b/awesome/bloat/titlebars/top.lua
new file mode 100644
index 0000000..247b8fd
--- /dev/null
+++ b/awesome/bloat/titlebars/top.lua
@@ -0,0 +1,99 @@
+local wibox = require("wibox")
+local awful = require("awful")
+local gears = require("gears")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+local helpers = require("helpers")
+
+local titlebar
+
+local get_titlebar = function(c, height, color)
+
+ local buttons = gears.table.join(awful.button({}, 1, function()
+ client.focus = c
+ c:raise()
+ awful.mouse.client.move(c)
+ end), awful.button({}, 3, function()
+ client.focus = c
+ c:raise()
+ awful.mouse.client.resize(c)
+ end))
+
+ --[[ local wid = wibox.widget {
+ {
+ {
+ bg = color,
+ shape = helpers.prrect(beautiful.border_radius, true, true,
+ false, false),
+ widget = wibox.container.background
+ },
+ top = beautiful.oof_border_width,
+ left = beautiful.oof_border_width,
+ right = beautiful.oof_border_width,
+ widget = wibox.container.margin
+ },
+ shape = helpers.prrect(beautiful.border_radius + 2, true, true, false,
+ false),
+ widget = wibox.container.background
+ }
+
+ wid.bg = beautiful.xcolor0
+ --]]
+
+ --[[
+ local function update()
+ if client.focus == c then
+ wid.bg = beautiful.xcolor8
+ else
+ wid.bg = beautiful.xcolor0
+ end
+ end
+ update()
+ c:connect_signal("focus", update)
+ c:connect_signal("unfocus", update)
+ --]]
+
+ awful.titlebar(c, {size = height, bg = color}):setup{
+ nil,
+ -- {
+ -- {
+ -- wid,
+ { -- Middle
+ { -- Title
+ align = 'center',
+ valign = 'center',
+ widget = awful.titlebar.widget.titlewidget(c)
+ },
+ buttons = buttons,
+ layout = wibox.layout.flex.horizontal
+ },
+ --[[ top = 14,
+ left = 14,
+ right = 14,
+ widget = wibox.container.margin
+ },
+ bg = beautiful.xbackground,
+ shape = helpers.prrect(beautiful.border_radius + 2, true, true,
+ false, false),
+ widget = wibox.container.background --]]
+ -- },
+ nil,
+ layout = wibox.layout.align.horizontal
+ }
+end
+
+local top = function(c)
+ local color = beautiful.xbackground
+
+ if c.class == "firefox" then
+ color = beautiful.xcolor0
+ else
+ color = beautiful.xcolor0
+ end
+
+ local titlebar_height = beautiful.titlebar_size
+ get_titlebar(c, titlebar_height, color)
+end
+
+return top
diff --git a/awesome/bloat/widgets/brightness_arc.lua b/awesome/bloat/widgets/brightness_arc.lua
new file mode 100644
index 0000000..13513e0
--- /dev/null
+++ b/awesome/bloat/widgets/brightness_arc.lua
@@ -0,0 +1,28 @@
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {150, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor5}, {0.75, beautiful.xcolor13}}
+}
+
+local brightness_arc = wibox.widget {
+ thickness = 8,
+ start_angle = 4.71238898, -- 2pi*3/4
+ rounded_edge = true,
+ bg = beautiful.xcolor0,
+ paddings = 10,
+ min_value = 0,
+ max_value = 100,
+ value = 25,
+ colors = {active_color},
+ widget = wibox.container.arcchart
+}
+
+awesome.connect_signal("ears::brightness", function(value)
+ if value >= 0 then brightness_arc.value = value end
+end)
+return brightness_arc
diff --git a/awesome/bloat/widgets/brightness_bar.lua b/awesome/bloat/widgets/brightness_bar.lua
new file mode 100644
index 0000000..98c7fc6
--- /dev/null
+++ b/awesome/bloat/widgets/brightness_bar.lua
@@ -0,0 +1,33 @@
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+-- Set colors
+local active_color_1 = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor5}, {0.75, beautiful.xcolor13}}
+}
+local background_color_1 = beautiful.xbackground
+
+local brightness_bar = wibox.widget {
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(10),
+ margins = {top = dpi(8), bottom = dpi(8)},
+ forced_width = dpi(200),
+ shape = gears.shape.rounded_bar,
+ bar_shape = gears.shape.rounded_bar,
+ color = active_color_1,
+ background_color = background_color_1,
+ border_width = 0,
+ border_color = beautiful.border_color,
+ widget = wibox.widget.progressbar
+}
+
+awesome.connect_signal("ears::brightness",
+ function(value) brightness_bar.value = value end)
+
+return brightness_bar
diff --git a/awesome/bloat/widgets/button.lua b/awesome/bloat/widgets/button.lua
new file mode 100644
index 0000000..56d66e5
--- /dev/null
+++ b/awesome/bloat/widgets/button.lua
@@ -0,0 +1,108 @@
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+local gears = require("gears")
+
+local button = {}
+
+button.create = function(image, size, radius, margin, bg, bg_hover, bg_press,
+ command)
+ local button_image = wibox.widget {
+ image = image,
+ forced_height = size,
+ forced_width = size,
+ widget = wibox.widget.imagebox
+ }
+
+ local button = wibox.widget {
+ {button_image, margins = dpi(margin), widget = wibox.container.margin},
+ bg = bg,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(radius))
+ end,
+ widget = wibox.container.background
+ }
+
+ button:connect_signal("button::press", function()
+ button.bg = bg_press
+ command()
+ end)
+
+ button:connect_signal("button::leave", function() button.bg = bg end)
+ button:connect_signal("mouse::enter", function() button.bg = bg_hover end)
+ button:connect_signal("mouse::leave", function() button.bg = bg end)
+
+ button.update_image = function(image) button_image.image = image end
+
+ return button
+end
+
+button.create_widget = function(widget, command)
+ local button = wibox.widget {
+ {widget, margins = dpi(10), widget = wibox.container.margin},
+ bg = beautiful.bg_normal,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(10))
+ end,
+ widget = wibox.container.background
+ }
+
+ button:connect_signal("button::press", function()
+ button.bg = beautiful.bg_very_light
+ command()
+ end)
+
+ button:connect_signal("button::leave",
+ function() button.bg = beautiful.bg_normal end)
+ button:connect_signal("mouse::enter",
+ function() button.bg = beautiful.bg_light end)
+ button:connect_signal("mouse::leave",
+ function() button.bg = beautiful.bg_normal end)
+
+ return button
+end
+
+button.create_image = function(image, image_hover)
+ local image_widget = wibox.widget {
+ image = image,
+ widget = wibox.widget.imagebox
+ }
+
+ image_widget:connect_signal("mouse::enter",
+ function() image_widget.image = image_hover end)
+ image_widget:connect_signal("mouse::leave",
+ function() image_widget.image = image end)
+
+ return image_widget
+end
+
+button.create_image_onclick = function(image, image_hover, onclick)
+ local image = button.create_image(image, image_hover)
+
+ local container = wibox.widget {image, widget = wibox.container.background}
+
+ container:connect_signal("button::press", onclick)
+
+ return container
+end
+
+button.create_text = function(color, color_hover, text, font)
+ local textWidget = wibox.widget {
+ font = font,
+ markup = "<span foreground='" .. color .. "'>" .. text .. "</span>",
+ widget = wibox.widget.textbox
+ }
+
+ textWidget:connect_signal("mouse::enter", function()
+ textWidget.markup =
+ "<span foreground='" .. color_hover .. "'>" .. text .. "</span>"
+ end)
+ textWidget:connect_signal("mouse::leave", function()
+ textWidget.markup = "<span foreground='" .. color .. "'>" .. text ..
+ "</span>"
+ end)
+
+ return textWidget
+end
+
+return button
diff --git a/awesome/bloat/widgets/cpu_arc.lua b/awesome/bloat/widgets/cpu_arc.lua
new file mode 100644
index 0000000..ddbd6b4
--- /dev/null
+++ b/awesome/bloat/widgets/cpu_arc.lua
@@ -0,0 +1,26 @@
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor4}, {0.75, beautiful.xcolor12}}
+}
+
+local cpu_arc = wibox.widget {
+ max_value = 100,
+ thickness = 8,
+ start_angle = 4.71238898, -- 2pi*3/4
+ rounded_edge = true,
+ bg = beautiful.xcolor0,
+ paddings = 10,
+ colors = {active_color},
+ widget = wibox.container.arcchart
+}
+
+awesome.connect_signal("ears::cpu", function(value) cpu_arc.value = value end)
+
+return cpu_arc
diff --git a/awesome/bloat/widgets/cpu_bar.lua b/awesome/bloat/widgets/cpu_bar.lua
new file mode 100644
index 0000000..13531b8
--- /dev/null
+++ b/awesome/bloat/widgets/cpu_bar.lua
@@ -0,0 +1,39 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+-- Set colors
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor4}, {0.75, beautiful.xcolor12}}
+}
+
+local background_color = beautiful.xbackground
+
+local cpu_bar = wibox.widget {
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(10),
+ margins = {top = dpi(8), bottom = dpi(8)},
+ forced_width = dpi(200),
+ shape = gears.shape.rounded_bar,
+ bar_shape = gears.shape.rounded_bar,
+ color = active_color,
+ background_color = background_color,
+ border_width = 0,
+ border_color = beautiful.border_color,
+ widget = wibox.widget.progressbar
+}
+
+awesome.connect_signal("ears::cpu", function(value)
+ -- Use this if you want to display usage percentage
+ cpu_bar.value = value
+ -- Use this if you want to display idle percentage
+ -- cpu_bar.value = tonumber(100 - value)
+end)
+
+return cpu_bar
diff --git a/awesome/bloat/widgets/disk_arc.lua b/awesome/bloat/widgets/disk_arc.lua
new file mode 100644
index 0000000..2681038
--- /dev/null
+++ b/awesome/bloat/widgets/disk_arc.lua
@@ -0,0 +1,28 @@
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {150, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor2}, {0.75, beautiful.xcolor10}}
+}
+
+local disk_arc = wibox.widget {
+ max_value = 100,
+ thickness = 8,
+ start_angle = 4.71238898, -- 2pi*3/4
+ rounded_edge = true,
+ bg = beautiful.xcolor0,
+ paddings = 10,
+ colors = {active_color},
+ widget = wibox.container.arcchart
+}
+
+awesome.connect_signal("ears::disk", function(used, total)
+ disk_arc.value = tonumber(100 * used / total)
+end)
+
+return disk_arc
diff --git a/awesome/bloat/widgets/disk_bar.lua b/awesome/bloat/widgets/disk_bar.lua
new file mode 100644
index 0000000..4eae8ca
--- /dev/null
+++ b/awesome/bloat/widgets/disk_bar.lua
@@ -0,0 +1,36 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+-- Set colors
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor2}, {0.75, beautiful.xcolor10}}
+}
+
+local background_color = beautiful.xbackground
+
+local disk_bar = wibox.widget {
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(10),
+ margins = {top = dpi(8), bottom = dpi(8)},
+ forced_width = dpi(200),
+ shape = gears.shape.rounded_bar,
+ bar_shape = gears.shape.rounded_bar,
+ color = active_color,
+ background_color = background_color,
+ border_width = 0,
+ border_color = beautiful.border_color,
+ widget = wibox.widget.progressbar
+}
+
+awesome.connect_signal("ears::disk", function(used, total)
+ disk_bar.value = tonumber(100 * used / total)
+end)
+
+return disk_bar
diff --git a/awesome/bloat/widgets/info.lua b/awesome/bloat/widgets/info.lua
new file mode 100644
index 0000000..3d32960
--- /dev/null
+++ b/awesome/bloat/widgets/info.lua
@@ -0,0 +1,57 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local naughty = require("naughty")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+
+local helpers = require("helpers")
+local pad = helpers.pad
+
+-- Text lines
+------------------------------------------------------------
+local user = wibox.widget {
+ markup = "<span foreground='" .. beautiful.xcolor6 .. "'>JavaCafe01</span>",
+ widget = wibox.widget.textbox
+}
+local name = wibox.widget {
+ markup = "<span foreground='" .. beautiful.xcolor4 .. "'>Gokul Swami</span>",
+ widget = wibox.widget.textbox
+}
+
+user:set_font(beautiful.font)
+user:set_valign("top")
+name:set_font(beautiful.font_name .. "14")
+name:set_valign("top")
+
+local text_area = wibox.layout.fixed.vertical()
+text_area:add(name)
+text_area:add(user)
+------------------------------------------------------------
+
+-- Bring it all together
+------------------------------------------------------------
+local align_vertical = wibox.layout.align.vertical()
+align_vertical:set_middle(text_area)
+align_vertical.expand = "none"
+local area = wibox.widget {
+ {
+ markup = "<span foreground='" .. beautiful.xcolor2 .. "'></span>",
+ font = "FiraCode Nerd Font Mono 40",
+ widget = wibox.widget.textbox
+ },
+ align_vertical,
+ expand = "outside",
+ layout = wibox.layout.align.horizontal
+}
+
+local main_wd = wibox.widget {
+ area,
+ left = dpi(80),
+ forced_width = dpi(200),
+ forced_height = dpi(100),
+ widget = wibox.container.margin
+}
+
+return main_wd
diff --git a/awesome/bloat/widgets/pacman_taglist.lua b/awesome/bloat/widgets/pacman_taglist.lua
new file mode 100644
index 0000000..bc85810
--- /dev/null
+++ b/awesome/bloat/widgets/pacman_taglist.lua
@@ -0,0 +1,92 @@
+local awful = require("awful")
+local gears = require("gears")
+local gfs = gears.filesystem
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+
+local get_taglist = function(s)
+
+ -- Taglist buttons
+ local taglist_buttons = gears.table.join(
+ awful.button({}, 1,
+ function(t) t:view_only() end),
+ awful.button({modkey}, 1, function(t)
+ if client.focus then client.focus:move_to_tag(t) end
+ end), awful.button({}, 3, awful.tag.viewtoggle),
+ awful.button({modkey}, 3, function(t)
+ if client.focus then client.focus:toggle_tag(t) end
+ end), awful.button({}, 4, function(t)
+ awful.tag.viewnext(t.screen)
+ end), awful.button({}, 5, function(t)
+ awful.tag.viewprev(t.screen)
+ end))
+
+ -- The actual png icons
+ -- I do have the svgs, but inkscape does a better job of scaling
+ local ghost = gears.surface.load_uncached(
+ gfs.get_configuration_dir() .. "icons/ghosts/ghost.png")
+ local ghost_icon = gears.color.recolor_image(ghost, beautiful.xcolor6)
+ local dot = gears.surface.load_uncached(
+ gfs.get_configuration_dir() .. "icons/ghosts/dot.png")
+ local dot_icon = gears.color.recolor_image(dot, beautiful.xcolor8)
+ local pacman = gears.surface.load_uncached(
+ gfs.get_configuration_dir() .. "icons/ghosts/pacman.png")
+ local pacman_icon = gears.color.recolor_image(pacman, beautiful.xcolor3)
+
+ -- Function to update the tags
+ local update_tags = function(self, c3)
+ local imgbox = self:get_children_by_id('icon_role')[1]
+ if c3.selected then
+ imgbox.image = pacman_icon
+ elseif #c3:clients() == 0 then
+ imgbox.image = dot_icon
+ else
+ imgbox.image = ghost_icon
+ end
+ end
+
+ local pac_taglist = awful.widget.taglist {
+ screen = s,
+ filter = awful.widget.taglist.filter.all,
+ style = {shape = gears.shape.rectangle},
+ layout = {spacing = 0, layout = wibox.layout.fixed.horizontal},
+ widget_template = {
+ {
+ {id = 'icon_role', widget = wibox.widget.imagebox},
+ id = 'margin_role',
+ top = dpi(7),
+ bottom = dpi(7),
+ left = dpi(10),
+ right = dpi(10),
+ widget = wibox.container.margin
+ },
+ id = 'background_role',
+ widget = wibox.container.background,
+ create_callback = function(self, c3, index, objects)
+ update_tags(self, c3)
+ self:connect_signal('mouse::enter', function()
+ if self.bg ~= beautiful.xbackground .. "60" then
+ self.backup = self.bg
+ self.has_backup = true
+ end
+ self.bg = beautiful.xbackground .. "60"
+ end)
+ self:connect_signal('mouse::leave', function()
+ if self.has_backup then
+ self.bg = self.backup
+ end
+ end)
+ end,
+ update_callback = function(self, c3, index, objects)
+ update_tags(self, c3)
+ end
+ },
+ buttons = taglist_buttons
+ }
+
+ return pac_taglist
+end
+
+return get_taglist
diff --git a/awesome/bloat/widgets/playerctl.lua b/awesome/bloat/widgets/playerctl.lua
new file mode 100644
index 0000000..f9fe171
--- /dev/null
+++ b/awesome/bloat/widgets/playerctl.lua
@@ -0,0 +1,171 @@
+local gears = require("gears")
+local awful = require("awful")
+local wibox = require("wibox")
+local helpers = require("helpers")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+
+local art = wibox.widget {
+ image = gears.filesystem.get_configuration_dir() .. "images/default.png",
+ resize = true,
+ forced_height = dpi(80),
+ forced_width = dpi(80),
+ clip_shape = helpers.rrect(beautiful.border_radius - 5),
+ widget = wibox.widget.imagebox
+}
+
+local create_button = function(symbol, color, command, playpause)
+
+ local icon = wibox.widget {
+ markup = helpers.colorize_text(symbol, color),
+ font = "FiraCode Nerd Font Mono 20",
+ align = "center",
+ valigin = "center",
+ widget = wibox.widget.textbox()
+ }
+
+ local button = wibox.widget {
+ icon,
+ forced_height = dpi(30),
+ forced_width = dpi(30),
+ widget = wibox.container.background
+ }
+
+ awesome.connect_signal("bling::playerctl::status", function(playing)
+ if playpause then
+ if playing then
+ icon.markup = helpers.colorize_text("", color)
+ else
+ icon.markup = helpers.colorize_text("", color)
+ end
+ end
+ end)
+
+ button:buttons(gears.table.join(
+ awful.button({}, 1, function() command() end)))
+
+ button:connect_signal("mouse::enter", function()
+ icon.markup = helpers.colorize_text(icon.text, beautiful.xforeground)
+ end)
+
+ button:connect_signal("mouse::leave", function()
+ icon.markup = helpers.colorize_text(icon.text, color)
+ end)
+
+ return button
+end
+
+local title_widget = wibox.widget {
+ markup = 'Nothing Playing',
+ align = 'center',
+ valign = 'center',
+ ellipsize = 'middle',
+ widget = wibox.widget.textbox
+}
+
+local artist_widget = wibox.widget {
+ markup = 'Nothing Playing',
+ align = 'center',
+ valign = 'center',
+ ellipsize = 'middle',
+ wrap = 'word_char',
+ widget = wibox.widget.textbox
+}
+
+-- Get Song Info
+awesome.connect_signal("bling::playerctl::title_artist_album",
+ function(title, artist, art_path)
+ -- Set art widget
+ art:set_image(gears.surface.load_uncached(art_path))
+
+ title_widget:set_markup_silently(
+ '<span foreground="' .. beautiful.xcolor5 .. '">' .. title .. '</span>')
+ artist_widget:set_markup_silently(
+ '<span foreground="' .. beautiful.xcolor6 .. '">' .. artist .. '</span>')
+end)
+
+local play_command =
+ function() awful.spawn.with_shell("playerctl play-pause") end
+local prev_command = function() awful.spawn.with_shell("playerctl previous") end
+local next_command = function() awful.spawn.with_shell("playerctl next") end
+
+local playerctl_play_symbol = create_button("", beautiful.xcolor4,
+ play_command, true)
+
+local playerctl_prev_symbol = create_button("玲", beautiful.xcolor4,
+ prev_command, false)
+local playerctl_next_symbol = create_button("怜", beautiful.xcolor4,
+ next_command, false)
+
+local slider = wibox.widget {
+ forced_height = dpi(5),
+ bar_shape = helpers.rrect(beautiful.border_radius),
+ shape = helpers.rrect(beautiful.border_radius),
+ background_color = beautiful.xbackground,
+ color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50},
+ stops = {{0, beautiful.xcolor0}, {0.75, beautiful.xcolor5}}
+ },
+ value = 25,
+ max_value = 100,
+ widget = wibox.widget.progressbar
+}
+
+awesome.connect_signal("bling::playerctl::position", function(pos, length)
+ slider.value = (pos / length) * 100
+end)
+
+local playerctl = wibox.widget {
+ {
+ art,
+ left = dpi(22),
+ top = dpi(17),
+ bottom = dpi(17),
+ layout = wibox.container.margin
+ },
+ {
+ {
+ {
+ {
+ title_widget,
+ artist_widget,
+ layout = wibox.layout.fixed.vertical
+ },
+ top = 10,
+ left = 25,
+ right = 25,
+ widget = wibox.container.margin
+ },
+ {
+ nil,
+ {
+ playerctl_prev_symbol,
+ playerctl_play_symbol,
+ playerctl_next_symbol,
+ spacing = dpi(40),
+ layout = wibox.layout.fixed.horizontal
+ },
+ nil,
+ expand = "none",
+ layout = wibox.layout.align.horizontal
+ },
+ {
+ slider,
+ top = dpi(10),
+ left = dpi(25),
+ right = dpi(25),
+ widget = wibox.container.margin
+ },
+ layout = wibox.layout.align.vertical
+ },
+ top = dpi(0),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+ },
+ layout = wibox.layout.align.horizontal
+}
+
+return playerctl
diff --git a/awesome/bloat/widgets/ram_arc.lua b/awesome/bloat/widgets/ram_arc.lua
new file mode 100644
index 0000000..3f8716d
--- /dev/null
+++ b/awesome/bloat/widgets/ram_arc.lua
@@ -0,0 +1,29 @@
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {150, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor3}, {0.75, beautiful.xcolor11}}
+}
+
+local ram_arc = wibox.widget {
+ max_value = 100,
+ thickness = 8,
+ start_angle = 4.71238898, -- 2pi*3/4
+ rounded_edge = true,
+ bg = beautiful.xcolor0,
+ paddings = 10,
+ colors = {active_color},
+ widget = wibox.container.arcchart
+}
+
+awesome.connect_signal("ears::ram", function(used, total)
+ local used_ram_percentage = (used / total) * 100
+ ram_arc.value = used_ram_percentage
+end)
+
+return ram_arc
diff --git a/awesome/bloat/widgets/ram_bar.lua b/awesome/bloat/widgets/ram_bar.lua
new file mode 100644
index 0000000..1c6db90
--- /dev/null
+++ b/awesome/bloat/widgets/ram_bar.lua
@@ -0,0 +1,56 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+-- Set colors
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor3}, {0.75, beautiful.xcolor11}}
+}
+
+local background_color = beautiful.xbackground
+
+local ram_bar = wibox.widget {
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(10),
+ margins = {top = dpi(8), bottom = dpi(8)},
+ forced_width = dpi(200),
+ shape = gears.shape.rounded_bar,
+ bar_shape = gears.shape.rounded_bar,
+ color = active_color,
+ background_color = background_color,
+ border_width = 0,
+ border_color = beautiful.border_color,
+ widget = wibox.widget.progressbar
+}
+
+local update_interval = 20
+-- Returns the used amount of ram in percentage
+-- TODO output of free is affected by system language. The following command
+-- works for any language:
+-- free -m | sed -n '2p' | awk '{printf "%d available out of %d\n", $7, $2}'
+local ram_script = [[
+ sh -c "
+ free -m | grep 'Mem:' | awk '{printf \"%d@@%d@\", $7, $2}'
+ "]]
+
+-- Periodically get ram info
+-- awful.widget.watch(ram_script, update_interval, function(widget, stdout)
+-- local available = stdout:match('(.*)@@')
+-- local total = stdout:match('@@(.*)@')
+-- local used = tonumber(total) - tonumber(available)
+-- local used_ram_percentage = (used / total) * 100
+-- ram_bar.value = used_ram_percentage
+-- end)
+
+awesome.connect_signal("ears::ram", function(used, total)
+ local used_ram_percentage = (used / total) * 100
+ ram_bar.value = used_ram_percentage
+end)
+
+return ram_bar
diff --git a/awesome/bloat/widgets/temp_arc.lua b/awesome/bloat/widgets/temp_arc.lua
new file mode 100644
index 0000000..7cd8ab9
--- /dev/null
+++ b/awesome/bloat/widgets/temp_arc.lua
@@ -0,0 +1,33 @@
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {150, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor1}, {0.75, beautiful.xcolor9}}
+}
+
+local temp_arc = wibox.widget {
+ max_value = 100,
+ thickness = 8,
+ start_angle = 4.71238898, -- 2pi*3/4
+ rounded_edge = true,
+ bg = beautiful.xcolor0,
+ paddings = 10,
+ colors = {active_color},
+ value = 10,
+ widget = wibox.container.arcchart
+}
+
+awesome.connect_signal("ears::temp", function(temp)
+ if temp == nil then
+ temp_arc.value = 10
+ else
+ temp_arc.value = temp
+ end
+end)
+
+return temp_arc
diff --git a/awesome/bloat/widgets/temp_bar.lua b/awesome/bloat/widgets/temp_bar.lua
new file mode 100644
index 0000000..aa792dd
--- /dev/null
+++ b/awesome/bloat/widgets/temp_bar.lua
@@ -0,0 +1,34 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+-- Set colors
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor1}, {0.75, beautiful.xcolor9}}
+}
+
+local background_color = beautiful.xbackground
+
+local temp_bar = wibox.widget {
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(10),
+ margins = {top = dpi(8), bottom = dpi(8)},
+ forced_width = dpi(200),
+ shape = gears.shape.rounded_bar,
+ bar_shape = gears.shape.rounded_bar,
+ color = active_color,
+ background_color = background_color,
+ border_width = 0,
+ border_color = beautiful.border_color,
+ widget = wibox.widget.progressbar
+}
+
+awesome.connect_signal("ears::temp", function(temp) temp_bar.value = temp end)
+
+return temp_bar
diff --git a/awesome/bloat/widgets/volume_arc.lua b/awesome/bloat/widgets/volume_arc.lua
new file mode 100644
index 0000000..52fc4c4
--- /dev/null
+++ b/awesome/bloat/widgets/volume_arc.lua
@@ -0,0 +1,34 @@
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {150, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor6}, {0.75, beautiful.xcolor14}}
+}
+
+local volume_arc = wibox.widget {
+ max_value = 100,
+ thickness = 8,
+ start_angle = 4.71238898, -- 2pi*3/4
+ rounded_edge = true,
+ bg = beautiful.xcolor0,
+ paddings = 10,
+ colors = {active_color},
+ widget = wibox.container.arcchart
+}
+
+awesome.connect_signal("ears::volume", function(volume, muted)
+ if muted then
+ volume_arc.bg = beautiful.xcolor1
+ else
+ volume_arc.bg = beautiful.xcolor0
+ end
+
+ volume_arc.value = volume
+end)
+
+return volume_arc
diff --git a/awesome/bloat/widgets/volume_bar.lua b/awesome/bloat/widgets/volume_bar.lua
new file mode 100644
index 0000000..1a4d961
--- /dev/null
+++ b/awesome/bloat/widgets/volume_bar.lua
@@ -0,0 +1,48 @@
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+local helpers = require('helpers')
+
+-- Set colors
+local active_color = {
+ type = 'linear',
+ from = {0, 0},
+ to = {200, 50}, -- replace with w,h later
+ stops = {{0, beautiful.xcolor6}, {0.75, beautiful.xcolor14}}
+}
+
+local muted_color = active_color
+local active_background_color = beautiful.xbackground
+local muted_background_color = beautiful.xcolor1
+
+local volume_bar = wibox.widget {
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(10),
+ margins = {top = dpi(8), bottom = dpi(8)},
+ forced_width = dpi(200),
+ shape = gears.shape.rounded_bar,
+ bar_shape = gears.shape.rounded_bar,
+ color = active_color,
+ background_color = active_background_color,
+ border_width = 0,
+ border_color = beautiful.border_color,
+ widget = wibox.widget.progressbar
+}
+
+awesome.connect_signal("ears::volume", function(volume, muted)
+ local bg_color
+ if muted then
+ fill_color = muted_color
+ bg_color = muted_background_color
+ else
+ fill_color = active_color
+ bg_color = active_background_color
+ end
+ volume_bar.value = volume
+ volume_bar.color = fill_color
+ volume_bar.background_color = bg_color
+end)
+
+return volume_bar
diff --git a/awesome/bloat/widgets/weather.lua b/awesome/bloat/widgets/weather.lua
new file mode 100644
index 0000000..376ac52
--- /dev/null
+++ b/awesome/bloat/widgets/weather.lua
@@ -0,0 +1,25 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = require("beautiful").xresources.apply_dpi
+
+local helpers = require("helpers")
+
+local weather_fg = beautiful.xcolor1
+
+local weather_heading = wibox.widget({
+ align = "center",
+ valign = "center",
+ font = beautiful.font_name .. "15",
+ markup = helpers.colorize_text("?", beautiful.xcolor4),
+ widget = wibox.widget.textbox()
+})
+
+awesome.connect_signal("ears::weather", function(temp, wind, emoji)
+ weather_heading.markup = helpers.colorize_text(
+ emoji .. " " .. tostring(temp) ..
+ "°F in San Diego", beautiful.xcolor4)
+end)
+
+return weather_heading
diff --git a/awesome/configs/picom.conf b/awesome/configs/picom.conf
new file mode 100644
index 0000000..ebe31b0
--- /dev/null
+++ b/awesome/configs/picom.conf
@@ -0,0 +1,92 @@
+# Animations
+transition-length = 300
+transition-pow-x = 0.3
+transition-pow-y = 0.3
+transition-pow-w = 0.3
+transition-pow-h = 0.3
+
+# Shadow
+shadow = false;
+shadow-radius = 17;
+shadow-offset-x = -17;
+shadow-offset-y = -17;
+shadow-opacity = 0.6;
+shadow-ignore-shaped = false;
+
+#shadow-exclude = "(!name = 'rofi' && !class_g = 'Rofi' && !name = 'dunst' && !class_g = 'Dunst' && !class_g *?= 'Polybar')"
+
+shadow-exclude = [
+ "class_g *?= 'VirtualBox'",
+ "class_g *?= 'Notify-osd'",
+ "class_g *?= 'trayer'",
+ "class_g *?= 'navigator'",
+ "class_g *?= 'Polybar'",
+ "class_g = 'boox'",
+ "class_g = 'slop'",
+ "class_g = 'hacksaw'",
+ "window_type *= 'normal' && ! name ~= ''",
+ "_GTK_FRAME_EXTENTS@:c",
+ "_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'",
+ "name = 'panel'",
+ "window_type = 'notification'",
+ #"window_type *= 'menu'",
+ #"window_type = 'utility'",
+ #"window_type = 'dock'",
+ #"window_type = 'dropdown_menu'",
+ #"window_type = 'popup_menu'"
+];
+
+
+
+# Fade
+fading = false;
+fade-delta = 1; # 30;
+fade-in-step = 0.01;
+fade-out-step = 0.01;
+no-fading-openclose = false;
+#fade-exclude = [ "name *= 'panel'",
+#];
+
+# Backend
+vsync = true;
+backend = "xrender";
+glx-no-stencil = true;
+glx-no-rebind-pixmap = true;
+use-damage = true;
+
+# Opacity
+inactive-opacity-override = false;
+#alpha-step = 0.06;
+opacity-rule = [
+ "100:class_g *?= 'st'",
+];
+
+focus-exclude = [
+ "class_g *?= 'Cairo-clock'",
+ "class_g *?= 'Virtualbox'",
+ "class_g *?= 'trayer'",
+ "_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'",
+ "name *?= 'Authy'"
+];
+
+#blur-background = true;
+#blur-method = "kawase";
+#blur-strength = 5;
+#blur-background-fixed = true;
+
+#blur-background-exclude = [
+# "window_type != 'splash'",
+#];
+
+wintypes:
+{
+ tooltip = { fade = true; shadow = false; focus = true; };
+ menu = { full-shadow = true;};
+ popup_menu = { full-shadow = true;};
+ utility = {full-shadow = true;};
+ toolbar = {full-shadow = true;};
+ normal = {full-shadow = true;};
+ notification = {full-shadow = true;};
+ dialog = {full-shadow = true};
+ dock = {shadow = false;};
+};
diff --git a/awesome/ears/battery.lua b/awesome/ears/battery.lua
new file mode 100644
index 0000000..5880f13
--- /dev/null
+++ b/awesome/ears/battery.lua
@@ -0,0 +1,59 @@
+-- Provides:
+-- ears::battery
+-- percentage (integer)
+-- ears::charger
+-- plugged (boolean)
+local awful = require("awful")
+
+local update_interval = 15
+
+-- Subscribe to power supply status changes with acpi_listen
+local charger_script = [[
+ sh -c '
+ acpi_listen | grep --line-buffered ac_adapter
+'
+]]
+
+-- First get battery file path
+-- If there are multiple, only get the first one
+-- TODO support multiple batteries
+awful.spawn.easy_async_with_shell(
+ "sh -c 'out=\"$(find /sys/class/power_supply/BAT?/capacity)\" && (echo \"$out\" | head -1) || false' ",
+ function(battery_file, _, __, exit_code)
+ -- No battery file found
+ if not (exit_code == 0) then return end
+ -- Periodically get battery info
+ awful.widget.watch("cat " .. battery_file, update_interval,
+ function(_, stdout)
+ awesome.emit_signal("ears::battery", tonumber(stdout))
+ end)
+ end)
+
+-- First get charger file path
+awful.spawn.easy_async_with_shell(
+ "sh -c 'out=\"$(find /sys/class/power_supply/*/online)\" && (echo \"$out\" | head -1) || false' ",
+ function(charger_file, _, __, exit_code)
+ -- No charger file found
+ if not (exit_code == 0) then return end
+ -- Then initialize function that emits charger info
+ local emit_charger_info = function()
+ awful.spawn.easy_async_with_shell("cat " .. charger_file,
+ function(out)
+ local status = tonumber(out) == 1
+ awesome.emit_signal("ears::charger", status)
+ end)
+ end
+
+ -- Run once to initialize widgets
+ emit_charger_info()
+
+ -- Kill old acpi_listen process
+ awful.spawn.easy_async_with_shell(
+ "ps x | grep \"acpi_listen\" | grep -v grep | awk '{print $1}' | xargs kill",
+ function()
+ -- Update charger status with each line printed
+ awful.spawn.with_line_callback(charger_script, {
+ stdout = function(_) emit_charger_info() end
+ })
+ end)
+ end)
diff --git a/awesome/ears/brightness.lua b/awesome/ears/brightness.lua
new file mode 100644
index 0000000..1198abe
--- /dev/null
+++ b/awesome/ears/brightness.lua
@@ -0,0 +1,38 @@
+-- Provides:
+-- ears::brightness
+-- percentage (integer)
+local awful = require("awful")
+
+-- Subscribe to backlight changes
+-- Requires inotify-tools
+local brightness_subscribe_script = [[
+ bash -c "
+ while (inotifywait -e modify /sys/class/backlight/?**/brightness -qq) do echo; done
+"]]
+
+local brightness_script = [[
+ sh -c "
+ xbacklight -get
+"]]
+
+local emit_brightness_info = function()
+ awful.spawn.with_line_callback(brightness_script, {
+ stdout = function(line)
+ percentage = math.floor(tonumber(line))
+ awesome.emit_signal("ears::brightness", percentage)
+ end
+ })
+end
+
+-- Run once to initialize widgets
+emit_brightness_info()
+
+-- Kill old inotifywait process
+awful.spawn.easy_async_with_shell("ps x | grep \"inotifywait -e modify /sys/class/backlight\" | grep -v grep | awk '{print $1}' | xargs kill", function ()
+ -- Update brightness status with each line printed
+ awful.spawn.with_line_callback(brightness_subscribe_script, {
+ stdout = function(_)
+ emit_brightness_info()
+ end
+ })
+end)
diff --git a/awesome/ears/cpu.lua b/awesome/ears/cpu.lua
new file mode 100644
index 0000000..6c5b276
--- /dev/null
+++ b/awesome/ears/cpu.lua
@@ -0,0 +1,18 @@
+-- Provides:
+-- ears::cpu
+-- used percentage (integer)
+local awful = require("awful")
+
+local update_interval = 5
+local cpu_idle_script = [[
+ sh -c "
+ vmstat 1 2 | tail -1 | awk '{printf \"%d\", $15}'
+ "]]
+
+-- Periodically get cpu info
+awful.widget.watch(cpu_idle_script, update_interval, function(widget, stdout)
+ -- local cpu_idle = stdout:match('+(.*)%.%d...(.*)%(')
+ local cpu_idle = stdout
+ cpu_idle = string.gsub(cpu_idle, '^%s*(.-)%s*$', '%1')
+ awesome.emit_signal("ears::cpu", 100 - tonumber(cpu_idle))
+end)
diff --git a/awesome/ears/disk.lua b/awesome/ears/disk.lua
new file mode 100644
index 0000000..785b95f
--- /dev/null
+++ b/awesome/ears/disk.lua
@@ -0,0 +1,22 @@
+-- Provides:
+-- ears::disk
+-- used (integer - mega bytes)
+-- total (integer - mega bytes)
+local awful = require("awful")
+local helpers = require("helpers")
+
+local update_interval = 10 -- every 3 minutes
+
+-- Use /dev/sdxY according to your setup
+local disk_script = [[
+ sh -c "
+ df -kh -B 1MB /dev/nvme0n1p2 | tail -1 | awk '{printf \"%d@%d\", $4, $3}'
+ "
+]]
+
+-- Periodically get disk space info
+awful.widget.watch(disk_script, update_interval, function(_, stdout)
+ local available = tonumber(stdout:match('^(.*)@')) / 1000
+ local used = tonumber(stdout:match('@(.*)$')) / 1000
+ awesome.emit_signal("ears::disk", used, available + used)
+end)
diff --git a/awesome/ears/init.lua b/awesome/ears/init.lua
new file mode 100644
index 0000000..ed214cd
--- /dev/null
+++ b/awesome/ears/init.lua
@@ -0,0 +1,14 @@
+-- ___ __ _ _ __ ___
+-- / _ \/ _` | '__/ __|
+-- | __/ (_| | | \__ \
+-- \___|\__,_|_| |___/
+-- These daemons are props to elenapan. I renamed them to ears, cuz why not?
+-- https://github.com/elenapan/dotfiles
+require("ears.battery")
+require("ears.volume")
+require("ears.brightness")
+require("ears.ram")
+require("ears.cpu")
+require("ears.temp")
+require("ears.disk")
+require("ears.weather")
diff --git a/awesome/ears/ram.lua b/awesome/ears/ram.lua
new file mode 100644
index 0000000..370ab3c
--- /dev/null
+++ b/awesome/ears/ram.lua
@@ -0,0 +1,23 @@
+-- Provides:
+-- ears::ram
+-- used (integer - mega bytes)
+-- total (integer - mega bytes)
+local awful = require("awful")
+
+local update_interval = 20
+-- Returns the used amount of ram in percentage
+-- TODO output of free is affected by system language. The following command
+-- works for any language:
+-- free -m | sed -n '2p' | awk '{printf "%d available out of %d\n", $7, $2}'
+local ram_script = [[
+ sh -c "
+ free -m | grep 'Mem:' | awk '{printf \"%d@@%d@\", $7, $2}'
+ "]]
+
+-- Periodically get ram info
+awful.widget.watch(ram_script, update_interval, function(widget, stdout)
+ local available = stdout:match('(.*)@@')
+ local total = stdout:match('@@(.*)@')
+ local used = tonumber(total) - tonumber(available)
+ awesome.emit_signal("ears::ram", used, total)
+end)
diff --git a/awesome/ears/temp.lua b/awesome/ears/temp.lua
new file mode 100644
index 0000000..3548fca
--- /dev/null
+++ b/awesome/ears/temp.lua
@@ -0,0 +1,15 @@
+-- Provides:
+-- ears::temperature
+-- temperature (integer - in Celcius)
+local awful = require("awful")
+
+local update_interval = 15
+local temp_script = [[
+ sh -c "
+ sensors | grep Package | awk '{print $4}' | cut -c 2-3
+ "]]
+
+-- Periodically get temperature info
+awful.widget.watch(temp_script, update_interval, function(widget, stdout)
+ awesome.emit_signal("ears::temp", tonumber(stdout))
+end)
diff --git a/awesome/ears/volume.lua b/awesome/ears/volume.lua
new file mode 100644
index 0000000..801a007
--- /dev/null
+++ b/awesome/ears/volume.lua
@@ -0,0 +1,53 @@
+-- Provides:
+-- ears::volume
+-- percentage (integer)
+-- muted (boolean)
+local awful = require("awful")
+
+local volume_old = -1
+local muted_old = -1
+local function emit_volume_info()
+ -- Get volume info of the currently active sink
+ -- The currently active sink has a star `*` in front of its index
+ -- In the output of `pacmd list-sinks`, lines +7 and +11 after "* index:"
+ -- contain the volume level and muted state respectively
+ -- This is why we are using `awk` to print them.
+ awful.spawn.easy_async_with_shell(
+ "pacmd list-sinks | awk '/\\* index: /{nr[NR+7];nr[NR+11]}; NR in nr'",
+ function(stdout)
+ local volume = stdout:match('(%d+)%% /')
+ local muted = stdout:match('muted:(%s+)[yes]')
+ local muted_int = muted and 1 or 0
+ local volume_int = tonumber(volume)
+ -- Only send signal if there was a change
+ -- We need this since we use `pactl subscribe` to detect
+ -- volume events. These are not only triggered when the
+ -- user adjusts the volume through a keybind, but also
+ -- through `pavucontrol` or even without user intervention,
+ -- when a media file starts playing.
+ if volume_int ~= volume_old or muted_int ~= muted_old then
+ awesome.emit_signal("ears::volume", volume_int, muted)
+ volume_old = volume_int
+ muted_old = muted_int
+ end
+ end)
+end
+
+-- Run once to initialize widgets
+emit_volume_info()
+
+-- Sleeps until pactl detects an event (volume up/down/toggle mute)
+local volume_script = [[
+ bash -c "
+ LANG=C pactl subscribe 2> /dev/null | grep --line-buffered \"Event 'change' on sink #\"
+ "]]
+
+-- Kill old pactl subscribe processes
+awful.spawn.easy_async({
+ "pkill", "--full", "--uid", os.getenv("USER"), "^pactl subscribe"
+}, function()
+ -- Run emit_volume_info() with each line printed
+ awful.spawn.with_line_callback(volume_script, {
+ stdout = function(line) emit_volume_info() end
+ })
+end)
diff --git a/awesome/ears/weather.lua b/awesome/ears/weather.lua
new file mode 100644
index 0000000..0850301
--- /dev/null
+++ b/awesome/ears/weather.lua
@@ -0,0 +1,32 @@
+-- Provides:
+-- evil::weather
+-- emote (string - emoji for weather)
+-- temp (integer - temperatur in °C)
+-- wind (integer - wind velocity in km/h)
+local awful = require("awful")
+local beautiful = require("beautiful")
+
+local city = beautiful.weather_city or "Tokyo"
+
+local update_interval = 60 * 60
+
+local disk_script = [[
+ sh -c '
+ wttr_str=`curl wttr.in/]] .. city .. [[?format=2`
+ echo $wttr_str
+ '
+]]
+
+-- Periodically get disk space info
+awful.widget.watch(disk_script, update_interval, function(_, stdout)
+ local list_weather_data = {}
+ for element in stdout:gmatch("%S+") do
+ table.insert(list_weather_data, element)
+ end
+ local emoji = list_weather_data[1]
+ local temp = tonumber(string.sub(list_weather_data[2], 8,
+ #list_weather_data[2] - 3))
+ local wind = tonumber(string.sub(list_weather_data[3], 11,
+ #list_weather_data[3] - 4))
+ awesome.emit_signal("ears::weather", temp, wind, emoji)
+end)
diff --git a/awesome/helpers.lua b/awesome/helpers.lua
new file mode 100644
index 0000000..fc1b6a2
--- /dev/null
+++ b/awesome/helpers.lua
@@ -0,0 +1,444 @@
+-- helpers.lua
+-- Functions that you use more than once and in different files would
+-- be nice to define here.
+local awful = require("awful")
+local gears = require("gears")
+local beautiful = require("beautiful")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+local wibox = require("wibox")
+local naughty = require("naughty")
+local cairo = require("lgi").cairo
+local helpers = {}
+
+function helpers.volume_control(step)
+ local cmd
+ if step == 0 then
+ cmd = "pactl set-sink-mute @DEFAULT_SINK@ toggle"
+ else
+ sign = step > 0 and "+" or ""
+ cmd =
+ "pactl set-sink-mute @DEFAULT_SINK@ 0 && pactl set-sink-volume @DEFAULT_SINK@ " ..
+ sign .. tostring(step) .. "%"
+ end
+ awful.spawn.with_shell(cmd)
+end
+
+-- Adds a maximized mask to a screen
+function helpers.screen_mask(s, bg)
+ local mask = wibox({
+ visible = false,
+ ontop = true,
+ type = "splash",
+ screen = s
+ })
+ awful.placement.maximize(mask)
+ mask.bg = bg
+ return mask
+end
+
+function helpers.custom_shape(cr, width, height)
+ cr:move_to(0, height / 25)
+ cr:line_to(height / 25, 0)
+ cr:line_to(width, 0)
+ cr:line_to(width, height - height / 25)
+ cr:line_to(width - height / 25, height)
+ cr:line_to(0, height)
+ cr:close_path()
+end
+
+-- Resize gaps on the fly
+
+helpers.resize_gaps = function(amt)
+ local t = awful.screen.focused().selected_tag
+ t.gap = t.gap + tonumber(amt)
+ awful.layout.arrange(awful.screen.focused())
+end
+
+-- Create rounded rectangle shape (in one line)
+
+helpers.rrect = function(radius)
+ return function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, radius)
+ end
+end
+
+-- Create pi
+
+helpers.pie = function(width, height, start_angle, end_angle, radius)
+ return function(cr)
+ gears.shape.pie(cr, width, height, start_angle, end_angle, radius)
+ end
+end
+
+-- Create parallelogram
+
+helpers.prgram = function(height, base)
+ return function(cr, width)
+ gears.shape.parallelogram(cr, width, height, base)
+ end
+end
+
+-- Create partially rounded rect
+
+helpers.prrect = function(radius, tl, tr, br, bl)
+ return function(cr, width, height)
+ gears.shape.partially_rounded_rect(cr, width, height, tl, tr, br, bl,
+ radius)
+ end
+end
+
+-- Markup helper
+
+function helpers.colorize_text(txt, fg)
+ return "<span foreground='" .. fg .. "'>" .. txt .. "</span>"
+end
+
+function helpers.client_menu_toggle()
+ local instance = nil
+
+ return function()
+ if instance and instance.wibox.visible then
+ instance:hide()
+ instance = nil
+ else
+ instance = awful.menu.clients({theme = {width = dpi(250)}})
+ end
+ end
+end
+
+-- Escapes a string so that it can be displayed inside pango markup
+-- tags. Modified from:
+-- https://github.com/kernelsauce/turbo/blob/master/turbo/escape.lua
+function helpers.pango_escape(s)
+ return (string.gsub(s, "[&<>]",
+ {["&"] = "&amp;", ["<"] = "&lt;", [">"] = "&gt;"}))
+end
+
+function helpers.vertical_pad(height)
+ return wibox.widget {
+ forced_height = height,
+ layout = wibox.layout.fixed.vertical
+ }
+end
+
+function helpers.horizontal_pad(width)
+ return wibox.widget {
+ forced_width = width,
+ layout = wibox.layout.fixed.horizontal
+ }
+end
+
+-- Maximizes client and also respects gaps
+function helpers.maximize(c)
+ c.maximized = not c.maximized
+ if c.maximized then
+ awful.placement.maximize(c, {
+ honor_padding = true,
+ honor_workarea = true,
+ margins = beautiful.useless_gap * 2
+ })
+
+ end
+ c:raise()
+end
+
+function helpers.move_to_edge(c, direction)
+ -- local workarea = awful.screen.focused().workarea
+ -- local client_geometry = c:geometry()
+ if direction == "up" then
+ local old_x = c:geometry().x
+ awful.placement.top(c, {
+ honor_padding = true,
+ honor_workarea = true,
+ honor_padding = true
+ })
+ c.x = old_x
+ -- c:geometry({ nil, y = workarea.y + beautiful.screen_margin * 2, nil, nil })
+ elseif direction == "down" then
+ local old_x = c:geometry().x
+ awful.placement.bottom(c, {
+ honor_padding = true,
+ honor_workarea = true,
+ honor_padding = true
+ })
+ c.x = old_x
+ -- c:geometry({ nil, y = workarea.height + workarea.y - client_geometry.height - beautiful.screen_margin * 2 - beautiful.border_width * 2, nil, nil })
+ elseif direction == "left" then
+ local old_y = c:geometry().y
+ awful.placement.left(c, {
+ honor_padding = true,
+ honor_workarea = true,
+ honor_padding = true
+ })
+ c.y = old_y
+ -- c:geometry({ x = workarea.x + beautiful.screen_margin * 2, nil, nil, nil })
+ elseif direction == "right" then
+ local old_y = c:geometry().y
+ awful.placement.right(c, {
+ honor_padding = true,
+ honor_workarea = true,
+ honor_padding = true
+ })
+ c.y = old_y
+ -- c:geometry({ x = workarea.width + workarea.x - client_geometry.width - beautiful.screen_margin * 2 - beautiful.border_width * 2, nil, nil, nil })
+ end
+end
+
+local double_tap_timer = nil
+function helpers.single_double_tap(single_tap_function, double_tap_function)
+ if double_tap_timer then
+ double_tap_timer:stop()
+ double_tap_timer = nil
+ double_tap_function()
+ -- naughty.notify({text = "We got a double tap"})
+ return
+ end
+
+ double_tap_timer = gears.timer.start_new(0.20, function()
+ double_tap_timer = nil
+ -- naughty.notify({text = "We got a single tap"})
+ if single_tap_function then single_tap_function() end
+ return false
+ end)
+end
+
+-- Used as a custom command in rofi to move a window into the current tag
+-- instead of following it.
+-- Rofi has access to the X window id of the client.
+function helpers.rofi_move_client_here(window)
+ local win = function(c) return awful.rules.match(c, {window = window}) end
+
+ for c in awful.client.iterate(win) do
+ c.minimized = false
+ c:move_to_tag(mouse.screen.selected_tag)
+ client.focus = c
+ c:raise()
+ end
+end
+
+-- Add a hover cursor to a widget by changing the cursor on
+-- mouse::enter and mouse::leave
+-- You can find the names of the available cursors by opening any
+-- cursor theme and looking in the "cursors folder"
+-- For example: "hand1" is the cursor that appears when hovering over
+-- links
+function helpers.add_hover_cursor(w, hover_cursor)
+ local original_cursor = "left_ptr"
+
+ w:connect_signal("mouse::enter", function()
+ local w = _G.mouse.current_wibox
+ if w then w.cursor = hover_cursor end
+ end)
+
+ w:connect_signal("mouse::leave", function()
+ local w = _G.mouse.current_wibox
+ if w then w.cursor = original_cursor end
+ end)
+end
+
+-- Tag back and forth:
+-- If you try to focus the tag you are already at, go back to the previous tag.
+-- Useful for quick switching after for example checking an incoming chat
+-- message at tag 2 and coming back to your work at tag 1 with the same
+-- keypress.
+-- Also focuses urgent clients if they exist in the tag. This fixes the issue
+-- (visual mismatch) where after switching to a tag which includes an urgent
+-- client, the urgent client is unfocused but still covers all other windows
+-- (even the currently focused window).
+function helpers.tag_back_and_forth(tag_index)
+ local s = mouse.screen
+ local tag = s.tags[tag_index]
+ if tag then
+ if tag == s.selected_tag then
+ awful.tag.history.restore()
+ else
+ tag:view_only()
+ end
+
+ local urgent_clients = function(c)
+ return awful.rules.match(c, {urgent = true, first_tag = tag})
+ end
+
+ for c in awful.client.iterate(urgent_clients) do
+ client.focus = c
+ c:raise()
+ end
+ end
+end
+
+-- Resize DWIM (Do What I Mean)
+-- Resize client or factor
+-- Constants --
+local floating_resize_amount = dpi(20)
+local tiling_resize_factor = 0.05
+---------------
+function helpers.resize_dwim(c, direction)
+ if awful.layout.get(mouse.screen) == awful.layout.suit.floating or
+ (c and c.floating) then
+ if direction == "up" then
+ c:relative_move(0, 0, 0, -floating_resize_amount)
+ elseif direction == "down" then
+ c:relative_move(0, 0, 0, floating_resize_amount)
+ elseif direction == "left" then
+ c:relative_move(0, 0, -floating_resize_amount, 0)
+ elseif direction == "right" then
+ c:relative_move(0, 0, floating_resize_amount, 0)
+ end
+ else
+ if direction == "up" then
+ awful.client.incwfact(-tiling_resize_factor)
+ elseif direction == "down" then
+ awful.client.incwfact(tiling_resize_factor)
+ elseif direction == "left" then
+ awful.tag.incmwfact(-tiling_resize_factor)
+ elseif direction == "right" then
+ awful.tag.incmwfact(tiling_resize_factor)
+ end
+ end
+end
+
+-- Move client to screen edge, respecting the screen workarea
+function helpers.move_to_edge(c, direction)
+ local workarea = awful.screen.focused().workarea
+ if direction == "up" then
+ c:geometry({nil, y = workarea.y + beautiful.useless_gap * 2, nil, nil})
+ elseif direction == "down" then
+ c:geometry({
+ nil,
+ y = workarea.height + workarea.y - c:geometry().height -
+ beautiful.useless_gap * 2 - beautiful.border_width * 2,
+ nil,
+ nil
+ })
+ elseif direction == "left" then
+ c:geometry({x = workarea.x + beautiful.useless_gap * 2, nil, nil, nil})
+ elseif direction == "right" then
+ c:geometry({
+ x = workarea.width + workarea.x - c:geometry().width -
+ beautiful.useless_gap * 2 - beautiful.border_width * 2,
+ nil,
+ nil,
+ nil
+ })
+ end
+end
+
+-- Move client DWIM (Do What I Mean)
+-- Move to edge if the client / layout is floating
+-- Swap by index if maximized
+-- Else swap client by direction
+function helpers.move_client_dwim(c, direction)
+ if c.floating or
+ (awful.layout.get(mouse.screen) == awful.layout.suit.floating) then
+ helpers.move_to_edge(c, direction)
+ elseif awful.layout.get(mouse.screen) == awful.layout.suit.max then
+ if direction == "up" or direction == "left" then
+ awful.client.swap.byidx(-1, c)
+ elseif direction == "down" or direction == "right" then
+ awful.client.swap.byidx(1, c)
+ end
+ else
+ awful.client.swap.bydirection(direction, c, nil)
+ end
+end
+
+-- Make client floating and snap to the desired edge
+function helpers.float_and_edge_snap(c, direction)
+ -- if not c.floating then
+ -- c.floating = true
+ -- end
+ naughty.notify({text = "double tap"})
+ c.floating = true
+ local workarea = awful.screen.focused().workarea
+ if direction == "up" then
+ local axis = 'horizontally'
+ local f = awful.placement.scale + awful.placement.top +
+ (axis and awful.placement['maximize_' .. axis] or nil)
+ local geo = f(client.focus, {
+ honor_padding = true,
+ honor_workarea = true,
+ to_percent = 0.5
+ })
+ elseif direction == "down" then
+ local axis = 'horizontally'
+ local f = awful.placement.scale + awful.placement.bottom +
+ (axis and awful.placement['maximize_' .. axis] or nil)
+ local geo = f(client.focus, {
+ honor_padding = true,
+ honor_workarea = true,
+ to_percent = 0.5
+ })
+ elseif direction == "left" then
+ local axis = 'vertically'
+ local f = awful.placement.scale + awful.placement.left +
+ (axis and awful.placement['maximize_' .. axis] or nil)
+ local geo = f(client.focus, {
+ honor_padding = true,
+ honor_workarea = true,
+ to_percent = 0.5
+ })
+ elseif direction == "right" then
+ local axis = 'vertically'
+ local f = awful.placement.scale + awful.placement.right +
+ (axis and awful.placement['maximize_' .. axis] or nil)
+ local geo = f(client.focus, {
+ honor_padding = true,
+ honor_workarea = true,
+ to_percent = 0.5
+ })
+ end
+end
+
+-- Rounds a number to any number of decimals
+function helpers.round(number, decimals)
+ local power = 10 ^ decimals
+ return math.floor(number * power) / power
+end
+
+function helpers.fake_escape()
+ root.fake_input('key_press', "Escape")
+ root.fake_input('key_release', "Escape")
+end
+
+function helpers.run_or_raise(match, move, spawn_cmd, spawn_args)
+ local matcher = function(c) return awful.rules.match(c, match) end
+
+ -- Find and raise
+ local found = false
+ for c in awful.client.iterate(matcher) do
+ found = true
+ c.minimized = false
+ if move then
+ c:move_to_tag(mouse.screen.selected_tag)
+ client.focus = c
+ c:raise()
+ else
+ c:jump_to()
+ end
+ break
+ end
+
+ -- Spawn if not found
+ if not found then awful.spawn(spawn_cmd, spawn_args) end
+end
+
+function helpers.pad(size)
+ local str = ""
+ for i = 1, size do str = str .. " " end
+ local pad = wibox.widget.textbox(str)
+ return pad
+end
+
+function helpers.float_and_resize(c, width, height)
+ c.width = width
+ c.height = height
+ awful.placement.centered(c, {honor_workarea = true, honor_padding = true})
+ awful.client.property.set(c, 'floating_geometry', c:geometry())
+ c.floating = true
+ c:raise()
+end
+
+return helpers
+
+-- EOF ------------------------------------------------------------------------
diff --git a/awesome/icons/ghosts/awesome.png b/awesome/icons/ghosts/awesome.png
new file mode 100644
index 0000000..1e2600a
--- /dev/null
+++ b/awesome/icons/ghosts/awesome.png
Binary files differ
diff --git a/awesome/icons/ghosts/battery.png b/awesome/icons/ghosts/battery.png
new file mode 100644
index 0000000..fe5fcba
--- /dev/null
+++ b/awesome/icons/ghosts/battery.png
Binary files differ
diff --git a/awesome/icons/ghosts/battery_charging.png b/awesome/icons/ghosts/battery_charging.png
new file mode 100644
index 0000000..54ce1db
--- /dev/null
+++ b/awesome/icons/ghosts/battery_charging.png
Binary files differ
diff --git a/awesome/icons/ghosts/dot.png b/awesome/icons/ghosts/dot.png
new file mode 100644
index 0000000..00a5ab4
--- /dev/null
+++ b/awesome/icons/ghosts/dot.png
Binary files differ
diff --git a/awesome/icons/ghosts/dot.svg b/awesome/icons/ghosts/dot.svg
new file mode 100644
index 0000000..f705217
--- /dev/null
+++ b/awesome/icons/ghosts/dot.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 31.955 31.955" style="enable-background:new 0 0 31.955 31.955;" xml:space="preserve">
+<g>
+ <path style="fill:#030104;" d="M27.25,4.655C20.996-1.571,10.88-1.546,4.656,4.706C-1.571,10.96-1.548,21.076,4.705,27.3
+ c6.256,6.226,16.374,6.203,22.597-0.051C33.526,20.995,33.505,10.878,27.25,4.655z"/>
+ <path style="fill:#030104;" d="M13.288,23.896l-1.768,5.207c2.567,0.829,5.331,0.886,7.926,0.17l-0.665-5.416
+ C17.01,24.487,15.067,24.5,13.288,23.896z M8.12,13.122l-5.645-0.859c-0.741,2.666-0.666,5.514,0.225,8.143l5.491-1.375
+ C7.452,17.138,7.426,15.029,8.12,13.122z M28.763,11.333l-4.965,1.675c0.798,2.106,0.716,4.468-0.247,6.522l5.351,0.672
+ C29.827,17.319,29.78,14.193,28.763,11.333z M11.394,2.883l1.018,5.528c2.027-0.954,4.356-1.05,6.442-0.288l1.583-5.137
+ C17.523,1.94,14.328,1.906,11.394,2.883z"/>
+ <circle style="fill:#030104;" cx="15.979" cy="15.977" r="6.117"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/awesome/icons/ghosts/ghost.png b/awesome/icons/ghosts/ghost.png
new file mode 100644
index 0000000..57f444a
--- /dev/null
+++ b/awesome/icons/ghosts/ghost.png
Binary files differ
diff --git a/awesome/icons/ghosts/ghost.svg b/awesome/icons/ghosts/ghost.svg
new file mode 100644
index 0000000..1496d8d
--- /dev/null
+++ b/awesome/icons/ghosts/ghost.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 333.561 333.561" style="enable-background:new 0 0 333.561 333.561;" xml:space="preserve">
+<path d="M295.023,70.021c-10.653-20.379-25.378-36.617-43.763-48.265C228.47,7.32,200.047,0,166.78,0s-61.69,7.32-84.48,21.757
+ c-18.386,11.647-33.11,27.886-43.763,48.265c-17.745,33.944-18.257,67.888-18.257,71.646v182.064c0,1.4,0.001,2.673,0.036,3.596
+ c0.214,5.784,4.052,6.233,5.223,6.233c2.327,0,3.61-1.173,7.316-4.88l0.213-0.214l34.969-44.641l34.895,44.274l0.392,0.441
+ c2.747,2.745,7.7,4.738,11.779,4.738h3.416c4.08,0,9.033-1.993,11.779-4.739l0.21-0.21l35.064-44.56l34.909,44.311l0.393,0.441
+ c2.756,2.756,7.71,4.756,11.779,4.756h3.416c4.08,0,9.034-1.993,11.78-4.739l0.21-0.21l35.063-44.559l34.906,44.444l0.396,0.447
+ c1.47,1.47,5.23,4.888,8.402,4.888c3.98,0,6.452-3.763,6.452-9.82V141.668C313.28,137.909,312.768,103.966,295.023,70.021z
+ M109.354,170.146c-17.999,0-32.59-14.591-32.59-32.59s14.591-32.59,32.59-32.59s32.591,14.591,32.591,32.59
+ S127.353,170.146,109.354,170.146z M223.354,170.146c-17.999,0-32.59-14.591-32.59-32.59s14.591-32.59,32.59-32.59
+ s32.591,14.591,32.591,32.59S241.353,170.146,223.354,170.146z"/>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/awesome/icons/ghosts/pacman.png b/awesome/icons/ghosts/pacman.png
new file mode 100644
index 0000000..d999d84
--- /dev/null
+++ b/awesome/icons/ghosts/pacman.png
Binary files differ
diff --git a/awesome/icons/ghosts/pacman.svg b/awesome/icons/ghosts/pacman.svg
new file mode 100644
index 0000000..47fe395
--- /dev/null
+++ b/awesome/icons/ghosts/pacman.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" height="571.11" width="541.6">
+ <path style="fill:#ffcc00" d="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"/>
+</svg> \ No newline at end of file
diff --git a/awesome/icons/ghosts/terminal.png b/awesome/icons/ghosts/terminal.png
new file mode 100644
index 0000000..b6e0a10
--- /dev/null
+++ b/awesome/icons/ghosts/terminal.png
Binary files differ
diff --git a/awesome/icons/notif-center/clear.png b/awesome/icons/notif-center/clear.png
new file mode 100644
index 0000000..1a4221a
--- /dev/null
+++ b/awesome/icons/notif-center/clear.png
Binary files differ
diff --git a/awesome/icons/notif-center/clear_grey.png b/awesome/icons/notif-center/clear_grey.png
new file mode 100644
index 0000000..9f5bfe6
--- /dev/null
+++ b/awesome/icons/notif-center/clear_grey.png
Binary files differ
diff --git a/awesome/icons/notif-center/delete.png b/awesome/icons/notif-center/delete.png
new file mode 100644
index 0000000..59cb779
--- /dev/null
+++ b/awesome/icons/notif-center/delete.png
Binary files differ
diff --git a/awesome/icons/notif-center/delete_grey.png b/awesome/icons/notif-center/delete_grey.png
new file mode 100644
index 0000000..a51b4d0
--- /dev/null
+++ b/awesome/icons/notif-center/delete_grey.png
Binary files differ
diff --git a/awesome/icons/notif-center/notification.png b/awesome/icons/notif-center/notification.png
new file mode 100644
index 0000000..81168c0
--- /dev/null
+++ b/awesome/icons/notif-center/notification.png
Binary files differ
diff --git a/awesome/images/bg.png b/awesome/images/bg.png
new file mode 100644
index 0000000..205947a
--- /dev/null
+++ b/awesome/images/bg.png
Binary files differ
diff --git a/awesome/images/default.png b/awesome/images/default.png
new file mode 100644
index 0000000..9c396d1
--- /dev/null
+++ b/awesome/images/default.png
Binary files differ
diff --git a/awesome/images/layout-machi_demo.gif b/awesome/images/layout-machi_demo.gif
new file mode 100644
index 0000000..08b7cc2
--- /dev/null
+++ b/awesome/images/layout-machi_demo.gif
Binary files differ
diff --git a/awesome/images/me.png b/awesome/images/me.png
new file mode 100644
index 0000000..98aff2e
--- /dev/null
+++ b/awesome/images/me.png
Binary files differ
diff --git a/awesome/images/rice.png b/awesome/images/rice.png
new file mode 100644
index 0000000..b9a1556
--- /dev/null
+++ b/awesome/images/rice.png
Binary files differ
diff --git a/awesome/images/round_shadow.png b/awesome/images/round_shadow.png
new file mode 100644
index 0000000..449a315
--- /dev/null
+++ b/awesome/images/round_shadow.png
Binary files differ
diff --git a/awesome/images/round_transparent.png b/awesome/images/round_transparent.png
new file mode 100644
index 0000000..09e348c
--- /dev/null
+++ b/awesome/images/round_transparent.png
Binary files differ
diff --git a/awesome/keys.lua b/awesome/keys.lua
new file mode 100644
index 0000000..49f156b
--- /dev/null
+++ b/awesome/keys.lua
@@ -0,0 +1,387 @@
+-- keys.lua
+-- Contains Global Keys
+local gears = require("gears")
+local awful = require("awful")
+local beautiful = require("beautiful")
+local hotkeys_popup = require("awful.hotkeys_popup")
+local helpers = require("helpers")
+-- Custom modules
+local notifPop = require("bloat.pop.notif")
+local machi = require("layout-machi")
+local bling = require("bling")
+
+-- Mouse Bindings
+awful.mouse.append_global_mousebindings({
+ awful.button({}, 4, awful.tag.viewprev),
+ awful.button({}, 5, awful.tag.viewnext)
+})
+
+-- Client and Tabs Bindings
+awful.keyboard.append_global_keybindings(
+ {
+ awful.key({"Mod1"}, "a",
+ function() bling.module.tabbed.pick_with_dmenu() end, {
+ description = "pick client to add to tab group",
+ group = "tabs"
+ }), awful.key({"Mod1"}, "s", function()
+ bling.module.tabbed.iter()
+ end, {description = "iterate through tabbing group", group = "tabs"}),
+ awful.key({"Mod1"}, "d", function() bling.module.tabbed.pop() end, {
+ description = "remove focused client from tabbing group",
+ group = "tabs"
+ }), awful.key({modkey}, "Down", function()
+ awful.client.focus.bydirection("down")
+ bling.module.flash_focus.flashfocus(client.focus)
+ end, {description = "focus down", group = "client"}),
+ awful.key({modkey}, "Up", function()
+ awful.client.focus.bydirection("up")
+ bling.module.flash_focus.flashfocus(client.focus)
+ end, {description = "focus up", group = "client"}),
+ awful.key({modkey}, "Left", function()
+ awful.client.focus.bydirection("left")
+ bling.module.flash_focus.flashfocus(client.focus)
+ end, {description = "focus left", group = "client"}),
+ awful.key({modkey}, "Right", function()
+ awful.client.focus.bydirection("right")
+ bling.module.flash_focus.flashfocus(client.focus)
+ end, {description = "focus right", group = "client"}),
+ awful.key({modkey}, "j", function() awful.client.focus.byidx(1) end,
+ {description = "focus next by index", group = "client"}),
+ awful.key({modkey}, "k", function() awful.client.focus.byidx(-1) end,
+ {description = "focus previous by index", group = "client"}),
+ awful.key({modkey, "Shift"}, "j",
+ function() awful.client.swap.byidx(1) end, {
+ description = "swap with next client by index",
+ group = "client"
+ }),
+ awful.key({modkey, "Shift"}, "k",
+ function() awful.client.swap.byidx(-1) end, {
+ description = "swap with previous client by index",
+ group = "client"
+ }), awful.key({modkey}, "u", awful.client.urgent.jumpto,
+ {description = "jump to urgent client", group = "client"}),
+ awful.key({modkey}, "Tab", function()
+ awful.client.focus.history.previous()
+ if client.focus then client.focus:raise() end
+ end, {description = "go back", group = "client"})
+ })
+
+-- Awesomewm
+awful.keyboard.append_global_keybindings(
+ {
+ -- Volume control
+ awful.key({}, "XF86AudioRaiseVolume",
+ function() awful.spawn("pamixer -i 3") end,
+ {description = "increase volume", group = "awesome"}),
+ awful.key({}, "XF86AudioLowerVolume",
+ function() awful.spawn("pamixer -d 3") end,
+ {description = "decrease volume", group = "awesome"}),
+ awful.key({}, "XF86AudioMute", function()
+ awful.spawn("pamixer -t")
+ end, {description = "mute volume", group = "awesome"}), -- Media Control
+ awful.key({}, "XF86AudioPlay",
+ function() awful.spawn("playerctl play-pause") end,
+ {description = "toggle playerctl", group = "awesome"}),
+ awful.key({}, "XF86AudioPrev",
+ function() awful.spawn("playerctl previous") end,
+ {description = "playerctl previous", group = "awesome"}),
+ awful.key({}, "XF86AudioNext",
+ function() awful.spawn("playerctl next") end,
+ {description = "playerctl next", group = "awesome"}),
+
+ -- Screen Shots/Vids
+ awful.key({}, "Print", function()
+ awful.spawn.with_shell(gears.filesystem.get_configuration_dir() ..
+ "scripts/shoot")
+ end, {description = "take a screenshot", group = "awesome"}),
+ awful.key({modkey}, "Print", function()
+ awful.spawn.with_shell(gears.filesystem.get_configuration_dir() ..
+ "scripts/shoot selnp")
+ end, {description = "take a selection with no pads", group = "awesome"}),
+ awful.key({modkey, "Shift"}, "Print", function()
+ awful.spawn.with_shell(gears.filesystem.get_configuration_dir() ..
+ "scripts/shoot sel")
+ end, {description = "take a selection with pads", group = "awesome"}),
+
+ -- Brightness
+ awful.key({}, "XF86MonBrightnessUp",
+ function() awful.spawn("xbacklight -inc 10") end,
+ {description = "increase brightness", group = "awesome"}),
+ awful.key({}, "XF86MonBrightnessDown",
+ function() awful.spawn("xbacklight -dec 10") end,
+ {description = "decrease brightness", group = "awesome"}),
+
+ -- ColorPicker
+ awful.key({modkey}, "p", function() awful.spawn("farge --notify") end,
+ {description = "color picker", group = "awesome"}),
+
+ -- Awesome stuff
+ awful.key({modkey}, "F1", hotkeys_popup.show_help,
+ {description = "show help", group = "awesome"}),
+ awful.key({modkey}, "Escape", awful.tag.history.restore,
+ {description = "go back", group = "tag"}),
+ awful.key({modkey, shift}, "w",
+ function() notifPop.visible = not notifPop.visible end,
+ {description = "show notifs", group = "awesome"}),
+ awful.key({modkey, shift}, "d", function()
+ awesome.emit_signal("widgets::dashboard::show")
+ end, {description = "show panel", group = "awesome"}),
+ awful.key({modkey}, "x", function()
+ awesome.emit_signal("widgets::exit_screen::show")
+ end, {description = "show exit screen", group = "awesome"}),
+ awful.key({modkey, "Control"}, "r", awesome.restart,
+ {description = "reload awesome", group = "awesome"}),
+ awful.key({modkey, "Shift"}, "q", awesome.quit,
+ {description = "quit awesome", group = "awesome"})
+
+ })
+
+-- Layout Machi
+awful.keyboard.append_global_keybindings(
+ {
+ awful.key({modkey}, ".",
+ function() machi.default_editor.start_interactive() end, {
+ description = "edit the current layout if it is a machi layout",
+ group = "layout"
+ }),
+ awful.key({modkey}, "/",
+ function() machi.switcher.start(client.focus) end, {
+ description = "switch between windows for a machi layout",
+ group = "layout"
+ })
+ })
+
+-- Launcher and screen
+awful.keyboard.append_global_keybindings(
+ {
+ awful.key({modkey, "Control"}, "j",
+ function() awful.screen.focus_relative(1) end,
+ {description = "focus the next screen", group = "screen"}),
+ awful.key({modkey, "Control"}, "k",
+ function() awful.screen.focus_relative(-1) end,
+ {description = "focus the previous screen", group = "screen"}),
+ awful.key({modkey}, "d", function() awful.spawn(launcher) end,
+ {description = "show rofi ", group = "launcher"}),
+ awful.key({modkey}, "e", function()
+ awful.spawn(gears.filesystem.get_configuration_dir() ..
+ "scripts/rofi-emoji")
+ end, {description = "show rofi emoji", group = "launcher"}),
+
+ -- Standard program
+ awful.key({modkey}, "t", function() awful.spawn(terminal) end,
+ {description = "open a terminal", group = "launcher"}),
+ awful.key({modkey, shift}, "t", function()
+ awful.spawn.easy_async_with_shell(
+ "slop -b 2 -c '0.61,0.9,0.75,1' -p -2", function(out)
+ local mywidth, myheight, myx, myy =
+ string.match(out, "(.*)x(.*)+(.*)+(.*)")
+
+ awful.spawn(terminal, {
+ geometry = {
+ x = myx,
+ y = myy,
+ height = myheight,
+ width = mywidth
+ },
+ floating = true
+ })
+
+ end)
+ end, {description = "open a terminal", group = "launcher"}),
+ awful.key({modkey}, "s", function() awful.spawn(music) end,
+ {description = "open spot-tui", group = "launcher"}),
+
+ awful.key({modkey}, "f", function() awful.spawn(filemanager) end,
+ {description = "open file browser", group = "launcher"}),
+ awful.key({modkey}, "v", function() awful.spawn(discord) end,
+ {description = "open discord", group = "launcher"}),
+ awful.key({modkey}, "w", function()
+ awful.spawn.with_shell(browser)
+ end, {description = "open firefox", group = "launcher"}),
+
+ awful.key({modkey}, "l", function() awful.tag.incmwfact(0.05) end, {
+ description = "increase master width factor",
+ group = "layout"
+ }), awful.key({modkey}, "h", function()
+ awful.tag.incmwfact(-0.05)
+ end, {description = "decrease master width factor", group = "layout"}),
+ awful.key({modkey, "Shift"}, "h",
+ function() awful.tag.incnmaster(1, nil, true) end, {
+ description = "increase the number of master clients",
+ group = "layout"
+ }), awful.key({modkey, "Shift"}, "l",
+ function() awful.tag.incnmaster(-1, nil, true) end, {
+ description = "decrease the number of master clients",
+ group = "layout"
+ }), awful.key({modkey, "Control"}, "h",
+ function() awful.tag.incncol(1, nil, true) end, {
+ description = "increase the number of columns",
+ group = "layout"
+ }), awful.key({modkey, "Control"}, "l",
+ function() awful.tag.incncol(-1, nil, true) end, {
+ description = "decrease the number of columns",
+ group = "layout"
+ }), awful.key({modkey}, "space", function() awful.layout.inc(1) end,
+ {description = "select next", group = "layout"}),
+ awful.key({modkey, "Shift"}, "space",
+ function() awful.layout.inc(-1) end,
+ {description = "select previous", group = "layout"}), -- Set Layout
+ awful.key({modkey, "Control"}, "w",
+ function() awful.layout.set(awful.layout.suit.max) end,
+ {description = "set max layout", group = "tag"}),
+ awful.key({modkey}, "s",
+ function() awful.layout.set(awful.layout.suit.tile) end,
+ {description = "set tile layout", group = "tag"}),
+ awful.key({modkey, shift}, "s",
+ function() awful.layout.set(awful.layout.suit.floating) end,
+ {description = "set floating layout", group = "tag"}),
+
+ awful.key({modkey, "Control"}, "n", function()
+ local c = awful.client.restore()
+ -- Focus restored client
+ if c then
+ c:emit_signal("request::activate", "key.unminimize",
+ {raise = true})
+ end
+ end, {description = "restore minimized", group = "client"})
+ })
+
+-- Client management keybinds
+client.connect_signal("request::default_keybindings", function()
+ awful.keyboard.append_client_keybindings(
+ {
+ awful.key({modkey, "Shift"}, "f", function(c)
+ c.fullscreen = not c.fullscreen
+ c:raise()
+ end, {description = "toggle fullscreen", group = "client"}),
+ awful.key({modkey}, "q", function(c) c:kill() end,
+ {description = "close", group = "client"}),
+ awful.key({modkey, "Control"}, "space",
+ awful.client.floating.toggle,
+ {description = "toggle floating", group = "client"}),
+ awful.key({modkey, "Control"}, "Return",
+ function(c) c:swap(awful.client.getmaster()) end,
+ {description = "move to master", group = "client"}),
+ awful.key({modkey}, "o", function(c) c:move_to_screen() end,
+ {description = "move to screen", group = "client"}),
+ -- awful.key({ modkey, "Shift" }, "t", function (c) c.ontop = not c.ontop end,
+ -- {description = "toggle keep on top", group = "client"}),
+ awful.key({modkey, shift}, "b", function(c)
+ c.floating = not c.floating
+ c.width = 400
+ c.height = 200
+ awful.placement.bottom_right(c)
+ c.sticky = not c.sticky
+ end, {description = "toggle keep on top", group = "client"}),
+
+ awful.key({modkey}, "n", function(c)
+ -- The client currently has the input focus, so it cannot be
+ -- minimized, since minimized clients can't have the focus.
+ c.minimized = true
+ end, {description = "minimize", group = "client"}),
+ awful.key({modkey}, "m", function(c)
+ c.maximized = not c.maximized
+ c:raise()
+ end, {description = "(un)maximize", group = "client"}),
+ awful.key({modkey, "Control"}, "m", function(c)
+ c.maximized_vertical = not c.maximized_vertical
+ c:raise()
+ end, {description = "(un)maximize vertically", group = "client"}),
+ awful.key({modkey, "Shift"}, "m", function(c)
+ c.maximized_horizontal = not c.maximized_horizontal
+ c:raise()
+ end, {description = "(un)maximize horizontally", group = "client"}),
+
+ -- On the fly useless gaps change
+ awful.key({modkey}, "=", function()
+ helpers.resize_gaps(5)
+ end),
+ awful.key({modkey}, "-", function()
+ helpers.resize_gaps(-5)
+ end), -- Single tap: Center client
+ -- Double tap: Center client + Floating + Resize
+ awful.key({modkey}, "c", function(c)
+ awful.placement.centered(c, {
+ honor_workarea = true,
+ honor_padding = true
+ })
+ helpers.single_double_tap(nil, function()
+ helpers.float_and_resize(c, screen_width * 0.25,
+ screen_height * 0.28)
+ end)
+ end)
+ })
+end)
+
+-- Num row keybinds
+awful.keyboard.append_global_keybindings(
+ {
+ awful.key {
+ modifiers = {modkey},
+ keygroup = "numrow",
+ description = "only view tag",
+ group = "tag",
+ on_press = function(index)
+ local screen = awful.screen.focused()
+ local tag = screen.tags[index]
+ if tag then tag:view_only() end
+ end
+ }, awful.key {
+ modifiers = {modkey, "Control"},
+ keygroup = "numrow",
+ description = "toggle tag",
+ group = "tag",
+ on_press = function(index)
+ local screen = awful.screen.focused()
+ local tag = screen.tags[index]
+ if tag then awful.tag.viewtoggle(tag) end
+ end
+ }, awful.key {
+ modifiers = {modkey, "Shift"},
+ keygroup = "numrow",
+ description = "move focused client to tag",
+ group = "tag",
+ on_press = function(index)
+ if client.focus then
+ local tag = client.focus.screen.tags[index]
+ if tag then client.focus:move_to_tag(tag) end
+ end
+ end
+ }, awful.key {
+ modifiers = {modkey, "Control", "Shift"},
+ keygroup = "numrow",
+ description = "toggle focused client on tag",
+ group = "tag",
+ on_press = function(index)
+ if client.focus then
+ local tag = client.focus.screen.tags[index]
+ if tag then client.focus:toggle_tag(tag) end
+ end
+ end
+ }, awful.key {
+ modifiers = {modkey},
+ keygroup = "numpad",
+ description = "select layout directly",
+ group = "layout",
+ on_press = function(index)
+ local t = awful.screen.focused().selected_tag
+ if t then t.layout = t.layouts[index] or t.layout end
+ end
+ }
+ })
+
+client.connect_signal("request::default_mousebindings", function()
+ awful.mouse.append_client_mousebindings(
+ {
+ awful.button({}, 1,
+ function(c)
+ c:activate{context = "mouse_click"}
+ end), awful.button({modkey}, 1, function(c)
+ c:activate{context = "mouse_click", action = "mouse_move"}
+ end), awful.button({modkey}, 3, function(c)
+ c:activate{context = "mouse_click", action = "mouse_resize"}
+ end)
+ })
+end)
+
+-- EOF ------------------------------------------------------------------------
diff --git a/awesome/layout-machi/LICENSE b/awesome/layout-machi/LICENSE
new file mode 100644
index 0000000..530a3e8
--- /dev/null
+++ b/awesome/layout-machi/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2019 Xinhao Yuan
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/awesome/layout-machi/README.md b/awesome/layout-machi/README.md
new file mode 100644
index 0000000..15e325f
--- /dev/null
+++ b/awesome/layout-machi/README.md
@@ -0,0 +1,284 @@
+# ![machi icon](icon.png) layout-machi
+
+A manual layout for Awesome with a rapid interactive editor.
+
+Demos: https://imgur.com/a/OlM60iw
+
+Draft mode: https://imgur.com/a/BOvMeQL
+
+## Why?
+
+TL;DR --- To bring back the control of the window layout.
+
+1. Dynamic tiling can be an overkill, since tiling is only useful for persistent windows, and people extensively use hibernate/sleep these days.
+2. Having window moving around can be annoying whenever a new window shows up.
+3. I want a flexible layout such that I can quickly adjust to whatever I need.
+
+## Compatibilities
+
+I developed it with Awesome git version. Hopefully it works with 4.3 stable.
+Please let me know if it does not work in 4.3 or older versions.
+
+## Really quick usage
+
+See `rc.patch` for adding layout-machi to the default 4.3 config.
+
+## Quick usage
+
+Suppose this git is checked out at `~/.config/awesome/layout-machi`
+
+Use `local machi = require("layout-machi")` to load the module.
+
+The package provide a default layout `machi.default_layout` and editor `machi.default_editor`, which can be added into the layout list.
+
+The package comes with the icon for `layoutbox`, which can be set with the following statement (after a theme has been loaded):
+
+`require("beautiful").layout_machi = machi.get_icon()`
+
+By default, any machi layout will use the layout command from `machi.layout.default_cmd`, which is initialized as `dw66.` (see interpretation below).
+You can change it after loading the module.
+
+## Use the layout
+
+Use `local layout = machi.layout.create(args)` to instantiate the layout with an editor object. `args` is a table of arguments, where the followings can be used:
+
+ - `name`: the constant name of the layout.
+ - `name_func`: a `function(t)` closure that returns a string for tag `t`. `name_func` overrides `name`.
+ - `persistent`: whether to keep a history of the command for the layout. The default is `true`.
+ - `default_cmd`: the command to use if there is no persistent history for this layout.
+ - `editor`: the editor used for the layout. The default is `machi.default_editor` (or `machi.editor.default_editor`).
+
+Either `name` or `name_func` must be set - others are optional.
+
+The function is compatible with the previous `machi.layout.create(name, editor, default_cmd)` calls.
+
+## The layout editor and commands
+
+### Starting editor in lua
+
+Call `local editor = machi.editor.create()` to create an editor.
+To edit the layout `l` on screen `s`, call `editor.start_interactive(s = awful.screen.focused(), l = awful.layout.get(s))`.
+
+### Basic usage
+
+The editing command starts with the open region of the entire workarea, perform "operations" to split the current region into multiple sub-regions, then recursively edits each of them (by default, the maximum split depth is 2).
+The layout is defined by a sequence of operations as a layout command.
+The layout editor allows users to interactively input their commands and shows the resulting layouts on screen, with the following auxiliary functions:
+
+1. `Up`/`Down`: restore to the history command
+2. `Backspace`: undo the last command.
+3. `Escape`: exit the editor without saving the layout.
+4. `Enter`: when all regions are defined, hit enter will save the layout.
+
+### Layout command
+
+As aforementioned, command a sequence of operations.
+There are three kinds of operations:
+
+1. Operations taking argument string and parsed as multiple numbers.
+
+ `h` horizontally split, `v` vertically split, `w` grid split, `d` draft split
+
+2. Operations taking argument string as a single number.
+
+ `s` shift active region, `t` set the maximum split depth, `x` set the nested layout of the current region.
+
+3. Operation not taking argument.
+
+ `.` finish all regions, `-` finish the current region, `/` remove the current region, `;` no-op
+
+Argument strings are composed of numbers and `,`. If the string contains `,`, it will be used to split argument into multiple numbers.
+Otherwise, each digit in the string will be treated as a separated number in type 1 ops.
+
+Each operation may take argument string either from before (such as `22w`) or after (such as `w22`).
+When any ambiguity arises, operation before always take the argument after. So `h11v` is interpreted as `h11` and `v`.
+
+For examples:
+
+`h-v`
+
+```
+11 22
+11 22
+11
+11 33
+11 33
+```
+
+
+`hvv` (or `22w`)
+
+```
+11 33
+11 33
+
+22 44
+22 44
+```
+
+
+`131h2v-12v`
+
+Details:
+
+ - `131h`: horizontally split the initial region (entire desktop) to the ratio of 1:3:1
+ - For the first `1` part:
+ - `2v`: vertically split the region to the ratio of 2:1
+ - `-`: skip the editing of the middle `3` part
+ - For the right `1` part:
+ - `12v`: split the right part vertically to the ratio of 1:2
+
+Tada!
+
+```
+11 3333 44
+11 3333 44
+11 3333
+11 3333 55
+ 3333 55
+22 3333 55
+22 3333 55
+```
+
+
+`12210121d`
+
+```
+11 2222 3333 44
+11 2222 3333 44
+
+55 6666 7777 88
+55 6666 7777 88
+55 6666 7777 88
+55 6666 7777 88
+
+99 AAAA BBBB CC
+99 AAAA BBBB CC
+```
+
+### Advanced grid layout
+
+__More document coming soon. For now there is only a running example.__
+
+Simple grid, `w44`:
+```
+0 1 2 3
+
+4 5 6 7
+
+8 9 A B
+
+C D E F
+```
+
+Merge grid from the top-left corner, size 3x1, `w4431`:
+```
+0-0-0 1
+
+2 3 4 5
+
+6 7 8 9
+
+A B C D
+```
+
+Another merge, size 1x3, `w443113`:
+```
+0-0-0 1
+ |
+2 3 4 1
+ |
+5 6 7 1
+
+8 9 A B
+```
+
+Another merge, size 1x3, `w44311313`:
+```
+0-0-0 1
+ |
+2 3 4 1
+| |
+2 5 6 1
+|
+2 7 8 9
+```
+
+Another merge, size 2x2, `w4431131322`:
+```
+0-0-0 1
+ |
+2 3-3 1
+| | | |
+2 3-3 1
+|
+2 4 5 6
+```
+
+Final merge, size 3x1, `w443113132231`:
+```
+0-0-0 1
+ |
+2 3-3 1
+| | | |
+2 3-3 1
+|
+2 4-4-4
+```
+
+### Draft mode
+
+__This mode is somewhat usable, yet it may change in the future.__
+
+Unlike the original machi layout, where a window fits in a single region, draft mode allows window to span across multiple regions.
+Each tiled window is associated with a upper-left region (ULR) and a bottom-right region (BRR).
+The geometry of the window is from the upper-left corner of the ULR to the bottom-right corner of the BRR.
+
+This is suppose to work with regions produced with `d` or `w` operation.
+To enable draft mode in a layout, configure the layout with a command with a leading `d`, for example, `d12210121`, or `dw66`.
+
+### Nested layouts
+
+__This feature is a toy. It may come with performance and usability issues - you have been warned.__
+
+Known caveats include:
+
+1. `arrange()` of the nested layouts are always called when the machi `arrange()` is called. This could be optimized with caching.
+2. `client.*wfact` and other layout related operations don't work as machi fakes tag data to the nested layout engine.
+ But it hopefully works if one changes the fields in the faked tag data.
+
+__This feature is not available in draft mode.__
+
+To set up nested layouts, you first need to check/modify `machi.editor.nested_layouts` array, which maps an argument string (`[0-9,]+`) to a layout object.
+In machi command, use the argument string with command `x` will set up the nested layout of the region to the mapped one.
+
+For example, since by default `machi.editor.nested_layouts["0"]` is `awful.layout.suit.tile` and `machi.editor.nested_layouts["1"]` is `awful.layout.suit.spiral`,
+the command `11h0x1x` will split the screen horizontally and apply the layouts accordingly - see the figure below.
+
+![nested layout screenshot](nested_layout_screenshot.png)
+
+### Persistent history
+
+By default, the last 100 command sequences are stored in `.cache/awesome/history_machi`.
+To change that, please refer to `editor.lua`. (XXX more documents)
+
+## Switcher
+
+Calling `machi.switcher.start()` will create a switcher supporting the following keys:
+
+ - Arrow keys: move focus into other regions by the direction.
+ - `Shift` + arrow keys: move the focused window to other regions by the direction. In draft mode, move the window while preserving its size.
+ - `Control`[ + `Shift`] + arrow keys: move the bottom-right (or top-left window if `Shift` is pressed) region of the focused window by direction. Only works in draft mode.
+ - `Tab`: switch beteen windows covering the current regions.
+
+So far, the key binding is not configurable. One has to modify the source code to change it.
+
+## Caveats
+
+1. layout-machi handles `beautiful.useless_gap` slightly differently.
+
+2. A compositor (e.g. picom, compton, xcompmgr) is required. Otherwise switcher and editor will block the clients.
+
+## License
+
+Apache 2.0 --- See LICENSE
diff --git a/awesome/layout-machi/editor.lua b/awesome/layout-machi/editor.lua
new file mode 100644
index 0000000..e0229c2
--- /dev/null
+++ b/awesome/layout-machi/editor.lua
@@ -0,0 +1,992 @@
+local api = {
+ beautiful = require("beautiful"),
+ wibox = require("wibox"),
+ awful = require("awful"),
+ screen = require("awful.screen"),
+ layout = require("awful.layout"),
+ naughty = require("naughty"),
+ gears = require("gears"),
+ gfs = require("gears.filesystem"),
+ lgi = require("lgi"),
+ dpi = require("beautiful.xresources").apply_dpi,
+}
+
+local ERROR = 2
+local WARNING = 1
+local INFO = 0
+local DEBUG = -1
+
+local module = {
+ log_level = WARNING,
+ nested_layouts = {
+ ["0"] = api.layout.suit.tile,
+ ["1"] = api.layout.suit.spiral,
+ ["2"] = api.layout.suit.fair,
+ ["3"] = api.layout.suit.fair.horizontal,
+ },
+}
+
+local function log(level, msg)
+ if level > module.log_level then
+ print(msg)
+ end
+end
+
+local function with_alpha(col, alpha)
+ local r, g, b
+ _, r, g, b, _ = col:get_rgba()
+ return api.lgi.cairo.SolidPattern.create_rgba(r, g, b, alpha)
+end
+
+local function max(a, b)
+ if a < b then return b else return a end
+end
+
+local function is_tiling(c)
+ return
+ not (c.tomb_floating or c.floating or c.maximized_horizontal or c.maximized_vertical or c.maximized or c.fullscreen)
+end
+
+local function set_tiling(c)
+ c.floating = false
+ c.maximized = false
+ c.maximized_vertical = false
+ c.maximized_horizontal = false
+ c.fullscreen = false
+end
+
+local function parse_arg_string(s, default)
+ local ret = {}
+ if #s == 0 then return ret end
+ local index = 1
+ local comma_mode = s:find(",") ~= nil
+
+ local p = index
+ while index <= #s do
+ if comma_mode then
+ if s:sub(index, index) == "," then
+ local r = tonumber(s:sub(p, index - 1))
+ if r == nil then
+ ret[#ret + 1] = default
+ else
+ ret[#ret + 1] = r
+ end
+ p = index + 1
+ end
+ else
+ local r = tonumber(s:sub(index, index))
+ if r == nil then
+ ret[#ret + 1] = default
+ else
+ ret[#ret + 1] = r
+ end
+ end
+ index = index + 1
+ end
+
+ if comma_mode then
+ local r = tonumber(s:sub(p, index - 1))
+ if r == nil then
+ ret[#ret + 1] = default
+ else
+ ret[#ret + 1] = r
+ end
+ p = index + 1
+ end
+
+ return ret
+end
+
+local function test_parse_arg_string()
+ local x = parse_arg_string("12a3", "aha")
+ assert(#x == 4 and x[1] == 1 and x[2] == 2 and x[3] == "aha" and x[4] == 3)
+ local x = parse_arg_string("12,a3,4", "aha")
+ assert(#x == 3 and x[1] == 12 and x[2] == "aha" and x[3] == 4)
+end
+
+-- test_parse_arg_string()
+
+local function fair_split(total, shares, shares_sum)
+ local ret = {}
+ local acc = 0
+ local acc_ret = 0
+ if shares_sum == nil then
+ shares_sum = 0
+ for i = 1, #shares do shares_sum = shares_sum + shares[i] end
+ end
+ for i = 1, #shares do
+ acc = acc + shares[i]
+ ret[i] = i < #shares and math.floor(total / shares_sum * acc - acc_ret + 0.5) or total - acc_ret
+ acc_ret = acc_ret + ret[i]
+ end
+ return ret
+end
+
+local function min(a, b)
+ if a < b then return a else return b end
+end
+
+local function max(a, b)
+ if a < b then return b else return a end
+end
+
+local function _area_tostring(wa)
+ return "{x:" .. tostring(wa.x) .. ",y:" .. tostring(wa.y) .. ",w:" .. tostring(wa.width) .. ",h:" .. tostring(wa.height) .. "}"
+end
+
+local function shrink_area_with_gap(a, inner_gap, outer_gap)
+ return { x = a.x + (a.bl and outer_gap or inner_gap / 2), y = a.y + (a.bu and outer_gap or inner_gap / 2),
+ width = a.width - (a.bl and outer_gap or inner_gap / 2) - (a.br and outer_gap or inner_gap / 2),
+ height = a.height - (a.bu and outer_gap or inner_gap / 2) - (a.bd and outer_gap or inner_gap / 2),
+ layout = a.layout }
+end
+
+function module.restore_data(data)
+ if data.history_file then
+ local file, err = io.open(data.history_file, "r")
+ if err then
+ log(INFO, "cannot read history from " .. data.history_file)
+ else
+ data.cmds = {}
+ data.last_cmd = {}
+ local last_layout_name
+ for line in file:lines() do
+ if line:sub(1, 1) == "+" then
+ last_layout_name = line:sub(2, #line)
+ else
+ if last_layout_name ~= nil then
+ log(DEBUG, "restore last cmd " .. line .. " for " .. last_layout_name)
+ data.last_cmd[last_layout_name] = line
+ last_layout_name = nil
+ else
+ log(DEBUG, "restore cmd " .. line)
+ data.cmds[#data.cmds + 1] = line
+ end
+ end
+ end
+ file:close()
+ end
+ end
+
+ return data
+end
+
+function module.create(data)
+ if data == nil then
+ data = module.restore_data({
+ history_file = api.gfs.get_cache_dir() .. "/history_machi",
+ history_save_max = 100,
+ })
+ end
+
+ if data.cmds == nil then
+ data.cmds = {}
+ end
+
+ if data.last_cmd == nil then
+ data.last_cmd = {}
+ end
+
+ local init_max_depth = 2
+
+ local closed_areas
+ local open_areas
+ local history
+ local arg_str
+ local max_depth
+ local current_info
+ local current_cmd
+ local pending_op
+ local to_exit
+ local to_apply
+
+ local function init(init_area, extend)
+ closed_areas = {}
+ open_areas = {
+ {
+ x = init_area.x - extend,
+ y = init_area.y - extend,
+ width = init_area.width + extend * 2,
+ height = init_area.height + extend * 2,
+ depth = 0,
+ group_id = 0,
+ bl = true, br = true, bu = true, bd = true,
+ }
+ }
+ history = {}
+ arg_str = ""
+ max_depth = init_max_depth
+ current_info = ""
+ current_cmd = ""
+ pending_op = nil
+ to_exit = false
+ to_apply = false
+ end
+
+ local function push_history()
+ if history == nil then return end
+ history[#history + 1] = {#closed_areas, #open_areas, {}, current_info, current_cmd, pending_op, max_depth, arg_str}
+ end
+
+ local function discard_history()
+ if history == nil then return end
+ table.remove(history, #history)
+ end
+
+ local function pop_history()
+ if history == nil or #history == 0 then return end
+ for i = history[#history][1] + 1, #closed_areas do
+ table.remove(closed_areas, #closed_areas)
+ end
+
+ for i = history[#history][2] + 1, #open_areas do
+ table.remove(open_areas, #open_areas)
+ end
+
+ for i = 1, #history[#history][3] do
+ open_areas[history[#history][2] - i + 1] = history[#history][3][i]
+ end
+
+ current_info = history[#history][4]
+ current_cmd = history[#history][5]
+ pending_op = history[#history][6]
+ max_depth = history[#history][7]
+ arg_str = history[#history][8]
+
+ table.remove(history, #history)
+ end
+
+ local function pop_open_area()
+ local a = open_areas[#open_areas]
+ table.remove(open_areas, #open_areas)
+ if history == nil or #history == 0 then return a end
+
+ local idx = history[#history][2] - #open_areas
+ -- only save when the position has been firstly poped
+ if idx > #history[#history][3] then
+ history[#history][3][#history[#history][3] + 1] = a
+ end
+ return a
+ end
+
+ local function push_area()
+ closed_areas[#closed_areas + 1] = pop_open_area()
+ end
+
+ local function push_children(c)
+ for i = #c, 1, -1 do
+ if c[i].x ~= math.floor(c[i].x)
+ or c[i].y ~= math.floor(c[i].y)
+ or c[i].width ~= math.floor(c[i].width)
+ or c[i].height ~= math.floor(c[i].height)
+ then
+ log(WARNING, "splitting yields floating area " .. _area_tostring(c[i]))
+ end
+ open_areas[#open_areas + 1] = c[i]
+ end
+ end
+
+ local op_count = 0
+
+ local function handle_op(method)
+ op_count = op_count + 1
+
+ local l = method:lower()
+ local alt = method ~= l
+ method = l
+
+ log(DEBUG, "op " .. method .. " " .. tostring(alt) .. " " .. arg_str)
+ if method == "h" or method == "v" then
+
+ local a = pop_open_area()
+ local args = parse_arg_string(arg_str, 0)
+ if #args == 0 then
+ args = {1, 1}
+ elseif #args == 1 then
+ args[2] = 1
+ end
+
+ local total = 0
+ local shares = { }
+ for i = 1, #args do
+ local arg
+ if not alt then
+ arg = args[i]
+ else
+ arg = args[#args - i + 1]
+ end
+ if arg < 1 then arg = 1 end
+ total = total + arg
+ shares[i] = arg
+ end
+ local children = {}
+
+ if method == "h" then
+ shares = fair_split(a.width, shares, total)
+ for i = 1, #shares do
+ local child = {
+ x = i == 1 and a.x or children[#children].x + children[#children].width,
+ y = a.y,
+ width = shares[i],
+ height = a.height,
+ depth = a.depth + 1,
+ group_id = op_count,
+ bl = i == 1 and a.bl or false,
+ br = i == #shares and a.br or false,
+ bu = a.bu,
+ bd = a.bd,
+ }
+ children[#children + 1] = child
+ end
+ else
+ shares = fair_split(a.height, shares, total)
+ for i = 1, #shares do
+ local child = {
+ x = a.x,
+ y = i == 1 and a.y or children[#children].y + children[#children].height,
+ width = a.width,
+ height = shares[i],
+ depth = a.depth + 1,
+ group_id = op_count,
+ bl = a.bl,
+ br = a.br,
+ bu = i == 1 and a.bu or false,
+ bd = i == #shares and a.bd or false,
+ }
+ children[#children + 1] = child
+ end
+ end
+
+ push_children(children)
+
+ elseif method == "w" then
+
+ local a = pop_open_area()
+ local args = parse_arg_string(arg_str, 0)
+ if #args == 0 then
+ args = {1, 1}
+ elseif #args == 1 then
+ args[2] = 1
+ end
+
+ local h_split, v_split
+ if alt then
+ h_split = args[2]
+ v_split = args[1]
+ else
+ h_split = args[1]
+ v_split = args[2]
+ end
+ if h_split < 1 then h_split = 1 end
+ if v_split < 1 then v_split = 1 end
+
+ local x_shares = {}
+ local y_shares = {}
+ for i = 1, h_split do x_shares[i] = 1 end
+ for i = 1, v_split do y_shares[i] = 1 end
+
+ x_shares = fair_split(a.width, x_shares, h_split)
+ y_shares = fair_split(a.height, y_shares, v_split)
+
+ local children = {}
+ for y_index = 1, v_split do
+ for x_index = 1, h_split do
+ local r = {
+ x = x_index == 1 and a.x or children[#children].x + children[#children].width,
+ y = y_index == 1 and a.y or (x_index == 1 and children[#children].y + children[#children].height or children[#children].y),
+ width = x_shares[x_index],
+ height = y_shares[y_index],
+ depth = a.depth + 1,
+ group_id = op_count,
+ }
+ if x_index == 1 then r.bl = a.bl else r.bl = false end
+ if x_index == h_split then r.br = a.br else r.br = false end
+ if y_index == 1 then r.bu = a.bu else r.bu = false end
+ if y_index == v_split then r.bd = a.bd else r.bd = false end
+ children[#children + 1] = r
+ end
+ end
+
+ local merged_children = {}
+ local start_index = 1
+ for i = 3, #args - 1, 2 do
+ -- find the first index that is not merged
+ while start_index <= #children and children[start_index] == false do
+ start_index = start_index + 1
+ end
+ if start_index > #children or children[start_index] == false then
+ break
+ end
+ local x = (start_index - 1) % h_split
+ local y = math.floor((start_index - 1) / h_split)
+ local w = args[i]
+ local h = args[i + 1]
+ if w < 1 then w = 1 end
+ if h == nil or h < 1 then h = 1 end
+ if alt then
+ local tmp = w
+ w = h
+ h = tmp
+ end
+ if x + w > h_split then w = h_split - x end
+ if y + h > v_split then h = v_split - y end
+ local end_index = start_index
+ for ty = y, y + h - 1 do
+ local succ = true
+ for tx = x, x + w - 1 do
+ if children[ty * h_split + tx + 1] == false then
+ succ = false
+ break
+ elseif ty == y then
+ end_index = ty * h_split + tx + 1
+ end
+ end
+
+ if not succ then
+ break
+ elseif ty > y then
+ end_index = ty * h_split + x + w
+ end
+ end
+
+ local r = {
+ x = children[start_index].x, y = children[start_index].y,
+ width = children[end_index].x + children[end_index].width - children[start_index].x,
+ height = children[end_index].y + children[end_index].height - children[start_index].y,
+ bu = children[start_index].bu, bl = children[start_index].bl,
+ bd = children[end_index].bd, br = children[end_index].br,
+ depth = a.depth + 1,
+ group_id = op_count
+ }
+ merged_children[#merged_children + 1] = r
+
+ for ty = y, y + h - 1 do
+ local succ = true
+ for tx = x, x + w - 1 do
+ local index = ty * h_split + tx + 1
+ if index <= end_index then
+ children[index] = false
+ else
+ break
+ end
+ end
+ end
+ end
+
+ -- clean up children, remove all `false'
+ local j = 1
+ for i = 1, #children do
+ if children[i] ~= false then
+ children[j] = children[i]
+ j = j + 1
+ end
+ end
+ for i = #children, j, -1 do
+ table.remove(children, i)
+ end
+
+ push_children(merged_children)
+ push_children(children)
+
+ elseif method == "d" then
+
+ local a = pop_open_area()
+ local shares = parse_arg_string(arg_str, 0)
+ local x_shares = {}
+ local y_shares = {}
+
+ local current = x_shares
+ for i = 1, #shares do
+ if not alt then
+ arg = shares[i]
+ else
+ arg = shares[#shares - i + 1]
+ end
+ if arg < 1 then
+ if current == x_shares then current = y_shares else break end
+ else
+ current[#current + 1] = arg
+ end
+ end
+
+ if #x_shares == 0 then
+ open_areas[#open_areas + 1] = a
+ return
+ elseif #y_shares == 0 then
+ y_shares = {1}
+ end
+
+ x_shares = fair_split(a.width, x_shares)
+ y_shares = fair_split(a.height, y_shares)
+
+ local children = {}
+ for y_index = 1, #y_shares do
+ for x_index = 1, #x_shares do
+ local r = {
+ x = x_index == 1 and a.x or children[#children].x + children[#children].width,
+ y = y_index == 1 and a.y or (x_index == 1 and children[#children].y + children[#children].height or children[#children].y),
+ width = x_shares[x_index],
+ height = y_shares[y_index],
+ depth = a.depth + 1,
+ group_id = op_count,
+ }
+ if x_index == 1 then r.bl = a.bl else r.bl = false end
+ if x_index == #x_shares then r.br = a.br else r.br = false end
+ if y_index == 1 then r.bu = a.bu else r.bu = false end
+ if y_index == #y_shares then r.bd = a.bd else r.bd = false end
+ children[#children + 1] = r
+ end
+ end
+
+ push_children(children)
+
+ elseif method == "s" then
+
+ if #open_areas > 0 then
+ local times = arg_str == "" and 1 or tonumber(arg_str)
+ local t = {}
+ while #open_areas > 0 do
+ t[#t + 1] = pop_open_area()
+ end
+ for i = #t, 1, -1 do
+ open_areas[#open_areas + 1] = t[(i + times - 1) % #t + 1]
+ end
+ end
+
+ elseif method == "t" then
+
+ local n = tonumber(arg_str)
+ if n ~= nil then
+ max_depth = n
+ end
+
+ elseif method == "x" then
+
+ push_area()
+ closed_areas[#closed_areas].layout = module.nested_layouts[arg_str]
+
+ elseif method == "-" then
+
+ push_area()
+
+ elseif method == "." then
+
+ while #open_areas > 0 do
+ push_area()
+ end
+
+ elseif method == "/" then
+
+ pop_open_area()
+
+ elseif method == ";" then
+
+ -- nothing
+
+ end
+
+ while #open_areas > 0 and open_areas[#open_areas].depth >= max_depth do
+ push_area()
+ end
+
+ arg_str = ""
+ end
+
+ local key_translate_tab = {
+ ["Return"] = ".",
+ [" "] = "-",
+ }
+
+ -- 3 for taking the arg string and an open area
+ -- 2 for taking an open area
+ -- 1 for taking nothing
+ -- 0 for args
+ local ch_info = {
+ ["h"] = 3, ["H"] = 3,
+ ["v"] = 3, ["V"] = 3,
+ ["w"] = 3, ["W"] = 3,
+ ["d"] = 3, ["D"] = 3,
+ ["s"] = 3, ["S"] = 3,
+ ["t"] = 3, ["T"] = 3,
+ ["x"] = 3,
+ ["-"] = 2,
+ ["/"] = 2,
+ ["."] = 1,
+ [";"] = 1,
+ ["0"] = 0, ["1"] = 0, ["2"] = 0, ["3"] = 0, ["4"] = 0,
+ ["5"] = 0, ["6"] = 0, ["7"] = 0, ["8"] = 0, ["9"] = 0,
+ [","] = 0,
+ }
+
+ local function handle_ch(key)
+ if key_translate_tab[key] ~= nil then
+ key = key_translate_tab[key]
+ end
+ local t = ch_info[key]
+ if t == nil then
+ return nil
+ elseif t == 3 then
+ if pending_op ~= nil then
+ handle_op(pending_op)
+ pending_op = nil
+ end
+ if #open_areas == 0 then return nil end
+ if arg_str == "" then
+ pending_op = key
+ else
+ handle_op(key)
+ end
+ elseif t == 2 or t == 1 then
+ if pending_op ~= nil then
+ handle_op(pending_op)
+ pending_op = nil
+ end
+ if #open_areas == 0 and t == 2 then return nil end
+ handle_op(key)
+ elseif t == 0 then
+ arg_str = arg_str .. key
+ end
+
+ return key
+ end
+
+ local function set_gap(inner_gap, outer_gap)
+ data.inner_gap = inner_gap
+ data.outer_gap = outer_gap
+ end
+
+ local function start_interactive(screen, layout)
+ local outer_gap = data.outer_gap or data.gap or api.beautiful.useless_gap * 2 or 0
+ local inner_gap = data.inner_gap or data.gap or api.beautiful.useless_gap * 2 or 0
+ local label_font_family = api.beautiful.get_font(
+ api.beautiful.font):get_family()
+ local label_size = api.dpi(30)
+ local info_size = api.dpi(60)
+ -- colors are in rgba
+ local border_color = with_alpha(api.gears.color(
+ api.beautiful.editor_border_color or api.beautiful.border_focus),
+ api.beautiful.editor_border_opacity or 0.75)
+ local active_color = with_alpha(api.gears.color(
+ api.beautiful.editor_active_color or api.beautiful.bg_focus),
+ api.beautiful.editor_active_opacity or 0.5)
+ local open_color = with_alpha(api.gears.color(
+ api.beautiful.editor_open_color or api.beautiful.bg_normal),
+ api.beautiful.editor_open_opacity or 0.5)
+ local closed_color = open_color
+
+ screen = screen or api.screen.focused()
+ layout = layout or api.layout.get(screen)
+ local tag = screen.selected_tag
+
+ if layout.machi_set_cmd == nil then
+ api.naughty.notify({
+ text = "The layout to edit is not machi",
+ timeout = 3,
+ })
+ return
+ end
+
+ local cmd_index = #data.cmds + 1
+ data.cmds[cmd_index] = ""
+
+ local start_x = screen.workarea.x
+ local start_y = screen.workarea.y
+
+ local kg
+ local infobox = api.wibox({
+ screen = screen,
+ x = screen.workarea.x,
+ y = screen.workarea.y,
+ width = screen.workarea.width,
+ height = screen.workarea.height,
+ bg = "#ffffff00",
+ opacity = 1,
+ ontop = true,
+ type = "dock",
+ })
+ infobox.visible = true
+
+ local function cleanup()
+ infobox.visible = false
+ end
+
+ local function draw_info(context, cr, width, height)
+ cr:set_source_rgba(0, 0, 0, 0)
+ cr:rectangle(0, 0, width, height)
+ cr:fill()
+
+ local msg, ext
+
+ for i, a in ipairs(closed_areas) do
+ local sa = shrink_area_with_gap(a, inner_gap, inner_gap / 2)
+ local to_highlight = false
+ if pending_op ~= nil then
+ to_highlight = a.group_id == op_count
+ end
+ cr:rectangle(sa.x - start_x, sa.y - start_y, sa.width, sa.height)
+ cr:clip()
+ if to_highlight then
+ cr:set_source(active_color)
+ else
+ cr:set_source(closed_color)
+ end
+ cr:rectangle(sa.x - start_x, sa.y - start_y, sa.width, sa.height)
+ cr:fill()
+ cr:set_source(border_color)
+ cr:rectangle(sa.x - start_x, sa.y - start_y, sa.width, sa.height)
+ cr:set_line_width(10.0)
+ cr:stroke()
+ cr:reset_clip()
+ end
+
+ for i, a in ipairs(open_areas) do
+ local sa = shrink_area_with_gap(a, inner_gap, inner_gap / 2)
+ local to_highlight = false
+ if pending_op == nil then
+ to_highlight = i == #open_areas
+ else
+ to_highlight = a.group_id == op_count
+ end
+ cr:rectangle(sa.x - start_x, sa.y - start_y, sa.width, sa.height)
+ cr:clip()
+ if i == #open_areas then
+ cr:set_source(active_color)
+ else
+ cr:set_source(open_color)
+ end
+ cr:rectangle(sa.x - start_x, sa.y - start_y, sa.width, sa.height)
+ cr:fill()
+
+ cr:set_source(border_color)
+ cr:rectangle(sa.x - start_x, sa.y - start_y, sa.width, sa.height)
+ cr:set_line_width(10.0)
+ if to_highlight then
+ cr:stroke()
+ else
+ cr:set_dash({5, 5}, 0)
+ cr:stroke()
+ cr:set_dash({}, 0)
+ end
+ cr:reset_clip()
+ end
+
+ cr:select_font_face(label_font_family, "normal", "normal")
+ cr:set_font_size(info_size)
+ cr:set_font_face(cr:get_font_face())
+ msg = current_info
+ ext = cr:text_extents(msg)
+ cr:move_to(width / 2 - ext.width / 2 - ext.x_bearing, height / 2 - ext.height / 2 - ext.y_bearing)
+ cr:text_path(msg)
+ cr:set_source_rgba(1, 1, 1, 1)
+ cr:fill()
+ cr:move_to(width / 2 - ext.width / 2 - ext.x_bearing, height / 2 - ext.height / 2 - ext.y_bearing)
+ cr:text_path(msg)
+ cr:set_source_rgba(0, 0, 0, 1)
+ cr:set_line_width(2.0)
+ cr:stroke()
+ end
+
+ local function refresh()
+ log(DEBUG, "closed areas:")
+ for i, a in ipairs(closed_areas) do
+ log(DEBUG, " " .. _area_tostring(a))
+ end
+ log(DEBUG, "open areas:")
+ for i, a in ipairs(open_areas) do
+ log(DEBUG, " " .. _area_tostring(a))
+ end
+ infobox.bgimage = draw_info
+ end
+
+ log(DEBUG, "interactive layout editing starts")
+
+ init(screen.workarea, inner_gap / 2 - outer_gap)
+ refresh()
+
+ kg = api.awful.keygrabber.run(
+ function (mod, key, event)
+ if event == "release" then
+ return
+ end
+
+ local ok, err = pcall(
+ function ()
+ if pending_op ~= nil then
+ pop_history()
+ end
+
+ if key == "BackSpace" then
+ pop_history()
+ elseif key == "Escape" then
+ table.remove(data.cmds, #data.cmds)
+ to_exit = true
+ elseif key == "Up" or key == "Down" then
+ if current_cmd ~= data.cmds[cmd_index] then
+ data.cmds[#data.cmds] = current_cmd
+ end
+
+ if key == "Up" and cmd_index > 1 then
+ cmd_index = cmd_index - 1
+ elseif key == "Down" and cmd_index < #data.cmds then
+ cmd_index = cmd_index + 1
+ end
+
+ log(DEBUG, "restore history #" .. tostring(cmd_index) .. ":" .. data.cmds[cmd_index])
+ init(screen.workarea, inner_gap / 2 - outer_gap)
+ for i = 1, #data.cmds[cmd_index] do
+ local cmd = data.cmds[cmd_index]:sub(i, i)
+
+ push_history()
+ local ret = handle_ch(cmd)
+
+ if ret == nil then
+ log(WARNING, "ret is nil")
+ else
+ current_info = current_info .. ret
+ current_cmd = current_cmd .. ret
+ end
+ end
+
+ if #open_areas == 0 then
+ current_info = current_info .. " (enter to save)"
+ end
+ elseif #open_areas > 0 then
+ push_history()
+ local ret = handle_ch(key)
+ if ret ~= nil then
+ current_info = current_info .. ret
+ current_cmd = current_cmd .. ret
+ else
+ pop_history()
+ end
+
+ if #open_areas == 0 then
+ current_info = current_info .. " (enter to apply)"
+ end
+ else
+ if key == "Return" then
+ table.remove(data.cmds, #data.cmds)
+ -- remove duplicated entries
+ local j = 1
+ for i = 1, #data.cmds do
+ if data.cmds[i] ~= current_cmd then
+ data.cmds[j] = data.cmds[i]
+ j = j + 1
+ end
+ end
+ for i = #data.cmds, j, -1 do
+ table.remove(data.cmds, i)
+ end
+ -- bring the current cmd to the front
+ data.cmds[#data.cmds + 1] = current_cmd
+
+ local instance_name, persistent = layout.machi_get_instance_info(tag)
+ if persistent then
+ data.last_cmd[instance_name] = current_cmd
+ if data.history_file then
+ local file, err = io.open(data.history_file, "w")
+ if err then
+ log(ERROR, "cannot save history to " .. data.history_file)
+ else
+ for i = max(1, #data.cmds - data.history_save_max + 1), #data.cmds do
+ log(DEBUG, "save cmd " .. data.cmds[i])
+ file:write(data.cmds[i] .. "\n")
+ end
+ for name, cmd in pairs(data.last_cmd) do
+ log(DEBUG, "save last cmd " .. cmd .. " for " .. name)
+ file:write("+" .. name .. "\n" .. cmd .. "\n")
+ end
+ end
+ file:close()
+ end
+ current_info = "Saved!"
+ else
+ current_info = "Applied!"
+ end
+
+ to_exit = true
+ to_apply = true
+ end
+ end
+
+ if not to_exit and pending_op ~= nil then
+ push_history()
+ handle_op(pending_op)
+ end
+
+ refresh()
+
+ if to_exit then
+ log(DEBUG, "interactive layout editing ends")
+ if to_apply then
+ layout.machi_set_cmd(current_cmd, tag)
+ api.layout.arrange(screen)
+ api.gears.timer{
+ timeout = 1,
+ autostart = true,
+ singleshot = true,
+ callback = cleanup,
+ }
+ else
+ cleanup()
+ end
+ end
+ end)
+
+ if not ok then
+ log(ERROR, "Getting error in keygrabber: " .. err)
+ to_exit = true
+ cleanup()
+ end
+
+ if to_exit then
+ api.awful.keygrabber.stop(kg)
+ end
+ end
+ )
+ end
+
+ local function run_cmd(init_area, cmd)
+ local outer_gap = data.outer_gap or data.gap or api.beautiful.useless_gap * 2 or 0
+ local inner_gap = data.inner_gap or data.gap or api.beautiful.useless_gap * 2 or 0
+ init(init_area, inner_gap / 2 - outer_gap)
+
+ for i = 1, #cmd do
+ handle_ch(cmd:sub(i, i))
+ end
+
+ local areas_with_gap = {}
+ for _, a in ipairs(closed_areas) do
+ areas_with_gap[#areas_with_gap + 1] = shrink_area_with_gap(a, inner_gap, inner_gap / 2)
+ end
+ table.sort(
+ areas_with_gap,
+ function (a1, a2)
+ local s1 = a1.width * a1.height
+ local s2 = a2.width * a2.height
+ if math.abs(s1 - s2) < 0.01 then
+ return (a1.x + a1.y) < (a2.x + a2.y)
+ else
+ return s1 > s2
+ end
+ end
+ )
+
+ return areas_with_gap
+ end
+
+ local function get_last_cmd(name)
+ return data.last_cmd[name]
+ end
+
+ return {
+ start_interactive = start_interactive,
+ run_cmd = run_cmd,
+ get_last_cmd = get_last_cmd,
+ set_gap = set_gap,
+ }
+end
+
+module.default_editor = module.create()
+
+return module
diff --git a/awesome/layout-machi/icon.png b/awesome/layout-machi/icon.png
new file mode 100644
index 0000000..e31a2a8
--- /dev/null
+++ b/awesome/layout-machi/icon.png
Binary files differ
diff --git a/awesome/layout-machi/init.lua b/awesome/layout-machi/init.lua
new file mode 100644
index 0000000..eca07e6
--- /dev/null
+++ b/awesome/layout-machi/init.lua
@@ -0,0 +1,39 @@
+local layout = require(... .. ".layout")
+local editor = require(... .. ".editor")
+local switcher = require(... .. ".switcher")
+local function default_name(tag)
+ if tag.machi_name_cache == nil then
+ tag.machi_name_cache =
+ tostring(tag.screen.geometry.width) .. "x" .. tostring(tag.screen.geometry.height) .. "+" ..
+ tostring(tag.screen.geometry.x) .. "+" .. tostring(tag.screen.geometry.y) .. '+' .. tag.name
+ end
+ return tag.machi_name_cache
+end
+local default_editor = editor.default_editor
+local default_layout = layout.create{ name_func = default_name }
+local gcolor = require("gears.color")
+local beautiful = require("beautiful")
+
+local icon_raw
+local source = debug.getinfo(1, "S").source
+if source:sub(1, 1) == "@" then
+ icon_raw = source:match("^@(.-)[^/]+$") .. "icon.png"
+end
+
+local function get_icon()
+ if icon_raw ~= nil then
+ return gcolor.recolor_image(icon_raw, beautiful.fg_normal)
+ else
+ return nil
+ end
+end
+
+return {
+ layout = layout,
+ editor = editor,
+ switcher = switcher,
+ default_editor = default_editor,
+ default_layout = default_layout,
+ icon_raw = icon_raw,
+ get_icon = get_icon,
+}
diff --git a/awesome/layout-machi/layout.lua b/awesome/layout-machi/layout.lua
new file mode 100644
index 0000000..99d37a6
--- /dev/null
+++ b/awesome/layout-machi/layout.lua
@@ -0,0 +1,395 @@
+local machi = {
+ editor = require((...):match("(.-)[^%.]+$") .. "editor"),
+}
+
+local api = {
+ screen = screen,
+ awful = require("awful"),
+}
+
+local ERROR = 2
+local WARNING = 1
+local INFO = 0
+local DEBUG = -1
+
+local module = {
+ log_level = WARNING,
+ global_default_cmd = "dw66.",
+ allowing_shrinking_by_mouse_moving = false,
+}
+
+local function log(level, msg)
+ if level > module.log_level then
+ print(msg)
+ end
+end
+
+local function min(a, b)
+ if a < b then return a else return b end
+end
+
+local function max(a, b)
+ if a < b then return b else return a end
+end
+
+local function get_screen(s)
+ return s and api.screen[s]
+end
+
+api.awful.mouse.resize.add_enter_callback(
+ function (c)
+ c.full_width_before_move = c.width + c.border_width * 2
+ c.full_height_before_move = c.height + c.border_width * 2
+ end, 'mouse.move')
+
+--- find the best region for the area-like object
+-- @param c area-like object - table with properties x, y, width, and height
+-- @param regions array of area-like objects
+-- @return the index of the best region
+local function find_region(c, regions)
+ local choice = 1
+ local choice_value = nil
+ local c_area = c.width * c.height
+ for i, a in ipairs(regions) do
+ local x_cap = max(0, min(c.x + c.width, a.x + a.width) - max(c.x, a.x))
+ local y_cap = max(0, min(c.y + c.height, a.y + a.height) - max(c.y, a.y))
+ local cap = x_cap * y_cap
+ -- -- a cap b / a cup b
+ -- local cup = c_area + a.width * a.height - cap
+ -- if cup > 0 then
+ -- local itx_ratio = cap / cup
+ -- if choice_value == nil or choice_value < itx_ratio then
+ -- choice_value = itx_ratio
+ -- choice = i
+ -- end
+ -- end
+ -- a cap b
+ if choice_value == nil or choice_value < cap then
+ choice = i
+ choice_value = cap
+ end
+ end
+ return choice
+end
+
+local function distance(x1, y1, x2, y2)
+ -- use d1
+ return math.abs(x1 - x2) + math.abs(y1 - y2)
+end
+
+local function find_lu(c, regions, rd)
+ local lu = nil
+ for i, a in ipairs(regions) do
+ if rd == nil or (a.x < regions[rd].x + regions[rd].width and a.y < regions[rd].y + regions[rd].height) then
+ if lu == nil or distance(c.x, c.y, a.x, a.y) < distance(c.x, c.y, regions[lu].x, regions[lu].y) then
+ lu = i
+ end
+ end
+ end
+ return lu
+end
+
+local function find_rd(c, regions, lu)
+ local x, y
+ x = c.x + c.width + (c.border_width or 0)
+ y = c.y + c.height + (c.border_width or 0)
+ local rd = nil
+ for i, a in ipairs(regions) do
+ if lu == nil or (a.x + a.width > regions[lu].x and a.y + a.height > regions[lu].y) then
+ if rd == nil or distance(x, y, a.x + a.width, a.y + a.height) < distance(x, y, regions[rd].x + regions[rd].width, regions[rd].y + regions[rd].height) then
+ rd = i
+ end
+ end
+ end
+ return rd
+end
+
+function module.set_geometry(c, region_lu, region_rd, useless_gap, border_width)
+ -- We try to negate the gap of outer layer
+ if region_lu ~= nil then
+ c.x = region_lu.x - useless_gap
+ c.y = region_lu.y - useless_gap
+ end
+
+ if region_rd ~= nil then
+ c.width = region_rd.x + region_rd.width - c.x + useless_gap - border_width * 2
+ c.height = region_rd.y + region_rd.height - c.y + useless_gap - border_width * 2
+ end
+end
+
+function module.create(args_or_name, editor, default_cmd)
+ local args
+ if type(args_or_name) == "string" then
+ args = {
+ name = args_or_name
+ }
+ elseif type(args_or_name) == "function" then
+ args = {
+ name_func = args_or_name
+ }
+ elseif type(args_or_name) == "table" then
+ args = args_or_name
+ else
+ return nil
+ end
+ args.editor = args.editor or editor or machi.editor.default_editor
+ args.default_cmd = args.default_cmd or default_cmd or global_default_cmd
+ args.persistent = args.persistent == nil or args.persistent
+
+ local layout = {}
+ local instances = {}
+
+ local function get_instance_info(tag)
+ return (args.name_func and args.name_func(tag) or args.name), args.persistent
+ end
+
+ local function get_instance_(tag)
+ local name, persistent = get_instance_info(tag)
+ if instances[name] == nil then
+ instances[name] = {
+ layout = layout,
+ cmd = persistent and args.editor.get_last_cmd(name) or nil,
+ regions_cache = {},
+ tag_data = {},
+ }
+ if instances[name].cmd == nil then
+ instances[name].cmd = args.default_cmd
+ end
+ end
+ return instances[name]
+ end
+
+ local function get_regions(workarea, tag)
+ local instance = get_instance_(tag)
+ local cmd = instance.cmd or module.global_default_cmd
+ if cmd == nil then return {}, false end
+
+ local key = tostring(workarea.width) .. "x" .. tostring(workarea.height) .. "+" .. tostring(workarea.x) .. "+" .. tostring(workarea.y)
+ if instance.regions_cache[key] == nil then
+ instance.regions_cache[key] = args.editor.run_cmd(workarea, cmd)
+ end
+ return instance.regions_cache[key], cmd:sub(1,1) == "d"
+ end
+
+ local function set_cmd(cmd, tag)
+ local instance = get_instance_(tag)
+ if instance.cmd ~= cmd then
+ instance.cmd = cmd
+ instance.regions_cache = {}
+ instance.tag_data = {}
+ end
+ end
+
+ local function arrange(p)
+ local useless_gap = p.useless_gap
+ local wa = get_screen(p.screen).workarea -- get the real workarea without the gap (instead of p.workarea)
+ local cls = p.clients
+ local tag = get_screen(p.screen).selected_tag
+ local instance = get_instance_(tag)
+ local regions, draft_mode = get_regions(wa, tag)
+
+ if #regions == 0 then return end
+ local nested_clients = {}
+
+ for _, c in ipairs(cls) do
+ if c.machi == nil then
+ c.machi = setmetatable({}, {__mode = "v"})
+ end
+ end
+
+ if draft_mode then
+ for i, c in ipairs(cls) do
+ if c.floating or c.immobilized then
+ log(DEBUG, "Ignore client " .. tostring(c))
+ else
+ local skip = false
+ if c.machi.lu ~= nil and c.machi.rd ~= nil and
+ c.machi.lu <= #regions and c.machi.rd <= #regions
+ then
+ if regions[c.machi.lu].x == c.x and
+ regions[c.machi.lu].y == c.y and
+ regions[c.machi.rd].x + regions[c.machi.rd].width - c.border_width * 2 == c.x + c.width and
+ regions[c.machi.rd].y + regions[c.machi.rd].height - c.border_width * 2 == c.y + c.height
+ then
+ skip = true
+ end
+ end
+
+ local lu = nil
+ local rd = nil
+ if not skip then
+ log(DEBUG, "Compute regions for " .. (c.name or ("<untitled:" .. tostring(c) .. ">")))
+ lu = find_lu(c, regions)
+ if lu ~= nil then
+ c.x = regions[lu].x
+ c.y = regions[lu].y
+ rd = find_rd(c, regions, lu)
+ end
+ end
+
+ if lu ~= nil and rd ~= nil then
+ c.machi.instance = instance
+ c.machi.region, c.machi.lu, c.machi.rd = nil, lu, rd
+ p.geometries[c] = {}
+ module.set_geometry(p.geometries[c], regions[lu], regions[rd], useless_gap, 0)
+ end
+ end
+ end
+ else
+ for i, c in ipairs(cls) do
+ if c.floating or c.immobilized then
+ log(DEBUG, "Ignore client " .. tostring(c))
+ else
+ if c.machi.region ~= nil and
+ regions[c.machi.region].layout == nil and
+ regions[c.machi.region].x == c.x and
+ regions[c.machi.region].y == c.y and
+ regions[c.machi.region].width - c.border_width * 2 == c.width and
+ regions[c.machi.region].height - c.border_width * 2 == c.height
+ then
+ else
+ log(DEBUG, "Compute regions for " .. (c.name or ("<untitled:" .. tostring(c) .. ">")))
+ local region = find_region(c, regions)
+ c.machi.instance = instance
+ c.machi.region, c.machi.lu, c.machi.rd = region, nil, nil
+ p.geometries[c] = {}
+ if regions[region].layout ~= nil then
+ local clients = nested_clients[region]
+ if clients == nil then clients = {}; nested_clients[region] = clients end
+ clients[#clients + 1] = c
+ else
+ module.set_geometry(p.geometries[c], regions[region], regions[region], useless_gap, 0)
+ end
+ end
+ end
+ end
+
+ for region, clients in pairs(nested_clients) do
+ if instance.tag_data[region] == nil then
+ -- TODO: Make the default more flexible.
+ instance.tag_data[region] = {
+ column_count = 1,
+ master_count = 1,
+ master_fill_policy = "expand",
+ useless_gap = 0,
+ master_width_factor = 0.5,
+ _private = {
+ awful_tag_properties = {
+ },
+ },
+ }
+ end
+ local nested_params = {
+ tag = instance.tag_data[region],
+ screen = p.screen,
+ clients = clients,
+ padding = 0,
+ geometry = {
+ x = regions[region].x,
+ y = regions[region].y,
+ width = regions[region].width,
+ height = regions[region].height,
+ },
+ -- Not sure how useless_gap adjustment works here. It seems to work anyway.
+ workarea = {
+ x = regions[region].x - useless_gap / 2,
+ y = regions[region].y - useless_gap / 2,
+ width = regions[region].width + useless_gap,
+ height = regions[region].height + useless_gap,
+ },
+ useless_gap = 0,
+ geometries = {},
+ }
+ regions[region].layout.arrange(nested_params)
+ for _, c in ipairs(clients) do
+ p.geometries[c] = {
+ x = nested_params.geometries[c].x - useless_gap / 2,
+ y = nested_params.geometries[c].y - useless_gap / 2,
+ width = nested_params.geometries[c].width + useless_gap,
+ height = nested_params.geometries[c].height + useless_gap,
+ }
+ end
+ end
+ end
+ end
+
+ local function resize_handler (c, context, h)
+ local workarea = c.screen.workarea
+ local regions, draft_mode = get_regions(workarea, c.screen.selected_tag)
+
+ if #regions == 0 then return end
+
+ if draft_mode then
+ local lu = find_lu(h, regions)
+ local rd = nil
+ if lu ~= nil then
+ if context == "mouse.move" then
+ -- Use the initial width and height since it may change in undesired way.
+ local hh = {}
+ hh.x = regions[lu].x
+ hh.y = regions[lu].y
+ hh.width = c.full_width_before_move
+ hh.height = c.full_height_before_move
+ rd = find_rd(hh, regions, lu)
+
+ if rd ~= nil and not module.allowing_shrinking_by_mouse_moving and
+ (regions[rd].x + regions[rd].width - regions[lu].x < c.full_width_before_move or
+ regions[rd].y + regions[rd].height - regions[lu].y < c.full_height_before_move) then
+ hh.x = regions[rd].x + regions[rd].width - c.full_width_before_move
+ hh.y = regions[rd].y + regions[rd].height - c.full_height_before_move
+ lu = find_lu(hh, regions, rd)
+ end
+ else
+ local hh = {}
+ hh.x = h.x
+ hh.y = h.y
+ hh.width = h.width
+ hh.height = h.height
+ hh.border_width = c.border_width
+ rd = find_rd(hh, regions, lu)
+ end
+
+ if lu ~= nil and rd ~= nil then
+ c.machi.lu = lu
+ c.machi.rd = rd
+ module.set_geometry(c, regions[lu], regions[rd], 0, c.border_width)
+ end
+ end
+ else
+ if context ~= "mouse.move" then return end
+
+ if #regions == 0 then return end
+
+ local center_x = h.x + h.width / 2
+ local center_y = h.y + h.height / 2
+
+ local choice = 1
+ local choice_value = nil
+
+ for i, r in ipairs(regions) do
+ local r_x = r.x + r.width / 2
+ local r_y = r.y + r.height / 2
+ local dis = (r_x - center_x) * (r_x - center_x) + (r_y - center_y) * (r_y - center_y)
+ if choice_value == nil or choice_value > dis then
+ choice = i
+ choice_value = dis
+ end
+ end
+
+ if c.machi.region ~= choice then
+ c.machi.region = choice
+ module.set_geometry(c, regions[choice], regions[choice], 0, c.border_width)
+ end
+ end
+ end
+
+ layout.name = "machi"
+ layout.arrange = arrange
+ layout.resize_handler = resize_handler
+ layout.machi_get_instance_info = get_instance_info
+ layout.machi_set_cmd = set_cmd
+ layout.machi_get_regions = get_regions
+ return layout
+end
+
+return module
diff --git a/awesome/layout-machi/nested_layout_screenshot.png b/awesome/layout-machi/nested_layout_screenshot.png
new file mode 100644
index 0000000..6ca121a
--- /dev/null
+++ b/awesome/layout-machi/nested_layout_screenshot.png
Binary files differ
diff --git a/awesome/layout-machi/rc.patch b/awesome/layout-machi/rc.patch
new file mode 100644
index 0000000..02f0c8f
--- /dev/null
+++ b/awesome/layout-machi/rc.patch
@@ -0,0 +1,38 @@
+--- /usr/etc/xdg/awesome/rc.lua 2019-10-02 22:20:36.000000000 -0400
++++ rc.lua 2019-10-06 12:13:41.090197230 -0400
+@@ -17,6 +17,7 @@
+ -- Enable hotkeys help widget for VIM and other apps
+ -- when client with a matching name is opened:
+ require("awful.hotkeys_popup.keys")
++local machi = require("layout-machi")
+
+ -- {{{ Error handling
+ -- Check if awesome encountered an error during startup and fell back to
+@@ -34,6 +35,8 @@
+ -- Themes define colours, icons, font and wallpapers.
+ beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua")
+
++beautiful.layout_machi = machi.get_icon()
++
+ -- This is used later as the default terminal and editor to run.
+ terminal = "xterm"
+ editor = os.getenv("EDITOR") or "nano"
+@@ -48,6 +51,7 @@
+
+ -- Table of layouts to cover with awful.layout.inc, order matters.
+ awful.layout.layouts = {
++ machi.default_layout,
+ awful.layout.suit.floating,
+ awful.layout.suit.tile,
+ awful.layout.suit.tile.left,
+@@ -262,6 +266,10 @@
+ awful.key({ modkey, "Shift" }, "q", awesome.quit,
+ {description = "quit awesome", group = "awesome"}),
+
++ awful.key({ modkey, }, ".", function () machi.default_editor.start_interactive() end,
++ {description = "edit the current layout if it is a machi layout", group = "layout"}),
++ awful.key({ modkey, }, "/", function () machi.switcher.start(client.focus) end,
++ {description = "switch between windows for a machi layout", group = "layout"}),
+ awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
+ {description = "increase master width factor", group = "layout"}),
+ awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
diff --git a/awesome/layout-machi/switcher.lua b/awesome/layout-machi/switcher.lua
new file mode 100644
index 0000000..dea08d0
--- /dev/null
+++ b/awesome/layout-machi/switcher.lua
@@ -0,0 +1,476 @@
+local machi = {
+ layout = require((...):match("(.-)[^%.]+$") .. "layout"),
+}
+
+local api = {
+ client = client,
+ beautiful = require("beautiful"),
+ wibox = require("wibox"),
+ awful = require("awful"),
+ screen = require("awful.screen"),
+ layout = require("awful.layout"),
+ naughty = require("naughty"),
+ gears = require("gears"),
+ lgi = require("lgi"),
+ dpi = require("beautiful.xresources").apply_dpi,
+}
+
+local ERROR = 2
+local WARNING = 1
+local INFO = 0
+local DEBUG = -1
+
+local module = {
+ log_level = WARNING,
+}
+
+local function log(level, msg)
+ if level > module.log_level then
+ print(msg)
+ end
+end
+
+local function min(a, b)
+ if a < b then return a else return b end
+end
+
+local function max(a, b)
+ if a < b then return b else return a end
+end
+
+local function with_alpha(col, alpha)
+ local r, g, b
+ _, r, g, b, _ = col:get_rgba()
+ return api.lgi.cairo.SolidPattern.create_rgba(r, g, b, alpha)
+end
+
+function module.start(c, exit_keys)
+ local tablist_font_desc = api.beautiful.get_merged_font(
+ api.beautiful.font, api.dpi(10))
+ local font_color = with_alpha(api.gears.color(api.beautiful.fg_normal), 1)
+ local font_color_hl = with_alpha(api.gears.color(api.beautiful.fg_focus), 1)
+ local label_size = api.dpi(30)
+ local border_color = with_alpha(api.gears.color(
+ api.beautiful.switcher_border_color or api.beautiful.border_focus),
+ api.beautiful.switcher_border_opacity or 0.25)
+ local fill_color = with_alpha(api.gears.color(
+ api.beautiful.switcher_fill_color or api.beautiful.bg_normal),
+ api.beautiful.switcher_fill_opacity or 0.25)
+ local box_bg = with_alpha(api.gears.color(
+ api.beautiful.switcher_box_bg or api.beautiful.bg_normal),
+ api.beautiful.switcher_box_opacity or 0.85)
+ local fill_color_hl = with_alpha(api.gears.color(
+ api.beautiful.switcher_fill_color_hl or api.beautiful.bg_focus),
+ api.beautiful.switcher_fill_hl_opacity or 1)
+ -- for comparing floats
+ local threshold = 0.1
+ local traverse_radius = api.dpi(5)
+
+ local screen = c and c.screen or api.screen.focused()
+ local start_x = screen.workarea.x
+ local start_y = screen.workarea.y
+
+ local layout = api.layout.get(screen)
+ if (c ~= nil and c.floating) or layout.machi_get_regions == nil then return end
+
+ local regions, draft_mode = layout.machi_get_regions(screen.workarea, screen.selected_tag)
+ if regions == nil or #regions == 0 then
+ return
+ end
+
+ local infobox = api.wibox({
+ screen = screen,
+ x = screen.workarea.x,
+ y = screen.workarea.y,
+ width = screen.workarea.width,
+ height = screen.workarea.height,
+ bg = "#ffffff00",
+ opacity = 1,
+ ontop = true,
+ type = "dock",
+ })
+ infobox.visible = true
+
+ local tablist_region = nil
+ local tablist = nil
+ local tablist_index = nil
+
+ local traverse_x, traverse_y
+ if c then
+ traverse_x = c.x + traverse_radius
+ traverse_y = c.y + traverse_radius
+ else
+ traverse_x = screen.workarea.x + screen.workarea.width / 2
+ traverse_y = screen.workarea.y + screen.workarea.height / 2
+ end
+
+ local function maintain_tablist()
+ if tablist == nil then
+ tablist = {}
+
+ for i, a in ipairs(regions) do
+ if a.x <= traverse_x and traverse_x < a.x + a.width and
+ a.y <= traverse_y and traverse_y < a.y + a.height
+ then
+ active_region = i
+ end
+ end
+
+ for _, tc in ipairs(screen.tiled_clients) do
+ if not (tc.floating or tc.immobilized)
+ then
+ if regions[active_region].x <= tc.x + tc.width + tc.border_width * 2 and tc.x <= regions[active_region].x + regions[active_region].width and
+ regions[active_region].y <= tc.y + tc.height + tc.border_width * 2 and tc.y <= regions[active_region].y + regions[active_region].height
+ then
+ tablist[#tablist + 1] = tc
+ end
+ end
+ end
+
+ tablist_index = 1
+
+ else
+
+ local j = 0
+ for i = 1, #tablist do
+ if tablist[i].valid then
+ j = j + 1
+ tablist[j] = tablist[i]
+ elseif i <= tablist_index and tablist_index > 0 then
+ tablist_index = tablist_index - 1
+ end
+ end
+
+ for i = #tablist, j + 1, -1 do
+ table.remove(tablist, i)
+ end
+ end
+
+ if c and not c.valid then c = nil end
+ if c == nil and #tablist > 0 then
+ c = tablist[tablist_index]
+ end
+ end
+
+ local function draw_info(context, cr, width, height)
+ maintain_tablist()
+
+ cr:set_source_rgba(0, 0, 0, 0)
+ cr:rectangle(0, 0, width, height)
+ cr:fill()
+
+ local msg, ext, active_region
+ for i, a in ipairs(regions) do
+
+ cr:rectangle(a.x - start_x, a.y - start_y, a.width, a.height)
+ cr:clip()
+ cr:set_source(fill_color)
+ cr:rectangle(a.x - start_x, a.y - start_y, a.width, a.height)
+ cr:fill()
+ cr:set_source(border_color)
+ cr:rectangle(a.x - start_x, a.y - start_y, a.width, a.height)
+ cr:set_line_width(10.0)
+ cr:stroke()
+ cr:reset_clip()
+
+ -- TODO deduplicate this with code in maintain_tablist()
+ if a.x <= traverse_x and traverse_x < a.x + a.width and
+ a.y <= traverse_y and traverse_y < a.y + a.height
+ then
+ active_region = i
+ end
+ end
+
+ if #tablist > 0 then
+ local a = regions[active_region]
+ local pl = api.lgi.Pango.Layout.create(cr)
+ pl:set_font_description(tablist_font_desc)
+
+ local vpadding = api.dpi(10)
+ local list_height = vpadding
+ local list_width = 2 * vpadding
+ local exts = {}
+
+ for index, tc in ipairs(tablist) do
+ local label = tc.name
+ pl:set_text(label)
+ local w, h
+ w, h = pl:get_size()
+ w = w / api.lgi.Pango.SCALE
+ h = h / api.lgi.Pango.SCALE
+ local ext = { width = w, height = h, x_bearing = 0, y_bearing = 0 }
+ exts[#exts + 1] = ext
+ list_height = list_height + ext.height + vpadding
+ list_width = max(list_width, w + 2 * vpadding)
+ end
+
+ local x_offset = a.x + a.width / 2 - start_x
+ local y_offset = a.y + a.height / 2 - list_height / 2 + vpadding - start_y
+
+ -- cr:rectangle(a.x - start_x, y_offset - vpadding - start_y, a.width, list_height)
+ -- cover the entire region
+ cr:rectangle(a.x - start_x, a.y - start_y, a.width, a.height)
+ cr:set_source(fill_color)
+ cr:fill()
+
+ cr:rectangle(a.x + (a.width - list_width) / 2 - start_x, a.y + (a.height - list_height) / 2 - start_y, list_width, list_height)
+ cr:set_source(box_bg)
+ cr:fill()
+
+ for index, tc in ipairs(tablist) do
+ local label = tc.name
+ local ext = exts[index]
+ if index == tablist_index then
+ cr:rectangle(x_offset - ext.width / 2 - vpadding / 2, y_offset - vpadding / 2, ext.width + vpadding, ext.height + vpadding)
+ cr:set_source(fill_color_hl)
+ cr:fill()
+ pl:set_text(label)
+ cr:move_to(x_offset - ext.width / 2 - ext.x_bearing, y_offset - ext.y_bearing)
+ cr:set_source(font_color_hl)
+ cr:show_layout(pl)
+ else
+ pl:set_text(label)
+ cr:move_to(x_offset - ext.width / 2 - ext.x_bearing, y_offset - ext.y_bearing)
+ cr:set_source(font_color)
+ cr:show_layout(pl)
+ end
+
+ y_offset = y_offset + ext.height + vpadding
+ end
+ end
+
+ -- show the traverse point
+ cr:rectangle(traverse_x - start_x - traverse_radius, traverse_y - start_y - traverse_radius, traverse_radius * 2, traverse_radius * 2)
+ cr:set_source_rgba(1, 1, 1, 1)
+ cr:fill()
+ end
+
+ infobox.bgimage = draw_info
+
+ local key_translate_tab = {
+ ["w"] = "Up",
+ ["a"] = "Left",
+ ["s"] = "Down",
+ ["d"] = "Right",
+ }
+
+ api.awful.client.focus.history.disable_tracking()
+
+ local kg
+ local function exit()
+ api.awful.client.focus.history.enable_tracking()
+ if api.client.focus then
+ api.client.emit_signal("focus", api.client.focus)
+ end
+ infobox.visible = false
+ api.awful.keygrabber.stop(kg)
+ end
+
+ local function handle_key(mod, key, event)
+ if event == "release" then
+ if exit_keys and exit_keys[key] then
+ exit()
+ end
+ return
+ end
+ if key_translate_tab[key] ~= nil then
+ key = key_translate_tab[key]
+ end
+
+ maintain_tablist()
+ assert(tablist ~= nil)
+
+ if key == "Tab" then
+ if #tablist > 0 then
+ tablist_index = tablist_index % #tablist + 1
+ c = tablist[tablist_index]
+ c:emit_signal("request::activate", "mouse.move", {raise=false})
+ c:raise()
+
+ infobox.bgimage = draw_info
+ end
+ elseif key == "Up" or key == "Down" or key == "Left" or key == "Right" then
+ local shift = false
+ local ctrl = false
+ for i, m in ipairs(mod) do
+ if m == "Shift" then shift = true
+ elseif m == "Control" then ctrl = true
+ end
+ end
+
+ local current_region = nil
+
+ if c and (shift or ctrl) then
+ for i, a in ipairs(regions) do
+ if a.x <= traverse_x and traverse_x < a.x + a.width and
+ a.y <= traverse_y and traverse_y < a.y + a.height
+ then
+ current_region = i
+ break
+ end
+ end
+
+ if shift then
+ if current_region == nil or
+ regions[current_region].x ~= c.x or
+ regions[current_region].y ~= c.y
+ then
+ traverse_x = c.x + traverse_radius
+ traverse_y = c.y + traverse_radius
+ current_region = nil
+ end
+ elseif ctrl then
+ local ex = c.x + c.width + c.border_width * 2
+ local ey = c.y + c.height + c.border_width * 2
+ if current_region == nil or
+ regions[current_region].x + regions[current_region].width ~= ex or
+ regions[current_region].y + regions[current_region].height ~= ey
+ then
+ traverse_x = ex - traverse_radius
+ traverse_y = ey - traverse_radius
+ current_region = nil
+ end
+ end
+ end
+
+ local choice = nil
+ local choice_value
+
+ for i, a in ipairs(regions) do
+ if a.x <= traverse_x and traverse_x < a.x + a.width and
+ a.y <= traverse_y and traverse_y < a.y + a.height
+ then
+ current_region = i
+ end
+
+ local v
+ if key == "Up" then
+ if a.x < traverse_x + threshold
+ and traverse_x < a.x + a.width + threshold then
+ v = traverse_y - a.y - a.height
+ else
+ v = -1
+ end
+ elseif key == "Down" then
+ if a.x < traverse_x + threshold
+ and traverse_x < a.x + a.width + threshold then
+ v = a.y - traverse_y
+ else
+ v = -1
+ end
+ elseif key == "Left" then
+ if a.y < traverse_y + threshold
+ and traverse_y < a.y + a.height + threshold then
+ v = traverse_x - a.x - a.width
+ else
+ v = -1
+ end
+ elseif key == "Right" then
+ if a.y < traverse_y + threshold
+ and traverse_y < a.y + a.height + threshold then
+ v = a.x - traverse_x
+ else
+ v = -1
+ end
+ end
+
+ if (v > threshold) and (choice_value == nil or choice_value > v) then
+ choice = i
+ choice_value = v
+ end
+ end
+
+ if choice == nil then
+ choice = current_region
+ if key == "Up" then
+ traverse_y = screen.workarea.y
+ elseif key == "Down" then
+ traverse_y = screen.workarea.y + screen.workarea.height
+ elseif key == "Left" then
+ traverse_x = screen.workarea.x
+ else
+ traverse_x = screen.workarea.x + screen.workarea.width
+ end
+ end
+
+ if choice ~= nil then
+ traverse_x = max(regions[choice].x + traverse_radius, min(regions[choice].x + regions[choice].width - traverse_radius, traverse_x))
+ traverse_y = max(regions[choice].y + traverse_radius, min(regions[choice].y + regions[choice].height - traverse_radius, traverse_y))
+ tablist = nil
+
+ if c and ctrl and draft_mode then
+ local lu = c.machi.lu
+ local rd = c.machi.rd
+
+ if shift then
+ lu = choice
+ if regions[rd].x + regions[rd].width <= regions[lu].x or
+ regions[rd].y + regions[rd].height <= regions[lu].y
+ then
+ rd = nil
+ end
+ else
+ rd = choice
+ if regions[rd].x + regions[rd].width <= regions[lu].x or
+ regions[rd].y + regions[rd].height <= regions[lu].y
+ then
+ lu = nil
+ end
+ end
+
+ if lu ~= nil and rd ~= nil then
+ machi.layout.set_geometry(c, regions[lu], regions[rd], 0, c.border_width)
+ elseif lu ~= nil then
+ machi.layout.set_geometry(c, regions[lu], nil, 0, c.border_width)
+ elseif rd ~= nil then
+ c.x = min(c.x, regions[rd].x)
+ c.y = min(c.y, regions[rd].y)
+ machi.layout.set_geometry(c, nil, regions[rd], 0, c.border_width)
+ end
+ c.machi.lu = lu
+ c.machi.rd = rd
+
+ c:emit_signal("request::activate", "mouse.move", {raise=false})
+ c:raise()
+ api.layout.arrange(screen)
+ elseif c and shift then
+ -- move the window
+ if draft_mode then
+ c.x = regions[choice].x
+ c.y = regions[choice].y
+ else
+ machi.layout.set_geometry(c, regions[choice], regions[choice], 0, c.border_width)
+ c.machi.region = choice
+ end
+ c:emit_signal("request::activate", "mouse.move", {raise=false})
+ c:raise()
+ api.layout.arrange(screen)
+
+ tablist = nil
+ else
+ maintain_tablist()
+ -- move the focus
+ if #tablist > 0 and tablist[1] ~= c then
+ c = tablist[1]
+ api.client.focus = c
+ end
+ end
+
+ infobox.bgimage = draw_info
+ end
+ elseif key == "Escape" or key == "Return" then
+ exit()
+ else
+ log(DEBUG, "Unhandled key " .. key)
+ end
+ end
+
+ kg = api.awful.keygrabber.run(
+ function (...)
+ ok, _ = pcall(handle_key, ...)
+ if not ok then exit() end
+ end
+ )
+end
+
+return module
diff --git a/awesome/rc.lua b/awesome/rc.lua
index 83da24b..42e41ca 100644
--- a/awesome/rc.lua
+++ b/awesome/rc.lua
@@ -1,56 +1,64 @@
+-- rc.lua
-- If LuaRocks is installed, make sure that packages installed through it are
-- found (e.g. lgi). If LuaRocks is not installed, do nothing.
pcall(require, "luarocks.loader")
-
-- Standard awesome library
local gears = require("gears")
+local gfs = require("gears.filesystem")
local awful = require("awful")
require("awful.autofocus")
-- Widget and layout library
local wibox = require("wibox")
-- Theme handling library
local beautiful = require("beautiful")
+local dpi = require("beautiful.xresources").apply_dpi
-- Notification library
local naughty = require("naughty")
-local menubar = require("menubar")
+-- Declarative object management
+local ruled = require("ruled")
local hotkeys_popup = require("awful.hotkeys_popup")
-- Enable hotkeys help widget for VIM and other apps
-- when client with a matching name is opened:
require("awful.hotkeys_popup.keys")
--- {{{ Error handling
+-- Helpers Library
+local helpers = require("helpers")
+
+-- Autostart and Errors -------------------------------------------------------
+
+local autostart = require("autostart")
+awesome.register_xproperty("WM_NAME", "string")
+
-- Check if awesome encountered an error during startup and fell back to
-- another config (This code will only ever execute for the fallback config)
-if awesome.startup_errors then
- naughty.notify({ preset = naughty.config.presets.critical,
- title = "Oops, there were errors during startup!",
- text = awesome.startup_errors })
-end
-
--- Handle runtime errors after startup
-do
- local in_error = false
- awesome.connect_signal("debug::error", function (err)
- -- Make sure we don't go into an endless error loop
- if in_error then return end
- in_error = true
+naughty.connect_signal("request::display_error", function(message, startup)
+ naughty.notification {
+ urgency = "critical",
+ title = "Oops, an error happened" ..
+ (startup and " during startup!" or "!"),
+ message = message
+ }
+end)
- naughty.notify({ preset = naughty.config.presets.critical,
- title = "Oops, an error happened!",
- text = tostring(err) })
- in_error = false
- end)
-end
--- }}}
+-- Variables & Inits ----------------------------------------------------------
--- {{{ Variable definitions
--- Themes define colours, icons, font and wallpapers.
-beautiful.init(gears.filesystem.get_configuration_dir() .. "theme.lua")
+-- Set Theme
+theme = "ghosts"
+beautiful.init(gfs.get_configuration_dir() .. "theme/" .. theme .. "/theme.lua")
--- This is used later as the default terminal and editor to run.
-terminal = "xterm"
-editor = "nvim"
+-- Default Applications
+terminal = "alacritty"
+editor = os.getenv("EDITOR") or "nvim"
editor_cmd = terminal .. " -e " .. editor
+browser = "brave"
+filemanager = "pcmanfm"
+discord = "discord"
+launcher = "rofi -show drun"
+music = terminal .. " -c music -e ncspot"
+
+-- Dims
+screen_width = awful.screen.focused().geometry.width
+screen_height = awful.screen.focused().geometry.height
-- Default modkey.
-- Usually, Mod4 is the key with a logo between Control and Alt.
@@ -58,516 +66,136 @@ editor_cmd = terminal .. " -e " .. editor
-- I suggest you to remap Mod4 to another key using xmodmap or other tools.
-- However, you can use another modifier like Mod1, but it may interact with others.
modkey = "Mod4"
+altkey = "Mod1"
+shift = "Shift"
+ctrl = "Control"
+
+-- Import Bling Module
+local bling = require("bling")
+-- Playerctl signal
+bling.signal.playerctl.enable()
+
+-- Layouts
+require("window")
+
+-- Screen Stuff ---------------------------------------------------------------
+
+-- Set Wallpaper
+screen.connect_signal("request::wallpaper", function(s)
+ --[[ bling.module.tiled_wallpaper("", s, {
+ fg = beautiful.xcolor8,
+ bg = beautiful.xcolor0,
+ offset_y = beautiful.wibar_height + 5,
+ offset_x = 0,
+ font = "FiraCode Nerd Font Mono",
+ font_size = 12,
+ padding = 60,
+ zickzack = true
+ }) --]]
+
+ gears.wallpaper.maximized(beautiful.wallpaper, s, false, nil)
+end)
--- Table of layouts to cover with awful.layout.inc, order matters.
-awful.layout.layouts = {
- --awful.layout.suit.floating,
- --awful.layout.suit.tile,
- --awful.layout.suit.tile.left,
- --awful.layout.suit.tile.bottom,
- --awful.layout.suit.tile.top,
- --awful.layout.suit.fair,
- --awful.layout.suit.fair.horizontal,
- awful.layout.suit.spiral,
- --awful.layout.suit.spiral.dwindle,
- --awful.layout.suit.max,
- --awful.layout.suit.max.fullscreen,
- --awful.layout.suit.magnifier,
- --awful.layout.suit.corner.nw,
- -- awful.layout.suit.corner.ne,
- -- awful.layout.suit.corner.sw,
- -- awful.layout.suit.corner.se,
-}
--- }}}
-
--- {{{ Menu
--- Create a launcher widget and a main menu
-myawesomemenu = {
- { "hotkeys", function() hotkeys_popup.show_help(nil, awful.screen.focused()) end },
- { "manual", terminal .. " -e man awesome" },
- { "edit config", editor_cmd .. " " .. awesome.conffile },
- { "restart", awesome.restart },
- { "quit", function() awesome.quit() end },
-}
-
-mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
- { "open terminal", terminal }
- }
- })
-
-mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
- menu = mymainmenu })
-
--- Menubar configuration
-menubar.utils.terminal = terminal -- Set the terminal for applications that require it
--- }}}
-
--- Keyboard map indicator and switcher
-mykeyboardlayout = awful.widget.keyboardlayout()
-
--- {{{ Wibar
--- Create a textclock widget
-mytextclock = wibox.widget.textclock()
+screen.connect_signal("request::desktop_decoration", function(s)
+ -- Screen padding
+ screen[s].padding = {left = 0, right = 0, top = 0, bottom = 0}
--- Create a wibox for each screen and add it
-local taglist_buttons = gears.table.join(
- awful.button({ }, 1, function(t) t:view_only() end),
- awful.button({ modkey }, 1, function(t)
- if client.focus then
- client.focus:move_to_tag(t)
- end
- end),
- awful.button({ }, 3, awful.tag.viewtoggle),
- awful.button({ modkey }, 3, function(t)
- if client.focus then
- client.focus:toggle_tag(t)
- end
- end),
- awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
- awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
- )
+ -- Each screen has its own tag table.
+ awful.tag({"1", "2", "3", "4", "5"}, s, awful.layout.layouts[1])
+end)
-local tasklist_buttons = gears.table.join(
- awful.button({ }, 1, function (c)
- if c == client.focus then
- c.minimized = true
- else
- c:emit_signal(
- "request::activate",
- "tasklist",
- {raise = true}
- )
- end
- end),
- awful.button({ }, 3, function()
- awful.menu.client_list({ theme = { width = 250 } })
- end),
- awful.button({ }, 4, function ()
- awful.client.focus.byidx(1)
- end),
- awful.button({ }, 5, function ()
- awful.client.focus.byidx(-1)
- end))
+-- Keys -----------------------------------------------------------------------
-local function set_wallpaper(s)
- -- Wallpaper
- if beautiful.wallpaper then
- local wallpaper = beautiful.wallpaper
- -- If wallpaper is a function, call it with the screen
- if type(wallpaper) == "function" then
- wallpaper = wallpaper(s)
- end
- gears.wallpaper.maximized(wallpaper, s, true)
- end
-end
+require("keys")
--- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
-screen.connect_signal("property::geometry", set_wallpaper)
+-- Rules ----------------------------------------------------------------------
-awful.screen.connect_for_each_screen(function(s)
- -- Wallpaper
- set_wallpaper(s)
+ruled.client.connect_signal("request::rules", function()
- -- Each screen has its own tag table.
- awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, awful.layout.layouts[1])
-
- -- Create a promptbox for each screen
- s.mypromptbox = awful.widget.prompt()
- -- Create an imagebox widget which will contain an icon indicating which layout we're using.
- -- We need one layoutbox per screen.
- s.mylayoutbox = awful.widget.layoutbox(s)
- s.mylayoutbox:buttons(gears.table.join(
- awful.button({ }, 1, function () awful.layout.inc( 1) end),
- awful.button({ }, 3, function () awful.layout.inc(-1) end),
- awful.button({ }, 4, function () awful.layout.inc( 1) end),
- awful.button({ }, 5, function () awful.layout.inc(-1) end)))
- -- Create a taglist widget
- s.mytaglist = awful.widget.taglist {
- screen = s,
- filter = awful.widget.taglist.filter.all,
- buttons = taglist_buttons
+ -- Global
+ ruled.client.append_rule {
+ id = "global",
+ rule = {},
+ properties = {
+ focus = awful.client.focus.filter,
+ raise = true,
+ size_hints_honor = false,
+ screen = awful.screen.preferred,
+ placement = awful.placement.centered + awful.placement.no_overlap +
+ awful.placement.no_offscreen
+ }
}
- -- Create a tasklist widget
- s.mytasklist = awful.widget.tasklist {
- screen = s,
- filter = awful.widget.tasklist.filter.currenttags,
- buttons = tasklist_buttons
+ -- Tasklist order
+ ruled.client.append_rule {
+ id = "tasklist_order",
+ rule = {},
+ properties = {},
+ callback = awful.client.setslave
}
- -- Create the wibox
- s.mywibox = awful.wibar({ position = "top", screen = s })
-
- -- Add widgets to the wibox
- s.mywibox:setup {
- layout = wibox.layout.align.horizontal,
- { -- Left widgets
- layout = wibox.layout.fixed.horizontal,
- mylauncher,
- s.mytaglist,
- s.mypromptbox,
- },
- s.mytasklist, -- Middle widget
- { -- Right widgets
- layout = wibox.layout.fixed.horizontal,
- mykeyboardlayout,
- wibox.widget.systray(),
- mytextclock,
- s.mylayoutbox,
+ -- Floate em
+ ruled.client.append_rule {
+ id = "floating",
+ rule_any = {
+ class = {"Arandr", "Blueman-manager", "Sxiv", "fzfmenu"},
+ role = {
+ "pop-up" -- e.g. Google Chrome's (detached) Developer Tools.
+ }
},
+ properties = {floating = true}
}
-end)
--- }}}
-
--- {{{ Mouse bindings
-root.buttons(gears.table.join(
- awful.button({ }, 3, function () mymainmenu:toggle() end),
- awful.button({ }, 4, awful.tag.viewnext),
- awful.button({ }, 5, awful.tag.viewprev)
-))
--- }}}
-
--- {{{ Key bindings
-globalkeys = gears.table.join(
- awful.key({ modkey, }, "s", hotkeys_popup.show_help,
- {description="show help", group="awesome"}),
- awful.key({ modkey, }, "Left", awful.tag.viewprev,
- {description = "view previous", group = "tag"}),
- awful.key({ modkey, }, "Right", awful.tag.viewnext,
- {description = "view next", group = "tag"}),
- awful.key({ modkey, }, "Escape", awful.tag.history.restore,
- {description = "go back", group = "tag"}),
-
- awful.key({ modkey, }, "j",
- function ()
- awful.client.focus.byidx( 1)
- end,
- {description = "focus next by index", group = "client"}
- ),
- awful.key({ modkey, }, "k",
- function ()
- awful.client.focus.byidx(-1)
- end,
- {description = "focus previous by index", group = "client"}
- ),
- awful.key({ modkey, }, "w", function () mymainmenu:show() end,
- {description = "show main menu", group = "awesome"}),
-
- -- Layout manipulation
- awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end,
- {description = "swap with next client by index", group = "client"}),
- awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end,
- {description = "swap with previous client by index", group = "client"}),
- awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end,
- {description = "focus the next screen", group = "screen"}),
- awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end,
- {description = "focus the previous screen", group = "screen"}),
- awful.key({ modkey, }, "u", awful.client.urgent.jumpto,
- {description = "jump to urgent client", group = "client"}),
- awful.key({ modkey, }, "Tab",
- function ()
- awful.client.focus.history.previous()
- if client.focus then
- client.focus:raise()
- end
- end,
- {description = "go back", group = "client"}),
- -- Standard program
- awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end,
- {description = "open a terminal", group = "launcher"}),
- awful.key({ modkey, "Control" }, "r", awesome.restart,
- {description = "reload awesome", group = "awesome"}),
- awful.key({ modkey, "Shift" }, "e", awesome.quit,
- {description = "quit awesome", group = "awesome"}),
-
- awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
- {description = "increase master width factor", group = "layout"}),
- awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
- {description = "decrease master width factor", group = "layout"}),
- awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end,
- {description = "increase the number of master clients", group = "layout"}),
- awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end,
- {description = "decrease the number of master clients", group = "layout"}),
- awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end,
- {description = "increase the number of columns", group = "layout"}),
- awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end,
- {description = "decrease the number of columns", group = "layout"}),
- awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end,
- {description = "select next", group = "layout"}),
- awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end,
- {description = "select previous", group = "layout"}),
-
- awful.key({ modkey, "Control" }, "n",
- function ()
- local c = awful.client.restore()
- -- Focus restored client
- if c then
- c:emit_signal(
- "request::activate", "key.unminimize", {raise = true}
- )
- end
- end,
- {description = "restore minimized", group = "client"}),
-
- -- Prompt
- awful.key({ modkey }, "r", function () awful.screen.focused().mypromptbox:run() end,
- {description = "run prompt", group = "launcher"}),
-
- awful.key({ modkey }, "x",
- function ()
- awful.prompt.run {
- prompt = "Run Lua code: ",
- textbox = awful.screen.focused().mypromptbox.widget,
- exe_callback = awful.util.eval,
- history_path = awful.util.get_cache_dir() .. "/history_eval"
- }
- end,
- {description = "lua execute prompt", group = "awesome"}),
- -- Menubar
- awful.key({ modkey }, "p", function() menubar.show() end,
- {description = "show the menubar", group = "launcher"})
-)
-
-clientkeys = gears.table.join(
- awful.key({ modkey, }, "f",
- function (c)
- c.fullscreen = not c.fullscreen
- c:raise()
- end,
- {description = "toggle fullscreen", group = "client"}),
- awful.key({ modkey, "Shift" }, "q", function (c) c:kill() end,
- {description = "close", group = "client"}),
- awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ,
- {description = "toggle floating", group = "client"}),
- awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
- {description = "move to master", group = "client"}),
- awful.key({ modkey, }, "o", function (c) c:move_to_screen() end,
- {description = "move to screen", group = "client"}),
- awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end,
- {description = "toggle keep on top", group = "client"}),
- awful.key({ modkey, }, "n",
- function (c)
- -- The client currently has the input focus, so it cannot be
- -- minimized, since minimized clients can't have the focus.
- c.minimized = true
- end ,
- {description = "minimize", group = "client"}),
- awful.key({ modkey, }, "m",
- function (c)
- c.maximized = not c.maximized
- c:raise()
- end ,
- {description = "(un)maximize", group = "client"}),
- awful.key({ modkey, "Control" }, "m",
- function (c)
- c.maximized_vertical = not c.maximized_vertical
- c:raise()
- end ,
- {description = "(un)maximize vertically", group = "client"}),
- awful.key({ modkey, "Shift" }, "m",
- function (c)
- c.maximized_horizontal = not c.maximized_horizontal
- c:raise()
- end ,
- {description = "(un)maximize horizontally", group = "client"}),
-
- -- custom keybindings
- awful.key({ modkey, 'Control' }, "b", function() awful.util.spawn("brave") end),
- awful.key({}, "n", function() naughty.notify(
- { preset = naughty.config.presets.critical,
- title = "Oops, there were errors during startup!",
- text = awesome.startup_errors }
- ) end)
-)
-
-
--- Bind all key numbers to tags.
--- Be careful: we use keycodes to make it work on any keyboard layout.
--- This should map on the top row of your keyboard, usually 1 to 9.
-for i = 1, 9 do
- globalkeys = gears.table.join(globalkeys,
- -- View tag only.
- awful.key({ modkey }, "#" .. i + 9,
- function ()
- local screen = awful.screen.focused()
- local tag = screen.tags[i]
- if tag then
- tag:view_only()
- end
- end,
- {description = "view tag #"..i, group = "tag"}),
- -- Toggle tag display.
- awful.key({ modkey, "Control" }, "#" .. i + 9,
- function ()
- local screen = awful.screen.focused()
- local tag = screen.tags[i]
- if tag then
- awful.tag.viewtoggle(tag)
- end
- end,
- {description = "toggle tag #" .. i, group = "tag"}),
- -- Move client to tag.
- awful.key({ modkey, "Shift" }, "#" .. i + 9,
- function ()
- if client.focus then
- local tag = client.focus.screen.tags[i]
- if tag then
- client.focus:move_to_tag(tag)
- end
- end
- end,
- {description = "move focused client to tag #"..i, group = "tag"}),
- -- Toggle tag on focused client.
- awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
- function ()
- if client.focus then
- local tag = client.focus.screen.tags[i]
- if tag then
- client.focus:toggle_tag(tag)
- end
- end
- end,
- {description = "toggle focused client on tag #" .. i, group = "tag"})
- )
-end
-
-clientbuttons = gears.table.join(
- awful.button({ }, 1, function (c)
- c:emit_signal("request::activate", "mouse_click", {raise = true})
- end),
- awful.button({ modkey }, 1, function (c)
- c:emit_signal("request::activate", "mouse_click", {raise = true})
- awful.mouse.client.move(c)
- end),
- awful.button({ modkey }, 3, function (c)
- c:emit_signal("request::activate", "mouse_click", {raise = true})
- awful.mouse.client.resize(c)
- end)
-)
-
--- Set keys
-root.keys(globalkeys)
--- }}}
-
--- {{{ Rules
--- Rules to apply to new clients (through the "manage" signal).
-awful.rules.rules = {
- -- All clients will match this rule.
- { rule = { },
- properties = { border_width = beautiful.border_width,
- border_color = beautiful.border_normal,
- focus = awful.client.focus.filter,
- raise = true,
- keys = clientkeys,
- buttons = clientbuttons,
- screen = awful.screen.preferred,
- placement = awful.placement.no_overlap+awful.placement.no_offscreen
- }
- },
-
- -- Floating clients.
- { rule_any = {
- instance = {
- "DTA", -- Firefox addon DownThemAll.
- "copyq", -- Includes session name in class.
- "pinentry",
- },
- class = {
- "Arandr",
- "Blueman-manager",
- "Gpick",
- "Kruler",
- "MessageWin", -- kalarm.
- "Sxiv",
- "Tor Browser", -- Needs a fixed window size to avoid fingerprinting by screen size.
- "Wpa_gui",
- "veromix",
- "xtightvncviewer"},
-
- -- Note that the name property shown in xprop might be set slightly after creation of the client
- -- and the name shown there might not match defined rules here.
- name = {
- "Event Tester", -- xev.
+ -- Borders
+ ruled.client.append_rule {
+ id = "borders",
+ rule_any = {type = {"normal", "dialog"}},
+ except_any = {
+ role = {"Popup"},
+ type = {"splash"},
+ name = {"^discord.com is sharing your screen.$"}
},
- role = {
- "AlarmWindow", -- Thunderbird's calendar.
- "ConfigManager", -- Thunderbird's about:config.
- "pop-up", -- e.g. Google Chrome's (detached) Developer Tools.
+ properties = {
+ border_width = beautiful.border_width,
+ border_color = beautiful.border_normal
}
- }, properties = { floating = true }},
-
- -- dont add titlebars to normal clients and dialogs
- { rule_any = {type = { "normal", "dialog" }
- }, properties = { titlebars_enabled = false }
- },
-
- -- Set Firefox to always map on the tag named "2" on screen 1.
- -- { rule = { class = "Firefox" },
- -- properties = { screen = 1, tag = "2" } },
-}
--- }}}
-
--- {{{ Signals
--- Signal function to execute when a new client appears.
-client.connect_signal("manage", function (c)
- -- Set the windows at the slave,
- -- i.e. put it at the end of others instead of setting it master.
- -- if not awesome.startup then awful.client.setslave(c) end
-
- if awesome.startup
- and not c.size_hints.user_position
- and not c.size_hints.program_position then
- -- Prevent clients from being unreachable after screen count changes.
- awful.placement.no_offscreen(c)
- end
-end)
-
--- Add a titlebar if titlebars_enabled is set to true in the rules.
-client.connect_signal("request::titlebars", function(c)
- -- buttons for the titlebar
- local buttons = gears.table.join(
- awful.button({ }, 1, function()
- c:emit_signal("request::activate", "titlebar", {raise = true})
- awful.mouse.client.move(c)
- end),
- awful.button({ }, 3, function()
- c:emit_signal("request::activate", "titlebar", {raise = true})
- awful.mouse.client.resize(c)
- end)
- )
+ }
- awful.titlebar(c) : setup {
- { -- Left
- awful.titlebar.widget.iconwidget(c),
- buttons = buttons,
- layout = wibox.layout.fixed.horizontal
- },
- { -- Middle
- { -- Title
- align = "center",
- widget = awful.titlebar.widget.titlewidget(c)
+ -- Center Placement
+ ruled.client.append_rule {
+ id = "center_placement",
+ rule_any = {
+ type = {"dialog"},
+ class = {
+ "Steam", "discord", "music", "markdown_input", "scratchpad"
},
- buttons = buttons,
- layout = wibox.layout.flex.horizontal
+ instance = {"music", "markdown_input", "scratchpad"},
+ role = {"GtkFileChooserDialog", "conversation"}
},
- { -- Right
- awful.titlebar.widget.floatingbutton (c),
- awful.titlebar.widget.maximizedbutton(c),
- awful.titlebar.widget.stickybutton (c),
- awful.titlebar.widget.ontopbutton (c),
- awful.titlebar.widget.closebutton (c),
- layout = wibox.layout.fixed.horizontal()
+ properties = {placement = awful.placement.center}
+ }
+
+ -- Titlebar rules
+ ruled.client.append_rule {
+ id = "titlebars",
+ rule_any = {type = {"normal", "dialog"}},
+ except_any = {
+ class = {"Steam", "zoom", "jetbrains-studio"},
+ type = {"splash"},
+ name = {"^discord.com is sharing your screen.$"}
},
- layout = wibox.layout.align.horizontal
+ properties = {titlebars_enabled = true}
}
end)
--- Enable sloppy focus, so that focus follows mouse.
-client.connect_signal("mouse::enter", function(c)
- c:emit_signal("request::activate", "mouse_enter", {raise = false})
-end)
+-- Import Daemons and Widgets
+require("ears")
+require("bloat")
+
+collectgarbage("setpause", 110)
+collectgarbage("setstepmul", 1000)
+
+-- collectgarbage("setpause", 160)
+-- collectgarbage("setstepmul", 400)
-client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
-client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
--- }}}
+-- EOF ------------------------------------------------------------------------
diff --git a/awesome/scripts/jeff b/awesome/scripts/jeff
new file mode 100755
index 0000000..8b76bf1
--- /dev/null
+++ b/awesome/scripts/jeff
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+# Wrapper for amazing software giph by phisch
+
+file="$HOME/Pictures/screenshots/gif_$(date '+%Y-%m-%d%H:%M:%S').gif"
+file2="$HOME/Videos/vid_$(date '+%Y-%m-%d%H:%M:%S').mp4"
+
+
+case $1 in
+ "sel")
+ giph -y -s -b 2 -c '0.61,0.9,0.75,1' -p 22 $file
+ ;;
+
+ "selnp")
+ giph -y -s -b 2 -c '0.61,0.9,0.75,1' $file
+ ;;
+
+ "selmp4")
+ giph -y -s -f 30 -b 2 -c '0.61,0.9,0.75,1' -p 22 $file2
+ ;;
+
+ "selnpmp4")
+ giph -y -s -f 30 -b 2 -c '0.61,0.9,0.75,1' $file2
+ ;;
+
+ "mp4")
+ giph -y -g "1920x1080+0+0" -f 30 $file2
+ ;;
+
+ *)
+ giph -y -g "1920x1080+0+0" $file
+ ;;
+esac
diff --git a/awesome/scripts/rofi-emoji b/awesome/scripts/rofi-emoji
new file mode 100755
index 0000000..b368bbb
--- /dev/null
+++ b/awesome/scripts/rofi-emoji
@@ -0,0 +1,134 @@
+#!/usr/bin/env bash
+# Source: https://gist.github.com/Tadly/0741821d3694deaec1ee454a95c591fa
+#
+# Use rofi to pick emoji because that's what this
+# century is about apparently...
+#
+# Requirements:
+# rofi, xsel, xdotool, curl, xmllint
+#
+# Usage:
+# 1. Download all emoji
+# $ rofi-emoji --download
+#
+# 2. Run it!
+# $ rofi-emoji
+#
+# Notes:
+# * You'll need a emoji font like "Noto Emoji" or "EmojiOne".
+# * Confirming an item will automatically paste it WITHOUT
+# writing it to your clipboard.
+# * Ctrl+C will copy it to your clipboard WITHOUT pasting it.
+#
+
+# Where to save the emojis file.
+EMOJI_FILE="$HOME/.cache/emojis.txt"
+
+# Urls of emoji to download.
+# You can remove what you don't need.
+URLS=(
+'https://emojipedia.org/people/'
+'https://emojipedia.org/nature/'
+'https://emojipedia.org/food-drink/'
+'https://emojipedia.org/activity/'
+'https://emojipedia.org/travel-places/'
+'https://emojipedia.org/objects/'
+'https://emojipedia.org/symbols/'
+'https://emojipedia.org/flags/'
+)
+
+
+function notify() {
+ if [ "$(command -v notify-send)" ]; then
+ notify-send "$1" "$2"
+ fi
+}
+
+
+function download() {
+ notify "$(basename "$0")" 'Downloading all emoji for your pleasure'
+
+ echo "" > "$EMOJI_FILE"
+
+ for url in "${URLS[@]}"; do
+ echo "Downloading: $url"
+
+ # Download the list of emoji and remove all the junk around it
+ emojis=$(curl -s "$url" | \
+ xmllint --html \
+ --xpath '//ul[@class="emoji-list"]' - 2>/dev/null)
+
+ # Get rid of starting/closing ul tags
+ emojis=$(echo "$emojis" | head -n -1 | tail -n +1)
+
+ # Extract the emoji and its description
+ emojis=$(echo "$emojis" | \
+ sed -rn 's/.*<span class="emoji">(.*)<\/span> (.*)<\/a><\/li>/\1 \2/p')
+
+ echo "$emojis" >> "$EMOJI_FILE"
+ done
+
+ notify "$(basename "$0")" "We're all set!"
+}
+
+function rofi_menu() { # {{{
+ rofi -width 25 -lines 7 -dmenu -i -p 'emoji: ' \
+ -kb-row-tab '' \
+ -kb-row-select Tab \
+ -kb-custom-1 Ctrl+c
+}
+# }}}
+
+function repeat() { # {{{
+ local rplc str="$1" count="$2"
+ rplc="$(printf "%${count}s")"
+ echo "${rplc// /"$str"}"
+}
+# }}}
+
+function toclipboard() { # {{{
+ xclip -i -selection primary
+ xclip -o -selection primary | xclip -i -selection clipboard
+}
+# }}}
+
+function display() {
+ local emoji line exit_code quantifier
+
+ emoji=$(cat "$EMOJI_FILE" | grep -v '#' | grep -v '^[[:space:]]*$')
+ line="$(echo "$emoji" | rofi_menu)"
+ exit_code=$?
+
+ line=($line)
+ last=${line[${#line[@]}-1]}
+ quantifier="${last:${#last}-1:1}"
+ if [[ ! "$quantifier" =~ [0-9] ]]; then
+ quantifier=1
+ fi
+ emoijs="$(repeat "${line[0]}" "$quantifier")"
+
+ if [ $exit_code == 0 ]; then
+ xdotool type --clearmodifiers "$emoijs"
+ echo -n "$emoijs" | toclipboard
+ elif [ $exit_code == 10 ]; then
+ echo -n "$emoijs" | toclipboard
+ fi
+}
+
+
+# Some simple argparsing
+if [[ "$1" =~ -D|--download ]]; then
+ download
+ exit 0
+elif [[ "$1" =~ -h|--help ]]; then
+ echo "usage: $0 [-D|--download]"
+ exit 0
+fi
+
+# Download all emoji if they don't exist yet
+if [ ! -f "$EMOJI_FILE" ]; then
+ download
+fi
+
+# display displays :)
+display
diff --git a/awesome/scripts/shoot b/awesome/scripts/shoot
new file mode 100755
index 0000000..d6c6253
--- /dev/null
+++ b/awesome/scripts/shoot
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+# My script for screenshots, im bad at scripting pls help to make smaller
+
+img="shot_$(date '+%m%d%H%M%S').png"
+file="$HOME/Pictures/screenshots/$img"
+
+case $1 in
+ "sel")
+ slop=$(slop -b 2 -c '0.61,0.9,0.75,1' -p 22 -f "%g") || exit 1
+ read -r G < <(echo $slop)
+ import -window root -crop $G $file
+ ;;
+
+ "selnp")
+ slop=$(slop -b 2 -c '0.61,0.9,0.75,1' -f "%g") || exit 1
+ read -r G < <(echo $slop)
+ import -window root -crop $G $file
+ ;;
+
+ *)
+ import -window root $file
+ ;;
+esac
+
+
+xclip -selection clipboard -t image/png -i $file
+notify-send -i $file "Screenshot saved"
diff --git a/awesome/theme/ghosts/theme.lua b/awesome/theme/ghosts/theme.lua
new file mode 100644
index 0000000..ede94a3
--- /dev/null
+++ b/awesome/theme/ghosts/theme.lua
@@ -0,0 +1,276 @@
+-- _ _
+-- | |_| |__ ___ _ __ ___ ___
+-- | __| '_ \ / _ \ '_ ` _ \ / _ \
+-- | |_| | | | __/ | | | | | __/
+-- \__|_| |_|\___|_| |_| |_|\___|
+local awful = require("awful")
+local theme_assets = require("beautiful.theme_assets")
+local xresources = require("beautiful.xresources")
+local dpi = xresources.apply_dpi
+local xrdb = xresources.get_current_theme()
+local gears = require("gears")
+local gfs = require("gears.filesystem")
+local themes_path = gfs.get_themes_dir()
+local helpers = require("helpers")
+
+-- Inherit default theme
+
+local theme = dofile(themes_path .. "default/theme.lua")
+theme.wallpaper = gfs.get_configuration_dir() .. "images/bg.png"
+
+-- Titlebar icon path
+
+local icon_path = gfs.get_configuration_dir() .. "icons/"
+
+theme.me = gears.surface.load_uncached(gfs.get_configuration_dir() ..
+ "images/me.png")
+
+-- Icons for Notif Center
+
+theme.clear_icon = icon_path .. "notif-center/clear.png"
+theme.clear_grey_icon = icon_path .. "notif-center/clear_grey.png"
+theme.notification_icon = icon_path .. "notif-center/notification.png"
+theme.delete_icon = icon_path .. "notif-center/delete.png"
+theme.delete_grey_icon = icon_path .. "notif-center/delete_grey.png"
+
+-- Load ~/.Xresources colors and set fallback colors
+
+theme.xbackground = xrdb.background or "#1a2026"
+theme.xforeground = xrdb.foreground or "#ffffff"
+theme.xcolor0 = xrdb.color0 or "#29343d"
+theme.xcolor1 = xrdb.color1 or "#f9929b"
+theme.xcolor2 = xrdb.color2 or "#7ed491"
+theme.xcolor3 = xrdb.color3 or "#fbdf90"
+theme.xcolor4 = xrdb.color4 or "#a3b8ef"
+theme.xcolor5 = xrdb.color5 or "#ccaced"
+theme.xcolor6 = xrdb.color6 or "#9ce5c0"
+theme.xcolor7 = xrdb.color7 or "#ffffff"
+theme.xcolor8 = xrdb.color8 or "#3b4b58"
+theme.xcolor9 = xrdb.color9 or "#fca2aa"
+theme.xcolor10 = xrdb.color10 or "#a5d4af"
+theme.xcolor11 = xrdb.color11 or "#fbeab9"
+theme.xcolor12 = xrdb.color12 or "#bac8ef"
+theme.xcolor13 = xrdb.color13 or "#d7c1ed"
+theme.xcolor14 = xrdb.color14 or "#c7e5d6"
+theme.xcolor15 = xrdb.color15 or "#eaeaea"
+
+-- Fonts
+theme.font_name = "FiraCode Nerd Font Mono "
+theme.font = theme.font_name .. "9"
+theme.icon_font = "FiraCode Nerd Font Mono 18"
+theme.font_taglist = "FiraCode Nerd Font Mono 13"
+theme.max_font = "FiraCode Nerd Font Mono 10"
+
+-- Background Colors
+
+theme.bg_dark = theme.xcolor0
+theme.bg_normal = theme.xbackground
+theme.bg_focus = theme.xcolor0
+theme.bg_urgent = theme.xcolor8
+theme.bg_minimize = theme.xcolor8
+
+-- Foreground Colors
+
+theme.fg_normal = theme.xcolor7
+theme.fg_focus = theme.xcolor4
+theme.fg_urgent = theme.xcolor3
+theme.fg_minimize = theme.xcolor8
+
+theme.button_close = theme.xcolor1
+
+-- Borders
+
+theme.border_width = dpi(2)
+theme.oof_border_width = dpi(0)
+theme.border_normal = theme.xcolor0
+theme.border_focus = theme.xcolor0
+theme.border_radius = dpi(12)
+theme.client_radius = dpi(12)
+theme.widget_border_width = dpi(2)
+theme.widget_border_color = theme.xcolor0
+
+-- Taglist
+
+-- Generate taglist squares:
+local taglist_square_size = dpi(0)
+theme.taglist_squares_sel = theme_assets.taglist_squares_sel(
+ taglist_square_size, theme.fg_normal)
+theme.taglist_squares_unsel = theme_assets.taglist_squares_unsel(
+ taglist_square_size, theme.fg_normal)
+theme.taglist_font = theme.font_taglist
+theme.taglist_bg = theme.wibar_bg
+theme.taglist_bg_focus = theme.xcolor0
+theme.taglist_fg_focus = theme.xcolor3
+theme.taglist_bg_urgent = theme.xcolor0
+theme.taglist_fg_urgent = theme.xcolor6
+theme.taglist_bg_occupied = theme.xcolor0
+theme.taglist_fg_occupied = theme.xcolor6
+theme.taglist_bg_empty = theme.xcolor0
+theme.taglist_fg_empty = theme.xcolor8
+theme.taglist_bg_volatile = transparent
+theme.taglist_fg_volatile = theme.xcolor11
+theme.taglist_disable_icon = true
+theme.taglist_shape_focus = helpers.rrect(theme.border_radius - 3)
+
+-- Tasklist
+
+theme.tasklist_font = theme.font
+theme.tasklist_plain_task_name = true
+theme.tasklist_bg_focus = theme.xcolor0
+theme.tasklist_fg_focus = theme.xcolor6
+theme.tasklist_bg_minimize = theme.xcolor0 .. "70"
+theme.tasklist_fg_minimize = theme.xforeground .. "70"
+theme.tasklist_bg_normal = theme.xcolor0
+theme.tasklist_fg_normal = theme.xforeground
+theme.tasklist_disable_task_name = false
+theme.tasklist_disable_icon = true
+theme.tasklist_bg_urgent = theme.xcolor0
+theme.tasklist_fg_urgent = theme.xcolor1
+theme.tasklist_align = "center"
+
+-- Titlebars
+
+theme.titlebar_size = dpi(40)
+theme.titlebar_height = dpi(20)
+theme.titlebar_bg_focus = theme.xbackground
+theme.titlebar_bg_normal = theme.xbackground
+theme.titlebar_fg_focus = theme.xcolor8
+theme.titlebar_fg_normal = theme.xbackground
+
+-- Edge snap
+
+theme.snap_bg = theme.xcolor4
+theme.snap_shape = helpers.rrect(theme.border_radius)
+
+-- Prompts
+
+theme.prompt_bg = transparent
+theme.prompt_fg = theme.xforeground
+
+-- Tooltips
+
+theme.tooltip_bg = theme.xbackground
+theme.tooltip_fg = theme.xforeground
+theme.tooltip_font = theme.font_name .. "12"
+theme.tooltip_border_width = theme.widget_border_width - 1
+theme.tooltip_border_color = theme.xcolor0
+theme.tooltip_opacity = 1
+theme.tooltip_align = "left"
+
+-- Menu
+
+theme.menu_font = theme.font
+theme.menu_bg_focus = theme.xcolor4
+theme.menu_fg_focus = theme.xcolor7
+theme.menu_bg_normal = theme.xbackground
+theme.menu_fg_normal = theme.xcolor7
+theme.menu_submenu_icon = gears.filesystem.get_configuration_dir() ..
+ "theme/icons/submenu.png"
+theme.menu_height = dpi(20)
+theme.menu_width = dpi(130)
+theme.menu_border_color = "#0000000"
+theme.menu_border_width = theme.border_width
+
+-- Hotkeys Pop Up
+
+theme.hotkeys_font = theme.font
+theme.hotkeys_border_color = theme.xcolor0
+theme.hotkeys_group_margin = dpi(40)
+theme.hotkeys_shape = helpers.custom_shape
+
+-- Layout List
+
+theme.layoutlist_border_color = theme.xcolor8
+theme.layoutlist_border_width = theme.border_width
+-- Recolor Layout icons:
+theme = theme_assets.recolor_layout(theme, theme.xforeground)
+
+-- Gaps
+
+theme.useless_gap = dpi(10)
+
+-- Exit Screen
+
+theme.exit_screen_fg = theme.xforeground
+theme.exit_screen_bg = theme.xcolor0 .. "55"
+
+-- Wibar
+
+theme.wibar_height = dpi(35)
+theme.wibar_margin = dpi(15)
+theme.wibar_spacing = dpi(15)
+theme.wibar_bg = theme.xbackground
+
+-- Systray
+
+theme.systray_icon_spacing = dpi(10)
+theme.bg_systray = theme.xcolor0
+theme.systray_icon_size = dpi(15)
+
+-- Collision
+
+theme.collision_focus_bg = theme.xcolor8
+theme.collision_focus_fg = theme.xcolor6
+theme.collision_focus_shape = helpers.rrect(theme.border_radius)
+theme.collision_focus_border_width = theme.border_width
+theme.collision_focus_border_color = theme.border_normal
+
+theme.collision_focus_bg_center = theme.xcolor8
+theme.collision_shape_width = dpi(50)
+theme.collision_shape_height = dpi(50)
+theme.collision_focus_shape_center = gears.shape.circle
+
+theme.collision_max_bg = theme.xbackground
+theme.collision_max_fg = theme.xcolor8
+theme.collision_max_shape = helpers.rrect(0)
+theme.bg_urgent = theme.xcolor1
+
+theme.collision_resize_width = dpi(20)
+theme.collision_resize_shape = theme.collision_focus_shape
+theme.collision_resize_border_width = theme.collision_focus_border_width
+theme.collision_resize_border_color = theme.collision_focus_border_color
+theme.collision_resize_padding = dpi(5)
+theme.collision_resize_bg = theme.collision_focus_bg
+theme.collision_resize_fg = theme.collision_focus_fg
+
+theme.collision_screen_shape = theme.collision_focus_shape
+theme.collision_screen_border_width = theme.collision_focus_border_width
+theme.collision_screen_border_color = theme.collision_focus_border_color
+theme.collision_screen_padding = dpi(5)
+theme.collision_screen_bg = theme.xbackground
+theme.collision_screen_fg = theme.xcolor4
+theme.collision_screen_bg_focus = theme.xcolor8
+theme.collision_screen_fg_focus = theme.xcolor4
+
+-- Tabs
+
+theme.mstab_bar_height = dpi(60)
+theme.mstab_bar_padding = dpi(0)
+theme.mstab_border_radius = dpi(6)
+theme.tabbar_style = "modern"
+theme.tabbar_bg_focus = theme.xbackground
+theme.tabbar_bg_normal = theme.xcolor0
+theme.tabbar_position = "bottom"
+theme.mstab_bar_ontop = true
+
+theme.notification_spacing = 10
+
+-- Weather
+
+theme.weather_city = "San_Diego"
+
+-- Swallowing
+
+theme.dont_swallow_classname_list = {
+ "firefox", "gimp", "Google-chrome", "Thunar"
+}
+
+-- Layout Machi
+
+theme.switcher_border_color = theme.xcolor4
+theme.switcher_border_opacity = 0.25
+theme.editor_border_color = theme.xcolor1
+theme.editor_border_opacity = 0.25
+theme.editor_active_opacity = 0.25
+
+return theme
diff --git a/awesome/utils/button.lua b/awesome/utils/button.lua
new file mode 100644
index 0000000..5b1d40a
--- /dev/null
+++ b/awesome/utils/button.lua
@@ -0,0 +1,160 @@
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = beautiful.xresources.apply_dpi
+local gears = require("gears")
+
+local button = {}
+
+button.create = function(image, size, radius, margin, bg, bg_hover, bg_press,
+ command)
+ local button_image = wibox.widget {
+ image = image,
+ forced_height = size,
+ forced_width = size,
+ widget = wibox.widget.imagebox
+ }
+
+ local button = wibox.widget {
+ {button_image, margins = dpi(margin), widget = wibox.container.margin},
+ bg = bg,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(radius))
+ end,
+ widget = wibox.container.background
+ }
+
+ button:connect_signal("button::press", function()
+ button.bg = bg_press
+ command()
+ end)
+
+ button:connect_signal("button::leave", function() button.bg = bg end)
+
+ local old_cursor, old_wibox
+ button:connect_signal("mouse::enter", function()
+ button.bg = bg_hover
+
+ -- change cursor
+ local wb = mouse.current_wibox
+ old_cursor, old_wibox = wb.cursor, wb
+ wb.cursor = "hand2"
+ end)
+ button:connect_signal("mouse::leave", function()
+ button.bg = bg
+
+ -- reset cursor
+ if old_wibox then
+ old_wibox.cursor = old_cursor
+ old_wibox = nil
+ end
+ end)
+
+ button.update_image = function(image) button_image.image = image end
+
+ return button
+end
+
+button.create_widget = function(widget, command)
+ local button = wibox.widget {
+ {widget, margins = dpi(10), widget = wibox.container.margin},
+ bg = beautiful.bg_normal,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(10))
+ end,
+ widget = wibox.container.background
+ }
+
+ button:connect_signal("button::press", function()
+ button.bg = beautiful.bg_very_light
+ command()
+ end)
+
+ button:connect_signal("button::leave",
+ function() button.bg = beautiful.bg_normal end)
+ button:connect_signal("mouse::enter",
+ function() button.bg = beautiful.bg_light end)
+ button:connect_signal("mouse::leave",
+ function() button.bg = beautiful.bg_normal end)
+
+ return button
+end
+
+button.create_image = function(image, image_hover)
+ local image_widget = wibox.widget {
+ image = image,
+ widget = wibox.widget.imagebox
+ }
+
+ local old_cursor, old_wibox
+ image_widget:connect_signal("mouse::enter", function()
+ image_widget.image = image_hover
+
+ -- change cursor
+ local wb = mouse.current_wibox
+ old_cursor, old_wibox = wb.cursor, wb
+ wb.cursor = "hand2"
+ end)
+ image_widget:connect_signal("mouse::leave", function()
+ image_widget.image = image
+
+ -- reset cursor
+ if old_wibox then
+ old_wibox.cursor = old_cursor
+ old_wibox = nil
+ end
+ end)
+
+ return image_widget
+end
+
+button.create_image_onclick = function(image, image_hover, onclick)
+ local image = button.create_image(image, image_hover)
+
+ local container = wibox.widget {image, widget = wibox.widget.background}
+
+ container:connect_signal("button::press", onclick)
+
+ return container
+end
+
+button.create_text = function(color, color_hover, text, font, onclick)
+ local textWidget = wibox.widget {
+ font = font,
+ align = "center",
+ valign = "center",
+ markup = "<span foreground='" .. color .. "'>" .. text .. "</span>",
+ widget = wibox.widget.textbox
+ }
+
+ local old_cursor, old_wibox
+ textWidget:connect_signal("mouse::enter", function()
+ textWidget.markup =
+ "<span foreground='" .. color_hover .. "'>" .. text .. "</span>"
+
+ -- change cursor
+ local wb = mouse.current_wibox
+
+ if wb then
+ old_cursor, old_wibox = wb.cursor, wb
+ wb.cursor = "hand2"
+ end
+ end)
+ textWidget:connect_signal("mouse::leave", function()
+ textWidget.markup = "<span foreground='" .. color .. "'>" .. text ..
+ "</span>"
+
+ -- reset cursor
+ if old_wibox then
+ old_wibox.cursor = old_cursor
+ old_wibox = nil
+ end
+ end)
+
+ if onclick ~= nil then
+ textWidget:connect_signal("button::press", onclick)
+ end
+
+ return textWidget
+end
+
+return button
diff --git a/awesome/utils/init.lua b/awesome/utils/init.lua
new file mode 100644
index 0000000..5a763a2
--- /dev/null
+++ b/awesome/utils/init.lua
@@ -0,0 +1,4 @@
+return {
+ popupLib = require("utils.popupLib"),
+ fd_async = require("utils.fd_async")
+}
diff --git a/awesome/utils/popupLib.lua b/awesome/utils/popupLib.lua
new file mode 100644
index 0000000..e72328b
--- /dev/null
+++ b/awesome/utils/popupLib.lua
@@ -0,0 +1,62 @@
+local awful = require("awful")
+local gears = require("gears")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = require('beautiful').xresources.apply_dpi
+local helpers = require('helpers')
+
+local popupLib = {}
+
+popupLib.create = function(x, y, height, width, widget, radius, tl, tr, bl, br)
+ local widgetContainer = wibox.widget {
+ {widget, margins = dpi(10), widget = wibox.container.margin},
+ forced_height = height,
+ forced_width = width,
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local widgetBG = wibox.widget {
+ widgetContainer,
+ bg = beautiful.xbackground,
+ border_color = beautiful.widget_border_color,
+ border_width = dpi(beautiful.widget_border_width),
+ shape = helpers.prrect(radius, tl, tr, bl, br),
+ widget = wibox.container.background
+ }
+
+ local popupWidget = awful.popup {
+ screen = screen.primary,
+ widget = widgetBG,
+ visible = false,
+ ontop = true,
+ x = x,
+ y = y,
+ bg = beautiful.xbackground .. "00"
+ -- shape = helpers.rrect(beautiful.client_radius),
+ -- border_width = beautiful.widget_border_width,
+ -- border_color = beautiful.widget_border_color
+ }
+
+ local mouseInPopup = false
+ local timer = gears.timer {
+ timeout = 1.25,
+ single_shot = true,
+ callback = function()
+ if not mouseInPopup then popupWidget.visible = false end
+ end
+ }
+
+ popupWidget:connect_signal("mouse::leave", function()
+ if popupWidget.visible then
+ mouseInPopup = false
+ timer:again()
+ end
+ end)
+
+ popupWidget:connect_signal("mouse::enter",
+ function() mouseInPopup = true end)
+
+ return popupWidget
+end
+
+return popupLib
diff --git a/awesome/window/better-resize.lua b/awesome/window/better-resize.lua
new file mode 100644
index 0000000..7812ff5
--- /dev/null
+++ b/awesome/window/better-resize.lua
@@ -0,0 +1,135 @@
+local capi = {
+ client = client,
+ mouse = mouse,
+ screen = screen,
+ mousegrabber = mousegrabber
+}
+local awful = require("awful")
+
+local function mouse_resize_handler(m, c)
+ awful.client.incwfact(0, c) -- needed to fix normalization at start
+ local start = m(capi.mouse.coords())
+ local x, y = start.x, start.y
+ local wa = m(c.screen.workarea)
+ local idx = awful.client.idx(c)
+ local c_above, c_below
+ local idx_above, idx_below
+ local wfact_above, wfact_below
+ local jump_to = {x = x, y = y}
+ local move_mwfact = false
+
+ do
+ local g = m(c:geometry())
+
+ local v_border = 0.2 * g.height
+
+ if idx.idx > 1 and y >= g.y and y <= g.y + v_border then
+ -- we are near the top edge of the window
+ c_above = awful.client.next(-1, c)
+ c_below = c
+ jump_to.y = g.y
+ idx_above = idx.idx - 1
+ idx_below = idx.idx
+ elseif idx.idx < (idx.num) and y >= g.y + g.height - v_border then
+ -- we are near the bottom edge of the window
+ c_above = c
+ c_below = awful.client.next(1, c)
+ idx_above = idx.idx
+ idx_below = idx.idx + 1
+ jump_to.y = g.y + g.height
+ end
+
+ local mw_split = wa.x + wa.width *
+ c.screen.selected_tag.master_width_factor
+
+ if math.abs(mw_split - x) > wa.width / 6 then
+ move_mwfact = false
+ else
+ move_mwfact = true
+ jump_to.x = mw_split
+ end
+ end
+
+ if idx_above then
+ local t = c.screen.selected_tag
+ local data = t.windowfact or {}
+ local colfact = data[idx.col] or {}
+ wfact_above = colfact[idx_above] or 1
+ wfact_below = colfact[idx_below] or 1
+ end
+
+ if idx_above and move_mwfact then
+ cursor = "cross"
+ elseif idx_above then
+ cursor = m({y = "sb_v_double_arrow", x = "sb_h_double_arrow"}).y
+ elseif move_mwfact then
+ cursor = m({y = "sb_v_double_arrow", x = "sb_h_double_arrow"}).x
+ else
+ return false
+ end
+
+ capi.mouse.coords(m(jump_to))
+
+ capi.mousegrabber.run(function(_mouse)
+ if not c.valid then return false end
+
+ local pressed = false
+ for _, v in ipairs(_mouse.buttons) do
+ if v then
+ pressed = true
+ break
+ end
+ end
+
+ _mouse = m(_mouse)
+
+ if pressed then
+ if move_mwfact then
+ c.screen.selected_tag.master_width_factor =
+ math.min(math.max((_mouse.x - wa.x) / wa.width, 0.01), 0.99)
+ end
+
+ if idx_above then
+ local factor_delta = (_mouse.y - jump_to.y) / wa.height
+
+ if factor_delta < 0 then
+ factor_delta = math.max(factor_delta, -(wfact_above - 0.05))
+ else
+ factor_delta = math.min(factor_delta, wfact_below - 0.05)
+ end
+
+ local t = c.screen.selected_tag
+ local data = t.windowfact or {}
+ local colfact = data[idx.col] or {}
+ colfact[idx_above] = wfact_above + factor_delta
+ colfact[idx_below] = wfact_below - factor_delta
+ awful.client.incwfact(0, c_above) -- just in case
+ end
+ return true
+ else
+ return false
+ end
+ end, cursor)
+
+ return true
+end
+
+awful.layout.suit.tile.mouse_resize_handler =
+ function(c) return mouse_resize_handler(function(x) return x end, c) end
+awful.layout.suit.tile.bottom.mouse_resize_handler =
+ function(c)
+ return mouse_resize_handler(function(q)
+ return {x = q.y, y = q.x, width = q.height, height = q.width}
+ end, c)
+ end
+
+-- local old_coords = mouse.coords
+
+-- mouse.coords = function(...)
+-- if select(1, ...) and not(select(1, ...).blah) then
+-- print("set mouse!!!")
+-- print(debug.traceback())
+
+-- end
+-- return old_coords(...)
+-- end
diff --git a/awesome/window/init.lua b/awesome/window/init.lua
new file mode 100644
index 0000000..d2df22d
--- /dev/null
+++ b/awesome/window/init.lua
@@ -0,0 +1,176 @@
+local awful = require("awful")
+local gears = require("gears")
+local gfs = gears.filesystem
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local dpi = require("beautiful.xresources").apply_dpi
+local helpers = require("helpers")
+
+-- Bling Module
+local bling = require("bling")
+
+-- Layout Machi
+local machi = require("layout-machi")
+beautiful.layout_machi = machi.get_icon()
+
+-- This is to slave windows' positions in floating layout
+-- Not Mine
+-- https://github.com/larkery/awesome/blob/master/savefloats.lua
+require("window.savefloats")
+-- Better mouse resizing on tiled
+-- Not mine
+-- https://github.com/larkery/awesome/blob/master/better-resize.lua
+require("window.better-resize")
+
+client.connect_signal("manage", function(c)
+
+ -- Set the windows at the slave,
+ -- i.e. put it at the end of others instead of setting it master.
+ -- if not awesome.startup then awful.client.setslave(c) end
+ if awesome.startup and not c.size_hints.user_position and
+ not c.size_hints.program_position then
+ -- Prevent clients from being unreachable after screen count changes.
+ awful.placement.no_offscreen(c)
+ end
+
+ -- Give ST and icon
+ if c.class == "st-256color" or c.class == "st-dialog" or c.class ==
+ "st-float" or c.instance == "st-256color" then
+ local new_icon = gears.surface(gfs.get_configuration_dir() ..
+ "icons/ghosts/terminal.png")
+ c.icon = new_icon._native
+ end
+end)
+
+-- Enable sloppy focus, so that focus follows mouse.
+client.connect_signal("mouse::enter", function(c)
+ c:emit_signal("request::activate", "mouse_enter", {raise = false})
+end)
+
+client.connect_signal("focus",
+ function(c) c.border_color = beautiful.border_focus end)
+
+client.connect_signal("unfocus",
+ function(c) c.border_color = beautiful.border_normal end)
+
+--[[client.connect_signal("focus", function(c)
+ gears.surface(c.content):write_to_png("/home/javacafe01/oof.png")
+end)]] --
+-- Custom Layouts -------------------------------------------------------------
+
+local mstab = bling.layout.mstab
+local centered = bling.layout.centered
+local vertical = bling.layout.vertical
+local horizontal = bling.layout.horizontal
+
+-- Set the layouts
+
+tag.connect_signal("request::default_layouts", function()
+ awful.layout.append_default_layouts({
+ awful.layout.suit.tile, awful.layout.suit.floating, centered, mstab,
+ vertical, horizontal, machi.default_layout
+ })
+end)
+
+-- Layout List Widget ---------------------------------------------------------
+
+-- List
+local ll = awful.widget.layoutlist {
+ source = awful.widget.layoutlist.source.default_layouts, -- DOC_HIDE
+ spacing = dpi(24),
+ base_layout = wibox.widget {
+ spacing = dpi(24),
+ forced_num_cols = 4,
+ layout = wibox.layout.grid.vertical
+ },
+ widget_template = {
+ {
+ {
+ id = 'icon_role',
+ forced_height = dpi(68),
+ forced_width = dpi(68),
+ widget = wibox.widget.imagebox
+ },
+ margins = dpi(24),
+
+ widget = wibox.container.margin
+ },
+ id = 'background_role',
+ forced_width = dpi(68),
+ forced_height = dpi(68),
+ widget = wibox.container.background
+ }
+}
+
+-- Popup
+local layout_popup = awful.popup {
+ widget = wibox.widget {
+ {ll, margins = dpi(24), widget = wibox.container.margin},
+ bg = beautiful.xbackground,
+ shape = helpers.rrect(beautiful.border_radius),
+ border_color = beautiful.widget_border_color,
+ border_width = beautiful.widget_border_width,
+ widget = wibox.container.background
+ },
+ placement = awful.placement.centered,
+ ontop = true,
+ visible = false,
+ bg = beautiful.bg_normal .. "00"
+}
+
+-- Key Bindings for Widget ----------------------------------------------------
+
+-- Make sure you remove the default `Mod4+Space` and `Mod4+Shift+Space`
+-- keybindings before adding this.
+function gears.table.iterate_value(t, value, step_size, filter, start_at)
+ local k = gears.table.hasitem(t, value, true, start_at)
+ if not k then return end
+
+ step_size = step_size or 1
+ local new_key = gears.math.cycle(#t, k + step_size)
+
+ if filter and not filter(t[new_key]) then
+ for i = 1, #t do
+ local k2 = gears.math.cycle(#t, new_key + i)
+ if filter(t[k2]) then return t[k2], k2 end
+ end
+ return
+ end
+
+ return t[new_key], new_key
+end
+
+awful.keygrabber {
+ start_callback = function() layout_popup.visible = true end,
+ stop_callback = function() layout_popup.visible = false end,
+ export_keybindings = true,
+ stop_event = "release",
+ stop_key = {"Escape", "Super_L", "Super_R", "Mod4"},
+ keybindings = {
+ {
+ {modkey, "Shift"}, " ", function()
+ awful.layout.set(gears.table.iterate_value(ll.layouts,
+ ll.current_layout, -1),
+ nil)
+ end
+ }, {
+ {modkey}, " ", function()
+ awful.layout.set(gears.table.iterate_value(ll.layouts,
+ ll.current_layout, 1),
+ nil)
+ end
+ }
+ }
+}
+
+-- Hide all windows when a splash is shown
+awesome.connect_signal("widgets::splash::visibility", function(vis)
+ local t = awful.screen.focused().selected_tag
+ if vis then
+ for idx, c in ipairs(t:clients()) do c.hidden = true end
+ else
+ for idx, c in ipairs(t:clients()) do c.hidden = false end
+ end
+end)
+
+-- EOF ------------------------------------------------------------------------
diff --git a/awesome/window/savefloats.lua b/awesome/window/savefloats.lua
new file mode 100644
index 0000000..f7c7dcf
--- /dev/null
+++ b/awesome/window/savefloats.lua
@@ -0,0 +1,55 @@
+local awful = require("awful")
+
+local function rel(screen, win)
+ return {
+ x = (win.x - screen.x) / screen.width,
+ y = (win.y - screen.y) / screen.height,
+ width = win.width / screen.width,
+ aspect = win.height / win.width
+ }
+end
+
+local function unrel(s, rel)
+ return rel and {
+ x = s.x + s.width * rel.x,
+ y = s.y + s.height * rel.y,
+ width = s.width * rel.width,
+ height = rel.aspect * s.width * rel.width
+ }
+end
+
+local stored = {}
+
+local function forget(c) stored[c] = nil end
+
+local floating = awful.layout.suit.floating
+
+function remember(c)
+ if floating == awful.layout.get(c.screen) or c.floating then
+ stored[c.window] = rel(c.screen.geometry, c:geometry())
+ end
+end
+
+function restore(c)
+ local s = stored[c.window]
+ if s then
+ c:geometry(unrel(c.screen.geometry, stored[c.window]))
+ return true
+ else
+ return false
+ end
+end
+
+client.connect_signal("manage", remember)
+client.connect_signal("property::geometry", remember)
+client.connect_signal("unmanage", forget)
+
+tag.connect_signal("property::layout", function(t)
+ if floating == awful.layout.get(t.screen) then
+ for _, c in ipairs(t:clients()) do
+ c:geometry(unrel(t.screen.geometry, stored[c.window]))
+ end
+ end
+end)
+
+return restore