screencopy: Capture cursor for window capture

This commit is contained in:
Victoria Brekenfeld 2022-11-04 16:57:42 +01:00
parent bcf3e43fcc
commit cab52fbeef
3 changed files with 116 additions and 10 deletions

2
Cargo.lock generated
View file

@ -318,7 +318,7 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-protocols" name = "cosmic-protocols"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#aee21196b19591e83c04c803bfa1a865fda46337" source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#a3e0aa740a3e0f8f7b486fef0d62fa09a1dfa328"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"wayland-backend", "wayland-backend",

View file

@ -1,4 +1,4 @@
use crate::state::State; use crate::{state::State, utils::prelude::SeatExt};
use id_tree::NodeId; use id_tree::NodeId;
use smithay::{ use smithay::{
backend::{ backend::{
@ -25,6 +25,7 @@ use smithay::{
}, },
}; };
use std::{ use std::{
collections::HashMap,
hash::Hash, hash::Hash,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -48,6 +49,7 @@ pub struct CosmicMapped {
element: CosmicMappedInternal, element: CosmicMappedInternal,
// associated data // associated data
last_cursor_position: Arc<Mutex<HashMap<usize, Point<f64, Logical>>>>,
//tiling //tiling
pub(super) tiling_node_id: Arc<Mutex<Option<NodeId>>>, pub(super) tiling_node_id: Arc<Mutex<Option<NodeId>>>,
@ -108,6 +110,45 @@ impl CosmicMapped {
} }
} }
pub fn active_window_offset(&self) -> Rectangle<i32, Logical> {
match &self.element {
CosmicMappedInternal::Stack(stack) => {
let location = (
0,
stack
.header
.lock()
.unwrap()
.as_ref()
.map_or(0, |header| header.height()),
);
let size = stack.active().geometry().size;
Rectangle::from_loc_and_size(location, size)
}
CosmicMappedInternal::Window(win) => {
let location = (
0,
win.header
.lock()
.unwrap()
.as_ref()
.map_or(0, |header| header.height()),
);
let size = win.window.geometry().size;
Rectangle::from_loc_and_size(location, size)
}
_ => unreachable!(),
}
}
pub fn cursor_position(&self, seat: &Seat<State>) -> Option<Point<f64, Logical>> {
self.last_cursor_position
.lock()
.unwrap()
.get(&seat.id())
.cloned()
}
pub fn set_active(&self, window: &Window) { pub fn set_active(&self, window: &Window) {
if let CosmicMappedInternal::Stack(stack) = &self.element { if let CosmicMappedInternal::Stack(stack) = &self.element {
stack.set_active(window); stack.set_active(window);
@ -565,6 +606,10 @@ impl KeyboardTarget<State> for CosmicMapped {
impl PointerTarget<State> for CosmicMapped { impl PointerTarget<State> for CosmicMapped {
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) { fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
self.last_cursor_position
.lock()
.unwrap()
.insert(seat.id(), event.location);
match &self.element { match &self.element {
CosmicMappedInternal::Stack(s) => PointerTarget::enter(s, seat, data, event), CosmicMappedInternal::Stack(s) => PointerTarget::enter(s, seat, data, event),
CosmicMappedInternal::Window(w) => PointerTarget::enter(w, seat, data, event), CosmicMappedInternal::Window(w) => PointerTarget::enter(w, seat, data, event),
@ -572,6 +617,10 @@ impl PointerTarget<State> for CosmicMapped {
} }
} }
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) { fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
self.last_cursor_position
.lock()
.unwrap()
.insert(seat.id(), event.location);
match &self.element { match &self.element {
CosmicMappedInternal::Stack(s) => PointerTarget::motion(s, seat, data, event), CosmicMappedInternal::Stack(s) => PointerTarget::motion(s, seat, data, event),
CosmicMappedInternal::Window(w) => PointerTarget::motion(w, seat, data, event), CosmicMappedInternal::Window(w) => PointerTarget::motion(w, seat, data, event),
@ -593,6 +642,7 @@ impl PointerTarget<State> for CosmicMapped {
} }
} }
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) { fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
self.last_cursor_position.lock().unwrap().remove(&seat.id());
match &self.element { match &self.element {
CosmicMappedInternal::Stack(s) => PointerTarget::leave(s, seat, data, serial, time), CosmicMappedInternal::Stack(s) => PointerTarget::leave(s, seat, data, serial, time),
CosmicMappedInternal::Window(w) => PointerTarget::leave(w, seat, data, serial, time), CosmicMappedInternal::Window(w) => PointerTarget::leave(w, seat, data, serial, time),
@ -623,6 +673,7 @@ impl From<CosmicWindow> for CosmicMapped {
fn from(w: CosmicWindow) -> Self { fn from(w: CosmicWindow) -> Self {
CosmicMapped { CosmicMapped {
element: CosmicMappedInternal::Window(w), element: CosmicMappedInternal::Window(w),
last_cursor_position: Arc::new(Mutex::new(HashMap::new())),
tiling_node_id: Arc::new(Mutex::new(None)), tiling_node_id: Arc::new(Mutex::new(None)),
last_geometry: Arc::new(Mutex::new(None)), last_geometry: Arc::new(Mutex::new(None)),
resize_state: Arc::new(Mutex::new(None)), resize_state: Arc::new(Mutex::new(None)),
@ -634,6 +685,7 @@ impl From<CosmicStack> for CosmicMapped {
fn from(s: CosmicStack) -> Self { fn from(s: CosmicStack) -> Self {
CosmicMapped { CosmicMapped {
element: CosmicMappedInternal::Stack(s), element: CosmicMappedInternal::Stack(s),
last_cursor_position: Arc::new(Mutex::new(HashMap::new())),
tiling_node_id: Arc::new(Mutex::new(None)), tiling_node_id: Arc::new(Mutex::new(None)),
last_geometry: Arc::new(Mutex::new(None)), last_geometry: Arc::new(Mutex::new(None)),
resize_state: Arc::new(Mutex::new(None)), resize_state: Arc::new(Mutex::new(None)),

View file

@ -20,7 +20,7 @@ use smithay::{
surface::WaylandSurfaceRenderElement, AsRenderElements, RenderElementStates, surface::WaylandSurfaceRenderElement, AsRenderElements, RenderElementStates,
}, },
gles2::{Gles2Renderbuffer, Gles2Renderer}, gles2::{Gles2Renderbuffer, Gles2Renderer},
Bind, BufferType, ExportMem, Offscreen, Renderer, Bind, BufferType, ExportMem, ImportAll, Offscreen, Renderer,
}, },
}, },
desktop::Window, desktop::Window,
@ -37,7 +37,7 @@ use smithay::{
}; };
use crate::{ use crate::{
backend::render::{render_output, render_workspace, CursorMode, CLEAR_COLOR}, backend::render::{cursor, render_output, render_workspace, CursorMode, CLEAR_COLOR},
state::{BackendData, ClientState, Common, State}, state::{BackendData, ClientState, Common, State},
utils::prelude::OutputExt, utils::prelude::OutputExt,
wayland::protocols::{ wayland::protocols::{
@ -49,6 +49,8 @@ use crate::{
}, },
}; };
use super::data_device::get_dnd_icon;
pub type PendingScreencopyBuffers = RefCell<Vec<(Session, BufferParams)>>; pub type PendingScreencopyBuffers = RefCell<Vec<(Session, BufferParams)>>;
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -670,6 +672,12 @@ pub fn render_workspace_to_buffer(
.map_err(|err| (FailureReason::Unspec, err.into())) .map_err(|err| (FailureReason::Unspec, err.into()))
} }
smithay::render_elements! {
pub WindowCaptureElement<R> where R: ImportAll;
WaylandElement=WaylandSurfaceRenderElement,
CursorElement=cursor::CursorRenderElement<R>,
}
pub fn render_window_to_buffer( pub fn render_window_to_buffer(
state: &mut State, state: &mut State,
session: &Session, session: &Session,
@ -706,12 +714,58 @@ pub fn render_window_to_buffer(
Transform::Normal, Transform::Normal,
|_node, renderer, dtr, age| { |_node, renderer, dtr, age| {
// TODO cursor elements! // TODO cursor elements!
let elements = let mut elements = AsRenderElements::<Gles2Renderer>::render_elements::<
AsRenderElements::<Gles2Renderer>::render_elements::<WaylandSurfaceRenderElement>( WindowCaptureElement<Gles2Renderer>,
window, >(
(-geometry.loc.x, -geometry.loc.y).into(), window,
Scale::from(1.0), (-geometry.loc.x, -geometry.loc.y).into(),
); Scale::from(1.0),
);
for seat in state.common.seats() {
if let Some(location) = {
// we need to find the mapped element in that case
if let Some(mapped) = state
.common
.shell
.element_for_surface(window.toplevel().wl_surface())
{
mapped.cursor_position(seat).and_then(|mut p| {
p -= mapped.active_window_offset().loc.to_f64();
if p.x < 0. || p.y < 0. {
None
} else {
Some(p)
}
})
} else {
None
}
} {
if session.cursor_mode() == ScreencopyCursorMode::Embedded {
elements.extend(
cursor::draw_cursor(
renderer,
seat,
location,
1.0.into(),
&state.common.start_time,
true,
)
.into_iter()
.map(WindowCaptureElement::from),
);
}
if let Some(wl_surface) = get_dnd_icon(seat) {
elements.extend(
cursor::draw_dnd_icon(&wl_surface, location.to_i32_round(), 1.0)
.into_iter()
.map(WindowCaptureElement::from),
);
}
}
}
dtr.render_output(renderer, age, &elements, CLEAR_COLOR, None) dtr.render_output(renderer, age, &elements, CLEAR_COLOR, None)
}, },