From f42a3a2cc941e34dd938b1e6bc24785a44781db2 Mon Sep 17 00:00:00 2001 From: delta Date: Sun, 21 May 2023 10:12:46 +0200 Subject: [PATCH] major update of awesome config add new icons, switch over to using stylesheets instead of gears.color.recolor_image, add a music widget to the panel, optimize services in common.lua, fix the application lense filtering and increase the update rate of services in common.lua Signed-off-by: delta --- .../awesome/assets/phosphor/browser-fill.svg | 1 + .config/awesome/assets/phosphor/code-fill.svg | 1 + .../assets/phosphor/discord-logo-fill.svg | 1 + .../assets/phosphor/game-controller-fill.svg | 1 + .../assets/phosphor/grid-four-fill.svg | 1 + .../awesome/assets/phosphor/house-fill.svg | 1 + .config/awesome/assets/phosphor/init.lua | 3 +- .../assets/phosphor/music-notes-fill.svg | 1 + .../awesome/assets/phosphor/pause-fill.svg | 1 + .config/awesome/assets/phosphor/play-fill.svg | 1 + .../assets/phosphor/skip-back-fill.svg | 1 + .../assets/phosphor/skip-forward-fill.svg | 1 + .../assets/phosphor/spotify-logo-fill.svg | 1 + .../assets/phosphor/vinyl-record-fill.svg | 1 + .config/awesome/misc/autostart.lua | 4 +- .config/awesome/misc/cfg.lua | 40 +- .config/awesome/misc/keys.lua | 19 +- .config/awesome/quarrel/bind.lua | 6 +- .config/awesome/quarrel/native/Cargo.toml | 4 +- .../quarrel/native/src/lenses/application.rs | 6 +- .config/awesome/quarrel/native/src/lib.rs | 6 + .config/awesome/quarrel/native/src/net/mod.rs | 8 +- .config/awesome/quarrel/native/src/time.rs | 75 ++ .config/awesome/quarrel/service.lua | 18 - .config/awesome/quarrel/store.lua | 3 + .config/awesome/quarrel/ui.lua | 91 ++- .config/awesome/quarrel/vars.lua | 2 - .config/awesome/rc.lua | 21 +- .config/awesome/services/common.lua | 72 +- .config/awesome/services/init.lua | 2 +- .config/awesome/services/playerctl.lua | 20 +- .config/awesome/signals/screen.lua | 59 +- .config/awesome/ui/fresnel/init.lua | 6 +- .config/awesome/ui/insightful/init.lua | 5 +- .config/awesome/ui/statusbar/init.lua | 13 +- .config/awesome/ui/statusbar/panel/init.lua | 58 +- .../ui/statusbar/panel/widgets/displays.lua | 84 +-- .../ui/statusbar/panel/widgets/imagebox.lua | 706 ++++++++++++++++++ .../ui/statusbar/panel/widgets/music.lua | 200 +++++ .../ui/statusbar/panel/widgets/power_menu.lua | 2 +- .../ui/statusbar/panel/widgets/wifi.lua | 42 ++ .../awesome/ui/statusbar/widgets/battery.lua | 32 - .../ui/statusbar/widgets/brightness.lua | 32 - .../awesome/ui/statusbar/widgets/displays.lua | 39 + .../awesome/ui/statusbar/widgets/taglist.lua | 25 +- .../awesome/ui/statusbar/widgets/volume.lua | 36 - .config/awesome/ui/statusbar/widgets/wifi.lua | 38 - 47 files changed, 1389 insertions(+), 401 deletions(-) create mode 100644 .config/awesome/assets/phosphor/browser-fill.svg create mode 100644 .config/awesome/assets/phosphor/code-fill.svg create mode 100644 .config/awesome/assets/phosphor/discord-logo-fill.svg create mode 100644 .config/awesome/assets/phosphor/game-controller-fill.svg create mode 100644 .config/awesome/assets/phosphor/grid-four-fill.svg create mode 100644 .config/awesome/assets/phosphor/house-fill.svg create mode 100644 .config/awesome/assets/phosphor/music-notes-fill.svg create mode 100644 .config/awesome/assets/phosphor/pause-fill.svg create mode 100644 .config/awesome/assets/phosphor/play-fill.svg create mode 100644 .config/awesome/assets/phosphor/skip-back-fill.svg create mode 100644 .config/awesome/assets/phosphor/skip-forward-fill.svg create mode 100644 .config/awesome/assets/phosphor/spotify-logo-fill.svg create mode 100644 .config/awesome/assets/phosphor/vinyl-record-fill.svg create mode 100644 .config/awesome/quarrel/native/src/time.rs delete mode 100644 .config/awesome/quarrel/service.lua create mode 100644 .config/awesome/quarrel/store.lua create mode 100644 .config/awesome/ui/statusbar/panel/widgets/imagebox.lua create mode 100644 .config/awesome/ui/statusbar/panel/widgets/music.lua create mode 100644 .config/awesome/ui/statusbar/panel/widgets/wifi.lua delete mode 100644 .config/awesome/ui/statusbar/widgets/battery.lua delete mode 100644 .config/awesome/ui/statusbar/widgets/brightness.lua create mode 100644 .config/awesome/ui/statusbar/widgets/displays.lua delete mode 100644 .config/awesome/ui/statusbar/widgets/volume.lua delete mode 100644 .config/awesome/ui/statusbar/widgets/wifi.lua diff --git a/.config/awesome/assets/phosphor/browser-fill.svg b/.config/awesome/assets/phosphor/browser-fill.svg new file mode 100644 index 0000000..68d95e5 --- /dev/null +++ b/.config/awesome/assets/phosphor/browser-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/code-fill.svg b/.config/awesome/assets/phosphor/code-fill.svg new file mode 100644 index 0000000..bae0f84 --- /dev/null +++ b/.config/awesome/assets/phosphor/code-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/discord-logo-fill.svg b/.config/awesome/assets/phosphor/discord-logo-fill.svg new file mode 100644 index 0000000..14ccd91 --- /dev/null +++ b/.config/awesome/assets/phosphor/discord-logo-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/game-controller-fill.svg b/.config/awesome/assets/phosphor/game-controller-fill.svg new file mode 100644 index 0000000..ee1ab62 --- /dev/null +++ b/.config/awesome/assets/phosphor/game-controller-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/grid-four-fill.svg b/.config/awesome/assets/phosphor/grid-four-fill.svg new file mode 100644 index 0000000..dc1869e --- /dev/null +++ b/.config/awesome/assets/phosphor/grid-four-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/house-fill.svg b/.config/awesome/assets/phosphor/house-fill.svg new file mode 100644 index 0000000..592fcd7 --- /dev/null +++ b/.config/awesome/assets/phosphor/house-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/init.lua b/.config/awesome/assets/phosphor/init.lua index c6a7eec..d17eae3 100644 --- a/.config/awesome/assets/phosphor/init.lua +++ b/.config/awesome/assets/phosphor/init.lua @@ -1,5 +1,4 @@ local gfs = require "gears.filesystem" -local gsurface = require "gears.surface" local qfs = require "quarrel.fs" local icons = {} @@ -7,7 +6,7 @@ local phosphor_dir = gfs.get_configuration_dir() .. "assets/phosphor/" for _, icon in ipairs(qfs.ls_files(phosphor_dir)) do if icon:match(".+%.(.+)") == "svg" then - icons[icon:match("(.+)%..+"):gsub("-", "_")] = gsurface.load_uncached(phosphor_dir .. icon) + icons[icon:match("(.+)%..+"):gsub("-", "_")] = phosphor_dir .. icon end end diff --git a/.config/awesome/assets/phosphor/music-notes-fill.svg b/.config/awesome/assets/phosphor/music-notes-fill.svg new file mode 100644 index 0000000..a5e893e --- /dev/null +++ b/.config/awesome/assets/phosphor/music-notes-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/pause-fill.svg b/.config/awesome/assets/phosphor/pause-fill.svg new file mode 100644 index 0000000..5226bcc --- /dev/null +++ b/.config/awesome/assets/phosphor/pause-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/play-fill.svg b/.config/awesome/assets/phosphor/play-fill.svg new file mode 100644 index 0000000..b591fb7 --- /dev/null +++ b/.config/awesome/assets/phosphor/play-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/skip-back-fill.svg b/.config/awesome/assets/phosphor/skip-back-fill.svg new file mode 100644 index 0000000..8ddcb2f --- /dev/null +++ b/.config/awesome/assets/phosphor/skip-back-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/skip-forward-fill.svg b/.config/awesome/assets/phosphor/skip-forward-fill.svg new file mode 100644 index 0000000..169cbc5 --- /dev/null +++ b/.config/awesome/assets/phosphor/skip-forward-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/spotify-logo-fill.svg b/.config/awesome/assets/phosphor/spotify-logo-fill.svg new file mode 100644 index 0000000..295cf53 --- /dev/null +++ b/.config/awesome/assets/phosphor/spotify-logo-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/assets/phosphor/vinyl-record-fill.svg b/.config/awesome/assets/phosphor/vinyl-record-fill.svg new file mode 100644 index 0000000..ae62442 --- /dev/null +++ b/.config/awesome/assets/phosphor/vinyl-record-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.config/awesome/misc/autostart.lua b/.config/awesome/misc/autostart.lua index 1747db6..3cd70f9 100644 --- a/.config/awesome/misc/autostart.lua +++ b/.config/awesome/misc/autostart.lua @@ -11,9 +11,9 @@ local programs = { "wezterm start --class code_term", "firefox", "discord", - "env LD_PRELOAD=/usr/lib/spotify-adblock.so spotify" + "LD_PRELOAD=/usr/lib/spotify-adblock.so spotify" } for _, program in ipairs(programs) do - awful.spawn(program) + awful.spawn.with_shell(program .. " 1>/dev/null 2>&1") end diff --git a/.config/awesome/misc/cfg.lua b/.config/awesome/misc/cfg.lua index 0d9bcba..05534b1 100644 --- a/.config/awesome/misc/cfg.lua +++ b/.config/awesome/misc/cfg.lua @@ -1,6 +1,38 @@ -local c = { - titlebars_enabled = false, - terminal = "wezterm" +local awful = require "awful" +local phosphor = require "assets.phosphor" + +local cfg = { + terminal = "wezterm", + tags = { + { + layout = awful.layout.suit.floating, + selected = true, + icon = phosphor.house_fill + }, + { + layout = awful.layout.suit.floating, + icon = phosphor.browser_fill + }, + { + layout = awful.layout.suit.tile.left, + master_width_factor = 0.7, + icon = phosphor.discord_logo_fill + }, + { + layout = awful.layout.suit.tile.top, + master_width_factor = 0.2, + icon = phosphor.spotify_logo_fill + }, + { + layout = awful.layout.suit.tile.right, + master_width_factor = 0.7, + icon = phosphor.code_fill + }, + { + layout = awful.layout.suit.floating, + icon = phosphor.game_controller_fill + } + } } -return c +return cfg diff --git a/.config/awesome/misc/keys.lua b/.config/awesome/misc/keys.lua index 432f3eb..646be52 100644 --- a/.config/awesome/misc/keys.lua +++ b/.config/awesome/misc/keys.lua @@ -1,12 +1,13 @@ local awful = require "awful" +local beautiful = require "beautiful" local cfg = require "misc.cfg" local fresnel = require "ui.fresnel" local gtimer = require "gears.timer" local insightful = require "ui.insightful" local naughty = require "naughty" +local playerctl = require "services.playerctl" local qbind = require "quarrel.bind" local qvars = require "quarrel.vars" -local playerctl = require "services.playerctl" local recording = { false, "" } @@ -120,7 +121,6 @@ awful.keyboard.append_global_keybindings { }, qbind:new { - mods = {}, triggers = "XF86AudioMute", press = function() awful.spawn("wpctl set-mute @DEFAULT_SINK@ toggle") @@ -129,7 +129,6 @@ awful.keyboard.append_global_keybindings { desc = "mute" }, qbind:new { - mods = {}, triggers = { { "XF86AudioRaiseVolume", true }, { "XF86AudioLowerVolume", false } @@ -145,7 +144,6 @@ awful.keyboard.append_global_keybindings { desc = "increase/decrease volume" }, qbind:new { - mods = {}, triggers = { { "XF86AudioNext", true }, { "XF86AudioPrev", false } @@ -161,7 +159,6 @@ awful.keyboard.append_global_keybindings { desc = "previous/next song" }, qbind:new { - mods = {}, triggers = "XF86AudioPlay", press = function() playerctl:play_pause() @@ -171,7 +168,6 @@ awful.keyboard.append_global_keybindings { }, qbind:new { - mods = {}, triggers = { { "XF86MonBrightnessUp", true }, { "XF86MonBrightnessDown", false } @@ -198,7 +194,6 @@ awful.keyboard.append_global_keybindings { }, qbind:new { - mods = {}, triggers = "Print", press = function() local date = os.date("%Y%m%d_%H%M%S") @@ -283,5 +278,15 @@ awful.keyboard.append_global_keybindings { press = awful.tag.viewnext, group = "tag", desc = "switch to next" + }, + qbind:new { + mods = qvars.mods.MC, + triggers = "x", + press = function() + local tag = awful.screen.focused().selected_tag + tag.master_width_factor = cfg.tags[tonumber(tag.name)].master_width_factor or beautiful.master_width_factor + end, + group = "tag", + desc = "reset master width" } } diff --git a/.config/awesome/quarrel/bind.lua b/.config/awesome/quarrel/bind.lua index 327da0b..4cb5d44 100644 --- a/.config/awesome/quarrel/bind.lua +++ b/.config/awesome/quarrel/bind.lua @@ -1,9 +1,11 @@ local awful = require "awful" local gtable = require "gears.table" -local insightful = require "ui.insightful" +local qstore = require "quarrel.store" local qbind = {} +qstore.bindings = {} + local function get_binding_function(trigger) if type(trigger) == "number" and trigger <= 5 and trigger > 0 then return "button" @@ -37,7 +39,7 @@ local function translate_binding(binding, trigger, multiple) end function qbind:new(binding) - if not binding.hidden then table.insert(insightful._bindings, binding) end + if not binding.hidden then table.insert(qstore.bindings, binding) end binding.mods = binding.mods or {} local awful_bindings = {} diff --git a/.config/awesome/quarrel/native/Cargo.toml b/.config/awesome/quarrel/native/Cargo.toml index 6c44528..9cff8fc 100644 --- a/.config/awesome/quarrel/native/Cargo.toml +++ b/.config/awesome/quarrel/native/Cargo.toml @@ -9,12 +9,14 @@ edition = "2021" freedesktop_entry_parser = "1.3.0" cpc = "1.9.1" mlua = { version = "0.8.7", features = [ "module", "lua54", "serialize" ] } -palette = { version = "0.6.1", default-features = false, features = [ "std" ] } rayon = "1.6.1" serde = { version = "1.0.152", features = [ "derive" ] } url = "2.3.1" rodio = "0.17.1" nix = "0.26.2" +chrono = "0.4.24" +itertools = "0.10.5" +html-escape = "0.2.13" [lib] crate-type = ["cdylib"] diff --git a/.config/awesome/quarrel/native/src/lenses/application.rs b/.config/awesome/quarrel/native/src/lenses/application.rs index b0135d4..0857802 100644 --- a/.config/awesome/quarrel/native/src/lenses/application.rs +++ b/.config/awesome/quarrel/native/src/lenses/application.rs @@ -13,10 +13,6 @@ use crate::lenses::entry::{ Entry, }; -fn contains_ignore_ascii_case(a: &str, b: &str) -> bool { - return false; -} - fn parse_entry(entry: &fd::Entry, path: &PathBuf) -> Result { let section = entry.section("Desktop Entry"); let name = section.attr("Name").ok_or(())?.to_string(); @@ -84,7 +80,7 @@ pub fn query(lua: &Lua, input: String) -> LuaResult { Ok(entries_to_lua_table( parsed_entries .into_iter() - .filter(|entry| entry.message.to_lowercase().contains(&input)) + .filter(|entry| entry.message.to_lowercase().contains(&input.to_lowercase())) .collect(), lua, )) diff --git a/.config/awesome/quarrel/native/src/lib.rs b/.config/awesome/quarrel/native/src/lib.rs index e21e306..d89b610 100644 --- a/.config/awesome/quarrel/native/src/lib.rs +++ b/.config/awesome/quarrel/native/src/lib.rs @@ -2,6 +2,7 @@ mod lenses; mod net; use mlua::prelude::*; +use html_escape::decode_html_entities_to_string; #[mlua::lua_module] fn qnative(lua: &Lua) -> LuaResult { @@ -12,6 +13,11 @@ fn qnative(lua: &Lua) -> LuaResult { let exports = lua.create_table()?; exports.set("lenses", lenses)?; exports.set("get_essid", lua.create_function(net::get_first_essid)?)?; + exports.set("decode_html", lua.create_function(|_: &Lua, string: String| { + let mut output = String::new(); + decode_html_entities_to_string(string, &mut output); + Ok(output) + })?)?; Ok(exports) } diff --git a/.config/awesome/quarrel/native/src/net/mod.rs b/.config/awesome/quarrel/native/src/net/mod.rs index c9d617c..71eaeea 100644 --- a/.config/awesome/quarrel/native/src/net/mod.rs +++ b/.config/awesome/quarrel/native/src/net/mod.rs @@ -10,7 +10,6 @@ use std::{ }, mem::size_of, os::fd::RawFd, - str, }; use mlua::prelude::*; @@ -23,7 +22,7 @@ use nix::{ SockFlag, SockType, }, - unistd::close + unistd::close, }; use wireless::{ IfConf, @@ -59,6 +58,7 @@ pub fn get_first_essid(_: &Lua, _: ()) -> LuaResult { if_req = if_conf.data.ifc_req; } + #[allow(clippy::cast_possible_truncation)] for _ in 0..if_conf.ifc_len / size_of::() as c_int { if let Ok(essid) = get_essid(socket, unsafe { *if_req }.ifr_name) { close(socket).map_err(LuaError::external)?; @@ -90,9 +90,7 @@ fn get_essid(socket: RawFd, if_name: [c_char; IF_NAMESIZE]) -> LuaResult ioctl_get_essid(socket, &mut wrq).map_err(LuaError::external)?; } - Ok(str::from_utf8(essid.as_slice()) - .map_err(LuaError::external)? - .to_owned()) + String::from_utf8(essid.to_vec()).map_err(LuaError::external) } fn get_first_socket() -> LuaResult { diff --git a/.config/awesome/quarrel/native/src/time.rs b/.config/awesome/quarrel/native/src/time.rs new file mode 100644 index 0000000..9850822 --- /dev/null +++ b/.config/awesome/quarrel/native/src/time.rs @@ -0,0 +1,75 @@ +use chrono::prelude::*; +use mlua::{ + prelude::*, + LuaSerdeExt, +}; + +// Taken from https://github.com/chronotope/chrono/issues/69#issuecomment-1510506428 +trait NaiveDateExt { + fn days_in_month(&self) -> u32; + fn days_in_year(&self) -> u32; + fn is_leap_year(&self) -> bool; +} + +impl NaiveDateExt for NaiveDate { + fn days_in_month(&self) -> u32 { + let month = self.month(); + match month { + 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, + 4 | 6 | 9 | 11 => 30, + 2 => { + if self.is_leap_year() { + 29 + } else { + 28 + } + } + _ => panic!("Invalid month: {}", month), + } + } + + fn days_in_year(&self) -> u32 { + if self.is_leap_year() { + 366 + } else { + 365 + } + } + + fn is_leap_year(&self) -> bool { + let year = self.year(); + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + } +} + +struct Day { + day: u32, + ce: bool, + weekday: Weekday, +} + +pub fn get_calendar_table(lua: &Lua, (year, month, day): (i32, u32, u32)) -> LuaResult { + let date = + NaiveDate::from_ymd_opt(year, month, day).ok_or(LuaError::external("invalid date"))?; + let days: Vec = (1..=date.days_in_month()) + .map(|day| NaiveDate::from_ymd_opt(date.year(), date.month(), day).unwrap()) + .map(|date| { + let (ce, year) = date.year_ce(); + Day { + day: date.day(), + ce, + weekday: date.weekday(), + } + }) + .collect(); + + let calendar: Vec> = vec![vec![], vec![], vec![], vec![], vec![], vec![], vec![]]; + + if days[1].weekday != Weekday::Mon { + get_calendar_table(lua) + } + + if days.last().unwrap().weekday != Weekday::Sun {} + + Ok(lua.create_table()?) +} diff --git a/.config/awesome/quarrel/service.lua b/.config/awesome/quarrel/service.lua deleted file mode 100644 index 2c77651..0000000 --- a/.config/awesome/quarrel/service.lua +++ /dev/null @@ -1,18 +0,0 @@ -local gtimer = require "gears.timer" - -local qservice = {} - -function qservice.register(name, service, icon) - gtimer { - timeout = 1, - call_now = true, - autostart = true, - callback = function() - local service_result = table.pack(service()) - awesome.emit_signal("services::" .. name, table.unpack(service_result)) - awesome.emit_signal("services::" .. name .. "::icon", icon(table.unpack(service_result))) - end - } -end - -return qservice diff --git a/.config/awesome/quarrel/store.lua b/.config/awesome/quarrel/store.lua new file mode 100644 index 0000000..9f6cff2 --- /dev/null +++ b/.config/awesome/quarrel/store.lua @@ -0,0 +1,3 @@ +local qstore = {} + +return qstore diff --git a/.config/awesome/quarrel/ui.lua b/.config/awesome/quarrel/ui.lua index 8e979cb..274d48a 100644 --- a/.config/awesome/quarrel/ui.lua +++ b/.config/awesome/quarrel/ui.lua @@ -1,5 +1,6 @@ local awful = require "awful" -local gears = require "gears" +local gtable = require "gears.table" +local qbind = require "quarrel.bind" local qvars = require "quarrel.vars" local wibox = require "wibox" @@ -17,12 +18,8 @@ function qui.font(factor) return qvars.text_font .. " " .. qvars.font_size * (factor or 1) end -function qui.symbol_font(factor) - return qvars.symbol_font .. " " .. qvars.font_size * (factor or 1) -end - function qui.styled(target) - return gears.table.crush({ + return gtable.crush({ bg = qvars.colors.bg, border_color = qvars.colors.bright.black, border_width = qvars.border_width, @@ -30,14 +27,14 @@ function qui.styled(target) }, target) end -function qui.popup(args) - args.widget = { +function qui.popup(target) + target.widget = { widget = wibox.container.margin, margins = qvars.big_padding, - args.widget + target.widget } - return awful.popup(qui.styled(args)) + return awful.popup(qui.styled(target)) end function qui.tooltip(objects, callback) @@ -49,4 +46,78 @@ function qui.tooltip(objects, callback) }) end +function qui.recolor(color) + return "svg{fill:" .. color .. "}" +end + +function qui.icon(image, color, target) + local widget = { + widget = wibox.widget.imagebox, + image = image, + forced_width = qvars.char_height, + forced_height = qvars.char_height, + stylesheet = qui.recolor(color or qvars.colors.fg) + } + if target then + return gtable.crush(widget, target) + else + return widget + end +end + +function qui.button(args) + args.press = args.press or function(_) end + local widget = wibox.widget(gtable.crush({ + widget = wibox.widget.imagebox, + image = args.image, + forced_height = qvars.char_height, + forced_width = qvars.char_height, + stylesheet = qui.recolor(qvars.colors.fg), + press = args.press + }, args.widget or {})) + + widget.buttons = { + qbind:new { + triggers = qvars.btns.left, + press = function() + widget:press() + end, + hidden = true + } + } + + return widget +end + +function qui.toggle(args) + args.press = args.press or function(_) end + local widget = qui.button({ + widget = gtable.crush({ + toggled = false, + silent_press = function(self, state) + if state then + self.toggled = state + else + self.toggled = not self.toggled + end + + if self.toggled then + self.image = args.on + else + self.image = args.off + end + end, + }, args.widget or {}), + image = args.off, + press = function(self) + if not args.manual then + self:silent_press() + end + args.press(self) + end + }) + + return widget +end + return qui diff --git a/.config/awesome/quarrel/vars.lua b/.config/awesome/quarrel/vars.lua index 391e875..27da3f2 100644 --- a/.config/awesome/quarrel/vars.lua +++ b/.config/awesome/quarrel/vars.lua @@ -22,7 +22,6 @@ qvars.padding = dpi(4) qvars.big_padding = dpi(8) qvars.text_font = "Fira Code Nerd Font Mono Medium" -qvars.symbol_font = "Symbols Nerd Font:style=1000-em" qvars.font_size = 8 qvars.font = qvars.text_font .. " " .. qvars.font_size @@ -35,7 +34,6 @@ qvars.char_height = char_height qvars.char_width = char_width qvars.bar_size = dpi(24) + qvars.big_padding * 2 --- qvars.expanded_bar_size = qvars.bar_size * 6 qvars.element_size = dpi(12) qvars.expanded_bar_size = qvars.big_padding + (qvars.big_padding * 2 + qvars.element_size * 4) * 3 + qvars.padding * 2 diff --git a/.config/awesome/rc.lua b/.config/awesome/rc.lua index aecbdb5..67a8187 100644 --- a/.config/awesome/rc.lua +++ b/.config/awesome/rc.lua @@ -1,14 +1,15 @@ -pcall(require, "luarocks.loader") +-- -- +-- ___ ___ ___ ___ ___ ___ ___ ___ -- +-- /\ \ /\ \ /\ \ /\ \ /\__\ /\ \ /\ \ /\ \ -- +-- /::\ \ /::\ \ _\:\ \ /::\ \ /::L_L_ _\:\ \ \:\ \ /::\ \ -- +-- /::\:\__\ /::\:\__\ /\/::\__\ /\:\:\__\ /:/L:\__\ /\/::\__\ /::\__\ /::\:\__\ -- +-- \/\::/ / \;:::/ / \::/\/__/ \:\:\/__/ \/_/:/ / \::/\/__/ /:/\/__/ \:\:\/ / -- +-- \/__/ |:\/__/ \:\__\ \::/ / /:/ / \:\__\ \/__/ \:\/ / -- +-- \|__| \/__/ \/__/ \/__/ \/__/ \/__/ -- +-- -- +---=-=-=-=-=-=-=-=-=-=-=-= A colourful and comfy AWM theme =-=-=-=-=-=-=-=-=-=-=-=--- --- ___ ___ ___ ___ ___ ___ ___ ___ --- /\ \ /\ \ /\ \ /\ \ /\__\ /\ \ /\ \ /\ \ --- /::\ \ /::\ \ _\:\ \ /::\ \ /::L_L_ _\:\ \ \:\ \ /::\ \ --- /::\:\__\ /::\:\__\ /\/::\__\ /\:\:\__\ /:/L:\__\ /\/::\__\ /::\__\ /::\:\__\ --- \/\::/ / \;:::/ / \::/\/__/ \:\:\/__/ \/_/:/ / \::/\/__/ /:/\/__/ \:\:\/ / --- \/__/ |:\/__/ \:\__\ \::/ / /:/ / \:\__\ \/__/ \:\/ / --- \|__| \/__/ \/__/ \/__/ \/__/ \/__/ --- ---=-=-=-=-=-=-=-=-=-=-=-= A colorful and comfy AWM theme =-=-=-=-=-=-=-=-=-=-=-=-- +pcall(require, "luarocks.loader") require("beautiful").init(require("gears.filesystem").get_configuration_dir() .. "/prismite.lua") diff --git a/.config/awesome/services/common.lua b/.config/awesome/services/common.lua index 07300db..b23a064 100644 --- a/.config/awesome/services/common.lua +++ b/.config/awesome/services/common.lua @@ -1,24 +1,51 @@ -local qfs = require "quarrel.fs" local gfs = require "gears.filesystem" -local qservice = require "quarrel.service" -local qjson = require "quarrel.json" -local qnative = require "quarrel.native" -local gcolor = require "gears.color" -local qmath = require "quarrel.math" +local gtimer = require "gears.timer" local phosphor = require "assets.phosphor" +local qfs = require "quarrel.fs" +local qjson = require "quarrel.json" +local qmath = require "quarrel.math" +local qnative = require "quarrel.native" +local qstore = require "quarrel.store" local qvars = require "quarrel.vars" +local q = require "quarrel" + +local function register(name, service, icon) + gtimer { + timeout = 0.5, + call_now = true, + autostart = true, + callback = function() + local service_result = table.pack(service()) + awesome.emit_signal("services::" .. name, table.unpack(service_result)) + awesome.emit_signal("services::" .. name .. "::icon", icon(table.unpack(service_result))) + end + } +end + +local function read(file, format) + local content = file:read(format or "a") + file:seek("set") + return content +end + +-- create file in case it's not there yet +if not gfs.file_readable("/tmp/wp_audio_status") then + assert(io.open("/tmp/wp_audio_status", "w")):write("{}"):close() +end +qstore.audio_file = assert(io.open("/tmp/wp_audio_status", "r")) +qstore.battery_capacity_file = assert(io.open("/sys/class/power_supply/BAT0/capacity", "r")) +qstore.battery_status_file = assert(io.open("/sys/class/power_supply/BAT0/status", "r")) +qstore.brightness_file = assert(io.open("/sys/class/backlight/amdgpu_bl0/actual_brightness", "r")) +qstore.wifi_file = assert(io.open("/proc/net/wireless", "r")) + -- follows the format `service = { provider, icon_provider }` local services = { audio = { -- volume, muted function() - if not gfs.file_readable("/tmp/wp_audio_status") then - awesome.emit_signal("services::audio", -1, false) - return - end - local audio_status = qjson.decode(qfs.read("/tmp/wp_audio_status")) - local default_sink = audio_status["alsa_output.usb-046d_G435_Wireless_Gaming_Headset_V001008005.1-01.analog-stereo"] + local audio_status = qjson.decode(read(qstore.audio_file)) + local default_sink = audio_status["G435 Wireless Gaming Headset Analog Stereo"] if not default_sink then return nil, false @@ -28,7 +55,7 @@ local services = { end, function(volume, muted) if muted or not volume then - return gcolor.recolor_image(phosphor["speaker_simple_x_fill"], qvars.colors.red) + return phosphor.speaker_simple_x_fill, qvars.colors.red end local icon_data = qmath.step_value(volume, { @@ -39,13 +66,13 @@ local services = { { 100 } }) - gcolor.recolor_image(phosphor["speaker_simple_" .. icon_data .. "_fill"], qvars.colors.fg) + return phosphor["speaker_simple_" .. icon_data .. "_fill"], qvars.colors.fg end }, battery = { -- capacity, status function() - return qfs.read("/sys/class/power_supply/BAT0/capacity", "n"), qfs.read("/sys/class/power_supply/BAT0/status", "l") + return read(qstore.battery_capacity_file, "n"), read(qstore.battery_status_file, "l") end, function(capacity, status) local icon_data = status == "Charging" and { "charging", "green" } or qmath.step_value(capacity, { @@ -57,13 +84,13 @@ local services = { { 100 } }) - return gcolor.recolor_image(phosphor["battery_vertical_" .. icon_data[1] .. "_fill"], qvars.colors[icon_data[2]]) + return phosphor["battery_vertical_" .. icon_data[1] .. "_fill"], qvars.colors[icon_data[2]] end }, brightness = { -- brightness function() - return qfs.read("/sys/class/backlight/amdgpu_bl0/actual_brightness", "n") + return read(qstore.brightness_file, "n") end, function(brightness) local icon_data = qmath.step_value(brightness, { @@ -75,7 +102,7 @@ local services = { { 255 } }) - return gcolor.recolor_image(phosphor[icon_data .. "_fill"], qvars.colors.fg) + return phosphor[icon_data .. "_fill"], qvars.colors.fg end }, wifi = { @@ -83,9 +110,10 @@ local services = { function() local lines = {} - for line in io.lines("/proc/net/wireless") do + for line in qstore.wifi_file:lines() do table.insert(lines, line) end + qstore.wifi_file:seek("set") if not lines[3] then return nil, 0, false @@ -97,7 +125,7 @@ local services = { end, function(_, strength, connected) if not connected then - return gcolor.recolor_image(phosphor.wifi_x_fill, qvars.colors.red) + return phosphor.wifi_x_fill, qvars.colors.red end local icon_data = qmath.step_value(strength, { @@ -108,11 +136,11 @@ local services = { { 100 } }) - return gcolor.recolor_image(phosphor["wifi_" .. icon_data[1] .. "_fill"], qvars.colors[icon_data[2]]) + return phosphor["wifi_" .. icon_data[1] .. "_fill"], qvars.colors[icon_data[2]] end } } for name, service in pairs(services) do - qservice.register(name, service[1], service[2]) + register(name, service[1], service[2]) end diff --git a/.config/awesome/services/init.lua b/.config/awesome/services/init.lua index 82e2096..4ac624f 100644 --- a/.config/awesome/services/init.lua +++ b/.config/awesome/services/init.lua @@ -1,2 +1,2 @@ -require "services.playerctl" require "services.common" +require "services.playerctl" diff --git a/.config/awesome/services/playerctl.lua b/.config/awesome/services/playerctl.lua index 01598f8..3fb0a3d 100644 --- a/.config/awesome/services/playerctl.lua +++ b/.config/awesome/services/playerctl.lua @@ -1,40 +1,40 @@ local playerctl = require "lib.bling.signal.playerctl".lib { - player = { "spotify", "ncmpcpp", "%any" } + player = { "spotify", "%any" } } -playerctl:connect_signal("metadata", function(...) +playerctl:connect_signal("metadata", function(_, ...) awesome.emit_signal("services::playerctl::metadata", ...) end) -playerctl:connect_signal("position", function(...) +playerctl:connect_signal("position", function(_, ...) awesome.emit_signal("services::playerctl::position", ...) end) -playerctl:connect_signal("playback_status", function(...) +playerctl:connect_signal("playback_status", function(_, ...) awesome.emit_signal("services::playerctl::playback_status", ...) end) -playerctl:connect_signal("seeked", function(...) +playerctl:connect_signal("seeked", function(_, ...) awesome.emit_signal("services::playerctl::seeked", ...) end) -playerctl:connect_signal("volume", function(...) +playerctl:connect_signal("volume", function(_, ...) awesome.emit_signal("services::playerctl::volume", ...) end) -playerctl:connect_signal("loop_status", function(...) +playerctl:connect_signal("loop_status", function(_, ...) awesome.emit_signal("services::playerctl::loop_status", ...) end) -playerctl:connect_signal("shuffle", function(...) +playerctl:connect_signal("shuffle", function(_, ...) awesome.emit_signal("services::playerctl::shuffle", ...) end) -playerctl:connect_signal("exit", function(...) +playerctl:connect_signal("exit", function(_, ...) awesome.emit_signal("services::playerctl::exit", ...) end) -playerctl:connect_signal("exit", function(...) +playerctl:connect_signal("exit", function(_, ...) awesome.emit_signal("services::playerctl::exit", ...) end) diff --git a/.config/awesome/signals/screen.lua b/.config/awesome/signals/screen.lua index ea247a3..706bf56 100644 --- a/.config/awesome/signals/screen.lua +++ b/.config/awesome/signals/screen.lua @@ -1,56 +1,11 @@ local awful = require "awful" +local cfg = require "misc.cfg" +local gtable = require "gears.table" screen.connect_signal("request::desktop_decoration", function(s) - awful.tag.add( - "1", - { - screen = s, - layout = awful.layout.suit.floating, - selected = true - } - ) - - awful.tag.add( - "2", - { - screen = s, - layout = awful.layout.suit.floating, - - } - ) - - awful.tag.add( - "3", - { - screen = s, - layout = awful.layout.suit.tile.left, - master_width_factor = 0.7 - } - ) - - awful.tag.add( - "4", - { - screen = s, - layout = awful.layout.suit.tile.top, - master_width_factor = 0.2 - } - ) - - awful.tag.add( - "5", - { - screen = s, - layout = awful.layout.suit.tile.right, - master_width_factor = 0.7 - } - ) - - awful.tag.add( - "6", - { - screen = s, - layout = awful.layout.suit.floating, - } - ) + for i, tag in ipairs(cfg.tags) do + awful.tag.add(tostring(i), gtable.crush({ + screen = s + }, tag)) + end end) diff --git a/.config/awesome/ui/fresnel/init.lua b/.config/awesome/ui/fresnel/init.lua index 29ead63..f31da12 100644 --- a/.config/awesome/ui/fresnel/init.lua +++ b/.config/awesome/ui/fresnel/init.lua @@ -25,7 +25,11 @@ fresnel._selected_index = 1 function fresnel:_exec_entry(entry_index) local exec = self._entries_exec[entry_index] if type(exec) ~= "userdata" and type(exec) ~= "nil" then - awful.spawn((exec[2] and cfg.terminal .. " -e " or "") .. exec[1]) + if exec[2] then + awful.spawn(cfg.terminal .. " -e /bin/sh -c " .. exec[1] .. " 1>/dev/null 2>&1") + else + awful.spawn.with_shell(exec[1] .. " 1>/dev/null 2>&1") + end end end diff --git a/.config/awesome/ui/insightful/init.lua b/.config/awesome/ui/insightful/init.lua index 7b3e537..e8a4a4d 100644 --- a/.config/awesome/ui/insightful/init.lua +++ b/.config/awesome/ui/insightful/init.lua @@ -1,6 +1,6 @@ local awful = require "awful" local beautiful = require "beautiful" -local gtable = require "gears.table" +local qstore = require "quarrel.store" local qtable = require "quarrel.table" local qui = require "quarrel.ui" local qvars = require "quarrel.vars" @@ -14,7 +14,6 @@ local mouse = "󰍽 " local insightful = {} insightful._toggled = false -insightful._bindings = {} insightful._selected_group = "" insightful._selected_group_index = 1 @@ -91,7 +90,7 @@ function insightful:_generate() local grouped_binds = {} local layout_container = insightful._widget.widget.layout_container - for _, keybind in ipairs(self._bindings) do + for _, keybind in ipairs(qstore.bindings) do local group = keybind.group or "general" local group_exists = grouped_binds[group] ~= nil diff --git a/.config/awesome/ui/statusbar/init.lua b/.config/awesome/ui/statusbar/init.lua index 7400a76..d4f2001 100644 --- a/.config/awesome/ui/statusbar/init.lua +++ b/.config/awesome/ui/statusbar/init.lua @@ -9,13 +9,10 @@ local qvars = require "quarrel.vars" local rubato = require "lib.rubato" local wibox = require "wibox" -local battery = require "ui.statusbar.widgets.battery" -local brightness = require "ui.statusbar.widgets.brightness" local clock = require "ui.statusbar.widgets.clock" +local displays = require "ui.statusbar.widgets.displays" local keyboardlayout = require "ui.statusbar.widgets.keyboardlayout" local taglist = require "ui.statusbar.widgets.taglist" -local volume = require "ui.statusbar.widgets.volume" -local wifi = require "ui.statusbar.widgets.wifi" screen.connect_signal("request::desktop_decoration", function(s) local expand_button = wibox.widget { @@ -52,10 +49,10 @@ screen.connect_signal("request::desktop_decoration", function(s) widget = wibox.container.place, valign = "bottom", { - brightness, - volume, - battery, - wifi, + displays.brightness, + displays.audio, + displays.battery, + displays.wifi, { widget = wibox.container.place, keyboardlayout diff --git a/.config/awesome/ui/statusbar/panel/init.lua b/.config/awesome/ui/statusbar/panel/init.lua index b9b414c..7685451 100644 --- a/.config/awesome/ui/statusbar/panel/init.lua +++ b/.config/awesome/ui/statusbar/panel/init.lua @@ -2,45 +2,47 @@ local qvars = require "quarrel.vars" local wibox = require "wibox" local displays = require "ui.statusbar.panel.widgets.displays" +local music = require "ui.statusbar.panel.widgets.music" local power_menu = require "ui.statusbar.panel.widgets.power_menu" - +local wifi = require "ui.statusbar.panel.widgets.wifi" local panel = wibox.widget { - -- widget = wibox.container.constraint, - -- width = qvars.expanded_bar_size, - -- strategy = "exact", - -- { - widget = wibox.container.margin, - margins = { - left = qvars.big_padding - }, + widget = wibox.container.margin, + margins = { + left = qvars.big_padding + }, + { { + widget = wibox.container.place, + valign = "top", { - widget = wibox.container.place, - valign = "top", { displays.battery, - displays.volume, + displays.audio, displays.brightness, layout = wibox.layout.fixed.horizontal, spacing = qvars.padding, - } - }, + }, + wifi, + music, + layout = wibox.layout.fixed.vertical, + spacing = qvars.padding + } + }, + { + widget = wibox.container.background, { - widget = wibox.container.background, - { - widget = wibox.widget.textbox, - text = ":)" - } - }, - { - widget = wibox.container.place, - valign = "bottom", - power_menu - }, - layout = wibox.layout.align.vertical, - } - -- } + widget = wibox.widget.textbox, + text = ":)" + } + }, + { + widget = wibox.container.place, + valign = "bottom", + power_menu + }, + layout = wibox.layout.align.vertical, + } } return panel diff --git a/.config/awesome/ui/statusbar/panel/widgets/displays.lua b/.config/awesome/ui/statusbar/panel/widgets/displays.lua index cd05253..de15bd5 100644 --- a/.config/awesome/ui/statusbar/panel/widgets/displays.lua +++ b/.config/awesome/ui/statusbar/panel/widgets/displays.lua @@ -1,9 +1,8 @@ -local qmath = require "quarrel.math" -local qvars = require "quarrel.vars" -local qui = require "quarrel.ui" -local wibox = require "wibox" local phosphor = require "assets.phosphor" -local gcolor = require "gears.color" +local qmath = require "quarrel.math" +local qui = require "quarrel.ui" +local qvars = require "quarrel.vars" +local wibox = require "wibox" local function create_display(icon, color) return wibox.widget(qui.styled { @@ -24,13 +23,7 @@ local function create_display(icon, color) forced_width = qvars.element_size * 4, { widget = wibox.container.place, - { - widget = wibox.widget.imagebox, - image = icon, - forced_height = qvars.char_height, - forced_width = qvars.char_height, - id = "icon" - } + qui.icon(icon, color, { id = "icon" }) }, id = "indicator" }, @@ -50,55 +43,40 @@ local function create_display(icon, color) }) end -local d_battery = create_display(gcolor.recolor_image(phosphor.battery_vertical_warning_fill, qvars.colors.fg), qvars.colors.red) - -awesome.connect_signal("services::battery", function(capacity, status) - local icon_data = status == "Charging" and { "charging", "green" } or qmath.step_value(capacity, { - { 0, { "empty", "red" } }, - { 20, { "low", "red" } }, - { 40, { "medium", "yellow" } }, - { 60, { "high", "green" } }, - { 80, { "full", "green" } }, - { 100 } - }) - - d_battery:get_children_by_id("indicator")[1].color = qvars.colors[icon_data[2]] - d_battery:get_children_by_id("indicator")[1].value = capacity - d_battery:get_children_by_id("icon")[1].image = gcolor.recolor_image(phosphor["battery_vertical_" .. icon_data[1] .. "_fill"], qvars.colors[icon_data[2]]) - - d_battery:get_children_by_id("text")[1].text = capacity .. "%" -end) - -local d_volume = create_display(gcolor.recolor_image(phosphor.speaker_simple_high_fill, qvars.colors.fg), qvars.colors.fg) - -awesome.connect_signal("services::audio", function(volume, muted) - d_volume:get_children_by_id("indicator")[1].value = math.min(volume, 100) - d_volume:get_children_by_id("text")[1].text = volume .. "%" - - if muted then - d_volume:get_children_by_id("icon")[1].image = gcolor.recolor_image(phosphor["speaker_simple_x_fill"], qvars.colors.red) +local d_audio = create_display(phosphor.speaker_simple_high_fill, qvars.colors.fg) +awesome.connect_signal("services::audio", function(volume) + if not volume then return end - - local icon_data = qmath.step_value(volume, { - { 0, "slash" }, - { 25, "none" }, - { 50, "low" }, - { 75, "high" }, - { 100 } - }) - - d_volume:get_children_by_id("icon")[1].image = gcolor.recolor_image(phosphor["speaker_simple_" .. icon_data .. "_fill"], qvars.colors.fg) + d_audio:get_children_by_id("indicator")[1].value = math.min(volume, 100) + d_audio:get_children_by_id("text")[1].text = volume .. "%" +end) +awesome.connect_signal("services::audio::icon", function(icon, color) + d_audio:get_children_by_id("indicator")[1].color = color + d_audio:get_children_by_id("icon")[1].image = icon + d_audio:get_children_by_id("icon")[1].stylesheet = qui.recolor(color) end) -local d_brightness = create_display(gcolor.recolor_image(phosphor.sun_fill, qvars.colors.fg), qvars.colors.fg) +local d_battery = create_display(phosphor.battery_vertical_warning_fill, qvars.colors.red) +awesome.connect_signal("services::battery", function(capacity) + d_battery:get_children_by_id("indicator")[1].value = capacity + d_battery:get_children_by_id("text")[1].text = capacity .. "%" +end) +awesome.connect_signal("services::battery::icon", function(icon, color) + d_battery:get_children_by_id("indicator")[1].color = color + d_battery:get_children_by_id("icon")[1].image = icon + d_battery:get_children_by_id("icon")[1].stylesheet = qui.recolor(color) +end) +local d_brightness = create_display(phosphor.sun_fill, qvars.colors.fg) awesome.connect_signal("services::brightness", function(brightness) brightness = math.floor(qmath.translate_range(brightness, 0, 255, 0, 100)) - d_brightness:get_children_by_id("indicator")[1].value = brightness - d_brightness:get_children_by_id("text")[1].text = brightness .. "%" end) +awesome.connect_signal("services::brightness::icon", function(icon, color) + d_brightness:get_children_by_id("icon")[1].image = icon + d_brightness:get_children_by_id("icon")[1].stylesheet = qui.recolor(color) +end) -return { battery = d_battery, volume = d_volume, brightness = d_brightness } +return { audio = d_audio, battery = d_battery, brightness = d_brightness } diff --git a/.config/awesome/ui/statusbar/panel/widgets/imagebox.lua b/.config/awesome/ui/statusbar/panel/widgets/imagebox.lua new file mode 100644 index 0000000..8c6e8a5 --- /dev/null +++ b/.config/awesome/ui/statusbar/panel/widgets/imagebox.lua @@ -0,0 +1,706 @@ +--------------------------------------------------------------------------- +-- A widget to display an image. +-- +-- The `wibox.widget.imagebox` is part of the Awesome WM's widget system +-- (see @{03-declarative-layout.md}). +-- +-- This widget displays an image. The image can be a file, +-- a cairo image surface, or an rsvg handle object (see the +-- [image property](#image)). +-- +-- Examples using a `wibox.widget.imagebox`: +-- --- +-- +-- @DOC_wibox_widget_defaults_imagebox_EXAMPLE@ +-- +-- Alternatively, you can declare the `imagebox` widget using the +-- declarative pattern (both variants are strictly equivalent): +-- +-- @DOC_wibox_widget_declarative-pattern_imagebox_EXAMPLE@ +-- +-- @author Uli Schlachter +-- @copyright 2010 Uli Schlachter +-- @widgetmod wibox.widget.imagebox +-- @supermodule wibox.widget.base +--------------------------------------------------------------------------- + +local lgi = require("lgi") +local cairo = lgi.cairo + +local base = require("wibox.widget.base") +local surface = require("gears.surface") +local gtable = require("gears.table") +local gdebug = require("gears.debug") +local setmetatable = setmetatable +local type = type +local math = math + +local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) + +-- Safe load for optional Rsvg module +local Rsvg = nil +do + local success, err = pcall(function() Rsvg = lgi.Rsvg end) + if not success then + gdebug.print_warning(debug.traceback("Could not load Rsvg: " .. tostring(err))) + end +end + +local imagebox = { mt = {} } + +local rsvg_handle_cache = setmetatable({}, { __mode = 'k' }) + +---Load rsvg handle form image file +-- @tparam string file Path to svg file. +-- @return Rsvg handle +-- @treturn table A table where cached data can be stored. +local function load_rsvg_handle(file) + if not Rsvg then return end + + local cache = (rsvg_handle_cache[file] or {})["handle"] + + if cache then + return cache, rsvg_handle_cache[file] + end + + local handle, err + + if file:match("<[?]?xml") or file:match(" 0 and surf.height > 0 + if not is_surf_valid then return false end + + ib._private.default = { width = surf.width, height = surf.height } + ib._private.handle = nil + ib._private.image = surf + return true +end + +---Apply RsvgHandle for given imagebox widget +local function set_handle(ib, handle, cache) + local dim = handle:get_dimensions() + local is_handle_valid = dim.width > 0 and dim.height > 0 + if not is_handle_valid then return false end + + ib._private.default = { width = dim.width, height = dim.height } + ib._private.handle = handle + ib._private.cache = cache + ib._private.image = nil + + return true +end + +---Try to load some image object from file then apply it to imagebox. +---@tparam table ib Imagebox +---@tparam string file Image file name +---@tparam function image_loader Function to load image object from file +---@tparam function image_setter Function to set image object to imagebox +---@treturn boolean True if image was successfully applied +local function load_and_apply(ib, file, image_loader, image_setter) + local image_applied + local object, cache = image_loader(file) + + if object then + image_applied = image_setter(ib, object, cache) + end + return image_applied +end + +---Update the cached size depending on the stylesheet and dpi. +-- +-- It's necessary because a single RSVG handle can be used by +-- many imageboxes. So DPI and Stylesheet need to be set each time. +local function update_dpi(self, ctx) + if not self._private.handle then return end + + local dpi = self._private.auto_dpi and + ctx.dpi or + self._private.dpi or + nil + + local need_dpi = dpi and + self._private.last_dpi ~= dpi + + local need_style = self._private.handle.set_stylesheet and + self._private.stylesheet + + local old_size = self._private.default and self._private.default.width + + if dpi and dpi ~= self._private.cache.dpi then + if type(dpi) == "table" then + self._private.handle:set_dpi_x_y(dpi.x, dpi.y) + else + self._private.handle:set_dpi(dpi) + end + end + + if need_style and self._private.cache.stylesheet ~= self._private.stylesheet then + self._private.handle:set_stylesheet(self._private.stylesheet) + end + + -- Reload the size. + if need_dpi or (need_style and self._private.stylesheet ~= self._private.last_stylesheet) then + set_handle(self, self._private.handle, self._private.cache) + end + + self._private.last_dpi = dpi + self._private.cache.dpi = dpi + self._private.last_stylesheet = self._private.stylesheet + self._private.cache.stylesheet = self._private.stylesheet + + -- This can happen in the constructor when `dpi` is set after `image`. + if old_size and old_size ~= self._private.default.width then + self:emit_signal("widget::redraw_needed") + self:emit_signal("widget::layout_changed") + end +end + +-- Draw an imagebox with the given cairo context in the given geometry. +function imagebox:draw(ctx, cr, width, height) + if width == 0 or height == 0 or not self._private.default then return end + + -- For valign = "top" and halign = "left" + local translate = { + x = 0, + y = 0, + } + + update_dpi(self, ctx) + + local w, h = self._private.default.width, self._private.default.height + + if self._private.resize then + -- That's for the "fit" policy. + local aspects = { + w = width / w, + h = height / h + } + + local policy = { + w = self._private.horizontal_fit_policy or "auto", + h = self._private.vertical_fit_policy or "auto" + } + + for _, aspect in ipairs {"w", "h"} do + if self._private.upscale == false and (w < width and h < height) then + aspects[aspect] = 1 + elseif self._private.downscale == false and (w >= width and h >= height) then + aspects[aspect] = 1 + elseif policy[aspect] == "none" then + aspects[aspect] = 1 + elseif policy[aspect] == "auto" then + aspects[aspect] = math.min(width / w, height / h) + elseif policy[aspect] == "cover" then + aspects[aspect] = math.max(width / w, height / h) + end + end + + if self._private.halign == "center" then + translate.x = math.floor((width - w*aspects.w)/2) + elseif self._private.halign == "right" then + translate.x = math.floor(width - (w*aspects.w)) + end + + if self._private.valign == "center" then + translate.y = math.floor((height - h*aspects.h)/2) + elseif self._private.valign == "bottom" then + translate.y = math.floor(height - (h*aspects.h)) + end + + cr:translate(translate.x, translate.y) + + -- Before using the scale, make sure it is below the threshold. + local threshold, max_factor = self._private.max_scaling_factor, math.max(aspects.w, aspects.h) + + if threshold and threshold > 0 and threshold < max_factor then + aspects.w = (aspects.w*threshold)/max_factor + aspects.h = (aspects.h*threshold)/max_factor + end + + -- Set the clip + if self._private.clip_shape then + cr:clip(self._private.clip_shape(cr, w*aspects.w, h*aspects.h, unpack(self._private.clip_args))) + end + + cr:scale(aspects.w, aspects.h) + else + if self._private.halign == "center" then + translate.x = math.floor((width - w)/2) + elseif self._private.halign == "right" then + translate.x = math.floor(width - w) + end + + if self._private.valign == "center" then + translate.y = math.floor((height - h)/2) + elseif self._private.valign == "bottom" then + translate.y = math.floor(height - h) + end + + cr:translate(translate.x, translate.y) + + -- Set the clip + if self._private.clip_shape then + cr:clip(self._private.clip_shape(cr, w, h, unpack(self._private.clip_args))) + end + end + + if self._private.handle then + self._private.handle:render_cairo(cr) + else + cr:set_source_surface(self._private.image, 0, 0) + + local filter = self._private.scaling_quality + + if filter then + cr:get_source():set_filter(cairo.Filter[filter:upper()]) + end + + cr:paint() + end +end + +-- Fit the imagebox into the given geometry +function imagebox:fit(ctx, width, height) + if not self._private.default then return 0, 0 end + + update_dpi(self, ctx) + + local w, h = self._private.default.width, self._private.default.height + + if w <= width and h <= height and self._private.upscale == false then + return w, h + end + + if (w < width or h < height) and self._private.downscale == false then + return w, h + end + + if self._private.resize or w > width or h > height then + local aspect = math.min(width / w, height / h) + return w * aspect, h * aspect + end + + return w, h +end + +--- The image rendered by the `imagebox`. +-- +-- @property image +-- @tparam[opt=nil] image|nil image +-- @propemits false false + +--- Set the `imagebox` image. +-- +-- The image can be a file, a cairo image surface, or an rsvg handle object +-- (see the [image property](#image)). +-- @method set_image +-- @hidden +-- @tparam image image The image to render. +-- @treturn boolean `true` on success, `false` if the image cannot be used. +-- @usage my_imagebox:set_image(beautiful.awesome_icon) +-- @usage my_imagebox:set_image('/usr/share/icons/theme/my_icon.png') +-- @see image +function imagebox:set_image(image) + local setup_succeed + + -- Keep the original to prevent the cache from being GCed. + self._private.original_image = image + + if type(image) == "userdata" and not (Rsvg and Rsvg.Handle:is_type_of(image)) then + -- This function is not documented to handle userdata objects, but + -- historically it did, and it did by just assuming they refer to a + -- cairo surface. + image = surface.load(image) + end + + if type(image) == "string" then + -- try to load rsvg handle from file + setup_succeed = load_and_apply(self, image, load_rsvg_handle, set_handle) + + if not setup_succeed then + -- rsvg handle failed, try to load cairo surface with pixbuf + setup_succeed = load_and_apply(self, image, surface.load, set_surface) + end + elseif Rsvg and Rsvg.Handle:is_type_of(image) then + -- try to apply given rsvg handle + rsvg_handle_cache[image] = rsvg_handle_cache[image] or {} + setup_succeed = set_handle(self, image, rsvg_handle_cache[image]) + elseif cairo.Surface:is_type_of(image) then + -- try to apply given cairo surface + setup_succeed = set_surface(self, image) + elseif not image then + -- nil as argument mean full imagebox reset + setup_succeed = true + self._private.handle = nil + self._private.image = nil + self._private.default = nil + end + + if not setup_succeed then return false end + + self:emit_signal("widget::redraw_needed") + self:emit_signal("widget::layout_changed") + self:emit_signal("property::image") + return true +end + +--- Set a clip shape for this imagebox. +-- +-- A clip shape defines an area and dimension to which the content should be +-- trimmed. +-- +-- @DOC_wibox_widget_imagebox_clip_shape_EXAMPLE@ +-- +-- @property clip_shape +-- @tparam[opt=gears.shape.rectangle] shape clip_shape A `gears.shape` compatible shape function. +-- @propemits true false +-- @see gears.shape + +--- Set a clip shape for this imagebox. +-- +-- A clip shape defines an area and dimensions to which the content should be +-- trimmed. +-- +-- Additional parameters will be passed to the clip shape function. +-- +-- @tparam function|gears.shape clip_shape A `gears_shape` compatible shape function. +-- @method set_clip_shape +-- @hidden +-- @see gears.shape +-- @see clip_shape +function imagebox:set_clip_shape(clip_shape, ...) + self._private.clip_shape = clip_shape + self._private.clip_args = {...} + self:emit_signal("widget::redraw_needed") + self:emit_signal("property::clip_shape", clip_shape) +end + +--- Should the image be resized to fit into the available space? +-- +-- Note that `upscale` and `downscale` can affect the value of `resize`. +-- If conflicting values are passed to the constructor, then the result +-- is undefined. +-- +-- @DOC_wibox_widget_imagebox_resize_EXAMPLE@ +-- @property resize +-- @propemits true false +-- @tparam[opt=true] boolean resize + +--- Allow the image to be upscaled (made bigger). +-- +-- Note that `upscale` and `downscale` can affect the value of `resize`. +-- If conflicting values are passed to the constructor, then the result +-- is undefined. +-- +-- @DOC_wibox_widget_imagebox_upscale_EXAMPLE@ +-- @property upscale +-- @tparam[opt=self.resize] boolean upscale +-- @see downscale +-- @see resize + +--- Allow the image to be downscaled (made smaller). +-- +-- Note that `upscale` and `downscale` can affect the value of `resize`. +-- If conflicting values are passed to the constructor, then the result +-- is undefined. +-- +-- @DOC_wibox_widget_imagebox_downscale_EXAMPLE@ +-- @property downscale +-- @tparam[opt=self.resize] boolean downscale +-- @see upscale +-- @see resize + +--- Set the SVG CSS stylesheet. +-- +-- If the image is an SVG (vector graphics), this property allows to set +-- a CSS stylesheet. It can be used to set colors and much more. +-- +-- Note that this property is a string, not a path. If the stylesheet is +-- stored on disk, read the content first. +-- +--@DOC_wibox_widget_imagebox_stylesheet_EXAMPLE@ +-- +-- @property stylesheet +-- @tparam[opt=""] string stylesheet +-- @propemits true false + +--- Set the SVG DPI (dot per inch). +-- +-- Force a specific DPI when rendering the `.svg`. For other file formats, +-- this does nothing. +-- +-- It can either be a number of a table containing the `x` and `y` keys. +-- +-- Please note that DPI and `resize` can "fight" each other and end up +-- making the image smaller instead of bigger. +-- +--@DOC_wibox_widget_imagebox_dpi_EXAMPLE@ +-- +-- @property dpi +-- @tparam[opt=96] number|table dpi +-- @negativeallowed false +-- @propemits true false +-- @see auto_dpi + +--- Use the object DPI when rendering the SVG. +-- +-- By default, the SVG are interpreted as-is. When this property is set, +-- the screen DPI will be passed to the SVG renderer. Depending on which +-- tool was used to create the `.svg`, this may do nothing at all. However, +-- for example, if the `.svg` uses `` elements and doesn't have an +-- hardcoded stylesheet, the result will differ. +-- +-- @property auto_dpi +-- @tparam[opt=false] boolean auto_dpi +-- @propemits true false +-- @see dpi + +for _, prop in ipairs {"stylesheet", "dpi", "auto_dpi"} do + imagebox["set_" .. prop] = function(self, value) + -- It will be set in :fit and :draw. The handle is shared + -- by multiple imagebox, so it cannot be set just once. + self._private[prop] = value + + self:emit_signal("widget::redraw_needed") + self:emit_signal("widget::layout_changed") + self:emit_signal("property::" .. prop) + end +end + +function imagebox:set_resize(allowed) + self._private.resize = allowed + + if allowed then + self._private.downscale = true + self._private.upscale = true + self:emit_signal("property::downscale", allowed) + self:emit_signal("property::upscale", allowed) + end + + self:emit_signal("widget::redraw_needed") + self:emit_signal("widget::layout_changed") + self:emit_signal("property::resize", allowed) +end + +for _, prop in ipairs {"downscale", "upscale" } do + imagebox["set_" .. prop] = function(self, allowed) + self._private[prop] = allowed + + if self._private.resize ~= (self._private.upscale or self._private.downscale) then + self._private.resize = self._private.upscale or self._private.downscale + self:emit_signal("property::resize", self._private.resize) + end + + self:emit_signal("widget::redraw_needed") + self:emit_signal("widget::layout_changed") + self:emit_signal("property::"..prop, allowed) + end +end + +--- Set the horizontal fit policy. +-- +-- Here is the result for a 22x32 image: +-- +-- @DOC_wibox_widget_imagebox_horizontal_fit_policy_EXAMPLE@ +-- +-- @property horizontal_fit_policy +-- @tparam[opt="auto"] string horizontal_fit_policy +-- @propertyvalue "auto" Honor the `resize` variable and preserve the aspect ratio. +-- @propertyvalue "none" Do not resize at all. +-- @propertyvalue "fit" Resize to the widget width. +-- @propertyvalue "cover" Resize to fill widget and preserve the aspect ratio. +-- @propemits true false +-- @see vertical_fit_policy +-- @see resize + +--- Set the vertical fit policy. +-- +-- Here is the result for a 32x22 image: +-- +-- @DOC_wibox_widget_imagebox_vertical_fit_policy_EXAMPLE@ +-- +-- @property vertical_fit_policy +-- @tparam[opt="auto"] string vertical_fit_policy +-- @propertyvalue "auto" Honor the `resize` variable and preserve the aspect ratio. +-- @propertyvalue "none" Do not resize at all. +-- @propertyvalue "fit" Resize to the widget height. +-- @propertyvalue "cover" Resize to fill widget and preserve the aspect ratio. +-- @propemits true false +-- @see horizontal_fit_policy +-- @see resize + + +--- The vertical alignment. +-- +-- @DOC_wibox_widget_imagebox_valign_EXAMPLE@ +-- +-- @property valign +-- @tparam[opt="center"] string valign +-- @propertyvalue "top" +-- @propertyvalue "center" +-- @propertyvalue "bottom" +-- @propemits true false +-- @see wibox.container.place +-- @see halign + +--- The horizontal alignment. +-- +-- @DOC_wibox_widget_imagebox_halign_EXAMPLE@ +-- +-- @property halign +-- @tparam[opt="center"] string halign +-- @propertyvalue "left" +-- @propertyvalue "center" +-- @propertyvalue "right" +-- @propemits true false +-- @see wibox.container.place +-- @see valign + +--- The maximum scaling factor. +-- +-- If an image is scaled too much, it gets very blurry. This +-- property allows to limit the scaling. +-- Use the properties `valign` and `halign` to control how the image will be +-- aligned. +-- +-- In the example below, the original size is 22x22 +-- +-- @DOC_wibox_widget_imagebox_max_scaling_factor_EXAMPLE@ +-- +-- @property max_scaling_factor +-- @tparam[opt=0] number max_scaling_factor Use `0` for "no limit". +-- @negativeallowed false +-- @propemits true false +-- @see valign +-- @see halign +-- @see scaling_quality + +--- Set the scaling aligorithm. +-- +-- Depending on how the image is used, what is the "correct" way to +-- scale can change. For example, upscaling a pixel art image should +-- not make it blurry. However, scaling up a photo should not make it +-- blocky. +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +--
ValueDescription
fastA high-performance filter
goodA reasonable-performance filter
bestThe highest-quality available
nearestNearest-neighbor filtering (blocky)
bilinearLinear interpolation in two dimensions
+-- +-- The image used in the example below has a resolution of 32x22 and is +-- intentionally blocky to highlight the difference. +-- It is zoomed by a factor of 3. +-- +-- @DOC_wibox_widget_imagebox_scaling_quality_EXAMPLE@ +-- +-- @property scaling_quality +-- @tparam[opt="good"] string scaling_quality +-- @propertyvalue "fast" A high-performance filter. +-- @propertyvalue "good" A reasonable-performance filter. +-- @propertyvalue "best" The highest-quality available. +-- @propertyvalue "nearest" Nearest-neighbor filtering (blocky). +-- @propertyvalue "bilinear" Linear interpolation in two dimensions. +-- @propemits true false +-- @see resize +-- @see horizontal_fit_policy +-- @see vertical_fit_policy +-- @see max_scaling_factor + +local defaults = { + halign = "left", + valign = "top", + horizontal_fit_policy = "auto", + vertical_fit_policy = "auto", + max_scaling_factor = 0, + scaling_quality = "good" +} + +local function get_default(prop, value) + if value == nil then return defaults[prop] end + + return value +end + +for prop in pairs(defaults) do + imagebox["set_"..prop] = function(self, value) + if value == self._private[prop] then return end + + self._private[prop] = get_default(prop, value) + self:emit_signal("widget::redraw_needed") + self:emit_signal("property::"..prop, self._private[prop]) + end + + imagebox["get_"..prop] = function(self) + if self._private[prop] == nil then + return defaults[prop] + end + + return self._private[prop] + end +end + +--- Returns a new `wibox.widget.imagebox` instance. +-- +-- This is the constructor of `wibox.widget.imagebox`. It creates a new +-- instance of imagebox widget. +-- +-- Alternatively, the declarative layout syntax can handle +-- `wibox.widget.imagebox` instanciation. +-- +-- The image can be a file, a cairo image surface, or an rsvg handle object +-- (see the [image property](#image)). +-- +-- Any additional arguments will be passed to the clip shape function. +-- @tparam[opt] image image The image to display (may be `nil`). +-- @tparam[opt] boolean resize_allowed If `false`, the image will be +-- clipped, else it will be resized to fit into the available space. +-- @tparam[opt] function clip_shape A `gears.shape` compatible function. +-- @treturn wibox.widget.imagebox A new `wibox.widget.imagebox` widget instance. +-- @constructorfct wibox.widget.imagebox +local function new(image, resize_allowed, clip_shape, ...) + local ret = base.make_widget(nil, nil, {enable_properties = true}) + + gtable.crush(ret, imagebox, true) + ret._private.resize = true + + if image then + ret:set_image(image) + end + + if resize_allowed ~= nil then + ret.resize = resize_allowed + end + + ret._private.clip_shape = clip_shape + ret._private.clip_args = {...} + + return ret +end + +function imagebox.mt:__call(...) + return new(...) +end + +return setmetatable(imagebox, imagebox.mt) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/.config/awesome/ui/statusbar/panel/widgets/music.lua b/.config/awesome/ui/statusbar/panel/widgets/music.lua new file mode 100644 index 0000000..3eedb55 --- /dev/null +++ b/.config/awesome/ui/statusbar/panel/widgets/music.lua @@ -0,0 +1,200 @@ +local cairo = require "lgi".cairo +local gcolor = require "gears.color" +local gsurface = require "gears.surface" +local imagebox = require "ui.statusbar.panel.widgets.imagebox" +local phosphor = require "assets.phosphor" +local playerctl = require "services.playerctl" +local qnative = require "quarrel.native" +local qui = require "quarrel.ui" +local qvars = require "quarrel.vars" +local wibox = require "wibox" + +local default_cover = phosphor.vinyl_record_fill +local default_text = "Nothing playing" + +local function faded_cover(cover) + local surface = gsurface(cover) + local w,h = gsurface.get_size(surface) + local cr = cairo.Context(surface) + local pattern = gcolor(qvars.colors.bg .. "aa") + cr:rectangle(0, 0, w, h) + cr:set_source(pattern) + cr:fill_preserve() + return surface +end + +local w_title = wibox.widget { + widget = wibox.widget.textbox, + text = "Nothing playing", +} + +local w_artist = wibox.widget { + widget = wibox.container.background, + fg = qvars.colors.dim.fg, + { + widget = wibox.widget.textbox, + text = "" + } +} + +local w_cover = wibox.widget { + widget = imagebox, + image = default_cover, + stylesheet = qui.recolor(qvars.colors.bright.black), + forced_height = qvars.char_height * 6 + qvars.big_padding * 2, + forced_width = qvars.expanded_bar_size - qvars.big_padding, + horizontal_fit_policy = "cover", + vertical_fit_policy = "cover", + valign = "center", + halign = "center" +} + +local w_progress_bar = wibox.widget { + widget = wibox.widget.progressbar, + max_value = 0, + value = 0, + forced_height = qvars.char_height / 2, + forced_width = qvars.expanded_bar_size - (qvars.big_padding + qvars.big_padding * 2 + qvars.padding * 2) - (qvars.char_height / 1.25 + qvars.padding) * 3, + color = qvars.colors.yellow, + background_color = qvars.colors.black, + shape = qvars.shape, +} + +local w_play_pause = qui.toggle { + widget = { + forced_height = qvars.char_height / 1.25, + forced_width = qvars.char_height / 1.25 + }, + off = phosphor.play_fill, + on = phosphor.pause_fill, + manual = true, + press = function() + playerctl:play_pause() + end +} + +local w_skip_forward = qui.button { + widget = { + forced_height = qvars.char_height / 1.25, + forced_width = qvars.char_height / 1.25 + }, + image = phosphor.skip_forward_fill, + press = function() + playerctl:next() + end +} + +local w_skip_back = qui.button { + widget = { + forced_height = qvars.char_height / 1.25, + forced_width = qvars.char_height / 1.25 + }, + image = phosphor.skip_back_fill, + press = function() + playerctl:previous() + end +} + +local music = wibox.widget(qui.styled { + widget = wibox.container.background, + { + { + widget = wibox.container.background, + bg = qvars.colors.black + }, + w_cover, + { + widget = wibox.container.margin, + margins = qvars.big_padding, + { + { + { + widget = wibox.container.background, + bg = qvars.colors.bg, + shape = qvars.shape, + { + widget = wibox.container.margin, + margins = qvars.padding, + { + { + widget = wibox.container.constraint, + width = qvars.expanded_bar_size - (qvars.big_padding + qvars.big_padding * 2 + qvars.padding * 2), + height = qvars.char_height, + { + widget = wibox.container.scroll.horizontal, + speed = 50, + step_function = wibox.container.scroll.step_functions.waiting_nonlinear_back_and_forth, + w_title + } + }, + { + widget = wibox.container.constraint, + width = qvars.expanded_bar_size - (qvars.big_padding + qvars.big_padding * 2 + qvars.padding * 2), + height = qvars.char_height, + { + widget = wibox.container.scroll.horizontal, + speed = 50, + step_function = wibox.container.scroll.step_functions.waiting_nonlinear_back_and_forth, + w_artist + } + }, + layout = wibox.layout.fixed.vertical + } + } + }, + nil, + nil, + layout = wibox.layout.align.horizontal + }, + nil, + { + widget = wibox.container.background, + bg = qvars.colors.bg, + shape = qvars.shape, + { + widget = wibox.container.margin, + margins = qvars.padding, + { + w_play_pause, + w_skip_back, + { + widget = wibox.container.place, + w_progress_bar + }, + w_skip_forward, + layout = wibox.layout.fixed.horizontal, + spacing = qvars.padding + } + } + }, + layout = wibox.layout.align.vertical + } + }, + layout = wibox.layout.stack + } +}) + +awesome.connect_signal("services::playerctl::metadata", function(title, artist, album_path) + w_title.text = title ~= "" and qnative.decode_html(title) or default_text + w_artist.widget.text = qnative.decode_html(artist) + w_cover.image = faded_cover(album_path) +end) + +awesome.connect_signal("services::playerctl::position", function(position, length) + w_progress_bar.value = position + w_progress_bar.max_value = length +end) + +awesome.connect_signal("services::playerctl::no_players", function() + w_title = default_text + w_artist = "" + w_cover.image = default_cover + w_progress_bar.value = 0 + w_progress_bar.max_value = 0 +end) + +awesome.connect_signal("services::playerctl::playback_status", function(playing) + w_play_pause:silent_press(playing) +end) + +return music diff --git a/.config/awesome/ui/statusbar/panel/widgets/power_menu.lua b/.config/awesome/ui/statusbar/panel/widgets/power_menu.lua index ffb5a76..cf0de28 100644 --- a/.config/awesome/ui/statusbar/panel/widgets/power_menu.lua +++ b/.config/awesome/ui/statusbar/panel/widgets/power_menu.lua @@ -1,7 +1,7 @@ local q = require "quarrel" local qbind = require "quarrel.bind" -local qvars = require "quarrel.vars" local qui = require "quarrel.ui" +local qvars = require "quarrel.vars" local wibox = require "wibox" local power_menu = wibox.widget { diff --git a/.config/awesome/ui/statusbar/panel/widgets/wifi.lua b/.config/awesome/ui/statusbar/panel/widgets/wifi.lua new file mode 100644 index 0000000..579474e --- /dev/null +++ b/.config/awesome/ui/statusbar/panel/widgets/wifi.lua @@ -0,0 +1,42 @@ +local phosphor = require "assets.phosphor" +local qui = require "quarrel.ui" +local qvars = require "quarrel.vars" +local wibox = require "wibox" + +local wifi = wibox.widget(qui.styled { + widget = wibox.container.background, + { + widget = wibox.container.margin, + margins = qvars.big_padding, + { + { + widget = wibox.container.place, + valign = "center", + halign = "center", + qui.icon(phosphor.wifi_x_fill, qvars.colors.red, { id = "icon" }) + }, + { + widget = wibox.widget.textbox, + text = "Disconnected", + id = "essid" + }, + layout = wibox.layout.fixed.horizontal, + spacing = qvars.padding + } + } +}) + +awesome.connect_signal("services::wifi", function(essid, _, connected) + if connected then + wifi:get_children_by_id("essid")[1].text = essid + else + wifi:get_children_by_id("essid")[1].text = "Disconnected" + end +end) + +awesome.connect_signal("services::wifi::icon", function(icon, color) + wifi:get_children_by_id("icon")[1].image = icon + wifi:get_children_by_id("icon")[1].stylesheet = qui.recolor(color) +end) + +return wifi diff --git a/.config/awesome/ui/statusbar/widgets/battery.lua b/.config/awesome/ui/statusbar/widgets/battery.lua deleted file mode 100644 index f220ff1..0000000 --- a/.config/awesome/ui/statusbar/widgets/battery.lua +++ /dev/null @@ -1,32 +0,0 @@ -local gcolor = require "gears.color" -local phosphor = require "assets.phosphor" -local qmath = require "quarrel.math" -local qvars = require "quarrel.vars" -local wibox = require "wibox" - -local battery = wibox.widget { - widget = wibox.container.place, - valign = "center", - halign = "center", - { - widget = wibox.widget.imagebox, - image = gcolor.recolor_image(phosphor.battery_vertical_warning_fill, qvars.colors.red), - forced_width = qvars.char_height, - forced_height = qvars.char_height - } -} - -awesome.connect_signal("services::battery", function(capacity, status) - local icon_data = status == "Charging" and { "charging", "green" } or qmath.step_value(capacity, { - { 0, { "empty", "red" } }, - { 20, { "low", "red" } }, - { 40, { "medium", "yellow" } }, - { 60, { "high", "green" } }, - { 80, { "full", "green" } }, - { 100 } - }) - - battery.widget.image = gcolor.recolor_image(phosphor["battery_vertical_" .. icon_data[1] .. "_fill"], qvars.colors[icon_data[2]]) -end) - -return battery diff --git a/.config/awesome/ui/statusbar/widgets/brightness.lua b/.config/awesome/ui/statusbar/widgets/brightness.lua deleted file mode 100644 index bfb8e91..0000000 --- a/.config/awesome/ui/statusbar/widgets/brightness.lua +++ /dev/null @@ -1,32 +0,0 @@ -local gcolor = require "gears.color" -local phosphor = require "assets.phosphor" -local qmath = require "quarrel.math" -local qvars = require "quarrel.vars" -local wibox = require "wibox" - -local brightness = wibox.widget { - widget = wibox.container.place, - valign = "center", - halign = "center", - { - widget = wibox.widget.imagebox, - image = gcolor.recolor_image(phosphor.moon_fill, qvars.colors.fg), - forced_width = qvars.char_height, - forced_height = qvars.char_height - } -} - -awesome.connect_signal("services::brightness", function(value) - local icon_data = qmath.step_value(value, { - { 0, "cloud_moon" }, - { 51, "moon" }, - { 102, "sun_horizon" }, - { 153, "sun_dim" }, - { 204, "sun" }, - { 255 } - }) - - brightness.widget.image = gcolor.recolor_image(phosphor[icon_data .. "_fill"], qvars.colors.fg) -end) - -return brightness diff --git a/.config/awesome/ui/statusbar/widgets/displays.lua b/.config/awesome/ui/statusbar/widgets/displays.lua new file mode 100644 index 0000000..44ff2c6 --- /dev/null +++ b/.config/awesome/ui/statusbar/widgets/displays.lua @@ -0,0 +1,39 @@ +local phosphor = require "assets.phosphor" +local qui = require "quarrel.ui" +local qvars = require "quarrel.vars" +local wibox = require "wibox" + +local function create_display(icon, color) + return wibox.widget { + widget = wibox.container.place, + valign = "center", + halign = "center", + qui.icon(icon, color) + } +end + +local battery = create_display(phosphor.battery_vertical_warning_fill, qvars.colors.red) +awesome.connect_signal("services::battery::icon", function(icon, color) + battery.widget.image = icon + battery.widget.stylesheet = qui.recolor(color) +end) + +local brightness = create_display(phosphor.moon_fill, qvars.colors.fg) +awesome.connect_signal("services::brightness::icon", function(icon, color) + brightness.widget.image = icon + brightness.widget.stylesheet = qui.recolor(color) +end) + +local audio = create_display(phosphor.speaker_simple_slash_fill, qvars.colors.red) +awesome.connect_signal("services::audio::icon", function(icon, color) + audio.widget.image = icon + audio.widget.stylesheet = qui.recolor(color) +end) + +local wifi = create_display(phosphor.wifi_x_fill, qvars.colors.red) +awesome.connect_signal("services::wifi::icon", function(icon, color) + wifi.widget.image = icon + wifi.widget.stylesheet = qui.recolor(color) +end) + +return { audio = audio, battery = battery, brightness = brightness, wifi = wifi } diff --git a/.config/awesome/ui/statusbar/widgets/taglist.lua b/.config/awesome/ui/statusbar/widgets/taglist.lua index 10618aa..1072426 100644 --- a/.config/awesome/ui/statusbar/widgets/taglist.lua +++ b/.config/awesome/ui/statusbar/widgets/taglist.lua @@ -1,7 +1,9 @@ local awful = require "awful" local gcolor = require "gears.color" +local gdebug = require "gears.debug" local phosphor = require "assets.phosphor" local qbind = require "quarrel.bind" +local qui = require "quarrel.ui" local qvars = require "quarrel.vars" local wibox = require "wibox" @@ -16,42 +18,33 @@ return awful.widget.taglist { widget = wibox.container.place, valign = "center", halign = "center", - { - widget = wibox.widget.imagebox, - image = gcolor.recolor_image(phosphor.circle_bold, qvars.colors.fg), - forced_width = qvars.char_height, - forced_height = qvars.char_height, - icon = phosphor.dot_fill - }, create_callback = function(self, tag) - -- self.widget.icon = phosphor[next(tag:clients()) and "circle_fill" or "circle_bold"] + self.widget = qui.icon(tag.icon) self:connect_signal("mouse::enter", function() if tag.selected then return end - - self.widget.image = gcolor.recolor_image(self.widget.icon, qvars.colors.yellow) + self.widget.stylesheet = qui.recolor(qvars.colors.yellow) end) self:connect_signal("mouse::leave", function() if tag.selected then return end - - self.widget.image = gcolor.recolor_image(self.widget.icon, qvars.colors.fg) + self.widget.stylesheet = qui.recolor(qvars.colors.fg) end) if tag.selected then - self.widget.image = gcolor.recolor_image(self.widget.icon, qvars.colors.yellow) + self.widget.stylesheet = qui.recolor(qvars.colors.yellow) return end - self.widget.image = gcolor.recolor_image(self.widget.icon, qvars.colors.fg) + self.widget.stylesheet = qui.recolor(qvars.colors.fg) end, update_callback = function(self, tag) -- self.widget.icon = phosphor[next(tag:clients()) and "circle_fill" or "circle_bold"] if tag.selected then - self.widget.image = gcolor.recolor_image(self.widget.icon, qvars.colors.yellow) + self.widget.stylesheet = qui.recolor(qvars.colors.yellow) else - self.widget.image = gcolor.recolor_image(self.widget.icon, qvars.colors.fg) + self.widget.stylesheet = qui.recolor(qvars.colors.fg) end end }, diff --git a/.config/awesome/ui/statusbar/widgets/volume.lua b/.config/awesome/ui/statusbar/widgets/volume.lua deleted file mode 100644 index 72723a0..0000000 --- a/.config/awesome/ui/statusbar/widgets/volume.lua +++ /dev/null @@ -1,36 +0,0 @@ -local gcolor = require "gears.color" -local phosphor = require "assets.phosphor" -local qmath = require "quarrel.math" -local qvars = require "quarrel.vars" -local wibox = require "wibox" - -local volume_widget = wibox.widget { - widget = wibox.container.place, - valign = "center", - halign = "center", - { - widget = wibox.widget.imagebox, - image = gcolor.recolor_image(phosphor.speaker_simple_slash_fill, qvars.colors.red), - forced_width = qvars.char_height, - forced_height = qvars.char_height - } -} - -awesome.connect_signal("services::audio", function(volume, muted) - if muted then - volume_widget.widget.image = gcolor.recolor_image(phosphor["speaker_simple_x_fill"], qvars.colors.red) - return - end - - local icon_data = qmath.step_value(volume, { - { 0, "slash" }, - { 25, "none" }, - { 50, "low" }, - { 75, "high" }, - { 100 } - }) - - volume_widget.widget.image = gcolor.recolor_image(phosphor["speaker_simple_" .. icon_data .. "_fill"], qvars.colors.fg) -end) - -return volume_widget diff --git a/.config/awesome/ui/statusbar/widgets/wifi.lua b/.config/awesome/ui/statusbar/widgets/wifi.lua deleted file mode 100644 index c895b0a..0000000 --- a/.config/awesome/ui/statusbar/widgets/wifi.lua +++ /dev/null @@ -1,38 +0,0 @@ -local gcolor = require "gears.color" -local phosphor = require "assets.phosphor" -local qmath = require "quarrel.math" -local qvars = require "quarrel.vars" -local wibox = require "wibox" -local q = require "quarrel" -local gdebug = require "gears.debug" - -local wifi = wibox.widget { - widget = wibox.container.place, - valign = "center", - halign = "center", - { - widget = wibox.widget.imagebox, - image = gcolor.recolor_image(phosphor.wifi_x_fill, qvars.colors.red), - forced_width = qvars.char_height, - forced_height = qvars.char_height - } -} - -awesome.connect_signal("services::wifi", function(essid, strength, connected) - if not connected then - wifi.widget.image = gcolor.recolor_image(phosphor.wifi_x_fill, qvars.colors.red) - return - end - - local icon_data = qmath.step_value(strength, { - { 0, { "none", "red" } }, - { 25, { "low", "yellow" } }, - { 50, { "medium", "yellow" } }, - { 75, { "high", "green" } }, - { 100 } - }) - - wifi.widget.image = gcolor.recolor_image(phosphor["wifi_" .. icon_data[1] .. "_fill"], qvars.colors[icon_data[2]]) -end) - -return wifi