feat: add Phase 1 interaction protocols
This commit is contained in:
1 parent
a941b80aa9
commit
37550f447d
8 files changed
+169
-6
No files matched your search
Generated
+1
@@ -368,6 +368,7 @@ checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
|||||||
name = "ferese"
|
name = "ferese"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"libc",
|
||||||
"smithay",
|
"smithay",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
|||||||
+1
-1
@@ -9,6 +9,7 @@ license = "MIT"
|
|||||||
rust-version = "1.87"
|
rust-version = "1.87"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
libc = "0.2.176"
|
||||||
smithay = { version = "0.7.0", default-features = false, features = [
|
smithay = { version = "0.7.0", default-features = false, features = [
|
||||||
"backend_winit",
|
"backend_winit",
|
||||||
"desktop",
|
"desktop",
|
||||||
@@ -16,4 +17,3 @@ smithay = { version = "0.7.0", default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@ license.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
libc.workspace = true
|
||||||
smithay.workspace = true
|
smithay.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use smithay::{
|
||||||
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
|
utils::SERIAL_COUNTER,
|
||||||
|
wayland::xdg_activation::{
|
||||||
|
XdgActivationHandler, XdgActivationState, XdgActivationToken, XdgActivationTokenData,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::Ferese;
|
||||||
|
|
||||||
|
const TOKEN_MAX_AGE: Duration = Duration::from_secs(10);
|
||||||
|
|
||||||
|
impl XdgActivationHandler for Ferese {
|
||||||
|
fn activation_state(&mut self) -> &mut XdgActivationState {
|
||||||
|
&mut self.xdg_activation_state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn token_created(&mut self, _token: XdgActivationToken, data: XdgActivationTokenData) -> bool {
|
||||||
|
data.serial.is_some() && data.timestamp.elapsed() <= TOKEN_MAX_AGE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_activation(
|
||||||
|
&mut self,
|
||||||
|
token: XdgActivationToken,
|
||||||
|
data: XdgActivationTokenData,
|
||||||
|
surface: WlSurface,
|
||||||
|
) {
|
||||||
|
let valid = data.serial.is_some() && data.timestamp.elapsed() <= TOKEN_MAX_AGE;
|
||||||
|
self.xdg_activation_state.remove_token(&token);
|
||||||
|
if !valid {
|
||||||
|
tracing::debug!("ignored stale or non-interactive activation request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(window) = self
|
||||||
|
.space
|
||||||
|
.elements()
|
||||||
|
.find(|window| {
|
||||||
|
window
|
||||||
|
.toplevel()
|
||||||
|
.is_some_and(|toplevel| toplevel.wl_surface() == &surface)
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.space.raise_element(&window, true);
|
||||||
|
let keyboard = self.seat.get_keyboard().expect("seat has a keyboard");
|
||||||
|
keyboard.set_focus(self, Some(surface), SERIAL_COUNTER.next_serial());
|
||||||
|
self.space.elements().for_each(|window| {
|
||||||
|
if let Some(toplevel) = window.toplevel() {
|
||||||
|
toplevel.send_pending_configure();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,18 @@
|
|||||||
|
mod activation;
|
||||||
mod compositor;
|
mod compositor;
|
||||||
mod xdg_shell;
|
mod xdg_shell;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
input::{Seat, SeatHandler, SeatState, pointer::CursorImageStatus},
|
input::{
|
||||||
|
Seat, SeatHandler, SeatState,
|
||||||
|
pointer::{CursorImageStatus, PointerHandle},
|
||||||
|
},
|
||||||
reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface},
|
reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface},
|
||||||
wayland::{
|
wayland::{
|
||||||
|
compositor::with_states,
|
||||||
|
fractional_scale::{FractionalScaleHandler, with_fractional_scale},
|
||||||
output::OutputHandler,
|
output::OutputHandler,
|
||||||
|
pointer_constraints::{PointerConstraintsHandler, with_pointer_constraint},
|
||||||
selection::{
|
selection::{
|
||||||
SelectionHandler,
|
SelectionHandler,
|
||||||
data_device::{
|
data_device::{
|
||||||
@@ -41,6 +48,37 @@ impl SeatHandler for Ferese {
|
|||||||
|
|
||||||
impl OutputHandler for Ferese {}
|
impl OutputHandler for Ferese {}
|
||||||
|
|
||||||
|
impl FractionalScaleHandler for Ferese {
|
||||||
|
fn new_fractional_scale(&mut self, surface: WlSurface) {
|
||||||
|
with_states(&surface, |states| {
|
||||||
|
with_fractional_scale(states, |scale| scale.set_preferred_scale(1.0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerConstraintsHandler for Ferese {
|
||||||
|
fn new_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle<Self>) {
|
||||||
|
let focused = pointer
|
||||||
|
.current_focus()
|
||||||
|
.is_some_and(|focused| focused == *surface);
|
||||||
|
if focused {
|
||||||
|
with_pointer_constraint(surface, pointer, |constraint| {
|
||||||
|
if let Some(constraint) = constraint {
|
||||||
|
constraint.activate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cursor_position_hint(
|
||||||
|
&mut self,
|
||||||
|
_surface: &WlSurface,
|
||||||
|
_pointer: &PointerHandle<Self>,
|
||||||
|
_location: smithay::utils::Point<f64, smithay::utils::Logical>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SelectionHandler for Ferese {
|
impl SelectionHandler for Ferese {
|
||||||
type SelectionUserData = ();
|
type SelectionUserData = ();
|
||||||
}
|
}
|
||||||
@@ -62,9 +100,15 @@ impl PrimarySelectionHandler for Ferese {
|
|||||||
|
|
||||||
smithay::delegate_compositor!(Ferese);
|
smithay::delegate_compositor!(Ferese);
|
||||||
smithay::delegate_data_device!(Ferese);
|
smithay::delegate_data_device!(Ferese);
|
||||||
|
smithay::delegate_fractional_scale!(Ferese);
|
||||||
smithay::delegate_output!(Ferese);
|
smithay::delegate_output!(Ferese);
|
||||||
|
smithay::delegate_pointer_constraints!(Ferese);
|
||||||
|
smithay::delegate_presentation!(Ferese);
|
||||||
smithay::delegate_primary_selection!(Ferese);
|
smithay::delegate_primary_selection!(Ferese);
|
||||||
|
smithay::delegate_relative_pointer!(Ferese);
|
||||||
smithay::delegate_seat!(Ferese);
|
smithay::delegate_seat!(Ferese);
|
||||||
smithay::delegate_shm!(Ferese);
|
smithay::delegate_shm!(Ferese);
|
||||||
|
smithay::delegate_viewporter!(Ferese);
|
||||||
|
smithay::delegate_xdg_activation!(Ferese);
|
||||||
smithay::delegate_xdg_decoration!(Ferese);
|
smithay::delegate_xdg_decoration!(Ferese);
|
||||||
smithay::delegate_xdg_shell!(Ferese);
|
smithay::delegate_xdg_shell!(Ferese);
|
||||||
+16
-2
@@ -1,11 +1,11 @@
|
|||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::{
|
backend::input::{
|
||||||
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent,
|
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent,
|
||||||
KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent,
|
KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent,
|
||||||
},
|
},
|
||||||
input::{
|
input::{
|
||||||
keyboard::FilterResult,
|
keyboard::FilterResult,
|
||||||
pointer::{AxisFrame, ButtonEvent, MotionEvent},
|
pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent},
|
||||||
},
|
},
|
||||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
utils::{SERIAL_COUNTER, Serial},
|
utils::{SERIAL_COUNTER, Serial},
|
||||||
@@ -47,6 +47,20 @@ impl Ferese {
|
|||||||
);
|
);
|
||||||
pointer.frame(self);
|
pointer.frame(self);
|
||||||
}
|
}
|
||||||
|
InputEvent::PointerMotion { event, .. } => {
|
||||||
|
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||||
|
let focus = self.surface_under(pointer.current_location());
|
||||||
|
pointer.relative_motion(
|
||||||
|
self,
|
||||||
|
focus,
|
||||||
|
&RelativeMotionEvent {
|
||||||
|
delta: event.delta(),
|
||||||
|
delta_unaccel: event.delta_unaccel(),
|
||||||
|
utime: (event.time_msec() as u64).saturating_mul(1_000),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
pointer.frame(self);
|
||||||
|
}
|
||||||
InputEvent::PointerButton { event, .. } => {
|
InputEvent::PointerButton { event, .. } => {
|
||||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
|||||||
@@ -14,12 +14,18 @@ use smithay::{
|
|||||||
utils::{Logical, Point},
|
utils::{Logical, Point},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{CompositorClientState, CompositorState},
|
compositor::{CompositorClientState, CompositorState},
|
||||||
|
fractional_scale::FractionalScaleManagerState,
|
||||||
output::OutputManagerState,
|
output::OutputManagerState,
|
||||||
|
pointer_constraints::PointerConstraintsState,
|
||||||
|
presentation::PresentationState,
|
||||||
|
relative_pointer::RelativePointerManagerState,
|
||||||
selection::{data_device::DataDeviceState, primary_selection::PrimarySelectionState},
|
selection::{data_device::DataDeviceState, primary_selection::PrimarySelectionState},
|
||||||
shell::xdg::XdgShellState,
|
shell::xdg::XdgShellState,
|
||||||
shell::xdg::decoration::XdgDecorationState,
|
shell::xdg::decoration::XdgDecorationState,
|
||||||
shm::ShmState,
|
shm::ShmState,
|
||||||
socket::ListeningSocketSource,
|
socket::ListeningSocketSource,
|
||||||
|
viewporter::ViewporterState,
|
||||||
|
xdg_activation::XdgActivationState,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,10 +40,16 @@ pub struct Ferese {
|
|||||||
pub compositor_state: CompositorState,
|
pub compositor_state: CompositorState,
|
||||||
pub data_device_state: DataDeviceState,
|
pub data_device_state: DataDeviceState,
|
||||||
pub decoration_state: XdgDecorationState,
|
pub decoration_state: XdgDecorationState,
|
||||||
|
pub fractional_scale_state: FractionalScaleManagerState,
|
||||||
pub output_manager_state: OutputManagerState,
|
pub output_manager_state: OutputManagerState,
|
||||||
|
pub pointer_constraints_state: PointerConstraintsState,
|
||||||
|
pub presentation_state: PresentationState,
|
||||||
pub primary_selection_state: PrimarySelectionState,
|
pub primary_selection_state: PrimarySelectionState,
|
||||||
|
pub relative_pointer_state: RelativePointerManagerState,
|
||||||
pub seat_state: SeatState<Self>,
|
pub seat_state: SeatState<Self>,
|
||||||
pub shm_state: ShmState,
|
pub shm_state: ShmState,
|
||||||
|
pub viewporter_state: ViewporterState,
|
||||||
|
pub xdg_activation_state: XdgActivationState,
|
||||||
pub xdg_shell_state: XdgShellState,
|
pub xdg_shell_state: XdgShellState,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,10 +62,17 @@ impl Ferese {
|
|||||||
let compositor_state = CompositorState::new::<Self>(&display_handle);
|
let compositor_state = CompositorState::new::<Self>(&display_handle);
|
||||||
let xdg_shell_state = XdgShellState::new::<Self>(&display_handle);
|
let xdg_shell_state = XdgShellState::new::<Self>(&display_handle);
|
||||||
let decoration_state = XdgDecorationState::new::<Self>(&display_handle);
|
let decoration_state = XdgDecorationState::new::<Self>(&display_handle);
|
||||||
|
let fractional_scale_state = FractionalScaleManagerState::new::<Self>(&display_handle);
|
||||||
let shm_state = ShmState::new::<Self>(&display_handle, Vec::new());
|
let shm_state = ShmState::new::<Self>(&display_handle, Vec::new());
|
||||||
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
|
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
|
||||||
|
let pointer_constraints_state = PointerConstraintsState::new::<Self>(&display_handle);
|
||||||
|
let presentation_state =
|
||||||
|
PresentationState::new::<Self>(&display_handle, libc::CLOCK_MONOTONIC as u32);
|
||||||
let data_device_state = DataDeviceState::new::<Self>(&display_handle);
|
let data_device_state = DataDeviceState::new::<Self>(&display_handle);
|
||||||
let primary_selection_state = PrimarySelectionState::new::<Self>(&display_handle);
|
let primary_selection_state = PrimarySelectionState::new::<Self>(&display_handle);
|
||||||
|
let relative_pointer_state = RelativePointerManagerState::new::<Self>(&display_handle);
|
||||||
|
let viewporter_state = ViewporterState::new::<Self>(&display_handle);
|
||||||
|
let xdg_activation_state = XdgActivationState::new::<Self>(&display_handle);
|
||||||
let mut seat_state = SeatState::new();
|
let mut seat_state = SeatState::new();
|
||||||
let mut seat = seat_state.new_wl_seat(&display_handle, "ferese-winit");
|
let mut seat = seat_state.new_wl_seat(&display_handle, "ferese-winit");
|
||||||
seat.add_keyboard(Default::default(), 200, 25)?;
|
seat.add_keyboard(Default::default(), 200, 25)?;
|
||||||
@@ -71,10 +90,16 @@ impl Ferese {
|
|||||||
compositor_state,
|
compositor_state,
|
||||||
data_device_state,
|
data_device_state,
|
||||||
decoration_state,
|
decoration_state,
|
||||||
|
fractional_scale_state,
|
||||||
output_manager_state,
|
output_manager_state,
|
||||||
|
pointer_constraints_state,
|
||||||
|
presentation_state,
|
||||||
primary_selection_state,
|
primary_selection_state,
|
||||||
|
relative_pointer_state,
|
||||||
seat_state,
|
seat_state,
|
||||||
shm_state,
|
shm_state,
|
||||||
|
viewporter_state,
|
||||||
|
xdg_activation_state,
|
||||||
xdg_shell_state,
|
xdg_shell_state,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-1
@@ -8,9 +8,12 @@ use smithay::{
|
|||||||
},
|
},
|
||||||
winit::{self, WinitEvent},
|
winit::{self, WinitEvent},
|
||||||
},
|
},
|
||||||
|
desktop::utils::OutputPresentationFeedback,
|
||||||
output::{Mode, Output, PhysicalProperties, Subpixel},
|
output::{Mode, Output, PhysicalProperties, Subpixel},
|
||||||
reexports::calloop::EventLoop,
|
reexports::calloop::EventLoop,
|
||||||
utils::{Rectangle, Transform},
|
reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback::Kind,
|
||||||
|
utils::{Clock, Monotonic, Rectangle, Transform},
|
||||||
|
wayland::presentation::Refresh,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Ferese;
|
use crate::Ferese;
|
||||||
@@ -41,6 +44,8 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
state.space.map_output(&output, (0, 0));
|
state.space.map_output(&output, (0, 0));
|
||||||
|
|
||||||
let mut damage_tracker = OutputDamageTracker::from_output(&output);
|
let mut damage_tracker = OutputDamageTracker::from_output(&output);
|
||||||
|
let clock = Clock::<Monotonic>::new();
|
||||||
|
let mut sequence = 0_u64;
|
||||||
event_loop
|
event_loop
|
||||||
.handle()
|
.handle()
|
||||||
.insert_source(event_source, move |event, _, state| match event {
|
.insert_source(event_source, move |event, _, state| match event {
|
||||||
@@ -56,6 +61,14 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
WinitEvent::Input(event) => state.process_input_event(event),
|
WinitEvent::Input(event) => state.process_input_event(event),
|
||||||
WinitEvent::Redraw => {
|
WinitEvent::Redraw => {
|
||||||
let damage = Rectangle::from_size(backend.window_size());
|
let damage = Rectangle::from_size(backend.window_size());
|
||||||
|
let mut presentation = OutputPresentationFeedback::new(&output);
|
||||||
|
state.space.elements().for_each(|window| {
|
||||||
|
window.take_presentation_feedback(
|
||||||
|
&mut presentation,
|
||||||
|
|_, _| Some(output.clone()),
|
||||||
|
|_, _| Kind::Vsync,
|
||||||
|
);
|
||||||
|
});
|
||||||
let rendered = (|| -> Result<(), Box<dyn Error>> {
|
let rendered = (|| -> Result<(), Box<dyn Error>> {
|
||||||
{
|
{
|
||||||
let (renderer, mut framebuffer) = backend.bind()?;
|
let (renderer, mut framebuffer) = backend.bind()?;
|
||||||
@@ -84,6 +97,13 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
state.loop_signal.stop();
|
state.loop_signal.stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
sequence = sequence.wrapping_add(1);
|
||||||
|
presentation.presented(
|
||||||
|
clock.now(),
|
||||||
|
Refresh::fixed(Duration::from_nanos(1_000_000_000 / 60)),
|
||||||
|
sequence,
|
||||||
|
Kind::Vsync,
|
||||||
|
);
|
||||||
state.space.elements().for_each(|window| {
|
state.space.elements().for_each(|window| {
|
||||||
window.send_frame(
|
window.send_frame(
|
||||||
&output,
|
&output,
|
||||||
|
|||||||
Reference in new issue
Block a user