Majorly rework

This commit is contained in:
Alexander Rosenberg 2024-04-28 06:36:50 -07:00
parent 17735ba956
commit 2f628d6a2c
Signed by: Zander671
GPG Key ID: 5FD0394ADBD72730
3 changed files with 168 additions and 235 deletions

8
Cargo.lock generated
View File

@ -109,18 +109,18 @@ checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.198" version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.198" version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@ -1,6 +1,6 @@
# A [river-status](https://codeberg.org/river/river) client # A [river-status](https://codeberg.org/river/river) client
## Original credit to this program goes to [snakedye / Bryan][1] at [https://gitlab.com/snakedye/ristate][2] ## Original credit for this program goes to [snakedye / Bryan][1] at [https://gitlab.com/snakedye/ristate][2]
[1]: https://gitlab.com/snakedye [1]: https://gitlab.com/snakedye
[2]: https://gitlab.com/snakedye/ristate [2]: https://gitlab.com/snakedye/ristate

View File

@ -11,70 +11,18 @@ use wayland_client::protocol::wl_registry::WlRegistry;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use wayland_client::protocol::{wl_output, wl_output::WlOutput, wl_seat, use wayland_client::protocol::{wl_output, wl_output::WlOutput, wl_seat,
wl_seat::WlSeat}; wl_seat::WlSeat};
use wayland_client::{Attached, DispatchData, Display, GlobalEvent, GlobalImplementor, GlobalManager, Main}; use wayland_client::{Attached, DispatchData, Display, GlobalEvent, GlobalManager, Main};
#[derive(Debug)] #[derive(Debug, Default)]
struct Flags { struct Flags {
tags: bool, once: bool,
titles: bool,
urgency: bool,
viewtags: bool,
layout: bool,
mode: bool,
focused: bool,
gtk_nums: bool,
seat: Option<String>, seat: Option<String>,
} }
impl Flags {
fn default() -> Flags {
Flags {
tags: false,
titles: false,
urgency: false,
viewtags: false,
layout: false,
mode: false,
focused: false,
gtk_nums: false,
seat: None,
}
}
}
#[derive(Clone)] #[derive(Clone, Default)]
struct Tags(u32); struct Tags(u32);
struct Env {
flags: Flags,
// I don't know very much about wayland, and it shows
output_id_map: HashMap<u32, u32>,
output_names: BTreeMap<u32, String>,
focused: Option<u32>,
layout: Option<String>,
titles: Option<HashMap<u32, String>>,
mode: Option<String>,
tags: Option<HashMap<u32, Tags>>,
urgency: Option<HashMap<u32, Tags>>,
viewtags: Option<HashMap<u32, Vec<u32>>>,
status_manager: Option<Main<ZriverStatusManagerV1>>,
}
impl Env {
fn translate_output_map<V: Clone>(
&self, input: &HashMap<u32, V>
) -> HashMap<String, V> {
let mut output = HashMap::<String, V>::new();
output.reserve(input.len());
for (id, val) in input {
if let Some(name) = self.output_names.get(&id) {
output.insert(name.clone(), val.clone());
}
}
output
}
}
impl Serialize for Tags { impl Serialize for Tags {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -90,119 +38,135 @@ impl Serialize for Tags {
} }
} }
#[derive(Clone, serde::Serialize, Default)]
struct OutputGeometry {
x: i32,
y: i32,
width: i32,
height: i32,
scale: i32,
refresh: f32,
}
#[derive(Clone, Default, serde::Serialize)]
struct Output {
#[serde(skip_serializing)]
name: String,
title: String,
geometry: OutputGeometry,
focused_tags: Tags,
urgent_tags: Tags,
populated_tags: Vec<u32>,
// for serde serialization
focused: bool,
gdk_id: u32,
}
#[derive(Default)]
struct ReadStatus {
wl_output: bool,
wl_seat: bool,
river_seat: bool,
river_output: bool,
}
struct Env {
status_manager: Option<Main<ZriverStatusManagerV1>>,
flags: Flags,
read_status: ReadStatus,
// I don't know very much about wayland, and it shows
output_id_map: HashMap<u32, u32>,
layout: Option<String>,
mode: Option<String>,
focused_output: Option<u32>,
outputs: BTreeMap<u32, Output>,
}
impl Env {
fn new() -> Env {
Env {
status_manager: None,
flags: configuration(),
read_status: Default::default(),
output_id_map: Default::default(),
layout: None,
mode: None,
focused_output: None,
outputs: Default::default(),
}
}
fn fmt(&self) {
println!("{}", serde_json::to_string(self).unwrap());
}
fn get_output(&mut self, id: u32) -> &mut Output {
if !self.outputs.contains_key(&id) {
self.outputs.insert(id, Default::default());
}
self.outputs.get_mut(&id).unwrap()
}
fn is_empty(&self) -> bool {
self.layout.is_none() && self.mode.is_none() && self.outputs.len() == 0
}
fn is_first_read_done(&self) -> bool{
self.read_status.wl_output && self.read_status.wl_seat &&
self.read_status.river_seat && self.read_status.river_output
}
}
impl Serialize for Env { impl Serialize for Env {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer { where S: Serializer {
let mut state = serializer.serialize_struct("Env", 8)?; let mut state = serializer.serialize_struct("Env", 9)?;
if let Some(layout) = self.layout.as_ref() { if let Some(layout) = self.layout.as_ref() {
state.serialize_field("layout", layout)?; state.serialize_field("layout", layout)?;
} else { } else {
state.skip_field("layout")?; state.skip_field("layout")?;
} }
if let Some(titles) = self.titles.as_ref() {
state.serialize_field("titles", &self.translate_output_map(titles))?;
} else {
state.skip_field("titles")?;
}
if let Some(mode) = self.mode.as_ref() { if let Some(mode) = self.mode.as_ref() {
state.serialize_field("mode", mode)?; state.serialize_field("mode", mode)?;
} else { } else {
state.skip_field("mode")?; state.skip_field("mode")?;
} }
// kind of inelegant let mut outputs: HashMap<String, Output> = HashMap::new();
if self.flags.focused && self.focused.is_some() && let mut gdk_id = 0;
self.output_names.contains_key(&self.focused.unwrap()) { for (output_id, output) in &self.outputs {
state.serialize_field( let mut new = output.clone();
"focused", &self.output_names[&self.focused.unwrap()])?; new.focused = if let Some(focused_id) = self.focused_output {
*output_id == focused_id
} else { } else {
state.skip_field("focused")?; false
} };
if let Some(tags) = self.tags.as_ref() { new.gdk_id = gdk_id;
state.serialize_field("tags", &self.translate_output_map(tags))?; outputs.insert(new.name.clone(), new);
} else { gdk_id += 1;
state.skip_field("tags")?;
}
if let Some(urgency) = self.urgency.as_ref() {
state.serialize_field("urgency", &self.translate_output_map(urgency))?;
} else {
state.skip_field("urgency")?;
}
if let Some(viewtags) = self.viewtags.as_ref() {
state.serialize_field("viewtags", &self.translate_output_map(viewtags))?;
} else {
state.skip_field("viewtags")?;
}
if self.flags.gtk_nums {
let mut name_id_map = HashMap::<&str, u32>::new();
name_id_map.reserve(self.output_names.len());
let mut id = 0;
for (key, value) in &self.output_names {
name_id_map.insert(value, id);
id += 1;
}
state.serialize_field("gtk_ids", &name_id_map)?;
} else {
state.skip_field("gtk_ids")?;
} }
state.serialize_field("outputs", &outputs)?;
state.end() state.end()
} }
} }
impl Env {
fn new() -> Env {
let flags = configuration();
Env {
layout: None,
mode: None,
focused: None,
titles: flags.titles.then(Default::default),
tags: flags.tags.then(Default::default),
urgency: flags.urgency.then(Default::default),
viewtags: flags.viewtags.then(Default::default),
status_manager: None,
flags,
output_id_map: Default::default(),
output_names: Default::default(),
}
}
fn fmt(&self) {
if self.titles.is_some()
|| self.tags.is_some()
|| self.mode.is_some()
|| self.urgency.is_some()
|| self.viewtags.is_some()
|| self.layout.is_some()
|| self.focused.is_some()
|| self.flags.gtk_nums
{
println!("{}", serde_json::to_string(self).unwrap());
}
}
}
fn handle_river_seat_status( fn handle_river_seat_status(
_status: Main<ZriverSeatStatusV1>, event: zriver_seat_status_v1::Event, _status: Main<ZriverSeatStatusV1>, event: zriver_seat_status_v1::Event,
mut env: DispatchData mut env: DispatchData
) { ) {
if let Some(env) = env.get::<Env>() { if let Some(env) = env.get::<Env>() {
env.read_status.river_seat = true;
match event { match event {
zriver_seat_status_v1::Event::FocusedOutput { output } => { zriver_seat_status_v1::Event::FocusedOutput { output } => {
if env.flags.focused || env.flags.titles { env.focused_output = Some(output.as_ref().id());
env.focused = Some(output.as_ref().id());
}
}, },
zriver_seat_status_v1::Event::FocusedView { title } => { zriver_seat_status_v1::Event::FocusedView { title } => {
if env.flags.titles && env.focused.is_some() { if let Some(focused_output) = env.focused_output {
if let Some(titles) = &mut env.titles { env.get_output(focused_output).title = title;
titles.insert(env.focused.unwrap(), title);
}
} }
}, },
zriver_seat_status_v1::Event::Mode { name } => { zriver_seat_status_v1::Event::Mode { name } => {
if env.flags.mode { env.mode = Some(name);
env.mode = Some(name);
}
}, },
_ => {}, _ => {},
} }
@ -212,22 +176,21 @@ fn handle_river_seat_status(
fn handle_seat_event( fn handle_seat_event(
seat: Main<WlSeat>, event: wl_seat::Event, mut env: DispatchData seat: Main<WlSeat>, event: wl_seat::Event, mut env: DispatchData
) { ) {
match event { if let Some(env) = env.get::<Env>() {
wl_seat::Event::Name { name } => { env.read_status.wl_seat = true;
if let Some(env) = env.get::<Env>() { match event {
if (env.flags.titles || env.flags.mode || env.flags.focused) wl_seat::Event::Name { name } => {
&& (env.flags.seat.is_none() if env.flags.seat.is_none()
|| name.eq(env.flags.seat.as_ref().unwrap())) || name == *env.flags.seat.as_ref().unwrap() {
{ if let Some(status_manager) = &env.status_manager {
if let Some(status_manager) = &env.status_manager { let seat_status =
let seat_status = status_manager.get_river_seat_status(&seat);
status_manager.get_river_seat_status(&seat); seat_status.quick_assign(handle_river_seat_status);
seat_status.quick_assign(handle_river_seat_status); }
} }
} },
} _ => {},
} }
_ => {}
} }
} }
@ -236,50 +199,33 @@ fn handle_river_output_status(
mut env: DispatchData mut env: DispatchData
) { ) {
if let Some(env) = env.get::<Env>() { if let Some(env) = env.get::<Env>() {
env.read_status.river_output = true;
let output_id = output.as_ref().id(); let output_id = output.as_ref().id();
match event { match event {
zriver_output_status_v1::Event::FocusedTags { zriver_output_status_v1::Event::FocusedTags {
tags: focused_tags, tags: focused_tags,
} => { } => env.get_output(output_id).focused_tags = Tags(focused_tags),
if let Some(tags) = &mut env.tags {
tags.insert(output_id, Tags(focused_tags));
}
}
zriver_output_status_v1::Event::ViewTags { zriver_output_status_v1::Event::ViewTags {
tags, tags,
} => { } => env.get_output(output_id).populated_tags = tags[0..]
if let Some(viewtags) = &mut env.viewtags { .chunks(4)
let tags: Vec<u32> = tags[0..] .map(|s| {
.chunks(4) let buf = [s[0], s[1], s[2], s[3]];
.map(|s| { let tagmask = u32::from_le_bytes(buf);
let buf = [s[0], s[1], s[2], s[3]]; for i in 0..32 {
let tagmask = u32::from_le_bytes(buf); if 1 << i == tagmask {
for i in 0..32 { return 1 + i;
if 1 << i == tagmask { }
return 1 + i; }
} 0
} }).collect(),
0
})
.collect();
viewtags.insert(output_id, tags);
}
}
zriver_output_status_v1::Event::UrgentTags { zriver_output_status_v1::Event::UrgentTags {
tags, tags,
} => { } => env.get_output(output_id).urgent_tags = Tags(tags),
if let Some(urgency) = &mut env.urgency {
urgency.insert(output_id, Tags(tags));
}
}
zriver_output_status_v1::Event::LayoutName { zriver_output_status_v1::Event::LayoutName {
name, name,
} => { } => env.layout = Some(name),
if env.flags.layout { _ => {},
env.layout = Some(name);
}
}
_ => {}
} }
} }
@ -288,11 +234,13 @@ fn handle_river_output_status(
fn handle_output_event( fn handle_output_event(
output: Main<WlOutput>, event: wl_output::Event, mut env: DispatchData output: Main<WlOutput>, event: wl_output::Event, mut env: DispatchData
) { ) {
let output_id = output.as_ref().id();
if let Some(env) = env.get::<Env>() { if let Some(env) = env.get::<Env>() {
env.read_status.wl_output = true;
match event { match event {
wl_output::Event::Geometry { wl_output::Event::Geometry {
x: _, x,
y: _, y,
physical_width: _, physical_width: _,
physical_height: _, physical_height: _,
subpixel: _, subpixel: _,
@ -307,13 +255,23 @@ fn handle_output_event(
handle_river_output_status(&output, event, env); handle_river_output_status(&output, event, env);
}); });
} }
} let entry = env.get_output(output_id);
entry.geometry.x = x;
entry.geometry.y = y;
},
wl_output::Event::Mode { flags: _, width, height, refresh } => {
let entry = env.get_output(output_id);
entry.geometry.width = width;
entry.geometry.height = height;
entry.geometry.refresh = refresh as f32 / 1000.0f32;
},
wl_output::Event::Name { wl_output::Event::Name {
name, name,
} => { } => env.get_output(output_id).name = name,
env.output_names.insert(output.as_ref().id(), name); wl_output::Event::Scale {
} factor
_ => {} } => env.get_output(output_id).geometry.scale = factor,
_ => {},
} }
} }
} }
@ -347,19 +305,7 @@ fn global_manager_callback(
GlobalEvent::Removed { id, interface: _ } => { GlobalEvent::Removed { id, interface: _ } => {
if let Some(env) = env.get::<Env>() { if let Some(env) = env.get::<Env>() {
if let Some(oid) = env.output_id_map.remove(&id) { if let Some(oid) = env.output_id_map.remove(&id) {
env.output_names.remove(&oid); env.outputs.remove(&oid);
if let Some(titles) = &mut env.titles {
titles.remove(&oid);
}
if let Some(tags) = &mut env.tags {
tags.remove(&oid);
}
if let Some(urgency) = &mut env.urgency {
urgency.remove(&oid);
}
if let Some(viewtags) = &mut env.viewtags {
viewtags.remove(&oid);
}
} }
} }
} }
@ -374,25 +320,12 @@ fn configuration() -> Flags {
match args.next() { match args.next() {
Some(flag) => match flag.as_str() { Some(flag) => match flag.as_str() {
"--seat" | "-s" => default.seat = args.next(), "--seat" | "-s" => default.seat = args.next(),
"--urgency" | "-u" => default.urgency = true, "--once" | "-o" => default.once = true,
"--title" | "-w" => default.titles = true,
"--mode" | "-m" => default.mode = true,
"--focused" | "-f" => default.focused = true,
"--tags" | "-t" => default.tags = true,
"--layout" | "-l" => default.layout = true,
"--view-tags" | "-vt" => default.viewtags = true,
"--gtk-ids" | "-g" => default.gtk_nums = true,
"--help" | "-h" => { "--help" | "-h" => {
print!("Usage: ristate [option]\n\n"); println!("Usage: ristate [option]\n");
print!(" --tag | -t the focused tag of each output\n"); println!(" --help | -h print this message and exit");
print!(" --titles | -w the titles of focused views\n"); println!(" --once | -o print the current status and exit");
print!(" --mode | -m the current input mode\n"); println!(" --seat | -s <string> select the seat");
print!(" --layout | -l display the name of the layout\n");
print!(" --focused | -f the name of the focused output\n");
print!(" --urgency | -u tags with urgent views on them\n");
print!(" --view-tags | -vt the tags with views on them\n");
print!(" --gtk-ids | -g attempt to map output names to their gtk id\n");
print!(" --seat | -s <string> select the seat\n");
std::process::exit(0); std::process::exit(0);
} }
_ => {} _ => {}
@ -400,11 +333,6 @@ fn configuration() -> Flags {
None => break, None => break,
} }
} }
if !default.urgency && !default.titles && !default.mode && !default.focused
&& !default.tags && !default.layout && !default.viewtags && !default.gtk_nums {
println!("error: You must specify at least one thing to listen for!");
std::process::exit(1);
}
default default
} }
@ -431,6 +359,11 @@ fn main() {
); );
}) })
.unwrap(); .unwrap();
env.fmt(); if !env.is_empty() && env.is_first_read_done() {
env.fmt();
if env.flags.once {
std::process::exit(0);
}
}
} }
} }