From d7c66522cf365f516babcfeb1d4a2d36c3ea41af Mon Sep 17 00:00:00 2001 From: delta Date: Wed, 29 Oct 2025 16:35:38 +0100 Subject: a small refactor --- .config/awesome/misc/keys.lua | 22 +- .config/awesome/prismite.lua | 3 - .config/awesome/quarrel/init.lua | 12 - .config/awesome/quarrel/native/Cargo.toml | 3 +- .config/awesome/quarrel/native/init.lua | 13 +- .config/awesome/quarrel/native/libqnative.so | 2 +- .../quarrel/native/src/lenses/application.rs | 110 +++-- .../quarrel/native/src/lenses/calculator.rs | 89 +++- .config/awesome/quarrel/native/src/lenses/mod.rs | 121 ++++-- .config/awesome/quarrel/native/src/lib.rs | 12 +- .config/awesome/quarrel/native/src/moondrop.rs | 2 - .config/awesome/quarrel/native/src/net/mod.rs | 5 +- .config/awesome/quarrel/native/src/util.rs | 2 +- .config/awesome/quarrel/table.lua | 8 + .config/awesome/quarrel/ui/init.lua | 34 ++ .config/awesome/ui/conductor/init.lua | 64 --- .config/awesome/ui/fresnel/init.lua | 472 +++++++++++++-------- .config/awesome/ui/init.lua | 2 +- .../awesome/ui/statusbar/panel/widgets/mpris.lua | 25 +- .config/awesome/ui/wicked/consts.lua | 8 + .config/awesome/ui/wicked/init.lua | 192 +++++---- 21 files changed, 755 insertions(+), 446 deletions(-) delete mode 100644 .config/awesome/quarrel/init.lua delete mode 100644 .config/awesome/ui/conductor/init.lua (limited to '.config/awesome') diff --git a/.config/awesome/misc/keys.lua b/.config/awesome/misc/keys.lua index 8d703b8..b36808b 100644 --- a/.config/awesome/misc/keys.lua +++ b/.config/awesome/misc/keys.lua @@ -132,15 +132,15 @@ awful.keyboard.append_global_keybindings { group = "awesome", desc = "toggle bar panel", }, - qbind { - mods = qbind.mods.M, - triggers = "l", - press = function() - powermenu:toggle() - end, - group = "awesome", - desc = "toggle powermenu", - }, + -- qbind { + -- mods = qbind.mods.M, + -- triggers = "l", + -- press = function() + -- powermenu:toggle() + -- end, + -- group = "awesome", + -- desc = "toggle powermenu", + -- }, qbind { triggers = "XF86AudioMute", @@ -305,7 +305,7 @@ awful.keyboard.append_global_keybindings { qbind { mods = qbind.mods.M, - triggers = "k", + triggers = "l", press = function() awful.spawn "xkblayout-state set +1" end, @@ -314,7 +314,7 @@ awful.keyboard.append_global_keybindings { }, qbind { mods = qbind.mods.MS, - triggers = "k", + triggers = "l", press = function() awful.spawn "xkblayout-state set -1" end, diff --git a/.config/awesome/prismite.lua b/.config/awesome/prismite.lua index 497a1b9..b9423e8 100644 --- a/.config/awesome/prismite.lua +++ b/.config/awesome/prismite.lua @@ -19,7 +19,6 @@ theme.fg_focus = qcolor.palette.fg() theme.fg_urgent = qcolor.palette.fg() theme.fg_minimize = qcolor.palette.fg() --- theme.useless_gap = dpi(2) theme.useless_gap = qui.PADDING / 2 theme.border_width = qui.BORDER_WIDTH theme.border_normal = qcolor.palette.border() @@ -34,9 +33,7 @@ theme.notification_max_width = qui.CHAR_WIDTH * 48 theme.notification_shape = qui.shape theme.notification_spacing = theme.useless_gap * 2 --- naughty.config.defaults.timeout = qvars.notif_timeout naughty.config.defaults.position = "bottom_right" --- naughty.config.defaults.border_width = qui.BORDER_WIDTH theme.tasklist_plain_task_name = true theme.enable_spawn_cursor = false diff --git a/.config/awesome/quarrel/init.lua b/.config/awesome/quarrel/init.lua deleted file mode 100644 index 5617c1a..0000000 --- a/.config/awesome/quarrel/init.lua +++ /dev/null @@ -1,12 +0,0 @@ -local n = require("naughty").notification - ----@class Quarrel -local quarrel = {} - ---- Send a notification with the specified message ----@param message any -function quarrel.debug(message) - n { message = tostring(message) } -end - -return quarrel diff --git a/.config/awesome/quarrel/native/Cargo.toml b/.config/awesome/quarrel/native/Cargo.toml index 2551507..1b98681 100644 --- a/.config/awesome/quarrel/native/Cargo.toml +++ b/.config/awesome/quarrel/native/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" [dependencies] freedesktop_entry_parser = "1.3.0" -cpc = "1.9.1" mlua = { version = "0.10.3", features = [ "module", "lua54", "serialize" ] } rayon = "1.6.1" serde = { version = "1.0.152", features = [ "derive" ] } @@ -23,6 +22,8 @@ ureq = "3.0.9" anyhow = { version = "1.0.97", features = ["backtrace"] } mdrop = { git = "https://github.com/frahz/mdrop" } sysinfo = "0.35.0" +fend-core = "1.5.7" +notify = "8.2.0" [lib] crate-type = ["cdylib"] diff --git a/.config/awesome/quarrel/native/init.lua b/.config/awesome/quarrel/native/init.lua index 6a823ba..fc0f4d3 100644 --- a/.config/awesome/quarrel/native/init.lua +++ b/.config/awesome/quarrel/native/init.lua @@ -8,11 +8,12 @@ package.cpath = package.cpath .. ";" .. cfg .. "quarrel/native/lib?.so" ---@field message string ---@field exec { [1]: string, [2]: boolean }? ----@alias query fun(input: string): Entry[] - ----@class Lenses ----@field [1] query Calculator lense ----@field [2] query Application lense +---@class Lense +---@field stale boolean +---@field name string +---@field query fun(self, input: string): (Entry|Entry[])? +---@field mark_stale fun(self) +---@field interrupt fun(self) ---@alias ReadMode "l" | "n" | string @@ -30,7 +31,7 @@ package.cpath = package.cpath .. ";" .. cfg .. "quarrel/native/lib?.so" ---@field get_essid fun(): string ---@class QuarrelNative ----@field lenses Lenses +---@field lenses Lense[] ---@field util Util ---@field net Net local qnative = require "qnative" diff --git a/.config/awesome/quarrel/native/libqnative.so b/.config/awesome/quarrel/native/libqnative.so index 5fc821d..e64f70a 120000 --- a/.config/awesome/quarrel/native/libqnative.so +++ b/.config/awesome/quarrel/native/libqnative.so @@ -1 +1 @@ -target/debug/libqnative.so \ No newline at end of file +/home/delta/.config/awesome/quarrel/native/target/release/libqnative.so \ No newline at end of file diff --git a/.config/awesome/quarrel/native/src/lenses/application.rs b/.config/awesome/quarrel/native/src/lenses/application.rs index 89b7bb4..38a7762 100644 --- a/.config/awesome/quarrel/native/src/lenses/application.rs +++ b/.config/awesome/quarrel/native/src/lenses/application.rs @@ -1,58 +1,118 @@ use std::{ - fs::read_dir, path::PathBuf + any::type_name, + fs::read_dir, + path::PathBuf, + sync::{ + atomic::{ + AtomicBool, + Ordering, + }, + Arc, + OnceLock, + RwLock, + }, }; use freedesktop_entry_parser as fd; use mlua::prelude::*; +use notify::RecommendedWatcher; use rayon::prelude::*; use url::Url; use crate::lenses::{ - Entry, - Lense, - Cache + Cache, Entries, Entry, Lense }; +static APPS_DIR: &'static str = "/usr/share/applications"; +static WATCHER: OnceLock = OnceLock::new(); + #[derive(Default)] -pub struct Application(pub Cache); +pub struct Application { + cache: RwLock, + should_interrupt: AtomicBool, +} impl Lense for Application { const NAME: &str = "Application"; - fn get_cache(&self) -> &Cache { - &self.0 + fn init() -> Arc { + let this = Arc::new(Application::default()); + let watcher_this = this.clone(); + WATCHER + .set( + notify::recommended_watcher(move |event| { + match event { + Ok(_) => { + // We don't care what specifically changed, just that *it did* + watcher_this.set_cache(Cache::Stale); + } + Err(err) => { + eprintln!("Watch error: {:?}", err) + } + } + }) + .expect("Failed to instantiate a watcher"), + ) + .expect("Failed to set a watcher"); + this } - fn set_cache(&mut self, cache: Cache) { - self.0 = cache; + #[inline] + fn set_cache(&self, cache: Cache) { + if let Err(err) = self.cache.write().map(|mut place| *place = cache) { + eprintln!( + "Failed to write cache value for {}: {:?}", + type_name::(), + err + ) + } + } + + #[inline] + fn get_cache(&self) -> Cache { + match self.cache.read() { + Ok(ok) => ok.clone(), + Err(err) => { + eprintln!( + "Failed to read cache value for {}: {:?}", + type_name::(), + err + ); + Cache::Stale + } + } } - fn query(_: &Lua, input: String) -> Result, anyhow::Error> { - let applications_dir = "/usr/share/applications"; - let entries = read_dir(applications_dir)? + #[inline] + fn set_interrupt(&self, interrupt: bool) { + // self.should_interrupt.store(interrupt, Ordering::Relaxed) + } + + #[inline] + fn get_interrupt(&self) -> bool { + false + // self.should_interrupt.load(Ordering::Relaxed) + } + + fn entries(&self, _: &Lua, _: String) -> Result { + let entries = read_dir(APPS_DIR)? .map(|result| result.map(|e| e.path())) .collect::, std::io::Error>>()?; - let parsed_entries: Vec = entries + let parsed_entries: Entries = entries .into_par_iter() .filter(|path| path.extension().is_some_and(|ext| ext == "desktop")) - .filter_map(|path| { - parse_entry(path).ok().flatten() - }) - .collect(); - - Ok( - parsed_entries - .into_iter() - .filter(|entry| entry.message.to_lowercase().contains(&input.to_lowercase())) - .collect(), - ) + .filter_map(|path| parse_entry(path).ok().flatten()) + .collect::>() + .into(); + + Ok(parsed_entries) } } fn parse_entry(path: PathBuf) -> Result, ()> { let Ok(entry) = fd::parse_entry(&path) else { - return Err(()) + return Err(()); }; let section = entry.section("Desktop Entry"); diff --git a/.config/awesome/quarrel/native/src/lenses/calculator.rs b/.config/awesome/quarrel/native/src/lenses/calculator.rs index 640bdeb..36f9805 100644 --- a/.config/awesome/quarrel/native/src/lenses/calculator.rs +++ b/.config/awesome/quarrel/native/src/lenses/calculator.rs @@ -1,40 +1,93 @@ -// use meval::eval_str; -use cpc::{ - eval, - units::Unit, +use std::sync::{ + atomic::{ + AtomicBool, + Ordering, + }, + Arc, + LazyLock, + Mutex, +}; + +use fend_core::{ + evaluate_with_interrupt, + Context, + Interrupt, }; use mlua::prelude::*; use crate::lenses::{ - Entry, - Cache, - Lense + Cache, Entries, Entry, Lense }; -pub struct Calculator; +static CTX: LazyLock> = LazyLock::new(|| { + let mut ctx = Context::new(); + ctx.use_coulomb_and_farad(); + Mutex::new(ctx) +}); + +#[derive(Default)] +pub struct Calculator { + should_interrupt: AtomicBool, +} impl Lense for Calculator { const NAME: &str = "Calculator"; - fn get_cache(&self) -> &Cache { - &Cache::Stale + fn init() -> std::sync::Arc { + Arc::new(Calculator::default()) + } + + #[inline] + fn set_cache(&self, _: Cache) {} + + #[inline] + fn get_cache(&self) -> Cache { + Cache::Stale + } + + #[inline] + fn set_interrupt(&self, interrupt: bool) { + self.should_interrupt.store(interrupt, Ordering::Relaxed); } - fn set_cache(&mut self, _: Cache) {} + #[inline] + fn get_interrupt(&self) -> bool { + self.should_interrupt.load(Ordering::Relaxed) + } - fn query(_: &Lua, input: String) -> Result, anyhow::Error> { - let result = match eval(input.trim(), true, Unit::Celsius, false) { + fn entries(&self, _: &Lua, input: String) -> Result { + let result = match evaluate_with_interrupt( + input.trim(), + &mut CTX.lock().expect("Failed to acquire Fend context lock"), + self, + ) { Ok(result) => { - format!("{result}") + result.get_main_result().to_string() + } + Err(err) => { + err } - Err(err) => { return Err(anyhow::anyhow!(err)); }, }; - Ok(vec![Entry { + Ok(if result.is_empty() { + Entries::None + } else { + Entries::Single(Entry { message: result, exec: None, - }; 1] - ) + }) + }) + + } + + #[inline] + fn filter(&self, entries: Entries, _: String) -> Entries { + entries } } +impl Interrupt for Calculator { + fn should_interrupt(&self) -> bool { + self.should_interrupt.load(Ordering::Relaxed) + } +} diff --git a/.config/awesome/quarrel/native/src/lenses/mod.rs b/.config/awesome/quarrel/native/src/lenses/mod.rs index 6eb5b58..bb7f727 100644 --- a/.config/awesome/quarrel/native/src/lenses/mod.rs +++ b/.config/awesome/quarrel/native/src/lenses/mod.rs @@ -1,13 +1,66 @@ pub mod application; pub mod calculator; +use std::sync::Arc; + +use itertools::Itertools; use mlua::{ prelude::*, LuaSerdeExt, }; -use serde::{Serialize, Deserialize}; +use rayon::iter::FromParallelIterator; +use serde::{ + Deserialize, + Serialize, +}; + +#[derive(Clone, Debug)] +pub enum Entries { + Multiple(Vec), + Single(Entry), + None +} -#[derive(Deserialize, Serialize, Clone)] +impl FromIterator for Entries { + fn from_iter>(iter: T) -> Self { + let mut iter = iter.into_iter(); + match (iter.next(), iter.next()) { + (None, None) => Self::None, + (Some(first), None) => Self::Single(first), + (None, Some(_)) => unreachable!(), + (Some(first), Some(second)) => { + let mut vec = Vec::from([first, second]); + vec.extend(iter); + Self::Multiple(vec) + }, + } + } +} + +impl From> for Entries { + fn from(entries: Vec) -> Self { + match entries.len() { + 0 => Self::None, + 1 => { + let entry = entries.into_iter().exactly_one().unwrap(); + Self::Single(entry) + }, + _ => Self::Multiple(entries) + } + } +} + +impl IntoLua for Entries { + fn into_lua(self, lua: &Lua) -> LuaResult { + match self { + Entries::Multiple(entries) => entries.into_lua(lua), + Entries::Single(entry) => entry.into_lua(lua), + Entries::None => Ok(LuaValue::Nil) + } + } +} + +#[derive(Deserialize, Serialize, Clone, Debug)] pub struct Entry { pub message: String, pub exec: Option<(String, bool)>, @@ -15,7 +68,7 @@ pub struct Entry { impl IntoLua for Entry { fn into_lua(self, lua: &Lua) -> LuaResult { - return lua.to_value(&self) + return lua.to_value(&self); } } @@ -25,55 +78,71 @@ impl FromLua for Entry { } } -#[derive(Default)] +#[derive(Default, Clone, Debug)] pub enum Cache { - Valid(Vec), + Valid(Entries), #[default] - Stale + Stale, } -pub struct _Lense(pub T); +pub struct _Lense(pub Arc); pub trait Lense { const NAME: &'static str; - fn set_cache(&mut self, cache: Cache); - fn get_cache(&self) -> &Cache; + fn init() -> Arc; + + fn set_cache(&self, cache: Cache); + fn get_cache(&self) -> Cache; + + fn set_interrupt(&self, interrupt: bool); + fn get_interrupt(&self) -> bool; - fn query(lua: &Lua, input: String) -> Result, anyhow::Error>; + fn entries(&self, lua: &Lua, input: String) -> Result; + fn filter(&self, entries: Entries, input: String) -> Entries { + let entry_contains = |entry: &Entry| { + entry.message.to_lowercase().contains(&input.to_lowercase()) + }; + match entries { + Entries::Multiple(entries) => entries.into_iter() + .filter(entry_contains) + .collect(), + Entries::Single(entry) => if entry_contains(&entry) { Entries::Single(entry) } else { Entries::None } + Entries::None => Entries::None + } + } } impl LuaUserData for _Lense { fn add_fields>(fields: &mut F) { - // fields.add_field_method_get("cache", |lua, this| { - // let cache = this.0.get_cache(); - // match cache { - // Cache::Valid(cache) => Ok(cache.clone().into_lua(lua)?), - // Cache::Stale => Ok(LuaNil) - // } - // }); - - // fields.add_field_method_set("cache", |_, this, cache: Vec| { - // Ok(this.0.set_cache(Cache::Valid(cache))) - // }); - - fields.add_field_method_get("stale", |_, this| Ok(matches!(this.0.get_cache(), Cache::Stale))); + fields.add_field_method_get("stale", |_, this| { + Ok(matches!(this.0.get_cache(), Cache::Stale)) + }); fields.add_field("name", T::NAME); } fn add_methods>(methods: &mut M) { methods.add_method_mut("query", |lua, this, input: String| { + this.0.set_interrupt(false); // reset interrupt so that we can use the lense again return Ok(match this.0.get_cache() { - Cache::Valid(entries) => entries.clone(), + Cache::Valid(entries) => this.0.filter(entries.clone(), input), Cache::Stale => { - let entries = T::query(lua, input).map_err(LuaError::external)?; + let entries = this.0.entries(lua, input.clone()).map_err(LuaError::external)?; + let mut entries = this.0.filter(entries, input); + match entries { + Entries::Multiple(ref mut entries) => entries.sort_by(|a, b| a.message.cmp(&b.message)), + _ => {} + } this.0.set_cache(Cache::Valid(entries.clone())); entries } }); }); - methods.add_method_mut("mark_stale", |_, this, _: ()| Ok(this.0.set_cache(Cache::Stale)) ); + methods.add_method_mut("mark_stale", |_, this, _: ()| { + Ok(this.0.set_cache(Cache::Stale)) + }); + methods.add_method_mut("interrupt", |_, this, _: ()| Ok(this.0.set_interrupt(true))); } } diff --git a/.config/awesome/quarrel/native/src/lib.rs b/.config/awesome/quarrel/native/src/lib.rs index 4f1780d..239ed2f 100644 --- a/.config/awesome/quarrel/native/src/lib.rs +++ b/.config/awesome/quarrel/native/src/lib.rs @@ -1,19 +1,19 @@ mod lenses; mod net; // mod http; -mod util; mod moondrop; +mod util; +use lenses::_Lense; use mlua::prelude::*; -use lenses::{ _Lense }; + +use crate::lenses::Lense; #[mlua::lua_module] fn qnative(lua: &Lua) -> LuaResult { let lenses = lua.create_table()?; - lenses.push(_Lense(lenses::calculator::Calculator))?; - lenses.push(_Lense(lenses::application::Application::default()))?; - // lenses.set("1", lua.create_function(lenses::calculator::Application::query)?)?; - // lenses.set("2", lua.create_function(lenses::application::Application::query)?)?; + lenses.push(_Lense(lenses::calculator::Calculator::init()))?; + lenses.push(_Lense(lenses::application::Application::init()))?; let util = lua.create_table()?; util.set("decode_html", lua.create_function(util::decode_html)?)?; diff --git a/.config/awesome/quarrel/native/src/moondrop.rs b/.config/awesome/quarrel/native/src/moondrop.rs index d416ef6..62a8ea0 100644 --- a/.config/awesome/quarrel/native/src/moondrop.rs +++ b/.config/awesome/quarrel/native/src/moondrop.rs @@ -1,3 +1 @@ use mdrop::Moondrop; - - diff --git a/.config/awesome/quarrel/native/src/net/mod.rs b/.config/awesome/quarrel/native/src/net/mod.rs index dbd87b9..383e800 100644 --- a/.config/awesome/quarrel/native/src/net/mod.rs +++ b/.config/awesome/quarrel/native/src/net/mod.rs @@ -9,7 +9,10 @@ use std::{ c_void, }, mem::size_of, - os::fd::{IntoRawFd, RawFd}, + os::fd::{ + IntoRawFd, + RawFd, + }, }; use mlua::prelude::*; diff --git a/.config/awesome/quarrel/native/src/util.rs b/.config/awesome/quarrel/native/src/util.rs index 41096d8..5b9c5f5 100644 --- a/.config/awesome/quarrel/native/src/util.rs +++ b/.config/awesome/quarrel/native/src/util.rs @@ -4,7 +4,7 @@ use std::{ io::{ Read, Seek, - Write + Write, }, rc::Rc, str::FromStr, diff --git a/.config/awesome/quarrel/table.lua b/.config/awesome/quarrel/table.lua index 2ae15ee..49ed45e 100644 --- a/.config/awesome/quarrel/table.lua +++ b/.config/awesome/quarrel/table.lua @@ -35,6 +35,14 @@ function qtable.filter(t, f, dict) return nt end +--- Get a slice of a table +---@param t table +---@param i integer start of the slice +---@param j integer end of the slice (inclusive) +function qtable.slice(t, i, j) + return { table.unpack(t, i, j) } +end + -- This is taken from http://lua-users.org/wiki/SortedIteration -- This version is stripped of comments and empty lines + some stuff is renamed diff --git a/.config/awesome/quarrel/ui/init.lua b/.config/awesome/quarrel/ui/init.lua index 5acaa51..2b63694 100644 --- a/.config/awesome/quarrel/ui/init.lua +++ b/.config/awesome/quarrel/ui/init.lua @@ -36,6 +36,28 @@ function M.styled(target) }, target) end +--- Wraps a widget inside of a margin widget +---@param target table +---@return table +function M.padded(target) + return { + widget = wibox.container.margin, + margins = M.PADDING, + target, + } +end + +--- Wraps a widget inside of a margin widget +---@param target table +---@return table +function M.padded_big(target) + return { + widget = wibox.container.margin, + margins = M.BIG_PADDING, + target, + } +end + --- Generates a styled popup ---@param target table ---@return table @@ -56,6 +78,18 @@ function M.recolor(color) return "svg{fill:" .. color .. "}" end +--- Generates icon widget +---@param args table +---@return table +function M.separator(args) + return wibox.widget(gtable.crush({ + widget = wibox.container.background, + bg = qcolor.palette.border(), + forced_height = not args.vertical and args.size, + forced_width = args.vertical and args.size, + }, args.widget or {})) +end + --- Generates icon widget ---@param args table ---@return table diff --git a/.config/awesome/ui/conductor/init.lua b/.config/awesome/ui/conductor/init.lua deleted file mode 100644 index 402945c..0000000 --- a/.config/awesome/ui/conductor/init.lua +++ /dev/null @@ -1,64 +0,0 @@ -local awful = require "awful" -local gshape = require "gears.shape" -local phosphor = require "assets.phosphor" -local q = require "quarrel" -local qui = require "quarrel.ui" -local qvars = require "quarrel.vars" -local wibox = require "wibox" - -local M = {} - -M._popup = qui.popup { - -- visible = false, - ontop = true, - placement = "right", - shape = function(cr, w, h) - gshape.partially_rounded_rect(cr, w, h, true, false, false, true, qui.BORDER_RADIUS) - end, - -- x = awful.screen.focused().geometry.width, - -- minimum_width = width, - -- maximum_width = width, - -- maximum_height = max_height, - widget = awful.widget.tasklist { - screen = awful.screen.focused(), - filter = awful.widget.tasklist.filter.allscreen, - layout = { - spacing = qui.BIG_PADDING, - layout = wibox.layout.fixed.vertical, - }, - widget_template = qui.styled { - widget = wibox.container.background, - { - { - widget = wibox.container.constraint, - strategy = "max", - height = qui.CHAR_HEIGHT, - width = qui.CHAR_HEIGHT, - { - widget = wibox.widget.imagebox, - id = "icon_role", - }, - }, - { - widget = wibox.container.constraint, - strategy = "max", - width = qui.CHAR_WIDTH * 24, - { - widget = wibox.widget.textbox, - id = "client_name", - }, - }, - layout = wibox.layout.fixed.horizontal, - spacing = qui.PADDING, - }, - create_callback = function(self, c) - self:get_children_by_id("client_name")[1].text = c.icon_name - end, - update_callback = function(self, c) - self:get_children_by_id("client_name")[1].text = c.name - end, - }, - }, -} - -return M diff --git a/.config/awesome/ui/fresnel/init.lua b/.config/awesome/ui/fresnel/init.lua index 5d091b6..dc8e333 100644 --- a/.config/awesome/ui/fresnel/init.lua +++ b/.config/awesome/ui/fresnel/init.lua @@ -1,5 +1,6 @@ -local al_prompt = require "lib.bling.widget.app_launcher.prompt" +local text_input = require "ui.fresnel.text_input" local awful = require "awful" +local qdebug = require "quarrel.debug" local cfg = require "misc.cfg" local gshape = require "gears.shape" local gtable = require "gears.table" @@ -13,19 +14,142 @@ local rubato = require "lib.rubato" local wibox = require "wibox" local btn = awful.button.names -local max_entries = 10 +local MAX_VISIBLE_ENTRIES = 10 +local DEFAULT_SCROLL_AMOUNT = 0 +local DEFAULT_SELECTED_IDX = 1 -local fresnel = {} +---@class (exact) Fresnel +---@field private _toggled boolean Whether fresnel is open +---@field private _entries (Entry|string)[] +---@field private _scroll_amount integer How many entries down are we +---@field private _prev_scroll_amount integer The _scroll_amount of the previous cycle +---@field private _visible_entries Entry[] The currently visible entries +---@field private _selected_idx integer The index of the currently selected entry. Is in the range 1.. +---@field private _prev_selected_idx integer The _selected_idx of the previous cycle +---@field private _active_lenses integer The number of lense titles in the _entries table +---@field private _lense_header_positions integer[] The positions of all the lense titles +---@field private _prev_text string +---@field private _first_query boolean +---@field private _make_header fun(string): wibox.container.background +---@field private _w_popup wibox.widget.base +---@field private _w_prompt wibox.widget.base +---@field private _w_status wibox.widget.base +---@field private _l_entries wibox.widget.base +---@field private _t_opacity table +---@field private _t_height table +local fresnel = { + _toggled = false, + _entries = {}, + _scroll_amount = DEFAULT_SCROLL_AMOUNT, + _prev_scroll_amount = DEFAULT_SCROLL_AMOUNT, + _visible_entries = {}, + _selected_idx = DEFAULT_SELECTED_IDX, + _prev_selected_idx = DEFAULT_SELECTED_IDX, + _lense_header_positions = {} +} -fresnel._toggled = false -fresnel._entries_exec = {} -fresnel._entries_offset = 0 -fresnel._entries_count = 0 -fresnel._visible_entries = 0 -fresnel._selected_index = 1 +---@private +---@param lense_name string +function fresnel._make_header(lense_name) + return wibox.widget { + widget = wibox.container.background, + fg = qcolor.palette.fg.low, + { + widget = wibox.container.margin, + margins = qui.PADDING, + { + { + widget = wibox.container.place, + { + widget = wibox.container.background, + bg = qcolor.palette.border(), + forced_height = qui.BORDER_WIDTH, + forced_width = qui.BIG_PADDING * 2, + }, + }, + { + widget = wibox.container.constraint, + strategy = "max", + height = qui.CHAR_HEIGHT, + { + widget = wibox.widget.textbox, + text = lense_name, + }, + }, + { + widget = wibox.container.place, + fill_horizontal = true, + content_fill_horizontal = true, + { + widget = wibox.container.background, + bg = qcolor.palette.border(), + forced_height = qui.BORDER_WIDTH, + }, + }, + layout = wibox.layout.fixed.horizontal, + spacing = qui.BIG_PADDING, + }, + }, + } +end -function fresnel:_exec_entry(entry_index) - local exec = self._entries_exec[entry_index] +---@private +---@param entry Entry +function fresnel:_make_entry(entry) + ---@class FresnelEntry : wibox.widget.base + ---@field _selected boolean + local entry_widget = wibox.widget { + widget = wibox.container.background, + shape = qui.shape, + { + widget = wibox.container.margin, + margins = qui.PADDING, + { + widget = wibox.container.constraint, + strategy = "max", + height = qui.CHAR_HEIGHT, + { + widget = wibox.widget.textbox, + text = entry.message, + }, + }, + }, + buttons = { + awful.button { + modifiers = {}, + button = btn.LEFT, + on_press = function() + fresnel:_exec_entry(entry) + end, + }, + }, + _selected = false, + } + + entry_widget:connect_signal("mouse::enter", function() + if entry_widget._selected == true then + return + end + entry_widget.bg = qcolor.palette.bg.high + end) + + entry_widget:connect_signal("mouse::leave", function() + if entry_widget._selected == true then + return + end + entry_widget.bg = qcolor.palette.bg() + end) + + return entry_widget +end + +---@private +---@param entry integer|Entry +function fresnel:_exec_entry(entry) + if type(entry) == "number" then + entry = self._visible_entries[entry] + end + local exec = entry.exec if type(exec) ~= "userdata" and type(exec) ~= "nil" then if exec[2] then awful.spawn(cfg.terminal .. " -e /bin/sh -c " .. exec[1] .. " 1>/dev/null 2>&1") @@ -35,172 +159,166 @@ function fresnel:_exec_entry(entry_index) end end -function fresnel:_update(query, scrolled) +---@private +---@param query string? +function fresnel:_update(query) query = query or "" - scrolled = scrolled or false + self._entries = {} + self._lense_header_positions = {} + self._active_lenses = 0 - if not scrolled then - self._selected_index = 1 - self._entries_offset = 0 + for _, lense in ipairs(qnative.lenses) do + local entries = lense:query(query) + if type(entries) == "table" then + table.insert(self._entries, lense.name) + table.insert(self._lense_header_positions, #self._entries) + if #entries > 0 then -- Entry[] + self._entries = gtable.join(self._entries, entries) + elseif entries.message then -- Entry + table.insert(self._entries, entries) + end + self._active_lenses = self._active_lenses + 1 + end -- either empty Entry[] or nil, in which case we shouldn't display them end - local layout = self._popup.widget:get_children_by_id("entry_layout")[1] - local status = self._popup.widget:get_children_by_id("status")[1] - local all_providers = {} - local entries_count = 0 + -- reset the scroll + if type(self._entries[1]) == "string" then + self._selected_idx = 2 -- to avoid selecting the header first + else + self._selected_idx = DEFAULT_SELECTED_IDX + end + self._scroll_amount = DEFAULT_SCROLL_AMOUNT + fresnel:_render(true) + self._first_query = false +end - self._entries_exec = {} - layout:reset() +---@private +---@param update boolean +function fresnel:_render(update) + local visible_entries_end = math.min(self._scroll_amount + MAX_VISIBLE_ENTRIES, #self._entries) + self._visible_entries = qtable.slice(self._entries, self._scroll_amount + 1, visible_entries_end) - for _, provider in qtable.opairs(qnative.lenses) do - local entries = provider(query) + local layout = fresnel._l_entries - table.sort(entries, function(a, b) - return a.message < b.message - end) + if self._scroll_amount ~= self._prev_scroll_amount or update or self._first_query then + layout:reset() + for i, entry in ipairs(self._visible_entries) do + if type(entry) == "string" then + layout:add(self._make_header(entry)) + else + local entry_widget = self:_make_entry(entry) + if self._selected_idx == i then + entry_widget._selected = true + entry_widget.bg = qcolor.palette.bg.high + end + layout:add(entry_widget) + end + end + elseif self._selected_idx ~= self._prev_selected_idx then + local entry_widget = layout.children[self._selected_idx] --[[@as FresnelEntry ]] + entry_widget._selected = true + entry_widget.bg = qcolor.palette.bg.high - all_providers = gtable.join(all_providers, entries) + local prev_entry_widget = layout.children[self._prev_selected_idx] --[[@as FresnelEntry ]] + prev_entry_widget._selected = false + prev_entry_widget.bg = qcolor.palette.bg() end - self._entries_count = #all_providers - - for i, entry in ipairs(all_providers) do - if i > self._entries_offset then - if entries_count == max_entries then - break - end - table.insert(self._entries_exec, entry.exec) - - local entry_widget = wibox.widget { - widget = wibox.container.background, - shape = qui.shape, - { - widget = wibox.container.margin, - margins = qui.PADDING, - { - widget = wibox.container.constraint, - strategy = "max", - height = qui.CHAR_HEIGHT, - { - { - widget = wibox.container.background, - fg = qcolor.palette.low, - { - widget = wibox.widget.textbox, - text = entry.provider .. " | ", - }, - }, - { - widget = wibox.widget.textbox, - text = entry.message, - }, - spacing = qui.PADDING, - layout = wibox.layout.fixed.horizontal, - }, - }, - }, - buttons = { - awful.button { - modifiers = {}, - button = btn.LEFT, - on_press = function() - self:_exec_entry(i) - end, - }, - }, - _selected = false, - } + local headers_passed = 0 + local current_position = self._scroll_amount + self._selected_idx + for _, position in ipairs(self._lense_header_positions) do + if current_position > position then + headers_passed = headers_passed + 1 + end + end + self._w_status.text = (self._scroll_amount + self._selected_idx - headers_passed) .. "/" .. (#self._entries - self._active_lenses) + self._prev_scroll_amount = self._scroll_amount + self._prev_selected_idx = self._selected_idx +end - if self._selected_index + self._entries_offset == i then - entry_widget._selected = true - entry_widget.bg = qcolor.palette.bg.high - end +---@param up boolean Whether to scroll up or down +function fresnel:scroll(up) + local direction = up and -1 or 1 + local offset = direction - entry_widget:connect_signal("mouse::enter", function() - if entry_widget._selected == true then - return - end - entry_widget.bg = qcolor.palette.bg.high - end) - entry_widget:connect_signal("mouse::leave", function() - if entry_widget._selected == true then - return - end - entry_widget.bg = qcolor.palette.bg() - end) + if type(self._entries[self._scroll_amount + self._selected_idx + offset]) == "string" then + offset = offset + direction + end - layout:add(entry_widget) + local new_selected_idx = self._selected_idx + offset + local new_position = self._scroll_amount + new_selected_idx + local new_scroll_amount = self._scroll_amount + offset - entries_count = entries_count + 1 - self._visible_entries = entries_count + if new_position < 1 then + if self._scroll_amount > 0 then + self._scroll_amount = self._scroll_amount + direction + self._selected_idx = self._selected_idx - direction + self:_render(false) end + return + elseif new_position > #self._entries then + return + end + + if up and new_selected_idx <= 0 then + self._scroll_amount = new_scroll_amount + elseif not up and new_selected_idx > #self._visible_entries then + self._scroll_amount = new_scroll_amount + else + self._selected_idx = new_selected_idx end - status.text = self._entries_offset + self._selected_index .. "/" .. self._entries_count + self:_render(false) end -fresnel._text = "" -fresnel._prompt = al_prompt { - prompt = "", - reset_on_stop = true, - ul_cursor = "low", - bg_cursor = qcolor.palette.bg.high, - changed_callback = function(text) - if fresnel._text == text then - return - end - if fresnel._toggled == false then - return - end - fresnel:_update(text) - fresnel._text = text - end, - keypressed_callback = function(mod, key) - if key == "Escape" or key == " " and mod.Mod4 then - fresnel:hide() - elseif key == "Return" then - fresnel:_exec_entry(fresnel._selected_index) - fresnel:hide() - elseif key == "Up" then - local next_index = fresnel._selected_index - 1 - if next_index < 1 and fresnel._entries_offset == 0 then - return - elseif next_index < 1 and fresnel._entries_offset > 0 then - fresnel._entries_offset = fresnel._entries_offset - 1 - else - fresnel._selected_index = next_index - end +fresnel._prev_text = "" +fresnel._w_prompt = wibox.widget { + widget = text_input, + reset_on_unfocus = true, + unfocus_keys = {}, +} - fresnel:_update(fresnel._text, true) - elseif key == "Down" then - local next_index = fresnel._selected_index + 1 - if - next_index > fresnel._visible_entries - and fresnel._entries_offset + fresnel._visible_entries == fresnel._entries_count - then - return - elseif - next_index > fresnel._visible_entries - and fresnel._entries_offset + fresnel._visible_entries < fresnel._entries_count - then - fresnel._entries_offset = fresnel._entries_offset + 1 - else - fresnel._selected_index = next_index - end +fresnel._w_prompt:connect_signal("unfocus", function () + fresnel:_hide() +end) - fresnel:_update(fresnel._text, true) - end - end, -} +fresnel._w_prompt:connect_signal("property::text", function(_, text) + fresnel:_update(text) +end) + +fresnel._w_prompt:connect_signal("key::press", function(_, _mods, key) + -- Convert index array to hash table + local mods = {} + for _, v in ipairs(_mods) do + mods[v] = true + end + + if key == "Escape" or key == " " and mods.Mod4 then + fresnel:hide() + elseif key == "Return" then + fresnel:_exec_entry(fresnel._selected_idx) + fresnel:hide() + elseif key == "k" and mods.Mod1 then + fresnel:scroll(true) + elseif key == "j" and mods.Mod1 then + fresnel:scroll(false) + end +end) local max_height = qui.BIG_PADDING * 2 + (qui.BIG_PADDING * 2 + qui.CHAR_HEIGHT) * 10 --- + qui.PADDING --- + qui.PADDING * 9 local width = awful.screen.focused().geometry.width / 2 -fresnel._popup = qui.popup { +fresnel._l_entries = wibox.widget { + spacing = qui.PADDING, + layout = wibox.layout.fixed.vertical, +} +fresnel._w_status = wibox.widget { + widget = wibox.widget.textbox, + text = "0/0", +} +fresnel._w_popup = qui.popup { -- visible = false, ontop = true, placement = false, @@ -222,7 +340,7 @@ fresnel._popup = qui.popup { { { widget = wibox.widget.textbox, - text = ">", + markup = [[>]], }, { widget = wibox.container.margin, @@ -237,15 +355,11 @@ fresnel._popup = qui.popup { { widget = wibox.container.background, fg = qcolor.palette.fg(), - fresnel._prompt.textbox, + fresnel._w_prompt, }, }, }, - { - widget = wibox.widget.textbox, - text = "0/0", - id = "status", - }, + fresnel._w_status, layout = wibox.layout.align.horizontal, }, }, @@ -255,52 +369,60 @@ fresnel._popup = qui.popup { margins = { top = qui.PADDING, }, - { - spacing = qui.PADDING, - layout = wibox.layout.fixed.vertical, - id = "entry_layout", - }, + fresnel._l_entries, }, layout = wibox.layout.align.vertical, }, } + function fresnel:show() + self._prev_scroll_amount = DEFAULT_SCROLL_AMOUNT + self._prev_selected_idx = DEFAULT_SELECTED_IDX + self._first_query = true self._toggled = true - self._opacity_timed.target = 1 - self._height_timed:set(max_height) + self._t_opacity.target = 1 + self._t_height:set(max_height) self:_update() - self._prompt:start() + self._w_prompt:focus() end -function fresnel:hide() +---@private +function fresnel:_hide() self._toggled = false - self._opacity_timed.target = 0 - self._height_timed:set(0) - self._prompt:stop() + self._t_opacity.target = 0 + self._t_height:set(0) + for _, lense in ipairs(qnative.lenses) do + lense:interrupt() + end +end + +function fresnel:hide() + self._w_prompt:unfocus() + self:_hide() end -fresnel._height_timed = qanim:new { +fresnel._t_height = qanim:new { duration = qvars.anim_duration, pos = 0, easing = qvars.easing, subscribed = function(pos) - fresnel._popup.shape = function(cr, w) + fresnel._w_popup.shape = function(cr, w) gshape.partially_rounded_rect(cr, w, pos, false, false, true, true, qui.BORDER_RADIUS) end end, } -- TODO: optimize the search algo to be more efficient and not require making fresnel invisible -fresnel._opacity_timed = rubato.timed { +fresnel._t_opacity = rubato.timed { duration = qvars.anim_duration, pos = 0, subscribed = function(pos) - fresnel._popup.opacity = pos + fresnel._w_popup.opacity = pos if pos == 0 then - fresnel._popup.visible = false + fresnel._w_popup.visible = false else - fresnel._popup.visible = true + fresnel._w_popup.visible = true end end, } diff --git a/.config/awesome/ui/init.lua b/.config/awesome/ui/init.lua index 6ad1c7b..8ba64f9 100644 --- a/.config/awesome/ui/init.lua +++ b/.config/awesome/ui/init.lua @@ -1,4 +1,4 @@ require "ui.statusbar" require "ui.decorations" --- require "ui.conductor" +-- require "ui.tidy" -- require "ui.osd" diff --git a/.config/awesome/ui/statusbar/panel/widgets/mpris.lua b/.config/awesome/ui/statusbar/panel/widgets/mpris.lua index c27bf66..687bbb1 100644 --- a/.config/awesome/ui/statusbar/panel/widgets/mpris.lua +++ b/.config/awesome/ui/statusbar/panel/widgets/mpris.lua @@ -99,11 +99,8 @@ M.widget = wibox.widget(qui.styled { { widget = client_background, { - widget = wibox.container.margin, - margins = qui.BIG_PADDING, - { nil, - { + qui.padded_big { { { widget = wibox.container.background, @@ -122,7 +119,6 @@ M.widget = wibox.widget(qui.styled { }, { widget = wibox.container.margin, - right = qui.BIG_PADDING, left = qui.BIG_PADDING, { { @@ -160,7 +156,6 @@ M.widget = wibox.widget(qui.styled { { widget = wibox.container.margin, top = qui.BIG_PADDING, - right = qui.BIG_PADDING, { { widget = wibox.widget.textbox, @@ -188,12 +183,22 @@ M.widget = wibox.widget(qui.styled { layout = wibox.layout.align.vertical, }, { - layout = wibox.layout.flex.vertical, - spacing = qui.BIG_PADDING, - id = "client_list", + qui.separator { + size = qui.BORDER_WIDTH, + vertical = true + }, + { + widget = wibox.container.background, + bg = qcolor.palette.bg.high, + qui.padded_big { + layout = wibox.layout.flex.vertical, + spacing = qui.BIG_PADDING, + id = "client_list", + } + }, + layout = wibox.layout.fixed.horizontal, }, layout = wibox.layout.align.horizontal, - }, }, }, }) diff --git a/.config/awesome/ui/wicked/consts.lua b/.config/awesome/ui/wicked/consts.lua index e00cae5..c864483 100644 --- a/.config/awesome/ui/wicked/consts.lua +++ b/.config/awesome/ui/wicked/consts.lua @@ -1,5 +1,13 @@ +local qcolor = require "quarrel.color" + local C = {} C.NOTIF_TIMEOUT = 3 +C.LEVEL_COLORS = { + debug = qcolor.palette.purple(), + info = qcolor.palette.blue(), + warn = qcolor.palette.orange(), + error = qcolor.palette.red(), +} return C diff --git a/.config/awesome/ui/wicked/init.lua b/.config/awesome/ui/wicked/init.lua index dea28d5..dd3324d 100644 --- a/.config/awesome/ui/wicked/init.lua +++ b/.config/awesome/ui/wicked/init.lua @@ -8,13 +8,14 @@ local qvars = require "quarrel.vars" local wibox = require "wibox" local rtimed = require("lib.rubato").timed local easing = require("lib.rubato").easing +local consts = require "ui.wicked.consts" local gtimer = require "gears.timer" local qcolor = require "quarrel.color" local qmarkup = require "quarrel.markup" local M = require "ui.wicked.consts" -function M.new(n) +function M.new(n, _, n_args) local intertext_margin = (n.title ~= "" or n.message ~= "") and qui.PADDING or 0 local title_height = n.title ~= "" and qui.CHAR_HEIGHT or 0 local message_height = n.message ~= "" and qui.CHAR_HEIGHT or 0 @@ -25,7 +26,33 @@ function M.new(n) app_name = n.app_name end - local notif = naughty.layout.box { + local w_progress, t_progress + + local level_color = consts.LEVEL_COLORS[n_args.level] or (n.urgency == "critical" and qcolor.palette.yellow()) + + if n.timeout > 0 then + w_progress = wibox.widget { + widget = wibox.container.radialprogressbar, + max_value = M.NOTIF_TIMEOUT, + border_color = qcolor.palette.bg.lowest, + color = qcolor.palette.yellow(), + border_width = qui.PADDING / 2, + forced_height = qui.CHAR_HEIGHT, + forced_width = qui.CHAR_HEIGHT, + } + + t_progress = rtimed { + duration = n.timeout, + pos = 0, + easing = easing.none, + clamp_position = true, + subscribed = function(pos) + w_progress.value = pos + end, + } + end + + local w_notif = naughty.layout.box { notification = n, placement = function(d) return awful.placement.right(d, { @@ -50,6 +77,8 @@ function M.new(n) { qui.styled { widget = wibox.container.background, + forced_width = beautiful.notification_max_width, + -- border_color = border_color, point = function(geo, args) return { x = args.parent.width, @@ -57,114 +86,111 @@ function M.new(n) } end, { + widget = wibox.container.margin, + margins = qui.BIG_PADDING, { - widget = wibox.container.margin, - margins = qui.BIG_PADDING, - { - { - widget = wibox.widget.textbox, - markup = qmarkup(app_name, { bold = true }), - }, - nil, - { - - widget = wibox.container.radialprogressbar, - max_value = M.NOTIF_TIMEOUT, - border_color = qcolor.palette.bg.lowest, - color = qcolor.palette.yellow(), - border_width = qui.BORDER_WIDTH, - forced_height = qui.CHAR_HEIGHT, - forced_width = qui.CHAR_HEIGHT, - id = "progress", - }, - layout = wibox.layout.align.horizontal, - }, - }, - { - widget = wibox.container.constraint, - height = qui.BORDER_WIDTH, - width = beautiful.notification_max_width, - strategy = "exact", - { - widget = wibox.container.background, - bg = qcolor.palette.border(), - }, - }, - { - widget = wibox.container.margin, - margins = qui.BIG_PADDING, { widget = wibox.container.constraint, - height = n.icon and qui.CHAR_HEIGHT * 2 + qui.PADDING - or (title_height + message_height + intertext_margin), - strategy = "exact", + width = beautiful.notification_max_width - (qui.BIG_PADDING + qui.BORDER_WIDTH) * 2 - (level_color and qui.BIG_PADDING + qui.PADDING or 0), + strategy = "max", { + widget = wibox.container.place, + content_fill_horizontal = true, { - widget = wibox.container.background, { - widget = naughty.widget.icon, - shape = qui.shape, - notification = n, + { + widget = wibox.widget.textbox, + markup = qmarkup(app_name, { bold = true }), + }, + nil, + w_progress, + layout = wibox.layout.align.horizontal, }, - }, - { { widget = wibox.container.constraint, - height = title_height, + height = qui.BORDER_WIDTH, strategy = "exact", { - widget = wibox.widget.textbox, - text = n.title or "", + widget = wibox.container.background, + bg = qcolor.palette.border(), }, }, { widget = wibox.container.constraint, - height = message_height, + height = n.icon and qui.CHAR_HEIGHT * 2 + qui.PADDING + or (title_height + message_height + intertext_margin), strategy = "exact", { - widget = wibox.widget.textbox, - text = n.message or "", + { + widget = naughty.widget.icon, + shape = qui.shape, + notification = n, + }, + { + { + widget = wibox.container.constraint, + height = title_height, + strategy = "exact", + { + widget = wibox.widget.textbox, + text = n.title or "", + }, + }, + { + widget = wibox.container.constraint, + height = message_height, + strategy = "exact", + { + widget = wibox.widget.textbox, + text = n.message or "", + }, + }, + spacing = intertext_margin, + layout = wibox.layout.fixed.vertical, + }, + fill_space = true, + spacing = n.icon and qui.BIG_PADDING, + layout = wibox.layout.fixed.horizontal, }, }, - spacing = intertext_margin, layout = wibox.layout.fixed.vertical, + spacing = qui.BIG_PADDING, }, - fill_space = true, - spacing = n.icon and qui.BIG_PADDING or nil, - layout = wibox.layout.fixed.horizontal, }, }, + -- { + -- widget = wibox.container.constraint, + -- strategy = "max", + -- widget = wibox.container.place, + { + forced_width = qui.PADDING, + widget = wibox.container.background, + bg = level_color, + shape = qui.shape, + -- }, + }, + layout = wibox.layout.fixed.horizontal, + spacing = level_color and qui.BIG_PADDING, + -- expand = "outside" }, - layout = wibox.layout.fixed.vertical, }, id = "bg", }, layout = wibox.layout.manual, - id = "manual", }, }, } local hiding = false - local old_destroy = notif._private.destroy_callback + local old_destroy = w_notif._private.destroy_callback - local progress = rtimed { - duration = n.timeout, - pos = 0, - easing = easing.none, - clamp_position = true, - subscribed = function(pos) - notif.widget:get_children_by_id("progress")[1].value = pos - end, - } - - local position = qanim:new { + local t_position = qanim:new { duration = qvars.anim_duration, pos = 0, easing = qvars.easing, subscribed = function(pos) gtimer.delayed_call(function() - notif.widget.widget:move(1, function(geo, args) + w_notif.widget.widget:move(1, function(geo, args) if pos == 0 and hiding then old_destroy() end @@ -176,30 +202,30 @@ function M.new(n) end) end, } - local opacity = rtimed { + local t_opacity = rtimed { duration = qvars.anim_duration, intro = qvars.anim_intro, easing = easing.quadratic, pos = 0, clamp_position = true, subscribed = function(pos) - notif.opacity = pos + w_notif.opacity = pos end, } - n:disconnect_signal("destroyed", notif._private.destroy_callback) - function notif._private.destroy_callback() - opacity.target = 0 - position:set(0) + n:disconnect_signal("destroyed", w_notif._private.destroy_callback) + function w_notif._private.destroy_callback() + t_opacity.target = 0 + t_position:set(0) hiding = true end - n:weak_connect_signal("destroyed", notif._private.destroy_callback) + n:weak_connect_signal("destroyed", w_notif._private.destroy_callback) - --- for some reason when urgency is critical, it somehow makes it not disappear - --- why? dunno, FIXME - opacity.target = 1 - position:set(beautiful.notification_max_width) - progress.target = M.NOTIF_TIMEOUT + t_opacity.target = 1 + t_position:set(beautiful.notification_max_width) + if t_progress then + t_progress.target = M.NOTIF_TIMEOUT + end end return setmetatable(M, { -- cgit v1.2.3