Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

seat/pointer: simplify ThemedPointer handling #380

Merged
merged 1 commit into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## Unreleased

#### Breaking Changes

- `ThemedPointer::set_cursor` now takes only `Connection` and `&str`.
- `SeatState:get_pointer_with_them*` now takes `Shm` and `WlSurface` for the themed cursor.
- `ThemedPointer` now automatically releases the associated `WlPointer`.
- `CursorIcon` from `cursor-icon` crate is now used for `set_cursor` and `Frame`.

## 0.17.0 - 2023-03-28

#### Breaking Changes
Expand Down
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
bitflags = "1.0"
nix = { version = "0.26.1", default-features = false, features = ["fs", "mman"] }
cursor-icon = "1.0.0"
dlib = "0.5"
lazy_static = "1.0"
memmap2 = "0.5.0"
log = "0.4"
memmap2 = "0.5.0"
nix = { version = "0.26.1", default-features = false, features = ["fs", "mman"] }
thiserror = "1.0.30"
wayland-backend = "0.1.0"
wayland-client = "0.30.1"
wayland-cursor = "0.30.0"
wayland-protocols = { version = "0.30.0", features = ["client", "unstable"] }
wayland-protocols-wlr = { version = "0.1.0", features = ["client"] }
wayland-cursor = "0.30.0"
wayland-scanner = "0.30.0"

xkbcommon = { version = "0.5", optional = true, features = ["wayland"] }
Expand Down
123 changes: 78 additions & 45 deletions examples/themed_window.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::sync::Arc;
use std::{convert::TryInto, num::NonZeroU32};

use smithay_client_toolkit::seat::keyboard::keysyms;
use smithay_client_toolkit::{
compositor::{CompositorHandler, CompositorState},
delegate_compositor, delegate_keyboard, delegate_output, delegate_pointer, delegate_registry,
Expand All @@ -11,7 +12,8 @@ use smithay_client_toolkit::{
seat::{
keyboard::{KeyEvent, KeyboardHandler, Modifiers},
pointer::{
PointerData, PointerEvent, PointerEventKind, PointerHandler, ThemeSpec, ThemedPointer,
CursorIcon, PointerData, PointerEvent, PointerEventKind, PointerHandler, ThemeSpec,
ThemedPointer,
},
Capability, SeatHandler, SeatState,
},
Expand All @@ -36,6 +38,44 @@ use wayland_client::{
Connection, Proxy, QueueHandle,
};

// Cursor shapes.
const CURSORS: &[CursorIcon] = &[
CursorIcon::Default,
CursorIcon::Crosshair,
CursorIcon::Pointer,
CursorIcon::Move,
CursorIcon::Text,
CursorIcon::Wait,
CursorIcon::Help,
CursorIcon::Progress,
CursorIcon::NotAllowed,
CursorIcon::ContextMenu,
CursorIcon::Cell,
CursorIcon::VerticalText,
CursorIcon::Alias,
CursorIcon::Copy,
CursorIcon::NoDrop,
CursorIcon::Grab,
CursorIcon::Grabbing,
CursorIcon::AllScroll,
CursorIcon::ZoomIn,
CursorIcon::ZoomOut,
CursorIcon::EResize,
CursorIcon::NResize,
CursorIcon::NeResize,
CursorIcon::NwResize,
CursorIcon::SResize,
CursorIcon::SeResize,
CursorIcon::SwResize,
CursorIcon::WResize,
CursorIcon::EwResize,
CursorIcon::NsResize,
CursorIcon::NeswResize,
CursorIcon::NwseResize,
CursorIcon::ColResize,
CursorIcon::RowResize,
];

fn main() {
env_logger::init();

Expand All @@ -60,7 +100,6 @@ fn main() {
.expect("Failed to create pool");

let window_surface = compositor_state.create_surface(&qh);
let pointer_surface = compositor_state.create_surface(&qh);

let window =
xdg_shell_state.create_window(window_surface, WindowDecorations::ServerDefault, &qh);
Expand All @@ -76,11 +115,13 @@ fn main() {
// the correct options.
window.commit();

println!("Press `n` to cycle through cursor icons.");

let mut simple_window = SimpleWindow {
registry_state,
seat_state,
output_state,
_compositor_state: compositor_state,
compositor_state,
subcompositor_state: Arc::new(subcompositor_state),
shm_state,
_xdg_shell_state: xdg_shell_state,
Expand All @@ -94,21 +135,20 @@ fn main() {
buffer: None,
window,
window_frame: None,
pointer_surface,
keyboard: None,
keyboard_focus: false,
themed_pointer: None,
set_cursor: false,
cursor_icon: String::from("diamond_cross"),
window_cursor_icon_idx: 0,
decorations_cursor: None,
};

// We don't draw immediately, the configure will notify us when to first draw.

loop {
event_queue.blocking_dispatch(&mut simple_window).unwrap();

if simple_window.exit {
println!("exiting example");
println!("Exiting example.");
break;
}
}
Expand All @@ -118,7 +158,7 @@ struct SimpleWindow {
registry_state: RegistryState,
seat_state: SeatState,
output_state: OutputState,
_compositor_state: CompositorState,
compositor_state: CompositorState,
subcompositor_state: Arc<SubcompositorState>,
shm_state: Shm,
_xdg_shell_state: XdgShell,
Expand All @@ -132,12 +172,12 @@ struct SimpleWindow {
buffer: Option<Buffer>,
window: Window,
window_frame: Option<FallbackFrame<Self>>,
pointer_surface: wl_surface::WlSurface,
keyboard: Option<wl_keyboard::WlKeyboard>,
keyboard_focus: bool,
themed_pointer: Option<ThemedPointer>,
set_cursor: bool,
cursor_icon: String,
window_cursor_icon_idx: usize,
decorations_cursor: Option<CursorIcon>,
}

impl CompositorHandler for SimpleWindow {
Expand Down Expand Up @@ -247,7 +287,7 @@ impl WindowHandler for SimpleWindow {
let width = width.unwrap_or(NonZeroU32::new(1).unwrap());
let height = height.unwrap_or(NonZeroU32::new(1).unwrap());

println!("{width}, {height}");
println!("New dimentions: {width}, {height}");
window_frame.resize(width, height);

let (x, y) = window_frame.location();
Expand Down Expand Up @@ -311,10 +351,16 @@ impl SeatHandler for SimpleWindow {

if capability == Capability::Pointer && self.themed_pointer.is_none() {
println!("Set pointer capability");
println!("Creating pointer theme");
let surface = self.compositor_state.create_surface(qh);
let themed_pointer = self
.seat_state
.get_pointer_with_theme(qh, &seat, ThemeSpec::default())
.get_pointer_with_theme(
qh,
&seat,
self.shm_state.wl_shm(),
surface,
ThemeSpec::default(),
)
.expect("Failed to create pointer");
self.themed_pointer.replace(themed_pointer);
}
Expand Down Expand Up @@ -367,7 +413,6 @@ impl KeyboardHandler for SimpleWindow {
_: u32,
) {
if self.window.wl_surface() == surface {
println!("Release keyboard focus on window");
self.keyboard_focus = false;
}
}
Expand All @@ -380,7 +425,12 @@ impl KeyboardHandler for SimpleWindow {
_: u32,
event: KeyEvent,
) {
println!("Key press: {event:?}");
if event.keysym == keysyms::XKB_KEY_n {
// Cycle through cursor icons.
self.window_cursor_icon_idx = (self.window_cursor_icon_idx + 1) % CURSORS.len();
println!("Setting cursor icon to: {}", CURSORS[self.window_cursor_icon_idx].name());
self.set_cursor = true;
}
}

fn release_key(
Expand All @@ -389,9 +439,8 @@ impl KeyboardHandler for SimpleWindow {
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_: u32,
event: KeyEvent,
_: KeyEvent,
) {
println!("Key release: {event:?}");
}

fn update_modifiers(
Expand All @@ -400,9 +449,8 @@ impl KeyboardHandler for SimpleWindow {
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_serial: u32,
modifiers: Modifiers,
_: Modifiers,
) {
println!("Update modifiers: {modifiers:?}");
}
}

Expand All @@ -420,24 +468,17 @@ impl PointerHandler for SimpleWindow {
match event.kind {
Enter { .. } => {
self.set_cursor = true;
self.cursor_icon = self
self.decorations_cursor = self
.window_frame
.as_mut()
.and_then(|frame| frame.click_point_moved(&event.surface, x, y))
.unwrap_or("diamond_cross")
.to_owned();

if &event.surface == self.window.wl_surface() {
println!("Pointer entered @{:?}", event.position);
}
.and_then(|frame| frame.click_point_moved(&event.surface, x, y));
}
Leave { .. } => {
if &event.surface != self.window.wl_surface() {
if let Some(window_frame) = self.window_frame.as_mut() {
window_frame.click_point_left();
}
}
println!("Pointer left");
}
Motion { .. } => {
if let Some(new_cursor) = self
Expand All @@ -446,11 +487,11 @@ impl PointerHandler for SimpleWindow {
.and_then(|frame| frame.click_point_moved(&event.surface, x, y))
{
self.set_cursor = true;
self.cursor_icon = new_cursor.to_owned();
self.decorations_cursor = Some(new_cursor);
}
}
Press { button, serial, .. } | Release { button, serial, .. } => {
let pressed = if matches!(event.kind, Press { .. }) { true } else { false };
let pressed = matches!(event.kind, Press { .. });
if &event.surface != self.window.wl_surface() {
let click = match button {
0x110 => FrameClick::Normal,
Expand All @@ -466,19 +507,15 @@ impl PointerHandler for SimpleWindow {
self.frame_action(pointer, serial, action);
}
} else if pressed {
println!("Press {:x} @ {:?}", button, event.position);
self.shift = self.shift.xor(Some(0));
}
}
Axis { horizontal, vertical, .. } => {
if &event.surface == self.window.wl_surface() {
println!("Scroll H:{horizontal:?}, V:{vertical:?}");
}
}
Axis { .. } => {}
}
}
}
}

impl SimpleWindow {
fn frame_action(&mut self, pointer: &wl_pointer::WlPointer, serial: u32, action: FrameAction) {
let pointer_data = pointer.data::<PointerData>().unwrap();
Expand All @@ -504,13 +541,9 @@ impl ShmHandler for SimpleWindow {
impl SimpleWindow {
pub fn draw(&mut self, conn: &Connection, qh: &QueueHandle<Self>) {
if self.set_cursor {
let _ = self.themed_pointer.as_mut().unwrap().set_cursor(
conn,
&self.cursor_icon,
self.shm_state.wl_shm(),
&self.pointer_surface,
1,
);
let cursor_icon =
self.decorations_cursor.unwrap_or(CURSORS[self.window_cursor_icon_idx]);
let _ = self.themed_pointer.as_mut().unwrap().set_cursor(conn, cursor_icon);
self.set_cursor = false;
}

Expand Down Expand Up @@ -562,11 +595,11 @@ impl SimpleWindow {
}

// Draw the decorations frame.
self.window_frame.as_mut().map(|frame| {
if let Some(frame) = self.window_frame.as_mut() {
if frame.is_dirty() && !frame.is_hidden() {
frame.draw();
}
});
}

// Damage the entire window
self.window.wl_surface().damage_buffer(0, 0, width as i32, height as i32);
Expand Down
Loading