Initial support for filtering what to capture to only what's needed
This commit is contained in:
parent
b29f1149a4
commit
b5931cd240
5 changed files with 110 additions and 40 deletions
50
src/main.rs
50
src/main.rs
|
|
@ -55,7 +55,7 @@ struct Workspace {
|
||||||
name: String,
|
name: String,
|
||||||
img: Option<iced::widget::image::Handle>,
|
img: Option<iced::widget::image::Handle>,
|
||||||
handle: zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
|
handle: zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
|
||||||
output_name: Option<String>,
|
output_name: String,
|
||||||
is_active: bool,
|
is_active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ struct Toplevel {
|
||||||
struct Output {
|
struct Output {
|
||||||
// Output, on the `iced_sctk` Wayland connection
|
// Output, on the `iced_sctk` Wayland connection
|
||||||
handle: wl_output::WlOutput,
|
handle: wl_output::WlOutput,
|
||||||
name: Option<String>,
|
name: String,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +78,7 @@ struct Output {
|
||||||
struct LayerSurface {
|
struct LayerSurface {
|
||||||
// Output, on the `iced_sctk` Wayland connection
|
// Output, on the `iced_sctk` Wayland connection
|
||||||
output: wl_output::WlOutput,
|
output: wl_output::WlOutput,
|
||||||
output_name: Option<String>,
|
output_name: String,
|
||||||
// for transitions, would need windows in more than one workspace? But don't capture all of
|
// for transitions, would need windows in more than one workspace? But don't capture all of
|
||||||
// them all the time every frame.
|
// them all the time every frame.
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ impl App {
|
||||||
fn create_surface(
|
fn create_surface(
|
||||||
&mut self,
|
&mut self,
|
||||||
output: wl_output::WlOutput,
|
output: wl_output::WlOutput,
|
||||||
output_name: Option<String>,
|
output_name: String,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
) -> Command<Msg> {
|
) -> Command<Msg> {
|
||||||
|
|
@ -177,14 +177,16 @@ impl App {
|
||||||
if !self.visible {
|
if !self.visible {
|
||||||
self.visible = true;
|
self.visible = true;
|
||||||
let outputs = self.outputs.clone();
|
let outputs = self.outputs.clone();
|
||||||
Command::batch(
|
let cmd = Command::batch(
|
||||||
outputs
|
outputs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|output| {
|
.map(|output| {
|
||||||
self.create_surface(output.handle, output.name, output.width, output.height)
|
self.create_surface(output.handle, output.name, output.width, output.height)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)
|
);
|
||||||
|
self.update_capture_filter();
|
||||||
|
cmd
|
||||||
} else {
|
} else {
|
||||||
Command::none()
|
Command::none()
|
||||||
}
|
}
|
||||||
|
|
@ -193,6 +195,7 @@ impl App {
|
||||||
// Close all shell surfaces
|
// Close all shell surfaces
|
||||||
fn hide(&mut self) -> Command<Msg> {
|
fn hide(&mut self) -> Command<Msg> {
|
||||||
self.visible = false;
|
self.visible = false;
|
||||||
|
self.update_capture_filter();
|
||||||
Command::batch(
|
Command::batch(
|
||||||
mem::take(&mut self.layer_surfaces)
|
mem::take(&mut self.layer_surfaces)
|
||||||
.into_keys()
|
.into_keys()
|
||||||
|
|
@ -200,6 +203,24 @@ impl App {
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_capture_filter(&self) {
|
||||||
|
if let Some(sender) = self.wayland_cmd_sender.as_ref() {
|
||||||
|
let mut capture_filter = wayland::CaptureFilter::default();
|
||||||
|
if self.visible {
|
||||||
|
// XXX handle on wrong connection
|
||||||
|
capture_filter.workspaces_on_outputs =
|
||||||
|
self.outputs.iter().map(|x| x.name.clone()).collect();
|
||||||
|
capture_filter.toplevels_on_workspaces = self
|
||||||
|
.workspaces
|
||||||
|
.iter()
|
||||||
|
.filter(|x| x.is_active)
|
||||||
|
.map(|x| x.handle.clone())
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
let _ = sender.send(wayland::Cmd::CaptureFilter(capture_filter));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application for App {
|
impl Application for App {
|
||||||
|
|
@ -225,20 +246,16 @@ impl Application for App {
|
||||||
Msg::WaylandEvent(evt) => match evt {
|
Msg::WaylandEvent(evt) => match evt {
|
||||||
WaylandEvent::Output(evt, output) => match evt {
|
WaylandEvent::Output(evt, output) => match evt {
|
||||||
OutputEvent::Created(Some(info)) => {
|
OutputEvent::Created(Some(info)) => {
|
||||||
if let Some((width, height)) = info.logical_size {
|
if let (Some((width, height)), Some(name)) = (info.logical_size, info.name)
|
||||||
|
{
|
||||||
self.outputs.push(Output {
|
self.outputs.push(Output {
|
||||||
handle: output.clone(),
|
handle: output.clone(),
|
||||||
name: info.name.clone(),
|
name: name.clone(),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
});
|
});
|
||||||
if self.visible {
|
if self.visible {
|
||||||
return self.create_surface(
|
return self.create_surface(output.clone(), name, width, height);
|
||||||
output.clone(),
|
|
||||||
info.name,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -249,7 +266,9 @@ impl Application for App {
|
||||||
output.width = width;
|
output.width = width;
|
||||||
output.height = height;
|
output.height = height;
|
||||||
}
|
}
|
||||||
output.name = info.name;
|
if let Some(name) = info.name {
|
||||||
|
output.name = name;
|
||||||
|
}
|
||||||
// XXX re-create surface?
|
// XXX re-create surface?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -300,6 +319,7 @@ impl Application for App {
|
||||||
is_active,
|
is_active,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
self.update_capture_filter();
|
||||||
}
|
}
|
||||||
wayland::Event::NewToplevel(handle, info) => {
|
wayland::Event::NewToplevel(handle, info) => {
|
||||||
println!("New toplevel: {info:?}");
|
println!("New toplevel: {info:?}");
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,16 @@ impl std::hash::Hash for CaptureSource {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct CaptureFilter {
|
pub struct CaptureFilter {
|
||||||
pub workspaces_on_outputs: Vec<wl_output::WlOutput>,
|
// TODO: Use `WlOutput` when one Wayland connection is used
|
||||||
|
pub workspaces_on_outputs: Vec<String>,
|
||||||
pub toplevels_on_workspaces: Vec<zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1>,
|
pub toplevels_on_workspaces: Vec<zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Capture {
|
pub struct Capture {
|
||||||
pub buffer: Mutex<Option<Buffer>>,
|
pub buffer: Mutex<Option<Buffer>>,
|
||||||
pub source: CaptureSource,
|
pub source: CaptureSource,
|
||||||
pub first_frame: AtomicBool,
|
first_frame: AtomicBool,
|
||||||
pub cancelled: AtomicBool,
|
running: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Capture {
|
impl Capture {
|
||||||
|
|
@ -57,7 +58,7 @@ impl Capture {
|
||||||
buffer: Mutex::new(None),
|
buffer: Mutex::new(None),
|
||||||
source,
|
source,
|
||||||
first_frame: AtomicBool::new(true),
|
first_frame: AtomicBool::new(true),
|
||||||
cancelled: AtomicBool::new(false),
|
running: AtomicBool::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,8 +68,17 @@ impl Capture {
|
||||||
Some(&session.data::<SessionData>()?.capture)
|
Some(&session.data::<SessionData>()?.capture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn running(&self) -> bool {
|
||||||
|
self.running.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn first_frame(&self) -> bool {
|
||||||
|
self.first_frame.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cancel(&self) {
|
pub fn cancel(&self) {
|
||||||
self.cancelled.store(true, Ordering::SeqCst);
|
self.running.store(false, Ordering::SeqCst);
|
||||||
|
*self.buffer.lock().unwrap() = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn capture(
|
pub fn capture(
|
||||||
|
|
@ -76,6 +86,10 @@ impl Capture {
|
||||||
manager: &zcosmic_screencopy_manager_v1::ZcosmicScreencopyManagerV1,
|
manager: &zcosmic_screencopy_manager_v1::ZcosmicScreencopyManagerV1,
|
||||||
qh: &QueueHandle<AppData>,
|
qh: &QueueHandle<AppData>,
|
||||||
) {
|
) {
|
||||||
|
// Mark as running. If already running, this is not the first frame.
|
||||||
|
let already_running = self.running.swap(true, Ordering::SeqCst);
|
||||||
|
self.first_frame.store(!already_running, Ordering::SeqCst);
|
||||||
|
|
||||||
let udata = SessionData {
|
let udata = SessionData {
|
||||||
session_data: Default::default(),
|
session_data: Default::default(),
|
||||||
capture: self.clone(),
|
capture: self.clone(),
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ pub enum Event {
|
||||||
ToplevelManager(zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1),
|
ToplevelManager(zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1),
|
||||||
WorkspaceManager(zcosmic_workspace_manager_v1::ZcosmicWorkspaceManagerV1),
|
WorkspaceManager(zcosmic_workspace_manager_v1::ZcosmicWorkspaceManagerV1),
|
||||||
// XXX Output name rather than `WlOutput`
|
// XXX Output name rather than `WlOutput`
|
||||||
Workspaces(Vec<(Option<String>, cctk::workspace::Workspace)>),
|
Workspaces(Vec<(String, cctk::workspace::Workspace)>),
|
||||||
WorkspaceCapture(
|
WorkspaceCapture(
|
||||||
zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
|
zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
|
||||||
image::Handle,
|
image::Handle,
|
||||||
|
|
@ -116,16 +116,52 @@ impl AppData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invalidate_capture_filter(&mut self) {
|
fn matches_capture_filter(&self, source: &CaptureSource) -> bool {
|
||||||
//for i in self.captures
|
match source {
|
||||||
// XXX drain filter
|
CaptureSource::Toplevel(toplevel) => {
|
||||||
// TODO cancel captures if needed, enable capture
|
let info = self.toplevel_info_state.info(toplevel).unwrap();
|
||||||
|
if let Some(workspace) = &info.workspace {
|
||||||
|
self.capture_filter
|
||||||
|
.toplevels_on_workspaces
|
||||||
|
.contains(workspace)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CaptureSource::Workspace(_, output) => {
|
||||||
|
if let Some(name) = &self.output_state.info(&output).unwrap().name {
|
||||||
|
self.capture_filter.workspaces_on_outputs.contains(name)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalidate_capture_filter(&self) {
|
||||||
|
for (source, capture) in self.captures.borrow_mut().iter_mut() {
|
||||||
|
let matches = self.matches_capture_filter(source);
|
||||||
|
let running = capture.running();
|
||||||
|
if running && !matches {
|
||||||
|
capture.cancel();
|
||||||
|
} else if !running & matches {
|
||||||
|
capture.capture(&self.screencopy_state.screencopy_manager, &self.qh);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_capture_source(&self, source: CaptureSource) {
|
fn add_capture_source(&self, source: CaptureSource) {
|
||||||
let capture = Arc::new(Capture::new(source.clone()));
|
self.captures
|
||||||
capture.capture(&self.screencopy_state.screencopy_manager, &self.qh);
|
.borrow_mut()
|
||||||
self.captures.borrow_mut().insert(source, capture);
|
.entry(source.clone())
|
||||||
|
.or_insert_with(|| {
|
||||||
|
let matches = self.matches_capture_filter(&source);
|
||||||
|
let capture = Arc::new(Capture::new(source));
|
||||||
|
if matches {
|
||||||
|
capture.capture(&self.screencopy_state.screencopy_manager, &self.qh);
|
||||||
|
}
|
||||||
|
capture
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_capture_source(&self, source: CaptureSource) {
|
fn remove_capture_source(&self, source: CaptureSource) {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ use cctk::{
|
||||||
wayland_client::{protocol::wl_shm, Connection, QueueHandle, WEnum},
|
wayland_client::{protocol::wl_shm, Connection, QueueHandle, WEnum},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
use super::{AppData, Buffer, Capture, CaptureSource, Event};
|
use super::{AppData, Buffer, Capture, CaptureSource, Event};
|
||||||
|
|
||||||
impl ScreencopyHandler for AppData {
|
impl ScreencopyHandler for AppData {
|
||||||
|
|
@ -21,7 +19,7 @@ impl ScreencopyHandler for AppData {
|
||||||
buffer_infos: &[BufferInfo],
|
buffer_infos: &[BufferInfo],
|
||||||
) {
|
) {
|
||||||
let capture = Capture::for_session(session).unwrap();
|
let capture = Capture::for_session(session).unwrap();
|
||||||
if capture.cancelled.load(Ordering::SeqCst) {
|
if !capture.running() {
|
||||||
session.destroy();
|
session.destroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -51,7 +49,7 @@ impl ScreencopyHandler for AppData {
|
||||||
let buffer = buffer.as_ref().unwrap();
|
let buffer = buffer.as_ref().unwrap();
|
||||||
|
|
||||||
session.attach_buffer(&buffer.buffer, None, 0); // XXX age?
|
session.attach_buffer(&buffer.buffer, None, 0); // XXX age?
|
||||||
if capture.first_frame.load(Ordering::SeqCst) {
|
if capture.first_frame() {
|
||||||
session.commit(zcosmic_screencopy_session_v1::Options::empty());
|
session.commit(zcosmic_screencopy_session_v1::Options::empty());
|
||||||
} else {
|
} else {
|
||||||
session.commit(zcosmic_screencopy_session_v1::Options::OnDamage);
|
session.commit(zcosmic_screencopy_session_v1::Options::OnDamage);
|
||||||
|
|
@ -66,7 +64,7 @@ impl ScreencopyHandler for AppData {
|
||||||
session: &zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1,
|
session: &zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1,
|
||||||
) {
|
) {
|
||||||
let capture = Capture::for_session(session).unwrap();
|
let capture = Capture::for_session(session).unwrap();
|
||||||
if capture.cancelled.load(Ordering::SeqCst) {
|
if !capture.running() {
|
||||||
session.destroy();
|
session.destroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +81,6 @@ impl ScreencopyHandler for AppData {
|
||||||
session.destroy();
|
session.destroy();
|
||||||
|
|
||||||
// Capture again on damage
|
// Capture again on damage
|
||||||
capture.first_frame.store(false, Ordering::SeqCst);
|
|
||||||
capture.capture(&self.screencopy_state.screencopy_manager, &self.qh);
|
capture.capture(&self.screencopy_state.screencopy_manager, &self.qh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,20 @@ impl WorkspaceHandler for AppData {
|
||||||
let mut workspaces = Vec::new();
|
let mut workspaces = Vec::new();
|
||||||
|
|
||||||
// XXX remove capture source for removed workspaces
|
// XXX remove capture source for removed workspaces
|
||||||
|
// Handle move to another output
|
||||||
|
|
||||||
for group in self.workspace_state.workspace_groups() {
|
for group in self.workspace_state.workspace_groups() {
|
||||||
for workspace in &group.workspaces {
|
for workspace in &group.workspaces {
|
||||||
if let Some(output) = group.output.as_ref() {
|
if let Some(output) = group.output.as_ref() {
|
||||||
let output_name = self.output_names.get(&output.id()).unwrap().clone();
|
if let Some(output_name) = self.output_names.get(&output.id()).unwrap().clone()
|
||||||
workspaces.push((output_name, workspace.clone()));
|
{
|
||||||
|
workspaces.push((output_name, workspace.clone()));
|
||||||
|
|
||||||
self.add_capture_source(CaptureSource::Workspace(
|
self.add_capture_source(CaptureSource::Workspace(
|
||||||
workspace.handle.clone(),
|
workspace.handle.clone(),
|
||||||
output.clone(),
|
output.clone(),
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue