From 1851c56e407cac72ca104cc5e75692cd9c648986 Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Mon, 8 Aug 2022 23:12:23 +0300 Subject: rewrite using latest walayd libs & implement HiDPI --- src/bar.rs | 412 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 src/bar.rs (limited to 'src/bar.rs') diff --git a/src/bar.rs b/src/bar.rs new file mode 100644 index 0000000..f3dc95c --- /dev/null +++ b/src/bar.rs @@ -0,0 +1,412 @@ +use std::collections::BinaryHeap; + +use pangocairo::cairo; +use smithay_client_toolkit::{ + reexports::client::protocol::{wl_seat, wl_shm}, + shell::layer::LayerSurface, +}; + +use crate::{ + button_manager::ButtonManager, + config::Config, + i3bar_protocol::{self, Block, MinWidth}, + ord_adaptor::DefaultLess, + pointer_btn::PointerBtn, + river_protocols::{control::RiverControlState, status::RiverOutputStatus}, + shared_state::SharedState, + state::ComputedBlock, + tags::{compute_tag_label, TagState, TagsInfo}, + text::{self, ComputedText, RenderOptions}, +}; + +pub struct Bar { + pub first_configure: bool, + pub width: u32, + pub height: u32, + pub scale: i32, + pub layer: LayerSurface, + pub blocks_btns: ButtonManager<(Option, Option)>, + pub river_output_status: Option, + pub river_control: RiverControlState, + pub tags_btns: ButtonManager, + pub tags_info: TagsInfo, + pub tags_computed: Vec, +} + +impl Bar { + pub fn configure(&mut self, ss: &mut SharedState, width: u32) { + if self.width != width { + self.width = width; + self.layer.set_exclusive_zone(self.height as i32); + } + + self.first_configure = false; + self.draw(ss); + } + + pub fn has_tags_provider(&self) -> bool { + // TODO: add more tags providers + self.river_output_status.is_some() + } + + pub fn click( + &mut self, + ss: &mut SharedState, + button: PointerBtn, + seat: &wl_seat::WlSeat, + x: f64, + _y: f64, + ) -> anyhow::Result<()> { + if let Some(tag) = self.tags_btns.click(x) { + if self.river_control.is_available() { + let cmd = match button { + PointerBtn::Left => "set-focused-tags", + PointerBtn::Right => "toggle-focused-tags", + _ => return Ok(()), + }; + self.river_control.run_command( + &ss.qh, + seat, + [cmd.into(), (1u32 << tag).to_string()], + )?; + } + } else if let Some((name, instance)) = self.blocks_btns.click(x) { + if let Some(cmd) = &mut ss.status_cmd { + cmd.send_click_event(&i3bar_protocol::Event { + name: name.as_deref(), + instance: instance.as_deref(), + button, + ..Default::default() + })?; + } + } + Ok(()) + } + + pub fn draw(&mut self, ss: &mut SharedState) { + if self.first_configure { + return; + } + + let stride = 4 * self.width as i32; + let width = self.width as i32; + let height = self.height as i32; + let width_f = width as f64; + let height_f = height as f64; + + let (buffer, canvas) = ss + .pool + .create_buffer( + width * self.scale, + height * self.scale, + stride * self.scale, + wl_shm::Format::Argb8888, + ) + .expect("create buffer"); + + let cairo_surf = unsafe { + cairo::ImageSurface::create_for_data_unsafe( + canvas.as_mut_ptr(), + cairo::Format::ARgb32, + width * self.scale, + height * self.scale, + stride * self.scale, + ) + .expect("cairo surface") + }; + + let cairo_ctx = cairo::Context::new(&cairo_surf).expect("cairo context"); + cairo_ctx.scale(self.scale as f64, self.scale as f64); + self.layer.wl_surface().set_buffer_scale(self.scale); + + // Background + ss.config.background.apply(&cairo_ctx); + cairo_ctx.paint().expect("cairo paint"); + + // Display tags + let mut offset_left = 0.0; + if self.has_tags_provider() { + if self.tags_computed.is_empty() { + let mut x_offset = 0.0; + // TODO make configurable + for (id, text) in ["1", "2", "3", "4", "5", "6", "7", "8", "9"] + .iter() + .enumerate() + { + let tag = + compute_tag_label(text.to_string(), ss.config.font.clone(), &cairo_ctx); + self.tags_btns.push(x_offset, tag.width, id); + x_offset += tag.width; + self.tags_computed.push(tag); + } + } + for (i, label) in self.tags_computed.iter().enumerate() { + let state = self.tags_info.get_state(i); + let (bg, fg) = match state { + TagState::Focused => (ss.config.tag_focused_bg, ss.config.tag_focused_fg), + TagState::Inactive => (ss.config.tag_bg, ss.config.tag_fg), + TagState::Urgent => (ss.config.tag_urgent_bg, ss.config.tag_urgent_fg), + }; + label.render( + &cairo_ctx, + RenderOptions { + x_offset: offset_left, + bar_height: height_f, + fg_color: fg, + bg_color: Some(bg), + r_left: if i == 0 || self.tags_info.get_state(i.saturating_sub(1)) != state + { + ss.config.tags_r + } else { + 0.0 + }, + r_right: if i == 8 || self.tags_info.get_state(i + 1) != state { + ss.config.tags_r + } else { + 0.0 + }, + overlap: 0.0, + }, + ); + offset_left += label.width; + } + } + + // Display the blocks + render_blocks( + &cairo_ctx, + &ss.config, + &ss.blocks, + &mut ss.blocks_cache, + &mut self.blocks_btns, + offset_left, + width_f, + height_f, + ); + + // Attach the buffer to the surface and mark the entire surface as damaged + buffer + .attach_to(self.layer.wl_surface()) + .expect("attaching buffer"); + self.layer + .wl_surface() + .damage_buffer(0, 0, width * self.scale, height * self.scale); + + // Finally, commit the surface + self.layer.wl_surface().commit(); + } +} + +#[allow(clippy::too_many_arguments)] +fn render_blocks( + context: &cairo::Context, + config: &Config, + blocks: &[Block], + blocks_cache: &mut Vec, + buttons: &mut ButtonManager<(Option, Option)>, + offset_left: f64, + full_width: f64, + full_height: f64, +) { + let comp_min_width = |block: &Block| { + let markup = block.markup.as_deref() == Some("pango"); + match &block.min_width { + Some(MinWidth::Pixels(p)) => Some(*p as f64), + Some(MinWidth::Text(t)) => Some(text::width_of(t, context, markup, &config.font.0)), + None => None, + } + }; + let comp_full = |block: &Block, min_width: Option| { + let markup = block.markup.as_deref() == Some("pango"); + text::Text { + text: block.full_text.clone(), + attr: text::Attributes { + font: config.font.clone(), + padding_left: 0.0, + padding_right: 0.0, + min_width, + align: block.align.unwrap_or_default(), + markup, + }, + } + .compute(context) + }; + let comp_short = |block: &Block, min_width: Option| { + let markup = block.markup.as_deref() == Some("pango"); + block.short_text.as_ref().map(|short_text| { + text::Text { + text: short_text.clone(), + attr: text::Attributes { + font: config.font.clone(), + padding_left: 0.0, + padding_right: 0.0, + min_width, + align: block.align.unwrap_or_default(), + markup, + }, + } + .compute(context) + }) + }; + + // update cashe + if blocks.len() != blocks_cache.len() { + blocks_cache.clear(); + for block in blocks { + let mw = comp_min_width(block); + blocks_cache.push(ComputedBlock { + block: block.clone(), + full: comp_full(block, mw), + short: comp_short(block, mw), + min_width: mw, + }); + } + } else { + for (block, computed) in blocks.iter().zip(blocks_cache.iter_mut()) { + if block.min_width != computed.block.min_width || block.markup != computed.block.markup + { + let mw = comp_min_width(block); + *computed = ComputedBlock { + block: block.clone(), + full: comp_full(block, mw), + short: comp_short(block, mw), + min_width: mw, + }; + } else { + if block.full_text != computed.block.full_text { + computed.block.full_text = block.full_text.clone(); + computed.full = comp_full(block, computed.min_width); + } + if block.short_text != computed.block.short_text { + computed.block.full_text = block.full_text.clone(); + computed.short = comp_short(block, computed.min_width); + } + computed.block.color = block.color; + computed.block.background = block.background; + computed.block.align = block.align; + computed.block.name = block.name.clone(); + computed.block.instance = block.instance.clone(); + computed.block.separator = block.separator; + computed.block.separator_block_width = block.separator_block_width; + } + } + } + + #[derive(Debug)] + struct LogialBlock<'a> { + blocks: Vec<(&'a ComputedBlock, bool)>, + delta: f64, + separator: bool, + separator_block_width: u8, + } + + let mut blocks_computed = Vec::new(); + let mut blocks_width = 0.0; + let mut s_start = 0; + while s_start < blocks.len() { + let mut s_end = s_start + 1; + let series_name = &blocks[s_start].name; + while s_end < blocks.len() + && blocks[s_end - 1].separator_block_width == 0 + && &blocks[s_end].name == series_name + { + s_end += 1; + } + + let mut series = LogialBlock { + blocks: Vec::with_capacity(s_end - s_start), + delta: 0.0, + separator: blocks[s_end - 1].separator, + separator_block_width: blocks[s_end - 1].separator_block_width, + }; + + for comp in &blocks_cache[s_start..s_end] { + blocks_width += comp.full.width; + if let Some(short) = &comp.short { + series.delta += comp.full.width - short.width; + } + series.blocks.push((comp, false)); + } + if s_end != blocks.len() { + blocks_width += series.separator_block_width as f64; + } + blocks_computed.push(series); + s_start = s_end; + } + + // Progressively switch to short mode + if offset_left + blocks_width > full_width { + let mut heap = BinaryHeap::new(); + for (i, b) in blocks_computed.iter().enumerate() { + if b.delta > 0.0 { + heap.push((DefaultLess(b.delta), i)); + } + } + while let Some((DefaultLess(delta), to_switch)) = heap.pop() { + for comp in &mut blocks_computed[to_switch].blocks { + comp.1 = true; + } + blocks_width -= delta; + if offset_left + blocks_width <= full_width { + break; + } + } + } + + // Remove all the empy blocks + for s in &mut blocks_computed { + s.blocks.retain(|(text, is_short)| { + (*is_short + && text + .short + .as_ref() + .map_or(text.full.width > 0.0, |s| s.width > 0.0)) + || (!is_short && text.full.width > 0.0) + }); + } + + // Render blocks + buttons.clear(); + let mut j = 0; + for series in blocks_computed { + let s_len = series.blocks.len(); + for (i, (computed, is_short)) in series.blocks.into_iter().enumerate() { + let block = &computed.block; + let to_render = if is_short { + computed.short.as_ref().unwrap_or(&computed.full) + } else { + &computed.full + }; + j += 1; + to_render.render( + context, + RenderOptions { + x_offset: full_width - blocks_width, + bar_height: full_height, + fg_color: block.color.unwrap_or(config.color), + bg_color: block.background, + r_left: if i == 0 { config.blocks_r } else { 0.0 }, + r_right: if i + 1 == s_len { config.blocks_r } else { 0.0 }, + overlap: config.blocks_overlap, + }, + ); + buttons.push( + full_width - blocks_width, + to_render.width, + (block.name.clone(), block.instance.clone()), + ); + blocks_width -= to_render.width; + } + if j != blocks.len() && series.separator_block_width > 0 { + let w = series.separator_block_width as f64; + if series.separator && config.separator_width > 0.0 { + config.separator.apply(context); + context.set_line_width(config.separator_width); + context.move_to(full_width - blocks_width + w * 0.5, full_height * 0.1); + context.line_to(full_width - blocks_width + w * 0.5, full_height * 0.9); + context.stroke().unwrap(); + } + blocks_width -= w; + } + } +} -- cgit v1.3.1 From 2a3c0d9ceac54c9f6d9312c610d2a161a4bb37c9 Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Tue, 9 Aug 2022 22:04:22 +0300 Subject: some renames --- src/bar.rs | 8 ++++---- src/state.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/bar.rs') diff --git a/src/bar.rs b/src/bar.rs index f3dc95c..b157190 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -20,7 +20,7 @@ use crate::{ }; pub struct Bar { - pub first_configure: bool, + pub configured: bool, pub width: u32, pub height: u32, pub scale: i32, @@ -35,12 +35,12 @@ pub struct Bar { impl Bar { pub fn configure(&mut self, ss: &mut SharedState, width: u32) { - if self.width != width { + if self.width != width && width != 0 { self.width = width; self.layer.set_exclusive_zone(self.height as i32); } - self.first_configure = false; + self.configured = true; self.draw(ss); } @@ -84,7 +84,7 @@ impl Bar { } pub fn draw(&mut self, ss: &mut SharedState) { - if self.first_configure { + if !self.configured { return; } diff --git a/src/state.rs b/src/state.rs index ea5ca4e..131e20f 100644 --- a/src/state.rs +++ b/src/state.rs @@ -194,7 +194,7 @@ impl OutputHandler for State { .expect("layer surface creation"); let river_output_status = self.river_status_state.new_output_status(qh, &output).ok(); self.bars.push(Bar { - first_configure: true, + configured: false, width: 0, height, scale: 1, -- cgit v1.3.1 From 2d77969c7719e72237ec365c3db9e35c3e178631 Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Tue, 9 Aug 2022 22:19:56 +0300 Subject: refactoring --- src/bar.rs | 23 ++++++------- src/tags.rs | 14 ++++---- src/text.rs | 109 +++++++++++++++++++----------------------------------------- 3 files changed, 52 insertions(+), 94 deletions(-) (limited to 'src/bar.rs') diff --git a/src/bar.rs b/src/bar.rs index b157190..ffc4d7c 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -133,8 +133,7 @@ impl Bar { .iter() .enumerate() { - let tag = - compute_tag_label(text.to_string(), ss.config.font.clone(), &cairo_ctx); + let tag = compute_tag_label(text, ss.config.font.clone(), &cairo_ctx); self.tags_btns.push(x_offset, tag.width, id); x_offset += tag.width; self.tags_computed.push(tag); @@ -218,9 +217,9 @@ fn render_blocks( }; let comp_full = |block: &Block, min_width: Option| { let markup = block.markup.as_deref() == Some("pango"); - text::Text { - text: block.full_text.clone(), - attr: text::Attributes { + text::ComputedText::new( + &block.full_text, + text::Attributes { font: config.font.clone(), padding_left: 0.0, padding_right: 0.0, @@ -228,15 +227,15 @@ fn render_blocks( align: block.align.unwrap_or_default(), markup, }, - } - .compute(context) + context, + ) }; let comp_short = |block: &Block, min_width: Option| { let markup = block.markup.as_deref() == Some("pango"); block.short_text.as_ref().map(|short_text| { - text::Text { - text: short_text.clone(), - attr: text::Attributes { + text::ComputedText::new( + short_text, + text::Attributes { font: config.font.clone(), padding_left: 0.0, padding_right: 0.0, @@ -244,8 +243,8 @@ fn render_blocks( align: block.align.unwrap_or_default(), markup, }, - } - .compute(context) + context, + ) }) }; diff --git a/src/tags.rs b/src/tags.rs index 8114a74..0c63570 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -1,4 +1,4 @@ -use crate::text::{Attributes, ComputedText, Text}; +use crate::text::{Attributes, ComputedText}; use cairo::Context; use pango::FontDescription; use pangocairo::{cairo, pango}; @@ -28,9 +28,10 @@ impl TagsInfo { } } -pub fn compute_tag_label(label: String, font: FontDescription, context: &Context) -> ComputedText { - let text = Text { - attr: Attributes { +pub fn compute_tag_label(label: &str, font: FontDescription, context: &Context) -> ComputedText { + ComputedText::new( + label, + Attributes { font, padding_left: 25.0, padding_right: 25.0, @@ -38,7 +39,6 @@ pub fn compute_tag_label(label: String, font: FontDescription, context: &Context align: Default::default(), markup: false, }, - text: label, - }; - text.compute(context) + context, + ) } diff --git a/src/text.rs b/src/text.rs index 60ed707..978a9cc 100644 --- a/src/text.rs +++ b/src/text.rs @@ -1,9 +1,8 @@ use crate::color::Color; -use pango::{EllipsizeMode, FontDescription}; +use pango::FontDescription; use pangocairo::{cairo, pango}; use serde::Deserialize; use std::f64::consts::{FRAC_PI_2, PI, TAU}; -use std::ops::Deref; #[derive(Clone, Debug, PartialEq)] pub struct RenderOptions { @@ -40,96 +39,55 @@ impl Default for Align { } } -fn create_pango_layout(cairo_context: &cairo::Context) -> pango::Layout { - pangocairo::create_layout(cairo_context).unwrap() -} - -fn show_pango_layout(cairo_context: &cairo::Context, layout: &pango::Layout) { - pangocairo::show_layout(cairo_context, layout); -} - #[derive(Clone, Debug, PartialEq)] -pub struct Text { +pub struct ComputedText { + pub layout: pango::Layout, pub attr: Attributes, - pub text: String, + pub width: f64, + pub height: f64, } -impl Text { - pub fn compute(mut self, context: &cairo::Context) -> ComputedText { - let (mut width, height) = { - let layout = create_pango_layout(context); - layout.set_font_description(Some(&self.attr.font)); - if self.attr.markup { - layout.set_markup(&self.text); - } else { - layout.set_text(&self.text); - } +impl ComputedText { + pub fn new(text: &str, mut attr: Attributes, context: &cairo::Context) -> Self { + let layout = pangocairo::create_layout(context).unwrap(); + layout.set_font_description(Some(&attr.font)); + if attr.markup { + layout.set_markup(text); + } else { + layout.set_text(text); + } - let (text_width, text_height) = layout.pixel_size(); - let width = f64::from(text_width) + self.attr.padding_right + self.attr.padding_right; - let height = f64::from(text_height); - (width, height) - }; + let (text_width, text_height) = layout.pixel_size(); + let mut width = f64::from(text_width) + attr.padding_right + attr.padding_right; + let height = f64::from(text_height); - if let Some(min_width) = self.attr.min_width { + if let Some(min_width) = attr.min_width { if width < min_width { let d = min_width - width; width = min_width; - match self.attr.align { - Align::Right => self.attr.padding_left += d, - Align::Left => self.attr.padding_right += d, + match attr.align { + Align::Right => attr.padding_left += d, + Align::Left => attr.padding_right += d, Align::Center => { - self.attr.padding_left += d * 0.5; - self.attr.padding_right += d * 0.5; + attr.padding_left += d * 0.5; + attr.padding_right += d * 0.5; } } } } - ComputedText { - text: self, + Self { + layout, + attr, width, height, } } -} -#[derive(Clone, Debug, PartialEq)] -pub struct ComputedText { - pub text: Text, - pub width: f64, - pub height: f64, -} - -impl Deref for ComputedText { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.text.text - } -} - -impl ComputedText { pub fn render(&self, context: &cairo::Context, options: RenderOptions) { - let text = &self.text; - let layout = create_pango_layout(context); - layout.set_font_description(Some(&text.attr.font)); - if text.attr.markup { - layout.set_markup(&text.text); - } else { - layout.set_text(&text.text); - } - context.save().unwrap(); context.translate(options.x_offset - options.overlap, 0.0); - // Set the width/height on the Pango layout so that it word-wraps/ellipises. - let text_width = self.width - text.attr.padding_left - text.attr.padding_right; - let text_height = self.height; - layout.set_ellipsize(EllipsizeMode::End); - layout.set_width(text_width as i32 * pango::SCALE); - layout.set_height(text_height as i32 * pango::SCALE); - // Draw background if let Some(bg) = options.bg_color { bg.apply(context); @@ -147,10 +105,10 @@ impl ComputedText { options.fg_color.apply(context); context.translate( - text.attr.padding_left + options.overlap, + self.attr.padding_left + options.overlap, (options.bar_height - self.height) * 0.5, ); - show_pango_layout(context, &layout); + pangocairo::show_layout(context, &self.layout); context.restore().unwrap(); } } @@ -177,9 +135,9 @@ fn rounded_rectangle( } pub fn width_of(text: &str, context: &cairo::Context, markup: bool, font: &FontDescription) -> f64 { - let text = Text { - text: text.into(), - attr: Attributes { + ComputedText::new( + text, + Attributes { font: font.clone(), padding_left: 0.0, padding_right: 0.0, @@ -187,6 +145,7 @@ pub fn width_of(text: &str, context: &cairo::Context, markup: bool, font: &FontD align: Default::default(), markup, }, - }; - text.compute(context).width + context, + ) + .width } -- cgit v1.3.1 From b154262dcbf0d1a5686921f24eb0b0c41ed95f29 Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Thu, 25 Aug 2022 09:18:56 +0300 Subject: feat: add hide_inactive_tags option --- src/bar.rs | 27 ++++++++++++++++----------- src/config.rs | 7 +++++++ src/river_protocols/status.rs | 8 ++++++++ src/river_protocols/status/dispatch.rs | 8 +++++++- src/state.rs | 16 ++++++++++++++++ src/tags.rs | 6 +++++- 6 files changed, 59 insertions(+), 13 deletions(-) (limited to 'src/bar.rs') diff --git a/src/bar.rs b/src/bar.rs index ffc4d7c..18ad54c 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -127,24 +127,28 @@ impl Bar { let mut offset_left = 0.0; if self.has_tags_provider() { if self.tags_computed.is_empty() { - let mut x_offset = 0.0; // TODO make configurable - for (id, text) in ["1", "2", "3", "4", "5", "6", "7", "8", "9"] - .iter() - .enumerate() - { - let tag = compute_tag_label(text, ss.config.font.clone(), &cairo_ctx); - self.tags_btns.push(x_offset, tag.width, id); - x_offset += tag.width; - self.tags_computed.push(tag); + for text in ["1", "2", "3", "4", "5", "6", "7", "8", "9"] { + self.tags_computed.push(compute_tag_label( + text, + ss.config.font.clone(), + &cairo_ctx, + )); } } + self.tags_btns.clear(); for (i, label) in self.tags_computed.iter().enumerate() { let state = self.tags_info.get_state(i); let (bg, fg) = match state { - TagState::Focused => (ss.config.tag_focused_bg, ss.config.tag_focused_fg), - TagState::Inactive => (ss.config.tag_bg, ss.config.tag_fg), TagState::Urgent => (ss.config.tag_urgent_bg, ss.config.tag_urgent_fg), + TagState::Focused => (ss.config.tag_focused_bg, ss.config.tag_focused_fg), + TagState::Active => (ss.config.tag_bg, ss.config.tag_fg), + TagState::Inactive => { + if ss.config.hide_inactive_tags { + continue; + } + (ss.config.tag_inactive_bg, ss.config.tag_inactive_fg) + } }; label.render( &cairo_ctx, @@ -167,6 +171,7 @@ impl Bar { overlap: 0.0, }, ); + self.tags_btns.push(offset_left, label.width, i); offset_left += label.width; } } diff --git a/src/config.rs b/src/config.rs index bd7b91c..9ae2395 100644 --- a/src/config.rs +++ b/src/config.rs @@ -20,6 +20,8 @@ pub struct Config { pub tag_focused_bg: Color, pub tag_urgent_fg: Color, pub tag_urgent_bg: Color, + pub tag_inactive_fg: Color, + pub tag_inactive_bg: Color, // font and size pub font: Font, pub height: u32, @@ -29,6 +31,8 @@ pub struct Config { pub blocks_overlap: f64, // command pub command: Option, + // misc + pub hide_inactive_tags: bool, } impl Default for Config { @@ -44,6 +48,8 @@ impl Default for Config { tag_focused_bg: Color::from_rgba_hex(0x689d68ff), tag_urgent_fg: Color::from_rgba_hex(0x282828ff), tag_urgent_bg: Color::from_rgba_hex(0xcc241dff), + tag_inactive_fg: Color::from_rgba_hex(0xd79921ff), + tag_inactive_bg: Color::from_rgba_hex(0x282828ff), font: Font::new("monospace 10"), height: 24, separator_width: 2.0, @@ -51,6 +57,7 @@ impl Default for Config { blocks_r: 0.0, blocks_overlap: 0.0, command: None, + hide_inactive_tags: false, } } } diff --git a/src/river_protocols/status.rs b/src/river_protocols/status.rs index 50c85e0..f19ac5f 100644 --- a/src/river_protocols/status.rs +++ b/src/river_protocols/status.rs @@ -96,6 +96,14 @@ pub trait RiverStatusHandler: Sized { output_status: &RiverOutputStatus, urgent: u32, ); + + fn views_tags_updated( + &mut self, + conn: &Connection, + qh: &QueueHandle, + output_status: &RiverOutputStatus, + tags: Vec, + ); } #[derive(Debug, Clone)] diff --git a/src/river_protocols/status/dispatch.rs b/src/river_protocols/status/dispatch.rs index d38037d..65d6e0c 100644 --- a/src/river_protocols/status/dispatch.rs +++ b/src/river_protocols/status/dispatch.rs @@ -79,7 +79,13 @@ where match event { Event::FocusedTags { tags } => data.focused_tags_updated(conn, qh, &status, tags), Event::UrgentTags { tags } => data.urgent_tags_updated(conn, qh, &status, tags), - Event::ViewTags { tags: _ } => (), + Event::ViewTags { tags } => { + let tags = tags + .chunks_exact(4) + .map(|bytes| u32::from_ne_bytes(bytes.try_into().unwrap())) + .collect(); + data.views_tags_updated(conn, qh, &status, tags); + } } } } diff --git a/src/state.rs b/src/state.rs index 131e20f..4dd9414 100644 --- a/src/state.rs +++ b/src/state.rs @@ -380,6 +380,22 @@ impl RiverStatusHandler for State { bar.tags_info.urgent = urgent; bar.draw(self.shared_state.as_mut().unwrap()); } + + fn views_tags_updated( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + output_status: &RiverOutputStatus, + tags: Vec, + ) { + let bar = self + .bars + .iter_mut() + .find(|b| b.river_output_status.as_ref() == Some(output_status)) + .unwrap(); + bar.tags_info.active = tags.into_iter().fold(0, |a, b| a | b); + bar.draw(self.shared_state.as_mut().unwrap()); + } } impl RiverControlHandler for State { diff --git a/src/tags.rs b/src/tags.rs index 0c63570..5a4a1b2 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -5,15 +5,17 @@ use pangocairo::{cairo, pango}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TagState { + Urgent, Focused, + Active, Inactive, - Urgent, } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct TagsInfo { pub focused: u32, pub urgent: u32, + pub active: u32, } impl TagsInfo { @@ -22,6 +24,8 @@ impl TagsInfo { TagState::Urgent } else if self.focused >> tag & 1 == 1 { TagState::Focused + } else if self.active >> tag & 1 == 1 { + TagState::Active } else { TagState::Inactive } -- cgit v1.3.1 From 39cc147656e2f61f7467f4b67b4c76fd9207c2f6 Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Thu, 25 Aug 2022 16:40:44 +0300 Subject: do not clone fonts --- src/bar.rs | 11 ++++------- src/tags.rs | 2 +- src/text.rs | 20 ++++++++++---------- 3 files changed, 15 insertions(+), 18 deletions(-) (limited to 'src/bar.rs') diff --git a/src/bar.rs b/src/bar.rs index 18ad54c..188152f 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -129,11 +129,8 @@ impl Bar { if self.tags_computed.is_empty() { // TODO make configurable for text in ["1", "2", "3", "4", "5", "6", "7", "8", "9"] { - self.tags_computed.push(compute_tag_label( - text, - ss.config.font.clone(), - &cairo_ctx, - )); + self.tags_computed + .push(compute_tag_label(text, &ss.config.font, &cairo_ctx)); } } self.tags_btns.clear(); @@ -225,7 +222,7 @@ fn render_blocks( text::ComputedText::new( &block.full_text, text::Attributes { - font: config.font.clone(), + font: &config.font, padding_left: 0.0, padding_right: 0.0, min_width, @@ -241,7 +238,7 @@ fn render_blocks( text::ComputedText::new( short_text, text::Attributes { - font: config.font.clone(), + font: &config.font, padding_left: 0.0, padding_right: 0.0, min_width, diff --git a/src/tags.rs b/src/tags.rs index 5a4a1b2..d22853d 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -32,7 +32,7 @@ impl TagsInfo { } } -pub fn compute_tag_label(label: &str, font: FontDescription, context: &Context) -> ComputedText { +pub fn compute_tag_label(label: &str, font: &FontDescription, context: &Context) -> ComputedText { ComputedText::new( label, Attributes { diff --git a/src/text.rs b/src/text.rs index 978a9cc..7a3b7fc 100644 --- a/src/text.rs +++ b/src/text.rs @@ -16,8 +16,8 @@ pub struct RenderOptions { } #[derive(Clone, Debug, PartialEq)] -pub struct Attributes { - pub font: FontDescription, +pub struct Attributes<'a> { + pub font: &'a FontDescription, pub padding_left: f64, pub padding_right: f64, pub min_width: Option, @@ -41,16 +41,16 @@ impl Default for Align { #[derive(Clone, Debug, PartialEq)] pub struct ComputedText { - pub layout: pango::Layout, - pub attr: Attributes, pub width: f64, - pub height: f64, + layout: pango::Layout, + height: f64, + padding_left: f64, } impl ComputedText { pub fn new(text: &str, mut attr: Attributes, context: &cairo::Context) -> Self { let layout = pangocairo::create_layout(context).unwrap(); - layout.set_font_description(Some(&attr.font)); + layout.set_font_description(Some(attr.font)); if attr.markup { layout.set_markup(text); } else { @@ -77,10 +77,10 @@ impl ComputedText { } Self { - layout, - attr, width, + layout, height, + padding_left: attr.padding_left, } } @@ -105,7 +105,7 @@ impl ComputedText { options.fg_color.apply(context); context.translate( - self.attr.padding_left + options.overlap, + self.padding_left + options.overlap, (options.bar_height - self.height) * 0.5, ); pangocairo::show_layout(context, &self.layout); @@ -138,7 +138,7 @@ pub fn width_of(text: &str, context: &cairo::Context, markup: bool, font: &FontD ComputedText::new( text, Attributes { - font: font.clone(), + font, padding_left: 0.0, padding_right: 0.0, min_width: None, -- cgit v1.3.1 From f0e53e6b8119d872f5986c3fcb4403d7b8214382 Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Sat, 27 Aug 2022 09:16:12 +0300 Subject: refactor --- src/bar.rs | 2 +- src/main.rs | 2 +- src/shared_state.rs | 16 +++++++++++++-- src/state.rs | 58 +++++++++++++++++++++++------------------------------ 4 files changed, 41 insertions(+), 37 deletions(-) (limited to 'src/bar.rs') diff --git a/src/bar.rs b/src/bar.rs index 188152f..ae69d37 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -95,7 +95,7 @@ impl Bar { let height_f = height as f64; let (buffer, canvas) = ss - .pool + .get_pool(height as usize * stride as usize) .create_buffer( width * self.scale, height * self.scale, diff --git a/src/main.rs b/src/main.rs index b158c91..7f8dd38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,7 +50,7 @@ async fn main() -> anyhow::Result<()> { readable = state.wait_for_status_cmd() => { readable?.clear_ready(); if let Err(e) = state.notify_available() { - if let Some(mut status_cmd) = state.shared_state.as_mut().unwrap().status_cmd.take() { + if let Some(mut status_cmd) = state.shared_state.status_cmd.take() { let _ = status_cmd.child.kill(); } state.set_error(e.to_string()); diff --git a/src/shared_state.rs b/src/shared_state.rs index c4ec9d6..554d856 100644 --- a/src/shared_state.rs +++ b/src/shared_state.rs @@ -1,4 +1,7 @@ -use smithay_client_toolkit::{reexports::client::QueueHandle, shm::slot::SlotPool}; +use smithay_client_toolkit::{ + reexports::client::QueueHandle, + shm::{slot::SlotPool, ShmState}, +}; use crate::{ config::Config, @@ -10,9 +13,18 @@ use crate::{ #[derive(Debug)] pub struct SharedState { pub qh: QueueHandle, - pub pool: SlotPool, + pub shm_state: ShmState, + pub pool: Option, pub config: Config, pub status_cmd: Option, pub blocks: Vec, pub blocks_cache: Vec, } + +impl SharedState { + pub fn get_pool(&mut self, len: usize) -> &mut SlotPool { + self.pool.get_or_insert_with(|| { + SlotPool::new(len, &self.shm_state).expect("Failed to create pool") + }) + } +} diff --git a/src/state.rs b/src/state.rs index 0390525..f459681 100644 --- a/src/state.rs +++ b/src/state.rs @@ -16,7 +16,7 @@ use smithay_client_toolkit::{ Capability, SeatHandler, SeatState, }, shell::layer::{Anchor, Layer, LayerHandler, LayerState, LayerSurface, LayerSurfaceConfigure}, - shm::{slot::SlotPool, ShmHandler, ShmState}, + shm::{ShmHandler, ShmState}, }; use tokio::io::unix::AsyncFdReadyGuard; @@ -40,14 +40,13 @@ pub struct State { seat_state: SeatState, output_state: OutputState, compositor_state: CompositorState, - shm_state: ShmState, layer_state: LayerState, river_status_state: RiverStatusState, river_control_state: RiverControlState, seats: Vec, bars: Vec, - pub shared_state: Option, + pub shared_state: SharedState, } struct Seat { @@ -78,29 +77,23 @@ impl State { seat_state: SeatState::new(), output_state: OutputState::new(), compositor_state: CompositorState::new(), - shm_state: ShmState::new(), layer_state: LayerState::new(), river_status_state: RiverStatusState::new(), river_control_state: RiverControlState::new(), seats: Vec::new(), bars: Vec::new(), - shared_state: None, + shared_state: SharedState { + qh: event_queue.handle(), + shm_state: ShmState::new(), + pool: None, + config, + status_cmd, + blocks: Vec::new(), + blocks_cache: Vec::new(), + }, }; - while !this.registry_state.ready() { - event_queue.blocking_dispatch(&mut this).unwrap(); - } - - this.shared_state = Some(SharedState { - qh: event_queue.handle(), - pool: SlotPool::new(1, &this.shm_state).expect("Failed to create pool"), - config, - status_cmd, - blocks: Vec::new(), - blocks_cache: Vec::new(), - }); - if let Err(e) = error { this.set_error(e.to_string()); } @@ -109,7 +102,7 @@ impl State { } pub fn set_blocks(&mut self, blocks: Vec) { - self.shared_state.as_mut().unwrap().blocks = blocks; + self.shared_state.blocks = blocks; self.draw_all(); } @@ -121,7 +114,7 @@ impl State { } pub fn notify_available(&mut self) -> anyhow::Result<()> { - if let Some(cmd) = &mut self.shared_state.as_mut().unwrap().status_cmd { + if let Some(cmd) = &mut self.shared_state.status_cmd { if let Some(blocks) = cmd.notify_available()? { self.set_blocks(blocks); } @@ -131,12 +124,12 @@ impl State { pub fn draw_all(&mut self) { for bar in &mut self.bars { - bar.draw(self.shared_state.as_mut().unwrap()); + bar.draw(&mut self.shared_state); } } pub async fn wait_for_status_cmd(&self) -> io::Result> { - match &self.shared_state.as_ref().unwrap().status_cmd { + match &self.shared_state.status_cmd { Some(cmd) => cmd.async_fd.readable().await, None => { pending::<()>().await; @@ -164,7 +157,7 @@ impl CompositorHandler for State { .find(|bar| bar.layer.wl_surface() == surface) { bar.scale = scale; - bar.draw(self.shared_state.as_mut().expect("no shared_state?")); + bar.draw(&mut self.shared_state); } } @@ -189,7 +182,7 @@ impl OutputHandler for State { qh: &QueueHandle, output: wl_output::WlOutput, ) { - let height = self.shared_state.as_ref().unwrap().config.height; + let height = self.shared_state.config.height; let surface = self.compositor_state.create_surface(qh).unwrap(); let layer = LayerSurface::builder() .output(&output) @@ -252,7 +245,7 @@ impl LayerHandler for State { .iter_mut() .find(|b| &b.layer == layer) .unwrap() - .configure(self.shared_state.as_mut().unwrap(), configure.new_size.0); + .configure(&mut self.shared_state, configure.new_size.0); } } @@ -311,7 +304,6 @@ impl PointerHandler for State { .iter_mut() .find(|p| &p.pointer == pointer) .unwrap(); - let shared_state = self.shared_state.as_mut().unwrap(); for event in events { if let Some(bar) = self .bars @@ -324,7 +316,7 @@ impl PointerHandler for State { } PointerEventKind::Press { button, .. } => { bar.click( - shared_state, + &mut self.shared_state, button.into(), &seat.seat, event.position.0, @@ -336,7 +328,7 @@ impl PointerHandler for State { vertical, source, .. } => { if source == Some(wl_pointer::AxisSource::Finger) { - if shared_state.config.invert_touchpad_scrolling { + if self.shared_state.config.invert_touchpad_scrolling { seat.finger_scroll -= vertical.absolute; } else { seat.finger_scroll += vertical.absolute; @@ -361,7 +353,7 @@ impl PointerHandler for State { }; bar.click( - shared_state, + &mut self.shared_state, btn, &seat.seat, event.position.0, @@ -378,7 +370,7 @@ impl PointerHandler for State { impl ShmHandler for State { fn shm_state(&mut self) -> &mut ShmState { - &mut self.shm_state + &mut self.shared_state.shm_state } } @@ -400,7 +392,7 @@ impl RiverStatusHandler for State { .find(|b| b.river_output_status.as_ref() == Some(output_status)) .unwrap(); bar.tags_info.focused = focused; - bar.draw(self.shared_state.as_mut().unwrap()); + bar.draw(&mut self.shared_state); } fn urgent_tags_updated( @@ -416,7 +408,7 @@ impl RiverStatusHandler for State { .find(|b| b.river_output_status.as_ref() == Some(output_status)) .unwrap(); bar.tags_info.urgent = urgent; - bar.draw(self.shared_state.as_mut().unwrap()); + bar.draw(&mut self.shared_state); } fn views_tags_updated( @@ -432,7 +424,7 @@ impl RiverStatusHandler for State { .find(|b| b.river_output_status.as_ref() == Some(output_status)) .unwrap(); bar.tags_info.active = tags.into_iter().fold(0, |a, b| a | b); - bar.draw(self.shared_state.as_mut().unwrap()); + bar.draw(&mut self.shared_state); } } -- cgit v1.3.1 From 899e07fbaac6ed28ddbac054e7957e646a38937c Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Fri, 23 Sep 2022 10:06:28 +0300 Subject: support transparent background --- src/bar.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/bar.rs') diff --git a/src/bar.rs b/src/bar.rs index ae69d37..0569b71 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -120,8 +120,11 @@ impl Bar { self.layer.wl_surface().set_buffer_scale(self.scale); // Background + cairo_ctx.save().unwrap(); + cairo_ctx.set_operator(cairo::Operator::Source); ss.config.background.apply(&cairo_ctx); - cairo_ctx.paint().expect("cairo paint"); + cairo_ctx.paint().unwrap(); + cairo_ctx.restore().unwrap(); // Display tags let mut offset_left = 0.0; -- cgit v1.3.1 From d45a4ef408c0f5a2071194d4c3285f0b7cb27dd0 Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Sun, 27 Nov 2022 21:06:35 +0200 Subject: update wayland libs & readd set_cursor --- Cargo.lock | 130 +++++++++++++++++++++++--------- Cargo.toml | 8 +- src/bar.rs | 10 +-- src/main.rs | 5 +- src/river_protocols/control.rs | 115 ++++++++++++++++------------ src/river_protocols/control/dispatch.rs | 70 ----------------- src/river_protocols/status.rs | 129 +++++++++++++++++++++---------- src/river_protocols/status/dispatch.rs | 92 ---------------------- src/state.rs | 81 ++++++++++---------- src/text.rs | 2 +- 10 files changed, 305 insertions(+), 337 deletions(-) delete mode 100644 src/river_protocols/control/dispatch.rs delete mode 100644 src/river_protocols/status/dispatch.rs (limited to 'src/bar.rs') diff --git a/Cargo.lock b/Cargo.lock index c0dcd48..15e4189 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,22 +42,23 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cairo-rs" -version = "0.15.12" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" +checksum = "08f9ee4a4ca9239c9a839453dce04b7ddee2f859ec4cd7acd1f5703b68db549c" dependencies = [ "bitflags", "cairo-sys-rs", "glib", "libc", + "once_cell", "thiserror", ] [[package]] name = "cairo-sys-rs" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +checksum = "5119ea655ec777b523f0b57279e70f8a4542f61b0e98a48f892b4ef043fd4c5d" dependencies = [ "glib-sys", "libc", @@ -160,6 +161,23 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-task" version = "0.3.24" @@ -173,6 +191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ "futures-core", + "futures-macro", "futures-task", "pin-project-lite", "pin-utils", @@ -190,17 +209,52 @@ dependencies = [ "wasi", ] +[[package]] +name = "gio" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1debf8d0315d69be0153aa76249db3c858ef69b7778ad3cc669e6d370c485" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6da1bba9d3f2ab13a6e9932c40f240dc99ebc9f0bdc35cfb130d1a3df36f374c" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + [[package]] name = "glib" -version = "0.15.12" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" +checksum = "d5abffa711471e015eb93d65d6ea20e7e9f6f7951fc0a1042280439319b2de06" dependencies = [ "bitflags", "futures-channel", "futures-core", "futures-executor", "futures-task", + "futures-util", + "gio-sys", "glib-macros", "glib-sys", "gobject-sys", @@ -212,9 +266,9 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.15.11" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" +checksum = "e195c1311fa6b04d7b896ea39385f6bd60ef5d25bf74a7c11c8c3f94f6c1a572" dependencies = [ "anyhow", "heck", @@ -227,9 +281,9 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.15.10" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +checksum = "b33357bb421a77bd849f6a0bfcaf3b4b256a2577802971bb5dd522d530f27021" dependencies = [ "libc", "system-deps", @@ -237,9 +291,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.15.10" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +checksum = "63ca11a57400f3d4fda594e002844be47900c9fb8b29e2155c6e37a1f24e51b3" dependencies = [ "glib-sys", "libc", @@ -378,10 +432,11 @@ dependencies = [ [[package]] name = "nix" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" dependencies = [ + "autocfg", "bitflags", "cfg-if", "libc", @@ -406,11 +461,12 @@ checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" [[package]] name = "pango" -version = "0.15.10" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +checksum = "7208c60f224cf6e44c551df5ee2ef38f9da0fd29d7c5a0402000b8ab0520e798" dependencies = [ "bitflags", + "gio", "glib", "libc", "once_cell", @@ -419,9 +475,9 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.15.10" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +checksum = "922441c228366ed98d3534b87bc7c987c50564094c3abbc3513717786419252d" dependencies = [ "glib-sys", "gobject-sys", @@ -431,9 +487,9 @@ dependencies = [ [[package]] name = "pangocairo" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7876a45c1f1d1a75a2601dc6d9ef2cb5a8be0e3d76f909d82450759929035366" +checksum = "a726760a29e5e17d965d5d7573548e385ae9ce99cb7adcf70d75d4627f23fc7a" dependencies = [ "bitflags", "cairo-rs", @@ -445,9 +501,9 @@ dependencies = [ [[package]] name = "pangocairo-sys" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cf746594916c81d5f739af9335c5f55a1f4606d80b3e1d821f18cf95a29494" +checksum = "b8281198ea4596bdc6e22b0d3565471c9456d7125e423a785f866640c18b57ec" dependencies = [ "cairo-sys-rs", "glib-sys", @@ -634,7 +690,7 @@ checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "smithay-client-toolkit" version = "0.16.0" -source = "git+https://github.com/Smithay/client-toolkit#1cc11af8538040f46173bf021ac079c342ddeebb" +source = "git+https://github.com/Smithay/client-toolkit#e5d7c9084f8d80bef4c625c6ef52ec42dde4e211" dependencies = [ "bitflags", "dlib", @@ -777,9 +833,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wayland-backend" -version = "0.1.0-beta.10" +version = "0.1.0-beta.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c089c872513a8dcc2b5cc26209d83f5ffab1841d8c7973edf2583620ebc018" +checksum = "f3f96c52ca34b33e6bb55497327428be54dad648973aa5d3d1e02982d2fcc298" dependencies = [ "cc", "downcast-rs", @@ -792,9 +848,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.30.0-beta.10" +version = "0.30.0-beta.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd71253f97d86ac930fb296ba995e31c178f1be6a7026244c3b3f3811d5086be" +checksum = "0f6ab5911cc8a28e9d781933c1afe0f97ffa6885ad8941294784d025f06e5ad9" dependencies = [ "bitflags", "futures-channel", @@ -807,9 +863,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.30.0-beta.10" +version = "0.30.0-beta.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e39f4325f2ea5c1548cda2a6edabb74c68b072c9d6db7d7363cd9fe4994b124b" +checksum = "fa5ce1bbc13a3d806648974cba1d53481fea2ac29483eb147e4cce1250fc5263" dependencies = [ "nix", "wayland-client", @@ -818,9 +874,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.30.0-beta.10" +version = "0.30.0-beta.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60406a2fb43ff670ece4976cdd0537bbcd1e583b54c3cd9a1b61065e966df0a7" +checksum = "e32104ba51988754f4429dbb59c7b7fd2ccf1feaa0009bb59e49a5e2f91e985d" dependencies = [ "bitflags", "wayland-backend", @@ -830,9 +886,9 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.1.0-beta.10" +version = "0.1.0-beta.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1cfe42e0cfcce47a421844ee82e49316cfab3ec6bcbb3a1076a0a2dd6c8d61e" +checksum = "130613a48629204e4ab50ea4b5de2efa2e17c58f71a5af15b39535f99421f8c3" dependencies = [ "bitflags", "wayland-backend", @@ -843,9 +899,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.30.0-beta.10" +version = "0.30.0-beta.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1398566f240c3ef845bdfd310c8ee6ba800d4db695d007f23f2190eeedfff93" +checksum = "1fb55ca28710dcc155078db4e2bd29aacf24bd311261c48750f38c6c5430bf1f" dependencies = [ "proc-macro2", "quick-xml", @@ -855,9 +911,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.30.0-beta.10" +version = "0.30.0-beta.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bacc6b678c3350910e5ad6c057b7503666080952c4ece0a7e8958fd33937b1f5" +checksum = "882bda56e8397384ad66ec0ebe763e0b3b53153a6327344f7d74b85981a271e1" dependencies = [ "dlib", "log", diff --git a/Cargo.toml b/Cargo.toml index 90ea6c7..40a46bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,13 +9,13 @@ env_logger = "0.9" anyhow = "1" dirs-next = "2" toml = "0.5" -pangocairo = "0.15" +pangocairo = "0.16" serde = { version = "1", features = ["derive"] } serde_json = "1" memchr = "2" -wayland-client = "0.30.0-beta.10" -wayland-scanner = "0.30.0-beta.10" -wayland-backend = "0.1.0-beta.10" +wayland-client = "0.30.0-beta.13" +wayland-scanner = "0.30.0-beta.13" +wayland-backend = "0.1.0-beta.13" [dependencies.smithay-client-toolkit] git = "https://github.com/Smithay/client-toolkit" diff --git a/src/bar.rs b/src/bar.rs index 0569b71..dfa63a3 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -27,7 +27,7 @@ pub struct Bar { pub layer: LayerSurface, pub blocks_btns: ButtonManager<(Option, Option)>, pub river_output_status: Option, - pub river_control: RiverControlState, + pub river_control: Option, pub tags_btns: ButtonManager, pub tags_info: TagsInfo, pub tags_computed: Vec, @@ -58,17 +58,13 @@ impl Bar { _y: f64, ) -> anyhow::Result<()> { if let Some(tag) = self.tags_btns.click(x) { - if self.river_control.is_available() { + if let Some(river_control) = &self.river_control { let cmd = match button { PointerBtn::Left => "set-focused-tags", PointerBtn::Right => "toggle-focused-tags", _ => return Ok(()), }; - self.river_control.run_command( - &ss.qh, - seat, - [cmd.into(), (1u32 << tag).to_string()], - )?; + river_control.run_command(&ss.qh, seat, [cmd.into(), (1u32 << tag).to_string()]); } } else if let Some((name, instance)) = self.blocks_btns.click(x) { if let Some(cmd) = &mut ss.status_cmd { diff --git a/src/main.rs b/src/main.rs index fb52f07..8ae31aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,14 +24,15 @@ use smithay_client_toolkit::reexports::client::Connection; use tokio::io::{unix::AsyncFd, Interest}; use state::State; +use wayland_client::globals::registry_queue_init; #[tokio::main(flavor = "current_thread")] async fn main() -> anyhow::Result<()> { env_logger::init(); let conn = Connection::connect_to_env()?; - let mut event_queue = conn.new_event_queue(); - let mut state = State::new(&conn, &mut event_queue); + let (globals, mut event_queue) = registry_queue_init(&conn).unwrap(); + let mut state = State::new(&mut event_queue, &globals); let async_fd = AsyncFd::with_interest( event_queue.prepare_read()?.connection_fd().as_raw_fd(), diff --git a/src/river_protocols/control.rs b/src/river_protocols/control.rs index 525a9db..7cce23d 100644 --- a/src/river_protocols/control.rs +++ b/src/river_protocols/control.rs @@ -1,67 +1,34 @@ -pub mod protocol { - use smithay_client_toolkit::reexports::client as wayland_client; - use smithay_client_toolkit::reexports::client::protocol::*; - - pub mod __interfaces { - use smithay_client_toolkit::reexports::client::protocol::__interfaces::*; - wayland_scanner::generate_interfaces!("protocols/river-control-unstable-v1.xml"); - } - use self::__interfaces::*; - - wayland_scanner::generate_client_code!("protocols/river-control-unstable-v1.xml"); -} - -mod dispatch; - -use std::sync::Arc; - -use smithay_client_toolkit::globals::GlobalData; +use wayland_client::globals::{BindError, GlobalList}; use wayland_client::{protocol::wl_seat, Connection, Dispatch, QueueHandle}; use protocol::{zriver_command_callback_v1, zriver_control_v1}; -use smithay_client_toolkit::error::GlobalError; -use smithay_client_toolkit::registry::GlobalProxy; - #[derive(Debug, Clone)] pub struct RiverControlState { - control: Arc>, + control: zriver_control_v1::ZriverControlV1, } impl RiverControlState { - pub fn new() -> Self { - Self { - control: Arc::new(GlobalProxy::NotReady), - } - } - - pub fn is_available(&self) -> bool { - self.control.get().is_ok() - } - - pub fn control(&self) -> Result<&zriver_control_v1::ZriverControlV1, GlobalError> { - self.control.get() + pub fn new(globals: &GlobalList, qh: &QueueHandle) -> Result + where + D: Dispatch + 'static, + { + let control = globals.bind(qh, 1..=1, ())?; + Ok(Self { control }) } - pub fn run_command( - &self, - qh: &QueueHandle, - seat: &wl_seat::WlSeat, - args: Args, - ) -> Result<(), GlobalError> + pub fn run_command(&self, qh: &QueueHandle, seat: &wl_seat::WlSeat, args: Args) where - D: Dispatch - + Dispatch + D: Dispatch + 'static, Args: IntoIterator, Arg: Into, { - let control = self.control()?; for arg in args { - control.add_argument(arg.into()); + self.control.add_argument(arg.into()); } - control.run_command(seat, qh, RiverCommandCallbackData {}); - Ok(()) + self.control + .run_command(seat, qh, RiverCommandCallbackData {}); } } @@ -82,10 +49,64 @@ pub struct RiverCommandCallbackData { macro_rules! delegate_river_control { ($ty: ty) => { ::smithay_client_toolkit::reexports::client::delegate_dispatch!($ty: [ - $crate::river_protocols::control::protocol::zriver_control_v1::ZriverControlV1: ::smithay_client_toolkit::globals::GlobalData + $crate::river_protocols::control::protocol::zriver_control_v1::ZriverControlV1: () ] => $crate::river_protocols::control::RiverControlState); ::smithay_client_toolkit::reexports::client::delegate_dispatch!($ty: [ $crate::river_protocols::control::protocol::zriver_command_callback_v1::ZriverCommandCallbackV1: $crate::river_protocols::control::RiverCommandCallbackData ] => $crate::river_protocols::control::RiverControlState); }; } + +impl Dispatch for RiverControlState +where + D: Dispatch + RiverControlHandler + 'static, +{ + fn event( + _: &mut D, + _: &zriver_control_v1::ZriverControlV1, + _: zriver_control_v1::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + unreachable!("zriver_control_v1 has no events") + } +} + +impl Dispatch + for RiverControlState +where + D: Dispatch + + RiverControlHandler + + 'static, +{ + fn event( + data: &mut D, + _callback: &zriver_command_callback_v1::ZriverCommandCallbackV1, + event: zriver_command_callback_v1::Event, + _udata: &RiverCommandCallbackData, + conn: &Connection, + qh: &QueueHandle, + ) { + use zriver_command_callback_v1::Event; + match event { + Event::Success { output } => data.command_success(conn, qh, output), + Event::Failure { failure_message } => data.command_success(conn, qh, failure_message), + } + } +} + +pub mod protocol { + #![allow(non_upper_case_globals)] + + use smithay_client_toolkit::reexports::client as wayland_client; + use smithay_client_toolkit::reexports::client::protocol::*; + + pub mod __interfaces { + use smithay_client_toolkit::reexports::client::protocol::__interfaces::*; + wayland_scanner::generate_interfaces!("protocols/river-control-unstable-v1.xml"); + } + use self::__interfaces::*; + + wayland_scanner::generate_client_code!("protocols/river-control-unstable-v1.xml"); +} diff --git a/src/river_protocols/control/dispatch.rs b/src/river_protocols/control/dispatch.rs deleted file mode 100644 index 14759e7..0000000 --- a/src/river_protocols/control/dispatch.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::sync::Arc; - -use super::protocol::{zriver_command_callback_v1, zriver_control_v1}; -use wayland_client::{Connection, Dispatch, QueueHandle}; - -use smithay_client_toolkit::{ - error::GlobalError, - globals::{GlobalData, ProvidesBoundGlobal}, - registry::{ProvidesRegistryState, RegistryHandler}, -}; - -use super::{RiverCommandCallbackData, RiverControlHandler, RiverControlState}; - -impl RegistryHandler for RiverControlState -where - D: Dispatch - + RiverControlHandler - + ProvidesRegistryState - + 'static, -{ - fn ready(data: &mut D, _conn: &Connection, qh: &QueueHandle) { - data.river_control_state().control = - Arc::new(data.registry().bind_one(qh, 1..=1, GlobalData).into()); - } -} - -impl ProvidesBoundGlobal for RiverControlState { - fn bound_global(&self) -> Result { - self.control.get().cloned() - } -} - -impl Dispatch for RiverControlState -where - D: Dispatch + RiverControlHandler + 'static, -{ - fn event( - _: &mut D, - _: &zriver_control_v1::ZriverControlV1, - _: zriver_control_v1::Event, - _: &GlobalData, - _: &Connection, - _: &QueueHandle, - ) { - unreachable!("zriver_control_v1 has no events") - } -} - -impl Dispatch - for RiverControlState -where - D: Dispatch - + RiverControlHandler - + 'static, -{ - fn event( - data: &mut D, - _callback: &zriver_command_callback_v1::ZriverCommandCallbackV1, - event: zriver_command_callback_v1::Event, - _udata: &RiverCommandCallbackData, - conn: &Connection, - qh: &QueueHandle, - ) { - use zriver_command_callback_v1::Event; - match event { - Event::Success { output } => data.command_success(conn, qh, output), - Event::Failure { failure_message } => data.command_success(conn, qh, failure_message), - } - } -} diff --git a/src/river_protocols/status.rs b/src/river_protocols/status.rs index 079572a..1779719 100644 --- a/src/river_protocols/status.rs +++ b/src/river_protocols/status.rs @@ -1,46 +1,29 @@ -pub mod protocol { - use smithay_client_toolkit::reexports::client as wayland_client; - use smithay_client_toolkit::reexports::client::protocol::*; - - pub mod __interfaces { - use smithay_client_toolkit::reexports::client::protocol::__interfaces::*; - wayland_scanner::generate_interfaces!("protocols/river-status-unstable-v1.xml"); - } - use self::__interfaces::*; - - wayland_scanner::generate_client_code!("protocols/river-status-unstable-v1.xml"); -} - -mod dispatch; - use std::sync::{Arc, Weak}; -use smithay_client_toolkit::globals::GlobalData; -use wayland_client::{protocol::wl_output, Connection, Dispatch, QueueHandle}; +use wayland_client::{ + globals::{BindError, GlobalList}, + protocol::wl_output, + Connection, Dispatch, QueueHandle, +}; use protocol::{zriver_output_status_v1, zriver_status_manager_v1}; -use smithay_client_toolkit::error::GlobalError; -use smithay_client_toolkit::registry::GlobalProxy; - -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct RiverStatusState { - status_manager: GlobalProxy, + status_manager: zriver_status_manager_v1::ZriverStatusManagerV1, output_statuses: Vec>, } impl RiverStatusState { - pub fn new() -> Self { - Self { - status_manager: GlobalProxy::NotReady, + pub fn new(globals: &GlobalList, qh: &QueueHandle) -> Result + where + D: Dispatch + 'static, + { + let status_manager = globals.bind(qh, 1..=1, ())?; + Ok(Self { + status_manager, output_statuses: Vec::new(), - } - } - - pub fn status_manager( - &self, - ) -> Result<&zriver_status_manager_v1::ZriverStatusManagerV1, GlobalError> { - self.status_manager.get() + }) } pub fn get_output_status( @@ -59,14 +42,15 @@ impl RiverStatusState { &mut self, qh: &QueueHandle, output: &wl_output::WlOutput, - ) -> Result + ) -> RiverOutputStatus where - D: Dispatch + D: Dispatch + Dispatch + 'static, { - let manager = self.status_manager()?; - let output_status = manager.get_river_output_status(output, qh, RiverStatusData {}); + let output_status = + self.status_manager + .get_river_output_status(output, qh, RiverStatusData {}); let output_status = RiverOutputStatus(Arc::new(OutputStatusInner { status: output_status, @@ -74,7 +58,7 @@ impl RiverStatusState { self.output_statuses.push(Arc::downgrade(&output_status.0)); - Ok(output_status) + output_status } } @@ -124,7 +108,7 @@ pub struct RiverStatusData { macro_rules! delegate_river_status { ($ty: ty) => { ::smithay_client_toolkit::reexports::client::delegate_dispatch!($ty: [ - $crate::river_protocols::status::protocol::zriver_status_manager_v1::ZriverStatusManagerV1: ::smithay_client_toolkit::globals::GlobalData + $crate::river_protocols::status::protocol::zriver_status_manager_v1::ZriverStatusManagerV1: () ] => $crate::river_protocols::status::RiverStatusState); ::smithay_client_toolkit::reexports::client::delegate_dispatch!($ty: [ $crate::river_protocols::status::protocol::zriver_output_status_v1::ZriverOutputStatusV1: $crate::river_protocols::status::RiverStatusData @@ -142,3 +126,72 @@ impl Drop for OutputStatusInner { self.status.destroy(); } } + +impl Dispatch for RiverStatusState +where + D: Dispatch + RiverStatusHandler + 'static, +{ + fn event( + _: &mut D, + _: &zriver_status_manager_v1::ZriverStatusManagerV1, + _: zriver_status_manager_v1::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + unreachable!("zriver_status_manager_v1 has no events") + } +} + +impl Dispatch + for RiverStatusState +where + D: Dispatch + + RiverStatusHandler + + 'static, +{ + fn event( + data: &mut D, + status: &zriver_output_status_v1::ZriverOutputStatusV1, + event: zriver_output_status_v1::Event, + _udata: &RiverStatusData, + conn: &Connection, + qh: &QueueHandle, + ) { + use zriver_output_status_v1::Event; + + // Remove any statuses that have been dropped + data.river_status_state() + .output_statuses + .retain(|status| status.upgrade().is_some()); + + if let Some(status) = data.river_status_state().get_output_status(status) { + match event { + Event::FocusedTags { tags } => data.focused_tags_updated(conn, qh, &status, tags), + Event::UrgentTags { tags } => data.urgent_tags_updated(conn, qh, &status, tags), + Event::ViewTags { tags } => { + let tags = tags + .chunks_exact(4) + .map(|bytes| u32::from_ne_bytes(bytes.try_into().unwrap())) + .collect(); + data.views_tags_updated(conn, qh, &status, tags); + } + } + } + } +} + +pub mod protocol { + #![allow(non_upper_case_globals)] + + use smithay_client_toolkit::reexports::client as wayland_client; + use smithay_client_toolkit::reexports::client::protocol::*; + + pub mod __interfaces { + use smithay_client_toolkit::reexports::client::protocol::__interfaces::*; + wayland_scanner::generate_interfaces!("protocols/river-status-unstable-v1.xml"); + } + use self::__interfaces::*; + + wayland_scanner::generate_client_code!("protocols/river-status-unstable-v1.xml"); +} diff --git a/src/river_protocols/status/dispatch.rs b/src/river_protocols/status/dispatch.rs deleted file mode 100644 index 65d6e0c..0000000 --- a/src/river_protocols/status/dispatch.rs +++ /dev/null @@ -1,92 +0,0 @@ -use super::protocol::{zriver_output_status_v1, zriver_status_manager_v1}; -use wayland_client::{Connection, Dispatch, QueueHandle}; - -use smithay_client_toolkit::{ - error::GlobalError, - globals::{GlobalData, ProvidesBoundGlobal}, - registry::{ProvidesRegistryState, RegistryHandler}, -}; - -use super::{RiverStatusData, RiverStatusHandler, RiverStatusState}; - -impl RegistryHandler for RiverStatusState -where - D: Dispatch - + RiverStatusHandler - + ProvidesRegistryState - + 'static, -{ - fn ready(data: &mut D, _conn: &Connection, qh: &QueueHandle) { - data.river_status_state().status_manager = - data.registry().bind_one(qh, 1..=2, GlobalData).into(); - } -} - -impl ProvidesBoundGlobal for RiverStatusState { - fn bound_global(&self) -> Result { - self.status_manager.get().cloned() - } -} - -impl ProvidesBoundGlobal for RiverStatusState { - fn bound_global(&self) -> Result { - self.status_manager.get().cloned() - } -} - -impl Dispatch - for RiverStatusState -where - D: Dispatch - + RiverStatusHandler - + 'static, -{ - fn event( - _: &mut D, - _: &zriver_status_manager_v1::ZriverStatusManagerV1, - _: zriver_status_manager_v1::Event, - _: &GlobalData, - _: &Connection, - _: &QueueHandle, - ) { - unreachable!("zriver_status_manager_v1 has no events") - } -} - -impl Dispatch - for RiverStatusState -where - D: Dispatch - + RiverStatusHandler - + 'static, -{ - fn event( - data: &mut D, - status: &zriver_output_status_v1::ZriverOutputStatusV1, - event: zriver_output_status_v1::Event, - _udata: &RiverStatusData, - conn: &Connection, - qh: &QueueHandle, - ) { - use zriver_output_status_v1::Event; - - // Remove any statuses that have been dropped - data.river_status_state() - .output_statuses - .retain(|status| status.upgrade().is_some()); - - if let Some(status) = data.river_status_state().get_output_status(status) { - match event { - Event::FocusedTags { tags } => data.focused_tags_updated(conn, qh, &status, tags), - Event::UrgentTags { tags } => data.urgent_tags_updated(conn, qh, &status, tags), - Event::ViewTags { tags } => { - let tags = tags - .chunks_exact(4) - .map(|bytes| u32::from_ne_bytes(bytes.try_into().unwrap())) - .collect(); - data.views_tags_updated(conn, qh, &status, tags); - } - } - } - } -} diff --git a/src/state.rs b/src/state.rs index 3d5b2d4..ed6c3d1 100644 --- a/src/state.rs +++ b/src/state.rs @@ -12,13 +12,16 @@ use smithay_client_toolkit::{ registry::{ProvidesRegistryState, RegistryState}, registry_handlers, seat::{ - pointer::{PointerEvent, PointerEventKind, PointerHandler}, + pointer::{PointerEvent, PointerEventKind, PointerHandler, ThemeSpec, ThemedPointer}, Capability, SeatHandler, SeatState, }, - shell::layer::{Anchor, Layer, LayerHandler, LayerState, LayerSurface, LayerSurfaceConfigure}, + shell::layer::{ + Anchor, Layer, LayerShell, LayerShellHandler, LayerSurface, LayerSurfaceConfigure, + }, shm::{ShmHandler, ShmState}, }; use tokio::io::unix::AsyncFdReadyGuard; +use wayland_client::globals::GlobalList; use crate::{ bar::Bar, @@ -40,9 +43,9 @@ pub struct State { seat_state: SeatState, output_state: OutputState, compositor_state: CompositorState, - layer_state: LayerState, - river_status_state: RiverStatusState, - river_control_state: RiverControlState, + layer_state: LayerShell, + river_status_state: Option, + river_control_state: Option, seats: Vec, bars: Vec, @@ -52,13 +55,17 @@ pub struct State { struct Seat { seat: wl_seat::WlSeat, pointer: wl_pointer::WlPointer, + themed_pointer: ThemedPointer, + pointer_surface: wl_surface::WlSurface, finger_scroll: f64, } impl State { - pub fn new(conn: &Connection, event_queue: &mut EventQueue) -> Self { + pub fn new(event_queue: &mut EventQueue, globals: &GlobalList) -> Self { let mut error = Ok(()); + let qh = event_queue.handle(); + let config = Config::new() .map_err(|e| error = Err(e)) .unwrap_or_default(); @@ -73,19 +80,19 @@ impl State { }; let mut this = Self { - registry_state: RegistryState::new(conn, &event_queue.handle()), - seat_state: SeatState::new(), - output_state: OutputState::new(), - compositor_state: CompositorState::new(), - layer_state: LayerState::new(), - river_status_state: RiverStatusState::new(), - river_control_state: RiverControlState::new(), + registry_state: RegistryState::new(globals), + seat_state: SeatState::new(globals, &qh), + output_state: OutputState::new(globals, &qh), + compositor_state: CompositorState::bind(globals, &qh).unwrap(), + layer_state: LayerShell::bind(globals, &qh).unwrap(), + river_status_state: RiverStatusState::new(globals, &qh).ok(), + river_control_state: RiverControlState::new(globals, &qh).ok(), seats: Vec::new(), bars: Vec::new(), shared_state: SharedState { qh: event_queue.handle(), - shm_state: ShmState::new(), + shm_state: ShmState::bind(globals, &qh).unwrap(), pool: None, config, status_cmd, @@ -140,10 +147,6 @@ impl State { } impl CompositorHandler for State { - fn compositor_state(&mut self) -> &mut CompositorState { - &mut self.compositor_state - } - fn scale_factor_changed( &mut self, _conn: &Connection, @@ -191,7 +194,10 @@ impl OutputHandler for State { .namespace("i3bar-river") .map(qh, &self.layer_state, surface, Layer::Top) .expect("layer surface creation"); - let river_output_status = self.river_status_state.new_output_status(qh, &output).ok(); + let river_output_status = self + .river_status_state + .as_mut() + .map(|s| s.new_output_status(qh, &output)); self.bars.push(Bar { configured: false, width: 0, @@ -224,11 +230,7 @@ impl OutputHandler for State { } } -impl LayerHandler for State { - fn layer_state(&mut self) -> &mut LayerState { - &mut self.layer_state - } - +impl LayerShellHandler for State { fn closed(&mut self, _conn: &Connection, _qh: &QueueHandle, layer: &LayerSurface) { self.bars.retain(|b| &b.layer != layer) } @@ -264,13 +266,15 @@ impl SeatHandler for State { capability: Capability, ) { if capability == Capability::Pointer { - let pointer = self + let (pointer, themed_pointer) = self .seat_state - .get_pointer(qh, &seat) + .get_pointer_with_theme(qh, &seat, ThemeSpec::System, 1) .expect("Failed to create pointer"); self.seats.push(Seat { seat, pointer, + themed_pointer, + pointer_surface: self.compositor_state.create_surface(qh).unwrap(), // TODO: make a PR to remove this unwrap finger_scroll: 0.0, }); } @@ -294,7 +298,7 @@ impl SeatHandler for State { impl PointerHandler for State { fn pointer_frame( &mut self, - _conn: &Connection, + conn: &Connection, _qh: &QueueHandle, pointer: &wl_pointer::WlPointer, events: &[PointerEvent], @@ -312,7 +316,14 @@ impl PointerHandler for State { { match event.kind { PointerEventKind::Enter { .. } => { - // TODO: set_cursor() + seat.themed_pointer + .set_cursor( + conn, + "default", + self.shared_state.shm_state.wl_shm(), + &seat.pointer_surface, + ) + .unwrap(); } PointerEventKind::Press { button, .. } => { bar.click( @@ -376,7 +387,7 @@ impl ShmHandler for State { impl RiverStatusHandler for State { fn river_status_state(&mut self) -> &mut RiverStatusState { - &mut self.river_status_state + self.river_status_state.as_mut().unwrap() } fn focused_tags_updated( @@ -430,7 +441,7 @@ impl RiverStatusHandler for State { impl RiverControlHandler for State { fn river_control_state(&mut self) -> &mut RiverControlState { - &mut self.river_control_state + self.river_control_state.as_mut().unwrap() } fn command_failure(&mut self, _: &Connection, _: &QueueHandle, message: String) { @@ -456,15 +467,7 @@ impl ProvidesRegistryState for State { fn registry(&mut self) -> &mut RegistryState { &mut self.registry_state } - registry_handlers![ - CompositorState, - OutputState, - ShmState, - SeatState, - LayerState, - RiverStatusState, - RiverControlState, - ]; + registry_handlers![OutputState,]; } #[derive(Debug)] diff --git a/src/text.rs b/src/text.rs index 7a3b7fc..9b27a11 100644 --- a/src/text.rs +++ b/src/text.rs @@ -49,7 +49,7 @@ pub struct ComputedText { impl ComputedText { pub fn new(text: &str, mut attr: Attributes, context: &cairo::Context) -> Self { - let layout = pangocairo::create_layout(context).unwrap(); + let layout = pangocairo::create_layout(context); layout.set_font_description(Some(attr.font)); if attr.markup { layout.set_markup(text); -- cgit v1.3.1