17 Commits
Author SHA1 Message Date
Kenny Levinsen 3eb7cddb6c Bump version to 0.3.0 2022-01-15 18:40:38 +01:00
Kenny Levinsen 2813ae0eff clock: Adjust to new font advance 2022-01-14 00:39:23 +01:00
Kenny Levinsen 1b1ffc4435 Update example config 2022-01-14 00:38:02 +01:00
Tadeo Kondrak cf9fabb052 draw: Use font's horizontal advance value 2022-01-14 00:36:50 +01:00
Cyril Levis 43fe73bf09 feat: add ranking based on usage to launcher widget
Signed-off-by: Cyril Levis <git@levis.name>
2022-01-02 17:08:18 +01:00
Cyril Levis d291e36b3f feat: allow choosing recent app with tabs 2021-12-30 22:22:01 +01:00
Cyril Levis fe37c15f95 feat: deduplicate desktop entries
We don't want duplicate entries because there are not distinguishable by Name.

People will sometimes override in there HOME dir some desktop files entries
in order to do some modifications.

The actual reading order is good and so `unique_by` name do the job.
2021-12-30 22:10:51 +01:00
Cyril Levis d4f62da6f5 feat: recurse deeper in applications folder
max recursion 2 levels
2021-12-30 22:04:19 +01:00
Tadeo Kondrak 1edefd9cad main: only bind up to version 3 of wl_output 2021-12-25 18:32:37 +01:00
Maxim Baz 90ffa7df27 Lex exec even when using custom opener
This fixes a few bugs I found related to custom opener.

Instead of sending the entire exec as a single argument, this properly
splits the command, trims trailing whitespaces, and lets the receiving
opener iterate over terms.
2021-12-25 17:59:45 +01:00
Kenny Levinsen d69e941ec1 Remove old FUNDING link 2021-10-15 22:47:10 +02:00
Kenny Levinsen 5e5e8876f6 cargo fmt 2021-09-02 21:15:35 +02:00
Kenny Levinsen 886d595f91 launcher: Migrate to SkimMatcherV2 2021-09-02 21:14:08 +02:00
Kenny Levinsen e04237b928 Use format string with panic 2021-09-02 21:13:57 +02:00
Kenny Levinsen ef84c519a2 app: Migrate to compare_exchange 2021-09-02 21:13:33 +02:00
Kenny Levinsen 1e647c7036 readme: Update discuss section 2021-05-19 17:51:27 +02:00
Kenny Levinsen 56f6b1668d cargo fmt 2021-03-04 00:23:09 +01:00
20 changed files with 242 additions and 105 deletions
-1
View File
@@ -1,4 +1,3 @@
# These are supported funding model platforms # These are supported funding model platforms
liberapay: kennylevinsen liberapay: kennylevinsen
custom: https://donate.kl.wtf/
Generated
+46
View File
@@ -152,6 +152,12 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e" checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]] [[package]]
name = "fake-simd" name = "fake-simd"
version = "0.1.2" version = "0.1.2"
@@ -185,6 +191,15 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "itertools"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.7" version = "0.4.7"
@@ -520,6 +535,15 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.123" version = "1.0.123"
@@ -663,6 +687,17 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.10.0+wasi-snapshot-preview1" version = "0.10.0+wasi-snapshot-preview1"
@@ -744,6 +779,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
@@ -762,6 +806,7 @@ dependencies = [
"dlib", "dlib",
"fontconfig", "fontconfig",
"fuzzy-matcher", "fuzzy-matcher",
"itertools",
"lazy_static", "lazy_static",
"libpulse-binding", "libpulse-binding",
"memmap", "memmap",
@@ -776,6 +821,7 @@ dependencies = [
"shlex", "shlex",
"timerfd", "timerfd",
"unicode-segmentation", "unicode-segmentation",
"walkdir",
"wayland-client", "wayland-client",
"wayland-protocols", "wayland-protocols",
] ]
+3 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "wldash" name = "wldash"
version = "0.2.0" version = "0.3.0"
authors = ["Kenny Levinsen <kl@kl.wtf>"] authors = ["Kenny Levinsen <kl@kl.wtf>"]
edition = "2018" edition = "2018"
@@ -37,6 +37,8 @@ rcalc_lib = "0.9"
rust-ini = "0.14" rust-ini = "0.14"
shlex = "0.1" shlex = "0.1"
timerfd = "1.0.0" timerfd = "1.0.0"
walkdir = "2.3.2"
itertools = "0.10.3"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true }
+4
View File
@@ -66,3 +66,7 @@ The launcher also accepts prefix operators to change its mode:
- Configurability - Configurability
- Cleanup and reorganization - Cleanup and reorganization
- Proper line editor for the launcher - Proper line editor for the launcher
## How to discuss
Go to #kennylevinsen @ irc.libera.chat to discuss, or use [~kennylevinsen/public-inbox@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/public-inbox).
+3 -3
View File
@@ -37,8 +37,8 @@
{"launcher": { {"launcher": {
"font_size": 32.0, "font_size": 32.0,
"length": 1200, "length": 1200,
"app_opener": "swaymsg exec ", "app_opener": "swaymsg exec -- ",
"term_opener": "alacritty -e ", "term_opener": "foot --",
"url_opener": "xdg-open " "url_opener": "xdg-open "
}} }}
]} ]}
@@ -52,4 +52,4 @@
"blue": 0, "blue": 0,
"opacity": 0.9 "opacity": 0.9
} }
} }
+2 -2
View File
@@ -45,6 +45,6 @@ widget:
- launcher: - launcher:
font_size: 32.0 font_size: 32.0
length: 1200 length: 1200
app_opener: "swaymsg exec " app_opener: "swaymsg exec --"
term_opener: "alacritty -e " term_opener: "foot --"
url_opener: "xdg-open " url_opener: "xdg-open "
+40 -40
View File
@@ -5,11 +5,9 @@ use std::sync::{Arc, Mutex};
use chrono::{Duration, Local, NaiveDateTime}; use chrono::{Duration, Local, NaiveDateTime};
use crate::keyboard::{ use crate::keyboard::{keysyms, map_keyboard, Event as KbEvent, KeyState, ModifiersState};
keysyms, map_keyboard, Event as KbEvent, KeyState, ModifiersState,
};
use wayland_client::protocol::{wl_compositor, wl_output, wl_pointer, wl_shm, wl_surface, wl_seat}; use wayland_client::protocol::{wl_compositor, wl_output, wl_pointer, wl_seat, wl_shm, wl_surface};
use wayland_client::{Display, EventQueue, GlobalEvent, GlobalManager, Main}; use wayland_client::{Display, EventQueue, GlobalEvent, GlobalManager, Main};
use wayland_protocols::wlr::unstable::layer_shell::v1::client::{ use wayland_protocols::wlr::unstable::layer_shell::v1::client::{
zwlr_layer_shell_v1, zwlr_layer_surface_v1, zwlr_layer_shell_v1, zwlr_layer_surface_v1,
@@ -17,7 +15,7 @@ use wayland_protocols::wlr::unstable::layer_shell::v1::client::{
use crate::buffer::Buffer; use crate::buffer::Buffer;
use crate::color::Color; use crate::color::Color;
use crate::widget::{WaitContext, DrawContext, Widget}; use crate::widget::{DrawContext, WaitContext, Widget};
use crate::cmd::Cmd; use crate::cmd::Cmd;
use crate::doublemempool::DoubleMemPool; use crate::doublemempool::DoubleMemPool;
@@ -68,28 +66,29 @@ impl AppInner {
Main<wl_surface::WlSurface>, Main<wl_surface::WlSurface>,
Main<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>, Main<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>,
) { ) {
let surface = compositor let surface = compositor.create_surface();
.create_surface();
let this_is_stupid = AtomicBool::new(false); let this_is_stupid = AtomicBool::new(false);
let shell_surface = shell let shell_surface = shell.get_layer_surface(
.get_layer_surface( &surface,
&surface, output,
output, zwlr_layer_shell_v1::Layer::Overlay,
zwlr_layer_shell_v1::Layer::Overlay, "".to_string(),
"".to_string());
shell_surface.quick_assign(move |layer, event, _| match event {
zwlr_layer_surface_v1::Event::Configure { serial, .. } => {
if !this_is_stupid.compare_and_swap(false, true, Ordering::SeqCst) {
*(configured_surfaces.lock().unwrap()) += 1;
layer.ack_configure(serial);
tx.send(Cmd::ForceDraw).unwrap();
}
}
_ => unreachable!(),
},
); );
shell_surface.quick_assign(move |layer, event, _| match event {
zwlr_layer_surface_v1::Event::Configure { serial, .. } => {
if this_is_stupid
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
{
*(configured_surfaces.lock().unwrap()) += 1;
layer.ack_configure(serial);
tx.send(Cmd::ForceDraw).unwrap();
}
}
_ => unreachable!(),
});
shell_surface.set_keyboard_interactivity(1); shell_surface.set_keyboard_interactivity(1);
shell_surface.set_size(1, 1); shell_surface.set_size(1, 1);
@@ -401,8 +400,7 @@ impl<'a> App<'a> {
version, version,
} => { } => {
if let "wl_output" = &interface[..] { if let "wl_output" = &interface[..] {
let output = registry let output = registry.bind(std::cmp::min(version, 3), id);
.bind(version, id);
inner_global.lock().unwrap().add_output(id, output); inner_global.lock().unwrap().add_output(id, output);
} }
} }
@@ -415,8 +413,8 @@ impl<'a> App<'a> {
// double sync to retrieve the global list // double sync to retrieve the global list
// and the globals metadata // and the globals metadata
event_queue.sync_roundtrip(&mut(), |_, _, _|{}).unwrap(); event_queue.sync_roundtrip(&mut (), |_, _, _| {}).unwrap();
event_queue.sync_roundtrip(&mut(), |_, _, _|{}).unwrap(); event_queue.sync_roundtrip(&mut (), |_, _, _| {}).unwrap();
// wl_compositor // wl_compositor
let compositor = manager let compositor = manager
@@ -435,10 +433,8 @@ impl<'a> App<'a> {
// //
// Get our seat // Get our seat
// //
let seat: Main<wl_seat::WlSeat> = manager let seat: Main<wl_seat::WlSeat> = manager.instantiate_range(1, 6).unwrap();
.instantiate_range(1, 6) event_queue.sync_roundtrip(&mut (), |_, _, _| {}).unwrap();
.unwrap();
event_queue.sync_roundtrip(&mut(), |_, _, _|{}).unwrap();
// //
// Keyboard processing // Keyboard processing
@@ -453,7 +449,7 @@ impl<'a> App<'a> {
num_lock: false, num_lock: false,
})); }));
let keyboard = Arc::new(Mutex::new(AppKeyboard{ let keyboard = Arc::new(Mutex::new(AppKeyboard {
current: None, current: None,
delay: 0, delay: 0,
rate: 0, rate: 0,
@@ -485,7 +481,10 @@ impl<'a> App<'a> {
let mut kbd = kb2.lock().unwrap(); let mut kbd = kb2.lock().unwrap();
kbd.current = Some(ev.clone()); kbd.current = Some(ev.clone());
kbd.next = if kbd.delay > 0 { kbd.next = if kbd.delay > 0 {
Some(Local::now().naive_local() + Duration::milliseconds(kbd.delay.into())) Some(
Local::now().naive_local()
+ Duration::milliseconds(kbd.delay.into()),
)
} else { } else {
None None
}; };
@@ -496,10 +495,10 @@ impl<'a> App<'a> {
} else { } else {
kb2.lock().unwrap().next = None; kb2.lock().unwrap().next = None;
} }
}, }
KbEvent::Leave { .. } => { KbEvent::Leave { .. } => {
kb2.lock().unwrap().next = None; kb2.lock().unwrap().next = None;
}, }
KbEvent::RepeatInfo { delay, rate } => { KbEvent::RepeatInfo { delay, rate } => {
let mut kbd = kb2.lock().unwrap(); let mut kbd = kb2.lock().unwrap();
kbd.delay = delay; kbd.delay = delay;
@@ -513,15 +512,16 @@ impl<'a> App<'a> {
// //
// Prepare shell so that we can create our shell surface // Prepare shell so that we can create our shell surface
// //
inner.lock().unwrap().set_shell(Some( inner
if let Ok(layer) = manager.instantiate_exact(1) { .lock()
.unwrap()
.set_shell(Some(if let Ok(layer) = manager.instantiate_exact(1) {
layer layer
} else { } else {
panic!("server didn't advertise `zwlr_layer_shell_v1`"); panic!("server didn't advertise `zwlr_layer_shell_v1`");
}, }));
));
event_queue.sync_roundtrip(&mut(), |_, _, _|{}).unwrap(); event_queue.sync_roundtrip(&mut (), |_, _, _| {}).unwrap();
// //
// Cursor processing // Cursor processing
+1 -1
View File
@@ -345,6 +345,6 @@ impl Default for Config {
fn get_font<'a>(name: &str, map: &'a FontMap) -> FontRef<'a> { fn get_font<'a>(name: &str, map: &'a FontMap) -> FontRef<'a> {
match map.get(name) { match map.get(name) {
Some(f) => f, Some(f) => f,
None => panic!(format!("Font {} is missing from the config", name)), None => panic!("Font {} is missing from the config", name),
} }
} }
+57
View File
@@ -0,0 +1,57 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::fs::{create_dir_all, File, OpenOptions};
use std::path::PathBuf;
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)]
pub struct Data {
pub entries: HashMap<String, i64>,
}
impl Data {
pub fn load() -> Result<Data, Box<dyn Error>> {
Ok(serde_yaml::from_reader(Self::read_file()?)?)
}
pub fn save(&self) -> Result<(), Box<dyn Error>> {
Ok(serde_yaml::to_writer(Self::write_file()?, self)?)
}
fn read_file() -> Result<File, Box<dyn Error>> {
Ok(OpenOptions::new()
.create(true)
.write(true)
.read(true)
.open(Self::path()?)?)
}
fn write_file() -> Result<File, Box<dyn Error>> {
Ok(OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(Self::path()?)?)
}
fn path() -> Result<PathBuf, Box<dyn Error>> {
let xdg_cache = match env::var_os("XDG_CACHE_HOME") {
Some(s) => s
.into_string()
.map_err(|_| "Unable to resolve $XDG_CACHE_HOME")?,
None => format!(
"{}/.cache",
env::var_os("HOME")
.ok_or("Unable to resolve $HOME")?
.into_string()
.map_err(|_| "Unable to resolve $HOME")?
),
};
let cache_dir = PathBuf::from(xdg_cache).join("wldash");
create_dir_all(&cache_dir)?;
Ok(cache_dir.join("data.yaml"))
}
}
+4 -2
View File
@@ -1,11 +1,12 @@
extern crate ini; extern crate ini;
use ini::{Ini, ParseOption}; use ini::{Ini, ParseOption};
use itertools::Itertools;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::fs;
use std::io::Error as io_error; use std::io::Error as io_error;
use std::io::ErrorKind; use std::io::ErrorKind;
use walkdir::WalkDir;
#[derive(Clone, Debug, Eq, Hash)] #[derive(Clone, Debug, Eq, Hash)]
pub struct Desktop { pub struct Desktop {
@@ -56,7 +57,7 @@ impl Desktop {
fn parse_dir(d: &str) -> Result<Vec<Desktop>, Box<dyn Error>> { fn parse_dir(d: &str) -> Result<Vec<Desktop>, Box<dyn Error>> {
let mut files: Vec<Desktop> = Vec::with_capacity(16); let mut files: Vec<Desktop> = Vec::with_capacity(16);
for entry in fs::read_dir(d)? { for entry in WalkDir::new(d) {
let entry = entry?; let entry = entry?;
let path = entry.path(); let path = entry.path();
@@ -107,5 +108,6 @@ pub fn load_desktop_files() -> Vec<Desktop> {
.filter(|d| { .filter(|d| {
!d.hidden && !d.no_display && (d.entry_type == "Application" || d.entry_type == "Link") !d.hidden && !d.no_display && (d.entry_type == "Application" || d.entry_type == "Link")
}) })
.unique_by(|x| x.name.clone())
.collect() .collect()
} }
+2 -3
View File
@@ -209,9 +209,9 @@ fn create_shm_fd() -> io::Result<RawFd> {
Err(nix::Error::Sys(errno)) => match unistd::close(fd) { Err(nix::Error::Sys(errno)) => match unistd::close(fd) {
Ok(_) => return Err(io::Error::from(errno)), Ok(_) => return Err(io::Error::from(errno)),
Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)), Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
Err(err) => panic!(err), Err(err) => panic!("{}", err),
}, },
Err(err) => panic!(err), Err(err) => panic!("{}", err),
}, },
Err(nix::Error::Sys(Errno::EEXIST)) => { Err(nix::Error::Sys(Errno::EEXIST)) => {
// If a file with that handle exists then change the handle // If a file with that handle exists then change the handle
@@ -228,7 +228,6 @@ fn create_shm_fd() -> io::Result<RawFd> {
} }
} }
pub struct DoubleMemPool { pub struct DoubleMemPool {
pool1: MemPool, pool1: MemPool,
pool2: MemPool, pool2: MemPool,
+11 -9
View File
@@ -8,16 +8,16 @@ struct CachedGlyph {
dimensions: (u32, u32), dimensions: (u32, u32),
origin: (i32, i32), origin: (i32, i32),
render: Vec<f32>, render: Vec<f32>,
advance: i32,
} }
impl CachedGlyph { impl CachedGlyph {
fn new(font: FontRef, size: f32, ch: char) -> CachedGlyph { fn new(font: FontRef, size: f32, ch: char) -> CachedGlyph {
let scale = Scale::uniform(size); let scale = Scale::uniform(size);
let v_metrics = font.v_metrics(scale); let v_metrics = font.v_metrics(scale);
let glyph = font let glyph = font.glyph(ch).scaled(scale);
.glyph(ch) let advance = glyph.h_metrics().advance_width as i32;
.scaled(scale) let glyph = glyph.positioned(point(0.0, v_metrics.ascent));
.positioned(point(0.0, v_metrics.ascent));
if let Some(bounding_box) = glyph.pixel_bounding_box() { if let Some(bounding_box) = glyph.pixel_bounding_box() {
let origin = (bounding_box.min.x, bounding_box.min.y); let origin = (bounding_box.min.x, bounding_box.min.y);
@@ -35,12 +35,14 @@ impl CachedGlyph {
origin, origin,
dimensions, dimensions,
render, render,
advance,
} }
} else { } else {
CachedGlyph { CachedGlyph {
origin: (0, 0), origin: (0, 0),
dimensions: ((size / 4.0) as u32, 0), dimensions: (0, 0),
render: Vec::new(), render: Vec::new(),
advance: (size / 4.0) as i32,
} }
} }
} }
@@ -118,7 +120,7 @@ impl<'a> Font<'a> {
} }
for glyph in glyphs { for glyph in glyphs {
glyph.draw(buf, (x_off, -off), bg, c); glyph.draw(buf, (x_off, -off), bg, c);
x_off += glyph.dimensions.0 as i32 + glyph.origin.0; x_off += glyph.advance;
} }
Ok((x_off as u32, self.size as u32)) Ok((x_off as u32, self.size as u32))
@@ -157,7 +159,7 @@ impl<'a> Font<'a> {
self.draw_cursor(buf, c, x_off as u32, height)?; self.draw_cursor(buf, c, x_off as u32, height)?;
} }
glyph.draw(buf, (x_off, -off), bg, c); glyph.draw(buf, (x_off, -off), bg, c);
x_off += glyph.dimensions.0 as i32 + glyph.origin.0; x_off += glyph.advance;
} }
if cursor == glyphs.len() { if cursor == glyphs.len() {
self.draw_cursor(buf, c, x_off as u32, height)?; self.draw_cursor(buf, c, x_off as u32, height)?;
@@ -193,7 +195,7 @@ impl<'a> Font<'a> {
)) ))
} }
}; };
let width = glyph.dimensions.0 as i32 + glyph.origin.0; let width = glyph.advance;
if width > max { if width > max {
max = width max = width
} }
@@ -285,7 +287,7 @@ impl<'a> Font<'a> {
} }
for (idx, glyph) in glyphs.into_iter().enumerate() { for (idx, glyph) in glyphs.into_iter().enumerate() {
glyph.draw(buf, (x_off, -off), bg, &color[idx]); glyph.draw(buf, (x_off, -off), bg, &color[idx]);
x_off += glyph.dimensions.0 as i32 + glyph.origin.0; x_off += glyph.advance;
} }
Ok((x_off as u32, self.size as u32)) Ok((x_off as u32, self.size as u32))
+14 -14
View File
@@ -1,17 +1,17 @@
#![allow(missing_docs, non_upper_case_globals, unused_parens, clippy::all)] #![allow(missing_docs, non_upper_case_globals, unused_parens, clippy::all)]
pub const XKB_KEY_BackSpace :u32 = 0xff08; /* Back space, back char */ pub const XKB_KEY_BackSpace: u32 = 0xff08; /* Back space, back char */
pub const XKB_KEY_Tab :u32 = 0xff09; pub const XKB_KEY_Tab: u32 = 0xff09;
pub const XKB_KEY_Return :u32 = 0xff0d; /* Return, enter */ pub const XKB_KEY_Return: u32 = 0xff0d; /* Return, enter */
pub const XKB_KEY_Escape :u32 = 0xff1b; pub const XKB_KEY_Escape: u32 = 0xff1b;
pub const XKB_KEY_Delete :u32 = 0xffff; /* Delete, rubout */ pub const XKB_KEY_Delete: u32 = 0xffff; /* Delete, rubout */
pub const XKB_KEY_Home :u32 = 0xff50; pub const XKB_KEY_Home: u32 = 0xff50;
pub const XKB_KEY_Left :u32 = 0xff51; /* Move left, left arrow */ pub const XKB_KEY_Left: u32 = 0xff51; /* Move left, left arrow */
pub const XKB_KEY_Right :u32 = 0xff53; /* Move right, right arrow */ pub const XKB_KEY_Right: u32 = 0xff53; /* Move right, right arrow */
pub const XKB_KEY_End :u32 = 0xff57; /* EOL */ pub const XKB_KEY_End: u32 = 0xff57; /* EOL */
pub const XKB_KEY_ISO_Left_Tab :u32 = 0xfe20; pub const XKB_KEY_ISO_Left_Tab: u32 = 0xfe20;
pub const XKB_KEY_e :u32 = 0x0065; /* U+0065 LATIN SMALL LETTER E */ pub const XKB_KEY_e: u32 = 0x0065; /* U+0065 LATIN SMALL LETTER E */
pub const XKB_KEY_a :u32 = 0x0061; /* U+0061 LATIN SMALL LETTER A */ pub const XKB_KEY_a: u32 = 0x0061; /* U+0061 LATIN SMALL LETTER A */
pub const XKB_KEY_c :u32 = 0x0063; /* U+0063 LATIN SMALL LETTER C */ pub const XKB_KEY_c: u32 = 0x0063; /* U+0063 LATIN SMALL LETTER C */
pub const XKB_KEY_u :u32 = 0x0075; /* U+0075 LATIN SMALL LETTER U */ pub const XKB_KEY_u: u32 = 0x0075; /* U+0075 LATIN SMALL LETTER U */
+14 -8
View File
@@ -23,8 +23,8 @@ use wayland_client::{
}; };
mod ffi; mod ffi;
mod state;
pub mod keysyms; pub mod keysyms;
mod state;
use self::state::KbState; use self::state::KbState;
pub use self::state::{ModifiersState, RMLVO}; pub use self::state::{ModifiersState, RMLVO};
@@ -118,10 +118,7 @@ where
let callback = Rc::new(RefCell::new(callback)); let callback = Rc::new(RefCell::new(callback));
// prepare the handler // prepare the handler
let mut kbd_handler = KbdHandler { let mut kbd_handler = KbdHandler { callback, state };
callback,
state,
};
keyboard.quick_assign(move |keyboard, event, data| { keyboard.quick_assign(move |keyboard, event, data| {
kbd_handler.event(keyboard.detach(), event, data) kbd_handler.event(keyboard.detach(), event, data)
@@ -331,8 +328,17 @@ impl KbdHandler {
} }
} }
fn repeat_info(&mut self, object: wl_keyboard::WlKeyboard, rate: i32, delay: i32, dispatch_data: wayland_client::DispatchData) { fn repeat_info(
(&mut *self.callback.borrow_mut())(Event::RepeatInfo { rate, delay }, object, dispatch_data); &mut self,
object: wl_keyboard::WlKeyboard,
rate: i32,
delay: i32,
dispatch_data: wayland_client::DispatchData,
) {
(&mut *self.callback.borrow_mut())(
Event::RepeatInfo { rate, delay },
object,
dispatch_data,
);
} }
} }
-1
View File
@@ -398,4 +398,3 @@ impl Drop for KbState {
} }
} }
} }
+7 -3
View File
@@ -12,15 +12,16 @@ use timerfd::{SetTimeFlags, TimerFd, TimerState};
mod app; mod app;
mod buffer; mod buffer;
mod keyboard;
mod cmd; mod cmd;
mod color; mod color;
mod config; mod config;
mod configfmt; mod configfmt;
mod data;
mod desktop; mod desktop;
mod doublemempool; mod doublemempool;
mod draw; mod draw;
mod fonts; mod fonts;
mod keyboard;
mod widget; mod widget;
mod widgets; mod widgets;
@@ -206,7 +207,10 @@ fn main() {
}); });
let mut timer = TimerFd::new().unwrap(); let mut timer = TimerFd::new().unwrap();
let ev_fd = PollFd::new(app.event_queue().display().get_connection_fd(), PollFlags::POLLIN); let ev_fd = PollFd::new(
app.event_queue().display().get_connection_fd(),
PollFlags::POLLIN,
);
let rx_fd = PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN); let rx_fd = PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN);
let tm_fd = PollFd::new(timer.as_raw_fd(), PollFlags::POLLIN); let tm_fd = PollFd::new(timer.as_raw_fd(), PollFlags::POLLIN);
let ipc_fd = PollFd::new(listener.as_raw_fd(), PollFlags::POLLIN); let ipc_fd = PollFd::new(listener.as_raw_fd(), PollFlags::POLLIN);
@@ -323,7 +327,7 @@ fn main() {
} }
app.event_queue() app.event_queue()
.dispatch_pending(&mut (), |_, _, _|{}) .dispatch_pending(&mut (), |_, _, _| {})
.expect("Failed to dispatch all messages."); .expect("Failed to dispatch all messages.");
} }
+1 -1
View File
@@ -1,8 +1,8 @@
use crate::buffer::Buffer; use crate::buffer::Buffer;
use crate::color::Color; use crate::color::Color;
pub use crate::keyboard::{KeyState, ModifiersState};
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use nix::poll::PollFd; use nix::poll::PollFd;
pub use crate::keyboard::{KeyState, ModifiersState};
pub struct DrawContext<'a> { pub struct DrawContext<'a> {
pub buf: &'a mut Buffer<'a>, pub buf: &'a mut Buffer<'a>,
+3 -3
View File
@@ -99,7 +99,7 @@ impl BarWidgetImpl for Alsa {
fn value(&self) -> f32 { fn value(&self) -> f32 {
match self.get_master_volume() { match self.get_master_volume() {
Ok(v) => v, Ok(v) => v,
Err(e) => panic!(e), Err(e) => panic!("{}", e),
} }
} }
fn color(&self) -> Color { fn color(&self) -> Color {
@@ -107,12 +107,12 @@ impl BarWidgetImpl for Alsa {
} }
fn inc(&mut self, diff: f32) { fn inc(&mut self, diff: f32) {
if let Err(e) = self.inc_master_volume(diff) { if let Err(e) = self.inc_master_volume(diff) {
panic!(e) panic!("{}", e)
} }
} }
fn set(&mut self, abs: f32) { fn set(&mut self, abs: f32) {
if let Err(e) = self.set_master_volume(abs) { if let Err(e) = self.set_master_volume(abs) {
panic!(e) panic!("{}", e)
} }
} }
fn toggle(&mut self) {} fn toggle(&mut self) {}
+1 -1
View File
@@ -21,7 +21,7 @@ impl<'a> Clock<'a> {
clock_cache.add_str_to_cache("0123456789:"); clock_cache.add_str_to_cache("0123456789:");
let digit = clock_cache.auto_widest("123456789")?; let digit = clock_cache.auto_widest("123456789")?;
let colon = (clock_cache.auto_widest(":")? as f32 * 1.25) as u32; let colon = clock_cache.auto_widest(":")?;
Ok(Box::new(Clock { Ok(Box::new(Clock {
cur_time: time, cur_time: time,
+29 -12
View File
@@ -14,8 +14,10 @@ use std::collections::HashMap;
use std::process::Command; use std::process::Command;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use fuzzy_matcher::skim::{fuzzy_indices, fuzzy_match}; use crate::data::Data;
use crate::keyboard::keysyms; use crate::keyboard::keysyms;
use fuzzy_matcher::skim::SkimMatcherV2;
use fuzzy_matcher::FuzzyMatcher;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
pub struct Launcher<'a> { pub struct Launcher<'a> {
@@ -33,6 +35,7 @@ pub struct Launcher<'a> {
length: u32, length: u32,
dirty: bool, dirty: bool,
tx: Sender<Cmd>, tx: Sender<Cmd>,
counter: Data,
} }
impl<'a> Launcher<'a> { impl<'a> Launcher<'a> {
@@ -60,6 +63,7 @@ impl<'a> Launcher<'a> {
length, length,
dirty: true, dirty: true,
tx: listener, tx: listener,
counter: Data::load().unwrap_or_default(),
}) })
} }
@@ -90,15 +94,17 @@ impl<'a> Launcher<'a> {
}; };
let mut width_remaining: i32 = (width - x_off) as i32; let mut width_remaining: i32 = (width - x_off) as i32;
let fuzzy_matcher = SkimMatcherV2::default();
for (idx, m) in self.matches.iter().enumerate() { for (idx, m) in self.matches.iter().enumerate() {
let mut b = match buf.offset((x_off, 0)) { let mut b = match buf.offset((x_off, 0)) {
Ok(b) => b, Ok(b) => b,
Err(_) => break, Err(_) => break,
}; };
let size = if idx == self.offset && !self.input.is_empty() { let size = if idx == self.offset {
let (_, indices) = let (_, indices) = fuzzy_matcher
fuzzy_indices(&m.name.to_lowercase(), &self.input.to_lowercase()) .fuzzy_indices(&m.name.to_lowercase(), &self.input.to_lowercase())
.unwrap_or((0, vec![])); .unwrap_or((0, vec![]));
let mut colors = Vec::with_capacity(m.name.len()); let mut colors = Vec::with_capacity(m.name.len());
for pos in 0..m.name.len() { for pos in 0..m.name.len() {
if indices.contains(&pos) { if indices.contains(&pos) {
@@ -213,17 +219,20 @@ fn wlcopy(s: &str) -> Result<(), String> {
struct Matcher { struct Matcher {
matches: HashMap<Desktop, i64>, matches: HashMap<Desktop, i64>,
counter: Data,
} }
impl Matcher { impl Matcher {
fn new() -> Self { fn new(counter: Data) -> Self {
Self { Self {
matches: HashMap::new(), matches: HashMap::new(),
counter,
} }
} }
fn try_match(&mut self, dtop: Desktop, val: &str, input: &str, prio: f32) { fn try_match(&mut self, dtop: Desktop, val: &str, input: &str, prio: f32) {
if let Some(ma) = fuzzy_match(val, input) { let fuzzy_matcher = SkimMatcherV2::default();
if let Some(ma) = fuzzy_matcher.fuzzy_match(val, input) {
let ma = ((ma as f32) * prio) as i64; let ma = ((ma as f32) * prio) as i64;
if let Some(ma_old) = self.matches.get(&dtop) { if let Some(ma_old) = self.matches.get(&dtop) {
// Skip over new matches for the same program that are worse // Skip over new matches for the same program that are worse
@@ -245,9 +254,12 @@ impl Matcher {
.collect::<Vec<(i64, Desktop)>>(); .collect::<Vec<(i64, Desktop)>>();
m.sort_by(|(ma1, d1), (ma2, d2)| { m.sort_by(|(ma1, d1), (ma2, d2)| {
if ma1 > ma2 { let count1 = self.counter.entries.get(&d1.name).unwrap_or(&0);
let count2 = self.counter.entries.get(&d2.name).unwrap_or(&0);
if ma1 + count1 > ma2 + count2 {
Ordering::Less Ordering::Less
} else if ma1 < ma2 { } else if ma1 + count1 < ma2 + count2 {
Ordering::Greater Ordering::Greater
} else if d1.name.len() < d2.name.len() { } else if d1.name.len() < d2.name.len() {
Ordering::Less Ordering::Less
@@ -303,7 +315,7 @@ impl<'a> Widget for Launcher<'a> {
} }
Some('!') => (), Some('!') => (),
_ => { _ => {
let mut matcher = Matcher::new(); let mut matcher = Matcher::new(self.counter.clone());
for desktop in self.options.iter() { for desktop in self.options.iter() {
matcher.try_match( matcher.try_match(
@@ -417,13 +429,18 @@ impl<'a> Widget for Launcher<'a> {
&self.app_opener &self.app_opener
}; };
let mut lexed = shlex::split(&exec).unwrap();
let lexed = if !prefix.is_empty() { let lexed = if !prefix.is_empty() {
let mut prefix = shlex::split(prefix).unwrap(); let mut prefix = shlex::split(prefix).unwrap();
prefix.push(exec); prefix.append(&mut lexed);
prefix prefix
} else { } else {
shlex::split(&exec).unwrap() lexed
}; };
*self.counter.entries.entry(d.name.clone()).or_insert(0) += 1;
self.counter.save().expect("Unable to save data");
if !lexed.is_empty() { if !lexed.is_empty() {
let _ = let _ =
Command::new(lexed[0].clone()).args(&lexed[1..]).spawn(); Command::new(lexed[0].clone()).args(&lexed[1..]).spawn();