aboutsummaryrefslogtreecommitdiff
path: root/.config/awesome
diff options
context:
space:
mode:
authordelta <darkussdelta@gmail.com>2025-10-29 16:35:38 +0100
committerdelta <darkussdelta@gmail.com>2025-10-29 16:35:38 +0100
commitd7c66522cf365f516babcfeb1d4a2d36c3ea41af (patch)
tree30c7d6103037b31170ae6d8fd58e3849e3cea823 /.config/awesome
parentdf418700b7d776f03ee5b58daa2d497cddb45aca (diff)
a small refactor
Diffstat (limited to '.config/awesome')
-rw-r--r--.config/awesome/misc/keys.lua22
-rw-r--r--.config/awesome/prismite.lua3
-rw-r--r--.config/awesome/quarrel/init.lua12
-rw-r--r--.config/awesome/quarrel/native/Cargo.toml3
-rw-r--r--.config/awesome/quarrel/native/init.lua13
l---------.config/awesome/quarrel/native/libqnative.so2
-rw-r--r--.config/awesome/quarrel/native/src/lenses/application.rs108
-rw-r--r--.config/awesome/quarrel/native/src/lenses/calculator.rs89
-rw-r--r--.config/awesome/quarrel/native/src/lenses/mod.rs121
-rw-r--r--.config/awesome/quarrel/native/src/lib.rs12
-rw-r--r--.config/awesome/quarrel/native/src/moondrop.rs2
-rw-r--r--.config/awesome/quarrel/native/src/net/mod.rs5
-rw-r--r--.config/awesome/quarrel/native/src/util.rs2
-rw-r--r--.config/awesome/quarrel/table.lua8
-rw-r--r--.config/awesome/quarrel/ui/init.lua34
-rw-r--r--.config/awesome/ui/conductor/init.lua64
-rw-r--r--.config/awesome/ui/fresnel/init.lua472
-rw-r--r--.config/awesome/ui/init.lua2
-rw-r--r--.config/awesome/ui/statusbar/panel/widgets/mpris.lua25
-rw-r--r--.config/awesome/ui/wicked/consts.lua8
-rw-r--r--.config/awesome/ui/wicked/init.lua192
21 files changed, 754 insertions, 445 deletions
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<RecommendedWatcher> = OnceLock::new();
+
#[derive(Default)]
-pub struct Application(pub Cache);
+pub struct Application {
+ cache: RwLock<Cache>,
+ should_interrupt: AtomicBool,
+}
impl Lense for Application {
const NAME: &str = "Application";
- fn get_cache(&self) -> &Cache {
- &self.0
+ fn init() -> Arc<Self> {
+ 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
+ }
+
+ #[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::<Self>(),
+ 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::<Self>(),
+ err
+ );
+ Cache::Stale
+ }
+ }
+ }
+
+ #[inline]
+ fn set_interrupt(&self, interrupt: bool) {
+ // self.should_interrupt.store(interrupt, Ordering::Relaxed)
}
- fn set_cache(&mut self, cache: Cache) {
- self.0 = cache;
+ #[inline]
+ fn get_interrupt(&self) -> bool {
+ false
+ // self.should_interrupt.load(Ordering::Relaxed)
}
- fn query(_: &Lua, input: String) -> Result<Vec<Entry>, anyhow::Error> {
- let applications_dir = "/usr/share/applications";
- let entries = read_dir(applications_dir)?
+ fn entries(&self, _: &Lua, _: String) -> Result<Entries, anyhow::Error> {
+ let entries = read_dir(APPS_DIR)?
.map(|result| result.map(|e| e.path()))
.collect::<Result<Vec<_>, std::io::Error>>()?;
- let parsed_entries: Vec<Entry> = 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();
+ .filter_map(|path| parse_entry(path).ok().flatten())
+ .collect::<Vec<Entry>>()
+ .into();
- Ok(
- parsed_entries
- .into_iter()
- .filter(|entry| entry.message.to_lowercase().contains(&input.to_lowercase()))
- .collect(),
- )
+ Ok(parsed_entries)
}
}
fn parse_entry(path: PathBuf) -> Result<Option<Entry>, ()> {
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<Mutex<Context>> = 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<Self> {
+ 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<Vec<Entry>, anyhow::Error> {
- let result = match eval(input.trim(), true, Unit::Celsius, false) {
+ fn entries(&self, _: &Lua, input: String) -> Result<Entries, anyhow::Error> {
+ 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<Entry>),
+ Single(Entry),
+ None
+}
-#[derive(Deserialize, Serialize, Clone)]
+impl FromIterator<Entry> for Entries {
+ fn from_iter<T: IntoIterator<Item = Entry>>(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<Vec<Entry>> for Entries {
+ fn from(entries: Vec<Entry>) -> 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<LuaValue> {
+ 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<LuaValue> {
- 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<Entry>),
+ Valid(Entries),
#[default]
- Stale
+ Stale,
}
-pub struct _Lense<T: Lense>(pub T);
+pub struct _Lense<T: Lense>(pub Arc<T>);
pub trait Lense {
const NAME: &'static str;
- fn set_cache(&mut self, cache: Cache);
- fn get_cache(&self) -> &Cache;
+ fn init() -> Arc<Self>;
+
+ 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<Vec<Entry>, anyhow::Error>;
+ fn entries(&self, lua: &Lua, input: String) -> Result<Entries, anyhow::Error>;
+ 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<T: Lense + 'static> LuaUserData for _Lense<T> {
fn add_fields<F: LuaUserDataFields<Self>>(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<Entry>| {
- // 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<M: LuaUserDataMethods<Self>>(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<LuaTable> {
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
@@ -59,6 +81,18 @@ 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
function M.icon(args)
return wibox.widget(gtable.crush({
widget = wibox.widget.imagebox,
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 = [[<span foreground="]] .. qcolor.palette.yellow() .. [[">></span>]],
},
{
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, {