feat: compose client cursor surfaces
This commit is contained in:
1 parent
bf10a2f838
commit
ee9da5d8c9
5 files changed
+67
-11
No files matched your search
@@ -50,10 +50,10 @@ impl CompositorHandler for Ferese {
|
|||||||
if let Some(window) = window {
|
if let Some(window) = window {
|
||||||
window.on_commit();
|
window.on_commit();
|
||||||
self.record_client_commit(&window);
|
self.record_client_commit(&window);
|
||||||
crate::backends::direct::render_all(self);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xdg_shell::handle_commit(&mut self.popups, &mut self.space, surface);
|
xdg_shell::handle_commit(&mut self.popups, &mut self.space, surface);
|
||||||
|
crate::backends::direct::render_all(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,10 @@ impl SeatHandler for Ferese {
|
|||||||
&mut self.seat_state
|
&mut self.seat_state
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursor_image(&mut self, _seat: &Seat<Self>, _image: CursorImageStatus) {}
|
fn cursor_image(&mut self, _seat: &Seat<Self>, image: CursorImageStatus) {
|
||||||
|
self.cursor_status = image;
|
||||||
|
crate::backends::direct::render_all(self);
|
||||||
|
}
|
||||||
|
|
||||||
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&WlSurface>) {
|
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&WlSurface>) {
|
||||||
let client = focused.and_then(|surface| self.display_handle.get_client(surface.id()).ok());
|
let client = focused.and_then(|surface| self.display_handle.get_client(surface.id()).ok());
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ impl Ferese {
|
|||||||
);
|
);
|
||||||
pointer.frame(self);
|
pointer.frame(self);
|
||||||
self.activate_focused_pointer_constraint(&pointer);
|
self.activate_focused_pointer_constraint(&pointer);
|
||||||
|
crate::backends::direct::render_all(self);
|
||||||
}
|
}
|
||||||
InputEvent::PointerMotion { event, .. } => {
|
InputEvent::PointerMotion { event, .. } => {
|
||||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||||
@@ -167,6 +168,7 @@ impl Ferese {
|
|||||||
);
|
);
|
||||||
pointer.frame(self);
|
pointer.frame(self);
|
||||||
self.activate_focused_pointer_constraint(&pointer);
|
self.activate_focused_pointer_constraint(&pointer);
|
||||||
|
crate::backends::direct::render_all(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");
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use ferese_layout::{Axis, Direction, GapConfig, LayoutResult, Rect, SizeConstrai
|
|||||||
use smithay::{
|
use smithay::{
|
||||||
backend::drm::DrmEventTime,
|
backend::drm::DrmEventTime,
|
||||||
desktop::{PopupManager, Space, Window, WindowSurfaceType},
|
desktop::{PopupManager, Space, Window, WindowSurfaceType},
|
||||||
input::{Seat, SeatState},
|
input::{Seat, SeatState, pointer::CursorImageStatus},
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::{EventLoop, Interest, LoopSignal, Mode, PostAction, generic::Generic},
|
calloop::{EventLoop, Interest, LoopSignal, Mode, PostAction, generic::Generic},
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||||
@@ -51,6 +51,7 @@ pub struct Ferese {
|
|||||||
pub window_ids: HashMap<Window, WindowId>,
|
pub window_ids: HashMap<Window, WindowId>,
|
||||||
pub window_geometry: HashMap<WindowId, WindowGeometry>,
|
pub window_geometry: HashMap<WindowId, WindowGeometry>,
|
||||||
pub focused_window: Option<WindowId>,
|
pub focused_window: Option<WindowId>,
|
||||||
|
pub cursor_status: CursorImageStatus,
|
||||||
pub intercepted_keys: HashSet<smithay::input::keyboard::Keycode>,
|
pub intercepted_keys: HashSet<smithay::input::keyboard::Keycode>,
|
||||||
pub direct_backend: Option<crate::backends::direct::DirectBackendState>,
|
pub direct_backend: Option<crate::backends::direct::DirectBackendState>,
|
||||||
next_window_id: u64,
|
next_window_id: u64,
|
||||||
@@ -111,6 +112,7 @@ impl Ferese {
|
|||||||
window_ids: HashMap::new(),
|
window_ids: HashMap::new(),
|
||||||
window_geometry: HashMap::new(),
|
window_geometry: HashMap::new(),
|
||||||
focused_window: None,
|
focused_window: None,
|
||||||
|
cursor_status: CursorImageStatus::default_named(),
|
||||||
intercepted_keys: HashSet::new(),
|
intercepted_keys: HashSet::new(),
|
||||||
direct_backend: None,
|
direct_backend: None,
|
||||||
next_window_id: 1,
|
next_window_id: 1,
|
||||||
|
|||||||
+57
-8
@@ -8,9 +8,10 @@ use smithay::{
|
|||||||
renderer::{
|
renderer::{
|
||||||
damage::OutputDamageTracker,
|
damage::OutputDamageTracker,
|
||||||
element::{
|
element::{
|
||||||
surface::WaylandSurfaceRenderElement,
|
Kind as RenderElementKind,
|
||||||
|
surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree},
|
||||||
utils::{
|
utils::{
|
||||||
ConstrainAlign, ConstrainScaleBehavior, CropRenderElement,
|
ConstrainAlign, ConstrainScaleBehavior, CropRenderElement, Relocate,
|
||||||
RelocateRenderElement, RescaleRenderElement,
|
RelocateRenderElement, RescaleRenderElement,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -22,11 +23,12 @@ use smithay::{
|
|||||||
space::{ConstrainBehavior, ConstrainReference, constrain_space_element},
|
space::{ConstrainBehavior, ConstrainReference, constrain_space_element},
|
||||||
utils::OutputPresentationFeedback,
|
utils::OutputPresentationFeedback,
|
||||||
},
|
},
|
||||||
|
input::pointer::{CursorImageStatus, CursorImageSurfaceData},
|
||||||
output::{Mode, Output, PhysicalProperties, Scale, Subpixel},
|
output::{Mode, Output, PhysicalProperties, Scale, Subpixel},
|
||||||
reexports::calloop::EventLoop,
|
reexports::calloop::EventLoop,
|
||||||
reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback::Kind,
|
reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback::Kind as PresentationKind,
|
||||||
utils::{Clock, Logical, Monotonic, Rectangle, Transform},
|
utils::{Clock, Logical, Monotonic, Physical, Point, Rectangle, Transform},
|
||||||
wayland::presentation::Refresh,
|
wayland::{compositor::with_states, presentation::Refresh},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Ferese;
|
use crate::Ferese;
|
||||||
@@ -98,7 +100,7 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
window.take_presentation_feedback(
|
window.take_presentation_feedback(
|
||||||
&mut presentation,
|
&mut presentation,
|
||||||
|_, _| Some(output.clone()),
|
|_, _| Some(output.clone()),
|
||||||
|_, _| Kind::Vsync,
|
|_, _| PresentationKind::Vsync,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
let rendered = (|| -> Result<(), Box<dyn Error>> {
|
let rendered = (|| -> Result<(), Box<dyn Error>> {
|
||||||
@@ -126,7 +128,7 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
clock.now(),
|
clock.now(),
|
||||||
Refresh::fixed(Duration::from_nanos(1_000_000_000 / 60)),
|
Refresh::fixed(Duration::from_nanos(1_000_000_000 / 60)),
|
||||||
sequence,
|
sequence,
|
||||||
Kind::Vsync,
|
PresentationKind::Vsync,
|
||||||
);
|
);
|
||||||
state.space.elements().for_each(|window| {
|
state.space.elements().for_each(|window| {
|
||||||
window.send_frame(
|
window.send_frame(
|
||||||
@@ -159,6 +161,8 @@ pub(crate) fn animated_window_elements(
|
|||||||
};
|
};
|
||||||
let scale = output.current_scale().fractional_scale();
|
let scale = output.current_scale().fractional_scale();
|
||||||
|
|
||||||
|
let mut elements = cursor_elements(state, renderer, output_geometry, scale);
|
||||||
|
elements.extend(
|
||||||
state
|
state
|
||||||
.space
|
.space
|
||||||
.elements()
|
.elements()
|
||||||
@@ -197,7 +201,52 @@ pub(crate) fn animated_window_elements(
|
|||||||
},
|
},
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten(),
|
||||||
|
);
|
||||||
|
elements
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cursor_elements(
|
||||||
|
state: &Ferese,
|
||||||
|
renderer: &mut GlesRenderer,
|
||||||
|
output_geometry: Rectangle<i32, Logical>,
|
||||||
|
scale: f64,
|
||||||
|
) -> Vec<AnimatedWindowRenderElement> {
|
||||||
|
let CursorImageStatus::Surface(surface) = &state.cursor_status else {
|
||||||
|
return Vec::new();
|
||||||
|
};
|
||||||
|
let Some(pointer) = state.seat.get_pointer() else {
|
||||||
|
return Vec::new();
|
||||||
|
};
|
||||||
|
let hotspot = with_states(surface, |states| {
|
||||||
|
states
|
||||||
|
.data_map
|
||||||
|
.get::<CursorImageSurfaceData>()
|
||||||
|
.map(|attributes| attributes.lock().unwrap().hotspot)
|
||||||
|
.unwrap_or_default()
|
||||||
|
});
|
||||||
|
let logical_location =
|
||||||
|
pointer.current_location() - output_geometry.loc.to_f64() - hotspot.to_f64();
|
||||||
|
let physical_location = logical_location.to_physical_precise_round(scale);
|
||||||
|
let output_crop =
|
||||||
|
Rectangle::<i32, Logical>::from_size(output_geometry.size).to_physical_precise_round(scale);
|
||||||
|
let origin = Point::<i32, Physical>::default();
|
||||||
|
|
||||||
|
render_elements_from_surface_tree::<GlesRenderer, WaylandSurfaceRenderElement<GlesRenderer>>(
|
||||||
|
renderer,
|
||||||
|
surface,
|
||||||
|
physical_location,
|
||||||
|
scale,
|
||||||
|
1.0,
|
||||||
|
RenderElementKind::Cursor,
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|element| {
|
||||||
|
let element = RescaleRenderElement::from_element(element, origin, 1.0);
|
||||||
|
let element = RelocateRenderElement::from_element(element, origin, Relocate::Relative);
|
||||||
|
|
||||||
|
CropRenderElement::from_element(element, scale, output_crop)
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user