Skip to content

Commit

Permalink
Support pointer actions
Browse files Browse the repository at this point in the history
  • Loading branch information
l4l committed Jul 11, 2024
1 parent e9c86d5 commit 5673677
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 9 deletions.
8 changes: 8 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub struct Config {

input_text: InputText,
list_items: ListItems,
mouse: Mouse,
}

impl Config {
Expand Down Expand Up @@ -111,6 +112,13 @@ struct Icon {
fallback_icon_path: Option<PathBuf>,
}

#[derive(Defaults, Deserialize)]
#[serde(default)]
struct Mouse {
launch_on_middle: bool,
wheel_scroll_multiplier: f64,
}

fn default_config_path() -> Result<Option<PathBuf>> {
let file = xdg::BaseDirectories::with_prefix(crate::prog_name!())
.context("failed to get xdg dirs")?
Expand Down
11 changes: 10 additions & 1 deletion src/config/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::desktop::IconConfig;
use crate::draw::{BgParams, InputTextParams, ListParams};
use crate::font::{Font, FontBackend, InnerFont};
use crate::icon::Icon;
use crate::window::Params as WindowParams;
use crate::window::{Params as WindowParams, PointerParams};

macro_rules! select_conf {
($config:ident, $inner:ident, $field:ident) => {
Expand Down Expand Up @@ -123,6 +123,15 @@ impl<'a> From<&'a Config> for Option<IconConfig> {
}
}

impl<'a> From<&'a Config> for PointerParams {
fn from(config: &'a Config) -> Self {
Self {
launch_on_middle: config.mouse.launch_on_middle,
wheel_scroll_multiplier: config.mouse.wheel_scroll_multiplier,
}
}
}

fn default_font() -> Font {
std::thread_local! {
static DEFAULT_FONT: Lazy<Font> = Lazy::new(|| Rc::new(InnerFont::default()));
Expand Down
23 changes: 18 additions & 5 deletions src/window.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use anyhow::Context;
use sctk::{
delegate_compositor, delegate_keyboard, delegate_layer, delegate_output, delegate_registry,
delegate_seat, delegate_shm, delegate_xdg_shell, delegate_xdg_window,
delegate_compositor, delegate_keyboard, delegate_layer, delegate_output, delegate_pointer,
delegate_registry, delegate_seat, delegate_shm, delegate_xdg_shell, delegate_xdg_window,
output::OutputState,
reexports::client::{
protocol::{wl_keyboard::WlKeyboard, wl_surface::WlSurface},
protocol::{wl_keyboard::WlKeyboard, wl_pointer::WlPointer, wl_surface::WlSurface},
*,
},
reexports::{
Expand All @@ -25,11 +25,13 @@ use sctk::{
};

use crate::state::State;
pub use pointer::Params as PointerParams;

mod compositor;
mod keyboard;
mod layer_shell;
mod output;
mod pointer;
mod registry;
mod seat;
mod shm;
Expand Down Expand Up @@ -60,15 +62,21 @@ pub struct Window {
height: u32,
scale: u16,

keyboard: Option<WlKeyboard>,
input: InputSource,
key_modifiers: sctk::seat::keyboard::Modifiers,
wheel_scroll_pending: f64,

loop_handle: LoopHandle<'static, Window>,
exit: bool,

error: Option<anyhow::Error>,
}

struct InputSource {
keyboard: Option<WlKeyboard>,
pointer: Option<WlPointer>,
}

enum RenderSurface {
Xdg(xdg_win::Window),
LayerShell(wlr_layer::LayerSurface),
Expand Down Expand Up @@ -159,8 +167,12 @@ impl Window {
width,
height,
scale,
keyboard: None,
input: InputSource {
keyboard: None,
pointer: None,
},
key_modifiers: Default::default(),
wheel_scroll_pending: 0.0,
loop_handle: event_loop.handle(),
exit: false,
error: None,
Expand Down Expand Up @@ -276,3 +288,4 @@ delegate_xdg_shell!(Window);
delegate_layer!(Window);
delegate_xdg_window!(Window);
delegate_registry!(Window);
delegate_pointer!(Window);
107 changes: 107 additions & 0 deletions src/window/pointer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use sctk::reexports::client::protocol::wl_pointer::AxisSource;
use sctk::reexports::client::{protocol, Connection, QueueHandle};
use sctk::seat::keyboard::Modifiers;
use sctk::seat::pointer::{PointerEvent, PointerEventKind, PointerHandler, *};

use super::Window;

// According to https://wayland.freedesktop.org/libinput/doc/1.19.0/wheel-api.html
// wheel typically has this angle per step.
// This actually should be configured and auto-detected (from udev probably?) but
// for now it should work for most cases and could be tuned via config.
const SCROLL_PER_STEP: f64 = 15.0;

pub struct Params {
pub launch_on_middle: bool,
pub wheel_scroll_multiplier: f64,
}

impl PointerHandler for Window {
fn pointer_frame(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_pointer: &protocol::wl_pointer::WlPointer,
events: &[PointerEvent],
) {
let mut changed = false;
let config = self.config.param::<Params>();

for event in events {
// Ignore events for other surfaces
if event.surface != *self.surface {
continue;
}

match event.kind {
// TODO: implement precise clicks on items
// PointerEventKind::Release {
// button: BTN_LEFT, ..
// } => ..,
PointerEventKind::Release {
button: BTN_MIDDLE, ..
} if config.launch_on_middle => {
let with_fork = matches!(self.key_modifiers, Modifiers { ctrl: true, .. });
if let Err(err) = self.state.eval_input(with_fork) {
self.error = Some(err);
}
}
PointerEventKind::Release {
button: BTN_RIGHT, ..
} => self.exit = true,
PointerEventKind::Release {
button: BTN_BACK, ..
} => self.state.prev_subitem(),
PointerEventKind::Release {
button: BTN_FORWARD,
..
} => self.state.next_subitem(),
PointerEventKind::Axis {
vertical:
AxisScroll {
absolute,
discrete: _,
// XXX: handle this one?
stop: _,
},
source:
Some(AxisSource::Wheel)
| Some(AxisSource::Finger)
| Some(AxisSource::Continuous),
time: _,
horizontal: _,
} => {
self.wheel_scroll_pending += absolute;
}
PointerEventKind::Enter { .. }
| PointerEventKind::Leave { .. }
| PointerEventKind::Motion { .. }
| PointerEventKind::Press { .. }
| PointerEventKind::Release { .. }
| PointerEventKind::Axis { .. } => continue,
}
changed = true;
}

if changed {
let scroll_per_step = SCROLL_PER_STEP
* if config.wheel_scroll_multiplier > 0.0 {
config.wheel_scroll_multiplier
} else {
1.0
};
let wheel_steps = (self.wheel_scroll_pending / scroll_per_step) as i32;
if wheel_steps != 0 {
self.wheel_scroll_pending -= f64::from(wheel_steps) * scroll_per_step;
}
let is_wheel_down = wheel_steps > 0;
for _ in 0..wheel_steps.abs() {
if is_wheel_down {
self.state.next_item();
} else {
self.state.prev_item();
}
}
}
}
}
11 changes: 8 additions & 3 deletions src/window/seat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl SeatHandler for Window {
capability: Capability,
) {
match capability {
Capability::Keyboard if self.keyboard.is_none() => {
Capability::Keyboard if self.input.keyboard.is_none() => {
let wl_keyboard = match self.seat_state.get_keyboard_with_repeat(
qh,
&seat,
Expand All @@ -32,7 +32,12 @@ impl SeatHandler for Window {
return;
}
};
self.keyboard = Some(wl_keyboard);
self.input.keyboard = Some(wl_keyboard);
}
Capability::Pointer if self.input.pointer.is_none() => {
if let Ok(p) = self.seat_state.get_pointer(qh, &seat) {
self.input.pointer = Some(p);
}
}
_ => {}
}
Expand All @@ -46,7 +51,7 @@ impl SeatHandler for Window {
capability: Capability,
) {
if let Capability::Keyboard = capability {
if let Some(k) = self.keyboard.take() {
if let Some(k) = self.input.keyboard.take() {
k.release();
}
}
Expand Down

0 comments on commit 5673677

Please sign in to comment.