diff --git a/awesome/crylia_bar/init.lua b/awesome/crylia_bar/init.lua
deleted file mode 100644
index c244c05..0000000
--- a/awesome/crylia_bar/init.lua
+++ /dev/null
@@ -1,65 +0,0 @@
---------------------------------------------------------------------------------------------------------------
--- This is the statusbar, every widget, module and so on is combined to all the stuff you see on the screen --
---------------------------------------------------------------------------------------------------------------
--- Awesome Libs
-local awful = require("awful")
-
-awful.screen.connect_for_each_screen(
--- For each screen this function is called once
--- If you want to change the modules per screen use the indices
--- e.g. 1 would be the primary screen and 2 the secondary screen.
- function(s)
- -- Create 9 tags
- awful.layout.layouts = user_vars.layouts
- awful.tag(
- { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
- s,
- user_vars.layouts[1]
- )
-
- require("src.modules.powermenu")(s)
- -- TODO: rewrite calendar osd, maybe write an own inplementation
- -- require("src.modules.calendar_osd")(s)
- require("src.modules.volume_osd")(s)
- require("src.modules.brightness_osd")(s)
- require("src.modules.titlebar")
- require("src.modules.volume_controller")(s)
-
- -- Widgets
- --s.battery = require("src.widgets.battery")()
- s.audio = require("src.widgets.audio")(s)
- s.date = require("src.widgets.date")()
- s.clock = require("src.widgets.clock")()
- --s.bluetooth = require("src.widgets.bluetooth")()
- s.layoutlist = require("src.widgets.layout_list")()
- s.powerbutton = require("src.widgets.power")()
- s.kblayout = require("src.widgets.kblayout")(s)
- s.taglist = require("src.widgets.taglist")(s)
- s.tasklist = require("src.widgets.tasklist")(s)
- --s.cpu_freq = require("src.widgets.cpu_info")("freq", "average")
-
- -- Add more of these if statements if you want to change
- -- the modules/widgets per screen.
- if s.index == 1 then
- s.systray = require("src.widgets.systray")(s)
- s.cpu_usage = require("src.widgets.cpu_info")("usage")
- s.cpu_temp = require("src.widgets.cpu_info")("temp")
- s.gpu_usage = require("src.widgets.gpu_info")("usage")
- s.gpu_temp = require("src.widgets.gpu_info")("temp")
-
- require("crylia_bar.left_bar")(s, { s.layoutlist, s.systray, s.taglist })
- require("crylia_bar.center_bar")(s, { s.tasklist })
- require("crylia_bar.right_bar")(s, { s.gpu_usage, s.gpu_temp, s.cpu_usage, s.cpu_temp, s.audio, s.kblayout, s.date, s.clock, s.powerbutton })
- require("crylia_bar.dock")(s, user_vars.dock_programs)
- end
-
- if s.index == 2 then
- s.network = require("src.widgets.network")()
- s.ram_info = require("src.widgets.ram_info")()
-
- require("crylia_bar.left_bar")(s, { s.layoutlist, s.taglist })
- require("crylia_bar.center_bar")(s, { s.tasklist })
- require("crylia_bar.right_bar")(s, { s.ram_info, s.audio, s.kblayout, s.network, s.date, s.clock, s.powerbutton })
- end
-end
-)
diff --git a/awesome/rc.lua b/awesome/rc.lua
index 0a1132f..07f5359 100644
--- a/awesome/rc.lua
+++ b/awesome/rc.lua
@@ -13,7 +13,7 @@ require("src.core.error_handling")
require("src.core.signals")
require("src.core.notifications")
require("src.core.rules")
-require("mappings.global_buttons")
-require("mappings.bind_to_tags")
-require("crylia_bar.init")
-require("src.tools.auto_starter")(user_vars.autostart)
+require("src.bindings.global_buttons")
+require("src.bindings.bind_to_tags")
+require("src.modules.init")
+--require("src.tools.auto_starter")(user_vars.autostart)
diff --git a/awesome/src/assets/icons/notifications/MEGAMIND.svg b/awesome/src/assets/icons/notifications/MEGAMIND.svg
new file mode 100644
index 0000000..950fad7
--- /dev/null
+++ b/awesome/src/assets/icons/notifications/MEGAMIND.svg
@@ -0,0 +1,319 @@
+
+
+
diff --git a/awesome/src/assets/icons/notifications/bell-outline.svg b/awesome/src/assets/icons/notifications/bell-outline.svg
new file mode 100644
index 0000000..b306aab
--- /dev/null
+++ b/awesome/src/assets/icons/notifications/bell-outline.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/notifications/megamind.svg b/awesome/src/assets/icons/notifications/megamind.svg
new file mode 100644
index 0000000..edad7ea
--- /dev/null
+++ b/awesome/src/assets/icons/notifications/megamind.svg
@@ -0,0 +1,54 @@
+
+
diff --git a/awesome/src/assets/icons/notifications/repeat-once.svg b/awesome/src/assets/icons/notifications/repeat-once.svg
new file mode 100644
index 0000000..af2555f
--- /dev/null
+++ b/awesome/src/assets/icons/notifications/repeat-once.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/src/assets/icons/notifications/repeat.svg b/awesome/src/assets/icons/notifications/repeat.svg
new file mode 100644
index 0000000..8086726
--- /dev/null
+++ b/awesome/src/assets/icons/notifications/repeat.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/src/assets/icons/notifications/shuffle.svg b/awesome/src/assets/icons/notifications/shuffle.svg
new file mode 100644
index 0000000..dc35411
--- /dev/null
+++ b/awesome/src/assets/icons/notifications/shuffle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/src/assets/icons/profile/clock.svg b/awesome/src/assets/icons/profile/clock.svg
new file mode 100644
index 0000000..84984a8
--- /dev/null
+++ b/awesome/src/assets/icons/profile/clock.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/src/assets/icons/profile/laptop.svg b/awesome/src/assets/icons/profile/laptop.svg
new file mode 100644
index 0000000..689816a
--- /dev/null
+++ b/awesome/src/assets/icons/profile/laptop.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/profile/penguin.svg b/awesome/src/assets/icons/profile/penguin.svg
new file mode 100644
index 0000000..c977e37
--- /dev/null
+++ b/awesome/src/assets/icons/profile/penguin.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/profile/user.svg b/awesome/src/assets/icons/profile/user.svg
new file mode 100644
index 0000000..0549b71
--- /dev/null
+++ b/awesome/src/assets/icons/profile/user.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/humidity.svg b/awesome/src/assets/icons/weather/humidity.svg
new file mode 100644
index 0000000..a6e7eb3
--- /dev/null
+++ b/awesome/src/assets/icons/weather/humidity.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/src/assets/icons/weather/weather-clear-night.svg b/awesome/src/assets/icons/weather/weather-clear-night.svg
new file mode 100644
index 0000000..7cce7bc
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-clear-night.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-cloudy-alert.svg b/awesome/src/assets/icons/weather/weather-cloudy-alert.svg
new file mode 100644
index 0000000..ffddf6a
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-cloudy-alert.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-cloudy.svg b/awesome/src/assets/icons/weather/weather-cloudy.svg
new file mode 100644
index 0000000..5106bbb
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-cloudy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-fog.svg b/awesome/src/assets/icons/weather/weather-fog.svg
new file mode 100644
index 0000000..3f1712d
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-fog.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-hail.svg b/awesome/src/assets/icons/weather/weather-hail.svg
new file mode 100644
index 0000000..66d7a83
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-hail.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-hazy.svg b/awesome/src/assets/icons/weather/weather-hazy.svg
new file mode 100644
index 0000000..2f91bb5
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-hazy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-hurricane.svg b/awesome/src/assets/icons/weather/weather-hurricane.svg
new file mode 100644
index 0000000..745214d
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-hurricane.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-lightning-rainy.svg b/awesome/src/assets/icons/weather/weather-lightning-rainy.svg
new file mode 100644
index 0000000..7ef4a8e
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-lightning-rainy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-lightning.svg b/awesome/src/assets/icons/weather/weather-lightning.svg
new file mode 100644
index 0000000..663b0bd
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-lightning.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-night-partly-cloudy.svg b/awesome/src/assets/icons/weather/weather-night-partly-cloudy.svg
new file mode 100644
index 0000000..92ac071
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-night-partly-cloudy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-partly-cloudy.svg b/awesome/src/assets/icons/weather/weather-partly-cloudy.svg
new file mode 100644
index 0000000..f2c4e07
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-partly-cloudy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-partly-lightning.svg b/awesome/src/assets/icons/weather/weather-partly-lightning.svg
new file mode 100644
index 0000000..d95d06c
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-partly-lightning.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-partly-rainy.svg b/awesome/src/assets/icons/weather/weather-partly-rainy.svg
new file mode 100644
index 0000000..47c0c25
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-partly-rainy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-partly-snowy-rainy.svg b/awesome/src/assets/icons/weather/weather-partly-snowy-rainy.svg
new file mode 100644
index 0000000..fe1b4ee
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-partly-snowy-rainy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-partly-snowy.svg b/awesome/src/assets/icons/weather/weather-partly-snowy.svg
new file mode 100644
index 0000000..c8a5273
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-partly-snowy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-pouring.svg b/awesome/src/assets/icons/weather/weather-pouring.svg
new file mode 100644
index 0000000..c92c5ef
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-pouring.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-rainy.svg b/awesome/src/assets/icons/weather/weather-rainy.svg
new file mode 100644
index 0000000..cebfcb6
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-rainy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-snowy-heavy.svg b/awesome/src/assets/icons/weather/weather-snowy-heavy.svg
new file mode 100644
index 0000000..c77b21a
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-snowy-heavy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-snowy-rainy.svg b/awesome/src/assets/icons/weather/weather-snowy-rainy.svg
new file mode 100644
index 0000000..83da969
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-snowy-rainy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-snowy.svg b/awesome/src/assets/icons/weather/weather-snowy.svg
new file mode 100644
index 0000000..e7835b8
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-snowy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-sunny-alert.svg b/awesome/src/assets/icons/weather/weather-sunny-alert.svg
new file mode 100644
index 0000000..1d44f94
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-sunny-alert.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-sunny.svg b/awesome/src/assets/icons/weather/weather-sunny.svg
new file mode 100644
index 0000000..6913b8d
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-sunny.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-sunset.svg b/awesome/src/assets/icons/weather/weather-sunset.svg
new file mode 100644
index 0000000..0f85f81
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-sunset.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-tornado.svg b/awesome/src/assets/icons/weather/weather-tornado.svg
new file mode 100644
index 0000000..1124ec3
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-tornado.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-windy-variant.svg b/awesome/src/assets/icons/weather/weather-windy-variant.svg
new file mode 100644
index 0000000..9cacbea
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-windy-variant.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/src/assets/icons/weather/weather-windy.svg b/awesome/src/assets/icons/weather/weather-windy.svg
new file mode 100644
index 0000000..f1f1a36
--- /dev/null
+++ b/awesome/src/assets/icons/weather/weather-windy.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/awesome/mappings/bind_to_tags.lua b/awesome/src/bindings/bind_to_tags.lua
similarity index 97%
rename from awesome/mappings/bind_to_tags.lua
rename to awesome/src/bindings/bind_to_tags.lua
index ccba2c7..ebc6247 100644
--- a/awesome/mappings/bind_to_tags.lua
+++ b/awesome/src/bindings/bind_to_tags.lua
@@ -1,7 +1,7 @@
-- Awesome Libs
local awful = require("awful")
local gears = require("gears")
-local globalkeys = require("../mappings/global_keys")
+local globalkeys = require("src.bindings.global_keys")
local modkey = user_vars.modkey
for i = 1, 9 do
diff --git a/awesome/mappings/client_buttons.lua b/awesome/src/bindings/client_buttons.lua
similarity index 100%
rename from awesome/mappings/client_buttons.lua
rename to awesome/src/bindings/client_buttons.lua
diff --git a/awesome/mappings/client_keys.lua b/awesome/src/bindings/client_keys.lua
similarity index 100%
rename from awesome/mappings/client_keys.lua
rename to awesome/src/bindings/client_keys.lua
diff --git a/awesome/mappings/global_buttons.lua b/awesome/src/bindings/global_buttons.lua
similarity index 100%
rename from awesome/mappings/global_buttons.lua
rename to awesome/src/bindings/global_buttons.lua
diff --git a/awesome/mappings/global_keys.lua b/awesome/src/bindings/global_keys.lua
similarity index 100%
rename from awesome/mappings/global_keys.lua
rename to awesome/src/bindings/global_keys.lua
diff --git a/awesome/src/core/error_handling.lua b/awesome/src/core/error_handling.lua
index c1e0b25..07eae32 100644
--- a/awesome/src/core/error_handling.lua
+++ b/awesome/src/core/error_handling.lua
@@ -9,17 +9,17 @@ do
awesome.connect_signal(
"debug::error",
function(err)
- if in_error then
- return
- end
- in_error = true
+ if in_error then
+ return
+ end
+ in_error = true
- naughty.notify({
- preset = naughty.config.presets.critical,
- title = "ERROR",
- text = tostring(err)
- })
- in_error = false
- end
+ naughty.notify({
+ preset = naughty.config.presets.critical,
+ title = "ERROR",
+ text = tostring(err)
+ })
+ in_error = false
+ end
)
end
diff --git a/awesome/src/core/notifications.lua b/awesome/src/core/notifications.lua
index 4580e9a..df1c2aa 100644
--- a/awesome/src/core/notifications.lua
+++ b/awesome/src/core/notifications.lua
@@ -10,6 +10,8 @@ local menubar = require('menubar')
local naughty = require("naughty")
local wibox = require("wibox")
+local rubato = require("src.lib.rubato")
+
local icondir = awful.util.getdir("config") .. "src/assets/icons/notifications/"
-- TODO: Figure out how to use hover effects without messing up the actions
@@ -42,335 +44,343 @@ naughty.connect_signal(
naughty.connect_signal(
"request::display",
function(n)
- if n.urgency == "critical" then
- n.title = string.format("%s",
- color["RedA200"], n.title) or ""
- n.message = string.format("%s", color["Red200"], n.message) or ""
- n.app_name = string.format("%s", color["RedA400"], n.app_name) or ""
- n.bg = color["Grey900"]
+ if user_vars.dnd then
+ n:destroy()
else
- n.title = string.format("%s",
- color["Pink200"], n.title) or ""
- n.message = string.format("%s", "#ffffffaa", n.message) or ""
- n.bg = color["Grey900"]
- n.timeout = n.timeout or 3
- end
+ if n.urgency == "critical" then
+ n.title = string.format("%s",
+ color["RedA200"], n.title) or ""
+ n.message = string.format("%s", color["Red200"], n.message) or ""
+ n.app_name = string.format("%s", color["RedA400"], n.app_name) or ""
+ n.bg = color["Grey900"]
+ else
+ n.title = string.format("%s",
+ color["Pink200"], n.title) or ""
+ n.message = string.format("%s", "#ffffffaa", n.message) or ""
+ n.bg = color["Grey900"]
+ n.timeout = n.timeout or 3
+ end
- local use_image = false
+ local use_image = false
- if n.app_name == "Spotify" then
- n.actions = { naughty.action {
- program = "Spotify",
- id = "skip-prev",
- icon = gears.color.recolor_image(icondir .. "skip-prev.svg", color["Cyan200"])
- }, naughty.action {
- program = "Spotify",
- id = "play-pause",
- icon = gears.color.recolor_image(icondir .. "play-pause.svg", color["Cyan200"])
- }, naughty.action {
- program = "Spotify",
- id = "skip-next",
- icon = gears.color.recolor_image(icondir .. "skip-next.svg", color["Cyan200"])
- } }
- use_image = true
- end
+ if n.app_name == "Spotify" then
+ n.actions = { naughty.action {
+ program = "Spotify",
+ id = "skip-prev",
+ icon = gears.color.recolor_image(icondir .. "skip-prev.svg", color["Cyan200"])
+ }, naughty.action {
+ program = "Spotify",
+ id = "play-pause",
+ icon = gears.color.recolor_image(icondir .. "play-pause.svg", color["Cyan200"])
+ }, naughty.action {
+ program = "Spotify",
+ id = "skip-next",
+ icon = gears.color.recolor_image(icondir .. "skip-next.svg", color["Cyan200"])
+ } }
+ use_image = true
+ end
- local action_template_widget = {}
+ local action_template_widget = {}
- if use_image then
- action_template_widget = {
- {
- {
- {
- {
- id = "icon_role",
- widget = wibox.widget.imagebox
- },
- id = "centered",
- valign = "center",
- halign = "center",
- widget = wibox.container.place
- },
- margins = dpi(5),
- widget = wibox.container.margin
- },
- forced_height = dpi(35),
- forced_width = dpi(35),
- fg = color["Cyan200"],
- bg = color["Grey800"],
- shape = function(cr, width, height)
- gears.shape.rounded_rect(cr, width, height, dpi(6))
- end,
- widget = wibox.container.background,
- id = "bgrnd"
- },
- id = "mrgn",
- top = dpi(10),
- bottom = dpi(10),
- widget = wibox.container.margin
- }
- else
- action_template_widget = {
- {
- {
- {
- {
- id = "text_role",
- font = "JetBrainsMono Nerd Font, Regular 12",
- widget = wibox.widget.textbox
- },
- id = "centered",
- widget = wibox.container.place
- },
- margins = dpi(5),
- widget = wibox.container.margin
- },
- fg = color["Green200"],
- bg = color["Grey800"],
- shape = function(cr, width, height)
- gears.shape.rounded_rect(cr, width, height, dpi(6))
- end,
- widget = wibox.container.background,
- id = "bgrnd"
- },
- id = "mrgn",
- top = dpi(10),
- bottom = dpi(10),
- widget = wibox.container.margin
- }
- end
-
- local actions_template = wibox.widget {
- notification = n,
- base_layout = wibox.widget {
- spacing = dpi(40),
- layout = wibox.layout.fixed.horizontal
- },
- widget_template = action_template_widget,
- style = {
- underline_normal = false,
- underline_selected = true,
- bg_normal = color["Grey100"],
- bg_selected = color["Grey200"]
- },
- widget = naughty.list.actions
- }
-
- local w_template = wibox.widget {
- {
- {
+ if use_image then
+ action_template_widget = {
{
{
{
{
- {
- {
- {
- {
- image = gears.color.recolor_image(icondir .. "notification-outline.svg", color["Teal200"]),
- resize = false,
- widget = wibox.widget.imagebox
- },
- right = dpi(5),
- widget = wibox.container.margin
- },
- {
- markup = n.app_name or 'System Notification',
- align = "center",
- valign = "center",
- widget = wibox.widget.textbox
- },
- layout = wibox.layout.fixed.horizontal
- },
- fg = color["Teal200"],
- widget = wibox.container.background
- },
- margins = dpi(10),
- widget = wibox.container.margin
+ id = "icon_role",
+ widget = wibox.widget.imagebox
},
- nil,
+ id = "centered",
+ valign = "center",
+ halign = "center",
+ widget = wibox.container.place
+ },
+ margins = dpi(5),
+ widget = wibox.container.margin
+ },
+ forced_height = dpi(35),
+ forced_width = dpi(35),
+ fg = color["Cyan200"],
+ bg = color["Grey800"],
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(6))
+ end,
+ widget = wibox.container.background,
+ id = "bgrnd"
+ },
+ id = "mrgn",
+ top = dpi(10),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+ }
+ else
+ action_template_widget = {
+ {
+ {
+ {
+ {
+ id = "text_role",
+ font = "JetBrainsMono Nerd Font, Regular 12",
+ widget = wibox.widget.textbox
+ },
+ id = "centered",
+ widget = wibox.container.place
+ },
+ margins = dpi(5),
+ widget = wibox.container.margin
+ },
+ fg = color["Green200"],
+ bg = color["Grey800"],
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(6))
+ end,
+ widget = wibox.container.background,
+ id = "bgrnd"
+ },
+ id = "mrgn",
+ top = dpi(10),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+ }
+ end
+
+ local actions_template = wibox.widget {
+ notification = n,
+ base_layout = wibox.widget {
+ spacing = dpi(40),
+ layout = wibox.layout.fixed.horizontal
+ },
+ widget_template = action_template_widget,
+ style = {
+ underline_normal = false,
+ underline_selected = true,
+ bg_normal = color["Grey100"],
+ bg_selected = color["Grey200"]
+ },
+ widget = naughty.list.actions
+ }
+
+ local w_template = wibox.widget {
+ {
+ {
+ {
+ {
{
- {
- {
- text = os.date("%H:%M"),
- widget = wibox.widget.textbox
- },
- id = "background",
- fg = color["Teal200"],
- widget = wibox.container.background
- },
{
{
{
{
{
- font = user_vars.font.specify .. ", 10",
- text = "✕",
- align = "center",
- valign = "center",
- widget = wibox.widget.textbox
+ image = gears.color.recolor_image(icondir .. "notification-outline.svg", color["Teal200"]),
+ resize = false,
+ widget = wibox.widget.imagebox
},
- start_angle = 4.71239,
- thickness = dpi(2),
- min_value = 0,
- max_value = 360,
- value = 360,
- widget = wibox.container.arcchart,
- id = "arc_chart"
+ right = dpi(5),
+ widget = wibox.container.margin
},
- id = "background",
- fg = color["Teal200"],
- bg = color["Grey900"],
- widget = wibox.container.background
+ {
+ markup = n.app_name or 'System Notification',
+ align = "center",
+ valign = "center",
+ widget = wibox.widget.textbox
+ },
+ layout = wibox.layout.fixed.horizontal
},
- strategy = "exact",
- width = dpi(20),
- height = dpi(20),
- widget = wibox.container.constraint,
- id = "const"
+ fg = color["Teal200"],
+ widget = wibox.container.background
},
margins = dpi(10),
- widget = wibox.container.margin,
- id = "arc_margin"
+ widget = wibox.container.margin
},
- layout = wibox.layout.fixed.horizontal,
- id = "arc_app_layout_2"
+ nil,
+ {
+ {
+ {
+ text = os.date("%H:%M"),
+ widget = wibox.widget.textbox
+ },
+ id = "background",
+ fg = color["Teal200"],
+ widget = wibox.container.background
+ },
+ {
+ {
+ {
+ {
+ {
+ font = user_vars.font.specify .. ", 10",
+ text = "✕",
+ align = "center",
+ valign = "center",
+ widget = wibox.widget.textbox
+ },
+ start_angle = 4.71239,
+ thickness = dpi(2),
+ min_value = 0,
+ max_value = n.timeout or 10,
+ value = n.timeout or 10,
+ widget = wibox.container.arcchart,
+ id = "arc_chart"
+ },
+ id = "background",
+ fg = color["Teal200"],
+ bg = color["Grey900"],
+ widget = wibox.container.background
+ },
+ strategy = "exact",
+ width = dpi(20),
+ height = dpi(20),
+ widget = wibox.container.constraint,
+ id = "const"
+ },
+ margins = dpi(10),
+ widget = wibox.container.margin,
+ id = "arc_margin"
+ },
+ layout = wibox.layout.fixed.horizontal,
+ id = "arc_app_layout_2"
+ },
+ id = "arc_app_layout",
+ layout = wibox.layout.align.horizontal
},
- id = "arc_app_layout",
- layout = wibox.layout.align.horizontal
+ id = "arc_app_bg",
+ border_color = color["Grey800"],
+ border_width = dpi(2),
+ widget = wibox.container.background
},
- id = "arc_app_bg",
- border_color = color["Grey800"],
- border_width = dpi(2),
- widget = wibox.container.background
- },
- {
{
{
{
{
- image = n.icon,
- resize = true,
- widget = wibox.widget.imagebox,
- clip_shape = function(cr, width, height)
- gears.shape.rounded_rect(cr, width, height, 10)
- end
+ {
+ image = n.icon,
+ resize = true,
+ widget = wibox.widget.imagebox,
+ clip_shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 10)
+ end
+ },
+ width = naughty.config.defaults.icon_size,
+ height = naughty.config.defaults.icon_size,
+ strategy = "exact",
+ widget = wibox.container.constraint
},
- width = naughty.config.defaults.icon_size,
- height = naughty.config.defaults.icon_size,
- strategy = "exact",
- widget = wibox.container.constraint
- },
- halign = "center",
- valign = "top",
- widget = wibox.container.place
- },
- left = dpi(20),
- bottom = dpi(15),
- top = dpi(15),
- right = dpi(10),
- widget = wibox.container.margin
- },
- {
- {
- {
- widget = naughty.widget.title,
- align = "left"
- },
- {
- widget = naughty.widget.message,
- align = "left"
- },
- {
- actions_template,
+ halign = "center",
+ valign = "top",
widget = wibox.container.place
},
- layout = wibox.layout.fixed.vertical
+ left = dpi(20),
+ bottom = dpi(15),
+ top = dpi(15),
+ right = dpi(10),
+ widget = wibox.container.margin
},
- left = dpi(10),
- bottom = dpi(10),
- top = dpi(10),
- right = dpi(20),
- widget = wibox.container.margin
+ {
+ {
+ {
+ widget = naughty.widget.title,
+ align = "left"
+ },
+ {
+ widget = naughty.widget.message,
+ align = "left"
+ },
+ {
+ actions_template,
+ widget = wibox.container.place
+ },
+ layout = wibox.layout.fixed.vertical
+ },
+ left = dpi(10),
+ bottom = dpi(10),
+ top = dpi(10),
+ right = dpi(20),
+ widget = wibox.container.margin
+ },
+ layout = wibox.layout.fixed.horizontal
},
- layout = wibox.layout.fixed.horizontal
+ id = "widget_layout",
+ layout = wibox.layout.fixed.vertical
},
- id = "widget_layout",
- layout = wibox.layout.fixed.vertical
+ id = "min_size",
+ strategy = "min",
+ width = dpi(100),
+ widget = wibox.container.constraint
},
- id = "min_size",
- strategy = "min",
- width = dpi(100),
+ id = "max_size",
+ strategy = "max",
+ width = Theme.notification_max_width or dpi(500),
widget = wibox.container.constraint
},
- id = "max_size",
- strategy = "max",
- width = Theme.notification_max_width or dpi(500),
- widget = wibox.container.constraint
- },
- id = "background",
- bg = color["Grey900"],
- border_color = color["Grey800"],
- border_width = dpi(4),
- shape = function(cr, width, height)
- gears.shape.rounded_rect(cr, width, height, 4)
- end,
- widget = wibox.container.background
- }
-
- local close = w_template.max_size.min_size.widget_layout.arc_app_bg.arc_app_layout.arc_app_layout_2.arc_margin.const.background
- local arc = close.arc_chart
-
- local timeout = n.timeout
- local remove_time = timeout
-
- if timeout ~= 0 then
- arc.value = 360
- local arc_timer = gears.timer {
- timeout = 0.1,
- call_now = true,
- autostart = true,
- callback = function()
- arc.value = (remove_time - 0) / (timeout - 0) * 360
- remove_time = remove_time - 0.1
- end
+ id = "background",
+ bg = color["Grey900"],
+ border_color = color["Grey800"],
+ border_width = dpi(4),
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 4)
+ end,
+ widget = wibox.container.background
}
- w_template:connect_signal(
- "mouse::enter",
- function()
- -- Setting to 0 doesn't work
- arc_timer:stop()
- n.timeout = 99999
- end
- )
+ local close = w_template.max_size.min_size.widget_layout.arc_app_bg.arc_app_layout.arc_app_layout_2.arc_margin.const.background
+ local arc = close.arc_chart
- w_template:connect_signal(
- "mouse::leave",
- function()
- arc_timer:start()
- n.timeout = remove_time
- end
- )
- end
+ local timeout = n.timeout
- Hover_signal(close, color["Grey900"], color["Teal200"])
+ if timeout ~= 0 then
- close:connect_signal(
- "button::press",
- function()
- n:destroy()
+ local rubato_timer = rubato.timed {
+ duration = n.timeout,
+ pos = n.timeout,
+ easing = rubato.linear,
+ subscribed = function(value)
+ arc.value = value
+ end
+ }
+
+ rubato_timer.target = 0
+
+ local last_position = n.timeout
+
+ w_template:connect_signal(
+ "mouse::enter",
+ function()
+ n.timeout = 99999
+ last_position = rubato_timer.pos
+ rubato_timer:abort()
+ end
+ )
+
+ w_template:connect_signal(
+ "mouse::leave",
+ function()
+ n.timeout = last_position
+ rubato_timer.pos = last_position
+ rubato_timer.duration = last_position
+ rubato_timer:reset()
+ rubato_timer.target = 0
+ end
+ )
end
- )
- w_template:connect_signal(
- "button::press",
- function(c, d, e, key)
- if key == 3 then
+ Hover_signal(close, color["Grey900"], color["Teal200"])
+
+ close:connect_signal(
+ "button::press",
+ function()
n:destroy()
end
- -- TODO: Find out how to get the associated client
- --[[ if key == 1 then
+ )
+
+ w_template:connect_signal(
+ "button::press",
+ function(c, d, e, key)
+ if key == 3 then
+ n:destroy()
+ end
+ -- TODO: Find out how to get the associated client
+ --[[ if key == 1 then
if n.clients then
n.clients[1]:activate {
switch_to_tag = true,
@@ -378,22 +388,23 @@ naughty.connect_signal(
}
end
end ]]
- end
- )
+ end
+ )
- local box = naughty.layout.box {
- notification = n,
- timeout = 3,
- type = "notification",
- screen = awful.screen.focused(),
- shape = function(cr, width, height)
- gears.shape.rounded_rect(cr, width, height, 10)
- end,
- widget_template = w_template
- }
+ local box = naughty.layout.box {
+ notification = n,
+ timeout = 3,
+ type = "notification",
+ screen = awful.screen.focused(),
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 10)
+ end,
+ widget_template = w_template
+ }
- box.buttons = {}
- n.buttons = {}
+ box.buttons = {}
+ n.buttons = {}
+ end
end
)
@@ -405,13 +416,13 @@ naughty.connect_signal(
)
-- Test notification
---[[naughty.notification {
+--[[ naughty.notification {
app_name = "System Notification",
- title = "A notification 3",
+ title = "A notification 2",
message = "This is very informative and overflowing",
icon = "/home/crylia/.config/awesome/src/assets/userpfp/crylia.png",
urgency = "normal",
- timeout = 1,
+ timeout = 0,
actions = {
naughty.action {
name = "Accept",
@@ -423,7 +434,7 @@ naughty.connect_signal(
name = "Ignore",
},
}
-}--]]
+} ]]
naughty.connect_signal(
"invoked",
diff --git a/awesome/src/core/rules.lua b/awesome/src/core/rules.lua
index 8388f63..fe5106e 100644
--- a/awesome/src/core/rules.lua
+++ b/awesome/src/core/rules.lua
@@ -15,8 +15,8 @@ awful.rules.rules = {
border_color = beautiful.border_normal,
focus = awful.client.focus.filter,
raise = true,
- keys = require("../../mappings/client_keys"),
- buttons = require("../../mappings/client_buttons"),
+ keys = require("src.bindings.client_keys"),
+ buttons = require("src.bindings.client_buttons"),
screen = awful.screen.preferred,
placement = awful.placement.no_overlap + awful.placement.no_offscreen
}
@@ -53,13 +53,13 @@ awful.rules.rules = {
awful.spawn.easy_async_with_shell(
"cat ~/.config/awesome/src/assets/rules.txt",
function(stdout)
- for class in stdout:gmatch("%a+") do
- ruled.client.append_rule {
- rule = { class = class },
- properties = {
- floating = true
- },
- }
+ for class in stdout:gmatch("%a+") do
+ ruled.client.append_rule {
+ rule = { class = class },
+ properties = {
+ floating = true
+ },
+ }
+ end
end
-end
)
diff --git a/awesome/src/lib/json-lua/json-lua.lua b/awesome/src/lib/json-lua/json-lua.lua
new file mode 100644
index 0000000..efc752e
--- /dev/null
+++ b/awesome/src/lib/json-lua/json-lua.lua
@@ -0,0 +1,1554 @@
+-- -*- coding: utf-8 -*-
+--
+-- Simple JSON encoding and decoding in pure Lua.
+--
+-- Copyright 2010-2016 Jeffrey Friedl
+-- http://regex.info/blog/
+-- Latest version: http://regex.info/blog/lua/json
+--
+-- This code is released under a Creative Commons CC-BY "Attribution" License:
+-- http://creativecommons.org/licenses/by/3.0/deed.en_US
+--
+-- It can be used for any purpose so long as:
+-- 1) the copyright notice above is maintained
+-- 2) the web-page links above are maintained
+-- 3) the 'AUTHOR_NOTE' string below is maintained
+--
+local VERSION = '20161109.21' -- version history at end of file
+local AUTHOR_NOTE = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json) version 20161109.21 ]-"
+
+--
+-- The 'AUTHOR_NOTE' variable exists so that information about the source
+-- of the package is maintained even in compiled versions. It's also
+-- included in OBJDEF below mostly to quiet warnings about unused variables.
+--
+local OBJDEF = {
+ VERSION = VERSION,
+ AUTHOR_NOTE = AUTHOR_NOTE,
+}
+
+
+--
+-- Simple JSON encoding and decoding in pure Lua.
+-- JSON definition: http://www.json.org/
+--
+--
+-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
+--
+-- local lua_value = JSON:decode(raw_json_text)
+--
+-- local raw_json_text = JSON:encode(lua_table_or_value)
+-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
+--
+--
+--
+-- DECODING (from a JSON string to a Lua table)
+--
+--
+-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
+--
+-- local lua_value = JSON:decode(raw_json_text)
+--
+-- If the JSON text is for an object or an array, e.g.
+-- { "what": "books", "count": 3 }
+-- or
+-- [ "Larry", "Curly", "Moe" ]
+--
+-- the result is a Lua table, e.g.
+-- { what = "books", count = 3 }
+-- or
+-- { "Larry", "Curly", "Moe" }
+--
+--
+-- The encode and decode routines accept an optional second argument,
+-- "etc", which is not used during encoding or decoding, but upon error
+-- is passed along to error handlers. It can be of any type (including nil).
+--
+--
+--
+-- ERROR HANDLING
+--
+-- With most errors during decoding, this code calls
+--
+-- JSON:onDecodeError(message, text, location, etc)
+--
+-- with a message about the error, and if known, the JSON text being
+-- parsed and the byte count where the problem was discovered. You can
+-- replace the default JSON:onDecodeError() with your own function.
+--
+-- The default onDecodeError() merely augments the message with data
+-- about the text and the location if known (and if a second 'etc'
+-- argument had been provided to decode(), its value is tacked onto the
+-- message as well), and then calls JSON.assert(), which itself defaults
+-- to Lua's built-in assert(), and can also be overridden.
+--
+-- For example, in an Adobe Lightroom plugin, you might use something like
+--
+-- function JSON:onDecodeError(message, text, location, etc)
+-- LrErrors.throwUserError("Internal Error: invalid JSON data")
+-- end
+--
+-- or even just
+--
+-- function JSON.assert(message)
+-- LrErrors.throwUserError("Internal Error: " .. message)
+-- end
+--
+-- If JSON:decode() is passed a nil, this is called instead:
+--
+-- JSON:onDecodeOfNilError(message, nil, nil, etc)
+--
+-- and if JSON:decode() is passed HTML instead of JSON, this is called:
+--
+-- JSON:onDecodeOfHTMLError(message, text, nil, etc)
+--
+-- The use of the fourth 'etc' argument allows stronger coordination
+-- between decoding and error reporting, especially when you provide your
+-- own error-handling routines. Continuing with the the Adobe Lightroom
+-- plugin example:
+--
+-- function JSON:onDecodeError(message, text, location, etc)
+-- local note = "Internal Error: invalid JSON data"
+-- if type(etc) = 'table' and etc.photo then
+-- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName')
+-- end
+-- LrErrors.throwUserError(note)
+-- end
+--
+-- :
+-- :
+--
+-- for i, photo in ipairs(photosToProcess) do
+-- :
+-- :
+-- local data = JSON:decode(someJsonText, { photo = photo })
+-- :
+-- :
+-- end
+--
+--
+--
+-- If the JSON text passed to decode() has trailing garbage (e.g. as with the JSON "[123]xyzzy"),
+-- the method
+--
+-- JSON:onTrailingGarbage(json_text, location, parsed_value, etc)
+--
+-- is invoked, where:
+--
+-- json_text is the original JSON text being parsed,
+-- location is the count of bytes into json_text where the garbage starts (6 in the example),
+-- parsed_value is the Lua result of what was successfully parsed ({123} in the example),
+-- etc is as above.
+--
+-- If JSON:onTrailingGarbage() does not abort, it should return the value decode() should return,
+-- or nil + an error message.
+--
+-- local new_value, error_message = JSON:onTrailingGarbage()
+--
+-- The default handler just invokes JSON:onDecodeError("trailing garbage"...), but you can have
+-- this package ignore trailing garbage via
+--
+-- function JSON:onTrailingGarbage(json_text, location, parsed_value, etc)
+-- return parsed_value
+-- end
+--
+--
+-- DECODING AND STRICT TYPES
+--
+-- Because both JSON objects and JSON arrays are converted to Lua tables,
+-- it's not normally possible to tell which original JSON type a
+-- particular Lua table was derived from, or guarantee decode-encode
+-- round-trip equivalency.
+--
+-- However, if you enable strictTypes, e.g.
+--
+-- JSON = assert(loadfile "JSON.lua")() --load the routines
+-- JSON.strictTypes = true
+--
+-- then the Lua table resulting from the decoding of a JSON object or
+-- JSON array is marked via Lua metatable, so that when re-encoded with
+-- JSON:encode() it ends up as the appropriate JSON type.
+--
+-- (This is not the default because other routines may not work well with
+-- tables that have a metatable set, for example, Lightroom API calls.)
+--
+--
+-- ENCODING (from a lua table to a JSON string)
+--
+-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
+--
+-- local raw_json_text = JSON:encode(lua_table_or_value)
+-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
+-- local custom_pretty = JSON:encode(lua_table_or_value, etc, { pretty = true, indent = "| ", align_keys = false })
+--
+-- On error during encoding, this code calls:
+--
+-- JSON:onEncodeError(message, etc)
+--
+-- which you can override in your local JSON object.
+--
+-- The 'etc' in the error call is the second argument to encode()
+-- and encode_pretty(), or nil if it wasn't provided.
+--
+--
+-- ENCODING OPTIONS
+--
+-- An optional third argument, a table of options, can be provided to encode().
+--
+-- encode_options = {
+-- -- options for making "pretty" human-readable JSON (see "PRETTY-PRINTING" below)
+-- pretty = true,
+-- indent = " ",
+-- align_keys = false,
+-- array_newline = false,
+--
+-- -- other output-related options
+-- null = "\0", -- see "ENCODING JSON NULL VALUES" below
+-- stringsAreUtf8 = false, -- see "HANDLING UNICODE LINE AND PARAGRAPH SEPARATORS FOR JAVA" below
+-- }
+--
+-- json_string = JSON:encode(mytable, etc, encode_options)
+--
+--
+--
+-- For reference, the defaults are:
+--
+-- pretty = false
+-- null = nil,
+-- stringsAreUtf8 = false,
+-- array_newline = false,
+--
+--
+--
+-- PRETTY-PRINTING
+--
+-- Enabling the 'pretty' encode option helps generate human-readable JSON.
+--
+-- pretty = JSON:encode(val, etc, {
+-- pretty = true,
+-- indent = " ",
+-- align_keys = false,
+-- })
+--
+-- encode_pretty() is also provided: it's identical to encode() except
+-- that encode_pretty() provides a default options table if none given in the call:
+--
+-- { pretty = true, align_keys = false, indent = " " }
+--
+-- For example, if
+--
+-- JSON:encode(data)
+--
+-- produces:
+--
+-- {"city":"Kyoto","climate":{"avg_temp":16,"humidity":"high","snowfall":"minimal"},"country":"Japan","wards":11}
+--
+-- then
+--
+-- JSON:encode_pretty(data)
+--
+-- produces:
+--
+-- {
+-- "city": "Kyoto",
+-- "climate": {
+-- "avg_temp": 16,
+-- "humidity": "high",
+-- "snowfall": "minimal"
+-- },
+-- "country": "Japan",
+-- "wards": 11
+-- }
+--
+-- The following three lines return identical results:
+-- JSON:encode_pretty(data)
+-- JSON:encode_pretty(data, nil, { pretty = true, align_keys = false, indent = " " })
+-- JSON:encode (data, nil, { pretty = true, align_keys = false, indent = " " })
+--
+-- An example of setting your own indent string:
+--
+-- JSON:encode_pretty(data, nil, { pretty = true, indent = "| " })
+--
+-- produces:
+--
+-- {
+-- | "city": "Kyoto",
+-- | "climate": {
+-- | | "avg_temp": 16,
+-- | | "humidity": "high",
+-- | | "snowfall": "minimal"
+-- | },
+-- | "country": "Japan",
+-- | "wards": 11
+-- }
+--
+-- An example of setting align_keys to true:
+--
+-- JSON:encode_pretty(data, nil, { pretty = true, indent = " ", align_keys = true })
+--
+-- produces:
+--
+-- {
+-- "city": "Kyoto",
+-- "climate": {
+-- "avg_temp": 16,
+-- "humidity": "high",
+-- "snowfall": "minimal"
+-- },
+-- "country": "Japan",
+-- "wards": 11
+-- }
+--
+-- which I must admit is kinda ugly, sorry. This was the default for
+-- encode_pretty() prior to version 20141223.14.
+--
+--
+-- HANDLING UNICODE LINE AND PARAGRAPH SEPARATORS FOR JAVA
+--
+-- If the 'stringsAreUtf8' encode option is set to true, consider Lua strings not as a sequence of bytes,
+-- but as a sequence of UTF-8 characters.
+--
+-- Currently, the only practical effect of setting this option is that Unicode LINE and PARAGRAPH
+-- separators, if found in a string, are encoded with a JSON escape instead of being dumped as is.
+-- The JSON is valid either way, but encoding this way, apparently, allows the resulting JSON
+-- to also be valid Java.
+--
+-- AMBIGUOUS SITUATIONS DURING THE ENCODING
+--
+-- During the encode, if a Lua table being encoded contains both string
+-- and numeric keys, it fits neither JSON's idea of an object, nor its
+-- idea of an array. To get around this, when any string key exists (or
+-- when non-positive numeric keys exist), numeric keys are converted to
+-- strings.
+--
+-- For example,
+-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
+-- produces the JSON object
+-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
+--
+-- To prohibit this conversion and instead make it an error condition, set
+-- JSON.noKeyConversion = true
+--
+--
+-- ENCODING JSON NULL VALUES
+--
+-- Lua tables completely omit keys whose value is nil, so without special handling there's
+-- no way to get a field in a JSON object with a null value. For example
+-- JSON:encode({ username = "admin", password = nil })
+-- produces
+-- {"username":"admin"}
+--
+-- In order to actually produce
+-- {"username":"admin", "password":null}
+-- one can include a string value for a "null" field in the options table passed to encode()....
+-- any Lua table entry with that value becomes null in the JSON output:
+-- JSON:encode({ username = "admin", password = "xyzzy" }, nil, { null = "xyzzy" })
+-- produces
+-- {"username":"admin", "password":null}
+--
+-- Just be sure to use a string that is otherwise unlikely to appear in your data.
+-- The string "\0" (a string with one null byte) may well be appropriate for many applications.
+--
+-- The "null" options also applies to Lua tables that become JSON arrays.
+-- JSON:encode({ "one", "two", nil, nil })
+-- produces
+-- ["one","two"]
+-- while
+-- NULL = "\0"
+-- JSON:encode({ "one", "two", NULL, NULL}, nil, { null = NULL })
+-- produces
+-- ["one","two",null,null]
+--
+--
+--
+--
+-- HANDLING LARGE AND/OR PRECISE NUMBERS
+--
+--
+-- Without special handling, numbers in JSON can lose precision in Lua.
+-- For example:
+--
+-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }')
+--
+-- print("small: ", type(T.small), T.small)
+-- print("big: ", type(T.big), T.big)
+-- print("precise: ", type(T.precise), T.precise)
+--
+-- produces
+--
+-- small: number 12345
+-- big: number 1.2345678901235e+28
+-- precise: number 9876.6789012346
+--
+-- Precision is lost with both 'big' and 'precise'.
+--
+-- This package offers ways to try to handle this better (for some definitions of "better")...
+--
+-- The most precise method is by setting the global:
+--
+-- JSON.decodeNumbersAsObjects = true
+--
+-- When this is set, numeric JSON data is encoded into Lua in a form that preserves the exact
+-- JSON numeric presentation when re-encoded back out to JSON, or accessed in Lua as a string.
+--
+-- (This is done by encoding the numeric data with a Lua table/metatable that returns
+-- the possibly-imprecise numeric form when accessed numerically, but the original precise
+-- representation when accessed as a string. You can also explicitly access
+-- via JSON:forceString() and JSON:forceNumber())
+--
+-- Consider the example above, with this option turned on:
+--
+-- JSON.decodeNumbersAsObjects = true
+--
+-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }')
+--
+-- print("small: ", type(T.small), T.small)
+-- print("big: ", type(T.big), T.big)
+-- print("precise: ", type(T.precise), T.precise)
+--
+-- This now produces:
+--
+-- small: table 12345
+-- big: table 12345678901234567890123456789
+-- precise: table 9876.67890123456789012345
+--
+-- However, within Lua you can still use the values (e.g. T.precise in the example above) in numeric
+-- contexts. In such cases you'll get the possibly-imprecise numeric version, but in string contexts
+-- and when the data finds its way to this package's encode() function, the original full-precision
+-- representation is used.
+--
+-- Even without using the JSON.decodeNumbersAsObjects option, you can encode numbers
+-- in your Lua table that retain high precision upon encoding to JSON, by using the JSON:asNumber()
+-- function:
+--
+-- T = {
+-- imprecise = 123456789123456789.123456789123456789,
+-- precise = JSON:asNumber("123456789123456789.123456789123456789")
+-- }
+--
+-- print(JSON:encode_pretty(T))
+--
+-- This produces:
+--
+-- {
+-- "precise": 123456789123456789.123456789123456789,
+-- "imprecise": 1.2345678912346e+17
+-- }
+--
+--
+--
+-- A different way to handle big/precise JSON numbers is to have decode() merely return
+-- the exact string representation of the number instead of the number itself.
+-- This approach might be useful when the numbers are merely some kind of opaque
+-- object identifier and you want to work with them in Lua as strings anyway.
+--
+-- This approach is enabled by setting
+--
+-- JSON.decodeIntegerStringificationLength = 10
+--
+-- The value is the number of digits (of the integer part of the number) at which to stringify numbers.
+--
+-- Consider our previous example with this option set to 10:
+--
+-- JSON.decodeIntegerStringificationLength = 10
+--
+-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }')
+--
+-- print("small: ", type(T.small), T.small)
+-- print("big: ", type(T.big), T.big)
+-- print("precise: ", type(T.precise), T.precise)
+--
+-- This produces:
+--
+-- small: number 12345
+-- big: string 12345678901234567890123456789
+-- precise: number 9876.6789012346
+--
+-- The long integer of the 'big' field is at least JSON.decodeIntegerStringificationLength digits
+-- in length, so it's converted not to a Lua integer but to a Lua string. Using a value of 0 or 1 ensures
+-- that all JSON numeric data becomes strings in Lua.
+--
+-- Note that unlike
+-- JSON.decodeNumbersAsObjects = true
+-- this stringification is simple and unintelligent: the JSON number simply becomes a Lua string, and that's the end of it.
+-- If the string is then converted back to JSON, it's still a string. After running the code above, adding
+-- print(JSON:encode(T))
+-- produces
+-- {"big":"12345678901234567890123456789","precise":9876.6789012346,"small":12345}
+-- which is unlikely to be desired.
+--
+-- There's a comparable option for the length of the decimal part of a number:
+--
+-- JSON.decodeDecimalStringificationLength
+--
+-- This can be used alone or in conjunction with
+--
+-- JSON.decodeIntegerStringificationLength
+--
+-- to trip stringification on precise numbers with at least JSON.decodeIntegerStringificationLength digits after
+-- the decimal point.
+--
+-- This example:
+--
+-- JSON.decodeIntegerStringificationLength = 10
+-- JSON.decodeDecimalStringificationLength = 5
+--
+-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }')
+--
+-- print("small: ", type(T.small), T.small)
+-- print("big: ", type(T.big), T.big)
+-- print("precise: ", type(T.precise), T.precise)
+--
+-- produces:
+--
+-- small: number 12345
+-- big: string 12345678901234567890123456789
+-- precise: string 9876.67890123456789012345
+--
+--
+--
+--
+--
+-- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT
+--
+-- assert
+-- onDecodeError
+-- onDecodeOfNilError
+-- onDecodeOfHTMLError
+-- onTrailingGarbage
+-- onEncodeError
+--
+-- If you want to create a separate Lua JSON object with its own error handlers,
+-- you can reload JSON.lua or use the :new() method.
+--
+---------------------------------------------------------------------------
+
+local default_pretty_indent = " "
+local default_pretty_options = { pretty = true, align_keys = false, indent = default_pretty_indent }
+
+local isArray = { __tostring = function() return "JSON array" end }
+isArray.__index = isArray
+local isObject = { __tostring = function() return "JSON object" end }
+isObject.__index = isObject
+
+function OBJDEF:newArray(tbl)
+ return setmetatable(tbl or {}, isArray)
+end
+
+function OBJDEF:newObject(tbl)
+ return setmetatable(tbl or {}, isObject)
+end
+
+local function getnum(op)
+ return type(op) == 'number' and op or op.N
+end
+
+local isNumber = {
+ __tostring = function(T) return T.S end,
+ __unm = function(op) return getnum(op) end,
+
+ __concat = function(op1, op2) return tostring(op1) .. tostring(op2) end,
+ __add = function(op1, op2) return getnum(op1) + getnum(op2) end,
+ __sub = function(op1, op2) return getnum(op1) - getnum(op2) end,
+ __mul = function(op1, op2) return getnum(op1) * getnum(op2) end,
+ __div = function(op1, op2) return getnum(op1) / getnum(op2) end,
+ __mod = function(op1, op2) return getnum(op1) % getnum(op2) end,
+ __pow = function(op1, op2) return getnum(op1) ^ getnum(op2) end,
+ __lt = function(op1, op2) return getnum(op1) < getnum(op2) end,
+ __eq = function(op1, op2) return getnum(op1) == getnum(op2) end,
+ __le = function(op1, op2) return getnum(op1) <= getnum(op2) end,
+}
+isNumber.__index = isNumber
+
+function OBJDEF:asNumber(item)
+
+ if getmetatable(item) == isNumber then
+ -- it's already a JSON number object.
+ return item
+ elseif type(item) == 'table' and type(item.S) == 'string' and type(item.N) == 'number' then
+ -- it's a number-object table that lost its metatable, so give it one
+ return setmetatable(item, isNumber)
+ else
+ -- the normal situation... given a number or a string representation of a number....
+ local holder = {
+ S = tostring(item), -- S is the representation of the number as a string, which remains precise
+ N = tonumber(item), -- N is the number as a Lua number.
+ }
+ return setmetatable(holder, isNumber)
+ end
+end
+
+--
+-- Given an item that might be a normal string or number, or might be an 'isNumber' object defined above,
+-- return the string version. This shouldn't be needed often because the 'isNumber' object should autoconvert
+-- to a string in most cases, but it's here to allow it to be forced when needed.
+--
+function OBJDEF:forceString(item)
+ if type(item) == 'table' and type(item.S) == 'string' then
+ return item.S
+ else
+ return tostring(item)
+ end
+end
+
+--
+-- Given an item that might be a normal string or number, or might be an 'isNumber' object defined above,
+-- return the numeric version.
+--
+function OBJDEF:forceNumber(item)
+ if type(item) == 'table' and type(item.N) == 'number' then
+ return item.N
+ else
+ return tonumber(item)
+ end
+end
+
+local function unicode_codepoint_as_utf8(codepoint)
+ --
+ -- codepoint is a number
+ --
+ if codepoint <= 127 then
+ return string.char(codepoint)
+
+ elseif codepoint <= 2047 then
+ --
+ -- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8
+ --
+ local highpart = math.floor(codepoint / 0x40)
+ local lowpart = codepoint - (0x40 * highpart)
+ return string.char(0xC0 + highpart,
+ 0x80 + lowpart)
+
+ elseif codepoint <= 65535 then
+ --
+ -- 1110yyyy 10yyyyxx 10xxxxxx
+ --
+ local highpart = math.floor(codepoint / 0x1000)
+ local remainder = codepoint - 0x1000 * highpart
+ local midpart = math.floor(remainder / 0x40)
+ local lowpart = remainder - 0x40 * midpart
+
+ highpart = 0xE0 + highpart
+ midpart = 0x80 + midpart
+ lowpart = 0x80 + lowpart
+
+ --
+ -- Check for an invalid character (thanks Andy R. at Adobe).
+ -- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070
+ --
+ if (highpart == 0xE0 and midpart < 0xA0) or
+ (highpart == 0xED and midpart > 0x9F) or
+ (highpart == 0xF0 and midpart < 0x90) or
+ (highpart == 0xF4 and midpart > 0x8F)
+ then
+ return "?"
+ else
+ return string.char(highpart,
+ midpart,
+ lowpart)
+ end
+
+ else
+ --
+ -- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
+ --
+ local highpart = math.floor(codepoint / 0x40000)
+ local remainder = codepoint - 0x40000 * highpart
+ local midA = math.floor(remainder / 0x1000)
+ remainder = remainder - 0x1000 * midA
+ local midB = math.floor(remainder / 0x40)
+ local lowpart = remainder - 0x40 * midB
+
+ return string.char(0xF0 + highpart,
+ 0x80 + midA,
+ 0x80 + midB,
+ 0x80 + lowpart)
+ end
+end
+
+function OBJDEF:onDecodeError(message, text, location, etc)
+ if text then
+ if location then
+ message = string.format("%s at byte %d of: %s", message, location, text)
+ else
+ message = string.format("%s: %s", message, text)
+ end
+ end
+
+ if etc ~= nil then
+ message = message .. " (" .. OBJDEF:encode(etc) .. ")"
+ end
+
+ if self.assert then
+ self.assert(false, message)
+ else
+ assert(false, message)
+ end
+end
+
+function OBJDEF:onTrailingGarbage(json_text, location, parsed_value, etc)
+ return self:onDecodeError("trailing garbage", json_text, location, etc)
+end
+
+OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError
+OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError
+
+function OBJDEF:onEncodeError(message, etc)
+ if etc ~= nil then
+ message = message .. " (" .. OBJDEF:encode(etc) .. ")"
+ end
+
+ if self.assert then
+ self.assert(false, message)
+ else
+ assert(false, message)
+ end
+end
+
+local function grok_number(self, text, start, options)
+ --
+ -- Grab the integer part
+ --
+ local integer_part = text:match('^-?[1-9]%d*', start)
+ or text:match("^-?0", start)
+
+ if not integer_part then
+ self:onDecodeError("expected number", text, start, options.etc)
+ return nil, start -- in case the error method doesn't abort, return something sensible
+ end
+
+ local i = start + integer_part:len()
+
+ --
+ -- Grab an optional decimal part
+ --
+ local decimal_part = text:match('^%.%d+', i) or ""
+
+ i = i + decimal_part:len()
+
+ --
+ -- Grab an optional exponential part
+ --
+ local exponent_part = text:match('^[eE][-+]?%d+', i) or ""
+
+ i = i + exponent_part:len()
+
+ local full_number_text = integer_part .. decimal_part .. exponent_part
+
+ if options.decodeNumbersAsObjects then
+ return OBJDEF:asNumber(full_number_text), i
+ end
+
+ --
+ -- If we're told to stringify under certain conditions, so do.
+ -- We punt a bit when there's an exponent by just stringifying no matter what.
+ -- I suppose we should really look to see whether the exponent is actually big enough one
+ -- way or the other to trip stringification, but I'll be lazy about it until someone asks.
+ --
+ if (options.decodeIntegerStringificationLength
+ and
+ (integer_part:len() >= options.decodeIntegerStringificationLength or exponent_part:len() > 0))
+
+ or
+
+ (options.decodeDecimalStringificationLength
+ and
+ (decimal_part:len() >= options.decodeDecimalStringificationLength or exponent_part:len() > 0))
+ then
+ return full_number_text, i -- this returns the exact string representation seen in the original JSON
+ end
+
+
+
+ local as_number = tonumber(full_number_text)
+
+ if not as_number then
+ self:onDecodeError("bad number", text, start, options.etc)
+ return nil, start -- in case the error method doesn't abort, return something sensible
+ end
+
+ return as_number, i
+end
+
+local function grok_string(self, text, start, options)
+
+ if text:sub(start, start) ~= '"' then
+ self:onDecodeError("expected string's opening quote", text, start, options.etc)
+ return nil, start -- in case the error method doesn't abort, return something sensible
+ end
+
+ local i = start + 1 -- +1 to bypass the initial quote
+ local text_len = text:len()
+ local VALUE = ""
+ while i <= text_len do
+ local c = text:sub(i, i)
+ if c == '"' then
+ return VALUE, i + 1
+ end
+ if c ~= '\\' then
+ VALUE = VALUE .. c
+ i = i + 1
+ elseif text:match('^\\b', i) then
+ VALUE = VALUE .. "\b"
+ i = i + 2
+ elseif text:match('^\\f', i) then
+ VALUE = VALUE .. "\f"
+ i = i + 2
+ elseif text:match('^\\n', i) then
+ VALUE = VALUE .. "\n"
+ i = i + 2
+ elseif text:match('^\\r', i) then
+ VALUE = VALUE .. "\r"
+ i = i + 2
+ elseif text:match('^\\t', i) then
+ VALUE = VALUE .. "\t"
+ i = i + 2
+ else
+ local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
+ if hex then
+ i = i + 6 -- bypass what we just read
+
+ -- We have a Unicode codepoint. It could be standalone, or if in the proper range and
+ -- followed by another in a specific range, it'll be a two-code surrogate pair.
+ local codepoint = tonumber(hex, 16)
+ if codepoint >= 0xD800 and codepoint <= 0xDBFF then
+ -- it's a hi surrogate... see whether we have a following low
+ local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
+ if lo_surrogate then
+ i = i + 6 -- bypass the low surrogate we just read
+ codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16)
+ else
+ -- not a proper low, so we'll just leave the first codepoint as is and spit it out.
+ end
+ end
+ VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint)
+
+ else
+
+ -- just pass through what's escaped
+ VALUE = VALUE .. text:match('^\\(.)', i)
+ i = i + 2
+ end
+ end
+ end
+
+ self:onDecodeError("unclosed string", text, start, options.etc)
+ return nil, start -- in case the error method doesn't abort, return something sensible
+end
+
+local function skip_whitespace(text, start)
+
+ local _, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2
+ if match_end then
+ return match_end + 1
+ else
+ return start
+ end
+end
+
+local grok_one -- assigned later
+
+local function grok_object(self, text, start, options)
+
+ if text:sub(start, start) ~= '{' then
+ self:onDecodeError("expected '{'", text, start, options.etc)
+ return nil, start -- in case the error method doesn't abort, return something sensible
+ end
+
+ local i = skip_whitespace(text, start + 1) -- +1 to skip the '{'
+
+ local VALUE = self.strictTypes and self:newObject {} or {}
+
+ if text:sub(i, i) == '}' then
+ return VALUE, i + 1
+ end
+ local text_len = text:len()
+ while i <= text_len do
+ local key, new_i = grok_string(self, text, i, options)
+
+ i = skip_whitespace(text, new_i)
+
+ if text:sub(i, i) ~= ':' then
+ self:onDecodeError("expected colon", text, i, options.etc)
+ return nil, i -- in case the error method doesn't abort, return something sensible
+ end
+
+ i = skip_whitespace(text, i + 1)
+
+ local new_val, new_i = grok_one(self, text, i, options)
+
+ VALUE[key] = new_val
+
+ --
+ -- Expect now either '}' to end things, or a ',' to allow us to continue.
+ --
+ i = skip_whitespace(text, new_i)
+
+ local c = text:sub(i, i)
+
+ if c == '}' then
+ return VALUE, i + 1
+ end
+
+ if text:sub(i, i) ~= ',' then
+ self:onDecodeError("expected comma or '}'", text, i, options.etc)
+ return nil, i -- in case the error method doesn't abort, return something sensible
+ end
+
+ i = skip_whitespace(text, i + 1)
+ end
+
+ self:onDecodeError("unclosed '{'", text, start, options.etc)
+ return nil, start -- in case the error method doesn't abort, return something sensible
+end
+
+local function grok_array(self, text, start, options)
+ if text:sub(start, start) ~= '[' then
+ self:onDecodeError("expected '['", text, start, options.etc)
+ return nil, start -- in case the error method doesn't abort, return something sensible
+ end
+
+ local i = skip_whitespace(text, start + 1) -- +1 to skip the '['
+ local VALUE = self.strictTypes and self:newArray {} or {}
+ if text:sub(i, i) == ']' then
+ return VALUE, i + 1
+ end
+
+ local VALUE_INDEX = 1
+
+ local text_len = text:len()
+ while i <= text_len do
+ local val, new_i = grok_one(self, text, i, options)
+
+ -- can't table.insert(VALUE, val) here because it's a no-op if val is nil
+ VALUE[VALUE_INDEX] = val
+ VALUE_INDEX = VALUE_INDEX + 1
+
+ i = skip_whitespace(text, new_i)
+
+ --
+ -- Expect now either ']' to end things, or a ',' to allow us to continue.
+ --
+ local c = text:sub(i, i)
+ if c == ']' then
+ return VALUE, i + 1
+ end
+ if text:sub(i, i) ~= ',' then
+ self:onDecodeError("expected comma or ']'", text, i, options.etc)
+ return nil, i -- in case the error method doesn't abort, return something sensible
+ end
+ i = skip_whitespace(text, i + 1)
+ end
+ self:onDecodeError("unclosed '['", text, start, options.etc)
+ return nil, i -- in case the error method doesn't abort, return something sensible
+end
+
+grok_one = function(self, text, start, options)
+ -- Skip any whitespace
+ start = skip_whitespace(text, start)
+
+ if start > text:len() then
+ self:onDecodeError("unexpected end of string", text, nil, options.etc)
+ return nil, start -- in case the error method doesn't abort, return something sensible
+ end
+
+ if text:find('^"', start) then
+ return grok_string(self, text, start, options.etc)
+
+ elseif text:find('^[-0123456789 ]', start) then
+ return grok_number(self, text, start, options)
+
+ elseif text:find('^%{', start) then
+ return grok_object(self, text, start, options)
+
+ elseif text:find('^%[', start) then
+ return grok_array(self, text, start, options)
+
+ elseif text:find('^true', start) then
+ return true, start + 4
+
+ elseif text:find('^false', start) then
+ return false, start + 5
+
+ elseif text:find('^null', start) then
+ return nil, start + 4
+
+ else
+ self:onDecodeError("can't parse JSON", text, start, options.etc)
+ return nil, 1 -- in case the error method doesn't abort, return something sensible
+ end
+end
+
+function OBJDEF:decode(text, etc, options)
+ --
+ -- If the user didn't pass in a table of decode options, make an empty one.
+ --
+ if type(options) ~= 'table' then
+ options = {}
+ end
+
+ --
+ -- If they passed in an 'etc' argument, stuff it into the options.
+ -- (If not, any 'etc' field in the options they passed in remains to be used)
+ --
+ if etc ~= nil then
+ options.etc = etc
+ end
+
+
+ if type(self) ~= 'table' or self.__index ~= OBJDEF then
+ local error_message = "JSON:decode must be called in method format"
+ OBJDEF:onDecodeError(error_message, nil, nil, options.etc)
+ return nil, error_message -- in case the error method doesn't abort, return something sensible
+ end
+
+ if text == nil then
+ local error_message = "nil passed to JSON:decode()"
+ self:onDecodeOfNilError(error_message, nil, nil, options.etc)
+ return nil, error_message -- in case the error method doesn't abort, return something sensible
+
+ elseif type(text) ~= 'string' then
+ local error_message = "expected string argument to JSON:decode()"
+ self:onDecodeError(string.format("%s, got %s", error_message, type(text)), nil, nil, options.etc)
+ return nil, error_message -- in case the error method doesn't abort, return something sensible
+ end
+
+ if text:match('^%s*$') then
+ -- an empty string is nothing, but not an error
+ return nil
+ end
+
+ if text:match('^%s*<') then
+ -- Can't be JSON... we'll assume it's HTML
+ local error_message = "HTML passed to JSON:decode()"
+ self:onDecodeOfHTMLError(error_message, text, nil, options.etc)
+ return nil, error_message -- in case the error method doesn't abort, return something sensible
+ end
+
+ --
+ -- Ensure that it's not UTF-32 or UTF-16.
+ -- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3),
+ -- but this package can't handle them.
+ --
+ if text:sub(1, 1):byte() == 0 or (text:len() >= 2 and text:sub(2, 2):byte() == 0) then
+ local error_message = "JSON package groks only UTF-8, sorry"
+ self:onDecodeError(error_message, text, nil, options.etc)
+ return nil, error_message -- in case the error method doesn't abort, return something sensible
+ end
+
+ --
+ -- apply global options
+ --
+ if options.decodeNumbersAsObjects == nil then
+ options.decodeNumbersAsObjects = self.decodeNumbersAsObjects
+ end
+ if options.decodeIntegerStringificationLength == nil then
+ options.decodeIntegerStringificationLength = self.decodeIntegerStringificationLength
+ end
+ if options.decodeDecimalStringificationLength == nil then
+ options.decodeDecimalStringificationLength = self.decodeDecimalStringificationLength
+ end
+
+ --
+ -- Finally, go parse it
+ --
+ local success, value, next_i = pcall(grok_one, self, text, 1, options)
+
+ if success then
+
+ local error_message = nil
+ if next_i ~= #text + 1 then
+ -- something's left over after we parsed the first thing.... whitespace is allowed.
+ next_i = skip_whitespace(text, next_i)
+
+ -- if we have something left over now, it's trailing garbage
+ if next_i ~= #text + 1 then
+ value, error_message = self:onTrailingGarbage(text, next_i, value, options.etc)
+ end
+ end
+ return value, error_message
+
+ else
+
+ -- If JSON:onDecodeError() didn't abort out of the pcall, we'll have received
+ -- the error message here as "value", so pass it along as an assert.
+ local error_message = value
+ if self.assert then
+ self.assert(false, error_message)
+ else
+ assert(false, error_message)
+ end
+ -- ...and if we're still here (because the assert didn't throw an error),
+ -- return a nil and throw the error message on as a second arg
+ return nil, error_message
+
+ end
+end
+
+local function backslash_replacement_function(c)
+ if c == "\n" then
+ return "\\n"
+ elseif c == "\r" then
+ return "\\r"
+ elseif c == "\t" then
+ return "\\t"
+ elseif c == "\b" then
+ return "\\b"
+ elseif c == "\f" then
+ return "\\f"
+ elseif c == '"' then
+ return '\\"'
+ elseif c == '\\' then
+ return '\\\\'
+ else
+ return string.format("\\u%04x", c:byte())
+ end
+end
+
+local chars_to_be_escaped_in_JSON_string = '['
+ .. '"' -- class sub-pattern to match a double quote
+ .. '%\\' -- class sub-pattern to match a backslash
+ .. '%z' -- class sub-pattern to match a null
+ .. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters
+ .. ']'
+
+
+local LINE_SEPARATOR_as_utf8 = unicode_codepoint_as_utf8(0x2028)
+local PARAGRAPH_SEPARATOR_as_utf8 = unicode_codepoint_as_utf8(0x2029)
+local function json_string_literal(value, options)
+ local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function)
+ if options.stringsAreUtf8 then
+ --
+ -- This feels really ugly to just look into a string for the sequence of bytes that we know to be a particular utf8 character,
+ -- but utf8 was designed purposefully to make this kind of thing possible. Still, feels dirty.
+ -- I'd rather decode the byte stream into a character stream, but it's not technically needed so
+ -- not technically worth it.
+ --
+ newval = newval:gsub(LINE_SEPARATOR_as_utf8, '\\u2028'):gsub(PARAGRAPH_SEPARATOR_as_utf8, '\\u2029')
+ end
+ return '"' .. newval .. '"'
+end
+
+local function object_or_array(self, T, etc)
+ --
+ -- We need to inspect all the keys... if there are any strings, we'll convert to a JSON
+ -- object. If there are only numbers, it's a JSON array.
+ --
+ -- If we'll be converting to a JSON object, we'll want to sort the keys so that the
+ -- end result is deterministic.
+ --
+ local string_keys = {}
+ local number_keys = {}
+ local number_keys_must_be_strings = false
+ local maximum_number_key
+
+ for key in pairs(T) do
+ if type(key) == 'string' then
+ table.insert(string_keys, key)
+ elseif type(key) == 'number' then
+ table.insert(number_keys, key)
+ if key <= 0 or key >= math.huge then
+ number_keys_must_be_strings = true
+ elseif not maximum_number_key or key > maximum_number_key then
+ maximum_number_key = key
+ end
+ else
+ self:onEncodeError("can't encode table with a key of type " .. type(key), etc)
+ end
+ end
+
+ if #string_keys == 0 and not number_keys_must_be_strings then
+ --
+ -- An empty table, or a numeric-only array
+ --
+ if #number_keys > 0 then
+ return nil, maximum_number_key -- an array
+ elseif tostring(T) == "JSON array" then
+ return nil
+ elseif tostring(T) == "JSON object" then
+ return {}
+ else
+ -- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects
+ return nil
+ end
+ end
+
+ table.sort(string_keys)
+
+ local map
+ if #number_keys > 0 then
+ --
+ -- If we're here then we have either mixed string/number keys, or numbers inappropriate for a JSON array
+ -- It's not ideal, but we'll turn the numbers into strings so that we can at least create a JSON object.
+ --
+
+ if self.noKeyConversion then
+ self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc)
+ end
+
+ --
+ -- Have to make a shallow copy of the source table so we can remap the numeric keys to be strings
+ --
+ map = {}
+ for key, val in pairs(T) do
+ map[key] = val
+ end
+
+ table.sort(number_keys)
+
+ --
+ -- Throw numeric keys in there as strings
+ --
+ for _, number_key in ipairs(number_keys) do
+ local string_key = tostring(number_key)
+ if map[string_key] == nil then
+ table.insert(string_keys, string_key)
+ map[string_key] = T[number_key]
+ else
+ self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc)
+ end
+ end
+ end
+
+ return string_keys, nil, map
+end
+
+--
+-- Encode
+--
+-- 'options' is nil, or a table with possible keys:
+--
+-- pretty -- If true, return a pretty-printed version.
+--
+-- indent -- A string (usually of spaces) used to indent each nested level.
+--
+-- align_keys -- If true, align all the keys when formatting a table.
+--
+-- null -- If this exists with a string value, table elements with this value are output as JSON null.
+--
+-- stringsAreUtf8 -- If true, consider Lua strings not as a sequence of bytes, but as a sequence of UTF-8 characters.
+-- (Currently, the only practical effect of setting this option is that Unicode LINE and PARAGRAPH
+-- separators, if found in a string, are encoded with a JSON escape instead of as raw UTF-8.
+-- The JSON is valid either way, but encoding this way, apparently, allows the resulting JSON
+-- to also be valid Java.)
+--
+--
+local encode_value -- must predeclare because it calls itself
+function encode_value(self, value, parents, etc, options, indent, for_key)
+
+ --
+ -- keys in a JSON object can never be null, so we don't even consider options.null when converting a key value
+ --
+ if value == nil or (not for_key and options and options.null and value == options.null) then
+ return 'null'
+
+ elseif type(value) == 'string' then
+ return json_string_literal(value, options)
+
+ elseif type(value) == 'number' then
+ if value ~= value then
+ --
+ -- NaN (Not a Number).
+ -- JSON has no NaN, so we have to fudge the best we can. This should really be a package option.
+ --
+ return "null"
+ elseif value >= math.huge then
+ --
+ -- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should
+ -- really be a package option. Note: at least with some implementations, positive infinity
+ -- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is.
+ -- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">="
+ -- case first.
+ --
+ return "1e+9999"
+ elseif value <= -math.huge then
+ --
+ -- Negative infinity.
+ -- JSON has no INF, so we have to fudge the best we can. This should really be a package option.
+ --
+ return "-1e+9999"
+ else
+ return tostring(value)
+ end
+
+ elseif type(value) == 'boolean' then
+ return tostring(value)
+
+ elseif type(value) ~= 'table' then
+ self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc)
+
+ elseif getmetatable(value) == isNumber then
+ return tostring(value)
+ else
+ --
+ -- A table to be converted to either a JSON object or array.
+ --
+ local T = value
+
+ if type(options) ~= 'table' then
+ options = {}
+ end
+ if type(indent) ~= 'string' then
+ indent = ""
+ end
+
+ if parents[T] then
+ self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc)
+ else
+ parents[T] = true
+ end
+
+ local result_value
+
+ local object_keys, maximum_number_key, map = object_or_array(self, T, etc)
+ if maximum_number_key then
+ --
+ -- An array...
+ --
+ local ITEMS = {}
+ local key_indent = indent .. tostring(options.indent or "")
+ for i = 1, maximum_number_key do
+ if not options.array_newline then
+ table.insert(ITEMS, encode_value(self, T[i], parents, etc, options, indent))
+ else
+ table.insert(ITEMS, encode_value(self, T[i], parents, etc, options, key_indent))
+ end
+ end
+
+ if options.pretty then
+ if not options.array_newline then
+ result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]"
+ else
+ result_value = "[\n" .. key_indent .. table.concat(ITEMS, ",\n" .. key_indent) .. "\n" .. indent .. "]"
+ end
+ else
+ result_value = "[" .. table.concat(ITEMS, ",") .. "]"
+ end
+
+ elseif object_keys then
+ --
+ -- An object
+ --
+ local TT = map or T
+
+ if options.pretty then
+
+ local KEYS = {}
+ local max_key_length = 0
+ for _, key in ipairs(object_keys) do
+ local encoded = encode_value(self, tostring(key), parents, etc, options, indent, true)
+ if options.align_keys then
+ max_key_length = math.max(max_key_length, #encoded)
+ end
+ table.insert(KEYS, encoded)
+ end
+ local key_indent = indent .. tostring(options.indent or "")
+ local subtable_indent = key_indent .. string.rep(" ", max_key_length) .. (options.align_keys and " " or "")
+ local FORMAT = "%s%" .. string.format("%d", max_key_length) .. "s: %s"
+
+ local COMBINED_PARTS = {}
+ for i, key in ipairs(object_keys) do
+ local encoded_val = encode_value(self, TT[key], parents, etc, options, subtable_indent)
+ table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val))
+ end
+ result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}"
+
+ else
+
+ local PARTS = {}
+ for _, key in ipairs(object_keys) do
+ local encoded_val = encode_value(self, TT[key], parents, etc, options, indent)
+ local encoded_key = encode_value(self, tostring(key), parents, etc, options, indent, true)
+ table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val))
+ end
+ result_value = "{" .. table.concat(PARTS, ",") .. "}"
+
+ end
+ else
+ --
+ -- An empty array/object... we'll treat it as an array, though it should really be an option
+ --
+ result_value = "[]"
+ end
+
+ parents[T] = false
+ return result_value
+ end
+end
+
+local function top_level_encode(self, value, etc, options)
+ local val = encode_value(self, value, {}, etc, options)
+ if val == nil then
+ --PRIVATE("may need to revert to the previous public verison if I can't figure out what the guy wanted")
+ return val
+ else
+ return val
+ end
+end
+
+function OBJDEF:encode(value, etc, options)
+ if type(self) ~= 'table' or self.__index ~= OBJDEF then
+ OBJDEF:onEncodeError("JSON:encode must be called in method format", etc)
+ end
+
+ --
+ -- If the user didn't pass in a table of decode options, make an empty one.
+ --
+ if type(options) ~= 'table' then
+ options = {}
+ end
+
+ return top_level_encode(self, value, etc, options)
+end
+
+function OBJDEF:encode_pretty(value, etc, options)
+ if type(self) ~= 'table' or self.__index ~= OBJDEF then
+ OBJDEF:onEncodeError("JSON:encode_pretty must be called in method format", etc)
+ end
+
+ --
+ -- If the user didn't pass in a table of decode options, use the default pretty ones
+ --
+ if type(options) ~= 'table' then
+ options = default_pretty_options
+ end
+
+ return top_level_encode(self, value, etc, options)
+end
+
+function OBJDEF.__tostring()
+ return "JSON encode/decode package"
+end
+
+OBJDEF.__index = OBJDEF
+
+function OBJDEF:new(args)
+ local new = {}
+
+ if args then
+ for key, val in pairs(args) do
+ new[key] = val
+ end
+ end
+
+ return setmetatable(new, OBJDEF)
+end
+
+return OBJDEF:new()
+
+--
+-- Version history:
+--
+-- 20161109.21 Oops, had a small boo-boo in the previous update.
+--
+-- 20161103.20 Used to silently ignore trailing garbage when decoding. Now fails via JSON:onTrailingGarbage()
+-- http://seriot.ch/parsing_json.php
+--
+-- Built-in error message about "expected comma or ']'" had mistakenly referred to '['
+--
+-- Updated the built-in error reporting to refer to bytes rather than characters.
+--
+-- The decode() method no longer assumes that error handlers abort.
+--
+-- Made the VERSION string a string instead of a number
+--
+
+-- 20160916.19 Fixed the isNumber.__index assignment (thanks to Jack Taylor)
+--
+-- 20160730.18 Added JSON:forceString() and JSON:forceNumber()
+--
+-- 20160728.17 Added concatenation to the metatable for JSON:asNumber()
+--
+-- 20160709.16 Could crash if not passed an options table (thanks jarno heikkinen ).
+--
+-- Made JSON:asNumber() a bit more resilient to being passed the results of itself.
+--
+-- 20160526.15 Added the ability to easily encode null values in JSON, via the new "null" encoding option.
+-- (Thanks to Adam B for bringing up the issue.)
+--
+-- Added some support for very large numbers and precise floats via
+-- JSON.decodeNumbersAsObjects
+-- JSON.decodeIntegerStringificationLength
+-- JSON.decodeDecimalStringificationLength
+--
+-- Added the "stringsAreUtf8" encoding option. (Hat tip to http://lua-users.org/wiki/JsonModules )
+--
+-- 20141223.14 The encode_pretty() routine produced fine results for small datasets, but isn't really
+-- appropriate for anything large, so with help from Alex Aulbach I've made the encode routines
+-- more flexible, and changed the default encode_pretty() to be more generally useful.
+--
+-- Added a third 'options' argument to the encode() and encode_pretty() routines, to control
+-- how the encoding takes place.
+--
+-- Updated docs to add assert() call to the loadfile() line, just as good practice so that
+-- if there is a problem loading JSON.lua, the appropriate error message will percolate up.
+--
+-- 20140920.13 Put back (in a way that doesn't cause warnings about unused variables) the author string,
+-- so that the source of the package, and its version number, are visible in compiled copies.
+--
+-- 20140911.12 Minor lua cleanup.
+-- Fixed internal reference to 'JSON.noKeyConversion' to reference 'self' instead of 'JSON'.
+-- (Thanks to SmugMug's David Parry for these.)
+--
+-- 20140418.11 JSON nulls embedded within an array were being ignored, such that
+-- ["1",null,null,null,null,null,"seven"],
+-- would return
+-- {1,"seven"}
+-- It's now fixed to properly return
+-- {1, nil, nil, nil, nil, nil, "seven"}
+-- Thanks to "haddock" for catching the error.
+--
+-- 20140116.10 The user's JSON.assert() wasn't always being used. Thanks to "blue" for the heads up.
+--
+-- 20131118.9 Update for Lua 5.3... it seems that tostring(2/1) produces "2.0" instead of "2",
+-- and this caused some problems.
+--
+-- 20131031.8 Unified the code for encode() and encode_pretty(); they had been stupidly separate,
+-- and had of course diverged (encode_pretty didn't get the fixes that encode got, so
+-- sometimes produced incorrect results; thanks to Mattie for the heads up).
+--
+-- Handle encoding tables with non-positive numeric keys (unlikely, but possible).
+--
+-- If a table has both numeric and string keys, or its numeric keys are inappropriate
+-- (such as being non-positive or infinite), the numeric keys are turned into
+-- string keys appropriate for a JSON object. So, as before,
+-- JSON:encode({ "one", "two", "three" })
+-- produces the array
+-- ["one","two","three"]
+-- but now something with mixed key types like
+-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
+-- instead of throwing an error produces an object:
+-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
+--
+-- To maintain the prior throw-an-error semantics, set
+-- JSON.noKeyConversion = true
+--
+-- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry.
+--
+-- 20130120.6 Comment update: added a link to the specific page on my blog where this code can
+-- be found, so that folks who come across the code outside of my blog can find updates
+-- more easily.
+--
+-- 20111207.5 Added support for the 'etc' arguments, for better error reporting.
+--
+-- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent.
+--
+-- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules:
+--
+-- * When encoding lua for JSON, Sparse numeric arrays are now handled by
+-- spitting out full arrays, such that
+-- JSON:encode({"one", "two", [10] = "ten"})
+-- returns
+-- ["one","two",null,null,null,null,null,null,null,"ten"]
+--
+-- In 20100810.2 and earlier, only up to the first non-null value would have been retained.
+--
+-- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999".
+-- Version 20100810.2 and earlier created invalid JSON in both cases.
+--
+-- * Unicode surrogate pairs are now detected when decoding JSON.
+--
+-- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding
+--
+-- 20100731.1 initial public release
+--
diff --git a/awesome/src/lib/rubato b/awesome/src/lib/rubato
new file mode 160000
index 0000000..7ed12e1
--- /dev/null
+++ b/awesome/src/lib/rubato
@@ -0,0 +1 @@
+Subproject commit 7ed12e183583a7ce3b59714452217af9a1f02ce6
diff --git a/awesome/src/modules/brightness_osd.lua b/awesome/src/modules/brightness_osd.lua
index 728eef1..d90730b 100644
--- a/awesome/src/modules/brightness_osd.lua
+++ b/awesome/src/modules/brightness_osd.lua
@@ -17,10 +17,10 @@ BACKLIGHT_SEPS = 0
awful.spawn.easy_async_with_shell(
"pkexec xfpm-power-backlight-helper --get-max-brightness",
function(stdout)
- BACKLIGHT_MAX_BRIGHTNESS = tonumber(stdout)
- BACKLIGHT_SEPS = BACKLIGHT_MAX_BRIGHTNESS / 100
- BACKLIGHT_SEPS = math.floor(BACKLIGHT_SEPS)
-end
+ BACKLIGHT_MAX_BRIGHTNESS = tonumber(stdout)
+ BACKLIGHT_SEPS = BACKLIGHT_MAX_BRIGHTNESS / 100
+ BACKLIGHT_SEPS = math.floor(BACKLIGHT_SEPS)
+ end
)
return function(s)
@@ -112,60 +112,61 @@ return function(s)
brightness_osd_widget.container.osd_layout.icon_slider_layout.slider_layout.brightness_slider:connect_signal(
"property::value",
function()
- awful.spawn.easy_async_with_shell(
- "pkexec xfpm-power-backlight-helper --get-brightness",
- function(stdout)
- local brightness_value = math.floor((tonumber(stdout) - 1) / (BACKLIGHT_MAX_BRIGHTNESS - 1) * 100)
- brightness_osd_widget.container.osd_layout.icon_slider_layout.label_value_layout.value:set_text(tostring(brightness_value) .. "%")
+ awful.spawn.easy_async_with_shell(
+ "pkexec xfpm-power-backlight-helper --get-brightness",
+ function(stdout)
+ local brightness_value = math.floor((tonumber(stdout) - 1) / (BACKLIGHT_MAX_BRIGHTNESS - 1) * 100)
+ brightness_osd_widget.container.osd_layout.icon_slider_layout.label_value_layout.value:set_text(tostring(brightness_value) .. "%")
- awesome.emit_signal(
- "widget::brightness:update",
- brightness_value
+ awesome.emit_signal(
+ "widget::brightness:update",
+ brightness_value
+ )
+
+ if awful.screen.focused().show_brightness_osd then
+ awesome.emit_signal(
+ "module::brightness_osd:show",
+ true
+ )
+ end
+
+ local icon = icondir .. "brightness"
+ if brightness_value >= 0 and brightness_value < 34 then
+ icon = icon .. "-low"
+ elseif brightness_value >= 34 and brightness_value < 67 then
+ icon = icon .. "-medium"
+ elseif brightness_value >= 67 then
+ icon = icon .. "-high"
+ end
+ brightness_osd_widget.container.osd_layout.icon_slider_layout.icon_margin1.icon_margin2.icon:set_image(icon .. ".svg")
+ awesome.emit_signal("update::backlight_widget", brightness_value, icon .. ".svg")
+ end
)
-
- if awful.screen.focused().show_brightness_osd then
- awesome.emit_signal(
- "module::brightness_osd:show",
- true
- )
- end
-
- local icon = icondir .. "brightness"
- if brightness_value >= 0 and brightness_value < 34 then
- icon = icon .. "-low"
- elseif brightness_value >= 34 and brightness_value < 67 then
- icon = icon .. "-medium"
- elseif brightness_value >= 67 then
- icon = icon .. "-high"
- end
- brightness_osd_widget.container.osd_layout.icon_slider_layout.icon_margin1.icon_margin2.icon:set_image(icon .. ".svg")
end
- )
- end
)
local update_slider = function()
awful.spawn.easy_async_with_shell(
[[ pkexec xfpm-power-backlight-helper --get-brightness ]],
function(stdout)
- stdout = math.floor((tonumber(stdout) - 1) / (BACKLIGHT_MAX_BRIGHTNESS - 1) * 100)
- brightness_osd_widget.container.osd_layout.icon_slider_layout.slider_layout.brightness_slider:set_value(stdout)
- end
+ stdout = math.floor((tonumber(stdout) - 1) / (BACKLIGHT_MAX_BRIGHTNESS - 1) * 100)
+ brightness_osd_widget.container.osd_layout.icon_slider_layout.slider_layout.brightness_slider:set_value(stdout)
+ end
)
end
awesome.connect_signal(
"module::brightness_slider:update",
function()
- update_slider()
- end
+ update_slider()
+ end
)
awesome.connect_signal(
"widget::brightness:update",
function(value)
- brightness_osd_widget.container.osd_layout.icon_slider_layout.slider_layout.brightness_slider:set_value(tonumber(value))
- end
+ brightness_osd_widget.container.osd_layout.icon_slider_layout.slider_layout.brightness_slider:set_value(tonumber(value))
+ end
)
update_slider()
@@ -199,36 +200,36 @@ return function(s)
awesome.connect_signal(
"widget::brightness_osd:rerun",
function()
- if hide_brightness_osd.started then
- hide_brightness_osd:again()
- else
- hide_brightness_osd:start()
+ if hide_brightness_osd.started then
+ hide_brightness_osd:again()
+ else
+ hide_brightness_osd:start()
+ end
end
- end
)
awesome.connect_signal(
"module::brightness_osd:show",
function()
- if s == mouse.screen then
- brightness_container.visible = true
+ if s == mouse.screen then
+ brightness_container.visible = true
+ end
end
- end
)
brightness_container:connect_signal(
"mouse::enter",
function()
- brightness_container.visible = true
- hide_brightness_osd:stop()
- end
+ brightness_container.visible = true
+ hide_brightness_osd:stop()
+ end
)
brightness_container:connect_signal(
"mouse::leave",
function()
- brightness_container.visible = true
- hide_brightness_osd:again()
- end
+ brightness_container.visible = true
+ hide_brightness_osd:again()
+ end
)
end
diff --git a/awesome/crylia_bar/center_bar.lua b/awesome/src/modules/crylia_bar/center_bar.lua
similarity index 100%
rename from awesome/crylia_bar/center_bar.lua
rename to awesome/src/modules/crylia_bar/center_bar.lua
diff --git a/awesome/crylia_bar/dock.lua b/awesome/src/modules/crylia_bar/dock.lua
similarity index 100%
rename from awesome/crylia_bar/dock.lua
rename to awesome/src/modules/crylia_bar/dock.lua
diff --git a/awesome/src/modules/crylia_bar/init.lua b/awesome/src/modules/crylia_bar/init.lua
new file mode 100644
index 0000000..6dbda0a
--- /dev/null
+++ b/awesome/src/modules/crylia_bar/init.lua
@@ -0,0 +1,52 @@
+--------------------------------------------------------------------------------------------------------------
+-- This is the statusbar, every widget, module and so on is combined to all the stuff you see on the screen --
+--------------------------------------------------------------------------------------------------------------
+
+return function(s)
+
+ -- Every Widget
+ --[[
+ If you are going to use a widget on a single screen only, put it inside the s.index == X where X is the screen number.
+ This will lead to better performance and prevent widgets to be loaded but not used
+ --]]
+ s.audio = require("src.widgets.audio")(s)
+ s.date = require("src.widgets.date")()
+ s.clock = require("src.widgets.clock")()
+ s.layoutlist = require("src.widgets.layout_list")()
+ s.powerbutton = require("src.widgets.power")()
+ s.kblayout = require("src.widgets.kblayout")(s)
+ s.taglist = require("src.widgets.taglist")(s)
+ s.tasklist = require("src.widgets.tasklist")(s)
+ -- s.battery = require("src.widgets.battery")()
+ -- s.bluetooth = require("src.widgets.bluetooth")()
+ -- s.cpu_freq = require("src.widgets.cpu_info")("freq", "average")
+ -- s.systray = require("src.widgets.systray")(s)
+ -- s.cpu_usage = require("src.widgets.cpu_info")("usage")
+ -- s.cpu_temp = require("src.widgets.cpu_info")("temp")
+ -- s.gpu_usage = require("src.widgets.gpu_info")("usage")
+ -- s.gpu_temp = require("src.widgets.gpu_info")("temp")
+ -- s.network = require("src.widgets.network")()
+ -- s.ram_info = require("src.widgets.ram_info")()
+
+ if s.index == 1 then
+ s.systray = require("src.widgets.systray")(s)
+ s.cpu_usage = require("src.widgets.cpu_info")("usage")
+ s.cpu_temp = require("src.widgets.cpu_info")("temp")
+ s.gpu_usage = require("src.widgets.gpu_info")("usage")
+ s.gpu_temp = require("src.widgets.gpu_info")("temp")
+
+ require("src.modules.crylia_bar.left_bar")(s, { s.layoutlist, s.systray, s.taglist })
+ require("src.modules.crylia_bar.center_bar")(s, { s.tasklist })
+ require("src.modules.crylia_bar.right_bar")(s, { s.gpu_usage, s.gpu_temp, s.cpu_usage, s.cpu_temp, s.audio, s.kblayout, s.date, s.clock, s.powerbutton })
+ require("src.modules.crylia_bar.dock")(s, user_vars.dock_programs)
+ end
+
+ if s.index == 2 then
+ s.network = require("src.widgets.network")()
+ s.ram_info = require("src.widgets.ram_info")()
+
+ require("src.modules.crylia_bar.left_bar")(s, { s.layoutlist, s.taglist })
+ require("src.modules.crylia_bar.center_bar")(s, { s.tasklist })
+ require("src.modules.crylia_bar.right_bar")(s, { s.ram_info, s.audio, s.kblayout, s.network, s.date, s.clock, s.powerbutton })
+ end
+end
diff --git a/awesome/crylia_bar/left_bar.lua b/awesome/src/modules/crylia_bar/left_bar.lua
similarity index 100%
rename from awesome/crylia_bar/left_bar.lua
rename to awesome/src/modules/crylia_bar/left_bar.lua
diff --git a/awesome/crylia_bar/right_bar.lua b/awesome/src/modules/crylia_bar/right_bar.lua
similarity index 100%
rename from awesome/crylia_bar/right_bar.lua
rename to awesome/src/modules/crylia_bar/right_bar.lua
diff --git a/awesome/src/modules/init.lua b/awesome/src/modules/init.lua
new file mode 100644
index 0000000..f0fe395
--- /dev/null
+++ b/awesome/src/modules/init.lua
@@ -0,0 +1,28 @@
+--------------------------------------------------------------------------------------------------------------
+-- This is the statusbar, every widget, module and so on is combined to all the stuff you see on the screen --
+--------------------------------------------------------------------------------------------------------------
+-- Awesome Libs
+local awful = require("awful")
+
+awful.screen.connect_for_each_screen(
+-- For each screen this function is called once
+-- If you want to change the modules per screen use the indices
+-- e.g. 1 would be the primary screen and 2 the secondary screen.
+ function(s)
+ -- Create 9 tags
+ awful.layout.layouts = user_vars.layouts
+ awful.tag(
+ { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
+ s,
+ user_vars.layouts[1]
+ )
+
+ require("src.modules.powermenu")(s)
+ require("src.modules.volume_osd")(s)
+ require("src.modules.brightness_osd")(s)
+ require("src.modules.titlebar")
+ require("src.modules.volume_controller")(s)
+ require("src.modules.crylia_bar.init")(s)
+ require("src.modules.notification-center.init")(s)
+ end
+)
diff --git a/awesome/src/modules/notification-center/init.lua b/awesome/src/modules/notification-center/init.lua
index e69de29..ffd01db 100644
--- a/awesome/src/modules/notification-center/init.lua
+++ b/awesome/src/modules/notification-center/init.lua
@@ -0,0 +1,371 @@
+-------------------------------------
+-- This is the notification-center --
+-------------------------------------
+
+-- Awesome Libs
+local awful = require("awful")
+local color = require("src.theme.colors")
+local dpi = require("beautiful").xresources.apply_dpi
+local gears = require("gears")
+local wibox = require("wibox")
+
+-- Icon directory path
+local icondir = awful.util.getdir("config") .. "src/assets/icons/notifications/"
+
+return function(s)
+
+ --#region Activation area
+
+ local activation_area = awful.popup {
+ bg = '#00000000',
+ widget = wibox.container.background,
+ ontop = true,
+ screen = s,
+ type = 'dock',
+ placement = function(c)
+ awful.placement.top(c)
+ end,
+ }
+
+ activation_area:setup({
+ widget = wibox.container.background,
+ forced_height = dpi(1),
+ forced_width = dpi(300),
+ bg = '#00000000',
+ layout = wibox.layout.fixed.horizontal
+ })
+
+ --#endregion
+
+ --#region Widgets
+ local nl = require("src.modules.notification-center.notification_list").notification_list
+ local music_widget = require("src.modules.notification-center.song_info")()
+ local time_date = require("src.modules.notification-center.time_date")()
+ local weather_widget = require("src.modules.notification-center.weather")()
+ local profile_widget = require("src.modules.notification-center.profile")()
+ local status_bars_widget = require("src.modules.notification-center.status_bars")()
+ --#endregion
+
+ --#region Notification buttons
+ local clear_all_widget = wibox.widget { -- Clear all button
+ {
+ {
+ {
+ text = "Clear",
+ valign = "center",
+ align = "center",
+ widget = wibox.widget.textbox,
+ id = "clearall"
+ },
+ id = "background4",
+ fg = color["Grey900"],
+ bg = color["Blue200"],
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 12)
+ end,
+ forced_width = dpi(80),
+ forced_height = dpi(40),
+ widget = wibox.container.background
+ },
+ id = "margin3",
+ margins = dpi(10),
+ widget = wibox.container.margin
+ },
+ id = "place",
+ widget = wibox.container.place,
+ valign = "bottom",
+ halign = "right",
+ }
+
+ local left_button = wibox.widget {
+ {
+ {
+ widget = wibox.container.background,
+ bg = color["Grey700"],
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(8))
+ end,
+ forced_height = dpi(30),
+ forced_width = dpi(30),
+ id = "circle"
+ },
+ left = dpi(5),
+ right = dpi(5),
+ widget = wibox.container.margin,
+ id = "margin"
+ },
+ visible = true,
+ valign = "center",
+ halign = "left",
+ widget = wibox.container.place,
+ }
+
+ local right_button = wibox.widget {
+ {
+ {
+ widget = wibox.container.background,
+ bg = color["Purple200"],
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(8))
+ end,
+ forced_height = dpi(30),
+ forced_width = dpi(30),
+ id = "circle"
+ },
+ left = dpi(5),
+ right = dpi(5),
+ widget = wibox.container.margin,
+ id = "margin"
+ },
+ valign = "center",
+ halign = "right",
+ visible = false,
+ widget = wibox.container.place,
+ }
+
+ local toggle_button = wibox.widget {
+ {
+ left_button,
+ right_button,
+ widget = wibox.layout.flex.horizontal
+ },
+ active = false,
+ widget = wibox.container.background,
+ bg = color["Grey900"],
+ border_color = color["Grey800"],
+ border_width = dpi(2),
+ forced_height = dpi(40),
+ forced_width = dpi(80),
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(10))
+ end,
+ }
+
+ toggle_button:connect_signal(
+ "button::press",
+ function()
+ if toggle_button.active then
+ left_button.visible = true
+ right_button.visible = false
+ toggle_button.active = not toggle_button.active
+ toggle_button.border_color = color["Grey800"]
+ user_vars.dnd = false
+ else
+ left_button.visible = false
+ right_button.visible = true
+ toggle_button.active = not toggle_button.active
+ toggle_button.border_color = color["Purple200"]
+ user_vars.dnd = true
+ end
+ end
+ )
+
+ local dnd = wibox.widget { -- Clear all button
+ {
+ {
+ {
+ {
+ text = "Do Not Disturb",
+ valign = "center",
+ align = "center",
+ widget = wibox.widget.textbox,
+ id = "clearall"
+ },
+ toggle_button,
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.horizontal,
+ id = "layout12"
+ },
+ id = "background4",
+ fg = color["Pink200"],
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 12)
+ end,
+ forced_height = dpi(40),
+ widget = wibox.container.background
+ },
+ id = "margin3",
+ margins = dpi(10),
+ widget = wibox.container.margin
+ },
+ id = "place",
+ widget = wibox.container.place,
+ valign = "bottom",
+ halign = "right",
+ }
+
+ -- TODO: Add rubato animation. For this the widget needs to be rewritten to use a single moving square
+ local no_notification_widget = wibox.widget {
+ {
+ {
+ valign = "center",
+ halign = "center",
+ resize = true,
+ forced_height = dpi(200),
+ forced_width = dpi(200),
+ image = icondir .. "megamind.svg",
+ widget = wibox.widget.imagebox,
+ id = "icon"
+ },
+ {
+ id = "txt",
+ markup = "No Notifications?",
+ valign = "center",
+ halign = "center",
+ widget = wibox.widget.textbox
+ },
+ id = "lay",
+ layout = wibox.layout.fixed.vertical
+ },
+ valign = "center",
+ halign = "center",
+ widget = wibox.container.place
+ }
+
+ --#endregion
+
+ --#region Notification center
+ local notification_center = awful.popup {
+ widget = wibox.container.background,
+ bg = color["Grey900"],
+ border_color = color["Grey800"],
+ border_width = dpi(4),
+ placement = function(c)
+ awful.placement.top(c, { margins = dpi(10) })
+ end,
+ ontop = true,
+ screen = s,
+ visible = false,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 12)
+ end,
+ }
+
+ -- TODO: Currently awesome doesn't come with a scroll container, there is a PR(#3309) and once its merged we can use it
+ local function notification_center_setup()
+ notification_center:setup({
+ widget = notification_center,
+ -- Custom widgets
+ {
+ time_date,
+ require("src.modules.notification-center.spacingline_widget")(),
+ {
+ {
+ weather_widget,
+ {
+ profile_widget,
+ layout = wibox.layout.fixed.vertical
+ },
+ layout = wibox.layout.fixed.horizontal
+ },
+ layout = wibox.layout.fixed.horizontal
+ },
+ status_bars_widget,
+ music_widget,
+ layout = wibox.layout.fixed.vertical
+ },
+ -- Notification list
+ {
+ {
+ {
+ nl,
+ height = dpi(680),
+ strategy = "max",
+ widget = wibox.container.constraint
+ },
+ {
+ no_notification_widget,
+ strategy = "max",
+ height = dpi(400),
+ widget = wibox.container.constraint
+ },
+ {
+ dnd,
+ nil,
+ clear_all_widget,
+ layout = wibox.layout.align.horizontal
+ },
+ id = "layout5",
+ layout = wibox.layout.align.vertical
+ },
+ id = "margin6",
+ margins = dpi(20),
+ widget = wibox.container.margin
+ },
+ id = "yes",
+ spacing_widget = {
+ {
+ fg = color["Grey800"],
+ bg = color["Grey800"],
+ widget = wibox.container.background
+ },
+ top = dpi(40),
+ bottom = dpi(40),
+ widget = wibox.container.margin
+ },
+ spacing = dpi(1),
+ forced_height = dpi(800),
+ forced_width = dpi(1000),
+ layout = wibox.layout.flex.horizontal
+ })
+ end
+
+ --#endregion
+
+ --#region Signals
+ -- Toggle notification_center visibility when mouse is over activation_area
+ activation_area:connect_signal(
+ "mouse::enter",
+ function()
+ notification_center.visible = true
+ notification_center_setup()
+ end
+ )
+
+ -- Update the notification center popup and check if there are no notifications
+ awesome.connect_signal(
+ "notification_center:update::needed",
+ function()
+ if #nl == 0 then
+ math.randomseed(os.time())
+ local prob = math.random(1, 10)
+
+ if (prob == 5) or (prob == 6) then
+ no_notification_widget.lay.icon.image = icondir .. "megamind.svg"
+ no_notification_widget.lay.txt.markup = "No Notifications?"
+ else
+ no_notification_widget.lay.icon.image = icondir .. "bell-outline.svg"
+ no_notification_widget.lay.txt.markup = "No Notification"
+ end
+ no_notification_widget.visible = true
+ else
+ no_notification_widget.visible = false
+ end
+ notification_center_setup()
+ end
+ )
+
+ -- Hide notification_center when mouse leaves it
+ notification_center:connect_signal(
+ "mouse::leave",
+ function()
+ notification_center.visible = false
+ end
+ )
+
+ -- Clear all notifications on button press
+ clear_all_widget:connect_signal(
+ "button::press",
+ function()
+ local size = #nl
+ for i = 0, size do
+ nl[i] = nil
+ end
+ awesome.emit_signal("notification_center:update::needed")
+ end
+ )
+
+ Hover_signal(clear_all_widget, color["Blue200"], color["Grey900"])
+ --#endregion
+
+end
diff --git a/awesome/src/modules/notification-center/notification_list.lua b/awesome/src/modules/notification-center/notification_list.lua
new file mode 100644
index 0000000..7ee0f86
--- /dev/null
+++ b/awesome/src/modules/notification-center/notification_list.lua
@@ -0,0 +1,261 @@
+-------------------------------------
+-- This is the notification-center --
+-------------------------------------
+
+-- Awesome Libs
+local awful = require("awful")
+local color = require("src.theme.colors")
+local dpi = require("beautiful").xresources.apply_dpi
+local gears = require("gears")
+local wibox = require("wibox")
+local naughty = require("naughty")
+
+-- Icon directory path
+local icondir = awful.util.getdir("config") .. "src/assets/icons/notifications/"
+
+local nl = {}
+
+nl.notification_list = { layout = wibox.layout.fixed.vertical, spacing = dpi(20) }
+
+-- @param {table} notification
+-- @return {widget} notifications_list
+function nl.create_notification(n)
+
+ n.time = os.time()
+
+ local time_ago_text = "- ago"
+
+ local timer_widget = wibox.widget {
+ {
+ {
+ text = time_ago_text,
+ widget = wibox.widget.textbox,
+ id = "txt"
+ },
+ id = "background",
+ fg = color["Teal200"],
+ widget = wibox.container.background
+ },
+ margins = dpi(10),
+ widget = wibox.container.margin,
+ }
+
+ gears.timer {
+ timeout = 1,
+ autostart = true,
+ call_now = true,
+ callback = function()
+ local time_ago = math.floor(os.time() - n.time)
+ local timer_text = timer_widget.background.txt
+ if time_ago < 5 then
+ timer_text:set_text("now")
+ elseif time_ago < 60 then
+ timer_text:set_text(time_ago .. "s ago")
+ elseif time_ago < 3600 then
+ timer_text:set_text(math.floor(time_ago / 60) .. "m ago")
+ elseif time_ago < 86400 then
+ timer_text:set_text(math.floor(time_ago / 3600) .. "h ago")
+ else
+ timer_text:set_text(math.floor(time_ago / 86400) .. "d ago")
+ end
+ end
+ }
+
+ local close_widget = wibox.widget {
+ {
+ {
+ {
+ {
+ font = user_vars.font.specify .. ", 10",
+ text = "✕",
+ align = "center",
+ valign = "center",
+ widget = wibox.widget.textbox
+ },
+ start_angle = 4.71239,
+ thickness = dpi(2),
+ min_value = 0,
+ max_value = 360,
+ value = 360,
+ widget = wibox.container.arcchart,
+ id = "arc_chart"
+ },
+ id = "background",
+ fg = color["Teal200"],
+ widget = wibox.container.background
+ },
+ strategy = "exact",
+ width = dpi(20),
+ height = dpi(20),
+ widget = wibox.container.constraint,
+ id = "const"
+ },
+ margins = dpi(10),
+ widget = wibox.container.margin,
+ id = "arc_margin"
+ }
+
+ local timer_close_widget = timer_widget
+
+ local notification = wibox.widget {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ image = gears.color.recolor_image(icondir .. "notification-outline.svg", color["Teal200"]),
+ resize = false,
+ widget = wibox.widget.imagebox
+ },
+ right = dpi(5),
+ widget = wibox.container.margin
+ },
+ {
+ markup = n.app_name or 'System Notification',
+ align = "center",
+ valign = "center",
+ widget = wibox.widget.textbox
+ },
+ layout = wibox.layout.fixed.horizontal
+ },
+ fg = color["Teal200"],
+ widget = wibox.container.background
+ },
+ margins = dpi(10),
+ widget = wibox.container.margin
+ },
+ nil,
+ {
+ timer_widget,
+ layout = wibox.layout.fixed.horizontal,
+ id = "arc_app_layout_2"
+ },
+ id = "arc_app_layout",
+ layout = wibox.layout.align.horizontal
+ },
+ id = "arc_app_bg",
+ border_color = color["Grey800"],
+ border_width = dpi(2),
+ widget = wibox.container.background
+ },
+ {
+ {
+ {
+ {
+ {
+ image = n.icon,
+ resize = true,
+ widget = wibox.widget.imagebox,
+ clip_shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 10)
+ end
+ },
+ width = naughty.config.defaults.icon_size,
+ height = naughty.config.defaults.icon_size,
+ strategy = "exact",
+ widget = wibox.container.constraint
+ },
+ halign = "center",
+ valign = "top",
+ widget = wibox.container.place
+ },
+ id = "margin01",
+ left = dpi(20),
+ bottom = dpi(15),
+ top = dpi(15),
+ right = dpi(10),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ {
+ markup = n.title,
+ widget = wibox.widget.textbox,
+ align = "left"
+ },
+ {
+ markup = n.message,
+ widget = wibox.widget.textbox,
+ align = "left"
+ },
+ layout = wibox.layout.fixed.vertical
+ },
+ left = dpi(10),
+ bottom = dpi(10),
+ top = dpi(10),
+ right = dpi(20),
+ widget = wibox.container.margin
+ },
+ layout = wibox.layout.fixed.horizontal
+ },
+ id = "widget_layout",
+ layout = wibox.layout.fixed.vertical
+ },
+ id = "min_size",
+ strategy = "min",
+ width = dpi(100),
+ widget = wibox.container.constraint
+ },
+ id = "max_size",
+ strategy = "max",
+ width = Theme.notification_max_width or dpi(500),
+ widget = wibox.container.constraint
+ },
+ pk = #nl.notification_list + 1,
+ bg = color["Grey900"],
+ border_color = color["Grey800"],
+ border_width = dpi(4),
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 8)
+ end,
+ widget = wibox.container.background
+ }
+
+ close_widget:connect_signal(
+ "button::press",
+ function(_, _, _, button)
+ if button == 1 then
+ for i, b in pairs(nl.notification_list) do
+ if b.pk == notification.pk then
+ table.remove(nl.notification_list, i)
+ awesome.emit_signal("notification_center:update::needed")
+ break
+ end
+ end
+ end
+ end
+ )
+
+ Hover_signal(close_widget.const.background, color["Grey900"], color["Teal200"])
+
+ notification:connect_signal(
+ "mouse::enter",
+ function()
+ notification:get_children_by_id("arc_app_layout_2")[1]:set(1, close_widget)
+ end
+ )
+
+ notification:connect_signal(
+ "mouse::leave",
+ function()
+ notification:get_children_by_id("arc_app_layout_2")[1]:set(1, timer_close_widget)
+ end
+ )
+
+ table.insert(nl.notification_list, notification)
+end
+
+naughty.connect_signal(
+ "request::display",
+ function(n)
+ nl.create_notification(n)
+ awesome.emit_signal("notification_center:update::needed")
+ end
+)
+
+return nl
diff --git a/awesome/src/modules/notification-center/profile.lua b/awesome/src/modules/notification-center/profile.lua
new file mode 100644
index 0000000..3f5fe3a
--- /dev/null
+++ b/awesome/src/modules/notification-center/profile.lua
@@ -0,0 +1,207 @@
+--------------------------------
+-- This is the profile widget --
+--------------------------------
+
+-- Awesome Libs
+local awful = require("awful")
+local color = require("src.theme.colors")
+local dpi = require("beautiful").xresources.apply_dpi
+local gears = require("gears")
+local wibox = require("wibox")
+
+-- Icon directory path
+local icondir = awful.util.getdir("config") .. "src/assets/icons/profile/"
+
+return function()
+
+ local profile_widget = wibox.widget {
+ {
+ {
+ {
+ {
+ {
+ {
+ image = gears.surface.load_uncached(awful.util.getdir("config") .. "src/assets/userpfp/crylia.png"),
+ id = "icon",
+ valign = "center",
+ halign = "center",
+ clip_shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(12))
+ end,
+ widget = wibox.widget.imagebox
+ },
+ strategy = "exact",
+ widget = wibox.container.constraint
+ },
+ id = "icon_margin",
+ margins = dpi(20),
+ widget = wibox.container.margin
+ },
+ {
+ {
+ {
+ {
+ { -- Username
+ id = "username_prefix",
+ image = gears.color.recolor_image(icondir .. "user.svg", color["Blue200"]),
+ valign = "center",
+ halign = "left",
+ resize = false,
+ widget = wibox.widget.imagebox
+ },
+ { -- Username
+ id = "username",
+ valign = "center",
+ align = "left",
+ widget = wibox.widget.textbox
+ },
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.horizontal
+ },
+ {
+ {
+ id = "os_prefix",
+ image = gears.color.recolor_image(icondir .. "laptop.svg", color["Blue200"]),
+ valign = "center",
+ halign = "left",
+ resize = false,
+ widget = wibox.widget.imagebox
+ },
+ { -- OS
+ id = "os",
+ valign = "center",
+ align = "left",
+ widget = wibox.widget.textbox
+ },
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.horizontal
+ },
+ {
+ {
+ id = "kernel_prefix",
+ image = gears.color.recolor_image(icondir .. "penguin.svg", color["Blue200"]),
+ valign = "center",
+ halign = "left",
+ resize = false,
+ widget = wibox.widget.imagebox
+ },
+ { -- Kernel
+ id = "kernel",
+ valign = "center",
+ align = "left",
+ widget = wibox.widget.textbox
+ },
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.horizontal
+ },
+ {
+ {
+ id = "uptime_prefix",
+ image = gears.color.recolor_image(icondir .. "clock.svg", color["Blue200"]),
+ valign = "center",
+ halign = "left",
+ resize = false,
+ widget = wibox.widget.imagebox
+ },
+ { -- Uptime
+ id = "uptime",
+ valign = "center",
+ align = "left",
+ widget = wibox.widget.textbox
+ },
+ spacing = dpi(10),
+ id = "uptime_layout",
+ layout = wibox.layout.fixed.horizontal
+ },
+ spacing = dpi(5),
+ id = "info_layout",
+ layout = wibox.layout.flex.vertical
+ },
+ id = "text_margin",
+ widget = wibox.container.constraint
+ },
+ id = "text_container",
+ bottom = dpi(20),
+ left = dpi(20),
+ widget = wibox.container.margin
+ },
+ id = "text_container_wrapper",
+ widget = wibox.layout.fixed.vertical
+ },
+ id = "wrapper",
+ fg = color["Green200"],
+ border_color = color["Grey800"],
+ border_width = dpi(4),
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(8))
+ end,
+ widget = wibox.container.background
+ },
+ id = "const",
+ strategy = "exact",
+ width = dpi(250),
+ height = dpi(350),
+ widget = wibox.container.constraint
+ },
+ top = dpi(20),
+ left = dpi(10),
+ right = dpi(20),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+ }
+
+ local function get_os_name_pretty()
+ awful.spawn.easy_async_with_shell(
+ "cat /etc/os-release | grep -w NAME",
+ function(stdout)
+ profile_widget:get_children_by_id("os")[1].text = stdout:match("\"(.+)\"")
+ end
+ )
+ end
+
+ -- function to get and set the kernel version
+ local function get_kernel_version()
+ awful.spawn.easy_async_with_shell(
+ "uname -r",
+ function(stdout)
+ profile_widget:get_children_by_id("kernel")[1].text = stdout:match("(%d+%.%d+%.%d+)")
+ end
+ )
+ end
+
+ --function to get the username and hostname
+ local function get_user_hostname()
+ awful.spawn.easy_async_with_shell(
+ "echo $USER@$(hostname)",
+ function(stdout)
+ profile_widget:get_children_by_id("username")[1].text = stdout:gsub("\n", "") or ""
+ end
+ )
+
+ end
+
+ -- function to fetch uptime async
+ local function get_uptime()
+ awful.spawn.easy_async_with_shell("uptime -p", function(stdout)
+
+ local hours = stdout:match("(%d+) hours") or 0
+ local minutes = stdout:match("(%d+) minutes") or 0
+
+ profile_widget:get_children_by_id("uptime")[1].text = hours .. "h, " .. minutes .. "m"
+ end)
+ end
+
+ get_os_name_pretty()
+ get_kernel_version()
+ get_user_hostname()
+
+ gears.timer {
+ timeout = 60,
+ autostart = true,
+ call_now = true,
+ callback = get_uptime
+ }
+
+ return profile_widget
+
+end
diff --git a/awesome/src/modules/notification-center/song_info.lua b/awesome/src/modules/notification-center/song_info.lua
new file mode 100644
index 0000000..3824037
--- /dev/null
+++ b/awesome/src/modules/notification-center/song_info.lua
@@ -0,0 +1,466 @@
+---------------------------
+-- This is the song-info --
+---------------------------
+
+-- Awesome Libs
+local awful = require("awful")
+local color = require("src.theme.colors")
+local dpi = require("beautiful").xresources.apply_dpi
+local gears = require("gears")
+local wibox = require("wibox")
+local naughty = require("naughty")
+
+-- Icon directory path
+local icondir = awful.util.getdir("config") .. "src/assets/icons/notifications/"
+
+return function(s)
+
+ --#region Music control button widgets
+
+ local function button_hover_effect(widget, svg, color, color2)
+ local mouse_enter = function()
+ widget.image = gears.surface.load_uncached(gears.color.recolor_image(icondir .. svg, color2))
+ local w = mouse.current_wibox
+ if w then
+ w.cursor = "hand1"
+ end
+ end
+
+ local mouse_leave = function()
+ widget.image = gears.surface.load_uncached(gears.color.recolor_image(icondir .. svg, color))
+ mouse.cursor = "left_ptr"
+ local w = mouse.current_wibox
+ if w then
+ w.cursor = "left_ptr"
+ end
+ end
+
+ widget:disconnect_signal("mouse::enter", mouse_enter)
+ widget:connect_signal("mouse::enter", mouse_enter)
+ widget:disconnect_signal("mouse::leave", mouse_leave)
+ widget:connect_signal("mouse::leave", mouse_leave)
+ end
+
+ local shuffle_button = wibox.widget {
+ resize = false,
+ image = gears.color.recolor_image(icondir .. "shuffle.svg", color["Grey800"]),
+ widget = wibox.widget.imagebox,
+ }
+
+ local function suffle_handler()
+ awful.spawn.easy_async_with_shell(
+ "playerctl shuffle",
+ function(stdout)
+ if stdout:match("On") then
+ awful.spawn.with_shell("playerctl shuffle off")
+ shuffle_button.image = gears.color.recolor_image(icondir .. "shuffle.svg", color["Grey800"])
+ else
+ awful.spawn.with_shell("playerctl shuffle on")
+ shuffle_button.image = gears.color.recolor_image(icondir .. "shuffle.svg", color["Green200"])
+ end
+ end
+ )
+ end
+
+ local function update_shuffle()
+ awful.spawn.easy_async_with_shell(
+ "playerctl shuffle",
+ function(stdout)
+ if stdout:match("On") then
+ shuffle_button.image = gears.color.recolor_image(icondir .. "shuffle.svg", color["Green200"])
+ else
+ shuffle_button.image = gears.color.recolor_image(icondir .. "shuffle.svg", color["Grey800"])
+ end
+ end
+ )
+ end
+
+ update_shuffle()
+
+ local repeat_button = wibox.widget {
+ resize = false,
+ image = gears.color.recolor_image(icondir .. "repeat.svg", color["Grey800"]),
+ widget = wibox.widget.imagebox,
+ id = "imagebox"
+ }
+
+ -- On first time load set the correct loop
+ local function update_loop()
+ awful.spawn.easy_async_with_shell(
+ "playerctl loop",
+ function(stdout)
+ local loop_mode = stdout:gsub("\n", "")
+ if loop_mode == "Track" then
+ repeat_button.image = gears.color.recolor_image(gears.surface.load_uncached(icondir .. "repeat-once.svg"), color["Green200"])
+ elseif loop_mode == "None" then
+ repeat_button.image = gears.color.recolor_image(gears.surface.load_uncached(icondir .. "repeat.svg"), color["Grey800"])
+ elseif loop_mode == "Playlist" then
+ repeat_button.image = gears.color.recolor_image(gears.surface.load_uncached(icondir .. "repeat.svg"), color["Green200"])
+ end
+ end
+ )
+ end
+
+ update_loop()
+ -- Activate shuffle when button is clicked
+ shuffle_button:buttons(gears.table.join(
+ awful.button({}, 1, suffle_handler)))
+
+ local prev_button = wibox.widget {
+ resize = false,
+ image = gears.color.recolor_image(icondir .. "skip-prev.svg", color["Teal200"]),
+ widget = wibox.widget.imagebox
+ }
+
+ -- Activate previous song when button is clicked
+ prev_button:buttons(gears.table.join(
+ awful.button({}, 1, function()
+ awful.spawn.easy_async_with_shell(
+ "playerctl previous && sleep 1",
+ function()
+ update_loop()
+ end
+ )
+ end)
+ ))
+
+ local pause_play_button = wibox.widget {
+ resize = false,
+ image = gears.color.recolor_image(icondir .. "play-pause.svg", color["Teal200"]),
+ widget = wibox.widget.imagebox
+ }
+
+ -- Activate play/pause when button is clicked
+ pause_play_button:buttons(gears.table.join(
+ awful.button({}, 1, function()
+ awful.spawn.with_shell("playerctl play-pause")
+ end)
+ ))
+
+ local next_button = wibox.widget {
+ resize = false,
+ image = gears.color.recolor_image(icondir .. "skip-next.svg", color["Teal200"]),
+ widget = wibox.widget.imagebox
+ }
+
+ -- Activate next song when button is clicked
+ next_button:buttons(gears.table.join(
+ awful.button({}, 1, function()
+ awful.spawn.easy_async_with_shell(
+ "playerctl next && sleep 1",
+ function()
+ update_loop()
+ end
+ )
+ end)
+ ))
+
+ --- This function updates the repeat button svg and changes the mode on click
+ local function loop_handler()
+ awful.spawn.easy_async_with_shell(
+ "playerctl loop",
+ function(stdout)
+ local loop_mode = stdout:gsub("\n", "")
+ if loop_mode == "None" then
+ awful.spawn.with_shell("playerctl loop playlist")
+ repeat_button.image = gears.color.recolor_image(gears.surface.load_uncached(icondir .. "repeat.svg"), color["Green200"])
+ elseif loop_mode == "Playlist" then
+ awful.spawn.with_shell("playerctl loop track")
+ repeat_button.image = gears.color.recolor_image(gears.surface.load_uncached(icondir .. "repeat-once.svg"), color["Green200"])
+ elseif loop_mode == "Track" then
+ awful.spawn.with_shell("playerctl loop none")
+ repeat_button.image = gears.color.recolor_image(gears.surface.load_uncached(icondir .. "repeat.svg"), color["Grey800"])
+ end
+ end
+ )
+ end
+
+ repeat_button:buttons(gears.table.join(awful.button({}, 1, loop_handler)))
+
+ button_hover_effect(prev_button, "skip-prev.svg", color["Teal200"], color["Teal300"])
+ button_hover_effect(pause_play_button, "play-pause.svg", color["Teal200"], color["Teal300"])
+ button_hover_effect(next_button, "skip-next.svg", color["Teal200"], color["Teal300"])
+
+ --#endregion
+
+ -- Main music widget
+ local music_widget = wibox.widget {
+ {
+ {
+ {
+ {
+ {
+ { -- Album art
+ {
+ image = "default image",
+ resize = true,
+ clip_shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(8))
+ end,
+ widget = wibox.widget.imagebox,
+ id = "imagebox"
+ },
+ width = dpi(80),
+ height = dpi(80),
+ strategy = "exact",
+ widget = wibox.container.constraint,
+ id = "const"
+ },
+ {
+ {
+ {
+ {
+ { --Title
+ halign = "center",
+ align = "center",
+ widget = wibox.widget.textbox,
+ id = "textbox4"
+ },
+ fg = color["Pink200"],
+ id = "textbox5",
+ widget = wibox.container.background
+ },
+ strategy = "max",
+ width = dpi(400),
+ widget = wibox.container.constraint
+ },
+ halign = "center",
+ valign = "center",
+ id = "textbox_container4",
+ widget = wibox.container.place
+ },
+ {
+ {
+ {
+ { --Artist
+ halign = "center",
+ align = "center",
+ widget = wibox.widget.textbox,
+ id = "textbox3"
+ },
+ fg = color["Teal200"],
+ id = "background",
+ widget = wibox.container.background
+ },
+ strategy = "max",
+ width = dpi(400),
+ widget = wibox.container.constraint
+ },
+ halign = "center",
+ valign = "center",
+ id = "artist_container",
+ widget = wibox.container.place
+ },
+ { --Buttons
+ {
+ {
+ shuffle_button,
+ prev_button,
+ pause_play_button,
+ next_button,
+ repeat_button,
+ spacing = dpi(15),
+ layout = wibox.layout.fixed.horizontal,
+ id = "layout5"
+ },
+ halign = "center",
+ widget = wibox.container.place,
+ id = "place2"
+ },
+ widget = wibox.container.margin,
+ id = "margin6"
+ },
+ layout = wibox.layout.flex.vertical,
+ id = "layout4"
+ },
+ fill_space = true,
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.horizontal,
+ id = "layout3"
+ },
+ widget = wibox.container.margin,
+ id = "margin5"
+ },
+ { --Song Duration
+ {
+ {
+ {
+ markup = "0:00",
+ widget = wibox.widget.textbox,
+ id = "textbox2"
+ },
+ fg = color["Lime200"],
+ widget = wibox.container.background,
+ id = "background3"
+ },
+ right = dpi(10),
+ widget = wibox.container.margin,
+ id = "margin4"
+ },
+ { -- Progressbar
+ {
+ color = color["Purple200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(5),
+ shape = function(cr, width)
+ gears.shape.rounded_bar(cr, width, dpi(5))
+ end,
+ widget = wibox.widget.progressbar,
+ id = "progressbar1"
+ },
+ valign = "center",
+ halign = "center",
+ widget = wibox.container.place,
+ id = "place1"
+ },
+ {
+ {
+ {
+ text = "00:00",
+ widget = wibox.widget.textbox,
+ id = "text1"
+ },
+ id = "background2",
+ fg = color["Lime200"],
+ widget = wibox.container.background
+ },
+ id = "margin3",
+ left = dpi(10),
+ widget = wibox.container.margin
+ },
+ id = "layout2",
+ layout = wibox.layout.align.horizontal
+ },
+ id = "layout1",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ },
+ id = "margin2",
+ widget = wibox.container.margin,
+ margins = dpi(10)
+ },
+ id = "background1",
+ border_color = color["Grey800"],
+ border_width = dpi(4),
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(8))
+ end,
+ widget = wibox.container.background
+ },
+ id = "margin1",
+ widget = wibox.container.margin,
+ top = dpi(10),
+ bottom = dpi(20),
+ left = dpi(20),
+ right = dpi(20)
+ }
+
+ -- Used to check if the music changed and if everthing should be updated
+ local trackid = ""
+ local artist = ""
+ local title = ""
+
+ -- Function to get spotify title, artist, album, album_art, length and track_id
+ local function get_spotify_metadata(skip_check)
+ skip_check = skip_check or false
+ awful.spawn.easy_async_with_shell(
+ "playerctl metadata",
+ function(stdout)
+ -- Only fetch info if the track changed or if the title/artist is empty
+ if skip_check or (not stdout:match(trackid)) or (not stdout:match(artist)) or (not stdout:match(title)) then
+ update_loop()
+ update_shuffle()
+ -- Get the song title
+ awful.spawn.easy_async_with_shell(
+ "playerctl metadata xesam:title",
+ function(stdout2)
+ local tit = stdout2:gsub("\n", "")
+ title = tit
+ music_widget:get_children_by_id("textbox4")[1].text = tit
+ end
+ )
+
+ -- Get the song artist
+ awful.spawn.easy_async_with_shell(
+ "playerctl metadata xesam:artist",
+ function(stdout2)
+ local art = stdout2:gsub("\n", "")
+ artist = art
+ music_widget:get_children_by_id("textbox3")[1].text = art
+ end
+ )
+
+ -- Get the song album image
+ awful.spawn.easy_async_with_shell(
+ "playerctl metadata mpris:artUrl",
+ function(album_art)
+ local url = album_art:gsub("\n", "")
+ awful.spawn.easy_async_with_shell(
+ -- TODO: curl does not stdout and is returns before it finished. This causes the image to sometimes not show correctly.
+ -- !Find a better solution than sleep 0.1
+ -- Maybe cache the image? Not sure if that would be a waste of space or not.
+ "curl -s " .. url .. " -o /tmp/album_art.jpg && echo /tmp/album_art.jpg && sleep 0.5",
+ function()
+ music_widget:get_children_by_id("imagebox")[1].image = gears.surface.load_uncached("/tmp/album_art.jpg")
+ end
+ )
+ end
+ )
+
+ -- Get the length of the song
+ awful.spawn.easy_async_with_shell(
+ "playerctl metadata mpris:length",
+ function(stdout2)
+ local length = stdout2:gsub("\n", "")
+ if length ~= "" then
+ local length_formated = string.format("%02d:%02d", math.floor(tonumber(length or 1) / 60000000) or 0, (math.floor(tonumber(length or 1) / 1000000) % 60) or 0)
+ music_widget:get_children_by_id("progressbar1")[1].max_value = tonumber(math.floor(tonumber(length) / 1000000))
+ music_widget:get_children_by_id("text1")[1].markup = string.format("%s", color["Teal200"], length_formated)
+ end
+ end
+ )
+ end
+
+ awful.spawn.easy_async_with_shell(
+ "playerctl metadata mpris:trackid",
+ function(stdout2)
+ trackid = stdout2:gsub("\n", "")
+ end
+ )
+ -- Update track id
+ trackid, artist, title = stdout, music_widget:get_children_by_id("textbox3")[1].text, music_widget:get_children_by_id("textbox4")[1].text
+ end
+ )
+ -- Always update the current song progression
+ awful.spawn.easy_async_with_shell(
+ "playerctl position",
+ function(stdout)
+ local time = stdout:gsub("\n", "")
+ if time ~= "" then
+ local time_formated = string.format("%02d:%02d", math.floor(tonumber(time or "1") / 60), math.floor(tonumber(time or "1")) % 60)
+ music_widget:get_children_by_id("textbox2")[1].markup = string.format("%s", color["Teal200"], time_formated)
+ music_widget:get_children_by_id("progressbar1")[1].value = tonumber(time)
+ end
+ end
+ )
+ end
+
+ -- Call every second, if performance is bad, set the timer to a higher value
+ gears.timer {
+ timeout = 1,
+ autostart = true,
+ call_now = true,
+ callback = function()
+ get_spotify_metadata()
+ end
+ }
+
+ -- get_spotify_metadata() on awesome reload
+ awesome.connect_signal("startup", function()
+ get_spotify_metadata(true)
+ end)
+
+ return music_widget
+end
diff --git a/awesome/src/modules/notification-center/spacingline_widget.lua b/awesome/src/modules/notification-center/spacingline_widget.lua
new file mode 100644
index 0000000..275148e
--- /dev/null
+++ b/awesome/src/modules/notification-center/spacingline_widget.lua
@@ -0,0 +1,23 @@
+------------------------------------------------
+-- This is the spacing widget under the clock --
+------------------------------------------------
+
+-- Awesome Libs
+local color = require("src.theme.colors")
+local dpi = require("beautiful").xresources.apply_dpi
+local wibox = require("wibox")
+
+return function()
+
+ return wibox.widget {
+ {
+ forced_height = dpi(2),
+ bg = color["Grey800"],
+ widget = wibox.container.background
+ },
+ left = dpi(80),
+ right = dpi(80),
+ widget = wibox.container.margin
+ }
+
+end
diff --git a/awesome/src/modules/notification-center/status_bars.lua b/awesome/src/modules/notification-center/status_bars.lua
new file mode 100644
index 0000000..0c12663
--- /dev/null
+++ b/awesome/src/modules/notification-center/status_bars.lua
@@ -0,0 +1,712 @@
+------------------------------------
+-- This is the status_bars widget --
+------------------------------------
+
+-- Awesome Libs
+local awful = require("awful")
+local color = require("src.theme.colors")
+local dpi = require("beautiful").xresources.apply_dpi
+local gears = require("gears")
+local wibox = require("wibox")
+
+local rubato = require("src.lib.rubato")
+
+-- Icon directory path
+local icondir = awful.util.getdir("config") .. "src/assets/icons/"
+
+--- Signal bars widget for the notification-center
+---@return wibox.widget
+return function()
+
+ ---Creates a layout with bar widgets based on the given table
+ ---@param widget_table string{}
+ ---@return table @{layout}
+ local function create_bar_layout(widget_table)
+ local bar_layout = { layout = wibox.layout.flex.horizontal, spacing = dpi(10) }
+
+ for _, widget in pairs(widget_table) do
+ local w
+ if widget == "cpu_usage" then
+ w = wibox.widget {
+ {
+ {
+ { --Bar
+ color = color["Blue200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 0,
+ forced_height = dpi(8),
+ shape = function(cr, width, heigth)
+ gears.shape.rounded_bar(cr, dpi(58), dpi(8))
+ end,
+ id = "progressbar1",
+ widget = wibox.widget.progressbar
+ },
+ id = "background1",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background2",
+ forced_height = dpi(58), --120 Base size - (10+10) margin - (4+4) Border - 24 Icon - 10 spacing = 58
+ forced_width = dpi(24),
+ direction = "east",
+ widget = wibox.container.rotate
+ },
+ {
+ { --Icon
+ image = gears.color.recolor_image(icondir .. "cpu/cpu.svg", color["Cyan200"]),
+ halign = "center",
+ valign = "center",
+ widget = wibox.widget.imagebox,
+ id = "icon1",
+ },
+ id = "background3",
+ height = dpi(24),
+ width = dpi(24),
+ widget = wibox.container.constraint
+ },
+ id = "cpu_layout",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local bar = w:get_children_by_id("progressbar1")[1]
+
+ local rubato_timer = rubato.timed {
+ duration = 1,
+ pos = bar.value,
+ easing = rubato.linear,
+ subscribed = function(v)
+ bar.value = v
+ end
+ }
+
+ local tooltip = awful.tooltip {
+ objects = { w },
+ mode = "inside",
+ preferred_alignments = "middle",
+ margins = dpi(10)
+ }
+
+ awesome.connect_signal(
+ "update::cpu_usage_widget",
+ function(cpu_usage)
+ w:get_children_by_id("progressbar1")[1].value = cpu_usage
+ tooltip.text = "CPU Usage: " .. cpu_usage .. "%"
+ rubato_timer.target = cpu_usage
+ end
+ )
+ elseif widget == "cpu_temp" then
+ w = wibox.widget {
+ {
+ {
+ { --Bar
+ color = color["Blue200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(8),
+ shape = function(cr, width, heigth)
+ gears.shape.rounded_bar(cr, dpi(58), dpi(8))
+ end,
+ id = "progressbar1",
+ widget = wibox.widget.progressbar
+ },
+ id = "background1",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background2",
+ forced_height = dpi(58), --120 Base size - (10+10) margin - (4+4) Border - 24 Icon - 10 spacing = 58
+ forced_width = dpi(24),
+ direction = "east",
+ widget = wibox.container.rotate
+ },
+ {
+ { --Icon
+ id = "icon1",
+ image = gears.color.recolor_image(icondir .. "cpu/thermometer.svg", color["Cyan200"]),
+ halign = "center",
+ valign = "center",
+ widget = wibox.widget.imagebox
+ },
+ id = "background3",
+ height = dpi(24),
+ width = dpi(24),
+ widget = wibox.container.constraint
+ },
+ id = "cpu_temp_layout",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local bar = w:get_children_by_id("progressbar1")[1]
+
+ local rubato_timer = rubato.timed {
+ duration = 1,
+ pos = bar.value,
+ easing = rubato.linear,
+ subscribed = function(v)
+ bar.value = v
+ end
+ }
+
+ local tooltip = awful.tooltip {
+ objects = { w },
+ mode = "inside",
+ preferred_alignments = "middle",
+ margins = dpi(10)
+ }
+
+ awesome.connect_signal(
+ "update::cpu_temp_widget",
+ function(cpu_temp, cpu_temp_icon)
+ w:get_children_by_id("progressbar1")[1].value = cpu_temp
+ w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(cpu_temp_icon, color["Blue200"])
+ tooltip.text = "CPU Temp: " .. cpu_temp .. "°C"
+ rubato_timer.target = cpu_temp
+ end
+ )
+ elseif widget == "ram_usage" then
+ w = wibox.widget {
+ {
+ {
+ { --Bar
+ color = color["Red200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(8),
+ shape = function(cr, width, heigth)
+ gears.shape.rounded_bar(cr, dpi(58), dpi(8))
+ end,
+ id = "progressbar1",
+ widget = wibox.widget.progressbar
+ },
+ id = "background1",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background2",
+ forced_height = dpi(58), --120 Base size - (10+10) margin - (4+4) Border - 24 Icon - 10 spacing = 58
+ forced_width = dpi(24),
+ direction = "east",
+ widget = wibox.container.rotate
+ },
+ {
+ { --Icon
+ image = gears.color.recolor_image(icondir .. "cpu/ram.svg", color["Red200"]),
+ halign = "center",
+ valign = "center",
+ widget = wibox.widget.imagebox
+ },
+ height = dpi(24),
+ width = dpi(24),
+ widget = wibox.container.constraint
+ },
+ id = "ram_layout",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local bar = w:get_children_by_id("progressbar1")[1]
+
+ local rubato_timer = rubato.timed {
+ duration = 1,
+ pos = bar.value,
+ easing = rubato.linear,
+ subscribed = function(v)
+ bar.value = v
+ end
+ }
+
+ local tooltip = awful.tooltip {
+ objects = { w },
+ mode = "inside",
+ preferred_alignments = "middle",
+ margins = dpi(10)
+ }
+
+ awesome.connect_signal(
+ "update::ram_widget",
+ function(ram_usage)
+ w:get_children_by_id("progressbar1")[1].value = ram_usage
+ tooltip.text = "RAM Usage: " .. ram_usage .. "%"
+ rubato_timer.target = ram_usage
+ end
+ )
+ elseif widget == "gpu_usage" then
+ w = wibox.widget {
+ {
+ {
+ { --Bar
+ color = color["Green200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(8),
+ shape = function(cr, width, heigth)
+ gears.shape.rounded_bar(cr, dpi(58), dpi(8))
+ end,
+ id = "progressbar1",
+ widget = wibox.widget.progressbar
+ },
+ id = "background1",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background2",
+ forced_height = dpi(58), --120 Base size - (10+10) margin - (4+4) Border - 24 Icon - 10 spacing = 58
+ forced_width = dpi(24),
+ direction = "east",
+ widget = wibox.container.rotate
+ },
+ {
+ { --Icon
+ image = gears.color.recolor_image(icondir .. "cpu/gpu.svg", color["Green200"]),
+ halign = "center",
+ valign = "center",
+ widget = wibox.widget.imagebox
+ },
+ height = dpi(24),
+ width = dpi(24),
+ widget = wibox.container.constraint
+ },
+ id = "gpu_layout",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local bar = w:get_children_by_id("progressbar1")[1]
+
+ local rubato_timer = rubato.timed {
+ duration = 1,
+ pos = bar.value,
+ easing = rubato.linear,
+ subscribed = function(v)
+ bar.value = v
+ end
+ }
+
+ local tooltip = awful.tooltip {
+ objects = { w },
+ mode = "inside",
+ preferred_alignments = "middle",
+ margins = dpi(10)
+ }
+
+ awesome.connect_signal(
+ "update::gpu_usage_widget",
+ function(gpu_usage)
+ w:get_children_by_id("progressbar1")[1].value = gpu_usage
+ tooltip.text = "GPU Usage: " .. gpu_usage .. "%"
+ rubato_timer.target = gpu_usage
+ end
+ )
+ elseif widget == "gpu_temp" then
+ w = wibox.widget {
+ {
+ {
+ { --Bar
+ color = color["Green200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(8),
+ shape = function(cr, width, heigth)
+ gears.shape.rounded_bar(cr, dpi(58), dpi(8))
+ end,
+ id = "progressbar1",
+ widget = wibox.widget.progressbar
+ },
+ id = "background1",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background2",
+ forced_height = dpi(58), --120 Base size - (10+10) margin - (4+4) Border - 24 Icon - 10 spacing = 58
+ forced_width = dpi(24),
+ direction = "east",
+ widget = wibox.container.rotate
+ },
+ {
+ { --Icon
+ id = "icon1",
+ image = gears.color.recolor_image(icondir .. "cpu/gpu.svg", color["Green200"]),
+ halign = "center",
+ valign = "center",
+ widget = wibox.widget.imagebox
+ },
+ id = "background3",
+ height = dpi(24),
+ width = dpi(24),
+ widget = wibox.container.constraint
+ },
+ id = "gpu_temp_layout",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local bar = w:get_children_by_id("progressbar1")[1]
+
+ local rubato_timer = rubato.timed {
+ duration = 1,
+ pos = bar.value,
+ easing = rubato.linear,
+ subscribed = function(v)
+ bar.value = v
+ end
+ }
+
+ local tooltip = awful.tooltip {
+ objects = { w },
+ mode = "inside",
+ preferred_alignments = "middle",
+ margins = dpi(10)
+ }
+
+ awesome.connect_signal(
+ "update::gpu_temp_widget",
+ function(gpu_temp, gpu_temp_icon)
+ w:get_children_by_id("progressbar1")[1].value = gpu_temp
+ w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(gpu_temp_icon, color["Green200"])
+ tooltip.text = "GPU Temp: " .. gpu_temp .. "°C"
+ rubato_timer.target = gpu_temp
+ end
+ )
+ elseif widget == "volume" then
+ w = wibox.widget {
+ {
+ {
+ { --Bar
+ color = color["Yellow200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(8),
+ shape = function(cr, width, heigth)
+ gears.shape.rounded_bar(cr, dpi(58), dpi(8))
+ end,
+ id = "progressbar1",
+ widget = wibox.widget.progressbar
+ },
+ id = "background1",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background2",
+ forced_height = dpi(58), --120 Base size - (10+10) margin - (4+4) Border - 24 Icon - 10 spacing = 58
+ forced_width = dpi(24),
+ direction = "east",
+ widget = wibox.container.rotate
+ },
+ {
+ { --Icon
+ id = "icon1",
+ image = gears.color.recolor_image(icondir .. "audio/volume-high.svg", color["Yellow200"]),
+ halign = "center",
+ valign = "center",
+ widget = wibox.widget.imagebox
+ },
+ id = "background3",
+ height = dpi(24),
+ width = dpi(24),
+ widget = wibox.container.constraint
+ },
+ id = "volume_layout",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local bar = w:get_children_by_id("progressbar1")[1]
+
+ local rubato_timer = rubato.timed {
+ duration = 1,
+ pos = bar.value,
+ easing = rubato.linear,
+ subscribed = function(v)
+ bar.value = v
+ end
+ }
+
+ local tooltip = awful.tooltip {
+ objects = { w },
+ mode = "inside",
+ preferred_alignments = "middle",
+ margins = dpi(10)
+ }
+
+ awesome.connect_signal(
+ "update::volume_widget",
+ function(volume, volume_icon)
+ w:get_children_by_id("progressbar1")[1].value = volume
+ w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(volume_icon, color["Yellow200"])
+ tooltip.text = "Volume: " .. volume .. "%"
+ rubato_timer.target = volume
+ end
+ )
+ elseif widget == "microphone" then
+ w = wibox.widget {
+ {
+ {
+ { --Bar
+ color = color["Purple200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(8),
+ shape = function(cr, width, heigth)
+ gears.shape.rounded_bar(cr, dpi(58), dpi(8))
+ end,
+ id = "progressbar1",
+ widget = wibox.widget.progressbar
+ },
+ id = "background1",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background2",
+ forced_height = dpi(58), --120 Base size - (10+10) margin - (4+4) Border - 24 Icon - 10 spacing = 58
+ forced_width = dpi(24),
+ direction = "east",
+ widget = wibox.container.rotate
+ },
+ {
+ { --Icon
+ id = "icon1",
+ image = gears.color.recolor_image(icondir .. "audio/microphone.svg", color["Purple200"]),
+ halign = "center",
+ valign = "center",
+ widget = wibox.widget.imagebox
+ },
+ id = "background3",
+ height = dpi(24),
+ width = dpi(24),
+ widget = wibox.container.constraint
+ },
+ id = "microphone_layout",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local bar = w:get_children_by_id("progressbar1")[1]
+
+ local rubato_timer = rubato.timed {
+ duration = 1,
+ pos = bar.value,
+ easing = rubato.linear,
+ subscribed = function(v)
+ bar.value = v
+ end
+ }
+
+ local tooltip = awful.tooltip {
+ objects = { w },
+ mode = "inside",
+ preferred_alignments = "middle",
+ margins = dpi(10)
+ }
+
+ awesome.connect_signal(
+ "update::microphone_widget",
+ function(microphone, microphone_icon)
+ w:get_children_by_id("progressbar1")[1].value = microphone
+ w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(microphone_icon, color["Purple200"])
+ tooltip.text = "Microphone: " .. microphone .. "%"
+ rubato_timer.target = microphone
+ end
+ )
+ elseif widget == "backlight" then
+ w = wibox.widget {
+ {
+ {
+ { --Bar
+ color = color["Pink200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(8),
+ shape = function(cr, width, heigth)
+ gears.shape.rounded_bar(cr, dpi(58), dpi(8))
+ end,
+ id = "progressbar1",
+ widget = wibox.widget.progressbar
+ },
+ id = "background1",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background2",
+ forced_height = dpi(58), --120 Base size - (10+10) margin - (4+4) Border - 24 Icon - 10 spacing = 58
+ forced_width = dpi(24),
+ direction = "east",
+ widget = wibox.container.rotate
+ },
+ {
+ { --Icon
+ id = "icon1",
+ image = gears.color.recolor_image(icondir .. "brightness/brightness-high.svg", color["Pink200"]),
+ halign = "center",
+ valign = "center",
+ widget = wibox.widget.imagebox
+ },
+ id = "background3",
+ height = dpi(24),
+ width = dpi(24),
+ widget = wibox.container.constraint
+ },
+ id = "brightness_layout",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local bar = w:get_children_by_id("progressbar1")[1]
+
+ local rubato_timer = rubato.timed {
+ duration = 1,
+ pos = bar.value,
+ easing = rubato.linear,
+ subscribed = function(v)
+ bar.value = v
+ end
+ }
+
+ local tooltip = awful.tooltip {
+ objects = { w },
+ mode = "inside",
+ preferred_alignments = "middle",
+ margins = dpi(10)
+ }
+
+ awesome.connect_signal(
+ "update::backlight_widget",
+ function(backlight, backlight_icon)
+ w:get_children_by_id("progressbar1")[1].value = backlight
+ w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(backlight_icon, color["Pink200"])
+ tooltip.text = "Backlight: " .. backlight .. "%"
+ rubato_timer.target = backlight
+ end
+ )
+ elseif widget == "battery" then
+ w = wibox.widget {
+ {
+ {
+ { --Bar
+ color = color["Purple200"],
+ background_color = color["Grey800"],
+ max_value = 100,
+ value = 50,
+ forced_height = dpi(8),
+ shape = function(cr, width, heigth)
+ gears.shape.rounded_bar(cr, dpi(58), dpi(8))
+ end,
+ id = "progressbar1",
+ widget = wibox.widget.progressbar
+ },
+ id = "background1",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background2",
+ forced_height = dpi(58), --120 Base size - (10+10) margin - (4+4) Border - 24 Icon - 10 spacing = 58
+ forced_width = dpi(24),
+ direction = "east",
+ widget = wibox.container.rotate
+ },
+ {
+ { --Icon
+ id = "icon1",
+ image = gears.color.recolor_image(icondir .. "battery/battery.svg", color["Purple200"]),
+ halign = "center",
+ valign = "center",
+ widget = wibox.widget.imagebox
+ },
+ id = "background3",
+ height = dpi(24),
+ width = dpi(24),
+ widget = wibox.container.constraint
+ },
+ id = "battery_layout",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ }
+
+ local bar = w:get_children_by_id("progressbar1")[1]
+
+ local rubato_timer = rubato.timed {
+ duration = 1,
+ pos = bar.value,
+ easing = rubato.linear,
+ subscribed = function(v)
+ bar.value = v
+ end
+ }
+
+ local tooltip = awful.tooltip {
+ objects = { w },
+ mode = "inside",
+ preferred_alignments = "middle",
+ margins = dpi(10)
+ }
+
+ awesome.connect_signal(
+ "update::battery_widget",
+ function(battery, battery_icon)
+ w:get_children_by_id("progressbar1")[1].value = battery
+ w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(battery_icon, color["Purple200"])
+ tooltip.text = "Battery: " .. battery .. "%"
+ rubato_timer.target = battery
+ end
+ )
+ end
+ table.insert(bar_layout, w)
+ end
+
+ return bar_layout
+ end
+
+ local signal_bars = wibox.widget {
+ {
+ {
+ {
+ {
+ create_bar_layout({ "cpu_usage", "cpu_temp", "ram_usage", "battery", "microphone", "backlight", "volume", "gpu_temp", "gpu_usage" }),
+ width = dpi(480),
+ strategy = "exact",
+ widget = wibox.container.constraint
+ },
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ magins = dpi(10),
+ layout = wibox.container.margin
+ },
+ forced_height = dpi(120),
+ forced_width = dpi(500),
+ border_color = color["Grey800"],
+ border_width = dpi(4),
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(10))
+ end,
+ widget = wibox.container.background
+ },
+ top = dpi(10),
+ left = dpi(20),
+ right = dpi(20),
+ bottom = dpi(10),
+ widget = wibox.container.margin
+ }
+
+ return signal_bars
+
+end
diff --git a/awesome/src/modules/notification-center/time_date.lua b/awesome/src/modules/notification-center/time_date.lua
new file mode 100644
index 0000000..b7c11f6
--- /dev/null
+++ b/awesome/src/modules/notification-center/time_date.lua
@@ -0,0 +1,65 @@
+----------------------------------
+-- This is the time_date widget --
+----------------------------------
+
+-- Awesome Libs
+local dpi = require("beautiful").xresources.apply_dpi
+local wibox = require("wibox")
+
+return function()
+
+ local time_date = wibox.widget {
+ {
+ {
+ {
+ { -- Time
+ {
+ id = "label",
+ align = "center",
+ valign = "center",
+ format = "%H:%M",
+ widget = wibox.widget.textclock
+ },
+ widget = wibox.container.margin
+ },
+ { -- Date and Day
+ { -- Date
+ {
+ id = "label",
+ align = "left",
+ valign = "bottom",
+ format = "%e %b %Y",
+ widget = wibox.widget.textclock
+ },
+ widget = wibox.container.margin
+ },
+ { -- Day
+ {
+ id = "label",
+ align = "left",
+ valign = "top",
+ format = "%A",
+ widget = wibox.widget.textclock
+ },
+ widget = wibox.container.margin
+ },
+ layout = wibox.layout.flex.vertical
+ },
+ spacing = dpi(20),
+ layout = wibox.layout.fixed.horizontal
+ },
+ valign = "center",
+ halign = "center",
+ widget = wibox.container.place
+ },
+ id = "background",
+ widget = wibox.container.background
+ },
+ id = "margin",
+ margins = dpi(20),
+ widget = wibox.container.margin
+ }
+
+ return time_date
+
+end
diff --git a/awesome/src/modules/notification-center/weather.lua b/awesome/src/modules/notification-center/weather.lua
new file mode 100644
index 0000000..6fd28e0
--- /dev/null
+++ b/awesome/src/modules/notification-center/weather.lua
@@ -0,0 +1,219 @@
+--------------------------------
+-- This is the weather widget --
+--------------------------------
+
+-- Awesome Libs
+local awful = require("awful")
+local color = require("src.theme.colors")
+local dpi = require("beautiful").xresources.apply_dpi
+local gears = require("gears")
+local wibox = require("wibox")
+local naughty = require("naughty")
+
+local json_lua = require("src.lib.json-lua.json-lua")
+
+-- Icon directory path
+local icondir = awful.util.getdir("config") .. "src/assets/icons/weather/"
+
+return function()
+
+ local api_secrets = {
+ key = user_vars.weather_secrets.key,
+ city_id = user_vars.weather_secrets.city_id,
+ unit = user_vars.weather_secrets.unit
+ }
+
+ local weather_widget = wibox.widget {
+ {
+ {
+ {
+ {
+ {
+ { -- Icon
+ valign = "center",
+ align = "center",
+ resize = true,
+ forced_width = dpi(64),
+ forced_height = dpi(64),
+ widget = wibox.widget.imagebox,
+ id = "icon"
+ },
+ id = "place2",
+ valing = "center",
+ halign = "center",
+ widget = wibox.container.place
+ },
+ { -- Temperature
+ text = "0°C",
+ valign = "center",
+ align = "center",
+ widget = wibox.widget.textbox,
+ font = "JetBrains Mono Bold 24",
+ id = "temp"
+ },
+ { -- City, Country
+ text = "City, Country",
+ valign = "center",
+ align = "center",
+ widget = wibox.widget.textbox,
+ id = "city_country",
+ },
+ {
+ { -- Description
+ text = "Description",
+ valign = "center",
+ align = "center",
+ widget = wibox.widget.textbox,
+ id = "description"
+ },
+ fg = color["LightBlue200"],
+ widget = wibox.container.background
+ },
+ { -- line
+ forced_height = dpi(4),
+ forced_width = dpi(10),
+ bg = color["Grey800"],
+ widget = wibox.container.background,
+ id = "line"
+ },
+ {
+ { -- Speed
+ {
+ image = gears.color.recolor_image(icondir .. "weather-windy.svg", color["OrangeA200"]),
+ resize = true,
+ forced_width = dpi(24),
+ forced_height = dpi(24),
+ widget = wibox.widget.imagebox
+ },
+ {
+ text = "",
+ valign = "center",
+ align = "center",
+ widget = wibox.widget.textbox,
+ id = "speed"
+ },
+ spacing = dpi(10),
+ id = "layout3",
+ layout = wibox.layout.fixed.horizontal
+ },
+ id = "place4",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ {
+ { -- Humidity
+ {
+ forced_width = dpi(24),
+ forced_height = dpi(24),
+ widget = wibox.widget.imagebox,
+ image = gears.color.recolor_image(icondir .. "humidity.svg", color["OrangeA200"]),
+ id = "humidity_icon"
+ },
+ {
+ text = "",
+ valign = "center",
+ align = "center",
+ widget = wibox.widget.textbox,
+ id = "humidity"
+ },
+ spacing = dpi(10),
+ id = "layoutHum",
+ layout = wibox.layout.fixed.horizontal
+ },
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "lyt",
+ spacing = dpi(10),
+ layout = wibox.layout.fixed.vertical
+ },
+ margins = dpi(20),
+ widget = wibox.container.margin,
+ },
+ id = "center",
+ halign = "center",
+ valign = "center",
+ widget = wibox.container.place
+ },
+ id = "background",
+ border_color = color["Grey800"],
+ border_width = dpi(4),
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(12))
+ end,
+ widget = wibox.container.background
+ },
+ id = "margin",
+ top = dpi(20),
+ left = dpi(20),
+ right = dpi(10),
+ bottom = dpi(10),
+ forced_width = dpi(250),
+ widget = wibox.container.margin
+ }
+
+ local function fetch_weather_data()
+ awful.spawn.easy_async_with_shell(
+ "curl -sf 'http://api.openweathermap.org/data/2.5/weather?id=" .. api_secrets.city_id .. "&units=" .. api_secrets.unit .. "&appid=" .. api_secrets.key .. "'",
+ function(stdout)
+ if not stdout:match('error') then
+ local weather_metadata = json_lua:decode(stdout)
+ if weather_metadata then
+ local temp = weather_metadata.main.temp
+ local humidity = weather_metadata.main.humidity
+ local city = weather_metadata.name
+ local country = weather_metadata.sys.country
+ local weather_icon = weather_metadata.weather[1].icon
+ local description = weather_metadata.weather[1].description
+ local speed = weather_metadata.wind.speed
+
+ local icon_table = {
+ ["01d"] = "weather-sunny",
+ ["01n"] = "weather-clear-night",
+ ["02d"] = "weather-partly-cloudy",
+ ["02n"] = "weather-night-partly-cloudy",
+ ["03d"] = "weather-cloudy",
+ ["03n"] = "weather-clouds-night",
+ ["04d"] = "weather-cloudy",
+ ["04n"] = "weather-cloudy",
+ ["09d"] = "weather-rainy",
+ ["09n"] = "weather-rainy",
+ ["10d"] = "weather-partly-rainy",
+ ["10n"] = "weather-partly-rainy",
+ ["11d"] = "weather-pouring",
+ ["11n"] = "weather-pouring",
+ ["13d"] = "weather-snowy",
+ ["13n"] = "weather-snowy",
+ ["50d"] = "weather-fog",
+ ["50n"] = "weather-fog"
+ }
+
+ weather_widget:get_children_by_id("icon")[1].image = icondir .. icon_table[weather_icon] .. ".svg"
+ weather_widget:get_children_by_id("temp")[1].text = math.floor(temp + 0.5) .. "°C"
+ weather_widget:get_children_by_id("city_country")[1].text = city .. ", " .. country
+ weather_widget:get_children_by_id("description")[1].text = description:sub(1, 1):upper() .. description:sub(2)
+ weather_widget:get_children_by_id("line")[1].bg = color["Grey800"]
+ weather_widget:get_children_by_id("speed")[1].text = speed .. " m/s"
+ weather_widget:get_children_by_id("humidity")[1].text = humidity .. "%"
+
+ end
+ end
+ end
+ )
+ end
+
+ fetch_weather_data()
+
+ gears.timer {
+ timeout = 900,
+ autostart = true,
+ callback = function()
+ fetch_weather_data()
+ end
+ }
+
+ return weather_widget
+
+end
diff --git a/awesome/src/modules/volume_controller.lua b/awesome/src/modules/volume_controller.lua
index a2b7cdb..ae437e2 100644
--- a/awesome/src/modules/volume_controller.lua
+++ b/awesome/src/modules/volume_controller.lua
@@ -706,10 +706,18 @@ return function(s)
stdout = function(line)
get_input_devices()
get_source_devices()
+ awful.spawn.with_shell("pkill pactl && pkill grep")
end
}
)
+ awesome.connect_signal(
+ "exit",
+ function()
+ awful.spawn.with_shell("pkill pactl && pkill grep")
+ end
+ )
+
-- Get microphone volume
local function get_mic_volume()
awful.spawn.easy_async_with_shell(
@@ -834,8 +842,10 @@ return function(s)
function(volume)
if volume > 0 then
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.icon:set_image(gears.color.recolor_image(icondir .. "microphone.svg", color["LightBlue200"]))
+ awesome.emit_signal("update::microphone_widget", tonumber(volume), icondir .. "microphone.svg")
else
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.icon:set_image(gears.color.recolor_image(icondir .. "microphone-off.svg", color["LightBlue200"]))
+ awesome.emit_signal("update::microphone_widget", tonumber(volume), icondir .. "microphone-off.svg")
end
end
)
diff --git a/awesome/src/scripts/wifi.sh b/awesome/src/scripts/wifi.sh
new file mode 100755
index 0000000..e69de29
diff --git a/awesome/src/theme/user_variables.lua b/awesome/src/theme/user_variables.lua
index af0494f..efac15f 100644
--- a/awesome/src/theme/user_variables.lua
+++ b/awesome/src/theme/user_variables.lua
@@ -8,6 +8,17 @@ local home = os.getenv("HOME")
-- If you want different default programs, wallpaper path or modkey; edit this file.
user_vars = {
+ -- Uses the openweather api https://home.openweathermap.org/api_keys
+ -- City ID is also from there
+ weather_secrets = {
+ key = "e71b00168ca7219563dde4514a425b14",
+ city_id = "2864118",
+ unit = "metric" -- "metric" or "imperial"
+ },
+
+ -- Do not Disturb will turn off all notifications but keep the notification-list in the notification-center
+ dnd = false,
+
-- Autotiling layouts
layouts = {
awful.layout.suit.tile,
@@ -38,7 +49,8 @@ user_vars = {
"flatpak run com.spotify.Client",
"discord",
"/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1",
- "setxkbmap -option caps:swapescape"
+ "setxkbmap -option caps:swapescape",
+ "whatsdesk"
},
-- Type 'ip a' and check your wlan and ethernet name
diff --git a/awesome/src/widgets/audio.lua b/awesome/src/widgets/audio.lua
index a584772..09dc3f6 100644
--- a/awesome/src/widgets/audio.lua
+++ b/awesome/src/widgets/audio.lua
@@ -79,6 +79,7 @@ return function(s)
audio_widget.container.audio_layout.icon_margin.icon_layout.icon:set_image(
gears.color.recolor_image(icon .. ".svg", color["Grey900"]))
awesome.emit_signal("get::volume", volume)
+ awesome.emit_signal("update::volume_widget", volume, icon .. ".svg")
end
)
end
diff --git a/awesome/src/widgets/battery.lua b/awesome/src/widgets/battery.lua
index ea80907..6ed2c55 100644
--- a/awesome/src/widgets/battery.lua
+++ b/awesome/src/widgets/battery.lua
@@ -163,7 +163,7 @@ return function()
battery_widget.container.battery_layout.icon_margin.icon_layout.icon:set_image(gears.surface.load_uncached(
gears.color.recolor_image(icondir .. icon .. '.svg', "#212121")))
-
+ awesome.emit_signal("update::battery_widget", battery_percentage, icondir .. icon .. ".svg")
end
)
end
diff --git a/awesome/src/widgets/cpu_info.lua b/awesome/src/widgets/cpu_info.lua
index f9b6318..1a5df70 100644
--- a/awesome/src/widgets/cpu_info.lua
+++ b/awesome/src/widgets/cpu_info.lua
@@ -155,6 +155,7 @@ return function(widget, clock_mode)
local diff_usage = (1000 * (diff_total - diff_idle) / diff_total + 5) / 10
cpu_usage_widget.container.cpu_layout.label.text = tostring(math.floor(diff_usage)) .. "%"
+ awesome.emit_signal("update::cpu_usage_widget", math.floor(diff_usage + 0.5))
total_prev = total
idle_prev = idle
@@ -185,6 +186,7 @@ return function(widget, clock_mode)
cpu_temp.container.cpu_layout.icon_margin.icon_layout.icon:set_image(temp_icon)
cpu_temp:set_bg(temp_color)
cpu_temp.container.cpu_layout.label.text = math.floor(temp_num) .. "°C"
+ awesome.emit_signal("update::cpu_temp_widget", temp_num, temp_icon)
end
)
@@ -205,9 +207,9 @@ return function(widget, clock_mode)
average = average + cpu_freq[i]
end
average = math.floor(average / #cpu_freq)
- cpu_clock.container.cpu_layout.label.text = tonumber(average) .. "Mhz"
+ cpu_clock.container.cpu_layout.label.text = average .. "Mhz"
elseif clock_mode then
- cpu_clock.container.cpu_layout.label.text = tonumber(cpu_freq[clock_mode]) .. "Mhz"
+ cpu_clock.container.cpu_layout.label.text = cpu_freq[clock_mode] .. "Mhz"
end
end
)
diff --git a/awesome/src/widgets/gpu_info.lua b/awesome/src/widgets/gpu_info.lua
index 69b88c9..16608d0 100644
--- a/awesome/src/widgets/gpu_info.lua
+++ b/awesome/src/widgets/gpu_info.lua
@@ -103,6 +103,7 @@ return function(widget)
3,
function(_, stdout)
gpu_usage_widget.container.gpu_layout.label.text = stdout:gsub("\n", "") .. "%"
+ awesome.emit_signal("update::gpu_usage_widget", tonumber(stdout))
end
)
@@ -131,6 +132,7 @@ return function(widget)
gpu_temp_widget.container.gpu_layout.icon_margin.icon_layout.icon:set_image(temp_icon)
gpu_temp_widget:set_bg(temp_color)
gpu_temp_widget.container.gpu_layout.label.text = tostring(temp_num) .. "°C"
+ awesome.emit_signal("update::gpu_temp_widget", temp_num, temp_icon)
end
)
diff --git a/awesome/src/widgets/ram_info.lua b/awesome/src/widgets/ram_info.lua
index 09b9c2e..14e8c74 100644
--- a/awesome/src/widgets/ram_info.lua
+++ b/awesome/src/widgets/ram_info.lua
@@ -64,7 +64,10 @@ return function()
local MemTotal, MemFree, MemAvailable = stdout:match("(%d+)\n(%d+)\n(%d+)\n")
- ram_widget.container.ram_layout.label.text = tostring(string.format("%.1f", ((MemTotal - MemAvailable) / 1024 / 1024)) .. "/" .. string.format("%.1f", (MemTotal / 1024 / 1024)) .. "GB"):gsub(",", ".")
+ local ram_string = tostring(string.format("%.1f", ((MemTotal - MemAvailable) / 1024 / 1024)) .. "/" .. string.format("%.1f", (MemTotal / 1024 / 1024)) .. "GB"):gsub(",", ".")
+
+ ram_widget.container.ram_layout.label.text = ram_string
+ awesome.emit_signal("update::ram_widget", math.floor(((MemTotal - MemAvailable) / MemTotal * 100) + 0.5))
end
)
diff --git a/awesome/src/widgets/systray.lua b/awesome/src/widgets/systray.lua
index 95111d7..41945f4 100644
--- a/awesome/src/widgets/systray.lua
+++ b/awesome/src/widgets/systray.lua
@@ -20,7 +20,7 @@ return function(s)
id = 'st'
},
strategy = "exact",
- layout = wibox.container.constraint,
+ widget = wibox.container.constraint,
id = "container"
},
widget = wibox.container.background,